oh-my-opencode 4.6.0 → 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/bin/version-mismatch.js +47 -0
- package/bin/version-mismatch.test.ts +120 -0
- 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 +577 -304
- package/dist/cli/install-codex/codex-config-reasoning.d.ts +2 -1
- package/dist/cli/install-codex/codex-model-catalog.d.ts +13 -0
- package/dist/features/background-agent/concurrency.d.ts +1 -0
- package/dist/features/background-agent/process-cleanup.d.ts +6 -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/tasks-todowrite-disabler/constants.d.ts +1 -1
- package/dist/index.js +811 -450
- package/dist/shared/command-executor/execute-hook-command.d.ts +2 -0
- package/dist/tools/skill/description-formatter.d.ts +5 -1
- package/dist/tools/skill/types.d.ts +1 -0
- package/package.json +12 -13
- package/packages/ast-grep-mcp/dist/cli.js +53 -9
- package/packages/lsp-tools-mcp/dist/lsp/process.js +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +6 -4
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +0 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/README.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +3 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +7 -7
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +4 -3
- 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/hooks/hooks.json +11 -0
- package/packages/omo-codex/plugin/model-catalog.json +49 -0
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +159 -0
- package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +269 -0
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +3 -1
- 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 +7 -7
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +4 -3
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +17 -17
- package/packages/omo-codex/plugin/test/aggregate.test.mjs +172 -19
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +129 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +2 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +146 -0
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +22 -0
- package/packages/omo-codex/scripts/install/cli-args.mjs +1 -1
- package/packages/omo-codex/scripts/install/config.mjs +2 -15
- package/packages/omo-codex/scripts/install/delegated-command.mjs +1 -1
- package/packages/omo-codex/scripts/install/legacy-bins.mjs +1 -0
- package/packages/omo-codex/scripts/install/model-catalog.mjs +66 -0
- package/packages/omo-codex/scripts/install/reasoning-config.mjs +65 -7
- package/packages/omo-codex/scripts/install-bin-links.test.mjs +23 -0
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +82 -3
- package/packages/omo-codex/scripts/install-config.test.mjs +5 -6
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +30 -2
- package/packages/omo-codex/scripts/install-local.mjs +1 -1
- 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 +7 -7
- package/packages/shared-skills/skills/start-work/SKILL.md +6 -6
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -11
- package/postinstall.mjs +36 -3
- package/dist/cli/install-codex/codex-config-mcp.d.ts +0 -1
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 = () => {};
|
|
@@ -64082,8 +64165,8 @@ var require_utils2 = __commonJS((exports, module) => {
|
|
|
64082
64165
|
}
|
|
64083
64166
|
return ind;
|
|
64084
64167
|
}
|
|
64085
|
-
function removeDotSegments(
|
|
64086
|
-
let input =
|
|
64168
|
+
function removeDotSegments(path22) {
|
|
64169
|
+
let input = path22;
|
|
64087
64170
|
const output = [];
|
|
64088
64171
|
let nextSlash = -1;
|
|
64089
64172
|
let len = 0;
|
|
@@ -64326,8 +64409,8 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
64326
64409
|
wsComponent.secure = undefined;
|
|
64327
64410
|
}
|
|
64328
64411
|
if (wsComponent.resourceName) {
|
|
64329
|
-
const [
|
|
64330
|
-
wsComponent.path =
|
|
64412
|
+
const [path22, query] = wsComponent.resourceName.split("?");
|
|
64413
|
+
wsComponent.path = path22 && path22 !== "/" ? path22 : undefined;
|
|
64331
64414
|
wsComponent.query = query;
|
|
64332
64415
|
wsComponent.resourceName = undefined;
|
|
64333
64416
|
}
|
|
@@ -67502,12 +67585,12 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
67502
67585
|
throw new Error(`Unknown format "${name}"`);
|
|
67503
67586
|
return f;
|
|
67504
67587
|
};
|
|
67505
|
-
function addFormats(ajv, list,
|
|
67588
|
+
function addFormats(ajv, list, fs23, exportName) {
|
|
67506
67589
|
var _a;
|
|
67507
67590
|
var _b;
|
|
67508
67591
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
|
|
67509
67592
|
for (const f of list)
|
|
67510
|
-
ajv.addFormat(f,
|
|
67593
|
+
ajv.addFormat(f, fs23[f]);
|
|
67511
67594
|
}
|
|
67512
67595
|
module.exports = exports = formatsPlugin;
|
|
67513
67596
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -67518,8 +67601,8 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
67518
67601
|
var require_windows = __commonJS((exports, module) => {
|
|
67519
67602
|
module.exports = isexe;
|
|
67520
67603
|
isexe.sync = sync;
|
|
67521
|
-
var
|
|
67522
|
-
function checkPathExt(
|
|
67604
|
+
var fs23 = __require("fs");
|
|
67605
|
+
function checkPathExt(path22, options) {
|
|
67523
67606
|
var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
|
|
67524
67607
|
if (!pathext) {
|
|
67525
67608
|
return true;
|
|
@@ -67530,25 +67613,25 @@ var require_windows = __commonJS((exports, module) => {
|
|
|
67530
67613
|
}
|
|
67531
67614
|
for (var i2 = 0;i2 < pathext.length; i2++) {
|
|
67532
67615
|
var p = pathext[i2].toLowerCase();
|
|
67533
|
-
if (p &&
|
|
67616
|
+
if (p && path22.substr(-p.length).toLowerCase() === p) {
|
|
67534
67617
|
return true;
|
|
67535
67618
|
}
|
|
67536
67619
|
}
|
|
67537
67620
|
return false;
|
|
67538
67621
|
}
|
|
67539
|
-
function checkStat(stat7,
|
|
67622
|
+
function checkStat(stat7, path22, options) {
|
|
67540
67623
|
if (!stat7.isSymbolicLink() && !stat7.isFile()) {
|
|
67541
67624
|
return false;
|
|
67542
67625
|
}
|
|
67543
|
-
return checkPathExt(
|
|
67626
|
+
return checkPathExt(path22, options);
|
|
67544
67627
|
}
|
|
67545
|
-
function isexe(
|
|
67546
|
-
|
|
67547
|
-
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));
|
|
67548
67631
|
});
|
|
67549
67632
|
}
|
|
67550
|
-
function sync(
|
|
67551
|
-
return checkStat(
|
|
67633
|
+
function sync(path22, options) {
|
|
67634
|
+
return checkStat(fs23.statSync(path22), path22, options);
|
|
67552
67635
|
}
|
|
67553
67636
|
});
|
|
67554
67637
|
|
|
@@ -67556,14 +67639,14 @@ var require_windows = __commonJS((exports, module) => {
|
|
|
67556
67639
|
var require_mode = __commonJS((exports, module) => {
|
|
67557
67640
|
module.exports = isexe;
|
|
67558
67641
|
isexe.sync = sync;
|
|
67559
|
-
var
|
|
67560
|
-
function isexe(
|
|
67561
|
-
|
|
67642
|
+
var fs23 = __require("fs");
|
|
67643
|
+
function isexe(path22, options, cb) {
|
|
67644
|
+
fs23.stat(path22, function(er, stat7) {
|
|
67562
67645
|
cb(er, er ? false : checkStat(stat7, options));
|
|
67563
67646
|
});
|
|
67564
67647
|
}
|
|
67565
|
-
function sync(
|
|
67566
|
-
return checkStat(
|
|
67648
|
+
function sync(path22, options) {
|
|
67649
|
+
return checkStat(fs23.statSync(path22), options);
|
|
67567
67650
|
}
|
|
67568
67651
|
function checkStat(stat7, options) {
|
|
67569
67652
|
return stat7.isFile() && checkMode(stat7, options);
|
|
@@ -67585,7 +67668,7 @@ var require_mode = __commonJS((exports, module) => {
|
|
|
67585
67668
|
|
|
67586
67669
|
// node_modules/.bun/isexe@2.0.0/node_modules/isexe/index.js
|
|
67587
67670
|
var require_isexe = __commonJS((exports, module) => {
|
|
67588
|
-
var
|
|
67671
|
+
var fs23 = __require("fs");
|
|
67589
67672
|
var core2;
|
|
67590
67673
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
67591
67674
|
core2 = require_windows();
|
|
@@ -67594,7 +67677,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67594
67677
|
}
|
|
67595
67678
|
module.exports = isexe;
|
|
67596
67679
|
isexe.sync = sync;
|
|
67597
|
-
function isexe(
|
|
67680
|
+
function isexe(path22, options, cb) {
|
|
67598
67681
|
if (typeof options === "function") {
|
|
67599
67682
|
cb = options;
|
|
67600
67683
|
options = {};
|
|
@@ -67604,7 +67687,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67604
67687
|
throw new TypeError("callback not provided");
|
|
67605
67688
|
}
|
|
67606
67689
|
return new Promise(function(resolve25, reject) {
|
|
67607
|
-
isexe(
|
|
67690
|
+
isexe(path22, options || {}, function(er, is) {
|
|
67608
67691
|
if (er) {
|
|
67609
67692
|
reject(er);
|
|
67610
67693
|
} else {
|
|
@@ -67613,7 +67696,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67613
67696
|
});
|
|
67614
67697
|
});
|
|
67615
67698
|
}
|
|
67616
|
-
core2(
|
|
67699
|
+
core2(path22, options || {}, function(er, is) {
|
|
67617
67700
|
if (er) {
|
|
67618
67701
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
67619
67702
|
er = null;
|
|
@@ -67623,9 +67706,9 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67623
67706
|
cb(er, is);
|
|
67624
67707
|
});
|
|
67625
67708
|
}
|
|
67626
|
-
function sync(
|
|
67709
|
+
function sync(path22, options) {
|
|
67627
67710
|
try {
|
|
67628
|
-
return core2.sync(
|
|
67711
|
+
return core2.sync(path22, options || {});
|
|
67629
67712
|
} catch (er) {
|
|
67630
67713
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
67631
67714
|
return false;
|
|
@@ -67639,7 +67722,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
67639
67722
|
// node_modules/.bun/which@2.0.2/node_modules/which/which.js
|
|
67640
67723
|
var require_which = __commonJS((exports, module) => {
|
|
67641
67724
|
var isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
67642
|
-
var
|
|
67725
|
+
var path22 = __require("path");
|
|
67643
67726
|
var COLON = isWindows2 ? ";" : ":";
|
|
67644
67727
|
var isexe = require_isexe();
|
|
67645
67728
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -67675,7 +67758,7 @@ var require_which = __commonJS((exports, module) => {
|
|
|
67675
67758
|
return opt.all && found.length ? resolve25(found) : reject(getNotFoundError(cmd));
|
|
67676
67759
|
const ppRaw = pathEnv[i2];
|
|
67677
67760
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
67678
|
-
const pCmd =
|
|
67761
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
67679
67762
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
67680
67763
|
resolve25(subStep(p, i2, 0));
|
|
67681
67764
|
});
|
|
@@ -67702,7 +67785,7 @@ var require_which = __commonJS((exports, module) => {
|
|
|
67702
67785
|
for (let i2 = 0;i2 < pathEnv.length; i2++) {
|
|
67703
67786
|
const ppRaw = pathEnv[i2];
|
|
67704
67787
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
67705
|
-
const pCmd =
|
|
67788
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
67706
67789
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
67707
67790
|
for (let j = 0;j < pathExt.length; j++) {
|
|
67708
67791
|
const cur = p + pathExt[j];
|
|
@@ -67743,7 +67826,7 @@ var require_path_key = __commonJS((exports, module) => {
|
|
|
67743
67826
|
|
|
67744
67827
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
67745
67828
|
var require_resolveCommand = __commonJS((exports, module) => {
|
|
67746
|
-
var
|
|
67829
|
+
var path22 = __require("path");
|
|
67747
67830
|
var which = require_which();
|
|
67748
67831
|
var getPathKey = require_path_key();
|
|
67749
67832
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -67760,7 +67843,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
|
|
|
67760
67843
|
try {
|
|
67761
67844
|
resolved = which.sync(parsed.command, {
|
|
67762
67845
|
path: env[getPathKey({ env })],
|
|
67763
|
-
pathExt: withoutPathExt ?
|
|
67846
|
+
pathExt: withoutPathExt ? path22.delimiter : undefined
|
|
67764
67847
|
});
|
|
67765
67848
|
} catch (e) {} finally {
|
|
67766
67849
|
if (shouldSwitchCwd) {
|
|
@@ -67768,7 +67851,7 @@ var require_resolveCommand = __commonJS((exports, module) => {
|
|
|
67768
67851
|
}
|
|
67769
67852
|
}
|
|
67770
67853
|
if (resolved) {
|
|
67771
|
-
resolved =
|
|
67854
|
+
resolved = path22.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
67772
67855
|
}
|
|
67773
67856
|
return resolved;
|
|
67774
67857
|
}
|
|
@@ -67813,8 +67896,8 @@ var require_shebang_command = __commonJS((exports, module) => {
|
|
|
67813
67896
|
if (!match) {
|
|
67814
67897
|
return null;
|
|
67815
67898
|
}
|
|
67816
|
-
const [
|
|
67817
|
-
const binary2 =
|
|
67899
|
+
const [path22, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
67900
|
+
const binary2 = path22.split("/").pop();
|
|
67818
67901
|
if (binary2 === "env") {
|
|
67819
67902
|
return argument;
|
|
67820
67903
|
}
|
|
@@ -67824,16 +67907,16 @@ var require_shebang_command = __commonJS((exports, module) => {
|
|
|
67824
67907
|
|
|
67825
67908
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
|
|
67826
67909
|
var require_readShebang = __commonJS((exports, module) => {
|
|
67827
|
-
var
|
|
67910
|
+
var fs23 = __require("fs");
|
|
67828
67911
|
var shebangCommand = require_shebang_command();
|
|
67829
67912
|
function readShebang(command) {
|
|
67830
67913
|
const size = 150;
|
|
67831
67914
|
const buffer2 = Buffer.alloc(size);
|
|
67832
67915
|
let fd;
|
|
67833
67916
|
try {
|
|
67834
|
-
fd =
|
|
67835
|
-
|
|
67836
|
-
|
|
67917
|
+
fd = fs23.openSync(command, "r");
|
|
67918
|
+
fs23.readSync(fd, buffer2, 0, size, 0);
|
|
67919
|
+
fs23.closeSync(fd);
|
|
67837
67920
|
} catch (e) {}
|
|
67838
67921
|
return shebangCommand(buffer2.toString());
|
|
67839
67922
|
}
|
|
@@ -67842,7 +67925,7 @@ var require_readShebang = __commonJS((exports, module) => {
|
|
|
67842
67925
|
|
|
67843
67926
|
// node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
|
|
67844
67927
|
var require_parse2 = __commonJS((exports, module) => {
|
|
67845
|
-
var
|
|
67928
|
+
var path22 = __require("path");
|
|
67846
67929
|
var resolveCommand2 = require_resolveCommand();
|
|
67847
67930
|
var escape2 = require_escape();
|
|
67848
67931
|
var readShebang = require_readShebang();
|
|
@@ -67867,7 +67950,7 @@ var require_parse2 = __commonJS((exports, module) => {
|
|
|
67867
67950
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
67868
67951
|
if (parsed.options.forceShell || needsShell) {
|
|
67869
67952
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
67870
|
-
parsed.command =
|
|
67953
|
+
parsed.command = path22.normalize(parsed.command);
|
|
67871
67954
|
parsed.command = escape2.command(parsed.command);
|
|
67872
67955
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
67873
67956
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -68574,6 +68657,10 @@ function registerAgentName(name) {
|
|
|
68574
68657
|
}
|
|
68575
68658
|
}
|
|
68576
68659
|
}
|
|
68660
|
+
function clearRegisteredAgentNames() {
|
|
68661
|
+
registeredAgentNames.clear();
|
|
68662
|
+
registeredAgentAliases.clear();
|
|
68663
|
+
}
|
|
68577
68664
|
function isAgentRegistered(name) {
|
|
68578
68665
|
return registeredAgentNames.has(normalizeRegisteredAgentName(name));
|
|
68579
68666
|
}
|
|
@@ -72094,9 +72181,18 @@ function debugLog2(...args) {
|
|
|
72094
72181
|
function getBinaryName2() {
|
|
72095
72182
|
return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
|
|
72096
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
|
+
}
|
|
72097
72192
|
function findCommentCheckerPathSync() {
|
|
72193
|
+
const binaryName = getBinaryName2();
|
|
72098
72194
|
const resolvedPath = resolveCommentCheckerBinary({
|
|
72099
|
-
binaryName
|
|
72195
|
+
binaryName,
|
|
72100
72196
|
cachedBinaryPath: getCachedBinaryPath2(),
|
|
72101
72197
|
existsSync: existsSync35,
|
|
72102
72198
|
importMetaUrl: import.meta.url
|
|
@@ -72105,6 +72201,11 @@ function findCommentCheckerPathSync() {
|
|
|
72105
72201
|
debugLog2("resolved binary path:", resolvedPath);
|
|
72106
72202
|
return resolvedPath;
|
|
72107
72203
|
}
|
|
72204
|
+
const pathBinary = resolveCommentCheckerPathFromPath(binaryName);
|
|
72205
|
+
if (pathBinary !== null && existsSync35(pathBinary)) {
|
|
72206
|
+
debugLog2("resolved PATH binary:", pathBinary);
|
|
72207
|
+
return pathBinary;
|
|
72208
|
+
}
|
|
72108
72209
|
debugLog2("no binary found in known locations");
|
|
72109
72210
|
return null;
|
|
72110
72211
|
}
|
|
@@ -76432,9 +76533,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
76432
76533
|
`);
|
|
76433
76534
|
const cacheEntry = transcriptCache.get(sessionId);
|
|
76434
76535
|
if (cacheEntry) {
|
|
76435
|
-
cacheEntry.baseEntries = allEntries;
|
|
76436
76536
|
cacheEntry.tempPath = tempPath;
|
|
76437
|
-
cacheEntry.createdAt = Date.now();
|
|
76438
76537
|
}
|
|
76439
76538
|
return tempPath;
|
|
76440
76539
|
} catch (error) {
|
|
@@ -85356,6 +85455,9 @@ function suppressComboStandalones(detected) {
|
|
|
85356
85455
|
return detected;
|
|
85357
85456
|
return detected.filter((k) => k.type !== "ultrawork" && k.type !== "hyperplan");
|
|
85358
85457
|
}
|
|
85458
|
+
function filterAlreadyInjectedKeywords(detected, text) {
|
|
85459
|
+
return detected.filter((keyword) => !text.includes(keyword.message));
|
|
85460
|
+
}
|
|
85359
85461
|
function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultMode) {
|
|
85360
85462
|
const disabledKeywords = config?.disabled_keywords;
|
|
85361
85463
|
const enabledExpansions = config?.enabled_expansions;
|
|
@@ -85433,6 +85535,11 @@ function createKeywordDetectorHook(ctx, _collector, _ralphLoop, config, defaultM
|
|
|
85433
85535
|
return;
|
|
85434
85536
|
}
|
|
85435
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
|
+
}
|
|
85436
85543
|
const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork");
|
|
85437
85544
|
if (hasUltrawork) {
|
|
85438
85545
|
const runtimeVariant = getRuntimeVariant(input, output.message);
|
|
@@ -87607,9 +87714,10 @@ function collectAssistantText(message) {
|
|
|
87607
87714
|
if (!Array.isArray(message.parts)) {
|
|
87608
87715
|
return "";
|
|
87609
87716
|
}
|
|
87717
|
+
const allowTextParts = message.info?.role === "assistant";
|
|
87610
87718
|
let text = "";
|
|
87611
87719
|
for (const part of message.parts) {
|
|
87612
|
-
if (part.type !== "
|
|
87720
|
+
if (part.type !== "tool_result" && !(allowTextParts && part.type === "text")) {
|
|
87613
87721
|
continue;
|
|
87614
87722
|
}
|
|
87615
87723
|
text += `${text ? `
|
|
@@ -87628,9 +87736,6 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
|
|
|
87628
87736
|
const messageArray = Array.isArray(messagesResponse) ? messagesResponse : Array.isArray(responseData) ? responseData : [];
|
|
87629
87737
|
for (let index = messageArray.length - 1;index >= 0; index -= 1) {
|
|
87630
87738
|
const message = messageArray[index];
|
|
87631
|
-
if (message.info?.role !== "assistant") {
|
|
87632
|
-
continue;
|
|
87633
|
-
}
|
|
87634
87739
|
const assistantText = collectAssistantText(message);
|
|
87635
87740
|
if (!isOracleVerified(assistantText)) {
|
|
87636
87741
|
continue;
|
|
@@ -87649,6 +87754,30 @@ async function detectOracleVerificationFromParentSession(ctx, parentSessionID, d
|
|
|
87649
87754
|
return;
|
|
87650
87755
|
}
|
|
87651
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
|
+
}
|
|
87652
87781
|
async function handlePendingVerification(ctx, input) {
|
|
87653
87782
|
const {
|
|
87654
87783
|
sessionID,
|
|
@@ -87664,6 +87793,15 @@ async function handlePendingVerification(ctx, input) {
|
|
|
87664
87793
|
if (!verificationSessionID && state3.session_id) {
|
|
87665
87794
|
const recoveredVerificationSessionID = await detectOracleVerificationFromParentSession(ctx, state3.session_id, directory, apiTimeoutMs);
|
|
87666
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
|
+
}
|
|
87667
87805
|
const updatedState = loopState.setVerificationSessionID(state3.session_id, recoveredVerificationSessionID);
|
|
87668
87806
|
if (updatedState) {
|
|
87669
87807
|
log(`[${HOOK_NAME3}] Recovered missing verification session from parent evidence`, {
|
|
@@ -87751,8 +87889,8 @@ var USER_MESSAGE_IN_PROGRESS_WINDOW_MS = 2000;
|
|
|
87751
87889
|
function sleep(ms) {
|
|
87752
87890
|
return ms > 0 ? new Promise((resolve14) => setTimeout(resolve14, ms)) : Promise.resolve();
|
|
87753
87891
|
}
|
|
87754
|
-
function
|
|
87755
|
-
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;
|
|
87756
87894
|
}
|
|
87757
87895
|
function getRuntimeRetryActivitySessionID(eventType, props) {
|
|
87758
87896
|
if (eventType === "message.updated") {
|
|
@@ -87935,8 +88073,8 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
87935
88073
|
if (!state3 || !state3.active) {
|
|
87936
88074
|
return;
|
|
87937
88075
|
}
|
|
87938
|
-
if (
|
|
87939
|
-
log(`[${HOOK_NAME3}] Skipped: background tasks
|
|
88076
|
+
if (hasActiveBackgroundTasks(options.backgroundManager, sessionID)) {
|
|
88077
|
+
log(`[${HOOK_NAME3}] Skipped: background tasks active`, { sessionID });
|
|
87940
88078
|
return;
|
|
87941
88079
|
}
|
|
87942
88080
|
const verificationSessionID = state3.verification_pending ? state3.verification_session_id : undefined;
|
|
@@ -88170,8 +88308,8 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
88170
88308
|
handleErroredLoopSession(props, options.loopState);
|
|
88171
88309
|
return;
|
|
88172
88310
|
}
|
|
88173
|
-
if (
|
|
88174
|
-
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 });
|
|
88175
88313
|
return;
|
|
88176
88314
|
}
|
|
88177
88315
|
log(`[${HOOK_NAME3}] Retrying after runtime session error`, {
|
|
@@ -92667,9 +92805,55 @@ async function discoverConfigSourceSkills(options) {
|
|
|
92667
92805
|
}));
|
|
92668
92806
|
return deduplicateSkillsByName(loadedBySource.flat());
|
|
92669
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
|
+
}
|
|
92670
92854
|
// src/tools/slashcommand/command-discovery.ts
|
|
92671
|
-
import { existsSync as
|
|
92672
|
-
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";
|
|
92673
92857
|
|
|
92674
92858
|
// src/tools/slashcommand/command-discovery-deps.ts
|
|
92675
92859
|
init_excluded_dirs();
|
|
@@ -94212,7 +94396,7 @@ function loadBuiltinCommands(disabledCommands, options) {
|
|
|
94212
94396
|
// src/tools/slashcommand/command-discovery.ts
|
|
94213
94397
|
var NESTED_COMMAND_SEPARATOR = "/";
|
|
94214
94398
|
function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
|
|
94215
|
-
if (!
|
|
94399
|
+
if (!existsSync64(commandsDir))
|
|
94216
94400
|
return [];
|
|
94217
94401
|
if (!statSync9(commandsDir).isDirectory()) {
|
|
94218
94402
|
log(`[command-discovery] Skipping non-directory path: ${commandsDir}`);
|
|
@@ -94227,16 +94411,16 @@ function discoverCommandsFromDir(commandsDir, scope, prefix = "") {
|
|
|
94227
94411
|
if (entry.name.startsWith("."))
|
|
94228
94412
|
continue;
|
|
94229
94413
|
const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` : entry.name;
|
|
94230
|
-
commands2.push(...discoverCommandsFromDir(
|
|
94414
|
+
commands2.push(...discoverCommandsFromDir(join76(commandsDir, entry.name), scope, nestedPrefix));
|
|
94231
94415
|
continue;
|
|
94232
94416
|
}
|
|
94233
94417
|
if (!isMarkdownFile(entry))
|
|
94234
94418
|
continue;
|
|
94235
|
-
const commandPath =
|
|
94419
|
+
const commandPath = join76(commandsDir, entry.name);
|
|
94236
94420
|
const baseCommandName = basename9(entry.name, ".md");
|
|
94237
94421
|
const commandName = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` : baseCommandName;
|
|
94238
94422
|
try {
|
|
94239
|
-
const content =
|
|
94423
|
+
const content = readFileSync47(commandPath, "utf-8");
|
|
94240
94424
|
const { data, body } = parseFrontmatter(content);
|
|
94241
94425
|
const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
|
|
94242
94426
|
const metadata = {
|
|
@@ -94288,8 +94472,8 @@ function deduplicateCommandInfosByName(commands2) {
|
|
|
94288
94472
|
return deduplicatedCommands;
|
|
94289
94473
|
}
|
|
94290
94474
|
function discoverCommandsSync(directory, options) {
|
|
94291
|
-
const userCommandsDir =
|
|
94292
|
-
const projectCommandsDir =
|
|
94475
|
+
const userCommandsDir = join76(getClaudeConfigDir(), "commands");
|
|
94476
|
+
const projectCommandsDir = join76(directory ?? process.cwd(), ".claude", "commands");
|
|
94293
94477
|
const opencodeGlobalDirs = getOpenCodeCommandDirs({ binary: "opencode" });
|
|
94294
94478
|
const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd());
|
|
94295
94479
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
@@ -94789,7 +94973,7 @@ var NOTEPAD_DIR = "notepads";
|
|
|
94789
94973
|
var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
|
|
94790
94974
|
var PROMETHEUS_PLANS_DIR = ".omo/plans";
|
|
94791
94975
|
// packages/boulder-state/src/top-level-task.ts
|
|
94792
|
-
import { existsSync as
|
|
94976
|
+
import { existsSync as existsSync65, readFileSync as readFileSync48 } from "fs";
|
|
94793
94977
|
var TODO_HEADING_PATTERN = /^##\s+TODOs\b/i;
|
|
94794
94978
|
var FINAL_VERIFICATION_HEADING_PATTERN = /^##\s+Final Verification Wave\b/i;
|
|
94795
94979
|
var SECOND_LEVEL_HEADING_PATTERN = /^##\s+/;
|
|
@@ -94812,11 +94996,11 @@ function buildTaskRef(section, taskLabel) {
|
|
|
94812
94996
|
};
|
|
94813
94997
|
}
|
|
94814
94998
|
function readCurrentTopLevelTask(planPath) {
|
|
94815
|
-
if (!
|
|
94999
|
+
if (!existsSync65(planPath)) {
|
|
94816
95000
|
return null;
|
|
94817
95001
|
}
|
|
94818
95002
|
try {
|
|
94819
|
-
const content =
|
|
95003
|
+
const content = readFileSync48(planPath, "utf-8");
|
|
94820
95004
|
const lines = content.split(/\r?\n/);
|
|
94821
95005
|
let section = "other";
|
|
94822
95006
|
for (const line of lines) {
|
|
@@ -94841,10 +95025,10 @@ function readCurrentTopLevelTask(planPath) {
|
|
|
94841
95025
|
}
|
|
94842
95026
|
}
|
|
94843
95027
|
// packages/boulder-state/src/storage/path.ts
|
|
94844
|
-
import { existsSync as
|
|
94845
|
-
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";
|
|
94846
95030
|
function getBoulderFilePath(directory) {
|
|
94847
|
-
return
|
|
95031
|
+
return join77(directory, BOULDER_DIR, BOULDER_FILE);
|
|
94848
95032
|
}
|
|
94849
95033
|
function resolveTrackedPath(baseDirectory, trackedPath) {
|
|
94850
95034
|
return isAbsolute13(trackedPath) ? resolve15(trackedPath) : resolve15(baseDirectory, trackedPath);
|
|
@@ -94862,14 +95046,14 @@ function resolveBoulderPlanPath(directory, state3) {
|
|
|
94862
95046
|
}
|
|
94863
95047
|
const absoluteWorktreePath = resolveTrackedPath(directory, worktreePath);
|
|
94864
95048
|
const worktreePlanPath = resolve15(absoluteWorktreePath, relativePlanPath);
|
|
94865
|
-
return
|
|
95049
|
+
return existsSync66(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
|
|
94866
95050
|
}
|
|
94867
95051
|
function resolveBoulderPlanPathForWork(directory, work) {
|
|
94868
95052
|
return resolveBoulderPlanPath(directory, work);
|
|
94869
95053
|
}
|
|
94870
95054
|
// packages/boulder-state/src/storage/plan-progress.ts
|
|
94871
|
-
import { existsSync as
|
|
94872
|
-
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";
|
|
94873
95057
|
var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
|
|
94874
95058
|
var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
|
|
94875
95059
|
var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
|
|
@@ -94882,11 +95066,11 @@ var PROMETHEUS_PLAN_DIRS = [PROMETHEUS_PLANS_DIR, LEGACY_PROMETHEUS_PLANS_DIR];
|
|
|
94882
95066
|
function findPrometheusPlans(directory) {
|
|
94883
95067
|
try {
|
|
94884
95068
|
return PROMETHEUS_PLAN_DIRS.flatMap((planDir) => {
|
|
94885
|
-
const plansDir =
|
|
94886
|
-
if (!
|
|
95069
|
+
const plansDir = join78(directory, planDir);
|
|
95070
|
+
if (!existsSync67(plansDir)) {
|
|
94887
95071
|
return [];
|
|
94888
95072
|
}
|
|
94889
|
-
return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) =>
|
|
95073
|
+
return readdirSync20(plansDir).filter((file) => file.endsWith(".md")).map((file) => join78(plansDir, file));
|
|
94890
95074
|
}).sort((left, right) => statSync10(right).mtimeMs - statSync10(left).mtimeMs);
|
|
94891
95075
|
} catch {
|
|
94892
95076
|
return [];
|
|
@@ -94896,11 +95080,11 @@ function getPlanName(planPath) {
|
|
|
94896
95080
|
return basename10(planPath, ".md");
|
|
94897
95081
|
}
|
|
94898
95082
|
function getPlanProgress(planPath) {
|
|
94899
|
-
if (!
|
|
95083
|
+
if (!existsSync67(planPath)) {
|
|
94900
95084
|
return { total: 0, completed: 0, isComplete: false };
|
|
94901
95085
|
}
|
|
94902
95086
|
try {
|
|
94903
|
-
const content =
|
|
95087
|
+
const content = readFileSync49(planPath, "utf-8");
|
|
94904
95088
|
const lines = content.split(/\r?\n/);
|
|
94905
95089
|
const hasStructuredSections = lines.some((line) => TODO_HEADING_PATTERN2.test(line) || FINAL_VERIFICATION_HEADING_PATTERN2.test(line));
|
|
94906
95090
|
if (hasStructuredSections) {
|
|
@@ -95030,14 +95214,14 @@ function selectMirrorWork(state3) {
|
|
|
95030
95214
|
return sorted[0] ?? null;
|
|
95031
95215
|
}
|
|
95032
95216
|
// packages/boulder-state/src/storage/read-state.ts
|
|
95033
|
-
import { existsSync as
|
|
95217
|
+
import { existsSync as existsSync68, readFileSync as readFileSync50 } from "fs";
|
|
95034
95218
|
function readBoulderState(directory) {
|
|
95035
95219
|
const filePath = getBoulderFilePath(directory);
|
|
95036
|
-
if (!
|
|
95220
|
+
if (!existsSync68(filePath)) {
|
|
95037
95221
|
return null;
|
|
95038
95222
|
}
|
|
95039
95223
|
try {
|
|
95040
|
-
const content =
|
|
95224
|
+
const content = readFileSync50(filePath, "utf-8");
|
|
95041
95225
|
const parsed = JSON.parse(content);
|
|
95042
95226
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
95043
95227
|
return null;
|
|
@@ -95168,13 +95352,13 @@ function getTaskSessionState(directory, taskKey) {
|
|
|
95168
95352
|
return state3.task_sessions[taskKey] ?? null;
|
|
95169
95353
|
}
|
|
95170
95354
|
// packages/boulder-state/src/storage/write-state.ts
|
|
95171
|
-
import { existsSync as
|
|
95355
|
+
import { existsSync as existsSync69, mkdirSync as mkdirSync17, unlinkSync as unlinkSync13, writeFileSync as writeFileSync18 } from "fs";
|
|
95172
95356
|
import { dirname as dirname25 } from "path";
|
|
95173
95357
|
function writeBoulderState(directory, state3) {
|
|
95174
95358
|
const filePath = getBoulderFilePath(directory);
|
|
95175
95359
|
try {
|
|
95176
95360
|
const dir = dirname25(filePath);
|
|
95177
|
-
if (!
|
|
95361
|
+
if (!existsSync69(dir)) {
|
|
95178
95362
|
mkdirSync17(dir, { recursive: true });
|
|
95179
95363
|
}
|
|
95180
95364
|
const stateToWrite = { ...state3 };
|
|
@@ -95210,7 +95394,7 @@ function writeBoulderState(directory, state3) {
|
|
|
95210
95394
|
function clearBoulderState(directory) {
|
|
95211
95395
|
const filePath = getBoulderFilePath(directory);
|
|
95212
95396
|
try {
|
|
95213
|
-
if (
|
|
95397
|
+
if (existsSync69(filePath)) {
|
|
95214
95398
|
unlinkSync13(filePath);
|
|
95215
95399
|
}
|
|
95216
95400
|
return true;
|
|
@@ -95915,6 +96099,23 @@ function buildExplicitPlanContext(params) {
|
|
|
95915
96099
|
const allPlans = findPrometheusPlans(directory);
|
|
95916
96100
|
const matchedPlan = findPlanByName(allPlans, explicitPlanName);
|
|
95917
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
|
+
}
|
|
95918
96119
|
return buildMissingPlanContext(explicitPlanName, allPlans);
|
|
95919
96120
|
}
|
|
95920
96121
|
const progress = getPlanProgress(matchedPlan);
|
|
@@ -96321,8 +96522,8 @@ function isAbortError2(error) {
|
|
|
96321
96522
|
// src/hooks/atlas/session-last-agent.ts
|
|
96322
96523
|
init_shared();
|
|
96323
96524
|
init_compaction_marker();
|
|
96324
|
-
import { readFileSync as
|
|
96325
|
-
import { join as
|
|
96525
|
+
import { readFileSync as readFileSync51, readdirSync as readdirSync21 } from "fs";
|
|
96526
|
+
import { join as join79 } from "path";
|
|
96326
96527
|
var defaultSessionLastAgentDeps = {
|
|
96327
96528
|
getMessageDir,
|
|
96328
96529
|
isSqliteBackend,
|
|
@@ -96376,7 +96577,7 @@ async function getLastAgentFromSession(sessionID, client, deps = {}) {
|
|
|
96376
96577
|
try {
|
|
96377
96578
|
const messages = readdirSync21(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
|
|
96378
96579
|
try {
|
|
96379
|
-
const content =
|
|
96580
|
+
const content = readFileSync51(join79(messageDir, fileName), "utf-8");
|
|
96380
96581
|
const parsed = JSON.parse(content);
|
|
96381
96582
|
return {
|
|
96382
96583
|
fileName,
|
|
@@ -96896,7 +97097,7 @@ function getTaskLabelSortValue(taskLabel) {
|
|
|
96896
97097
|
const parsed = Number.parseInt(taskLabel.replace(/[^0-9]/g, ""), 10);
|
|
96897
97098
|
return Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed;
|
|
96898
97099
|
}
|
|
96899
|
-
function
|
|
97100
|
+
function hasRunningBackgroundTasks(sessionID, options) {
|
|
96900
97101
|
const backgroundManager = options?.backgroundManager;
|
|
96901
97102
|
return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
|
|
96902
97103
|
}
|
|
@@ -97025,7 +97226,7 @@ function scheduleRetry(input) {
|
|
|
97025
97226
|
});
|
|
97026
97227
|
if (!canContinueSession)
|
|
97027
97228
|
return;
|
|
97028
|
-
if (
|
|
97229
|
+
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
97029
97230
|
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
97030
97231
|
return;
|
|
97031
97232
|
}
|
|
@@ -97211,7 +97412,7 @@ async function handleAtlasSessionIdle(input) {
|
|
|
97211
97412
|
sessionState.promptFailureCount = 0;
|
|
97212
97413
|
sessionState.lastFailureAt = undefined;
|
|
97213
97414
|
}
|
|
97214
|
-
if (
|
|
97415
|
+
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
97215
97416
|
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
97216
97417
|
log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
|
|
97217
97418
|
return;
|
|
@@ -97371,7 +97572,7 @@ function createAtlasEventHandler(input) {
|
|
|
97371
97572
|
// src/hooks/atlas/tool-execute-after.ts
|
|
97372
97573
|
init_logger();
|
|
97373
97574
|
init_session_utils();
|
|
97374
|
-
import { existsSync as
|
|
97575
|
+
import { existsSync as existsSync71, readFileSync as readFileSync53 } from "fs";
|
|
97375
97576
|
import { resolve as resolve18 } from "path";
|
|
97376
97577
|
|
|
97377
97578
|
// src/hooks/atlas/background-launch-session-tracking.ts
|
|
@@ -97519,7 +97720,7 @@ async function resolveFallbackTrackedSessionId(input) {
|
|
|
97519
97720
|
init_git_worktree();
|
|
97520
97721
|
|
|
97521
97722
|
// src/hooks/atlas/final-wave-plan-state.ts
|
|
97522
|
-
import { existsSync as
|
|
97723
|
+
import { existsSync as existsSync70, readFileSync as readFileSync52 } from "fs";
|
|
97523
97724
|
var TODO_HEADING_PATTERN3 = /^##\s+TODOs\b/i;
|
|
97524
97725
|
var FINAL_VERIFICATION_HEADING_PATTERN3 = /^##\s+Final Verification Wave\b/i;
|
|
97525
97726
|
var SECOND_LEVEL_HEADING_PATTERN3 = /^##\s+/;
|
|
@@ -97527,11 +97728,11 @@ var UNCHECKED_CHECKBOX_PATTERN3 = /^\s*[-*]\s*\[\s*\]\s*(.+)$/;
|
|
|
97527
97728
|
var TODO_TASK_PATTERN3 = /^\d+\./;
|
|
97528
97729
|
var FINAL_WAVE_TASK_PATTERN3 = /^F\d+\./i;
|
|
97529
97730
|
function readFinalWavePlanState(planPath) {
|
|
97530
|
-
if (!
|
|
97731
|
+
if (!existsSync70(planPath)) {
|
|
97531
97732
|
return null;
|
|
97532
97733
|
}
|
|
97533
97734
|
try {
|
|
97534
|
-
const content =
|
|
97735
|
+
const content = readFileSync52(planPath, "utf-8");
|
|
97535
97736
|
const lines = content.split(/\r?\n/);
|
|
97536
97737
|
let section = "other";
|
|
97537
97738
|
let pendingImplementationTaskCount = 0;
|
|
@@ -97781,7 +97982,7 @@ function isWriteOrEditToolName(toolName) {
|
|
|
97781
97982
|
|
|
97782
97983
|
// src/hooks/atlas/tool-execute-after.ts
|
|
97783
97984
|
function isTrackedTaskChecked(planPath, taskKey) {
|
|
97784
|
-
if (!
|
|
97985
|
+
if (!existsSync71(planPath)) {
|
|
97785
97986
|
return false;
|
|
97786
97987
|
}
|
|
97787
97988
|
const [section, label] = taskKey.split(":");
|
|
@@ -97794,7 +97995,7 @@ function isTrackedTaskChecked(planPath, taskKey) {
|
|
|
97794
97995
|
return false;
|
|
97795
97996
|
}
|
|
97796
97997
|
try {
|
|
97797
|
-
const content =
|
|
97998
|
+
const content = readFileSync53(planPath, "utf-8");
|
|
97798
97999
|
return matcher.test(content);
|
|
97799
98000
|
} catch {
|
|
97800
98001
|
return false;
|
|
@@ -97838,11 +98039,11 @@ function parseCheckedTopLevelTaskKeys(planContent) {
|
|
|
97838
98039
|
return checkedKeys;
|
|
97839
98040
|
}
|
|
97840
98041
|
function readCheckedTaskKeysFromPlan(planPath) {
|
|
97841
|
-
if (!
|
|
98042
|
+
if (!existsSync71(planPath)) {
|
|
97842
98043
|
return new Set;
|
|
97843
98044
|
}
|
|
97844
98045
|
try {
|
|
97845
|
-
return parseCheckedTopLevelTaskKeys(
|
|
98046
|
+
return parseCheckedTopLevelTaskKeys(readFileSync53(planPath, "utf-8"));
|
|
97846
98047
|
} catch {
|
|
97847
98048
|
return new Set;
|
|
97848
98049
|
}
|
|
@@ -98049,7 +98250,7 @@ init_logger();
|
|
|
98049
98250
|
init_replace_tool_args();
|
|
98050
98251
|
init_system_directive();
|
|
98051
98252
|
init_session_utils();
|
|
98052
|
-
import { existsSync as
|
|
98253
|
+
import { existsSync as existsSync72, readFileSync as readFileSync54 } from "fs";
|
|
98053
98254
|
import { resolve as resolve19 } from "path";
|
|
98054
98255
|
var TASK_SECTION_HEADER_PATTERN = /^##\s*1\.\s*TASK\s*$/i;
|
|
98055
98256
|
var TODO_TASK_LINE_PATTERN = /^(?:[-*]\s*\[\s*\]\s*)?(\d+)\.\s+(.+)$/;
|
|
@@ -98110,8 +98311,8 @@ function createToolExecuteBeforeHandler2(input) {
|
|
|
98110
98311
|
const planPath = sessionWork ? resolveBoulderPlanPathForWork(ctx.directory, sessionWork) : state3 ? resolveBoulderPlanPath(ctx.directory, state3) : null;
|
|
98111
98312
|
if (planPath && resolve19(filePath) === resolve19(planPath) && pendingPlanSnapshots) {
|
|
98112
98313
|
try {
|
|
98113
|
-
if (
|
|
98114
|
-
pendingPlanSnapshots.set(toolInput.callID,
|
|
98314
|
+
if (existsSync72(planPath)) {
|
|
98315
|
+
pendingPlanSnapshots.set(toolInput.callID, readFileSync54(planPath, "utf-8"));
|
|
98115
98316
|
}
|
|
98116
98317
|
} catch {
|
|
98117
98318
|
pendingPlanSnapshots.delete(toolInput.callID);
|
|
@@ -99971,16 +100172,16 @@ function createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState) {
|
|
|
99971
100172
|
init_shared();
|
|
99972
100173
|
|
|
99973
100174
|
// src/hooks/tasks-todowrite-disabler/constants.ts
|
|
99974
|
-
var BLOCKED_TOOLS2 = ["
|
|
99975
|
-
var REPLACEMENT_MESSAGE = `TodoRead
|
|
100175
|
+
var BLOCKED_TOOLS2 = ["TodoRead"];
|
|
100176
|
+
var REPLACEMENT_MESSAGE = `TodoRead is DISABLED because experimental.task_system is enabled.
|
|
99976
100177
|
|
|
99977
|
-
**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.
|
|
99978
100179
|
|
|
99979
|
-
**Use these tools instead:**
|
|
99980
|
-
- TaskCreate: Create new task with auto-generated ID
|
|
99981
|
-
- TaskUpdate: Update status, assign owner, add dependencies
|
|
100180
|
+
**Use these tools instead of TodoRead:**
|
|
99982
100181
|
- TaskList: List active tasks with dependency info
|
|
99983
100182
|
- TaskGet: Get full task details
|
|
100183
|
+
- TaskCreate: Create new task with auto-generated ID
|
|
100184
|
+
- TaskUpdate: Update status, assign owner, add dependencies
|
|
99984
100185
|
|
|
99985
100186
|
**Workflow:**
|
|
99986
100187
|
1. TaskCreate({ subject: "your task description" })
|
|
@@ -99999,7 +100200,7 @@ Even if the task seems trivial (1 line fix, simple edit, quick change), you MUST
|
|
|
99999
100200
|
|
|
100000
100201
|
**WHY?** Task tracking = visibility = accountability. Skipping registration = invisible work = chaos.
|
|
100001
100202
|
|
|
100002
|
-
DO NOT retry
|
|
100203
|
+
DO NOT retry TodoRead. Use TaskList or TaskGet NOW.`;
|
|
100003
100204
|
|
|
100004
100205
|
// src/hooks/tasks-todowrite-disabler/hook.ts
|
|
100005
100206
|
function createTasksTodowriteDisablerHook(config) {
|
|
@@ -100445,6 +100646,7 @@ function getLastUserRetryPayload(messagesResponse, sessionID) {
|
|
|
100445
100646
|
}
|
|
100446
100647
|
|
|
100447
100648
|
// src/hooks/runtime-fallback/auto-retry.ts
|
|
100649
|
+
init_internal_initiator_marker();
|
|
100448
100650
|
var SESSION_TTL_MS = 30 * 60 * 1000;
|
|
100449
100651
|
function createAutoRetryHelpers(deps) {
|
|
100450
100652
|
const {
|
|
@@ -100557,7 +100759,7 @@ function createAutoRetryHelpers(deps) {
|
|
|
100557
100759
|
sessionID,
|
|
100558
100760
|
hint: "This can occur when the working directory contains .git and messages are not yet persisted"
|
|
100559
100761
|
});
|
|
100560
|
-
return [
|
|
100762
|
+
return [createInternalAgentContinuationTextPart("continue")];
|
|
100561
100763
|
})();
|
|
100562
100764
|
log(`[${HOOK_NAME11}] Auto-retrying with fallback model (${source})`, {
|
|
100563
100765
|
sessionID,
|
|
@@ -101851,12 +102053,12 @@ function createRuntimeFallbackHook(ctx, options, factoryOverrides = {}) {
|
|
|
101851
102053
|
};
|
|
101852
102054
|
}
|
|
101853
102055
|
// src/hooks/write-existing-file-guard/hook.ts
|
|
101854
|
-
import { existsSync as
|
|
101855
|
-
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";
|
|
101856
102058
|
|
|
101857
102059
|
// src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
|
|
101858
102060
|
init_shared();
|
|
101859
|
-
import { existsSync as
|
|
102061
|
+
import { existsSync as existsSync73 } from "fs";
|
|
101860
102062
|
|
|
101861
102063
|
// src/hooks/write-existing-file-guard/session-read-permissions.ts
|
|
101862
102064
|
function touchSession(sessionLastAccess, sessionID) {
|
|
@@ -101957,7 +102159,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
101957
102159
|
return;
|
|
101958
102160
|
}
|
|
101959
102161
|
if (toolName === "read") {
|
|
101960
|
-
if (!
|
|
102162
|
+
if (!existsSync73(resolvedPath) || !input.sessionID) {
|
|
101961
102163
|
return;
|
|
101962
102164
|
}
|
|
101963
102165
|
registerReadPermission({
|
|
@@ -101974,7 +102176,7 @@ async function handleWriteExistingFileGuardToolExecuteBefore(params) {
|
|
|
101974
102176
|
if (argsRecord && "overwrite" in argsRecord) {
|
|
101975
102177
|
delete argsRecord.overwrite;
|
|
101976
102178
|
}
|
|
101977
|
-
if (!
|
|
102179
|
+
if (!existsSync73(resolvedPath)) {
|
|
101978
102180
|
return;
|
|
101979
102181
|
}
|
|
101980
102182
|
if (isOmoWorkspacePath(canonicalPath)) {
|
|
@@ -102033,7 +102235,7 @@ function isPathInsideDirectory(pathToCheck, directory) {
|
|
|
102033
102235
|
}
|
|
102034
102236
|
function toCanonicalPath2(absolutePath) {
|
|
102035
102237
|
let canonicalPath = absolutePath;
|
|
102036
|
-
if (
|
|
102238
|
+
if (existsSync74(absolutePath)) {
|
|
102037
102239
|
try {
|
|
102038
102240
|
canonicalPath = realpathSync8.native(absolutePath);
|
|
102039
102241
|
} catch {
|
|
@@ -102041,8 +102243,8 @@ function toCanonicalPath2(absolutePath) {
|
|
|
102041
102243
|
}
|
|
102042
102244
|
} else {
|
|
102043
102245
|
const absoluteDir = dirname26(absolutePath);
|
|
102044
|
-
const resolvedDir =
|
|
102045
|
-
canonicalPath =
|
|
102246
|
+
const resolvedDir = existsSync74(absoluteDir) ? realpathSync8.native(absoluteDir) : absoluteDir;
|
|
102247
|
+
canonicalPath = join80(resolvedDir, basename11(absolutePath));
|
|
102046
102248
|
}
|
|
102047
102249
|
return normalize2(canonicalPath);
|
|
102048
102250
|
}
|
|
@@ -103086,16 +103288,16 @@ class Diff {
|
|
|
103086
103288
|
}
|
|
103087
103289
|
}
|
|
103088
103290
|
}
|
|
103089
|
-
addToPath(
|
|
103090
|
-
const last =
|
|
103291
|
+
addToPath(path18, added, removed, oldPosInc, options) {
|
|
103292
|
+
const last = path18.lastComponent;
|
|
103091
103293
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
103092
103294
|
return {
|
|
103093
|
-
oldPos:
|
|
103295
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
103094
103296
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
103095
103297
|
};
|
|
103096
103298
|
} else {
|
|
103097
103299
|
return {
|
|
103098
|
-
oldPos:
|
|
103300
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
103099
103301
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
103100
103302
|
};
|
|
103101
103303
|
}
|
|
@@ -104757,8 +104959,8 @@ init_jsonc_parser2();
|
|
|
104757
104959
|
init_opencode_config_dir();
|
|
104758
104960
|
init_plugin_identity();
|
|
104759
104961
|
init_plugin_entry_migrator();
|
|
104760
|
-
import { existsSync as
|
|
104761
|
-
import { join as
|
|
104962
|
+
import { existsSync as existsSync75, readFileSync as readFileSync55 } from "fs";
|
|
104963
|
+
import { join as join81 } from "path";
|
|
104762
104964
|
|
|
104763
104965
|
// src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts
|
|
104764
104966
|
init_migrate_legacy_plugin_entry();
|
|
@@ -104766,18 +104968,18 @@ init_migrate_legacy_plugin_entry();
|
|
|
104766
104968
|
// src/hooks/legacy-plugin-toast/auto-migrate.ts
|
|
104767
104969
|
function detectOpenCodeConfigPath(overrideConfigDir) {
|
|
104768
104970
|
if (overrideConfigDir) {
|
|
104769
|
-
const jsoncPath =
|
|
104770
|
-
const jsonPath =
|
|
104771
|
-
if (
|
|
104971
|
+
const jsoncPath = join81(overrideConfigDir, "opencode.jsonc");
|
|
104972
|
+
const jsonPath = join81(overrideConfigDir, "opencode.json");
|
|
104973
|
+
if (existsSync75(jsoncPath))
|
|
104772
104974
|
return jsoncPath;
|
|
104773
|
-
if (
|
|
104975
|
+
if (existsSync75(jsonPath))
|
|
104774
104976
|
return jsonPath;
|
|
104775
104977
|
return null;
|
|
104776
104978
|
}
|
|
104777
104979
|
const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
|
|
104778
|
-
if (
|
|
104980
|
+
if (existsSync75(paths.configJsonc))
|
|
104779
104981
|
return paths.configJsonc;
|
|
104780
|
-
if (
|
|
104982
|
+
if (existsSync75(paths.configJson))
|
|
104781
104983
|
return paths.configJson;
|
|
104782
104984
|
return null;
|
|
104783
104985
|
}
|
|
@@ -104786,7 +104988,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
|
|
|
104786
104988
|
if (!configPath)
|
|
104787
104989
|
return { migrated: false, from: null, to: null, configPath: null };
|
|
104788
104990
|
try {
|
|
104789
|
-
const content =
|
|
104991
|
+
const content = readFileSync55(configPath, "utf-8");
|
|
104790
104992
|
const parseResult = parseJsoncSafe(content);
|
|
104791
104993
|
if (!parseResult.data?.plugin)
|
|
104792
104994
|
return { migrated: false, from: null, to: null, configPath };
|
|
@@ -104970,7 +105172,7 @@ function createNotepadWriteGuardHook() {
|
|
|
104970
105172
|
};
|
|
104971
105173
|
}
|
|
104972
105174
|
// src/hooks/plan-format-validator/hook.ts
|
|
104973
|
-
import { existsSync as
|
|
105175
|
+
import { existsSync as existsSync76, readFileSync as readFileSync56 } from "fs";
|
|
104974
105176
|
import { resolve as resolve21 } from "path";
|
|
104975
105177
|
init_logger();
|
|
104976
105178
|
var WRITE_TOOLS = new Set(["Write", "Edit", "write", "edit"]);
|
|
@@ -105054,9 +105256,9 @@ function createPlanFormatValidatorHook(_ctx) {
|
|
|
105054
105256
|
if (!isPlanFilePath(filePath))
|
|
105055
105257
|
return;
|
|
105056
105258
|
const resolvedPath = resolve21(_ctx.directory, filePath);
|
|
105057
|
-
if (!
|
|
105259
|
+
if (!existsSync76(resolvedPath))
|
|
105058
105260
|
return;
|
|
105059
|
-
const content =
|
|
105261
|
+
const content = readFileSync56(resolvedPath, "utf-8");
|
|
105060
105262
|
if (!CHECKBOX_PATTERN.test(content))
|
|
105061
105263
|
return;
|
|
105062
105264
|
const rawCount = countRawTopLevelCheckboxes(content);
|
|
@@ -105186,21 +105388,21 @@ tool.schema = z36;
|
|
|
105186
105388
|
|
|
105187
105389
|
// src/shared/ripgrep-cli.ts
|
|
105188
105390
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
105189
|
-
import { existsSync as
|
|
105190
|
-
import { dirname as dirname27, join as
|
|
105391
|
+
import { existsSync as existsSync78 } from "fs";
|
|
105392
|
+
import { dirname as dirname27, join as join83 } from "path";
|
|
105191
105393
|
|
|
105192
105394
|
// src/tools/grep/downloader.ts
|
|
105193
105395
|
init_shared();
|
|
105194
105396
|
init_plugin_identity();
|
|
105195
105397
|
init_binary_downloader();
|
|
105196
|
-
import { existsSync as
|
|
105197
|
-
import { join as
|
|
105398
|
+
import { existsSync as existsSync77, readdirSync as readdirSync22 } from "fs";
|
|
105399
|
+
import { join as join82 } from "path";
|
|
105198
105400
|
function findFileRecursive(dir, filename) {
|
|
105199
105401
|
try {
|
|
105200
105402
|
const entries = readdirSync22(dir, { withFileTypes: true, recursive: true });
|
|
105201
105403
|
for (const entry of entries) {
|
|
105202
105404
|
if (entry.isFile() && entry.name === filename) {
|
|
105203
|
-
return
|
|
105405
|
+
return join82(entry.parentPath ?? dir, entry.name);
|
|
105204
105406
|
}
|
|
105205
105407
|
}
|
|
105206
105408
|
} catch {
|
|
@@ -105221,11 +105423,11 @@ function getPlatformKey() {
|
|
|
105221
105423
|
}
|
|
105222
105424
|
function getInstallDir() {
|
|
105223
105425
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
105224
|
-
return
|
|
105426
|
+
return join82(homeDir, ".cache", CACHE_DIR_NAME, "bin");
|
|
105225
105427
|
}
|
|
105226
105428
|
function getRgPath() {
|
|
105227
105429
|
const isWindows2 = process.platform === "win32";
|
|
105228
|
-
return
|
|
105430
|
+
return join82(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
105229
105431
|
}
|
|
105230
105432
|
async function extractTarGz2(archivePath, destDir) {
|
|
105231
105433
|
const platformKey = getPlatformKey();
|
|
@@ -105242,7 +105444,7 @@ async function extractZip2(archivePath, destDir) {
|
|
|
105242
105444
|
const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
|
|
105243
105445
|
const foundPath = findFileRecursive(destDir, binaryName);
|
|
105244
105446
|
if (foundPath) {
|
|
105245
|
-
const destPath =
|
|
105447
|
+
const destPath = join82(destDir, binaryName);
|
|
105246
105448
|
if (foundPath !== destPath) {
|
|
105247
105449
|
const { renameSync: renameSync6 } = await import("fs");
|
|
105248
105450
|
renameSync6(foundPath, destPath);
|
|
@@ -105257,13 +105459,13 @@ async function downloadAndInstallRipgrep() {
|
|
|
105257
105459
|
}
|
|
105258
105460
|
const installDir = getInstallDir();
|
|
105259
105461
|
const rgPath = getRgPath();
|
|
105260
|
-
if (
|
|
105462
|
+
if (existsSync77(rgPath)) {
|
|
105261
105463
|
return rgPath;
|
|
105262
105464
|
}
|
|
105263
105465
|
ensureCacheDir(installDir);
|
|
105264
105466
|
const filename = `ripgrep-${RG_VERSION}-${config.platform}.${config.extension}`;
|
|
105265
105467
|
const url = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
|
|
105266
|
-
const archivePath =
|
|
105468
|
+
const archivePath = join82(installDir, filename);
|
|
105267
105469
|
try {
|
|
105268
105470
|
await downloadArchive(url, archivePath);
|
|
105269
105471
|
if (config.extension === "tar.gz") {
|
|
@@ -105272,7 +105474,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
105272
105474
|
await extractZip2(archivePath, installDir);
|
|
105273
105475
|
}
|
|
105274
105476
|
ensureExecutable(rgPath);
|
|
105275
|
-
if (!
|
|
105477
|
+
if (!existsSync77(rgPath)) {
|
|
105276
105478
|
throw new Error("ripgrep binary not found after extraction");
|
|
105277
105479
|
}
|
|
105278
105480
|
return rgPath;
|
|
@@ -105284,7 +105486,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
105284
105486
|
}
|
|
105285
105487
|
function getInstalledRipgrepPath() {
|
|
105286
105488
|
const rgPath = getRgPath();
|
|
105287
|
-
return
|
|
105489
|
+
return existsSync77(rgPath) ? rgPath : null;
|
|
105288
105490
|
}
|
|
105289
105491
|
|
|
105290
105492
|
// src/shared/ripgrep-cli.ts
|
|
@@ -105320,15 +105522,15 @@ function getOpenCodeBundledRg() {
|
|
|
105320
105522
|
const isWindows2 = process.platform === "win32";
|
|
105321
105523
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
105322
105524
|
const candidates = [
|
|
105323
|
-
|
|
105324
|
-
|
|
105325
|
-
|
|
105326
|
-
|
|
105327
|
-
|
|
105328
|
-
|
|
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)
|
|
105329
105531
|
];
|
|
105330
105532
|
for (const candidate of candidates) {
|
|
105331
|
-
if (
|
|
105533
|
+
if (existsSync78(candidate)) {
|
|
105332
105534
|
return candidate;
|
|
105333
105535
|
}
|
|
105334
105536
|
}
|
|
@@ -106071,10 +106273,13 @@ function formatSlashCommand(command) {
|
|
|
106071
106273
|
return lines.join(`
|
|
106072
106274
|
`);
|
|
106073
106275
|
}
|
|
106074
|
-
function formatCombinedDescription(skills2, commands2) {
|
|
106075
|
-
const availableSkills = skills2 ?? [];
|
|
106276
|
+
function formatCombinedDescription(skills2, commands2, options = {}) {
|
|
106277
|
+
const availableSkills = options.includeSkills ? skills2 ?? [] : [];
|
|
106076
106278
|
const availableCommands = commands2 ?? [];
|
|
106077
106279
|
if (availableSkills.length === 0 && availableCommands.length === 0) {
|
|
106280
|
+
if ((skills2?.length ?? 0) > 0) {
|
|
106281
|
+
return TOOL_DESCRIPTION_PREFIX;
|
|
106282
|
+
}
|
|
106078
106283
|
return TOOL_DESCRIPTION_NO_SKILLS;
|
|
106079
106284
|
}
|
|
106080
106285
|
const availableItems = [
|
|
@@ -106086,7 +106291,7 @@ function formatCombinedDescription(skills2, commands2) {
|
|
|
106086
106291
|
}
|
|
106087
106292
|
return `${TOOL_DESCRIPTION_PREFIX}
|
|
106088
106293
|
<available_items>
|
|
106089
|
-
Priority: project > user > opencode > builtin/plugin | Skills listed before commands
|
|
106294
|
+
Priority: project > user > opencode > builtin/plugin${options.includeSkills ? " | Skills listed before commands" : ""}
|
|
106090
106295
|
Invoke via: skill(name="item-name") - omit leading slash for commands.
|
|
106091
106296
|
${availableItems.join(`
|
|
106092
106297
|
`)}
|
|
@@ -106328,7 +106533,9 @@ function createSkillTool(options) {
|
|
|
106328
106533
|
const commands2 = getCommands();
|
|
106329
106534
|
const publicSkills = skills2.filter((s) => !s.definition.agent);
|
|
106330
106535
|
const skillInfos = publicSkills.map(loadedSkillToInfo);
|
|
106331
|
-
cachedDescription = formatCombinedDescription(skillInfos, commands2
|
|
106536
|
+
cachedDescription = formatCombinedDescription(skillInfos, commands2, {
|
|
106537
|
+
includeSkills: options.includeSkillsInDescription
|
|
106538
|
+
});
|
|
106332
106539
|
return cachedDescription;
|
|
106333
106540
|
};
|
|
106334
106541
|
if (options.skills !== undefined) {
|
|
@@ -106346,12 +106553,16 @@ function createSkillTool(options) {
|
|
|
106346
106553
|
}
|
|
106347
106554
|
} catch {}
|
|
106348
106555
|
}
|
|
106349
|
-
cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription
|
|
106556
|
+
cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription, {
|
|
106557
|
+
includeSkills: options.includeSkillsInDescription
|
|
106558
|
+
});
|
|
106350
106559
|
if (needsAsyncRefresh) {
|
|
106351
106560
|
buildDescription(true);
|
|
106352
106561
|
}
|
|
106353
106562
|
} else if (options.commands !== undefined) {
|
|
106354
|
-
cachedDescription = formatCombinedDescription([], options.commands
|
|
106563
|
+
cachedDescription = formatCombinedDescription([], options.commands, {
|
|
106564
|
+
includeSkills: options.includeSkillsInDescription
|
|
106565
|
+
});
|
|
106355
106566
|
}
|
|
106356
106567
|
return tool({
|
|
106357
106568
|
get description() {
|
|
@@ -106367,7 +106578,9 @@ function createSkillTool(options) {
|
|
|
106367
106578
|
async execute(args, ctx) {
|
|
106368
106579
|
const skills2 = await getSkills(ctx);
|
|
106369
106580
|
const commands2 = getCommands();
|
|
106370
|
-
cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2
|
|
106581
|
+
cachedDescription = formatCombinedDescription(skills2.map(loadedSkillToInfo), commands2, {
|
|
106582
|
+
includeSkills: options.includeSkillsInDescription
|
|
106583
|
+
});
|
|
106371
106584
|
const requestedName = args.name.replace(/^\//, "");
|
|
106372
106585
|
const matchedSkill = matchSkillByName(skills2, requestedName);
|
|
106373
106586
|
if (matchedSkill) {
|
|
@@ -106428,9 +106641,9 @@ var skill = createSkillTool({ directory: process.cwd() });
|
|
|
106428
106641
|
// src/tools/session-manager/constants.ts
|
|
106429
106642
|
init_shared();
|
|
106430
106643
|
init_shared();
|
|
106431
|
-
import { join as
|
|
106432
|
-
var TODO_DIR2 =
|
|
106433
|
-
var TRANSCRIPT_DIR2 =
|
|
106644
|
+
import { join as join84 } from "path";
|
|
106645
|
+
var TODO_DIR2 = join84(getClaudeConfigDir(), "todos");
|
|
106646
|
+
var TRANSCRIPT_DIR2 = join84(getClaudeConfigDir(), "transcripts");
|
|
106434
106647
|
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
106435
106648
|
|
|
106436
106649
|
Returns a list of available session IDs with metadata including message count, date range, and agents used.
|
|
@@ -106507,12 +106720,12 @@ init_opencode_storage_detection();
|
|
|
106507
106720
|
init_shared();
|
|
106508
106721
|
|
|
106509
106722
|
// src/tools/session-manager/file-storage.ts
|
|
106510
|
-
import { existsSync as
|
|
106723
|
+
import { existsSync as existsSync79 } from "fs";
|
|
106511
106724
|
import { readdir as readdir5, readFile as readFile8 } from "fs/promises";
|
|
106512
|
-
import { join as
|
|
106725
|
+
import { join as join85 } from "path";
|
|
106513
106726
|
init_opencode_message_dir();
|
|
106514
106727
|
async function getFileMainSessions(directory) {
|
|
106515
|
-
if (!
|
|
106728
|
+
if (!existsSync79(SESSION_STORAGE))
|
|
106516
106729
|
return [];
|
|
106517
106730
|
const sessions = [];
|
|
106518
106731
|
try {
|
|
@@ -106520,13 +106733,13 @@ async function getFileMainSessions(directory) {
|
|
|
106520
106733
|
for (const projectDir of projectDirs) {
|
|
106521
106734
|
if (!projectDir.isDirectory())
|
|
106522
106735
|
continue;
|
|
106523
|
-
const projectPath =
|
|
106736
|
+
const projectPath = join85(SESSION_STORAGE, projectDir.name);
|
|
106524
106737
|
const sessionFiles = await readdir5(projectPath);
|
|
106525
106738
|
for (const file of sessionFiles) {
|
|
106526
106739
|
if (!file.endsWith(".json"))
|
|
106527
106740
|
continue;
|
|
106528
106741
|
try {
|
|
106529
|
-
const content = await readFile8(
|
|
106742
|
+
const content = await readFile8(join85(projectPath, file), "utf-8");
|
|
106530
106743
|
const meta = JSON.parse(content);
|
|
106531
106744
|
if (meta.parentID)
|
|
106532
106745
|
continue;
|
|
@@ -106544,7 +106757,7 @@ async function getFileMainSessions(directory) {
|
|
|
106544
106757
|
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
106545
106758
|
}
|
|
106546
106759
|
async function getFileAllSessions() {
|
|
106547
|
-
if (!
|
|
106760
|
+
if (!existsSync79(MESSAGE_STORAGE))
|
|
106548
106761
|
return [];
|
|
106549
106762
|
const sessions = [];
|
|
106550
106763
|
async function scanDirectory(dir) {
|
|
@@ -106553,7 +106766,7 @@ async function getFileAllSessions() {
|
|
|
106553
106766
|
for (const entry of entries) {
|
|
106554
106767
|
if (!entry.isDirectory())
|
|
106555
106768
|
continue;
|
|
106556
|
-
const sessionPath =
|
|
106769
|
+
const sessionPath = join85(dir, entry.name);
|
|
106557
106770
|
const files = await readdir5(sessionPath);
|
|
106558
106771
|
if (files.some((file) => file.endsWith(".json"))) {
|
|
106559
106772
|
sessions.push(entry.name);
|
|
@@ -106573,7 +106786,7 @@ async function fileSessionExists(sessionID) {
|
|
|
106573
106786
|
}
|
|
106574
106787
|
async function getFileSessionMessages(sessionID) {
|
|
106575
106788
|
const messageDir = getMessageDir(sessionID);
|
|
106576
|
-
if (!messageDir || !
|
|
106789
|
+
if (!messageDir || !existsSync79(messageDir))
|
|
106577
106790
|
return [];
|
|
106578
106791
|
const messages = [];
|
|
106579
106792
|
try {
|
|
@@ -106582,7 +106795,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
106582
106795
|
if (!file.endsWith(".json"))
|
|
106583
106796
|
continue;
|
|
106584
106797
|
try {
|
|
106585
|
-
const content = await readFile8(
|
|
106798
|
+
const content = await readFile8(join85(messageDir, file), "utf-8");
|
|
106586
106799
|
const meta = JSON.parse(content);
|
|
106587
106800
|
const parts = await readParts2(meta.id);
|
|
106588
106801
|
messages.push({
|
|
@@ -106608,8 +106821,8 @@ async function getFileSessionMessages(sessionID) {
|
|
|
106608
106821
|
});
|
|
106609
106822
|
}
|
|
106610
106823
|
async function readParts2(messageID) {
|
|
106611
|
-
const partDir =
|
|
106612
|
-
if (!
|
|
106824
|
+
const partDir = join85(PART_STORAGE, messageID);
|
|
106825
|
+
if (!existsSync79(partDir))
|
|
106613
106826
|
return [];
|
|
106614
106827
|
const parts = [];
|
|
106615
106828
|
try {
|
|
@@ -106618,7 +106831,7 @@ async function readParts2(messageID) {
|
|
|
106618
106831
|
if (!file.endsWith(".json"))
|
|
106619
106832
|
continue;
|
|
106620
106833
|
try {
|
|
106621
|
-
const content = await readFile8(
|
|
106834
|
+
const content = await readFile8(join85(partDir, file), "utf-8");
|
|
106622
106835
|
parts.push(JSON.parse(content));
|
|
106623
106836
|
} catch {
|
|
106624
106837
|
continue;
|
|
@@ -106630,14 +106843,14 @@ async function readParts2(messageID) {
|
|
|
106630
106843
|
return parts.sort((a, b) => a.id.localeCompare(b.id));
|
|
106631
106844
|
}
|
|
106632
106845
|
async function getFileSessionTodos(sessionID) {
|
|
106633
|
-
if (!
|
|
106846
|
+
if (!existsSync79(TODO_DIR2))
|
|
106634
106847
|
return [];
|
|
106635
106848
|
try {
|
|
106636
106849
|
const allFiles = await readdir5(TODO_DIR2);
|
|
106637
106850
|
const todoFiles = allFiles.filter((file) => file === `${sessionID}.json`);
|
|
106638
106851
|
for (const file of todoFiles) {
|
|
106639
106852
|
try {
|
|
106640
|
-
const content = await readFile8(
|
|
106853
|
+
const content = await readFile8(join85(TODO_DIR2, file), "utf-8");
|
|
106641
106854
|
const data = JSON.parse(content);
|
|
106642
106855
|
if (!Array.isArray(data))
|
|
106643
106856
|
continue;
|
|
@@ -106657,10 +106870,10 @@ async function getFileSessionTodos(sessionID) {
|
|
|
106657
106870
|
return [];
|
|
106658
106871
|
}
|
|
106659
106872
|
async function getFileSessionTranscript(sessionID) {
|
|
106660
|
-
if (!
|
|
106873
|
+
if (!existsSync79(TRANSCRIPT_DIR2))
|
|
106661
106874
|
return 0;
|
|
106662
|
-
const transcriptFile =
|
|
106663
|
-
if (!
|
|
106875
|
+
const transcriptFile = join85(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
106876
|
+
if (!existsSync79(transcriptFile))
|
|
106664
106877
|
return 0;
|
|
106665
106878
|
try {
|
|
106666
106879
|
const content = await readFile8(transcriptFile, "utf-8");
|
|
@@ -108465,25 +108678,25 @@ init_session_tools_store();
|
|
|
108465
108678
|
init_file_utils2();
|
|
108466
108679
|
init_shared();
|
|
108467
108680
|
init_opencode_config_dir();
|
|
108468
|
-
import { existsSync as
|
|
108469
|
-
import { join as
|
|
108681
|
+
import { existsSync as existsSync82, readdirSync as readdirSync23 } from "fs";
|
|
108682
|
+
import { join as join86 } from "path";
|
|
108470
108683
|
|
|
108471
108684
|
// src/features/claude-code-agent-loader/agent-definitions-loader.ts
|
|
108472
108685
|
init_frontmatter2();
|
|
108473
108686
|
init_logger();
|
|
108474
|
-
import { existsSync as
|
|
108687
|
+
import { existsSync as existsSync81, readFileSync as readFileSync58 } from "fs";
|
|
108475
108688
|
import { basename as basename12, extname as extname3 } from "path";
|
|
108476
108689
|
|
|
108477
108690
|
// src/features/claude-code-agent-loader/json-agent-loader.ts
|
|
108478
108691
|
init_jsonc_parser2();
|
|
108479
108692
|
init_claude_model_mapper();
|
|
108480
|
-
import { existsSync as
|
|
108693
|
+
import { existsSync as existsSync80, readFileSync as readFileSync57 } from "fs";
|
|
108481
108694
|
function parseJsonAgentFile(filePath, scope) {
|
|
108482
108695
|
try {
|
|
108483
|
-
if (!
|
|
108696
|
+
if (!existsSync80(filePath)) {
|
|
108484
108697
|
return null;
|
|
108485
108698
|
}
|
|
108486
|
-
const content =
|
|
108699
|
+
const content = readFileSync57(filePath, "utf-8");
|
|
108487
108700
|
const { data } = parseJsoncSafe(content);
|
|
108488
108701
|
if (!data) {
|
|
108489
108702
|
return null;
|
|
@@ -108520,10 +108733,10 @@ function parseJsonAgentFile(filePath, scope) {
|
|
|
108520
108733
|
init_claude_model_mapper();
|
|
108521
108734
|
function parseMarkdownAgentFile(filePath, scope) {
|
|
108522
108735
|
try {
|
|
108523
|
-
if (!
|
|
108736
|
+
if (!existsSync81(filePath)) {
|
|
108524
108737
|
return null;
|
|
108525
108738
|
}
|
|
108526
|
-
const content =
|
|
108739
|
+
const content = readFileSync58(filePath, "utf-8");
|
|
108527
108740
|
const { data, body } = parseFrontmatter(content);
|
|
108528
108741
|
const fileName = basename12(filePath);
|
|
108529
108742
|
const agentName = fileName.replace(/\.md$/i, "");
|
|
@@ -108555,7 +108768,7 @@ function parseMarkdownAgentFile(filePath, scope) {
|
|
|
108555
108768
|
function loadAgentDefinitions(paths, scope) {
|
|
108556
108769
|
const result = Object.create(null);
|
|
108557
108770
|
for (const filePath of paths) {
|
|
108558
|
-
if (!
|
|
108771
|
+
if (!existsSync81(filePath)) {
|
|
108559
108772
|
log(`[agent-definitions-loader] File not found, skipping: ${filePath}`);
|
|
108560
108773
|
continue;
|
|
108561
108774
|
}
|
|
@@ -108580,7 +108793,7 @@ function loadAgentDefinitions(paths, scope) {
|
|
|
108580
108793
|
|
|
108581
108794
|
// src/features/claude-code-agent-loader/loader.ts
|
|
108582
108795
|
function loadAgentsFromDir(agentsDir, scope) {
|
|
108583
|
-
if (!
|
|
108796
|
+
if (!existsSync82(agentsDir)) {
|
|
108584
108797
|
return [];
|
|
108585
108798
|
}
|
|
108586
108799
|
const entries = readdirSync23(agentsDir, { withFileTypes: true });
|
|
@@ -108588,7 +108801,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
108588
108801
|
for (const entry of entries) {
|
|
108589
108802
|
if (!isMarkdownFile(entry))
|
|
108590
108803
|
continue;
|
|
108591
|
-
const agentPath =
|
|
108804
|
+
const agentPath = join86(agentsDir, entry.name);
|
|
108592
108805
|
const agent = parseMarkdownAgentFile(agentPath, scope);
|
|
108593
108806
|
if (agent) {
|
|
108594
108807
|
agents.push(agent);
|
|
@@ -108597,7 +108810,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
108597
108810
|
return agents;
|
|
108598
108811
|
}
|
|
108599
108812
|
function loadUserAgents() {
|
|
108600
|
-
const userAgentsDir =
|
|
108813
|
+
const userAgentsDir = join86(getClaudeConfigDir(), "agents");
|
|
108601
108814
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
108602
108815
|
const result = Object.create(null);
|
|
108603
108816
|
for (const agent of agents) {
|
|
@@ -108606,7 +108819,7 @@ function loadUserAgents() {
|
|
|
108606
108819
|
return result;
|
|
108607
108820
|
}
|
|
108608
108821
|
function loadProjectAgents(directory) {
|
|
108609
|
-
const projectAgentsDir =
|
|
108822
|
+
const projectAgentsDir = join86(directory ?? process.cwd(), ".claude", "agents");
|
|
108610
108823
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
108611
108824
|
const result = Object.create(null);
|
|
108612
108825
|
for (const agent of agents) {
|
|
@@ -108618,7 +108831,7 @@ function loadOpencodeGlobalAgents() {
|
|
|
108618
108831
|
const result = Object.create(null);
|
|
108619
108832
|
const configDirs = getOpenCodeConfigDirs({ binary: "opencode" });
|
|
108620
108833
|
for (const configDir of configDirs) {
|
|
108621
|
-
const opencodeAgentsDir =
|
|
108834
|
+
const opencodeAgentsDir = join86(configDir, "agents");
|
|
108622
108835
|
const agents = loadAgentsFromDir(opencodeAgentsDir, "opencode");
|
|
108623
108836
|
for (const agent of agents) {
|
|
108624
108837
|
if (!(agent.name in result)) {
|
|
@@ -108629,7 +108842,7 @@ function loadOpencodeGlobalAgents() {
|
|
|
108629
108842
|
return result;
|
|
108630
108843
|
}
|
|
108631
108844
|
function loadOpencodeProjectAgents(directory) {
|
|
108632
|
-
const opencodeProjectDir =
|
|
108845
|
+
const opencodeProjectDir = join86(directory ?? process.cwd(), ".opencode", "agents");
|
|
108633
108846
|
const agents = loadAgentsFromDir(opencodeProjectDir, "opencode-project");
|
|
108634
108847
|
const result = Object.create(null);
|
|
108635
108848
|
for (const agent of agents) {
|
|
@@ -108641,16 +108854,16 @@ function loadOpencodeProjectAgents(directory) {
|
|
|
108641
108854
|
init_opencode_config_dir();
|
|
108642
108855
|
init_jsonc_parser2();
|
|
108643
108856
|
init_resolve_agent_definition_paths();
|
|
108644
|
-
import * as
|
|
108645
|
-
import * as
|
|
108857
|
+
import * as fs22 from "fs";
|
|
108858
|
+
import * as path18 from "path";
|
|
108646
108859
|
init_claude_model_mapper();
|
|
108647
|
-
function
|
|
108860
|
+
function getConfigPaths4(directory) {
|
|
108648
108861
|
const globalConfigDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
108649
108862
|
const paths = [
|
|
108650
|
-
|
|
108651
|
-
|
|
108652
|
-
|
|
108653
|
-
|
|
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")
|
|
108654
108867
|
];
|
|
108655
108868
|
return paths;
|
|
108656
108869
|
}
|
|
@@ -108679,15 +108892,15 @@ function convertInlineAgent(agentData) {
|
|
|
108679
108892
|
}
|
|
108680
108893
|
function readOpencodeConfigAgents(directory) {
|
|
108681
108894
|
const result = Object.create(null);
|
|
108682
|
-
for (const configPath of
|
|
108895
|
+
for (const configPath of getConfigPaths4(directory)) {
|
|
108683
108896
|
try {
|
|
108684
|
-
if (!
|
|
108897
|
+
if (!fs22.existsSync(configPath))
|
|
108685
108898
|
continue;
|
|
108686
|
-
const content =
|
|
108899
|
+
const content = fs22.readFileSync(configPath, "utf-8");
|
|
108687
108900
|
const parseResult = parseJsoncSafe(content);
|
|
108688
108901
|
if (!parseResult.data)
|
|
108689
108902
|
continue;
|
|
108690
|
-
const configDir =
|
|
108903
|
+
const configDir = path18.dirname(configPath);
|
|
108691
108904
|
const agentsToLoad = parseResult.data.agents || parseResult.data.agent;
|
|
108692
108905
|
if (agentsToLoad && typeof agentsToLoad === "object") {
|
|
108693
108906
|
for (const [agentName, agentData] of Object.entries(agentsToLoad)) {
|
|
@@ -109383,9 +109596,9 @@ import { pathToFileURL } from "url";
|
|
|
109383
109596
|
// src/tools/look-at/image-converter.ts
|
|
109384
109597
|
init_shared();
|
|
109385
109598
|
import * as childProcess2 from "child_process";
|
|
109386
|
-
import { existsSync as
|
|
109599
|
+
import { existsSync as existsSync84, mkdtempSync, readFileSync as readFileSync60, rmSync as rmSync4, unlinkSync as unlinkSync14, writeFileSync as writeFileSync19 } from "fs";
|
|
109387
109600
|
import { tmpdir as tmpdir7 } from "os";
|
|
109388
|
-
import { dirname as dirname31, join as
|
|
109601
|
+
import { dirname as dirname31, join as join88 } from "path";
|
|
109389
109602
|
var SUPPORTED_FORMATS = new Set([
|
|
109390
109603
|
"image/jpeg",
|
|
109391
109604
|
"image/png",
|
|
@@ -109423,11 +109636,11 @@ function needsConversion(mimeType) {
|
|
|
109423
109636
|
return mimeType.startsWith("image/");
|
|
109424
109637
|
}
|
|
109425
109638
|
function convertImageToJpeg(inputPath, mimeType) {
|
|
109426
|
-
if (!
|
|
109639
|
+
if (!existsSync84(inputPath)) {
|
|
109427
109640
|
throw new Error(`File not found: ${inputPath}`);
|
|
109428
109641
|
}
|
|
109429
|
-
const tempDir = mkdtempSync(
|
|
109430
|
-
const outputPath =
|
|
109642
|
+
const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-img-"));
|
|
109643
|
+
const outputPath = join88(tempDir, "converted.jpg");
|
|
109431
109644
|
log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
|
|
109432
109645
|
try {
|
|
109433
109646
|
if (process.platform === "darwin") {
|
|
@@ -109437,7 +109650,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109437
109650
|
encoding: "utf-8",
|
|
109438
109651
|
timeout: CONVERSION_TIMEOUT_MS
|
|
109439
109652
|
});
|
|
109440
|
-
if (
|
|
109653
|
+
if (existsSync84(outputPath)) {
|
|
109441
109654
|
log(`[image-converter] Converted using sips: ${outputPath}`);
|
|
109442
109655
|
return outputPath;
|
|
109443
109656
|
}
|
|
@@ -109452,7 +109665,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109452
109665
|
encoding: "utf-8",
|
|
109453
109666
|
timeout: CONVERSION_TIMEOUT_MS
|
|
109454
109667
|
});
|
|
109455
|
-
if (
|
|
109668
|
+
if (existsSync84(outputPath)) {
|
|
109456
109669
|
log(`[image-converter] Converted using ImageMagick: ${outputPath}`);
|
|
109457
109670
|
return outputPath;
|
|
109458
109671
|
}
|
|
@@ -109465,7 +109678,7 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109465
109678
|
` + ` RHEL/CentOS: sudo yum install ImageMagick`);
|
|
109466
109679
|
} catch (error) {
|
|
109467
109680
|
try {
|
|
109468
|
-
if (
|
|
109681
|
+
if (existsSync84(outputPath)) {
|
|
109469
109682
|
unlinkSync14(outputPath);
|
|
109470
109683
|
}
|
|
109471
109684
|
} catch {}
|
|
@@ -109479,11 +109692,11 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
109479
109692
|
function cleanupConvertedImage(filePath) {
|
|
109480
109693
|
try {
|
|
109481
109694
|
const tempDirectory = dirname31(filePath);
|
|
109482
|
-
if (
|
|
109695
|
+
if (existsSync84(filePath)) {
|
|
109483
109696
|
unlinkSync14(filePath);
|
|
109484
109697
|
log(`[image-converter] Cleaned up temporary file: ${filePath}`);
|
|
109485
109698
|
}
|
|
109486
|
-
if (
|
|
109699
|
+
if (existsSync84(tempDirectory)) {
|
|
109487
109700
|
rmSync4(tempDirectory, { recursive: true, force: true });
|
|
109488
109701
|
log(`[image-converter] Cleaned up temporary directory: ${tempDirectory}`);
|
|
109489
109702
|
}
|
|
@@ -109492,9 +109705,9 @@ function cleanupConvertedImage(filePath) {
|
|
|
109492
109705
|
}
|
|
109493
109706
|
}
|
|
109494
109707
|
function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
109495
|
-
const tempDir = mkdtempSync(
|
|
109708
|
+
const tempDir = mkdtempSync(join88(tmpdir7(), "opencode-b64-"));
|
|
109496
109709
|
const inputExt = mimeType.split("/")[1] || "bin";
|
|
109497
|
-
const inputPath =
|
|
109710
|
+
const inputPath = join88(tempDir, `input.${inputExt}`);
|
|
109498
109711
|
const tempFiles = [inputPath];
|
|
109499
109712
|
try {
|
|
109500
109713
|
const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
@@ -109503,14 +109716,14 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
|
109503
109716
|
log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
|
|
109504
109717
|
const outputPath = convertImageToJpeg(inputPath, mimeType);
|
|
109505
109718
|
tempFiles.push(outputPath);
|
|
109506
|
-
const convertedBuffer =
|
|
109719
|
+
const convertedBuffer = readFileSync60(outputPath);
|
|
109507
109720
|
const convertedBase64 = convertedBuffer.toString("base64");
|
|
109508
109721
|
log(`[image-converter] Base64 conversion successful`);
|
|
109509
109722
|
return { base64: convertedBase64, tempFiles };
|
|
109510
109723
|
} catch (error) {
|
|
109511
109724
|
tempFiles.forEach((file) => {
|
|
109512
109725
|
try {
|
|
109513
|
-
if (
|
|
109726
|
+
if (existsSync84(file))
|
|
109514
109727
|
unlinkSync14(file);
|
|
109515
109728
|
} catch {}
|
|
109516
109729
|
});
|
|
@@ -109649,13 +109862,68 @@ function asSessionMessage(value) {
|
|
|
109649
109862
|
function getCreatedTime(message) {
|
|
109650
109863
|
return message.info?.time?.created ?? 0;
|
|
109651
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
|
+
}
|
|
109652
109891
|
function getTextParts(message) {
|
|
109653
109892
|
if (!Array.isArray(message.parts))
|
|
109654
109893
|
return [];
|
|
109655
109894
|
return message.parts.filter((part) => isObject2(part)).map((part) => ({
|
|
109656
109895
|
type: typeof part["type"] === "string" ? part["type"] : undefined,
|
|
109657
|
-
text: typeof part["text"] === "string" ? part["text"] : undefined
|
|
109658
|
-
|
|
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;
|
|
109659
109927
|
}
|
|
109660
109928
|
function extractLatestAssistantText(messages) {
|
|
109661
109929
|
return extractLatestAssistantOutcome(messages).text;
|
|
@@ -109671,9 +109939,7 @@ function extractLatestAssistantOutcome(messages) {
|
|
|
109671
109939
|
if (!lastAssistantMessage) {
|
|
109672
109940
|
return { text: null, errorName: null, hasAssistant, completed: false };
|
|
109673
109941
|
}
|
|
109674
|
-
const
|
|
109675
|
-
const text = textParts.map((part) => part.text).join(`
|
|
109676
|
-
`) || null;
|
|
109942
|
+
const text = extractTextFromParts(getTextParts(lastAssistantMessage));
|
|
109677
109943
|
const allParts = Array.isArray(lastAssistantMessage.parts) ? lastAssistantMessage.parts : [];
|
|
109678
109944
|
const errorPart = allParts.find((part) => isObject2(part) && typeof part["type"] === "string" && part["type"] === "error");
|
|
109679
109945
|
const errorName = errorPart && typeof errorPart["error"] === "string" ? errorPart["error"] : null;
|
|
@@ -110071,9 +110337,9 @@ function getMissingFilePathFromError(error) {
|
|
|
110071
110337
|
if (!(error instanceof Error)) {
|
|
110072
110338
|
return null;
|
|
110073
110339
|
}
|
|
110074
|
-
const
|
|
110075
|
-
if (typeof
|
|
110076
|
-
return
|
|
110340
|
+
const path19 = Reflect.get(error, "path");
|
|
110341
|
+
if (typeof path19 === "string" && path19.length > 0) {
|
|
110342
|
+
return path19;
|
|
110077
110343
|
}
|
|
110078
110344
|
if (error instanceof Error) {
|
|
110079
110345
|
const match = /open '([^']+)'/.exec(error.message);
|
|
@@ -113048,7 +113314,7 @@ function isExplicitSyncRun(runInBackground) {
|
|
|
113048
113314
|
// src/tools/delegate-task/index.ts
|
|
113049
113315
|
init_constants();
|
|
113050
113316
|
// src/tools/task/task-create.ts
|
|
113051
|
-
import { join as
|
|
113317
|
+
import { join as join90 } from "path";
|
|
113052
113318
|
|
|
113053
113319
|
// src/tools/task/types.ts
|
|
113054
113320
|
import { z as z37 } from "zod";
|
|
@@ -113104,18 +113370,18 @@ var TaskDeleteInputSchema = z37.object({
|
|
|
113104
113370
|
|
|
113105
113371
|
// src/features/claude-tasks/storage.ts
|
|
113106
113372
|
init_opencode_config_dir();
|
|
113107
|
-
import { join as
|
|
113108
|
-
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";
|
|
113109
113375
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
113110
113376
|
function getTaskDir(config = {}) {
|
|
113111
113377
|
const tasksConfig = config.sisyphus?.tasks;
|
|
113112
113378
|
const storagePath = tasksConfig?.storage_path;
|
|
113113
113379
|
if (storagePath) {
|
|
113114
|
-
return isAbsolute17(storagePath) ? storagePath :
|
|
113380
|
+
return isAbsolute17(storagePath) ? storagePath : join89(process.cwd(), storagePath);
|
|
113115
113381
|
}
|
|
113116
113382
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
113117
113383
|
const listId = resolveTaskListId(config);
|
|
113118
|
-
return
|
|
113384
|
+
return join89(configDir, "tasks", listId);
|
|
113119
113385
|
}
|
|
113120
113386
|
function sanitizePathSegment(value) {
|
|
113121
113387
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
|
|
@@ -113133,16 +113399,16 @@ function resolveTaskListId(config = {}) {
|
|
|
113133
113399
|
return sanitizePathSegment(basename14(process.cwd()));
|
|
113134
113400
|
}
|
|
113135
113401
|
function ensureDir(dirPath) {
|
|
113136
|
-
if (!
|
|
113402
|
+
if (!existsSync85(dirPath)) {
|
|
113137
113403
|
mkdirSync18(dirPath, { recursive: true });
|
|
113138
113404
|
}
|
|
113139
113405
|
}
|
|
113140
113406
|
function readJsonSafe(filePath, schema2) {
|
|
113141
113407
|
try {
|
|
113142
|
-
if (!
|
|
113408
|
+
if (!existsSync85(filePath)) {
|
|
113143
113409
|
return null;
|
|
113144
113410
|
}
|
|
113145
|
-
const content =
|
|
113411
|
+
const content = readFileSync61(filePath, "utf-8");
|
|
113146
113412
|
const parsed = JSON.parse(content);
|
|
113147
113413
|
const result = schema2.safeParse(parsed);
|
|
113148
113414
|
if (!result.success) {
|
|
@@ -113162,7 +113428,7 @@ function writeJsonAtomic(filePath, data) {
|
|
|
113162
113428
|
renameSync6(tempPath, filePath);
|
|
113163
113429
|
} catch (error) {
|
|
113164
113430
|
try {
|
|
113165
|
-
if (
|
|
113431
|
+
if (existsSync85(tempPath)) {
|
|
113166
113432
|
unlinkSync15(tempPath);
|
|
113167
113433
|
}
|
|
113168
113434
|
} catch {}
|
|
@@ -113174,7 +113440,7 @@ function generateTaskId() {
|
|
|
113174
113440
|
return `T-${randomUUID5()}`;
|
|
113175
113441
|
}
|
|
113176
113442
|
function acquireLock2(dirPath) {
|
|
113177
|
-
const lockPath =
|
|
113443
|
+
const lockPath = join89(dirPath, ".lock");
|
|
113178
113444
|
const lockId = randomUUID5();
|
|
113179
113445
|
const createLock = (timestamp2) => {
|
|
113180
113446
|
writeFileSync20(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
|
|
@@ -113184,7 +113450,7 @@ function acquireLock2(dirPath) {
|
|
|
113184
113450
|
};
|
|
113185
113451
|
const isStale = () => {
|
|
113186
113452
|
try {
|
|
113187
|
-
const lockContent =
|
|
113453
|
+
const lockContent = readFileSync61(lockPath, "utf-8");
|
|
113188
113454
|
const lockData = JSON.parse(lockContent);
|
|
113189
113455
|
const lockAge = Date.now() - lockData.timestamp;
|
|
113190
113456
|
return lockAge > STALE_LOCK_THRESHOLD_MS;
|
|
@@ -113222,9 +113488,9 @@ function acquireLock2(dirPath) {
|
|
|
113222
113488
|
acquired: true,
|
|
113223
113489
|
release: () => {
|
|
113224
113490
|
try {
|
|
113225
|
-
if (!
|
|
113491
|
+
if (!existsSync85(lockPath))
|
|
113226
113492
|
return;
|
|
113227
|
-
const lockContent =
|
|
113493
|
+
const lockContent = readFileSync61(lockPath, "utf-8");
|
|
113228
113494
|
const lockData = JSON.parse(lockContent);
|
|
113229
113495
|
if (lockData.id !== lockId)
|
|
113230
113496
|
return;
|
|
@@ -113387,7 +113653,7 @@ async function handleCreate(args, config, ctx, context) {
|
|
|
113387
113653
|
threadID: context.sessionID
|
|
113388
113654
|
};
|
|
113389
113655
|
const validatedTask = TaskObjectSchema.parse(task);
|
|
113390
|
-
writeJsonAtomic(
|
|
113656
|
+
writeJsonAtomic(join90(taskDir, `${taskId}.json`), validatedTask);
|
|
113391
113657
|
await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
|
|
113392
113658
|
return JSON.stringify({
|
|
113393
113659
|
task: {
|
|
@@ -113409,7 +113675,7 @@ async function handleCreate(args, config, ctx, context) {
|
|
|
113409
113675
|
}
|
|
113410
113676
|
}
|
|
113411
113677
|
// src/tools/task/task-get.ts
|
|
113412
|
-
import { join as
|
|
113678
|
+
import { join as join91 } from "path";
|
|
113413
113679
|
var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
|
|
113414
113680
|
function parseTaskId(id) {
|
|
113415
113681
|
if (!TASK_ID_PATTERN.test(id))
|
|
@@ -113434,7 +113700,7 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
113434
113700
|
return JSON.stringify({ error: "invalid_task_id" });
|
|
113435
113701
|
}
|
|
113436
113702
|
const taskDir = getTaskDir(config);
|
|
113437
|
-
const taskPath =
|
|
113703
|
+
const taskPath = join91(taskDir, `${taskId}.json`);
|
|
113438
113704
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
113439
113705
|
return JSON.stringify({ task: task ?? null });
|
|
113440
113706
|
} catch (error) {
|
|
@@ -113447,8 +113713,8 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
113447
113713
|
});
|
|
113448
113714
|
}
|
|
113449
113715
|
// src/tools/task/task-list.ts
|
|
113450
|
-
import { join as
|
|
113451
|
-
import { existsSync as
|
|
113716
|
+
import { join as join92 } from "path";
|
|
113717
|
+
import { existsSync as existsSync86, readdirSync as readdirSync25 } from "fs";
|
|
113452
113718
|
function createTaskList(config) {
|
|
113453
113719
|
return tool({
|
|
113454
113720
|
description: `List all active tasks with summary information.
|
|
@@ -113459,7 +113725,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113459
113725
|
args: {},
|
|
113460
113726
|
execute: async () => {
|
|
113461
113727
|
const taskDir = getTaskDir(config);
|
|
113462
|
-
if (!
|
|
113728
|
+
if (!existsSync86(taskDir)) {
|
|
113463
113729
|
return JSON.stringify({ tasks: [] });
|
|
113464
113730
|
}
|
|
113465
113731
|
const files = readdirSync25(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
|
|
@@ -113468,7 +113734,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113468
113734
|
}
|
|
113469
113735
|
const allTasks = [];
|
|
113470
113736
|
for (const fileId of files) {
|
|
113471
|
-
const task = readJsonSafe(
|
|
113737
|
+
const task = readJsonSafe(join92(taskDir, `${fileId}.json`), TaskObjectSchema);
|
|
113472
113738
|
if (task) {
|
|
113473
113739
|
allTasks.push(task);
|
|
113474
113740
|
}
|
|
@@ -113496,7 +113762,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
113496
113762
|
});
|
|
113497
113763
|
}
|
|
113498
113764
|
// src/tools/task/task-update.ts
|
|
113499
|
-
import { join as
|
|
113765
|
+
import { join as join93 } from "path";
|
|
113500
113766
|
var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
|
|
113501
113767
|
function parseTaskId2(id) {
|
|
113502
113768
|
if (!TASK_ID_PATTERN2.test(id))
|
|
@@ -113544,7 +113810,7 @@ async function handleUpdate(args, config, ctx, context) {
|
|
|
113544
113810
|
return JSON.stringify({ error: "task_lock_unavailable" });
|
|
113545
113811
|
}
|
|
113546
113812
|
try {
|
|
113547
|
-
const taskPath =
|
|
113813
|
+
const taskPath = join93(taskDir, `${taskId}.json`);
|
|
113548
113814
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
113549
113815
|
if (!task) {
|
|
113550
113816
|
return JSON.stringify({ error: "task_not_found" });
|
|
@@ -113602,10 +113868,10 @@ init_bun_file_shim();
|
|
|
113602
113868
|
// src/tools/hashline-edit/formatter-trigger.ts
|
|
113603
113869
|
init_shared();
|
|
113604
113870
|
init_bun_spawn_shim();
|
|
113605
|
-
import
|
|
113871
|
+
import path19 from "path";
|
|
113606
113872
|
var cachedFormattersByDirectory = new Map;
|
|
113607
113873
|
function getFormatterCacheKey(directory) {
|
|
113608
|
-
return
|
|
113874
|
+
return path19.resolve(directory);
|
|
113609
113875
|
}
|
|
113610
113876
|
async function resolveFormatters(client, directory) {
|
|
113611
113877
|
const cacheKey = getFormatterCacheKey(directory);
|
|
@@ -113656,7 +113922,7 @@ function buildFormatterCommand(command, filePath) {
|
|
|
113656
113922
|
return command.map((arg) => arg.replace(/\$FILE/g, filePath));
|
|
113657
113923
|
}
|
|
113658
113924
|
async function runFormattersForFile(client, directory, filePath) {
|
|
113659
|
-
const ext =
|
|
113925
|
+
const ext = path19.extname(filePath);
|
|
113660
113926
|
if (!ext)
|
|
113661
113927
|
return;
|
|
113662
113928
|
const formatters = await resolveFormatters(client, directory);
|
|
@@ -113976,17 +114242,17 @@ function buildMemberPromptBody(member, text) {
|
|
|
113976
114242
|
// src/features/team-mode/team-mailbox/reservation.ts
|
|
113977
114243
|
init_paths();
|
|
113978
114244
|
import { mkdir as mkdir3, readdir as readdir6, rename as rename2, stat as stat5 } from "fs/promises";
|
|
113979
|
-
import
|
|
114245
|
+
import path20 from "path";
|
|
113980
114246
|
var RESERVED_PREFIX = ".delivering-";
|
|
113981
114247
|
var RESERVED_SUFFIX = ".json";
|
|
113982
114248
|
function isMissingPathError(error) {
|
|
113983
114249
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
113984
114250
|
}
|
|
113985
114251
|
function buildReservation(inboxDir, messageId) {
|
|
113986
|
-
const inboxPath =
|
|
113987
|
-
const reservedPath =
|
|
113988
|
-
const processedDir =
|
|
113989
|
-
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`);
|
|
113990
114256
|
return { reservedPath, inboxPath, processedPath, processedDir };
|
|
113991
114257
|
}
|
|
113992
114258
|
async function reserveMessageForDelivery(teamRunId, recipientName, messageId, config) {
|
|
@@ -114022,7 +114288,7 @@ init_store();
|
|
|
114022
114288
|
init_locks();
|
|
114023
114289
|
import { Buffer as Buffer2 } from "buffer";
|
|
114024
114290
|
import { mkdir as mkdir4, readdir as readdir7, stat as stat6 } from "fs/promises";
|
|
114025
|
-
import
|
|
114291
|
+
import path21 from "path";
|
|
114026
114292
|
|
|
114027
114293
|
class BroadcastNotPermittedError extends Error {
|
|
114028
114294
|
constructor(message = "broadcast requires lead role") {
|
|
@@ -114091,7 +114357,7 @@ async function getUnreadSizeBytes(inboxDir) {
|
|
|
114091
114357
|
return !entry.name.startsWith(".");
|
|
114092
114358
|
});
|
|
114093
114359
|
const sizes = await Promise.all(unreadEntries.map(async (entry) => {
|
|
114094
|
-
const fileStats = await stat6(
|
|
114360
|
+
const fileStats = await stat6(path21.join(inboxDir, entry.name));
|
|
114095
114361
|
return fileStats.size;
|
|
114096
114362
|
}));
|
|
114097
114363
|
return sizes.reduce((totalBytes, fileSize) => totalBytes + fileSize, 0);
|
|
@@ -114137,8 +114403,8 @@ async function sendMessage(message, teamRunId, config, context) {
|
|
|
114137
114403
|
if (nextUnreadSizeBytes > config.recipient_unread_max_bytes) {
|
|
114138
114404
|
throw new RecipientBackpressureError;
|
|
114139
114405
|
}
|
|
114140
|
-
const unreservedPath =
|
|
114141
|
-
const reservedPath =
|
|
114406
|
+
const unreservedPath = path21.join(inboxDir, `${message.messageId}.json`);
|
|
114407
|
+
const reservedPath = path21.join(inboxDir, `.delivering-${message.messageId}.json`);
|
|
114142
114408
|
if (await fileExists(unreservedPath) || await fileExists(reservedPath)) {
|
|
114143
114409
|
throw new DuplicateMessageIdError;
|
|
114144
114410
|
}
|
|
@@ -114892,8 +115158,8 @@ function createUnstableAgentBabysitter(args) {
|
|
|
114892
115158
|
directory: ctx.directory,
|
|
114893
115159
|
client: {
|
|
114894
115160
|
session: {
|
|
114895
|
-
messages: async ({ path:
|
|
114896
|
-
const result = await ctx.client.session.messages({ path:
|
|
115161
|
+
messages: async ({ path: path22 }) => {
|
|
115162
|
+
const result = await ctx.client.session.messages({ path: path22 });
|
|
114897
115163
|
if (Array.isArray(result))
|
|
114898
115164
|
return result;
|
|
114899
115165
|
if (typeof result === "object" && result !== null) {
|
|
@@ -115052,7 +115318,7 @@ function createHooks(args) {
|
|
|
115052
115318
|
};
|
|
115053
115319
|
}
|
|
115054
115320
|
// src/features/background-agent/manager.ts
|
|
115055
|
-
import { join as
|
|
115321
|
+
import { join as join95 } from "path";
|
|
115056
115322
|
init_shared();
|
|
115057
115323
|
init_event_session_id();
|
|
115058
115324
|
init_session_category_registry();
|
|
@@ -115332,8 +115598,8 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
115332
115598
|
}
|
|
115333
115599
|
|
|
115334
115600
|
// src/features/background-agent/compaction-aware-message-resolver.ts
|
|
115335
|
-
import { readdirSync as readdirSync26, readFileSync as
|
|
115336
|
-
import { join as
|
|
115601
|
+
import { readdirSync as readdirSync26, readFileSync as readFileSync62 } from "fs";
|
|
115602
|
+
import { join as join94 } from "path";
|
|
115337
115603
|
init_compaction_marker();
|
|
115338
115604
|
init_compaction_marker();
|
|
115339
115605
|
function hasFullAgentAndModel(message) {
|
|
@@ -115414,7 +115680,7 @@ function findNearestMessageExcludingCompaction(messageDir, sessionID) {
|
|
|
115414
115680
|
const messages = [];
|
|
115415
115681
|
for (const file of files) {
|
|
115416
115682
|
try {
|
|
115417
|
-
const content =
|
|
115683
|
+
const content = readFileSync62(join94(messageDir, file), "utf-8");
|
|
115418
115684
|
const parsed = JSON.parse(content);
|
|
115419
115685
|
if (hasCompactionPartInStorage(parsed.id) || isCompactionAgent(parsed.agent)) {
|
|
115420
115686
|
continue;
|
|
@@ -115454,6 +115720,16 @@ class ConcurrencyManager {
|
|
|
115454
115720
|
}
|
|
115455
115721
|
return 5;
|
|
115456
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
|
+
}
|
|
115457
115733
|
async acquire(model) {
|
|
115458
115734
|
const limit = this.getConcurrencyLimit(model);
|
|
115459
115735
|
if (limit === Infinity) {
|
|
@@ -115488,6 +115764,9 @@ class ConcurrencyManager {
|
|
|
115488
115764
|
const queue = this.queues.get(model);
|
|
115489
115765
|
while (queue && queue.length > 0) {
|
|
115490
115766
|
const next = queue.shift();
|
|
115767
|
+
if (!next) {
|
|
115768
|
+
continue;
|
|
115769
|
+
}
|
|
115491
115770
|
if (!next.settled) {
|
|
115492
115771
|
next.resolve();
|
|
115493
115772
|
return;
|
|
@@ -115681,7 +115960,8 @@ async function tryFallbackRetry(args) {
|
|
|
115681
115960
|
});
|
|
115682
115961
|
throw new TeamModeFallbackError(`team-mode fallback denied: cannot preserve team context for task ${task.id} (teamRunId=${task.teamRunId})`);
|
|
115683
115962
|
}
|
|
115684
|
-
const
|
|
115963
|
+
const rawKey = task.model ? `${task.model.providerID}/${task.model.modelID}` : task.agent;
|
|
115964
|
+
const key = concurrencyManager.getConcurrencyKey(rawKey);
|
|
115685
115965
|
const queue = queuesByKey.get(key) ?? [];
|
|
115686
115966
|
const retryInput = {
|
|
115687
115967
|
description: task.description,
|
|
@@ -116337,8 +116617,13 @@ function scheduleForcedExit(cleanupResult, exitCode, exitAfterCleanup = false) {
|
|
|
116337
116617
|
}
|
|
116338
116618
|
});
|
|
116339
116619
|
}
|
|
116620
|
+
var _shutdownInProgress = false;
|
|
116621
|
+
function markShutdownStarted() {
|
|
116622
|
+
_shutdownInProgress = true;
|
|
116623
|
+
}
|
|
116340
116624
|
function registerProcessSignal(signal, handler, exitAfter) {
|
|
116341
116625
|
const listener = () => {
|
|
116626
|
+
markShutdownStarted();
|
|
116342
116627
|
const cleanupResult = handler();
|
|
116343
116628
|
if (exitAfter) {
|
|
116344
116629
|
scheduleForcedExit(cleanupResult, 0, true);
|
|
@@ -116365,11 +116650,32 @@ function describeProcessCleanupError(error) {
|
|
|
116365
116650
|
}
|
|
116366
116651
|
return { raw: String(error) };
|
|
116367
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
|
+
}
|
|
116368
116672
|
function registerErrorEvent(signal) {
|
|
116369
116673
|
let logging = false;
|
|
116370
116674
|
const listener = (error) => {
|
|
116371
116675
|
if (logging)
|
|
116372
116676
|
return;
|
|
116677
|
+
if (isHarmlessShutdownError(error))
|
|
116678
|
+
return;
|
|
116373
116679
|
logging = true;
|
|
116374
116680
|
log(`[background-agent] ${signal} observed; keeping host alive and skipping cleanup (signal handlers run on real shutdown)`, describeProcessCleanupError(error));
|
|
116375
116681
|
logging = false;
|
|
@@ -116394,9 +116700,13 @@ function registerManagerForCleanup(manager) {
|
|
|
116394
116700
|
for (const m of cleanupManagers) {
|
|
116395
116701
|
try {
|
|
116396
116702
|
promises.push(Promise.resolve(m.shutdown()).catch((error) => {
|
|
116703
|
+
if (isHarmlessShutdownError(error))
|
|
116704
|
+
return;
|
|
116397
116705
|
log("[background-agent] Error during async shutdown cleanup:", error);
|
|
116398
116706
|
}));
|
|
116399
116707
|
} catch (error) {
|
|
116708
|
+
if (isHarmlessShutdownError(error))
|
|
116709
|
+
continue;
|
|
116400
116710
|
log("[background-agent] Error during shutdown cleanup:", error);
|
|
116401
116711
|
}
|
|
116402
116712
|
}
|
|
@@ -118089,10 +118399,8 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118089
118399
|
};
|
|
118090
118400
|
}
|
|
118091
118401
|
getConcurrencyKeyFromInput(input) {
|
|
118092
|
-
|
|
118093
|
-
|
|
118094
|
-
}
|
|
118095
|
-
return input.agent;
|
|
118402
|
+
const modelKey = input.model ? `${input.model.providerID}/${input.model.modelID}` : input.agent;
|
|
118403
|
+
return this.concurrencyManager.getConcurrencyKey(modelKey);
|
|
118096
118404
|
}
|
|
118097
118405
|
async trackTask(input) {
|
|
118098
118406
|
const existingTask = this.tasks.get(input.taskId);
|
|
@@ -118106,7 +118414,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118106
118414
|
existingTask.parentAgent = input.parentAgent;
|
|
118107
118415
|
}
|
|
118108
118416
|
if (!existingTask.concurrencyGroup) {
|
|
118109
|
-
existingTask.concurrencyGroup = input.concurrencyKey
|
|
118417
|
+
existingTask.concurrencyGroup = input.concurrencyKey ? this.concurrencyManager.getConcurrencyKey(input.concurrencyKey) : existingTask.agent;
|
|
118110
118418
|
}
|
|
118111
118419
|
if (existingTask.sessionId) {
|
|
118112
118420
|
subagentSessions.add(existingTask.sessionId);
|
|
@@ -118122,9 +118430,10 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118122
118430
|
log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.sessionId, status: existingTask.status });
|
|
118123
118431
|
return existingTask;
|
|
118124
118432
|
}
|
|
118125
|
-
const
|
|
118126
|
-
|
|
118127
|
-
|
|
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);
|
|
118128
118437
|
}
|
|
118129
118438
|
const task = {
|
|
118130
118439
|
id: input.taskId,
|
|
@@ -118141,7 +118450,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118141
118450
|
lastUpdate: new Date
|
|
118142
118451
|
},
|
|
118143
118452
|
parentAgent: input.parentAgent,
|
|
118144
|
-
concurrencyKey
|
|
118453
|
+
concurrencyKey,
|
|
118145
118454
|
concurrencyGroup
|
|
118146
118455
|
};
|
|
118147
118456
|
this.addTask(task);
|
|
@@ -118177,7 +118486,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
118177
118486
|
clearTimeout(completionTimer);
|
|
118178
118487
|
this.completionTimers.delete(existingTask.id);
|
|
118179
118488
|
}
|
|
118180
|
-
const concurrencyKey = existingTask.concurrencyGroup ?? existingTask.agent;
|
|
118489
|
+
const concurrencyKey = this.concurrencyManager.getConcurrencyKey(existingTask.concurrencyGroup ?? existingTask.agent);
|
|
118181
118490
|
await this.concurrencyManager.acquire(concurrencyKey);
|
|
118182
118491
|
existingTask.concurrencyKey = concurrencyKey;
|
|
118183
118492
|
existingTask.concurrencyGroup = concurrencyKey;
|
|
@@ -119203,7 +119512,7 @@ The task was re-queued on a fallback model after a retryable failure.
|
|
|
119203
119512
|
parentSessionID: task.parentSessionId
|
|
119204
119513
|
});
|
|
119205
119514
|
}
|
|
119206
|
-
const messageDir =
|
|
119515
|
+
const messageDir = join95(MESSAGE_STORAGE, task.parentSessionId);
|
|
119207
119516
|
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionId) : null;
|
|
119208
119517
|
agent = currentMessage?.agent ?? task.parentAgent;
|
|
119209
119518
|
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
@@ -119546,11 +119855,11 @@ The task was re-queued on a fallback model after a retryable failure.
|
|
|
119546
119855
|
}
|
|
119547
119856
|
// src/features/mcp-oauth/storage.ts
|
|
119548
119857
|
init_shared();
|
|
119549
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
119550
|
-
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";
|
|
119551
119860
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
119552
119861
|
function getMcpOauthStoragePath() {
|
|
119553
|
-
return
|
|
119862
|
+
return join96(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
|
|
119554
119863
|
}
|
|
119555
119864
|
function normalizeHost(serverHost) {
|
|
119556
119865
|
let host = serverHost.trim();
|
|
@@ -119587,11 +119896,11 @@ function buildKey(serverHost, resource) {
|
|
|
119587
119896
|
}
|
|
119588
119897
|
function readStore() {
|
|
119589
119898
|
const filePath = getMcpOauthStoragePath();
|
|
119590
|
-
if (!
|
|
119899
|
+
if (!existsSync87(filePath)) {
|
|
119591
119900
|
return null;
|
|
119592
119901
|
}
|
|
119593
119902
|
try {
|
|
119594
|
-
const content =
|
|
119903
|
+
const content = readFileSync63(filePath, "utf-8");
|
|
119595
119904
|
return JSON.parse(content);
|
|
119596
119905
|
} catch {
|
|
119597
119906
|
return null;
|
|
@@ -119601,7 +119910,7 @@ function writeStore(store2) {
|
|
|
119601
119910
|
const filePath = getMcpOauthStoragePath();
|
|
119602
119911
|
try {
|
|
119603
119912
|
const dir = dirname33(filePath);
|
|
119604
|
-
if (!
|
|
119913
|
+
if (!existsSync87(dir)) {
|
|
119605
119914
|
mkdirSync19(dir, { recursive: true });
|
|
119606
119915
|
}
|
|
119607
119916
|
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
@@ -125490,8 +125799,33 @@ async function executeActions(actions, ctx) {
|
|
|
125490
125799
|
// src/features/tmux-subagent/polling-manager.ts
|
|
125491
125800
|
init_tmux();
|
|
125492
125801
|
init_shared();
|
|
125493
|
-
init_shared();
|
|
125494
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
|
|
125495
125829
|
var MIN_STABILITY_TIME_MS3 = 10 * 1000;
|
|
125496
125830
|
var STABLE_POLLS_REQUIRED = 3;
|
|
125497
125831
|
|
|
@@ -125547,7 +125881,7 @@ class TmuxPollingManager {
|
|
|
125547
125881
|
}
|
|
125548
125882
|
await this.activateFocusedPanes();
|
|
125549
125883
|
const statusResult = await this.client.session.status({ path: undefined });
|
|
125550
|
-
const allStatuses =
|
|
125884
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
125551
125885
|
log("[tmux-session-manager] pollSessions", {
|
|
125552
125886
|
trackedSessions: Array.from(this.sessions.keys()),
|
|
125553
125887
|
allStatusKeys: Object.keys(allStatuses)
|
|
@@ -125594,7 +125928,7 @@ class TmuxPollingManager {
|
|
|
125594
125928
|
if ((tracked.stableIdlePolls ?? 0) >= STABLE_POLLS_REQUIRED) {
|
|
125595
125929
|
const stableWindowActivityVersion = tracked.observedIdleActivityVersion ?? activityVersion;
|
|
125596
125930
|
const recheckResult = await this.client.session.status({ path: undefined });
|
|
125597
|
-
const recheckStatuses =
|
|
125931
|
+
const recheckStatuses = parseSessionStatusResponse(recheckResult);
|
|
125598
125932
|
const recheckStatus = recheckStatuses[sessionId];
|
|
125599
125933
|
const latestTracked = this.sessions.get(sessionId) ?? tracked;
|
|
125600
125934
|
const recheckActivityVersion = latestTracked.activityVersion ?? 0;
|
|
@@ -125735,36 +126069,18 @@ init_tmux();
|
|
|
125735
126069
|
init_shared();
|
|
125736
126070
|
|
|
125737
126071
|
// src/features/tmux-subagent/attachable-session-status.ts
|
|
125738
|
-
var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy"];
|
|
126072
|
+
var ATTACHABLE_SESSION_STATUSES = ["idle", "running", "busy", "retry"];
|
|
125739
126073
|
function isAttachableSessionStatus(status) {
|
|
125740
126074
|
return ATTACHABLE_SESSION_STATUSES.some((attachableSessionStatus) => attachableSessionStatus === status);
|
|
125741
126075
|
}
|
|
125742
126076
|
|
|
125743
|
-
// src/features/tmux-subagent/session-status-parser.ts
|
|
125744
|
-
function parseSessionStatusMap(data) {
|
|
125745
|
-
if (typeof data !== "object" || data === null)
|
|
125746
|
-
return {};
|
|
125747
|
-
const record3 = data;
|
|
125748
|
-
const result = {};
|
|
125749
|
-
for (const [sessionId, value] of Object.entries(record3)) {
|
|
125750
|
-
if (typeof value !== "object" || value === null)
|
|
125751
|
-
continue;
|
|
125752
|
-
const valueRecord = value;
|
|
125753
|
-
const type2 = valueRecord["type"];
|
|
125754
|
-
if (typeof type2 !== "string")
|
|
125755
|
-
continue;
|
|
125756
|
-
result[sessionId] = { type: type2 };
|
|
125757
|
-
}
|
|
125758
|
-
return result;
|
|
125759
|
-
}
|
|
125760
|
-
|
|
125761
126077
|
// src/features/tmux-subagent/session-ready-waiter.ts
|
|
125762
126078
|
async function waitForSessionReady(params) {
|
|
125763
126079
|
const startTime = Date.now();
|
|
125764
126080
|
while (Date.now() - startTime < SESSION_READY_TIMEOUT_MS) {
|
|
125765
126081
|
try {
|
|
125766
126082
|
const statusResult = await params.client.session.status({ path: undefined });
|
|
125767
|
-
const allStatuses =
|
|
126083
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
125768
126084
|
const sessionStatus = allStatuses[params.sessionId]?.type;
|
|
125769
126085
|
if (isAttachableSessionStatus(sessionStatus)) {
|
|
125770
126086
|
log("[tmux-session-manager] session ready", {
|
|
@@ -126273,7 +126589,7 @@ class TmuxSessionManager {
|
|
|
126273
126589
|
async getSessionStatusType(sessionId) {
|
|
126274
126590
|
try {
|
|
126275
126591
|
const statusResult = await this.client.session.status({ path: undefined });
|
|
126276
|
-
const allStatuses =
|
|
126592
|
+
const allStatuses = parseSessionStatusResponse(statusResult);
|
|
126277
126593
|
return allStatuses[sessionId]?.type;
|
|
126278
126594
|
} catch (error) {
|
|
126279
126595
|
this.deps.log("[tmux-session-manager] failed to read session status before spawn", {
|
|
@@ -127179,14 +127495,14 @@ async function isTmuxAvailable() {
|
|
|
127179
127495
|
}
|
|
127180
127496
|
|
|
127181
127497
|
// src/openclaw/reply-listener.ts
|
|
127182
|
-
import { dirname as dirname35, join as
|
|
127498
|
+
import { dirname as dirname35, join as join99 } from "path";
|
|
127183
127499
|
|
|
127184
127500
|
// src/openclaw/session-registry.ts
|
|
127185
127501
|
init_data_path();
|
|
127186
127502
|
import {
|
|
127187
|
-
existsSync as
|
|
127503
|
+
existsSync as existsSync88,
|
|
127188
127504
|
mkdirSync as mkdirSync20,
|
|
127189
|
-
readFileSync as
|
|
127505
|
+
readFileSync as readFileSync64,
|
|
127190
127506
|
writeFileSync as writeFileSync22,
|
|
127191
127507
|
openSync as openSync3,
|
|
127192
127508
|
closeSync as closeSync3,
|
|
@@ -127195,11 +127511,11 @@ import {
|
|
|
127195
127511
|
statSync as statSync12,
|
|
127196
127512
|
constants as constants20
|
|
127197
127513
|
} from "fs";
|
|
127198
|
-
import { join as
|
|
127514
|
+
import { join as join97, dirname as dirname34 } from "path";
|
|
127199
127515
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
127200
|
-
var OPENCLAW_STORAGE_DIR =
|
|
127201
|
-
var REGISTRY_PATH =
|
|
127202
|
-
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");
|
|
127203
127519
|
var SECURE_FILE_MODE = 384;
|
|
127204
127520
|
var MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
127205
127521
|
var LOCK_TIMEOUT_MS = 2000;
|
|
@@ -127208,7 +127524,7 @@ var LOCK_RETRY_MS2 = 20;
|
|
|
127208
127524
|
var LOCK_STALE_MS = 1e4;
|
|
127209
127525
|
function ensureRegistryDir() {
|
|
127210
127526
|
const registryDir = dirname34(REGISTRY_PATH);
|
|
127211
|
-
if (!
|
|
127527
|
+
if (!existsSync88(registryDir)) {
|
|
127212
127528
|
mkdirSync20(registryDir, { recursive: true, mode: 448 });
|
|
127213
127529
|
}
|
|
127214
127530
|
}
|
|
@@ -127227,9 +127543,9 @@ function isPidAlive2(pid) {
|
|
|
127227
127543
|
}
|
|
127228
127544
|
function readLockSnapshot() {
|
|
127229
127545
|
try {
|
|
127230
|
-
if (!
|
|
127546
|
+
if (!existsSync88(REGISTRY_LOCK_PATH))
|
|
127231
127547
|
return null;
|
|
127232
|
-
const raw =
|
|
127548
|
+
const raw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
|
|
127233
127549
|
const trimmed = raw.trim();
|
|
127234
127550
|
if (!trimmed)
|
|
127235
127551
|
return { raw, pid: null, token: null };
|
|
@@ -127253,9 +127569,9 @@ function readLockSnapshot() {
|
|
|
127253
127569
|
}
|
|
127254
127570
|
function removeLockIfUnchanged(snapshot) {
|
|
127255
127571
|
try {
|
|
127256
|
-
if (!
|
|
127572
|
+
if (!existsSync88(REGISTRY_LOCK_PATH))
|
|
127257
127573
|
return false;
|
|
127258
|
-
const currentRaw =
|
|
127574
|
+
const currentRaw = readFileSync64(REGISTRY_LOCK_PATH, "utf-8");
|
|
127259
127575
|
if (currentRaw !== snapshot.raw)
|
|
127260
127576
|
return false;
|
|
127261
127577
|
unlinkSync17(REGISTRY_LOCK_PATH);
|
|
@@ -127359,10 +127675,10 @@ function withRegistryLock(onLocked, onLockUnavailable) {
|
|
|
127359
127675
|
}
|
|
127360
127676
|
}
|
|
127361
127677
|
function readAllMappingsUnsafe() {
|
|
127362
|
-
if (!
|
|
127678
|
+
if (!existsSync88(REGISTRY_PATH))
|
|
127363
127679
|
return [];
|
|
127364
127680
|
try {
|
|
127365
|
-
const content =
|
|
127681
|
+
const content = readFileSync64(REGISTRY_PATH, "utf-8");
|
|
127366
127682
|
return content.split(`
|
|
127367
127683
|
`).filter((line) => line.trim()).map((line) => {
|
|
127368
127684
|
try {
|
|
@@ -127417,7 +127733,7 @@ function removeSession(sessionId) {
|
|
|
127417
127733
|
import {
|
|
127418
127734
|
appendFileSync as appendFileSync6,
|
|
127419
127735
|
chmodSync as chmodSync3,
|
|
127420
|
-
existsSync as
|
|
127736
|
+
existsSync as existsSync90,
|
|
127421
127737
|
renameSync as renameSync8,
|
|
127422
127738
|
statSync as statSync13,
|
|
127423
127739
|
unlinkSync as unlinkSync18,
|
|
@@ -127425,31 +127741,31 @@ import {
|
|
|
127425
127741
|
} from "fs";
|
|
127426
127742
|
|
|
127427
127743
|
// src/openclaw/reply-listener-paths.ts
|
|
127428
|
-
import { existsSync as
|
|
127744
|
+
import { existsSync as existsSync89, mkdirSync as mkdirSync21 } from "fs";
|
|
127429
127745
|
import { homedir as homedir19 } from "os";
|
|
127430
|
-
import { join as
|
|
127746
|
+
import { join as join98 } from "path";
|
|
127431
127747
|
var REPLY_LISTENER_SECURE_FILE_MODE = 384;
|
|
127432
127748
|
function resolveReplyListenerHomeDir() {
|
|
127433
127749
|
return process.env.HOME ?? process.env.USERPROFILE ?? homedir19();
|
|
127434
127750
|
}
|
|
127435
127751
|
function getReplyListenerStateDir() {
|
|
127436
|
-
return
|
|
127752
|
+
return join98(resolveReplyListenerHomeDir(), ".omo", "openclaw", "state");
|
|
127437
127753
|
}
|
|
127438
127754
|
function getReplyListenerPidFilePath() {
|
|
127439
|
-
return
|
|
127755
|
+
return join98(getReplyListenerStateDir(), "reply-listener.pid");
|
|
127440
127756
|
}
|
|
127441
127757
|
function getReplyListenerStateFilePath() {
|
|
127442
|
-
return
|
|
127758
|
+
return join98(getReplyListenerStateDir(), "reply-listener-state.json");
|
|
127443
127759
|
}
|
|
127444
127760
|
function getReplyListenerConfigFilePath() {
|
|
127445
|
-
return
|
|
127761
|
+
return join98(getReplyListenerStateDir(), "reply-listener-config.json");
|
|
127446
127762
|
}
|
|
127447
127763
|
function getReplyListenerLogFilePath() {
|
|
127448
|
-
return
|
|
127764
|
+
return join98(getReplyListenerStateDir(), "reply-listener.log");
|
|
127449
127765
|
}
|
|
127450
127766
|
function ensureReplyListenerStateDir() {
|
|
127451
127767
|
const stateDir = getReplyListenerStateDir();
|
|
127452
|
-
if (!
|
|
127768
|
+
if (!existsSync89(stateDir)) {
|
|
127453
127769
|
mkdirSync21(stateDir, { recursive: true, mode: 448 });
|
|
127454
127770
|
}
|
|
127455
127771
|
}
|
|
@@ -127465,13 +127781,13 @@ function writeSecureReplyListenerFile(filePath, content) {
|
|
|
127465
127781
|
}
|
|
127466
127782
|
function rotateReplyListenerLogIfNeeded(logPath) {
|
|
127467
127783
|
try {
|
|
127468
|
-
if (!
|
|
127784
|
+
if (!existsSync90(logPath))
|
|
127469
127785
|
return;
|
|
127470
127786
|
const stats = statSync13(logPath);
|
|
127471
127787
|
if (stats.size <= MAX_REPLY_LISTENER_LOG_SIZE_BYTES)
|
|
127472
127788
|
return;
|
|
127473
127789
|
const backupPath = `${logPath}.old`;
|
|
127474
|
-
if (
|
|
127790
|
+
if (existsSync90(backupPath)) {
|
|
127475
127791
|
unlinkSync18(backupPath);
|
|
127476
127792
|
}
|
|
127477
127793
|
renameSync8(logPath, backupPath);
|
|
@@ -127512,7 +127828,7 @@ class ReplyListenerRateLimiter {
|
|
|
127512
127828
|
}
|
|
127513
127829
|
|
|
127514
127830
|
// src/openclaw/reply-listener-state.ts
|
|
127515
|
-
import { existsSync as
|
|
127831
|
+
import { existsSync as existsSync91, readFileSync as readFileSync65, unlinkSync as unlinkSync19 } from "fs";
|
|
127516
127832
|
var REPLY_LISTENER_STARTUP_TOKEN_ENV = "OMO_OPENCLAW_REPLY_LISTENER_STARTUP_TOKEN";
|
|
127517
127833
|
function createDefaultReplyListenerState() {
|
|
127518
127834
|
return {
|
|
@@ -127574,9 +127890,9 @@ function createPendingReplyListenerState(startupToken) {
|
|
|
127574
127890
|
function readReplyListenerDaemonState() {
|
|
127575
127891
|
try {
|
|
127576
127892
|
const stateFilePath = getReplyListenerStateFilePath();
|
|
127577
|
-
if (!
|
|
127893
|
+
if (!existsSync91(stateFilePath))
|
|
127578
127894
|
return null;
|
|
127579
|
-
return normalizeReplyListenerState(JSON.parse(
|
|
127895
|
+
return normalizeReplyListenerState(JSON.parse(readFileSync65(stateFilePath, "utf-8")));
|
|
127580
127896
|
} catch {
|
|
127581
127897
|
return null;
|
|
127582
127898
|
}
|
|
@@ -127591,9 +127907,9 @@ function writeReplyListenerDaemonState(state3) {
|
|
|
127591
127907
|
function readReplyListenerDaemonConfig() {
|
|
127592
127908
|
try {
|
|
127593
127909
|
const configFilePath = getReplyListenerConfigFilePath();
|
|
127594
|
-
if (!
|
|
127910
|
+
if (!existsSync91(configFilePath))
|
|
127595
127911
|
return null;
|
|
127596
|
-
return JSON.parse(
|
|
127912
|
+
return JSON.parse(readFileSync65(configFilePath, "utf-8"));
|
|
127597
127913
|
} catch {
|
|
127598
127914
|
return null;
|
|
127599
127915
|
}
|
|
@@ -127604,9 +127920,9 @@ function writeReplyListenerDaemonConfig(config) {
|
|
|
127604
127920
|
function readReplyListenerPid() {
|
|
127605
127921
|
try {
|
|
127606
127922
|
const pidFilePath = getReplyListenerPidFilePath();
|
|
127607
|
-
if (!
|
|
127923
|
+
if (!existsSync91(pidFilePath))
|
|
127608
127924
|
return null;
|
|
127609
|
-
const pid = Number.parseInt(
|
|
127925
|
+
const pid = Number.parseInt(readFileSync65(pidFilePath, "utf-8").trim(), 10);
|
|
127610
127926
|
return Number.isNaN(pid) ? null : pid;
|
|
127611
127927
|
} catch {
|
|
127612
127928
|
return null;
|
|
@@ -127617,7 +127933,7 @@ function writeReplyListenerPid(pid) {
|
|
|
127617
127933
|
}
|
|
127618
127934
|
function removeReplyListenerPid() {
|
|
127619
127935
|
const pidFilePath = getReplyListenerPidFilePath();
|
|
127620
|
-
if (
|
|
127936
|
+
if (existsSync91(pidFilePath)) {
|
|
127621
127937
|
unlinkSync19(pidFilePath);
|
|
127622
127938
|
}
|
|
127623
127939
|
}
|
|
@@ -127634,7 +127950,7 @@ function markReplyListenerStopped(state3, error) {
|
|
|
127634
127950
|
|
|
127635
127951
|
// src/openclaw/reply-listener-process.ts
|
|
127636
127952
|
init_bun_spawn_shim();
|
|
127637
|
-
import { readFileSync as
|
|
127953
|
+
import { readFileSync as readFileSync66 } from "fs";
|
|
127638
127954
|
var REPLY_LISTENER_DAEMON_IDENTITY_MARKER = "--openclaw-reply-listener-daemon";
|
|
127639
127955
|
var REPLY_LISTENER_DAEMON_ENV_ALLOWLIST = [
|
|
127640
127956
|
"PATH",
|
|
@@ -127689,7 +128005,7 @@ function isReplyListenerProcessRunning(pid) {
|
|
|
127689
128005
|
async function isReplyListenerDaemonProcess(pid) {
|
|
127690
128006
|
try {
|
|
127691
128007
|
if (process.platform === "linux") {
|
|
127692
|
-
const cmdline =
|
|
128008
|
+
const cmdline = readFileSync66(`/proc/${pid}/cmdline`, "utf-8");
|
|
127693
128009
|
return cmdline.includes(REPLY_LISTENER_DAEMON_IDENTITY_MARKER);
|
|
127694
128010
|
}
|
|
127695
128011
|
const processInfo = spawn2(["ps", "-p", String(pid), "-o", "args="], {
|
|
@@ -127851,7 +128167,7 @@ async function startReplyListener(config) {
|
|
|
127851
128167
|
pendingState.configSignature = getReplyListenerRuntimeSignature(normalizedConfig);
|
|
127852
128168
|
writeReplyListenerDaemonState(pendingState);
|
|
127853
128169
|
const currentFile = import.meta.url;
|
|
127854
|
-
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");
|
|
127855
128171
|
try {
|
|
127856
128172
|
const processInfo = spawnReplyListenerDaemon(daemonScript, startupToken);
|
|
127857
128173
|
processInfo.unref();
|
|
@@ -128235,21 +128551,21 @@ init_transformer();
|
|
|
128235
128551
|
init_logger();
|
|
128236
128552
|
init_scope_filter2();
|
|
128237
128553
|
init_bun_file_shim();
|
|
128238
|
-
import { existsSync as
|
|
128239
|
-
import { join as
|
|
128554
|
+
import { existsSync as existsSync92, readFileSync as readFileSync67 } from "fs";
|
|
128555
|
+
import { join as join100 } from "path";
|
|
128240
128556
|
import { homedir as homedir20 } from "os";
|
|
128241
128557
|
function getMcpConfigPaths() {
|
|
128242
128558
|
const claudeConfigDir = getClaudeConfigDir();
|
|
128243
128559
|
const cwd = process.cwd();
|
|
128244
128560
|
return [
|
|
128245
|
-
{ path:
|
|
128246
|
-
{ path:
|
|
128247
|
-
{ path:
|
|
128248
|
-
{ 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" }
|
|
128249
128565
|
];
|
|
128250
128566
|
}
|
|
128251
128567
|
async function loadMcpConfigFile(filePath) {
|
|
128252
|
-
if (!
|
|
128568
|
+
if (!existsSync92(filePath)) {
|
|
128253
128569
|
return null;
|
|
128254
128570
|
}
|
|
128255
128571
|
try {
|
|
@@ -128264,11 +128580,11 @@ function getSystemMcpServerNames() {
|
|
|
128264
128580
|
const names = new Set;
|
|
128265
128581
|
const paths = getMcpConfigPaths();
|
|
128266
128582
|
const cwd = process.cwd();
|
|
128267
|
-
for (const { path:
|
|
128268
|
-
if (!
|
|
128583
|
+
for (const { path: path22 } of paths) {
|
|
128584
|
+
if (!existsSync92(path22))
|
|
128269
128585
|
continue;
|
|
128270
128586
|
try {
|
|
128271
|
-
const content =
|
|
128587
|
+
const content = readFileSync67(path22, "utf-8");
|
|
128272
128588
|
const config = JSON.parse(content);
|
|
128273
128589
|
if (!config?.mcpServers)
|
|
128274
128590
|
continue;
|
|
@@ -128293,30 +128609,30 @@ async function loadMcpConfigs(disabledMcps = []) {
|
|
|
128293
128609
|
const paths = getMcpConfigPaths();
|
|
128294
128610
|
const disabledSet = new Set(disabledMcps);
|
|
128295
128611
|
const cwd = process.cwd();
|
|
128296
|
-
for (const { path:
|
|
128297
|
-
const config = await loadMcpConfigFile(
|
|
128612
|
+
for (const { path: path22, scope } of paths) {
|
|
128613
|
+
const config = await loadMcpConfigFile(path22);
|
|
128298
128614
|
if (!config?.mcpServers)
|
|
128299
128615
|
continue;
|
|
128300
128616
|
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
128301
128617
|
if (disabledSet.has(name)) {
|
|
128302
|
-
log(`Skipping MCP "${name}" (in disabled_mcps)`, { path:
|
|
128618
|
+
log(`Skipping MCP "${name}" (in disabled_mcps)`, { path: path22 });
|
|
128303
128619
|
continue;
|
|
128304
128620
|
}
|
|
128305
128621
|
if (!shouldLoadMcpServer(serverConfig, cwd)) {
|
|
128306
128622
|
log(`Skipping MCP server "${name}" because local scope does not match cwd`, {
|
|
128307
|
-
path:
|
|
128623
|
+
path: path22,
|
|
128308
128624
|
projectPath: serverConfig.projectPath,
|
|
128309
128625
|
cwd
|
|
128310
128626
|
});
|
|
128311
128627
|
continue;
|
|
128312
128628
|
}
|
|
128313
128629
|
if (serverConfig.disabled) {
|
|
128314
|
-
log(`Disabling MCP server "${name}"`, { path:
|
|
128630
|
+
log(`Disabling MCP server "${name}"`, { path: path22 });
|
|
128315
128631
|
delete servers[name];
|
|
128316
128632
|
const existingIndex = loadedServers.findIndex((s) => s.name === name);
|
|
128317
128633
|
if (existingIndex !== -1) {
|
|
128318
128634
|
loadedServers.splice(existingIndex, 1);
|
|
128319
|
-
log(`Removed previously loaded MCP server "${name}"`, { path:
|
|
128635
|
+
log(`Removed previously loaded MCP server "${name}"`, { path: path22 });
|
|
128320
128636
|
}
|
|
128321
128637
|
continue;
|
|
128322
128638
|
}
|
|
@@ -128328,7 +128644,7 @@ async function loadMcpConfigs(disabledMcps = []) {
|
|
|
128328
128644
|
loadedServers.splice(existingIndex, 1);
|
|
128329
128645
|
}
|
|
128330
128646
|
loadedServers.push({ name, scope, config: transformed });
|
|
128331
|
-
log(`Loaded MCP server "${name}" from ${scope}`, { path:
|
|
128647
|
+
log(`Loaded MCP server "${name}" from ${scope}`, { path: path22 });
|
|
128332
128648
|
} catch (error) {
|
|
128333
128649
|
log(`Failed to transform MCP server "${name}"`, error);
|
|
128334
128650
|
}
|
|
@@ -130108,6 +130424,8 @@ Each exploration prompt should include four fields: **CONTEXT** (what task, whic
|
|
|
130108
130424
|
|
|
130109
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.
|
|
130110
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
|
+
|
|
130111
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.
|
|
130112
130430
|
|
|
130113
130431
|
### Tool persistence
|
|
@@ -134617,7 +134935,7 @@ createHephaestusAgent2.mode = MODE10;
|
|
|
134617
134935
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
134618
134936
|
init_contains_path2();
|
|
134619
134937
|
init_logger();
|
|
134620
|
-
import { existsSync as
|
|
134938
|
+
import { existsSync as existsSync93, readFileSync as readFileSync68 } from "fs";
|
|
134621
134939
|
import { homedir as homedir21 } from "os";
|
|
134622
134940
|
import { isAbsolute as isAbsolute18, resolve as resolve25 } from "path";
|
|
134623
134941
|
function resolvePromptAppend(promptAppend, configDir) {
|
|
@@ -134641,11 +134959,11 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
134641
134959
|
});
|
|
134642
134960
|
return `[WARNING: Path rejected: ${promptAppend} (resolved outside project root ${projectRoot}; file:// prompts must reside within the project boundary)]`;
|
|
134643
134961
|
}
|
|
134644
|
-
if (!
|
|
134962
|
+
if (!existsSync93(filePath)) {
|
|
134645
134963
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
134646
134964
|
}
|
|
134647
134965
|
try {
|
|
134648
|
-
return
|
|
134966
|
+
return readFileSync68(filePath, "utf8");
|
|
134649
134967
|
} catch {
|
|
134650
134968
|
return `[WARNING: Could not read file: ${promptAppend}]`;
|
|
134651
134969
|
}
|
|
@@ -135921,7 +136239,7 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
|
|
|
135921
136239
|
location: "plugin"
|
|
135922
136240
|
}));
|
|
135923
136241
|
const discoveredAvailable = discoveredSkills.filter((s) => {
|
|
135924
|
-
if (
|
|
136242
|
+
if (disabledSkills?.has(s.name))
|
|
135925
136243
|
return false;
|
|
135926
136244
|
if (agentName && s.definition.agent && s.definition.agent !== agentName)
|
|
135927
136245
|
return false;
|
|
@@ -135931,7 +136249,10 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills,
|
|
|
135931
136249
|
description: skill2.definition.description ?? "",
|
|
135932
136250
|
location: mapScopeToLocation(skill2.scope)
|
|
135933
136251
|
}));
|
|
135934
|
-
|
|
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());
|
|
135935
136256
|
}
|
|
135936
136257
|
|
|
135937
136258
|
// src/agents/builtin-agents/general-agents.ts
|
|
@@ -136806,7 +137127,7 @@ function buildPlanDemoteConfig(prometheusConfig, planOverride) {
|
|
|
136806
137127
|
}
|
|
136807
137128
|
|
|
136808
137129
|
// src/shared/host-skill-config.ts
|
|
136809
|
-
function
|
|
137130
|
+
function toStringArray2(value) {
|
|
136810
137131
|
if (!Array.isArray(value))
|
|
136811
137132
|
return [];
|
|
136812
137133
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
@@ -136815,10 +137136,7 @@ function adaptHostSkillConfig(value) {
|
|
|
136815
137136
|
if (!value || typeof value !== "object")
|
|
136816
137137
|
return;
|
|
136817
137138
|
const hostSkillConfig = value;
|
|
136818
|
-
const sources =
|
|
136819
|
-
...toStringArray(hostSkillConfig.paths),
|
|
136820
|
-
...toStringArray(hostSkillConfig.urls)
|
|
136821
|
-
];
|
|
137139
|
+
const sources = toStringArray2(hostSkillConfig.paths);
|
|
136822
137140
|
if (sources.length === 0)
|
|
136823
137141
|
return;
|
|
136824
137142
|
return { sources };
|
|
@@ -136863,7 +137181,7 @@ async function applyAgentConfig(params) {
|
|
|
136863
137181
|
discoverOpencodeProjectSkills(params.ctx.directory),
|
|
136864
137182
|
includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([])
|
|
136865
137183
|
]);
|
|
136866
|
-
const allDiscoveredSkills = [
|
|
137184
|
+
const allDiscoveredSkills = deduplicateSkillsByName([
|
|
136867
137185
|
...discoveredConfigSourceSkills,
|
|
136868
137186
|
...discoveredHostConfigSkills,
|
|
136869
137187
|
...discoveredOpencodeProjectSkills,
|
|
@@ -136872,7 +137190,7 @@ async function applyAgentConfig(params) {
|
|
|
136872
137190
|
...discoveredOpencodeGlobalSkills,
|
|
136873
137191
|
...discoveredUserSkills,
|
|
136874
137192
|
...discoveredGlobalAgentsSkills
|
|
136875
|
-
];
|
|
137193
|
+
]);
|
|
136876
137194
|
const browserProvider = params.pluginConfig.browser_automation_engine?.provider ?? "playwright";
|
|
136877
137195
|
const currentModel = params.config.model;
|
|
136878
137196
|
const disabledSkills = new Set(params.pluginConfig.disabled_skills ?? []);
|
|
@@ -137045,6 +137363,7 @@ async function applyAgentConfig(params) {
|
|
|
137045
137363
|
setDefaultAgentForSort(params.config.default_agent ?? configuredDefaultAgent);
|
|
137046
137364
|
}
|
|
137047
137365
|
const agentResult = params.config.agent;
|
|
137366
|
+
clearRegisteredAgentNames();
|
|
137048
137367
|
for (const name of Object.keys(agentResult)) {
|
|
137049
137368
|
registerAgentName(name);
|
|
137050
137369
|
}
|
|
@@ -137060,8 +137379,8 @@ init_model_sanitizer();
|
|
|
137060
137379
|
init_file_utils2();
|
|
137061
137380
|
init_shared();
|
|
137062
137381
|
init_logger();
|
|
137063
|
-
import { promises as
|
|
137064
|
-
import { join as
|
|
137382
|
+
import { promises as fs23 } from "fs";
|
|
137383
|
+
import { join as join101, basename as basename16 } from "path";
|
|
137065
137384
|
|
|
137066
137385
|
// src/features/claude-code-command-loader/loader-cache.ts
|
|
137067
137386
|
var commandLoaderCache = new Map;
|
|
@@ -137069,13 +137388,13 @@ var commandLoaderCache = new Map;
|
|
|
137069
137388
|
// src/features/claude-code-command-loader/loader.ts
|
|
137070
137389
|
async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
|
|
137071
137390
|
try {
|
|
137072
|
-
await
|
|
137391
|
+
await fs23.access(commandsDir);
|
|
137073
137392
|
} catch {
|
|
137074
137393
|
return [];
|
|
137075
137394
|
}
|
|
137076
137395
|
let realPath;
|
|
137077
137396
|
try {
|
|
137078
|
-
realPath = await
|
|
137397
|
+
realPath = await fs23.realpath(commandsDir);
|
|
137079
137398
|
} catch (error) {
|
|
137080
137399
|
log(`Failed to resolve command directory: ${commandsDir}`, error);
|
|
137081
137400
|
return [];
|
|
@@ -137086,7 +137405,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
137086
137405
|
visited.add(realPath);
|
|
137087
137406
|
let entries;
|
|
137088
137407
|
try {
|
|
137089
|
-
entries = await
|
|
137408
|
+
entries = await fs23.readdir(commandsDir, { withFileTypes: true });
|
|
137090
137409
|
} catch (error) {
|
|
137091
137410
|
log(`Failed to read command directory: ${commandsDir}`, error);
|
|
137092
137411
|
return [];
|
|
@@ -137098,7 +137417,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
137098
137417
|
continue;
|
|
137099
137418
|
if (entry.name.startsWith("."))
|
|
137100
137419
|
continue;
|
|
137101
|
-
const subDirPath =
|
|
137420
|
+
const subDirPath = join101(commandsDir, entry.name);
|
|
137102
137421
|
const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
137103
137422
|
const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
|
|
137104
137423
|
commands2.push(...subCommands);
|
|
@@ -137106,11 +137425,11 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
137106
137425
|
}
|
|
137107
137426
|
if (!isMarkdownFile(entry))
|
|
137108
137427
|
continue;
|
|
137109
|
-
const commandPath =
|
|
137428
|
+
const commandPath = join101(commandsDir, entry.name);
|
|
137110
137429
|
const baseCommandName = basename16(entry.name, ".md");
|
|
137111
137430
|
const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
|
|
137112
137431
|
try {
|
|
137113
|
-
const content = await
|
|
137432
|
+
const content = await fs23.readFile(commandPath, "utf-8");
|
|
137114
137433
|
const { data, body } = parseFrontmatter(content);
|
|
137115
137434
|
const wrappedTemplate = `<command-instruction>
|
|
137116
137435
|
${body.trim()}
|
|
@@ -137165,12 +137484,12 @@ function commandsToRecord(commands2) {
|
|
|
137165
137484
|
return result;
|
|
137166
137485
|
}
|
|
137167
137486
|
async function loadUserCommands() {
|
|
137168
|
-
const userCommandsDir =
|
|
137487
|
+
const userCommandsDir = join101(getClaudeConfigDir(), "commands");
|
|
137169
137488
|
const commands2 = await loadCommandsFromDir(userCommandsDir, "user");
|
|
137170
137489
|
return commandsToRecord(commands2);
|
|
137171
137490
|
}
|
|
137172
137491
|
async function loadProjectCommands(directory) {
|
|
137173
|
-
const projectCommandsDir =
|
|
137492
|
+
const projectCommandsDir = join101(directory ?? process.cwd(), ".claude", "commands");
|
|
137174
137493
|
const commands2 = await loadCommandsFromDir(projectCommandsDir, "project");
|
|
137175
137494
|
return commandsToRecord(commands2);
|
|
137176
137495
|
}
|
|
@@ -137321,13 +137640,13 @@ var grep_app = {
|
|
|
137321
137640
|
};
|
|
137322
137641
|
|
|
137323
137642
|
// src/mcp/ast-grep.ts
|
|
137324
|
-
import { existsSync as
|
|
137643
|
+
import { existsSync as existsSync94 } from "fs";
|
|
137325
137644
|
import { dirname as dirname36, resolve as resolve26 } from "path";
|
|
137326
137645
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
137327
137646
|
|
|
137328
137647
|
// src/mcp/cli-suffix.ts
|
|
137329
|
-
function normalizeCliPath(
|
|
137330
|
-
return
|
|
137648
|
+
function normalizeCliPath(path22) {
|
|
137649
|
+
return path22.replaceAll("\\", "/");
|
|
137331
137650
|
}
|
|
137332
137651
|
function hasCliSuffix(candidatePath, suffix) {
|
|
137333
137652
|
return normalizeCliPath(candidatePath).endsWith(normalizeCliPath(suffix));
|
|
@@ -137421,11 +137740,11 @@ function getModuleDirectory(moduleUrl) {
|
|
|
137421
137740
|
}
|
|
137422
137741
|
function createFallbackCandidate(resolveExecutable) {
|
|
137423
137742
|
const runtime6 = resolveJavaScriptRuntime(resolveExecutable);
|
|
137424
|
-
const
|
|
137425
|
-
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 };
|
|
137426
137745
|
}
|
|
137427
137746
|
function resolveAstGrepCommand(options = {}) {
|
|
137428
|
-
const pathExists = options.exists ??
|
|
137747
|
+
const pathExists = options.exists ?? existsSync94;
|
|
137429
137748
|
const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
|
|
137430
137749
|
const candidates = [];
|
|
137431
137750
|
const seenPaths = new Set;
|
|
@@ -137461,7 +137780,7 @@ function createAstGrepMcpConfig(options = {}) {
|
|
|
137461
137780
|
}
|
|
137462
137781
|
|
|
137463
137782
|
// src/mcp/lsp.ts
|
|
137464
|
-
import { existsSync as
|
|
137783
|
+
import { existsSync as existsSync95 } from "fs";
|
|
137465
137784
|
import { dirname as dirname37, resolve as resolve27 } from "path";
|
|
137466
137785
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
137467
137786
|
var SUBMODULE_REL = "packages/lsp-tools-mcp";
|
|
@@ -137550,7 +137869,7 @@ function createBootstrapCandidate(root, resolveExecutable) {
|
|
|
137550
137869
|
};
|
|
137551
137870
|
}
|
|
137552
137871
|
function resolveLspCommand(options = {}) {
|
|
137553
|
-
const pathExists = options.exists ??
|
|
137872
|
+
const pathExists = options.exists ?? existsSync95;
|
|
137554
137873
|
const resolveExecutable = options.resolveExecutable ?? resolveRuntimeExecutable;
|
|
137555
137874
|
const candidates = [];
|
|
137556
137875
|
const seenPaths = new Set;
|
|
@@ -138082,11 +138401,25 @@ async function createSkillContext(args) {
|
|
|
138082
138401
|
return true;
|
|
138083
138402
|
});
|
|
138084
138403
|
const includeClaudeSkills = pluginConfig.claude_code?.skills !== false;
|
|
138085
|
-
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([
|
|
138086
138415
|
discoverConfigSourceSkills({
|
|
138087
138416
|
config: pluginConfig.skills,
|
|
138088
138417
|
configDir: directory
|
|
138089
138418
|
}),
|
|
138419
|
+
discoverConfigSourceSkills({
|
|
138420
|
+
config: hostSkillConfig,
|
|
138421
|
+
configDir: directory
|
|
138422
|
+
}),
|
|
138090
138423
|
includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
138091
138424
|
discoverOpencodeGlobalSkills(),
|
|
138092
138425
|
includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
|
|
@@ -138094,7 +138427,12 @@ async function createSkillContext(args) {
|
|
|
138094
138427
|
discoverProjectAgentsSkills(directory),
|
|
138095
138428
|
discoverGlobalAgentsSkills()
|
|
138096
138429
|
]);
|
|
138097
|
-
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);
|
|
138098
138436
|
const filteredUserSkills = filterProviderGatedSkills(userSkills, browserProvider);
|
|
138099
138437
|
const filteredGlobalSkills = filterProviderGatedSkills(globalSkills, browserProvider);
|
|
138100
138438
|
const filteredProjectSkills = filterProviderGatedSkills(projectSkills, browserProvider);
|
|
@@ -138535,7 +138873,7 @@ async function loadTeamSpec(teamName, config, projectRoot, options) {
|
|
|
138535
138873
|
|
|
138536
138874
|
// src/features/team-mode/team-runtime/create.ts
|
|
138537
138875
|
import { access as access4, mkdir as mkdir5 } from "fs/promises";
|
|
138538
|
-
import
|
|
138876
|
+
import path22 from "path";
|
|
138539
138877
|
init_paths();
|
|
138540
138878
|
init_store();
|
|
138541
138879
|
init_team_session_registry();
|
|
@@ -138809,7 +139147,7 @@ async function findExistingRuntime(spec, leadSessionId, config) {
|
|
|
138809
139147
|
}
|
|
138810
139148
|
}
|
|
138811
139149
|
async function createMemberWorktree(memberWorktreePath, projectRoot) {
|
|
138812
|
-
const absolutePath =
|
|
139150
|
+
const absolutePath = path22.isAbsolute(memberWorktreePath) ? memberWorktreePath : path22.resolve(projectRoot, memberWorktreePath);
|
|
138813
139151
|
await mkdir5(absolutePath, { recursive: true });
|
|
138814
139152
|
return absolutePath;
|
|
138815
139153
|
}
|
|
@@ -139080,6 +139418,29 @@ var TeamCreateArgsSchema = z41.object({
|
|
|
139080
139418
|
ctx.addIssue({ code: "custom", message: "Provide exactly one of teamName or inline_spec." });
|
|
139081
139419
|
}
|
|
139082
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
|
+
]);
|
|
139083
139444
|
var TeamDeleteArgsSchema = z41.object({ teamRunId: z41.string().min(1), force: z41.boolean().optional() });
|
|
139084
139445
|
var TeamShutdownRequestArgsSchema = z41.object({ teamRunId: z41.string().min(1), targetMemberName: z41.string().min(1) });
|
|
139085
139446
|
var TeamApproveShutdownArgsSchema = z41.object({ teamRunId: z41.string().min(1), memberName: z41.string().min(1) });
|
|
@@ -139114,8 +139475,8 @@ function parseTeamCreateArgs(rawArgs) {
|
|
|
139114
139475
|
}
|
|
139115
139476
|
return result.data;
|
|
139116
139477
|
}
|
|
139117
|
-
function formatZodIssuePath(
|
|
139118
|
-
return
|
|
139478
|
+
function formatZodIssuePath(path23) {
|
|
139479
|
+
return path23.length > 0 ? path23.join(".") : "<root>";
|
|
139119
139480
|
}
|
|
139120
139481
|
function formatTeamSpecIssues(error) {
|
|
139121
139482
|
return error.issues.slice(0, 5).map((issue) => `${formatZodIssuePath(issue.path)}: ${issue.message}`).join("; ");
|
|
@@ -139178,7 +139539,7 @@ function createTeamCreateTool(config, client, bgMgr, tmuxMgr, executorConfig, de
|
|
|
139178
139539
|
description: "Create a team run from a named or inline team spec.",
|
|
139179
139540
|
args: {
|
|
139180
139541
|
teamName: tool.schema.string().optional().describe("Named team spec to load. Provide exactly one of teamName or inline_spec."),
|
|
139181
|
-
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." }] }.'),
|
|
139182
139543
|
leadSessionId: tool.schema.string().optional().describe("Optional non-empty session ID override. Usually omit this and let team_create use the current session.")
|
|
139183
139544
|
},
|
|
139184
139545
|
async execute(rawArgs, toolContext) {
|
|
@@ -139288,7 +139649,7 @@ init_store();
|
|
|
139288
139649
|
// src/features/team-mode/team-tasklist/list.ts
|
|
139289
139650
|
init_logger();
|
|
139290
139651
|
import { readdir as readdir8, readFile as readFile10 } from "fs/promises";
|
|
139291
|
-
import
|
|
139652
|
+
import path23 from "path";
|
|
139292
139653
|
|
|
139293
139654
|
// src/features/team-mode/team-registry/index.ts
|
|
139294
139655
|
init_paths();
|
|
@@ -139307,7 +139668,7 @@ async function listTasks(teamRunId, config, filter) {
|
|
|
139307
139668
|
for (const entry of entries) {
|
|
139308
139669
|
if (entry.isDirectory() || entry.name.startsWith(".") || !entry.name.endsWith(".json"))
|
|
139309
139670
|
continue;
|
|
139310
|
-
const taskPath =
|
|
139671
|
+
const taskPath = path23.join(tasksDirectory, entry.name);
|
|
139311
139672
|
try {
|
|
139312
139673
|
const taskContent = await readFile10(taskPath, "utf8");
|
|
139313
139674
|
const parsedTask = TaskSchema.safeParse(JSON.parse(taskContent));
|
|
@@ -139339,7 +139700,7 @@ async function listTasks(teamRunId, config, filter) {
|
|
|
139339
139700
|
// src/features/team-mode/team-runtime/status.ts
|
|
139340
139701
|
init_paths();
|
|
139341
139702
|
import { readdir as readdir9 } from "fs/promises";
|
|
139342
|
-
import
|
|
139703
|
+
import path24 from "path";
|
|
139343
139704
|
function getPrimaryModelKey(bgMgr, leadSessionId) {
|
|
139344
139705
|
if (!bgMgr || !leadSessionId)
|
|
139345
139706
|
return;
|
|
@@ -139390,10 +139751,10 @@ async function aggregateStatus(teamRunId, config, bgMgr) {
|
|
|
139390
139751
|
const concurrencyCounts = resolveConcurrencyCounts(teamBackgroundManager, runtimeState.leadSessionId);
|
|
139391
139752
|
const teamRunIdSpecific = teamBackgroundManager?.listTasksByParentSession?.(runtimeState.leadSessionId ?? teamRunId)?.length;
|
|
139392
139753
|
const baseDir = resolveBaseDir(config);
|
|
139393
|
-
const claimsDir =
|
|
139754
|
+
const claimsDir = path24.join(getTasksDir(baseDir, teamRunId), "claims");
|
|
139394
139755
|
const staleLockEntries = await readdir9(claimsDir, { withFileTypes: true }).catch(() => []);
|
|
139395
139756
|
const staleLockPaths = await Promise.all(staleLockEntries.filter((entry) => entry.isFile() && entry.name.endsWith(".lock")).map(async (entry) => {
|
|
139396
|
-
const lockPath =
|
|
139757
|
+
const lockPath = path24.join(claimsDir, entry.name);
|
|
139397
139758
|
return await detectStaleLock(lockPath, 300000) ? lockPath : undefined;
|
|
139398
139759
|
}));
|
|
139399
139760
|
return {
|
|
@@ -139492,7 +139853,7 @@ function createTeamListTool(config, client, deps = defaultDeps7) {
|
|
|
139492
139853
|
|
|
139493
139854
|
// src/features/team-mode/team-tasklist/claim.ts
|
|
139494
139855
|
import { access as access5, mkdir as mkdir6 } from "fs/promises";
|
|
139495
|
-
import
|
|
139856
|
+
import path26 from "path";
|
|
139496
139857
|
init_locks();
|
|
139497
139858
|
init_types2();
|
|
139498
139859
|
|
|
@@ -139506,11 +139867,11 @@ function canClaim(task, allTasks) {
|
|
|
139506
139867
|
|
|
139507
139868
|
// src/features/team-mode/team-tasklist/get.ts
|
|
139508
139869
|
import { readFile as readFile11 } from "fs/promises";
|
|
139509
|
-
import
|
|
139870
|
+
import path25 from "path";
|
|
139510
139871
|
init_types2();
|
|
139511
139872
|
async function getTask(teamRunId, taskId, config) {
|
|
139512
139873
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139513
|
-
const taskContent = await readFile11(
|
|
139874
|
+
const taskContent = await readFile11(path25.join(tasksDirectory, `${taskId}.json`), "utf8");
|
|
139514
139875
|
return TaskSchema.parse(JSON.parse(taskContent));
|
|
139515
139876
|
}
|
|
139516
139877
|
|
|
@@ -139549,9 +139910,9 @@ class BlockedByError extends Error {
|
|
|
139549
139910
|
async function claimTask(teamRunId, taskId, memberName, config) {
|
|
139550
139911
|
const baseDirectory = resolveBaseDir(config);
|
|
139551
139912
|
const tasksDirectory = getTasksDir(baseDirectory, teamRunId);
|
|
139552
|
-
const claimsDirectory =
|
|
139553
|
-
const taskPath =
|
|
139554
|
-
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`);
|
|
139555
139916
|
await mkdir6(claimsDirectory, { recursive: true, mode: 448 });
|
|
139556
139917
|
const task = await getTask(teamRunId, taskId, config);
|
|
139557
139918
|
if (task.status !== "pending") {
|
|
@@ -139590,7 +139951,7 @@ async function claimTask(teamRunId, taskId, memberName, config) {
|
|
|
139590
139951
|
}
|
|
139591
139952
|
// src/features/team-mode/team-tasklist/store.ts
|
|
139592
139953
|
import { mkdir as mkdir7, readFile as readFile12 } from "fs/promises";
|
|
139593
|
-
import
|
|
139954
|
+
import path27 from "path";
|
|
139594
139955
|
init_locks();
|
|
139595
139956
|
init_types2();
|
|
139596
139957
|
var HIGH_WATERMARK_FILE = ".highwatermark";
|
|
@@ -139607,9 +139968,9 @@ async function readHighWatermark(watermarkPath) {
|
|
|
139607
139968
|
async function createTask(teamRunId, taskInput, config) {
|
|
139608
139969
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139609
139970
|
await mkdir7(tasksDirectory, { recursive: true, mode: 448 });
|
|
139610
|
-
await mkdir7(
|
|
139611
|
-
return withLock(
|
|
139612
|
-
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);
|
|
139613
139974
|
const nextTaskId = await readHighWatermark(watermarkPath) + 1;
|
|
139614
139975
|
await atomicWrite(watermarkPath, String(nextTaskId));
|
|
139615
139976
|
const now = Date.now();
|
|
@@ -139620,13 +139981,13 @@ async function createTask(teamRunId, taskInput, config) {
|
|
|
139620
139981
|
createdAt: now,
|
|
139621
139982
|
updatedAt: now
|
|
139622
139983
|
});
|
|
139623
|
-
await atomicWrite(
|
|
139984
|
+
await atomicWrite(path27.join(tasksDirectory, `${task.id}.json`), `${JSON.stringify(task, null, 2)}
|
|
139624
139985
|
`);
|
|
139625
139986
|
return task;
|
|
139626
139987
|
}, { ownerTag: `create-task:${teamRunId}` });
|
|
139627
139988
|
}
|
|
139628
139989
|
// src/features/team-mode/team-tasklist/update.ts
|
|
139629
|
-
import
|
|
139990
|
+
import path28 from "path";
|
|
139630
139991
|
init_locks();
|
|
139631
139992
|
init_types2();
|
|
139632
139993
|
var ALLOWED_TRANSITIONS = {
|
|
@@ -139675,7 +140036,7 @@ async function updateTaskStatus(teamRunId, taskId, newStatus, memberName, config
|
|
|
139675
140036
|
updatedAt: Date.now()
|
|
139676
140037
|
});
|
|
139677
140038
|
const tasksDirectory = getTasksDir(resolveBaseDir(config), teamRunId);
|
|
139678
|
-
await atomicWrite(
|
|
140039
|
+
await atomicWrite(path28.join(tasksDirectory, `${taskId}.json`), `${JSON.stringify(updatedTask, null, 2)}
|
|
139679
140040
|
`);
|
|
139680
140041
|
return updatedTask;
|
|
139681
140042
|
}
|
|
@@ -140407,8 +140768,8 @@ init_agent_display_names();
|
|
|
140407
140768
|
// src/plugin/ultrawork-db-model-override.ts
|
|
140408
140769
|
init_data_path();
|
|
140409
140770
|
init_shared();
|
|
140410
|
-
import { join as
|
|
140411
|
-
import { existsSync as
|
|
140771
|
+
import { join as join102 } from "path";
|
|
140772
|
+
import { existsSync as existsSync96 } from "fs";
|
|
140412
140773
|
async function importBunSqlite() {
|
|
140413
140774
|
if (typeof globalThis.Bun === "undefined") {
|
|
140414
140775
|
return null;
|
|
@@ -140421,7 +140782,7 @@ async function importBunSqlite() {
|
|
|
140421
140782
|
}
|
|
140422
140783
|
}
|
|
140423
140784
|
function getDbPath() {
|
|
140424
|
-
return
|
|
140785
|
+
return join102(getDataDir(), "opencode", "opencode.db");
|
|
140425
140786
|
}
|
|
140426
140787
|
var MAX_MICROTASK_RETRIES = 10;
|
|
140427
140788
|
function tryUpdateMessageModel(db, messageId, targetModel, variant) {
|
|
@@ -140504,7 +140865,7 @@ function scheduleDeferredModelOverride(messageId, targetModel, variant) {
|
|
|
140504
140865
|
return;
|
|
140505
140866
|
}
|
|
140506
140867
|
const dbPath = getDbPath();
|
|
140507
|
-
if (!
|
|
140868
|
+
if (!existsSync96(dbPath)) {
|
|
140508
140869
|
log("[ultrawork-db-override] DB not found, skipping deferred override");
|
|
140509
140870
|
return;
|
|
140510
140871
|
}
|
|
@@ -141049,19 +141410,19 @@ init_session_tools_store();
|
|
|
141049
141410
|
// src/features/team-mode/team-mailbox/ack.ts
|
|
141050
141411
|
init_paths();
|
|
141051
141412
|
import { mkdir as mkdir8, rename as rename3 } from "fs/promises";
|
|
141052
|
-
import
|
|
141413
|
+
import path29 from "path";
|
|
141053
141414
|
async function ackMessages(teamRunId, memberName, messageIds, config) {
|
|
141054
141415
|
const baseDir = resolveBaseDir(config);
|
|
141055
141416
|
const inboxDir = getInboxDir(baseDir, teamRunId, memberName);
|
|
141056
|
-
const processedDir =
|
|
141417
|
+
const processedDir = path29.join(inboxDir, "processed");
|
|
141057
141418
|
await mkdir8(processedDir, { recursive: true, mode: 448 });
|
|
141058
141419
|
for (const messageId of messageIds) {
|
|
141059
141420
|
const messageFileName = `${messageId}.json`;
|
|
141060
141421
|
const sourcePaths = [
|
|
141061
|
-
|
|
141062
|
-
|
|
141422
|
+
path29.join(inboxDir, messageFileName),
|
|
141423
|
+
path29.join(inboxDir, `.delivering-${messageFileName}`)
|
|
141063
141424
|
];
|
|
141064
|
-
const targetPath =
|
|
141425
|
+
const targetPath = path29.join(processedDir, messageFileName);
|
|
141065
141426
|
for (const sourcePath of sourcePaths) {
|
|
141066
141427
|
try {
|
|
141067
141428
|
await rename3(sourcePath, targetPath);
|
|
@@ -142809,9 +143170,9 @@ function createPluginInterface(args) {
|
|
|
142809
143170
|
}
|
|
142810
143171
|
|
|
142811
143172
|
// src/plugin-config.ts
|
|
142812
|
-
import * as
|
|
143173
|
+
import * as fs24 from "fs";
|
|
142813
143174
|
import { homedir as homedir22 } from "os";
|
|
142814
|
-
import * as
|
|
143175
|
+
import * as path30 from "path";
|
|
142815
143176
|
init_shared();
|
|
142816
143177
|
init_plugin_identity();
|
|
142817
143178
|
|
|
@@ -142941,22 +143302,22 @@ function resolveHomeDirectory() {
|
|
|
142941
143302
|
return process.env.HOME ?? process.env.USERPROFILE ?? homedir22();
|
|
142942
143303
|
}
|
|
142943
143304
|
function resolveConfigPathAfterLegacyMigration(detectedPath) {
|
|
142944
|
-
if (!
|
|
143305
|
+
if (!path30.basename(detectedPath).startsWith(LEGACY_CONFIG_BASENAME)) {
|
|
142945
143306
|
return detectedPath;
|
|
142946
143307
|
}
|
|
142947
143308
|
const migrated = migrateLegacyConfigFile(detectedPath);
|
|
142948
|
-
const canonicalPath =
|
|
142949
|
-
if (migrated ||
|
|
143309
|
+
const canonicalPath = path30.join(path30.dirname(detectedPath), `${CONFIG_BASENAME}${path30.extname(detectedPath)}`);
|
|
143310
|
+
if (migrated || fs24.existsSync(canonicalPath)) {
|
|
142950
143311
|
return canonicalPath;
|
|
142951
143312
|
}
|
|
142952
143313
|
return detectedPath;
|
|
142953
143314
|
}
|
|
142954
143315
|
function loadExplicitGitMasterOverrides(configPath) {
|
|
142955
143316
|
try {
|
|
142956
|
-
if (!
|
|
143317
|
+
if (!fs24.existsSync(configPath)) {
|
|
142957
143318
|
return;
|
|
142958
143319
|
}
|
|
142959
|
-
const content =
|
|
143320
|
+
const content = fs24.readFileSync(configPath, "utf-8");
|
|
142960
143321
|
const rawConfig = parseJsonc(content);
|
|
142961
143322
|
const gitMaster = rawConfig.git_master;
|
|
142962
143323
|
if (gitMaster && typeof gitMaster === "object" && !Array.isArray(gitMaster)) {
|
|
@@ -143013,8 +143374,8 @@ function parseConfigPartially(rawConfig) {
|
|
|
143013
143374
|
}
|
|
143014
143375
|
function loadConfigFromPath2(configPath, _ctx) {
|
|
143015
143376
|
try {
|
|
143016
|
-
if (
|
|
143017
|
-
const content =
|
|
143377
|
+
if (fs24.existsSync(configPath)) {
|
|
143378
|
+
const content = fs24.readFileSync(configPath, "utf-8");
|
|
143018
143379
|
const rawConfig = parseJsonc(content);
|
|
143019
143380
|
migrateConfigFile(configPath, rawConfig);
|
|
143020
143381
|
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
|
|
@@ -143149,7 +143510,7 @@ function loadPluginConfig(directory, ctx) {
|
|
|
143149
143510
|
stopDirectory
|
|
143150
143511
|
});
|
|
143151
143512
|
const canonicalAncestorPathsNearestFirst = ancestorConfigPathsNearestFirst.map((ancestorPath) => {
|
|
143152
|
-
const opencodeDir =
|
|
143513
|
+
const opencodeDir = path30.dirname(ancestorPath);
|
|
143153
143514
|
const ancestorDetected = detectPluginConfigFile(opencodeDir, {
|
|
143154
143515
|
basenames: [CONFIG_BASENAME],
|
|
143155
143516
|
legacyBasenames: [LEGACY_CONFIG_BASENAME]
|
|
@@ -143190,8 +143551,8 @@ function loadPluginConfig(directory, ctx) {
|
|
|
143190
143551
|
const ancestorConfig = loadConfigFromPath2(ancestorPath, ctx);
|
|
143191
143552
|
const ancestorOverrides = loadExplicitGitMasterOverrides(ancestorPath);
|
|
143192
143553
|
if (ancestorConfig?.agent_definitions) {
|
|
143193
|
-
const ancestorBasePath =
|
|
143194
|
-
const ancestorDir =
|
|
143554
|
+
const ancestorBasePath = path30.dirname(ancestorPath);
|
|
143555
|
+
const ancestorDir = path30.dirname(ancestorBasePath);
|
|
143195
143556
|
ancestorConfig.agent_definitions = resolveAgentDefinitionPaths(ancestorConfig.agent_definitions, ancestorBasePath, ancestorDir);
|
|
143196
143557
|
}
|
|
143197
143558
|
if (ancestorConfig) {
|