@co0ontty/wand 4.69.0 → 4.70.0-beta.g02757ae
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/build-info.json +4 -4
- package/dist/server-workspace-routes.js +16 -3
- package/dist/structured-client-protocol.js +72 -1
- package/dist/wand-task-sync.d.ts +1 -0
- package/dist/wand-task-sync.js +1 -1
- package/dist/web-ui/content/scripts.js +42 -42
- package/dist/web-ui/embedded-assets.js +1 -1
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-09-
|
|
4
|
-
"version": "4.
|
|
5
|
-
"channel": "
|
|
2
|
+
"commit": "02757aebae5ba53dab99bdce06ffb7788be51832",
|
|
3
|
+
"builtAt": "2026-09-18T01:31:07.090Z",
|
|
4
|
+
"version": "4.70.0-beta.g02757ae",
|
|
5
|
+
"channel": "beta"
|
|
6
6
|
}
|
|
@@ -13,6 +13,7 @@ import { archiveBoardTaskForWorkspaceTask, archiveWorkspaceTask, ensureBoardTask
|
|
|
13
13
|
import { isSessionProvider } from "./session-provider.js";
|
|
14
14
|
import { firstLayoutTabId } from "./layout-tree.js";
|
|
15
15
|
import { refreshAutoBoardTaskTitles } from "./server-task-routes.js";
|
|
16
|
+
import { provisionalTaskTitleFromDescription } from "./task-title.js";
|
|
16
17
|
function workspaceSessionTitle(session, names = {}) {
|
|
17
18
|
return resolveSessionDisplayTitle(session, collectSessionTopicBlocklist({
|
|
18
19
|
taskName: names.taskName,
|
|
@@ -112,9 +113,11 @@ function taskRuntimeCwd(task, workspace) {
|
|
|
112
113
|
}
|
|
113
114
|
function createTaskForWorkspace(storage, workspace, body) {
|
|
114
115
|
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
115
|
-
//
|
|
116
|
+
// 首个会话的提示词:任务没起名时用它先总结一个标题,不再留「未命名任务」占位。
|
|
117
|
+
const description = typeof body.description === "string" ? body.description.trim() : "";
|
|
118
|
+
// 留空(或老客户端回传的占位名)走自动命名:先用提示词总结,再交给模型改写。
|
|
116
119
|
const named = name.length > 0 && !isUnnamedWorkspaceTaskName(name);
|
|
117
|
-
const
|
|
120
|
+
const provisional = named ? "" : provisionalTaskTitleFromDescription(description);
|
|
118
121
|
// 里程碑是全局列表;建任务时可选,非法 id 直接报错而不是静默丢掉。
|
|
119
122
|
const requestedMilestoneId = typeof body.milestoneId === "string" ? body.milestoneId.trim() : "";
|
|
120
123
|
if (requestedMilestoneId && !storage.getWandMilestone(requestedMilestoneId)) {
|
|
@@ -131,6 +134,10 @@ function createTaskForWorkspace(storage, workspace, body) {
|
|
|
131
134
|
}
|
|
132
135
|
const baseRef = typeof body.baseRef === "string" && body.baseRef.trim() ? body.baseRef.trim() : undefined;
|
|
133
136
|
const runCwd = mountedCwd ?? workspace.cwd;
|
|
137
|
+
// 什么都没给(无名字、无提示词)时用带随机数的占位名,后续会话内容一到就自动改名。
|
|
138
|
+
const taskName = named
|
|
139
|
+
? name
|
|
140
|
+
: provisional || `${UNNAMED_WORKSPACE_TASK_NAME} ${crypto.randomInt(1000, 10000)}`;
|
|
134
141
|
let worktree = null;
|
|
135
142
|
if (body.worktree === true) {
|
|
136
143
|
const setup = prepareSessionWorktree({
|
|
@@ -148,7 +155,10 @@ function createTaskForWorkspace(storage, workspace, body) {
|
|
|
148
155
|
worktree,
|
|
149
156
|
milestoneId,
|
|
150
157
|
});
|
|
151
|
-
ensureBoardTaskForWorkspaceTask(storage, task, workspace, {
|
|
158
|
+
ensureBoardTaskForWorkspaceTask(storage, task, workspace, {
|
|
159
|
+
titleSource: named ? "user" : "auto",
|
|
160
|
+
description,
|
|
161
|
+
});
|
|
152
162
|
return {
|
|
153
163
|
task,
|
|
154
164
|
cwd: taskRuntimeCwd(task, workspace),
|
|
@@ -414,6 +424,8 @@ export function registerWorkspaceRoutes(app, storage, sessions, titleOptions = {
|
|
|
414
424
|
const workspace = storage.ensureGlobalWorkspace();
|
|
415
425
|
try {
|
|
416
426
|
const created = createTaskForWorkspace(storage, workspace, req.body);
|
|
427
|
+
// 带提示词建的任务立刻排上模型总结(响应里已经是提示词临时标题)。
|
|
428
|
+
refreshAutoBoardTaskTitles(storage, titleOptions);
|
|
417
429
|
res.status(201).json({
|
|
418
430
|
...created.task,
|
|
419
431
|
cwd: created.cwd,
|
|
@@ -711,6 +723,7 @@ export function registerWorkspaceRoutes(app, storage, sessions, titleOptions = {
|
|
|
711
723
|
}
|
|
712
724
|
try {
|
|
713
725
|
const created = createTaskForWorkspace(storage, workspace, req.body);
|
|
726
|
+
refreshAutoBoardTaskTitles(storage, titleOptions);
|
|
714
727
|
res.status(201).json({
|
|
715
728
|
...created.task,
|
|
716
729
|
cwd: created.cwd,
|
|
@@ -43,6 +43,77 @@ function questionsFromInput(input) {
|
|
|
43
43
|
}
|
|
44
44
|
return questions;
|
|
45
45
|
}
|
|
46
|
+
/** 派发子 Agent 的工具名:Claude Code 的 Task/Agent,以及 Wand pi 扩展的 subagent。 */
|
|
47
|
+
const SUBAGENT_TOOL_NAMES = new Set(["Task", "Agent"]);
|
|
48
|
+
const PI_SUBAGENT_TOOL_NAME = "Pi/subagent";
|
|
49
|
+
/**
|
|
50
|
+
* 历史 turn / 非 Claude provider 的子 Agent 工具调用没有 `__subagent` 盖章,
|
|
51
|
+
* 按调用参数现场补一份,让「子 Agent」面板在所有端都拿得到同一份分组。
|
|
52
|
+
*
|
|
53
|
+
* 只认一次真正的派发:Claude 的 Task/Agent(`subagent_type` 可省),
|
|
54
|
+
* pi 扩展的 `Pi/subagent` 必须带 `agent`,避免把管理类调用误当子任务。
|
|
55
|
+
*/
|
|
56
|
+
function deriveSubagentMeta(block) {
|
|
57
|
+
const existing = block.__subagent;
|
|
58
|
+
if (existing?.taskId)
|
|
59
|
+
return existing;
|
|
60
|
+
const input = asRecord(block.input) ?? {};
|
|
61
|
+
if (block.name === PI_SUBAGENT_TOOL_NAME) {
|
|
62
|
+
const agent = text(input.agent);
|
|
63
|
+
const task = text(input.task);
|
|
64
|
+
if (!agent && !task)
|
|
65
|
+
return null;
|
|
66
|
+
return {
|
|
67
|
+
taskId: block.id,
|
|
68
|
+
...(agent ? { agentType: agent } : {}),
|
|
69
|
+
...(task ? { taskDescription: task } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const agentType = text(input.subagent_type);
|
|
73
|
+
// Claude 的 Task/Agent 允许省 `subagent_type`;其他工具只有在真给了 `subagent_type` 时才算派发。
|
|
74
|
+
if (!SUBAGENT_TOOL_NAMES.has(block.name) && !agentType)
|
|
75
|
+
return null;
|
|
76
|
+
const description = text(input.description);
|
|
77
|
+
return {
|
|
78
|
+
taskId: block.id,
|
|
79
|
+
...(agentType ? { agentType } : {}),
|
|
80
|
+
...(description ? { taskDescription: description } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 给没有盖章的子 Agent 调用打上 `__subagent`:派发用的 tool_use 自己带一份,
|
|
85
|
+
* 对应的 tool_result(`tool_use_id` 命中 taskId)带同一份,客户端才好判定完成态。
|
|
86
|
+
*/
|
|
87
|
+
function stampDerivedSubagents(messages) {
|
|
88
|
+
const byTaskId = new Map();
|
|
89
|
+
for (const turn of messages) {
|
|
90
|
+
for (const block of turn.content) {
|
|
91
|
+
if (block.type !== "tool_use")
|
|
92
|
+
continue;
|
|
93
|
+
const meta = deriveSubagentMeta(block);
|
|
94
|
+
if (meta)
|
|
95
|
+
byTaskId.set(meta.taskId, meta);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (byTaskId.size === 0)
|
|
99
|
+
return messages;
|
|
100
|
+
return messages.map((turn) => ({
|
|
101
|
+
...turn,
|
|
102
|
+
content: turn.content.map((block) => {
|
|
103
|
+
if (block.__subagent)
|
|
104
|
+
return block;
|
|
105
|
+
if (block.type === "tool_use") {
|
|
106
|
+
const meta = byTaskId.get(block.id);
|
|
107
|
+
return meta ? { ...block, __subagent: meta } : block;
|
|
108
|
+
}
|
|
109
|
+
if (block.type === "tool_result") {
|
|
110
|
+
const meta = byTaskId.get(block.tool_use_id);
|
|
111
|
+
return meta ? { ...block, __subagent: meta } : block;
|
|
112
|
+
}
|
|
113
|
+
return block;
|
|
114
|
+
}),
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
46
117
|
function toolResultText(block) {
|
|
47
118
|
if (block.type !== "tool_result")
|
|
48
119
|
return "";
|
|
@@ -124,7 +195,7 @@ function tasksFromSegment(messages, start, end) {
|
|
|
124
195
|
* This is the external interface consumed by every client.
|
|
125
196
|
*/
|
|
126
197
|
export function enrichStructuredMessages(messages) {
|
|
127
|
-
const enriched = messages.map((turn) => ({
|
|
198
|
+
const enriched = stampDerivedSubagents(messages).map((turn) => ({
|
|
128
199
|
...turn,
|
|
129
200
|
content: turn.content.map((block) => {
|
|
130
201
|
if (block.type !== "tool_use" || block.name !== "AskUserQuestion")
|
package/dist/wand-task-sync.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export declare function taskAutoNameSignature(source: string): string;
|
|
|
21
21
|
/** Identity is the task id, never its title. Same-named tasks stay independent. */
|
|
22
22
|
export declare function ensureBoardTaskForWorkspaceTask(storage: WandStorage, task: WorkspaceTask, workspace: Workspace, options?: {
|
|
23
23
|
titleSource?: WandTaskTitleSource;
|
|
24
|
+
description?: string;
|
|
24
25
|
}): WandTask;
|
|
25
26
|
/** A board task always has a sidebar container, even before its first session. */
|
|
26
27
|
export declare function ensureWorkspaceTaskForBoardTask(storage: WandStorage, card: WandTask): WorkspaceTask;
|
package/dist/wand-task-sync.js
CHANGED
|
@@ -96,7 +96,7 @@ export function ensureBoardTaskForWorkspaceTask(storage, task, workspace, option
|
|
|
96
96
|
title: task.name,
|
|
97
97
|
// 占位名(未命名任务 / 新任务 / 空)走自动命名;用户填过名就是 user,永不被模型覆盖。
|
|
98
98
|
titleSource: options.titleSource ?? (isUnnamedWorkspaceTaskName(task.name) ? "auto" : "user"),
|
|
99
|
-
description: "",
|
|
99
|
+
description: options.description ?? "",
|
|
100
100
|
status: task.status === "done" ? "done" : "todo",
|
|
101
101
|
milestoneId: task.milestoneId ?? null,
|
|
102
102
|
});
|