codebee 0.1.99 → 0.1.101
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/CHANGELOG.md +14 -0
- package/README.md +6 -5
- package/app/core/acp_client.py +426 -0
- package/app/core/backend_profiles.py +188 -0
- package/app/core/builtin_agent.py +12 -0
- package/app/core/command_auth.py +302 -0
- package/app/core/gitmod.py +6 -2
- package/app/core/jobs.py +3 -2
- package/app/core/manager.py +59 -4
- package/app/core/market_remote.py +20 -7
- package/app/core/openapi.py +32 -0
- package/app/core/pipeline.py +110 -9
- package/app/core/plugins.py +9 -2
- package/app/core/project_memory.py +73 -6
- package/app/core/registry.py +13 -0
- package/app/core/runner.py +13 -1
- package/app/core/store.py +18 -1
- package/app/main.py +70 -0
- package/app/ui/app.js +82 -2
- package/app/ui/index.html +19 -0
- package/package.json +1 -1
package/app/ui/app.js
CHANGED
|
@@ -4764,7 +4764,8 @@ window.loadProjectMemory = async function (taskId) {
|
|
|
4764
4764
|
box.innerHTML = entries.map((entry) => {
|
|
4765
4765
|
const canApprove = entry.status === "pending" && !entry.expired && entry.verified;
|
|
4766
4766
|
const canRestore = entry.status === "archived" && !entry.expired && entry.verified;
|
|
4767
|
-
const
|
|
4767
|
+
const feedback = entry.status === "approved" ? '<button type="button" class="ghost small" onclick="feedbackProjectMemory(\'' + jsq(taskId) + '\',\'' + jsq(entry.id) + '\',true,' + Number(entry.version) + ')">' + esc(t("有用")) + '</button><button type="button" class="ghost small" onclick="feedbackProjectMemory(\'' + jsq(taskId) + '\',\'' + jsq(entry.id) + '\',false,' + Number(entry.version) + ')">' + esc(t("无用")) + '</button>' : "";
|
|
4768
|
+
const actions = feedback + (canApprove ? '<button type="button" class="ghost small" onclick="decideProjectMemory(\'' + jsq(taskId) + '\',\'' + jsq(entry.id) + '\',\'approve\',' + Number(entry.version) + ')">' + esc(t("批准")) + "</button><button type=\"button\" class=\"ghost small\" onclick=\"decideProjectMemory('" + jsq(taskId) + "','" + jsq(entry.id) + "','reject'," + Number(entry.version) + ')">' + esc(t("拒绝")) + "</button>" : "") +
|
|
4768
4769
|
(entry.status === "approved" ? '<button type="button" class="ghost small" onclick="decideProjectMemory(\'' + jsq(taskId) + '\',\'' + jsq(entry.id) + '\',\'archive\',' + Number(entry.version) + ')">' + esc(t("归档")) + "</button>" : "") +
|
|
4769
4770
|
(canRestore ? '<button type="button" class="ghost small" onclick="decideProjectMemory(\'' + jsq(taskId) + '\',\'' + jsq(entry.id) + '\',\'restore\',' + Number(entry.version) + ')">' + esc(t("恢复")) + "</button>" : "");
|
|
4770
4771
|
return '<article class="rd-memory-row"><div><strong>' + esc(entry.title || t("项目记忆")) + '</strong><span class="chip">' + esc(entry.status || "") + (entry.expired ? " · " + esc(t("已过期")) : "") + '</span></div><pre>' + esc(entry.content || "") + '</pre><div class="rd-memory-actions">' + actions + "</div></article>";
|
|
@@ -4782,6 +4783,16 @@ window.decideProjectMemory = async function (taskId, id, action, version) {
|
|
|
4782
4783
|
} catch (error) { toast(t("项目记忆操作失败:") + error.message, true); }
|
|
4783
4784
|
};
|
|
4784
4785
|
|
|
4786
|
+
window.feedbackProjectMemory = async function (taskId, id, useful, version) {
|
|
4787
|
+
try {
|
|
4788
|
+
await api("/api/tasks/" + encodeURIComponent(taskId) + "/memory", {
|
|
4789
|
+
method: "POST", headers: Object.assign({ "Content-Type": "application/json" }, authHeaders()),
|
|
4790
|
+
body: JSON.stringify({ id, action: "feedback", useful, expected_version: version }),
|
|
4791
|
+
});
|
|
4792
|
+
await loadProjectMemory(taskId);
|
|
4793
|
+
} catch (error) { toast(t("项目记忆反馈失败:") + error.message, true); }
|
|
4794
|
+
};
|
|
4795
|
+
|
|
4785
4796
|
window.loadRunCheckpoints = async function (requestedRunId) {
|
|
4786
4797
|
const runId = requestedRunId || S.detailRunId || ((S.state || {}).task_latest || {})[S.detailTaskKey]?.id;
|
|
4787
4798
|
if (!runId) return;
|
|
@@ -10378,7 +10389,7 @@ function codeThemeFor(mode) {
|
|
|
10378
10389
|
return ok ? ok.id : (mode === "dark" ? "github-dark" : "github");
|
|
10379
10390
|
}
|
|
10380
10391
|
function codeLineNum() { return localStorage.getItem(CT_LINENUM_KEY) !== "0"; } // 缺省开
|
|
10381
|
-
function codeWrap() { return localStorage.getItem(CT_WRAP_KEY)
|
|
10392
|
+
function codeWrap() { return localStorage.getItem(CT_WRAP_KEY) !== "0"; } // 缺省开:长行自动换行,别撑出横向滚动条
|
|
10382
10393
|
function codeFontSize() {
|
|
10383
10394
|
const n = parseFloat(localStorage.getItem(CT_SIZE_KEY) || "12.5");
|
|
10384
10395
|
return isFinite(n) ? Math.min(22, Math.max(10, n)) : 12.5;
|
|
@@ -13362,8 +13373,77 @@ async function loadSettings() {
|
|
|
13362
13373
|
}
|
|
13363
13374
|
} catch (e) { /* 忽略 */ }
|
|
13364
13375
|
loadSettingsV2(); // 引擎调参卡独立拉取(挂了不影响基础设置)
|
|
13376
|
+
loadBackendProfiles();
|
|
13377
|
+
loadCommandAuth();
|
|
13365
13378
|
}
|
|
13366
13379
|
|
|
13380
|
+
async function loadBackendProfiles() {
|
|
13381
|
+
const box = $("acp-profiles");
|
|
13382
|
+
if (!box) return;
|
|
13383
|
+
try {
|
|
13384
|
+
const data = await api("/api/backend-profiles");
|
|
13385
|
+
const rows = data.profiles || [];
|
|
13386
|
+
box.innerHTML = rows.length ? rows.map((row) =>
|
|
13387
|
+
'<div class="list-row"><span><b>' + esc(row.label || row.id) + '</b> · ' + esc(row.command || "") +
|
|
13388
|
+
(row.enabled === false ? ' · ' + esc(t("已停用")) : '') + '</span><button class="ghost small" type="button" onclick="deleteAcpProfile(\'' + jsq(row.id) + '\')">' + esc(t("删除")) + '</button></div>'
|
|
13389
|
+
).join("") : '<span class="hint">' + esc(t("暂无 ACP 后端")) + '</span>';
|
|
13390
|
+
} catch (error) {
|
|
13391
|
+
box.innerHTML = '<span class="hint">' + esc(t("ACP 配置加载失败:")) + esc(error.message) + '</span>';
|
|
13392
|
+
}
|
|
13393
|
+
}
|
|
13394
|
+
|
|
13395
|
+
window.saveAcpProfile = async function () {
|
|
13396
|
+
const msg = $("acp-msg");
|
|
13397
|
+
try {
|
|
13398
|
+
const argsText = ($("acp-args") || {}).value || "[]";
|
|
13399
|
+
const args = JSON.parse(argsText);
|
|
13400
|
+
if (!Array.isArray(args)) throw new Error(t("参数必须是 JSON 数组"));
|
|
13401
|
+
await api("/api/backend-profiles", { method: "POST", headers: Object.assign({ "Content-Type": "application/json" }, authHeaders()),
|
|
13402
|
+
body: JSON.stringify({ label: $("acp-label").value, command: $("acp-command").value,
|
|
13403
|
+
args, workspace_path: $("acp-workspace").value }) });
|
|
13404
|
+
if (msg) msg.textContent = t("ACP 后端已保存");
|
|
13405
|
+
["acp-label", "acp-command", "acp-args", "acp-workspace"].forEach((id) => { const el = $(id); if (el) el.value = id === "acp-args" ? "[]" : ""; });
|
|
13406
|
+
await loadBackendProfiles();
|
|
13407
|
+
await refreshState();
|
|
13408
|
+
} catch (error) { if (msg) msg.textContent = t("ACP 保存失败:") + error.message; }
|
|
13409
|
+
};
|
|
13410
|
+
|
|
13411
|
+
window.deleteAcpProfile = async function (id) {
|
|
13412
|
+
try {
|
|
13413
|
+
await api("/api/backend-profiles/" + encodeURIComponent(id) + "/delete", { method: "POST", headers: authHeaders(), body: "{}" });
|
|
13414
|
+
await loadBackendProfiles();
|
|
13415
|
+
await refreshState();
|
|
13416
|
+
} catch (error) { toast(t("删除 ACP 失败:") + error.message, true); }
|
|
13417
|
+
};
|
|
13418
|
+
|
|
13419
|
+
async function loadCommandAuth() {
|
|
13420
|
+
const pendingBox = $("command-auth-pending");
|
|
13421
|
+
const mode = $("command-auth-mode");
|
|
13422
|
+
if (!pendingBox || !mode) return;
|
|
13423
|
+
try {
|
|
13424
|
+
const data = await api("/api/command-auth");
|
|
13425
|
+
mode.value = data.mode || "legacy";
|
|
13426
|
+
const rows = data.pending || [];
|
|
13427
|
+
pendingBox.innerHTML = rows.length ? rows.map((row) =>
|
|
13428
|
+
'<div class="list-row"><span><code>' + esc(row.command || "") + '</code> · ' + esc(row.source || "") + '</span><button class="ghost small" type="button" onclick="decideCommandAuth(\'' + jsq(row.id) + '\',true)">' + esc(t("批准一次")) + '</button><button class="ghost small" type="button" onclick="decideCommandAuth(\'' + jsq(row.id) + '\',false)">' + esc(t("拒绝")) + '</button></div>'
|
|
13429
|
+
).join("") : '<span class="hint">' + esc(t("暂无待批准命令")) + '</span>';
|
|
13430
|
+
} catch (error) { pendingBox.innerHTML = '<span class="hint">' + esc(t("授权状态加载失败:")) + esc(error.message) + '</span>'; }
|
|
13431
|
+
}
|
|
13432
|
+
|
|
13433
|
+
window.saveCommandAuthMode = async function () {
|
|
13434
|
+
try {
|
|
13435
|
+
await api("/api/command-auth", { method: "POST", headers: Object.assign({ "Content-Type": "application/json" }, authHeaders()), body: JSON.stringify({ mode: $("command-auth-mode").value }) });
|
|
13436
|
+
await loadCommandAuth();
|
|
13437
|
+
} catch (error) { const msg = $("command-auth-msg"); if (msg) msg.textContent = t("授权策略保存失败:") + error.message; }
|
|
13438
|
+
};
|
|
13439
|
+
|
|
13440
|
+
window.decideCommandAuth = async function (id, approve) {
|
|
13441
|
+
try {
|
|
13442
|
+
await api("/api/command-auth/requests/" + encodeURIComponent(id), { method: "POST", headers: Object.assign({ "Content-Type": "application/json" }, authHeaders()), body: JSON.stringify({ approve, scope: "once" }) });
|
|
13443
|
+
await loadCommandAuth();
|
|
13444
|
+
} catch (error) { const msg = $("command-auth-msg"); if (msg) msg.textContent = t("命令授权操作失败:") + error.message; }
|
|
13445
|
+
};
|
|
13446
|
+
|
|
13367
13447
|
/* ---------------- settings_v2 引擎调参卡(schema 驱动) ----------------
|
|
13368
13448
|
* /api/settings-v2 拉 describe(含字段元数据),按 namespace 渲染控件;
|
|
13369
13449
|
* 保存走 /api/settings-v2/<ns> mutate(expected_revision CAS,409=别处已改,
|
package/app/ui/index.html
CHANGED
|
@@ -1076,6 +1076,25 @@
|
|
|
1076
1076
|
</div>
|
|
1077
1077
|
<p data-i18n="内置智能体(直连对话/直接执行)会把服务器的工具并入工具循环(mcp__服务器__工具 名)。命令在你本机执行,与「执行命令」工具同一自主权级别;工具清单缓存 5 分钟。留空 = 不启用。" class="hint">内置智能体(直连对话/直接执行)会把服务器的工具并入工具循环(mcp__服务器__工具 名)。命令在你本机执行,与「执行命令」工具同一自主权级别;工具清单缓存 5 分钟。留空 = 不启用。</p>
|
|
1078
1078
|
</div>
|
|
1079
|
+
<h3 class="sec-title">ACP Backend Profiles</h3>
|
|
1080
|
+
<p class="hint">接入遵循 Agent Client Protocol v1 的本地或 SSH stdio Agent。密钥只保存在本机,读取时始终脱敏。</p>
|
|
1081
|
+
<div class="field">
|
|
1082
|
+
<div id="acp-profiles" class="list"></div>
|
|
1083
|
+
<div class="input-row" style="margin-top:6px">
|
|
1084
|
+
<input id="acp-label" type="text" placeholder="名称">
|
|
1085
|
+
<input id="acp-command" type="text" placeholder="启动命令,例如 acp-agent">
|
|
1086
|
+
<input id="acp-args" type="text" placeholder="参数 JSON 数组,例如 [\"--stdio\"]">
|
|
1087
|
+
<input id="acp-workspace" type="text" placeholder="Agent 工作区(可空)">
|
|
1088
|
+
<button class="ghost small" type="button" onclick="saveAcpProfile()">保存 ACP</button>
|
|
1089
|
+
</div>
|
|
1090
|
+
<p id="acp-msg" class="hint"></p>
|
|
1091
|
+
</div>
|
|
1092
|
+
<h3 class="sec-title">命令授权</h3>
|
|
1093
|
+
<div class="field">
|
|
1094
|
+
<div class="input-row"><select id="command-auth-mode"><option value="legacy">legacy:自动执行</option><option value="restricted">restricted:逐条等待批准</option></select><button class="ghost small" type="button" onclick="saveCommandAuthMode()">保存策略</button></div>
|
|
1095
|
+
<div id="command-auth-pending" class="list"></div>
|
|
1096
|
+
<p id="command-auth-msg" class="hint"></p>
|
|
1097
|
+
</div>
|
|
1079
1098
|
<h3 data-i18n="推送通知" class="sec-title">推送通知</h3>
|
|
1080
1099
|
<div class="field"><label data-i18n="群机器人 Webhook(钉钉 / 飞书 / 企业微信,按域名自动适配)">群机器人 Webhook(钉钉 / 飞书 / 企业微信,按域名自动适配)</label>
|
|
1081
1100
|
<div class="input-row">
|
package/package.json
CHANGED