@co0ontty/wand 4.76.0 → 4.77.0-beta.g6c4df97

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.
Files changed (71) hide show
  1. package/dist/agent-dispatch.d.ts +46 -0
  2. package/dist/agent-dispatch.js +84 -0
  3. package/dist/ai-team-availability.d.ts +69 -0
  4. package/dist/ai-team-availability.js +100 -0
  5. package/dist/ai-team-prompts.d.ts +113 -0
  6. package/dist/ai-team-prompts.js +435 -0
  7. package/dist/ai-team-runner.d.ts +241 -0
  8. package/dist/ai-team-runner.js +1370 -0
  9. package/dist/ai-team-types.d.ts +147 -0
  10. package/dist/ai-team-types.js +32 -0
  11. package/dist/attention.d.ts +40 -0
  12. package/dist/attention.js +86 -0
  13. package/dist/build-info.json +4 -4
  14. package/dist/claude-sdk-runner.d.ts +5 -0
  15. package/dist/claude-sdk-runner.js +2 -1
  16. package/dist/commit-task-archive.d.ts +3 -0
  17. package/dist/commit-task-archive.js +43 -0
  18. package/dist/config.js +0 -2
  19. package/dist/git-quick-commit.d.ts +2 -1
  20. package/dist/git-quick-commit.js +72 -60
  21. package/dist/message-truncator.d.ts +41 -5
  22. package/dist/message-truncator.js +255 -38
  23. package/dist/missions.d.ts +4 -2
  24. package/dist/missions.js +2 -2
  25. package/dist/process-manager.d.ts +1 -0
  26. package/dist/process-manager.js +17 -8
  27. package/dist/prompt-optimizer.js +13 -13
  28. package/dist/server-ai-team-routes.d.ts +11 -0
  29. package/dist/server-ai-team-routes.js +283 -0
  30. package/dist/server-attention-routes.d.ts +9 -0
  31. package/dist/server-attention-routes.js +26 -0
  32. package/dist/server-file-routes.js +1 -1
  33. package/dist/server-session-routes.js +41 -5
  34. package/dist/server-settings-routes.js +1 -1
  35. package/dist/server-task-routes.d.ts +2 -0
  36. package/dist/server-task-routes.js +6 -40
  37. package/dist/server-workspace-routes.js +13 -5
  38. package/dist/server.js +43 -0
  39. package/dist/session-topic.js +13 -13
  40. package/dist/session-transport.d.ts +3 -0
  41. package/dist/session-transport.js +1 -0
  42. package/dist/storage.d.ts +54 -1
  43. package/dist/storage.js +413 -2
  44. package/dist/structured-claude-adapter.d.ts +5 -0
  45. package/dist/structured-claude-adapter.js +13 -2
  46. package/dist/structured-claude-protocol.d.ts +2 -0
  47. package/dist/structured-claude-protocol.js +4 -0
  48. package/dist/structured-codex-adapter.js +2 -2
  49. package/dist/structured-grok-adapter.js +2 -1
  50. package/dist/structured-opencode-adapter.js +2 -2
  51. package/dist/structured-pi-adapter.js +2 -1
  52. package/dist/structured-provider-common.d.ts +17 -0
  53. package/dist/structured-provider-common.js +52 -0
  54. package/dist/structured-qoder-adapter.js +2 -1
  55. package/dist/structured-session-manager.d.ts +18 -1
  56. package/dist/structured-session-manager.js +67 -10
  57. package/dist/system-ai.d.ts +13 -2
  58. package/dist/system-ai.js +9 -5
  59. package/dist/task-title.js +10 -10
  60. package/dist/types.d.ts +25 -2
  61. package/dist/wand-task-sync.d.ts +1 -0
  62. package/dist/wand-task-sync.js +1 -0
  63. package/dist/web-ui/content/ai-teams.js +12 -0
  64. package/dist/web-ui/content/scripts.js +86 -5301
  65. package/dist/web-ui/content/styles.css +1 -1
  66. package/dist/web-ui/embedded-assets.d.ts +1 -0
  67. package/dist/web-ui/embedded-assets.js +3 -2
  68. package/dist/web-ui/scripts.d.ts +8 -0
  69. package/dist/web-ui/scripts.js +28 -2
  70. package/dist/ws-broadcast.js +52 -19
  71. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -31,6 +31,9 @@ import { registerTaskRoutes } from "./server-task-routes.js";
31
31
  import { getGithubConnectorStatus } from "./github-connector.js";
