oh-my-opencode 4.5.12 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/opencode-qa/SKILL.md +194 -0
- package/.agents/skills/opencode-qa/references/cli-commands.md +188 -0
- package/.agents/skills/opencode-qa/references/db-investigation.md +197 -0
- package/.agents/skills/opencode-qa/references/events-hooks.md +110 -0
- package/.agents/skills/opencode-qa/references/sdk.md +96 -0
- package/.agents/skills/opencode-qa/references/server-api.md +200 -0
- package/.agents/skills/opencode-qa/references/testing-harness.md +218 -0
- package/.agents/skills/opencode-qa/references/tui-tmux.md +52 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-id.sh +53 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-name.sh +57 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-text.sh +158 -0
- package/.agents/skills/opencode-qa/scripts/export-roundtrip.sh +57 -0
- package/.agents/skills/opencode-qa/scripts/lib/common.sh +216 -0
- package/.agents/skills/opencode-qa/scripts/server-smoke.sh +64 -0
- package/.agents/skills/opencode-qa/scripts/sse-hook-probe.sh +106 -0
- package/.agents/skills/opencode-qa/scripts/tui-smoke.sh +89 -0
- package/README.ja.md +13 -3
- package/README.ko.md +13 -3
- package/README.md +24 -14
- package/README.ru.md +13 -3
- package/README.zh-cn.md +13 -3
- package/bin/oh-my-opencode.js +4 -3
- package/bin/oh-my-opencode.test.ts +35 -7
- package/bin/platform.d.ts +1 -1
- package/bin/platform.js +4 -4
- package/bin/platform.test.ts +31 -9
- package/bin/version-mismatch.js +47 -0
- package/bin/version-mismatch.test.ts +120 -0
- package/dist/cli/cleanup-command.d.ts +4 -0
- package/dist/cli/cleanup.d.ts +11 -0
- package/dist/cli/cli-program.d.ts +2 -1
- package/dist/cli/codex-ulw-loop.d.ts +12 -0
- package/dist/cli/doctor/checks/tui-plugin-config.d.ts +2 -0
- package/dist/cli/index.js +2189 -529
- package/dist/cli/install-codex/codex-cache.d.ts +1 -0
- package/dist/cli/install-codex/codex-cleanup-config.d.ts +6 -0
- package/dist/cli/install-codex/codex-cleanup.d.ts +21 -0
- package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -0
- package/dist/cli/install-codex/codex-config-reasoning.d.ts +2 -0
- package/dist/cli/install-codex/codex-config-toml.d.ts +2 -1
- package/dist/cli/install-codex/codex-installation-detection.d.ts +36 -0
- package/dist/cli/install-codex/codex-model-catalog.d.ts +13 -0
- package/dist/cli/install-codex/codex-package-layout.d.ts +1 -0
- package/dist/cli/install-codex/codex-project-local-cleanup-best-effort.d.ts +7 -0
- package/dist/cli/install-codex/codex-project-local-cleanup.d.ts +35 -0
- package/dist/cli/install-codex/git-bash.d.ts +35 -0
- package/dist/cli/install-codex/index.d.ts +4 -0
- package/dist/cli/install-codex/toml-section-editor.d.ts +2 -0
- package/dist/cli/install-codex/types.d.ts +20 -0
- package/dist/cli/run/event-state.d.ts +1 -0
- package/dist/cli/run/poll-for-completion.d.ts +1 -0
- package/dist/cli/run/prompt-start.d.ts +7 -0
- package/dist/cli/star-request.d.ts +9 -0
- package/dist/config/schema/hooks.d.ts +0 -1
- package/dist/create-hooks.d.ts +0 -1
- package/dist/features/background-agent/concurrency.d.ts +1 -0
- package/dist/features/background-agent/process-cleanup.d.ts +6 -0
- package/dist/features/builtin-skills/skills/debugging.d.ts +2 -0
- package/dist/features/builtin-skills/skills/index.d.ts +1 -0
- package/dist/features/claude-code-session-state/state.d.ts +1 -0
- package/dist/features/opencode-skill-loader/index.d.ts +1 -0
- package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +5 -0
- package/dist/features/tmux-subagent/attachable-session-status.d.ts +1 -1
- package/dist/features/tmux-subagent/session-status-parser.d.ts +1 -0
- package/dist/hooks/comment-checker/cli.d.ts +1 -0
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/tasks-todowrite-disabler/constants.d.ts +1 -1
- package/dist/index.js +1077 -563
- package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
- package/dist/plugin/messages-transform.d.ts +8 -1
- package/dist/plugin/user-abort-interrupted-recovery-guard.d.ts +6 -0
- package/dist/shared/command-executor/execute-hook-command.d.ts +2 -0
- package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +14 -0
- package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +7 -0
- package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +1 -0
- package/dist/shared/prompt-async-gate/timing.d.ts +1 -0
- package/dist/shared/prompt-async-gate/types.d.ts +2 -0
- package/dist/shared/prompt-async-gate.d.ts +1 -1
- package/dist/tools/skill/description-formatter.d.ts +5 -1
- package/dist/tools/skill/types.d.ts +1 -0
- package/package.json +22 -18
- package/packages/ast-grep-mcp/dist/cli.js +53 -9
- package/packages/git-bash-mcp/dist/cli.js +367 -0
- package/packages/lsp-tools-mcp/dist/lsp/process.js +1 -1
- package/packages/omo-codex/plugin/.mcp.json +11 -0
- package/packages/omo-codex/plugin/components/comment-checker/README.md +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +29 -0
- package/packages/omo-codex/plugin/components/git-bash/package.json +23 -0
- package/packages/omo-codex/plugin/components/git-bash/src/cli.ts +33 -0
- package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +180 -0
- package/packages/omo-codex/plugin/components/git-bash/src/index.ts +10 -0
- package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +195 -0
- package/packages/omo-codex/plugin/components/git-bash/tsconfig.build.json +13 -0
- package/packages/omo-codex/plugin/components/git-bash/tsconfig.json +25 -0
- package/packages/omo-codex/plugin/components/lsp/README.md +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/cli.ts +5 -5
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +33 -0
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +19 -27
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-cli.test.ts +28 -0
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-errors.test.ts +55 -0
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +7 -5
- package/packages/omo-codex/plugin/components/rules/README.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +6 -4
- package/packages/omo-codex/plugin/components/rules/bundled-rules/windows-git-bash.md +10 -0
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +0 -2
- package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +3 -1
- package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +97 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +6 -5
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +22 -0
- package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +4 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +8 -7
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +9 -8
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +32 -6
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +27 -4
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +25 -0
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +28 -205
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +231 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +19 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +102 -5
- package/packages/omo-codex/plugin/hooks/hooks.json +35 -2
- package/packages/omo-codex/plugin/model-catalog.json +49 -0
- package/packages/omo-codex/plugin/package-lock.json +19 -0
- package/packages/omo-codex/plugin/package.json +3 -1
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +159 -0
- package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +16 -1
- package/packages/omo-codex/plugin/scripts/build-components.mjs +2 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +269 -0
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +89 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -6
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +127 -0
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +9 -0
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +33 -8
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +25 -5
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +28 -205
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +231 -0
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +17 -17
- package/packages/omo-codex/plugin/test/aggregate.test.mjs +188 -20
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +129 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +58 -11
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +34 -0
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +21 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +146 -0
- package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +48 -0
- package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +76 -0
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +67 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +54 -2
- package/packages/omo-codex/scripts/install/cache.mjs +5 -3
- package/packages/omo-codex/scripts/install/cli-args.mjs +112 -0
- package/packages/omo-codex/scripts/install/config.mjs +23 -1
- package/packages/omo-codex/scripts/install/delegated-command.mjs +25 -0
- package/packages/omo-codex/scripts/install/git-bash.mjs +99 -0
- package/packages/omo-codex/scripts/install/git-bash.test.mjs +174 -0
- package/packages/omo-codex/scripts/install/legacy-bins.mjs +1 -0
- package/packages/omo-codex/scripts/install/mcp-runtime-cache.mjs +5 -1
- package/packages/omo-codex/scripts/install/model-catalog.mjs +66 -0
- package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +7 -1
- package/packages/omo-codex/scripts/install/permissions.d.mts +1 -0
- package/packages/omo-codex/scripts/install/permissions.mjs +26 -0
- package/packages/omo-codex/scripts/install/project-local-cleanup.mjs +229 -0
- package/packages/omo-codex/scripts/install/reasoning-config.mjs +72 -0
- package/packages/omo-codex/scripts/install/source-package-build.mjs +20 -0
- package/packages/omo-codex/scripts/install/toml-editor.mjs +19 -2
- package/packages/omo-codex/scripts/install-bin-links.test.mjs +23 -0
- package/packages/omo-codex/scripts/install-cli-args.test.mjs +146 -0
- package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +48 -0
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +141 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +205 -0
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +157 -0
- package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +145 -0
- package/packages/omo-codex/scripts/install-local.mjs +91 -8
- package/packages/omo-codex/scripts/install-local.test.mjs +15 -0
- package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +60 -0
- package/packages/omo-codex/scripts/install-packaged-local.test.mjs +67 -0
- package/packages/omo-codex/scripts/install-project-local-cleanup.test.mjs +277 -0
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +127 -0
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +9 -0
- package/packages/shared-skills/skills/review-work/SKILL.md +33 -8
- package/packages/shared-skills/skills/start-work/SKILL.md +25 -5
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -11
- package/postinstall.mjs +36 -3
- package/dist/hooks/context-window-monitor.d.ts +0 -19
package/dist/index.js
CHANGED
|
@@ -4503,6 +4503,7 @@ import { spawn } from "child_process";
|
|
|
4503
4503
|
async function executeHookCommand(command, stdin, cwd, options) {
|
|
4504
4504
|
const home = getHomeDirectory();
|
|
4505
4505
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS;
|
|
4506
|
+
const killGraceMs = options?.killGraceMs ?? SIGKILL_GRACE_MS;
|
|
4506
4507
|
const expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd);
|
|
4507
4508
|
let finalCommand = expandedCommand;
|
|
4508
4509
|
if (options?.forceZsh) {
|
|
@@ -4519,6 +4520,7 @@ async function executeHookCommand(command, stdin, cwd, options) {
|
|
|
4519
4520
|
}
|
|
4520
4521
|
return new Promise((resolve2) => {
|
|
4521
4522
|
let settled = false;
|
|
4523
|
+
let timedOut = false;
|
|
4522
4524
|
let killTimer = null;
|
|
4523
4525
|
const isWin32 = process.platform === "win32";
|
|
4524
4526
|
const PROTECTED_ENV_KEYS = new Set(["HOME", "CLAUDE_PROJECT_DIR"]);
|
|
@@ -4566,6 +4568,15 @@ async function executeHookCommand(command, stdin, cwd, options) {
|
|
|
4566
4568
|
resolve2(result);
|
|
4567
4569
|
};
|
|
4568
4570
|
proc.on("close", (code) => {
|
|
4571
|
+
if (timedOut) {
|
|
4572
|
+
appendTimeoutNotice();
|
|
4573
|
+
settle({
|
|
4574
|
+
exitCode: 124,
|
|
4575
|
+
stdout: stdout.trim(),
|
|
4576
|
+
stderr: stderr.trim()
|
|
4577
|
+
});
|
|
4578
|
+
return;
|
|
4579
|
+
}
|
|
4569
4580
|
settle({
|
|
4570
4581
|
exitCode: code ?? 1,
|
|
4571
4582
|
stdout: stdout.trim(),
|
|
@@ -4575,6 +4586,19 @@ async function executeHookCommand(command, stdin, cwd, options) {
|
|
|
4575
4586
|
proc.on("error", (err) => {
|
|
4576
4587
|
settle({ exitCode: 1, stderr: err.message });
|
|
4577
4588
|
});
|
|
4589
|
+
const killWindowsProcessTree = (onComplete) => {
|
|
4590
|
+
if (!proc.pid) {
|
|
4591
|
+
onComplete?.();
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
const killer = spawn("taskkill", ["/PID", String(proc.pid), "/T", "/F"], {
|
|
4595
|
+
windowsHide: true,
|
|
4596
|
+
stdio: "ignore"
|
|
4597
|
+
});
|
|
4598
|
+
const finish = () => onComplete?.();
|
|
4599
|
+
killer.on("error", finish);
|
|
4600
|
+
killer.on("close", finish);
|
|
4601
|
+
};
|
|
4578
4602
|
const killProcessGroup = (signal) => {
|
|
4579
4603
|
try {
|
|
4580
4604
|
if (!isWin32 && proc.pid) {
|
|
@@ -4585,20 +4609,57 @@ async function executeHookCommand(command, stdin, cwd, options) {
|
|
|
4585
4609
|
}
|
|
4586
4610
|
} else {
|
|
4587
4611
|
proc.kill(signal);
|
|
4612
|
+
if (signal === "SIGKILL") {
|
|
4613
|
+
killWindowsProcessTree();
|
|
4614
|
+
}
|
|
4588
4615
|
}
|
|
4589
4616
|
} catch {}
|
|
4590
4617
|
};
|
|
4618
|
+
const appendTimeoutNotice = () => {
|
|
4619
|
+
if (!stderr.includes("Hook command timed out after")) {
|
|
4620
|
+
stderr += `
|
|
4621
|
+
Hook command timed out after ${timeoutMs}ms`;
|
|
4622
|
+
}
|
|
4623
|
+
};
|
|
4591
4624
|
const timeoutTimer = setTimeout(() => {
|
|
4592
4625
|
if (settled)
|
|
4593
4626
|
return;
|
|
4627
|
+
timedOut = true;
|
|
4628
|
+
appendTimeoutNotice();
|
|
4629
|
+
if (isWin32) {
|
|
4630
|
+
killWindowsProcessTree(() => {
|
|
4631
|
+
settle({
|
|
4632
|
+
exitCode: 124,
|
|
4633
|
+
stdout: stdout.trim(),
|
|
4634
|
+
stderr: stderr.trim()
|
|
4635
|
+
});
|
|
4636
|
+
});
|
|
4637
|
+
return;
|
|
4638
|
+
}
|
|
4594
4639
|
killProcessGroup("SIGTERM");
|
|
4595
4640
|
killTimer = setTimeout(() => {
|
|
4596
4641
|
if (settled)
|
|
4597
4642
|
return;
|
|
4643
|
+
if (isWin32) {
|
|
4644
|
+
killWindowsProcessTree(() => {
|
|
4645
|
+
settle({
|
|
4646
|
+
exitCode: 124,
|
|
4647
|
+
stdout: stdout.trim(),
|
|
4648
|
+
stderr: stderr.trim()
|
|
4649
|
+
});
|
|
4650
|
+
});
|
|
4651
|
+
return;
|
|
4652
|
+
}
|
|
4598
4653
|
killProcessGroup("SIGKILL");
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4654
|
+
settle({
|
|
4655
|
+
exitCode: 124,
|
|
4656
|
+
stdout: stdout.trim(),
|
|
4657
|
+
stderr: stderr.trim()
|
|
4658
|
+
});
|
|
4659
|
+
}, killGraceMs);
|
|
4660
|
+
if (killTimer && typeof killTimer === "object" && "unref" in killTimer) {
|
|
4661
|
+
killTimer.unref();
|
|
4662
|
+
}
|
|
4602
4663
|
}, timeoutMs);
|
|
4603
4664
|
if (timeoutTimer && typeof timeoutTimer === "object" && "unref" in timeoutTimer) {
|
|
4604
4665
|
timeoutTimer.unref();
|
|
@@ -4965,8 +5026,8 @@ var init_model_requirements = __esm(() => {
|
|
|
4965
5026
|
{ providers: ["opencode-go"], model: "qwen3.5-plus" },
|
|
4966
5027
|
{ providers: ["vercel"], model: "minimax-m2.7-highspeed" },
|
|
4967
5028
|
{ providers: ["opencode-go", "vercel"], model: "minimax-m2.7" },
|
|
4968
|
-
{ providers: ["anthropic", "
|
|
4969
|
-
{ providers: ["openai", "
|
|
5029
|
+
{ providers: ["anthropic", "vercel"], model: "claude-haiku-4-5" },
|
|
5030
|
+
{ providers: ["openai", "vercel"], model: "gpt-5.4-nano" }
|
|
4970
5031
|
]
|
|
4971
5032
|
},
|
|
4972
5033
|
explore: {
|
|
@@ -4975,8 +5036,8 @@ var init_model_requirements = __esm(() => {
|
|
|
4975
5036
|
{ providers: ["opencode-go"], model: "qwen3.5-plus" },
|
|
4976
5037
|
{ providers: ["vercel"], model: "minimax-m2.7-highspeed" },
|
|
4977
5038
|
{ providers: ["opencode-go", "vercel"], model: "minimax-m2.7" },
|
|
4978
|
-
{ providers: ["anthropic", "
|
|
4979
|
-
{ providers: ["openai", "
|
|
5039
|
+
{ providers: ["anthropic", "vercel"], model: "claude-haiku-4-5" },
|
|
5040
|
+
{ providers: ["openai", "vercel"], model: "gpt-5.4-nano" }
|
|
4980
5041
|
]
|
|
4981
5042
|
},
|
|
4982
5043
|
"multimodal-looker": {
|
|
@@ -5155,7 +5216,7 @@ var init_model_requirements = __esm(() => {
|
|
|
5155
5216
|
model: "gpt-5.4-mini"
|
|
5156
5217
|
},
|
|
5157
5218
|
{
|
|
5158
|
-
providers: ["anthropic", "github-copilot", "
|
|
5219
|
+
providers: ["anthropic", "github-copilot", "vercel"],
|
|
5159
5220
|
model: "claude-haiku-4-5"
|
|
5160
5221
|
},
|
|
5161
5222
|
{
|
|
@@ -5432,7 +5493,7 @@ var init_model_capability_heuristics = __esm(() => {
|
|
|
5432
5493
|
},
|
|
5433
5494
|
{
|
|
5434
5495
|
family: "kimi",
|
|
5435
|
-
|
|
5496
|
+
pattern: /(?:kimi|k2(?![-.]?p\d))/,
|
|
5436
5497
|
variants: ["low", "medium", "high"],
|
|
5437
5498
|
supportsThinking: false
|
|
5438
5499
|
},
|
|
@@ -5673,7 +5734,7 @@ function claudeVersionDot(model) {
|
|
|
5673
5734
|
function applyGatewayTransforms(model) {
|
|
5674
5735
|
return claudeVersionDot(model).replace(GEMINI_31_PRO_PREVIEW, "gemini-3.1-pro-preview");
|
|
5675
5736
|
}
|
|
5676
|
-
function transformModelForProviderUsingAnthropicBehavior(provider, model
|
|
5737
|
+
function transformModelForProviderUsingAnthropicBehavior(provider, model) {
|
|
5677
5738
|
if (provider === "vercel") {
|
|
5678
5739
|
const slashIndex = model.indexOf("/");
|
|
5679
5740
|
if (slashIndex !== -1) {
|
|
@@ -5694,12 +5755,12 @@ function transformModelForProviderUsingAnthropicBehavior(provider, model, direct
|
|
|
5694
5755
|
return model.replace(GEMINI_31_PRO_PREVIEW, "gemini-3.1-pro-preview").replace(GEMINI_3_FLASH_PREVIEW, "gemini-3-flash-preview");
|
|
5695
5756
|
}
|
|
5696
5757
|
if (provider === "anthropic") {
|
|
5697
|
-
return
|
|
5758
|
+
return model;
|
|
5698
5759
|
}
|
|
5699
5760
|
return model;
|
|
5700
5761
|
}
|
|
5701
5762
|
function transformModelForProvider(provider, model) {
|
|
5702
|
-
return transformModelForProviderUsingAnthropicBehavior(provider, model
|
|
5763
|
+
return transformModelForProviderUsingAnthropicBehavior(provider, model);
|
|
5703
5764
|
}
|
|
5704
5765
|
var CLAUDE_VERSION_DOT, GEMINI_31_PRO_PREVIEW, GEMINI_3_FLASH_PREVIEW;
|
|
5705
5766
|
var init_provider_model_id_transform = __esm(() => {
|
|
@@ -8736,8 +8797,30 @@ function resolveConfigPath(pathValue) {
|
|
|
8736
8797
|
return resolvedPath;
|
|
8737
8798
|
}
|
|
8738
8799
|
}
|
|
8800
|
+
function isWslEnvironment() {
|
|
8801
|
+
return process.platform === "linux" && (Boolean(process.env.WSL_DISTRO_NAME?.trim()) || Boolean(process.env.WSL_INTEROP?.trim()));
|
|
8802
|
+
}
|
|
8803
|
+
function isWindowsUserConfigRoot(pathValue) {
|
|
8804
|
+
const normalizedPath = pathValue.replaceAll("\\", "/").toLowerCase();
|
|
8805
|
+
return /^[a-z]:\/users\//.test(normalizedPath) || /^\/mnt\/[a-z]\/users\//.test(normalizedPath);
|
|
8806
|
+
}
|
|
8807
|
+
function getWindowsUserFromConfigRoot(pathValue) {
|
|
8808
|
+
const normalizedPath = pathValue.replaceAll("\\", "/");
|
|
8809
|
+
const match = /^(?:[a-z]:|\/mnt\/[a-z])\/Users\/([^/]+)/i.exec(normalizedPath);
|
|
8810
|
+
return match?.[1] ?? null;
|
|
8811
|
+
}
|
|
8812
|
+
function getWslLinuxHomeDir(windowsConfigRoot) {
|
|
8813
|
+
const envHome = process.env.HOME?.trim();
|
|
8814
|
+
if (envHome && envHome.startsWith("/") && !isWindowsUserConfigRoot(envHome)) {
|
|
8815
|
+
return envHome;
|
|
8816
|
+
}
|
|
8817
|
+
const user = process.env.USER?.trim() || process.env.LOGNAME?.trim() || process.env.SUDO_USER?.trim() || (windowsConfigRoot ? getWindowsUserFromConfigRoot(windowsConfigRoot) : undefined);
|
|
8818
|
+
return user ? join6("/home", user) : null;
|
|
8819
|
+
}
|
|
8739
8820
|
function getCliDefaultConfigDir() {
|
|
8740
|
-
const
|
|
8821
|
+
const envXdgConfig = process.env.XDG_CONFIG_HOME?.trim();
|
|
8822
|
+
const shouldIgnoreWindowsXdg = envXdgConfig !== undefined && envXdgConfig.length > 0 && isWslEnvironment() && isWindowsUserConfigRoot(envXdgConfig);
|
|
8823
|
+
const xdgConfig = shouldIgnoreWindowsXdg ? join6(getWslLinuxHomeDir(envXdgConfig) ?? "/home", ".config") : envXdgConfig || join6(homedir5(), ".config");
|
|
8741
8824
|
return resolveConfigPath(join6(xdgConfig, "opencode"));
|
|
8742
8825
|
}
|
|
8743
8826
|
function getCliCustomConfigDir() {
|
|
@@ -54030,7 +54113,7 @@ function buildTmuxAttachCommand(serverUrl, sessionId, directory = process.cwd())
|
|
|
54030
54113
|
}
|
|
54031
54114
|
function buildTmuxPlaceholderCommand(description) {
|
|
54032
54115
|
const escapedDescription = shellEscapeForDoubleQuotedCommand(description);
|
|
54033
|
-
return `${TMUX_COMMAND_SHELL} -c "printf '%s\\n%s\\n' "OMO subagent pane ready: ${escapedDescription}" "Focus this pane to attach
|
|
54116
|
+
return `${TMUX_COMMAND_SHELL} -c "printf '%s\\n%s\\n' \\"OMO subagent pane ready: ${escapedDescription}\\" \\"Focus this pane to attach.\\"; while :; do sleep 86400; done"`;
|
|
54034
54117
|
}
|
|
54035
54118
|
var TMUX_COMMAND_SHELL = "/bin/sh";
|
|
54036
54119
|
var init_pane_command = () => {};
|
|
@@ -55033,7 +55116,7 @@ async function withDispatchTimeout(operation, dispatchTimeoutMs, operationName)
|
|
|
55033
55116
|
}
|
|
55034
55117
|
}
|
|
55035
55118
|
}
|
|
55036
|
-
var DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS = 2000, DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS = 30000, DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS = 5000, DEFAULT_PROMPT_QUEUE_RETRY_MS = 250, promptGateMessagesFetchTimeoutMsForTesting;
|
|
55119
|
+
var DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS = 2000, DEFAULT_PROMPT_SEMANTIC_DEDUPE_HOLD_MS = 15000, DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS = 30000, DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS = 5000, DEFAULT_PROMPT_QUEUE_RETRY_MS = 250, promptGateMessagesFetchTimeoutMsForTesting;
|
|
55037
55120
|
|
|
55038
55121
|
// src/shared/prompt-async-gate/pending-tool-turn.ts
|
|
55039
55122
|
function getPromptQuery(input) {
|
|
@@ -55146,6 +55229,45 @@ var init_pending_tool_turn = __esm(() => {
|
|
|
55146
55229
|
init_message_inspection_error();
|
|
55147
55230
|
});
|
|
55148
55231
|
|
|
55232
|
+
// src/shared/prompt-async-gate/recent-dispatches.ts
|
|
55233
|
+
function recentDispatchKey(sessionID, dedupeKey) {
|
|
55234
|
+
return `${sessionID}\x00${dedupeKey}`;
|
|
55235
|
+
}
|
|
55236
|
+
function pruneRecentPromptDispatches(now = Date.now()) {
|
|
55237
|
+
for (const [key, dispatch] of recentPromptDispatches) {
|
|
55238
|
+
if (dispatch.expiresAt <= now) {
|
|
55239
|
+
recentPromptDispatches.delete(key);
|
|
55240
|
+
}
|
|
55241
|
+
}
|
|
55242
|
+
}
|
|
55243
|
+
function getRecentPromptDispatch(sessionID, dedupeKey) {
|
|
55244
|
+
pruneRecentPromptDispatches();
|
|
55245
|
+
return recentPromptDispatches.get(recentDispatchKey(sessionID, dedupeKey));
|
|
55246
|
+
}
|
|
55247
|
+
function rememberRecentPromptDispatch(args) {
|
|
55248
|
+
pruneRecentPromptDispatches();
|
|
55249
|
+
if (args.holdMs <= 0) {
|
|
55250
|
+
return;
|
|
55251
|
+
}
|
|
55252
|
+
recentPromptDispatches.set(recentDispatchKey(args.sessionID, args.dedupeKey), {
|
|
55253
|
+
source: args.source,
|
|
55254
|
+
expiresAt: Date.now() + args.holdMs
|
|
55255
|
+
});
|
|
55256
|
+
log("[prompt-async-gate] remembered semantic prompt dispatch", {
|
|
55257
|
+
sessionID: args.sessionID,
|
|
55258
|
+
source: args.source,
|
|
55259
|
+
holdMs: args.holdMs
|
|
55260
|
+
});
|
|
55261
|
+
}
|
|
55262
|
+
function deleteRecentPromptDispatch(sessionID, dedupeKey) {
|
|
55263
|
+
recentPromptDispatches.delete(recentDispatchKey(sessionID, dedupeKey));
|
|
55264
|
+
}
|
|
55265
|
+
var recentPromptDispatches;
|
|
55266
|
+
var init_recent_dispatches = __esm(() => {
|
|
55267
|
+
init_logger();
|
|
55268
|
+
recentPromptDispatches = new Map;
|
|
55269
|
+
});
|
|
55270
|
+
|
|
55149
55271
|
// src/shared/prompt-async-gate/reservations.ts
|
|
55150
55272
|
function setExpiredReservationHandler(handler) {
|
|
55151
55273
|
expiredReservationHandler = handler;
|
|
@@ -55227,6 +55349,7 @@ async function dispatchAfterSessionIdle(args) {
|
|
|
55227
55349
|
dedupeKey,
|
|
55228
55350
|
settleMs,
|
|
55229
55351
|
postDispatchHoldMs,
|
|
55352
|
+
semanticDedupeHoldMs,
|
|
55230
55353
|
dispatchTimeoutMs,
|
|
55231
55354
|
checkStatus,
|
|
55232
55355
|
checkToolState,
|
|
@@ -55284,10 +55407,25 @@ async function dispatchAfterSessionIdle(args) {
|
|
|
55284
55407
|
log(`[prompt-async-gate] ${sessionName} dispatching`, { sessionID, source });
|
|
55285
55408
|
dispatchAttempted = true;
|
|
55286
55409
|
const response = await withDispatchTimeout(dispatch(input), dispatchTimeoutMs, `[prompt-async-gate] ${sessionName} dispatch`);
|
|
55410
|
+
rememberRecentPromptDispatch({
|
|
55411
|
+
sessionID,
|
|
55412
|
+
dedupeKey,
|
|
55413
|
+
source,
|
|
55414
|
+
holdMs: semanticDedupeHoldMs
|
|
55415
|
+
});
|
|
55287
55416
|
log(`[prompt-async-gate] ${sessionName} dispatched`, { sessionID, source });
|
|
55288
55417
|
return { status: "dispatched", response };
|
|
55289
55418
|
} catch (error) {
|
|
55290
|
-
|
|
55419
|
+
if (dispatchAttempted) {
|
|
55420
|
+
rememberRecentPromptDispatch({
|
|
55421
|
+
sessionID,
|
|
55422
|
+
dedupeKey,
|
|
55423
|
+
source,
|
|
55424
|
+
holdMs: semanticDedupeHoldMs
|
|
55425
|
+
});
|
|
55426
|
+
}
|
|
55427
|
+
const errorText = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
55428
|
+
log(`[prompt-async-gate] ${sessionName} failed`, { sessionID, source, error: errorText });
|
|
55291
55429
|
return { status: "failed", error, dispatchAttempted };
|
|
55292
55430
|
} finally {
|
|
55293
55431
|
finishPromptReservation(sessionID, reservation, dispatchAttempted, postDispatchHoldMs);
|
|
@@ -55297,6 +55435,7 @@ var init_session_idle_dispatch = __esm(() => {
|
|
|
55297
55435
|
init_logger();
|
|
55298
55436
|
init_session_idle_settle();
|
|
55299
55437
|
init_pending_tool_turn();
|
|
55438
|
+
init_recent_dispatches();
|
|
55300
55439
|
init_reservations();
|
|
55301
55440
|
});
|
|
55302
55441
|
|
|
@@ -55404,6 +55543,7 @@ async function drainPromptQueue(sessionID, awaitedEntry) {
|
|
|
55404
55543
|
dedupeKey: entry.dedupeKey,
|
|
55405
55544
|
settleMs: entry.settleMs,
|
|
55406
55545
|
postDispatchHoldMs: entry.postDispatchHoldMs,
|
|
55546
|
+
semanticDedupeHoldMs: entry.semanticDedupeHoldMs,
|
|
55407
55547
|
dispatchTimeoutMs: entry.dispatchTimeoutMs,
|
|
55408
55548
|
checkStatus: entry.checkStatus,
|
|
55409
55549
|
checkToolState: entry.checkToolState,
|
|
@@ -55487,27 +55627,119 @@ var init_queue = __esm(() => {
|
|
|
55487
55627
|
});
|
|
55488
55628
|
});
|
|
55489
55629
|
|
|
55490
|
-
// src/shared/prompt-async-gate.ts
|
|
55630
|
+
// src/shared/prompt-async-gate/semantic-dedupe.ts
|
|
55631
|
+
import { createHash } from "crypto";
|
|
55632
|
+
function isPlainRecord(value) {
|
|
55633
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
55634
|
+
return false;
|
|
55635
|
+
}
|
|
55636
|
+
const prototype = Object.getPrototypeOf(value);
|
|
55637
|
+
return prototype === Object.prototype || prototype === null;
|
|
55638
|
+
}
|
|
55639
|
+
function canonicalizePromptInputForDedupe(key, value, seen = new WeakSet, depth = 0) {
|
|
55640
|
+
if (key === "signal") {
|
|
55641
|
+
return "[AbortSignal]";
|
|
55642
|
+
}
|
|
55643
|
+
if (typeof value === "function") {
|
|
55644
|
+
return `[Function:${value.name}]`;
|
|
55645
|
+
}
|
|
55646
|
+
if (depth > MAX_PROMPT_DEDUPE_DEPTH) {
|
|
55647
|
+
return "[MaxDepth]";
|
|
55648
|
+
}
|
|
55649
|
+
if (Array.isArray(value)) {
|
|
55650
|
+
if (seen.has(value)) {
|
|
55651
|
+
return "[Circular]";
|
|
55652
|
+
}
|
|
55653
|
+
seen.add(value);
|
|
55654
|
+
try {
|
|
55655
|
+
return value.map((entry) => canonicalizePromptInputForDedupe("", entry, seen, depth + 1));
|
|
55656
|
+
} finally {
|
|
55657
|
+
seen.delete(value);
|
|
55658
|
+
}
|
|
55659
|
+
}
|
|
55660
|
+
if (!isPlainRecord(value)) {
|
|
55661
|
+
return value;
|
|
55662
|
+
}
|
|
55663
|
+
if (seen.has(value)) {
|
|
55664
|
+
return "[Circular]";
|
|
55665
|
+
}
|
|
55666
|
+
seen.add(value);
|
|
55667
|
+
try {
|
|
55668
|
+
const canonicalEntries = [];
|
|
55669
|
+
for (const entryKey of Object.keys(value).sort()) {
|
|
55670
|
+
canonicalEntries.push([
|
|
55671
|
+
entryKey,
|
|
55672
|
+
canonicalizePromptInputForDedupe(entryKey, value[entryKey], seen, depth + 1)
|
|
55673
|
+
]);
|
|
55674
|
+
}
|
|
55675
|
+
return Object.fromEntries(canonicalEntries);
|
|
55676
|
+
} finally {
|
|
55677
|
+
seen.delete(value);
|
|
55678
|
+
}
|
|
55679
|
+
}
|
|
55680
|
+
function isContinuationTextPartLike(value) {
|
|
55681
|
+
if (!isPlainRecord(value)) {
|
|
55682
|
+
return false;
|
|
55683
|
+
}
|
|
55684
|
+
if (value.type !== "text" || typeof value.text !== "string") {
|
|
55685
|
+
return false;
|
|
55686
|
+
}
|
|
55687
|
+
if (!hasInternalInitiatorMarker(value.text)) {
|
|
55688
|
+
return false;
|
|
55689
|
+
}
|
|
55690
|
+
if (!isPlainRecord(value.metadata)) {
|
|
55691
|
+
return false;
|
|
55692
|
+
}
|
|
55693
|
+
return value.metadata.compaction_continue === true;
|
|
55694
|
+
}
|
|
55695
|
+
function hasContinuationPromptIntent(input) {
|
|
55696
|
+
if (!isPlainRecord(input) || !isPlainRecord(input.body) || !Array.isArray(input.body.parts)) {
|
|
55697
|
+
return false;
|
|
55698
|
+
}
|
|
55699
|
+
return input.body.parts.some((part) => isContinuationTextPartLike(part));
|
|
55700
|
+
}
|
|
55701
|
+
function normalizePromptInputForSemanticDedupe(input) {
|
|
55702
|
+
if (hasContinuationPromptIntent(input)) {
|
|
55703
|
+
return {
|
|
55704
|
+
__omo_internal_intent: "continuation"
|
|
55705
|
+
};
|
|
55706
|
+
}
|
|
55707
|
+
return canonicalizePromptInputForDedupe("", input);
|
|
55708
|
+
}
|
|
55491
55709
|
function stringifyPromptInputForDedupe(input) {
|
|
55492
55710
|
try {
|
|
55493
|
-
const serialized = JSON.stringify(input
|
|
55494
|
-
if (key === "signal") {
|
|
55495
|
-
return "[AbortSignal]";
|
|
55496
|
-
}
|
|
55497
|
-
if (typeof value === "function") {
|
|
55498
|
-
return `[Function:${value.name}]`;
|
|
55499
|
-
}
|
|
55500
|
-
return value;
|
|
55501
|
-
});
|
|
55711
|
+
const serialized = JSON.stringify(normalizePromptInputForSemanticDedupe(input));
|
|
55502
55712
|
return serialized ?? String(input);
|
|
55503
|
-
} catch {
|
|
55504
|
-
|
|
55713
|
+
} catch (error) {
|
|
55714
|
+
const errorTag = error instanceof Error ? error.name : String(error);
|
|
55715
|
+
return `${String(input)}:[unserializable:${errorTag}]`;
|
|
55505
55716
|
}
|
|
55506
55717
|
}
|
|
55507
|
-
function
|
|
55718
|
+
function createSemanticPromptDedupeKey(input) {
|
|
55508
55719
|
const fingerprint = stringifyPromptInputForDedupe(input);
|
|
55509
|
-
|
|
55720
|
+
const digest = createHash("sha256").update(fingerprint, "utf8").digest("hex");
|
|
55721
|
+
return `semantic:${digest}`;
|
|
55510
55722
|
}
|
|
55723
|
+
function coalesceRecentSemanticPromptDispatch(args) {
|
|
55724
|
+
const recentDispatch = getRecentPromptDispatch(args.sessionID, args.dedupeKey);
|
|
55725
|
+
if (!recentDispatch) {
|
|
55726
|
+
return;
|
|
55727
|
+
}
|
|
55728
|
+
log("[prompt-async-gate] prompt coalesced with recent semantic dispatch", {
|
|
55729
|
+
sessionID: args.sessionID,
|
|
55730
|
+
source: args.source,
|
|
55731
|
+
queuedBy: recentDispatch.source
|
|
55732
|
+
});
|
|
55733
|
+
return { status: "queued", queuedBy: recentDispatch.source, position: 0 };
|
|
55734
|
+
}
|
|
55735
|
+
var MAX_PROMPT_DEDUPE_DEPTH = 64;
|
|
55736
|
+
var init_semantic_dedupe = __esm(() => {
|
|
55737
|
+
init_internal_initiator_marker();
|
|
55738
|
+
init_logger();
|
|
55739
|
+
init_recent_dispatches();
|
|
55740
|
+
});
|
|
55741
|
+
|
|
55742
|
+
// src/shared/prompt-async-gate.ts
|
|
55511
55743
|
function hasObjectSessionPath(input) {
|
|
55512
55744
|
return typeof input === "object" && input !== null && "path" in input && typeof input.path === "object" && input.path !== null && "id" in input.path && typeof input.path.id === "string";
|
|
55513
55745
|
}
|
|
@@ -55537,9 +55769,10 @@ async function dispatchInternalPrompt(args) {
|
|
|
55537
55769
|
source,
|
|
55538
55770
|
settleMs = DEFAULT_SESSION_IDLE_SETTLE_MS
|
|
55539
55771
|
} = args;
|
|
55540
|
-
const dedupeKey = args.dedupeKey ??
|
|
55772
|
+
const dedupeKey = args.dedupeKey ?? createSemanticPromptDedupeKey(input);
|
|
55541
55773
|
const queueRetryMs = args.queueRetryMs ?? DEFAULT_PROMPT_QUEUE_RETRY_MS;
|
|
55542
55774
|
const postDispatchHoldMs = args.postDispatchHoldMs ?? DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS;
|
|
55775
|
+
const semanticDedupeHoldMs = args.semanticDedupeHoldMs ?? (postDispatchHoldMs > 0 ? DEFAULT_PROMPT_SEMANTIC_DEDUPE_HOLD_MS : 0);
|
|
55543
55776
|
const dispatchTimeoutMs = args.dispatchTimeoutMs ?? DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS;
|
|
55544
55777
|
const sessionName = args.mode === "async" ? "promptAsync" : "prompt";
|
|
55545
55778
|
const dispatch = (() => {
|
|
@@ -55572,6 +55805,10 @@ async function dispatchInternalPrompt(args) {
|
|
|
55572
55805
|
if (queuedBy !== undefined || isPromptQueueDraining(sessionID)) {
|
|
55573
55806
|
return { status: "reserved", reservedBy: queuedBy ?? source };
|
|
55574
55807
|
}
|
|
55808
|
+
const recentDispatchResult2 = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
|
|
55809
|
+
if (recentDispatchResult2) {
|
|
55810
|
+
return recentDispatchResult2;
|
|
55811
|
+
}
|
|
55575
55812
|
return dispatchAfterSessionIdle({
|
|
55576
55813
|
sessionName,
|
|
55577
55814
|
client,
|
|
@@ -55581,6 +55818,7 @@ async function dispatchInternalPrompt(args) {
|
|
|
55581
55818
|
dedupeKey,
|
|
55582
55819
|
settleMs,
|
|
55583
55820
|
postDispatchHoldMs,
|
|
55821
|
+
semanticDedupeHoldMs,
|
|
55584
55822
|
dispatchTimeoutMs,
|
|
55585
55823
|
checkStatus: args.checkStatus !== false,
|
|
55586
55824
|
checkToolState: args.checkToolState !== false,
|
|
@@ -55588,6 +55826,10 @@ async function dispatchInternalPrompt(args) {
|
|
|
55588
55826
|
});
|
|
55589
55827
|
}
|
|
55590
55828
|
if (args.queue !== false) {
|
|
55829
|
+
const recentDispatchResult2 = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
|
|
55830
|
+
if (recentDispatchResult2) {
|
|
55831
|
+
return recentDispatchResult2;
|
|
55832
|
+
}
|
|
55591
55833
|
return enqueueInternalPrompt({
|
|
55592
55834
|
id: nextPromptQueueID(),
|
|
55593
55835
|
sessionID,
|
|
@@ -55598,6 +55840,7 @@ async function dispatchInternalPrompt(args) {
|
|
|
55598
55840
|
dedupeKey,
|
|
55599
55841
|
settleMs,
|
|
55600
55842
|
postDispatchHoldMs,
|
|
55843
|
+
semanticDedupeHoldMs,
|
|
55601
55844
|
dispatchTimeoutMs,
|
|
55602
55845
|
queueRetryMs,
|
|
55603
55846
|
checkStatus: args.checkStatus !== false,
|
|
@@ -55605,6 +55848,10 @@ async function dispatchInternalPrompt(args) {
|
|
|
55605
55848
|
dispatch: async (_dispatchInput) => dispatchWithPathCompatibility(dispatch, input)
|
|
55606
55849
|
});
|
|
55607
55850
|
}
|
|
55851
|
+
const recentDispatchResult = coalesceRecentSemanticPromptDispatch({ sessionID, dedupeKey, source });
|
|
55852
|
+
if (recentDispatchResult) {
|
|
55853
|
+
return recentDispatchResult;
|
|
55854
|
+
}
|
|
55608
55855
|
return dispatchAfterSessionIdle({
|
|
55609
55856
|
sessionName,
|
|
55610
55857
|
client,
|
|
@@ -55614,6 +55861,7 @@ async function dispatchInternalPrompt(args) {
|
|
|
55614
55861
|
dedupeKey,
|
|
55615
55862
|
settleMs,
|
|
55616
55863
|
postDispatchHoldMs,
|
|
55864
|
+
semanticDedupeHoldMs,
|
|
55617
55865
|
dispatchTimeoutMs,
|
|
55618
55866
|
checkStatus: args.checkStatus !== false,
|
|
55619
55867
|
checkToolState: args.checkToolState !== false,
|
|
@@ -55638,6 +55886,7 @@ function releasePromptAsyncReservation(sessionID, source, options) {
|
|
|
55638
55886
|
return false;
|
|
55639
55887
|
}
|
|
55640
55888
|
deletePromptReservation(sessionID);
|
|
55889
|
+
deleteRecentPromptDispatch(sessionID, existing.dedupeKey);
|
|
55641
55890
|
releaseInFlightPromptMatchingDedupe(sessionID, existing.dedupeKey);
|
|
55642
55891
|
schedulePromptQueueDrain(sessionID, 0);
|
|
55643
55892
|
log("[prompt-async-gate] promptAsync reservation released", {
|
|
@@ -55651,8 +55900,10 @@ var init_prompt_async_gate = __esm(() => {
|
|
|
55651
55900
|
init_logger();
|
|
55652
55901
|
init_session_idle_settle();
|
|
55653
55902
|
init_queue();
|
|
55903
|
+
init_recent_dispatches();
|
|
55654
55904
|
init_reservations();
|
|
55655
55905
|
init_session_idle_dispatch();
|
|
55906
|
+
init_semantic_dedupe();
|
|
55656
55907
|
});
|
|
55657
55908
|
|
|
55658
55909
|
// src/shared/prompt-failure-classifier.ts
|
|
@@ -63914,8 +64165,8 @@ var require_utils2 = __commonJS((exports, module) => {
|
|
|
63914
64165
|
}
|
|
63915
64166
|
return ind;
|
|
63916
64167
|
}
|
|
63917
|
-
function removeDotSegments(
|
|
63918
|
-
let input =
|
|
64168
|
+
function removeDotSegments(path22) {
|
|
64169
|
+
let input = path22;
|
|
63919
64170
|
const output = [];
|
|
63920
64171
|
let nextSlash = -1;
|
|
63921
64172
|
let len = 0;
|
|
@@ -64158,8 +64409,8 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
64158
64409
|
wsComponent.secure = undefined;
|
|
64159
64410
|
}
|
|
64160
64411
|
if (wsComponent.resourceName) {
|
|
64161
|
-
const [
|
|
64162
|
-
wsComponent.path =
|
|
64412
|
+
const [path22, query] = wsComponent.resourceName.split("?");
|
|
64413
|
+
wsComponent.path = path22 && path22 !== "/" ? path22 : undefined;
|
|
64163
64414
|
wsComponent.query = query;
|
|
64164
64415
|
wsComponent.resourceName = undefined;
|
|
64165
64416
|
}
|
|
@@ -67334,12 +67585,12 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
67334
67585
|
throw new Error(`Unknown format "${name}"`);
|
|
67335
67586
|
return f;
|
|
67336
67587
|
};
|
|
67337
|
-
function addFormats(ajv, list,
|
|
67588
|
+
function addFormats(ajv, list, fs23, exportName) {
|
|
67338
67589
|
var _a;
|
|
67339
67590
|
var _b;
|
|
67340
67591
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
|
|
67341
67592
|
for (const f of list)
|
|
67342
|
-
ajv.addFormat(f,
|
|
67593
|
+
ajv.addFormat(f, fs23[f]);
|
|
67343
67594
|
}
|
|
67344
67595
|
module.exports = exports = formatsPlugin;
|
|
67345
67596
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -67350,8 +67601,8 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
67350
67601
|
var require_windows = __commonJS((exports, module) => {
|
|
67351
67602
|
module.exports = isexe;
|
|
67352
67603
|
isexe.sync = sync;
|
|
67353
|
-
var
|
|
67354
|
-
function checkPathExt(
|
|
67604
|
+
var fs23 = __require("fs");
|
|
67605
|
+
function checkPathExt(path22, options) {
|
|
67355
67606
|
var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
|
|
67356
67607
|
if (!pathext) {
|
|
67357
67608
|
return true;
|
|
@@ -67362,25 +67613,25 @@ var require_windows = __commonJS((exports, module) => {
|
|
|
67362
67613
|
}
|
|
67363
67614
|
for (var i2 = 0;i2 < pathext.length; i2++) {
|
|
67364
67615
|
var p = pathext[i2].toLowerCase();
|
|
67365
|
-
if (p &&
|
|
67616
|
+
if (p && path22.substr(-p.length).toLowerCase() === p) {
|
|
67366
67617
|
return true;
|
|
67367
67618
|
}
|
|
67368
67619
|
}
|
|
67369
67620
|
return false;
|
|
67370
67621
|
}
|
|
67371
|
-
function checkStat(stat7,
|
|
67622
|
+
function checkStat(stat7, path22, options) {
|
|
67372
67623
|
if (!stat7.isSymbolicLink() && !stat7.isFile()) {
|
|
67373
67624
|
return false;
|
|
67374
67625
|
}
|
|
67375
|
-
return checkPathExt(
|
|
67626
|
+
return checkPathExt(path22, options);
|
|
67376
67627
|
}
|
|
67377
|
-
function isexe(
|
|
67378
|
-
|
|
67379
|
-
cb(er, er ? false : checkStat(stat7,
|
|
67628
|
+
function isexe(path22, options, cb) {
|
|
67629
|
+
fs23.stat(path22, function(er, stat7) {
|
|
67630
|
+
cb(er, er ? false : checkStat(stat7, path22, options));
|
|
67380
67631
|
});
|
|
67381
67632
|
}
|
|
67382
|
-
function sync(
|
|
67383
|
-
return checkStat(
|
|
67633
|
+
function sync(path22, options) {
|
|
67634
|
+
return checkStat(fs23.statSync(path22), path22, options);
|
|
67384
67635
|
}
|
|
67385
67636
|
});
|
|
67386
67637
|
|
|
@@ -67388,14 +67639,14 @@ var require_windows = __commonJS((exports, module) => {
|
|
|
67388
67639
|
var require_mode = __commonJS((exports, module) => {
|
|
67389
67640
|
module.exports = isexe;
|
|
67390
67641
|
isexe.sync = sync;
|
|
67391
|
-
var
|
|
67392
|
-
function isexe(
|
|
67393
|
-
|
|
67642
|
+
var fs23 = __require("fs");
|
|
67643
|
+
function isexe(path22, options, cb) {
|
|
67644
|
+
fs23.stat(path22, function(er, stat7) {
|
|
67394
67645
|
cb(er, er ? false : checkStat(stat7, options));
|
|
67395
67646
|
});
|
|
67396
67647
|
}
|
|
67397
|
-
function sync(
|
|
67398
|
-
return checkStat(
|
|
67648
|
+
function sync(path22, options) {
|
|
67649
|
+
return checkStat(fs23.statSync(path22), options);
|
|
67399
67650
|
}
|
|
67400
67651
|
function checkStat(stat7, options) {
|
|
67401
67652
|
return stat7.isFile() && checkMode(stat7, options);
|
|
@@ -67417,7 +67668,7 @@ var require_mode = __commonJS((exports, module) => {
|
|
|
67417
67668
|
|
|
67418
67669
|
// node_modules/.bun/isexe@2.0.0/node_modules/isexe/index.js
|
|
67419
67670
|
var require_isexe = __commonJS((exports, module) => {
|
|
67420
|
-
var
|
|
67671
|
+
var fs23 = __require("fs");
|
|
67421
67672
|
var core2;
|
|
67422
67673
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
67423
67674
|
core2 = require_windows();
|
|
@@ -67426,7 +67677,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67426
67677
|
}
|
|
67427
67678
|
module.exports = isexe;
|
|
67428
67679
|
isexe.sync = sync;
|
|
67429
|
-
function isexe(
|
|
67680
|
+
function isexe(path22, options, cb) {
|
|
67430
67681
|
if (typeof options === "function") {
|
|
67431
67682
|
cb = options;
|
|
67432
67683
|
options = {};
|
|
@@ -67436,7 +67687,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67436
67687
|
throw new TypeError("callback not provided");
|
|
67437
67688
|
}
|
|
67438
67689
|
return new Promise(function(resolve25, reject) {
|
|
67439
|
-
isexe(
|
|
67690
|
+
isexe(path22, options || {}, function(er, is) {
|
|
67440
67691
|
if (er) {
|
|
67441
67692
|
reject(er);
|
|
67442
67693
|
} else {
|
|
@@ -67445,7 +67696,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67445
67696
|
});
|
|
67446
67697
|
});
|
|
67447
67698
|
}
|
|
67448
|
-
core2(
|
|
67699
|
+
core2(path22, options || {}, function(er, is) {
|
|
67449
67700
|
if (er) {
|
|
67450
67701
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
67451
67702
|
er = null;
|
|
@@ -67455,9 +67706,9 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67455
67706
|
cb(er, is);
|
|
67456
67707
|
});
|
|
67457
67708
|
}
|
|
67458
|
-
function sync(
|
|
67709
|
+
function sync(path22, options) {
|
|
67459
67710
|
try {
|
|
67460
|
-
return core2.sync(
|
|
67711
|
+
return core2.sync(path22, options || {});
|
|
67461
67712
|
} catch (er) {
|
|
67462
67713
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
67463
67714
|
return false;
|
|
@@ -67471,7 +67722,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67471
67722
|
// node_modules/.bun/which@2.0.2/node_modules/which/which.js
|
|
67472
67723
|
var require_which = __commonJS((exports, module) => {
|
|
67473
67724
|
var isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
67474
|
-
var
|
|
67725
|
+
var path22 = __require("path");
|
|
67475
67726
|
var COLON = isWindows2 ? ";" : ":";
|
|
67476
67727
|
var isexe = require_isexe();
|
|
67477
67728
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -67507,7 +67758,7 @@ var require_which = __commonJS((exports, module) => {
|
|
|
67507
67758
|
return opt.all && found.length ? resolve25(found) : reject(getNotFoundError(cmd));
|
|
67508
67759
|
const ppRaw = pathEnv[i2];
|
|
67509
67760
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
67510
|
-
const pCmd =
|
|
67761
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
67511
67762
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
67512
67763
|
resolve25(subStep(p, i2, 0));
|
|
67513
67764
|
});
|
|
@@ -67534,7 +67785,7 @@ var require_which = __commonJS((exports, module) => {
|
|
|
67534
67785
|
for (let i2 = 0;i2 < pathEnv.length; i2++) {
|
|
67535
67786
|
const ppRaw = pathEnv[i2];
|
|
67536
67787
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
67537
|
-
const pCmd =
|
|
67788
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
67538
67789
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
67539
67790
|
for (let j = 0;j < pathExt.length; j++) {
|
|
67540
67791
|
const cur = p + pathExt[j];
|
|
@@ -67575,7 +67826,7 @@ var require_path_key = __commonJS((exports, module) => {
|
|
|
67575
67826
|
|
|
67576
67827
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
67577
67828
|
var require_resolveCommand = __commonJS((exports, module) => {
|
|
67578
|
-
var
|
|
67829
|
+
var path22 = __require("path");
|
|
67579
67830
|
var which = require_which();
|
|
67580
67831
|
var getPathKey = require_path_key();
|
|
67581
67832
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -67592,7 +67843,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
|
|
|
67592
67843
|
try {
|
|
67593
67844
|
resolved = which.sync(parsed.command, {
|
|
67594
67845
|
path: env[getPathKey({ env })],
|
|
67595
|
-
pathExt: withoutPathExt ?
|
|
67846
|
+
pathExt: withoutPathExt ? path22.delimiter : undefined
|
|
67596
67847
|
});
|
|
67597
67848
|
} catch (e) {} finally {
|
|
67598
67849
|
if (shouldSwitchCwd) {
|
|
@@ -67600,7 +67851,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
|
|
|
67600
67851
|
}
|
|
67601
67852
|
}
|
|
67602
67853
|
if (resolved) {
|
|
67603
|
-
resolved =
|
|
67854
|
+
resolved = path22.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
67604
67855
|
}
|
|
67605
67856
|
return resolved;
|
|
67606
67857
|
}
|
|
@@ -67645,8 +67896,8 @@ var require_shebang_command = __commonJS((exports, module) => {
|
|
|
67645
67896
|
if (!match) {
|
|
67646
67897
|
return null;
|
|
67647
67898
|
}
|
|
67648
|
-
const [
|
|
67649
|
-
const binary2 =
|
|
67899
|
+
const [path22, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
67900
|
+
const binary2 = path22.split("/").pop();
|
|
67650
67901
|
if (binary2 === "env") {
|
|
67651
67902
|
return argument;
|
|
67652
67903
|
}
|
|
@@ -67656,16 +67907,16 @@ var require_shebang_command = __commonJS((exports, module) => {
|
|
|
67656
67907
|
|
|
67657
67908
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
|
|
67658
67909
|
var require_readShebang = __commonJS((exports, module) => {
|
|
67659
|
-
var
|
|
67910
|
+
var fs23 = __require("fs");
|
|
67660
67911
|
var shebangCommand = require_shebang_command();
|
|
67661
67912
|
function readShebang(command) {
|
|
67662
67913
|
const size = 150;
|
|
67663
67914
|
const buffer2 = Buffer.alloc(size);
|
|
67664
67915
|
let fd;
|
|
67665
67916
|
try {
|
|
67666
|
-
fd =
|
|
67667
|
-
|
|
67668
|
-
|
|
67917
|
+
fd = fs23.openSync(command, "r");
|
|
67918
|
+
fs23.readSync(fd, buffer2, 0, size, 0);
|
|
67919
|
+
fs23.closeSync(fd);
|
|
67669
67920
|
} catch (e) {}
|
|
67670
67921
|
return shebangCommand(buffer2.toString());
|
|
67671
67922
|
}
|
|
@@ -67674,7 +67925,7 @@ var require_readShebang = __commonJS((exports, module) => {
|
|
|
67674
67925
|
|
|
67675
67926
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
|
|
67676
67927
|
var require_parse2 = __commonJS((exports, module) => {
|
|
67677
|
-
var
|
|
67928
|
+
var path22 = __require("path");
|
|
67678
67929
|
var resolveCommand2 = require_resolveCommand();
|
|
67679
67930
|
var escape2 = require_escape();
|
|
67680
67931
|
var readShebang = require_readShebang();
|
|
@@ -67699,7 +67950,7 @@ var require_parse2 = __commonJS((exports, module) => {
|
|
|
67699
67950
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
67700
67951
|
if (parsed.options.forceShell || needsShell) {
|
|
67701
67952
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
67702
|
-
parsed.command =
|
|
67953
|
+
parsed.command = path22.normalize(parsed.command);
|
|
67703
67954
|
parsed.command = escape2.command(parsed.command);
|
|
67704
67955
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
67705
67956
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -68406,6 +68657,10 @@ function registerAgentName(name) {
|
|
|
68406
68657
|
}
|
|
68407
68658
|
}
|
|
68408
68659
|
}
|
|
68660
|
+
function clearRegisteredAgentNames() {
|
|
68661
|
+
registeredAgentNames.clear();
|
|
68662
|
+
registeredAgentAliases.clear();
|
|
68663
|
+
}
|
|
68409
68664
|
function isAgentRegistered(name) {
|
|
68410
68665
|
return registeredAgentNames.has(normalizeRegisteredAgentName(name));
|
|
68411
68666
|
}
|
|
@@ -69458,80 +69713,6 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
69458
69713
|
dispose: () => sessionStateStore.shutdown()
|
|
69459
69714
|
};
|
|
69460
69715
|
}
|
|
69461
|
-
// src/hooks/context-window-monitor.ts
|
|
69462
|
-
init_context_limit_resolver2();
|
|
69463
|
-
init_compaction_marker();
|
|
69464
|
-
init_event_session_id();
|
|
69465
|
-
init_system_directive();
|
|
69466
|
-
var CONTEXT_WARNING_THRESHOLD = 0.7;
|
|
69467
|
-
function createContextReminder(actualLimit) {
|
|
69468
|
-
const limitTokens = actualLimit.toLocaleString();
|
|
69469
|
-
return `${createSystemDirective(SystemDirectiveTypes.CONTEXT_WINDOW_MONITOR)}
|
|
69470
|
-
|
|
69471
|
-
You are using a ${limitTokens}-token context window.
|
|
69472
|
-
You still have context remaining - do NOT rush or skip tasks.
|
|
69473
|
-
Complete your work thoroughly and methodically.`;
|
|
69474
|
-
}
|
|
69475
|
-
function createContextWindowMonitorHook(_ctx, modelCacheState) {
|
|
69476
|
-
const remindedSessions = new Set;
|
|
69477
|
-
const tokenCache = new Map;
|
|
69478
|
-
const toolExecuteAfter = async (input, output) => {
|
|
69479
|
-
const { sessionID } = input;
|
|
69480
|
-
if (remindedSessions.has(sessionID))
|
|
69481
|
-
return;
|
|
69482
|
-
const cached2 = tokenCache.get(sessionID);
|
|
69483
|
-
if (!cached2)
|
|
69484
|
-
return;
|
|
69485
|
-
const actualLimit = resolveActualContextLimit(cached2.providerID, cached2.modelID, modelCacheState);
|
|
69486
|
-
if (!actualLimit)
|
|
69487
|
-
return;
|
|
69488
|
-
const lastTokens = cached2.tokens;
|
|
69489
|
-
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
69490
|
-
const actualUsagePercentage = totalInputTokens / actualLimit;
|
|
69491
|
-
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD)
|
|
69492
|
-
return;
|
|
69493
|
-
remindedSessions.add(sessionID);
|
|
69494
|
-
const clampedPercentage = Math.min(Math.max(actualUsagePercentage, 0), 1);
|
|
69495
|
-
const usedPct = (clampedPercentage * 100).toFixed(1);
|
|
69496
|
-
const remainingPct = ((1 - clampedPercentage) * 100).toFixed(1);
|
|
69497
|
-
const usedTokens = totalInputTokens.toLocaleString();
|
|
69498
|
-
const limitTokens = actualLimit.toLocaleString();
|
|
69499
|
-
output.output += `
|
|
69500
|
-
|
|
69501
|
-
${createContextReminder(actualLimit)}
|
|
69502
|
-
[Context Status: ${usedPct}% used (${usedTokens}/${limitTokens} tokens), ${remainingPct}% remaining]`;
|
|
69503
|
-
};
|
|
69504
|
-
const eventHandler = async ({ event }) => {
|
|
69505
|
-
const props = event.properties;
|
|
69506
|
-
if (event.type === "session.deleted") {
|
|
69507
|
-
const sessionID = resolveSessionEventID(props);
|
|
69508
|
-
if (sessionID) {
|
|
69509
|
-
remindedSessions.delete(sessionID);
|
|
69510
|
-
tokenCache.delete(sessionID);
|
|
69511
|
-
}
|
|
69512
|
-
}
|
|
69513
|
-
if (event.type === "message.updated") {
|
|
69514
|
-
const info = props?.info;
|
|
69515
|
-
const finish = info?.finish;
|
|
69516
|
-
if (!info || info.role !== "assistant" || !finish)
|
|
69517
|
-
return;
|
|
69518
|
-
if (isCompactionAgent(info.agent))
|
|
69519
|
-
return;
|
|
69520
|
-
const sessionID = resolveMessageEventSessionID(props);
|
|
69521
|
-
if (!sessionID || !info.providerID || !info.tokens)
|
|
69522
|
-
return;
|
|
69523
|
-
tokenCache.set(sessionID, {
|
|
69524
|
-
providerID: info.providerID,
|
|
69525
|
-
modelID: info.modelID ?? "",
|
|
69526
|
-
tokens: info.tokens
|
|
69527
|
-
});
|
|
69528
|
-
}
|
|
69529
|
-
};
|
|
69530
|
-
return {
|
|
69531
|
-
"tool.execute.after": toolExecuteAfter,
|
|
69532
|
-
event: eventHandler
|
|
69533
|
-
};
|
|
69534
|
-
}
|
|
69535
69716
|
// src/hooks/session-notification-content.ts
|
|
69536
69717
|
init_shared();
|
|
69537
69718
|
function extractMessageText(message) {
|
|
@@ -72000,9 +72181,18 @@ function debugLog2(...args) {
|
|
|
72000
72181
|
function getBinaryName2() {
|
|
72001
72182
|
return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
|
|
72002
72183
|
}
|
|
72184
|
+
function resolveCommentCheckerPathFromPath(binaryName, which = Bun.which) {
|
|
72185
|
+
try {
|
|
72186
|
+
return which(binaryName);
|
|
72187
|
+
} catch (error) {
|
|
72188
|
+
debugLog2("PATH lookup failed:", error);
|
|
72189
|
+
return null;
|
|
72190
|
+
}
|
|
72191
|
+
}
|
|
72003
72192
|
function findCommentCheckerPathSync() {
|
|
72193
|
+
const binaryName = getBinaryName2();
|
|
72004
72194
|
const resolvedPath = resolveCommentCheckerBinary({
|
|
72005
|
-
binaryName
|
|
72195
|
+
binaryName,
|
|
72006
72196
|
cachedBinaryPath: getCachedBinaryPath2(),
|
|
72007
72197
|
existsSync: existsSync35,
|
|
72008
72198
|
importMetaUrl: import.meta.url
|
|
@@ -72011,6 +72201,11 @@ function findCommentCheckerPathSync() {
|
|
|
72011
72201
|
debugLog2("resolved binary path:", resolvedPath);
|
|
72012
72202
|
return resolvedPath;
|
|
72013
72203
|
}
|
|
72204
|
+
const pathBinary = resolveCommentCheckerPathFromPath(binaryName);
|
|
72205
|
+
if (pathBinary !== null && existsSync35(pathBinary)) {
|
|
72206
|
+
debugLog2("resolved PATH binary:", pathBinary);
|
|
72207
|
+
return pathBinary;
|
|
72208
|
+
}
|
|
72014
72209
|
debugLog2("no binary found in known locations");
|
|
72015
72210
|
return null;
|
|
72016
72211
|
}
|
|
@@ -72900,7 +73095,7 @@ function findClosingDelimiter(content, openingLength) {
|
|
|
72900
73095
|
}
|
|
72901
73096
|
// packages/rules-engine/src/matcher.ts
|
|
72902
73097
|
var import_picomatch = __toESM(require_picomatch2(), 1);
|
|
72903
|
-
import { createHash } from "crypto";
|
|
73098
|
+
import { createHash as createHash2 } from "crypto";
|
|
72904
73099
|
import { basename as basename6, relative as relative8 } from "path";
|
|
72905
73100
|
var matcherCache = new Map;
|
|
72906
73101
|
var MAX_MATCHER_CACHE_ENTRIES = 256;
|
|
@@ -72929,7 +73124,7 @@ function shouldApplyRule(metadata, currentFilePath, projectRoot) {
|
|
|
72929
73124
|
return { applies: false };
|
|
72930
73125
|
}
|
|
72931
73126
|
function createContentHash(content) {
|
|
72932
|
-
return
|
|
73127
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
72933
73128
|
}
|
|
72934
73129
|
function isDuplicateByRealPath(realPath, cache) {
|
|
72935
73130
|
return cache.has(realPath);
|
|
@@ -76338,9 +76533,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
76338
76533
|
`);
|
|
76339
76534
|
const cacheEntry = transcriptCache.get(sessionId);
|
|
76340
76535
|
if (cacheEntry) {
|
|
76341
|
-
cacheEntry.baseEntries = allEntries;
|
|
76342
76536
|
cacheEntry.tempPath = tempPath;
|
|
76343
|
-
cacheEntry.createdAt = Date.now();
|
|
76344
76537
|
}
|
|
76345
76538
|
return tempPath;
|
|
76346
76539
|
} catch (error) {
|
|
@@ -85262,6 +85455,9 @@ function suppressComboStandalones(detected) {
|
|
|
85262
85455
|
return detected;
|
|
85263
85456
|
return detected.filter((k) => k.type !== "ultrawork" && k.type !== "hyperplan");
|
|
85264
85457
|
}
|
|
85458
|
+
function filterAlreadyInjectedKeywords(detected, text) {
|
|
85459
|
+
return detected.filter((keyword) => !text.includes(keyword.message));
|
|
85460
|
+
}
|
|
85265
85461
|
function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultMode) {
|
|
85266
85462
|
const disabledKeywords = config?.disabled_keywords;
|
|
85267
85463
|
const enabledExpansions = config?.enabled_expansions;
|
|
@@ -85339,6 +85535,11 @@ function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultM
|
|
|
85339
85535
|
return;
|
|
85340
85536
|
}
|
|
85341
85537
|
}
|
|
85538
|
+
detectedKeywords = filterAlreadyInjectedKeywords(detectedKeywords, cleanText);
|
|
85539
|
+
if (detectedKeywords.length === 0) {
|
|
85540
|
+
log(`[keyword-detector] Skipping already injected keyword messages`, { sessionID: input.sessionID });
|
|
85541
|
+
return;
|
|
85542
|
+
}
|
|
85342
85543
|
const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork");
|
|
85343
85544
|
if (hasUltrawork) {
|
|
85344
85545
|
const runtimeVariant = getRuntimeVariant(input, output.message);
|
|
@@ -87513,9 +87714,10 @@ function collectAssistantText(message) {
|
|
|
87513
87714
|
if (!Array.isArray(message.parts)) {
|
|
87514
87715
|
return "";
|
|
87515
87716
|
}
|
|
87717
|
+
const allowTextParts = message.info?.role === "assistant";
|
|
87516
87718
|
let text = "";
|
|
87517
87719
|
for (const part of message.parts) {
|
|
87518
|
-
if (part.type !== "
|
|
87720
|
+
if (part.type !== "tool_result" && !(allowTextParts && part.type === "text")) {
|
|
87519
87721
|
continue;
|
|
87520
87722
|
}
|
|
87521
87723
|
text += `${text ? `
|
|
@@ -87534,9 +87736,6 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
|
|
|
87534
87736
|
const messageArray = Array.isArray(messagesResponse) ? messagesResponse : Array.isArray(responseData) ? responseData : [];
|
|
87535
87737
|
for (let index = messageArray.length - 1;index >= 0; index -= 1) {
|
|
87536
87738
|
const message = messageArray[index];
|
|
87537
|
-
if (message.info?.role !== "assistant") {
|
|
87538
|
-
continue;
|
|
87539
|
-
}
|
|
87540
87739
|
const assistantText = collectAssistantText(message);
|
|
87541
87740
|
if (!isOracleVerified(assistantText)) {
|
|
87542
87741
|
continue;
|
|
@@ -87555,6 +87754,30 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
|
|
|
87555
87754
|
return;
|
|
87556
87755
|
}
|
|
87557
87756
|
}
|
|
87757
|
+
function showCompletionToastBestEffort(ctx, state3) {
|
|
87758
|
+
const showToast = ctx.client.tui?.showToast;
|
|
87759
|
+
if (!showToast) {
|
|
87760
|
+
return;
|
|
87761
|
+
}
|
|
87762
|
+
const toastBody = {
|
|
87763
|
+
body: {
|
|
87764
|
+
title: "ULTRAWORK LOOP COMPLETE!",
|
|
87765
|
+
message: `JUST ULW ULW! Task completed after ${state3.iteration} iteration(s)`,
|
|
87766
|
+
variant: "success",
|
|
87767
|
+
duration: 5000
|
|
87768
|
+
}
|
|
87769
|
+
};
|
|
87770
|
+
const logToastError = (error) => {
|
|
87771
|
+
log(`[${HOOK_NAME3}] Failed to show ulw completion toast`, {
|
|
87772
|
+
error: String(error)
|
|
87773
|
+
});
|
|
87774
|
+
};
|
|
87775
|
+
try {
|
|
87776
|
+
Promise.resolve(showToast(toastBody)).catch(logToastError);
|
|
87777
|
+
} catch (error) {
|
|
87778
|
+
logToastError(error);
|
|
87779
|
+
}
|
|
87780
|
+
}
|
|
87558
87781
|
async function handlePendingVerification(ctx, input) {
|
|
87559
87782
|
const {
|
|
87560
87783
|
sessionID,
|
|
@@ -87570,6 +87793,15 @@ async function handlePendingVerification(ctx, input) {
|
|
|
87570
87793
|
if (!verificationSessionID && state3.session_id) {
|
|
87571
87794
|
const recoveredVerificationSessionID = await detectOracleVerificationFromParentSession(ctx, state3.session_id, directory, apiTimeoutMs);
|
|
87572
87795
|
if (recoveredVerificationSessionID) {
|
|
87796
|
+
if (state3.completion_promise === ULTRAWORK_VERIFICATION_PROMISE) {
|
|
87797
|
+
log(`[${HOOK_NAME3}] Oracle verification evidence found in parent session, completing ultrawork loop`, {
|
|
87798
|
+
parentSessionID: state3.session_id,
|
|
87799
|
+
recoveredVerificationSessionID
|
|
87800
|
+
});
|
|
87801
|
+
loopState.clear();
|
|
87802
|
+
showCompletionToastBestEffort(ctx, state3);
|
|
87803
|
+
return;
|
|
87804
|
+
}
|
|
87573
87805
|
const updatedState = loopState.setVerificationSessionID(state3.session_id, recoveredVerificationSessionID);
|
|
87574
87806
|
if (updatedState) {
|
|
87575
87807
|
log(`[${HOOK_NAME3}] Recovered missing verification session from parent evidence`, {
|
|
@@ -87657,8 +87889,8 @@ var USER_MESSAGE_IN_PROGRESS_WINDOW_MS = 2000;
|
|
|
87657
87889
|
function sleep(ms) {
|
|
87658
87890
|
return ms > 0 ? new Promise((resolve14) => setTimeout(resolve14, ms)) : Promise.resolve();
|
|
87659
87891
|
}
|
|
87660
|
-
function
|
|
87661
|
-
return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
|
|
87892
|
+
function hasActiveBackgroundTasks(backgroundManager, sessionID) {
|
|
87893
|
+
return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "pending" || task.status === "running") : false;
|
|
87662
87894
|
}
|
|
87663
87895
|
function getRuntimeRetryActivitySessionID(eventType, props) {
|
|
87664
87896
|
if (eventType === "message.updated") {
|
|
@@ -87841,8 +88073,8 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
87841
88073
|
if (!state3 || !state3.active) {
|
|
87842
88074
|
return;
|
|
87843
88075
|
}
|
|
87844
|
-
if (
|
|
87845
|
-
log(`[${HOOK_NAME3}] Skipped: background tasks
|
|
88076
|
+
if (hasActiveBackgroundTasks(options.backgroundManager, sessionID)) {
|
|
88077
|
+
log(`[${HOOK_NAME3}] Skipped: background tasks active`, { sessionID });
|
|
87846
88078
|
return;
|
|
87847
88079
|
}
|
|
87848
88080
|
const verificationSessionID = state3.verification_pending ? state3.verification_session_id : undefined;
|
|
@@ -88076,8 +88308,8 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
88076
88308
|
handleErroredLoopSession(props, options.loopState);
|
|
88077
88309
|
return;
|
|
88078
88310
|
}
|
|
88079
|
-
if (
|
|
88080
|
-
log(`[${HOOK_NAME3}] Skipped runtime error retry: background tasks
|
|
88311
|
+
if (hasActiveBackgroundTasks(options.backgroundManager, sessionID)) {
|
|
88312
|
+
log(`[${HOOK_NAME3}] Skipped runtime error retry: background tasks active`, { sessionID });
|
|
88081
88313
|
return;
|
|
88082
88314
|
}
|
|
88083
88315
|
log(`[${HOOK_NAME3}] Retrying after runtime session error`, {
|
|
@@ -91169,6 +91401,12 @@ var initDeepSkill = {
|
|
|
91169
91401
|
template: loadSharedSkillTemplate("init-deep"),
|
|
91170
91402
|
argumentHint: "[--create-new] [--max-depth=N]"
|
|
91171
91403
|
};
|
|
91404
|
+
// src/features/builtin-skills/skills/debugging.ts
|
|
91405
|
+
var debuggingSkill = {
|
|
91406
|
+
name: "debugging",
|
|
91407
|
+
description: "MUST USE for any real runtime debugging across ANY language or binary \u2014 crashes, silent failures, wrong responses, stuck processes, memory leaks, async misbehavior, unexplained timing, reverse engineering. Runs a hypothesis-driven loop: form \u22653 hypotheses, investigate in parallel, after 2 failed rounds spawn Oracles from orthogonal angles, confirm root cause, lock with a failing test, fix minimally, QA by actually USING the system, scrub artifacts. The actual HOW lives in `references/` \u2014 READ THEM. Triggers: 'debug this', 'why is X not working', 'hanging', 'attach a debugger', 'reverse engineer', 'pwndbg', 'gdb', 'lldb', 'node inspect', 'tsx debug', 'pdb', 'dlv', 'delve', 'rust-gdb', 'set a breakpoint', 'context window exploded', 'why is the response empty', 'attach the debugger', 'debug it', 'why is this happening', 'trace this bug', 'reproduce and fix', 'silent failure', 'HTTP 200 but empty', 'why did it stop', 'inspect the binary', 'reverse engineering', 'playwright'.",
|
|
91408
|
+
template: loadSharedSkillTemplate("debugging")
|
|
91409
|
+
};
|
|
91172
91410
|
// src/features/builtin-skills/security-research/SKILL.md
|
|
91173
91411
|
var SKILL_default = `# Security Research - Team Mode Vulnerability Audit
|
|
91174
91412
|
|
|
@@ -91604,6 +91842,7 @@ function createBuiltinSkills(options = {}) {
|
|
|
91604
91842
|
reviewWorkSkill,
|
|
91605
91843
|
removeAiSlopsSkill,
|
|
91606
91844
|
initDeepSkill,
|
|
91845
|
+
debuggingSkill,
|
|
91607
91846
|
securityResearchSkill,
|
|
91608
91847
|
securityReviewSkill
|
|
91609
91848
|
];
|
|
@@ -92008,7 +92247,6 @@ var GitMasterConfigSchema = z17.object({
|
|
|
92008
92247
|
import { z as z18 } from "zod";
|
|
92009
92248
|
var HookNameSchema = z18.enum([
|
|
92010
92249
|
"todo-continuation-enforcer",
|
|
92011
|
-
"context-window-monitor",
|
|
92012
92250
|
"session-recovery",
|
|
92013
92251
|
"session-notification",
|
|
92014
92252
|
"comment-checker",
|
|
@@ -92567,9 +92805,55 @@ async function discoverConfigSourceSkills(options) {
|
|
|
92567
92805
|
}));
|
|
92568
92806
|
return deduplicateSkillsByName(loadedBySource.flat());
|
|
92569
92807
|
}
|
|
92808
|
+
// src/features/opencode-skill-loader/opencode-config-skills-reader.ts
|
|
92809
|
+
init_jsonc_parser2();
|
|
92810
|
+
init_opencode_config_dir();
|
|
92811
|
+
import * as fs21 from "fs";
|
|
92812
|
+
import * as path17 from "path";
|
|
92813
|
+
function getConfigPaths3(directory) {
|
|
92814
|
+
const globalConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
92815
|
+
return [
|
|
92816
|
+
path17.join(directory, ".opencode", "opencode.json"),
|
|
92817
|
+
path17.join(directory, ".opencode", "opencode.jsonc"),
|
|
92818
|
+
path17.join(globalConfigDir, "opencode.json"),
|
|
92819
|
+
path17.join(globalConfigDir, "opencode.jsonc")
|
|
92820
|
+
];
|
|
92821
|
+
}
|
|
92822
|
+
function toStringArray(value) {
|
|
92823
|
+
if (!Array.isArray(value))
|
|
92824
|
+
return [];
|
|
92825
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
92826
|
+
}
|
|
92827
|
+
function readOpencodeConfigSkills(directory) {
|
|
92828
|
+
const paths = [];
|
|
92829
|
+
const urls = [];
|
|
92830
|
+
for (const configPath of getConfigPaths3(directory)) {
|
|
92831
|
+
try {
|
|
92832
|
+
if (!fs21.existsSync(configPath))
|
|
92833
|
+
continue;
|
|
92834
|
+
const content = fs21.readFileSync(configPath, "utf-8");
|
|
92835
|
+
const parseResult = parseJsoncSafe(content);
|
|
92836
|
+
if (!parseResult.data?.skills)
|
|
92837
|
+
continue;
|
|
92838
|
+
for (const p of toStringArray(parseResult.data.skills.paths)) {
|
|
92839
|
+
if (!paths.includes(p))
|
|
92840
|
+
paths.push(p);
|
|
92841
|
+
}
|
|
92842
|
+
for (const u of toStringArray(parseResult.data.skills.urls)) {
|
|
92843
|
+
if (!urls.includes(u))
|
|
92844
|
+
urls.push(u);
|
|
92845
|
+
}
|
|
92846
|
+
} catch {
|
|
92847
|
+
continue;
|
|
92848
|
+
}
|
|
92849
|
+
}
|
|
92850
|
+
if (paths.length === 0 && urls.length === 0)
|
|
92851
|
+
return;
|
|
92852
|
+
return { paths, urls };
|
|
92853
|
+
}
|
|
92570
92854
|
// src/tools/slashcommand/command-discovery.ts
|
|
92571
|
-
import { existsSync as
|
|
92572
|
-
import { basename as basename9, join as
|
|
92855
|
+
import { existsSync as existsSync64, readdirSync as readdirSync19, readFileSync as readFileSync47, statSync as statSync9 } from "fs";
|
|
92856
|
+
import { basename as basename9, join as join76 } from "path";
|
|
92573
92857
|
|
|
92574
92858
|
// src/tools/slashcommand/command-discovery-deps.ts
|
|
92575
92859
|
init_excluded_dirs();
|
|
@@ -94112,7 +94396,7 @@ function loadBuiltinCommands(disabledCommands, options) {
|
|
|
94112
94396
|
// src/tools/slashcommand/command-discovery.ts
|
|
94113
94397
|
var NESTED_COMMAND_SEPARATOR = "/";
|
|
94114
94398
|
function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
|
|
94115
|
-
if (!
|
|
94399
|
+
if (!existsSync64(commandsDir))
|
|
94116
94400
|
return [];
|
|
94117
94401
|
if (!statSync9(commandsDir).isDirectory()) {
|
|
94118
94402
|
log(`[command-discovery] Skipping non-directory path: ${commandsDir}`);
|
|
@@ -94127,16 +94411,16 @@ function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
|
|
|
94127
94411
|
if (entry.name.startsWith("."))
|
|
94128
94412
|
continue;
|
|
94129
94413
|
const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` : entry.name;
|
|
94130
|
-
commands2.push(...discoverCommandsFromDir(
|
|
94414
|
+
commands2.push(...discoverCommandsFromDir(join76(commandsDir, entry.name), scope, nestedPrefix));
|
|
94131
94415
|
continue;
|
|
94132
94416
|
}
|
|
94133
94417
|
if (!isMarkdownFile(entry))
|
|
94134
94418
|
continue;
|
|
94135
|
-
const commandPath =
|
|
94419
|
+
const commandPath = join76(commandsDir, entry.name);
|
|
94136
94420
|
const baseCommandName = basename9(entry.name, ".md");
|
|
94137
94421
|
const commandName = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` : baseCommandName;
|
|
94138
94422
|
try {
|
|
94139
|
-
const content =
|
|
94423
|
+
const content = readFileSync47(commandPath, "utf-8");
|
|
94140
94424
|
const { data, body } = parseFrontmatter(content);
|
|
94141
94425
|
const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
|
|
94142
94426
|
const metadata = {
|
|
@@ -94188,8 +94472,8 @@ function deduplicateCommandInfosByName(commands2) {
|
|
|
94188
94472
|
return deduplicatedCommands;
|
|
94189
94473
|
}
|
|
94190
94474
|
function discoverCommandsSync(directory, options) {
|
|
94191
|
-
const userCommandsDir =
|
|
94192
|
-
const projectCommandsDir =
|
|
94475
|
+
const userCommandsDir = join76(getClaudeConfigDir(), "commands");
|
|
94476
|
+
const projectCommandsDir = join76(directory ?? process.cwd(), ".claude", "commands");
|
|
94193
94477
|
const opencodeGlobalDirs = getOpenCodeCommandDirs({ binary: "opencode" });
|
|
94194
94478
|
const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd());
|
|
94195
94479
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
@@ -94689,7 +94973,7 @@ var NOTEPAD_DIR = "notepads";
|
|
|
94689
94973
|
var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
|
|
94690
94974
|
var PROMETHEUS_PLANS_DIR = ".omo/plans";
|
|
94691
94975
|
// packages/boulder-state/src/top-level-task.ts
|
|
94692
|
-
import { existsSync as
|
|
94976
|
+
import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
|
|
94693
94977
|
var TODO_HEADING_PATTERN = /^##\s+TODOs\b/i;
|
|
94694
94978
|
var FINAL_VERIFICATION_HEADING_PATTERN = /^##\s+Final Verification Wave\b/i;
|
|
94695
94979
|
var SECOND_LEVEL_HEADING_PATTERN = /^##\s+/;
|
|
@@ -94712,11 +94996,11 @@ function buildTaskRef(section, taskLabel) {
|
|
|
94712
94996
|
};
|
|
94713
94997
|
}
|
|
94714
94998
|
function readCurrentTopLevelTask(planPath) {
|
|
94715
|
-
if (!
|
|
94999
|
+
if (!existsSync65(planPath)) {
|
|
94716
95000
|
return null;
|
|
94717
95001
|
}
|
|
94718
95002
|
try {
|
|
94719
|
-
const content =
|
|
95003
|
+
const content = readFileSync48(planPath, "utf-8");
|
|
94720
95004
|
const lines = content.split(/\r?\n/);
|
|
94721
95005
|
let section = "other";
|
|
94722
95006
|
for (const line of lines) {
|
|
@@ -94741,10 +95025,10 @@ function readCurrentTopLevelTask(planPath) {
|
|
|
94741
95025
|
}
|
|
94742
95026
|
}
|
|
94743
95027
|
// packages/boulder-state/src/storage/path.ts
|
|
94744
|
-
import { existsSync as
|
|
94745
|
-
import { isAbsolute as isAbsolute13, join as
|
|
95028
|
+
import { existsSync as existsSync66 } from "fs";
|
|
95029
|
+
import { isAbsolute as isAbsolute13, join as join77, relative as relative11, resolve as resolve15 } from "path";
|
|
94746
95030
|
function getBoulderFilePath(directory) {
|
|
94747
|
-
return
|
|
95031
|
+
return join77(directory, BOULDER_DIR, BOULDER_FILE);
|
|
94748
95032
|
}
|
|
94749
95033
|
function resolveTrackedPath(baseDirectory, trackedPath) {
|
|
94750
95034
|
return isAbsolute13(trackedPath) ? resolve15(trackedPath) : resolve15(baseDirectory, trackedPath);
|
|
@@ -94762,14 +95046,14 @@ function resolveBoulderPlanPath(directory, state3) {
|
|
|
94762
95046
|
}
|
|
94763
95047
|
const absoluteWorktreePath = resolveTrackedPath(directory, worktreePath);
|
|
94764
95048
|
const worktreePlanPath = resolve15(absoluteWorktreePath, relativePlanPath);
|
|
94765
|
-
return
|
|
95049
|
+
return existsSync66(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
|
|
94766
95050
|
}
|
|
94767
95051
|
function resolveBoulderPlanPathForWork(directory, work) {
|
|
94768
95052
|
return resolveBoulderPlanPath(directory, work);
|
|
94769
95053
|
}
|
|
94770
95054
|
// packages/boulder-state/src/storage/plan-progress.ts
|
|
94771
|
-
import { existsSync as
|
|
94772
|
-
import { basename as basename10, join as
|
|
95055
|
+
import { existsSync as existsSync67, readFileSync as readFileSync49, readdirSync as readdirSync20, statSync as statSync10 } from "fs";
|
|
95056
|
+
import { basename as basename10, join as join78 } from "path";
|
|
94773
95057
|
var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
|
|
94774
95058
|
var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
|
|
94775
95059
|
var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
|
|
@@ -94782,11 +95066,11 @@ var PROMETHEUS_PLAN_DIRS = [PROMETHEUS_PLANS_DIR, LEGACY_PROMETHEUS_PLANS_DIR];
|
|
|
94782
95066
|
function findPrometheusPlans(directory) {
|
|
94783
95067
|
try {
|
|
94784
95068
|
return PROMETHEUS_PLAN_DIRS.flatMap((planDir) => {
|
|
94785
|
-
const plansDir =
|
|
94786
|
-
if (!
|
|
95069
|
+
const plansDir = join78(directory, planDir);
|
|
95070
|
+
if (!existsSync67(plansDir)) {
|
|
94787
95071
|
return [];
|
|
94788
95072
|
}
|
|
94789
|
-
return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) =>
|
|
95073
|
+
return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) => join78(plansDir, file));
|
|
94790
95074
|
}).sort((left, right) => statSync10(right).mtimeMs - statSync10(left).mtimeMs);
|
|
94791
95075
|
} catch {
|
|
94792
95076
|
return [];
|
|
@@ -94796,11 +95080,11 @@ function getPlanName(planPath) {
|
|
|
94796
95080
|
return basename10(planPath, ".md");
|
|
94797
95081
|
}
|
|
94798
95082
|
function getPlanProgress(planPath) {
|
|
94799
|
-
if (!
|
|
95083
|
+
if (!existsSync67(planPath)) {
|
|
94800
95084
|
return { total: 0, completed: 0, isComplete: false };
|
|
94801
95085
|
}
|
|
94802
95086
|
try {
|
|
94803
|
-
const content =
|
|
95087
|
+
const content = readFileSync49(planPath, "utf-8");
|
|
94804
95088
|
const lines = content.split(/\r?\n/);
|
|
94805
95089
|
const hasStructuredSections = lines.some((line) => TODO_HEADING_PATTERN2.test(line) || FINAL_VERIFICATION_HEADING_PATTERN2.test(line));
|
|
94806
95090
|
if (hasStructuredSections) {
|
|
@@ -94930,14 +95214,14 @@ function selectMirrorWork(state3) {
|
|
|
94930
95214
|
return sorted[0] ?? null;
|
|
94931
95215
|
}
|
|
94932
95216
|
// packages/boulder-state/src/storage/read-state.ts
|
|
94933
|
-
import { existsSync as
|
|
95217
|
+
import { existsSync as existsSync68, readFileSync as readFileSync50 } from "fs";
|
|
94934
95218
|
function readBoulderState(directory) {
|
|
94935
95219
|
const filePath = getBoulderFilePath(directory);
|
|
94936
|
-
if (!
|
|
95220
|
+
if (!existsSync68(filePath)) {
|
|
94937
95221
|
return null;
|
|
94938
95222
|
}
|
|
94939
95223
|
try {
|
|
94940
|
-
const content =
|
|
95224
|
+
const content = readFileSync50(filePath, "utf-8");
|
|
94941
95225
|
const parsed = JSON.parse(content);
|
|
94942
95226
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
94943
95227
|
return null;
|
|
@@ -95068,13 +95352,13 @@ function getTaskSessionState(directory, taskKey) {
|
|
|
95068
95352
|
return state3.task_sessions[taskKey] ?? null;
|
|
95069
95353
|
}
|
|
95070
95354
|
// packages/boulder-state/src/storage/write-state.ts
|
|
95071
|
-
import { existsSync as
|
|
95355
|
+
import { existsSync as existsSync69, mkdirSync as mkdirSync17, unlinkSync as unlinkSync13, writeFileSync as writeFileSync18 } from "fs";
|
|
95072
95356
|
import { dirname as dirname25 } from "path";
|
|
95073
95357
|
function writeBoulderState(directory, state3) {
|
|
95074
95358
|
const filePath = getBoulderFilePath(directory);
|
|
95075
95359
|
try {
|
|
95076
95360
|
const dir = dirname25(filePath);
|
|
95077
|
-
if (!
|
|
95361
|
+
if (!existsSync69(dir)) {
|
|
95078
95362
|
mkdirSync17(dir, { recursive: true });
|
|
95079
95363
|
}
|
|
95080
95364
|
const stateToWrite = { ...state3 };
|
|
@@ -95110,7 +95394,7 @@ function writeBoulderState(directory, state3) {
|
|
|
95110
95394
|
function clearBoulderState(directory) {
|
|
95111
95395
|
const filePath = getBoulderFilePath(directory);
|
|
95112
95396
|
try {
|
|
95113
|
-
if (
|
|
95397
|
+
if (existsSync69(filePath)) {
|
|
95114
95398
|
unlinkSync13(filePath);
|
|
95115
95399
|
}
|
|
95116
95400
|
return true;
|
|
@@ -95815,6 +96099,23 @@ function buildExplicitPlanContext(params) {
|
|
|
95815
96099
|
const allPlans = findPrometheusPlans(directory);
|
|
95816
96100
|
const matchedPlan = findPlanByName(allPlans, explicitPlanName);
|
|
95817
96101
|
if (!matchedPlan) {
|
|
96102
|
+
const incompletePlans = allPlans.filter((planPath) => !getPlanProgress(planPath).isComplete);
|
|
96103
|
+
if (incompletePlans.length === 1) {
|
|
96104
|
+
createNewWorkOrInitialize({
|
|
96105
|
+
directory,
|
|
96106
|
+
planPath: incompletePlans[0],
|
|
96107
|
+
sessionId,
|
|
96108
|
+
activeAgent,
|
|
96109
|
+
worktreePath
|
|
96110
|
+
});
|
|
96111
|
+
return buildAutoSelectedPlanContextInfoOnly({
|
|
96112
|
+
planPath: incompletePlans[0],
|
|
96113
|
+
sessionId,
|
|
96114
|
+
timestamp: timestamp2,
|
|
96115
|
+
worktreeBlock,
|
|
96116
|
+
reason: `Only incomplete plan available after "${explicitPlanName}" did not match any plan`
|
|
96117
|
+
});
|
|
96118
|
+
}
|
|
95818
96119
|
return buildMissingPlanContext(explicitPlanName, allPlans);
|
|
95819
96120
|
}
|
|
95820
96121
|
const progress = getPlanProgress(matchedPlan);
|
|
@@ -96221,8 +96522,8 @@ function isAbortError2(error) {
|
|
|
96221
96522
|
// src/hooks/atlas/session-last-agent.ts
|
|
96222
96523
|
init_shared();
|
|
96223
96524
|
init_compaction_marker();
|
|
96224
|
-
import { readFileSync as
|
|
96225
|
-
import { join as
|
|
96525
|
+
import { readFileSync as readFileSync51, readdirSync as readdirSync21 } from "fs";
|
|
96526
|
+
import { join as join79 } from "path";
|
|
96226
96527
|
var defaultSessionLastAgentDeps = {
|
|
96227
96528
|
getMessageDir,
|
|
96228
96529
|
isSqliteBackend,
|
|
@@ -96276,7 +96577,7 @@ async function getLastAgentFromSession(sessionID, client, deps = {}) {
|
|
|
96276
96577
|
try {
|
|
96277
96578
|
const messages = readdirSync21(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
|
|
96278
96579
|
try {
|
|
96279
|
-
const content =
|
|
96580
|
+
const content = readFileSync51(join79(messageDir, fileName), "utf-8");
|
|
96280
96581
|
const parsed = JSON.parse(content);
|
|
96281
96582
|
return {
|
|
96282
96583
|
fileName,
|
|
@@ -96796,7 +97097,7 @@ function getTaskLabelSortValue(taskLabel) {
|
|
|
96796
97097
|
const parsed = Number.parseInt(taskLabel.replace(/[^0-9]/g, ""), 10);
|
|
96797
97098
|
return Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed;
|
|
96798
97099
|
}
|
|
96799
|
-
function
|
|
97100
|
+
function hasRunningBackgroundTasks(sessionID, options) {
|
|
96800
97101
|
const backgroundManager = options?.backgroundManager;
|
|
96801
97102
|
return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
|
|
96802
97103
|
}
|
|
@@ -96925,7 +97226,7 @@ function scheduleRetry(input) {
|
|
|
96925
97226
|
});
|
|
96926
97227
|
if (!canContinueSession)
|
|
96927
97228
|
return;
|
|
96928
|
-
if (
|
|
97229
|
+
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
96929
97230
|
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
96930
97231
|
return;
|
|
96931
97232
|
}
|
|
@@ -97111,7 +97412,7 @@ async function handleAtlasSessionIdle(input) {
|
|
|
97111
97412
|
sessionState.promptFailureCount = 0;
|
|
97112
97413
|
sessionState.lastFailureAt = undefined;
|
|
97113
97414
|
}
|
|
97114
|
-
if (
|
|
97415
|
+
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
97115
97416
|
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
97116
97417
|
log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
|
|
97117
97418
|
return;
|
|
@@ -97271,7 +97572,7 @@ function createAtlasEventHandler(input) {
|
|
|
97271
97572
|
// src/hooks/atlas/tool-execute-after.ts
|
|
97272
97573
|
init_logger();
|
|
97273
97574
|
init_session_utils();
|
|
97274
|
-
import { existsSync as
|
|
97575
|
+
import { existsSync as existsSync71, readFileSync as readFileSync53 } from "fs";
|
|
97275
97576
|
import { resolve as resolve18 } from "path";
|
|
97276
97577
|
|
|
97277
97578
|
// src/hooks/atlas/background-launch-session-tracking.ts
|
|
@@ -97419,7 +97720,7 @@ async function resolveFallbackTrackedSessionId(input) {
|
|
|
97419
97720
|
init_git_worktree();
|
|
97420
97721
|
|
|
97421
97722
|
// src/hooks/atlas/final-wave-plan-state.ts
|
|
97422
|
-
import { existsSync as
|
|
97723
|
+
import { existsSync as existsSync70, readFileSync as readFileSync52 } from "fs";
|
|
97423
97724
|
var TODO_HEADING_PATTERN3 = /^##\s+TODOs\b/i;
|
|
97424
97725
|
var FINAL_VERIFICATION_HEADING_PATTERN3 = /^##\s+Final Verification Wave\b/i;
|
|
97425
97726
|
var SECOND_LEVEL_HEADING_PATTERN3 = /^##\s+/;
|
|
@@ -97427,11 +97728,11 @@ var UNCHECKED_CHECKBOX_PATTERN3 = /^\s*[-*]\s*\[\s*\]\s*(.+)$/;
|
|
|
97427
97728
|
var TODO_TASK_PATTERN3 = /^\d+\./;
|
|
97428
97729
|
var FINAL_WAVE_TASK_PATTERN3 = /^F\d+\./i;
|
|
97429
97730
|
function readFinalWavePlanState(planPath) {
|
|
97430
|
-
if (!
|
|
97731
|
+
if (!existsSync70(planPath)) {
|
|
97431
97732
|
return null;
|
|
97432
97733
|
}
|
|
97433
97734
|
try {
|
|
97434
|
-
const content =
|
|
97735
|
+
const content = readFileSync52(planPath, "utf-8");
|
|
97435
97736
|
const lines = content.split(/\r?\n/);
|
|
97436
97737
|
let section = "other";
|
|
97437
97738
|
let pendingImplementationTaskCount = 0;
|
|
@@ -97681,7 +97982,7 @@ function isWriteOrEditToolName(toolName) {
|
|
|
97681
97982
|
|
|
97682
97983
|
// src/hooks/atlas/tool-execute-after.ts
|
|
97683
97984
|
function isTrackedTaskChecked(planPath, taskKey) {
|
|
97684
|
-
if (!
|
|
97985
|
+
if (!existsSync71(planPath)) {
|
|
97685
97986
|
return false;
|
|
97686
97987
|
}
|
|
97687
97988
|
const [section, label] = taskKey.split(":");
|
|
@@ -97694,7 +97995,7 @@ function isTrackedTaskChecked(planPath, taskKey) {
|
|
|
97694
97995
|
return false;
|
|
97695
97996
|
}
|
|
97696
97997
|
try {
|
|
97697
|
-
const content =
|
|
97998
|
+
const content = readFileSync53(planPath, "utf-8");
|
|
97698
97999
|
return matcher.test(content);
|
|
97699
98000
|
} catch {
|
|
97700
98001
|
return false;
|
|
@@ -97738,11 +98039,11 @@ function parseCheckedTopLevelTaskKeys(planContent) {
|
|
|
97738
98039
|
return checkedKeys;
|
|
97739
98040
|
}
|
|
97740
98041
|
function readCheckedTaskKeysFromPlan(planPath) {
|
|
97741
|
-
if (!
|
|
98042
|
+
if (!existsSync71(planPath)) {
|
|
97742
98043
|
return new Set;
|
|
97743
98044
|
}
|
|
97744
98045
|
try {
|
|
97745
|
-
return parseCheckedTopLevelTaskKeys(
|
|
98046
|
+
return parseCheckedTopLevelTaskKeys(readFileSync53(planPath, "utf-8"));
|
|
97746
98047
|
} catch {
|
|
97747
98048
|
return new Set;
|
|
97748
98049
|
}
|
|
@@ -97949,7 +98250,7 @@ init_logger();
|
|
|
97949
98250
|
init_replace_tool_args();
|
|
97950
98251
|
init_system_directive();
|
|
97951
98252
|
init_session_utils();
|
|
97952
|
-
import { existsSync as
|
|
98253
|
+
import { existsSync as existsSync72, readFileSync as readFileSync54 } from "fs";
|
|
97953
98254
|
import { resolve as resolve19 } from "path";
|
|
97954
98255
|
var TASK_SECTION_HEADER_PATTERN = /^##\s*1\.\s*TASK\s*$/i;
|
|
97955
98256
|
var TODO_TASK_LINE_PATTERN = /^(?:[-*]\s*\[\s*\]\s*)?(\d+)\.\s+(.+)$/;
|
|
@@ -98010,8 +98311,8 @@ function createToolExecuteBeforeHandler2(input) {
|
|
|
98010
98311
|
const planPath = sessionWork ? resolveBoulderPlanPathForWork(ctx.directory, sessionWork) : state3 ? resolveBoulderPlanPath(ctx.directory, state3) : null;
|
|
98011
98312
|
if (planPath && resolve19(filePath) === resolve19(planPath) && pendingPlanSnapshots) {
|
|
98012
98313
|
try {
|
|
98013
|
-
if (
|
|
98014
|
-
pendingPlanSnapshots.set(toolInput.callID,
|
|
98314
|
+
if (existsSync72(planPath)) {
|
|
98315
|
+
pendingPlanSnapshots.set(toolInput.callID, readFileSync54(planPath, "utf-8"));
|
|
98015
98316
|
}
|
|
98016
98317
|
} catch {
|
|
98017
98318
|
pendingPlanSnapshots.delete(toolInput.callID);
|
|
@@ -99871,16 +100172,16 @@ function createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState) {
|
|
|
99871
100172
|
init_shared();
|
|
99872
100173
|
|
|
99873
100174
|
// src/hooks/tasks-todowrite-disabler/constants.ts
|
|
99874
|
-
var BLOCKED_TOOLS2 = ["
|
|
99875
|
-
var REPLACEMENT_MESSAGE = `TodoRead
|
|
100175
|
+
var BLOCKED_TOOLS2 = ["TodoRead"];
|
|
100176
|
+
var REPLACEMENT_MESSAGE = `TodoRead is DISABLED because experimental.task_system is enabled.
|
|
99876
100177
|
|
|
99877
|
-
**ACTION REQUIRED**:
|
|
100178
|
+
**ACTION REQUIRED**: Use Task tools to inspect work state. TodoWrite is still allowed so the live todo panel keeps updating, but reads belong to the task system.
|
|
99878
100179
|
|
|
99879
|
-
**Use these tools instead:**
|
|
99880
|
-
- TaskCreate: Create new task with auto-generated ID
|
|
99881
|
-
- TaskUpdate: Update status, assign owner, add dependencies
|
|
100180
|
+
**Use these tools instead of TodoRead:**
|
|
99882
100181
|
- TaskList: List active tasks with dependency info
|
|
99883
100182
|
- TaskGet: Get full task details
|
|
100183
|
+
- TaskCreate: Create new task with auto-generated ID
|
|
100184
|
+
- TaskUpdate: Update status, assign owner, add dependencies
|
|
99884
100185
|
|
|
99885
100186
|
**Workflow:**
|
|
99886
100187
|
1. TaskCreate({ subject: "your task description" })
|
|
@@ -99899,7 +100200,7 @@ Even if the task seems trivial (1 line fix, simple edit, quick change), you MUST
|
|
|
99899
100200
|
|
|
99900
100201
|
**WHY?** Task tracking = visibility = accountability. Skipping registration = invisible work = chaos.
|
|
99901
100202
|
|
|
99902
|
-
DO NOT retry
|
|
100203
|
+
DO NOT retry TodoRead. Use TaskList or TaskGet NOW.`;
|
|
99903
100204
|
|
|
99904
100205
|
// src/hooks/tasks-todowrite-disabler/hook.ts
|
|
99905
100206
|
function createTasksTodowriteDisablerHook(config) {
|
|
@@ -100345,6 +100646,7 @@ function getLastUserRetryPayload(messagesResponse, sessionID) {
|
|
|
100345
100646
|
}
|
|
100346
100647
|
|
|
100347
100648
|
// src/hooks/runtime-fallback/auto-retry.ts
|
|
100649
|
+
init_internal_initiator_marker();
|
|
100348
100650
|
var SESSION_TTL_MS = 30 * 60 * 1000;
|
|
100349
100651
|
function createAutoRetryHelpers(deps) {
|
|
100350
100652
|
const {
|
|
@@ -100457,7 +100759,7 @@ function createAutoRetryHelpers(deps) {
|
|
|
100457
100759
|
sessionID,
|
|
100458
100760
|
hint: "This can occur when the working directory contains .git and messages are not yet persisted"
|
|
100459
100761
|
});
|
|
100460
|
-
return [
|
|
100762
|
+
return [createInternalAgentContinuationTextPart("continue")];
|
|
100461
100763
|
})();
|
|
100462
100764
|
log(`[${HOOK_NAME11}] Auto-retrying with fallback model (${source})`, {
|
|
100463
100765
|
sessionID,
|
|
@@ -101751,12 +102053,12 @@ function createRuntimeFallbackHook(ctx, options, factoryOverrides = {}) {
|
|
|
101751
102053
|
};
|
|
101752
102054
|
}
|
|
101753
102055
|
// src/hooks/write-existing-file-guard/hook.ts
|
|
101754
|
-
import { existsSync as
|
|
101755
|
-
import { basename as basename11, dirname as dirname26, isAbsolute as isAbsolute16, join as
|
|
102056
|
+
import { existsSync as existsSync74, realpathSync as realpathSync8 } from "fs";
|
|
102057
|
+
import { basename as basename11, dirname as dirname26, isAbsolute as isAbsolute16, join as join80, normalize as normalize2, relative as relative13, resolve as resolve20 } from "path";
|
|
101756
102058
|
|
|
101757
102059
|
// src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
|
|
101758
102060
|
init_shared();
|
|
101759
|
-
import { existsSync as
|
|
102061
|
+
import { existsSync as existsSync73 } from "fs";
|
|
101760
102062
|
|
|
101761
102063
|
// src/hooks/write-existing-file-guard/session-read-permissions.ts
|
|
101762
102064
|
function touchSession(sessionLastAccess, sessionID) {
|
|
@@ -101857,7 +102159,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
101857
102159
|
return;
|
|
101858
102160
|
}
|
|
101859
102161
|
if (toolName === "read") {
|
|
101860
|
-
if (!
|
|
102162
|
+
if (!existsSync73(resolvedPath) || !input.sessionID) {
|
|
101861
102163
|
return;
|
|
101862
102164
|
}
|
|
101863
102165
|
registerReadPermission({
|
|
@@ -101874,7 +102176,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
101874
102176
|
if (argsRecord && "overwrite" in argsRecord) {
|
|
101875
102177
|
delete argsRecord.overwrite;
|
|
101876
102178
|
}
|
|
101877
|
-
if (!
|
|
102179
|
+
if (!existsSync73(resolvedPath)) {
|
|
101878
102180
|
return;
|
|
101879
102181
|
}
|
|
101880
102182
|
if (isOmoWorkspacePath(canonicalPath)) {
|
|
@@ -101933,7 +102235,7 @@ function isPathInsideDirectory(pathToCheck, directory) {
|
|
|
101933
102235
|
}
|
|
101934
102236
|
function toCanonicalPath2(absolutePath) {
|
|
101935
102237
|
let canonicalPath = absolutePath;
|
|
101936
|
-
if (
|
|
102238
|
+
if (existsSync74(absolutePath)) {
|
|
101937
102239
|
try {
|
|
101938
102240
|
canonicalPath = realpathSync8.native(absolutePath);
|
|
101939
102241
|
} catch {
|
|
@@ -101941,8 +102243,8 @@ function toCanonicalPath2(absolutePath) {
|
|
|
101941
102243
|
}
|
|
101942
102244
|
} else {
|
|
101943
102245
|
const absoluteDir = dirname26(absolutePath);
|
|
101944
|
-
const resolvedDir =
|
|
101945
|
-
canonicalPath =
|
|
102246
|
+
const resolvedDir = existsSync74(absoluteDir) ? realpathSync8.native(absoluteDir) : absoluteDir;
|
|
102247
|
+
canonicalPath = join80(resolvedDir, basename11(absolutePath));
|
|
101946
102248
|
}
|
|
101947
102249
|
return normalize2(canonicalPath);
|
|
101948
102250
|
}
|
|
@@ -102986,16 +103288,16 @@ class Diff {
|
|
|
102986
103288
|
}
|
|
102987
103289
|
}
|
|
102988
103290
|
}
|
|
102989
|
-
addToPath(
|
|
102990
|
-
const last =
|
|
103291
|
+
addToPath(path18, added, removed, oldPosInc, options) {
|
|
103292
|
+
const last = path18.lastComponent;
|
|
102991
103293
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
102992
103294
|
return {
|
|
102993
|
-
oldPos:
|
|
103295
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
102994
103296
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
102995
103297
|
};
|
|
102996
103298
|
} else {
|
|
102997
103299
|
return {
|
|
102998
|
-
oldPos:
|
|
103300
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
102999
103301
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
103000
103302
|
};
|
|
103001
103303
|
}
|
|
@@ -104657,8 +104959,8 @@ init_jsonc_parser2();
|
|
|
104657
104959
|
init_opencode_config_dir();
|
|
104658
104960
|
init_plugin_identity();
|
|
104659
104961
|
init_plugin_entry_migrator();
|
|
104660
|
-
import { existsSync as
|
|
104661
|
-
import { join as
|
|
104962
|
+
import { existsSync as existsSync75, readFileSync as readFileSync55 } from "fs";
|
|
104963
|
+
import { join as join81 } from "path";
|
|
104662
104964
|
|
|
104663
104965
|
// src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts
|
|
104664
104966
|
init_migrate_legacy_plugin_entry();
|
|
@@ -104666,18 +104968,18 @@ init_migrate_legacy_plugin_entry();
|
|
|
104666
104968
|
// src/hooks/legacy-plugin-toast/auto-migrate.ts
|
|
104667
104969
|
function detectOpenCodeConfigPath(overrideConfigDir) {
|
|
104668
104970
|
if (overrideConfigDir) {
|
|
104669
|
-
const jsoncPath =
|
|
104670
|
-
const jsonPath =
|
|
104671
|
-
if (
|
|
104971
|
+
const jsoncPath = join81(overrideConfigDir, "opencode.jsonc");
|
|
104972
|
+
const jsonPath = join81(overrideConfigDir, "opencode.json");
|
|
104973
|
+
if (existsSync75(jsoncPath))
|
|
104672
104974
|
return jsoncPath;
|
|
104673
|
-
if (
|
|
104975
|
+
if (existsSync75(jsonPath))
|
|
104674
104976
|
return jsonPath;
|
|
104675
104977
|
return null;
|
|
104676
104978
|
}
|
|
104677
104979
|
const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
104678
|
-
if (
|
|
104980
|
+
if (existsSync75(paths.configJsonc))
|
|
104679
104981
|
return paths.configJsonc;
|
|
104680
|
-
if (
|
|
104982
|
+
if (existsSync75(paths.configJson))
|
|
104681
104983
|
return paths.configJson;
|
|
104682
104984
|
return null;
|
|
104683
104985
|
}
|
|
@@ -104686,7 +104988,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
|
|
|
104686
104988
|
if (!configPath)
|
|
104687
104989
|
return { migrated: false, from: null, to: null, configPath: null };
|
|
104688
104990
|
try {
|
|
104689
|
-
const content =
|
|
104991
|
+
const content = readFileSync55(configPath, "utf-8");
|
|
104690
104992
|
const parseResult = parseJsoncSafe(content);
|
|
104691
104993
|
if (!parseResult.data?.plugin)
|
|
104692
104994
|
return { migrated: false, from: null, to: null, configPath };
|
|
@@ -104870,7 +105172,7 @@ function createNotepadWriteGuardHook() {
|
|
|
104870
105172
|
};
|
|
104871
105173
|
}
|
|
104872
105174
|
// src/hooks/plan-format-validator/hook.ts
|
|
104873
|
-
import { existsSync as
|
|
105175
|
+
import { existsSync as existsSync76, readFileSync as readFileSync56 } from "fs";
|
|
104874
105176
|
import { resolve as resolve21 } from "path";
|
|
104875
105177
|
init_logger();
|
|
104876
105178
|
var WRITE_TOOLS = new Set(["Write", "Edit", "write", "edit"]);
|
|
@@ -104954,9 +105256,9 @@ function createPlanFormatValidatorHook(_ctx) {
|
|
|
104954
105256
|
if (!isPlanFilePath(filePath))
|
|
104955
105257
|
return;
|
|
104956
105258
|
const resolvedPath = resolve21(_ctx.directory, filePath);
|
|
104957
|
-
if (!
|
|
105259
|
+
if (!existsSync76(resolvedPath))
|
|
104958
105260
|
return;
|
|
104959
|
-
const content =
|
|
105261
|
+
const content = readFileSync56(resolvedPath, "utf-8");
|
|
104960
105262
|
if (!CHECKBOX_PATTERN.test(content))
|
|
104961
105263
|
return;
|
|
104962
105264
|
const rawCount = countRawTopLevelCheckboxes(content);
|
|
@@ -105086,21 +105388,21 @@ tool.schema = z36;
|
|
|
105086
105388
|
|
|
105087
105389
|
// src/shared/ripgrep-cli.ts
|
|
105088
105390
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
105089
|
-
import { existsSync as
|
|
105090
|
-
import { dirname as dirname27, join as
|
|
105391
|
+
import { existsSync as existsSync78 } from "fs";
|
|
105392
|
+
import { dirname as dirname27, join as join83 } from "path";
|
|
105091
105393
|
|
|
105092
105394
|
// src/tools/grep/downloader.ts
|
|
105093
105395
|
init_shared();
|
|
105094
105396
|
init_plugin_identity();
|
|
105095
105397
|
init_binary_downloader();
|
|
105096
|
-
import { existsSync as
|
|
105097
|
-
import { join as
|
|
105398
|
+
import { existsSync as existsSync77, readdirSync as readdirSync22 } from "fs";
|
|
105399
|
+
import { join as join82 } from "path";
|
|
105098
105400
|
function findFileRecursive(dir, filename) {
|
|
105099
105401
|
try {
|
|
105100
105402
|
const entries = readdirSync22(dir, { withFileTypes: true, recursive: true });
|
|
105101
105403
|
for (const entry of entries) {
|
|
105102
105404
|
if (entry.isFile() && entry.name === filename) {
|
|
105103
|
-
return
|
|
105405
|
+
return join82(entry.parentPath ?? dir, entry.name);
|
|
105104
105406
|
}
|
|
105105
105407
|
}
|
|
105106
105408
|
} catch {
|
|
@@ -105121,11 +105423,11 @@ function getPlatformKey() {
|
|
|
105121
105423
|
}
|
|
105122
105424
|
function getInstallDir() {
|
|
105123
105425
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
105124
|
-
return
|
|
105426
|
+
return join82(homeDir, ".cache", CACHE_DIR_NAME, "bin");
|
|
105125
105427
|
}
|
|
105126
105428
|
function getRgPath() {
|
|
105127
105429
|
const isWindows2 = process.platform === "win32";
|
|
105128
|
-
return
|
|
105430
|
+
return join82(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
105129
105431
|
}
|
|
105130
105432
|
async function extractTarGz2(archivePath, destDir) {
|
|
105131
105433
|
const platformKey = getPlatformKey();
|
|
@@ -105142,7 +105444,7 @@ async function extractZip2(archivePath, destDir) {
|
|
|
105142
105444
|
const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
|
|
105143
105445
|
const foundPath = findFileRecursive(destDir, binaryName);
|
|
105144
105446
|
if (foundPath) {
|
|
105145
|
-
const destPath =
|
|
105447
|
+
const destPath = join82(destDir, binaryName);
|
|
105146
105448
|
if (foundPath !== destPath) {
|
|
105147
105449
|
const { renameSync: renameSync6 } = await import("fs");
|
|
105148
105450
|
renameSync6(foundPath, destPath);
|
|
@@ -105157,13 +105459,13 @@ async function downloadAndInstallRipgrep() {
|
|
|
105157
105459
|
}
|
|
105158
105460
|
const installDir = getInstallDir();
|
|
105159
105461
|
const rgPath = getRgPath();
|
|
105160
|
-
if (
|
|
105462
|
+
if (existsSync77(rgPath)) {
|
|
105161
105463
|
return rgPath;
|
|
105162
105464
|
}
|
|
105163
105465
|
ensureCacheDir(installDir);
|
|
105164
105466
|
const filename = `ripgrep-${RG_VERSION}-${config.platform}.${config.extension}`;
|
|
105165
105467
|
const url = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
|
|
105166
|
-
const archivePath =
|
|
105468
|
+
const archivePath = join82(installDir, filename);
|
|
105167
105469
|
try {
|
|
105168
105470
|
await downloadArchive(url, archivePath);
|
|
105169
105471
|
if (config.extension === "tar.gz") {
|
|
@@ -105172,7 +105474,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
105172
105474
|
await extractZip2(archivePath, installDir);
|
|
105173
105475
|
}
|
|
105174
105476
|
ensureExecutable(rgPath);
|
|
105175
|
-
if (!
|
|
105477
|
+
if (!existsSync77(rgPath)) {
|
|
105176
105478
|
throw new Error("ripgrep binary not found after extraction");
|
|
105177
105479
|
}
|
|
105178
105480
|
return rgPath;
|
|
@@ -105184,7 +105486,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
105184
105486
|
}
|
|
105185
105487
|
function getInstalledRipgrepPath() {
|
|
105186
105488
|
const rgPath = getRgPath();
|
|
105187
|
-
return
|
|
105489
|
+
return existsSync77(rgPath) ? rgPath : null;
|
|
105188
105490
|
}
|
|
105189
105491
|
|
|
105190
105492
|
// src/shared/ripgrep-cli.ts
|
|
@@ -105220,15 +105522,15 @@ function getOpenCodeBundledRg() {
|
|
|
105220
105522
|
const isWindows2 = process.platform === "win32";
|
|
105221
105523
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
105222
105524
|
const candidates = [
|
|
105223
|
-
|
|
105224
|
-
|
|
105225
|
-
|
|
105226
|
-
|
|
105227
|
-
|
|
105228
|
-
|
|
105525
|
+
join83(getOpenCodeCacheDir(), "bin", rgName),
|
|
105526
|
+
join83(getDataDir(), "opencode", "bin", rgName),
|
|
105527
|
+
join83(execDir, rgName),
|
|
105528
|
+
join83(execDir, "bin", rgName),
|
|
105529
|
+
join83(execDir, "..", "bin", rgName),
|
|
105530
|
+
join83(execDir, "..", "libexec", rgName)
|
|
105229
105531
|
];
|
|
105230
105532
|
for (const candidate of candidates) {
|
|
105231
|
-
if (
|
|
105533
|
+
if (existsSync78(candidate)) {
|
|
105232
105534
|
return candidate;
|
|
105233
105535
|
}
|
|
105234
105536
|
}
|
|
@@ -105971,10 +106273,13 @@ function formatSlashCommand(command) {
|
|
|
105971
106273
|
return lines.join(`
|
|
105972
106274
|
`);
|
|
105973
106275
|
}
|
|
105974
|
-
function formatCombinedDescription(skills2, commands2) {
|
|
105975
|
-
const availableSkills = skills2 ?? [];
|
|
106276
|
+
function formatCombinedDescription(skills2, commands2, options = {}) {
|
|
106277
|
+
const availableSkills = options.includeSkills ? skills2 ?? [] : [];
|
|
105976
106278
|
const availableCommands = commands2 ?? [];
|
|
105977
106279
|
if (availableSkills.length === 0 && availableCommands.length === 0) {
|
|
106280
|
+
if ((skills2?.length ?? 0) > 0) {
|
|
106281
|
+
return TOOL_DESCRIPTION_PREFIX;
|
|
106282
|
+
}
|
|
105978
106283
|
return TOOL_DESCRIPTION_NO_SKILLS;
|
|
105979
106284
|
}
|
|
105980
106285
|
const availableItems = [
|
|
@@ -105986,7 +106291,7 @@ function formatCombinedDescription(skills2, commands2) {
|
|
|
105986
106291
|
}
|
|
105987
106292
|
return `${TOOL_DESCRIPTION_PREFIX}
|
|
105988
106293
|
<available_items>
|
|
105989
|
-
Priority: project > user > opencode > builtin/plugin | Skills listed before commands
|
|
106294
|
+
Priority: project > user > opencode > builtin/plugin${options.includeSkills ? " | Skills listed before commands" : ""}
|
|
105990
106295
|
Invoke via: skill(name="item-name") - omit leading slash for commands.
|
|
105991
106296
|
${availableItems.join(`
|
|
105992
106297
|
`)}
|
|
@@ -106228,7 +106533,9 @@ function createSkillTool(options) {
|
|
|
106228
106533
|
const commands2 = getCommands();
|
|
106229
106534
|
const publicSkills = skills2.filter((s) => !s.definition.agent);
|
|
106230
106535
|
const skillInfos = publicSkills.map(loadedSkillToInfo);
|
|
106231
|
-
cachedDescription = formatCombinedDescription(skillInfos, commands2
|
|
106536
|
+
cachedDescription = formatCombinedDescription(skillInfos, commands2, {
|
|
106537
|
+
includeSkills: options.includeSkillsInDescription
|
|
106538
|
+
});
|
|
106232
106539
|
return cachedDescription;
|
|
106233
106540
|
};
|
|
106234
106541
|
if (options.skills !== undefined) {
|
|
@@ -106246,12 +106553,16 @@ function createSkillTool(options) {
|
|
|
106246
106553
|
}
|
|
106247
106554
|
} catch {}
|
|
106248
106555
|
}
|
|
106249
|
-
cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription
|
|
106556
|
+
cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription, {
|
|
106557
|
+
includeSkills: options.includeSkillsInDescription
|
|
106558
|
+
});
|
|
106250
106559
|
if (needsAsyncRefresh) {
|
|
106251
106560
|
buildDescription(true);
|
|
106252
106561
|
}
|
|
106253
106562
|
} else if (options.commands !== undefined) {
|
|
106254
|
-
cachedDescription = formatCombinedDescription([], options.commands
|
|
106563
|
+
cachedDescription = formatCombinedDescription([], options.commands, {
|
|
106564
|
+
includeSkills: options.includeSkillsInDescription
|
|
106565
|
+
});
|
|
106255
106566
|
}
|
|
106256
106567
|
return tool({
|
|
106257
106568
|
get description() {
|
|
@@ -106267,7 +106578,9 @@ function createSkillTool(options) {
|
|
|
106267
106578
|
async execute(args, ctx) {
|
|
106268
106579
|
const skills2 = await getSkills(ctx);
|
|
106269
106580
|
const commands2 = getCommands();
|
|
106270
|
-
cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2
|
|
106581
|
+
cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2, {
|
|
106582
|
+
includeSkills: options.includeSkillsInDescription
|
|
106583
|
+
});
|
|
106271
106584
|
const requestedName = args.name.replace(/^\//, "");
|
|
106272
106585
|
const matchedSkill = matchSkillByName(skills2, requestedName);
|
|
106273
106586
|
if (matchedSkill) {
|
|
@@ -106328,9 +106641,9 @@ var skill = createSkillTool({ directory: process.cwd() });
|
|
|
106328
106641
|
// src/tools/session-manager/constants.ts
|
|
106329
106642
|
init_shared();
|
|
106330
106643
|
init_shared();
|
|
106331
|
-
import { join as
|
|
106332
|
-
var TODO_DIR2 =
|
|
106333
|
-
var TRANSCRIPT_DIR2 =
|
|
106644
|
+
import { join as join84 } from "path";
|
|
106645
|
+
var TODO_DIR2 = join84(getClaudeConfigDir(), "todos");
|
|
106646
|
+
var TRANSCRIPT_DIR2 = join84(getClaudeConfigDir(), "transcripts");
|
|
106334
106647
|
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
106335
106648
|
|
|
106336
106649
|
Returns a list of available session IDs with metadata including message count, date range, and agents used.
|
|
@@ -106407,12 +106720,12 @@ init_opencode_storage_detection();
|
|
|
106407
106720
|
init_shared();
|
|
106408
106721
|
|
|
106409
106722
|
// src/tools/session-manager/file-storage.ts
|
|
106410
|
-
import { existsSync as
|
|
106723
|
+
import { existsSync as existsSync79 } from "fs";
|
|
106411
106724
|
import { readdir as readdir5, readFile as readFile8 } from "fs/promises";
|
|
106412
|
-
import { join as
|
|
106725
|
+
import { join as join85 } from "path";
|
|
106413
106726
|
init_opencode_message_dir();
|
|
106414
106727
|
async function getFileMainSessions(directory) {
|
|
106415
|
-
if (!
|
|
106728
|
+
if (!existsSync79(SESSION_STORAGE))
|
|
106416
106729
|
return [];
|
|
106417
106730
|
const sessions = [];
|
|
106418
106731
|
try {
|
|
@@ -106420,13 +106733,13 @@ async function getFileMainSessions(directory) {
|
|
|
106420
106733
|
for (const projectDir of projectDirs) {
|
|
106421
106734
|
if (!projectDir.isDirectory())
|
|
106422
106735
|
continue;
|
|
106423
|
-
const projectPath =
|
|
106736
|
+
const projectPath = join85(SESSION_STORAGE, projectDir.name);
|
|
106424
106737
|
const sessionFiles = await readdir5(projectPath);
|
|
106425
106738
|
for (const file of sessionFiles) {
|
|
106426
106739
|
if (!file.endsWith(".json"))
|
|
106427
106740
|
continue;
|
|
106428
106741
|
try {
|
|
106429
|
-
const content = await readFile8(
|
|
106742
|
+
const content = await readFile8(join85(projectPath, file), "utf-8");
|
|
106430
106743
|
const meta = JSON.parse(content);
|
|
106431
106744
|
if (meta.parentID)
|
|
106432
106745
|
continue;
|
|
@@ -106444,7 +106757,7 @@ async function getFileMainSessions(directory) {
|
|
|
106444
106757
|
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
106445
106758
|
}
|
|
106446
106759
|
async function getFileAllSessions() {
|
|
106447
|
-
if (!
|
|
106760
|
+
if (!existsSync79(MESSAGE_STORAGE))
|
|
106448
106761
|
return [];
|
|
106449
106762
|
const sessions = [];
|
|
106450
106763
|
async function scanDirectory(dir) {
|
|
@@ -106453,7 +106766,7 @@ async function getFileAllSessions() {
|
|
|
106453
106766
|
for (const entry of entries) {
|
|
106454
106767
|
if (!entry.isDirectory())
|
|
106455
106768
|
continue;
|
|
106456
|
-
const sessionPath =
|
|
106769
|
+
const sessionPath = join85(dir, entry.name);
|
|
106457
106770
|
const files = await readdir5(sessionPath);
|
|
106458
106771
|
if (files.some((file) => file.endsWith(".json"))) {
|
|
106459
106772
|
sessions.push(entry.name);
|
|
@@ -106473,7 +106786,7 @@ async function fileSessionExists(sessionID) {
|
|
|
106473
106786
|
}
|
|
106474
106787
|
async function getFileSessionMessages(sessionID) {
|
|
106475
106788
|
const messageDir = getMessageDir(sessionID);
|
|
106476
|
-
if (!messageDir || !
|
|
106789
|
+
if (!messageDir || !existsSync79(messageDir))
|
|
106477
106790
|
return [];
|
|
106478
106791
|
const messages = [];
|
|
106479
106792
|
try {
|
|
@@ -106482,7 +106795,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
106482
106795
|
if (!file.endsWith(".json"))
|
|
106483
106796
|
continue;
|
|
106484
106797
|
try {
|
|
106485
|
-
const content = await readFile8(
|
|
106798
|
+
const content = await readFile8(join85(messageDir, file), "utf-8");
|
|
106486
106799
|
const meta = JSON.parse(content);
|
|
106487
106800
|
const parts = await readParts2(meta.id);
|
|
106488
106801
|
messages.push({
|
|
@@ -106508,8 +106821,8 @@ async function getFileSessionMessages(sessionID) {
|
|
|
106508
106821
|
});
|
|
106509
106822
|
}
|
|
106510
106823
|
async function readParts2(messageID) {
|
|
106511
|
-
const partDir =
|
|
106512
|
-
if (!
|
|
106824
|
+
const partDir = join85(PART_STORAGE, messageID);
|
|
106825
|
+
if (!existsSync79(partDir))
|
|
106513
106826
|
return [];
|
|
106514
106827
|
const parts = [];
|
|
106515
106828
|
try {
|
|
@@ -106518,7 +106831,7 @@ async function readParts2(messageID) {
|
|
|
106518
106831
|
if (!file.endsWith(".json"))
|
|
106519
106832
|
continue;
|
|
106520
106833
|
try {
|
|
106521
|
-
const content = await readFile8(
|
|
106834
|
+
const content = await readFile8(join85(partDir, file), "utf-8");
|
|
106522
106835
|
parts.push(JSON.parse(content));
|
|
106523
106836
|
} catch {
|
|
106524
106837
|
continue;
|
|
@@ -106530,14 +106843,14 @@ async function readParts2(messageID) {
|
|
|
106530
106843
|
return parts.sort((a, b) => a.id.localeCompare(b.id));
|
|
106531
106844
|
}
|
|
106532
106845
|
async function getFileSessionTodos(sessionID) {
|
|
106533
|
-
if (!
|
|
106846
|
+
if (!existsSync79(TODO_DIR2))
|
|
106534
106847
|
return [];
|
|
106535
106848
|
try {
|
|
106536
106849
|
const allFiles = await readdir5(TODO_DIR2);
|
|
106537
106850
|
const todoFiles = allFiles.filter((file) => file === `${sessionID}.json`);
|
|
106538
106851
|
for (const file of todoFiles) {
|
|
106539
106852
|
try {
|
|
106540
|
-
const content = await readFile8(
|
|
106853
|
+
const content = await readFile8(join85(TODO_DIR2, file), "utf-8");
|
|
106541
106854
|
const data = JSON.parse(content);
|
|
106542
106855
|
if (!Array.isArray(data))
|
|
106543
106856
|
continue;
|
|
@@ -106557,10 +106870,10 @@ async function getFileSessionTodos(sessionID) {
|
|
|
106557
106870
|
return [];
|
|
106558
106871
|
}
|
|
106559
106872
|
async function getFileSessionTranscript(sessionID) {
|
|
106560
|
-
if (!
|
|
106873
|
+
if (!existsSync79(TRANSCRIPT_DIR2))
|
|
106561
106874
|
return 0;
|
|
106562
|
-
const transcriptFile =
|
|
106563
|
-
if (!
|
|
106875
|
+
const transcriptFile = join85(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
106876
|
+
if (!existsSync79(transcriptFile))
|
|
106564
106877
|
return 0;
|
|
106565
106878
|
try {
|
|
106566
106879
|
const content = await readFile8(transcriptFile, "utf-8");
|
|
@@ -108365,25 +108678,25 @@ init_session_tools_store();
|
|
|
108365
108678
|
init_file_utils2();
|
|
108366
108679
|
init_shared();
|
|
108367
108680
|
init_opencode_config_dir();
|
|
108368
|
-
import { existsSync as
|
|
108369
|
-
import { join as
|
|
108681
|
+
import { existsSync as existsSync82, readdirSync as readdirSync23 } from "fs";
|
|
108682
|
+
import { join as join86 } from "path";
|
|
108370
108683
|
|
|
108371
108684
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
108372
108685
|
init_frontmatter2();
|
|
108373
108686
|
init_logger();
|
|
108374
|
-
import { existsSync as
|
|
108687
|
+
import { existsSync as existsSync81, readFileSync as readFileSync58 } from "fs";
|
|
108375
108688
|
import { basename as basename12, extname as extname3 } from "path";
|
|
108376
108689
|
|
|
108377
108690
|
// src/features/claude-code-agent-loader/json-agent-loader.ts
|
|
108378
108691
|
init_jsonc_parser2();
|
|
108379
108692
|
init_claude_model_mapper();
|
|
108380
|
-
import { existsSync as
|
|
108693
|
+
import { existsSync as existsSync80, readFileSync as readFileSync57 } from "fs";
|
|
108381
108694
|
function parseJsonAgentFile(filePath, scope) {
|
|
108382
108695
|
try {
|
|
108383
|
-
if (!
|
|
108696
|
+
if (!existsSync80(filePath)) {
|
|
108384
108697
|
return null;
|
|
108385
108698
|
}
|
|
108386
|
-
const content =
|
|
108699
|
+
const content = readFileSync57(filePath, "utf-8");
|
|
108387
108700
|
const { data } = parseJsoncSafe(content);
|
|
108388
108701
|
if (!data) {
|
|
108389
108702
|
return null;
|
|
@@ -108420,10 +108733,10 @@ function parseJsonAgentFile(filePath, scope) {
|
|
|
108420
108733
|
init_claude_model_mapper();
|
|
108421
108734
|
function parseMarkdownAgentFile(filePath, scope) {
|
|
108422
108735
|
try {
|
|
108423
|
-
if (!
|
|
108736
|
+
if (!existsSync81(filePath)) {
|
|
108424
108737
|
return null;
|
|
108425
108738
|
}
|
|
108426
|
-
const content =
|
|
108739
|
+
const content = readFileSync58(filePath, "utf-8");
|
|
108427
108740
|
const { data, body } = parseFrontmatter(content);
|
|
108428
108741
|
const fileName = basename12(filePath);
|
|
108429
108742
|
const agentName = fileName.replace(/\.md$/i, "");
|
|
@@ -108455,7 +108768,7 @@ function parseMarkdownAgentFile(filePath, scope) {
|
|
|
108455
108768
|
function loadAgentDefinitions(paths, scope) {
|
|
108456
108769
|
const result = Object.create(null);
|
|
108457
108770
|
for (const filePath of paths) {
|
|
108458
|
-
if (!
|
|
108771
|
+
if (!existsSync81(filePath)) {
|
|
108459
108772
|
log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
|
|
108460
108773
|
continue;
|
|
108461
108774
|
}
|
|
@@ -108480,7 +108793,7 @@ function loadAgentDefinitions(paths, scope) {
|
|
|
108480
108793
|
|
|
108481
108794
|
// src/features/claude-code-agent-loader/loader.ts
|
|
108482
108795
|
function loadAgentsFromDir(agentsDir, scope) {
|
|
108483
|
-
if (!
|
|
108796
|
+
if (!existsSync82(agentsDir)) {
|
|
108484
108797
|
return [];
|
|
108485
108798
|
}
|
|
108486
108799
|
const entries = readdirSync23(agentsDir, { withFileTypes: true });
|
|
@@ -108488,7 +108801,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
108488
108801
|
for (const entry of entries) {
|
|
108489
108802
|
if (!isMarkdownFile(entry))
|
|
108490
108803
|
continue;
|
|
108491
|
-
const agentPath =
|
|
108804
|
+
const agentPath = join86(agentsDir, entry.name);
|
|
108492
108805
|
const agent = parseMarkdownAgentFile(agentPath, scope);
|
|
108493
108806
|
if (agent) {
|
|
108494
108807
|
agents.push(agent);
|
|
@@ -108497,7 +108810,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
108497
108810
|
return agents;
|
|
108498
108811
|
}
|
|
108499
108812
|
function loadUserAgents() {
|
|
108500
|
-
const userAgentsDir =
|
|
108813
|
+
const userAgentsDir = join86(getClaudeConfigDir(), "agents");
|
|
108501
108814
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
108502
108815
|
const result = Object.create(null);
|
|
108503
108816
|
for (const agent of agents) {
|
|
@@ -108506,7 +108819,7 @@ function loadUserAgents() {
|
|
|
108506
108819
|
return result;
|
|
108507
108820
|
}
|
|
108508
108821
|
function loadProjectAgents(directory) {
|
|
108509
|
-
const projectAgentsDir =
|
|
108822
|
+
const projectAgentsDir = join86(directory ?? process.cwd(), ".claude", "agents");
|
|
108510
108823
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
108511
108824
|
const result = Object.create(null);
|
|
108512
108825
|
for (const agent of agents) {
|
|
@@ -108518,7 +108831,7 @@ function loadOpencodeGlobalAgents() {
|
|
|
108518
108831
|
const result = Object.create(null);
|
|
108519
108832
|
const configDirs = getOpenCodeConfigDirs({ binary: "opencode" });
|
|
108520
108833
|
for (const configDir of configDirs) {
|
|
108521
|
-
const opencodeAgentsDir =
|
|
108834
|
+
const opencodeAgentsDir = join86(configDir, "agents");
|
|
108522
108835
|
const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
|
|
108523
108836
|
for (const agent of agents) {
|
|
108524
108837
|
if (!(agent.name in result)) {
|
|
@@ -108529,7 +108842,7 @@ function loadOpencodeGlobalAgents() {
|
|
|
108529
108842
|
return result;
|
|
108530
108843
|
}
|
|
108531
108844
|
function loadOpencodeProjectAgents(directory) {
|
|
108532
|
-
const opencodeProjectDir =
|
|
108845
|
+
const opencodeProjectDir = join86(directory ?? process.cwd(), ".opencode", "agents");
|
|
108533
108846
|
const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
|
|
108534
108847
|
const result = Object.create(null);
|
|
108535
108848
|
for (const agent of agents) {
|
|
@@ -108541,16 +108854,16 @@ function loadOpencodeProjectAgents(directory) {
|
|
|
108541
108854
|
init_opencode_config_dir();
|
|
108542
108855
|
init_jsonc_parser2();
|
|
108543
108856
|
init_resolve_agent_definition_paths();
|
|
108544
|
-
import * as
|
|
108545
|
-
import * as
|
|
108857
|
+
import * as fs22 from "fs";
|
|
108858
|
+
import * as path18 from "path";
|
|
108546
108859
|
init_claude_model_mapper();
|
|
108547
|
-
function
|
|
108860
|
+
function getConfigPaths4(directory) {
|
|
108548
108861
|
const globalConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
108549
108862
|
const paths = [
|
|
108550
|
-
|
|
108551
|
-
|
|
108552
|
-
|
|
108553
|
-
|
|
108863
|
+
path18.join(directory, ".opencode", "opencode.json"),
|
|
108864
|
+
path18.join(directory, ".opencode", "opencode.jsonc"),
|
|
108865
|
+
path18.join(globalConfigDir, "opencode.json"),
|
|
108866
|
+
path18.join(globalConfigDir, "opencode.jsonc")
|
|
108554
108867
|
];
|
|
108555
108868
|
return paths;
|
|
108556
108869
|
}
|
|
@@ -108579,15 +108892,15 @@ function convertInlineAgent(agentData) {
|
|
|
108579
108892
|
}
|
|
108580
108893
|
function readOpencodeConfigAgents(directory) {
|
|
108581
108894
|
const result = Object.create(null);
|
|
108582
|
-
for (const configPath of
|
|
108895
|
+
for (const configPath of getConfigPaths4(directory)) {
|
|
108583
108896
|
try {
|
|
108584
|
-
if (!
|
|
108897
|
+
if (!fs22.existsSync(configPath))
|
|
108585
108898
|
continue;
|
|
108586
|
-
const content =
|
|
108899
|
+
const content = fs22.readFileSync(configPath, "utf-8");
|
|
108587
108900
|
const parseResult = parseJsoncSafe(content);
|
|
108588
108901
|
if (!parseResult.data)
|
|
108589
108902
|
continue;
|
|
108590
|
-
const configDir =
|
|
108903
|
+
const configDir = path18.dirname(configPath);
|
|
108591
108904
|
const agentsToLoad = parseResult.data.agents || parseResult.data.agent;
|
|
108592
108905
|
if (agentsToLoad && typeof agentsToLoad === "object") {
|
|
108593
108906
|
for (const [agentName, agentData] of Object.entries(agentsToLoad)) {
|
|
@@ -109283,9 +109596,9 @@ import { pathToFileURL } from "url";
|
|
|
109283
109596
|
// src/tools/look-at/image-converter.ts
|
|
109284
109597
|
init_shared();
|
|
109285
109598
|
import * as childProcess2 from "child_process";
|
|
109286
|
-
import { existsSync as
|
|
109599
|
+
import { existsSync as existsSync84, mkdtempSync, readFileSync as readFileSync60, rmSync as rmSync4, unlinkSync as unlinkSync14, writeFileSync as writeFileSync19 } from "fs";
|
|
109287
109600
|
import { tmpdir as tmpdir7 } from "os";
|
|
109288
|
-
import { dirname as dirname31, join as
|
|
109601
|
+
import { dirname as dirname31, join as join88 } from "path";
|
|
109289
109602
|
var SUPPORTED_FORMATS = new Set([
|
|
109290
109603
|
"image/jpeg",
|
|
109291
109604
|
"image/png",
|
|
@@ -109323,11 +109636,11 @@ function needsConversion(mimeType) {
|
|
|
109323
109636
|
return mimeType.startsWith("image/");
|
|
109324
109637
|
}
|
|
109325
109638
|
function convertImageToJpeg(inputPath, mimeType) {
|
|
109326
|
-
if (!
|
|
109639
|
+
if (!existsSync84(inputPath)) {
|
|
109327
109640
|
throw new Error(`File not found: ${inputPath}`);
|
|
109328
109641
|
}
|
|
109329
|
-
const tempDir = mkdtempSync(
|
|
109330
|
-
const outputPath =
|
|
109642
|
+
const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-img-"));
|
|
109643
|
+
const outputPath = join88(tempDir, "converted.jpg");
|
|
109331
109644
|
log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
|
|
109332
109645
|
try {
|
|
109333
109646
|
if (process.platform === "darwin") {
|
|
@@ -109337,7 +109650,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109337
109650
|
encoding: "utf-8",
|
|
109338
109651
|
timeout: CONVERSION_TIMEOUT_MS
|
|
109339
109652
|
});
|
|
109340
|
-
if (
|
|
109653
|
+
if (existsSync84(outputPath)) {
|
|
109341
109654
|
log(`[image-converter] Converted using sips: ${outputPath}`);
|
|
109342
109655
|
return outputPath;
|
|
109343
109656
|
}
|
|
@@ -109352,7 +109665,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109352
109665
|
encoding: "utf-8",
|
|
109353
109666
|
timeout: CONVERSION_TIMEOUT_MS
|
|
109354
109667
|
});
|
|
109355
|
-
if (
|
|
109668
|
+
if (existsSync84(outputPath)) {
|
|
109356
109669
|
log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
|
|
109357
109670
|
return outputPath;
|
|
109358
109671
|
}
|
|
@@ -109365,7 +109678,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109365
109678
|
` + ` RHEL/CentOS: sudo yum install ImageMagick`);
|
|
109366
109679
|
} catch (error) {
|
|
109367
109680
|
try {
|
|
109368
|
-
if (
|
|
109681
|
+
if (existsSync84(outputPath)) {
|
|
109369
109682
|
unlinkSync14(outputPath);
|
|
109370
109683
|
}
|
|
109371
109684
|
} catch {}
|
|
@@ -109379,11 +109692,11 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109379
109692
|
function cleanupConvertedImage(filePath) {
|
|
109380
109693
|
try {
|
|
109381
109694
|
const tempDirectory = dirname31(filePath);
|
|
109382
|
-
if (
|
|
109695
|
+
if (existsSync84(filePath)) {
|
|
109383
109696
|
unlinkSync14(filePath);
|
|
109384
109697
|
log(`[image-converter] Cleaned up temporary file: ${filePath}`);
|
|
109385
109698
|
}
|
|
109386
|
-
if (
|
|
109699
|
+
if (existsSync84(tempDirectory)) {
|
|
109387
109700
|
rmSync4(tempDirectory, { recursive: true, force: true });
|
|
109388
109701
|
log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
|
|
109389
109702
|
}
|
|
@@ -109392,9 +109705,9 @@ function cleanupConvertedImage(filePath) {
|
|
|
109392
109705
|
}
|
|
109393
109706
|
}
|
|
109394
109707
|
function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
109395
|
-
const tempDir = mkdtempSync(
|
|
109708
|
+
const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-b64-"));
|
|
109396
109709
|
const inputExt = mimeType.split("/")[1] || "bin";
|
|
109397
|
-
const inputPath =
|
|
109710
|
+
const inputPath = join88(tempDir, `input.${inputExt}`);
|
|
109398
109711
|
const tempFiles = [inputPath];
|
|
109399
109712
|
try {
|
|
109400
109713
|
const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
@@ -109403,14 +109716,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
|
109403
109716
|
log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
|
|
109404
109717
|
const outputPath = convertImageToJpeg(inputPath, mimeType);
|
|
109405
109718
|
tempFiles.push(outputPath);
|
|
109406
|
-
const convertedBuffer =
|
|
109719
|
+
const convertedBuffer = readFileSync60(outputPath);
|
|
109407
109720
|
const convertedBase64 = convertedBuffer.toString("base64");
|
|
109408
109721
|
log(`[image-converter] Base64 conversion successful`);
|
|
109409
109722
|
return { base64: convertedBase64, tempFiles };
|
|
109410
109723
|
} catch (error) {
|
|
109411
109724
|
tempFiles.forEach((file) => {
|
|
109412
109725
|
try {
|
|
109413
|
-
if (
|
|
109726
|
+
if (existsSync84(file))
|
|
109414
109727
|
unlinkSync14(file);
|
|
109415
109728
|
} catch {}
|
|
109416
109729
|
});
|
|
@@ -109549,13 +109862,68 @@ function asSessionMessage(value) {
|
|
|
109549
109862
|
function getCreatedTime(message) {
|
|
109550
109863
|
return message.info?.time?.created ?? 0;
|
|
109551
109864
|
}
|
|
109865
|
+
function asText(value) {
|
|
109866
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
109867
|
+
}
|
|
109868
|
+
function collectContentText(value) {
|
|
109869
|
+
const directText = asText(value);
|
|
109870
|
+
if (directText)
|
|
109871
|
+
return [directText];
|
|
109872
|
+
if (!Array.isArray(value))
|
|
109873
|
+
return [];
|
|
109874
|
+
const texts = [];
|
|
109875
|
+
for (const block of value) {
|
|
109876
|
+
if (!isObject2(block))
|
|
109877
|
+
continue;
|
|
109878
|
+
const text = asText(block["text"]) ?? asText(block["content"]);
|
|
109879
|
+
if (text)
|
|
109880
|
+
texts.push(text);
|
|
109881
|
+
}
|
|
109882
|
+
return texts;
|
|
109883
|
+
}
|
|
109884
|
+
function normalizeThinkingText(text) {
|
|
109885
|
+
const answerMatches = [...text.matchAll(/<answer\b[^>]*>([\s\S]*?)<\/answer>/gi)].map((match) => match[1]?.trim()).filter((value) => Boolean(value));
|
|
109886
|
+
const withoutThinking = text.replace(/<think\b[^>]*>[\s\S]*?<\/think>/gi, "").trim();
|
|
109887
|
+
const normalized = answerMatches.length > 0 ? answerMatches.join(`
|
|
109888
|
+
`) : withoutThinking;
|
|
109889
|
+
return normalized.length > 0 ? normalized : null;
|
|
109890
|
+
}
|
|
109552
109891
|
function getTextParts(message) {
|
|
109553
109892
|
if (!Array.isArray(message.parts))
|
|
109554
109893
|
return [];
|
|
109555
109894
|
return message.parts.filter((part) => isObject2(part)).map((part) => ({
|
|
109556
109895
|
type: typeof part["type"] === "string" ? part["type"] : undefined,
|
|
109557
|
-
text: typeof part["text"] === "string" ? part["text"] : undefined
|
|
109558
|
-
|
|
109896
|
+
text: typeof part["text"] === "string" ? part["text"] : undefined,
|
|
109897
|
+
content: part["content"],
|
|
109898
|
+
reasoning: typeof part["reasoning"] === "string" ? part["reasoning"] : undefined,
|
|
109899
|
+
reasoningContent: typeof part["reasoning_content"] === "string" ? part["reasoning_content"] : undefined
|
|
109900
|
+
}));
|
|
109901
|
+
}
|
|
109902
|
+
function extractTextFromParts(parts) {
|
|
109903
|
+
const textCandidates = [];
|
|
109904
|
+
const reasoningCandidates = [];
|
|
109905
|
+
for (const part of parts) {
|
|
109906
|
+
const contentTexts = collectContentText(part.content);
|
|
109907
|
+
const directText = asText(part.text);
|
|
109908
|
+
if (part.type === "text") {
|
|
109909
|
+
if (directText)
|
|
109910
|
+
textCandidates.push(directText);
|
|
109911
|
+
textCandidates.push(...contentTexts);
|
|
109912
|
+
} else if (part.type === "reasoning" || part.type === "thinking") {
|
|
109913
|
+
if (directText)
|
|
109914
|
+
reasoningCandidates.push(directText);
|
|
109915
|
+
textCandidates.push(...contentTexts);
|
|
109916
|
+
}
|
|
109917
|
+
const reasoningText = asText(part.reasoningContent) ?? asText(part.reasoning);
|
|
109918
|
+
if (reasoningText)
|
|
109919
|
+
reasoningCandidates.push(reasoningText);
|
|
109920
|
+
}
|
|
109921
|
+
const primaryText = textCandidates.map(normalizeThinkingText).filter((text) => text !== null).join(`
|
|
109922
|
+
`);
|
|
109923
|
+
if (primaryText)
|
|
109924
|
+
return primaryText;
|
|
109925
|
+
return reasoningCandidates.map(normalizeThinkingText).filter((text) => text !== null).join(`
|
|
109926
|
+
`) || null;
|
|
109559
109927
|
}
|
|
109560
109928
|
function extractLatestAssistantText(messages) {
|
|
109561
109929
|
return extractLatestAssistantOutcome(messages).text;
|
|
@@ -109571,9 +109939,7 @@ function extractLatestAssistantOutcome(messages) {
|
|
|
109571
109939
|
if (!lastAssistantMessage) {
|
|
109572
109940
|
return { text: null, errorName: null, hasAssistant, completed: false };
|
|
109573
109941
|
}
|
|
109574
|
-
const
|
|
109575
|
-
const text = textParts.map((part) => part.text).join(`
|
|
109576
|
-
`) || null;
|
|
109942
|
+
const text = extractTextFromParts(getTextParts(lastAssistantMessage));
|
|
109577
109943
|
const allParts = Array.isArray(lastAssistantMessage.parts) ? lastAssistantMessage.parts : [];
|
|
109578
109944
|
const errorPart = allParts.find((part) => isObject2(part) && typeof part["type"] === "string" && part["type"] === "error");
|
|
109579
109945
|
const errorName = errorPart && typeof errorPart["error"] === "string" ? errorPart["error"] : null;
|
|
@@ -109971,9 +110337,9 @@ function getMissingFilePathFromError(error) {
|
|
|
109971
110337
|
if (!(error instanceof Error)) {
|
|
109972
110338
|
return null;
|
|
109973
110339
|
}
|
|
109974
|
-
const
|
|
109975
|
-
if (typeof
|
|
109976
|
-
return
|
|
110340
|
+
const path19 = Reflect.get(error, "path");
|
|
110341
|
+
if (typeof path19 === "string" && path19.length > 0) {
|
|
110342
|
+
return path19;
|
|
109977
110343
|
}
|
|
109978
110344
|
if (error instanceof Error) {
|
|
109979
110345
|
const match = /open '([^']+)'/.exec(error.message);
|
|
@@ -112948,7 +113314,7 @@ function isExplicitSyncRun(runInBackground) {
|
|
|
112948
113314
|
// src/tools/delegate-task/index.ts
|
|
112949
113315
|
init_constants();
|
|
112950
113316
|
// src/tools/task/task-create.ts
|
|
112951
|
-
import { join as
|
|
113317
|
+
import { join as join90 } from "path";
|
|
112952
113318
|
|
|
112953
113319
|
// src/tools/task/types.ts
|
|
112954
113320
|
import { z as z37 } from "zod";
|
|
@@ -113004,18 +113370,18 @@ var TaskDeleteInputSchema = z37.object({
|
|
|
113004
113370
|
|
|
113005
113371
|
// src/features/claude-tasks/storage.ts
|
|
113006
113372
|
init_opencode_config_dir();
|
|
113007
|
-
import { join as
|
|
113008
|
-
import { existsSync as
|
|
113373
|
+
import { join as join89, dirname as dirname32, basename as basename14, isAbsolute as isAbsolute17 } from "path";
|
|
113374
|
+
import { existsSync as existsSync85, mkdirSync as mkdirSync18, readFileSync as readFileSync61, writeFileSync as writeFileSync20, renameSync as renameSync6, unlinkSync as unlinkSync15, readdirSync as readdirSync24 } from "fs";
|
|
113009
113375
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
113010
113376
|
function getTaskDir(config = {}) {
|
|
113011
113377
|
const tasksConfig = config.sisyphus?.tasks;
|
|
113012
113378
|
const storagePath = tasksConfig?.storage_path;
|
|
113013
113379
|
if (storagePath) {
|
|
113014
|
-
return isAbsolute17(storagePath) ? storagePath :
|
|
113380
|
+
return isAbsolute17(storagePath) ? storagePath : join89(process.cwd(), storagePath);
|
|
113015
113381
|
}
|
|
113016
113382
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
113017
113383
|
const listId = resolveTaskListId(config);
|
|
113018
|
-
return
|
|
113384
|
+
return join89(configDir, "tasks", listId);
|
|
113019
113385
|
}
|
|
113020
113386
|
function sanitizePathSegment(value) {
|
|
113021
113387
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
|
|
@@ -113033,16 +113399,16 @@ function resolveTaskListId(config = {}) {
|
|
|
113033
113399
|
return sanitizePathSegment(basename14(process.cwd()));
|
|
113034
113400
|
}
|
|
113035
113401
|
function ensureDir(dirPath) {
|
|
113036
|
-
if (!
|
|
113402
|
+
if (!existsSync85(dirPath)) {
|
|
113037
113403
|
mkdirSync18(dirPath, { recursive: true });
|
|
113038
113404
|
}
|
|
113039
113405
|
}
|
|
113040
113406
|
function readJsonSafe(filePath, schema2) {
|
|
113041
113407
|
try {
|
|
113042
|
-
if (!
|
|
113408
|
+
if (!existsSync85(filePath)) {
|
|
113043
113409
|
return null;
|
|
113044
113410
|
}
|
|
113045
|
-
const content =
|
|
113411
|
+
const content = readFileSync61(filePath, "utf-8");
|
|
113046
113412
|
const parsed = JSON.parse(content);
|
|
113047
113413
|
const result = schema2.safeParse(parsed);
|
|
113048
113414
|
if (!result.success) {
|
|
@@ -113062,7 +113428,7 @@ function writeJsonAtomic(filePath, data) {
|
|
|
113062
113428
|
renameSync6(tempPath, filePath);
|
|
113063
113429
|
} catch (error) {
|
|
113064
113430
|
try {
|
|
113065
|
-
if (
|
|
113431
|
+
if (existsSync85(tempPath)) {
|
|
113066
113432
|
unlinkSync15(tempPath);
|
|
113067
113433
|
}
|
|
113068
113434
|
} catch {}
|
|
@@ -113074,7 +113440,7 @@ function generateTaskId() {
|
|
|
113074
113440
|
return `T-${randomUUID5()}`;
|
|
113075
113441
|
}
|
|
113076
113442
|
function acquireLock2(dirPath) {
|
|
113077
|
-
const lockPath =
|
|
113443
|
+
const lockPath = join89(dirPath, ".lock");
|
|
113078
113444
|
const lockId = randomUUID5();
|
|
113079
113445
|
const createLock = (timestamp2) => {
|
|
113080
113446
|
writeFileSync20(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
|
|
@@ -113084,7 +113450,7 @@ function acquireLock2(dirPath) {
|
|
|
113084
113450
|
};
|
|
113085
113451
|
const isStale = () => {
|
|
113086
113452
|
try {
|
|
113087
|
-
const lockContent =
|
|
113453
|
+
const lockContent = readFileSync61(lockPath, "utf-8");
|
|
113088
113454
|
const lockData = JSON.parse(lockContent);
|
|
113089
113455
|
const lockAge = Date.now() - lockData.timestamp;
|
|
113090
113456
|
return lockAge > STALE_LOCK_THRESHOLD_MS;
|
|
@@ -113122,9 +113488,9 @@ function acquireLock2(dirPath) {
|
|
|
113122
113488
|
acquired: true,
|
|
113123
113489
|
release: () => {
|
|
113124
113490
|
try {
|
|
113125
|
-
if (!
|
|
113491
|
+
if (!existsSync85(lockPath))
|
|
113126
113492
|
return;
|
|
113127
|
-
const lockContent =
|
|
113493
|
+
const lockContent = readFileSync61(lockPath, "utf-8");
|
|
113128
113494
|
const lockData = JSON.parse(lockContent);
|
|
113129
113495
|
if (lockData.id !== lockId)
|
|
113130
113496
|
return;
|
|
@@ -113287,7 +113653,7 @@ async function handleCreate(args, config, ctx, context) {
|
|
|
113287
113653
|
threadID: context.sessionID
|
|
113288
113654
|
};
|
|
113289
113655
|
const validatedTask = TaskObjectSchema.parse(task);
|
|
113290
|
-
writeJsonAtomic(
|
|
113656
|
+
writeJsonAtomic(join90(taskDir, `${taskId}.json`), validatedTask);
|
|
113291
113657
|
await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
|
|
113292
113658
|
return JSON.stringify({
|
|
113293
113659
|
task: {
|
|
@@ -113309,7 +113675,7 @@ async function handleCreate(args, config, ctx, context) {
|
|
|
113309
113675
|
}
|
|
113310
113676
|
}
|
|
113311
113677
|
// src/tools/task/task-get.ts
|
|
113312
|
-
import { join as
|
|
113678
|
+
import { join as join91 } from "path";
|
|
113313
113679
|
var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
|
|
113314
113680
|
function parseTaskId(id) {
|
|
113315
113681
|
if (!TASK_ID_PATTERN.test(id))
|
|
@@ -113334,7 +113700,7 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
113334
113700
|
return JSON.stringify({ error: "invalid_task_id" });
|
|
113335
113701
|
}
|
|
113336
113702
|
const taskDir = getTaskDir(config);
|
|
113337
|
-
const taskPath =
|
|
113703
|
+
const taskPath = join91(taskDir, `${taskId}.json`);
|
|
113338
113704
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
113339
113705
|
return JSON.stringify({ task: task ?? null });
|
|
113340
113706
|
} catch (error) {
|
|
@@ -113347,8 +113713,8 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
113347
113713
|
});
|
|
113348
113714
|
}
|
|
113349
113715
|
// src/tools/task/task-list.ts
|
|
113350
|
-
import { join as
|
|
113351
|
-
import { existsSync as
|
|
113716
|
+
import { join as join92 } from "path";
|
|
113717
|
+
import { existsSync as existsSync86, readdirSync as readdirSync25 } from "fs";
|
|
113352
113718
|
function createTaskList(config) {
|
|
113353
113719
|
return tool({
|
|
113354
113720
|
description: `List all active tasks with summary information.
|
|
@@ -113359,7 +113725,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113359
113725
|
args: {},
|
|
113360
113726
|
execute: async () => {
|
|
113361
113727
|
const taskDir = getTaskDir(config);
|
|
113362
|
-
if (!
|
|
113728
|
+
if (!existsSync86(taskDir)) {
|
|
113363
113729
|
return JSON.stringify({ tasks: [] });
|
|
113364
113730
|
}
|
|
113365
113731
|
const files = readdirSync25(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
|
|
@@ -113368,7 +113734,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113368
113734
|
}
|
|
113369
113735
|
const allTasks = [];
|
|
113370
113736
|
for (const fileId of files) {
|
|
113371
|
-
const task = readJsonSafe(
|
|
113737
|
+
const task = readJsonSafe(join92(taskDir, `${fileId}.json`), TaskObjectSchema);
|
|
113372
113738
|
if (task) {
|
|
113373
113739
|
allTasks.push(task);
|
|
113374
113740
|
}
|
|
@@ -113396,7 +113762,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113396
113762
|
});
|
|
113397
113763
|
}
|
|
113398
113764
|
// src/tools/task/task-update.ts
|
|
113399
|
-
import { join as
|
|
113765
|
+
import { join as join93 } from "path";
|
|
113400
113766
|
var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
|
|
113401
113767
|
function parseTaskId2(id) {
|
|
113402
113768
|
if (!TASK_ID_PATTERN2.test(id))
|
|
@@ -113444,7 +113810,7 @@ async function handleUpdate(args, config, ctx, context) {
|
|
|
113444
113810
|
return JSON.stringify({ error: "task_lock_unavailable" });
|
|
113445
113811
|
}
|
|
113446
113812
|
try {
|
|
113447
|
-
const taskPath =
|
|
113813
|
+
const taskPath = join93(taskDir, `${taskId}.json`);
|
|
113448
113814
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
113449
113815
|
if (!task) {
|
|
113450
113816
|
return JSON.stringify({ error: "task_not_found" });
|
|
@@ -113502,10 +113868,10 @@ init_bun_file_shim();
|
|
|
113502
113868
|
// src/tools/hashline-edit/formatter-trigger.ts
|
|
113503
113869
|
init_shared();
|
|
113504
113870
|
init_bun_spawn_shim();
|
|
113505
|
-
import
|
|
113871
|
+
import path19 from "path";
|
|
113506
113872
|
var cachedFormattersByDirectory = new Map;
|
|
113507
113873
|
function getFormatterCacheKey(directory) {
|
|
113508
|
-
return
|
|
113874
|
+
return path19.resolve(directory);
|
|
113509
113875
|
}
|
|
113510
113876
|
async function resolveFormatters(client, directory) {
|
|
113511
113877
|
const cacheKey = getFormatterCacheKey(directory);
|
|
@@ -113556,7 +113922,7 @@ function buildFormatterCommand(command, filePath) {
|
|
|
113556
113922
|
return command.map((arg) => arg.replace(/\$FILE/g, filePath));
|
|
113557
113923
|
}
|
|
113558
113924
|
async function runFormattersForFile(client, directory, filePath) {
|
|
113559
|
-
const ext =
|
|
113925
|
+
const ext = path19.extname(filePath);
|
|
113560
113926
|
if (!ext)
|
|
113561
113927
|
return;
|
|
113562
113928
|
const formatters = await resolveFormatters(client, directory);
|
|
@@ -113876,17 +114242,17 @@ function buildMemberPromptBody(member, text) {
|
|
|
113876
114242
|
// src/features/team-mode/team-mailbox/reservation.ts
|
|
113877
114243
|
init_paths();
|
|
113878
114244
|
import { mkdir as mkdir3, readdir as readdir6, rename as rename2, stat as stat5 } from "fs/promises";
|
|
113879
|
-
import
|
|
114245
|
+
import path20 from "path";
|
|
113880
114246
|
var RESERVED_PREFIX = ".delivering-";
|
|
113881
114247
|
var RESERVED_SUFFIX = ".json";
|
|
113882
114248
|
function isMissingPathError(error) {
|
|
113883
114249
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
113884
114250
|
}
|
|
113885
114251
|
function buildReservation(inboxDir, messageId) {
|
|
113886
|
-
const inboxPath =
|
|
113887
|
-
const reservedPath =
|
|
113888
|
-
const processedDir =
|
|
113889
|
-
const processedPath =
|
|
114252
|
+
const inboxPath = path20.join(inboxDir, `${messageId}.json`);
|
|
114253
|
+
const reservedPath = path20.join(inboxDir, `${RESERVED_PREFIX}${messageId}${RESERVED_SUFFIX}`);
|
|
114254
|
+
const processedDir = path20.join(inboxDir, "processed");
|
|
114255
|
+
const processedPath = path20.join(processedDir, `${messageId}.json`);
|
|
113890
114256
|
return { reservedPath, inboxPath, processedPath, processedDir };
|
|
113891
114257
|
}
|
|
113892
114258
|
async function reserveMessageForDelivery(teamRunId, recipientName, messageId, config) {
|
|
@@ -113922,7 +114288,7 @@ init_store();
|
|
|
113922
114288
|
init_locks();
|
|
113923
114289
|
import { Buffer as Buffer2 } from "buffer";
|
|
113924
114290
|
import { mkdir as mkdir4, readdir as readdir7, stat as stat6 } from "fs/promises";
|
|
113925
|
-
import
|
|
114291
|
+
import path21 from "path";
|
|
113926
114292
|
|
|
113927
114293
|
class BroadcastNotPermittedError extends Error {
|
|
113928
114294
|
constructor(message = "broadcast requires lead role") {
|
|
@@ -113991,7 +114357,7 @@ async function getUnreadSizeBytes(inboxDir) {
|
|
|
113991
114357
|
return !entry.name.startsWith(".");
|
|
113992
114358
|
});
|
|
113993
114359
|
const sizes = await Promise.all(unreadEntries.map(async (entry) => {
|
|
113994
|
-
const fileStats = await stat6(
|
|
114360
|
+
const fileStats = await stat6(path21.join(inboxDir, entry.name));
|
|
113995
114361
|
return fileStats.size;
|
|
113996
114362
|
}));
|
|
113997
114363
|
return sizes.reduce((totalBytes, fileSize) => totalBytes + fileSize, 0);
|
|
@@ -114037,8 +114403,8 @@ async function sendMessage(message, teamRunId, config, context) {
|
|
|
114037
114403
|
if (nextUnreadSizeBytes > config.recipient_unread_max_bytes) {
|
|
114038
114404
|
throw new RecipientBackpressureError;
|
|
114039
114405
|
}
|
|
114040
|
-
const unreservedPath =
|
|
114041
|
-
const reservedPath =
|
|
114406
|
+
const unreservedPath = path21.join(inboxDir, `${message.messageId}.json`);
|
|
114407
|
+
const reservedPath = path21.join(inboxDir, `.delivering-${message.messageId}.json`);
|
|
114042
114408
|
if (await fileExists(unreservedPath) || await fileExists(reservedPath)) {
|
|
114043
114409
|
throw new DuplicateMessageIdError;
|
|
114044
114410
|
}
|
|
@@ -114387,7 +114753,6 @@ function createRuntimeTmuxConfig(pluginConfig) {
|
|
|
114387
114753
|
function createSessionHooks(args) {
|
|
114388
114754
|
const { ctx, pluginConfig, modelCacheState, backgroundManager, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args;
|
|
114389
114755
|
const safeHook = (hookName, factory) => safeCreateHook(hookName, factory, { enabled: safeHookEnabled });
|
|
114390
|
-
const contextWindowMonitor = isHookEnabled("context-window-monitor") ? safeHook("context-window-monitor", () => createContextWindowMonitorHook(ctx, modelCacheState)) : null;
|
|
114391
114756
|
const preemptiveCompaction = isHookEnabled("preemptive-compaction") && pluginConfig.experimental?.preemptive_compaction ? safeHook("preemptive-compaction", () => createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState)) : null;
|
|
114392
114757
|
const sessionRecovery = isHookEnabled("session-recovery") ? safeHook("session-recovery", () => createSessionRecoveryHook(ctx, { experimental: pluginConfig.experimental })) : null;
|
|
114393
114758
|
let sessionNotification = null;
|
|
@@ -114485,7 +114850,6 @@ function createSessionHooks(args) {
|
|
|
114485
114850
|
})) : null;
|
|
114486
114851
|
const legacyPluginToast = isHookEnabled("legacy-plugin-toast") ? safeHook("legacy-plugin-toast", () => createLegacyPluginToastHook(ctx)) : null;
|
|
114487
114852
|
return {
|
|
114488
|
-
contextWindowMonitor,
|
|
114489
114853
|
preemptiveCompaction,
|
|
114490
114854
|
sessionRecovery,
|
|
114491
114855
|
sessionNotification,
|
|
@@ -114794,8 +115158,8 @@ function createUnstableAgentBabysitter(args) {
|
|
|
114794
115158
|
directory: ctx.directory,
|
|
114795
115159
|
client: {
|
|
114796
115160
|
session: {
|
|
114797
|
-
messages: async ({ path:
|
|
114798
|
-
const result = await ctx.client.session.messages({ path:
|
|
115161
|
+
messages: async ({ path: path22 }) => {
|
|
115162
|
+
const result = await ctx.client.session.messages({ path: path22 });
|
|
114799
115163
|
if (Array.isArray(result))
|
|
114800
115164
|
return result;
|
|
114801
115165
|
if (typeof result === "object" && result !== null) {
|
|
@@ -114954,7 +115318,7 @@ function createHooks(args) {
|
|
|
114954
115318
|
};
|
|
114955
115319
|
}
|
|
114956
115320
|
// src/features/background-agent/manager.ts
|
|
114957
|
-
import { join as
|
|
115321
|
+
import { join as join95 } from "path";
|
|
114958
115322
|
init_shared();
|
|
114959
115323
|
init_event_session_id();
|
|
114960
115324
|
init_session_category_registry();
|
|
@@ -115234,8 +115598,8 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
115234
115598
|
}
|
|
115235
115599
|
|
|
115236
115600
|
// src/features/background-agent/compaction-aware-message-resolver.ts
|
|
115237
|
-
import { readdirSync as readdirSync26, readFileSync as
|
|
115238
|
-
import { join as
|
|
115601
|
+
import { readdirSync as readdirSync26, readFileSync as readFileSync62 } from "fs";
|
|
115602
|
+
import { join as join94 } from "path";
|
|
115239
115603
|
init_compaction_marker();
|
|
115240
115604
|
init_compaction_marker();
|
|
115241
115605
|
function hasFullAgentAndModel(message) {
|
|
@@ -115316,7 +115680,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
|
|
|
115316
115680
|
const messages = [];
|
|
115317
115681
|
for (const file of files) {
|
|
115318
115682
|
try {
|
|
115319
|
-
const content =
|
|
115683
|
+
const content = readFileSync62(join94(messageDir, file), "utf-8");
|
|
115320
115684
|
const parsed = JSON.parse(content);
|
|
115321
115685
|
if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
|
|
115322
115686
|
continue;
|
|
@@ -115356,6 +115720,16 @@ class ConcurrencyManager {
|
|
|
115356
115720
|
}
|
|
115357
115721
|
return 5;
|
|
115358
115722
|
}
|
|
115723
|
+
getConcurrencyKey(model) {
|
|
115724
|
+
if (this.config?.modelConcurrency?.[model] !== undefined) {
|
|
115725
|
+
return model;
|
|
115726
|
+
}
|
|
115727
|
+
const provider = model.split("/")[0];
|
|
115728
|
+
if (provider && this.config?.providerConcurrency?.[provider] !== undefined) {
|
|
115729
|
+
return provider;
|
|
115730
|
+
}
|
|
115731
|
+
return model;
|
|
115732
|
+
}
|
|
115359
115733
|
async acquire(model) {
|
|
115360
115734
|
const limit = this.getConcurrencyLimit(model);
|
|
115361
115735
|
if (limit === Infinity) {
|
|
@@ -115390,6 +115764,9 @@ class ConcurrencyManager {
|
|
|
115390
115764
|
const queue = this.queues.get(model);
|
|
115391
115765
|
while (queue && queue.length > 0) {
|
|
115392
115766
|
const next = queue.shift();
|
|
115767
|
+
if (!next) {
|
|
115768
|
+
continue;
|
|
115769
|
+
}
|
|
115393
115770
|
if (!next.settled) {
|
|
115394
115771
|
next.resolve();
|
|
115395
115772
|
return;
|
|
@@ -115583,7 +115960,8 @@ async function tryFallbackRetry(args) {
|
|
|
115583
115960
|
});
|
|
115584
115961
|
throw new TeamModeFallbackError(`team-mode fallback denied: cannot preserve team context for task ${task.id} (teamRunId=${task.teamRunId})`);
|
|
115585
115962
|
}
|
|
115586
|
-
const
|
|
115963
|
+
const rawKey = task.model ? `${task.model.providerID}/${task.model.modelID}` : task.agent;
|
|
115964
|
+
const key = concurrencyManager.getConcurrencyKey(rawKey);
|
|
115587
115965
|
const queue = queuesByKey.get(key) ?? [];
|
|
115588
115966
|
const retryInput = {
|
|
115589
115967
|
description: task.description,
|
|
@@ -116063,7 +116441,8 @@ class ParentWakeNotifier {
|
|
|
116063
116441
|
const role = this.getParentWakeMessageRole(message);
|
|
116064
116442
|
if (role === "assistant") {
|
|
116065
116443
|
const waiting = this.getParentWakeMessageFinish(message) === "tool-calls" || message.parts?.some((part) => this.parentWakePartIsWaitingOnTool(part)) === true;
|
|
116066
|
-
|
|
116444
|
+
const activityAt = getParentWakeMessageActivityAt(message);
|
|
116445
|
+
return waiting ? { waiting: true, activityAt } : { waiting: false, activityAt };
|
|
116067
116446
|
}
|
|
116068
116447
|
if (role === "user") {
|
|
116069
116448
|
if (isSyntheticOrInternalUserMessage(message)) {
|
|
@@ -116162,16 +116541,18 @@ class ParentWakeNotifier {
|
|
|
116162
116541
|
}
|
|
116163
116542
|
const latestToolWaitAgeMs = toolWaitState.activityAt === undefined ? 0 : now - toolWaitState.activityAt;
|
|
116164
116543
|
const deferAge = now - wake.toolCallDeferralStartedAt;
|
|
116544
|
+
const latestAssistantActivityAgeMs = toolWaitState.activityAt === undefined ? deferAge : now - toolWaitState.activityAt;
|
|
116165
116545
|
if (wake.shouldReply && toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs && latestToolWaitAgeMs >= this.options.toolCallDeferMaxMs) {
|
|
116166
116546
|
log("[background-agent] Sending parent wake after stale tool-call deferral window:", {
|
|
116167
116547
|
sessionID
|
|
116168
116548
|
});
|
|
116169
116549
|
return { defer: false, skipPromptGateToolStateCheck: true };
|
|
116170
116550
|
}
|
|
116171
|
-
if (!toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs) {
|
|
116551
|
+
if (!toolWaitState.waiting && deferAge >= this.options.toolCallDeferMaxMs && latestAssistantActivityAgeMs >= this.options.toolCallDeferMaxMs) {
|
|
116172
116552
|
log("[background-agent] Sending parent wake after stale assistant-text deferral window:", {
|
|
116173
116553
|
sessionID,
|
|
116174
|
-
deferAgeMs: deferAge
|
|
116554
|
+
deferAgeMs: deferAge,
|
|
116555
|
+
latestAssistantActivityAgeMs
|
|
116175
116556
|
});
|
|
116176
116557
|
return { defer: false, skipPromptGateToolStateCheck: true };
|
|
116177
116558
|
}
|
|
@@ -116236,8 +116617,13 @@ function scheduleForcedExit(cleanupResult, exitCode, exitAfterCleanup = false) {
|
|
|
116236
116617
|
}
|
|
116237
116618
|
});
|
|
116238
116619
|
}
|
|
116620
|
+
var _shutdownInProgress = false;
|
|
116621
|
+
function markShutdownStarted() {
|
|
116622
|
+
_shutdownInProgress = true;
|
|
116623
|
+
}
|
|
116239
116624
|
function registerProcessSignal(signal, handler, exitAfter) {
|
|
116240
116625
|
const listener = () => {
|
|
116626
|
+
markShutdownStarted();
|
|
116241
116627
|
const cleanupResult = handler();
|
|
116242
116628
|
if (exitAfter) {
|
|
116243
116629
|
scheduleForcedExit(cleanupResult, 0, true);
|
|
@@ -116264,11 +116650,32 @@ function describeProcessCleanupError(error) {
|
|
|
116264
116650
|
}
|
|
116265
116651
|
return { raw: String(error) };
|
|
116266
116652
|
}
|
|
116653
|
+
var HARMLESS_SHUTDOWN_ERRNO_CODES = new Set(["EPIPE", "ECONNRESET"]);
|
|
116654
|
+
var STDIO_WRITE_FDS = new Set([1, 2]);
|
|
116655
|
+
function isStdioWriteError(error) {
|
|
116656
|
+
const syscall = error.syscall;
|
|
116657
|
+
const fd = error.fd;
|
|
116658
|
+
return syscall === "write" && typeof fd === "number" && STDIO_WRITE_FDS.has(fd);
|
|
116659
|
+
}
|
|
116660
|
+
function isHarmlessShutdownError(error) {
|
|
116661
|
+
if (!error || typeof error !== "object")
|
|
116662
|
+
return false;
|
|
116663
|
+
const code = error.code;
|
|
116664
|
+
if (typeof code !== "string")
|
|
116665
|
+
return false;
|
|
116666
|
+
if (!HARMLESS_SHUTDOWN_ERRNO_CODES.has(code))
|
|
116667
|
+
return false;
|
|
116668
|
+
if (isStdioWriteError(error))
|
|
116669
|
+
return true;
|
|
116670
|
+
return _shutdownInProgress;
|
|
116671
|
+
}
|
|
116267
116672
|
function registerErrorEvent(signal) {
|
|
116268
116673
|
let logging = false;
|
|
116269
116674
|
const listener = (error) => {
|
|
116270
116675
|
if (logging)
|
|
116271
116676
|
return;
|
|
116677
|
+
if (isHarmlessShutdownError(error))
|
|
116678
|
+
return;
|
|
116272
116679
|
logging = true;
|
|
116273
116680
|
log(`[background-agent] ${signal} observed; keeping host alive and skipping cleanup (signal handlers run on real shutdown)`, describeProcessCleanupError(error));
|
|
116274
116681
|
logging = false;
|
|
@@ -116293,9 +116700,13 @@ function registerManagerForCleanup(manager) {
|
|
|
116293
116700
|
for (const m of cleanupManagers) {
|
|
116294
116701
|
try {
|
|
116295
116702
|
promises.push(Promise.resolve(m.shutdown()).catch((error) => {
|
|
116703
|
+
if (isHarmlessShutdownError(error))
|
|
116704
|
+
return;
|
|
116296
116705
|
log("[background-agent] Error during async shutdown cleanup:", error);
|
|
116297
116706
|
}));
|
|
116298
116707
|
} catch (error) {
|
|
116708
|
+
if (isHarmlessShutdownError(error))
|
|
116709
|
+
continue;
|
|
116299
116710
|
log("[background-agent] Error during shutdown cleanup:", error);
|
|
116300
116711
|
}
|
|
116301
116712
|
}
|
|
@@ -117988,10 +118399,8 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
117988
118399
|
};
|
|
117989
118400
|
}
|
|
117990
118401
|
getConcurrencyKeyFromInput(input) {
|
|
117991
|
-
|
|
117992
|
-
|
|
117993
|
-
}
|
|
117994
|
-
return input.agent;
|
|
118402
|
+
const modelKey = input.model ? `${input.model.providerID}/${input.model.modelID}` : input.agent;
|
|
118403
|
+
return this.concurrencyManager.getConcurrencyKey(modelKey);
|
|
117995
118404
|
}
|
|
117996
118405
|
async trackTask(input) {
|
|
117997
118406
|
const existingTask = this.tasks.get(input.taskId);
|
|
@@ -118005,7 +118414,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118005
118414
|
existingTask.parentAgent = input.parentAgent;
|
|
118006
118415
|
}
|
|
118007
118416
|
if (!existingTask.concurrencyGroup) {
|
|
118008
|
-
existingTask.concurrencyGroup = input.concurrencyKey
|
|
118417
|
+
existingTask.concurrencyGroup = input.concurrencyKey ? this.concurrencyManager.getConcurrencyKey(input.concurrencyKey) : existingTask.agent;
|
|
118009
118418
|
}
|
|
118010
118419
|
if (existingTask.sessionId) {
|
|
118011
118420
|
subagentSessions.add(existingTask.sessionId);
|
|
@@ -118021,9 +118430,10 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118021
118430
|
log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.sessionId, status: existingTask.status });
|
|
118022
118431
|
return existingTask;
|
|
118023
118432
|
}
|
|
118024
|
-
const
|
|
118025
|
-
|
|
118026
|
-
|
|
118433
|
+
const concurrencyKey = input.concurrencyKey ? this.concurrencyManager.getConcurrencyKey(input.concurrencyKey) : undefined;
|
|
118434
|
+
const concurrencyGroup = concurrencyKey ?? input.agent ?? "task";
|
|
118435
|
+
if (concurrencyKey) {
|
|
118436
|
+
await this.concurrencyManager.acquire(concurrencyKey);
|
|
118027
118437
|
}
|
|
118028
118438
|
const task = {
|
|
118029
118439
|
id: input.taskId,
|
|
@@ -118040,7 +118450,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118040
118450
|
lastUpdate: new Date
|
|
118041
118451
|
},
|
|
118042
118452
|
parentAgent: input.parentAgent,
|
|
118043
|
-
concurrencyKey
|
|
118453
|
+
concurrencyKey,
|
|
118044
118454
|
concurrencyGroup
|
|
118045
118455
|
};
|
|
118046
118456
|
this.addTask(task);
|
|
@@ -118076,7 +118486,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118076
118486
|
clearTimeout(completionTimer);
|
|
118077
118487
|
this.completionTimers.delete(existingTask.id);
|
|
118078
118488
|
}
|
|
118079
|
-
const concurrencyKey = existingTask.concurrencyGroup ?? existingTask.agent;
|
|
118489
|
+
const concurrencyKey = this.concurrencyManager.getConcurrencyKey(existingTask.concurrencyGroup ?? existingTask.agent);
|
|
118080
118490
|
await this.concurrencyManager.acquire(concurrencyKey);
|
|
118081
118491
|
existingTask.concurrencyKey = concurrencyKey;
|
|
118082
118492
|
existingTask.concurrencyGroup = concurrencyKey;
|
|
@@ -119102,7 +119512,7 @@ The task was re-queued on a fallback model after a retryable failure.
|
|
|
119102
119512
|
parentSessionID: task.parentSessionId
|
|
119103
119513
|
});
|
|
119104
119514
|
}
|
|
119105
|
-
const messageDir =
|
|
119515
|
+
const messageDir = join95(MESSAGE_STORAGE, task.parentSessionId);
|
|
119106
119516
|
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionId) : null;
|
|
119107
119517
|
agent = currentMessage?.agent ?? task.parentAgent;
|
|
119108
119518
|
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
@@ -119445,11 +119855,11 @@ The task was re-queued on a fallback model after a retryable failure.
|
|
|
119445
119855
|
}
|
|
119446
119856
|
// src/features/mcp-oauth/storage.ts
|
|
119447
119857
|
init_shared();
|
|
119448
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
119449
|
-
import { dirname as dirname33, join as
|
|
119858
|
+
import { chmodSync as chmodSync2, existsSync as existsSync87, mkdirSync as mkdirSync19, readFileSync as readFileSync63, renameSync as renameSync7, unlinkSync as unlinkSync16, writeFileSync as writeFileSync21 } from "fs";
|
|
119859
|
+
import { dirname as dirname33, join as join96 } from "path";
|
|
119450
119860
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
119451
119861
|
function getMcpOauthStoragePath() {
|
|
119452
|
-
return
|
|
119862
|
+
return join96(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
|
|
119453
119863
|
}
|
|
119454
119864
|
function normalizeHost(serverHost) {
|
|
119455
119865
|
let host = serverHost.trim();
|
|
@@ -119486,11 +119896,11 @@ function buildKey(serverHost, resource) {
|
|
|
119486
119896
|
}
|
|
119487
119897
|
function readStore() {
|
|
119488
119898
|
const filePath = getMcpOauthStoragePath();
|
|
119489
|
-
if (!
|
|
119899
|
+
if (!existsSync87(filePath)) {
|
|
119490
119900
|
return null;
|
|
119491
119901
|
}
|
|
119492
119902
|
try {
|
|
119493
|
-
const content =
|
|
119903
|
+
const content = readFileSync63(filePath, "utf-8");
|
|
119494
119904
|
return JSON.parse(content);
|
|
119495
119905
|
} catch {
|
|
119496
119906
|
return null;
|
|
@@ -119500,7 +119910,7 @@ function writeStore(store2) {
|
|
|
119500
119910
|
const filePath = getMcpOauthStoragePath();
|
|
119501
119911
|
try {
|
|
119502
119912
|
const dir = dirname33(filePath);
|
|
119503
|
-
if (!
|
|
119913
|
+
if (!existsSync87(dir)) {
|
|
119504
119914
|
mkdirSync19(dir, { recursive: true });
|
|
119505
119915
|
}
|
|
119506
119916
|
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
@@ -119692,13 +120102,13 @@ async function findAvailablePort2(startPort = DEFAULT_PORT) {
|
|
|
119692
120102
|
|
|
119693
120103
|
// src/features/mcp-oauth/oauth-authorization-flow.ts
|
|
119694
120104
|
import { spawn as spawn3 } from "child_process";
|
|
119695
|
-
import { createHash as
|
|
120105
|
+
import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
119696
120106
|
import { createServer as createServer2 } from "http";
|
|
119697
120107
|
function generateCodeVerifier() {
|
|
119698
120108
|
return randomBytes2(32).toString("base64url");
|
|
119699
120109
|
}
|
|
119700
120110
|
function generateCodeChallenge(verifier) {
|
|
119701
|
-
return
|
|
120111
|
+
return createHash3("sha256").update(verifier).digest("base64url");
|
|
119702
120112
|
}
|
|
119703
120113
|
function buildAuthorizationUrl(authorizationEndpoint, options) {
|
|
119704
120114
|
const url = new URL(authorizationEndpoint);
|
|
@@ -125389,8 +125799,33 @@ async function executeActions(actions, ctx) {
|
|
|
125389
125799
|
// src/features/tmux-subagent/polling-manager.ts
|
|
125390
125800
|
init_tmux();
|
|
125391
125801
|
init_shared();
|
|
125392
|
-
init_shared();
|
|
125393
125802
|
init_event_session_id();
|
|
125803
|
+
|
|
125804
|
+
// src/features/tmux-subagent/session-status-parser.ts
|
|
125805
|
+
function parseSessionStatusResponse(response) {
|
|
125806
|
+
if (typeof response === "object" && response !== null && "data" in response) {
|
|
125807
|
+
return parseSessionStatusMap(response.data);
|
|
125808
|
+
}
|
|
125809
|
+
return parseSessionStatusMap(response);
|
|
125810
|
+
}
|
|
125811
|
+
function parseSessionStatusMap(data) {
|
|
125812
|
+
if (typeof data !== "object" || data === null)
|
|
125813
|
+
return {};
|
|
125814
|
+
const record3 = data;
|
|
125815
|
+
const result = {};
|
|
125816
|
+
for (const [sessionId, value] of Object.entries(record3)) {
|
|
125817
|
+
if (typeof value !== "object" || value === null)
|
|
125818
|
+
continue;
|
|
125819
|
+
const valueRecord = value;
|
|
125820
|
+
const type2 = valueRecord["type"];
|
|
125821
|
+
if (typeof type2 !== "string")
|
|
125822
|
+
continue;
|
|
125823
|
+
result[sessionId] = { type: type2 };
|
|
125824
|
+
}
|
|
125825
|
+
return result;
|
|
125826
|
+
}
|
|
125827
|
+
|
|
125828
|
+
// src/features/tmux-subagent/polling-manager.ts
|
|
125394
125829
|
var MIN_STABILITY_TIME_MS3 = 10 * 1000;
|
|
125395
125830
|
var STABLE_POLLS_REQUIRED = 3;
|
|
125396
125831
|
|
|
@@ -125446,7 +125881,7 @@ class TmuxPollingManager {
|
|
|
125446
125881
|
}
|
|
125447
125882
|
await this.activateFocusedPanes();
|
|
125448
125883
|
const statusResult = await this.client.session.status({ path: undefined });
|
|
125449
|
-
const allStatuses =
|
|
125884
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
125450
125885
|
log("[tmux-session-manager] pollSessions", {
|
|
125451
125886
|
trackedSessions: Array.from(this.sessions.keys()),
|
|
125452
125887
|
allStatusKeys: Object.keys(allStatuses)
|
|
@@ -125493,7 +125928,7 @@ class TmuxPollingManager {
|
|
|
125493
125928
|
if ((tracked.stableIdlePolls ?? 0) >= STABLE_POLLS_REQUIRED) {
|
|
125494
125929
|
const stableWindowActivityVersion = tracked.observedIdleActivityVersion ?? activityVersion;
|
|
125495
125930
|
const recheckResult = await this.client.session.status({ path: undefined });
|
|
125496
|
-
const recheckStatuses =
|
|
125931
|
+
const recheckStatuses = parseSessionStatusResponse(recheckResult);
|
|
125497
125932
|
const recheckStatus = recheckStatuses[sessionId];
|
|
125498
125933
|
const latestTracked = this.sessions.get(sessionId) ?? tracked;
|
|
125499
125934
|
const recheckActivityVersion = latestTracked.activityVersion ?? 0;
|
|
@@ -125634,36 +126069,18 @@ init_tmux();
|
|
|
125634
126069
|
init_shared();
|
|
125635
126070
|
|
|
125636
126071
|
// src/features/tmux-subagent/attachable-session-status.ts
|
|
125637
|
-
var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy"];
|
|
126072
|
+
var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy", "retry"];
|
|
125638
126073
|
function isAttachableSessionStatus(status) {
|
|
125639
126074
|
return ATTACHABLE_SESSION_STATUSES.some((attachableSessionStatus) => attachableSessionStatus === status);
|
|
125640
126075
|
}
|
|
125641
126076
|
|
|
125642
|
-
// src/features/tmux-subagent/session-status-parser.ts
|
|
125643
|
-
function parseSessionStatusMap(data) {
|
|
125644
|
-
if (typeof data !== "object" || data === null)
|
|
125645
|
-
return {};
|
|
125646
|
-
const record3 = data;
|
|
125647
|
-
const result = {};
|
|
125648
|
-
for (const [sessionId, value] of Object.entries(record3)) {
|
|
125649
|
-
if (typeof value !== "object" || value === null)
|
|
125650
|
-
continue;
|
|
125651
|
-
const valueRecord = value;
|
|
125652
|
-
const type2 = valueRecord["type"];
|
|
125653
|
-
if (typeof type2 !== "string")
|
|
125654
|
-
continue;
|
|
125655
|
-
result[sessionId] = { type: type2 };
|
|
125656
|
-
}
|
|
125657
|
-
return result;
|
|
125658
|
-
}
|
|
125659
|
-
|
|
125660
126077
|
// src/features/tmux-subagent/session-ready-waiter.ts
|
|
125661
126078
|
async function waitForSessionReady(params) {
|
|
125662
126079
|
const startTime = Date.now();
|
|
125663
126080
|
while (Date.now() - startTime < SESSION_READY_TIMEOUT_MS) {
|
|
125664
126081
|
try {
|
|
125665
126082
|
const statusResult = await params.client.session.status({ path: undefined });
|
|
125666
|
-
const allStatuses =
|
|
126083
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
125667
126084
|
const sessionStatus = allStatuses[params.sessionId]?.type;
|
|
125668
126085
|
if (isAttachableSessionStatus(sessionStatus)) {
|
|
125669
126086
|
log("[tmux-session-manager] session ready", {
|
|
@@ -126172,7 +126589,7 @@ class TmuxSessionManager {
|
|
|
126172
126589
|
async getSessionStatusType(sessionId) {
|
|
126173
126590
|
try {
|
|
126174
126591
|
const statusResult = await this.client.session.status({ path: undefined });
|
|
126175
|
-
const allStatuses =
|
|
126592
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
126176
126593
|
return allStatuses[sessionId]?.type;
|
|
126177
126594
|
} catch (error) {
|
|
126178
126595
|
this.deps.log("[tmux-session-manager] failed to read session status before spawn", {
|
|
@@ -127078,14 +127495,14 @@ async function isTmuxAvailable() {
|
|
|
127078
127495
|
}
|
|
127079
127496
|
|
|
127080
127497
|
// src/openclaw/reply-listener.ts
|
|
127081
|
-
import { dirname as dirname35, join as
|
|
127498
|
+
import { dirname as dirname35, join as join99 } from "path";
|
|
127082
127499
|
|
|
127083
127500
|
// src/openclaw/session-registry.ts
|
|
127084
127501
|
init_data_path();
|
|
127085
127502
|
import {
|
|
127086
|
-
existsSync as
|
|
127503
|
+
existsSync as existsSync88,
|
|
127087
127504
|
mkdirSync as mkdirSync20,
|
|
127088
|
-
readFileSync as
|
|
127505
|
+
readFileSync as readFileSync64,
|
|
127089
127506
|
writeFileSync as writeFileSync22,
|
|
127090
127507
|
openSync as openSync3,
|
|
127091
127508
|
closeSync as closeSync3,
|
|
@@ -127094,11 +127511,11 @@ import {
|
|
|
127094
127511
|
statSync as statSync12,
|
|
127095
127512
|
constants as constants20
|
|
127096
127513
|
} from "fs";
|
|
127097
|
-
import { join as
|
|
127514
|
+
import { join as join97, dirname as dirname34 } from "path";
|
|
127098
127515
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
127099
|
-
var OPENCLAW_STORAGE_DIR =
|
|
127100
|
-
var REGISTRY_PATH =
|
|
127101
|
-
var REGISTRY_LOCK_PATH =
|
|
127516
|
+
var OPENCLAW_STORAGE_DIR = join97(getOpenCodeStorageDir(), "openclaw");
|
|
127517
|
+
var REGISTRY_PATH = join97(OPENCLAW_STORAGE_DIR, "reply-session-registry.jsonl");
|
|
127518
|
+
var REGISTRY_LOCK_PATH = join97(OPENCLAW_STORAGE_DIR, "reply-session-registry.lock");
|
|
127102
127519
|
var SECURE_FILE_MODE = 384;
|
|
127103
127520
|
var MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
127104
127521
|
var LOCK_TIMEOUT_MS = 2000;
|
|
@@ -127107,7 +127524,7 @@ var LOCK_RETRY_MS2 = 20;
|
|
|
127107
127524
|
var LOCK_STALE_MS = 1e4;
|
|
127108
127525
|
function ensureRegistryDir() {
|
|
127109
127526
|
const registryDir = dirname34(REGISTRY_PATH);
|
|
127110
|
-
if (!
|
|
127527
|
+
if (!existsSync88(registryDir)) {
|
|
127111
127528
|
mkdirSync20(registryDir, { recursive: true, mode: 448 });
|
|
127112
127529
|
}
|
|
127113
127530
|
}
|
|
@@ -127126,9 +127543,9 @@ function isPidAlive2(pid) {
|
|
|
127126
127543
|
}
|
|
127127
127544
|
function readLockSnapshot() {
|
|
127128
127545
|
try {
|
|
127129
|
-
if (!
|
|
127546
|
+
if (!existsSync88(REGISTRY_LOCK_PATH))
|
|
127130
127547
|
return null;
|
|
127131
|
-
const raw =
|
|
127548
|
+
const raw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
|
|
127132
127549
|
const trimmed = raw.trim();
|
|
127133
127550
|
if (!trimmed)
|
|
127134
127551
|
return { raw, pid: null, token: null };
|
|
@@ -127152,9 +127569,9 @@ function readLockSnapshot() {
|
|
|
127152
127569
|
}
|
|
127153
127570
|
function removeLockIfUnchanged(snapshot) {
|
|
127154
127571
|
try {
|
|
127155
|
-
if (!
|
|
127572
|
+
if (!existsSync88(REGISTRY_LOCK_PATH))
|
|
127156
127573
|
return false;
|
|
127157
|
-
const currentRaw =
|
|
127574
|
+
const currentRaw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
|
|
127158
127575
|
if (currentRaw !== snapshot.raw)
|
|
127159
127576
|
return false;
|
|
127160
127577
|
unlinkSync17(REGISTRY_LOCK_PATH);
|
|
@@ -127258,10 +127675,10 @@ function withRegistryLock(onLocked, onLockUnavailable) {
|
|
|
127258
127675
|
}
|
|
127259
127676
|
}
|
|
127260
127677
|
function readAllMappingsUnsafe() {
|
|
127261
|
-
if (!
|
|
127678
|
+
if (!existsSync88(REGISTRY_PATH))
|
|
127262
127679
|
return [];
|
|
127263
127680
|
try {
|
|
127264
|
-
const content =
|
|
127681
|
+
const content = readFileSync64(REGISTRY_PATH, "utf-8");
|
|
127265
127682
|
return content.split(`
|
|
127266
127683
|
`).filter((line) => line.trim()).map((line) => {
|
|
127267
127684
|
try {
|
|
@@ -127316,7 +127733,7 @@ function removeSession(sessionId) {
|
|
|
127316
127733
|
import {
|
|
127317
127734
|
appendFileSync as appendFileSync6,
|
|
127318
127735
|
chmodSync as chmodSync3,
|
|
127319
|
-
existsSync as
|
|
127736
|
+
existsSync as existsSync90,
|
|
127320
127737
|
renameSync as renameSync8,
|
|
127321
127738
|
statSync as statSync13,
|
|
127322
127739
|
unlinkSync as unlinkSync18,
|
|
@@ -127324,31 +127741,31 @@ import {
|
|
|
127324
127741
|
} from "fs";
|
|
127325
127742
|
|
|
127326
127743
|
// src/openclaw/reply-listener-paths.ts
|
|
127327
|
-
import { existsSync as
|
|
127744
|
+
import { existsSync as existsSync89, mkdirSync as mkdirSync21 } from "fs";
|
|
127328
127745
|
import { homedir as homedir19 } from "os";
|
|
127329
|
-
import { join as
|
|
127746
|
+
import { join as join98 } from "path";
|
|
127330
127747
|
var REPLY_LISTENER_SECURE_FILE_MODE = 384;
|
|
127331
127748
|
function resolveReplyListenerHomeDir() {
|
|
127332
127749
|
return process.env.HOME ?? process.env.USERPROFILE ?? homedir19();
|
|
127333
127750
|
}
|
|
127334
127751
|
function getReplyListenerStateDir() {
|
|
127335
|
-
return
|
|
127752
|
+
return join98(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
|
|
127336
127753
|
}
|
|
127337
127754
|
function getReplyListenerPidFilePath() {
|
|
127338
|
-
return
|
|
127755
|
+
return join98(getReplyListenerStateDir(), "reply-listener.pid");
|
|
127339
127756
|
}
|
|
127340
127757
|
function getReplyListenerStateFilePath() {
|
|
127341
|
-
return
|
|
127758
|
+
return join98(getReplyListenerStateDir(), "reply-listener-state.json");
|
|
127342
127759
|
}
|
|
127343
127760
|
function getReplyListenerConfigFilePath() {
|
|
127344
|
-
return
|
|
127761
|
+
return join98(getReplyListenerStateDir(), "reply-listener-config.json");
|
|
127345
127762
|
}
|
|
127346
127763
|
function getReplyListenerLogFilePath() {
|
|
127347
|
-
return
|
|
127764
|
+
return join98(getReplyListenerStateDir(), "reply-listener.log");
|
|
127348
127765
|
}
|
|
127349
127766
|
function ensureReplyListenerStateDir() {
|
|
127350
127767
|
const stateDir = getReplyListenerStateDir();
|
|
127351
|
-
if (!
|
|
127768
|
+
if (!existsSync89(stateDir)) {
|
|
127352
127769
|
mkdirSync21(stateDir, { recursive: true, mode: 448 });
|
|
127353
127770
|
}
|
|
127354
127771
|
}
|
|
@@ -127364,13 +127781,13 @@ function writeSecureReplyListenerFile(filePath, content) {
|
|
|
127364
127781
|
}
|
|
127365
127782
|
function rotateReplyListenerLogIfNeeded(logPath) {
|
|
127366
127783
|
try {
|
|
127367
|
-
if (!
|
|
127784
|
+
if (!existsSync90(logPath))
|
|
127368
127785
|
return;
|
|
127369
127786
|
const stats = statSync13(logPath);
|
|
127370
127787
|
if (stats.size <= MAX_REPLY_LISTENER_LOG_SIZE_BYTES)
|
|
127371
127788
|
return;
|
|
127372
127789
|
const backupPath = `${logPath}.old`;
|
|
127373
|
-
if (
|
|
127790
|
+
if (existsSync90(backupPath)) {
|
|
127374
127791
|
unlinkSync18(backupPath);
|
|
127375
127792
|
}
|
|
127376
127793
|
renameSync8(logPath, backupPath);
|
|
@@ -127411,7 +127828,7 @@ class ReplyListenerRateLimiter {
|
|
|
127411
127828
|
}
|
|
127412
127829
|
|
|
127413
127830
|
// src/openclaw/reply-listener-state.ts
|
|
127414
|
-
import { existsSync as
|
|
127831
|
+
import { existsSync as existsSync91, readFileSync as readFileSync65, unlinkSync as unlinkSync19 } from "fs";
|
|
127415
127832
|
var REPLY_LISTENER_STARTUP_TOKEN_ENV = "OMO_OPENCLAW_REPLY_LISTENER_STARTUP_TOKEN";
|
|
127416
127833
|
function createDefaultReplyListenerState() {
|
|
127417
127834
|
return {
|
|
@@ -127473,9 +127890,9 @@ function createPendingReplyListenerState(startupToken) {
|
|
|
127473
127890
|
function readReplyListenerDaemonState() {
|
|
127474
127891
|
try {
|
|
127475
127892
|
const stateFilePath = getReplyListenerStateFilePath();
|
|
127476
|
-
if (!
|
|
127893
|
+
if (!existsSync91(stateFilePath))
|
|
127477
127894
|
return null;
|
|
127478
|
-
return normalizeReplyListenerState(JSON.parse(
|
|
127895
|
+
return normalizeReplyListenerState(JSON.parse(readFileSync65(stateFilePath, "utf-8")));
|
|
127479
127896
|
} catch {
|
|
127480
127897
|
return null;
|
|
127481
127898
|
}
|
|
@@ -127490,9 +127907,9 @@ function writeReplyListenerDaemonState(state3) {
|
|
|
127490
127907
|
function readReplyListenerDaemonConfig() {
|
|
127491
127908
|
try {
|
|
127492
127909
|
const configFilePath = getReplyListenerConfigFilePath();
|
|
127493
|
-
if (!
|
|
127910
|
+
if (!existsSync91(configFilePath))
|
|
127494
127911
|
return null;
|
|
127495
|
-
return JSON.parse(
|
|
127912
|
+
return JSON.parse(readFileSync65(configFilePath, "utf-8"));
|
|
127496
127913
|
} catch {
|
|
127497
127914
|
return null;
|
|
127498
127915
|
}
|
|
@@ -127503,9 +127920,9 @@ function writeReplyListenerDaemonConfig(config) {
|
|
|
127503
127920
|
function readReplyListenerPid() {
|
|
127504
127921
|
try {
|
|
127505
127922
|
const pidFilePath = getReplyListenerPidFilePath();
|
|
127506
|
-
if (!
|
|
127923
|
+
if (!existsSync91(pidFilePath))
|
|
127507
127924
|
return null;
|
|
127508
|
-
const pid = Number.parseInt(
|
|
127925
|
+
const pid = Number.parseInt(readFileSync65(pidFilePath, "utf-8").trim(), 10);
|
|
127509
127926
|
return Number.isNaN(pid) ? null : pid;
|
|
127510
127927
|
} catch {
|
|
127511
127928
|
return null;
|
|
@@ -127516,7 +127933,7 @@ function writeReplyListenerPid(pid) {
|
|
|
127516
127933
|
}
|
|
127517
127934
|
function removeReplyListenerPid() {
|
|
127518
127935
|
const pidFilePath = getReplyListenerPidFilePath();
|
|
127519
|
-
if (
|
|
127936
|
+
if (existsSync91(pidFilePath)) {
|
|
127520
127937
|
unlinkSync19(pidFilePath);
|
|
127521
127938
|
}
|
|
127522
127939
|
}
|
|
@@ -127533,7 +127950,7 @@ function markReplyListenerStopped(state3, error) {
|
|
|
127533
127950
|
|
|
127534
127951
|
// src/openclaw/reply-listener-process.ts
|
|
127535
127952
|
init_bun_spawn_shim();
|
|
127536
|
-
import { readFileSync as
|
|
127953
|
+
import { readFileSync as readFileSync66 } from "fs";
|
|
127537
127954
|
var REPLY_LISTENER_DAEMON_IDENTITY_MARKER = "--openclaw-reply-listener-daemon";
|
|
127538
127955
|
var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
|
|
127539
127956
|
"PATH",
|
|
@@ -127588,7 +128005,7 @@ function isReplyListenerProcessRunning(pid) {
|
|
|
127588
128005
|
async function isReplyListenerDaemonProcess(pid) {
|
|
127589
128006
|
try {
|
|
127590
128007
|
if (process.platform === "linux") {
|
|
127591
|
-
const cmdline =
|
|
128008
|
+
const cmdline = readFileSync66(`/proc/${pid}/cmdline`, "utf-8");
|
|
127592
128009
|
return cmdline.includes(REPLY_LISTENER_DAEMON_IDENTITY_MARKER);
|
|
127593
128010
|
}
|
|
127594
128011
|
const processInfo = spawn2(["ps", "-p", String(pid), "-o", "args="], {
|
|
@@ -127750,7 +128167,7 @@ async function startReplyListener(config) {
|
|
|
127750
128167
|
pendingState.configSignature = getReplyListenerRuntimeSignature(normalizedConfig);
|
|
127751
128168
|
writeReplyListenerDaemonState(pendingState);
|
|
127752
128169
|
const currentFile = import.meta.url;
|
|
127753
|
-
const daemonScript = currentFile.endsWith(".ts") ?
|
|
128170
|
+
const daemonScript = currentFile.endsWith(".ts") ? join99(dirname35(new URL(currentFile).pathname), "daemon.ts") : join99(dirname35(new URL(currentFile).pathname), "daemon.js");
|
|
127754
128171
|
try {
|
|
127755
128172
|
const processInfo = spawnReplyListenerDaemon(daemonScript, startupToken);
|
|
127756
128173
|
processInfo.unref();
|
|
@@ -128134,21 +128551,21 @@ init_transformer();
|
|
|
128134
128551
|
init_logger();
|
|
128135
128552
|
init_scope_filter2();
|
|
128136
128553
|
init_bun_file_shim();
|
|
128137
|
-
import { existsSync as
|
|
128138
|
-
import { join as
|
|
128554
|
+
import { existsSync as existsSync92, readFileSync as readFileSync67 } from "fs";
|
|
128555
|
+
import { join as join100 } from "path";
|
|
128139
128556
|
import { homedir as homedir20 } from "os";
|
|
128140
128557
|
function getMcpConfigPaths() {
|
|
128141
128558
|
const claudeConfigDir = getClaudeConfigDir();
|
|
128142
128559
|
const cwd = process.cwd();
|
|
128143
128560
|
return [
|
|
128144
|
-
{ path:
|
|
128145
|
-
{ path:
|
|
128146
|
-
{ path:
|
|
128147
|
-
{ path:
|
|
128561
|
+
{ path: join100(homedir20(), ".claude.json"), scope: "user" },
|
|
128562
|
+
{ path: join100(claudeConfigDir, ".mcp.json"), scope: "user" },
|
|
128563
|
+
{ path: join100(cwd, ".mcp.json"), scope: "project" },
|
|
128564
|
+
{ path: join100(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
128148
128565
|
];
|
|
128149
128566
|
}
|
|
128150
128567
|
async function loadMcpConfigFile(filePath) {
|
|
128151
|
-
if (!
|
|
128568
|
+
if (!existsSync92(filePath)) {
|
|
128152
128569
|
return null;
|
|
128153
128570
|
}
|
|
128154
128571
|
try {
|
|
@@ -128163,11 +128580,11 @@ function getSystemMcpServerNames() {
|
|
|
128163
128580
|
const names = new Set;
|
|
128164
128581
|
const paths = getMcpConfigPaths();
|
|
128165
128582
|
const cwd = process.cwd();
|
|
128166
|
-
for (const { path:
|
|
128167
|
-
if (!
|
|
128583
|
+
for (const { path: path22 } of paths) {
|
|
128584
|
+
if (!existsSync92(path22))
|
|
128168
128585
|
continue;
|
|
128169
128586
|
try {
|
|
128170
|
-
const content =
|
|
128587
|
+
const content = readFileSync67(path22, "utf-8");
|
|
128171
128588
|
const config = JSON.parse(content);
|
|
128172
128589
|
if (!config?.mcpServers)
|
|
128173
128590
|
continue;
|
|
@@ -128192,30 +128609,30 @@ async function loadMcpConfigs(disabledMcps = []) {
|
|
|
128192
128609
|
const paths = getMcpConfigPaths();
|
|
128193
128610
|
const disabledSet = new Set(disabledMcps);
|
|
128194
128611
|
const cwd = process.cwd();
|
|
128195
|
-
for (const { path:
|
|
128196
|
-
const config = await loadMcpConfigFile(
|
|
128612
|
+
for (const { path: path22, scope } of paths) {
|
|
128613
|
+
const config = await loadMcpConfigFile(path22);
|
|
128197
128614
|
if (!config?.mcpServers)
|
|
128198
128615
|
continue;
|
|
128199
128616
|
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
128200
128617
|
if (disabledSet.has(name)) {
|
|
128201
|
-
log(`Skipping MCP "${name}" (in disabled_mcps)`, { path:
|
|
128618
|
+
log(`Skipping MCP "${name}" (in disabled_mcps)`, { path: path22 });
|
|
128202
128619
|
continue;
|
|
128203
128620
|
}
|
|
128204
128621
|
if (!shouldLoadMcpServer(serverConfig, cwd)) {
|
|
128205
128622
|
log(`Skipping MCP server "${name}" because local scope does not match cwd`, {
|
|
128206
|
-
path:
|
|
128623
|
+
path: path22,
|
|
128207
128624
|
projectPath: serverConfig.projectPath,
|
|
128208
128625
|
cwd
|
|
128209
128626
|
});
|
|
128210
128627
|
continue;
|
|
128211
128628
|
}
|
|
128212
128629
|
if (serverConfig.disabled) {
|
|
128213
|
-
log(`Disabling MCP server "${name}"`, { path:
|
|
128630
|
+
log(`Disabling MCP server "${name}"`, { path: path22 });
|
|
128214
128631
|
delete servers[name];
|
|
128215
128632
|
const existingIndex = loadedServers.findIndex((s) => s.name === name);
|
|
128216
128633
|
if (existingIndex !== -1) {
|
|
128217
128634
|
loadedServers.splice(existingIndex, 1);
|
|
128218
|
-
log(`Removed previously loaded MCP server "${name}"`, { path:
|
|
128635
|
+
log(`Removed previously loaded MCP server "${name}"`, { path: path22 });
|
|
128219
128636
|
}
|
|
128220
128637
|
continue;
|
|
128221
128638
|
}
|
|
@@ -128227,7 +128644,7 @@ async function loadMcpConfigs(disabledMcps = []) {
|
|
|
128227
128644
|
loadedServers.splice(existingIndex, 1);
|
|
128228
128645
|
}
|
|
128229
128646
|
loadedServers.push({ name, scope, config: transformed });
|
|
128230
|
-
log(`Loaded MCP server "${name}" from ${scope}`, { path:
|
|
128647
|
+
log(`Loaded MCP server "${name}" from ${scope}`, { path: path22 });
|
|
128231
128648
|
} catch (error) {
|
|
128232
128649
|
log(`Failed to transform MCP server "${name}"`, error);
|
|
128233
128650
|
}
|
|
@@ -130007,6 +130424,8 @@ Each exploration prompt should include four fields: **CONTEXT** (what task, whic
|
|
|
130007
130424
|
|
|
130008
130425
|
After firing exploration agents, keep the returned background task IDs (\`bg_...\`) for result collection and continuation session IDs (\`ses_...\`) for follow-ups. Continue only with non-overlapping preparation: setting up files, reading known-path files, drafting questions. If no non-overlapping work exists, end your response and wait for the completion notification; then use \`background_output(task_id="bg_...")\`, not \`task(task_id="ses_...")\`, to collect results.
|
|
130009
130426
|
|
|
130427
|
+
System reminders are input-only signals from the harness. Never write, quote, simulate, or pre-emptively emit \`<system-reminder>\` blocks yourself, and never call \`background_output\` merely because you imagined such a reminder. Only collect a background task after an actual harness-provided completion notification arrives.
|
|
130428
|
+
|
|
130010
130429
|
Stop searching when you have enough context to proceed confidently, when the same information keeps appearing across sources, when two iterations yield no new useful data, or when you found a direct answer.
|
|
130011
130430
|
|
|
130012
130431
|
### Tool persistence
|
|
@@ -134516,7 +134935,7 @@ createHephaestusAgent2.mode = MODE10;
|
|
|
134516
134935
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
134517
134936
|
init_contains_path2();
|
|
134518
134937
|
init_logger();
|
|
134519
|
-
import { existsSync as
|
|
134938
|
+
import { existsSync as existsSync93, readFileSync as readFileSync68 } from "fs";
|
|
134520
134939
|
import { homedir as homedir21 } from "os";
|
|
134521
134940
|
import { isAbsolute as isAbsolute18, resolve as resolve25 } from "path";
|
|
134522
134941
|
function resolvePromptAppend(promptAppend, configDir) {
|
|
@@ -134540,11 +134959,11 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
134540
134959
|
});
|
|
134541
134960
|
return `[WARNING: Path rejected: ${promptAppend} (resolved outside project root ${projectRoot}; file:// prompts must reside within the project boundary)]`;
|
|
134542
134961
|
}
|
|
134543
|
-
if (!
|
|
134962
|
+
if (!existsSync93(filePath)) {
|
|
134544
134963
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
134545
134964
|
}
|
|
134546
134965
|
try {
|
|
134547
|
-
return
|
|
134966
|
+
return readFileSync68(filePath, "utf8");
|
|
134548
134967
|
} catch {
|
|
134549
134968
|
return `[WARNING: Could not read file: ${promptAppend}]`;
|
|
134550
134969
|
}
|
|
@@ -135820,7 +136239,7 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
|
|
|
135820
136239
|
location: "plugin"
|
|
135821
136240
|
}));
|
|
135822
136241
|
const discoveredAvailable = discoveredSkills.filter((s) => {
|
|
135823
|
-
if (
|
|
136242
|
+
if (disabledSkills?.has(s.name))
|
|
135824
136243
|
return false;
|
|
135825
136244
|
if (agentName && s.definition.agent && s.definition.agent !== agentName)
|
|
135826
136245
|
return false;
|
|
@@ -135830,7 +136249,10 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
|
|
|
135830
136249
|
description: skill2.definition.description ?? "",
|
|
135831
136250
|
location: mapScopeToLocation(skill2.scope)
|
|
135832
136251
|
}));
|
|
135833
|
-
|
|
136252
|
+
const skillMap = new Map;
|
|
136253
|
+
builtinAvailable.forEach((skill2) => skillMap.set(skill2.name, skill2));
|
|
136254
|
+
discoveredAvailable.forEach((skill2) => skillMap.set(skill2.name, skill2));
|
|
136255
|
+
return Array.from(skillMap.values());
|
|
135834
136256
|
}
|
|
135835
136257
|
|
|
135836
136258
|
// src/agents/builtin-agents/general-agents.ts
|
|
@@ -136705,7 +137127,7 @@ function buildPlanDemoteConfig(prometheusConfig, planOverride) {
|
|
|
136705
137127
|
}
|
|
136706
137128
|
|
|
136707
137129
|
// src/shared/host-skill-config.ts
|
|
136708
|
-
function
|
|
137130
|
+
function toStringArray2(value) {
|
|
136709
137131
|
if (!Array.isArray(value))
|
|
136710
137132
|
return [];
|
|
136711
137133
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
@@ -136714,10 +137136,7 @@ function adaptHostSkillConfig(value) {
|
|
|
136714
137136
|
if (!value || typeof value !== "object")
|
|
136715
137137
|
return;
|
|
136716
137138
|
const hostSkillConfig = value;
|
|
136717
|
-
const sources =
|
|
136718
|
-
...toStringArray(hostSkillConfig.paths),
|
|
136719
|
-
...toStringArray(hostSkillConfig.urls)
|
|
136720
|
-
];
|
|
137139
|
+
const sources = toStringArray2(hostSkillConfig.paths);
|
|
136721
137140
|
if (sources.length === 0)
|
|
136722
137141
|
return;
|
|
136723
137142
|
return { sources };
|
|
@@ -136762,7 +137181,7 @@ async function applyAgentConfig(params) {
|
|
|
136762
137181
|
discoverOpencodeProjectSkills(params.ctx.directory),
|
|
136763
137182
|
includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
|
|
136764
137183
|
]);
|
|
136765
|
-
const allDiscoveredSkills = [
|
|
137184
|
+
const allDiscoveredSkills = deduplicateSkillsByName([
|
|
136766
137185
|
...discoveredConfigSourceSkills,
|
|
136767
137186
|
...discoveredHostConfigSkills,
|
|
136768
137187
|
...discoveredOpencodeProjectSkills,
|
|
@@ -136771,7 +137190,7 @@ async function applyAgentConfig(params) {
|
|
|
136771
137190
|
...discoveredOpencodeGlobalSkills,
|
|
136772
137191
|
...discoveredUserSkills,
|
|
136773
137192
|
...discoveredGlobalAgentsSkills
|
|
136774
|
-
];
|
|
137193
|
+
]);
|
|
136775
137194
|
const browserProvider = params.pluginConfig.browser_automation_engine?.provider ?? "playwright";
|
|
136776
137195
|
const currentModel = params.config.model;
|
|
136777
137196
|
const disabledSkills = new Set(params.pluginConfig.disabled_skills ?? []);
|
|
@@ -136944,6 +137363,7 @@ async function applyAgentConfig(params) {
|
|
|
136944
137363
|
setDefaultAgentForSort(params.config.default_agent ?? configuredDefaultAgent);
|
|
136945
137364
|
}
|
|
136946
137365
|
const agentResult = params.config.agent;
|
|
137366
|
+
clearRegisteredAgentNames();
|
|
136947
137367
|
for (const name of Object.keys(agentResult)) {
|
|
136948
137368
|
registerAgentName(name);
|
|
136949
137369
|
}
|
|
@@ -136959,8 +137379,8 @@ init_model_sanitizer();
|
|
|
136959
137379
|
init_file_utils2();
|
|
136960
137380
|
init_shared();
|
|
136961
137381
|
init_logger();
|
|
136962
|
-
import { promises as
|
|
136963
|
-
import { join as
|
|
137382
|
+
import { promises as fs23 } from "fs";
|
|
137383
|
+
import { join as join101, basename as basename16 } from "path";
|
|
136964
137384
|
|
|
136965
137385
|
// src/features/claude-code-command-loader/loader-cache.ts
|
|
136966
137386
|
var commandLoaderCache = new Map;
|
|
@@ -136968,13 +137388,13 @@ var commandLoaderCache = new Map;
|
|
|
136968
137388
|
// src/features/claude-code-command-loader/loader.ts
|
|
136969
137389
|
async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
|
|
136970
137390
|
try {
|
|
136971
|
-
await
|
|
137391
|
+
await fs23.access(commandsDir);
|
|
136972
137392
|
} catch {
|
|
136973
137393
|
return [];
|
|
136974
137394
|
}
|
|
136975
137395
|
let realPath;
|
|
136976
137396
|
try {
|
|
136977
|
-
realPath = await
|
|
137397
|
+
realPath = await fs23.realpath(commandsDir);
|
|
136978
137398
|
} catch (error) {
|
|
136979
137399
|
log(`Failed to resolve command directory: ${commandsDir}`, error);
|
|
136980
137400
|
return [];
|
|
@@ -136985,7 +137405,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
136985
137405
|
visited.add(realPath);
|
|
136986
137406
|
let entries;
|
|
136987
137407
|
try {
|
|
136988
|
-
entries = await
|
|
137408
|
+
entries = await fs23.readdir(commandsDir, { withFileTypes: true });
|
|
136989
137409
|
} catch (error) {
|
|
136990
137410
|
log(`Failed to read command directory: ${commandsDir}`, error);
|
|
136991
137411
|
return [];
|
|
@@ -136997,7 +137417,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
136997
137417
|
continue;
|
|
136998
137418
|
if (entry.name.startsWith("."))
|
|
136999
137419
|
continue;
|
|
137000
|
-
const subDirPath =
|
|
137420
|
+
const subDirPath = join101(commandsDir, entry.name);
|
|
137001
137421
|
const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
137002
137422
|
const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
|
|
137003
137423
|
commands2.push(...subCommands);
|
|
@@ -137005,11 +137425,11 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
137005
137425
|
}
|
|
137006
137426
|
if (!isMarkdownFile(entry))
|
|
137007
137427
|
continue;
|
|
137008
|
-
const commandPath =
|
|
137428
|
+
const commandPath = join101(commandsDir, entry.name);
|
|
137009
137429
|
const baseCommandName = basename16(entry.name, ".md");
|
|
137010
137430
|
const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
|
|
137011
137431
|
try {
|
|
137012
|
-
const content = await
|
|
137432
|
+
const content = await fs23.readFile(commandPath, "utf-8");
|
|
137013
137433
|
const { data, body } = parseFrontmatter(content);
|
|
137014
137434
|
const wrappedTemplate = `<command-instruction>
|
|
137015
137435
|
${body.trim()}
|
|
@@ -137064,12 +137484,12 @@ function commandsToRecord(commands2) {
|
|
|
137064
137484
|
return result;
|
|
137065
137485
|
}
|
|
137066
137486
|
async function loadUserCommands() {
|
|
137067
|
-
const userCommandsDir =
|
|
137487
|
+
const userCommandsDir = join101(getClaudeConfigDir(), "commands");
|
|
137068
137488
|
const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
|
|
137069
137489
|
return commandsToRecord(commands2);
|
|
137070
137490
|
}
|
|
137071
137491
|
async function loadProjectCommands(directory) {
|
|
137072
|
-
const projectCommandsDir =
|
|
137492
|
+
const projectCommandsDir = join101(directory ?? process.cwd(), ".claude", "commands");
|
|
137073
137493
|
const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
|
|
137074
137494
|
return commandsToRecord(commands2);
|
|
137075
137495
|
}
|
|
@@ -137220,13 +137640,13 @@ var grep_app = {
|
|
|
137220
137640
|
};
|
|
137221
137641
|
|
|
137222
137642
|
// src/mcp/ast-grep.ts
|
|
137223
|
-
import { existsSync as
|
|
137643
|
+
import { existsSync as existsSync94 } from "fs";
|
|
137224
137644
|
import { dirname as dirname36, resolve as resolve26 } from "path";
|
|
137225
137645
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
137226
137646
|
|
|
137227
137647
|
// src/mcp/cli-suffix.ts
|
|
137228
|
-
function normalizeCliPath(
|
|
137229
|
-
return
|
|
137648
|
+
function normalizeCliPath(path22) {
|
|
137649
|
+
return path22.replaceAll("\\", "/");
|
|
137230
137650
|
}
|
|
137231
137651
|
function hasCliSuffix(candidatePath, suffix) {
|
|
137232
137652
|
return normalizeCliPath(candidatePath).endsWith(normalizeCliPath(suffix));
|
|
@@ -137320,11 +137740,11 @@ function getModuleDirectory(moduleUrl) {
|
|
|
137320
137740
|
}
|
|
137321
137741
|
function createFallbackCandidate(resolveExecutable) {
|
|
137322
137742
|
const runtime6 = resolveJavaScriptRuntime(resolveExecutable);
|
|
137323
|
-
const
|
|
137324
|
-
return { command: [runtime6.command,
|
|
137743
|
+
const path22 = resolve26(PACKAGE_REL, DIST_CLI_REL);
|
|
137744
|
+
return { command: [runtime6.command, path22, "mcp"], path: path22, exists: runtime6.available, runtimeAvailable: runtime6.available };
|
|
137325
137745
|
}
|
|
137326
137746
|
function resolveAstGrepCommand(options = {}) {
|
|
137327
|
-
const pathExists = options.exists ??
|
|
137747
|
+
const pathExists = options.exists ?? existsSync94;
|
|
137328
137748
|
const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
|
|
137329
137749
|
const candidates = [];
|
|
137330
137750
|
const seenPaths = new Set;
|
|
@@ -137360,7 +137780,7 @@ function createAstGrepMcpConfig(options = {}) {
|
|
|
137360
137780
|
}
|
|
137361
137781
|
|
|
137362
137782
|
// src/mcp/lsp.ts
|
|
137363
|
-
import { existsSync as
|
|
137783
|
+
import { existsSync as existsSync95 } from "fs";
|
|
137364
137784
|
import { dirname as dirname37, resolve as resolve27 } from "path";
|
|
137365
137785
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
137366
137786
|
var SUBMODULE_REL = "packages/lsp-tools-mcp";
|
|
@@ -137449,7 +137869,7 @@ function createBootstrapCandidate(root, resolveExecutable) {
|
|
|
137449
137869
|
};
|
|
137450
137870
|
}
|
|
137451
137871
|
function resolveLspCommand(options = {}) {
|
|
137452
|
-
const pathExists = options.exists ??
|
|
137872
|
+
const pathExists = options.exists ?? existsSync95;
|
|
137453
137873
|
const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
|
|
137454
137874
|
const candidates = [];
|
|
137455
137875
|
const seenPaths = new Set;
|
|
@@ -137981,11 +138401,25 @@ async function createSkillContext(args) {
|
|
|
137981
138401
|
return true;
|
|
137982
138402
|
});
|
|
137983
138403
|
const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
|
|
137984
|
-
const
|
|
138404
|
+
const hostSkillConfig = adaptHostSkillConfig(readOpencodeConfigSkills(directory));
|
|
138405
|
+
const [
|
|
138406
|
+
configSourceSkills,
|
|
138407
|
+
hostConfigSkills,
|
|
138408
|
+
userSkills,
|
|
138409
|
+
globalSkills,
|
|
138410
|
+
projectSkills,
|
|
138411
|
+
opencodeProjectSkills,
|
|
138412
|
+
agentsProjectSkills,
|
|
138413
|
+
agentsGlobalSkills
|
|
138414
|
+
] = await Promise.all([
|
|
137985
138415
|
discoverConfigSourceSkills({
|
|
137986
138416
|
config: pluginConfig.skills,
|
|
137987
138417
|
configDir: directory
|
|
137988
138418
|
}),
|
|
138419
|
+
discoverConfigSourceSkills({
|
|
138420
|
+
config: hostSkillConfig,
|
|
138421
|
+
configDir: directory
|
|
138422
|
+
}),
|
|
137989
138423
|
includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
137990
138424
|
discoverOpencodeGlobalSkills(),
|
|
137991
138425
|
includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
|
|
@@ -137993,7 +138427,12 @@ async function createSkillContext(args) {
|
|
|
137993
138427
|
discoverProjectAgentsSkills(directory),
|
|
137994
138428
|
discoverGlobalAgentsSkills()
|
|
137995
138429
|
]);
|
|
137996
|
-
const
|
|
138430
|
+
const configSkillsHostWins = new Map;
|
|
138431
|
+
for (const skill2 of configSourceSkills)
|
|
138432
|
+
configSkillsHostWins.set(skill2.name, skill2);
|
|
138433
|
+
for (const skill2 of hostConfigSkills)
|
|
138434
|
+
configSkillsHostWins.set(skill2.name, skill2);
|
|
138435
|
+
const filteredConfigSourceSkills = filterProviderGatedSkills(Array.from(configSkillsHostWins.values()), browserProvider);
|
|
137997
138436
|
const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
|
|
137998
138437
|
const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
|
|
137999
138438
|
const filteredProjectSkills = filterProviderGatedSkills(projectSkills, browserProvider);
|
|
@@ -138434,7 +138873,7 @@ async function loadTeamSpec(teamName, config, projectRoot, options) {
|
|
|
138434
138873
|
|
|
138435
138874
|
// src/features/team-mode/team-runtime/create.ts
|
|
138436
138875
|
import { access as access4, mkdir as mkdir5 } from "fs/promises";
|
|
138437
|
-
import
|
|
138876
|
+
import path22 from "path";
|
|
138438
138877
|
init_paths();
|
|
138439
138878
|
init_store();
|
|
138440
138879
|
init_team_session_registry();
|
|
@@ -138708,7 +139147,7 @@ async function findExistingRuntime(spec, leadSessionId, config) {
|
|
|
138708
139147
|
}
|
|
138709
139148
|
}
|
|
138710
139149
|
async function createMemberWorktree(memberWorktreePath, projectRoot) {
|
|
138711
|
-
const absolutePath =
|
|
139150
|
+
const absolutePath = path22.isAbsolute(memberWorktreePath) ? memberWorktreePath : path22.resolve(projectRoot, memberWorktreePath);
|
|
138712
139151
|
await mkdir5(absolutePath, { recursive: true });
|
|
138713
139152
|
return absolutePath;
|
|
138714
139153
|
}
|
|
@@ -138979,6 +139418,29 @@ var TeamCreateArgsSchema = z41.object({
|
|
|
138979
139418
|
ctx.addIssue({ code: "custom", message: "Provide exactly one of teamName or inline_spec." });
|
|
138980
139419
|
}
|
|
138981
139420
|
});
|
|
139421
|
+
var TeamCreateInlineMemberToolSchema = tool.schema.object({
|
|
139422
|
+
name: tool.schema.string().optional().describe("Member name, kebab-case or natural text; normalized before team creation."),
|
|
139423
|
+
kind: tool.schema.enum(["category", "subagent_type"]).optional().describe("Member kind. Use category for category-routed workers, or subagent_type for a specific eligible agent."),
|
|
139424
|
+
category: tool.schema.string().optional().describe("Required for category members unless a fallback category can be inferred. Examples: quick, unspecified-low, unspecified-high, deep, ultrabrain, visual-engineering, writing, artistry, git, data-analysis."),
|
|
139425
|
+
subagent_type: tool.schema.string().optional().describe("Required for subagent_type members. Eligible examples: sisyphus, atlas, sisyphus-junior."),
|
|
139426
|
+
prompt: tool.schema.string().optional().describe("Task prompt for this member. Category members need a concrete work prompt."),
|
|
139427
|
+
systemPrompt: tool.schema.string().optional().describe("Legacy alias for prompt; normalized before team creation."),
|
|
139428
|
+
loadSkills: tool.schema.array(tool.schema.string()).optional().describe("Optional skills to load for this member."),
|
|
139429
|
+
role: tool.schema.string().optional().describe("Optional natural-language role used to build a prompt when prompt is omitted."),
|
|
139430
|
+
description: tool.schema.string().optional().describe("Optional natural-language description used to build a prompt when prompt is omitted.")
|
|
139431
|
+
});
|
|
139432
|
+
var TeamCreateInlineSpecToolSchema = tool.schema.union([
|
|
139433
|
+
tool.schema.object({
|
|
139434
|
+
name: tool.schema.string().describe("Team name, kebab-case or natural text; normalized before team creation."),
|
|
139435
|
+
description: tool.schema.string().optional().describe("Optional team description."),
|
|
139436
|
+
leadAgentId: tool.schema.string().optional().describe("Optional member name to use as team lead."),
|
|
139437
|
+
lead: TeamCreateInlineMemberToolSchema.optional().describe("Optional explicit lead member."),
|
|
139438
|
+
members: tool.schema.array(TeamCreateInlineMemberToolSchema).describe("Team members; members must be a flat array, not an object or nested groups. Provide 1-8 members."),
|
|
139439
|
+
teamAllowedPaths: tool.schema.array(tool.schema.string()).optional().describe("Optional paths the team may access."),
|
|
139440
|
+
sessionPermission: tool.schema.string().optional().describe("Optional session permission policy.")
|
|
139441
|
+
}),
|
|
139442
|
+
tool.schema.string().describe("JSON string containing the same inline team spec object.")
|
|
139443
|
+
]);
|
|
138982
139444
|
var TeamDeleteArgsSchema = z41.object({ teamRunId: z41.string().min(1), force: z41.boolean().optional() });
|
|
138983
139445
|
var TeamShutdownRequestArgsSchema = z41.object({ teamRunId: z41.string().min(1), targetMemberName: z41.string().min(1) });
|
|
138984
139446
|
var TeamApproveShutdownArgsSchema = z41.object({ teamRunId: z41.string().min(1), memberName: z41.string().min(1) });
|
|
@@ -139013,8 +139475,8 @@ function parseTeamCreateArgs(rawArgs) {
|
|
|
139013
139475
|
}
|
|
139014
139476
|
return result.data;
|
|
139015
139477
|
}
|
|
139016
|
-
function formatZodIssuePath(
|
|
139017
|
-
return
|
|
139478
|
+
function formatZodIssuePath(path23) {
|
|
139479
|
+
return path23.length > 0 ? path23.join(".") : "<root>";
|
|
139018
139480
|
}
|
|
139019
139481
|
function formatTeamSpecIssues(error) {
|
|
139020
139482
|
return error.issues.slice(0, 5).map((issue) => `${formatZodIssuePath(issue.path)}: ${issue.message}`).join("; ");
|
|
@@ -139077,7 +139539,7 @@ function createTeamCreateTool(config, client, bgMgr, tmuxMgr, executorConfig, de
|
|
|
139077
139539
|
description: "Create a team run from a named or inline team spec.",
|
|
139078
139540
|
args: {
|
|
139079
139541
|
teamName: tool.schema.string().optional().describe("Named team spec to load. Provide exactly one of teamName or inline_spec."),
|
|
139080
|
-
inline_spec:
|
|
139542
|
+
inline_spec: TeamCreateInlineSpecToolSchema.optional().describe('Inline team spec object or JSON string. Provide exactly one of teamName or inline_spec; members must be a flat array, e.g. { name: "project-analysis-team", members: [{ name: "structure-analyst", category: "quick", prompt: "Analyze project structure." }] }.'),
|
|
139081
139543
|
leadSessionId: tool.schema.string().optional().describe("Optional non-empty session ID override. Usually omit this and let team_create use the current session.")
|
|
139082
139544
|
},
|
|
139083
139545
|
async execute(rawArgs, toolContext) {
|
|
@@ -139187,7 +139649,7 @@ init_store();
|
|
|
139187
139649
|
// src/features/team-mode/team-tasklist/list.ts
|
|
139188
139650
|
init_logger();
|
|
139189
139651
|
import { readdir as readdir8, readFile as readFile10 } from "fs/promises";
|
|
139190
|
-
import
|
|
139652
|
+
import path23 from "path";
|
|
139191
139653
|
|
|
139192
139654
|
// src/features/team-mode/team-registry/index.ts
|
|
139193
139655
|
init_paths();
|
|
@@ -139206,7 +139668,7 @@ async function listTasks(teamRunId, config, filter) {
|
|
|
139206
139668
|
for (const entry of entries) {
|
|
139207
139669
|
if (entry.isDirectory() || entry.name.startsWith(".") || !entry.name.endsWith(".json"))
|
|
139208
139670
|
continue;
|
|
139209
|
-
const taskPath =
|
|
139671
|
+
const taskPath = path23.join(tasksDirectory, entry.name);
|
|
139210
139672
|
try {
|
|
139211
139673
|
const taskContent = await readFile10(taskPath, "utf8");
|
|
139212
139674
|
const parsedTask = TaskSchema.safeParse(JSON.parse(taskContent));
|
|
@@ -139238,7 +139700,7 @@ async function listTasks(teamRunId, config, filter) {
|
|
|
139238
139700
|
// src/features/team-mode/team-runtime/status.ts
|
|
139239
139701
|
init_paths();
|
|
139240
139702
|
import { readdir as readdir9 } from "fs/promises";
|
|
139241
|
-
import
|
|
139703
|
+
import path24 from "path";
|
|
139242
139704
|
function getPrimaryModelKey(bgMgr, leadSessionId) {
|
|
139243
139705
|
if (!bgMgr || !leadSessionId)
|
|
139244
139706
|
return;
|
|
@@ -139289,10 +139751,10 @@ async function aggregateStatus(teamRunId, config, bgMgr) {
|
|
|
139289
139751
|
const concurrencyCounts = resolveConcurrencyCounts(teamBackgroundManager, runtimeState.leadSessionId);
|
|
139290
139752
|
const teamRunIdSpecific = teamBackgroundManager?.listTasksByParentSession?.(runtimeState.leadSessionId ?? teamRunId)?.length;
|
|
139291
139753
|
const baseDir = resolveBaseDir(config);
|
|
139292
|
-
const claimsDir =
|
|
139754
|
+
const claimsDir = path24.join(getTasksDir(baseDir, teamRunId), "claims");
|
|
139293
139755
|
const staleLockEntries = await readdir9(claimsDir, { withFileTypes: true }).catch(() => []);
|
|
139294
139756
|
const staleLockPaths = await Promise.all(staleLockEntries.filter((entry) => entry.isFile() && entry.name.endsWith(".lock")).map(async (entry) => {
|
|
139295
|
-
const lockPath =
|
|
139757
|
+
const lockPath = path24.join(claimsDir, entry.name);
|
|
139296
139758
|
return await detectStaleLock(lockPath, 300000) ? lockPath : undefined;
|
|
139297
139759
|
}));
|
|
139298
139760
|
return {
|
|
@@ -139391,7 +139853,7 @@ function createTeamListTool(config, client, deps = defaultDeps7) {
|
|
|
139391
139853
|
|
|
139392
139854
|
// src/features/team-mode/team-tasklist/claim.ts
|
|
139393
139855
|
import { access as access5, mkdir as mkdir6 } from "fs/promises";
|
|
139394
|
-
import
|
|
139856
|
+
import path26 from "path";
|
|
139395
139857
|
init_locks();
|
|
139396
139858
|
init_types2();
|
|
139397
139859
|
|
|
@@ -139405,11 +139867,11 @@ function canClaim(task, allTasks) {
|
|
|
139405
139867
|
|
|
139406
139868
|
// src/features/team-mode/team-tasklist/get.ts
|
|
139407
139869
|
import { readFile as readFile11 } from "fs/promises";
|
|
139408
|
-
import
|
|
139870
|
+
import path25 from "path";
|
|
139409
139871
|
init_types2();
|
|
139410
139872
|
async function getTask(teamRunId, taskId, config) {
|
|
139411
139873
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139412
|
-
const taskContent = await readFile11(
|
|
139874
|
+
const taskContent = await readFile11(path25.join(tasksDirectory, `${taskId}.json`), "utf8");
|
|
139413
139875
|
return TaskSchema.parse(JSON.parse(taskContent));
|
|
139414
139876
|
}
|
|
139415
139877
|
|
|
@@ -139448,9 +139910,9 @@ class BlockedByError extends Error {
|
|
|
139448
139910
|
async function claimTask(teamRunId, taskId, memberName, config) {
|
|
139449
139911
|
const baseDirectory = resolveBaseDir(config);
|
|
139450
139912
|
const tasksDirectory = getTasksDir(baseDirectory, teamRunId);
|
|
139451
|
-
const claimsDirectory =
|
|
139452
|
-
const taskPath =
|
|
139453
|
-
const claimLockPath =
|
|
139913
|
+
const claimsDirectory = path26.join(tasksDirectory, "claims");
|
|
139914
|
+
const taskPath = path26.join(tasksDirectory, `${taskId}.json`);
|
|
139915
|
+
const claimLockPath = path26.join(claimsDirectory, `${taskId}.lock`);
|
|
139454
139916
|
await mkdir6(claimsDirectory, { recursive: true, mode: 448 });
|
|
139455
139917
|
const task = await getTask(teamRunId, taskId, config);
|
|
139456
139918
|
if (task.status !== "pending") {
|
|
@@ -139489,7 +139951,7 @@ async function claimTask(teamRunId, taskId, memberName, config) {
|
|
|
139489
139951
|
}
|
|
139490
139952
|
// src/features/team-mode/team-tasklist/store.ts
|
|
139491
139953
|
import { mkdir as mkdir7, readFile as readFile12 } from "fs/promises";
|
|
139492
|
-
import
|
|
139954
|
+
import path27 from "path";
|
|
139493
139955
|
init_locks();
|
|
139494
139956
|
init_types2();
|
|
139495
139957
|
var HIGH_WATERMARK_FILE = ".highwatermark";
|
|
@@ -139506,9 +139968,9 @@ async function readHighWatermark(watermarkPath) {
|
|
|
139506
139968
|
async function createTask(teamRunId, taskInput, config) {
|
|
139507
139969
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139508
139970
|
await mkdir7(tasksDirectory, { recursive: true, mode: 448 });
|
|
139509
|
-
await mkdir7(
|
|
139510
|
-
return withLock(
|
|
139511
|
-
const watermarkPath =
|
|
139971
|
+
await mkdir7(path27.join(tasksDirectory, "claims"), { recursive: true, mode: 448 });
|
|
139972
|
+
return withLock(path27.join(tasksDirectory, ".lock"), async () => {
|
|
139973
|
+
const watermarkPath = path27.join(tasksDirectory, HIGH_WATERMARK_FILE);
|
|
139512
139974
|
const nextTaskId = await readHighWatermark(watermarkPath) + 1;
|
|
139513
139975
|
await atomicWrite(watermarkPath, String(nextTaskId));
|
|
139514
139976
|
const now = Date.now();
|
|
@@ -139519,13 +139981,13 @@ async function createTask(teamRunId, taskInput, config) {
|
|
|
139519
139981
|
createdAt: now,
|
|
139520
139982
|
updatedAt: now
|
|
139521
139983
|
});
|
|
139522
|
-
await atomicWrite(
|
|
139984
|
+
await atomicWrite(path27.join(tasksDirectory, `${task.id}.json`), `${JSON.stringify(task, null, 2)}
|
|
139523
139985
|
`);
|
|
139524
139986
|
return task;
|
|
139525
139987
|
}, { ownerTag: `create-task:${teamRunId}` });
|
|
139526
139988
|
}
|
|
139527
139989
|
// src/features/team-mode/team-tasklist/update.ts
|
|
139528
|
-
import
|
|
139990
|
+
import path28 from "path";
|
|
139529
139991
|
init_locks();
|
|
139530
139992
|
init_types2();
|
|
139531
139993
|
var ALLOWED_TRANSITIONS = {
|
|
@@ -139574,7 +140036,7 @@ async function updateTaskStatus(teamRunId, taskId, newStatus, memberName, config
|
|
|
139574
140036
|
updatedAt: Date.now()
|
|
139575
140037
|
});
|
|
139576
140038
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139577
|
-
await atomicWrite(
|
|
140039
|
+
await atomicWrite(path28.join(tasksDirectory, `${taskId}.json`), `${JSON.stringify(updatedTask, null, 2)}
|
|
139578
140040
|
`);
|
|
139579
140041
|
return updatedTask;
|
|
139580
140042
|
}
|
|
@@ -140306,8 +140768,8 @@ init_agent_display_names();
|
|
|
140306
140768
|
// src/plugin/ultrawork-db-model-override.ts
|
|
140307
140769
|
init_data_path();
|
|
140308
140770
|
init_shared();
|
|
140309
|
-
import { join as
|
|
140310
|
-
import { existsSync as
|
|
140771
|
+
import { join as join102 } from "path";
|
|
140772
|
+
import { existsSync as existsSync96 } from "fs";
|
|
140311
140773
|
async function importBunSqlite() {
|
|
140312
140774
|
if (typeof globalThis.Bun === "undefined") {
|
|
140313
140775
|
return null;
|
|
@@ -140320,7 +140782,7 @@ async function importBunSqlite() {
|
|
|
140320
140782
|
}
|
|
140321
140783
|
}
|
|
140322
140784
|
function getDbPath() {
|
|
140323
|
-
return
|
|
140785
|
+
return join102(getDataDir(), "opencode", "opencode.db");
|
|
140324
140786
|
}
|
|
140325
140787
|
var MAX_MICROTASK_RETRIES = 10;
|
|
140326
140788
|
function tryUpdateMessageModel(db, messageId, targetModel, variant) {
|
|
@@ -140403,7 +140865,7 @@ function scheduleDeferredModelOverride(messageId, targetModel, variant) {
|
|
|
140403
140865
|
return;
|
|
140404
140866
|
}
|
|
140405
140867
|
const dbPath = getDbPath();
|
|
140406
|
-
if (!
|
|
140868
|
+
if (!existsSync96(dbPath)) {
|
|
140407
140869
|
log("[ultrawork-db-override] DB not found, skipping deferred override");
|
|
140408
140870
|
return;
|
|
140409
140871
|
}
|
|
@@ -140762,11 +141224,17 @@ init_model_normalization();
|
|
|
140762
141224
|
var ASSISTANT_PREFILL_RECOVERY_TEXT = "[internal] Continue from the previous assistant state.";
|
|
140763
141225
|
var ASSISTANT_PREFILL_UNSUPPORTED_PROVIDERS = new Set([
|
|
140764
141226
|
"anthropic",
|
|
140765
|
-
"
|
|
141227
|
+
"aws-bedrock-anthropic",
|
|
141228
|
+
"github-copilot",
|
|
141229
|
+
"github-copilot-enterprise",
|
|
141230
|
+
"google-vertex-anthropic",
|
|
141231
|
+
"opencode",
|
|
141232
|
+
"opencode-go",
|
|
141233
|
+
"opencode-zen-proxy",
|
|
141234
|
+
"vercel"
|
|
140766
141235
|
]);
|
|
140767
141236
|
var ASSISTANT_PREFILL_UNSUPPORTED_MODEL_PREFIXES = [
|
|
140768
|
-
"claude-opus-4
|
|
140769
|
-
"claude-opus-4-6",
|
|
141237
|
+
"claude-opus-4",
|
|
140770
141238
|
"claude-sonnet-4-6",
|
|
140771
141239
|
"claude-mythos"
|
|
140772
141240
|
];
|
|
@@ -140817,15 +141285,26 @@ function findLastUserModel(messages) {
|
|
|
140817
141285
|
}
|
|
140818
141286
|
return;
|
|
140819
141287
|
}
|
|
141288
|
+
function normalizeAssistantPrefillModelID(modelID) {
|
|
141289
|
+
const normalizedModelID = normalizeModelID(modelID.toLowerCase());
|
|
141290
|
+
return normalizedModelID.split(/[/.~:@]+/).find((segment) => segment.startsWith("claude-")) ?? normalizedModelID;
|
|
141291
|
+
}
|
|
141292
|
+
function hasAnthropicModelNamespace(modelID) {
|
|
141293
|
+
const normalizedModelID = normalizeModelID(modelID.toLowerCase());
|
|
141294
|
+
return /(?:^|[/.~:@])anthropic(?:$|[/.~:@])/.test(normalizedModelID);
|
|
141295
|
+
}
|
|
141296
|
+
function providerCanExposeUnsupportedAssistantPrefill(providerID, modelID) {
|
|
141297
|
+
return ASSISTANT_PREFILL_UNSUPPORTED_PROVIDERS.has(providerID) || hasAnthropicModelNamespace(modelID);
|
|
141298
|
+
}
|
|
140820
141299
|
function shouldRepairAssistantPrefillForModel(model) {
|
|
140821
141300
|
if (!model) {
|
|
140822
141301
|
return false;
|
|
140823
141302
|
}
|
|
140824
141303
|
const providerID = model.providerID.toLowerCase();
|
|
140825
|
-
if (!
|
|
141304
|
+
if (!providerCanExposeUnsupportedAssistantPrefill(providerID, model.modelID)) {
|
|
140826
141305
|
return false;
|
|
140827
141306
|
}
|
|
140828
|
-
const modelID =
|
|
141307
|
+
const modelID = normalizeAssistantPrefillModelID(model.modelID);
|
|
140829
141308
|
return ASSISTANT_PREFILL_UNSUPPORTED_MODEL_PREFIXES.some((prefix) => modelID.startsWith(prefix));
|
|
140830
141309
|
}
|
|
140831
141310
|
function isCompactionContinuationPart(part) {
|
|
@@ -140886,9 +141365,10 @@ async function runMessagesTransformHookSafely(hookName, handler, input, output)
|
|
|
140886
141365
|
try {
|
|
140887
141366
|
await Promise.resolve(handler(input, output));
|
|
140888
141367
|
} catch (error) {
|
|
141368
|
+
const hookError = error instanceof Error ? error : new Error(String(error));
|
|
140889
141369
|
log("[messages-transform] hook execution failed", {
|
|
140890
141370
|
hook: hookName,
|
|
140891
|
-
error
|
|
141371
|
+
error: hookError
|
|
140892
141372
|
});
|
|
140893
141373
|
}
|
|
140894
141374
|
}
|
|
@@ -140930,19 +141410,19 @@ init_session_tools_store();
|
|
|
140930
141410
|
// src/features/team-mode/team-mailbox/ack.ts
|
|
140931
141411
|
init_paths();
|
|
140932
141412
|
import { mkdir as mkdir8, rename as rename3 } from "fs/promises";
|
|
140933
|
-
import
|
|
141413
|
+
import path29 from "path";
|
|
140934
141414
|
async function ackMessages(teamRunId, memberName, messageIds, config) {
|
|
140935
141415
|
const baseDir = resolveBaseDir(config);
|
|
140936
141416
|
const inboxDir = getInboxDir(baseDir, teamRunId, memberName);
|
|
140937
|
-
const processedDir =
|
|
141417
|
+
const processedDir = path29.join(inboxDir, "processed");
|
|
140938
141418
|
await mkdir8(processedDir, { recursive: true, mode: 448 });
|
|
140939
141419
|
for (const messageId of messageIds) {
|
|
140940
141420
|
const messageFileName = `${messageId}.json`;
|
|
140941
141421
|
const sourcePaths = [
|
|
140942
|
-
|
|
140943
|
-
|
|
141422
|
+
path29.join(inboxDir, messageFileName),
|
|
141423
|
+
path29.join(inboxDir, `.delivering-${messageFileName}`)
|
|
140944
141424
|
];
|
|
140945
|
-
const targetPath =
|
|
141425
|
+
const targetPath = path29.join(processedDir, messageFileName);
|
|
140946
141426
|
for (const sourcePath of sourcePaths) {
|
|
140947
141427
|
try {
|
|
140948
141428
|
await rename3(sourcePath, targetPath);
|
|
@@ -141514,6 +141994,33 @@ function normalizeSessionStatusToIdle(input) {
|
|
|
141514
141994
|
|
|
141515
141995
|
// src/plugin/event.ts
|
|
141516
141996
|
init_event_session_id();
|
|
141997
|
+
|
|
141998
|
+
// src/plugin/user-abort-interrupted-recovery-guard.ts
|
|
141999
|
+
var USER_ABORT_ERROR_NAMES = new Set(["MessageAbortedError", "AbortError"]);
|
|
142000
|
+
function createUserAbortInterruptedRecoveryGuard() {
|
|
142001
|
+
const abortedSessions = new Set;
|
|
142002
|
+
return {
|
|
142003
|
+
noteSessionError(sessionID, errorName) {
|
|
142004
|
+
if (!errorName || !USER_ABORT_ERROR_NAMES.has(errorName)) {
|
|
142005
|
+
return false;
|
|
142006
|
+
}
|
|
142007
|
+
abortedSessions.add(sessionID);
|
|
142008
|
+
return true;
|
|
142009
|
+
},
|
|
142010
|
+
shouldSkipRecovery(sessionID) {
|
|
142011
|
+
const shouldSkip = abortedSessions.has(sessionID);
|
|
142012
|
+
if (shouldSkip) {
|
|
142013
|
+
abortedSessions.delete(sessionID);
|
|
142014
|
+
}
|
|
142015
|
+
return shouldSkip;
|
|
142016
|
+
},
|
|
142017
|
+
clear(sessionID) {
|
|
142018
|
+
abortedSessions.delete(sessionID);
|
|
142019
|
+
}
|
|
142020
|
+
};
|
|
142021
|
+
}
|
|
142022
|
+
|
|
142023
|
+
// src/plugin/event.ts
|
|
141517
142024
|
function isRecord26(value) {
|
|
141518
142025
|
return typeof value === "object" && value !== null;
|
|
141519
142026
|
}
|
|
@@ -141598,6 +142105,7 @@ function createEventHandler2(args) {
|
|
|
141598
142105
|
const lastKnownModelBySession = new Map;
|
|
141599
142106
|
const modelFallbackContinuationsInFlight = new Set;
|
|
141600
142107
|
const lastDispatchedModelFallbackContinuationKeys = new Map;
|
|
142108
|
+
const userAbortInterruptedRecoveryGuard = createUserAbortInterruptedRecoveryGuard();
|
|
141601
142109
|
const resolveFallbackProviderID = (sessionID, providerHint) => {
|
|
141602
142110
|
const normalizedProviderHint = providerHint?.trim();
|
|
141603
142111
|
if (normalizedProviderHint) {
|
|
@@ -141651,7 +142159,6 @@ function createEventHandler2(args) {
|
|
|
141651
142159
|
await runEventHookSafely("sessionNotification", hooks2.sessionNotification, input);
|
|
141652
142160
|
await runEventHookSafely("todoContinuationEnforcer", hooks2.todoContinuationEnforcer?.handler, input);
|
|
141653
142161
|
await runEventHookSafely("unstableAgentBabysitter", hooks2.unstableAgentBabysitter?.event, input);
|
|
141654
|
-
await runEventHookSafely("contextWindowMonitor", hooks2.contextWindowMonitor?.event, input);
|
|
141655
142162
|
await runEventHookSafely("preemptiveCompaction", hooks2.preemptiveCompaction?.event, input);
|
|
141656
142163
|
await runEventHookSafely("directoryAgentsInjector", hooks2.directoryAgentsInjector?.event, input);
|
|
141657
142164
|
await runEventHookSafely("directoryReadmeInjector", hooks2.directoryReadmeInjector?.event, input);
|
|
@@ -141713,6 +142220,10 @@ function createEventHandler2(args) {
|
|
|
141713
142220
|
if (!sessionID || !hooks2.sessionRecovery?.handleInterruptedToolResultsOnIdle) {
|
|
141714
142221
|
return false;
|
|
141715
142222
|
}
|
|
142223
|
+
if (userAbortInterruptedRecoveryGuard.shouldSkipRecovery(sessionID)) {
|
|
142224
|
+
log("[event] interrupted tool recovery skipped after user abort", { sessionID });
|
|
142225
|
+
return false;
|
|
142226
|
+
}
|
|
141716
142227
|
return hooks2.sessionRecovery.handleInterruptedToolResultsOnIdle(sessionID);
|
|
141717
142228
|
};
|
|
141718
142229
|
const dispatchIdleOnlyHooks = async (input) => {
|
|
@@ -141872,10 +142383,6 @@ function createEventHandler2(args) {
|
|
|
141872
142383
|
const emittedAt = recentSyntheticIdles.get(sessionID);
|
|
141873
142384
|
if (emittedAt !== undefined && now - emittedAt < DEDUP_WINDOW_MS2) {
|
|
141874
142385
|
recentSyntheticIdles.delete(sessionID);
|
|
141875
|
-
const lastAnyIdleAt = recentAnyIdles.get(sessionID);
|
|
141876
|
-
if (lastAnyIdleAt === emittedAt) {
|
|
141877
|
-
recentAnyIdles.delete(sessionID);
|
|
141878
|
-
}
|
|
141879
142386
|
}
|
|
141880
142387
|
}
|
|
141881
142388
|
const recovered = await recoverInterruptedToolResultsOnIdleEvent(input);
|
|
@@ -141964,6 +142471,7 @@ function createEventHandler2(args) {
|
|
|
141964
142471
|
lastKnownModelBySession.delete(sessionID);
|
|
141965
142472
|
modelFallbackContinuationsInFlight.delete(sessionID);
|
|
141966
142473
|
lastDispatchedModelFallbackContinuationKeys.delete(sessionID);
|
|
142474
|
+
userAbortInterruptedRecoveryGuard.clear(sessionID);
|
|
141967
142475
|
if (modelFallback) {
|
|
141968
142476
|
clearPendingModelFallback(modelFallback, sessionID);
|
|
141969
142477
|
clearSessionFallbackChain(modelFallback, sessionID);
|
|
@@ -142042,6 +142550,10 @@ function createEventHandler2(args) {
|
|
|
142042
142550
|
lastKnownModelBySession.set(sessionID, { providerID, modelID });
|
|
142043
142551
|
setSessionModel(sessionID, { providerID, modelID });
|
|
142044
142552
|
}
|
|
142553
|
+
userAbortInterruptedRecoveryGuard.clear(sessionID);
|
|
142554
|
+
}
|
|
142555
|
+
if (sessionID && role === "assistant") {
|
|
142556
|
+
userAbortInterruptedRecoveryGuard.noteSessionError(sessionID, extractErrorName3(info?.error));
|
|
142045
142557
|
}
|
|
142046
142558
|
if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
|
|
142047
142559
|
try {
|
|
@@ -142157,6 +142669,9 @@ function createEventHandler2(args) {
|
|
|
142157
142669
|
const errorName = extractErrorName3(error);
|
|
142158
142670
|
const errorMessage = extractErrorMessage3(error);
|
|
142159
142671
|
const errorInfo = { name: errorName, message: errorMessage };
|
|
142672
|
+
if (sessionID) {
|
|
142673
|
+
userAbortInterruptedRecoveryGuard.noteSessionError(sessionID, errorName);
|
|
142674
|
+
}
|
|
142160
142675
|
if (hooks2.sessionRecovery?.isRecoverableError(error)) {
|
|
142161
142676
|
const messageInfo = {
|
|
142162
142677
|
id: props?.messageID,
|
|
@@ -142356,7 +142871,6 @@ function createToolExecuteAfterHandler3(args) {
|
|
|
142356
142871
|
await hooks2.toolOutputTruncator?.["tool.execute.after"]?.(hookInput, output);
|
|
142357
142872
|
await hooks2.claudeCodeHooks?.["tool.execute.after"]?.(hookInput, output);
|
|
142358
142873
|
await hooks2.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output);
|
|
142359
|
-
await hooks2.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output);
|
|
142360
142874
|
await hooks2.commentChecker?.["tool.execute.after"]?.(hookInput, output);
|
|
142361
142875
|
await hooks2.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output);
|
|
142362
142876
|
await hooks2.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output);
|
|
@@ -142656,9 +143170,9 @@ function createPluginInterface(args) {
|
|
|
142656
143170
|
}
|
|
142657
143171
|
|
|
142658
143172
|
// src/plugin-config.ts
|
|
142659
|
-
import * as
|
|
143173
|
+
import * as fs24 from "fs";
|
|
142660
143174
|
import { homedir as homedir22 } from "os";
|
|
142661
|
-
import * as
|
|
143175
|
+
import * as path30 from "path";
|
|
142662
143176
|
init_shared();
|
|
142663
143177
|
init_plugin_identity();
|
|
142664
143178
|
|
|
@@ -142788,22 +143302,22 @@ function resolveHomeDirectory() {
|
|
|
142788
143302
|
return process.env.HOME ?? process.env.USERPROFILE ?? homedir22();
|
|
142789
143303
|
}
|
|
142790
143304
|
function resolveConfigPathAfterLegacyMigration(detectedPath) {
|
|
142791
|
-
if (!
|
|
143305
|
+
if (!path30.basename(detectedPath).startsWith(LEGACY_CONFIG_BASENAME)) {
|
|
142792
143306
|
return detectedPath;
|
|
142793
143307
|
}
|
|
142794
143308
|
const migrated = migrateLegacyConfigFile(detectedPath);
|
|
142795
|
-
const canonicalPath =
|
|
142796
|
-
if (migrated ||
|
|
143309
|
+
const canonicalPath = path30.join(path30.dirname(detectedPath), `${CONFIG_BASENAME}${path30.extname(detectedPath)}`);
|
|
143310
|
+
if (migrated || fs24.existsSync(canonicalPath)) {
|
|
142797
143311
|
return canonicalPath;
|
|
142798
143312
|
}
|
|
142799
143313
|
return detectedPath;
|
|
142800
143314
|
}
|
|
142801
143315
|
function loadExplicitGitMasterOverrides(configPath) {
|
|
142802
143316
|
try {
|
|
142803
|
-
if (!
|
|
143317
|
+
if (!fs24.existsSync(configPath)) {
|
|
142804
143318
|
return;
|
|
142805
143319
|
}
|
|
142806
|
-
const content =
|
|
143320
|
+
const content = fs24.readFileSync(configPath, "utf-8");
|
|
142807
143321
|
const rawConfig = parseJsonc(content);
|
|
142808
143322
|
const gitMaster = rawConfig.git_master;
|
|
142809
143323
|
if (gitMaster && typeof gitMaster === "object" && !Array.isArray(gitMaster)) {
|
|
@@ -142860,8 +143374,8 @@ function parseConfigPartially(rawConfig) {
|
|
|
142860
143374
|
}
|
|
142861
143375
|
function loadConfigFromPath2(configPath, _ctx) {
|
|
142862
143376
|
try {
|
|
142863
|
-
if (
|
|
142864
|
-
const content =
|
|
143377
|
+
if (fs24.existsSync(configPath)) {
|
|
143378
|
+
const content = fs24.readFileSync(configPath, "utf-8");
|
|
142865
143379
|
const rawConfig = parseJsonc(content);
|
|
142866
143380
|
migrateConfigFile(configPath, rawConfig);
|
|
142867
143381
|
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
|
|
@@ -142996,7 +143510,7 @@ function loadPluginConfig(directory, ctx) {
|
|
|
142996
143510
|
stopDirectory
|
|
142997
143511
|
});
|
|
142998
143512
|
const canonicalAncestorPathsNearestFirst = ancestorConfigPathsNearestFirst.map((ancestorPath) => {
|
|
142999
|
-
const opencodeDir =
|
|
143513
|
+
const opencodeDir = path30.dirname(ancestorPath);
|
|
143000
143514
|
const ancestorDetected = detectPluginConfigFile(opencodeDir, {
|
|
143001
143515
|
basenames: [CONFIG_BASENAME],
|
|
143002
143516
|
legacyBasenames: [LEGACY_CONFIG_BASENAME]
|
|
@@ -143037,8 +143551,8 @@ function loadPluginConfig(directory, ctx) {
|
|
|
143037
143551
|
const ancestorConfig = loadConfigFromPath2(ancestorPath, ctx);
|
|
143038
143552
|
const ancestorOverrides = loadExplicitGitMasterOverrides(ancestorPath);
|
|
143039
143553
|
if (ancestorConfig?.agent_definitions) {
|
|
143040
|
-
const ancestorBasePath =
|
|
143041
|
-
const ancestorDir =
|
|
143554
|
+
const ancestorBasePath = path30.dirname(ancestorPath);
|
|
143555
|
+
const ancestorDir = path30.dirname(ancestorBasePath);
|
|
143042
143556
|
ancestorConfig.agent_definitions = resolveAgentDefinitionPaths(ancestorConfig.agent_definitions, ancestorBasePath, ancestorDir);
|
|
143043
143557
|
}
|
|
143044
143558
|
if (ancestorConfig) {
|