@cydm/pie 1.0.48 → 1.0.49
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/builtin/extensions/ask-user/index.js +1 -1
- package/dist/builtin/extensions/plan-mode/index.js +1 -1
- package/dist/builtin/extensions/subagent/index.js +2 -2
- package/dist/builtin/extensions/todo/index.js +1 -1
- package/dist/chunks/{chunk-IJMP3JTX.js → chunk-7RYOIXA2.js} +212 -43
- package/dist/chunks/{chunk-U4B6RJ6Z.js → chunk-J6PEH6ST.js} +1 -1
- package/dist/cli.js +127 -80
- package/package.json +2 -2
- package/dist/builtin/extensions/kimi-attachments/index.js +0 -47
- package/dist/builtin/extensions/kimi-attachments/package.json +0 -11
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createAskUserCapability
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-7RYOIXA2.js";
|
|
5
5
|
import "../../../chunks/chunk-FKAO25XH.js";
|
|
6
6
|
import "../../../chunks/chunk-K6ZOCJ4V.js";
|
|
7
7
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createCliHostCapabilities
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-J6PEH6ST.js";
|
|
5
5
|
import {
|
|
6
6
|
createSharedFileSystemTools,
|
|
7
7
|
createSubagentCapability
|
|
8
|
-
} from "../../../chunks/chunk-
|
|
8
|
+
} from "../../../chunks/chunk-7RYOIXA2.js";
|
|
9
9
|
import "../../../chunks/chunk-FKAO25XH.js";
|
|
10
10
|
import "../../../chunks/chunk-K6ZOCJ4V.js";
|
|
11
11
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
executeManageTodoList,
|
|
8
8
|
executionStateToTodos,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-7RYOIXA2.js";
|
|
11
11
|
import "../../../chunks/chunk-FKAO25XH.js";
|
|
12
12
|
import "../../../chunks/chunk-K6ZOCJ4V.js";
|
|
13
13
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
@@ -7869,6 +7869,193 @@ function fuzzyFindText(content, oldText) {
|
|
|
7869
7869
|
function stripBom(content) {
|
|
7870
7870
|
return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
|
|
7871
7871
|
}
|
|
7872
|
+
function findEditMatch(content, oldText, newText) {
|
|
7873
|
+
const direct = fuzzyFindText(content, oldText);
|
|
7874
|
+
if (direct.found) {
|
|
7875
|
+
return { found: true, occurrences: direct.occurrences, matches: direct.matches, matchKind: direct.matchKind };
|
|
7876
|
+
}
|
|
7877
|
+
return findWhitespaceRelaxedMatch(content, oldText, newText);
|
|
7878
|
+
}
|
|
7879
|
+
function leadingWhitespace(line) {
|
|
7880
|
+
const match2 = line.match(/^[ \t]*/);
|
|
7881
|
+
return match2 ? match2[0] : "";
|
|
7882
|
+
}
|
|
7883
|
+
function findRelaxedWindows(fileLines, qLines) {
|
|
7884
|
+
const firstNonBlank = qLines.findIndex((line) => line.trim() !== "");
|
|
7885
|
+
if (firstNonBlank === -1) return [];
|
|
7886
|
+
const anchor = qLines[firstNonBlank].trim();
|
|
7887
|
+
if (!anchor) return [];
|
|
7888
|
+
const windows = [];
|
|
7889
|
+
for (let anchorFileLine = 0; anchorFileLine < fileLines.length; anchorFileLine++) {
|
|
7890
|
+
if (fileLines[anchorFileLine].trim() !== anchor) continue;
|
|
7891
|
+
const startLine = anchorFileLine - firstNonBlank;
|
|
7892
|
+
if (startLine < 0) continue;
|
|
7893
|
+
let fileLine = startLine;
|
|
7894
|
+
let ok = true;
|
|
7895
|
+
let lastPaired = -1;
|
|
7896
|
+
const qLineToFileLine = /* @__PURE__ */ new Map();
|
|
7897
|
+
for (let qLine = 0; qLine < qLines.length; qLine++) {
|
|
7898
|
+
if (fileLine >= fileLines.length) {
|
|
7899
|
+
ok = false;
|
|
7900
|
+
break;
|
|
7901
|
+
}
|
|
7902
|
+
const q = qLines[qLine];
|
|
7903
|
+
const f = fileLines[fileLine];
|
|
7904
|
+
if (q.trim() === "") {
|
|
7905
|
+
if (f.trim() !== "") {
|
|
7906
|
+
ok = false;
|
|
7907
|
+
break;
|
|
7908
|
+
}
|
|
7909
|
+
} else {
|
|
7910
|
+
if (f.trim() !== q.trim()) {
|
|
7911
|
+
ok = false;
|
|
7912
|
+
break;
|
|
7913
|
+
}
|
|
7914
|
+
qLineToFileLine.set(qLine, fileLine);
|
|
7915
|
+
lastPaired = fileLine;
|
|
7916
|
+
}
|
|
7917
|
+
fileLine++;
|
|
7918
|
+
}
|
|
7919
|
+
if (ok && lastPaired !== -1) windows.push({ startLine, endLine: lastPaired, qLineToFileLine });
|
|
7920
|
+
}
|
|
7921
|
+
return windows;
|
|
7922
|
+
}
|
|
7923
|
+
function lineSpanToCharSpan(fileLines, startLine, endLine) {
|
|
7924
|
+
let index = 0;
|
|
7925
|
+
for (let i = 0; i < startLine; i++) index += fileLines[i].length + 1;
|
|
7926
|
+
let matchLength = 0;
|
|
7927
|
+
for (let i = startLine; i <= endLine; i++) matchLength += fileLines[i].length + (i < endLine ? 1 : 0);
|
|
7928
|
+
return { index, matchLength };
|
|
7929
|
+
}
|
|
7930
|
+
function reindentNewText(newText, qLines, fileLines, window) {
|
|
7931
|
+
const newLines = newText.split("\n");
|
|
7932
|
+
const qIndent = (qLine) => {
|
|
7933
|
+
const fileLine = window.qLineToFileLine.get(qLine);
|
|
7934
|
+
return fileLine === void 0 ? "" : leadingWhitespace(fileLines[fileLine]);
|
|
7935
|
+
};
|
|
7936
|
+
const qIdx = [];
|
|
7937
|
+
for (let i = 0; i < qLines.length; i++) if (qLines[i].trim() !== "") qIdx.push(i);
|
|
7938
|
+
const nIdx = [];
|
|
7939
|
+
const nPosOfLine = /* @__PURE__ */ new Map();
|
|
7940
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
7941
|
+
if (newLines[i].trim() === "") continue;
|
|
7942
|
+
nPosOfLine.set(i, nIdx.length);
|
|
7943
|
+
nIdx.push(i);
|
|
7944
|
+
}
|
|
7945
|
+
if (nIdx.length === 0) return newText;
|
|
7946
|
+
const counterpart = /* @__PURE__ */ new Map();
|
|
7947
|
+
let p = 0;
|
|
7948
|
+
while (p < qIdx.length && p < nIdx.length && qLines[qIdx[p]].trim() === newLines[nIdx[p]].trim()) {
|
|
7949
|
+
counterpart.set(p, p);
|
|
7950
|
+
p++;
|
|
7951
|
+
}
|
|
7952
|
+
let s = 0;
|
|
7953
|
+
while (s < qIdx.length - p && s < nIdx.length - p && qLines[qIdx[qIdx.length - 1 - s]].trim() === newLines[nIdx[nIdx.length - 1 - s]].trim()) {
|
|
7954
|
+
counterpart.set(nIdx.length - 1 - s, qIdx.length - 1 - s);
|
|
7955
|
+
s++;
|
|
7956
|
+
}
|
|
7957
|
+
const midQ = [];
|
|
7958
|
+
for (let pos = p; pos < qIdx.length - s; pos++) midQ.push(pos);
|
|
7959
|
+
const midN = [];
|
|
7960
|
+
for (let pos = p; pos < nIdx.length - s; pos++) midN.push(pos);
|
|
7961
|
+
const pairRegion = (qLo, qHi, nLo, nHi) => {
|
|
7962
|
+
const qCount = qHi - qLo;
|
|
7963
|
+
const nCount = nHi - nLo;
|
|
7964
|
+
const paired = Math.min(qCount, nCount);
|
|
7965
|
+
for (let k = 0; k < paired; k++) counterpart.set(nLo + k, qLo + k);
|
|
7966
|
+
const fallbackQ = qCount > 0 ? qHi - 1 : Math.max(qLo - 1, 0);
|
|
7967
|
+
for (let k = paired; k < nCount; k++) counterpart.set(nLo + k, fallbackQ);
|
|
7968
|
+
};
|
|
7969
|
+
const qTextCounts = /* @__PURE__ */ new Map();
|
|
7970
|
+
for (const qPos of midQ) {
|
|
7971
|
+
const t = qLines[qIdx[qPos]].trim();
|
|
7972
|
+
qTextCounts.set(t, (qTextCounts.get(t) ?? 0) + 1);
|
|
7973
|
+
}
|
|
7974
|
+
const qPosByText = /* @__PURE__ */ new Map();
|
|
7975
|
+
for (const qPos of midQ) {
|
|
7976
|
+
const t = qLines[qIdx[qPos]].trim();
|
|
7977
|
+
if (qTextCounts.get(t) === 1) qPosByText.set(t, qPos);
|
|
7978
|
+
}
|
|
7979
|
+
const nTextCounts = /* @__PURE__ */ new Map();
|
|
7980
|
+
for (const nPos of midN) {
|
|
7981
|
+
const t = newLines[nIdx[nPos]].trim();
|
|
7982
|
+
nTextCounts.set(t, (nTextCounts.get(t) ?? 0) + 1);
|
|
7983
|
+
}
|
|
7984
|
+
let cursorQ = p;
|
|
7985
|
+
let cursorN = p;
|
|
7986
|
+
for (const nPos of midN) {
|
|
7987
|
+
const t = newLines[nIdx[nPos]].trim();
|
|
7988
|
+
const qPos = qPosByText.get(t);
|
|
7989
|
+
if (nTextCounts.get(t) !== 1 || qPos === void 0 || qPos < cursorQ) continue;
|
|
7990
|
+
pairRegion(cursorQ, qPos, cursorN, nPos);
|
|
7991
|
+
counterpart.set(nPos, qPos);
|
|
7992
|
+
cursorQ = qPos + 1;
|
|
7993
|
+
cursorN = nPos + 1;
|
|
7994
|
+
}
|
|
7995
|
+
pairRegion(cursorQ, qIdx.length - s, cursorN, nIdx.length - s);
|
|
7996
|
+
const result = [];
|
|
7997
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
7998
|
+
if (newLines[i].trim() === "") {
|
|
7999
|
+
result.push("");
|
|
8000
|
+
continue;
|
|
8001
|
+
}
|
|
8002
|
+
const nPos = nPosOfLine.get(i) ?? 0;
|
|
8003
|
+
const qPos = counterpart.get(nPos) ?? 0;
|
|
8004
|
+
result.push(qIndent(qIdx[qPos] ?? qIdx[0]) + newLines[i].trim());
|
|
8005
|
+
}
|
|
8006
|
+
return result.join("\n");
|
|
8007
|
+
}
|
|
8008
|
+
function findWhitespaceRelaxedMatch(content, oldText, newText) {
|
|
8009
|
+
const fileLines = content.split("\n");
|
|
8010
|
+
const qLines = oldText.split("\n");
|
|
8011
|
+
const windows = findRelaxedWindows(fileLines, qLines);
|
|
8012
|
+
if (windows.length === 0) {
|
|
8013
|
+
return { found: false, occurrences: 0, matches: [], matchKind: "none" };
|
|
8014
|
+
}
|
|
8015
|
+
const matches = windows.map((window) => {
|
|
8016
|
+
const span = lineSpanToCharSpan(fileLines, window.startLine, window.endLine);
|
|
8017
|
+
return { ...span, replacementText: reindentNewText(newText, qLines, fileLines, window) };
|
|
8018
|
+
});
|
|
8019
|
+
return { found: true, occurrences: matches.length, matches, matchKind: "whitespace-relaxed" };
|
|
8020
|
+
}
|
|
8021
|
+
function describeClosestRegion(content, oldText) {
|
|
8022
|
+
const qLines = oldText.split("\n");
|
|
8023
|
+
const firstNonBlank = qLines.findIndex((line) => line.trim() !== "");
|
|
8024
|
+
if (firstNonBlank === -1) return void 0;
|
|
8025
|
+
const anchor = qLines[firstNonBlank].trim();
|
|
8026
|
+
const fileLines = content.split("\n");
|
|
8027
|
+
const clip = (text) => text.length > 90 ? `${text.slice(0, 90)}\u2026` : text;
|
|
8028
|
+
let best;
|
|
8029
|
+
for (let i = 0; i < fileLines.length; i++) {
|
|
8030
|
+
if (fileLines[i].trim() !== anchor) continue;
|
|
8031
|
+
let matched = 0;
|
|
8032
|
+
let fi = i;
|
|
8033
|
+
let firstDiff;
|
|
8034
|
+
for (let qi = firstNonBlank; qi < qLines.length; qi++) {
|
|
8035
|
+
const q = qLines[qi].trim();
|
|
8036
|
+
if (!q) continue;
|
|
8037
|
+
while (fi < fileLines.length && !fileLines[fi].trim()) fi++;
|
|
8038
|
+
if (fi >= fileLines.length || fileLines[fi].trim() !== q) {
|
|
8039
|
+
firstDiff = { fileNo: fi + 1, fileLine: fileLines[fi] ?? "<end of file>", qLine: qLines[qi] };
|
|
8040
|
+
break;
|
|
8041
|
+
}
|
|
8042
|
+
matched++;
|
|
8043
|
+
fi++;
|
|
8044
|
+
}
|
|
8045
|
+
if (!best || matched > best.matched) best = { start: i, matched, firstDiff };
|
|
8046
|
+
}
|
|
8047
|
+
const total = qLines.filter((line) => line.trim() !== "").length;
|
|
8048
|
+
if (!best) {
|
|
8049
|
+
return `No line matching ${JSON.stringify(clip(anchor))} exists in this file \u2014 the text may live in a different file, or the file changed since it was read.`;
|
|
8050
|
+
}
|
|
8051
|
+
const parts = [`Closest match: file lines ${best.start + 1}\u2013${best.start + total} (${best.matched}/${total} lines matched by trimmed content).`];
|
|
8052
|
+
if (best.firstDiff) {
|
|
8053
|
+
parts.push(`First difference at line ${best.firstDiff.fileNo}: file has ${JSON.stringify(clip(best.firstDiff.fileLine.trim()))}, edit expected ${JSON.stringify(clip(best.firstDiff.qLine.trim()))}.`);
|
|
8054
|
+
} else {
|
|
8055
|
+
parts.push("All non-empty lines match by trimmed content \u2014 the mismatch is leading whitespace or blank-line placement.");
|
|
8056
|
+
}
|
|
8057
|
+
return parts.join(" ");
|
|
8058
|
+
}
|
|
7872
8059
|
function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
7873
8060
|
const oldLines = normalizeToLF(stripBom(oldContent).text).split("\n");
|
|
7874
8061
|
const newLines = normalizeToLF(stripBom(newContent).text).split("\n");
|
|
@@ -7982,7 +8169,8 @@ function createEditErrorResult(params) {
|
|
|
7982
8169
|
const detailLines = [
|
|
7983
8170
|
params.message,
|
|
7984
8171
|
params.recoveryHint,
|
|
7985
|
-
params.alreadyAppliedCandidate ? "Diagnostic: newText already appears in the current file, but edit_file did not treat that as success because it may be an unrelated occurrence." : ""
|
|
8172
|
+
params.alreadyAppliedCandidate ? "Diagnostic: newText already appears in the current file, but edit_file did not treat that as success because it may be an unrelated occurrence." : "",
|
|
8173
|
+
params.closestMatch ? `Diagnostic: ${params.closestMatch}` : ""
|
|
7986
8174
|
].filter(Boolean);
|
|
7987
8175
|
return {
|
|
7988
8176
|
content: [{ type: "text", text: detailLines.join("\n") }],
|
|
@@ -8034,7 +8222,7 @@ function createEditTool(cwd, options) {
|
|
|
8034
8222
|
newText: Type.String({ description: "Replacement text", maxLength: MAX_EDIT_INPUT_CHARS }),
|
|
8035
8223
|
replaceAll: Type.Optional(Type.Boolean({ description: "Replace every occurrence" }))
|
|
8036
8224
|
}), {
|
|
8037
|
-
description: "
|
|
8225
|
+
description: "Replacements applied in order: each edit matches the file as left by the previous edit, so later edits can build on earlier ones. Whole-line indentation drift is tolerated \u2014 matches locate by trimmed content and the replacement adopts the file's indentation.",
|
|
8038
8226
|
minItems: 1,
|
|
8039
8227
|
maxItems: MAX_EDIT_BLOCKS
|
|
8040
8228
|
})
|
|
@@ -8043,7 +8231,7 @@ function createEditTool(cwd, options) {
|
|
|
8043
8231
|
return {
|
|
8044
8232
|
name: "edit",
|
|
8045
8233
|
label: "edit",
|
|
8046
|
-
description: `Make precise exact-text replacements in one file. For multiple changes in the same file, put all
|
|
8234
|
+
description: `Make precise exact-text replacements in one file. For multiple changes in the same file, put all replacements in one edits[] call \u2014 they apply in order, so later edits can target what earlier ones just changed. ${pathResolutionDescription}`,
|
|
8047
8235
|
parameters: editSchema,
|
|
8048
8236
|
execute: async (_toolCallId, params, signal) => {
|
|
8049
8237
|
const { path: path4, root } = params;
|
|
@@ -8087,7 +8275,9 @@ function createEditTool(cwd, options) {
|
|
|
8087
8275
|
const { bom, text: content } = stripBom(rawContent);
|
|
8088
8276
|
const originalEnding = detectLineEnding(content);
|
|
8089
8277
|
const normalizedContent = normalizeToLF(content);
|
|
8090
|
-
|
|
8278
|
+
let workingContent = normalizedContent;
|
|
8279
|
+
const plannedKinds = /* @__PURE__ */ new Set();
|
|
8280
|
+
let replacedOccurrences = 0;
|
|
8091
8281
|
let totalOldOccurrences = 0;
|
|
8092
8282
|
let totalNewOccurrences = 0;
|
|
8093
8283
|
let anyReplaceAll = false;
|
|
@@ -8095,8 +8285,8 @@ function createEditTool(cwd, options) {
|
|
|
8095
8285
|
throwIfAborted();
|
|
8096
8286
|
const normalizedOldText = normalizeToLF(replacement.oldText);
|
|
8097
8287
|
const normalizedNewText = normalizeToLF(replacement.newText);
|
|
8098
|
-
const newTextOccurrences = countOccurrences(
|
|
8099
|
-
const matchResult =
|
|
8288
|
+
const newTextOccurrences = countOccurrences(workingContent, normalizedNewText);
|
|
8289
|
+
const matchResult = findEditMatch(workingContent, normalizedOldText, normalizedNewText);
|
|
8100
8290
|
totalOldOccurrences += matchResult.occurrences;
|
|
8101
8291
|
totalNewOccurrences += newTextOccurrences;
|
|
8102
8292
|
anyReplaceAll ||= replacement.replaceAll;
|
|
@@ -8111,7 +8301,8 @@ function createEditTool(cwd, options) {
|
|
|
8111
8301
|
replaceAll: replacement.replaceAll,
|
|
8112
8302
|
staleBaseLikely: newTextOccurrences > 0,
|
|
8113
8303
|
alreadyAppliedCandidate: newTextOccurrences > 0,
|
|
8114
|
-
recoveryHint: newTextOccurrences > 0 ? "The replacement may already be present. Read the current file before retrying." : "Read the latest file and retry with exact text."
|
|
8304
|
+
recoveryHint: newTextOccurrences > 0 ? "The replacement may already be present. Read the current file before retrying." : "Read the latest file and retry with exact text.",
|
|
8305
|
+
closestMatch: describeClosestRegion(workingContent, normalizedOldText)
|
|
8115
8306
|
}));
|
|
8116
8307
|
return;
|
|
8117
8308
|
}
|
|
@@ -8128,9 +8319,9 @@ function createEditTool(cwd, options) {
|
|
|
8128
8319
|
}));
|
|
8129
8320
|
return;
|
|
8130
8321
|
}
|
|
8131
|
-
const
|
|
8132
|
-
const changingMatches =
|
|
8133
|
-
(match2) =>
|
|
8322
|
+
const selected = replacement.replaceAll ? matchResult.matches : matchResult.matches.slice(0, 1);
|
|
8323
|
+
const changingMatches = selected.filter(
|
|
8324
|
+
(match2) => workingContent.slice(match2.index, match2.index + match2.matchLength) !== (match2.replacementText ?? normalizedNewText)
|
|
8134
8325
|
);
|
|
8135
8326
|
if (changingMatches.length === 0) {
|
|
8136
8327
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
@@ -8146,42 +8337,20 @@ function createEditTool(cwd, options) {
|
|
|
8146
8337
|
}));
|
|
8147
8338
|
return;
|
|
8148
8339
|
}
|
|
8149
|
-
for (const match2 of changingMatches) {
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
for (let index = 1; index < ordered.length; index++) {
|
|
8155
|
-
throwIfAborted();
|
|
8156
|
-
const previous = ordered[index - 1];
|
|
8157
|
-
const current = ordered[index];
|
|
8158
|
-
if (current.index < previous.index + previous.matchLength) {
|
|
8159
|
-
if (signal) signal.removeEventListener("abort", onAbort);
|
|
8160
|
-
resolve3(createEditErrorResult({
|
|
8161
|
-
message: `Edits overlap in ${path4}; no changes were made.`,
|
|
8162
|
-
matchKind: "mixed",
|
|
8163
|
-
errorReason: "overlapping_edits",
|
|
8164
|
-
oldTextOccurrences: totalOldOccurrences,
|
|
8165
|
-
newTextOccurrences: totalNewOccurrences,
|
|
8166
|
-
replaceAll: anyReplaceAll,
|
|
8167
|
-
recoveryHint: "Merge overlapping replacements into one exact edit."
|
|
8168
|
-
}));
|
|
8169
|
-
return;
|
|
8340
|
+
for (const match2 of [...changingMatches].sort((left, right) => right.index - left.index)) {
|
|
8341
|
+
throwIfAborted();
|
|
8342
|
+
workingContent = workingContent.substring(0, match2.index) + (match2.replacementText ?? normalizedNewText) + workingContent.substring(match2.index + match2.matchLength);
|
|
8343
|
+
replacedOccurrences++;
|
|
8344
|
+
if (matchResult.matchKind !== "none") plannedKinds.add(matchResult.matchKind);
|
|
8170
8345
|
}
|
|
8171
8346
|
}
|
|
8172
8347
|
throwIfAborted();
|
|
8173
|
-
|
|
8174
|
-
let newContent = baseContent;
|
|
8175
|
-
for (const match2 of [...planned].sort((left, right) => right.index - left.index)) {
|
|
8176
|
-
throwIfAborted();
|
|
8177
|
-
newContent = newContent.substring(0, match2.index) + match2.newText + newContent.substring(match2.index + match2.matchLength);
|
|
8178
|
-
}
|
|
8179
|
-
if (baseContent === newContent) {
|
|
8348
|
+
if (workingContent === normalizedContent) {
|
|
8180
8349
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
8181
8350
|
resolve3(
|
|
8182
8351
|
createEditErrorResult({
|
|
8183
8352
|
message: `No changes made to ${path4}. The replacement produced identical content.`,
|
|
8184
|
-
matchKind:
|
|
8353
|
+
matchKind: plannedKinds.size === 1 ? [...plannedKinds][0] : "mixed",
|
|
8185
8354
|
errorReason: "replacement_no_change",
|
|
8186
8355
|
oldTextOccurrences: totalOldOccurrences,
|
|
8187
8356
|
newTextOccurrences: totalNewOccurrences,
|
|
@@ -8192,6 +8361,7 @@ function createEditTool(cwd, options) {
|
|
|
8192
8361
|
);
|
|
8193
8362
|
return;
|
|
8194
8363
|
}
|
|
8364
|
+
const newContent = workingContent;
|
|
8195
8365
|
const finalContent = bom + restoreLineEndings(newContent, originalEnding);
|
|
8196
8366
|
throwIfAborted();
|
|
8197
8367
|
await fs2.writeFile(absolutePath, finalContent, "utf-8");
|
|
@@ -8201,13 +8371,12 @@ function createEditTool(cwd, options) {
|
|
|
8201
8371
|
signal.removeEventListener("abort", onAbort);
|
|
8202
8372
|
}
|
|
8203
8373
|
const diffResult = generateDiffString(content, restoreLineEndings(newContent, originalEnding));
|
|
8204
|
-
const
|
|
8205
|
-
const matchKind = matchKinds.size === 1 ? planned[0]?.matchKind ?? "none" : "mixed";
|
|
8374
|
+
const matchKind = plannedKinds.size === 1 ? [...plannedKinds][0] : "mixed";
|
|
8206
8375
|
resolve3({
|
|
8207
8376
|
content: [
|
|
8208
8377
|
{
|
|
8209
8378
|
type: "text",
|
|
8210
|
-
text: `Changed ${path4}: ${replacements.length} edit block${replacements.length === 1 ? "" : "s"}, ${
|
|
8379
|
+
text: `Changed ${path4}: ${replacements.length} edit block${replacements.length === 1 ? "" : "s"}, ${replacedOccurrences} replacement${replacedOccurrences === 1 ? "" : "s"}. First changed line: ${diffResult.firstChangedLine}.`
|
|
8211
8380
|
},
|
|
8212
8381
|
{ type: "text", text: boundedDiff(diffResult.diff) }
|
|
8213
8382
|
],
|
|
@@ -8221,7 +8390,7 @@ function createEditTool(cwd, options) {
|
|
|
8221
8390
|
oldTextOccurrences: totalOldOccurrences,
|
|
8222
8391
|
newTextOccurrences: totalNewOccurrences,
|
|
8223
8392
|
replaceAll: anyReplaceAll,
|
|
8224
|
-
replacedOccurrences
|
|
8393
|
+
replacedOccurrences,
|
|
8225
8394
|
replacedBlocks: replacements.length
|
|
8226
8395
|
}
|
|
8227
8396
|
});
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,10 @@ import {
|
|
|
19
19
|
getThemesDir,
|
|
20
20
|
migrateConfigFromAgentDir,
|
|
21
21
|
truncateHeadTail
|
|
22
|
-
} from "./chunks/chunk-
|
|
22
|
+
} from "./chunks/chunk-J6PEH6ST.js";
|
|
23
|
+
import {
|
|
24
|
+
resolveCliProjectRoot
|
|
25
|
+
} from "./chunks/chunk-WLFOBECN.js";
|
|
23
26
|
import {
|
|
24
27
|
AGENTS_CONTEXT_FILE_NAME,
|
|
25
28
|
AgentSessionController,
|
|
@@ -70,7 +73,7 @@ import {
|
|
|
70
73
|
setExtensionEnabledInSettings,
|
|
71
74
|
shouldPreserveExecutionStateForUserText,
|
|
72
75
|
supersedeExecutionState
|
|
73
|
-
} from "./chunks/chunk-
|
|
76
|
+
} from "./chunks/chunk-7RYOIXA2.js";
|
|
74
77
|
import "./chunks/chunk-FKAO25XH.js";
|
|
75
78
|
import {
|
|
76
79
|
Deref,
|
|
@@ -108,9 +111,6 @@ import {
|
|
|
108
111
|
sortToolModelCandidatesByCapability,
|
|
109
112
|
type_exports
|
|
110
113
|
} from "./chunks/chunk-K6ZOCJ4V.js";
|
|
111
|
-
import {
|
|
112
|
-
resolveCliProjectRoot
|
|
113
|
-
} from "./chunks/chunk-WLFOBECN.js";
|
|
114
114
|
import {
|
|
115
115
|
__commonJS,
|
|
116
116
|
__require,
|
|
@@ -51855,13 +51855,6 @@ var Editor = class {
|
|
|
51855
51855
|
autocompleteState = null;
|
|
51856
51856
|
autocompletePrefix = "";
|
|
51857
51857
|
autocompleteMaxVisible = 5;
|
|
51858
|
-
/**
|
|
51859
|
-
* Whether the user moved the autocomplete selection (arrows/paging).
|
|
51860
|
-
* A bare "/" + Enter still submits the slash itself (root command menu),
|
|
51861
|
-
* but once the user has actively highlighted an item, Enter must accept
|
|
51862
|
-
* that selection instead of re-opening the same menu.
|
|
51863
|
-
*/
|
|
51864
|
-
autocompleteListTouched = false;
|
|
51865
51858
|
// Paste tracking for large pastes
|
|
51866
51859
|
pastes = /* @__PURE__ */ new Map();
|
|
51867
51860
|
pasteCounter = 0;
|
|
@@ -52098,12 +52091,10 @@ var Editor = class {
|
|
|
52098
52091
|
return;
|
|
52099
52092
|
}
|
|
52100
52093
|
if (kb.matches(data, "selectUp") || kb.matches(data, "selectDown")) {
|
|
52101
|
-
this.autocompleteListTouched = true;
|
|
52102
52094
|
this.autocompleteList.handleInput(data);
|
|
52103
52095
|
return;
|
|
52104
52096
|
}
|
|
52105
52097
|
if (kb.matches(data, "cursorLeft") || kb.matches(data, "cursorRight") || kb.matches(data, "pageUp") || kb.matches(data, "pageDown")) {
|
|
52106
|
-
this.autocompleteListTouched = true;
|
|
52107
52098
|
this.autocompleteList.handleInput(data);
|
|
52108
52099
|
return;
|
|
52109
52100
|
}
|
|
@@ -52128,32 +52119,26 @@ var Editor = class {
|
|
|
52128
52119
|
return;
|
|
52129
52120
|
}
|
|
52130
52121
|
if (kb.matches(data, "selectConfirm")) {
|
|
52131
|
-
const
|
|
52132
|
-
|
|
52133
|
-
|
|
52134
|
-
this.
|
|
52135
|
-
|
|
52136
|
-
|
|
52137
|
-
|
|
52138
|
-
this.
|
|
52139
|
-
|
|
52140
|
-
|
|
52141
|
-
|
|
52142
|
-
|
|
52143
|
-
|
|
52144
|
-
|
|
52145
|
-
|
|
52146
|
-
);
|
|
52147
|
-
|
|
52148
|
-
this.
|
|
52149
|
-
this.
|
|
52150
|
-
|
|
52151
|
-
this.cancelAutocomplete();
|
|
52152
|
-
} else {
|
|
52153
|
-
this.cancelAutocomplete();
|
|
52154
|
-
if (this.onChange) this.onChange(this.getText());
|
|
52155
|
-
return;
|
|
52156
|
-
}
|
|
52122
|
+
const selected = this.autocompleteList.getSelectedItem();
|
|
52123
|
+
if (selected && this.autocompleteProvider) {
|
|
52124
|
+
this.pushUndoSnapshot();
|
|
52125
|
+
this.lastAction = null;
|
|
52126
|
+
const result = this.autocompleteProvider.applyCompletion(
|
|
52127
|
+
this.state.lines,
|
|
52128
|
+
this.state.cursorLine,
|
|
52129
|
+
this.state.cursorCol,
|
|
52130
|
+
selected,
|
|
52131
|
+
this.autocompletePrefix
|
|
52132
|
+
);
|
|
52133
|
+
this.state.lines = result.lines;
|
|
52134
|
+
this.state.cursorLine = result.cursorLine;
|
|
52135
|
+
this.setCursorCol(result.cursorCol);
|
|
52136
|
+
if (this.autocompletePrefix.startsWith("/")) {
|
|
52137
|
+
this.cancelAutocomplete();
|
|
52138
|
+
} else {
|
|
52139
|
+
this.cancelAutocomplete();
|
|
52140
|
+
if (this.onChange) this.onChange(this.getText());
|
|
52141
|
+
return;
|
|
52157
52142
|
}
|
|
52158
52143
|
}
|
|
52159
52144
|
}
|
|
@@ -53149,7 +53134,6 @@ var Editor = class {
|
|
|
53149
53134
|
);
|
|
53150
53135
|
if (suggestions && suggestions.items.length > 0) {
|
|
53151
53136
|
this.autocompletePrefix = suggestions.prefix;
|
|
53152
|
-
this.autocompleteListTouched = false;
|
|
53153
53137
|
this.autocompleteList = new SelectList(
|
|
53154
53138
|
suggestions.items,
|
|
53155
53139
|
this.computeAutocompleteMaxVisible(suggestions.items.length),
|
|
@@ -53221,7 +53205,6 @@ var Editor = class {
|
|
|
53221
53205
|
return;
|
|
53222
53206
|
}
|
|
53223
53207
|
this.autocompletePrefix = suggestions.prefix;
|
|
53224
|
-
this.autocompleteListTouched = false;
|
|
53225
53208
|
this.autocompleteList = new SelectList(
|
|
53226
53209
|
suggestions.items,
|
|
53227
53210
|
this.computeAutocompleteMaxVisible(suggestions.items.length),
|
|
@@ -53236,7 +53219,6 @@ var Editor = class {
|
|
|
53236
53219
|
this.autocompleteState = null;
|
|
53237
53220
|
this.autocompleteList = void 0;
|
|
53238
53221
|
this.autocompletePrefix = "";
|
|
53239
|
-
this.autocompleteListTouched = false;
|
|
53240
53222
|
}
|
|
53241
53223
|
isShowingAutocomplete() {
|
|
53242
53224
|
return this.autocompleteState !== null;
|
|
@@ -62729,7 +62711,12 @@ var BUILTIN_SLASH_COMMANDS = [
|
|
|
62729
62711
|
{ name: "tools/subagent", description: "Spawn subagents in parallel to handle tasks" },
|
|
62730
62712
|
{ name: "files/upload", description: "Attach a file to the conversation" },
|
|
62731
62713
|
{ name: "files/upload-pic", description: "Attach an image to the conversation" },
|
|
62732
|
-
{ name: "files/upload-video", description: "Attach a video to the conversation" }
|
|
62714
|
+
{ name: "files/upload-video", description: "Attach a video to the conversation" },
|
|
62715
|
+
{ name: "files/list", description: "List uploaded files" },
|
|
62716
|
+
{ name: "files/status", description: "Check file status" },
|
|
62717
|
+
{ name: "files/refresh", description: "Refresh expired files" },
|
|
62718
|
+
{ name: "files/delete", description: "Delete a file" },
|
|
62719
|
+
{ name: "files/stats", description: "Show file statistics" }
|
|
62733
62720
|
];
|
|
62734
62721
|
|
|
62735
62722
|
// src/commands/interactive-debug-commands.ts
|
|
@@ -65305,6 +65292,7 @@ function handleSkillsCommand(host) {
|
|
|
65305
65292
|
host.showSelector((done) => {
|
|
65306
65293
|
const settingsManager = host.options.settingsManager;
|
|
65307
65294
|
const discovered = listDiscoveredSkills(host);
|
|
65295
|
+
const lastPersisted = /* @__PURE__ */ new Map();
|
|
65308
65296
|
const items = discovered.map((skill) => ({
|
|
65309
65297
|
id: `skill:${skill.name}`,
|
|
65310
65298
|
label: skill.name,
|
|
@@ -65312,25 +65300,23 @@ function handleSkillsCommand(host) {
|
|
|
65312
65300
|
currentValue: settingsManager.isSkillEnabled(skill.name) ? "on" : "off",
|
|
65313
65301
|
values: ["on", "off"]
|
|
65314
65302
|
}));
|
|
65303
|
+
for (const item of items) lastPersisted.set(item.id, item.currentValue);
|
|
65315
65304
|
const settingsList = new SettingsList(
|
|
65316
65305
|
items,
|
|
65317
65306
|
12,
|
|
65318
|
-
|
|
65319
|
-
label: (text, selected) => selected ? theme.fg("accent", text) : theme.fg("text", text),
|
|
65320
|
-
value: (text, selected) => selected ? theme.fg("accent", text) : theme.fg("accent", text),
|
|
65321
|
-
description: (text) => theme.fg("muted", text),
|
|
65322
|
-
cursor: "> ",
|
|
65323
|
-
hint: (text) => theme.fg("dim", text)
|
|
65324
|
-
},
|
|
65307
|
+
getSettingsListTheme(),
|
|
65325
65308
|
(id, newValue) => {
|
|
65326
65309
|
const name = id.slice("skill:".length);
|
|
65327
65310
|
const enabled = newValue === "on";
|
|
65311
|
+
const previous = lastPersisted.get(id) ?? "on";
|
|
65328
65312
|
try {
|
|
65329
65313
|
settingsManager.setSkillEnabled(name, enabled);
|
|
65330
65314
|
} catch (error) {
|
|
65315
|
+
settingsList.updateValue(id, previous);
|
|
65331
65316
|
host.showError(`Failed to update skill "${name}": ${errorMessage2(error)}`);
|
|
65332
65317
|
return;
|
|
65333
65318
|
}
|
|
65319
|
+
lastPersisted.set(id, newValue);
|
|
65334
65320
|
applyReloadedSkills(host, discoverSkills(host));
|
|
65335
65321
|
host.showStatus(`Skill "${name}" ${enabled ? "enabled" : "disabled"} (reloaded).`);
|
|
65336
65322
|
},
|
|
@@ -65628,23 +65614,8 @@ async function handleSkillsReload(host) {
|
|
|
65628
65614
|
host.chatContainer.addChild(new Text(theme.fg("accent", "Reloading skills..."), 1, 0));
|
|
65629
65615
|
host.ui.requestRender();
|
|
65630
65616
|
try {
|
|
65631
|
-
const
|
|
65632
|
-
|
|
65633
|
-
const projectDir = path25.join(process.cwd(), ".pie", "skills");
|
|
65634
|
-
const result = loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) });
|
|
65635
|
-
host.skills = result.skills.filter((skill) => host.options.settingsManager.isSkillEnabled(skill.name));
|
|
65636
|
-
host.skillsSection = formatSkillsForPrompt(host.skills);
|
|
65637
|
-
host.applyRuntimeToolMode(host.allTools.length > 0 ? host.allTools : host.agent.state.tools);
|
|
65638
|
-
host.updateSystemPromptTools();
|
|
65639
|
-
for (const skill of host.skills) {
|
|
65640
|
-
const skillPath = ["skills", `skill:${skill.name}`];
|
|
65641
|
-
if (!commandTree.find(skillPath)) {
|
|
65642
|
-
commandTree.register(skillPath, {
|
|
65643
|
-
description: skill.description,
|
|
65644
|
-
handler: (_2, args) => host.handleSkillInvoke(skill.name, args || "")
|
|
65645
|
-
});
|
|
65646
|
-
}
|
|
65647
|
-
}
|
|
65617
|
+
const result = discoverSkills(host);
|
|
65618
|
+
applyReloadedSkills(host, result);
|
|
65648
65619
|
const builtinCount = host.skills.filter((s) => s.source === "builtin").length;
|
|
65649
65620
|
const userCount = host.skills.filter((s) => s.source === "user" || s.source === "user-agents").length;
|
|
65650
65621
|
const projectCount = host.skills.filter((s) => s.source === "project" || s.source === "project-agents").length;
|
|
@@ -65677,10 +65648,18 @@ function collectKnownToolNames(host) {
|
|
|
65677
65648
|
const disabled = disabledNames.filter((name) => !liveNames.includes(name));
|
|
65678
65649
|
return { active: [...liveNames].sort(), disabled: [...disabled].sort() };
|
|
65679
65650
|
}
|
|
65651
|
+
function describeToggleEffect(host, name, enabled) {
|
|
65652
|
+
const loaded = collectKnownToolNames(host).active.includes(name);
|
|
65653
|
+
if (enabled) {
|
|
65654
|
+
return loaded ? `Tool "${name}" enabled (active now).` : `Tool "${name}" enabled in ~/.pie/settings.json (loads on next start \u2014 it was not loaded this session).`;
|
|
65655
|
+
}
|
|
65656
|
+
return loaded ? `Tool "${name}" disabled (removed from this session).` : `Tool "${name}" disabled in ~/.pie/settings.json.`;
|
|
65657
|
+
}
|
|
65680
65658
|
function showToolsManager(host) {
|
|
65681
65659
|
host.showSelector((done) => {
|
|
65682
65660
|
const { active, disabled } = collectKnownToolNames(host);
|
|
65683
65661
|
const settingsManager = host.options.settingsManager;
|
|
65662
|
+
const lastPersisted = /* @__PURE__ */ new Map();
|
|
65684
65663
|
const items = [
|
|
65685
65664
|
...active.map((name) => ({
|
|
65686
65665
|
id: `tool:${name}`,
|
|
@@ -65692,28 +65671,30 @@ function showToolsManager(host) {
|
|
|
65692
65671
|
...disabled.map((name) => ({
|
|
65693
65672
|
id: `tool:${name}`,
|
|
65694
65673
|
label: name,
|
|
65695
|
-
description: "Not loaded this session (
|
|
65674
|
+
description: "Not loaded this session (starts enabled next launch)",
|
|
65696
65675
|
currentValue: "off",
|
|
65697
65676
|
values: ["on", "off"]
|
|
65698
65677
|
}))
|
|
65699
65678
|
];
|
|
65679
|
+
for (const item of items) lastPersisted.set(item.id, item.currentValue);
|
|
65700
65680
|
const settingsList = new SettingsList(
|
|
65701
65681
|
items,
|
|
65702
65682
|
14,
|
|
65703
65683
|
getSettingsListTheme(),
|
|
65704
|
-
(
|
|
65705
|
-
const name =
|
|
65684
|
+
(id, newValue) => {
|
|
65685
|
+
const name = id.slice("tool:".length);
|
|
65706
65686
|
const enabled = newValue === "on";
|
|
65687
|
+
const previous = lastPersisted.get(id) ?? "off";
|
|
65707
65688
|
try {
|
|
65708
65689
|
settingsManager.setToolEnabled(name, enabled);
|
|
65709
65690
|
} catch (error) {
|
|
65691
|
+
settingsList.updateValue(id, previous);
|
|
65710
65692
|
host.showError(`Failed to update tool "${name}": ${errorMessage3(error)}`);
|
|
65711
65693
|
return;
|
|
65712
65694
|
}
|
|
65695
|
+
lastPersisted.set(id, newValue);
|
|
65713
65696
|
host.applyRuntimeToolMode();
|
|
65714
|
-
host.showStatus(
|
|
65715
|
-
enabled ? `Tool "${name}" enabled (active now).` : `Tool "${name}" disabled (removed from this session).`
|
|
65716
|
-
);
|
|
65697
|
+
host.showStatus(describeToggleEffect(host, name, enabled));
|
|
65717
65698
|
},
|
|
65718
65699
|
() => done(),
|
|
65719
65700
|
{ enableSearch: true }
|
|
@@ -65733,7 +65714,7 @@ function renderHeader(width) {
|
|
|
65733
65714
|
const lines = [];
|
|
65734
65715
|
lines.push(theme.bold(theme.fg("accent", "Tools")));
|
|
65735
65716
|
lines.push("");
|
|
65736
|
-
lines.push(theme.fg("muted", "Enter/Space toggles \xB7
|
|
65717
|
+
lines.push(theme.fg("muted", "Enter/Space toggles \xB7 live tools apply immediately \xB7 Esc to close"));
|
|
65737
65718
|
const hint = "Usage: /tools/enable <name> | /tools/disable <name>";
|
|
65738
65719
|
if (width > 20) lines.push(theme.fg("dim", hint));
|
|
65739
65720
|
return lines;
|
|
@@ -65762,7 +65743,7 @@ function handleToolsCommand(host, args) {
|
|
|
65762
65743
|
host.applyRuntimeToolMode();
|
|
65763
65744
|
host.chatContainer.addChild(new Spacer(1));
|
|
65764
65745
|
host.chatContainer.addChild(new Text(
|
|
65765
|
-
theme.fg("accent",
|
|
65746
|
+
theme.fg("accent", describeToggleEffect(host, name, enabled)),
|
|
65766
65747
|
1,
|
|
65767
65748
|
0
|
|
65768
65749
|
));
|
|
@@ -66471,7 +66452,7 @@ function registerBuiltinCommands(host) {
|
|
|
66471
66452
|
handler: (_2, args) => host.handleToolsCommand(args ? `list ${args}` : "list")
|
|
66472
66453
|
});
|
|
66473
66454
|
commandTree.register(["tools", "enable"], {
|
|
66474
|
-
description: "Enable a tool by name (writes settings;
|
|
66455
|
+
description: "Enable a tool by name (writes settings; live tools apply now)",
|
|
66475
66456
|
handler: (_2, args) => host.handleToolsCommand(`enable ${args || ""}`)
|
|
66476
66457
|
});
|
|
66477
66458
|
commandTree.register(["tools", "disable"], {
|
|
@@ -66633,6 +66614,7 @@ function ringTerminalBell(options = {}) {
|
|
|
66633
66614
|
function ringTurnSettledBell(host) {
|
|
66634
66615
|
if ((host.agentSessionController?.pendingMessageCount ?? 0) > 0) return;
|
|
66635
66616
|
if (host.executionState.read().awaitingContinuation) return;
|
|
66617
|
+
if (host.peekTodoAutoContinuePrompt?.()) return;
|
|
66636
66618
|
host.ringAttentionBell?.("turn-settled");
|
|
66637
66619
|
}
|
|
66638
66620
|
function attentionMessage(reason) {
|
|
@@ -70275,12 +70257,19 @@ function clearContinuationTimeout(host, reason) {
|
|
|
70275
70257
|
function isWaitingForUserInteraction(host) {
|
|
70276
70258
|
return host.activeInteractionCount > 0;
|
|
70277
70259
|
}
|
|
70260
|
+
function peekTodoAutoContinuePrompt(host) {
|
|
70261
|
+
if (isWaitingForUserInteraction(host)) return void 0;
|
|
70262
|
+
if (host.submitLock || host.isProcessing || host.isInterrupting || host.isCompacting) return void 0;
|
|
70263
|
+
const hasTodoTool = (host.agent?.state?.tools ?? []).some((tool) => tool.name === "manage_todo_list");
|
|
70264
|
+
if (!hasTodoTool) return void 0;
|
|
70265
|
+
return host.executionState.takeTodoClosureFollowUp() || void 0;
|
|
70266
|
+
}
|
|
70278
70267
|
function getTodoAutoContinueMessage(host) {
|
|
70268
|
+
const prompt = peekTodoAutoContinuePrompt(host);
|
|
70279
70269
|
if (isWaitingForUserInteraction(host)) return { reason: "waiting_for_user_interaction" };
|
|
70280
70270
|
if (host.submitLock || host.isProcessing || host.isInterrupting || host.isCompacting) return { reason: "host_busy" };
|
|
70281
70271
|
const hasTodoTool = (host.agent?.state?.tools ?? []).some((tool) => tool.name === "manage_todo_list");
|
|
70282
70272
|
if (!hasTodoTool) return { reason: "todo_tool_unavailable" };
|
|
70283
|
-
const prompt = host.executionState.takeTodoClosureFollowUp();
|
|
70284
70273
|
if (!prompt) return { reason: "no_active_todo_follow_up" };
|
|
70285
70274
|
host.logDebug("todo_closure:follow_up", {
|
|
70286
70275
|
textPreview: prompt.slice(0, 120),
|
|
@@ -71317,11 +71306,14 @@ async function restoreExtensionProviderCredentials(modelRegistry) {
|
|
|
71317
71306
|
}
|
|
71318
71307
|
|
|
71319
71308
|
// src/attachments/resolver.ts
|
|
71309
|
+
var PROVIDER_SOURCE = "(provider)";
|
|
71320
71310
|
var AttachmentResolver = class {
|
|
71321
|
-
constructor(extensions) {
|
|
71311
|
+
constructor(extensions, builtInHandlers = []) {
|
|
71322
71312
|
this.extensions = extensions;
|
|
71313
|
+
this.builtInHandlers = builtInHandlers;
|
|
71323
71314
|
}
|
|
71324
71315
|
extensions;
|
|
71316
|
+
builtInHandlers;
|
|
71325
71317
|
findHandler(model, attachment) {
|
|
71326
71318
|
const candidate = this.collectCandidates(model, attachment)[0];
|
|
71327
71319
|
if (!candidate) return void 0;
|
|
@@ -71346,6 +71338,15 @@ var AttachmentResolver = class {
|
|
|
71346
71338
|
}
|
|
71347
71339
|
collectCandidates(model, attachment) {
|
|
71348
71340
|
const matches = [];
|
|
71341
|
+
for (const handler of this.builtInHandlers) {
|
|
71342
|
+
if (!handler.matches(model, attachment)) continue;
|
|
71343
|
+
matches.push({
|
|
71344
|
+
handlerName: handler.name,
|
|
71345
|
+
extensionPath: PROVIDER_SOURCE,
|
|
71346
|
+
priority: handler.priority ?? 0,
|
|
71347
|
+
prepare: handler.prepare.bind(handler)
|
|
71348
|
+
});
|
|
71349
|
+
}
|
|
71349
71350
|
for (const extension of this.extensions) {
|
|
71350
71351
|
for (const handler of extension.attachmentHandlers.values()) {
|
|
71351
71352
|
if (!handler.matches(model, attachment)) continue;
|
|
@@ -71368,6 +71369,48 @@ var AttachmentResolver = class {
|
|
|
71368
71369
|
}
|
|
71369
71370
|
};
|
|
71370
71371
|
|
|
71372
|
+
// src/attachments/provider-handlers.ts
|
|
71373
|
+
function getModality(mimeType) {
|
|
71374
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
71375
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
71376
|
+
return "file";
|
|
71377
|
+
}
|
|
71378
|
+
function isKimiAttachmentPlatform(model) {
|
|
71379
|
+
return model.attachmentPlatform === "kimi" || model.filePlatform === "kimi";
|
|
71380
|
+
}
|
|
71381
|
+
var kimiNativeAttachmentHandler = {
|
|
71382
|
+
name: "kimi-native-attachments",
|
|
71383
|
+
priority: 100,
|
|
71384
|
+
matches(model, attachment) {
|
|
71385
|
+
return isKimiAttachmentPlatform(model) && Boolean(attachment.fileId) && getModality(attachment.mimeType) !== "file";
|
|
71386
|
+
},
|
|
71387
|
+
async prepare(_model, attachment, ctx) {
|
|
71388
|
+
const fileId = attachment.fileId;
|
|
71389
|
+
if (!fileId) {
|
|
71390
|
+
return {
|
|
71391
|
+
items: [{ type: "text", text: `[${attachment.id}]` }],
|
|
71392
|
+
warnings: ["\u9644\u4EF6\u7F3A\u5C11 fileId\uFF0C\u65E0\u6CD5\u8D70 Kimi \u539F\u751F\u5F15\u7528"]
|
|
71393
|
+
};
|
|
71394
|
+
}
|
|
71395
|
+
const modality = getModality(attachment.mimeType);
|
|
71396
|
+
const url = `ms://${fileId}`;
|
|
71397
|
+
ctx.log(`Kimi handler prepared ${modality} reference for ${attachment.id}`);
|
|
71398
|
+
return {
|
|
71399
|
+
items: [
|
|
71400
|
+
{
|
|
71401
|
+
type: "file-ref",
|
|
71402
|
+
mimeType: attachment.mimeType,
|
|
71403
|
+
url,
|
|
71404
|
+
modality
|
|
71405
|
+
}
|
|
71406
|
+
]
|
|
71407
|
+
};
|
|
71408
|
+
}
|
|
71409
|
+
};
|
|
71410
|
+
var providerAttachmentHandlers = [
|
|
71411
|
+
kimiNativeAttachmentHandler
|
|
71412
|
+
];
|
|
71413
|
+
|
|
71371
71414
|
// src/app/runtime-composition-pipeline.ts
|
|
71372
71415
|
var CLI_COMPOSITION_STEP_ORDER = [
|
|
71373
71416
|
"model_config",
|
|
@@ -71518,7 +71561,7 @@ async function loadInteractiveExtensions(host) {
|
|
|
71518
71561
|
buildExtensionLoadOptions(host.options.settingsManager, host.options.extensionFlags)
|
|
71519
71562
|
);
|
|
71520
71563
|
host.extensions = extensions;
|
|
71521
|
-
host.attachmentResolver = new AttachmentResolver(extensions);
|
|
71564
|
+
host.attachmentResolver = new AttachmentResolver(extensions, providerAttachmentHandlers);
|
|
71522
71565
|
host.extensionRunner = new ExtensionRunner(
|
|
71523
71566
|
extensions,
|
|
71524
71567
|
extensionActions,
|
|
@@ -71690,6 +71733,10 @@ var InteractiveMode = class {
|
|
|
71690
71733
|
getTodoAutoContinueMessage() {
|
|
71691
71734
|
return getTodoAutoContinueMessage(this.continuationHost);
|
|
71692
71735
|
}
|
|
71736
|
+
/** Side-effect-free todo auto-continue prediction for the turn-settled bell. */
|
|
71737
|
+
peekTodoAutoContinuePrompt() {
|
|
71738
|
+
return peekTodoAutoContinuePrompt(this.continuationHost);
|
|
71739
|
+
}
|
|
71693
71740
|
appendWarningSummary(message) {
|
|
71694
71741
|
return appendWarningSummary(this.continuationHost, message);
|
|
71695
71742
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cydm/pie",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.49",
|
|
4
4
|
"description": "Pie AI Agent CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"test": "npm run test:offline",
|
|
19
19
|
"pretest:offline": "npm run build --workspace @pie/agent-framework && npm run build --workspace @pie/shared-headless-capabilities && npm run build",
|
|
20
20
|
"posttest:offline": "node --test --import tsx test/remote-model-catalog.test.ts",
|
|
21
|
-
"test:offline": "node --test --import tsx test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-
|
|
21
|
+
"test:offline": "node --test --import tsx test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-provider.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/hierarchical-command-system.test.ts test/extensions-enablement.test.ts test/skill-tool-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/calm-mode.test.ts test/project-root.test.ts test/guard-advisory-context.test.ts test/clear-command-usage.test.ts test/daily-agent-smoke.terminal.test.ts test/slash-menu-toggles.terminal.test.ts",
|
|
22
22
|
"test:all": "npm run test:offline && npm run test:terminal:vitest",
|
|
23
23
|
"test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/viewport-position-final.test.ts test/resume-header.terminal.test.ts --no-file-parallelism",
|
|
24
24
|
"test:todo-tui": "PIE_REAL_TODO_TUI=1 node --test --import tsx test/todo-closure.terminal.test.ts",
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
-
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
3
|
-
|
|
4
|
-
// builtin/extensions/kimi-attachments/index.ts
|
|
5
|
-
function isKimiAttachmentPlatform(model) {
|
|
6
|
-
return model.attachmentPlatform === "kimi" || model.filePlatform === "kimi";
|
|
7
|
-
}
|
|
8
|
-
function getModality(mimeType) {
|
|
9
|
-
if (mimeType.startsWith("image/")) return "image";
|
|
10
|
-
if (mimeType.startsWith("video/")) return "video";
|
|
11
|
-
return "file";
|
|
12
|
-
}
|
|
13
|
-
function kimiAttachmentsExtension(ctx) {
|
|
14
|
-
ctx.log("Kimi attachment extension loaded");
|
|
15
|
-
ctx.registerAttachmentHandler({
|
|
16
|
-
name: "kimi-native-attachments",
|
|
17
|
-
priority: 100,
|
|
18
|
-
matches(model, attachment) {
|
|
19
|
-
return isKimiAttachmentPlatform(model) && Boolean(attachment.fileId) && getModality(attachment.mimeType) !== "file";
|
|
20
|
-
},
|
|
21
|
-
async prepare(_model, attachment, prepareCtx) {
|
|
22
|
-
const fileId = attachment.fileId;
|
|
23
|
-
if (!fileId) {
|
|
24
|
-
return {
|
|
25
|
-
items: [{ type: "text", text: `[${attachment.id}]` }],
|
|
26
|
-
warnings: ["\u9644\u4EF6\u7F3A\u5C11 fileId\uFF0C\u65E0\u6CD5\u8D70 Kimi \u539F\u751F\u5F15\u7528"]
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
const modality = getModality(attachment.mimeType);
|
|
30
|
-
const url = `ms://${fileId}`;
|
|
31
|
-
prepareCtx.log(`Kimi handler prepared ${modality} reference for ${attachment.id}`);
|
|
32
|
-
return {
|
|
33
|
-
items: [
|
|
34
|
-
{
|
|
35
|
-
type: "file-ref",
|
|
36
|
-
mimeType: attachment.mimeType,
|
|
37
|
-
url,
|
|
38
|
-
modality
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
export {
|
|
46
|
-
kimiAttachmentsExtension as default
|
|
47
|
-
};
|