oh-my-opencode 3.6.0 → 3.7.1
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.ja.md +6 -6
- package/README.ko.md +6 -6
- package/README.md +6 -6
- package/README.zh-cn.md +6 -6
- package/dist/agents/sisyphus-junior/gpt.d.ts +4 -14
- package/dist/cli/index.js +357 -104
- package/dist/cli/run/event-handlers.d.ts +1 -0
- package/dist/cli/run/opencode-bin-path.d.ts +3 -0
- package/dist/cli/run/opencode-binary-resolver.d.ts +5 -0
- package/dist/cli/run/session-resolver.d.ts +1 -0
- package/dist/cli/run/types.d.ts +29 -0
- package/dist/config/schema/browser-automation.d.ts +2 -0
- package/dist/config/schema/experimental.d.ts +1 -0
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +3 -0
- package/dist/create-hooks.d.ts +3 -0
- package/dist/create-managers.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +3 -0
- package/dist/features/builtin-skills/skills/index.d.ts +1 -0
- package/dist/features/builtin-skills/skills/playwright-cli.d.ts +10 -0
- package/dist/features/tmux-subagent/action-executor-core.d.ts +21 -0
- package/dist/features/tmux-subagent/action-executor.d.ts +3 -12
- package/dist/features/tmux-subagent/grid-planning.d.ts +2 -2
- package/dist/features/tmux-subagent/pane-split-availability.d.ts +3 -2
- package/dist/features/tmux-subagent/polling-manager.d.ts +1 -0
- package/dist/features/tmux-subagent/spawn-target-finder.d.ts +1 -1
- package/dist/hooks/context-window-monitor.d.ts +5 -1
- package/dist/hooks/directory-agents-injector/hook.d.ts +3 -1
- package/dist/hooks/directory-readme-injector/hook.d.ts +3 -1
- package/dist/hooks/hashline-read-enhancer/hook.d.ts +18 -0
- package/dist/hooks/hashline-read-enhancer/index.d.ts +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/preemptive-compaction.d.ts +4 -1
- package/dist/hooks/rules-injector/hook.d.ts +3 -1
- package/dist/hooks/think-mode/switcher.d.ts +7 -0
- package/dist/hooks/tool-output-truncator.d.ts +3 -0
- package/dist/index.js +1758 -830
- package/dist/plugin/hooks/create-core-hooks.d.ts +3 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts +2 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +4 -1
- package/dist/shared/dynamic-truncator.d.ts +7 -3
- package/dist/shared/fallback-model-availability.d.ts +9 -2
- package/dist/shared/git-worktree/index.d.ts +2 -0
- package/dist/shared/git-worktree/parse-status-porcelain-line.d.ts +6 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/model-availability.d.ts +0 -5
- package/dist/shared/session-directory-resolver.d.ts +7 -0
- package/dist/shared/tmux/tmux-utils/layout.d.ts +2 -2
- package/dist/tools/call-omo-agent/tools.d.ts +1 -1
- package/dist/tools/delegate-task/sync-prompt-sender.d.ts +7 -1
- package/dist/tools/hashline-edit/constants.d.ts +2 -0
- package/dist/tools/hashline-edit/edit-operations.d.ts +6 -0
- package/dist/tools/hashline-edit/hash-computation.d.ts +3 -0
- package/dist/tools/hashline-edit/index.d.ts +7 -0
- package/dist/tools/hashline-edit/tools.d.ts +2 -0
- package/dist/tools/hashline-edit/types.d.ts +22 -0
- package/dist/tools/hashline-edit/validation.d.ts +6 -0
- package/dist/tools/index.d.ts +1 -0
- package/package.json +8 -8
- package/dist/features/background-agent/background-event-handler.d.ts +0 -26
- package/dist/features/background-agent/background-manager-shutdown.d.ts +0 -25
- package/dist/features/background-agent/notification-tracker.d.ts +0 -6
- package/dist/features/background-agent/notify-parent-session.d.ts +0 -10
- package/dist/features/background-agent/poll-running-tasks.d.ts +0 -15
- package/dist/features/background-agent/process-signal.d.ts +0 -2
- package/dist/features/background-agent/session-validator.d.ts +0 -7
- package/dist/features/background-agent/spawner/task-factory.d.ts +0 -2
- package/dist/features/background-agent/spawner/task-resumer.d.ts +0 -3
- package/dist/features/background-agent/spawner/task-starter.d.ts +0 -3
- package/dist/features/background-agent/stale-task-pruner.d.ts +0 -15
- package/dist/features/background-agent/task-canceller.d.ts +0 -27
- package/dist/features/background-agent/task-completer.d.ts +0 -13
- package/dist/features/background-agent/task-launch.d.ts +0 -15
- package/dist/features/background-agent/task-queries.d.ts +0 -7
- package/dist/features/background-agent/task-queue-processor.d.ts +0 -14
- package/dist/features/background-agent/task-resumer.d.ts +0 -14
- package/dist/features/background-agent/task-starter.d.ts +0 -27
- package/dist/features/background-agent/task-tracker.d.ts +0 -18
- package/dist/features/tmux-subagent/manager-cleanup.d.ts +0 -12
- package/dist/features/tmux-subagent/session-cleaner.d.ts +0 -23
- package/dist/features/tmux-subagent/session-spawner.d.ts +0 -34
- package/dist/hooks/interactive-bash-session/interactive-bash-session-hook.d.ts +0 -23
- package/dist/shared/available-models-fetcher.d.ts +0 -4
- package/dist/shared/model-cache-availability.d.ts +0 -2
- package/dist/tools/background-task/modules/background-cancel.d.ts +0 -4
- package/dist/tools/background-task/modules/background-output.d.ts +0 -3
- package/dist/tools/background-task/modules/background-task.d.ts +0 -3
- package/dist/tools/background-task/modules/formatters.d.ts +0 -11
- package/dist/tools/background-task/modules/message-processing.d.ts +0 -59
- package/dist/tools/background-task/modules/utils.d.ts +0 -16
- package/dist/tools/call-omo-agent/agent-type-normalizer.d.ts +0 -2
- package/dist/tools/call-omo-agent/sync-agent-executor.d.ts +0 -4
- package/dist/tools/delegate-task/skill-content-resolver.d.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -15329,9 +15329,12 @@ function normalizeSDKResponse(response, fallback, options) {
|
|
|
15329
15329
|
}
|
|
15330
15330
|
|
|
15331
15331
|
// src/shared/dynamic-truncator.ts
|
|
15332
|
-
var
|
|
15332
|
+
var DEFAULT_ANTHROPIC_ACTUAL_LIMIT = 200000;
|
|
15333
15333
|
var CHARS_PER_TOKEN_ESTIMATE = 4;
|
|
15334
15334
|
var DEFAULT_TARGET_MAX_TOKENS = 50000;
|
|
15335
|
+
function getAnthropicActualLimit(modelCacheState) {
|
|
15336
|
+
return (modelCacheState?.anthropicContext1MEnabled ?? false) || process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : DEFAULT_ANTHROPIC_ACTUAL_LIMIT;
|
|
15337
|
+
}
|
|
15335
15338
|
function estimateTokens(text) {
|
|
15336
15339
|
return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
15337
15340
|
}
|
|
@@ -15392,7 +15395,7 @@ function truncateToTokenLimit(output, maxTokens, preserveHeaderLines = 3) {
|
|
|
15392
15395
|
removedCount
|
|
15393
15396
|
};
|
|
15394
15397
|
}
|
|
15395
|
-
async function getContextWindowUsage(ctx, sessionID) {
|
|
15398
|
+
async function getContextWindowUsage(ctx, sessionID, modelCacheState) {
|
|
15396
15399
|
try {
|
|
15397
15400
|
const response = await ctx.client.session.messages({
|
|
15398
15401
|
path: { id: sessionID }
|
|
@@ -15404,17 +15407,18 @@ async function getContextWindowUsage(ctx, sessionID) {
|
|
|
15404
15407
|
const lastAssistant = assistantMessages[assistantMessages.length - 1];
|
|
15405
15408
|
const lastTokens = lastAssistant.tokens;
|
|
15406
15409
|
const usedTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0) + (lastTokens?.output ?? 0);
|
|
15407
|
-
const
|
|
15410
|
+
const anthropicActualLimit = getAnthropicActualLimit(modelCacheState);
|
|
15411
|
+
const remainingTokens = anthropicActualLimit - usedTokens;
|
|
15408
15412
|
return {
|
|
15409
15413
|
usedTokens,
|
|
15410
15414
|
remainingTokens,
|
|
15411
|
-
usagePercentage: usedTokens /
|
|
15415
|
+
usagePercentage: usedTokens / anthropicActualLimit
|
|
15412
15416
|
};
|
|
15413
15417
|
} catch {
|
|
15414
15418
|
return null;
|
|
15415
15419
|
}
|
|
15416
15420
|
}
|
|
15417
|
-
async function dynamicTruncate(ctx, sessionID, output, options = {}) {
|
|
15421
|
+
async function dynamicTruncate(ctx, sessionID, output, options = {}, modelCacheState) {
|
|
15418
15422
|
if (typeof output !== "string") {
|
|
15419
15423
|
return { result: String(output ?? ""), truncated: false };
|
|
15420
15424
|
}
|
|
@@ -15422,7 +15426,7 @@ async function dynamicTruncate(ctx, sessionID, output, options = {}) {
|
|
|
15422
15426
|
targetMaxTokens = DEFAULT_TARGET_MAX_TOKENS,
|
|
15423
15427
|
preserveHeaderLines = 3
|
|
15424
15428
|
} = options;
|
|
15425
|
-
const usage = await getContextWindowUsage(ctx, sessionID);
|
|
15429
|
+
const usage = await getContextWindowUsage(ctx, sessionID, modelCacheState);
|
|
15426
15430
|
if (!usage) {
|
|
15427
15431
|
return truncateToTokenLimit(output, targetMaxTokens, preserveHeaderLines);
|
|
15428
15432
|
}
|
|
@@ -15435,10 +15439,10 @@ async function dynamicTruncate(ctx, sessionID, output, options = {}) {
|
|
|
15435
15439
|
}
|
|
15436
15440
|
return truncateToTokenLimit(output, maxOutputTokens, preserveHeaderLines);
|
|
15437
15441
|
}
|
|
15438
|
-
function createDynamicTruncator(ctx) {
|
|
15442
|
+
function createDynamicTruncator(ctx, modelCacheState) {
|
|
15439
15443
|
return {
|
|
15440
|
-
truncate: (sessionID, output, options) => dynamicTruncate(ctx, sessionID, output, options),
|
|
15441
|
-
getUsage: (sessionID) => getContextWindowUsage(ctx, sessionID),
|
|
15444
|
+
truncate: (sessionID, output, options) => dynamicTruncate(ctx, sessionID, output, options, modelCacheState),
|
|
15445
|
+
getUsage: (sessionID) => getContextWindowUsage(ctx, sessionID, modelCacheState),
|
|
15442
15446
|
truncateSync: (output, maxTokens, preserveHeaderLines) => truncateToTokenLimit(output, maxTokens, preserveHeaderLines)
|
|
15443
15447
|
};
|
|
15444
15448
|
}
|
|
@@ -17434,7 +17438,7 @@ init_logger();
|
|
|
17434
17438
|
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
17435
17439
|
import { join as join10 } from "path";
|
|
17436
17440
|
function normalizeModelName(name) {
|
|
17437
|
-
return name.toLowerCase().replace(/claude-(opus|sonnet|haiku)-
|
|
17441
|
+
return name.toLowerCase().replace(/claude-(opus|sonnet|haiku)-(\d+)[.-](\d+)/g, "claude-$1-$2.$3");
|
|
17438
17442
|
}
|
|
17439
17443
|
function fuzzyMatchModel(target, available, providers) {
|
|
17440
17444
|
log("[fuzzyMatchModel] called", { target, availableCount: available.size, providers });
|
|
@@ -17459,6 +17463,7 @@ function fuzzyMatchModel(target, available, providers) {
|
|
|
17459
17463
|
const matches = candidates.filter((model) => normalizeModelName(model).includes(targetNormalized));
|
|
17460
17464
|
log("[fuzzyMatchModel] substring matches", { targetNormalized, matchCount: matches.length, matches });
|
|
17461
17465
|
if (matches.length === 0) {
|
|
17466
|
+
log("[fuzzyMatchModel] WARNING: no match found", { target, availableCount: available.size, providers });
|
|
17462
17467
|
return null;
|
|
17463
17468
|
}
|
|
17464
17469
|
const exactMatch = matches.find((model) => normalizeModelName(model) === targetNormalized);
|
|
@@ -17620,55 +17625,6 @@ async function fetchAvailableModels(client, options) {
|
|
|
17620
17625
|
}
|
|
17621
17626
|
return modelSet;
|
|
17622
17627
|
}
|
|
17623
|
-
function isAnyFallbackModelAvailable(fallbackChain, availableModels) {
|
|
17624
|
-
if (availableModels.size > 0) {
|
|
17625
|
-
for (const entry of fallbackChain) {
|
|
17626
|
-
const hasAvailableProvider = entry.providers.some((provider) => {
|
|
17627
|
-
return fuzzyMatchModel(entry.model, availableModels, [provider]) !== null;
|
|
17628
|
-
});
|
|
17629
|
-
if (hasAvailableProvider) {
|
|
17630
|
-
return true;
|
|
17631
|
-
}
|
|
17632
|
-
}
|
|
17633
|
-
}
|
|
17634
|
-
const connectedProviders = readConnectedProvidersCache();
|
|
17635
|
-
if (connectedProviders) {
|
|
17636
|
-
const connectedSet = new Set(connectedProviders);
|
|
17637
|
-
for (const entry of fallbackChain) {
|
|
17638
|
-
if (entry.providers.some((p) => connectedSet.has(p))) {
|
|
17639
|
-
log("[isAnyFallbackModelAvailable] model not in available set, but provider is connected", {
|
|
17640
|
-
model: entry.model,
|
|
17641
|
-
availableCount: availableModels.size
|
|
17642
|
-
});
|
|
17643
|
-
return true;
|
|
17644
|
-
}
|
|
17645
|
-
}
|
|
17646
|
-
}
|
|
17647
|
-
return false;
|
|
17648
|
-
}
|
|
17649
|
-
function isAnyProviderConnected(providers, availableModels) {
|
|
17650
|
-
if (availableModels.size > 0) {
|
|
17651
|
-
const providerSet = new Set(providers);
|
|
17652
|
-
for (const model of availableModels) {
|
|
17653
|
-
const [provider] = model.split("/");
|
|
17654
|
-
if (providerSet.has(provider)) {
|
|
17655
|
-
log("[isAnyProviderConnected] found model from required provider", { provider, model });
|
|
17656
|
-
return true;
|
|
17657
|
-
}
|
|
17658
|
-
}
|
|
17659
|
-
}
|
|
17660
|
-
const connectedProviders = readConnectedProvidersCache();
|
|
17661
|
-
if (connectedProviders) {
|
|
17662
|
-
const connectedSet = new Set(connectedProviders);
|
|
17663
|
-
for (const provider of providers) {
|
|
17664
|
-
if (connectedSet.has(provider)) {
|
|
17665
|
-
log("[isAnyProviderConnected] provider connected via cache", { provider });
|
|
17666
|
-
return true;
|
|
17667
|
-
}
|
|
17668
|
-
}
|
|
17669
|
-
}
|
|
17670
|
-
return false;
|
|
17671
|
-
}
|
|
17672
17628
|
function isModelCacheAvailable() {
|
|
17673
17629
|
if (hasProviderModelsCache()) {
|
|
17674
17630
|
return true;
|
|
@@ -17816,6 +17772,139 @@ function normalizeModel2(model) {
|
|
|
17816
17772
|
function resolveModel(input) {
|
|
17817
17773
|
return normalizeModel2(input.userModel) ?? normalizeModel2(input.inheritedModel) ?? input.systemDefault;
|
|
17818
17774
|
}
|
|
17775
|
+
// src/shared/fallback-model-availability.ts
|
|
17776
|
+
init_logger();
|
|
17777
|
+
|
|
17778
|
+
// src/shared/model-name-matcher.ts
|
|
17779
|
+
init_logger();
|
|
17780
|
+
function normalizeModelName2(name) {
|
|
17781
|
+
return name.toLowerCase().replace(/claude-(opus|sonnet|haiku)-(\d+)[.-](\d+)/g, "claude-$1-$2.$3");
|
|
17782
|
+
}
|
|
17783
|
+
function fuzzyMatchModel2(target, available, providers) {
|
|
17784
|
+
log("[fuzzyMatchModel] called", { target, availableCount: available.size, providers });
|
|
17785
|
+
if (available.size === 0) {
|
|
17786
|
+
log("[fuzzyMatchModel] empty available set");
|
|
17787
|
+
return null;
|
|
17788
|
+
}
|
|
17789
|
+
const targetNormalized = normalizeModelName2(target);
|
|
17790
|
+
let candidates = Array.from(available);
|
|
17791
|
+
if (providers && providers.length > 0) {
|
|
17792
|
+
const providerSet = new Set(providers);
|
|
17793
|
+
candidates = candidates.filter((model) => {
|
|
17794
|
+
const [provider] = model.split("/");
|
|
17795
|
+
return providerSet.has(provider);
|
|
17796
|
+
});
|
|
17797
|
+
log("[fuzzyMatchModel] filtered by providers", {
|
|
17798
|
+
candidateCount: candidates.length,
|
|
17799
|
+
candidates: candidates.slice(0, 10)
|
|
17800
|
+
});
|
|
17801
|
+
}
|
|
17802
|
+
if (candidates.length === 0) {
|
|
17803
|
+
log("[fuzzyMatchModel] no candidates after filter");
|
|
17804
|
+
return null;
|
|
17805
|
+
}
|
|
17806
|
+
const matches = candidates.filter((model) => normalizeModelName2(model).includes(targetNormalized));
|
|
17807
|
+
log("[fuzzyMatchModel] substring matches", {
|
|
17808
|
+
targetNormalized,
|
|
17809
|
+
matchCount: matches.length,
|
|
17810
|
+
matches
|
|
17811
|
+
});
|
|
17812
|
+
if (matches.length === 0) {
|
|
17813
|
+
return null;
|
|
17814
|
+
}
|
|
17815
|
+
const exactMatch = matches.find((model) => normalizeModelName2(model) === targetNormalized);
|
|
17816
|
+
if (exactMatch) {
|
|
17817
|
+
log("[fuzzyMatchModel] exact match found", { exactMatch });
|
|
17818
|
+
return exactMatch;
|
|
17819
|
+
}
|
|
17820
|
+
const exactModelIdMatches = matches.filter((model) => {
|
|
17821
|
+
const modelId = model.split("/").slice(1).join("/");
|
|
17822
|
+
return normalizeModelName2(modelId) === targetNormalized;
|
|
17823
|
+
});
|
|
17824
|
+
if (exactModelIdMatches.length > 0) {
|
|
17825
|
+
const result2 = exactModelIdMatches.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
|
|
17826
|
+
log("[fuzzyMatchModel] exact model ID match found", {
|
|
17827
|
+
result: result2,
|
|
17828
|
+
candidateCount: exactModelIdMatches.length
|
|
17829
|
+
});
|
|
17830
|
+
return result2;
|
|
17831
|
+
}
|
|
17832
|
+
const result = matches.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
|
|
17833
|
+
log("[fuzzyMatchModel] shortest match", { result });
|
|
17834
|
+
return result;
|
|
17835
|
+
}
|
|
17836
|
+
|
|
17837
|
+
// src/shared/fallback-model-availability.ts
|
|
17838
|
+
function resolveFirstAvailableFallback(fallbackChain, availableModels) {
|
|
17839
|
+
for (const entry of fallbackChain) {
|
|
17840
|
+
for (const provider of entry.providers) {
|
|
17841
|
+
const matchedModel = fuzzyMatchModel2(entry.model, availableModels, [provider]);
|
|
17842
|
+
log("[resolveFirstAvailableFallback] attempt", {
|
|
17843
|
+
provider,
|
|
17844
|
+
requestedModel: entry.model,
|
|
17845
|
+
resolvedModel: matchedModel
|
|
17846
|
+
});
|
|
17847
|
+
if (matchedModel !== null) {
|
|
17848
|
+
log("[resolveFirstAvailableFallback] resolved", {
|
|
17849
|
+
provider,
|
|
17850
|
+
requestedModel: entry.model,
|
|
17851
|
+
resolvedModel: matchedModel
|
|
17852
|
+
});
|
|
17853
|
+
return { provider, model: matchedModel };
|
|
17854
|
+
}
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17857
|
+
log("[resolveFirstAvailableFallback] WARNING: no fallback model resolved", {
|
|
17858
|
+
chain: fallbackChain.map((entry) => ({
|
|
17859
|
+
model: entry.model,
|
|
17860
|
+
providers: entry.providers
|
|
17861
|
+
})),
|
|
17862
|
+
availableCount: availableModels.size
|
|
17863
|
+
});
|
|
17864
|
+
return null;
|
|
17865
|
+
}
|
|
17866
|
+
function isAnyFallbackModelAvailable(fallbackChain, availableModels) {
|
|
17867
|
+
if (resolveFirstAvailableFallback(fallbackChain, availableModels) !== null) {
|
|
17868
|
+
return true;
|
|
17869
|
+
}
|
|
17870
|
+
const connectedProviders = readConnectedProvidersCache();
|
|
17871
|
+
if (connectedProviders) {
|
|
17872
|
+
const connectedSet = new Set(connectedProviders);
|
|
17873
|
+
for (const entry of fallbackChain) {
|
|
17874
|
+
if (entry.providers.some((p) => connectedSet.has(p))) {
|
|
17875
|
+
log("[isAnyFallbackModelAvailable] WARNING: No fuzzy match found for any model in fallback chain, but provider is connected. Agent may fail at runtime.", { chain: fallbackChain.map((entryItem) => entryItem.model), availableCount: availableModels.size });
|
|
17876
|
+
return true;
|
|
17877
|
+
}
|
|
17878
|
+
}
|
|
17879
|
+
}
|
|
17880
|
+
return false;
|
|
17881
|
+
}
|
|
17882
|
+
function isAnyProviderConnected(providers, availableModels) {
|
|
17883
|
+
if (availableModels.size > 0) {
|
|
17884
|
+
const providerSet = new Set(providers);
|
|
17885
|
+
for (const model of availableModels) {
|
|
17886
|
+
const [provider] = model.split("/");
|
|
17887
|
+
if (providerSet.has(provider)) {
|
|
17888
|
+
log("[isAnyProviderConnected] found model from required provider", {
|
|
17889
|
+
provider,
|
|
17890
|
+
model
|
|
17891
|
+
});
|
|
17892
|
+
return true;
|
|
17893
|
+
}
|
|
17894
|
+
}
|
|
17895
|
+
}
|
|
17896
|
+
const connectedProviders = readConnectedProvidersCache();
|
|
17897
|
+
if (connectedProviders) {
|
|
17898
|
+
const connectedSet = new Set(connectedProviders);
|
|
17899
|
+
for (const provider of providers) {
|
|
17900
|
+
if (connectedSet.has(provider)) {
|
|
17901
|
+
log("[isAnyProviderConnected] provider connected via cache", { provider });
|
|
17902
|
+
return true;
|
|
17903
|
+
}
|
|
17904
|
+
}
|
|
17905
|
+
}
|
|
17906
|
+
return false;
|
|
17907
|
+
}
|
|
17819
17908
|
// src/features/hook-message-injector/injector.ts
|
|
17820
17909
|
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync, writeFileSync as writeFileSync3 } from "fs";
|
|
17821
17910
|
import { join as join11 } from "path";
|
|
@@ -18303,13 +18392,29 @@ async function replaceTmuxPane(paneId, sessionId, description, config, serverUrl
|
|
|
18303
18392
|
}
|
|
18304
18393
|
// src/shared/tmux/tmux-utils/layout.ts
|
|
18305
18394
|
var {spawn: spawn8 } = globalThis.Bun;
|
|
18306
|
-
async function
|
|
18395
|
+
async function applyLayout(layout, mainPaneSize) {
|
|
18396
|
+
const tmux = await getTmuxPath();
|
|
18397
|
+
if (!tmux)
|
|
18398
|
+
return;
|
|
18399
|
+
const layoutProc = spawn8([tmux, "select-layout", layout], {
|
|
18400
|
+
stdout: "ignore",
|
|
18401
|
+
stderr: "ignore"
|
|
18402
|
+
});
|
|
18403
|
+
await layoutProc.exited;
|
|
18404
|
+
if (layout.startsWith("main-")) {
|
|
18405
|
+
const dimension = layout === "main-horizontal" ? "main-pane-height" : "main-pane-width";
|
|
18406
|
+
const sizeProc = spawn8([tmux, "set-window-option", dimension, `${mainPaneSize}%`], { stdout: "ignore", stderr: "ignore" });
|
|
18407
|
+
await sizeProc.exited;
|
|
18408
|
+
}
|
|
18409
|
+
}
|
|
18410
|
+
async function enforceMainPaneWidth(mainPaneId, windowWidth, mainPaneSize) {
|
|
18307
18411
|
const { log: log2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
|
|
18308
18412
|
const tmux = await getTmuxPath();
|
|
18309
18413
|
if (!tmux)
|
|
18310
18414
|
return;
|
|
18311
18415
|
const dividerWidth = 1;
|
|
18312
|
-
const
|
|
18416
|
+
const boundedMainPaneSize = Math.max(20, Math.min(80, mainPaneSize));
|
|
18417
|
+
const mainWidth = Math.floor((windowWidth - dividerWidth) * boundedMainPaneSize / 100);
|
|
18313
18418
|
const proc = spawn8([tmux, "resize-pane", "-t", mainPaneId, "-x", String(mainWidth)], {
|
|
18314
18419
|
stdout: "ignore",
|
|
18315
18420
|
stderr: "ignore"
|
|
@@ -18318,7 +18423,8 @@ async function enforceMainPaneWidth(mainPaneId, windowWidth) {
|
|
|
18318
18423
|
log2("[enforceMainPaneWidth] main pane resized", {
|
|
18319
18424
|
mainPaneId,
|
|
18320
18425
|
mainWidth,
|
|
18321
|
-
windowWidth
|
|
18426
|
+
windowWidth,
|
|
18427
|
+
mainPaneSize: boundedMainPaneSize
|
|
18322
18428
|
});
|
|
18323
18429
|
}
|
|
18324
18430
|
// src/shared/model-suggestion-retry.ts
|
|
@@ -18668,6 +18774,26 @@ async function deletePart(client, sessionID, messageID, partID) {
|
|
|
18668
18774
|
return false;
|
|
18669
18775
|
}
|
|
18670
18776
|
}
|
|
18777
|
+
// src/shared/git-worktree/parse-status-porcelain-line.ts
|
|
18778
|
+
function toGitFileStatus(statusToken) {
|
|
18779
|
+
if (statusToken === "A" || statusToken === "??")
|
|
18780
|
+
return "added";
|
|
18781
|
+
if (statusToken === "D")
|
|
18782
|
+
return "deleted";
|
|
18783
|
+
return "modified";
|
|
18784
|
+
}
|
|
18785
|
+
function parseGitStatusPorcelainLine(line) {
|
|
18786
|
+
if (!line)
|
|
18787
|
+
return null;
|
|
18788
|
+
const statusToken = line.substring(0, 2).trim();
|
|
18789
|
+
const filePath = line.substring(3);
|
|
18790
|
+
if (!filePath)
|
|
18791
|
+
return null;
|
|
18792
|
+
return {
|
|
18793
|
+
filePath,
|
|
18794
|
+
status: toGitFileStatus(statusToken)
|
|
18795
|
+
};
|
|
18796
|
+
}
|
|
18671
18797
|
// src/shared/git-worktree/parse-status-porcelain.ts
|
|
18672
18798
|
function parseGitStatusPorcelain(output) {
|
|
18673
18799
|
const map2 = new Map;
|
|
@@ -18675,19 +18801,10 @@ function parseGitStatusPorcelain(output) {
|
|
|
18675
18801
|
return map2;
|
|
18676
18802
|
for (const line of output.split(`
|
|
18677
18803
|
`)) {
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
const status = line.substring(0, 2).trim();
|
|
18681
|
-
const filePath = line.substring(3);
|
|
18682
|
-
if (!filePath)
|
|
18804
|
+
const parsed = parseGitStatusPorcelainLine(line);
|
|
18805
|
+
if (!parsed)
|
|
18683
18806
|
continue;
|
|
18684
|
-
|
|
18685
|
-
map2.set(filePath, "added");
|
|
18686
|
-
} else if (status === "D") {
|
|
18687
|
-
map2.set(filePath, "deleted");
|
|
18688
|
-
} else {
|
|
18689
|
-
map2.set(filePath, "modified");
|
|
18690
|
-
}
|
|
18807
|
+
map2.set(parsed.filePath, parsed.status);
|
|
18691
18808
|
}
|
|
18692
18809
|
return map2;
|
|
18693
18810
|
}
|
|
@@ -19372,14 +19489,20 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
19372
19489
|
}
|
|
19373
19490
|
// src/hooks/context-window-monitor.ts
|
|
19374
19491
|
var ANTHROPIC_DISPLAY_LIMIT = 1e6;
|
|
19375
|
-
var
|
|
19492
|
+
var DEFAULT_ANTHROPIC_ACTUAL_LIMIT2 = 200000;
|
|
19376
19493
|
var CONTEXT_WARNING_THRESHOLD = 0.7;
|
|
19494
|
+
function getAnthropicActualLimit2(modelCacheState) {
|
|
19495
|
+
return (modelCacheState?.anthropicContext1MEnabled ?? false) || process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : DEFAULT_ANTHROPIC_ACTUAL_LIMIT2;
|
|
19496
|
+
}
|
|
19377
19497
|
var CONTEXT_REMINDER = `${createSystemDirective(SystemDirectiveTypes.CONTEXT_WINDOW_MONITOR)}
|
|
19378
19498
|
|
|
19379
19499
|
You are using Anthropic Claude with 1M context window.
|
|
19380
19500
|
You have plenty of context remaining - do NOT rush or skip tasks.
|
|
19381
19501
|
Complete your work thoroughly and methodically.`;
|
|
19382
|
-
function
|
|
19502
|
+
function isAnthropicProvider(providerID) {
|
|
19503
|
+
return providerID === "anthropic" || providerID === "google-vertex-anthropic";
|
|
19504
|
+
}
|
|
19505
|
+
function createContextWindowMonitorHook(_ctx, modelCacheState) {
|
|
19383
19506
|
const remindedSessions = new Set;
|
|
19384
19507
|
const tokenCache = new Map;
|
|
19385
19508
|
const toolExecuteAfter = async (input, output) => {
|
|
@@ -19389,11 +19512,11 @@ function createContextWindowMonitorHook(_ctx) {
|
|
|
19389
19512
|
const cached = tokenCache.get(sessionID);
|
|
19390
19513
|
if (!cached)
|
|
19391
19514
|
return;
|
|
19392
|
-
if (cached.providerID
|
|
19515
|
+
if (!isAnthropicProvider(cached.providerID))
|
|
19393
19516
|
return;
|
|
19394
19517
|
const lastTokens = cached.tokens;
|
|
19395
19518
|
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
19396
|
-
const actualUsagePercentage = totalInputTokens /
|
|
19519
|
+
const actualUsagePercentage = totalInputTokens / getAnthropicActualLimit2(modelCacheState);
|
|
19397
19520
|
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD)
|
|
19398
19521
|
return;
|
|
19399
19522
|
remindedSessions.add(sessionID);
|
|
@@ -33307,6 +33430,7 @@ function isCliPathUsable(cliPath) {
|
|
|
33307
33430
|
var pendingCalls = new Map;
|
|
33308
33431
|
var PENDING_CALL_TTL = 60000;
|
|
33309
33432
|
var cleanupIntervalStarted = false;
|
|
33433
|
+
var cleanupInterval;
|
|
33310
33434
|
function cleanupOldPendingCalls() {
|
|
33311
33435
|
const now = Date.now();
|
|
33312
33436
|
for (const [callID, call] of pendingCalls) {
|
|
@@ -33319,7 +33443,10 @@ function startPendingCallCleanup() {
|
|
|
33319
33443
|
if (cleanupIntervalStarted)
|
|
33320
33444
|
return;
|
|
33321
33445
|
cleanupIntervalStarted = true;
|
|
33322
|
-
setInterval(cleanupOldPendingCalls, 1e4);
|
|
33446
|
+
cleanupInterval = setInterval(cleanupOldPendingCalls, 1e4);
|
|
33447
|
+
if (typeof cleanupInterval === "object" && "unref" in cleanupInterval) {
|
|
33448
|
+
cleanupInterval.unref();
|
|
33449
|
+
}
|
|
33323
33450
|
}
|
|
33324
33451
|
function registerPendingCall(callID, pendingCall) {
|
|
33325
33452
|
pendingCalls.set(callID, pendingCall);
|
|
@@ -33476,7 +33603,7 @@ var TOOL_SPECIFIC_MAX_TOKENS = {
|
|
|
33476
33603
|
WebFetch: WEBFETCH_MAX_TOKENS
|
|
33477
33604
|
};
|
|
33478
33605
|
function createToolOutputTruncatorHook(ctx, options) {
|
|
33479
|
-
const truncator = createDynamicTruncator(ctx);
|
|
33606
|
+
const truncator = createDynamicTruncator(ctx, options?.modelCacheState);
|
|
33480
33607
|
const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? false;
|
|
33481
33608
|
const toolExecuteAfter = async (input, output) => {
|
|
33482
33609
|
if (!truncateAll && !TRUNCATABLE_TOOLS.includes(input.tool))
|
|
@@ -33632,9 +33759,9 @@ ${result}${truncationNotice}`;
|
|
|
33632
33759
|
}
|
|
33633
33760
|
|
|
33634
33761
|
// src/hooks/directory-agents-injector/hook.ts
|
|
33635
|
-
function createDirectoryAgentsInjectorHook(ctx) {
|
|
33762
|
+
function createDirectoryAgentsInjectorHook(ctx, modelCacheState) {
|
|
33636
33763
|
const sessionCaches = new Map;
|
|
33637
|
-
const truncator = createDynamicTruncator(ctx);
|
|
33764
|
+
const truncator = createDynamicTruncator(ctx, modelCacheState);
|
|
33638
33765
|
const toolExecuteAfter = async (input, output) => {
|
|
33639
33766
|
const toolName = input.tool.toLowerCase();
|
|
33640
33767
|
if (toolName === "read") {
|
|
@@ -33760,9 +33887,9 @@ ${result}${truncationNotice}`;
|
|
|
33760
33887
|
}
|
|
33761
33888
|
|
|
33762
33889
|
// src/hooks/directory-readme-injector/hook.ts
|
|
33763
|
-
function createDirectoryReadmeInjectorHook(ctx) {
|
|
33890
|
+
function createDirectoryReadmeInjectorHook(ctx, modelCacheState) {
|
|
33764
33891
|
const sessionCaches = new Map;
|
|
33765
|
-
const truncator = createDynamicTruncator(ctx);
|
|
33892
|
+
const truncator = createDynamicTruncator(ctx, modelCacheState);
|
|
33766
33893
|
const toolExecuteAfter = async (input, output) => {
|
|
33767
33894
|
const toolName = input.tool.toLowerCase();
|
|
33768
33895
|
if (toolName === "read") {
|
|
@@ -35389,6 +35516,13 @@ var THINKING_CONFIGS = {
|
|
|
35389
35516
|
},
|
|
35390
35517
|
maxTokens: 128000
|
|
35391
35518
|
},
|
|
35519
|
+
"google-vertex-anthropic": {
|
|
35520
|
+
thinking: {
|
|
35521
|
+
type: "enabled",
|
|
35522
|
+
budgetTokens: 64000
|
|
35523
|
+
},
|
|
35524
|
+
maxTokens: 128000
|
|
35525
|
+
},
|
|
35392
35526
|
"amazon-bedrock": {
|
|
35393
35527
|
reasoningConfig: {
|
|
35394
35528
|
type: "enabled",
|
|
@@ -35431,6 +35565,7 @@ var THINKING_CONFIGS = {
|
|
|
35431
35565
|
};
|
|
35432
35566
|
var THINKING_CAPABLE_MODELS = {
|
|
35433
35567
|
anthropic: ["claude-sonnet-4", "claude-opus-4", "claude-3"],
|
|
35568
|
+
"google-vertex-anthropic": ["claude-sonnet-4", "claude-opus-4", "claude-3"],
|
|
35434
35569
|
"amazon-bedrock": ["claude", "anthropic"],
|
|
35435
35570
|
google: ["gemini-2", "gemini-3"],
|
|
35436
35571
|
"google-vertex": ["gemini-2", "gemini-3"],
|
|
@@ -36426,7 +36561,7 @@ function getToolInput(sessionId, toolName, invocationId) {
|
|
|
36426
36561
|
return null;
|
|
36427
36562
|
return entry.toolInput;
|
|
36428
36563
|
}
|
|
36429
|
-
var
|
|
36564
|
+
var cleanupInterval2 = setInterval(() => {
|
|
36430
36565
|
const now = Date.now();
|
|
36431
36566
|
for (const [key, entry] of cache.entries()) {
|
|
36432
36567
|
if (now - entry.timestamp > CACHE_TTL) {
|
|
@@ -36434,8 +36569,8 @@ var cleanupInterval = setInterval(() => {
|
|
|
36434
36569
|
}
|
|
36435
36570
|
}
|
|
36436
36571
|
}, CACHE_TTL);
|
|
36437
|
-
if (typeof
|
|
36438
|
-
|
|
36572
|
+
if (typeof cleanupInterval2 === "object" && "unref" in cleanupInterval2) {
|
|
36573
|
+
cleanupInterval2.unref();
|
|
36439
36574
|
}
|
|
36440
36575
|
|
|
36441
36576
|
// src/hooks/claude-code-hooks/handlers/tool-execute-after-handler.ts
|
|
@@ -37195,8 +37330,8 @@ ${result}${truncationNotice}`;
|
|
|
37195
37330
|
|
|
37196
37331
|
// src/hooks/rules-injector/hook.ts
|
|
37197
37332
|
var TRACKED_TOOLS = ["read", "write", "edit", "multiedit"];
|
|
37198
|
-
function createRulesInjectorHook(ctx) {
|
|
37199
|
-
const truncator = createDynamicTruncator(ctx);
|
|
37333
|
+
function createRulesInjectorHook(ctx, modelCacheState) {
|
|
37334
|
+
const truncator = createDynamicTruncator(ctx, modelCacheState);
|
|
37200
37335
|
const { getSessionCache: getSessionCache3, clearSessionCache } = createSessionCacheStore();
|
|
37201
37336
|
const { processFilePathForInjection } = createRuleInjectionProcessor({
|
|
37202
37337
|
workspaceDirectory: ctx.directory,
|
|
@@ -37848,6 +37983,7 @@ async function showLocalDevToast(ctx, version2, isSisyphusEnabled) {
|
|
|
37848
37983
|
// src/hooks/auto-update-checker/hook.ts
|
|
37849
37984
|
function createAutoUpdateCheckerHook(ctx, options = {}) {
|
|
37850
37985
|
const { showStartupToast = true, isSisyphusEnabled = false, autoUpdate = true } = options;
|
|
37986
|
+
const isCliRunMode = process.env.OPENCODE_CLI_RUN_MODE === "true";
|
|
37851
37987
|
const getToastMessage = (isUpdate, latestVersion) => {
|
|
37852
37988
|
if (isSisyphusEnabled) {
|
|
37853
37989
|
return isUpdate ? `Sisyphus on steroids is steering OpenCode.
|
|
@@ -37861,6 +37997,8 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
|
|
|
37861
37997
|
event: ({ event }) => {
|
|
37862
37998
|
if (event.type !== "session.created")
|
|
37863
37999
|
return;
|
|
38000
|
+
if (isCliRunMode)
|
|
38001
|
+
return;
|
|
37864
38002
|
if (hasChecked)
|
|
37865
38003
|
return;
|
|
37866
38004
|
const props = event.properties;
|
|
@@ -42046,6 +42184,265 @@ agent-browser trace stop trace.zip # Stop and save trace
|
|
|
42046
42184
|
Install: \`bun add -g agent-browser && agent-browser install\`. Run \`agent-browser --help\` for all commands. Repo: https://github.com/vercel-labs/agent-browser`,
|
|
42047
42185
|
allowedTools: ["Bash(agent-browser:*)"]
|
|
42048
42186
|
};
|
|
42187
|
+
// src/features/builtin-skills/skills/playwright-cli.ts
|
|
42188
|
+
var playwrightCliSkill = {
|
|
42189
|
+
name: "playwright",
|
|
42190
|
+
description: "MUST USE for any browser-related tasks. Browser automation via playwright-cli - verification, browsing, information gathering, web scraping, testing, screenshots, and all browser interactions.",
|
|
42191
|
+
template: `# Browser Automation with playwright-cli
|
|
42192
|
+
|
|
42193
|
+
## Quick start
|
|
42194
|
+
|
|
42195
|
+
\`\`\`bash
|
|
42196
|
+
# open new browser
|
|
42197
|
+
playwright-cli open
|
|
42198
|
+
# navigate to a page
|
|
42199
|
+
playwright-cli goto https://playwright.dev
|
|
42200
|
+
# interact with the page using refs from the snapshot
|
|
42201
|
+
playwright-cli click e15
|
|
42202
|
+
playwright-cli type "page.click"
|
|
42203
|
+
playwright-cli press Enter
|
|
42204
|
+
# take a screenshot
|
|
42205
|
+
playwright-cli screenshot
|
|
42206
|
+
# close the browser
|
|
42207
|
+
playwright-cli close
|
|
42208
|
+
\`\`\`
|
|
42209
|
+
|
|
42210
|
+
## Commands
|
|
42211
|
+
|
|
42212
|
+
### Core
|
|
42213
|
+
|
|
42214
|
+
\`\`\`bash
|
|
42215
|
+
playwright-cli open
|
|
42216
|
+
# open and navigate right away
|
|
42217
|
+
playwright-cli open https://example.com/
|
|
42218
|
+
playwright-cli goto https://playwright.dev
|
|
42219
|
+
playwright-cli type "search query"
|
|
42220
|
+
playwright-cli click e3
|
|
42221
|
+
playwright-cli dblclick e7
|
|
42222
|
+
playwright-cli fill e5 "user@example.com"
|
|
42223
|
+
playwright-cli drag e2 e8
|
|
42224
|
+
playwright-cli hover e4
|
|
42225
|
+
playwright-cli select e9 "option-value"
|
|
42226
|
+
playwright-cli upload ./document.pdf
|
|
42227
|
+
playwright-cli check e12
|
|
42228
|
+
playwright-cli uncheck e12
|
|
42229
|
+
playwright-cli snapshot
|
|
42230
|
+
playwright-cli snapshot --filename=after-click.yaml
|
|
42231
|
+
playwright-cli eval "document.title"
|
|
42232
|
+
playwright-cli eval "el => el.textContent" e5
|
|
42233
|
+
playwright-cli dialog-accept
|
|
42234
|
+
playwright-cli dialog-accept "confirmation text"
|
|
42235
|
+
playwright-cli dialog-dismiss
|
|
42236
|
+
playwright-cli resize 1920 1080
|
|
42237
|
+
playwright-cli close
|
|
42238
|
+
\`\`\`
|
|
42239
|
+
|
|
42240
|
+
### Navigation
|
|
42241
|
+
|
|
42242
|
+
\`\`\`bash
|
|
42243
|
+
playwright-cli go-back
|
|
42244
|
+
playwright-cli go-forward
|
|
42245
|
+
playwright-cli reload
|
|
42246
|
+
\`\`\`
|
|
42247
|
+
|
|
42248
|
+
### Keyboard
|
|
42249
|
+
|
|
42250
|
+
\`\`\`bash
|
|
42251
|
+
playwright-cli press Enter
|
|
42252
|
+
playwright-cli press ArrowDown
|
|
42253
|
+
playwright-cli keydown Shift
|
|
42254
|
+
playwright-cli keyup Shift
|
|
42255
|
+
\`\`\`
|
|
42256
|
+
|
|
42257
|
+
### Mouse
|
|
42258
|
+
|
|
42259
|
+
\`\`\`bash
|
|
42260
|
+
playwright-cli mousemove 150 300
|
|
42261
|
+
playwright-cli mousedown
|
|
42262
|
+
playwright-cli mousedown right
|
|
42263
|
+
playwright-cli mouseup
|
|
42264
|
+
playwright-cli mouseup right
|
|
42265
|
+
playwright-cli mousewheel 0 100
|
|
42266
|
+
\`\`\`
|
|
42267
|
+
|
|
42268
|
+
### Save as
|
|
42269
|
+
|
|
42270
|
+
\`\`\`bash
|
|
42271
|
+
playwright-cli screenshot
|
|
42272
|
+
playwright-cli screenshot e5
|
|
42273
|
+
playwright-cli screenshot --filename=page.png
|
|
42274
|
+
playwright-cli pdf --filename=page.pdf
|
|
42275
|
+
\`\`\`
|
|
42276
|
+
|
|
42277
|
+
### Tabs
|
|
42278
|
+
|
|
42279
|
+
\`\`\`bash
|
|
42280
|
+
playwright-cli tab-list
|
|
42281
|
+
playwright-cli tab-new
|
|
42282
|
+
playwright-cli tab-new https://example.com/page
|
|
42283
|
+
playwright-cli tab-close
|
|
42284
|
+
playwright-cli tab-close 2
|
|
42285
|
+
playwright-cli tab-select 0
|
|
42286
|
+
\`\`\`
|
|
42287
|
+
|
|
42288
|
+
### Storage
|
|
42289
|
+
|
|
42290
|
+
\`\`\`bash
|
|
42291
|
+
playwright-cli state-save
|
|
42292
|
+
playwright-cli state-save auth.json
|
|
42293
|
+
playwright-cli state-load auth.json
|
|
42294
|
+
|
|
42295
|
+
# Cookies
|
|
42296
|
+
playwright-cli cookie-list
|
|
42297
|
+
playwright-cli cookie-list --domain=example.com
|
|
42298
|
+
playwright-cli cookie-get session_id
|
|
42299
|
+
playwright-cli cookie-set session_id abc123
|
|
42300
|
+
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
|
|
42301
|
+
playwright-cli cookie-delete session_id
|
|
42302
|
+
playwright-cli cookie-clear
|
|
42303
|
+
|
|
42304
|
+
# LocalStorage
|
|
42305
|
+
playwright-cli localstorage-list
|
|
42306
|
+
playwright-cli localstorage-get theme
|
|
42307
|
+
playwright-cli localstorage-set theme dark
|
|
42308
|
+
playwright-cli localstorage-delete theme
|
|
42309
|
+
playwright-cli localstorage-clear
|
|
42310
|
+
|
|
42311
|
+
# SessionStorage
|
|
42312
|
+
playwright-cli sessionstorage-list
|
|
42313
|
+
playwright-cli sessionstorage-get step
|
|
42314
|
+
playwright-cli sessionstorage-set step 3
|
|
42315
|
+
playwright-cli sessionstorage-delete step
|
|
42316
|
+
playwright-cli sessionstorage-clear
|
|
42317
|
+
\`\`\`
|
|
42318
|
+
|
|
42319
|
+
### Network
|
|
42320
|
+
|
|
42321
|
+
\`\`\`bash
|
|
42322
|
+
playwright-cli route "**/*.jpg" --status=404
|
|
42323
|
+
playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
|
|
42324
|
+
playwright-cli route-list
|
|
42325
|
+
playwright-cli unroute "**/*.jpg"
|
|
42326
|
+
playwright-cli unroute
|
|
42327
|
+
\`\`\`
|
|
42328
|
+
|
|
42329
|
+
### DevTools
|
|
42330
|
+
|
|
42331
|
+
\`\`\`bash
|
|
42332
|
+
playwright-cli console
|
|
42333
|
+
playwright-cli console warning
|
|
42334
|
+
playwright-cli network
|
|
42335
|
+
playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
|
|
42336
|
+
playwright-cli tracing-start
|
|
42337
|
+
playwright-cli tracing-stop
|
|
42338
|
+
playwright-cli video-start
|
|
42339
|
+
playwright-cli video-stop video.webm
|
|
42340
|
+
\`\`\`
|
|
42341
|
+
|
|
42342
|
+
### Install
|
|
42343
|
+
|
|
42344
|
+
\`\`\`bash
|
|
42345
|
+
playwright-cli install --skills
|
|
42346
|
+
playwright-cli install-browser
|
|
42347
|
+
\`\`\`
|
|
42348
|
+
|
|
42349
|
+
### Configuration
|
|
42350
|
+
\`\`\`bash
|
|
42351
|
+
# Use specific browser when creating session
|
|
42352
|
+
playwright-cli open --browser=chrome
|
|
42353
|
+
playwright-cli open --browser=firefox
|
|
42354
|
+
playwright-cli open --browser=webkit
|
|
42355
|
+
playwright-cli open --browser=msedge
|
|
42356
|
+
# Connect to browser via extension
|
|
42357
|
+
playwright-cli open --extension
|
|
42358
|
+
|
|
42359
|
+
# Use persistent profile (by default profile is in-memory)
|
|
42360
|
+
playwright-cli open --persistent
|
|
42361
|
+
# Use persistent profile with custom directory
|
|
42362
|
+
playwright-cli open --profile=/path/to/profile
|
|
42363
|
+
|
|
42364
|
+
# Start with config file
|
|
42365
|
+
playwright-cli open --config=my-config.json
|
|
42366
|
+
|
|
42367
|
+
# Close the browser
|
|
42368
|
+
playwright-cli close
|
|
42369
|
+
# Delete user data for the default session
|
|
42370
|
+
playwright-cli delete-data
|
|
42371
|
+
\`\`\`
|
|
42372
|
+
|
|
42373
|
+
### Browser Sessions
|
|
42374
|
+
|
|
42375
|
+
\`\`\`bash
|
|
42376
|
+
# create new browser session named "mysession" with persistent profile
|
|
42377
|
+
playwright-cli -s=mysession open example.com --persistent
|
|
42378
|
+
# same with manually specified profile directory (use when requested explicitly)
|
|
42379
|
+
playwright-cli -s=mysession open example.com --profile=/path/to/profile
|
|
42380
|
+
playwright-cli -s=mysession click e6
|
|
42381
|
+
playwright-cli -s=mysession close # stop a named browser
|
|
42382
|
+
playwright-cli -s=mysession delete-data # delete user data for persistent session
|
|
42383
|
+
|
|
42384
|
+
playwright-cli list
|
|
42385
|
+
# Close all browsers
|
|
42386
|
+
playwright-cli close-all
|
|
42387
|
+
# Forcefully kill all browser processes
|
|
42388
|
+
playwright-cli kill-all
|
|
42389
|
+
\`\`\`
|
|
42390
|
+
|
|
42391
|
+
## Example: Form submission
|
|
42392
|
+
|
|
42393
|
+
\`\`\`bash
|
|
42394
|
+
playwright-cli open https://example.com/form
|
|
42395
|
+
playwright-cli snapshot
|
|
42396
|
+
|
|
42397
|
+
playwright-cli fill e1 "user@example.com"
|
|
42398
|
+
playwright-cli fill e2 "password123"
|
|
42399
|
+
playwright-cli click e3
|
|
42400
|
+
playwright-cli snapshot
|
|
42401
|
+
playwright-cli close
|
|
42402
|
+
\`\`\`
|
|
42403
|
+
|
|
42404
|
+
## Example: Multi-tab workflow
|
|
42405
|
+
|
|
42406
|
+
\`\`\`bash
|
|
42407
|
+
playwright-cli open https://example.com
|
|
42408
|
+
playwright-cli tab-new https://example.com/other
|
|
42409
|
+
playwright-cli tab-list
|
|
42410
|
+
playwright-cli tab-select 0
|
|
42411
|
+
playwright-cli snapshot
|
|
42412
|
+
playwright-cli close
|
|
42413
|
+
\`\`\`
|
|
42414
|
+
|
|
42415
|
+
## Example: Debugging with DevTools
|
|
42416
|
+
|
|
42417
|
+
\`\`\`bash
|
|
42418
|
+
playwright-cli open https://example.com
|
|
42419
|
+
playwright-cli click e4
|
|
42420
|
+
playwright-cli fill e7 "test"
|
|
42421
|
+
playwright-cli console
|
|
42422
|
+
playwright-cli network
|
|
42423
|
+
playwright-cli close
|
|
42424
|
+
\`\`\`
|
|
42425
|
+
|
|
42426
|
+
\`\`\`bash
|
|
42427
|
+
playwright-cli open https://example.com
|
|
42428
|
+
playwright-cli tracing-start
|
|
42429
|
+
playwright-cli click e4
|
|
42430
|
+
playwright-cli fill e7 "test"
|
|
42431
|
+
playwright-cli tracing-stop
|
|
42432
|
+
playwright-cli close
|
|
42433
|
+
\`\`\`
|
|
42434
|
+
|
|
42435
|
+
## Specific tasks
|
|
42436
|
+
|
|
42437
|
+
* **Request mocking** [references/request-mocking.md](references/request-mocking.md)
|
|
42438
|
+
* **Running Playwright code** [references/running-code.md](references/running-code.md)
|
|
42439
|
+
* **Browser session management** [references/session-management.md](references/session-management.md)
|
|
42440
|
+
* **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
|
|
42441
|
+
* **Test generation** [references/test-generation.md](references/test-generation.md)
|
|
42442
|
+
* **Tracing** [references/tracing.md](references/tracing.md)
|
|
42443
|
+
* **Video recording** [references/video-recording.md](references/video-recording.md)`,
|
|
42444
|
+
allowedTools: ["Bash(playwright-cli:*)"]
|
|
42445
|
+
};
|
|
42049
42446
|
// src/features/builtin-skills/skills/frontend-ui-ux.ts
|
|
42050
42447
|
var frontendUiUxSkill = {
|
|
42051
42448
|
name: "frontend-ui-ux",
|
|
@@ -43455,7 +43852,14 @@ EOF
|
|
|
43455
43852
|
// src/features/builtin-skills/skills.ts
|
|
43456
43853
|
function createBuiltinSkills(options = {}) {
|
|
43457
43854
|
const { browserProvider = "playwright", disabledSkills } = options;
|
|
43458
|
-
|
|
43855
|
+
let browserSkill;
|
|
43856
|
+
if (browserProvider === "agent-browser") {
|
|
43857
|
+
browserSkill = agentBrowserSkill;
|
|
43858
|
+
} else if (browserProvider === "playwright-cli") {
|
|
43859
|
+
browserSkill = playwrightCliSkill;
|
|
43860
|
+
} else {
|
|
43861
|
+
browserSkill = playwrightSkill;
|
|
43862
|
+
}
|
|
43459
43863
|
const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill];
|
|
43460
43864
|
if (!disabledSkills) {
|
|
43461
43865
|
return skills;
|
|
@@ -45835,9 +46239,14 @@ function createUnstableAgentBabysitterHook(ctx, options) {
|
|
|
45835
46239
|
// src/hooks/preemptive-compaction.ts
|
|
45836
46240
|
init_logger();
|
|
45837
46241
|
var DEFAULT_ACTUAL_LIMIT = 200000;
|
|
45838
|
-
|
|
46242
|
+
function getAnthropicActualLimit3(modelCacheState) {
|
|
46243
|
+
return (modelCacheState?.anthropicContext1MEnabled ?? false) || process.env.ANTHROPIC_1M_CONTEXT === "true" || process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true" ? 1e6 : DEFAULT_ACTUAL_LIMIT;
|
|
46244
|
+
}
|
|
45839
46245
|
var PREEMPTIVE_COMPACTION_THRESHOLD = 0.78;
|
|
45840
|
-
function
|
|
46246
|
+
function isAnthropicProvider2(providerID) {
|
|
46247
|
+
return providerID === "anthropic" || providerID === "google-vertex-anthropic";
|
|
46248
|
+
}
|
|
46249
|
+
function createPreemptiveCompactionHook(ctx, modelCacheState) {
|
|
45841
46250
|
const compactionInProgress = new Set;
|
|
45842
46251
|
const compactedSessions = new Set;
|
|
45843
46252
|
const tokenCache = new Map;
|
|
@@ -45848,7 +46257,7 @@ function createPreemptiveCompactionHook(ctx) {
|
|
|
45848
46257
|
const cached2 = tokenCache.get(sessionID);
|
|
45849
46258
|
if (!cached2)
|
|
45850
46259
|
return;
|
|
45851
|
-
const actualLimit = cached2.providerID
|
|
46260
|
+
const actualLimit = isAnthropicProvider2(cached2.providerID) ? getAnthropicActualLimit3(modelCacheState) : DEFAULT_ACTUAL_LIMIT;
|
|
45852
46261
|
const lastTokens = cached2.tokens;
|
|
45853
46262
|
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
45854
46263
|
const usageRatio = totalInputTokens / actualLimit;
|
|
@@ -45982,13 +46391,332 @@ function createWriteExistingFileGuardHook(ctx) {
|
|
|
45982
46391
|
}
|
|
45983
46392
|
};
|
|
45984
46393
|
}
|
|
46394
|
+
// src/tools/hashline-edit/constants.ts
|
|
46395
|
+
var HASH_DICT = [
|
|
46396
|
+
"00",
|
|
46397
|
+
"01",
|
|
46398
|
+
"02",
|
|
46399
|
+
"03",
|
|
46400
|
+
"04",
|
|
46401
|
+
"05",
|
|
46402
|
+
"06",
|
|
46403
|
+
"07",
|
|
46404
|
+
"08",
|
|
46405
|
+
"09",
|
|
46406
|
+
"0a",
|
|
46407
|
+
"0b",
|
|
46408
|
+
"0c",
|
|
46409
|
+
"0d",
|
|
46410
|
+
"0e",
|
|
46411
|
+
"0f",
|
|
46412
|
+
"10",
|
|
46413
|
+
"11",
|
|
46414
|
+
"12",
|
|
46415
|
+
"13",
|
|
46416
|
+
"14",
|
|
46417
|
+
"15",
|
|
46418
|
+
"16",
|
|
46419
|
+
"17",
|
|
46420
|
+
"18",
|
|
46421
|
+
"19",
|
|
46422
|
+
"1a",
|
|
46423
|
+
"1b",
|
|
46424
|
+
"1c",
|
|
46425
|
+
"1d",
|
|
46426
|
+
"1e",
|
|
46427
|
+
"1f",
|
|
46428
|
+
"20",
|
|
46429
|
+
"21",
|
|
46430
|
+
"22",
|
|
46431
|
+
"23",
|
|
46432
|
+
"24",
|
|
46433
|
+
"25",
|
|
46434
|
+
"26",
|
|
46435
|
+
"27",
|
|
46436
|
+
"28",
|
|
46437
|
+
"29",
|
|
46438
|
+
"2a",
|
|
46439
|
+
"2b",
|
|
46440
|
+
"2c",
|
|
46441
|
+
"2d",
|
|
46442
|
+
"2e",
|
|
46443
|
+
"2f",
|
|
46444
|
+
"30",
|
|
46445
|
+
"31",
|
|
46446
|
+
"32",
|
|
46447
|
+
"33",
|
|
46448
|
+
"34",
|
|
46449
|
+
"35",
|
|
46450
|
+
"36",
|
|
46451
|
+
"37",
|
|
46452
|
+
"38",
|
|
46453
|
+
"39",
|
|
46454
|
+
"3a",
|
|
46455
|
+
"3b",
|
|
46456
|
+
"3c",
|
|
46457
|
+
"3d",
|
|
46458
|
+
"3e",
|
|
46459
|
+
"3f",
|
|
46460
|
+
"40",
|
|
46461
|
+
"41",
|
|
46462
|
+
"42",
|
|
46463
|
+
"43",
|
|
46464
|
+
"44",
|
|
46465
|
+
"45",
|
|
46466
|
+
"46",
|
|
46467
|
+
"47",
|
|
46468
|
+
"48",
|
|
46469
|
+
"49",
|
|
46470
|
+
"4a",
|
|
46471
|
+
"4b",
|
|
46472
|
+
"4c",
|
|
46473
|
+
"4d",
|
|
46474
|
+
"4e",
|
|
46475
|
+
"4f",
|
|
46476
|
+
"50",
|
|
46477
|
+
"51",
|
|
46478
|
+
"52",
|
|
46479
|
+
"53",
|
|
46480
|
+
"54",
|
|
46481
|
+
"55",
|
|
46482
|
+
"56",
|
|
46483
|
+
"57",
|
|
46484
|
+
"58",
|
|
46485
|
+
"59",
|
|
46486
|
+
"5a",
|
|
46487
|
+
"5b",
|
|
46488
|
+
"5c",
|
|
46489
|
+
"5d",
|
|
46490
|
+
"5e",
|
|
46491
|
+
"5f",
|
|
46492
|
+
"60",
|
|
46493
|
+
"61",
|
|
46494
|
+
"62",
|
|
46495
|
+
"63",
|
|
46496
|
+
"64",
|
|
46497
|
+
"65",
|
|
46498
|
+
"66",
|
|
46499
|
+
"67",
|
|
46500
|
+
"68",
|
|
46501
|
+
"69",
|
|
46502
|
+
"6a",
|
|
46503
|
+
"6b",
|
|
46504
|
+
"6c",
|
|
46505
|
+
"6d",
|
|
46506
|
+
"6e",
|
|
46507
|
+
"6f",
|
|
46508
|
+
"70",
|
|
46509
|
+
"71",
|
|
46510
|
+
"72",
|
|
46511
|
+
"73",
|
|
46512
|
+
"74",
|
|
46513
|
+
"75",
|
|
46514
|
+
"76",
|
|
46515
|
+
"77",
|
|
46516
|
+
"78",
|
|
46517
|
+
"79",
|
|
46518
|
+
"7a",
|
|
46519
|
+
"7b",
|
|
46520
|
+
"7c",
|
|
46521
|
+
"7d",
|
|
46522
|
+
"7e",
|
|
46523
|
+
"7f",
|
|
46524
|
+
"80",
|
|
46525
|
+
"81",
|
|
46526
|
+
"82",
|
|
46527
|
+
"83",
|
|
46528
|
+
"84",
|
|
46529
|
+
"85",
|
|
46530
|
+
"86",
|
|
46531
|
+
"87",
|
|
46532
|
+
"88",
|
|
46533
|
+
"89",
|
|
46534
|
+
"8a",
|
|
46535
|
+
"8b",
|
|
46536
|
+
"8c",
|
|
46537
|
+
"8d",
|
|
46538
|
+
"8e",
|
|
46539
|
+
"8f",
|
|
46540
|
+
"90",
|
|
46541
|
+
"91",
|
|
46542
|
+
"92",
|
|
46543
|
+
"93",
|
|
46544
|
+
"94",
|
|
46545
|
+
"95",
|
|
46546
|
+
"96",
|
|
46547
|
+
"97",
|
|
46548
|
+
"98",
|
|
46549
|
+
"99",
|
|
46550
|
+
"9a",
|
|
46551
|
+
"9b",
|
|
46552
|
+
"9c",
|
|
46553
|
+
"9d",
|
|
46554
|
+
"9e",
|
|
46555
|
+
"9f",
|
|
46556
|
+
"a0",
|
|
46557
|
+
"a1",
|
|
46558
|
+
"a2",
|
|
46559
|
+
"a3",
|
|
46560
|
+
"a4",
|
|
46561
|
+
"a5",
|
|
46562
|
+
"a6",
|
|
46563
|
+
"a7",
|
|
46564
|
+
"a8",
|
|
46565
|
+
"a9",
|
|
46566
|
+
"aa",
|
|
46567
|
+
"ab",
|
|
46568
|
+
"ac",
|
|
46569
|
+
"ad",
|
|
46570
|
+
"ae",
|
|
46571
|
+
"af",
|
|
46572
|
+
"b0",
|
|
46573
|
+
"b1",
|
|
46574
|
+
"b2",
|
|
46575
|
+
"b3",
|
|
46576
|
+
"b4",
|
|
46577
|
+
"b5",
|
|
46578
|
+
"b6",
|
|
46579
|
+
"b7",
|
|
46580
|
+
"b8",
|
|
46581
|
+
"b9",
|
|
46582
|
+
"ba",
|
|
46583
|
+
"bb",
|
|
46584
|
+
"bc",
|
|
46585
|
+
"bd",
|
|
46586
|
+
"be",
|
|
46587
|
+
"bf",
|
|
46588
|
+
"c0",
|
|
46589
|
+
"c1",
|
|
46590
|
+
"c2",
|
|
46591
|
+
"c3",
|
|
46592
|
+
"c4",
|
|
46593
|
+
"c5",
|
|
46594
|
+
"c6",
|
|
46595
|
+
"c7",
|
|
46596
|
+
"c8",
|
|
46597
|
+
"c9",
|
|
46598
|
+
"ca",
|
|
46599
|
+
"cb",
|
|
46600
|
+
"cc",
|
|
46601
|
+
"cd",
|
|
46602
|
+
"ce",
|
|
46603
|
+
"cf",
|
|
46604
|
+
"d0",
|
|
46605
|
+
"d1",
|
|
46606
|
+
"d2",
|
|
46607
|
+
"d3",
|
|
46608
|
+
"d4",
|
|
46609
|
+
"d5",
|
|
46610
|
+
"d6",
|
|
46611
|
+
"d7",
|
|
46612
|
+
"d8",
|
|
46613
|
+
"d9",
|
|
46614
|
+
"da",
|
|
46615
|
+
"db",
|
|
46616
|
+
"dc",
|
|
46617
|
+
"dd",
|
|
46618
|
+
"de",
|
|
46619
|
+
"df",
|
|
46620
|
+
"e0",
|
|
46621
|
+
"e1",
|
|
46622
|
+
"e2",
|
|
46623
|
+
"e3",
|
|
46624
|
+
"e4",
|
|
46625
|
+
"e5",
|
|
46626
|
+
"e6",
|
|
46627
|
+
"e7",
|
|
46628
|
+
"e8",
|
|
46629
|
+
"e9",
|
|
46630
|
+
"ea",
|
|
46631
|
+
"eb",
|
|
46632
|
+
"ec",
|
|
46633
|
+
"ed",
|
|
46634
|
+
"ee",
|
|
46635
|
+
"ef",
|
|
46636
|
+
"f0",
|
|
46637
|
+
"f1",
|
|
46638
|
+
"f2",
|
|
46639
|
+
"f3",
|
|
46640
|
+
"f4",
|
|
46641
|
+
"f5",
|
|
46642
|
+
"f6",
|
|
46643
|
+
"f7",
|
|
46644
|
+
"f8",
|
|
46645
|
+
"f9",
|
|
46646
|
+
"fa",
|
|
46647
|
+
"fb",
|
|
46648
|
+
"fc",
|
|
46649
|
+
"fd",
|
|
46650
|
+
"fe",
|
|
46651
|
+
"ff"
|
|
46652
|
+
];
|
|
46653
|
+
|
|
46654
|
+
// src/tools/hashline-edit/hash-computation.ts
|
|
46655
|
+
function computeLineHash(_lineNumber, content) {
|
|
46656
|
+
const stripped = content.replace(/\s+/g, "");
|
|
46657
|
+
const hash2 = Bun.hash.xxHash32(stripped);
|
|
46658
|
+
const index = hash2 % 256;
|
|
46659
|
+
return HASH_DICT[index];
|
|
46660
|
+
}
|
|
46661
|
+
|
|
46662
|
+
// src/hooks/hashline-read-enhancer/hook.ts
|
|
46663
|
+
var READ_LINE_PATTERN = /^(\d+): (.*)$/;
|
|
46664
|
+
function isReadTool(toolName) {
|
|
46665
|
+
return toolName.toLowerCase() === "read";
|
|
46666
|
+
}
|
|
46667
|
+
function shouldProcess(config2) {
|
|
46668
|
+
return config2.hashline_edit?.enabled ?? false;
|
|
46669
|
+
}
|
|
46670
|
+
function isTextFile(output) {
|
|
46671
|
+
const firstLine = output.split(`
|
|
46672
|
+
`)[0] ?? "";
|
|
46673
|
+
return READ_LINE_PATTERN.test(firstLine);
|
|
46674
|
+
}
|
|
46675
|
+
function transformLine(line) {
|
|
46676
|
+
const match = READ_LINE_PATTERN.exec(line);
|
|
46677
|
+
if (!match) {
|
|
46678
|
+
return line;
|
|
46679
|
+
}
|
|
46680
|
+
const lineNumber = parseInt(match[1], 10);
|
|
46681
|
+
const content = match[2];
|
|
46682
|
+
const hash2 = computeLineHash(lineNumber, content);
|
|
46683
|
+
return `${lineNumber}:${hash2}|${content}`;
|
|
46684
|
+
}
|
|
46685
|
+
function transformOutput(output) {
|
|
46686
|
+
if (!output) {
|
|
46687
|
+
return output;
|
|
46688
|
+
}
|
|
46689
|
+
if (!isTextFile(output)) {
|
|
46690
|
+
return output;
|
|
46691
|
+
}
|
|
46692
|
+
const lines = output.split(`
|
|
46693
|
+
`);
|
|
46694
|
+
return lines.map(transformLine).join(`
|
|
46695
|
+
`);
|
|
46696
|
+
}
|
|
46697
|
+
function createHashlineReadEnhancerHook(_ctx, config2) {
|
|
46698
|
+
return {
|
|
46699
|
+
"tool.execute.after": async (input, output) => {
|
|
46700
|
+
if (!isReadTool(input.tool)) {
|
|
46701
|
+
return;
|
|
46702
|
+
}
|
|
46703
|
+
if (typeof output.output !== "string") {
|
|
46704
|
+
return;
|
|
46705
|
+
}
|
|
46706
|
+
if (!shouldProcess(config2)) {
|
|
46707
|
+
return;
|
|
46708
|
+
}
|
|
46709
|
+
output.output = transformOutput(output.output);
|
|
46710
|
+
}
|
|
46711
|
+
};
|
|
46712
|
+
}
|
|
45985
46713
|
// src/hooks/anthropic-effort/hook.ts
|
|
45986
46714
|
var OPUS_4_6_PATTERN = /claude-opus-4[-.]6/i;
|
|
45987
46715
|
function normalizeModelID2(modelID) {
|
|
45988
46716
|
return modelID.replace(/\.(\d+)/g, "-$1");
|
|
45989
46717
|
}
|
|
45990
46718
|
function isClaudeProvider(providerID, modelID) {
|
|
45991
|
-
if (["anthropic", "opencode"].includes(providerID))
|
|
46719
|
+
if (["anthropic", "google-vertex-anthropic", "opencode"].includes(providerID))
|
|
45992
46720
|
return true;
|
|
45993
46721
|
if (providerID === "github-copilot" && modelID.toLowerCase().includes("claude"))
|
|
45994
46722
|
return true;
|
|
@@ -47987,10 +48715,11 @@ function createSgResultFromStdout(stdout) {
|
|
|
47987
48715
|
|
|
47988
48716
|
// src/tools/ast-grep/cli.ts
|
|
47989
48717
|
async function runSg(options) {
|
|
48718
|
+
const shouldSeparateWritePass = !!(options.rewrite && options.updateAll);
|
|
47990
48719
|
const args = ["run", "-p", options.pattern, "--lang", options.lang, "--json=compact"];
|
|
47991
48720
|
if (options.rewrite) {
|
|
47992
48721
|
args.push("-r", options.rewrite);
|
|
47993
|
-
if (options.updateAll) {
|
|
48722
|
+
if (options.updateAll && !shouldSeparateWritePass) {
|
|
47994
48723
|
args.push("--update-all");
|
|
47995
48724
|
}
|
|
47996
48725
|
}
|
|
@@ -48083,7 +48812,26 @@ async function runSg(options) {
|
|
|
48083
48812
|
}
|
|
48084
48813
|
return { matches: [], totalMatches: 0, truncated: false };
|
|
48085
48814
|
}
|
|
48086
|
-
|
|
48815
|
+
const jsonResult = createSgResultFromStdout(stdout);
|
|
48816
|
+
if (shouldSeparateWritePass && jsonResult.matches.length > 0) {
|
|
48817
|
+
const writeArgs = args.filter((a) => a !== "--json=compact");
|
|
48818
|
+
writeArgs.push("--update-all");
|
|
48819
|
+
const writeProc = spawn10([cliPath, ...writeArgs], {
|
|
48820
|
+
stdout: "pipe",
|
|
48821
|
+
stderr: "pipe"
|
|
48822
|
+
});
|
|
48823
|
+
try {
|
|
48824
|
+
const writeOutput = await collectProcessOutputWithTimeout(writeProc, timeout);
|
|
48825
|
+
if (writeOutput.exitCode !== 0) {
|
|
48826
|
+
const errorDetail = writeOutput.stderr.trim() || `ast-grep exited with code ${writeOutput.exitCode}`;
|
|
48827
|
+
return { ...jsonResult, error: `Replace failed: ${errorDetail}` };
|
|
48828
|
+
}
|
|
48829
|
+
} catch (error45) {
|
|
48830
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
48831
|
+
return { ...jsonResult, error: `Replace failed: ${errorMessage}` };
|
|
48832
|
+
}
|
|
48833
|
+
}
|
|
48834
|
+
return jsonResult;
|
|
48087
48835
|
}
|
|
48088
48836
|
|
|
48089
48837
|
// src/tools/ast-grep/result-formatter.ts
|
|
@@ -51027,7 +51775,7 @@ session_id: ${sessionID}
|
|
|
51027
51775
|
}
|
|
51028
51776
|
|
|
51029
51777
|
// src/tools/call-omo-agent/tools.ts
|
|
51030
|
-
function createCallOmoAgent(ctx, backgroundManager) {
|
|
51778
|
+
function createCallOmoAgent(ctx, backgroundManager, disabledAgents = []) {
|
|
51031
51779
|
const agentDescriptions = ALLOWED_AGENTS.map((name) => `- ${name}: Specialized agent for ${name} tasks`).join(`
|
|
51032
51780
|
`);
|
|
51033
51781
|
const description = CALL_OMO_AGENT_DESCRIPTION.replace("{agents}", agentDescriptions);
|
|
@@ -51048,6 +51796,9 @@ function createCallOmoAgent(ctx, backgroundManager) {
|
|
|
51048
51796
|
}
|
|
51049
51797
|
const normalizedAgent = args.subagent_type.toLowerCase();
|
|
51050
51798
|
args = { ...args, subagent_type: normalizedAgent };
|
|
51799
|
+
if (disabledAgents.some((disabled) => disabled.toLowerCase() === normalizedAgent)) {
|
|
51800
|
+
return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your oh-my-opencode.json to use it.`;
|
|
51801
|
+
}
|
|
51051
51802
|
if (args.run_in_background) {
|
|
51052
51803
|
if (args.session_id) {
|
|
51053
51804
|
return `Error: session_id is not supported in background mode. Use run_in_background=false to continue an existing session.`;
|
|
@@ -52240,28 +52991,49 @@ async function createSyncSession(client2, input) {
|
|
|
52240
52991
|
|
|
52241
52992
|
// src/tools/delegate-task/sync-prompt-sender.ts
|
|
52242
52993
|
init_constants();
|
|
52243
|
-
|
|
52994
|
+
var sendSyncPromptDeps = {
|
|
52995
|
+
promptWithModelSuggestionRetry,
|
|
52996
|
+
promptSyncWithModelSuggestionRetry
|
|
52997
|
+
};
|
|
52998
|
+
function isOracleAgent(agentToUse) {
|
|
52999
|
+
return agentToUse.toLowerCase() === "oracle";
|
|
53000
|
+
}
|
|
53001
|
+
function isUnexpectedEofError(error45) {
|
|
53002
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
53003
|
+
const lowered = message.toLowerCase();
|
|
53004
|
+
return lowered.includes("unexpected eof") || lowered.includes("json parse error");
|
|
53005
|
+
}
|
|
53006
|
+
async function sendSyncPrompt(client2, input, deps = sendSyncPromptDeps) {
|
|
53007
|
+
const allowTask = isPlanFamily(input.agentToUse);
|
|
53008
|
+
const tools = {
|
|
53009
|
+
task: allowTask,
|
|
53010
|
+
call_omo_agent: true,
|
|
53011
|
+
question: false,
|
|
53012
|
+
...getAgentToolRestrictions(input.agentToUse)
|
|
53013
|
+
};
|
|
53014
|
+
setSessionTools(input.sessionID, tools);
|
|
53015
|
+
const promptArgs = {
|
|
53016
|
+
path: { id: input.sessionID },
|
|
53017
|
+
body: {
|
|
53018
|
+
agent: input.agentToUse,
|
|
53019
|
+
system: input.systemContent,
|
|
53020
|
+
tools,
|
|
53021
|
+
parts: [{ type: "text", text: input.args.prompt }],
|
|
53022
|
+
...input.categoryModel ? { model: { providerID: input.categoryModel.providerID, modelID: input.categoryModel.modelID } } : {},
|
|
53023
|
+
...input.categoryModel?.variant ? { variant: input.categoryModel.variant } : {}
|
|
53024
|
+
}
|
|
53025
|
+
};
|
|
52244
53026
|
try {
|
|
52245
|
-
|
|
52246
|
-
const tools = {
|
|
52247
|
-
task: allowTask,
|
|
52248
|
-
call_omo_agent: true,
|
|
52249
|
-
question: false,
|
|
52250
|
-
...getAgentToolRestrictions(input.agentToUse)
|
|
52251
|
-
};
|
|
52252
|
-
setSessionTools(input.sessionID, tools);
|
|
52253
|
-
await promptWithModelSuggestionRetry(client2, {
|
|
52254
|
-
path: { id: input.sessionID },
|
|
52255
|
-
body: {
|
|
52256
|
-
agent: input.agentToUse,
|
|
52257
|
-
system: input.systemContent,
|
|
52258
|
-
tools,
|
|
52259
|
-
parts: [{ type: "text", text: input.args.prompt }],
|
|
52260
|
-
...input.categoryModel ? { model: { providerID: input.categoryModel.providerID, modelID: input.categoryModel.modelID } } : {},
|
|
52261
|
-
...input.categoryModel?.variant ? { variant: input.categoryModel.variant } : {}
|
|
52262
|
-
}
|
|
52263
|
-
});
|
|
53027
|
+
await deps.promptWithModelSuggestionRetry(client2, promptArgs);
|
|
52264
53028
|
} catch (promptError) {
|
|
53029
|
+
if (isOracleAgent(input.agentToUse) && isUnexpectedEofError(promptError)) {
|
|
53030
|
+
try {
|
|
53031
|
+
await deps.promptSyncWithModelSuggestionRetry(client2, promptArgs);
|
|
53032
|
+
return null;
|
|
53033
|
+
} catch (oracleRetryError) {
|
|
53034
|
+
promptError = oracleRetryError;
|
|
53035
|
+
}
|
|
53036
|
+
}
|
|
52265
53037
|
if (input.toastManager && input.taskId !== undefined) {
|
|
52266
53038
|
input.toastManager.removeTask(input.taskId);
|
|
52267
53039
|
}
|
|
@@ -52689,6 +53461,7 @@ Available categories: ${categoryNames.join(", ")}`
|
|
|
52689
53461
|
}
|
|
52690
53462
|
// src/tools/delegate-task/subagent-resolver.ts
|
|
52691
53463
|
init_constants();
|
|
53464
|
+
init_logger();
|
|
52692
53465
|
async function resolveSubagentExecution(args, executorCtx, parentAgent, categoryExamples) {
|
|
52693
53466
|
const { client: client2, agentOverrides } = executorCtx;
|
|
52694
53467
|
if (!args.subagent_type?.trim()) {
|
|
@@ -52764,7 +53537,19 @@ Create the work plan directly - that's your job as the planning agent.`
|
|
|
52764
53537
|
if (!categoryModel && matchedAgent.model) {
|
|
52765
53538
|
categoryModel = matchedAgent.model;
|
|
52766
53539
|
}
|
|
52767
|
-
} catch {
|
|
53540
|
+
} catch (error45) {
|
|
53541
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
53542
|
+
log("[delegate-task] Failed to resolve subagent execution", {
|
|
53543
|
+
requestedAgent: agentToUse,
|
|
53544
|
+
parentAgent,
|
|
53545
|
+
error: errorMessage
|
|
53546
|
+
});
|
|
53547
|
+
return {
|
|
53548
|
+
agentToUse: "",
|
|
53549
|
+
categoryModel: undefined,
|
|
53550
|
+
error: `Failed to delegate to agent "${agentToUse}": ${errorMessage}`
|
|
53551
|
+
};
|
|
53552
|
+
}
|
|
52768
53553
|
return { agentToUse, categoryModel };
|
|
52769
53554
|
}
|
|
52770
53555
|
// src/tools/delegate-task/tools.ts
|
|
@@ -53492,6 +54277,223 @@ async function handleUpdate(args, config3, ctx, context) {
|
|
|
53492
54277
|
return JSON.stringify({ error: "internal_error" });
|
|
53493
54278
|
}
|
|
53494
54279
|
}
|
|
54280
|
+
// src/tools/hashline-edit/validation.ts
|
|
54281
|
+
function parseLineRef(ref) {
|
|
54282
|
+
const match = ref.match(/^(\d+):([0-9a-f]{2})$/);
|
|
54283
|
+
if (!match) {
|
|
54284
|
+
throw new Error(`Invalid line reference format: "${ref}". Expected format: "LINE:HASH" (e.g., "42:a3")`);
|
|
54285
|
+
}
|
|
54286
|
+
return {
|
|
54287
|
+
line: Number.parseInt(match[1], 10),
|
|
54288
|
+
hash: match[2]
|
|
54289
|
+
};
|
|
54290
|
+
}
|
|
54291
|
+
function validateLineRef(lines, ref) {
|
|
54292
|
+
const { line, hash: hash2 } = parseLineRef(ref);
|
|
54293
|
+
if (line < 1 || line > lines.length) {
|
|
54294
|
+
throw new Error(`Line number ${line} out of bounds. File has ${lines.length} lines.`);
|
|
54295
|
+
}
|
|
54296
|
+
const content = lines[line - 1];
|
|
54297
|
+
const currentHash = computeLineHash(line, content);
|
|
54298
|
+
if (currentHash !== hash2) {
|
|
54299
|
+
throw new Error(`Hash mismatch at line ${line}. Expected hash: ${hash2}, current hash: ${currentHash}. ` + `Line content may have changed. Current content: "${content}"`);
|
|
54300
|
+
}
|
|
54301
|
+
}
|
|
54302
|
+
// src/tools/hashline-edit/edit-operations.ts
|
|
54303
|
+
function unescapeNewlines(text) {
|
|
54304
|
+
return text.replace(/\\n/g, `
|
|
54305
|
+
`);
|
|
54306
|
+
}
|
|
54307
|
+
function getEditLineNumber(edit) {
|
|
54308
|
+
switch (edit.type) {
|
|
54309
|
+
case "set_line":
|
|
54310
|
+
return parseLineRef(edit.line).line;
|
|
54311
|
+
case "replace_lines":
|
|
54312
|
+
return parseLineRef(edit.end_line).line;
|
|
54313
|
+
case "insert_after":
|
|
54314
|
+
return parseLineRef(edit.line).line;
|
|
54315
|
+
case "replace":
|
|
54316
|
+
return Number.NEGATIVE_INFINITY;
|
|
54317
|
+
default:
|
|
54318
|
+
return Number.POSITIVE_INFINITY;
|
|
54319
|
+
}
|
|
54320
|
+
}
|
|
54321
|
+
function applyHashlineEdits(content, edits) {
|
|
54322
|
+
if (edits.length === 0) {
|
|
54323
|
+
return content;
|
|
54324
|
+
}
|
|
54325
|
+
const sortedEdits = [...edits].sort((a, b) => getEditLineNumber(b) - getEditLineNumber(a));
|
|
54326
|
+
let result = content;
|
|
54327
|
+
let lines = result.split(`
|
|
54328
|
+
`);
|
|
54329
|
+
for (const edit of sortedEdits) {
|
|
54330
|
+
switch (edit.type) {
|
|
54331
|
+
case "set_line": {
|
|
54332
|
+
validateLineRef(lines, edit.line);
|
|
54333
|
+
const { line } = parseLineRef(edit.line);
|
|
54334
|
+
lines[line - 1] = unescapeNewlines(edit.text);
|
|
54335
|
+
break;
|
|
54336
|
+
}
|
|
54337
|
+
case "replace_lines": {
|
|
54338
|
+
validateLineRef(lines, edit.start_line);
|
|
54339
|
+
validateLineRef(lines, edit.end_line);
|
|
54340
|
+
const { line: startLine } = parseLineRef(edit.start_line);
|
|
54341
|
+
const { line: endLine } = parseLineRef(edit.end_line);
|
|
54342
|
+
if (startLine > endLine) {
|
|
54343
|
+
throw new Error(`Invalid range: start line ${startLine} cannot be greater than end line ${endLine}`);
|
|
54344
|
+
}
|
|
54345
|
+
const newLines = unescapeNewlines(edit.text).split(`
|
|
54346
|
+
`);
|
|
54347
|
+
lines.splice(startLine - 1, endLine - startLine + 1, ...newLines);
|
|
54348
|
+
break;
|
|
54349
|
+
}
|
|
54350
|
+
case "insert_after": {
|
|
54351
|
+
validateLineRef(lines, edit.line);
|
|
54352
|
+
const { line } = parseLineRef(edit.line);
|
|
54353
|
+
const newLines = unescapeNewlines(edit.text).split(`
|
|
54354
|
+
`);
|
|
54355
|
+
lines.splice(line, 0, ...newLines);
|
|
54356
|
+
break;
|
|
54357
|
+
}
|
|
54358
|
+
case "replace": {
|
|
54359
|
+
result = lines.join(`
|
|
54360
|
+
`);
|
|
54361
|
+
if (!result.includes(edit.old_text)) {
|
|
54362
|
+
throw new Error(`Text not found: "${edit.old_text}"`);
|
|
54363
|
+
}
|
|
54364
|
+
result = result.replaceAll(edit.old_text, unescapeNewlines(edit.new_text));
|
|
54365
|
+
lines = result.split(`
|
|
54366
|
+
`);
|
|
54367
|
+
break;
|
|
54368
|
+
}
|
|
54369
|
+
}
|
|
54370
|
+
}
|
|
54371
|
+
return lines.join(`
|
|
54372
|
+
`);
|
|
54373
|
+
}
|
|
54374
|
+
// src/tools/hashline-edit/tools.ts
|
|
54375
|
+
function generateDiff(oldContent, newContent, filePath) {
|
|
54376
|
+
const oldLines = oldContent.split(`
|
|
54377
|
+
`);
|
|
54378
|
+
const newLines = newContent.split(`
|
|
54379
|
+
`);
|
|
54380
|
+
let diff = `--- ${filePath}
|
|
54381
|
+
+++ ${filePath}
|
|
54382
|
+
`;
|
|
54383
|
+
const maxLines = Math.max(oldLines.length, newLines.length);
|
|
54384
|
+
for (let i2 = 0;i2 < maxLines; i2++) {
|
|
54385
|
+
const oldLine = oldLines[i2] ?? "";
|
|
54386
|
+
const newLine = newLines[i2] ?? "";
|
|
54387
|
+
const lineNum = i2 + 1;
|
|
54388
|
+
const hash2 = computeLineHash(lineNum, newLine);
|
|
54389
|
+
if (i2 >= oldLines.length) {
|
|
54390
|
+
diff += `+ ${lineNum}:${hash2}|${newLine}
|
|
54391
|
+
`;
|
|
54392
|
+
} else if (i2 >= newLines.length) {
|
|
54393
|
+
diff += `- ${lineNum}: |${oldLine}
|
|
54394
|
+
`;
|
|
54395
|
+
} else if (oldLine !== newLine) {
|
|
54396
|
+
diff += `- ${lineNum}: |${oldLine}
|
|
54397
|
+
`;
|
|
54398
|
+
diff += `+ ${lineNum}:${hash2}|${newLine}
|
|
54399
|
+
`;
|
|
54400
|
+
}
|
|
54401
|
+
}
|
|
54402
|
+
return diff;
|
|
54403
|
+
}
|
|
54404
|
+
function createHashlineEditTool() {
|
|
54405
|
+
return tool({
|
|
54406
|
+
description: `Edit files using LINE:HASH format for precise, safe modifications.
|
|
54407
|
+
|
|
54408
|
+
LINE:HASH FORMAT:
|
|
54409
|
+
Each line reference must be in "LINE:HASH" format where:
|
|
54410
|
+
- LINE: 1-based line number
|
|
54411
|
+
- HASH: First 2 characters of xxHash32 hash of line content (computed with computeLineHash)
|
|
54412
|
+
- Example: "5:a3|const x = 1" means line 5 with hash "a3"
|
|
54413
|
+
|
|
54414
|
+
GETTING HASHES:
|
|
54415
|
+
Use the read tool - it returns lines in "LINE:HASH|content" format.
|
|
54416
|
+
|
|
54417
|
+
FOUR OPERATION TYPES:
|
|
54418
|
+
|
|
54419
|
+
1. set_line: Replace a single line
|
|
54420
|
+
{ "type": "set_line", "line": "5:a3", "text": "const y = 2" }
|
|
54421
|
+
|
|
54422
|
+
2. replace_lines: Replace a range of lines
|
|
54423
|
+
{ "type": "replace_lines", "start_line": "5:a3", "end_line": "7:b2", "text": "new
|
|
54424
|
+
content" }
|
|
54425
|
+
|
|
54426
|
+
3. insert_after: Insert lines after a specific line
|
|
54427
|
+
{ "type": "insert_after", "line": "5:a3", "text": "console.log('hi')" }
|
|
54428
|
+
|
|
54429
|
+
4. replace: Simple text replacement (no hash validation)
|
|
54430
|
+
{ "type": "replace", "old_text": "foo", "new_text": "bar" }
|
|
54431
|
+
|
|
54432
|
+
HASH MISMATCH HANDLING:
|
|
54433
|
+
If the hash doesn't match the current content, the edit fails with a hash mismatch error. This prevents editing stale content.
|
|
54434
|
+
|
|
54435
|
+
BOTTOM-UP APPLICATION:
|
|
54436
|
+
Edits are applied from bottom to top (highest line numbers first) to preserve line number references.
|
|
54437
|
+
|
|
54438
|
+
ESCAPING:
|
|
54439
|
+
Use \\n in text to represent literal newlines.`,
|
|
54440
|
+
args: {
|
|
54441
|
+
path: tool.schema.string().describe("Absolute path to the file to edit"),
|
|
54442
|
+
edits: tool.schema.array(tool.schema.union([
|
|
54443
|
+
tool.schema.object({
|
|
54444
|
+
type: tool.schema.literal("set_line"),
|
|
54445
|
+
line: tool.schema.string().describe("Line reference in LINE:HASH format"),
|
|
54446
|
+
text: tool.schema.string().describe("New content for the line")
|
|
54447
|
+
}),
|
|
54448
|
+
tool.schema.object({
|
|
54449
|
+
type: tool.schema.literal("replace_lines"),
|
|
54450
|
+
start_line: tool.schema.string().describe("Start line in LINE:HASH format"),
|
|
54451
|
+
end_line: tool.schema.string().describe("End line in LINE:HASH format"),
|
|
54452
|
+
text: tool.schema.string().describe("New content to replace the range")
|
|
54453
|
+
}),
|
|
54454
|
+
tool.schema.object({
|
|
54455
|
+
type: tool.schema.literal("insert_after"),
|
|
54456
|
+
line: tool.schema.string().describe("Line reference in LINE:HASH format"),
|
|
54457
|
+
text: tool.schema.string().describe("Content to insert after the line")
|
|
54458
|
+
}),
|
|
54459
|
+
tool.schema.object({
|
|
54460
|
+
type: tool.schema.literal("replace"),
|
|
54461
|
+
old_text: tool.schema.string().describe("Text to find"),
|
|
54462
|
+
new_text: tool.schema.string().describe("Replacement text")
|
|
54463
|
+
})
|
|
54464
|
+
])).describe("Array of edit operations to apply")
|
|
54465
|
+
},
|
|
54466
|
+
execute: async (args) => {
|
|
54467
|
+
try {
|
|
54468
|
+
const { path: filePath, edits } = args;
|
|
54469
|
+
if (!filePath) {
|
|
54470
|
+
return "Error: path parameter is required";
|
|
54471
|
+
}
|
|
54472
|
+
if (!edits || !Array.isArray(edits) || edits.length === 0) {
|
|
54473
|
+
return "Error: edits parameter must be a non-empty array";
|
|
54474
|
+
}
|
|
54475
|
+
const file2 = Bun.file(filePath);
|
|
54476
|
+
const exists = await file2.exists();
|
|
54477
|
+
if (!exists) {
|
|
54478
|
+
return `Error: File not found: ${filePath}`;
|
|
54479
|
+
}
|
|
54480
|
+
const oldContent = await file2.text();
|
|
54481
|
+
const newContent = applyHashlineEdits(oldContent, edits);
|
|
54482
|
+
await Bun.write(filePath, newContent);
|
|
54483
|
+
const diff = generateDiff(oldContent, newContent, filePath);
|
|
54484
|
+
return `Successfully applied ${edits.length} edit(s) to ${filePath}
|
|
54485
|
+
|
|
54486
|
+
${diff}`;
|
|
54487
|
+
} catch (error45) {
|
|
54488
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
54489
|
+
if (message.includes("hash")) {
|
|
54490
|
+
return `Error: Hash mismatch - ${message}`;
|
|
54491
|
+
}
|
|
54492
|
+
return `Error: ${message}`;
|
|
54493
|
+
}
|
|
54494
|
+
}
|
|
54495
|
+
});
|
|
54496
|
+
}
|
|
53495
54497
|
// src/tools/index.ts
|
|
53496
54498
|
function createBackgroundTools(manager, client2) {
|
|
53497
54499
|
const outputManager = manager;
|
|
@@ -53512,10 +54514,10 @@ var builtinTools = {
|
|
|
53512
54514
|
|
|
53513
54515
|
// src/plugin/hooks/create-session-hooks.ts
|
|
53514
54516
|
function createSessionHooks(args) {
|
|
53515
|
-
const { ctx, pluginConfig, isHookEnabled, safeHookEnabled } = args;
|
|
54517
|
+
const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args;
|
|
53516
54518
|
const safeHook = (hookName, factory) => safeCreateHook(hookName, factory, { enabled: safeHookEnabled });
|
|
53517
|
-
const contextWindowMonitor = isHookEnabled("context-window-monitor") ? safeHook("context-window-monitor", () => createContextWindowMonitorHook(ctx)) : null;
|
|
53518
|
-
const preemptiveCompaction = isHookEnabled("preemptive-compaction") && pluginConfig.experimental?.preemptive_compaction ? safeHook("preemptive-compaction", () => createPreemptiveCompactionHook(ctx)) : null;
|
|
54519
|
+
const contextWindowMonitor = isHookEnabled("context-window-monitor") ? safeHook("context-window-monitor", () => createContextWindowMonitorHook(ctx, modelCacheState)) : null;
|
|
54520
|
+
const preemptiveCompaction = isHookEnabled("preemptive-compaction") && pluginConfig.experimental?.preemptive_compaction ? safeHook("preemptive-compaction", () => createPreemptiveCompactionHook(ctx, modelCacheState)) : null;
|
|
53519
54521
|
const sessionRecovery = isHookEnabled("session-recovery") ? safeHook("session-recovery", () => createSessionRecoveryHook(ctx, { experimental: pluginConfig.experimental })) : null;
|
|
53520
54522
|
let sessionNotification = null;
|
|
53521
54523
|
if (isHookEnabled("session-notification")) {
|
|
@@ -53574,10 +54576,13 @@ function createSessionHooks(args) {
|
|
|
53574
54576
|
|
|
53575
54577
|
// src/plugin/hooks/create-tool-guard-hooks.ts
|
|
53576
54578
|
function createToolGuardHooks(args) {
|
|
53577
|
-
const { ctx, pluginConfig, isHookEnabled, safeHookEnabled } = args;
|
|
54579
|
+
const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args;
|
|
53578
54580
|
const safeHook = (hookName, factory) => safeCreateHook(hookName, factory, { enabled: safeHookEnabled });
|
|
53579
54581
|
const commentChecker = isHookEnabled("comment-checker") ? safeHook("comment-checker", () => createCommentCheckerHooks(pluginConfig.comment_checker)) : null;
|
|
53580
|
-
const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? safeHook("tool-output-truncator", () => createToolOutputTruncatorHook(ctx, {
|
|
54582
|
+
const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? safeHook("tool-output-truncator", () => createToolOutputTruncatorHook(ctx, {
|
|
54583
|
+
modelCacheState,
|
|
54584
|
+
experimental: pluginConfig.experimental
|
|
54585
|
+
})) : null;
|
|
53581
54586
|
let directoryAgentsInjector = null;
|
|
53582
54587
|
if (isHookEnabled("directory-agents-injector")) {
|
|
53583
54588
|
const currentVersion = getOpenCodeVersion();
|
|
@@ -53588,14 +54593,15 @@ function createToolGuardHooks(args) {
|
|
|
53588
54593
|
nativeVersion: OPENCODE_NATIVE_AGENTS_INJECTION_VERSION
|
|
53589
54594
|
});
|
|
53590
54595
|
} else {
|
|
53591
|
-
directoryAgentsInjector = safeHook("directory-agents-injector", () => createDirectoryAgentsInjectorHook(ctx));
|
|
54596
|
+
directoryAgentsInjector = safeHook("directory-agents-injector", () => createDirectoryAgentsInjectorHook(ctx, modelCacheState));
|
|
53592
54597
|
}
|
|
53593
54598
|
}
|
|
53594
|
-
const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? safeHook("directory-readme-injector", () => createDirectoryReadmeInjectorHook(ctx)) : null;
|
|
54599
|
+
const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? safeHook("directory-readme-injector", () => createDirectoryReadmeInjectorHook(ctx, modelCacheState)) : null;
|
|
53595
54600
|
const emptyTaskResponseDetector = isHookEnabled("empty-task-response-detector") ? safeHook("empty-task-response-detector", () => createEmptyTaskResponseDetectorHook(ctx)) : null;
|
|
53596
|
-
const rulesInjector = isHookEnabled("rules-injector") ? safeHook("rules-injector", () => createRulesInjectorHook(ctx)) : null;
|
|
54601
|
+
const rulesInjector = isHookEnabled("rules-injector") ? safeHook("rules-injector", () => createRulesInjectorHook(ctx, modelCacheState)) : null;
|
|
53597
54602
|
const tasksTodowriteDisabler = isHookEnabled("tasks-todowrite-disabler") ? safeHook("tasks-todowrite-disabler", () => createTasksTodowriteDisablerHook({ experimental: pluginConfig.experimental })) : null;
|
|
53598
54603
|
const writeExistingFileGuard = isHookEnabled("write-existing-file-guard") ? safeHook("write-existing-file-guard", () => createWriteExistingFileGuardHook(ctx)) : null;
|
|
54604
|
+
const hashlineReadEnhancer = isHookEnabled("hashline-read-enhancer") ? safeHook("hashline-read-enhancer", () => createHashlineReadEnhancerHook(ctx, { hashline_edit: { enabled: pluginConfig.experimental?.hashline_edit ?? false } })) : null;
|
|
53599
54605
|
return {
|
|
53600
54606
|
commentChecker,
|
|
53601
54607
|
toolOutputTruncator,
|
|
@@ -53604,7 +54610,8 @@ function createToolGuardHooks(args) {
|
|
|
53604
54610
|
emptyTaskResponseDetector,
|
|
53605
54611
|
rulesInjector,
|
|
53606
54612
|
tasksTodowriteDisabler,
|
|
53607
|
-
writeExistingFileGuard
|
|
54613
|
+
writeExistingFileGuard,
|
|
54614
|
+
hashlineReadEnhancer
|
|
53608
54615
|
};
|
|
53609
54616
|
}
|
|
53610
54617
|
|
|
@@ -53770,16 +54777,18 @@ function createTransformHooks(args) {
|
|
|
53770
54777
|
|
|
53771
54778
|
// src/plugin/hooks/create-core-hooks.ts
|
|
53772
54779
|
function createCoreHooks(args) {
|
|
53773
|
-
const { ctx, pluginConfig, isHookEnabled, safeHookEnabled } = args;
|
|
54780
|
+
const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args;
|
|
53774
54781
|
const session = createSessionHooks({
|
|
53775
54782
|
ctx,
|
|
53776
54783
|
pluginConfig,
|
|
54784
|
+
modelCacheState,
|
|
53777
54785
|
isHookEnabled,
|
|
53778
54786
|
safeHookEnabled
|
|
53779
54787
|
});
|
|
53780
54788
|
const tool3 = createToolGuardHooks({
|
|
53781
54789
|
ctx,
|
|
53782
54790
|
pluginConfig,
|
|
54791
|
+
modelCacheState,
|
|
53783
54792
|
isHookEnabled,
|
|
53784
54793
|
safeHookEnabled
|
|
53785
54794
|
});
|
|
@@ -53897,6 +54906,7 @@ function createHooks(args) {
|
|
|
53897
54906
|
const {
|
|
53898
54907
|
ctx,
|
|
53899
54908
|
pluginConfig,
|
|
54909
|
+
modelCacheState,
|
|
53900
54910
|
backgroundManager,
|
|
53901
54911
|
isHookEnabled,
|
|
53902
54912
|
safeHookEnabled,
|
|
@@ -53906,6 +54916,7 @@ function createHooks(args) {
|
|
|
53906
54916
|
const core3 = createCoreHooks({
|
|
53907
54917
|
ctx,
|
|
53908
54918
|
pluginConfig,
|
|
54919
|
+
modelCacheState,
|
|
53909
54920
|
isHookEnabled,
|
|
53910
54921
|
safeHookEnabled
|
|
53911
54922
|
});
|
|
@@ -54095,7 +55106,7 @@ var POLLING_INTERVAL_MS = 3000;
|
|
|
54095
55106
|
var TASK_CLEANUP_DELAY_MS = 10 * 60 * 1000;
|
|
54096
55107
|
|
|
54097
55108
|
// src/features/background-agent/manager.ts
|
|
54098
|
-
import { existsSync as existsSync61, readdirSync as readdirSync18 } from "fs";
|
|
55109
|
+
import { existsSync as existsSync61, readFileSync as readFileSync40, readdirSync as readdirSync18 } from "fs";
|
|
54099
55110
|
import { join as join72 } from "path";
|
|
54100
55111
|
|
|
54101
55112
|
class BackgroundManager {
|
|
@@ -54108,6 +55119,7 @@ class BackgroundManager {
|
|
|
54108
55119
|
client;
|
|
54109
55120
|
directory;
|
|
54110
55121
|
pollingInterval;
|
|
55122
|
+
pollingInFlight = false;
|
|
54111
55123
|
concurrencyManager;
|
|
54112
55124
|
shutdownTriggered = false;
|
|
54113
55125
|
config;
|
|
@@ -54119,6 +55131,7 @@ class BackgroundManager {
|
|
|
54119
55131
|
completionTimers = new Map;
|
|
54120
55132
|
idleDeferralTimers = new Map;
|
|
54121
55133
|
notificationQueueByParent = new Map;
|
|
55134
|
+
enableParentSessionNotifications;
|
|
54122
55135
|
taskHistory = new TaskHistory;
|
|
54123
55136
|
constructor(ctx, config3, options) {
|
|
54124
55137
|
this.tasks = new Map;
|
|
@@ -54131,6 +55144,7 @@ class BackgroundManager {
|
|
|
54131
55144
|
this.tmuxEnabled = options?.tmuxConfig?.enabled ?? false;
|
|
54132
55145
|
this.onSubagentSessionCreated = options?.onSubagentSessionCreated;
|
|
54133
55146
|
this.onShutdown = options?.onShutdown;
|
|
55147
|
+
this.enableParentSessionNotifications = options?.enableParentSessionNotifications ?? true;
|
|
54134
55148
|
this.registerProcessCleanup();
|
|
54135
55149
|
}
|
|
54136
55150
|
async launch(input) {
|
|
@@ -54965,13 +55979,12 @@ class BackgroundManager {
|
|
|
54965
55979
|
} else {
|
|
54966
55980
|
allComplete = true;
|
|
54967
55981
|
}
|
|
55982
|
+
const completedTasks = allComplete ? Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running" && t.status !== "pending") : [];
|
|
54968
55983
|
const statusText = task.status === "completed" ? "COMPLETED" : task.status === "interrupt" ? "INTERRUPTED" : "CANCELLED";
|
|
54969
55984
|
const errorInfo = task.error ? `
|
|
54970
55985
|
**Error:** ${task.error}` : "";
|
|
54971
55986
|
let notification;
|
|
54972
|
-
let completedTasks = [];
|
|
54973
55987
|
if (allComplete) {
|
|
54974
|
-
completedTasks = Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running" && t.status !== "pending");
|
|
54975
55988
|
const completedTasksText = completedTasks.map((t) => `- \`${t.id}\`: ${t.description}`).join(`
|
|
54976
55989
|
`);
|
|
54977
55990
|
notification = `<system-reminder>
|
|
@@ -54997,59 +56010,69 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
54997
56010
|
}
|
|
54998
56011
|
let agent = task.parentAgent;
|
|
54999
56012
|
let model;
|
|
55000
|
-
|
|
55001
|
-
|
|
55002
|
-
|
|
55003
|
-
|
|
55004
|
-
|
|
55005
|
-
|
|
55006
|
-
|
|
55007
|
-
|
|
55008
|
-
|
|
56013
|
+
if (this.enableParentSessionNotifications) {
|
|
56014
|
+
try {
|
|
56015
|
+
const messagesResp = await this.client.session.messages({ path: { id: task.parentSessionID } });
|
|
56016
|
+
const messages = normalizeSDKResponse(messagesResp, []);
|
|
56017
|
+
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
56018
|
+
const info = messages[i2].info;
|
|
56019
|
+
if (isCompactionAgent(info?.agent)) {
|
|
56020
|
+
continue;
|
|
56021
|
+
}
|
|
56022
|
+
if (info?.agent || info?.model || info?.modelID && info?.providerID) {
|
|
56023
|
+
agent = info.agent ?? task.parentAgent;
|
|
56024
|
+
model = info.model ?? (info.providerID && info.modelID ? { providerID: info.providerID, modelID: info.modelID } : undefined);
|
|
56025
|
+
break;
|
|
56026
|
+
}
|
|
55009
56027
|
}
|
|
55010
|
-
}
|
|
55011
|
-
|
|
55012
|
-
|
|
55013
|
-
|
|
55014
|
-
|
|
55015
|
-
|
|
55016
|
-
});
|
|
55017
|
-
}
|
|
55018
|
-
const messageDir = getMessageDir2(task.parentSessionID);
|
|
55019
|
-
const currentMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
|
|
55020
|
-
agent = currentMessage?.agent ?? task.parentAgent;
|
|
55021
|
-
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
55022
|
-
}
|
|
55023
|
-
log("[background-agent] notifyParentSession context:", {
|
|
55024
|
-
taskId: task.id,
|
|
55025
|
-
resolvedAgent: agent,
|
|
55026
|
-
resolvedModel: model
|
|
55027
|
-
});
|
|
55028
|
-
try {
|
|
55029
|
-
await this.client.session.promptAsync({
|
|
55030
|
-
path: { id: task.parentSessionID },
|
|
55031
|
-
body: {
|
|
55032
|
-
noReply: !allComplete,
|
|
55033
|
-
...agent !== undefined ? { agent } : {},
|
|
55034
|
-
...model !== undefined ? { model } : {},
|
|
55035
|
-
...task.parentTools ? { tools: task.parentTools } : {},
|
|
55036
|
-
parts: [{ type: "text", text: notification }]
|
|
56028
|
+
} catch (error45) {
|
|
56029
|
+
if (this.isAbortedSessionError(error45)) {
|
|
56030
|
+
log("[background-agent] Parent session aborted while loading messages; using messageDir fallback:", {
|
|
56031
|
+
taskId: task.id,
|
|
56032
|
+
parentSessionID: task.parentSessionID
|
|
56033
|
+
});
|
|
55037
56034
|
}
|
|
55038
|
-
|
|
55039
|
-
|
|
56035
|
+
const messageDir = getMessageDir2(task.parentSessionID);
|
|
56036
|
+
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir) : null;
|
|
56037
|
+
agent = currentMessage?.agent ?? task.parentAgent;
|
|
56038
|
+
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
56039
|
+
}
|
|
56040
|
+
log("[background-agent] notifyParentSession context:", {
|
|
55040
56041
|
taskId: task.id,
|
|
55041
|
-
|
|
55042
|
-
|
|
56042
|
+
resolvedAgent: agent,
|
|
56043
|
+
resolvedModel: model
|
|
55043
56044
|
});
|
|
55044
|
-
|
|
55045
|
-
|
|
55046
|
-
|
|
56045
|
+
try {
|
|
56046
|
+
await this.client.session.promptAsync({
|
|
56047
|
+
path: { id: task.parentSessionID },
|
|
56048
|
+
body: {
|
|
56049
|
+
noReply: !allComplete,
|
|
56050
|
+
...agent !== undefined ? { agent } : {},
|
|
56051
|
+
...model !== undefined ? { model } : {},
|
|
56052
|
+
...task.parentTools ? { tools: task.parentTools } : {},
|
|
56053
|
+
parts: [{ type: "text", text: notification }]
|
|
56054
|
+
}
|
|
56055
|
+
});
|
|
56056
|
+
log("[background-agent] Sent notification to parent session:", {
|
|
55047
56057
|
taskId: task.id,
|
|
55048
|
-
|
|
56058
|
+
allComplete,
|
|
56059
|
+
noReply: !allComplete
|
|
55049
56060
|
});
|
|
55050
|
-
}
|
|
55051
|
-
|
|
56061
|
+
} catch (error45) {
|
|
56062
|
+
if (this.isAbortedSessionError(error45)) {
|
|
56063
|
+
log("[background-agent] Parent session aborted while sending notification; continuing cleanup:", {
|
|
56064
|
+
taskId: task.id,
|
|
56065
|
+
parentSessionID: task.parentSessionID
|
|
56066
|
+
});
|
|
56067
|
+
} else {
|
|
56068
|
+
log("[background-agent] Failed to send notification:", error45);
|
|
56069
|
+
}
|
|
55052
56070
|
}
|
|
56071
|
+
} else {
|
|
56072
|
+
log("[background-agent] Parent session notifications disabled, skipping prompt injection:", {
|
|
56073
|
+
taskId: task.id,
|
|
56074
|
+
parentSessionID: task.parentSessionID
|
|
56075
|
+
});
|
|
55053
56076
|
}
|
|
55054
56077
|
if (allComplete) {
|
|
55055
56078
|
for (const completedTask of completedTasks) {
|
|
@@ -55253,46 +56276,53 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
55253
56276
|
}
|
|
55254
56277
|
}
|
|
55255
56278
|
async pollRunningTasks() {
|
|
55256
|
-
this.
|
|
55257
|
-
|
|
55258
|
-
|
|
55259
|
-
|
|
55260
|
-
|
|
55261
|
-
|
|
55262
|
-
|
|
55263
|
-
|
|
55264
|
-
|
|
55265
|
-
|
|
55266
|
-
|
|
55267
|
-
const
|
|
55268
|
-
if (
|
|
55269
|
-
|
|
55270
|
-
|
|
55271
|
-
|
|
55272
|
-
|
|
55273
|
-
|
|
55274
|
-
|
|
55275
|
-
|
|
55276
|
-
|
|
55277
|
-
|
|
55278
|
-
|
|
56279
|
+
if (this.pollingInFlight)
|
|
56280
|
+
return;
|
|
56281
|
+
this.pollingInFlight = true;
|
|
56282
|
+
try {
|
|
56283
|
+
this.pruneStaleTasksAndNotifications();
|
|
56284
|
+
const statusResult = await this.client.session.status();
|
|
56285
|
+
const allStatuses = normalizeSDKResponse(statusResult, {});
|
|
56286
|
+
await this.checkAndInterruptStaleTasks(allStatuses);
|
|
56287
|
+
for (const task of this.tasks.values()) {
|
|
56288
|
+
if (task.status !== "running")
|
|
56289
|
+
continue;
|
|
56290
|
+
const sessionID = task.sessionID;
|
|
56291
|
+
if (!sessionID)
|
|
56292
|
+
continue;
|
|
56293
|
+
try {
|
|
56294
|
+
const sessionStatus = allStatuses[sessionID];
|
|
56295
|
+
if (sessionStatus?.type === "idle") {
|
|
56296
|
+
const hasValidOutput = await this.validateSessionHasOutput(sessionID);
|
|
56297
|
+
if (!hasValidOutput) {
|
|
56298
|
+
log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
|
|
56299
|
+
continue;
|
|
56300
|
+
}
|
|
56301
|
+
if (task.status !== "running")
|
|
56302
|
+
continue;
|
|
56303
|
+
const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
|
|
56304
|
+
if (hasIncompleteTodos2) {
|
|
56305
|
+
log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
|
|
56306
|
+
continue;
|
|
56307
|
+
}
|
|
56308
|
+
await this.tryCompleteTask(task, "polling (idle status)");
|
|
55279
56309
|
continue;
|
|
55280
56310
|
}
|
|
55281
|
-
|
|
55282
|
-
|
|
56311
|
+
log("[background-agent] Session still running, relying on event-based progress:", {
|
|
56312
|
+
taskId: task.id,
|
|
56313
|
+
sessionID,
|
|
56314
|
+
sessionStatus: sessionStatus?.type ?? "not_in_status",
|
|
56315
|
+
toolCalls: task.progress?.toolCalls ?? 0
|
|
56316
|
+
});
|
|
56317
|
+
} catch (error45) {
|
|
56318
|
+
log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
|
|
55283
56319
|
}
|
|
55284
|
-
log("[background-agent] Session still running, relying on event-based progress:", {
|
|
55285
|
-
taskId: task.id,
|
|
55286
|
-
sessionID,
|
|
55287
|
-
sessionStatus: sessionStatus?.type ?? "not_in_status",
|
|
55288
|
-
toolCalls: task.progress?.toolCalls ?? 0
|
|
55289
|
-
});
|
|
55290
|
-
} catch (error45) {
|
|
55291
|
-
log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
|
|
55292
56320
|
}
|
|
55293
|
-
|
|
55294
|
-
|
|
55295
|
-
|
|
56321
|
+
if (!this.hasRunningTasks()) {
|
|
56322
|
+
this.stopPolling();
|
|
56323
|
+
}
|
|
56324
|
+
} finally {
|
|
56325
|
+
this.pollingInFlight = false;
|
|
55296
56326
|
}
|
|
55297
56327
|
}
|
|
55298
56328
|
shutdown() {
|
|
@@ -55378,6 +56408,47 @@ function getMessageDir2(sessionID) {
|
|
|
55378
56408
|
}
|
|
55379
56409
|
return null;
|
|
55380
56410
|
}
|
|
56411
|
+
function isCompactionAgent(agent) {
|
|
56412
|
+
return agent?.trim().toLowerCase() === "compaction";
|
|
56413
|
+
}
|
|
56414
|
+
function hasFullAgentAndModel(message) {
|
|
56415
|
+
return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
|
|
56416
|
+
}
|
|
56417
|
+
function hasPartialAgentOrModel(message) {
|
|
56418
|
+
const hasAgent = !!message.agent && !isCompactionAgent(message.agent);
|
|
56419
|
+
const hasModel = !!message.model?.providerID && !!message.model?.modelID;
|
|
56420
|
+
return hasAgent || hasModel;
|
|
56421
|
+
}
|
|
56422
|
+
function findNearestMessageExcludingCompaction(messageDir) {
|
|
56423
|
+
try {
|
|
56424
|
+
const files = readdirSync18(messageDir).filter((name) => name.endsWith(".json")).sort().reverse();
|
|
56425
|
+
for (const file2 of files) {
|
|
56426
|
+
try {
|
|
56427
|
+
const content = readFileSync40(join72(messageDir, file2), "utf-8");
|
|
56428
|
+
const parsed = JSON.parse(content);
|
|
56429
|
+
if (hasFullAgentAndModel(parsed)) {
|
|
56430
|
+
return parsed;
|
|
56431
|
+
}
|
|
56432
|
+
} catch {
|
|
56433
|
+
continue;
|
|
56434
|
+
}
|
|
56435
|
+
}
|
|
56436
|
+
for (const file2 of files) {
|
|
56437
|
+
try {
|
|
56438
|
+
const content = readFileSync40(join72(messageDir, file2), "utf-8");
|
|
56439
|
+
const parsed = JSON.parse(content);
|
|
56440
|
+
if (hasPartialAgentOrModel(parsed)) {
|
|
56441
|
+
return parsed;
|
|
56442
|
+
}
|
|
56443
|
+
} catch {
|
|
56444
|
+
continue;
|
|
56445
|
+
}
|
|
56446
|
+
}
|
|
56447
|
+
} catch {
|
|
56448
|
+
return null;
|
|
56449
|
+
}
|
|
56450
|
+
return null;
|
|
56451
|
+
}
|
|
55381
56452
|
// src/features/background-agent/state.ts
|
|
55382
56453
|
class TaskStateManager {
|
|
55383
56454
|
tasks = new Map;
|
|
@@ -59363,7 +60434,7 @@ class StreamableHTTPClientTransport {
|
|
|
59363
60434
|
}
|
|
59364
60435
|
|
|
59365
60436
|
// src/features/mcp-oauth/storage.ts
|
|
59366
|
-
import { chmodSync as chmodSync2, existsSync as existsSync62, mkdirSync as mkdirSync14, readFileSync as
|
|
60437
|
+
import { chmodSync as chmodSync2, existsSync as existsSync62, mkdirSync as mkdirSync14, readFileSync as readFileSync41, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
|
|
59367
60438
|
import { dirname as dirname20, join as join73 } from "path";
|
|
59368
60439
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
59369
60440
|
function getMcpOauthStoragePath() {
|
|
@@ -59408,7 +60479,7 @@ function readStore() {
|
|
|
59408
60479
|
return null;
|
|
59409
60480
|
}
|
|
59410
60481
|
try {
|
|
59411
|
-
const content =
|
|
60482
|
+
const content = readFileSync41(filePath, "utf-8");
|
|
59412
60483
|
return JSON.parse(content);
|
|
59413
60484
|
} catch {
|
|
59414
60485
|
return null;
|
|
@@ -60538,14 +61609,14 @@ var MIN_SPLIT_WIDTH = 2 * MIN_PANE_WIDTH + DIVIDER_SIZE;
|
|
|
60538
61609
|
var MIN_SPLIT_HEIGHT = 2 * MIN_PANE_HEIGHT + DIVIDER_SIZE;
|
|
60539
61610
|
|
|
60540
61611
|
// src/features/tmux-subagent/grid-planning.ts
|
|
60541
|
-
function calculateCapacity(windowWidth, windowHeight, minPaneWidth = MIN_PANE_WIDTH) {
|
|
60542
|
-
const availableWidth = Math.floor(windowWidth * (1 - MAIN_PANE_RATIO));
|
|
61612
|
+
function calculateCapacity(windowWidth, windowHeight, minPaneWidth = MIN_PANE_WIDTH, mainPaneWidth) {
|
|
61613
|
+
const availableWidth = typeof mainPaneWidth === "number" ? Math.max(0, windowWidth - mainPaneWidth - DIVIDER_SIZE) : Math.floor(windowWidth * (1 - MAIN_PANE_RATIO));
|
|
60543
61614
|
const cols = Math.min(MAX_GRID_SIZE, Math.max(0, Math.floor((availableWidth + DIVIDER_SIZE) / (minPaneWidth + DIVIDER_SIZE))));
|
|
60544
61615
|
const rows = Math.min(MAX_GRID_SIZE, Math.max(0, Math.floor((windowHeight + DIVIDER_SIZE) / (MIN_PANE_HEIGHT + DIVIDER_SIZE))));
|
|
60545
61616
|
return { cols, rows, total: cols * rows };
|
|
60546
61617
|
}
|
|
60547
|
-
function computeGridPlan(windowWidth, windowHeight, paneCount) {
|
|
60548
|
-
const capacity = calculateCapacity(windowWidth, windowHeight);
|
|
61618
|
+
function computeGridPlan(windowWidth, windowHeight, paneCount, mainPaneWidth, minPaneWidth) {
|
|
61619
|
+
const capacity = calculateCapacity(windowWidth, windowHeight, minPaneWidth ?? MIN_PANE_WIDTH, mainPaneWidth);
|
|
60549
61620
|
const { cols: maxCols, rows: maxRows } = capacity;
|
|
60550
61621
|
if (maxCols === 0 || maxRows === 0 || paneCount === 0) {
|
|
60551
61622
|
return { cols: 1, rows: 1, slotWidth: 0, slotHeight: 0 };
|
|
@@ -60565,7 +61636,7 @@ function computeGridPlan(windowWidth, windowHeight, paneCount) {
|
|
|
60565
61636
|
}
|
|
60566
61637
|
}
|
|
60567
61638
|
}
|
|
60568
|
-
const availableWidth = Math.floor(windowWidth * (1 - MAIN_PANE_RATIO));
|
|
61639
|
+
const availableWidth = typeof mainPaneWidth === "number" ? Math.max(0, windowWidth - mainPaneWidth - DIVIDER_SIZE) : Math.floor(windowWidth * (1 - MAIN_PANE_RATIO));
|
|
60569
61640
|
const slotWidth = Math.floor(availableWidth / bestCols);
|
|
60570
61641
|
const slotHeight = Math.floor(windowHeight / bestRows);
|
|
60571
61642
|
return { cols: bestCols, rows: bestRows, slotWidth, slotHeight };
|
|
@@ -60610,8 +61681,8 @@ function canSplitPane(pane, direction, minPaneWidth = MIN_PANE_WIDTH) {
|
|
|
60610
61681
|
}
|
|
60611
61682
|
return pane.height >= MIN_SPLIT_HEIGHT;
|
|
60612
61683
|
}
|
|
60613
|
-
function getBestSplitDirection(pane) {
|
|
60614
|
-
const canH = pane.width >=
|
|
61684
|
+
function getBestSplitDirection(pane, minPaneWidth = MIN_PANE_WIDTH) {
|
|
61685
|
+
const canH = pane.width >= minSplitWidthFor(minPaneWidth);
|
|
60615
61686
|
const canV = pane.height >= MIN_SPLIT_HEIGHT;
|
|
60616
61687
|
if (!canH && !canV)
|
|
60617
61688
|
return null;
|
|
@@ -60640,38 +61711,38 @@ function findFirstEmptySlot(occupancy, plan) {
|
|
|
60640
61711
|
}
|
|
60641
61712
|
return { row: plan.rows - 1, col: plan.cols - 1 };
|
|
60642
61713
|
}
|
|
60643
|
-
function findSplittableTarget(state3, _preferredDirection) {
|
|
61714
|
+
function findSplittableTarget(state3, minPaneWidth, _preferredDirection) {
|
|
60644
61715
|
if (!state3.mainPane)
|
|
60645
61716
|
return null;
|
|
60646
61717
|
const existingCount = state3.agentPanes.length;
|
|
60647
61718
|
if (existingCount === 0) {
|
|
60648
61719
|
const virtualMainPane = { ...state3.mainPane, width: state3.windowWidth };
|
|
60649
|
-
if (canSplitPane(virtualMainPane, "-h")) {
|
|
61720
|
+
if (canSplitPane(virtualMainPane, "-h", minPaneWidth)) {
|
|
60650
61721
|
return { targetPaneId: state3.mainPane.paneId, splitDirection: "-h" };
|
|
60651
61722
|
}
|
|
60652
61723
|
return null;
|
|
60653
61724
|
}
|
|
60654
|
-
const plan = computeGridPlan(state3.windowWidth, state3.windowHeight, existingCount + 1);
|
|
60655
|
-
const mainPaneWidth =
|
|
61725
|
+
const plan = computeGridPlan(state3.windowWidth, state3.windowHeight, existingCount + 1, state3.mainPane.width, minPaneWidth);
|
|
61726
|
+
const mainPaneWidth = state3.mainPane.width;
|
|
60656
61727
|
const occupancy = buildOccupancy(state3.agentPanes, plan, mainPaneWidth);
|
|
60657
61728
|
const targetSlot = findFirstEmptySlot(occupancy, plan);
|
|
60658
61729
|
const leftPane = occupancy.get(`${targetSlot.row}:${targetSlot.col - 1}`);
|
|
60659
|
-
if (leftPane && canSplitPane(leftPane, "-h")) {
|
|
61730
|
+
if (leftPane && canSplitPane(leftPane, "-h", minPaneWidth)) {
|
|
60660
61731
|
return { targetPaneId: leftPane.paneId, splitDirection: "-h" };
|
|
60661
61732
|
}
|
|
60662
61733
|
const abovePane = occupancy.get(`${targetSlot.row - 1}:${targetSlot.col}`);
|
|
60663
|
-
if (abovePane && canSplitPane(abovePane, "-v")) {
|
|
61734
|
+
if (abovePane && canSplitPane(abovePane, "-v", minPaneWidth)) {
|
|
60664
61735
|
return { targetPaneId: abovePane.paneId, splitDirection: "-v" };
|
|
60665
61736
|
}
|
|
60666
|
-
const splittablePanes = state3.agentPanes.map((pane) => ({ pane, direction: getBestSplitDirection(pane) })).filter((item) => item.direction !== null).sort((a, b) => b.pane.width * b.pane.height - a.pane.width * a.pane.height);
|
|
61737
|
+
const splittablePanes = state3.agentPanes.map((pane) => ({ pane, direction: getBestSplitDirection(pane, minPaneWidth) })).filter((item) => item.direction !== null).sort((a, b) => b.pane.width * b.pane.height - a.pane.width * a.pane.height);
|
|
60667
61738
|
const best = splittablePanes[0];
|
|
60668
61739
|
if (best) {
|
|
60669
61740
|
return { targetPaneId: best.pane.paneId, splitDirection: best.direction };
|
|
60670
61741
|
}
|
|
60671
61742
|
return null;
|
|
60672
61743
|
}
|
|
60673
|
-
function findSpawnTarget(state3) {
|
|
60674
|
-
return findSplittableTarget(state3);
|
|
61744
|
+
function findSpawnTarget(state3, minPaneWidth = MIN_PANE_WIDTH) {
|
|
61745
|
+
return findSplittableTarget(state3, minPaneWidth);
|
|
60675
61746
|
}
|
|
60676
61747
|
// src/features/tmux-subagent/oldest-agent-pane.ts
|
|
60677
61748
|
function findOldestAgentPane(agentPanes, sessionMappings) {
|
|
@@ -60699,7 +61770,7 @@ function decideSpawnActions(state3, sessionId, description, config3, sessionMapp
|
|
|
60699
61770
|
return { canSpawn: false, actions: [], reason: "no main pane found" };
|
|
60700
61771
|
}
|
|
60701
61772
|
const minPaneWidth = config3.agentPaneWidth;
|
|
60702
|
-
const agentAreaWidth = Math.
|
|
61773
|
+
const agentAreaWidth = Math.max(0, state3.windowWidth - state3.mainPane.width - DIVIDER_SIZE);
|
|
60703
61774
|
const currentCount = state3.agentPanes.length;
|
|
60704
61775
|
if (agentAreaWidth < minPaneWidth) {
|
|
60705
61776
|
return {
|
|
@@ -60729,7 +61800,7 @@ function decideSpawnActions(state3, sessionId, description, config3, sessionMapp
|
|
|
60729
61800
|
return { canSpawn: false, actions: [], reason: "mainPane too small to split" };
|
|
60730
61801
|
}
|
|
60731
61802
|
if (isSplittableAtCount(agentAreaWidth, currentCount, minPaneWidth)) {
|
|
60732
|
-
const spawnTarget = findSpawnTarget(state3);
|
|
61803
|
+
const spawnTarget = findSpawnTarget(state3, minPaneWidth);
|
|
60733
61804
|
if (spawnTarget) {
|
|
60734
61805
|
return {
|
|
60735
61806
|
canSpawn: true,
|
|
@@ -60751,19 +61822,14 @@ function decideSpawnActions(state3, sessionId, description, config3, sessionMapp
|
|
|
60751
61822
|
canSpawn: true,
|
|
60752
61823
|
actions: [
|
|
60753
61824
|
{
|
|
60754
|
-
type: "
|
|
61825
|
+
type: "replace",
|
|
60755
61826
|
paneId: oldestPane.paneId,
|
|
60756
|
-
|
|
60757
|
-
|
|
60758
|
-
|
|
60759
|
-
type: "spawn",
|
|
60760
|
-
sessionId,
|
|
60761
|
-
description,
|
|
60762
|
-
targetPaneId: state3.mainPane.paneId,
|
|
60763
|
-
splitDirection: "-h"
|
|
61827
|
+
oldSessionId: oldestMapping?.sessionId || "",
|
|
61828
|
+
newSessionId: sessionId,
|
|
61829
|
+
description
|
|
60764
61830
|
}
|
|
60765
61831
|
],
|
|
60766
|
-
reason: "
|
|
61832
|
+
reason: "replaced oldest pane to avoid split churn"
|
|
60767
61833
|
};
|
|
60768
61834
|
}
|
|
60769
61835
|
if (oldestPane) {
|
|
@@ -60792,36 +61858,48 @@ function decideCloseAction(state3, sessionId, sessionMappings) {
|
|
|
60792
61858
|
return null;
|
|
60793
61859
|
return { type: "close", paneId: mapping.paneId, sessionId };
|
|
60794
61860
|
}
|
|
60795
|
-
// src/features/tmux-subagent/action-executor.ts
|
|
60796
|
-
async function enforceMainPane(windowState) {
|
|
61861
|
+
// src/features/tmux-subagent/action-executor-core.ts
|
|
61862
|
+
async function enforceMainPane(windowState, config3, deps) {
|
|
60797
61863
|
if (!windowState.mainPane)
|
|
60798
61864
|
return;
|
|
60799
|
-
await enforceMainPaneWidth(windowState.mainPane.paneId, windowState.windowWidth);
|
|
61865
|
+
await deps.enforceMainPaneWidth(windowState.mainPane.paneId, windowState.windowWidth, config3.main_pane_size);
|
|
60800
61866
|
}
|
|
60801
|
-
async function
|
|
61867
|
+
async function executeActionWithDeps(action, ctx, deps) {
|
|
60802
61868
|
if (action.type === "close") {
|
|
60803
|
-
const success2 = await closeTmuxPane(action.paneId);
|
|
61869
|
+
const success2 = await deps.closeTmuxPane(action.paneId);
|
|
60804
61870
|
if (success2) {
|
|
60805
|
-
await enforceMainPane(ctx.windowState);
|
|
61871
|
+
await enforceMainPane(ctx.windowState, ctx.config, deps);
|
|
60806
61872
|
}
|
|
60807
61873
|
return { success: success2 };
|
|
60808
61874
|
}
|
|
60809
61875
|
if (action.type === "replace") {
|
|
60810
|
-
const result2 = await replaceTmuxPane(action.paneId, action.newSessionId, action.description, ctx.config, ctx.serverUrl);
|
|
61876
|
+
const result2 = await deps.replaceTmuxPane(action.paneId, action.newSessionId, action.description, ctx.config, ctx.serverUrl);
|
|
60811
61877
|
return {
|
|
60812
61878
|
success: result2.success,
|
|
60813
61879
|
paneId: result2.paneId
|
|
60814
61880
|
};
|
|
60815
61881
|
}
|
|
60816
|
-
const result = await spawnTmuxPane(action.sessionId, action.description, ctx.config, ctx.serverUrl, action.targetPaneId, action.splitDirection);
|
|
61882
|
+
const result = await deps.spawnTmuxPane(action.sessionId, action.description, ctx.config, ctx.serverUrl, action.targetPaneId, action.splitDirection);
|
|
60817
61883
|
if (result.success) {
|
|
60818
|
-
await enforceMainPane(ctx.windowState);
|
|
61884
|
+
await enforceMainPane(ctx.windowState, ctx.config, deps);
|
|
60819
61885
|
}
|
|
60820
61886
|
return {
|
|
60821
61887
|
success: result.success,
|
|
60822
61888
|
paneId: result.paneId
|
|
60823
61889
|
};
|
|
60824
61890
|
}
|
|
61891
|
+
|
|
61892
|
+
// src/features/tmux-subagent/action-executor.ts
|
|
61893
|
+
var DEFAULT_DEPS = {
|
|
61894
|
+
spawnTmuxPane,
|
|
61895
|
+
closeTmuxPane,
|
|
61896
|
+
replaceTmuxPane,
|
|
61897
|
+
applyLayout,
|
|
61898
|
+
enforceMainPaneWidth
|
|
61899
|
+
};
|
|
61900
|
+
async function executeAction(action, ctx) {
|
|
61901
|
+
return executeActionWithDeps(action, ctx, DEFAULT_DEPS);
|
|
61902
|
+
}
|
|
60825
61903
|
async function executeActions(actions, ctx) {
|
|
60826
61904
|
const results = [];
|
|
60827
61905
|
let spawnedPaneId;
|
|
@@ -60850,6 +61928,7 @@ class TmuxPollingManager {
|
|
|
60850
61928
|
sessions;
|
|
60851
61929
|
closeSessionById;
|
|
60852
61930
|
pollInterval;
|
|
61931
|
+
pollingInFlight = false;
|
|
60853
61932
|
constructor(client2, sessions, closeSessionById) {
|
|
60854
61933
|
this.client = client2;
|
|
60855
61934
|
this.sessions = sessions;
|
|
@@ -60869,11 +61948,14 @@ class TmuxPollingManager {
|
|
|
60869
61948
|
}
|
|
60870
61949
|
}
|
|
60871
61950
|
async pollSessions() {
|
|
60872
|
-
if (this.
|
|
60873
|
-
this.stopPolling();
|
|
61951
|
+
if (this.pollingInFlight)
|
|
60874
61952
|
return;
|
|
60875
|
-
|
|
61953
|
+
this.pollingInFlight = true;
|
|
60876
61954
|
try {
|
|
61955
|
+
if (this.sessions.size === 0) {
|
|
61956
|
+
this.stopPolling();
|
|
61957
|
+
return;
|
|
61958
|
+
}
|
|
60877
61959
|
const statusResult = await this.client.session.status({ path: undefined });
|
|
60878
61960
|
const allStatuses = normalizeSDKResponse(statusResult, {});
|
|
60879
61961
|
log("[tmux-session-manager] pollSessions", {
|
|
@@ -60950,6 +62032,8 @@ class TmuxPollingManager {
|
|
|
60950
62032
|
}
|
|
60951
62033
|
} catch (err) {
|
|
60952
62034
|
log("[tmux-session-manager] poll error", { error: String(err) });
|
|
62035
|
+
} finally {
|
|
62036
|
+
this.pollingInFlight = false;
|
|
60953
62037
|
}
|
|
60954
62038
|
}
|
|
60955
62039
|
}
|
|
@@ -61101,10 +62185,12 @@ class TmuxSessionManager {
|
|
|
61101
62185
|
if (result.success && result.spawnedPaneId) {
|
|
61102
62186
|
const sessionReady = await this.waitForSessionReady(sessionId);
|
|
61103
62187
|
if (!sessionReady) {
|
|
61104
|
-
log("[tmux-session-manager] session not ready after timeout,
|
|
62188
|
+
log("[tmux-session-manager] session not ready after timeout, closing spawned pane", {
|
|
61105
62189
|
sessionId,
|
|
61106
62190
|
paneId: result.spawnedPaneId
|
|
61107
62191
|
});
|
|
62192
|
+
await executeAction({ type: "close", paneId: result.spawnedPaneId, sessionId }, { config: this.tmuxConfig, serverUrl: this.serverUrl, windowState: state3 });
|
|
62193
|
+
return;
|
|
61108
62194
|
}
|
|
61109
62195
|
const now = Date.now();
|
|
61110
62196
|
this.sessions.set(sessionId, {
|
|
@@ -61248,17 +62334,15 @@ function buildToolSelectionTable(agents, tools = [], _skills = []) {
|
|
|
61248
62334
|
"### Tool & Agent Selection:",
|
|
61249
62335
|
""
|
|
61250
62336
|
];
|
|
61251
|
-
rows.push("| Resource | Cost | When to Use |");
|
|
61252
|
-
rows.push("|----------|------|-------------|");
|
|
61253
62337
|
if (tools.length > 0) {
|
|
61254
62338
|
const toolsDisplay = formatToolsForPrompt(tools);
|
|
61255
|
-
rows.push(
|
|
62339
|
+
rows.push(`- ${toolsDisplay} \u2014 **FREE** \u2014 Not Complex, Scope Clear, No Implicit Assumptions`);
|
|
61256
62340
|
}
|
|
61257
62341
|
const costOrder = { FREE: 0, CHEAP: 1, EXPENSIVE: 2 };
|
|
61258
62342
|
const sortedAgents = [...agents].filter((a) => a.metadata.category !== "utility").sort((a, b) => costOrder[a.metadata.cost] - costOrder[b.metadata.cost]);
|
|
61259
62343
|
for (const agent of sortedAgents) {
|
|
61260
62344
|
const shortDesc = agent.description.split(".")[0] || agent.description;
|
|
61261
|
-
rows.push(
|
|
62345
|
+
rows.push(`- \`${agent.name}\` agent \u2014 **${agent.metadata.cost}** \u2014 ${shortDesc}`);
|
|
61262
62346
|
}
|
|
61263
62347
|
rows.push("");
|
|
61264
62348
|
rows.push("**Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)");
|
|
@@ -61275,11 +62359,12 @@ function buildExploreSection(agents) {
|
|
|
61275
62359
|
|
|
61276
62360
|
Use it as a **peer tool**, not a fallback. Fire liberally.
|
|
61277
62361
|
|
|
61278
|
-
|
|
61279
|
-
|
|
61280
|
-
${avoidWhen.map((w) => `| ${w} | |`).join(`
|
|
62362
|
+
**Use Direct Tools when:**
|
|
62363
|
+
${avoidWhen.map((w) => `- ${w}`).join(`
|
|
61281
62364
|
`)}
|
|
61282
|
-
|
|
62365
|
+
|
|
62366
|
+
**Use Explore Agent when:**
|
|
62367
|
+
${useWhen.map((w) => `- ${w}`).join(`
|
|
61283
62368
|
`)}`;
|
|
61284
62369
|
}
|
|
61285
62370
|
function buildLibrarianSection(agents) {
|
|
@@ -61291,14 +62376,8 @@ function buildLibrarianSection(agents) {
|
|
|
61291
62376
|
|
|
61292
62377
|
Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
|
|
61293
62378
|
|
|
61294
|
-
|
|
61295
|
-
|
|
61296
|
-
| Search OUR codebase | Search EXTERNAL resources |
|
|
61297
|
-
| Find patterns in THIS repo | Find examples in OTHER repos |
|
|
61298
|
-
| How does our code work? | How does this library work? |
|
|
61299
|
-
| Project-specific logic | Official API documentation |
|
|
61300
|
-
| | Library best practices & quirks |
|
|
61301
|
-
| | OSS implementation examples |
|
|
62379
|
+
**Contextual Grep (Internal)** \u2014 search OUR codebase, find patterns in THIS repo, project-specific logic.
|
|
62380
|
+
**Reference Grep (External)** \u2014 search EXTERNAL resources, official API docs, library best practices, OSS implementation examples.
|
|
61302
62381
|
|
|
61303
62382
|
**Trigger phrases** (fire librarian immediately):
|
|
61304
62383
|
${useWhen.map((w) => `- "${w}"`).join(`
|
|
@@ -61307,13 +62386,11 @@ ${useWhen.map((w) => `- "${w}"`).join(`
|
|
|
61307
62386
|
function buildDelegationTable(agents) {
|
|
61308
62387
|
const rows = [
|
|
61309
62388
|
"### Delegation Table:",
|
|
61310
|
-
""
|
|
61311
|
-
"| Domain | Delegate To | Trigger |",
|
|
61312
|
-
"|--------|-------------|---------|"
|
|
62389
|
+
""
|
|
61313
62390
|
];
|
|
61314
62391
|
for (const agent of agents) {
|
|
61315
62392
|
for (const trigger of agent.metadata.triggers) {
|
|
61316
|
-
rows.push(
|
|
62393
|
+
rows.push(`- **${trigger.domain}** \u2192 \`${agent.name}\` \u2014 ${trigger.trigger}`);
|
|
61317
62394
|
}
|
|
61318
62395
|
}
|
|
61319
62396
|
return rows.join(`
|
|
@@ -61327,8 +62404,6 @@ function formatCustomSkillsBlock(customRows, customSkills, headerLevel = "####")
|
|
|
61327
62404
|
**The user has installed these custom skills. They MUST be evaluated for EVERY delegation.**
|
|
61328
62405
|
Subagents are STATELESS \u2014 they lose all custom knowledge unless you pass these skills via \`load_skills\`.
|
|
61329
62406
|
|
|
61330
|
-
| Skill | Expertise Domain | Source |
|
|
61331
|
-
|-------|------------------|--------|
|
|
61332
62407
|
${customRows.join(`
|
|
61333
62408
|
`)}
|
|
61334
62409
|
|
|
@@ -61340,26 +62415,24 @@ function buildCategorySkillsDelegationGuide(categories, skills) {
|
|
|
61340
62415
|
return "";
|
|
61341
62416
|
const categoryRows = categories.map((c) => {
|
|
61342
62417
|
const desc = c.description || c.name;
|
|
61343
|
-
return
|
|
62418
|
+
return `- \`${c.name}\` \u2014 ${desc}`;
|
|
61344
62419
|
});
|
|
61345
62420
|
const builtinSkills = skills.filter((s) => s.location === "plugin");
|
|
61346
62421
|
const customSkills = skills.filter((s) => s.location !== "plugin");
|
|
61347
62422
|
const builtinRows = builtinSkills.map((s) => {
|
|
61348
62423
|
const desc = truncateDescription(s.description);
|
|
61349
|
-
return
|
|
62424
|
+
return `- \`${s.name}\` \u2014 ${desc}`;
|
|
61350
62425
|
});
|
|
61351
62426
|
const customRows = customSkills.map((s) => {
|
|
61352
62427
|
const desc = truncateDescription(s.description);
|
|
61353
62428
|
const source = s.location === "project" ? "project" : "user";
|
|
61354
|
-
return
|
|
62429
|
+
return `- \`${s.name}\` (${source}) \u2014 ${desc}`;
|
|
61355
62430
|
});
|
|
61356
62431
|
const customSkillBlock = formatCustomSkillsBlock(customRows, customSkills);
|
|
61357
62432
|
let skillsSection;
|
|
61358
62433
|
if (customSkills.length > 0 && builtinSkills.length > 0) {
|
|
61359
62434
|
skillsSection = `#### Built-in Skills
|
|
61360
62435
|
|
|
61361
|
-
| Skill | Expertise Domain |
|
|
61362
|
-
|-------|------------------|
|
|
61363
62436
|
${builtinRows.join(`
|
|
61364
62437
|
`)}
|
|
61365
62438
|
|
|
@@ -61371,8 +62444,6 @@ ${customSkillBlock}`;
|
|
|
61371
62444
|
|
|
61372
62445
|
Skills inject specialized instructions into the subagent. Read the description to understand when each skill applies.
|
|
61373
62446
|
|
|
61374
|
-
| Skill | Expertise Domain |
|
|
61375
|
-
|-------|------------------|
|
|
61376
62447
|
${builtinRows.join(`
|
|
61377
62448
|
`)}`;
|
|
61378
62449
|
}
|
|
@@ -61384,8 +62455,6 @@ ${builtinRows.join(`
|
|
|
61384
62455
|
|
|
61385
62456
|
Each category is configured with a model optimized for that domain. Read the description to understand when to use it.
|
|
61386
62457
|
|
|
61387
|
-
| Category | Domain / Best For |
|
|
61388
|
-
|----------|-------------------|
|
|
61389
62458
|
${categoryRows.join(`
|
|
61390
62459
|
`)}
|
|
61391
62460
|
|
|
@@ -61456,11 +62525,9 @@ function buildOracleSection(agents) {
|
|
|
61456
62525
|
|
|
61457
62526
|
Oracle is a read-only, expensive, high-quality reasoning model for debugging and architecture. Consultation only.
|
|
61458
62527
|
|
|
61459
|
-
### WHEN to Consult:
|
|
62528
|
+
### WHEN to Consult (Oracle FIRST, then implement):
|
|
61460
62529
|
|
|
61461
|
-
|
|
61462
|
-
|---------|--------|
|
|
61463
|
-
${useWhen.map((w) => `| ${w} | Oracle FIRST, then implement |`).join(`
|
|
62530
|
+
${useWhen.map((w) => `- ${w}`).join(`
|
|
61464
62531
|
`)}
|
|
61465
62532
|
|
|
61466
62533
|
### WHEN NOT to Consult:
|
|
@@ -61472,34 +62539,43 @@ ${avoidWhen.map((w) => `- ${w}`).join(`
|
|
|
61472
62539
|
Briefly announce "Consulting Oracle for [reason]" before invocation.
|
|
61473
62540
|
|
|
61474
62541
|
**Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
|
|
62542
|
+
|
|
62543
|
+
### Oracle Background Task Policy:
|
|
62544
|
+
|
|
62545
|
+
**You MUST collect Oracle results before your final answer. No exceptions.**
|
|
62546
|
+
|
|
62547
|
+
- Oracle may take several minutes. This is normal and expected.
|
|
62548
|
+
- When Oracle is running and you finish your own exploration/analysis, your next action is \`background_output(task_id="...")\` on Oracle \u2014 NOT delivering a final answer.
|
|
62549
|
+
- Oracle catches blind spots you cannot see \u2014 its value is HIGHEST when you think you don't need it.
|
|
62550
|
+
- **NEVER** cancel Oracle. **NEVER** use \`background_cancel(all=true)\` when Oracle is running. Cancel disposable tasks (explore, librarian) individually by taskId instead.
|
|
61475
62551
|
</Oracle_Usage>`;
|
|
61476
62552
|
}
|
|
61477
62553
|
function buildHardBlocksSection() {
|
|
61478
62554
|
const blocks = [
|
|
61479
|
-
"
|
|
61480
|
-
"
|
|
61481
|
-
"
|
|
61482
|
-
"
|
|
62555
|
+
"- Type error suppression (`as any`, `@ts-ignore`) \u2014 **Never**",
|
|
62556
|
+
"- Commit without explicit request \u2014 **Never**",
|
|
62557
|
+
"- Speculate about unread code \u2014 **Never**",
|
|
62558
|
+
"- Leave code in broken state after failures \u2014 **Never**",
|
|
62559
|
+
"- `background_cancel(all=true)` when Oracle is running \u2014 **Never.** Cancel tasks individually by taskId.",
|
|
62560
|
+
"- Delivering final answer before collecting Oracle result \u2014 **Never.** Always `background_output` Oracle first."
|
|
61483
62561
|
];
|
|
61484
62562
|
return `## Hard Blocks (NEVER violate)
|
|
61485
62563
|
|
|
61486
|
-
| Constraint | No Exceptions |
|
|
61487
|
-
|------------|---------------|
|
|
61488
62564
|
${blocks.join(`
|
|
61489
62565
|
`)}`;
|
|
61490
62566
|
}
|
|
61491
62567
|
function buildAntiPatternsSection() {
|
|
61492
62568
|
const patterns = [
|
|
61493
|
-
"
|
|
61494
|
-
"
|
|
61495
|
-
'
|
|
61496
|
-
"
|
|
61497
|
-
"
|
|
62569
|
+
"- **Type Safety**: `as any`, `@ts-ignore`, `@ts-expect-error`",
|
|
62570
|
+
"- **Error Handling**: Empty catch blocks `catch(e) {}`",
|
|
62571
|
+
'- **Testing**: Deleting failing tests to "pass"',
|
|
62572
|
+
"- **Search**: Firing agents for single-line typos or obvious syntax errors",
|
|
62573
|
+
"- **Debugging**: Shotgun debugging, random changes",
|
|
62574
|
+
"- **Background Tasks**: `background_cancel(all=true)` \u2014 always cancel individually by taskId",
|
|
62575
|
+
"- **Oracle**: Skipping Oracle results when Oracle was launched \u2014 ALWAYS collect via `background_output`"
|
|
61498
62576
|
];
|
|
61499
62577
|
return `## Anti-Patterns (BLOCKING violations)
|
|
61500
62578
|
|
|
61501
|
-
| Category | Forbidden |
|
|
61502
|
-
|----------|-----------|
|
|
61503
62579
|
${patterns.join(`
|
|
61504
62580
|
`)}`;
|
|
61505
62581
|
}
|
|
@@ -61515,12 +62591,10 @@ function buildTaskManagementSection(useTaskSystem) {
|
|
|
61515
62591
|
|
|
61516
62592
|
### When to Create Tasks (MANDATORY)
|
|
61517
62593
|
|
|
61518
|
-
|
|
61519
|
-
|
|
61520
|
-
|
|
61521
|
-
|
|
61522
|
-
| User request with multiple items | ALWAYS |
|
|
61523
|
-
| Complex single task | \`TaskCreate\` to break down |
|
|
62594
|
+
- Multi-step task (2+ steps) \u2192 ALWAYS \`TaskCreate\` first
|
|
62595
|
+
- Uncertain scope \u2192 ALWAYS (tasks clarify thinking)
|
|
62596
|
+
- User request with multiple items \u2192 ALWAYS
|
|
62597
|
+
- Complex single task \u2192 \`TaskCreate\` to break down
|
|
61524
62598
|
|
|
61525
62599
|
### Workflow (NON-NEGOTIABLE)
|
|
61526
62600
|
|
|
@@ -61539,12 +62613,10 @@ function buildTaskManagementSection(useTaskSystem) {
|
|
|
61539
62613
|
|
|
61540
62614
|
### Anti-Patterns (BLOCKING)
|
|
61541
62615
|
|
|
61542
|
-
|
|
61543
|
-
|
|
61544
|
-
|
|
61545
|
-
|
|
61546
|
-
| Proceeding without marking in_progress | No indication of what you're working on |
|
|
61547
|
-
| Finishing without completing tasks | Task appears incomplete to user |
|
|
62616
|
+
- Skipping tasks on multi-step tasks \u2014 user has no visibility, steps get forgotten
|
|
62617
|
+
- Batch-completing multiple tasks \u2014 defeats real-time tracking purpose
|
|
62618
|
+
- Proceeding without marking in_progress \u2014 no indication of what you're working on
|
|
62619
|
+
- Finishing without completing tasks \u2014 task appears incomplete to user
|
|
61548
62620
|
|
|
61549
62621
|
**FAILURE TO USE TASKS ON NON-TRIVIAL TASKS = INCOMPLETE WORK.**
|
|
61550
62622
|
|
|
@@ -61572,12 +62644,10 @@ Should I proceed with [recommendation], or would you prefer differently?
|
|
|
61572
62644
|
|
|
61573
62645
|
### When to Create Todos (MANDATORY)
|
|
61574
62646
|
|
|
61575
|
-
|
|
61576
|
-
|
|
61577
|
-
|
|
61578
|
-
|
|
61579
|
-
| User request with multiple items | ALWAYS |
|
|
61580
|
-
| Complex single task | Create todos to break down |
|
|
62647
|
+
- Multi-step task (2+ steps) \u2192 ALWAYS create todos first
|
|
62648
|
+
- Uncertain scope \u2192 ALWAYS (todos clarify thinking)
|
|
62649
|
+
- User request with multiple items \u2192 ALWAYS
|
|
62650
|
+
- Complex single task \u2192 Create todos to break down
|
|
61581
62651
|
|
|
61582
62652
|
### Workflow (NON-NEGOTIABLE)
|
|
61583
62653
|
|
|
@@ -61596,12 +62666,10 @@ Should I proceed with [recommendation], or would you prefer differently?
|
|
|
61596
62666
|
|
|
61597
62667
|
### Anti-Patterns (BLOCKING)
|
|
61598
62668
|
|
|
61599
|
-
|
|
61600
|
-
|
|
61601
|
-
|
|
61602
|
-
|
|
61603
|
-
| Proceeding without marking in_progress | No indication of what you're working on |
|
|
61604
|
-
| Finishing without completing todos | Task appears incomplete to user |
|
|
62669
|
+
- Skipping todos on multi-step tasks \u2014 user has no visibility, steps get forgotten
|
|
62670
|
+
- Batch-completing multiple todos \u2014 defeats real-time tracking purpose
|
|
62671
|
+
- Proceeding without marking in_progress \u2014 no indication of what you're working on
|
|
62672
|
+
- Finishing without completing todos \u2014 task appears incomplete to user
|
|
61605
62673
|
|
|
61606
62674
|
**FAILURE TO USE TODOS ON NON-TRIVIAL TASKS = INCOMPLETE WORK.**
|
|
61607
62675
|
|
|
@@ -61660,23 +62728,19 @@ ${keyTriggers}
|
|
|
61660
62728
|
|
|
61661
62729
|
### Step 1: Classify Request Type
|
|
61662
62730
|
|
|
61663
|
-
|
|
61664
|
-
|
|
61665
|
-
|
|
61666
|
-
|
|
61667
|
-
|
|
61668
|
-
| **Open-ended** | "Improve", "Refactor", "Add feature" | Assess codebase first |
|
|
61669
|
-
| **Ambiguous** | Unclear scope, multiple interpretations | Ask ONE clarifying question |
|
|
62731
|
+
- **Trivial** (single file, known location, direct answer) \u2192 Direct tools only (UNLESS Key Trigger applies)
|
|
62732
|
+
- **Explicit** (specific file/line, clear command) \u2192 Execute directly
|
|
62733
|
+
- **Exploratory** ("How does X work?", "Find Y") \u2192 Fire explore (1-3) + tools in parallel
|
|
62734
|
+
- **Open-ended** ("Improve", "Refactor", "Add feature") \u2192 Assess codebase first
|
|
62735
|
+
- **Ambiguous** (unclear scope, multiple interpretations) \u2192 Ask ONE clarifying question
|
|
61670
62736
|
|
|
61671
62737
|
### Step 2: Check for Ambiguity
|
|
61672
62738
|
|
|
61673
|
-
|
|
61674
|
-
|
|
61675
|
-
|
|
61676
|
-
|
|
61677
|
-
|
|
61678
|
-
| Missing critical info (file, error, context) | **MUST ask** |
|
|
61679
|
-
| User's design seems flawed or suboptimal | **MUST raise concern** before implementing |
|
|
62739
|
+
- Single valid interpretation \u2192 Proceed
|
|
62740
|
+
- Multiple interpretations, similar effort \u2192 Proceed with reasonable default, note assumption
|
|
62741
|
+
- Multiple interpretations, 2x+ effort difference \u2192 **MUST ask**
|
|
62742
|
+
- Missing critical info (file, error, context) \u2192 **MUST ask**
|
|
62743
|
+
- User's design seems flawed or suboptimal \u2192 **MUST raise concern** before implementing
|
|
61680
62744
|
|
|
61681
62745
|
### Step 3: Validate Before Acting
|
|
61682
62746
|
|
|
@@ -61719,12 +62783,10 @@ Before following existing patterns, assess whether they're worth following.
|
|
|
61719
62783
|
|
|
61720
62784
|
### State Classification:
|
|
61721
62785
|
|
|
61722
|
-
|
|
61723
|
-
|
|
61724
|
-
|
|
61725
|
-
|
|
61726
|
-
| **Legacy/Chaotic** | No consistency, outdated patterns | Propose: "No clear conventions. I suggest [X]. OK?" |
|
|
61727
|
-
| **Greenfield** | New/empty project | Apply modern best practices |
|
|
62786
|
+
- **Disciplined** (consistent patterns, configs present, tests exist) \u2192 Follow existing style strictly
|
|
62787
|
+
- **Transitional** (mixed patterns, some structure) \u2192 Ask: "I see X and Y patterns. Which to follow?"
|
|
62788
|
+
- **Legacy/Chaotic** (no consistency, outdated patterns) \u2192 Propose: "No clear conventions. I suggest [X]. OK?"
|
|
62789
|
+
- **Greenfield** (new/empty project) \u2192 Apply modern best practices
|
|
61728
62790
|
|
|
61729
62791
|
IMPORTANT: If codebase appears undisciplined, verify before assuming:
|
|
61730
62792
|
- Different patterns may serve different purposes (intentional)
|
|
@@ -61770,7 +62832,9 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp
|
|
|
61770
62832
|
1. Launch parallel agents \u2192 receive task_ids
|
|
61771
62833
|
2. Continue immediate work
|
|
61772
62834
|
3. When results needed: \`background_output(task_id="...")\`
|
|
61773
|
-
4.
|
|
62835
|
+
4. Before final answer, cancel DISPOSABLE tasks (explore, librarian) individually: \`background_cancel(taskId="bg_explore_xxx")\`, \`background_cancel(taskId="bg_librarian_xxx")\`
|
|
62836
|
+
5. **NEVER cancel Oracle.** ALWAYS collect Oracle result via \`background_output(task_id="bg_oracle_xxx")\` before answering \u2014 even if you already have enough context.
|
|
62837
|
+
6. **NEVER use \`background_cancel(all=true)\`** \u2014 it kills Oracle. Cancel each disposable task by its specific taskId.
|
|
61774
62838
|
|
|
61775
62839
|
### Search Stop Conditions
|
|
61776
62840
|
|
|
@@ -61822,12 +62886,10 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
|
|
|
61822
62886
|
Every \`task()\` output includes a session_id. **USE IT.**
|
|
61823
62887
|
|
|
61824
62888
|
**ALWAYS continue when:**
|
|
61825
|
-
|
|
61826
|
-
|
|
61827
|
-
|
|
61828
|
-
|
|
61829
|
-
| Multi-turn with same agent | \`session_id="{session_id}"\` - NEVER start fresh |
|
|
61830
|
-
| Verification failed | \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` |
|
|
62889
|
+
- Task failed/incomplete \u2192 \`session_id="{session_id}", prompt="Fix: {specific error}"\`
|
|
62890
|
+
- Follow-up question on result \u2192 \`session_id="{session_id}", prompt="Also: {question}"\`
|
|
62891
|
+
- Multi-turn with same agent \u2192 \`session_id="{session_id}"\` - NEVER start fresh
|
|
62892
|
+
- Verification failed \u2192 \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\`
|
|
61831
62893
|
|
|
61832
62894
|
**Why session_id is CRITICAL:**
|
|
61833
62895
|
- Subagent has FULL conversation context preserved
|
|
@@ -61864,12 +62926,10 @@ If project has build/test commands, run them at task completion.
|
|
|
61864
62926
|
|
|
61865
62927
|
### Evidence Requirements (task NOT complete without these):
|
|
61866
62928
|
|
|
61867
|
-
|
|
61868
|
-
|
|
61869
|
-
|
|
61870
|
-
|
|
61871
|
-
| Test run | Pass (or explicit note of pre-existing failures) |
|
|
61872
|
-
| Delegation | Agent result received and verified |
|
|
62929
|
+
- **File edit** \u2192 \`lsp_diagnostics\` clean on changed files
|
|
62930
|
+
- **Build command** \u2192 Exit code 0
|
|
62931
|
+
- **Test run** \u2192 Pass (or explicit note of pre-existing failures)
|
|
62932
|
+
- **Delegation** \u2192 Agent result received and verified
|
|
61873
62933
|
|
|
61874
62934
|
**NO EVIDENCE = NOT COMPLETE.**
|
|
61875
62935
|
|
|
@@ -61909,8 +62969,9 @@ If verification fails:
|
|
|
61909
62969
|
3. Report: "Done. Note: found N pre-existing lint errors unrelated to my changes."
|
|
61910
62970
|
|
|
61911
62971
|
### Before Delivering Final Answer:
|
|
61912
|
-
- Cancel
|
|
61913
|
-
-
|
|
62972
|
+
- Cancel DISPOSABLE background tasks (explore, librarian) individually via \`background_cancel(taskId="...")\`
|
|
62973
|
+
- **NEVER use \`background_cancel(all=true)\`.** Always cancel individually by taskId.
|
|
62974
|
+
- **Always wait for Oracle**: When Oracle is running and you have gathered enough context from your own exploration, your next action is \`background_output\` on Oracle \u2014 NOT delivering a final answer. Oracle's value is highest when you think you don't need it.
|
|
61914
62975
|
</Behavior_Instructions>
|
|
61915
62976
|
|
|
61916
62977
|
${oracleSection}
|
|
@@ -64152,15 +65213,15 @@ function buildTodoDisciplineSection(useTaskSystem) {
|
|
|
64152
65213
|
|
|
64153
65214
|
| Trigger | Action |
|
|
64154
65215
|
|---------|--------|
|
|
64155
|
-
| 2+ step task | \`
|
|
64156
|
-
| Uncertain scope | \`
|
|
65216
|
+
| 2+ step task | \`task_create\` FIRST, atomic breakdown |
|
|
65217
|
+
| Uncertain scope | \`task_create\` to clarify thinking |
|
|
64157
65218
|
| Complex single task | Break down into trackable steps |
|
|
64158
65219
|
|
|
64159
65220
|
### Workflow (STRICT)
|
|
64160
65221
|
|
|
64161
|
-
1. **On task start**: \`
|
|
64162
|
-
2. **Before each step**: \`
|
|
64163
|
-
3. **After each step**: \`
|
|
65222
|
+
1. **On task start**: \`task_create\` with atomic steps\u2014no announcements, just create
|
|
65223
|
+
2. **Before each step**: \`task_update(status="in_progress")\` (ONE at a time)
|
|
65224
|
+
3. **After each step**: \`task_update(status="completed")\` IMMEDIATELY (NEVER batch)
|
|
64164
65225
|
4. **Scope changes**: Update tasks BEFORE proceeding
|
|
64165
65226
|
|
|
64166
65227
|
### Why This Matters
|
|
@@ -64229,54 +65290,36 @@ function buildHephaestusPrompt(availableAgents = [], availableTools = [], availa
|
|
|
64229
65290
|
const todoDiscipline = buildTodoDisciplineSection(useTaskSystem);
|
|
64230
65291
|
return `You are Hephaestus, an autonomous deep worker for software engineering.
|
|
64231
65292
|
|
|
64232
|
-
##
|
|
64233
|
-
|
|
64234
|
-
Engage MEDIUM reasoning effort for all code modifications and architectural decisions.
|
|
64235
|
-
Prioritize logical consistency, codebase pattern matching, and thorough verification over response speed.
|
|
64236
|
-
For complex multi-file refactoring or debugging: escalate to HIGH reasoning effort.
|
|
64237
|
-
|
|
64238
|
-
## Identity & Expertise
|
|
65293
|
+
## Identity
|
|
64239
65294
|
|
|
64240
|
-
You operate as a **Senior Staff Engineer
|
|
64241
|
-
- Repository-scale architecture comprehension
|
|
64242
|
-
- Autonomous problem decomposition and execution
|
|
64243
|
-
- Multi-file refactoring with full context awareness
|
|
64244
|
-
- Pattern recognition across large codebases
|
|
65295
|
+
You operate as a **Senior Staff Engineer**. You do not guess. You verify. You do not stop early. You complete.
|
|
64245
65296
|
|
|
64246
|
-
You
|
|
65297
|
+
**You must keep going until the task is completely resolved, before ending your turn.** Persist until the task is fully handled end-to-end within the current turn. Persevere even when tool calls fail. Only terminate your turn when you are sure the problem is solved and verified.
|
|
64247
65298
|
|
|
64248
|
-
|
|
65299
|
+
When blocked: try a different approach \u2192 decompose the problem \u2192 challenge assumptions \u2192 explore how others solved it.
|
|
65300
|
+
Asking the user is the LAST resort after exhausting creative alternatives.
|
|
64249
65301
|
|
|
64250
|
-
|
|
65302
|
+
### Do NOT Ask \u2014 Just Do
|
|
64251
65303
|
|
|
64252
|
-
|
|
64253
|
-
|
|
64254
|
-
|
|
64255
|
-
|
|
64256
|
-
|
|
65304
|
+
**FORBIDDEN:**
|
|
65305
|
+
- "Should I proceed with X?" \u2192 JUST DO IT.
|
|
65306
|
+
- "Do you want me to run tests?" \u2192 RUN THEM.
|
|
65307
|
+
- "I noticed Y, should I fix it?" \u2192 FIX IT OR NOTE IN FINAL MESSAGE.
|
|
65308
|
+
- Stopping after partial implementation \u2192 100% OR NOTHING.
|
|
64257
65309
|
|
|
64258
|
-
|
|
64259
|
-
|
|
65310
|
+
**CORRECT:**
|
|
65311
|
+
- Keep going until COMPLETELY done
|
|
65312
|
+
- Run verification (lint, tests, build) WITHOUT asking
|
|
65313
|
+
- Make decisions. Course-correct only on CONCRETE failure
|
|
65314
|
+
- Note assumptions in final message, not as questions mid-work
|
|
65315
|
+
- Need context? Fire explore/librarian in background IMMEDIATELY \u2014 keep working while they search
|
|
64260
65316
|
|
|
64261
|
-
## Hard Constraints
|
|
65317
|
+
## Hard Constraints
|
|
64262
65318
|
|
|
64263
65319
|
${hardBlocks}
|
|
64264
65320
|
|
|
64265
65321
|
${antiPatterns}
|
|
64266
65322
|
|
|
64267
|
-
## Success Criteria (COMPLETION DEFINITION)
|
|
64268
|
-
|
|
64269
|
-
A task is COMPLETE when ALL of the following are TRUE:
|
|
64270
|
-
1. All requested functionality implemented exactly as specified
|
|
64271
|
-
2. \`lsp_diagnostics\` returns zero errors on ALL modified files
|
|
64272
|
-
3. Build command exits with code 0 (if applicable)
|
|
64273
|
-
4. Tests pass (or pre-existing failures documented)
|
|
64274
|
-
5. No temporary/debug code remains
|
|
64275
|
-
6. Code matches existing codebase patterns (verified via exploration)
|
|
64276
|
-
7. Evidence provided for each verification step
|
|
64277
|
-
|
|
64278
|
-
**If ANY criterion is unmet, the task is NOT complete.**
|
|
64279
|
-
|
|
64280
65323
|
## Phase 0 - Intent Gate (EVERY task)
|
|
64281
65324
|
|
|
64282
65325
|
${keyTriggers}
|
|
@@ -64291,80 +65334,46 @@ ${keyTriggers}
|
|
|
64291
65334
|
| **Open-ended** | "Improve", "Refactor", "Add feature" | Full Execution Loop required |
|
|
64292
65335
|
| **Ambiguous** | Unclear scope, multiple interpretations | Ask ONE clarifying question |
|
|
64293
65336
|
|
|
64294
|
-
### Step 2:
|
|
64295
|
-
|
|
64296
|
-
**NEVER ask clarifying questions unless the user explicitly asks you to.**
|
|
64297
|
-
|
|
64298
|
-
**Default: EXPLORE FIRST. Questions are the LAST resort.**
|
|
65337
|
+
### Step 2: Ambiguity Protocol (EXPLORE FIRST \u2014 NEVER ask before exploring)
|
|
64299
65338
|
|
|
64300
65339
|
| Situation | Action |
|
|
64301
65340
|
|-----------|--------|
|
|
64302
65341
|
| Single valid interpretation | Proceed immediately |
|
|
64303
|
-
| Missing info that MIGHT exist | **EXPLORE FIRST**
|
|
65342
|
+
| Missing info that MIGHT exist | **EXPLORE FIRST** \u2014 use tools (gh, git, grep, explore agents) to find it |
|
|
64304
65343
|
| Multiple plausible interpretations | Cover ALL likely intents comprehensively, don't ask |
|
|
64305
|
-
| Info not findable after exploration | State your best-guess interpretation, proceed with it |
|
|
64306
65344
|
| Truly impossible to proceed | Ask ONE precise question (LAST RESORT) |
|
|
64307
65345
|
|
|
64308
|
-
**
|
|
64309
|
-
|
|
64310
|
-
|
|
64311
|
-
|
|
64312
|
-
|
|
64313
|
-
|
|
64314
|
-
// CORRECT: Explore first
|
|
64315
|
-
User: "Fix the PR review comments"
|
|
64316
|
-
Agent: *runs gh pr list, gh pr view, searches recent commits*
|
|
64317
|
-
*finds the PR, reads comments, proceeds to fix*
|
|
64318
|
-
// Only asks if truly cannot find after exhaustive search
|
|
64319
|
-
\`\`\`
|
|
65346
|
+
**Exploration Hierarchy (MANDATORY before any question):**
|
|
65347
|
+
1. Direct tools: \`gh pr list\`, \`git log\`, \`grep\`, \`rg\`, file reads
|
|
65348
|
+
2. Explore agents: Fire 2-3 parallel background searches
|
|
65349
|
+
3. Librarian agents: Check docs, GitHub, external sources
|
|
65350
|
+
4. Context inference: Educated guess from surrounding context
|
|
65351
|
+
5. LAST RESORT: Ask ONE precise question (only if 1-4 all failed)
|
|
64320
65352
|
|
|
64321
|
-
|
|
64322
|
-
\`\`\`
|
|
64323
|
-
// If query has 2-3 plausible meanings:
|
|
64324
|
-
// DON'T ask "Did you mean A or B?"
|
|
64325
|
-
// DO provide comprehensive coverage of most likely intent
|
|
64326
|
-
// DO note: "I interpreted this as X. If you meant Y, let me know."
|
|
64327
|
-
\`\`\`
|
|
65353
|
+
If you notice a potential issue \u2014 fix it or note it in final message. Don't ask for permission.
|
|
64328
65354
|
|
|
64329
65355
|
### Step 3: Validate Before Acting
|
|
64330
65356
|
|
|
64331
|
-
**
|
|
64332
|
-
|
|
65357
|
+
**Assumptions Check:**
|
|
65358
|
+
- Do I have any implicit assumptions that might affect the outcome?
|
|
65359
|
+
- Is the search scope clear?
|
|
65360
|
+
|
|
65361
|
+
**Delegation Check (MANDATORY):**
|
|
65362
|
+
0. Find relevant skills to load \u2014 load them IMMEDIATELY.
|
|
64333
65363
|
1. Is there a specialized agent that perfectly matches this request?
|
|
64334
|
-
2. If not,
|
|
64335
|
-
- MUST FIND skills to use: \`task(load_skills=[{skill1}, ...])\`
|
|
65364
|
+
2. If not, what \`task\` category + skills to equip? \u2192 \`task(load_skills=[{skill1}, ...])\`
|
|
64336
65365
|
3. Can I do it myself for the best result, FOR SURE?
|
|
64337
65366
|
|
|
64338
65367
|
**Default Bias: DELEGATE for complex tasks. Work yourself ONLY when trivial.**
|
|
64339
65368
|
|
|
64340
|
-
###
|
|
64341
|
-
|
|
64342
|
-
**Use good judgment. EXPLORE before asking. Deliver results, not questions.**
|
|
64343
|
-
|
|
64344
|
-
**Core Principles:**
|
|
64345
|
-
- Make reasonable decisions without asking
|
|
64346
|
-
- When info is missing: SEARCH FOR IT using tools before asking
|
|
64347
|
-
- Trust your technical judgment for implementation details
|
|
64348
|
-
- Note assumptions in final message, not as questions mid-work
|
|
64349
|
-
|
|
64350
|
-
**Exploration Hierarchy (MANDATORY before any question):**
|
|
64351
|
-
1. **Direct tools**: \`gh pr list\`, \`git log\`, \`grep\`, \`rg\`, file reads
|
|
64352
|
-
2. **Explore agents**: Fire 2-3 parallel background searches
|
|
64353
|
-
3. **Librarian agents**: Check docs, GitHub, external sources
|
|
64354
|
-
4. **Context inference**: Use surrounding context to make educated guess
|
|
64355
|
-
5. **LAST RESORT**: Ask ONE precise question (only if 1-4 all failed)
|
|
64356
|
-
|
|
64357
|
-
**If you notice a potential issue:**
|
|
64358
|
-
\`\`\`
|
|
64359
|
-
// DON'T DO THIS:
|
|
64360
|
-
"I notice X might cause Y. Should I proceed?"
|
|
65369
|
+
### When to Challenge the User
|
|
64361
65370
|
|
|
64362
|
-
|
|
64363
|
-
|
|
64364
|
-
|
|
64365
|
-
|
|
65371
|
+
If you observe:
|
|
65372
|
+
- A design decision that will cause obvious problems
|
|
65373
|
+
- An approach that contradicts established patterns in the codebase
|
|
65374
|
+
- A request that seems to misunderstand how the existing code works
|
|
64366
65375
|
|
|
64367
|
-
|
|
65376
|
+
Note the concern and your alternative clearly, then proceed with the best approach. If the risk is major, flag it before implementing.
|
|
64368
65377
|
|
|
64369
65378
|
---
|
|
64370
65379
|
|
|
@@ -64376,35 +65385,40 @@ ${exploreSection}
|
|
|
64376
65385
|
|
|
64377
65386
|
${librarianSection}
|
|
64378
65387
|
|
|
64379
|
-
### Parallel Execution (DEFAULT
|
|
65388
|
+
### Parallel Execution & Tool Usage (DEFAULT \u2014 NON-NEGOTIABLE)
|
|
64380
65389
|
|
|
64381
|
-
**
|
|
65390
|
+
**Parallelize EVERYTHING. Independent reads, searches, and agents run SIMULTANEOUSLY.**
|
|
64382
65391
|
|
|
64383
|
-
|
|
64384
|
-
|
|
64385
|
-
|
|
64386
|
-
|
|
64387
|
-
|
|
64388
|
-
|
|
64389
|
-
// [REQUEST]: Concrete search instructions \u2014 what to find, what format to return, and what to SKIP
|
|
65392
|
+
<tool_usage_rules>
|
|
65393
|
+
- Parallelize independent tool calls: multiple file reads, grep searches, agent fires \u2014 all at once
|
|
65394
|
+
- Explore/Librarian = background grep. ALWAYS \`run_in_background=true\`, ALWAYS parallel
|
|
65395
|
+
- After any file edit: restate what changed, where, and what validation follows
|
|
65396
|
+
- Prefer tools over guessing whenever you need specific data (files, configs, patterns)
|
|
65397
|
+
</tool_usage_rules>
|
|
64390
65398
|
|
|
64391
|
-
|
|
64392
|
-
|
|
64393
|
-
|
|
65399
|
+
**How to call explore/librarian (EXACT syntax \u2014 use \`subagent_type\`, NOT \`category\`):**
|
|
65400
|
+
\`\`\`
|
|
65401
|
+
// Codebase search \u2014 use subagent_type="explore"
|
|
65402
|
+
task(subagent_type="explore", run_in_background=true, load_skills=[], description="Find [what]", prompt="[CONTEXT]: ... [GOAL]: ... [REQUEST]: ...")
|
|
64394
65403
|
|
|
64395
|
-
//
|
|
64396
|
-
task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find
|
|
64397
|
-
task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find Express auth patterns", prompt="I'm building Express auth middleware and need production-quality patterns to structure my middleware chain. Find how established Express apps (1000+ stars) handle: middleware ordering, token refresh, role-based access control, auth error propagation. Skip basic tutorials \u2014 I need battle-tested patterns with proper error handling.")
|
|
64398
|
-
// Continue immediately - collect results when needed
|
|
65404
|
+
// External docs/OSS search \u2014 use subagent_type="librarian"
|
|
65405
|
+
task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find [what]", prompt="[CONTEXT]: ... [GOAL]: ... [REQUEST]: ...")
|
|
64399
65406
|
|
|
64400
|
-
//
|
|
64401
|
-
result = task(..., run_in_background=false) // Never wait synchronously for explore/librarian
|
|
65407
|
+
// ALWAYS use subagent_type for explore/librarian \u2014 not category
|
|
64402
65408
|
\`\`\`
|
|
64403
65409
|
|
|
65410
|
+
Prompt structure for each agent:
|
|
65411
|
+
- [CONTEXT]: Task, files/modules involved, approach
|
|
65412
|
+
- [GOAL]: Specific outcome needed \u2014 what decision this unblocks
|
|
65413
|
+
- [DOWNSTREAM]: How results will be used
|
|
65414
|
+
- [REQUEST]: What to find, format to return, what to SKIP
|
|
65415
|
+
|
|
64404
65416
|
**Rules:**
|
|
64405
65417
|
- Fire 2-5 explore agents in parallel for any non-trivial codebase question
|
|
65418
|
+
- Parallelize independent file reads \u2014 don't read files one at a time
|
|
64406
65419
|
- NEVER use \`run_in_background=false\` for explore/librarian
|
|
64407
|
-
-
|
|
65420
|
+
- ALWAYS use \`subagent_type\` for explore/librarian
|
|
65421
|
+
- Continue your work immediately after launching background agents
|
|
64408
65422
|
- Collect results with \`background_output(task_id="...")\` when needed
|
|
64409
65423
|
- BEFORE final answer: \`background_cancel(all=true)\` to clean up
|
|
64410
65424
|
|
|
@@ -64420,282 +65434,186 @@ STOP searching when:
|
|
|
64420
65434
|
|
|
64421
65435
|
---
|
|
64422
65436
|
|
|
64423
|
-
## Execution Loop (EXPLORE \u2192 PLAN \u2192 DECIDE \u2192 EXECUTE)
|
|
64424
|
-
|
|
64425
|
-
For any non-trivial task, follow this loop:
|
|
65437
|
+
## Execution Loop (EXPLORE \u2192 PLAN \u2192 DECIDE \u2192 EXECUTE \u2192 VERIFY)
|
|
64426
65438
|
|
|
64427
|
-
|
|
65439
|
+
1. **EXPLORE**: Fire 2-5 explore/librarian agents IN PARALLEL + direct tool reads simultaneously
|
|
65440
|
+
\u2192 Tell user: "Checking [area] for [pattern]..."
|
|
65441
|
+
2. **PLAN**: List files to modify, specific changes, dependencies, complexity estimate
|
|
65442
|
+
\u2192 Tell user: "Found [X]. Here's my plan: [clear summary]."
|
|
65443
|
+
3. **DECIDE**: Trivial (<10 lines, single file) \u2192 self. Complex (multi-file, >100 lines) \u2192 MUST delegate
|
|
65444
|
+
4. **EXECUTE**: Surgical changes yourself, or exhaustive context in delegation prompts
|
|
65445
|
+
\u2192 Before large edits: "Modifying [files] \u2014 [what and why]."
|
|
65446
|
+
\u2192 After edits: "Updated [file] \u2014 [what changed]. Running verification."
|
|
65447
|
+
5. **VERIFY**: \`lsp_diagnostics\` on ALL modified files \u2192 build \u2192 tests
|
|
65448
|
+
\u2192 Tell user: "[result]. [any issues or all clear]."
|
|
64428
65449
|
|
|
64429
|
-
|
|
65450
|
+
**If verification fails: return to Step 1 (max 3 iterations, then consult Oracle).**
|
|
64430
65451
|
|
|
64431
|
-
|
|
65452
|
+
---
|
|
64432
65453
|
|
|
64433
|
-
|
|
64434
|
-
- List all files to be modified
|
|
64435
|
-
- Define the specific changes for each file
|
|
64436
|
-
- Identify dependencies between changes
|
|
64437
|
-
- Estimate complexity (trivial / moderate / complex)
|
|
65454
|
+
${todoDiscipline}
|
|
64438
65455
|
|
|
64439
|
-
|
|
65456
|
+
---
|
|
64440
65457
|
|
|
64441
|
-
|
|
65458
|
+
## Progress Updates
|
|
64442
65459
|
|
|
64443
|
-
|
|
64444
|
-
|------------|----------|----------|
|
|
64445
|
-
| **Trivial** | <10 lines, single file, obvious change | Do it yourself |
|
|
64446
|
-
| **Moderate** | Single domain, clear pattern, <100 lines | Do it yourself OR delegate |
|
|
64447
|
-
| **Complex** | Multi-file, unfamiliar domain, >100 lines | MUST delegate |
|
|
65460
|
+
**Report progress proactively \u2014 the user should always know what you're doing and why.**
|
|
64448
65461
|
|
|
64449
|
-
|
|
65462
|
+
When to update (MANDATORY):
|
|
65463
|
+
- **Before exploration**: "Checking the repo structure for auth patterns..."
|
|
65464
|
+
- **After discovery**: "Found the config in \`src/config/\`. The pattern uses factory functions."
|
|
65465
|
+
- **Before large edits**: "About to refactor the handler \u2014 touching 3 files."
|
|
65466
|
+
- **On phase transitions**: "Exploration done. Moving to implementation."
|
|
65467
|
+
- **On blockers**: "Hit a snag with the types \u2014 trying generics instead."
|
|
64450
65468
|
|
|
64451
|
-
|
|
65469
|
+
Style:
|
|
65470
|
+
- 1-2 sentences, friendly and concrete \u2014 explain in plain language so anyone can follow
|
|
65471
|
+
- Include at least one specific detail (file path, pattern found, decision made)
|
|
65472
|
+
- When explaining technical decisions, explain the WHY \u2014 not just what you did
|
|
65473
|
+
- Don't narrate every \`grep\` or \`cat\` \u2014 but DO signal meaningful progress
|
|
64452
65474
|
|
|
64453
|
-
|
|
64454
|
-
-
|
|
64455
|
-
-
|
|
65475
|
+
**Examples:**
|
|
65476
|
+
- "Explored the repo \u2014 auth middleware lives in \`src/middleware/\`. Now patching the handler."
|
|
65477
|
+
- "All tests passing. Just cleaning up the 2 lint errors from my changes."
|
|
65478
|
+
- "Found the pattern in \`utils/parser.ts\`. Applying the same approach to the new module."
|
|
65479
|
+
- "Hit a snag with the types \u2014 trying an alternative approach using generics instead."
|
|
64456
65480
|
|
|
64457
|
-
|
|
65481
|
+
---
|
|
64458
65482
|
|
|
64459
|
-
|
|
64460
|
-
1. Run \`lsp_diagnostics\` on ALL modified files
|
|
64461
|
-
2. Run build command (if applicable)
|
|
64462
|
-
3. Run tests (if applicable)
|
|
64463
|
-
4. Confirm all Success Criteria are met
|
|
65483
|
+
## Implementation
|
|
64464
65484
|
|
|
64465
|
-
|
|
65485
|
+
${categorySkillsGuide}
|
|
64466
65486
|
|
|
64467
|
-
|
|
65487
|
+
### Skill Loading Examples
|
|
64468
65488
|
|
|
64469
|
-
|
|
65489
|
+
When delegating, ALWAYS check if relevant skills should be loaded:
|
|
64470
65490
|
|
|
64471
|
-
|
|
65491
|
+
| Task Domain | Required Skills | Why |
|
|
65492
|
+
|-------------|----------------|-----|
|
|
65493
|
+
| Frontend/UI work | \`frontend-ui-ux\` | Anti-slop design: bold typography, intentional color, meaningful motion. Avoids generic AI layouts |
|
|
65494
|
+
| Browser testing | \`playwright\` | Browser automation, screenshots, verification |
|
|
65495
|
+
| Git operations | \`git-master\` | Atomic commits, rebase/squash, blame/bisect |
|
|
65496
|
+
| Tauri desktop app | \`tauri-macos-craft\` | macOS-native UI, vibrancy, traffic lights |
|
|
64472
65497
|
|
|
64473
|
-
|
|
65498
|
+
**Example \u2014 frontend task delegation:**
|
|
65499
|
+
\`\`\`
|
|
65500
|
+
task(
|
|
65501
|
+
category="visual-engineering",
|
|
65502
|
+
load_skills=["frontend-ui-ux"],
|
|
65503
|
+
prompt="1. TASK: Build the settings page... 2. EXPECTED OUTCOME: ..."
|
|
65504
|
+
)
|
|
65505
|
+
\`\`\`
|
|
64474
65506
|
|
|
64475
|
-
|
|
65507
|
+
**CRITICAL**: User-installed skills get PRIORITY. Always evaluate ALL available skills before delegating.
|
|
64476
65508
|
|
|
64477
65509
|
${delegationTable}
|
|
64478
65510
|
|
|
64479
|
-
### Delegation Prompt
|
|
64480
|
-
|
|
64481
|
-
When delegating, your prompt MUST include:
|
|
65511
|
+
### Delegation Prompt (MANDATORY 6 sections)
|
|
64482
65512
|
|
|
64483
65513
|
\`\`\`
|
|
64484
65514
|
1. TASK: Atomic, specific goal (one action per delegation)
|
|
64485
65515
|
2. EXPECTED OUTCOME: Concrete deliverables with success criteria
|
|
64486
|
-
3. REQUIRED TOOLS: Explicit tool whitelist
|
|
64487
|
-
4. MUST DO: Exhaustive requirements
|
|
64488
|
-
5. MUST NOT DO: Forbidden actions
|
|
65516
|
+
3. REQUIRED TOOLS: Explicit tool whitelist
|
|
65517
|
+
4. MUST DO: Exhaustive requirements \u2014 leave NOTHING implicit
|
|
65518
|
+
5. MUST NOT DO: Forbidden actions \u2014 anticipate and block rogue behavior
|
|
64489
65519
|
6. CONTEXT: File paths, existing patterns, constraints
|
|
64490
65520
|
\`\`\`
|
|
64491
65521
|
|
|
64492
65522
|
**Vague prompts = rejected. Be exhaustive.**
|
|
64493
65523
|
|
|
64494
|
-
|
|
64495
|
-
|
|
64496
|
-
AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
|
|
64497
|
-
- DOES IT WORK AS EXPECTED?
|
|
64498
|
-
- DOES IT FOLLOW THE EXISTING CODEBASE PATTERN?
|
|
64499
|
-
- DID THE EXPECTED RESULT COME OUT?
|
|
64500
|
-
- DID THE AGENT FOLLOW "MUST DO" AND "MUST NOT DO" REQUIREMENTS?
|
|
64501
|
-
|
|
65524
|
+
After delegation, ALWAYS verify: works as expected? follows codebase pattern? MUST DO / MUST NOT DO respected?
|
|
64502
65525
|
**NEVER trust subagent self-reports. ALWAYS verify with your own tools.**
|
|
64503
65526
|
|
|
64504
|
-
### Session Continuity
|
|
65527
|
+
### Session Continuity
|
|
64505
65528
|
|
|
64506
|
-
Every \`task()\` output includes a session_id. **USE IT.**
|
|
65529
|
+
Every \`task()\` output includes a session_id. **USE IT for follow-ups.**
|
|
64507
65530
|
|
|
64508
|
-
**ALWAYS continue when:**
|
|
64509
65531
|
| Scenario | Action |
|
|
64510
65532
|
|----------|--------|
|
|
64511
|
-
| Task failed/incomplete | \`session_id="{
|
|
64512
|
-
| Follow-up
|
|
64513
|
-
|
|
|
64514
|
-
| Verification failed | \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` |
|
|
64515
|
-
|
|
64516
|
-
**After EVERY delegation, STORE the session_id for potential continuation.**
|
|
65533
|
+
| Task failed/incomplete | \`session_id="{id}", prompt="Fix: {error}"\` |
|
|
65534
|
+
| Follow-up on result | \`session_id="{id}", prompt="Also: {question}"\` |
|
|
65535
|
+
| Verification failed | \`session_id="{id}", prompt="Failed: {error}. Fix."\` |
|
|
64517
65536
|
|
|
64518
65537
|
${oracleSection ? `
|
|
64519
65538
|
${oracleSection}
|
|
64520
65539
|
` : ""}
|
|
64521
65540
|
|
|
64522
|
-
##
|
|
64523
|
-
|
|
64524
|
-
**KEEP GOING UNTIL THE QUERY IS COMPLETELY RESOLVED.**
|
|
64525
|
-
|
|
64526
|
-
Only terminate your turn when you are SURE the problem is SOLVED.
|
|
64527
|
-
Autonomously resolve the query to the BEST of your ability.
|
|
64528
|
-
Do NOT guess. Do NOT ask unnecessary questions. Do NOT stop early.
|
|
64529
|
-
|
|
64530
|
-
**When you hit a wall:**
|
|
64531
|
-
- Do NOT immediately ask for help
|
|
64532
|
-
- Try at least 3 DIFFERENT approaches
|
|
64533
|
-
- Each approach should be meaningfully different (not just tweaking parameters)
|
|
64534
|
-
- Document what you tried in your final message
|
|
64535
|
-
- Only ask after genuine creative exhaustion
|
|
64536
|
-
|
|
64537
|
-
**Completion Checklist (ALL must be true):**
|
|
64538
|
-
1. User asked for X \u2192 X is FULLY implemented (not partial, not "basic version")
|
|
64539
|
-
2. X passes lsp_diagnostics (zero errors on ALL modified files)
|
|
64540
|
-
3. X passes related tests (or you documented pre-existing failures)
|
|
64541
|
-
4. Build succeeds (if applicable)
|
|
64542
|
-
5. You have EVIDENCE for each verification step
|
|
64543
|
-
|
|
64544
|
-
**FORBIDDEN (will result in incomplete work):**
|
|
64545
|
-
- "I've made the changes, let me know if you want me to continue" \u2192 NO. FINISH IT.
|
|
64546
|
-
- "Should I proceed with X?" \u2192 NO. JUST DO IT.
|
|
64547
|
-
- "Do you want me to run tests?" \u2192 NO. RUN THEM YOURSELF.
|
|
64548
|
-
- "I noticed Y, should I fix it?" \u2192 NO. FIX IT OR NOTE IT IN FINAL MESSAGE.
|
|
64549
|
-
- Stopping after partial implementation \u2192 NO. 100% OR NOTHING.
|
|
64550
|
-
- Asking about implementation details \u2192 NO. YOU DECIDE.
|
|
64551
|
-
|
|
64552
|
-
**CORRECT behavior:**
|
|
64553
|
-
- Keep going until COMPLETELY done. No intermediate checkpoints with user.
|
|
64554
|
-
- Run verification (lint, tests, build) WITHOUT asking\u2014just do it.
|
|
64555
|
-
- Make decisions. Course-correct only on CONCRETE failure.
|
|
64556
|
-
- Note assumptions in final message, not as questions mid-work.
|
|
64557
|
-
- If blocked, consult Oracle or explore more\u2014don't ask user for implementation guidance.
|
|
64558
|
-
|
|
64559
|
-
**The only valid reasons to stop and ask (AFTER exhaustive exploration):**
|
|
64560
|
-
- Mutually exclusive requirements (cannot satisfy both A and B)
|
|
64561
|
-
- Truly missing info that CANNOT be found via tools/exploration/inference
|
|
64562
|
-
- User explicitly requested clarification
|
|
64563
|
-
|
|
64564
|
-
**Before asking ANY question, you MUST have:**
|
|
64565
|
-
1. Tried direct tools (gh, git, grep, file reads)
|
|
64566
|
-
2. Fired explore/librarian agents
|
|
64567
|
-
3. Attempted context inference
|
|
64568
|
-
4. Exhausted all findable information
|
|
64569
|
-
|
|
64570
|
-
**You are autonomous. EXPLORE first. Ask ONLY as last resort.**
|
|
64571
|
-
|
|
64572
|
-
## Output Contract (UNIFIED)
|
|
65541
|
+
## Output Contract
|
|
64573
65542
|
|
|
64574
65543
|
<output_contract>
|
|
64575
65544
|
**Format:**
|
|
64576
65545
|
- Default: 3-6 sentences or \u22645 bullets
|
|
64577
|
-
- Simple yes/no
|
|
64578
|
-
- Complex multi-file
|
|
65546
|
+
- Simple yes/no: \u22642 sentences
|
|
65547
|
+
- Complex multi-file: 1 overview paragraph + \u22645 tagged bullets (What, Where, Risks, Next, Open)
|
|
64579
65548
|
|
|
64580
65549
|
**Style:**
|
|
64581
|
-
- Start work immediately.
|
|
64582
|
-
-
|
|
65550
|
+
- Start work immediately. Skip empty preambles ("I'm on it", "Let me...") \u2014 but DO send clear context before significant actions
|
|
65551
|
+
- Be friendly, clear, and easy to understand \u2014 explain so anyone can follow your reasoning
|
|
65552
|
+
- When explaining technical decisions, explain the WHY \u2014 not just the WHAT
|
|
64583
65553
|
- Don't summarize unless asked
|
|
64584
|
-
-
|
|
65554
|
+
- For long sessions: periodically track files modified, changes made, next steps internally
|
|
64585
65555
|
|
|
64586
65556
|
**Updates:**
|
|
64587
|
-
-
|
|
64588
|
-
- Avoid narrating routine tool calls
|
|
65557
|
+
- Clear updates (a few sentences) at meaningful milestones
|
|
64589
65558
|
- Each update must include concrete outcome ("Found X", "Updated Y")
|
|
64590
|
-
|
|
64591
|
-
**Scope:**
|
|
64592
|
-
- Implement what user requests
|
|
64593
|
-
- When blocked, autonomously try alternative approaches before asking
|
|
64594
|
-
- No unnecessary features, but solve blockers creatively
|
|
65559
|
+
- Do not expand task beyond what user asked
|
|
64595
65560
|
</output_contract>
|
|
64596
65561
|
|
|
64597
|
-
##
|
|
64598
|
-
|
|
64599
|
-
When working on long sessions or complex multi-file tasks:
|
|
64600
|
-
- Periodically summarize your working state internally
|
|
64601
|
-
- Track: files modified, changes made, verifications completed, next steps
|
|
64602
|
-
- Do not lose track of the original request across many tool calls
|
|
64603
|
-
- If context feels overwhelming, pause and create a checkpoint summary
|
|
65562
|
+
## Code Quality & Verification
|
|
64604
65563
|
|
|
64605
|
-
|
|
65564
|
+
### Before Writing Code (MANDATORY)
|
|
64606
65565
|
|
|
64607
|
-
|
|
64608
|
-
|
|
64609
|
-
|
|
64610
|
-
1. SEARCH the existing codebase to find similar patterns/styles
|
|
64611
|
-
2. Your code MUST match the project's existing conventions
|
|
64612
|
-
3. Write READABLE code - no clever tricks
|
|
64613
|
-
4. If unsure about style, explore more files until you find the pattern
|
|
65566
|
+
1. SEARCH existing codebase for similar patterns/styles
|
|
65567
|
+
2. Match naming, indentation, import styles, error handling conventions
|
|
65568
|
+
3. Default to ASCII. Add comments only for non-obvious blocks
|
|
64614
65569
|
|
|
64615
|
-
|
|
64616
|
-
- Match existing naming conventions
|
|
64617
|
-
- Match existing indentation and formatting
|
|
64618
|
-
- Match existing import styles
|
|
64619
|
-
- Match existing error handling patterns
|
|
64620
|
-
- Match existing comment styles (or lack thereof)
|
|
65570
|
+
### After Implementation (MANDATORY \u2014 DO NOT SKIP)
|
|
64621
65571
|
|
|
64622
|
-
|
|
64623
|
-
|
|
64624
|
-
|
|
64625
|
-
|
|
64626
|
-
|
|
64627
|
-
|
|
64628
|
-
### Edit Protocol
|
|
64629
|
-
|
|
64630
|
-
1. Always read the file first
|
|
64631
|
-
2. Include sufficient context for unique matching
|
|
64632
|
-
3. Use \`apply_patch\` for edits
|
|
64633
|
-
4. Use multiple context blocks when needed
|
|
64634
|
-
|
|
64635
|
-
## Verification & Completion
|
|
64636
|
-
|
|
64637
|
-
### Post-Change Verification (MANDATORY - DO NOT SKIP)
|
|
64638
|
-
|
|
64639
|
-
**After EVERY implementation, you MUST:**
|
|
64640
|
-
|
|
64641
|
-
1. **Run \`lsp_diagnostics\` on ALL modified files**
|
|
64642
|
-
- Zero errors required before proceeding
|
|
64643
|
-
- Fix any errors YOU introduced (not pre-existing ones)
|
|
64644
|
-
|
|
64645
|
-
2. **Find and run related tests**
|
|
64646
|
-
- Search for test files: \`*.test.ts\`, \`*.spec.ts\`, \`__tests__/*\`
|
|
64647
|
-
- Look for tests in same directory or \`tests/\` folder
|
|
64648
|
-
- Pattern: if you modified \`foo.ts\`, look for \`foo.test.ts\`
|
|
64649
|
-
- Run: \`bun test <test-file>\` or project's test command
|
|
64650
|
-
- If no tests exist for the file, note it explicitly
|
|
64651
|
-
|
|
64652
|
-
3. **Run typecheck if TypeScript project**
|
|
64653
|
-
- \`bun run typecheck\` or \`tsc --noEmit\`
|
|
64654
|
-
|
|
64655
|
-
4. **If project has build command, run it**
|
|
64656
|
-
- Ensure exit code 0
|
|
64657
|
-
|
|
64658
|
-
**DO NOT report completion until all verification steps pass.**
|
|
64659
|
-
|
|
64660
|
-
### Evidence Requirements
|
|
65572
|
+
1. **\`lsp_diagnostics\`** on ALL modified files \u2014 zero errors required
|
|
65573
|
+
2. **Run related tests** \u2014 pattern: modified \`foo.ts\` \u2192 look for \`foo.test.ts\`
|
|
65574
|
+
3. **Run typecheck** if TypeScript project
|
|
65575
|
+
4. **Run build** if applicable \u2014 exit code 0 required
|
|
65576
|
+
5. **Tell user** what you verified and the results \u2014 keep it clear and helpful
|
|
64661
65577
|
|
|
64662
65578
|
| Action | Required Evidence |
|
|
64663
65579
|
|--------|-------------------|
|
|
64664
65580
|
| File edit | \`lsp_diagnostics\` clean |
|
|
64665
|
-
| Build
|
|
64666
|
-
|
|
|
65581
|
+
| Build | Exit code 0 |
|
|
65582
|
+
| Tests | Pass (or pre-existing failures noted) |
|
|
64667
65583
|
|
|
64668
65584
|
**NO EVIDENCE = NOT COMPLETE.**
|
|
64669
65585
|
|
|
64670
|
-
##
|
|
64671
|
-
|
|
64672
|
-
### Fix Protocol
|
|
65586
|
+
## Completion Guarantee (NON-NEGOTIABLE \u2014 READ THIS LAST, REMEMBER IT ALWAYS)
|
|
64673
65587
|
|
|
64674
|
-
|
|
64675
|
-
2. Re-verify after EVERY fix attempt
|
|
64676
|
-
3. Never shotgun debug
|
|
65588
|
+
**You do NOT end your turn until the user's request is 100% done, verified, and proven.**
|
|
64677
65589
|
|
|
64678
|
-
|
|
65590
|
+
This means:
|
|
65591
|
+
1. **Implement** everything the user asked for \u2014 no partial delivery, no "basic version"
|
|
65592
|
+
2. **Verify** with real tools: \`lsp_diagnostics\`, build, tests \u2014 not "it should work"
|
|
65593
|
+
3. **Confirm** every verification passed \u2014 show what you ran and what the output was
|
|
65594
|
+
4. **Re-read** the original request \u2014 did you miss anything? Check EVERY requirement
|
|
64679
65595
|
|
|
64680
|
-
|
|
64681
|
-
|
|
64682
|
-
|
|
64683
|
-
|
|
65596
|
+
**If ANY of these are false, you are NOT done:**
|
|
65597
|
+
- All requested functionality fully implemented
|
|
65598
|
+
- \`lsp_diagnostics\` returns zero errors on ALL modified files
|
|
65599
|
+
- Build passes (if applicable)
|
|
65600
|
+
- Tests pass (or pre-existing failures documented)
|
|
65601
|
+
- You have EVIDENCE for each verification step
|
|
64684
65602
|
|
|
64685
|
-
|
|
65603
|
+
**Keep going until the task is fully resolved.** Persist even when tool calls fail. Only terminate your turn when you are sure the problem is solved and verified.
|
|
64686
65604
|
|
|
64687
|
-
|
|
64688
|
-
2. **REVERT** to last working state
|
|
64689
|
-
3. **DOCUMENT** what you tried (all 3 approaches)
|
|
64690
|
-
4. **CONSULT** Oracle with full context
|
|
64691
|
-
5. If Oracle cannot help, **ASK USER** with clear explanation of attempts
|
|
65605
|
+
**When you think you're done: Re-read the request. Run verification ONE MORE TIME. Then report.**
|
|
64692
65606
|
|
|
64693
|
-
|
|
65607
|
+
## Failure Recovery
|
|
64694
65608
|
|
|
64695
|
-
|
|
65609
|
+
1. Fix root causes, not symptoms. Re-verify after EVERY attempt.
|
|
65610
|
+
2. If first approach fails \u2192 try alternative (different algorithm, pattern, library)
|
|
65611
|
+
3. After 3 DIFFERENT approaches fail:
|
|
65612
|
+
- STOP all edits \u2192 REVERT to last working state
|
|
65613
|
+
- DOCUMENT what you tried \u2192 CONSULT Oracle
|
|
65614
|
+
- If Oracle fails \u2192 ASK USER with clear explanation
|
|
64696
65615
|
|
|
64697
|
-
|
|
64698
|
-
- Prefer small, focused changes over large refactors`;
|
|
65616
|
+
**Never**: Leave code broken, delete failing tests, shotgun debug`;
|
|
64699
65617
|
}
|
|
64700
65618
|
function createHephaestusAgent(model, availableAgents, availableToolNames, availableSkills, availableCategories, useTaskSystem = false) {
|
|
64701
65619
|
const tools = availableToolNames ? categorizeTools(availableToolNames) : [];
|
|
@@ -64781,7 +65699,7 @@ function buildAgent(source, model, categories, gitMasterConfig, browserProvider,
|
|
|
64781
65699
|
}
|
|
64782
65700
|
|
|
64783
65701
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
64784
|
-
import { existsSync as existsSync63, readFileSync as
|
|
65702
|
+
import { existsSync as existsSync63, readFileSync as readFileSync42 } from "fs";
|
|
64785
65703
|
import { homedir as homedir13 } from "os";
|
|
64786
65704
|
import { isAbsolute as isAbsolute7, resolve as resolve10 } from "path";
|
|
64787
65705
|
function resolvePromptAppend(promptAppend, configDir) {
|
|
@@ -64800,7 +65718,7 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
64800
65718
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
64801
65719
|
}
|
|
64802
65720
|
try {
|
|
64803
|
-
return
|
|
65721
|
+
return readFileSync42(filePath, "utf8");
|
|
64804
65722
|
} catch {
|
|
64805
65723
|
return `[WARNING: Could not read file: ${promptAppend}]`;
|
|
64806
65724
|
}
|
|
@@ -65182,10 +66100,12 @@ var agentMetadata = {
|
|
|
65182
66100
|
};
|
|
65183
66101
|
async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory, systemDefaultModel, categories, gitMasterConfig, discoveredSkills = [], customAgentSummaries, browserProvider, uiSelectedModel, disabledSkills, useTaskSystem = false) {
|
|
65184
66102
|
const connectedProviders = readConnectedProvidersCache();
|
|
66103
|
+
const providerModelsConnected = connectedProviders ? readProviderModelsCache()?.connected ?? [] : [];
|
|
66104
|
+
const mergedConnectedProviders = Array.from(new Set([...connectedProviders ?? [], ...providerModelsConnected]));
|
|
65185
66105
|
const availableModels = await fetchAvailableModels(undefined, {
|
|
65186
|
-
connectedProviders:
|
|
66106
|
+
connectedProviders: mergedConnectedProviders.length > 0 ? mergedConnectedProviders : undefined
|
|
65187
66107
|
});
|
|
65188
|
-
const isFirstRunNoCache = availableModels.size === 0 &&
|
|
66108
|
+
const isFirstRunNoCache = availableModels.size === 0 && mergedConnectedProviders.length === 0;
|
|
65189
66109
|
const result = {};
|
|
65190
66110
|
const mergedCategories = mergeCategories(categories);
|
|
65191
66111
|
const availableCategories = Object.entries(mergedCategories).map(([name]) => ({
|
|
@@ -66647,15 +67567,12 @@ var PROMETHEUS_PERMISSION = {
|
|
|
66647
67567
|
// src/agents/sisyphus-junior/default.ts
|
|
66648
67568
|
function buildDefaultSisyphusJuniorPrompt(useTaskSystem, promptAppend) {
|
|
66649
67569
|
const todoDiscipline = buildTodoDisciplineSection2(useTaskSystem);
|
|
66650
|
-
const constraintsSection = buildConstraintsSection(useTaskSystem);
|
|
66651
67570
|
const verificationText = useTaskSystem ? "All tasks marked completed" : "All todos marked completed";
|
|
66652
67571
|
const prompt = `<Role>
|
|
66653
67572
|
Sisyphus-Junior - Focused executor from OhMyOpenCode.
|
|
66654
|
-
Execute tasks directly.
|
|
67573
|
+
Execute tasks directly.
|
|
66655
67574
|
</Role>
|
|
66656
67575
|
|
|
66657
|
-
${constraintsSection}
|
|
66658
|
-
|
|
66659
67576
|
${todoDiscipline}
|
|
66660
67577
|
|
|
66661
67578
|
<Verification>
|
|
@@ -66676,34 +67593,13 @@ Task NOT complete without:
|
|
|
66676
67593
|
|
|
66677
67594
|
` + resolvePromptAppend(promptAppend);
|
|
66678
67595
|
}
|
|
66679
|
-
function buildConstraintsSection(useTaskSystem) {
|
|
66680
|
-
if (useTaskSystem) {
|
|
66681
|
-
return `<Critical_Constraints>
|
|
66682
|
-
BLOCKED ACTIONS (will fail if attempted):
|
|
66683
|
-
- task (agent delegation tool): BLOCKED \u2014 you cannot delegate work to other agents
|
|
66684
|
-
|
|
66685
|
-
ALLOWED tools:
|
|
66686
|
-
- call_omo_agent: You CAN spawn explore/librarian agents for research
|
|
66687
|
-
- task_create, task_update, task_list, task_get: ALLOWED \u2014 use these for tracking your work
|
|
66688
|
-
|
|
66689
|
-
You work ALONE for implementation. No delegation of implementation tasks.
|
|
66690
|
-
</Critical_Constraints>`;
|
|
66691
|
-
}
|
|
66692
|
-
return `<Critical_Constraints>
|
|
66693
|
-
BLOCKED ACTIONS (will fail if attempted):
|
|
66694
|
-
- task (agent delegation tool): BLOCKED \u2014 you cannot delegate work to other agents
|
|
66695
|
-
|
|
66696
|
-
ALLOWED: call_omo_agent - You CAN spawn explore/librarian agents for research.
|
|
66697
|
-
You work ALONE for implementation. No delegation of implementation tasks.
|
|
66698
|
-
</Critical_Constraints>`;
|
|
66699
|
-
}
|
|
66700
67596
|
function buildTodoDisciplineSection2(useTaskSystem) {
|
|
66701
67597
|
if (useTaskSystem) {
|
|
66702
67598
|
return `<Task_Discipline>
|
|
66703
67599
|
TASK OBSESSION (NON-NEGOTIABLE):
|
|
66704
|
-
- 2+ steps \u2192
|
|
66705
|
-
-
|
|
66706
|
-
-
|
|
67600
|
+
- 2+ steps \u2192 task_create FIRST, atomic breakdown
|
|
67601
|
+
- task_update(status="in_progress") before starting (ONE at a time)
|
|
67602
|
+
- task_update(status="completed") IMMEDIATELY after each step
|
|
66707
67603
|
- NEVER batch completions
|
|
66708
67604
|
|
|
66709
67605
|
No tasks on multi-step work = INCOMPLETE WORK.
|
|
@@ -66722,130 +67618,146 @@ No todos on multi-step work = INCOMPLETE WORK.
|
|
|
66722
67618
|
// src/agents/sisyphus-junior/gpt.ts
|
|
66723
67619
|
function buildGptSisyphusJuniorPrompt(useTaskSystem, promptAppend) {
|
|
66724
67620
|
const taskDiscipline = buildGptTaskDisciplineSection(useTaskSystem);
|
|
66725
|
-
const blockedActionsSection = buildGptBlockedActionsSection(useTaskSystem);
|
|
66726
67621
|
const verificationText = useTaskSystem ? "All tasks marked completed" : "All todos marked completed";
|
|
66727
|
-
const prompt =
|
|
66728
|
-
You are Sisyphus-Junior - Focused task executor from OhMyOpenCode.
|
|
66729
|
-
Role: Execute tasks directly. You work ALONE.
|
|
66730
|
-
</identity>
|
|
67622
|
+
const prompt = `You are Sisyphus-Junior \u2014 a focused task executor from OhMyOpenCode.
|
|
66731
67623
|
|
|
66732
|
-
|
|
66733
|
-
- Default: 2-4 sentences for status updates.
|
|
66734
|
-
- For progress: 1 sentence + current step.
|
|
66735
|
-
- AVOID long explanations; prefer compact bullets.
|
|
66736
|
-
- Do NOT rephrase the task unless semantics change.
|
|
66737
|
-
</output_verbosity_spec>
|
|
67624
|
+
## Identity
|
|
66738
67625
|
|
|
66739
|
-
|
|
66740
|
-
- Implement EXACTLY and ONLY what is requested.
|
|
66741
|
-
- No extra features, no UX embellishments, no scope creep.
|
|
66742
|
-
- If any instruction is ambiguous, choose the simplest valid interpretation OR ask.
|
|
66743
|
-
- Do NOT invent new requirements.
|
|
66744
|
-
- Do NOT expand task boundaries beyond what's written.
|
|
66745
|
-
</scope_and_design_constraints>
|
|
67626
|
+
You execute tasks directly as a **Senior Engineer**. You do not guess. You verify. You do not stop early. You complete.
|
|
66746
67627
|
|
|
66747
|
-
|
|
67628
|
+
**KEEP GOING. SOLVE PROBLEMS. ASK ONLY WHEN TRULY IMPOSSIBLE.**
|
|
66748
67629
|
|
|
66749
|
-
|
|
66750
|
-
|
|
66751
|
-
|
|
66752
|
-
|
|
66753
|
-
|
|
66754
|
-
-
|
|
66755
|
-
|
|
67630
|
+
When blocked: try a different approach \u2192 decompose the problem \u2192 challenge assumptions \u2192 explore how others solved it.
|
|
67631
|
+
|
|
67632
|
+
### Do NOT Ask \u2014 Just Do
|
|
67633
|
+
|
|
67634
|
+
**FORBIDDEN:**
|
|
67635
|
+
- "Should I proceed with X?" \u2192 JUST DO IT.
|
|
67636
|
+
- "Do you want me to run tests?" \u2192 RUN THEM.
|
|
67637
|
+
- "I noticed Y, should I fix it?" \u2192 FIX IT OR NOTE IN FINAL MESSAGE.
|
|
67638
|
+
- Stopping after partial implementation \u2192 100% OR NOTHING.
|
|
67639
|
+
|
|
67640
|
+
**CORRECT:**
|
|
67641
|
+
- Keep going until COMPLETELY done
|
|
67642
|
+
- Run verification (lint, tests, build) WITHOUT asking
|
|
67643
|
+
- Make decisions. Course-correct only on CONCRETE failure
|
|
67644
|
+
- Note assumptions in final message, not as questions mid-work
|
|
67645
|
+
- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY \u2014 keep working while they search
|
|
67646
|
+
|
|
67647
|
+
## Scope Discipline
|
|
67648
|
+
|
|
67649
|
+
- Implement EXACTLY and ONLY what is requested
|
|
67650
|
+
- No extra features, no UX embellishments, no scope creep
|
|
67651
|
+
- If ambiguous, choose the simplest valid interpretation OR ask ONE precise question
|
|
67652
|
+
- Do NOT invent new requirements or expand task boundaries
|
|
67653
|
+
|
|
67654
|
+
## Ambiguity Protocol (EXPLORE FIRST)
|
|
67655
|
+
|
|
67656
|
+
| Situation | Action |
|
|
67657
|
+
|-----------|--------|
|
|
67658
|
+
| Single valid interpretation | Proceed immediately |
|
|
67659
|
+
| Missing info that MIGHT exist | **EXPLORE FIRST** \u2014 use tools (grep, rg, file reads, explore agents) to find it |
|
|
67660
|
+
| Multiple plausible interpretations | State your interpretation, proceed with simplest approach |
|
|
67661
|
+
| Truly impossible to proceed | Ask ONE precise question (LAST RESORT) |
|
|
66756
67662
|
|
|
66757
67663
|
<tool_usage_rules>
|
|
66758
|
-
-
|
|
66759
|
-
|
|
66760
|
-
|
|
66761
|
-
|
|
66762
|
-
-
|
|
67664
|
+
- Parallelize independent tool calls: multiple file reads, grep searches, agent fires \u2014 all at once
|
|
67665
|
+
- Explore/Librarian via call_omo_agent = background research. Fire them and keep working
|
|
67666
|
+
- After any file edit: restate what changed, where, and what validation follows
|
|
67667
|
+
- Prefer tools over guessing whenever you need specific data (files, configs, patterns)
|
|
67668
|
+
- ALWAYS use tools over internal knowledge for file contents, project state, and verification
|
|
66763
67669
|
</tool_usage_rules>
|
|
66764
67670
|
|
|
66765
67671
|
${taskDiscipline}
|
|
66766
67672
|
|
|
66767
|
-
|
|
66768
|
-
|
|
67673
|
+
## Progress Updates
|
|
67674
|
+
|
|
67675
|
+
**Report progress proactively \u2014 the user should always know what you're doing and why.**
|
|
67676
|
+
|
|
67677
|
+
When to update (MANDATORY):
|
|
67678
|
+
- **Before exploration**: "Checking the repo structure for [pattern]..."
|
|
67679
|
+
- **After discovery**: "Found the config in \`src/config/\`. The pattern uses factory functions."
|
|
67680
|
+
- **Before large edits**: "About to modify [files] \u2014 [what and why]."
|
|
67681
|
+
- **After edits**: "Updated [file] \u2014 [what changed]. Running verification."
|
|
67682
|
+
- **On blockers**: "Hit a snag with [issue] \u2014 trying [alternative] instead."
|
|
67683
|
+
|
|
67684
|
+
Style:
|
|
67685
|
+
- A few sentences, friendly and concrete \u2014 explain in plain language so anyone can follow
|
|
67686
|
+
- Include at least one specific detail (file path, pattern found, decision made)
|
|
67687
|
+
- When explaining technical decisions, explain the WHY \u2014 not just what you did
|
|
67688
|
+
|
|
67689
|
+
## Code Quality & Verification
|
|
67690
|
+
|
|
67691
|
+
### Before Writing Code (MANDATORY)
|
|
67692
|
+
|
|
67693
|
+
1. SEARCH existing codebase for similar patterns/styles
|
|
67694
|
+
2. Match naming, indentation, import styles, error handling conventions
|
|
67695
|
+
3. Default to ASCII. Add comments only for non-obvious blocks
|
|
67696
|
+
|
|
67697
|
+
### After Implementation (MANDATORY \u2014 DO NOT SKIP)
|
|
67698
|
+
|
|
67699
|
+
1. **\`lsp_diagnostics\`** on ALL modified files \u2014 zero errors required
|
|
67700
|
+
2. **Run related tests** \u2014 pattern: modified \`foo.ts\` \u2192 look for \`foo.test.ts\`
|
|
67701
|
+
3. **Run typecheck** if TypeScript project
|
|
67702
|
+
4. **Run build** if applicable \u2014 exit code 0 required
|
|
67703
|
+
5. **Tell user** what you verified and the results \u2014 keep it clear and helpful
|
|
67704
|
+
|
|
66769
67705
|
| Check | Tool | Expected |
|
|
66770
67706
|
|-------|------|----------|
|
|
66771
67707
|
| Diagnostics | lsp_diagnostics | ZERO errors on changed files |
|
|
66772
67708
|
| Build | Bash | Exit code 0 (if applicable) |
|
|
66773
|
-
| Tracking | ${useTaskSystem ? "
|
|
67709
|
+
| Tracking | ${useTaskSystem ? "task_update" : "todowrite"} | ${verificationText} |
|
|
66774
67710
|
|
|
66775
67711
|
**No evidence = not complete.**
|
|
66776
|
-
</verification_spec>
|
|
66777
67712
|
|
|
66778
|
-
|
|
66779
|
-
|
|
66780
|
-
|
|
66781
|
-
|
|
66782
|
-
-
|
|
66783
|
-
|
|
67713
|
+
## Output Contract
|
|
67714
|
+
|
|
67715
|
+
<output_contract>
|
|
67716
|
+
**Format:**
|
|
67717
|
+
- Default: 3-6 sentences or \u22645 bullets
|
|
67718
|
+
- Simple yes/no: \u22642 sentences
|
|
67719
|
+
- Complex multi-file: 1 overview paragraph + \u22645 tagged bullets (What, Where, Risks, Next, Open)
|
|
67720
|
+
|
|
67721
|
+
**Style:**
|
|
67722
|
+
- Start work immediately. Skip empty preambles ("I'm on it", "Let me...") \u2014 but DO send clear context before significant actions
|
|
67723
|
+
- Be friendly, clear, and easy to understand \u2014 explain so anyone can follow your reasoning
|
|
67724
|
+
- When explaining technical decisions, explain the WHY \u2014 not just the WHAT
|
|
67725
|
+
</output_contract>
|
|
67726
|
+
|
|
67727
|
+
## Failure Recovery
|
|
67728
|
+
|
|
67729
|
+
1. Fix root causes, not symptoms. Re-verify after EVERY attempt.
|
|
67730
|
+
2. If first approach fails \u2192 try alternative (different algorithm, pattern, library)
|
|
67731
|
+
3. After 3 DIFFERENT approaches fail \u2192 STOP and report what you tried clearly`;
|
|
66784
67732
|
if (!promptAppend)
|
|
66785
67733
|
return prompt;
|
|
66786
67734
|
return prompt + `
|
|
66787
67735
|
|
|
66788
67736
|
` + resolvePromptAppend(promptAppend);
|
|
66789
67737
|
}
|
|
66790
|
-
function buildGptBlockedActionsSection(useTaskSystem) {
|
|
66791
|
-
if (useTaskSystem) {
|
|
66792
|
-
return `<blocked_actions>
|
|
66793
|
-
BLOCKED (will fail if attempted):
|
|
66794
|
-
| Tool | Status | Description |
|
|
66795
|
-
|------|--------|-------------|
|
|
66796
|
-
| task | BLOCKED | Agent delegation tool \u2014 you cannot spawn other agents |
|
|
66797
|
-
|
|
66798
|
-
ALLOWED:
|
|
66799
|
-
| Tool | Usage |
|
|
66800
|
-
|------|-------|
|
|
66801
|
-
| call_omo_agent | Spawn explore/librarian for research ONLY |
|
|
66802
|
-
| task_create | Create tasks to track your work |
|
|
66803
|
-
| task_update | Update task status (in_progress, completed) |
|
|
66804
|
-
| task_list | List active tasks |
|
|
66805
|
-
| task_get | Get task details by ID |
|
|
66806
|
-
|
|
66807
|
-
You work ALONE for implementation. No delegation.
|
|
66808
|
-
</blocked_actions>`;
|
|
66809
|
-
}
|
|
66810
|
-
return `<blocked_actions>
|
|
66811
|
-
BLOCKED (will fail if attempted):
|
|
66812
|
-
| Tool | Status | Description |
|
|
66813
|
-
|------|--------|-------------|
|
|
66814
|
-
| task | BLOCKED | Agent delegation tool \u2014 you cannot spawn other agents |
|
|
66815
|
-
|
|
66816
|
-
ALLOWED:
|
|
66817
|
-
| Tool | Usage |
|
|
66818
|
-
|------|-------|
|
|
66819
|
-
| call_omo_agent | Spawn explore/librarian for research ONLY |
|
|
66820
|
-
|
|
66821
|
-
You work ALONE for implementation. No delegation.
|
|
66822
|
-
</blocked_actions>`;
|
|
66823
|
-
}
|
|
66824
67738
|
function buildGptTaskDisciplineSection(useTaskSystem) {
|
|
66825
67739
|
if (useTaskSystem) {
|
|
66826
|
-
return
|
|
66827
|
-
|
|
67740
|
+
return `## Task Discipline (NON-NEGOTIABLE)
|
|
67741
|
+
|
|
66828
67742
|
| Trigger | Action |
|
|
66829
67743
|
|---------|--------|
|
|
66830
|
-
| 2+ steps |
|
|
66831
|
-
| Starting step |
|
|
66832
|
-
| Completing step |
|
|
67744
|
+
| 2+ steps | task_create FIRST, atomic breakdown |
|
|
67745
|
+
| Starting step | task_update(status="in_progress") \u2014 ONE at a time |
|
|
67746
|
+
| Completing step | task_update(status="completed") IMMEDIATELY |
|
|
66833
67747
|
| Batching | NEVER batch completions |
|
|
66834
67748
|
|
|
66835
|
-
No tasks on multi-step work = INCOMPLETE WORK
|
|
66836
|
-
</task_discipline_spec>`;
|
|
67749
|
+
No tasks on multi-step work = INCOMPLETE WORK.`;
|
|
66837
67750
|
}
|
|
66838
|
-
return
|
|
66839
|
-
|
|
67751
|
+
return `## Todo Discipline (NON-NEGOTIABLE)
|
|
67752
|
+
|
|
66840
67753
|
| Trigger | Action |
|
|
66841
67754
|
|---------|--------|
|
|
66842
67755
|
| 2+ steps | todowrite FIRST, atomic breakdown |
|
|
66843
|
-
| Starting step | Mark in_progress
|
|
67756
|
+
| Starting step | Mark in_progress \u2014 ONE at a time |
|
|
66844
67757
|
| Completing step | Mark completed IMMEDIATELY |
|
|
66845
67758
|
| Batching | NEVER batch completions |
|
|
66846
67759
|
|
|
66847
|
-
No todos on multi-step work = INCOMPLETE WORK
|
|
66848
|
-
</todo_discipline_spec>`;
|
|
67760
|
+
No todos on multi-step work = INCOMPLETE WORK.`;
|
|
66849
67761
|
}
|
|
66850
67762
|
// src/agents/sisyphus-junior/agent.ts
|
|
66851
67763
|
var MODE10 = "subagent";
|
|
@@ -66911,7 +67823,7 @@ function createSisyphusJuniorAgentWithOverrides(override, systemDefaultModel, us
|
|
|
66911
67823
|
}
|
|
66912
67824
|
createSisyphusJuniorAgentWithOverrides.mode = MODE10;
|
|
66913
67825
|
// src/features/claude-code-agent-loader/loader.ts
|
|
66914
|
-
import { existsSync as existsSync64, readdirSync as readdirSync19, readFileSync as
|
|
67826
|
+
import { existsSync as existsSync64, readdirSync as readdirSync19, readFileSync as readFileSync43 } from "fs";
|
|
66915
67827
|
import { join as join74, basename as basename7 } from "path";
|
|
66916
67828
|
function parseToolsConfig(toolsStr) {
|
|
66917
67829
|
if (!toolsStr)
|
|
@@ -66937,7 +67849,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
66937
67849
|
const agentPath = join74(agentsDir, entry.name);
|
|
66938
67850
|
const agentName = basename7(entry.name, ".md");
|
|
66939
67851
|
try {
|
|
66940
|
-
const content =
|
|
67852
|
+
const content = readFileSync43(agentPath, "utf-8");
|
|
66941
67853
|
const { data, body } = parseFrontmatter(content);
|
|
66942
67854
|
const name = data.name || agentName;
|
|
66943
67855
|
const originalDescription = data.description || "";
|
|
@@ -67105,6 +68017,10 @@ function buildPlanDemoteConfig(prometheusConfig, planOverride) {
|
|
|
67105
68017
|
}
|
|
67106
68018
|
|
|
67107
68019
|
// src/plugin-handlers/agent-config-handler.ts
|
|
68020
|
+
function hasConfiguredDefaultAgent(config3) {
|
|
68021
|
+
const defaultAgent = config3.default_agent;
|
|
68022
|
+
return typeof defaultAgent === "string" && defaultAgent.trim().length > 0;
|
|
68023
|
+
}
|
|
67108
68024
|
async function applyAgentConfig(params) {
|
|
67109
68025
|
const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map((agent) => {
|
|
67110
68026
|
return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
|
|
@@ -67153,7 +68069,9 @@ async function applyAgentConfig(params) {
|
|
|
67153
68069
|
const shouldDemotePlan = plannerEnabled && replacePlan;
|
|
67154
68070
|
const configAgent = params.config.agent;
|
|
67155
68071
|
if (isSisyphusEnabled && builtinAgents.sisyphus) {
|
|
67156
|
-
params.config
|
|
68072
|
+
if (!hasConfiguredDefaultAgent(params.config)) {
|
|
68073
|
+
params.config.default_agent = getAgentDisplayName("sisyphus");
|
|
68074
|
+
}
|
|
67157
68075
|
const agentConfig = {
|
|
67158
68076
|
sisyphus: builtinAgents.sisyphus
|
|
67159
68077
|
};
|
|
@@ -67381,7 +68299,7 @@ function remapCommandAgentFields(commands2) {
|
|
|
67381
68299
|
}
|
|
67382
68300
|
}
|
|
67383
68301
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
67384
|
-
import { existsSync as existsSync65, readFileSync as
|
|
68302
|
+
import { existsSync as existsSync65, readFileSync as readFileSync44 } from "fs";
|
|
67385
68303
|
import { join as join76 } from "path";
|
|
67386
68304
|
import { homedir as homedir14 } from "os";
|
|
67387
68305
|
|
|
@@ -67449,7 +68367,7 @@ function getSystemMcpServerNames() {
|
|
|
67449
68367
|
if (!existsSync65(path10))
|
|
67450
68368
|
continue;
|
|
67451
68369
|
try {
|
|
67452
|
-
const content =
|
|
68370
|
+
const content = readFileSync44(path10, "utf-8");
|
|
67453
68371
|
const config3 = JSON.parse(content);
|
|
67454
68372
|
if (!config3?.mcpServers)
|
|
67455
68373
|
continue;
|
|
@@ -67627,7 +68545,7 @@ init_logger();
|
|
|
67627
68545
|
|
|
67628
68546
|
// src/features/claude-code-plugin-loader/discovery.ts
|
|
67629
68547
|
init_logger();
|
|
67630
|
-
import { existsSync as existsSync66, readFileSync as
|
|
68548
|
+
import { existsSync as existsSync66, readFileSync as readFileSync45 } from "fs";
|
|
67631
68549
|
import { homedir as homedir15 } from "os";
|
|
67632
68550
|
import { join as join77 } from "path";
|
|
67633
68551
|
function getPluginsBaseDir() {
|
|
@@ -67645,7 +68563,7 @@ function loadInstalledPlugins() {
|
|
|
67645
68563
|
return null;
|
|
67646
68564
|
}
|
|
67647
68565
|
try {
|
|
67648
|
-
const content =
|
|
68566
|
+
const content = readFileSync45(dbPath, "utf-8");
|
|
67649
68567
|
return JSON.parse(content);
|
|
67650
68568
|
} catch (error45) {
|
|
67651
68569
|
log("Failed to load installed plugins database", error45);
|
|
@@ -67664,7 +68582,7 @@ function loadClaudeSettings() {
|
|
|
67664
68582
|
return null;
|
|
67665
68583
|
}
|
|
67666
68584
|
try {
|
|
67667
|
-
const content =
|
|
68585
|
+
const content = readFileSync45(settingsPath, "utf-8");
|
|
67668
68586
|
return JSON.parse(content);
|
|
67669
68587
|
} catch (error45) {
|
|
67670
68588
|
log("Failed to load Claude settings", error45);
|
|
@@ -67677,7 +68595,7 @@ function loadPluginManifest(installPath) {
|
|
|
67677
68595
|
return null;
|
|
67678
68596
|
}
|
|
67679
68597
|
try {
|
|
67680
|
-
const content =
|
|
68598
|
+
const content = readFileSync45(manifestPath, "utf-8");
|
|
67681
68599
|
return JSON.parse(content);
|
|
67682
68600
|
} catch (error45) {
|
|
67683
68601
|
log(`Failed to load plugin manifest from ${manifestPath}`, error45);
|
|
@@ -67766,7 +68684,7 @@ function discoverInstalledPlugins(options) {
|
|
|
67766
68684
|
}
|
|
67767
68685
|
|
|
67768
68686
|
// src/features/claude-code-plugin-loader/command-loader.ts
|
|
67769
|
-
import { existsSync as existsSync67, readdirSync as readdirSync20, readFileSync as
|
|
68687
|
+
import { existsSync as existsSync67, readdirSync as readdirSync20, readFileSync as readFileSync46 } from "fs";
|
|
67770
68688
|
import { basename as basename9, join as join78 } from "path";
|
|
67771
68689
|
init_logger();
|
|
67772
68690
|
function loadPluginCommands(plugins) {
|
|
@@ -67782,7 +68700,7 @@ function loadPluginCommands(plugins) {
|
|
|
67782
68700
|
const commandName = basename9(entry.name, ".md");
|
|
67783
68701
|
const namespacedName = `${plugin.name}:${commandName}`;
|
|
67784
68702
|
try {
|
|
67785
|
-
const content =
|
|
68703
|
+
const content = readFileSync46(commandPath, "utf-8");
|
|
67786
68704
|
const { data, body } = parseFrontmatter(content);
|
|
67787
68705
|
const wrappedTemplate = `<command-instruction>
|
|
67788
68706
|
${body.trim()}
|
|
@@ -67813,7 +68731,7 @@ $ARGUMENTS
|
|
|
67813
68731
|
}
|
|
67814
68732
|
|
|
67815
68733
|
// src/features/claude-code-plugin-loader/skill-loader.ts
|
|
67816
|
-
import { existsSync as existsSync68, readdirSync as readdirSync21, readFileSync as
|
|
68734
|
+
import { existsSync as existsSync68, readdirSync as readdirSync21, readFileSync as readFileSync47 } from "fs";
|
|
67817
68735
|
import { join as join79 } from "path";
|
|
67818
68736
|
init_logger();
|
|
67819
68737
|
function loadPluginSkillsAsCommands(plugins) {
|
|
@@ -67833,7 +68751,7 @@ function loadPluginSkillsAsCommands(plugins) {
|
|
|
67833
68751
|
if (!existsSync68(skillMdPath))
|
|
67834
68752
|
continue;
|
|
67835
68753
|
try {
|
|
67836
|
-
const content =
|
|
68754
|
+
const content = readFileSync47(skillMdPath, "utf-8");
|
|
67837
68755
|
const { data, body } = parseFrontmatter(content);
|
|
67838
68756
|
const skillName = data.name || entry.name;
|
|
67839
68757
|
const namespacedName = `${plugin.name}:${skillName}`;
|
|
@@ -67868,7 +68786,7 @@ $ARGUMENTS
|
|
|
67868
68786
|
}
|
|
67869
68787
|
|
|
67870
68788
|
// src/features/claude-code-plugin-loader/agent-loader.ts
|
|
67871
|
-
import { existsSync as existsSync69, readdirSync as readdirSync22, readFileSync as
|
|
68789
|
+
import { existsSync as existsSync69, readdirSync as readdirSync22, readFileSync as readFileSync48 } from "fs";
|
|
67872
68790
|
import { basename as basename10, join as join80 } from "path";
|
|
67873
68791
|
init_logger();
|
|
67874
68792
|
function parseToolsConfig2(toolsStr) {
|
|
@@ -67896,7 +68814,7 @@ function loadPluginAgents(plugins) {
|
|
|
67896
68814
|
const agentName = basename10(entry.name, ".md");
|
|
67897
68815
|
const namespacedName = `${plugin.name}:${agentName}`;
|
|
67898
68816
|
try {
|
|
67899
|
-
const content =
|
|
68817
|
+
const content = readFileSync48(agentPath, "utf-8");
|
|
67900
68818
|
const { data, body } = parseFrontmatter(content);
|
|
67901
68819
|
const originalDescription = data.description || "";
|
|
67902
68820
|
const formattedDescription = `(plugin: ${plugin.name}) ${originalDescription}`;
|
|
@@ -67983,14 +68901,14 @@ async function loadPluginMcpServers(plugins) {
|
|
|
67983
68901
|
|
|
67984
68902
|
// src/features/claude-code-plugin-loader/hook-loader.ts
|
|
67985
68903
|
init_logger();
|
|
67986
|
-
import { existsSync as existsSync71, readFileSync as
|
|
68904
|
+
import { existsSync as existsSync71, readFileSync as readFileSync49 } from "fs";
|
|
67987
68905
|
function loadPluginHooksConfigs(plugins) {
|
|
67988
68906
|
const configs = [];
|
|
67989
68907
|
for (const plugin of plugins) {
|
|
67990
68908
|
if (!plugin.hooksPath || !existsSync71(plugin.hooksPath))
|
|
67991
68909
|
continue;
|
|
67992
68910
|
try {
|
|
67993
|
-
const content =
|
|
68911
|
+
const content = readFileSync49(plugin.hooksPath, "utf-8");
|
|
67994
68912
|
let config3 = JSON.parse(content);
|
|
67995
68913
|
config3 = resolvePluginPaths(config3, plugin.installPath);
|
|
67996
68914
|
configs.push(config3);
|
|
@@ -68182,7 +69100,7 @@ function createConfigHandler(deps) {
|
|
|
68182
69100
|
}
|
|
68183
69101
|
// src/create-managers.ts
|
|
68184
69102
|
function createManagers(args) {
|
|
68185
|
-
const { ctx, pluginConfig, tmuxConfig, modelCacheState } = args;
|
|
69103
|
+
const { ctx, pluginConfig, tmuxConfig, modelCacheState, backgroundNotificationHookEnabled } = args;
|
|
68186
69104
|
const tmuxSessionManager = new TmuxSessionManager(ctx, tmuxConfig);
|
|
68187
69105
|
const backgroundManager = new BackgroundManager(ctx, pluginConfig.background_task, {
|
|
68188
69106
|
tmuxConfig,
|
|
@@ -68208,7 +69126,8 @@ function createManagers(args) {
|
|
|
68208
69126
|
tmuxSessionManager.cleanup().catch((error45) => {
|
|
68209
69127
|
log("[index] tmux cleanup error during shutdown:", error45);
|
|
68210
69128
|
});
|
|
68211
|
-
}
|
|
69129
|
+
},
|
|
69130
|
+
enableParentSessionNotifications: backgroundNotificationHookEnabled
|
|
68212
69131
|
});
|
|
68213
69132
|
initTaskToastManager(ctx.client);
|
|
68214
69133
|
const skillMcpManager = new SkillMcpManager;
|
|
@@ -68310,7 +69229,7 @@ function filterDisabledTools(tools, disabledTools) {
|
|
|
68310
69229
|
function createToolRegistry(args) {
|
|
68311
69230
|
const { ctx, pluginConfig, managers, skillContext, availableCategories } = args;
|
|
68312
69231
|
const backgroundTools = createBackgroundTools(managers.backgroundManager, ctx.client);
|
|
68313
|
-
const callOmoAgent = createCallOmoAgent(ctx, managers.backgroundManager);
|
|
69232
|
+
const callOmoAgent = createCallOmoAgent(ctx, managers.backgroundManager, pluginConfig.disabled_agents ?? []);
|
|
68314
69233
|
const isMultimodalLookerEnabled = !(pluginConfig.disabled_agents ?? []).some((agent) => agent.toLowerCase() === "multimodal-looker");
|
|
68315
69234
|
const lookAt = isMultimodalLookerEnabled ? createLookAt(ctx) : null;
|
|
68316
69235
|
const delegateTask = createDelegateTask({
|
|
@@ -68367,6 +69286,8 @@ function createToolRegistry(args) {
|
|
|
68367
69286
|
task_list: createTaskList(pluginConfig),
|
|
68368
69287
|
task_update: createTaskUpdateTool(pluginConfig, ctx)
|
|
68369
69288
|
} : {};
|
|
69289
|
+
const hashlineEnabled = pluginConfig.experimental?.hashline_edit ?? false;
|
|
69290
|
+
const hashlineToolsRecord = hashlineEnabled ? { edit: createHashlineEditTool() } : {};
|
|
68370
69291
|
const allTools = {
|
|
68371
69292
|
...builtinTools,
|
|
68372
69293
|
...createGrepTools(ctx),
|
|
@@ -68381,7 +69302,8 @@ function createToolRegistry(args) {
|
|
|
68381
69302
|
skill_mcp: skillMcpTool,
|
|
68382
69303
|
slashcommand: slashcommandTool,
|
|
68383
69304
|
interactive_bash,
|
|
68384
|
-
...taskToolsRecord
|
|
69305
|
+
...taskToolsRecord,
|
|
69306
|
+
...hashlineToolsRecord
|
|
68385
69307
|
};
|
|
68386
69308
|
const filteredTools = filterDisabledTools(allTools, pluginConfig.disabled_tools);
|
|
68387
69309
|
return {
|
|
@@ -68746,6 +69668,7 @@ function createToolExecuteAfterHandler3(args) {
|
|
|
68746
69668
|
await hooks.delegateTaskRetry?.["tool.execute.after"]?.(input, output);
|
|
68747
69669
|
await hooks.atlasHook?.["tool.execute.after"]?.(input, output);
|
|
68748
69670
|
await hooks.taskResumeInfo?.["tool.execute.after"]?.(input, output);
|
|
69671
|
+
await hooks.hashlineReadEnhancer?.["tool.execute.after"]?.(input, output);
|
|
68749
69672
|
};
|
|
68750
69673
|
}
|
|
68751
69674
|
|
|
@@ -68987,7 +69910,8 @@ var BackgroundTaskConfigSchema = exports_external.object({
|
|
|
68987
69910
|
var BrowserAutomationProviderSchema = exports_external.enum([
|
|
68988
69911
|
"playwright",
|
|
68989
69912
|
"agent-browser",
|
|
68990
|
-
"dev-browser"
|
|
69913
|
+
"dev-browser",
|
|
69914
|
+
"playwright-cli"
|
|
68991
69915
|
]);
|
|
68992
69916
|
var BrowserAutomationConfigSchema = exports_external.object({
|
|
68993
69917
|
provider: BrowserAutomationProviderSchema.default("playwright")
|
|
@@ -69086,7 +70010,8 @@ var ExperimentalConfigSchema = exports_external.object({
|
|
|
69086
70010
|
dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
|
|
69087
70011
|
task_system: exports_external.boolean().optional(),
|
|
69088
70012
|
plugin_load_timeout_ms: exports_external.number().min(1000).optional(),
|
|
69089
|
-
safe_hook_creation: exports_external.boolean().optional()
|
|
70013
|
+
safe_hook_creation: exports_external.boolean().optional(),
|
|
70014
|
+
hashline_edit: exports_external.boolean().optional()
|
|
69090
70015
|
});
|
|
69091
70016
|
// src/config/schema/git-master.ts
|
|
69092
70017
|
var GitMasterConfigSchema = exports_external.object({
|
|
@@ -69136,7 +70061,8 @@ var HookNameSchema = exports_external.enum([
|
|
|
69136
70061
|
"stop-continuation-guard",
|
|
69137
70062
|
"tasks-todowrite-disabler",
|
|
69138
70063
|
"write-existing-file-guard",
|
|
69139
|
-
"anthropic-effort"
|
|
70064
|
+
"anthropic-effort",
|
|
70065
|
+
"hashline-read-enhancer"
|
|
69140
70066
|
]);
|
|
69141
70067
|
// src/config/schema/notification.ts
|
|
69142
70068
|
var NotificationConfigSchema = exports_external.object({
|
|
@@ -69434,7 +70360,8 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
69434
70360
|
ctx,
|
|
69435
70361
|
pluginConfig,
|
|
69436
70362
|
tmuxConfig,
|
|
69437
|
-
modelCacheState
|
|
70363
|
+
modelCacheState,
|
|
70364
|
+
backgroundNotificationHookEnabled: isHookEnabled("background-notification")
|
|
69438
70365
|
});
|
|
69439
70366
|
const toolsResult = await createTools({
|
|
69440
70367
|
ctx,
|
|
@@ -69444,6 +70371,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
69444
70371
|
const hooks2 = createHooks({
|
|
69445
70372
|
ctx,
|
|
69446
70373
|
pluginConfig,
|
|
70374
|
+
modelCacheState,
|
|
69447
70375
|
backgroundManager: managers.backgroundManager,
|
|
69448
70376
|
isHookEnabled,
|
|
69449
70377
|
safeHookEnabled,
|
|
@@ -69462,10 +70390,10 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
69462
70390
|
...pluginInterface,
|
|
69463
70391
|
"experimental.session.compacting": async (_input, output) => {
|
|
69464
70392
|
await hooks2.compactionTodoPreserver?.capture(_input.sessionID);
|
|
69465
|
-
|
|
69466
|
-
|
|
70393
|
+
await hooks2.claudeCodeHooks?.["experimental.session.compacting"]?.(_input, output);
|
|
70394
|
+
if (hooks2.compactionContextInjector) {
|
|
70395
|
+
output.context.push(hooks2.compactionContextInjector(_input.sessionID));
|
|
69467
70396
|
}
|
|
69468
|
-
output.context.push(hooks2.compactionContextInjector(_input.sessionID));
|
|
69469
70397
|
}
|
|
69470
70398
|
};
|
|
69471
70399
|
};
|