opencode-acp 1.18.1-pr.416.175 → 1.18.1-pr.416.177
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
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,
|
|
@@ -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.some((dir) => containsOrIs(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
|
|
9919
|
+
const fsp2 = await import("fs/promises");
|
|
9920
|
+
const { constants } = await import("fs");
|
|
9813
9921
|
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : targets[0]?.blocks[0]?.summary ?? "(no content available)";
|
|
9814
|
-
|
|
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.write(Buffer.from(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
|
}
|
|
@@ -10553,10 +10667,10 @@ function hideFailedCompressCalls(messages) {
|
|
|
10553
10667
|
|
|
10554
10668
|
// lib/logger.ts
|
|
10555
10669
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
10556
|
-
import { join as
|
|
10670
|
+
import { join as join5 } from "path";
|
|
10557
10671
|
import { existsSync as existsSync4 } from "fs";
|
|
10558
|
-
import { homedir as
|
|
10559
|
-
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.177" : "dev";
|
|
10560
10674
|
var LEVEL_RANK = {
|
|
10561
10675
|
debug: 10,
|
|
10562
10676
|
info: 20,
|
|
@@ -10576,8 +10690,8 @@ var Logger = class {
|
|
|
10576
10690
|
constructor(enabled, level) {
|
|
10577
10691
|
const resolved = level !== void 0 && LEVEL_RANK[level] !== void 0 ? level : void 0;
|
|
10578
10692
|
this.level = resolved ?? (enabled ? "debug" : "warn");
|
|
10579
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
10580
|
-
this.logDir =
|
|
10693
|
+
const configHome = process.env.XDG_CONFIG_HOME || join5(homedir4(), ".config");
|
|
10694
|
+
this.logDir = join5(configHome, "opencode", "logs", "acp");
|
|
10581
10695
|
}
|
|
10582
10696
|
/** Back-compat view of the old flag: true only at full debug verbosity. */
|
|
10583
10697
|
get enabled() {
|
|
@@ -10639,11 +10753,11 @@ var Logger = class {
|
|
|
10639
10753
|
const dataStr = this.formatData(data);
|
|
10640
10754
|
const logLine = `${timestamp} ${level.padEnd(5)} ${component}: ${message}${dataStr ? " | " + dataStr : ""} | v=${LOG_VERSION}
|
|
10641
10755
|
`;
|
|
10642
|
-
const dailyLogDir =
|
|
10756
|
+
const dailyLogDir = join5(this.logDir, "daily");
|
|
10643
10757
|
if (!existsSync4(dailyLogDir)) {
|
|
10644
10758
|
await mkdir2(dailyLogDir, { recursive: true });
|
|
10645
10759
|
}
|
|
10646
|
-
const logFile =
|
|
10760
|
+
const logFile = join5(dailyLogDir, `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.log`);
|
|
10647
10761
|
await writeFile2(logFile, logLine, { flag: "a" });
|
|
10648
10762
|
} catch (error) {
|
|
10649
10763
|
}
|
|
@@ -10754,7 +10868,7 @@ var Logger = class {
|
|
|
10754
10868
|
async saveContext(sessionId, messages) {
|
|
10755
10869
|
if (this.level !== "debug") return;
|
|
10756
10870
|
try {
|
|
10757
|
-
const contextDir =
|
|
10871
|
+
const contextDir = join5(this.logDir, "context", sessionId);
|
|
10758
10872
|
if (!existsSync4(contextDir)) {
|
|
10759
10873
|
await mkdir2(contextDir, { recursive: true });
|
|
10760
10874
|
}
|
|
@@ -10762,9 +10876,9 @@ var Logger = class {
|
|
|
10762
10876
|
(msg) => msg.parts && msg.parts.length > 0
|
|
10763
10877
|
);
|
|
10764
10878
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10765
|
-
const contextFile =
|
|
10879
|
+
const contextFile = join5(contextDir, `${timestamp}.json`);
|
|
10766
10880
|
await writeFile2(contextFile, JSON.stringify(minimized, null, 2));
|
|
10767
|
-
const versionFile =
|
|
10881
|
+
const versionFile = join5(contextDir, "_version");
|
|
10768
10882
|
if (!existsSync4(versionFile)) {
|
|
10769
10883
|
await writeFile2(versionFile, LOG_VERSION);
|
|
10770
10884
|
}
|
|
@@ -10775,8 +10889,8 @@ var Logger = class {
|
|
|
10775
10889
|
|
|
10776
10890
|
// lib/prompts/store.ts
|
|
10777
10891
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, statSync as statSync2 } from "fs";
|
|
10778
|
-
import { join as
|
|
10779
|
-
import { homedir as
|
|
10892
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
10893
|
+
import { homedir as homedir5 } from "os";
|
|
10780
10894
|
|
|
10781
10895
|
// lib/prompts/system.ts
|
|
10782
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.`;
|
|
@@ -11083,7 +11197,7 @@ function createBundledRuntimePrompts(candidatesEnabled) {
|
|
|
11083
11197
|
function findOpencodeDir2(startDir) {
|
|
11084
11198
|
let current = startDir;
|
|
11085
11199
|
while (current !== "/") {
|
|
11086
|
-
const candidate =
|
|
11200
|
+
const candidate = join6(current, ".opencode");
|
|
11087
11201
|
if (existsSync5(candidate)) {
|
|
11088
11202
|
try {
|
|
11089
11203
|
if (statSync2(candidate).isDirectory()) {
|
|
@@ -11092,7 +11206,7 @@ function findOpencodeDir2(startDir) {
|
|
|
11092
11206
|
} catch {
|
|
11093
11207
|
}
|
|
11094
11208
|
}
|
|
11095
|
-
const parent =
|
|
11209
|
+
const parent = dirname3(current);
|
|
11096
11210
|
if (parent === current) {
|
|
11097
11211
|
break;
|
|
11098
11212
|
}
|
|
@@ -11101,13 +11215,13 @@ function findOpencodeDir2(startDir) {
|
|
|
11101
11215
|
return null;
|
|
11102
11216
|
}
|
|
11103
11217
|
function resolvePromptPaths(workingDirectory) {
|
|
11104
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
11105
|
-
const globalRoot =
|
|
11106
|
-
const defaultsDir =
|
|
11107
|
-
const globalOverridesDir =
|
|
11108
|
-
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;
|
|
11109
11223
|
const opencodeDir = findOpencodeDir2(workingDirectory);
|
|
11110
|
-
const projectOverridesDir = opencodeDir ?
|
|
11224
|
+
const projectOverridesDir = opencodeDir ? join6(opencodeDir, "acp-prompts", "overrides") : null;
|
|
11111
11225
|
return {
|
|
11112
11226
|
defaultsDir,
|
|
11113
11227
|
globalOverridesDir,
|
|
@@ -11280,16 +11394,16 @@ var PromptStore = class {
|
|
|
11280
11394
|
const candidates = [];
|
|
11281
11395
|
if (this.paths.projectOverridesDir) {
|
|
11282
11396
|
candidates.push({
|
|
11283
|
-
path:
|
|
11397
|
+
path: join6(this.paths.projectOverridesDir, fileName)
|
|
11284
11398
|
});
|
|
11285
11399
|
}
|
|
11286
11400
|
if (this.paths.configDirOverridesDir) {
|
|
11287
11401
|
candidates.push({
|
|
11288
|
-
path:
|
|
11402
|
+
path: join6(this.paths.configDirOverridesDir, fileName)
|
|
11289
11403
|
});
|
|
11290
11404
|
}
|
|
11291
11405
|
candidates.push({
|
|
11292
|
-
path:
|
|
11406
|
+
path: join6(this.paths.globalOverridesDir, fileName)
|
|
11293
11407
|
});
|
|
11294
11408
|
return candidates;
|
|
11295
11409
|
}
|
|
@@ -11313,7 +11427,7 @@ var PromptStore = class {
|
|
|
11313
11427
|
const managedContent = buildDefaultPromptFileContent(
|
|
11314
11428
|
bundledEditable || bundledPrompts[definition.runtimeField]
|
|
11315
11429
|
);
|
|
11316
|
-
const filePath =
|
|
11430
|
+
const filePath = join6(this.paths.defaultsDir, definition.fileName);
|
|
11317
11431
|
try {
|
|
11318
11432
|
const existing = readFileIfExists(filePath);
|
|
11319
11433
|
if (existing === managedContent) {
|
|
@@ -11327,7 +11441,7 @@ var PromptStore = class {
|
|
|
11327
11441
|
});
|
|
11328
11442
|
}
|
|
11329
11443
|
}
|
|
11330
|
-
const readmePath =
|
|
11444
|
+
const readmePath = join6(this.paths.defaultsDir, DEFAULTS_README_FILE);
|
|
11331
11445
|
const readmeContent = buildDefaultsReadmeContent();
|
|
11332
11446
|
try {
|
|
11333
11447
|
const existing = readFileIfExists(readmePath);
|
|
@@ -11792,7 +11906,7 @@ ${report}`;
|
|
|
11792
11906
|
// lib/commands/export.ts
|
|
11793
11907
|
import * as fs2 from "fs/promises";
|
|
11794
11908
|
import { existsSync as existsSync6 } from "fs";
|
|
11795
|
-
import { dirname as
|
|
11909
|
+
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join7, resolve as resolve2 } from "path";
|
|
11796
11910
|
var ALL_TIERS = [1, 2, 3];
|
|
11797
11911
|
var TIER_NAMES = {
|
|
11798
11912
|
1: "Tier 1 \u2014 Capture",
|
|
@@ -11905,7 +12019,7 @@ function parseTiers(raw) {
|
|
|
11905
12019
|
}
|
|
11906
12020
|
function resolveDefaultOutputPath(sessionId, cwd2) {
|
|
11907
12021
|
const short = (sessionId || "session").slice(0, 8);
|
|
11908
|
-
return
|
|
12022
|
+
return join7(cwd2, ".opencode", `acp-export-${short}.md`);
|
|
11909
12023
|
}
|
|
11910
12024
|
function formatTokens2(n) {
|
|
11911
12025
|
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
@@ -12033,9 +12147,9 @@ async function handleExportCommand(ctx, args) {
|
|
|
12033
12147
|
return;
|
|
12034
12148
|
}
|
|
12035
12149
|
const cwd2 = ctx.workingDirectory || process.cwd();
|
|
12036
|
-
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);
|
|
12037
12151
|
try {
|
|
12038
|
-
const dir =
|
|
12152
|
+
const dir = dirname4(targetPath);
|
|
12039
12153
|
if (!existsSync6(dir)) {
|
|
12040
12154
|
await fs2.mkdir(dir, { recursive: true });
|
|
12041
12155
|
}
|
|
@@ -13028,7 +13142,7 @@ function findBiliProxyProviders(provider) {
|
|
|
13028
13142
|
|
|
13029
13143
|
// lib/update.ts
|
|
13030
13144
|
import { readFile as readFile2, rm } from "fs/promises";
|
|
13031
|
-
import { basename, dirname as
|
|
13145
|
+
import { basename as basename2, dirname as dirname5, join as join8 } from "path";
|
|
13032
13146
|
import { fileURLToPath } from "url";
|
|
13033
13147
|
var PACKAGE_NAME = "opencode-acp";
|
|
13034
13148
|
function startAutoUpdate(ctx, enabled, logger) {
|
|
@@ -13075,7 +13189,7 @@ async function checkAutoUpdate(signal, logger) {
|
|
|
13075
13189
|
logger?.info("Auto-update skipped: package dir not found");
|
|
13076
13190
|
return { updated: false };
|
|
13077
13191
|
}
|
|
13078
|
-
const pkg = await readPackageJson(
|
|
13192
|
+
const pkg = await readPackageJson(join8(packageDir, "package.json"));
|
|
13079
13193
|
if (!pkg?.name || !pkg.version) {
|
|
13080
13194
|
logger?.info("Auto-update skipped: package.json unreadable", { packageDir });
|
|
13081
13195
|
return { updated: false };
|
|
@@ -13114,21 +13228,21 @@ async function checkAutoUpdate(signal, logger) {
|
|
|
13114
13228
|
return { updated: true, name: pkg.name, current: pkg.version, latest };
|
|
13115
13229
|
}
|
|
13116
13230
|
async function findPackageDir(name) {
|
|
13117
|
-
let dir =
|
|
13231
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
13118
13232
|
for (; ; ) {
|
|
13119
|
-
const pkg = await readPackageJson(
|
|
13233
|
+
const pkg = await readPackageJson(join8(dir, "package.json"));
|
|
13120
13234
|
if (pkg?.name === name) return dir;
|
|
13121
|
-
const parent =
|
|
13235
|
+
const parent = dirname5(dir);
|
|
13122
13236
|
if (parent === dir) return void 0;
|
|
13123
13237
|
dir = parent;
|
|
13124
13238
|
}
|
|
13125
13239
|
}
|
|
13126
13240
|
async function updateTarget(packageDir, name) {
|
|
13127
|
-
const packageParent =
|
|
13128
|
-
const nodeModulesDir =
|
|
13129
|
-
if (
|
|
13130
|
-
const wrapperDir =
|
|
13131
|
-
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"));
|
|
13132
13246
|
const spec = wrapperSpec(wrapperDir, name) ?? wrapperPkg?.dependencies?.[name];
|
|
13133
13247
|
if (!spec || !isAutoUpdatableSpec(spec)) return void 0;
|
|
13134
13248
|
return { removeDir: wrapperDir, spec };
|
|
@@ -13136,13 +13250,13 @@ async function updateTarget(packageDir, name) {
|
|
|
13136
13250
|
function wrapperSpec(wrapperDir, name) {
|
|
13137
13251
|
if (name.startsWith("@")) {
|
|
13138
13252
|
const [scope, pkg] = name.split("/");
|
|
13139
|
-
if (!scope || !pkg ||
|
|
13253
|
+
if (!scope || !pkg || basename2(dirname5(wrapperDir)) !== scope) return void 0;
|
|
13140
13254
|
const prefix2 = `${pkg}@`;
|
|
13141
|
-
const base2 =
|
|
13255
|
+
const base2 = basename2(wrapperDir);
|
|
13142
13256
|
return base2.startsWith(prefix2) ? base2.slice(prefix2.length) : void 0;
|
|
13143
13257
|
}
|
|
13144
13258
|
const prefix = `${name}@`;
|
|
13145
|
-
const base =
|
|
13259
|
+
const base = basename2(wrapperDir);
|
|
13146
13260
|
return base.startsWith(prefix) ? base.slice(prefix.length) : void 0;
|
|
13147
13261
|
}
|
|
13148
13262
|
function isAutoUpdatableSpec(spec) {
|
|
@@ -13240,7 +13354,7 @@ var server = (async (ctx) => {
|
|
|
13240
13354
|
}
|
|
13241
13355
|
const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
|
|
13242
13356
|
logger.info("ACP plugin initialized", {
|
|
13243
|
-
version: true ? "1.18.1-pr.416.
|
|
13357
|
+
version: true ? "1.18.1-pr.416.177" : "dev",
|
|
13244
13358
|
workspace: ctx.directory,
|
|
13245
13359
|
logLevel: logger.level,
|
|
13246
13360
|
debug: config.debug,
|