@co0ontty/wand 4.89.5 → 4.90.0
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/README.md +5 -3
- package/dist/agent-dispatch.js +4 -9
- package/dist/ai-team-employee-binding.js +10 -9
- package/dist/ai-team-runner.d.ts +2 -1
- package/dist/ai-team-runner.js +38 -2
- package/dist/ai-team-types.js +3 -2
- package/dist/ai-text-runner.d.ts +61 -0
- package/dist/ai-text-runner.js +653 -0
- package/dist/avatar-input.d.ts +2 -0
- package/dist/avatar-input.js +19 -0
- package/dist/bounded-process-output.d.ts +5 -0
- package/dist/bounded-process-output.js +9 -0
- package/dist/build-info.json +3 -3
- package/dist/command-error.d.ts +6 -0
- package/dist/command-error.js +8 -0
- package/dist/config.js +11 -42
- package/dist/conversation-service.d.ts +12 -2
- package/dist/conversation-service.js +104 -25
- package/dist/conversation-session-preview.d.ts +2 -0
- package/dist/conversation-session-preview.js +4 -0
- package/dist/decision-client.js +22 -6
- package/dist/decision-expert-employee.js +2 -2
- package/dist/decision-expert-identity.d.ts +1 -1
- package/dist/decision-expert-identity.js +1 -1
- package/dist/decision-expert-service.d.ts +1 -0
- package/dist/decision-expert-service.js +82 -76
- package/dist/decision-hardware.js +4 -3
- package/dist/decision-types.d.ts +4 -0
- package/dist/decision-types.js +4 -0
- package/dist/deployment-lock.d.ts +13 -0
- package/dist/deployment-lock.js +189 -0
- package/dist/employee-text.js +1 -1
- package/dist/fixed-employee-avatar.d.ts +7 -0
- package/dist/fixed-employee-avatar.js +13 -0
- package/dist/git-quick-commit.d.ts +5 -40
- package/dist/git-quick-commit.js +8 -636
- package/dist/hr-employee-identity.d.ts +5 -0
- package/dist/hr-employee-identity.js +5 -0
- package/dist/hr-employee.d.ts +5 -0
- package/dist/hr-employee.js +21 -0
- package/dist/middleware/path-safety.js +1 -1
- package/dist/milestone-scope.js +1 -1
- package/dist/model-auto-assign.d.ts +1 -1
- package/dist/model-auto-assign.js +1 -1
- package/dist/models.d.ts +4 -0
- package/dist/models.js +21 -1
- package/dist/npm-update-utils.js +5 -44
- package/dist/pi-auto-resources.js +6 -3
- package/dist/plush-avatar.d.ts +10 -1
- package/dist/plush-avatar.js +13 -1
- package/dist/plush-cat-appearance.d.ts +97 -0
- package/dist/plush-cat-appearance.js +118 -0
- package/dist/plush-cat-whiskers.d.ts +6 -0
- package/dist/plush-cat-whiskers.js +42 -0
- package/dist/process-manager.d.ts +22 -21
- package/dist/process-manager.js +49 -83
- package/dist/prompt-optimizer.d.ts +1 -1
- package/dist/prompt-optimizer.js +1 -1
- package/dist/render-host.js +1 -19
- package/dist/scheduled-task-service.d.ts +41 -0
- package/dist/scheduled-task-service.js +294 -0
- package/dist/scheduled-task-state.d.ts +11 -0
- package/dist/scheduled-task-state.js +65 -0
- package/dist/scheduled-task-time.d.ts +4 -0
- package/dist/scheduled-task-time.js +82 -0
- package/dist/scheduled-task-types.d.ts +71 -0
- package/dist/scheduled-task-types.js +1 -0
- package/dist/server-ai-team-routes.js +3 -17
- package/dist/server-employee-routes.d.ts +3 -0
- package/dist/server-employee-routes.js +20 -38
- package/dist/server-file-routes.js +44 -1
- package/dist/server-pi-recommendation-routes.js +13 -4
- package/dist/server-request.d.ts +2 -0
- package/dist/server-request.js +9 -0
- package/dist/server-resume-routes.js +1 -1
- package/dist/server-scheduled-task-routes.d.ts +4 -0
- package/dist/server-scheduled-task-routes.js +34 -0
- package/dist/server-session-routes.d.ts +5 -13
- package/dist/server-session-routes.js +35 -70
- package/dist/server-task-routes.d.ts +6 -21
- package/dist/server-task-routes.js +25 -120
- package/dist/server-team-dispatch-routes.js +12 -2
- package/dist/server-workspace-routes.d.ts +1 -1
- package/dist/server-workspace-routes.js +33 -78
- package/dist/server.js +55 -20
- package/dist/session-model.d.ts +15 -0
- package/dist/session-model.js +23 -0
- package/dist/session-registry.d.ts +5 -1
- package/dist/session-registry.js +20 -11
- package/dist/session-request.d.ts +9 -0
- package/dist/session-request.js +27 -0
- package/dist/session-topic.d.ts +1 -1
- package/dist/session-topic.js +1 -1
- package/dist/session-transport.d.ts +3 -1
- package/dist/session-transport.js +11 -5
- package/dist/silicon-employee-draft.d.ts +2 -2
- package/dist/silicon-employee-draft.js +3 -3
- package/dist/socket-probe.d.ts +2 -0
- package/dist/socket-probe.js +20 -0
- package/dist/storage-schedules.d.ts +20 -0
- package/dist/storage-schedules.js +78 -0
- package/dist/storage-schema.d.ts +3 -0
- package/dist/storage-schema.js +702 -0
- package/dist/storage.d.ts +42 -8
- package/dist/storage.js +182 -715
- package/dist/structured-claude-adapter.js +12 -0
- package/dist/structured-claude-protocol.d.ts +4 -0
- package/dist/structured-claude-protocol.js +18 -4
- package/dist/structured-codex-adapter.js +11 -0
- package/dist/structured-exec-pump.js +79 -38
- package/dist/structured-failure.d.ts +21 -0
- package/dist/structured-failure.js +14 -0
- package/dist/structured-gemini-adapter.js +12 -2
- package/dist/structured-grok-adapter.js +12 -2
- package/dist/structured-opencode-adapter.js +8 -1
- package/dist/structured-qoder-adapter.js +14 -0
- package/dist/structured-session-manager.d.ts +13 -18
- package/dist/structured-session-manager.js +147 -517
- package/dist/system-employee.d.ts +1 -1
- package/dist/system-employee.js +1 -1
- package/dist/task-archive-policy.js +1 -1
- package/dist/task-read-model.d.ts +27 -0
- package/dist/task-read-model.js +47 -0
- package/dist/task-retention.d.ts +1 -1
- package/dist/task-retention.js +1 -1
- package/dist/task-title-service.d.ts +30 -0
- package/dist/task-title-service.js +122 -0
- package/dist/task-title.d.ts +1 -1
- package/dist/task-title.js +1 -1
- package/dist/terminal-daemon-client.js +1 -18
- package/dist/user-memory.js +1 -1
- package/dist/web-ui/asset-runtime.d.ts +12 -0
- package/dist/web-ui/asset-runtime.js +6 -0
- package/dist/web-ui/composer-avatar-activity.d.ts +6 -0
- package/dist/web-ui/composer-avatar-activity.js +29 -0
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/module-manifest.json +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chat-render-PY6DIXNZ.js +24 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-2YZLCGYN.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-6CFHW3FA.js +111 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-6XQEBIEX.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-DDSO7OX7.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-G3CXNMA2.js +20 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-LGVAPHRS.js +36 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-NURCNMRU.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-PCMFGZKX.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-QRNA4D7E.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-TMRPHNJO.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-WC7RK7LP.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-YOXXNXOX.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/chunk-YX475LXO.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/employee-card-MDWKU4V3.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-56WPSON2.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-5QOHKHNC.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-AWIJ5L2K.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-BOZLGIT5.js +69 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-EZV22Q7Y.js +4 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-IW43Z5ZF.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-JT7NIUQL.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-JWEIDB55.js +3 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-OU5TRYH6.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-PRSTCPVE.js +5 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-TWPJI3HE.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-WZGJSNML.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-X6KQVFD6.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-YKCQFMQR.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/host-bridge-2LZX6UUZ.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/library-bridge-MQFJGTGY.js +4 -0
- package/dist/web-ui/content/modules/5478be410b112154/page-T3VUCU2W.js +3 -0
- package/dist/web-ui/content/modules/5478be410b112154/panel-HJBGBBPY.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/runtime.js +920 -0
- package/dist/web-ui/content/modules/5478be410b112154/sha256-ANXV72UC.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/task-board-host-AVMDIHIV.js +2 -0
- package/dist/web-ui/content/modules/5478be410b112154/workspace-agent-picker-KI7QVSK3.js +1 -0
- package/dist/web-ui/content/modules/5478be410b112154/workspace-window-L542FGP2.js +1 -0
- package/dist/web-ui/content/plush-avatar.js +177 -177
- package/dist/web-ui/content/scripts.js +1 -994
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/content/tailwind.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +32 -0
- package/dist/web-ui/embedded-assets.js +10 -8
- package/dist/web-ui/markdown.d.ts +3 -2
- package/dist/web-ui/markdown.js +61 -48
- package/dist/web-ui/message-file-target.d.ts +13 -0
- package/dist/web-ui/message-file-target.js +85 -0
- package/dist/web-ui/provider-identity.d.ts +1 -1
- package/dist/web-ui/provider-identity.js +3 -4
- package/dist/web-ui/react/local-preview/controller.d.ts +2 -0
- package/dist/web-ui/react/local-preview/controller.js +12 -0
- package/dist/web-ui/scripts.d.ts +10 -0
- package/dist/web-ui/scripts.js +42 -5
- package/package.json +6 -3
- package/browser-extension/icons/wand-128.png +0 -0
- package/browser-extension/icons/wand-16.png +0 -0
- package/browser-extension/icons/wand-32.png +0 -0
- package/browser-extension/icons/wand-48.png +0 -0
- package/dist/web-ui/content/licenses/codex-LICENSE.txt +0 -21
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
import { employeeAvatarValue, isFixedAvatarEmployee } from "./fixed-employee-avatar.js";
|
|
2
|
+
import { HR_EMPLOYEE_KEY } from "./hr-employee-identity.js";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { AI_TEAM_MAX_CANDIDATES, SILICON_EMPLOYEE_AVATAR_MAX_CHARS, agentKey, isBuiltinSiliconEmployee, parseSiliconEmployeeTags, siliconEmployeeTags, } from "./ai-team-types.js";
|
|
4
5
|
import { getErrorMessage } from "./error-utils.js";
|
|
5
6
|
import { asyncRoute } from "./express-async.js";
|
|
6
|
-
import {
|
|
7
|
+
import { parseStoredAvatar } from "./avatar-input.js";
|
|
8
|
+
import { bodyObject, boundedText, sendRouteError, text } from "./server-request.js";
|
|
7
9
|
import { parseTaskAgent } from "./server-task-routes.js";
|
|
8
10
|
import { resolveSystemAiContext } from "./session-ai-context.js";
|
|
9
11
|
import { employeeCliAvailable } from "./silicon-employee-dispatch.js";
|
|
10
12
|
import { EMPLOYEE_CREATION_DEFAULTS_PREF, resolveSiliconEmployeeDefaults, } from "./silicon-employee-defaults.js";
|
|
11
13
|
import { availableEmployeeProviders, generateSiliconEmployeeDraft, SiliconEmployeeDraftError, validateStructuredEmployeeDraft, } from "./silicon-employee-draft.js";
|
|
12
14
|
import { SESSION_PROVIDERS } from "./session-provider.js";
|
|
13
|
-
import { parsePlushAvatar, parsePlushCatAvatar } from "./plush-avatar.js";
|
|
14
15
|
import { DEFAULT_WAND_TASK_AGENT_KIND } from "./task-types.js";
|
|
15
16
|
import { EMPLOYEE_KNOWLEDGE_MAX_ENTRIES } from "./employee-knowledge-types.js";
|
|
16
|
-
/**
|
|
17
|
-
function employeeDraftAiOptions(storage, config, free) {
|
|
17
|
+
/** Recruitment uses HR’s own ordered candidates and persona, never the ops chain. */
|
|
18
|
+
export function employeeDraftAiOptions(storage, config, free) {
|
|
18
19
|
if (!config)
|
|
19
|
-
|
|
20
|
+
throw new Error("招聘需要服务端 AI 配置。");
|
|
21
|
+
const hr = storage.getSystemSiliconEmployee(HR_EMPLOYEE_KEY);
|
|
22
|
+
if (!hr)
|
|
23
|
+
throw new Error("系统 HR 嘟嘟尚未初始化,请重启服务后重试。");
|
|
20
24
|
const provider = config.defaultProvider ?? "claude";
|
|
21
|
-
return resolveSystemAiContext({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
return { ...resolveSystemAiContext({
|
|
26
|
+
provider,
|
|
27
|
+
structuredState: undefined,
|
|
28
|
+
runner: undefined,
|
|
29
|
+
command: provider === "qoder" ? "qodercli" : provider,
|
|
30
|
+
selectedModel: null,
|
|
31
|
+
thinkingEffort: config.defaultThinkingEffort,
|
|
32
|
+
}, config, hr, free), opsPersona: hr.prompt };
|
|
29
33
|
}
|
|
30
34
|
function sendEmployeeError(res, error, context) {
|
|
31
35
|
const message = getErrorMessage(error, "硅基员工操作失败。");
|
|
@@ -50,30 +54,8 @@ function rejectSystemEmployeeMutation(existing, action) {
|
|
|
50
54
|
return;
|
|
51
55
|
throw new Error(`「${existing.name}」是 Wand 内置员工,不能${action}。`);
|
|
52
56
|
}
|
|
53
|
-
function boundedText(value, label, min, max) {
|
|
54
|
-
const result = text(value);
|
|
55
|
-
if (result.length < min)
|
|
56
|
-
throw new Error(`${label}不能为空。`);
|
|
57
|
-
if (result.length > max)
|
|
58
|
-
throw new Error(`${label}不能超过 ${max} 个字符。`);
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
57
|
function parseAvatar(value, name) {
|
|
62
|
-
|
|
63
|
-
throw new Error(`员工「${name}」的头像格式无效。`);
|
|
64
|
-
}
|
|
65
|
-
const avatar = text(value);
|
|
66
|
-
if (!avatar || /^cat:\d{1,2}$/.test(avatar))
|
|
67
|
-
return avatar;
|
|
68
|
-
if (parsePlushAvatar(avatar) || parsePlushCatAvatar(avatar))
|
|
69
|
-
return avatar;
|
|
70
|
-
if (!/^data:image\/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$/.test(avatar)) {
|
|
71
|
-
throw new Error(`员工「${name}」的头像格式无效。`);
|
|
72
|
-
}
|
|
73
|
-
if (avatar.length > SILICON_EMPLOYEE_AVATAR_MAX_CHARS) {
|
|
74
|
-
throw new Error(`员工「${name}」的头像太大。`);
|
|
75
|
-
}
|
|
76
|
-
return avatar;
|
|
58
|
+
return parseStoredAvatar(value, `员工「${name}」`, SILICON_EMPLOYEE_AVATAR_MAX_CHARS);
|
|
77
59
|
}
|
|
78
60
|
/** Other built-ins keep profile locks; the two stable cat identities lock only avatar. */
|
|
79
61
|
const SYSTEM_EMPLOYEE_LOCKED_FIELDS = [
|
|
@@ -90,7 +72,7 @@ export function parseSystemEmployeeAgents(value, existing) {
|
|
|
90
72
|
const body = bodyObject(value);
|
|
91
73
|
for (const field of SYSTEM_EMPLOYEE_LOCKED_FIELDS.filter((field) => !isFixedAvatarEmployee(existing) || field.key === "avatar")) {
|
|
92
74
|
const incoming = body[field.key];
|
|
93
|
-
if (incoming === undefined
|
|
75
|
+
if (incoming === undefined)
|
|
94
76
|
continue;
|
|
95
77
|
const current = existing[field.key];
|
|
96
78
|
const isSame = typeof incoming === "string" && (incoming === current
|
|
@@ -102,7 +84,7 @@ export function parseSystemEmployeeAgents(value, existing) {
|
|
|
102
84
|
if (body.tags !== undefined && JSON.stringify(body.tags) !== JSON.stringify(siliconEmployeeTags(existing))) {
|
|
103
85
|
throw new Error("该员工是内置的,标签不可修改。");
|
|
104
86
|
}
|
|
105
|
-
if (
|
|
87
|
+
if (body.id !== undefined && body.id !== existing.id)
|
|
106
88
|
throw new Error("该员工是内置的,身份不可修改。");
|
|
107
89
|
if (body.systemKey !== undefined && body.systemKey !== existing.systemKey) {
|
|
108
90
|
throw new Error("该员工是内置的,身份不可修改。");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { exec } from "node:child_process";
|
|
3
3
|
import { createReadStream } from "node:fs";
|
|
4
|
-
import { lstat, mkdir, readdir, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { lstat, mkdir, readdir, readFile, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import { promisify } from "node:util";
|
|
@@ -44,6 +44,40 @@ export function recordRecentPath(storage, cwd) {
|
|
|
44
44
|
}
|
|
45
45
|
export function registerFileRoutes(app, deps) {
|
|
46
46
|
const { storage, defaultCwd } = deps;
|
|
47
|
+
// Resolve relative artifacts against the stored source session, never a client-supplied cwd.
|
|
48
|
+
app.get("/api/session-file/:sessionId", asyncRoute(async (req, res) => {
|
|
49
|
+
const session = storage.getSessionSlim(String(req.params.sessionId));
|
|
50
|
+
if (!session?.cwd) {
|
|
51
|
+
res.status(404).json({ error: "文件所属会话不存在。" });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const relative = typeof req.query.path === "string" ? req.query.path : "";
|
|
55
|
+
if (!relative || path.isAbsolute(relative) || /[\u0000-\u001f]/.test(relative) || /^[a-z][a-z\d+.-]*:/i.test(relative)) {
|
|
56
|
+
res.status(400).json({ error: "文件相对路径无效。" });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const resolved = path.resolve(session.cwd, relative);
|
|
60
|
+
if (!isPathWithinBase(resolved, path.resolve(session.cwd)) || isBlockedFolderPath(resolved)) {
|
|
61
|
+
res.status(403).json({ error: "文件路径超出会话目录。" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const canonical = await realpath(resolved).catch(() => null);
|
|
65
|
+
const base = await realpath(session.cwd).catch(() => null);
|
|
66
|
+
if (canonical && base && (!isPathWithinBase(canonical, base) || isBlockedFolderPath(canonical))) {
|
|
67
|
+
res.status(403).json({ error: "文件链接目标超出会话目录。" });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (req.query.mode === "preview") {
|
|
71
|
+
if (!/\.html?$/i.test(resolved)) {
|
|
72
|
+
res.status(400).json({ error: "目标不是 HTML 文件。" });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
res.redirect(307, "/api/local-file/" + Buffer.from(resolved).toString("base64url") + "/");
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
res.redirect(307, "/api/file-raw?path=" + encodeURIComponent(resolved) + (req.query.mode === "download" ? "&download=1" : ""));
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
47
81
|
app.get("/api/path-suggestions", asyncRoute(async (req, res) => {
|
|
48
82
|
const query = typeof req.query.q === "string" ? req.query.q : "";
|
|
49
83
|
try {
|
|
@@ -397,6 +431,7 @@ export function registerFileRoutes(app, deps) {
|
|
|
397
431
|
headers: {
|
|
398
432
|
"Cache-Control": "private, max-age=60",
|
|
399
433
|
"X-Content-Type-Options": "nosniff",
|
|
434
|
+
...(/\.html?$/i.test(ext) ? { "Content-Security-Policy": "sandbox allow-scripts; connect-src 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'" } : {}),
|
|
400
435
|
},
|
|
401
436
|
readErrorMessage: "Failed to read file",
|
|
402
437
|
});
|
|
@@ -463,6 +498,12 @@ export function registerFileRoutes(app, deps) {
|
|
|
463
498
|
res.status(400).json({ error: "目标不是普通文件。" });
|
|
464
499
|
return;
|
|
465
500
|
}
|
|
501
|
+
const canonicalBase = await realpath(baseRoot);
|
|
502
|
+
const canonicalFile = await realpath(filePath);
|
|
503
|
+
if (!isPathWithinBase(canonicalFile, canonicalBase) || isBlockedFolderPath(canonicalFile)) {
|
|
504
|
+
res.status(403).json({ error: "访问被拒绝:资源链接目标越界。" });
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
466
507
|
const ext = path.extname(filePath).toLowerCase();
|
|
467
508
|
const baseName = path.basename(filePath);
|
|
468
509
|
const encodedName = encodeURIComponent(baseName);
|
|
@@ -474,6 +515,8 @@ export function registerFileRoutes(app, deps) {
|
|
|
474
515
|
headers: {
|
|
475
516
|
"Cache-Control": "private, no-cache",
|
|
476
517
|
"X-Content-Type-Options": "nosniff",
|
|
518
|
+
// Even opening the artifact directly must not grant the Wand origin.
|
|
519
|
+
...(/\.html?$/i.test(ext) ? { "Content-Security-Policy": "sandbox allow-scripts; connect-src 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'" } : {}),
|
|
477
520
|
},
|
|
478
521
|
readErrorMessage: "读取本地文件失败。",
|
|
479
522
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DECISION_EXPERT_NAME } from "./decision-expert-identity.js";
|
|
2
|
+
import { DECISION_CHAIN_WAIT_MS, DecisionError } from "./decision-types.js";
|
|
2
3
|
import { discoverPiResources, resolvePiResourceSelection } from "./pi-resource-catalog.js";
|
|
3
4
|
import { parsePiRecommendationRequest, recommendPiResources } from "./pi-resource-recommendation.js";
|
|
4
5
|
/** Uses the parent's login + sessions-scope middleware; inference-only tokens cannot enter this route. */
|
|
@@ -26,7 +27,7 @@ export function registerPiRecommendationRoute(app, deps) {
|
|
|
26
27
|
}
|
|
27
28
|
const status = deps.decisions?.status();
|
|
28
29
|
if (!deps.decisions || !status?.enabled || !status.supported || !status.configured || settings.localDecision === false) {
|
|
29
|
-
const notice = status && "notice" in status && typeof status.notice === "string" ? status.notice :
|
|
30
|
+
const notice = status && "notice" in status && typeof status.notice === "string" ? status.notice : `本地决策未启用或不可用,原选择未改变;请配置「${DECISION_EXPERT_NAME}」调用链。`;
|
|
30
31
|
throw new DecisionError("UNAVAILABLE", notice, 503);
|
|
31
32
|
}
|
|
32
33
|
const input = parsePiRecommendationRequest(req.body);
|
|
@@ -34,11 +35,19 @@ export function registerPiRecommendationRoute(app, deps) {
|
|
|
34
35
|
throw new DecisionError("BUSY", "本会话正在推荐,请等待当前请求完成。", 409);
|
|
35
36
|
active.add(id);
|
|
36
37
|
owns = true;
|
|
37
|
-
timer = setTimeout(() => abort.abort(), 15_000);
|
|
38
38
|
const inventory = await discoverPiResources(deps.config, deps.structured.get(id).cwd);
|
|
39
39
|
resolvePiResourceSelection(inventory, input.candidates);
|
|
40
40
|
const result = await recommendPiResources({ ...input, catalog: inventory.catalog,
|
|
41
|
-
evaluate: (value, caller, signal) =>
|
|
41
|
+
evaluate: async (value, caller, signal) => {
|
|
42
|
+
const decisionTimer = setTimeout(() => abort.abort(), DECISION_CHAIN_WAIT_MS);
|
|
43
|
+
timer = decisionTimer;
|
|
44
|
+
try {
|
|
45
|
+
return await deps.decisions.evaluate(value, caller, signal);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
clearTimeout(decisionTimer);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
42
51
|
caller: `pi-recommend:${id}`, signal: abort.signal });
|
|
43
52
|
const latest = deps.structured.get(id);
|
|
44
53
|
if (!latest || latest.archived || latest.provider !== "pi" || latest.piSettings?.localDecision === false
|
package/dist/server-request.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/** 取字符串并 trim;非字符串一律当缺省处理。 */
|
|
9
9
|
export declare function text(value: unknown, fallback?: string): string;
|
|
10
|
+
/** Shared length check for employee and team name fields. */
|
|
11
|
+
export declare function boundedText(value: unknown, label: string, min: number, max: number): string;
|
|
10
12
|
/** Express query 值可能是数组,取第一个字符串。 */
|
|
11
13
|
export declare function firstQueryStringValue(value: unknown): string | undefined;
|
|
12
14
|
/** 请求头可能是数组(重复头),取第一个值。 */
|
package/dist/server-request.js
CHANGED
|
@@ -10,6 +10,15 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
10
10
|
export function text(value, fallback = "") {
|
|
11
11
|
return typeof value === "string" ? value.trim() : fallback;
|
|
12
12
|
}
|
|
13
|
+
/** Shared length check for employee and team name fields. */
|
|
14
|
+
export function boundedText(value, label, min, max) {
|
|
15
|
+
const result = text(value);
|
|
16
|
+
if (result.length < min)
|
|
17
|
+
throw new Error(`${label}不能为空。`);
|
|
18
|
+
if (result.length > max)
|
|
19
|
+
throw new Error(`${label}不能超过 ${max} 个字符。`);
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
13
22
|
/** Express query 值可能是数组,取第一个字符串。 */
|
|
14
23
|
export function firstQueryStringValue(value) {
|
|
15
24
|
if (typeof value === "string")
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { asyncRoute } from "./express-async.js";
|
|
12
12
|
import { getErrorMessage } from "./error-utils.js";
|
|
13
13
|
import { isProviderSessionId, isSafeProviderSessionId } from "./resume-policy.js";
|
|
14
|
-
import { parseExecutionMode, parseSessionCreationOrigin } from "./
|
|
14
|
+
import { parseExecutionMode, parseSessionCreationOrigin } from "./session-request.js";
|
|
15
15
|
import { resolveWorkspaceIdForNewSession } from "./workspace-binding.js";
|
|
16
16
|
const STRUCTURED_RESUME_SPECS = [
|
|
17
17
|
{
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import { type ScheduledTaskService } from "./scheduled-task-service.js";
|
|
3
|
+
/** Authentication and the sessions capability are enforced by the server route family. */
|
|
4
|
+
export declare function registerScheduledTaskRoutes(app: Express, service: ScheduledTaskService): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ScheduledTaskConflictError, ScheduledTaskNotFoundError } from "./scheduled-task-service.js";
|
|
2
|
+
import { sendRouteError } from "./server-request.js";
|
|
3
|
+
function failure(res, error) {
|
|
4
|
+
sendRouteError(res, error, "定时任务操作失败。", error instanceof ScheduledTaskNotFoundError ? 404
|
|
5
|
+
: error instanceof ScheduledTaskConflictError ? 409 : 400);
|
|
6
|
+
}
|
|
7
|
+
/** Authentication and the sessions capability are enforced by the server route family. */
|
|
8
|
+
export function registerScheduledTaskRoutes(app, service) {
|
|
9
|
+
app.get("/api/scheduled-tasks", (req, res) => { res.json({ tasks: service.list(req.query.includeCancelled === "1") }); });
|
|
10
|
+
app.get("/api/scheduled-tasks/:id", (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
res.json(service.get(req.params.id));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
failure(res, error);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
app.post("/api/scheduled-tasks", (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
res.status(201).json({ task: service.create(req.body) });
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
failure(res, error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
app.patch("/api/scheduled-tasks/:id", (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
res.json({ task: service.update(req.params.id, req.body) });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
failure(res, error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import type { Express } from "express";
|
|
2
|
+
import type { OpenRouterFreeModelsService } from "./openrouter-free-models.js";
|
|
2
3
|
import { ProcessManager } from "./process-manager.js";
|
|
3
|
-
import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
4
4
|
import { WandStorage } from "./storage.js";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
6
|
+
import { ExecutionMode, ProcessEvent, SessionSnapshot, WandConfig } from "./types.js";
|
|
7
7
|
import { toSessionListItemDTO } from "./session-transport.js";
|
|
8
|
-
import { type ProviderHistoryDeleter, SessionRegistry } from "./session-registry.js";
|
|
9
8
|
import { type PiRecommendationRuntime } from "./server-pi-recommendation-routes.js";
|
|
10
9
|
import { type SessionDirectoryNode } from "./session-directory-tree.js";
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
sessionSource?: unknown;
|
|
14
|
-
automationId?: unknown;
|
|
15
|
-
} | null | undefined): {
|
|
16
|
-
sessionSource: SessionSource;
|
|
17
|
-
automationId?: string;
|
|
18
|
-
};
|
|
10
|
+
import { SessionRegistry, type ProviderHistoryDeleter } from "./session-registry.js";
|
|
11
|
+
export { parseExecutionMode, parseSessionCreationOrigin } from "./session-request.js";
|
|
19
12
|
type SessionDeletionProcesses = Pick<ProcessManager, "get" | "delete"> & ProviderHistoryDeleter;
|
|
20
13
|
type SessionDeletionStructured = Pick<StructuredSessionManager, "get" | "delete">;
|
|
21
14
|
/**
|
|
@@ -49,4 +42,3 @@ export declare function buildSessionListPage(sessions: SessionSnapshot[], offset
|
|
|
49
42
|
export declare function buildSessionDirectoryTree(sessions: SessionSnapshot[], customNames?: ReadonlyMap<string, string>): SessionDirectoryTreeResponse;
|
|
50
43
|
export declare function registerSessionRoutes(app: Express, processes: ProcessManager, structured: StructuredSessionManager, storage: WandStorage, defaultMode: ExecutionMode, config: WandConfig, sessions: SessionRegistry, onSessionCreated?: (cwd: string | undefined | null) => void, onCompletionViewed?: (event: ProcessEvent) => void, decisions?: PiRecommendationRuntime, free?: Pick<OpenRouterFreeModelsService, "resolveForCall">): void;
|
|
51
44
|
export declare function registerClaudeHistoryRoutes(app: Express, processes: ProcessManager, storage: WandStorage): void;
|
|
52
|
-
export {};
|
|
@@ -1,41 +1,36 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { parseExecutionMode, parseSessionCreationOrigin } from "./session-request.js";
|
|
3
|
+
import { isExecutionMode } from "./config.js";
|
|
4
|
+
import { DECISION_EXPERT_NAME } from "./decision-expert-identity.js";
|
|
4
5
|
import { defaultRoleForCli } from "./default-employee.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { toSessionDetailDTO, toSessionListItemDTO } from "./session-transport.js";
|
|
6
|
+
import { fallbackProviderModel, resolveExplicitOrFallbackModel, sessionEmployeeFields } from "./session-model.js";
|
|
7
|
+
import { PtyInputDeliveryError, SessionInputError } from "./process-manager.js";
|
|
8
|
+
import { generateCommitMessageOnly, getGitStatusAsync, QuickCommitError, runPush, runQuickCommitWithFallback, runTagHead, } from "./git-quick-commit.js";
|
|
9
9
|
import { checkSessionWorktreeMergeabilityAsync, cleanupSessionWorktreeAsync, getWorktreeMergeErrorCode, mergeSessionWorktreeAsync, WorktreeMergeError, } from "./git-worktree.js";
|
|
10
|
-
import {
|
|
10
|
+
import { alignedBlockStart, blockWindowMessagesForTransport, compactToolMessagesForTransport, messageWindowByteBudget, sliceTurnBlocksForTransport, truncateMessagesForTransport, visibleBlockCount, windowMessagesForTransport } from "./message-truncator.js";
|
|
11
|
+
import { inspectPiExecution } from "./pi-execution.js";
|
|
11
12
|
import { resolveSystemAiContext } from "./session-ai-context.js";
|
|
12
|
-
import {
|
|
13
|
+
import { resolveSessionCwd } from "./session-cwd.js";
|
|
14
|
+
import { toSessionDetailDTO, toSessionListItemDTO } from "./session-transport.js";
|
|
13
15
|
import { getErrorMessage } from "./error-utils.js";
|
|
16
|
+
import { asyncRoute } from "./express-async.js";
|
|
14
17
|
import { buildIterationCommitContext, COMMIT_CONTEXT_MODE_PREF_KEY, isCommitContextMode, readCommitContextMode, resolveCommitContextInput, } from "./iteration-log.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
+
import { installedPiExtensions } from "./pi-extension-resources.js";
|
|
19
|
+
import { discoverPiResources, resolvePiResourceSelection } from "./pi-resource-catalog.js";
|
|
20
|
+
import { effectivePiSessionSettings, patchPiSessionSettings } from "./pi-session-settings.js";
|
|
18
21
|
import { parseBoundedInteger } from "./request-limits.js";
|
|
19
|
-
import {
|
|
22
|
+
import { buildProviderResumeCommand, isProviderSessionId } from "./resume-policy.js";
|
|
23
|
+
import { registerPiRecommendationRoute } from "./server-pi-recommendation-routes.js";
|
|
20
24
|
import { sendRouteError } from "./server-request.js";
|
|
21
25
|
import { registerStructuredResumeRoutes } from "./server-resume-routes.js";
|
|
22
|
-
import {
|
|
26
|
+
import { buildDirectoryTree, normalizeSessionDirectory, } from "./session-directory-tree.js";
|
|
27
|
+
import { inferProviderFromCommand, isSessionProvider, providerCliCommand, SESSION_PROVIDERS } from "./session-provider.js";
|
|
28
|
+
import { addHiddenSessionIds, deleteOwnedSessionWithHistory, removeHiddenSessionIds } from "./session-registry.js";
|
|
29
|
+
import { selectEmployeeCandidate } from "./silicon-employee-dispatch.js";
|
|
23
30
|
import { enrichStructuredMessages, WAND_PROTOCOL_VERSION } from "./structured-client-protocol.js";
|
|
24
31
|
import { asRecord, isStructuredImagePart } from "./structured-content.js";
|
|
25
|
-
import { installedPiExtensions } from "./pi-extension-resources.js";
|
|
26
|
-
import { registerPiRecommendationRoute } from "./server-pi-recommendation-routes.js";
|
|
27
|
-
import { discoverPiResources, resolvePiResourceSelection } from "./pi-resource-catalog.js";
|
|
28
|
-
import { effectivePiSessionSettings, patchPiSessionSettings } from "./pi-session-settings.js";
|
|
29
|
-
import { buildDirectoryTree, normalizeSessionDirectory, } from "./session-directory-tree.js";
|
|
30
32
|
import { projectCwdForSession, renameWorkspaceDirectory, resolveWorkspaceIdForNewSession, } from "./workspace-binding.js";
|
|
31
|
-
export
|
|
32
|
-
if (value === undefined)
|
|
33
|
-
return fallback;
|
|
34
|
-
if (!isExecutionMode(value)) {
|
|
35
|
-
throw new Error(`无效执行模式: ${String(value)}`);
|
|
36
|
-
}
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
33
|
+
export { parseExecutionMode, parseSessionCreationOrigin } from "./session-request.js";
|
|
39
34
|
/** 提交输入模式:query 覆盖 > 记住的偏好 > 默认(有提示词就优先用提示词)。 */
|
|
40
35
|
function commitModeForRead(storage, override) {
|
|
41
36
|
return readCommitContextMode(storage, override);
|
|
@@ -53,24 +48,6 @@ async function iterationCommitInput(storage, snapshot, body) {
|
|
|
53
48
|
function commitMessageFromIteration(body) {
|
|
54
49
|
return body.autoMessage !== false && !body.customMessage?.trim();
|
|
55
50
|
}
|
|
56
|
-
export function parseSessionCreationOrigin(body) {
|
|
57
|
-
const rawSource = body?.sessionSource;
|
|
58
|
-
if (rawSource !== undefined && rawSource !== "interactive" && rawSource !== "automation" && rawSource !== "startup") {
|
|
59
|
-
throw new Error("sessionSource 必须是 interactive、automation 或 startup。");
|
|
60
|
-
}
|
|
61
|
-
const rawAutomationId = body?.automationId;
|
|
62
|
-
if (rawAutomationId !== undefined && typeof rawAutomationId !== "string") {
|
|
63
|
-
throw new Error("automationId 必须是非空字符串。");
|
|
64
|
-
}
|
|
65
|
-
const automationId = rawAutomationId?.trim();
|
|
66
|
-
if (rawAutomationId !== undefined && !automationId) {
|
|
67
|
-
throw new Error("automationId 必须是非空字符串。");
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
sessionSource: rawSource ?? "interactive",
|
|
71
|
-
...(automationId ? { automationId } : {}),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
51
|
function getInputErrorResponse(error, sessionId) {
|
|
75
52
|
if (error instanceof PtyInputDeliveryError) {
|
|
76
53
|
return {
|
|
@@ -129,24 +106,14 @@ function getInputDebugMeta(error) {
|
|
|
129
106
|
* immediately reappear as a "non-Wand" session after the Wand row is removed.
|
|
130
107
|
*/
|
|
131
108
|
export function deleteSessionWithProviderHistory(processes, structured, storage, id) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
structured
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (!snapshot || !providerSessionId)
|
|
141
|
-
return;
|
|
142
|
-
const provider = snapshot.provider
|
|
143
|
-
?? snapshot.structuredState?.provider
|
|
144
|
-
?? inferProviderFromCommand(snapshot.command)
|
|
145
|
-
?? "claude";
|
|
146
|
-
deleteProviderNativeHistory(processes, provider, providerSessionId, snapshot.cwd);
|
|
147
|
-
// History deletion is intentionally best-effort at the filesystem layer.
|
|
148
|
-
// Keep a tombstone as a fallback for permission errors or process tail writes.
|
|
149
|
-
addHiddenSessionIds(storage, [providerSessionId]);
|
|
109
|
+
deleteOwnedSessionWithHistory(() => {
|
|
110
|
+
const snapshot = structured.get(id) ?? processes.get(id);
|
|
111
|
+
if (snapshot?.sessionKind === "structured")
|
|
112
|
+
structured.delete(id);
|
|
113
|
+
else
|
|
114
|
+
processes.delete(id);
|
|
115
|
+
return snapshot;
|
|
116
|
+
}, processes, storage);
|
|
150
117
|
}
|
|
151
118
|
function sessionSortTimestamp(snapshot) {
|
|
152
119
|
const timestamp = Date.parse(snapshot.startedAt);
|
|
@@ -157,7 +124,7 @@ function buildSessionListEntries(sessions) {
|
|
|
157
124
|
type: "managed",
|
|
158
125
|
key: `session-${session.id}`,
|
|
159
126
|
sortTimestamp: sessionSortTimestamp(session),
|
|
160
|
-
session: toSessionListItemDTO(session),
|
|
127
|
+
session: toSessionListItemDTO(session, { avatar: "compact" }),
|
|
161
128
|
})).sort((left, right) => {
|
|
162
129
|
const timestampOrder = right.sortTimestamp - left.sortTimestamp;
|
|
163
130
|
return timestampOrder || left.key.localeCompare(right.key);
|
|
@@ -454,7 +421,7 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
454
421
|
}
|
|
455
422
|
});
|
|
456
423
|
app.get("/api/sessions", (_req, res) => {
|
|
457
|
-
res.json(sessions.listSlim().map(toSessionListItemDTO));
|
|
424
|
+
res.json(sessions.listSlim().map((session) => toSessionListItemDTO(session)));
|
|
458
425
|
});
|
|
459
426
|
app.get("/api/sessions/provider-usage", (_req, res) => {
|
|
460
427
|
res.json(storage.countInteractiveSessionsByProvider());
|
|
@@ -524,8 +491,8 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
524
491
|
model: rawModel && rawModel !== "default"
|
|
525
492
|
? rawModel
|
|
526
493
|
: (employeeAgent && !requestedProvider
|
|
527
|
-
?
|
|
528
|
-
: rawModel ||
|
|
494
|
+
? resolveExplicitOrFallbackModel(config, provider, employeeAgent.model)
|
|
495
|
+
: rawModel || fallbackProviderModel(config, provider)),
|
|
529
496
|
thinkingEffort: employeeAgent?.thinkingEffort ?? (typeof body.thinkingEffort === "string"
|
|
530
497
|
? body.thinkingEffort
|
|
531
498
|
: config.defaultThinkingEffort),
|
|
@@ -533,9 +500,7 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
533
500
|
workspaceTaskId: body.workspaceTaskId,
|
|
534
501
|
// 角色与规则走系统提示通道,不拼进 prompt(见 AGENTS.md「Session 输入契约」)。
|
|
535
502
|
systemPrompt: role?.prompt ?? body.systemPrompt,
|
|
536
|
-
|
|
537
|
-
employeeName: role?.name,
|
|
538
|
-
employeeAvatar: role?.avatar,
|
|
503
|
+
...sessionEmployeeFields(role),
|
|
539
504
|
employeeCandidates: employee?.agents,
|
|
540
505
|
employeeCandidateIndex: requestedProvider ? undefined : selectedEmployeeCandidate?.index,
|
|
541
506
|
...(engineDecision ? { engine: engineDecision.engine } : {}),
|
|
@@ -679,7 +644,7 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
679
644
|
&& status?.enabled === true && status.supported && status.configured;
|
|
680
645
|
const recommendationReason = !resourceCatalog.supported ? resourceCatalog.reason
|
|
681
646
|
: settings.localDecision === false ? "本会话已关闭本地决策。"
|
|
682
|
-
: !recommendationAvailable ? status && "notice" in status && typeof status.notice === "string" ? status.notice :
|
|
647
|
+
: !recommendationAvailable ? status && "notice" in status && typeof status.notice === "string" ? status.notice : `本地决策未启用或运行环境不可用;请配置「${DECISION_EXPERT_NAME}」调用链。` : "";
|
|
683
648
|
return { recommendationAvailable, recommendationReason,
|
|
684
649
|
autoResourcesAvailable: recommendationAvailable, autoResourcesReason: recommendationReason,
|
|
685
650
|
autoCodemodeAvailable: recommendationAvailable, skillLocksAvailable: resourceCatalog.supported,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Express } from "express";
|
|
2
|
-
import {
|
|
3
|
-
import { generateWandTaskTitle } from "./task-title.js";
|
|
2
|
+
import type { AiTeamRunner } from "./ai-team-runner.js";
|
|
4
3
|
import type { OpenRouterFreeModelsService } from "./openrouter-free-models.js";
|
|
4
|
+
import type { ProcessManager } from "./process-manager.js";
|
|
5
5
|
import type { SessionRegistry } from "./session-registry.js";
|
|
6
|
+
import { type WandStorage } from "./storage.js";
|
|
6
7
|
import type { StructuredSessionManager } from "./structured-session-manager.js";
|
|
7
|
-
import
|
|
8
|
-
import type { AiTeamRunner } from "./ai-team-runner.js";
|
|
8
|
+
import { generateWandTaskTitle } from "./task-title.js";
|
|
9
9
|
import type { WandTaskAgent, WandTaskAgentKind, WandTaskAgentMode } from "./task-types.js";
|
|
10
10
|
import type { WandConfig } from "./types.js";
|
|
11
11
|
/** 任务面板上次选用的 CLI 工具 / 模型 / 思考深度;从未保存过时回落到 Claude 默认。 */
|
|
@@ -31,21 +31,6 @@ export declare function parentTaskIdFrom(storage: WandStorage, value: unknown, w
|
|
|
31
31
|
* 避免把用户在 Web 上选的工作模式悄悄复位成标准。
|
|
32
32
|
*/
|
|
33
33
|
export declare function parseTaskAgent(value: unknown, fallbackMode?: WandTaskAgentMode, fallbackKind?: WandTaskAgentKind): WandTaskAgent | null;
|
|
34
|
-
|
|
35
|
-
export
|
|
36
|
-
export interface AutoTaskTitleOptions {
|
|
37
|
-
config?: WandConfig;
|
|
38
|
-
free?: Pick<OpenRouterFreeModelsService, "resolveForCall">;
|
|
39
|
-
/** 可注入的标题生成器;测试里换成同步桩,避免真的起 CLI。 */
|
|
40
|
-
generateTitle?: typeof generateWandTaskTitle;
|
|
41
|
-
/** 未从任务所属工作区解析到目录时的兜底 cwd。 */
|
|
42
|
-
cwd?: string;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* 扫描标题仍可自动命名的看板任务(titleSource=auto,或仍是占位名的历史卡片):
|
|
46
|
-
* 先用任务描述 + 所有绑定会话的内容立即改掉占位名,再交给后台模型总结更贴切的标题。
|
|
47
|
-
* 同一个输入指纹只处理一次:内容没变就跳过,也避免自动标题与模型结果来回震荡。
|
|
48
|
-
* 用户建任务时写了名字、或事后改过名(titleSource=user 且不是占位名)的任务永不进入这里。
|
|
49
|
-
*/
|
|
50
|
-
export declare function refreshAutoBoardTaskTitles(storage: WandStorage, options?: AutoTaskTitleOptions): void;
|
|
34
|
+
export { refreshAutoBoardTaskTitles, whenWandTaskTitlesSettled } from "./task-title-service.js";
|
|
35
|
+
export type { AutoTaskTitleOptions } from "./task-title-service.js";
|
|
51
36
|
export declare function registerTaskRoutes(app: Express, deps: TaskRouteDependencies): void;
|