gitee-ai-employee 1.2.5 → 1.2.7
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/dsh/client.js +3 -7
- package/dsh/index.js +41 -23
- package/package.json +1 -1
package/dsh/client.js
CHANGED
|
@@ -359,16 +359,12 @@ window.__ModuleLoader__.load({
|
|
|
359
359
|
var accepted = 0
|
|
360
360
|
var skipped = 0
|
|
361
361
|
var tasks = repos.map(function (spec) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
var idx = rest.indexOf('/')
|
|
365
|
-
var owner = rest.slice(0, idx)
|
|
366
|
-
var repo = rest.slice(idx + 1)
|
|
367
|
-
if (!owner || !repo) return Promise.resolve({ accepted: false })
|
|
362
|
+
// 原始仓库行交给服务端统一解析(owner/repo、gitee:owner/repo、完整克隆地址均可)。
|
|
363
|
+
// 客户端不再自己 indexOf 切分——全路径 URL 会被切成 owner='https:' 导致克隆失败。
|
|
368
364
|
return fetch('/gitee-ai/scan', {
|
|
369
365
|
method: 'POST',
|
|
370
366
|
headers: { 'Content-Type': 'application/json' },
|
|
371
|
-
body: JSON.stringify({
|
|
367
|
+
body: JSON.stringify({ spec: spec, dryRun: false }),
|
|
372
368
|
}).then(function (r) { return r.json().catch(function () { return { accepted: false } }) })
|
|
373
369
|
.then(function (b) {
|
|
374
370
|
if (b && b.accepted) accepted++
|
package/dsh/index.js
CHANGED
|
@@ -22,6 +22,15 @@ import { fileURLToPath } from "node:url";
|
|
|
22
22
|
import { tmpdir, homedir } from "node:os";
|
|
23
23
|
import { join } from "node:path";
|
|
24
24
|
|
|
25
|
+
// 路径分隔符:Windows 用反斜杠,mac / linux 用正斜杠(保证跨平台路径正确)。
|
|
26
|
+
const PATH_SEP = (typeof process !== "undefined" && process.platform === "win32") ? "\\" : "/";
|
|
27
|
+
|
|
28
|
+
// 插件自身版本(读包内 package.json),用于启动日志 / 状态接口自报,
|
|
29
|
+
// 便于在运行日志里一眼确认当前加载的到底是不是最新版。
|
|
30
|
+
const PLUGIN_VERSION = (() => {
|
|
31
|
+
try { return JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")).version || "?"; } catch (e) { return "?"; }
|
|
32
|
+
})();
|
|
33
|
+
|
|
25
34
|
const DEFAULT_CONFIG = {
|
|
26
35
|
giteeToken: "",
|
|
27
36
|
githubToken: "",
|
|
@@ -168,7 +177,7 @@ export default {
|
|
|
168
177
|
let webServer = ctx.get("webServer");
|
|
169
178
|
const shell = ctx.shell;
|
|
170
179
|
const timer = ctx.timer;
|
|
171
|
-
console.log("[gitee-ai]
|
|
180
|
+
console.log("[gitee-ai] plugin v" + PLUGIN_VERSION + " loaded | " + ((typeof process !== "undefined" && process.platform) || "?") + " | node " + ((typeof process !== "undefined" && process.version) || "?"));
|
|
172
181
|
ensureWorkerPreset();
|
|
173
182
|
|
|
174
183
|
// ── 提示词归一化:兼容 {id:{name,prompt}} 与 [{id,name,prompt}] 两种形态 ──
|
|
@@ -371,12 +380,12 @@ export default {
|
|
|
371
380
|
}
|
|
372
381
|
}
|
|
373
382
|
const stamp = Date.now() + "-" + (++apiSeq);
|
|
374
|
-
const outFile = config.tmpDir + "
|
|
375
|
-
const codeFile = config.tmpDir + "
|
|
383
|
+
const outFile = config.tmpDir + PATH_SEP + "gitee-out-" + stamp + ".json";
|
|
384
|
+
const codeFile = config.tmpDir + PATH_SEP + "gitee-code-" + stamp + ".txt";
|
|
376
385
|
let cmd;
|
|
377
386
|
if (body !== undefined && body !== null) {
|
|
378
387
|
const b64 = Buffer.from(JSON.stringify(body), "utf8").toString("base64");
|
|
379
|
-
const tmp = config.tmpDir + "
|
|
388
|
+
const tmp = config.tmpDir + PATH_SEP + "gitee-body-" + stamp + ".json";
|
|
380
389
|
cmd = `[IO.File]::WriteAllText('${tmp}', [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${b64}')), (New-Object System.Text.UTF8Encoding($false))); & 'C:\\Windows\\System32\\curl.exe' -sS -o '${outFile}' -w '%{http_code}' -X ${method} '${url}' -H 'Content-Type: application/json' -H 'Authorization: token ${token}' -d '@${tmp}' | Set-Content -Encoding ASCII '${codeFile}'`;
|
|
381
390
|
} else {
|
|
382
391
|
cmd = `& 'C:\\Windows\\System32\\curl.exe' -sS -o '${outFile}' -w '%{http_code}' '${url}' -H 'Authorization: token ${token}' | Set-Content -Encoding ASCII '${codeFile}'`;
|
|
@@ -480,10 +489,10 @@ export default {
|
|
|
480
489
|
} catch (e) {
|
|
481
490
|
diag.ok = false;
|
|
482
491
|
diag.error = String((e && e.message) || e);
|
|
483
|
-
try { writeFileSync(config.tmpDir + "
|
|
492
|
+
try { writeFileSync(config.tmpDir + PATH_SEP + "gitee-my-repos-" + p + "-last.json", JSON.stringify(diag, null, 2), "utf8"); } catch (e2) {}
|
|
484
493
|
return { ok: false, error: diag.error };
|
|
485
494
|
}
|
|
486
|
-
try { writeFileSync(config.tmpDir + "
|
|
495
|
+
try { writeFileSync(config.tmpDir + PATH_SEP + "gitee-my-repos-" + p + "-last.json", JSON.stringify(diag, null, 2), "utf8"); } catch (e2) {}
|
|
487
496
|
return { ok: true, repos: out };
|
|
488
497
|
}
|
|
489
498
|
|
|
@@ -513,19 +522,16 @@ export default {
|
|
|
513
522
|
return config.gitUser;
|
|
514
523
|
}
|
|
515
524
|
|
|
516
|
-
function repoDir(owner, repo) { return config.workRoot +
|
|
525
|
+
function repoDir(owner, repo) { return config.workRoot + PATH_SEP + owner + PATH_SEP + repo; }
|
|
517
526
|
function shellQuote(v) { return `'${String(v).replace(/'/g, "''")}'`; }
|
|
518
527
|
async function ensureRepo(platform, owner, repo) {
|
|
519
528
|
const dir = repoDir(owner, repo);
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
} catch (e) { /* fallthrough */ }
|
|
527
|
-
const parent = config.workRoot + "\\" + owner;
|
|
528
|
-
await sh(`New-Item -ItemType Directory -Force -Path ${shellQuote(parent)} | Out-Null`, { timeoutMs: 15000 });
|
|
529
|
+
// 跨平台检查是否已克隆:直接走文件系统,不依赖 PowerShell / shell 语法(mac / linux 亦可)
|
|
530
|
+
if (existsSync(dir + PATH_SEP + ".git")) {
|
|
531
|
+
await sh(`git -C ${shellQuote(dir)} fetch origin --prune --tags`, { timeoutMs: 300000 });
|
|
532
|
+
return dir;
|
|
533
|
+
}
|
|
534
|
+
mkdirSync(config.workRoot + PATH_SEP + owner, { recursive: true });
|
|
529
535
|
const url = await cloneUrlFor(platform, owner, repo);
|
|
530
536
|
const r = await sh(`git clone ${shellQuote(url)} ${shellQuote(dir)}`, { timeoutMs: 600000 });
|
|
531
537
|
if (r.exitCode !== 0) {
|
|
@@ -677,8 +683,7 @@ export default {
|
|
|
677
683
|
}
|
|
678
684
|
async function readScanResult(resultFile) {
|
|
679
685
|
try {
|
|
680
|
-
const
|
|
681
|
-
const text = (r.stdout.text || "").trim();
|
|
686
|
+
const text = readFileSync(resultFile, "utf8").trim();
|
|
682
687
|
if (!text) return { findings: [], note: "empty-result" };
|
|
683
688
|
const parsed = JSON.parse(text);
|
|
684
689
|
const arr = Array.isArray(parsed) ? parsed : (Array.isArray(parsed.findings) ? parsed.findings : []);
|
|
@@ -760,7 +765,6 @@ export default {
|
|
|
760
765
|
const scanDir = join(dir, ".gitee-scan");
|
|
761
766
|
const resultFile = join(scanDir, "result.json");
|
|
762
767
|
try { mkdirSync(scanDir, { recursive: true }); } catch (e) {}
|
|
763
|
-
void sh(`New-Item -ItemType Directory -Force -Path ${shellQuote(scanDir)} | Out-Null`, { timeoutMs: 15000 }).catch(() => {});
|
|
764
768
|
const taskText = buildScanTask({ p, owner, repo, dir, commit, prompts, resultFile });
|
|
765
769
|
let summary;
|
|
766
770
|
try {
|
|
@@ -1664,7 +1668,7 @@ ${["critical", "high", "medium", "low", "none"].map((s) => `<option value="${s}"
|
|
|
1664
1668
|
}
|
|
1665
1669
|
|
|
1666
1670
|
// ── 扫描 API(固定路径,client 设置卡片调用)──
|
|
1667
|
-
// POST /gitee-ai/scan {platform?,owner,repo,dryRun?,force?,prompts?,customPrompt?}
|
|
1671
|
+
// POST /gitee-ai/scan {spec}(原始仓库行,统一解析)或 {platform?,owner,repo,dryRun?,force?,prompts?,customPrompt?}
|
|
1668
1672
|
// GET /gitee-ai/scan → 提示词清单 + 扫描任务 + 去重状态
|
|
1669
1673
|
let scanApiDisposer = null;
|
|
1670
1674
|
if (webServer) {
|
|
@@ -1682,9 +1686,22 @@ ${["critical", "high", "medium", "low", "none"].map((s) => `<option value="${s}"
|
|
|
1682
1686
|
if (ct.includes("application/json")) {
|
|
1683
1687
|
try { body = JSON.parse(raw || "{}"); } catch (e) { body = {}; }
|
|
1684
1688
|
} else if (raw) body = parseForm(raw);
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1689
|
+
let platform = normPlatform(body.platform || config.defaultPlatform);
|
|
1690
|
+
let owner = String(body.owner || "").trim();
|
|
1691
|
+
let repo = String(body.repo || "").trim();
|
|
1692
|
+
// 支持直接传原始仓库行(client「立即扫描全部仓库」就是传 spec 行):
|
|
1693
|
+
// 统一走 parseRepoSpec,兼容 owner/repo、gitee:/github: 前缀、完整克隆地址。
|
|
1694
|
+
// (不能在这里对 URL 用 indexOf('/') 切分——会把 https://… 切成 owner='https:')
|
|
1695
|
+
if (body.spec !== undefined && String(body.spec).trim()) {
|
|
1696
|
+
const parsed = parseRepoSpec(String(body.spec));
|
|
1697
|
+
if (!parsed) {
|
|
1698
|
+
send(res, 400, { ok: false, error: "无法解析仓库:" + String(body.spec) + "(支持 owner/repo、gitee:owner/repo、完整克隆地址)" });
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
platform = parsed.platform;
|
|
1702
|
+
owner = parsed.owner;
|
|
1703
|
+
repo = parsed.repo;
|
|
1704
|
+
}
|
|
1688
1705
|
if (!owner || !repo) { send(res, 400, { ok: false, error: "owner/repo required" }); return; }
|
|
1689
1706
|
const opts = {
|
|
1690
1707
|
dryRun: body.dryRun === true || body.dryRun === "true",
|
|
@@ -1858,6 +1875,7 @@ ${["critical", "high", "medium", "low", "none"].map((s) => `<option value="${s}"
|
|
|
1858
1875
|
workRoot: config.workRoot, autoMerge: config.autoMerge,
|
|
1859
1876
|
autoCloseIssue: !!config.autoCloseIssue, tokenConfigured: tokenOk(),
|
|
1860
1877
|
githubTokenConfigured: tokenOkFor("github"),
|
|
1878
|
+
version: PLUGIN_VERSION,
|
|
1861
1879
|
defaultPlatform: config.defaultPlatform || "gitee",
|
|
1862
1880
|
gitUser: config.gitUser || "", pollEnabled: !!config.pollEnabled,
|
|
1863
1881
|
pollIntervalMs: config.pollIntervalMs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitee-ai-employee",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Gitee/GitHub AI 员工:issue 里 @ 机器人自动开发并提 PR;v1.2 新增代码安全扫描——配置仓库地址后按内置/自定义提示词扫描漏洞,去重后提交 issue。An issue-driven AI developer for DeepSeek Harness (Gitee & GitHub) with optional static security scanning (dedup + issue reporting).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|