32
32
  import { registerMissionRoutes } from "./server-mission-routes.js";
33
33
  import { Missions } from "./missions.js";
34
+ import { createAiTeamRunner } from "./ai-team-runner.js";
35
+ import { registerAiTeamRoutes } from "./server-ai-team-routes.js";
36
+ import { registerAttentionRoutes } from "./server-attention-routes.js";
34
37
  import { refreshProviderCliUpdateState, registerAdminUpdateRoutes, registerPublicUpdateRoutes, ServerUpdateState, } from "./server-update-routes.js";
35
38
  import { parseSessionCreationOrigin, registerClaudeHistoryRoutes, registerSessionRoutes } from "./server-session-routes.js";
36
39
  import { registerWorkspaceRoutes } from "./server-workspace-routes.js";
@@ -54,6 +57,7 @@ import { DistributionManager } from "./distribution-manager.js";
54
57
  import { isLogBusActive, wandTuiLog } from "./tui/log-bus.js";
55
58
  import { EMBEDDED_WEB_ASSETS } from "./web-ui/embedded-assets.js";
56
59
  import { renderApp } from "./web-ui/index.js";
60
+ import { getAiTeamsChunk } from "./web-ui/scripts.js";
57
61
  import { WsBroadcastManager } from "./ws-broadcast.js";
58
62
  import { TerminalDaemonClient } from "./terminal-daemon-client.js";
59
63
  import { createUpgradeAwareTerminalHost } from "./render-host.js";
