@cydm/pie 1.0.1 → 1.0.2
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 +2924 -0
- package/dist/builtin/extensions/changelog/index.js +200 -0
- package/dist/builtin/extensions/deploy/index.js +11 -0
- package/dist/builtin/extensions/document-attachments/index.js +144 -0
- package/dist/builtin/extensions/files/index.js +10 -0
- package/dist/builtin/extensions/init/index.js +144 -0
- package/dist/builtin/extensions/kimi-attachments/index.js +46 -0
- package/dist/builtin/extensions/plan-mode/index.js +209 -0
- package/dist/builtin/extensions/questionnaire/index.js +2753 -0
- package/dist/builtin/extensions/subagent/index.js +11031 -0
- package/dist/builtin/extensions/todo/index.js +162 -0
- package/dist/builtin/skills/browser-tools/CHANGELOG.md +47 -0
- package/dist/builtin/skills/browser-tools/browser-cookies.js +35 -0
- package/dist/builtin/skills/browser-tools/browser-screenshot.js +34 -0
- package/dist/builtin/skills/browser-tools/browser-start.js +86 -0
- package/dist/builtin/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/builtin/skills/skill-creator/SKILL.md +485 -0
- package/dist/builtin/skills/skill-creator/agents/analyzer.md +274 -0
- package/dist/builtin/skills/skill-creator/agents/comparator.md +202 -0
- package/dist/builtin/skills/skill-creator/agents/grader.md +223 -0
- package/dist/builtin/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/builtin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/dist/builtin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/dist/builtin/skills/skill-creator/references/schemas.md +430 -0
- package/dist/builtin/skills/skill-creator/scripts/__init__.py +0 -0
- package/dist/builtin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/dist/builtin/skills/skill-creator/scripts/generate_report.py +326 -0
- package/dist/builtin/skills/skill-creator/scripts/improve_description.py +247 -0
- package/dist/builtin/skills/skill-creator/scripts/package_skill.py +136 -0
- package/dist/builtin/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/dist/builtin/skills/skill-creator/scripts/run_eval.py +310 -0
- package/dist/builtin/skills/skill-creator/scripts/run_loop.py +328 -0
- package/dist/builtin/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/cli.js +78983 -0
- package/dist/theme/dark.json +85 -0
- package/dist/theme/light.json +84 -0
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// builtin/extensions/changelog/index.ts
|
|
10
|
+
function getRecentCommits(cwd, count = 10) {
|
|
11
|
+
try {
|
|
12
|
+
const { spawnSync } = __require("child_process");
|
|
13
|
+
const result = spawnSync(
|
|
14
|
+
"git",
|
|
15
|
+
["log", `--max-count=${count}`, "--pretty=format:%h %s", "--no-merges"],
|
|
16
|
+
{ cwd, encoding: "utf8" }
|
|
17
|
+
);
|
|
18
|
+
return result.status === 0 ? result.stdout : "";
|
|
19
|
+
} catch {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function getChangedFiles(cwd) {
|
|
24
|
+
try {
|
|
25
|
+
const { spawnSync } = __require("child_process");
|
|
26
|
+
const result = spawnSync(
|
|
27
|
+
"git",
|
|
28
|
+
["diff", "HEAD~5", "--name-only", "--stat"],
|
|
29
|
+
{ cwd, encoding: "utf8" }
|
|
30
|
+
);
|
|
31
|
+
return result.status === 0 ? result.stdout : "";
|
|
32
|
+
} catch {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function readChangelog(cwd) {
|
|
37
|
+
try {
|
|
38
|
+
const fs = await import("fs");
|
|
39
|
+
const path = await import("path");
|
|
40
|
+
const changelogPath = path.join(cwd, "CHANGELOG.md");
|
|
41
|
+
if (fs.existsSync(changelogPath)) {
|
|
42
|
+
return fs.readFileSync(changelogPath, "utf-8");
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function changelogExtension(ctx) {
|
|
49
|
+
ctx.log("Changelog extension loaded");
|
|
50
|
+
ctx.ui.notify("\u{1F4DD} Changelog extension loaded", "info");
|
|
51
|
+
ctx.registerCommand({
|
|
52
|
+
path: ["tools", "changelog"],
|
|
53
|
+
description: "Smart changelog management with gap detection",
|
|
54
|
+
handler: async (ctx2, args) => {
|
|
55
|
+
const fs = await import("fs");
|
|
56
|
+
const path = await import("path");
|
|
57
|
+
const changelogPath = path.join(ctx2.cwd, "CHANGELOG.md");
|
|
58
|
+
if (args?.includes("--show")) {
|
|
59
|
+
if (!fs.existsSync(changelogPath)) {
|
|
60
|
+
return "No CHANGELOG.md found.";
|
|
61
|
+
}
|
|
62
|
+
const content = fs.readFileSync(changelogPath, "utf-8");
|
|
63
|
+
return "Current CHANGELOG:\n\n" + content.slice(0, 2e3) + (content.length > 2e3 ? "\n\n..." : "");
|
|
64
|
+
}
|
|
65
|
+
if (args?.trim() === "check") {
|
|
66
|
+
const commits2 = getRecentCommits(ctx2.cwd, 15);
|
|
67
|
+
const changelog2 = await readChangelog(ctx2.cwd);
|
|
68
|
+
const changedFiles2 = getChangedFiles(ctx2.cwd);
|
|
69
|
+
if (!commits2) {
|
|
70
|
+
return "No git history found. Cannot check for missing entries.";
|
|
71
|
+
}
|
|
72
|
+
return `\u{1F50D} CHANGELOG \u9057\u6F0F\u68C0\u67E5
|
|
73
|
+
|
|
74
|
+
\u8BF7\u5206\u6790\u4EE5\u4E0B\u4FE1\u606F\uFF0C\u68C0\u67E5 CHANGELOG \u662F\u5426\u6709\u9057\u6F0F\uFF1A
|
|
75
|
+
|
|
76
|
+
## \u6700\u8FD1 Git \u63D0\u4EA4
|
|
77
|
+
${commits2 || "(\u65E0\u6CD5\u83B7\u53D6)"}
|
|
78
|
+
|
|
79
|
+
## \u53D8\u66F4\u6587\u4EF6
|
|
80
|
+
${changedFiles2 || "(\u65E0\u6CD5\u83B7\u53D6)"}
|
|
81
|
+
|
|
82
|
+
## \u5F53\u524D CHANGELOG
|
|
83
|
+
${changelog2 ? changelog2.slice(0, 1500) + "\n..." : "(\u6587\u4EF6\u4E0D\u5B58\u5728)"}
|
|
84
|
+
|
|
85
|
+
\u8BF7\u5BF9\u6BD4\u5206\u6790\uFF1A
|
|
86
|
+
1. \u54EA\u4E9B\u91CD\u8981\u7684\u53D8\u66F4\u5DF2\u7ECF\u63D0\u4EA4\u5230 git \u4F46\u6CA1\u6709\u8BB0\u5F55\u5728 CHANGELOG\uFF1F
|
|
87
|
+
2. \u5F53\u524D [Unreleased] \u90E8\u5206\u662F\u5426\u5B8C\u6574\u53CD\u6620\u4E86\u6700\u8FD1\u7684\u5DE5\u4F5C\uFF1F
|
|
88
|
+
3. \u5217\u51FA\u9057\u6F0F\u7684\u6761\u76EE\u5EFA\u8BAE\uFF08\u6309 Added/Changed/Fixed \u5206\u7C7B\uFF09
|
|
89
|
+
|
|
90
|
+
\u53EA\u8FD4\u56DE\u5206\u6790\u62A5\u544A\uFF0C\u4E0D\u8981\u4FEE\u6539\u6587\u4EF6\u3002`;
|
|
91
|
+
}
|
|
92
|
+
if (args?.startsWith("add ")) {
|
|
93
|
+
const description = args.slice(4).trim();
|
|
94
|
+
const existingChangelog = await readChangelog(ctx2.cwd);
|
|
95
|
+
ctx2.ui.notify(`\u{1F4DD} \u6B63\u5728\u751F\u6210 changelog \u6761\u76EE...`, "info");
|
|
96
|
+
return `\u8BF7\u5C06\u4EE5\u4E0B\u63CF\u8FF0\u8F6C\u6362\u4E3A\u4E13\u4E1A\u7684 CHANGELOG \u6761\u76EE\uFF1A
|
|
97
|
+
|
|
98
|
+
\u63CF\u8FF0\uFF1A"${description}"
|
|
99
|
+
|
|
100
|
+
${existingChangelog ? `
|
|
101
|
+
\u53C2\u8003\u73B0\u6709\u683C\u5F0F\uFF1A
|
|
102
|
+
\`\`\`
|
|
103
|
+
${existingChangelog.slice(0, 800)}
|
|
104
|
+
...
|
|
105
|
+
\`\`\`` : ""}
|
|
106
|
+
|
|
107
|
+
\u8981\u6C42\uFF1A
|
|
108
|
+
1. \u9009\u62E9\u5408\u9002\u7684\u5206\u7C7B\uFF1A**Added** / **Changed** / **Fixed** / **Removed** / **Deprecated** / **Security**
|
|
109
|
+
2. \u4F7F\u7528\u73B0\u5728\u65F6\u6001\uFF0C\u7B80\u6D01\u4F46\u5305\u542B\u5173\u952E\u6280\u672F\u7EC6\u8282
|
|
110
|
+
3. \u5982\u6709\u76F8\u5173\u6587\u4EF6\u8DEF\u5F84\uFF0C\u8BF7\u5305\u542B
|
|
111
|
+
|
|
112
|
+
\u683C\u5F0F\u793A\u4F8B\uFF1A
|
|
113
|
+
- **Added**: \u65B0\u589E\u7528\u6237\u8BA4\u8BC1\u6A21\u5757\uFF0C\u652F\u6301 JWT token \u9A8C\u8BC1\uFF08src/auth/\uFF09
|
|
114
|
+
- **Fixed**: \u4FEE\u590D\u5185\u5B58\u6CC4\u6F0F\u95EE\u9898\uFF0C\u4F18\u5316\u4E86\u5927\u6587\u4EF6\u5904\u7406\u6027\u80FD
|
|
115
|
+
|
|
116
|
+
\u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md\uFF1A
|
|
117
|
+
- \u5982\u679C\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u6807\u51C6\u683C\u5F0F\uFF08\u5305\u542B ## [Unreleased] \u90E8\u5206\uFF09
|
|
118
|
+
- \u5C06\u65B0\u6761\u76EE\u6DFB\u52A0\u5230 [Unreleased] \u90E8\u5206\u7684\u5408\u9002\u4F4D\u7F6E
|
|
119
|
+
- \u4FDD\u6301\u73B0\u6709\u6761\u76EE\u4E0D\u53D8`;
|
|
120
|
+
}
|
|
121
|
+
if (args?.startsWith("release")) {
|
|
122
|
+
const versionHint = args.slice(7).trim();
|
|
123
|
+
const existingChangelog = await readChangelog(ctx2.cwd);
|
|
124
|
+
if (!existingChangelog) {
|
|
125
|
+
return "No CHANGELOG.md found. Create one first with /changelog";
|
|
126
|
+
}
|
|
127
|
+
ctx2.ui.notify(`\u{1F4DD} Preparing release ${versionHint || "..."}`, "info");
|
|
128
|
+
return `\u8BF7\u5C06 [Unreleased] \u90E8\u5206\u7684\u5185\u5BB9\u6574\u7406\u4E3A\u4E00\u4E2A\u65B0\u7248\u672C\u53D1\u5E03\u3002
|
|
129
|
+
|
|
130
|
+
\u5F53\u524D CHANGELOG\uFF1A
|
|
131
|
+
\`\`\`
|
|
132
|
+
${existingChangelog.slice(0, 1500)}
|
|
133
|
+
...
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
\u7248\u672C\u63D0\u793A\uFF1A${versionHint || "\u6839\u636E\u53D8\u66F4\u5185\u5BB9\u81EA\u52A8\u5224\u65AD\uFF08patch/minor/major\uFF09"}
|
|
137
|
+
|
|
138
|
+
Semantic Versioning \u89C4\u5219\uFF1A
|
|
139
|
+
- **patch** (0.0.x): Bug fixes only
|
|
140
|
+
- **minor** (0.x.0): New features, backward compatible
|
|
141
|
+
- **major** (x.0.0): Breaking changes
|
|
142
|
+
|
|
143
|
+
\u4EFB\u52A1\uFF1A
|
|
144
|
+
1. \u5206\u6790 [Unreleased] \u4E2D\u7684\u53D8\u66F4\u7C7B\u578B
|
|
145
|
+
2. \u786E\u5B9A\u5408\u9002\u7684\u7248\u672C\u53F7\uFF08\u5982\u679C\u7528\u6237\u672A\u6307\u5B9A\uFF09
|
|
146
|
+
3. \u521B\u5EFA\u65B0\u7684\u7248\u672C\u8282\uFF08\u5982 ## [1.2.0] - 2024-03-06\uFF09
|
|
147
|
+
4. \u5C06 [Unreleased] \u7684\u5185\u5BB9\u79FB\u52A8\u5230\u65B0\u7248\u672C\u8282
|
|
148
|
+
5. \u6E05\u7A7A [Unreleased] \u90E8\u5206\uFF0C\u53EA\u4FDD\u7559\u7A7A\u5217\u8868
|
|
149
|
+
6. \u5728\u6587\u4EF6\u5E95\u90E8\u66F4\u65B0\u7248\u672C\u5BF9\u6BD4\u94FE\u63A5\uFF08\u5982\u679C\u9700\u8981\uFF09
|
|
150
|
+
|
|
151
|
+
\u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md`;
|
|
152
|
+
}
|
|
153
|
+
const commits = getRecentCommits(ctx2.cwd, 15);
|
|
154
|
+
const changelog = await readChangelog(ctx2.cwd);
|
|
155
|
+
const changedFiles = getChangedFiles(ctx2.cwd);
|
|
156
|
+
if (!commits && !changelog) {
|
|
157
|
+
return "No git history or CHANGELOG.md found. Initialize with: /changelog add <description>";
|
|
158
|
+
}
|
|
159
|
+
ctx2.ui.notify("\u{1F50D} \u5206\u6790\u53D8\u66F4\u5E76\u68C0\u67E5\u9057\u6F0F...", "info");
|
|
160
|
+
return `\u{1F4DD} \u667A\u80FD Changelog \u66F4\u65B0
|
|
161
|
+
|
|
162
|
+
\u8BF7\u5206\u6790\u4EE5\u4E0B\u4FE1\u606F\uFF0C\u68C0\u67E5\u5E76\u8865\u5145\u9057\u6F0F\u7684 CHANGELOG \u6761\u76EE\uFF1A
|
|
163
|
+
|
|
164
|
+
## \u6700\u8FD1 Git \u63D0\u4EA4\u8BB0\u5F55
|
|
165
|
+
${commits || "(\u65E0\u6CD5\u83B7\u53D6 git \u5386\u53F2)"}
|
|
166
|
+
|
|
167
|
+
## \u6700\u8FD1\u53D8\u66F4\u7684\u6587\u4EF6
|
|
168
|
+
${changedFiles || "(\u65E0\u6CD5\u83B7\u53D6)"}
|
|
169
|
+
|
|
170
|
+
## \u5F53\u524D CHANGELOG.md
|
|
171
|
+
${changelog ? "\n```\n" + changelog.slice(0, 2e3) + "\n...\n```" : "(\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u9700\u8981\u521B\u5EFA)"}
|
|
172
|
+
|
|
173
|
+
## \u4EFB\u52A1
|
|
174
|
+
|
|
175
|
+
1. **\u5BF9\u6BD4\u5206\u6790**\uFF1A
|
|
176
|
+
- \u67E5\u770B git \u63D0\u4EA4\u4E2D\u6709\u54EA\u4E9B\u91CD\u8981\u53D8\u66F4
|
|
177
|
+
- \u5BF9\u6BD4 CHANGELOG \u7684 [Unreleased] \u90E8\u5206
|
|
178
|
+
- \u8BC6\u522B\u9057\u6F0F\u7684\u6761\u76EE
|
|
179
|
+
|
|
180
|
+
2. **\u8865\u5145\u9057\u6F0F**\uFF08\u5982\u679C\u6709\uFF09\uFF1A
|
|
181
|
+
- \u4E3A\u6BCF\u4E2A\u9057\u6F0F\u7684\u53D8\u66F4\u521B\u5EFA\u4E13\u4E1A\u6761\u76EE
|
|
182
|
+
- \u5206\u7C7B\uFF1A**Added** / **Changed** / **Fixed** / **Removed**
|
|
183
|
+
- \u5305\u542B\u6280\u672F\u7EC6\u8282\u548C\u6587\u4EF6\u8DEF\u5F84
|
|
184
|
+
|
|
185
|
+
3. **\u66F4\u65B0\u6587\u4EF6**\uFF1A
|
|
186
|
+
- \u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md
|
|
187
|
+
- \u5982\u679C\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u6807\u51C6\u683C\u5F0F
|
|
188
|
+
- \u53EA\u6DFB\u52A0\u9057\u6F0F\u7684\u6761\u76EE\uFF0C\u4FDD\u6301\u73B0\u6709\u5185\u5BB9
|
|
189
|
+
|
|
190
|
+
4. **\u62A5\u544A\u7ED3\u679C**\uFF1A
|
|
191
|
+
- \u6DFB\u52A0\u4E86\u54EA\u4E9B\u6761\u76EE
|
|
192
|
+
- \u662F\u5426\u6709\u4E0D\u786E\u5B9A\u662F\u5426\u9700\u8981\u8BB0\u5F55\u7684\u5185\u5BB9`;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
ctx.log("Changelog extension ready");
|
|
196
|
+
ctx.ui.notify(" Changelog extension loaded", "info");
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
changelogExtension as default
|
|
200
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// builtin/extensions/deploy/index.ts
|
|
4
|
+
function deployExtension(ctx) {
|
|
5
|
+
ctx.log("Deploy extension loaded");
|
|
6
|
+
ctx.ui.notify("\u{1F680} Deploy extension loaded", "info");
|
|
7
|
+
ctx.log("Deploy extension ready");
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
deployExtension as default
|
|
11
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// builtin/extensions/document-attachments/index.ts
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
var MAX_TEXT_CHARS = 24e3;
|
|
8
|
+
var PYTHON_CANDIDATES = [
|
|
9
|
+
process.env.PYTHON,
|
|
10
|
+
"/opt/anaconda3/bin/python3",
|
|
11
|
+
"python3"
|
|
12
|
+
].filter((value) => Boolean(value));
|
|
13
|
+
function isTextCapable(model) {
|
|
14
|
+
return (model.input ?? []).includes("text");
|
|
15
|
+
}
|
|
16
|
+
function isSupportedDocument(attachment) {
|
|
17
|
+
return attachment.mimeType === "application/pdf" || attachment.mimeType === "text/html" || attachment.mimeType === "text/plain" || attachment.mimeType === "text/markdown" || attachment.mimeType === "application/json" || attachment.name.endsWith(".html") || attachment.name.endsWith(".htm") || attachment.name.endsWith(".md") || attachment.name.endsWith(".txt") || attachment.name.endsWith(".json") || attachment.name.endsWith(".pdf");
|
|
18
|
+
}
|
|
19
|
+
function truncateText(text) {
|
|
20
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
21
|
+
if (normalized.length <= MAX_TEXT_CHARS) return normalized;
|
|
22
|
+
return `${normalized.slice(0, MAX_TEXT_CHARS)}
|
|
23
|
+
|
|
24
|
+
[Truncated after ${MAX_TEXT_CHARS} characters]`;
|
|
25
|
+
}
|
|
26
|
+
function runPythonScript(script, fallbackMessage) {
|
|
27
|
+
const failures = [];
|
|
28
|
+
for (const pythonBin of PYTHON_CANDIDATES) {
|
|
29
|
+
const result = spawnSync(pythonBin, ["-c", script], { encoding: "utf8" });
|
|
30
|
+
if (result.status === 0) {
|
|
31
|
+
return result.stdout;
|
|
32
|
+
}
|
|
33
|
+
const detail = (result.stderr || result.stdout || `exit ${result.status}`).trim();
|
|
34
|
+
failures.push(`${pythonBin}: ${detail}`);
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`${fallbackMessage}
|
|
37
|
+
${failures.join("\n")}`);
|
|
38
|
+
}
|
|
39
|
+
function extractHtmlText(filePath) {
|
|
40
|
+
const script = `
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
from html.parser import HTMLParser
|
|
43
|
+
|
|
44
|
+
class Extractor(HTMLParser):
|
|
45
|
+
def __init__(self):
|
|
46
|
+
super().__init__()
|
|
47
|
+
self.parts = []
|
|
48
|
+
self.skip_depth = 0
|
|
49
|
+
def handle_starttag(self, tag, attrs):
|
|
50
|
+
if tag in ("script", "style"):
|
|
51
|
+
self.skip_depth += 1
|
|
52
|
+
def handle_endtag(self, tag):
|
|
53
|
+
if tag in ("script", "style") and self.skip_depth > 0:
|
|
54
|
+
self.skip_depth -= 1
|
|
55
|
+
def handle_data(self, data):
|
|
56
|
+
if self.skip_depth:
|
|
57
|
+
return
|
|
58
|
+
data = data.strip()
|
|
59
|
+
if data:
|
|
60
|
+
self.parts.append(data)
|
|
61
|
+
|
|
62
|
+
p = Path(${JSON.stringify(filePath)})
|
|
63
|
+
parser = Extractor()
|
|
64
|
+
parser.feed(p.read_text("utf-8"))
|
|
65
|
+
print("\\n".join(parser.parts))
|
|
66
|
+
`;
|
|
67
|
+
return runPythonScript(script, "Failed to extract HTML text");
|
|
68
|
+
}
|
|
69
|
+
function extractPdfText(filePath) {
|
|
70
|
+
const script = `
|
|
71
|
+
reader = None
|
|
72
|
+
errors = []
|
|
73
|
+
|
|
74
|
+
for module_name in ("pypdf", "PyPDF2"):
|
|
75
|
+
try:
|
|
76
|
+
module = __import__(module_name, fromlist=["PdfReader"])
|
|
77
|
+
reader = module.PdfReader(${JSON.stringify(filePath)})
|
|
78
|
+
break
|
|
79
|
+
except Exception as exc:
|
|
80
|
+
errors.append(f"{module_name}: {exc}")
|
|
81
|
+
|
|
82
|
+
if reader is None:
|
|
83
|
+
raise RuntimeError(" | ".join(errors) or "No supported PDF reader module found")
|
|
84
|
+
|
|
85
|
+
parts = []
|
|
86
|
+
for page in reader.pages:
|
|
87
|
+
try:
|
|
88
|
+
text = page.extract_text() or ""
|
|
89
|
+
except Exception:
|
|
90
|
+
text = ""
|
|
91
|
+
if text.strip():
|
|
92
|
+
parts.append(text)
|
|
93
|
+
print("\\n\\n".join(parts))
|
|
94
|
+
`;
|
|
95
|
+
return runPythonScript(script, "Failed to extract PDF text");
|
|
96
|
+
}
|
|
97
|
+
function extractPlainText(filePath) {
|
|
98
|
+
return fs.readFileSync(filePath, "utf8");
|
|
99
|
+
}
|
|
100
|
+
function extractDocumentText(attachment) {
|
|
101
|
+
const filePath = attachment.path;
|
|
102
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
103
|
+
throw new Error(`Local attachment path is unavailable for ${attachment.name}`);
|
|
104
|
+
}
|
|
105
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
106
|
+
if (attachment.mimeType === "application/pdf" || ext === ".pdf") {
|
|
107
|
+
return extractPdfText(filePath);
|
|
108
|
+
}
|
|
109
|
+
if (attachment.mimeType === "text/html" || ext === ".html" || ext === ".htm") {
|
|
110
|
+
return extractHtmlText(filePath);
|
|
111
|
+
}
|
|
112
|
+
return extractPlainText(filePath);
|
|
113
|
+
}
|
|
114
|
+
function documentAttachmentsExtension(ctx) {
|
|
115
|
+
ctx.log("Document attachment extension loaded");
|
|
116
|
+
ctx.registerAttachmentHandler({
|
|
117
|
+
name: "local-document-preprocess",
|
|
118
|
+
priority: 20,
|
|
119
|
+
matches(model, attachment) {
|
|
120
|
+
return isTextCapable(model) && isSupportedDocument(attachment) && Boolean(attachment.path);
|
|
121
|
+
},
|
|
122
|
+
async prepare(_model, attachment, prepareCtx) {
|
|
123
|
+
const extracted = extractDocumentText(attachment);
|
|
124
|
+
const text = truncateText(extracted);
|
|
125
|
+
prepareCtx.log(`Document handler extracted ${text.length} chars from ${attachment.name}`);
|
|
126
|
+
const prefix = [
|
|
127
|
+
`[Document: ${attachment.name}]`,
|
|
128
|
+
`MIME: ${attachment.mimeType}`,
|
|
129
|
+
""
|
|
130
|
+
].join("\n");
|
|
131
|
+
return {
|
|
132
|
+
items: [
|
|
133
|
+
{
|
|
134
|
+
type: "text",
|
|
135
|
+
text: `${prefix}${text}`
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
documentAttachmentsExtension as default
|
|
144
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// builtin/extensions/files/index.ts
|
|
4
|
+
function filesExtension(ctx) {
|
|
5
|
+
ctx.log("Files extension loaded");
|
|
6
|
+
ctx.ui.notify("\u{1F4C1} Files extension loaded", "info");
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
filesExtension as default
|
|
10
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// builtin/extensions/init/index.ts
|
|
4
|
+
async function loadExistingKnowledge(cwd) {
|
|
5
|
+
try {
|
|
6
|
+
const fs = await import("fs");
|
|
7
|
+
const path = await import("path");
|
|
8
|
+
const agentsPath = path.join(cwd, ".pie", "agents.md");
|
|
9
|
+
if (fs.existsSync(agentsPath)) {
|
|
10
|
+
return fs.readFileSync(agentsPath, "utf-8");
|
|
11
|
+
}
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
async function ensurePieDir(cwd) {
|
|
17
|
+
const fs = await import("fs");
|
|
18
|
+
const path = await import("path");
|
|
19
|
+
const pieDir = path.join(cwd, ".pie");
|
|
20
|
+
if (!fs.existsSync(pieDir)) {
|
|
21
|
+
fs.mkdirSync(pieDir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function buildResearchPrompt(params) {
|
|
25
|
+
const { isUpdate, existingContent, userIntent, cwd } = params;
|
|
26
|
+
if (isUpdate && existingContent) {
|
|
27
|
+
const truncatedContent = existingContent.length > 4e3 ? existingContent.slice(0, 4e3) + "\n... (truncated)" : existingContent;
|
|
28
|
+
return `\u{1F4DD} \u66F4\u65B0\u9879\u76EE\u77E5\u8BC6\u6587\u6863
|
|
29
|
+
|
|
30
|
+
\u5F53\u524D .pie/agents.md \u5185\u5BB9\uFF1A
|
|
31
|
+
\`\`\`
|
|
32
|
+
${truncatedContent}
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
${userIntent ? `\u{1F4CC} \u7528\u6237\u66F4\u65B0\u610F\u56FE\uFF1A${userIntent}
|
|
36
|
+
|
|
37
|
+
` : ""}\u8BF7\u91CD\u65B0\u7814\u7A76\u9879\u76EE\u5E76\u66F4\u65B0\u77E5\u8BC6\u6587\u6863\uFF1A
|
|
38
|
+
|
|
39
|
+
1. \u63A2\u7D22\u5F53\u524D\u4EE3\u7801\u7ED3\u6784\uFF0C\u5BF9\u6BD4\u73B0\u6709\u6587\u6863
|
|
40
|
+
2. \u8BC6\u522B\u65B0\u589E/\u53D8\u66F4/\u79FB\u9664\u7684\u6A21\u5757\u548C\u6587\u4EF6
|
|
41
|
+
3. ${userIntent ? `\u91CD\u70B9\u5173\u6CE8\uFF1A${userIntent}` : "\u8865\u5145\u7F3A\u5931\u7684\u7EC6\u8282\u548C\u67B6\u6784\u8BF4\u660E\uFF0C\u66F4\u65B0\u8FC7\u65F6\u7684\u4FE1\u606F"}
|
|
42
|
+
4. \u4FDD\u6301\u6587\u6863\u7ED3\u6784\u6E05\u6670\uFF0C\u7EF4\u62A4\u7AE0\u8282\u5B8C\u6574\u6027
|
|
43
|
+
5. \u66F4\u65B0\u540E\u786E\u4FDD agents.md \u4ECD\u7136\u6709\u7528\u4E14\u51C6\u786E
|
|
44
|
+
|
|
45
|
+
\u8BF7\u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 \`.pie/agents.md\` \u6587\u4EF6\u3002
|
|
46
|
+
|
|
47
|
+
\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}`;
|
|
48
|
+
}
|
|
49
|
+
return `\u{1F50D} \u521D\u59CB\u5316\u9879\u76EE\u7814\u7A76
|
|
50
|
+
|
|
51
|
+
${userIntent ? `\u{1F4CC} \u7528\u6237\u7814\u7A76\u610F\u56FE\uFF1A${userIntent}
|
|
52
|
+
|
|
53
|
+
` : ""}\u8BF7\u5E2E\u6211\u5168\u9762\u7814\u7A76\u5F53\u524D\u9879\u76EE\u5E76\u521B\u5EFA \`.pie/agents.md\` \u77E5\u8BC6\u6587\u6863\u3002
|
|
54
|
+
|
|
55
|
+
\u7814\u7A76\u4EFB\u52A1\uFF1A
|
|
56
|
+
1. \u8BC6\u522B\u9879\u76EE\u7C7B\u578B\u548C\u6280\u672F\u6808\uFF08\u67E5\u770B package.json, Cargo.toml, go.mod, requirements.txt, pyproject.toml \u7B49\uFF09
|
|
57
|
+
2. \u63A2\u7D22\u6E90\u4EE3\u7801\u76EE\u5F55\u7ED3\u6784\uFF08src/, lib/, app/ \u7B49\u5E38\u89C1\u76EE\u5F55\uFF09
|
|
58
|
+
3. \u8BFB\u53D6\u5173\u952E\u914D\u7F6E\u6587\u4EF6\u7406\u89E3\u9879\u76EE\u8BBE\u7F6E
|
|
59
|
+
4. \u8BC6\u522B\u4E3B\u8981\u6A21\u5757\u3001\u5165\u53E3\u70B9\u3001\u6838\u5FC3\u7C7B/\u51FD\u6570
|
|
60
|
+
5. \u5206\u6790\u67B6\u6784\u6A21\u5F0F\u548C\u8BBE\u8BA1\u51B3\u7B56
|
|
61
|
+
6. \u63A8\u65AD\u5F00\u53D1\u89C4\u8303\uFF08\u4EE3\u7801\u98CE\u683C\u3001\u6D4B\u8BD5\u3001\u6784\u5EFA\u6D41\u7A0B\uFF09
|
|
62
|
+
|
|
63
|
+
\u8BF7\u751F\u6210\u5305\u542B\u4EE5\u4E0B\u7AE0\u8282\u7684 agents.md\uFF1A
|
|
64
|
+
|
|
65
|
+
\`\`\`
|
|
66
|
+
# Project: <\u9879\u76EE\u540D\u79F0>
|
|
67
|
+
|
|
68
|
+
## \u6982\u89C8
|
|
69
|
+
- \u7C7B\u578B\uFF1A<\u9879\u76EE\u7C7B\u578B>
|
|
70
|
+
- \u6280\u672F\u6808\uFF1A<\u4E3B\u8981\u6280\u672F>
|
|
71
|
+
- \u4E00\u53E5\u8BDD\u63CF\u8FF0\uFF1A<\u9879\u76EE\u7528\u9014>
|
|
72
|
+
|
|
73
|
+
## \u67B6\u6784\u5206\u6790
|
|
74
|
+
- \u6A21\u5757\u5212\u5206
|
|
75
|
+
- \u5173\u952E\u7EC4\u4EF6\u8BF4\u660E
|
|
76
|
+
- \u4F9D\u8D56\u5173\u7CFB
|
|
77
|
+
|
|
78
|
+
## \u6838\u5FC3\u6587\u4EF6
|
|
79
|
+
| \u7528\u9014 | \u8DEF\u5F84 | \u8BF4\u660E |
|
|
80
|
+
|------|------|------|
|
|
81
|
+
|
|
82
|
+
## \u5F00\u53D1\u89C4\u8303
|
|
83
|
+
- \u4EE3\u7801\u98CE\u683C
|
|
84
|
+
- \u6D4B\u8BD5\u6A21\u5F0F
|
|
85
|
+
- \u6784\u5EFA/\u8FD0\u884C\u65B9\u5F0F
|
|
86
|
+
|
|
87
|
+
## \u63A2\u7D22\u6E05\u5355\uFF08\u5F85\u6DF1\u5165\u7814\u7A76\uFF09
|
|
88
|
+
- [ ]
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
\u8BF7\u4F7F\u7528 write \u5DE5\u5177\u521B\u5EFA \`.pie/agents.md\` \u6587\u4EF6\u3002
|
|
92
|
+
|
|
93
|
+
\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}`;
|
|
94
|
+
}
|
|
95
|
+
async function initExtension(ctx) {
|
|
96
|
+
ctx.log("Init extension loaded");
|
|
97
|
+
let cachedKnowledge = null;
|
|
98
|
+
try {
|
|
99
|
+
cachedKnowledge = await loadExistingKnowledge(ctx.cwd);
|
|
100
|
+
if (cachedKnowledge) {
|
|
101
|
+
const firstLine = cachedKnowledge.split("\n")[0] || "";
|
|
102
|
+
const projectName = firstLine.replace(/^#\s*/, "").trim() || "\u9879\u76EE";
|
|
103
|
+
ctx.ui.notify(`\u{1F4DA} \u5DF2\u52A0\u8F7D ${projectName} \u77E5\u8BC6\u6587\u6863`, "info");
|
|
104
|
+
ctx.log(`Pre-loaded agents.md (${cachedKnowledge.length} chars)`);
|
|
105
|
+
} else {
|
|
106
|
+
ctx.ui.notify("\u{1F4DA} Init extension loaded (no existing knowledge)", "info");
|
|
107
|
+
ctx.log("No existing agents.md found");
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
ctx.ui.notify("\u{1F4DA} Init extension loaded", "info");
|
|
111
|
+
ctx.log(`Failed to pre-load agents.md: ${err}`);
|
|
112
|
+
}
|
|
113
|
+
ctx.registerCommand({
|
|
114
|
+
path: ["tools", "init"],
|
|
115
|
+
description: "\u7814\u7A76\u9879\u76EE\u5E76\u751F\u6210/\u66F4\u65B0 agents.md \u77E5\u8BC6\u6587\u6863",
|
|
116
|
+
handler: async (ctx2, args) => {
|
|
117
|
+
await ensurePieDir(ctx2.cwd);
|
|
118
|
+
const existingContent = await loadExistingKnowledge(ctx2.cwd);
|
|
119
|
+
const isUpdate = !!existingContent;
|
|
120
|
+
const userIntent = args?.trim();
|
|
121
|
+
cachedKnowledge = existingContent;
|
|
122
|
+
if (isUpdate) {
|
|
123
|
+
if (userIntent) {
|
|
124
|
+
ctx2.ui.notify(`\u{1F4DD} \u6B63\u5728\u66F4\u65B0\u9879\u76EE\u77E5\u8BC6\uFF08${userIntent}\uFF09...`, "info");
|
|
125
|
+
} else {
|
|
126
|
+
ctx2.ui.notify("\u{1F4DD} \u6B63\u5728\u66F4\u65B0\u9879\u76EE\u77E5\u8BC6...", "info");
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
ctx2.ui.notify("\u{1F50D} \u6B63\u5728\u521D\u59CB\u5316\u9879\u76EE\u7814\u7A76...", "info");
|
|
130
|
+
}
|
|
131
|
+
const researchPrompt = buildResearchPrompt({
|
|
132
|
+
isUpdate,
|
|
133
|
+
existingContent,
|
|
134
|
+
userIntent,
|
|
135
|
+
cwd: ctx2.cwd
|
|
136
|
+
});
|
|
137
|
+
return researchPrompt;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
ctx.log("Init extension ready");
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
initExtension as default
|
|
144
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// builtin/extensions/kimi-attachments/index.ts
|
|
4
|
+
function isKimiProvider(provider) {
|
|
5
|
+
return provider === "kimi-cn" || provider === "kimi-api" || provider === "kimi";
|
|
6
|
+
}
|
|
7
|
+
function getModality(mimeType) {
|
|
8
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
9
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
10
|
+
return "file";
|
|
11
|
+
}
|
|
12
|
+
function kimiAttachmentsExtension(ctx) {
|
|
13
|
+
ctx.log("Kimi attachment extension loaded");
|
|
14
|
+
ctx.registerAttachmentHandler({
|
|
15
|
+
name: "kimi-native-attachments",
|
|
16
|
+
priority: 100,
|
|
17
|
+
matches(model, attachment) {
|
|
18
|
+
return isKimiProvider(model.provider) && Boolean(attachment.fileId) && getModality(attachment.mimeType) !== "file";
|
|
19
|
+
},
|
|
20
|
+
async prepare(_model, attachment, prepareCtx) {
|
|
21
|
+
const fileId = attachment.fileId;
|
|
22
|
+
if (!fileId) {
|
|
23
|
+
return {
|
|
24
|
+
items: [{ type: "text", text: `[${attachment.id}]` }],
|
|
25
|
+
warnings: ["\u9644\u4EF6\u7F3A\u5C11 fileId\uFF0C\u65E0\u6CD5\u8D70 Kimi \u539F\u751F\u5F15\u7528"]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const modality = getModality(attachment.mimeType);
|
|
29
|
+
const url = `ms://${fileId}`;
|
|
30
|
+
prepareCtx.log(`Kimi handler prepared ${modality} reference for ${attachment.id}`);
|
|
31
|
+
return {
|
|
32
|
+
items: [
|
|
33
|
+
{
|
|
34
|
+
type: "file-ref",
|
|
35
|
+
mimeType: attachment.mimeType,
|
|
36
|
+
url,
|
|
37
|
+
modality
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
kimiAttachmentsExtension as default
|
|
46
|
+
};
|