opencode-acp 1.18.1-pr.416.174 → 1.18.1-pr.416.176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +186 -70
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/decompress.d.ts.map +1 -1
- package/dist/lib/compress/hide-consumed.d.ts.map +1 -1
- package/dist/lib/compress/tofile-target.d.ts +23 -0
- package/dist/lib/compress/tofile-target.d.ts.map +1 -0
- package/dist/lib/message-ids.d.ts +4 -3
- package/dist/lib/message-ids.d.ts.map +1 -1
- package/dist/lib/state/rebuild.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3020,8 +3020,8 @@ function saveSessionState(sessionState, logger, sessionName) {
|
|
|
3020
3020
|
queue = { pending: [], waiters: [], draining: false };
|
|
3021
3021
|
saveQueues.set(key, queue);
|
|
3022
3022
|
}
|
|
3023
|
-
const promise = new Promise((
|
|
3024
|
-
queue.waiters.push({ resolve:
|
|
3023
|
+
const promise = new Promise((resolve3, reject) => {
|
|
3024
|
+
queue.waiters.push({ resolve: resolve3, reject });
|
|
3025
3025
|
});
|
|
3026
3026
|
queue.pending.push({
|
|
3027
3027
|
sessionId: sessionState.sessionId,
|
|
@@ -4619,8 +4619,8 @@ function restoreForkCompressionState(state, forkMessages, parent, parentMessages
|
|
|
4619
4619
|
effectiveToolIds,
|
|
4620
4620
|
// [Issue #415] The parent record is raw persisted JSON; legacy
|
|
4621
4621
|
// 4-digit boundary refs must be normalized like every other ref.
|
|
4622
|
-
startId: migrateMessageRef(block.startId),
|
|
4623
|
-
endId: migrateMessageRef(block.endId)
|
|
4622
|
+
startId: typeof block.startId === "string" ? migrateMessageRef(block.startId) : block.startId,
|
|
4623
|
+
endId: typeof block.endId === "string" ? migrateMessageRef(block.endId) : block.endId
|
|
4624
4624
|
});
|
|
4625
4625
|
}
|
|
4626
4626
|
const activeParentIds = new Set(parent.prune.messages.activeBlockIds);
|
|
@@ -9598,6 +9598,102 @@ function extractTextContent(msg) {
|
|
|
9598
9598
|
return textParts.join(" ").replace(/\s+/g, " ").trim();
|
|
9599
9599
|
}
|
|
9600
9600
|
|
|
9601
|
+
// lib/compress/tofile-target.ts
|
|
9602
|
+
import * as fsp from "fs/promises";
|
|
9603
|
+
import { homedir as homedir3, tmpdir } from "os";
|
|
9604
|
+
import { dirname as dirname2, join as join4, relative, resolve } from "path";
|
|
9605
|
+
async function resolveSafeToFileTarget(targetPath, options) {
|
|
9606
|
+
const osTmp = tmpdir();
|
|
9607
|
+
const allowedDirs = options?.allowedDirs ?? [osTmp, join4(homedir3(), ".cache", "opencode")];
|
|
9608
|
+
const dirList = allowedDirs.join(" or ");
|
|
9609
|
+
if (typeof targetPath !== "string" || targetPath.length === 0) {
|
|
9610
|
+
return {
|
|
9611
|
+
ok: false,
|
|
9612
|
+
error: `Error: toFile path must be under ${dirList}. Got: ${targetPath}`
|
|
9613
|
+
};
|
|
9614
|
+
}
|
|
9615
|
+
const resolvedPath = resolve(targetPath);
|
|
9616
|
+
const lexicallyAllowed = allowedDirs.some((dir) => {
|
|
9617
|
+
const rel = relative(resolve(dir), resolvedPath);
|
|
9618
|
+
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/") && !isWinAbsolute(rel);
|
|
9619
|
+
});
|
|
9620
|
+
if (!lexicallyAllowed) {
|
|
9621
|
+
return {
|
|
9622
|
+
ok: false,
|
|
9623
|
+
error: `Error: toFile path must be under ${dirList}. Got: ${targetPath}`
|
|
9624
|
+
};
|
|
9625
|
+
}
|
|
9626
|
+
let realAncestor = null;
|
|
9627
|
+
const tail = [];
|
|
9628
|
+
let current = resolvedPath;
|
|
9629
|
+
while (true) {
|
|
9630
|
+
try {
|
|
9631
|
+
realAncestor = await fsp.realpath(current);
|
|
9632
|
+
break;
|
|
9633
|
+
} catch (err) {
|
|
9634
|
+
const code = err.code;
|
|
9635
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
9636
|
+
return {
|
|
9637
|
+
ok: false,
|
|
9638
|
+
error: `Error: cannot validate toFile path: ${err.message}`
|
|
9639
|
+
};
|
|
9640
|
+
}
|
|
9641
|
+
const parent = dirname2(current);
|
|
9642
|
+
if (parent === current) {
|
|
9643
|
+
return {
|
|
9644
|
+
ok: false,
|
|
9645
|
+
error: `Error: cannot validate toFile path: no existing ancestor found`
|
|
9646
|
+
};
|
|
9647
|
+
}
|
|
9648
|
+
tail.unshift(basename(current));
|
|
9649
|
+
current = parent;
|
|
9650
|
+
}
|
|
9651
|
+
}
|
|
9652
|
+
const physicalPath = tail.length > 0 ? join4(realAncestor, ...tail) : realAncestor;
|
|
9653
|
+
const realAllowedDirs = [];
|
|
9654
|
+
for (const dir of allowedDirs) {
|
|
9655
|
+
try {
|
|
9656
|
+
realAllowedDirs.push(await fsp.realpath(resolve(dir)));
|
|
9657
|
+
} catch {
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
const physicallyAllowed = realAllowedDirs.every((dir) => !containsOrIs(join4(dir), physicalPath) === false) && realAllowedDirs.some((dir) => containsOrIs(join4(dir), physicalPath));
|
|
9661
|
+
if (!physicallyAllowed) {
|
|
9662
|
+
return {
|
|
9663
|
+
ok: false,
|
|
9664
|
+
error: `Error: toFile path resolves outside the allowed directories via a symlink. Got: ${targetPath}`
|
|
9665
|
+
};
|
|
9666
|
+
}
|
|
9667
|
+
try {
|
|
9668
|
+
const stat = await fsp.lstat(resolvedPath);
|
|
9669
|
+
if (stat.isSymbolicLink()) {
|
|
9670
|
+
return {
|
|
9671
|
+
ok: false,
|
|
9672
|
+
error: `Error: toFile target exists as a symlink and will not be followed. Got: ${targetPath}`
|
|
9673
|
+
};
|
|
9674
|
+
}
|
|
9675
|
+
} catch (err) {
|
|
9676
|
+
const code = err.code;
|
|
9677
|
+
if (code !== "ENOENT") {
|
|
9678
|
+
return {
|
|
9679
|
+
ok: false,
|
|
9680
|
+
error: `Error: cannot validate toFile path: ${err.message}`
|
|
9681
|
+
};
|
|
9682
|
+
}
|
|
9683
|
+
}
|
|
9684
|
+
return { ok: true, filePath: resolvedPath };
|
|
9685
|
+
}
|
|
9686
|
+
function isWinAbsolute(p) {
|
|
9687
|
+
return /^[a-zA-Z]:[\\/]/.test(p);
|
|
9688
|
+
}
|
|
9689
|
+
function basename(p) {
|
|
9690
|
+
return p.split(/[\\/]/).filter(Boolean).pop() ?? p;
|
|
9691
|
+
}
|
|
9692
|
+
function containsOrIs(root, p) {
|
|
9693
|
+
const rel = relative(root, p);
|
|
9694
|
+
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/") && !isWinAbsolute(rel);
|
|
9695
|
+
}
|
|
9696
|
+
|
|
9601
9697
|
// lib/compress/decompress.ts
|
|
9602
9698
|
async function prepareDecompressSession(ctx, toolCtx) {
|
|
9603
9699
|
await toolCtx.ask({
|
|
@@ -9631,7 +9727,13 @@ function resolveTargets(args, state, rawMessages, logger) {
|
|
|
9631
9727
|
if (mode.mode === "block") {
|
|
9632
9728
|
return resolveSingleBlockTarget(messagesState, args.blockId);
|
|
9633
9729
|
}
|
|
9634
|
-
return resolveRangeTarget(
|
|
9730
|
+
return resolveRangeTarget(
|
|
9731
|
+
state,
|
|
9732
|
+
rawMessages,
|
|
9733
|
+
args.startId,
|
|
9734
|
+
args.endId,
|
|
9735
|
+
logger
|
|
9736
|
+
);
|
|
9635
9737
|
}
|
|
9636
9738
|
function resolveSingleBlockTarget(messagesState, blockIdArg) {
|
|
9637
9739
|
const targetBlockId = parseBlockIdArg(blockIdArg);
|
|
@@ -9743,11 +9845,21 @@ IMPORTANT:
|
|
|
9743
9845
|
- Do NOT call this tool in parallel with compress \u2014 their state mutations may conflict.`;
|
|
9744
9846
|
function buildSchema2() {
|
|
9745
9847
|
return {
|
|
9746
|
-
blockId: tool3.schema.string().optional().describe(
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9848
|
+
blockId: tool3.schema.string().optional().describe(
|
|
9849
|
+
'Block reference to decompress (e.g., "b0", "b2"). Mutually exclusive with startId/endId.'
|
|
9850
|
+
),
|
|
9851
|
+
startId: tool3.schema.string().optional().describe(
|
|
9852
|
+
'Range start: message ref (e.g., "m00150") or block ref (e.g., "b2"). Used with endId.'
|
|
9853
|
+
),
|
|
9854
|
+
endId: tool3.schema.string().optional().describe(
|
|
9855
|
+
'Range end: message ref (e.g., "m00200") or block ref (e.g., "b5"). Used with startId.'
|
|
9856
|
+
),
|
|
9857
|
+
toFile: tool3.schema.string().optional().describe(
|
|
9858
|
+
"If provided, writes restored content to this file path instead of inflating context. Block stays compressed. Path must be under /tmp or ~/.cache/opencode/. Example: '/tmp/block52.txt'"
|
|
9859
|
+
),
|
|
9860
|
+
full: tool3.schema.boolean().optional().describe(
|
|
9861
|
+
"If true, restores ALL content down to original messages (multi-level decompress). Default: false \u2014 restores one tier up (e.g., decompressing a T2 block restores T1 summaries, not raw messages). Use full:true only when you need the exact original content and have context budget for it."
|
|
9862
|
+
)
|
|
9751
9863
|
};
|
|
9752
9864
|
}
|
|
9753
9865
|
function extractMessageId(m) {
|
|
@@ -9771,7 +9883,12 @@ function createDecompressTool(factoryCtx) {
|
|
|
9771
9883
|
const contextUsageBefore = effectiveLimitBefore ? Math.round(
|
|
9772
9884
|
getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitBefore.limit * 100
|
|
9773
9885
|
) : void 0;
|
|
9774
|
-
const resolved = resolveTargets(
|
|
9886
|
+
const resolved = resolveTargets(
|
|
9887
|
+
args,
|
|
9888
|
+
ctx.state,
|
|
9889
|
+
rawMessages,
|
|
9890
|
+
ctx.logger
|
|
9891
|
+
);
|
|
9775
9892
|
if (!resolved.ok) {
|
|
9776
9893
|
return resolved.error;
|
|
9777
9894
|
}
|
|
@@ -9787,19 +9904,9 @@ function createDecompressTool(factoryCtx) {
|
|
|
9787
9904
|
}
|
|
9788
9905
|
if (args.toFile) {
|
|
9789
9906
|
const targetPath = args.toFile;
|
|
9790
|
-
const
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
os.tmpdir() + "/",
|
|
9794
|
-
path.join(os.homedir(), ".cache", "opencode") + "/"
|
|
9795
|
-
];
|
|
9796
|
-
const resolvedPath = path.resolve(targetPath);
|
|
9797
|
-
const isAllowed = allowedDirs.some((dir) => {
|
|
9798
|
-
const rel = path.relative(dir, resolvedPath);
|
|
9799
|
-
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
9800
|
-
});
|
|
9801
|
-
if (!isAllowed) {
|
|
9802
|
-
return `Error: toFile path must be under ${os.tmpdir()} or ~/.cache/opencode/. Got: ${targetPath}`;
|
|
9907
|
+
const safe = await resolveSafeToFileTarget(targetPath);
|
|
9908
|
+
if (!safe.ok) {
|
|
9909
|
+
return safe.error;
|
|
9803
9910
|
}
|
|
9804
9911
|
const msgIdSet = /* @__PURE__ */ new Set();
|
|
9805
9912
|
for (const block of activeBlocks) {
|
|
@@ -9809,9 +9916,16 @@ function createDecompressTool(factoryCtx) {
|
|
|
9809
9916
|
}
|
|
9810
9917
|
const blockMessages = rawMessages.filter((m) => msgIdSet.has(extractMessageId(m)));
|
|
9811
9918
|
const lines2 = blockMessages.map(extractMessageText2);
|
|
9812
|
-
const { writeFile: writeFile4 } = await import("fs/promises");
|
|
9813
9919
|
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : targets[0]?.blocks[0]?.summary ?? "(no content available)";
|
|
9814
|
-
await
|
|
9920
|
+
const fsp2 = await import("fs/promises");
|
|
9921
|
+
const { constants } = await import("fs");
|
|
9922
|
+
const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | (process.platform === "win32" ? 0 : constants.O_NOFOLLOW);
|
|
9923
|
+
const handle = await fsp2.open(safe.filePath, flags, 384);
|
|
9924
|
+
try {
|
|
9925
|
+
await handle.writeFile(fileContent, "utf-8");
|
|
9926
|
+
} finally {
|
|
9927
|
+
await handle.close();
|
|
9928
|
+
}
|
|
9815
9929
|
const displayIds2 = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
9816
9930
|
return `Block(s) ${displayIds2} content (${blockMessages.length} messages, ${fileContent.length} chars) written to ${targetPath}. Block(s) stay compressed \u2014 context unchanged. Use read tool to access specific parts.`;
|
|
9817
9931
|
}
|
|
@@ -9888,7 +10002,9 @@ function isLiveBlock(block) {
|
|
|
9888
10002
|
return block.active && !block.deactivatedByUser && !block.deactivatedByUserDeep;
|
|
9889
10003
|
}
|
|
9890
10004
|
function rangeKey(startId, endId) {
|
|
9891
|
-
|
|
10005
|
+
const s = typeof startId === "string" ? migrateMessageRef(startId) : startId;
|
|
10006
|
+
const e = typeof endId === "string" ? migrateMessageRef(endId) : endId;
|
|
10007
|
+
return `${s}::${e}`;
|
|
9892
10008
|
}
|
|
9893
10009
|
function rewriteCompressInput(part, liveKeys) {
|
|
9894
10010
|
if (part.type !== "tool") return null;
|
|
@@ -10551,10 +10667,10 @@ function hideFailedCompressCalls(messages) {
|
|
|
10551
10667
|
|
|
10552
10668
|
// lib/logger.ts
|
|
10553
10669
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
10554
|
-
import { join as
|
|
10670
|
+
import { join as join5 } from "path";
|
|
10555
10671
|
import { existsSync as existsSync4 } from "fs";
|
|
10556
|
-
import { homedir as
|
|
10557
|
-
var LOG_VERSION = true ? "1.18.1-pr.416.
|
|
10672
|
+
import { homedir as homedir4 } from "os";
|
|
10673
|
+
var LOG_VERSION = true ? "1.18.1-pr.416.176" : "dev";
|
|
10558
10674
|
var LEVEL_RANK = {
|
|
10559
10675
|
debug: 10,
|
|
10560
10676
|
info: 20,
|
|
@@ -10574,8 +10690,8 @@ var Logger = class {
|
|
|
10574
10690
|
constructor(enabled, level) {
|
|
10575
10691
|
const resolved = level !== void 0 && LEVEL_RANK[level] !== void 0 ? level : void 0;
|
|
10576
10692
|
this.level = resolved ?? (enabled ? "debug" : "warn");
|
|
10577
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
10578
|
-
this.logDir =
|
|
10693
|
+
const configHome = process.env.XDG_CONFIG_HOME || join5(homedir4(), ".config");
|
|
10694
|
+
this.logDir = join5(configHome, "opencode", "logs", "acp");
|
|
10579
10695
|
}
|
|
10580
10696
|
/** Back-compat view of the old flag: true only at full debug verbosity. */
|
|
10581
10697
|
get enabled() {
|
|
@@ -10637,11 +10753,11 @@ var Logger = class {
|
|
|
10637
10753
|
const dataStr = this.formatData(data);
|
|
10638
10754
|
const logLine = `${timestamp} ${level.padEnd(5)} ${component}: ${message}${dataStr ? " | " + dataStr : ""} | v=${LOG_VERSION}
|
|
10639
10755
|
`;
|
|
10640
|
-
const dailyLogDir =
|
|
10756
|
+
const dailyLogDir = join5(this.logDir, "daily");
|
|
10641
10757
|
if (!existsSync4(dailyLogDir)) {
|
|
10642
10758
|
await mkdir2(dailyLogDir, { recursive: true });
|
|
10643
10759
|
}
|
|
10644
|
-
const logFile =
|
|
10760
|
+
const logFile = join5(dailyLogDir, `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.log`);
|
|
10645
10761
|
await writeFile2(logFile, logLine, { flag: "a" });
|
|
10646
10762
|
} catch (error) {
|
|
10647
10763
|
}
|
|
@@ -10752,7 +10868,7 @@ var Logger = class {
|
|
|
10752
10868
|
async saveContext(sessionId, messages) {
|
|
10753
10869
|
if (this.level !== "debug") return;
|
|
10754
10870
|
try {
|
|
10755
|
-
const contextDir =
|
|
10871
|
+
const contextDir = join5(this.logDir, "context", sessionId);
|
|
10756
10872
|
if (!existsSync4(contextDir)) {
|
|
10757
10873
|
await mkdir2(contextDir, { recursive: true });
|
|
10758
10874
|
}
|
|
@@ -10760,9 +10876,9 @@ var Logger = class {
|
|
|
10760
10876
|
(msg) => msg.parts && msg.parts.length > 0
|
|
10761
10877
|
);
|
|
10762
10878
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10763
|
-
const contextFile =
|
|
10879
|
+
const contextFile = join5(contextDir, `${timestamp}.json`);
|
|
10764
10880
|
await writeFile2(contextFile, JSON.stringify(minimized, null, 2));
|
|
10765
|
-
const versionFile =
|
|
10881
|
+
const versionFile = join5(contextDir, "_version");
|
|
10766
10882
|
if (!existsSync4(versionFile)) {
|
|
10767
10883
|
await writeFile2(versionFile, LOG_VERSION);
|
|
10768
10884
|
}
|
|
@@ -10773,8 +10889,8 @@ var Logger = class {
|
|
|
10773
10889
|
|
|
10774
10890
|
// lib/prompts/store.ts
|
|
10775
10891
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, statSync as statSync2 } from "fs";
|
|
10776
|
-
import { join as
|
|
10777
|
-
import { homedir as
|
|
10892
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
10893
|
+
import { homedir as homedir5 } from "os";
|
|
10778
10894
|
|
|
10779
10895
|
// lib/prompts/system.ts
|
|
10780
10896
|
var ACP_STATUS_TOOL_LINE_RANGES = `- \`acp_status\` \u2014 Context status with compressible ranges. No args = overview + ranges. \`scope:"uncompressed"\` for range view; add \`view:"messages"\` for per-message listing with \`tool\`/\`sort\` filters. \`scope:"compressed"\` for block details.`;
|
|
@@ -11081,7 +11197,7 @@ function createBundledRuntimePrompts(candidatesEnabled) {
|
|
|
11081
11197
|
function findOpencodeDir2(startDir) {
|
|
11082
11198
|
let current = startDir;
|
|
11083
11199
|
while (current !== "/") {
|
|
11084
|
-
const candidate =
|
|
11200
|
+
const candidate = join6(current, ".opencode");
|
|
11085
11201
|
if (existsSync5(candidate)) {
|
|
11086
11202
|
try {
|
|
11087
11203
|
if (statSync2(candidate).isDirectory()) {
|
|
@@ -11090,7 +11206,7 @@ function findOpencodeDir2(startDir) {
|
|
|
11090
11206
|
} catch {
|
|
11091
11207
|
}
|
|
11092
11208
|
}
|
|
11093
|
-
const parent =
|
|
11209
|
+
const parent = dirname3(current);
|
|
11094
11210
|
if (parent === current) {
|
|
11095
11211
|
break;
|
|
11096
11212
|
}
|
|
@@ -11099,13 +11215,13 @@ function findOpencodeDir2(startDir) {
|
|
|
11099
11215
|
return null;
|
|
11100
11216
|
}
|
|
11101
11217
|
function resolvePromptPaths(workingDirectory) {
|
|
11102
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
11103
|
-
const globalRoot =
|
|
11104
|
-
const defaultsDir =
|
|
11105
|
-
const globalOverridesDir =
|
|
11106
|
-
const configDirOverridesDir = process.env.OPENCODE_CONFIG_DIR ?
|
|
11218
|
+
const configHome = process.env.XDG_CONFIG_HOME || join6(homedir5(), ".config");
|
|
11219
|
+
const globalRoot = join6(configHome, "opencode", "acp-prompts");
|
|
11220
|
+
const defaultsDir = join6(globalRoot, "defaults");
|
|
11221
|
+
const globalOverridesDir = join6(globalRoot, "overrides");
|
|
11222
|
+
const configDirOverridesDir = process.env.OPENCODE_CONFIG_DIR ? join6(process.env.OPENCODE_CONFIG_DIR, "acp-prompts", "overrides") : null;
|
|
11107
11223
|
const opencodeDir = findOpencodeDir2(workingDirectory);
|
|
11108
|
-
const projectOverridesDir = opencodeDir ?
|
|
11224
|
+
const projectOverridesDir = opencodeDir ? join6(opencodeDir, "acp-prompts", "overrides") : null;
|
|
11109
11225
|
return {
|
|
11110
11226
|
defaultsDir,
|
|
11111
11227
|
globalOverridesDir,
|
|
@@ -11278,16 +11394,16 @@ var PromptStore = class {
|
|
|
11278
11394
|
const candidates = [];
|
|
11279
11395
|
if (this.paths.projectOverridesDir) {
|
|
11280
11396
|
candidates.push({
|
|
11281
|
-
path:
|
|
11397
|
+
path: join6(this.paths.projectOverridesDir, fileName)
|
|
11282
11398
|
});
|
|
11283
11399
|
}
|
|
11284
11400
|
if (this.paths.configDirOverridesDir) {
|
|
11285
11401
|
candidates.push({
|
|
11286
|
-
path:
|
|
11402
|
+
path: join6(this.paths.configDirOverridesDir, fileName)
|
|
11287
11403
|
});
|
|
11288
11404
|
}
|
|
11289
11405
|
candidates.push({
|
|
11290
|
-
path:
|
|
11406
|
+
path: join6(this.paths.globalOverridesDir, fileName)
|
|
11291
11407
|
});
|
|
11292
11408
|
return candidates;
|
|
11293
11409
|
}
|
|
@@ -11311,7 +11427,7 @@ var PromptStore = class {
|
|
|
11311
11427
|
const managedContent = buildDefaultPromptFileContent(
|
|
11312
11428
|
bundledEditable || bundledPrompts[definition.runtimeField]
|
|
11313
11429
|
);
|
|
11314
|
-
const filePath =
|
|
11430
|
+
const filePath = join6(this.paths.defaultsDir, definition.fileName);
|
|
11315
11431
|
try {
|
|
11316
11432
|
const existing = readFileIfExists(filePath);
|
|
11317
11433
|
if (existing === managedContent) {
|
|
@@ -11325,7 +11441,7 @@ var PromptStore = class {
|
|
|
11325
11441
|
});
|
|
11326
11442
|
}
|
|
11327
11443
|
}
|
|
11328
|
-
const readmePath =
|
|
11444
|
+
const readmePath = join6(this.paths.defaultsDir, DEFAULTS_README_FILE);
|
|
11329
11445
|
const readmeContent = buildDefaultsReadmeContent();
|
|
11330
11446
|
try {
|
|
11331
11447
|
const existing = readFileIfExists(readmePath);
|
|
@@ -11790,7 +11906,7 @@ ${report}`;
|
|
|
11790
11906
|
// lib/commands/export.ts
|
|
11791
11907
|
import * as fs2 from "fs/promises";
|
|
11792
11908
|
import { existsSync as existsSync6 } from "fs";
|
|
11793
|
-
import { dirname as
|
|
11909
|
+
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join7, resolve as resolve2 } from "path";
|
|
11794
11910
|
var ALL_TIERS = [1, 2, 3];
|
|
11795
11911
|
var TIER_NAMES = {
|
|
11796
11912
|
1: "Tier 1 \u2014 Capture",
|
|
@@ -11903,7 +12019,7 @@ function parseTiers(raw) {
|
|
|
11903
12019
|
}
|
|
11904
12020
|
function resolveDefaultOutputPath(sessionId, cwd2) {
|
|
11905
12021
|
const short = (sessionId || "session").slice(0, 8);
|
|
11906
|
-
return
|
|
12022
|
+
return join7(cwd2, ".opencode", `acp-export-${short}.md`);
|
|
11907
12023
|
}
|
|
11908
12024
|
function formatTokens2(n) {
|
|
11909
12025
|
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
@@ -12031,9 +12147,9 @@ async function handleExportCommand(ctx, args) {
|
|
|
12031
12147
|
return;
|
|
12032
12148
|
}
|
|
12033
12149
|
const cwd2 = ctx.workingDirectory || process.cwd();
|
|
12034
|
-
const targetPath = options.outputPath !== "" ? isAbsolute2(options.outputPath) ? options.outputPath :
|
|
12150
|
+
const targetPath = options.outputPath !== "" ? isAbsolute2(options.outputPath) ? options.outputPath : resolve2(cwd2, options.outputPath) : resolveDefaultOutputPath(sessionId, cwd2);
|
|
12035
12151
|
try {
|
|
12036
|
-
const dir =
|
|
12152
|
+
const dir = dirname4(targetPath);
|
|
12037
12153
|
if (!existsSync6(dir)) {
|
|
12038
12154
|
await fs2.mkdir(dir, { recursive: true });
|
|
12039
12155
|
}
|
|
@@ -13026,7 +13142,7 @@ function findBiliProxyProviders(provider) {
|
|
|
13026
13142
|
|
|
13027
13143
|
// lib/update.ts
|
|
13028
13144
|
import { readFile as readFile2, rm } from "fs/promises";
|
|
13029
|
-
import { basename, dirname as
|
|
13145
|
+
import { basename as basename2, dirname as dirname5, join as join8 } from "path";
|
|
13030
13146
|
import { fileURLToPath } from "url";
|
|
13031
13147
|
var PACKAGE_NAME = "opencode-acp";
|
|
13032
13148
|
function startAutoUpdate(ctx, enabled, logger) {
|
|
@@ -13073,7 +13189,7 @@ async function checkAutoUpdate(signal, logger) {
|
|
|
13073
13189
|
logger?.info("Auto-update skipped: package dir not found");
|
|
13074
13190
|
return { updated: false };
|
|
13075
13191
|
}
|
|
13076
|
-
const pkg = await readPackageJson(
|
|
13192
|
+
const pkg = await readPackageJson(join8(packageDir, "package.json"));
|
|
13077
13193
|
if (!pkg?.name || !pkg.version) {
|
|
13078
13194
|
logger?.info("Auto-update skipped: package.json unreadable", { packageDir });
|
|
13079
13195
|
return { updated: false };
|
|
@@ -13112,21 +13228,21 @@ async function checkAutoUpdate(signal, logger) {
|
|
|
13112
13228
|
return { updated: true, name: pkg.name, current: pkg.version, latest };
|
|
13113
13229
|
}
|
|
13114
13230
|
async function findPackageDir(name) {
|
|
13115
|
-
let dir =
|
|
13231
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
13116
13232
|
for (; ; ) {
|
|
13117
|
-
const pkg = await readPackageJson(
|
|
13233
|
+
const pkg = await readPackageJson(join8(dir, "package.json"));
|
|
13118
13234
|
if (pkg?.name === name) return dir;
|
|
13119
|
-
const parent =
|
|
13235
|
+
const parent = dirname5(dir);
|
|
13120
13236
|
if (parent === dir) return void 0;
|
|
13121
13237
|
dir = parent;
|
|
13122
13238
|
}
|
|
13123
13239
|
}
|
|
13124
13240
|
async function updateTarget(packageDir, name) {
|
|
13125
|
-
const packageParent =
|
|
13126
|
-
const nodeModulesDir =
|
|
13127
|
-
if (
|
|
13128
|
-
const wrapperDir =
|
|
13129
|
-
const wrapperPkg = await readPackageJson(
|
|
13241
|
+
const packageParent = dirname5(packageDir);
|
|
13242
|
+
const nodeModulesDir = basename2(packageParent).startsWith("@") ? dirname5(packageParent) : packageParent;
|
|
13243
|
+
if (basename2(nodeModulesDir) !== "node_modules") return void 0;
|
|
13244
|
+
const wrapperDir = dirname5(nodeModulesDir);
|
|
13245
|
+
const wrapperPkg = await readPackageJson(join8(wrapperDir, "package.json"));
|
|
13130
13246
|
const spec = wrapperSpec(wrapperDir, name) ?? wrapperPkg?.dependencies?.[name];
|
|
13131
13247
|
if (!spec || !isAutoUpdatableSpec(spec)) return void 0;
|
|
13132
13248
|
return { removeDir: wrapperDir, spec };
|
|
@@ -13134,13 +13250,13 @@ async function updateTarget(packageDir, name) {
|
|
|
13134
13250
|
function wrapperSpec(wrapperDir, name) {
|
|
13135
13251
|
if (name.startsWith("@")) {
|
|
13136
13252
|
const [scope, pkg] = name.split("/");
|
|
13137
|
-
if (!scope || !pkg ||
|
|
13253
|
+
if (!scope || !pkg || basename2(dirname5(wrapperDir)) !== scope) return void 0;
|
|
13138
13254
|
const prefix2 = `${pkg}@`;
|
|
13139
|
-
const base2 =
|
|
13255
|
+
const base2 = basename2(wrapperDir);
|
|
13140
13256
|
return base2.startsWith(prefix2) ? base2.slice(prefix2.length) : void 0;
|
|
13141
13257
|
}
|
|
13142
13258
|
const prefix = `${name}@`;
|
|
13143
|
-
const base =
|
|
13259
|
+
const base = basename2(wrapperDir);
|
|
13144
13260
|
return base.startsWith(prefix) ? base.slice(prefix.length) : void 0;
|
|
13145
13261
|
}
|
|
13146
13262
|
function isAutoUpdatableSpec(spec) {
|
|
@@ -13238,7 +13354,7 @@ var server = (async (ctx) => {
|
|
|
13238
13354
|
}
|
|
13239
13355
|
const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
|
|
13240
13356
|
logger.info("ACP plugin initialized", {
|
|
13241
|
-
version: true ? "1.18.1-pr.416.
|
|
13357
|
+
version: true ? "1.18.1-pr.416.176" : "dev",
|
|
13242
13358
|
workspace: ctx.directory,
|
|
13243
13359
|
logLevel: logger.level,
|
|
13244
13360
|
debug: config.debug,
|