@@ -343,6 +347,26 @@ export async function startServer(config, configPath, options = {}) {
343
347
  const structuredSessions = new StructuredSessionManager(storage, config, structuredLogger, undefined, {}, structuredHosts.host);
344
348
  const sessionRegistry = new SessionRegistry(processes, structuredSessions, storage);
345
349
  const missions = new Missions(storage, structuredSessions, sessionRegistry);
350
+ // wsManager 在后面才建:团队运行的变更通知经由这个转发口,接好之前静默丢弃。
351
+ let notifyAiTeamRun = (_data) => { };
352
+ // 团队降级的 model-unknown 事前比对只看这份已发现的清单;没刷新过就是空,判定方向是放行。
353
+ const aiTeamModelIds = (provider) => {
354
+ const cache = modelCatalog.snapshot();
355
+ const key = {
356
+ claude: "models",
357
+ codex: "codexModels",
358
+ opencode: "opencodeModels",
359
+ grok: "grokModels",
360
+ qoder: "qoderModels",
361
+ pi: "piModels",
362
+ }[provider];
363
+ return cache[key].map((entry) => entry.id);
364
+ };
365
+ const aiTeams = createAiTeamRunner({
366
+ storage, config, structured: structuredSessions, processes, sessions: sessionRegistry,
367
+ notify: (run) => notifyAiTeamRun({ kind: "ai-team-run", runId: run.id, taskId: run.taskId }),
368
+ models: aiTeamModelIds,
369
+ });
346
370
  const updateState = new ServerUpdateState();
347
371
  const getUpdateChannel = () => normalizeUpdateChannel(storage.getConfigValue("updateChannel"));
348
372
  let disconnectAuthenticatedSockets = () => { };
@@ -396,6 +420,14 @@ export async function startServer(config, configPath, options = {}) {
396
420
  app.get("/vendor/xterm/xterm.bundle.js", (req, res) => sendEmbeddedVendorAsset("/vendor/xterm/xterm.bundle.js", req, res));
397
421
  app.get("/vendor/xterm/xterm.css", (req, res) => sendEmbeddedVendorAsset("/vendor/xterm/xterm.css", req, res));
398
422
  app.get("/vendor/qrcode/qrcode.bundle.js", (req, res) => sendEmbeddedVendorAsset("/vendor/qrcode/qrcode.bundle.js", req, res));
423
+ // AI 团队页按需脚本:页面 meta 里的地址带内容 hash,hash 对得上才长缓存。
424
+ app.get("/assets/ai-teams.js", (req, res) => {
425
+ const chunk = getAiTeamsChunk();
426
+ res.setHeader("Cache-Control", req.query.v === chunk.hash
427
+ ? "public, max-age=604800, immutable"
428
+ : "no-cache");
429
+ res.type("application/javascript").send(chunk.content);
430
+ });
399
431
  // ── Web UI endpoints ──
400
432
  app.get("/", (_req, res) => {
401
433
  res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
@@ -644,6 +676,8 @@ export async function startServer(config, configPath, options = {}) {
644
676
  registerGithubRoutes(app, { storage, requireAdmin, sessions: sessionRegistry });
645
677
  // 任务管理与 Missions 一样只需登录:原生 connected-app 也要能列/建/派发。
646
678
  registerTaskRoutes(app, { storage, sessions: sessionRegistry, structured: structuredSessions, processes, config });
679
+ registerAiTeamRoutes(app, { storage, runner: aiTeams });
680
+ registerAttentionRoutes(app, { sessions: sessionRegistry, runner: aiTeams });
647
681
  registerAdminUpdateRoutes(app, {
648
682
  storage,
649
683
  config,
@@ -760,6 +794,7 @@ export async function startServer(config, configPath, options = {}) {
760
794
  cols: reqCols,
761
795
  rows: reqRows,
762
796
  thinkingEffort: body.thinkingEffort ?? config.defaultThinkingEffort,
797
+ systemPrompt: body.systemPrompt,
763
798
  workspaceId,
764
799
  workspaceTaskId: body.workspaceTaskId,
765
800
  ...origin,
@@ -839,15 +874,21 @@ export async function startServer(config, configPath, options = {}) {
839
874
  // Wire process events to WebSocket broadcast
840
875
  processes.on("process", (event) => {
841
876
  missions.ingest(event);
877
+ aiTeams.ingest(event);
842
878
  wsManager.emitEvent(event);
843
879
  });
844
880
  structuredSessions.setEventEmitter((event) => {
845
881
  missions.ingest(event);
882
+ aiTeams.ingest(event);
846
883
  wsManager.emitEvent(event);
847
884
  });
885
+ notifyAiTeamRun = (data) => {
886
+ wsManager.emitEvent({ type: "notification", sessionId: "__system__", data });
887
+ };
848
888
  // Re-attach structured CLI runs that kept going inside terminald while the
849
889
  // previous web process was down; fire-and-forget, failures are logged inside.
850
890
  void structuredSessions.recoverDetachedRuns();
891
+ aiTeams.reconcile();
851
892
  // ── Restart endpoint (needs server + wss in scope) ──
852
893
  /**
853
894
  * 统一的关服 + 重启。重启方式由 computeRelaunch 决定:
@@ -900,6 +941,7 @@ export async function startServer(config, configPath, options = {}) {
900
941
  structuredSessions.dispose();
901
942
  }
902
943
  catch { /* noop */ }
944
+ aiTeams.dispose();
903
945
  try {
904
946
  structuredHosts.rustClient?.disconnect();
905
947
  }
@@ -1177,6 +1219,7 @@ export async function startServer(config, configPath, options = {}) {
1177
1219
  structuredSessions.dispose();
1178
1220
  }
1179
1221
  catch { /* best-effort shutdown */ }
1222
+ aiTeams.dispose();
1180
1223
  try {
1181
1224
  structuredHosts.rustClient?.disconnect();
1182
1225
  }
@@ -245,19 +245,19 @@ export async function generateSessionTopic(userMessages, cwd, language, ai = {})
245
245
  if (!input)
246
246
  throw new Error("没有可总结的用户消息。");
247
247
  const outputLanguage = language?.trim() || "与用户消息相同的语言";
248
- const prompt = [
249
- "请综合总结下面这段用户与编码助手对话中的所有用户消息,用于单个终端/会话的列表标题。",
250
- `使用${outputLanguage}输出。`,
251
- "只输出一个 JSON 对象,不要 Markdown、解释或额外文字。",
252
- '格式:{"title":"不超过20个字的具体主题标题","description":"不超过60个字的一句话任务描述"}',
253
- "标题必须概括该会话用户命令自己的具体工作,不要复述项目名、目录名或上级任务标题,也不要使用“关于”“请求”“任务”等空泛词。",
254
- "描述保留当前整体目标、关键对象和新增要求。",
255
- "后续轮次与前面目标有关时必须共同概括;发生目标切换时优先反映最新目标,同时保留仍有效的上下文。",
256
- "",
257
- "按发送顺序排列的用户消息:",
258
- input,
259
- ].join("\n");
260
- const raw = await callConfiguredAiText(prompt, cwd ?? process.cwd(), language ?? "", ai);
248
+ const request = {
249
+ system: [
250
+ "请综合总结用户消息里的所有轮次,用于单个终端/会话的列表标题。",
251
+ `使用${outputLanguage}输出。`,
252
+ "只输出一个 JSON 对象,不要 Markdown、解释或额外文字。",
253
+ '格式:{"title":"不超过20个字的具体主题标题","description":"不超过60个字的一句话任务描述"}',
254
+ "标题必须概括该会话用户命令自己的具体工作,不要复述项目名、目录名或上级任务标题,也不要使用“关于”“请求”“任务”等空泛词。",
255
+ "描述保留当前整体目标、关键对象和新增要求。",
256
+ "后续轮次与前面目标有关时必须共同概括;发生目标切换时优先反映最新目标,同时保留仍有效的上下文。",
257
+ ].join("\n"),
258
+ prompt: `按发送顺序排列的用户消息:\n${input}`,
259
+ };
260
+ const raw = await callConfiguredAiText(request, cwd ?? process.cwd(), language ?? "", ai);
261
261
  const topic = parseTopic(raw);
262
262
  if (!topic)
263
263
  throw new Error("模型返回的会话主题格式无效。");
@@ -21,6 +21,8 @@ export interface SessionDetailDTO extends SessionBaseDTO {
21
21
  messageTotal?: number;
22
22
  leadingBlockOffset?: number;
23
23
  leadingBlockTotal?: number;
24
+ /** 被切掉的头部里用户可感知的块数(默认收起的工具 / 思考块不计入)。 */
25
+ leadingVisibleCount?: number;
24
26
  }
25
27
  /** Resolve every client-visible title on the server so all clients show the same value. */
26
28
  export declare function resolveSessionDisplayTitle(snapshot: SessionSnapshot, blockedTitles?: readonly string[]): string;
@@ -32,6 +34,7 @@ export interface SessionDetailDTOOptions {
32
34
  messageTotal?: number;
33
35
  leadingBlockOffset?: number;
34
36
  leadingBlockTotal?: number;
37
+ leadingVisibleCount?: number;
35
38
  outputLimit?: number;
36
39
  }
37
40
  export declare function toSessionDetailDTO(snapshot: SessionSnapshot, options?: SessionDetailDTOOptions): SessionDetailDTO;
@@ -92,6 +92,7 @@ export function toSessionDetailDTO(snapshot, options = {}) {
92
92
  ...(options.messageTotal !== undefined ? { messageTotal: options.messageTotal } : {}),
93
93
  ...(options.leadingBlockOffset !== undefined ? { leadingBlockOffset: options.leadingBlockOffset } : {}),
94
94
  ...(options.leadingBlockTotal !== undefined ? { leadingBlockTotal: options.leadingBlockTotal } : {}),
95
+ ...(options.leadingVisibleCount !== undefined ? { leadingVisibleCount: options.leadingVisibleCount } : {}),
95
96
  };
96
97
  }
97
98
  /** Bound snapshot-like event payloads before they enter per-client WS queues. */
package/dist/storage.d.ts CHANGED
@@ -1,6 +1,22 @@
1
- import { SessionSnapshot, ConversationTurn, StructuredSessionState, Workspace, LayoutNode, TaskWindowLayout, WorkspaceDefaultProvider, WorkspaceKind, WorkspaceTask, WorkspaceTaskWorktree, WorkspaceTaskStatus } from "./types.js";
1
+ import { SessionSnapshot, ConversationTurn, SessionProvider, StructuredSessionState, Workspace, LayoutNode, TaskWindowLayout, WorkspaceDefaultProvider, WorkspaceKind, WorkspaceTask, WorkspaceTaskWorktree, WorkspaceTaskStatus } from "./types.js";
2
+ import type { AiTeam, AiTeamRun, AiTeamRunChatMarker, AiTeamRunStatus, AiTeamStep, CandidateFailureKind, StepDispatchInfo } from "./ai-team-types.js";
3
+ import type { WandTaskAgentKind } from "./task-types.js";
2
4
  import type { AgentActivityItem, Mission, MissionAttempt, MissionReviewComment, MissionReviewStatus, MissionStatus } from "./mission-types.js";
3
5
  import { type PasswordVault, type PasswordVaultItem, type PasswordVaultItemFilter, type PasswordVaultItemInput } from "./password-manager.js";
6
+ /** `ai_team_runs.run_state_json`:本次运行的候选黑名单(§3.4 修正 B12 两层键值 + host-disabled)。 */
7
+ export interface AiTeamRunState {
8
+ /** spawn-missing:该 provider 的候选全部直接跳过。 */
9
+ providers: SessionProvider[];
10
+ /** 五元组 key → 拉黑它的原因(model-unknown / startup-timeout)。 */
11
+ agents: Array<{
12
+ key: string;
13
+ kind: CandidateFailureKind;
14
+ }>;
15
+ /** 五元组 key → startup-timeout 累计次数(到 2 次进 agents)。 */
16
+ strikes: Record<string, number>;
17
+ /** host-disabled:整个 run 不再尝试该 kind 的候选。 */
18
+ hostDisabled: WandTaskAgentKind[];
19
+ }
4
20
  export interface ConnectorMeta {
5
21
  provider: string;
6
22
  apiUrl: string | null;
@@ -88,6 +104,8 @@ export declare class WandStorage {
88
104
  setSessionWorkspaceId(sessionId: string, workspaceId: string | null): void;
89
105
  /** Lightweight count of persisted sessions grouped by workspace. */
90
106
  countSessionsByWorkspace(): Map<string, number>;
107
+ /** Count user-initiated CLI launches (one per session), including archived sessions. */
108
+ countInteractiveSessionsByProvider(): Record<SessionProvider, number>;
91
109
  /** Sessions not yet attached to a project. Omits messages/output. */
92
110
  listUnboundSessionBindings(): Array<{
93
111
  id: string;
@@ -265,6 +283,33 @@ export declare class WandStorage {
265
283
  deleteAuthSession(token: string): void;
266
284
  deleteAllAuthSessions(): void;
267
285
  deleteExpiredAuthSessions(now: number): void;
286
+ listAiTeams(): AiTeam[];
287
+ getAiTeam(id: string): AiTeam | null;
288
+ saveAiTeam(team: AiTeam): void;
289
+ /** 只删团队定义;已有运行保存了团队快照,不受影响。 */
290
+ deleteAiTeam(id: string): void;
291
+ saveAiTeamRun(run: AiTeamRun): void;
292
+ /** 群聊会话对应的最近一次运行(同一个群聊可以接着开新运行)。 */
293
+ getLatestAiTeamRunByChat(sessionId: string): AiTeamRun | null;
294
+ /**
295
+ * 会话列表用的群聊标记索引:chat_session_id → 最近一次运行的入口信息。
296
+ * 一次查询建整张表,供 /api/tasks 每请求一次构建;不逐会话查询。
297
+ */
298
+ listAiTeamRunChatMarkers(): Map<string, AiTeamRunChatMarker>;
299
+ getAiTeamRun(id: string): AiTeamRun | null;
300
+ listAiTeamRuns(filter?: {
301
+ taskId?: string;
302
+ teamId?: string;
303
+ statuses?: readonly AiTeamRunStatus[];
304
+ limit?: number;
305
+ }): AiTeamRun[];
306
+ saveAiTeamStep(step: AiTeamStep): void;
307
+ listAiTeamSteps(runId: string): AiTeamStep[];
308
+ getRunningAiTeamStepBySession(sessionId: string): AiTeamStep | null;
309
+ /** `ai_team_runs.run_state_json` 的读侧入口(§3.4);脏值 / 旧行退化成空黑名单。 */
310
+ getAiTeamRunState(runId: string): AiTeamRunState;
311
+ /** 只写 `run_state_json` 一列,不碰 `saveAiTeamRun` 负责的业务字段。 */
312
+ setAiTeamRunState(runId: string, state: AiTeamRunState): void;
268
313
  saveMission(mission: Mission): void;
269
314
  getMission(id: string): Mission | null;
270
315
  listMissions(includeArchived?: boolean): Mission[];
@@ -301,4 +346,12 @@ export declare class WandStorage {
301
346
  private mapSessionRow;
302
347
  deleteSession(id: string): void;
303
348
  }
349
+ /**
350
+ * `ai_team_steps.dispatch_info_json` 的读侧校验(§3.2)。脏值 / 旧行默认 `{}` 一律退化成
351
+ * 「首选、没跳过任何候选」,坏条目逐条丢弃,不整字段作废——降级留痕是可观测性数据,
352
+ * 不能因为一条脏记录把整条链丢掉。
353
+ */
354
+ export declare function parseStepDispatchInfo(raw: unknown): StepDispatchInfo;
355
+ /** `ai_team_runs.run_state_json` 的读侧校验(§3.4);脏值退化成空黑名单。 */
356
+ export declare function parseAiTeamRunState(raw: unknown): AiTeamRunState;
304
357
  export {};