@co0ontty/wand 4.81.0 → 4.82.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.
Files changed (64) hide show
  1. package/dist/agent-dispatch.js +7 -4
  2. package/dist/ai-team-prompts.d.ts +1 -1
  3. package/dist/ai-team-prompts.js +2 -2
  4. package/dist/ai-team-runner.d.ts +2 -0
  5. package/dist/ai-team-runner.js +60 -7
  6. package/dist/ai-team-types.d.ts +6 -0
  7. package/dist/ai-team-types.js +11 -0
  8. package/dist/build-info.json +3 -3
  9. package/dist/cli.js +11 -0
  10. package/dist/config.js +2 -0
  11. package/dist/default-employee.d.ts +11 -0
  12. package/dist/default-employee.js +33 -0
  13. package/dist/employee-knowledge-cli.d.ts +2 -0
  14. package/dist/employee-knowledge-cli.js +52 -0
  15. package/dist/employee-knowledge-content.d.ts +4 -0
  16. package/dist/employee-knowledge-content.js +23 -0
  17. package/dist/employee-knowledge-types.d.ts +15 -0
  18. package/dist/employee-knowledge-types.js +3 -0
  19. package/dist/employee-knowledge.d.ts +6 -0
  20. package/dist/employee-knowledge.js +84 -0
  21. package/dist/git-quick-commit.d.ts +2 -0
  22. package/dist/git-quick-commit.js +121 -58
  23. package/dist/iteration-log.d.ts +5 -0
  24. package/dist/iteration-log.js +12 -1
  25. package/dist/message-truncator.js +13 -9
  26. package/dist/models.d.ts +4 -0
  27. package/dist/models.js +38 -10
  28. package/dist/pi-model-discovery.d.ts +12 -0
  29. package/dist/pi-model-discovery.js +281 -0
  30. package/dist/process-manager.d.ts +23 -1
  31. package/dist/process-manager.js +68 -1
  32. package/dist/prompt-optimizer.js +10 -11
  33. package/dist/pty-turn-activity.d.ts +27 -0
  34. package/dist/pty-turn-activity.js +31 -0
  35. package/dist/server-employee-routes.js +52 -6
  36. package/dist/server-session-routes.js +11 -5
  37. package/dist/server-task-routes.js +6 -1
  38. package/dist/server-user-memory.d.ts +9 -0
  39. package/dist/server-user-memory.js +96 -0
  40. package/dist/server.js +22 -2
  41. package/dist/session-topic.js +6 -5
  42. package/dist/silicon-employee-draft.js +1 -3
  43. package/dist/storage.d.ts +38 -0
  44. package/dist/storage.js +276 -3
  45. package/dist/structured-claude-adapter.d.ts +1 -1
  46. package/dist/structured-claude-adapter.js +2 -0
  47. package/dist/structured-provider-common.d.ts +2 -2
  48. package/dist/structured-provider-common.js +6 -6
  49. package/dist/structured-session-manager.js +5 -4
  50. package/dist/task-title.js +8 -7
  51. package/dist/team-report-file-link.d.ts +6 -0
  52. package/dist/team-report-file-link.js +54 -0
  53. package/dist/team-report-preview.d.ts +3 -0
  54. package/dist/team-report-preview.js +70 -0
  55. package/dist/types.d.ts +15 -0
  56. package/dist/user-memory-types.d.ts +42 -0
  57. package/dist/user-memory-types.js +6 -0
  58. package/dist/user-memory.d.ts +30 -0
  59. package/dist/user-memory.js +190 -0
  60. package/dist/web-ui/content/ai-teams.js +13 -13
  61. package/dist/web-ui/content/scripts.js +59 -61
  62. package/dist/web-ui/content/styles.css +1 -1
  63. package/dist/web-ui/embedded-assets.js +3 -3
  64. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { PtyInputDeliveryError, SessionInputError } from "./process-manager.js";
3
3
  import { getDefaultModelForProvider, isExecutionMode } from "./config.js";
4
+ import { defaultRoleForCli } from "./default-employee.js";
4
5
  import { alignedBlockStart, blockWindowMessagesForTransport, compactToolMessagesForTransport, sliceTurnBlocksForTransport, truncateMessagesForTransport, visibleBlockCount, windowMessagesForTransport } from "./message-truncator.js";
5
6
  import { toSessionDetailDTO, toSessionListItemDTO } from "./session-transport.js";
6
7
  import { checkSessionWorktreeMergeabilityAsync, cleanupSessionWorktreeAsync, getWorktreeMergeErrorCode, mergeSessionWorktreeAsync, WorktreeMergeError, } from "./git-worktree.js";
@@ -463,9 +464,14 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
463
464
  res.status(400).json({ error: "结构化会话当前仅支持 Claude、Codex、OpenCode、Grok、Qoder、Pi 或 Gemini provider。" });
464
465
  return;
465
466
  }
466
- const provider = employeeAgent?.provider ?? (isSessionProvider(body.provider) ? body.provider : "claude");
467
+ const provider = employeeAgent?.provider
468
+ ?? (isSessionProvider(body.provider) ? body.provider : config.defaultProvider ?? "claude");
467
469
  const rawModel = typeof body.model === "string" ? body.model.trim() : "";
468
470
  const origin = parseSessionCreationOrigin(body);
471
+ // Explicit employees/custom role rules and internal automation retain their own role.
472
+ const defaultEmployee = !employee && !body.systemPrompt?.trim()
473
+ && origin.sessionSource === "interactive" ? defaultRoleForCli(storage, provider) : null;
474
+ const role = employee ?? defaultEmployee;
469
475
  const cwd = resolveSessionCwd(body.cwd, config.defaultCwd);
470
476
  const snapshot = structured.createSession({
471
477
  cwd,
@@ -484,10 +490,10 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
484
490
  workspaceId: resolveWorkspaceIdForNewSession(storage, cwd, body.workspaceId),
485
491
  workspaceTaskId: body.workspaceTaskId,
486
492
  // 角色与规则走系统提示通道,不拼进 prompt(见 AGENTS.md「Session 输入契约」)。
487
- systemPrompt: employee?.prompt ?? body.systemPrompt,
488
- employeeId: employee?.id,
489
- employeeName: employee?.name,
490
- employeeAvatar: employee?.avatar,
493
+ systemPrompt: role?.prompt ?? body.systemPrompt,
494
+ employeeId: role?.id,
495
+ employeeName: role?.name,
496
+ employeeAvatar: role?.avatar,
491
497
  employeeCandidates: employee?.agents,
492
498
  employeeCandidateIndex: selectedEmployeeCandidate?.index,
493
499
  ...origin,
@@ -9,6 +9,7 @@ import { recordIterationPromptForTask } from "./iteration-log.js";
9
9
  import { resolveSystemAiContext } from "./session-ai-context.js";
10
10
  import { memberAgents } from "./ai-team-types.js";
11
11
  import { selectEmployeeCandidate } from "./silicon-employee-dispatch.js";
12
+ import { defaultRoleForCli } from "./default-employee.js";
12
13
  import { DEFAULT_WAND_TASK_AGENT_KIND, DEFAULT_WAND_TASK_AGENT_MODE, DEFAULT_WAND_TASK_PRIORITY, isWandTaskAgentKind, isWandTaskAgentMode, normalizeWandTaskAgentMode, WAND_MILESTONE_NAME_MAX_LENGTH } from "./task-types.js";
13
14
  import { isAutoNameableBoardTask, taskAutoNameSignature, taskAutoNameSourceText } from "./wand-task-sync.js";
14
15
  import { isSessionProvider } from "./session-provider.js";
@@ -697,8 +698,12 @@ export function registerTaskRoutes(app, deps) {
697
698
  const cliDefault = subject?.type === "cli"
698
699
  ? parseTaskAgent({ ...cliAgentForSubject(subject, task.agent), ...(body.kind === "pty" ? { kind: "pty" } : {}) })
699
700
  : null;
701
+ const fallbackCandidate = !subject && body.agent === undefined && !task.agent
702
+ && !body.provider ? selectEmployeeCandidate(defaultRoleForCli(storage, config.defaultProvider)).agent : null;
703
+ const fallbackAgent = fallbackCandidate && body.kind === "pty"
704
+ ? { ...fallbackCandidate, kind: "pty" } : fallbackCandidate;
700
705
  const agent = selected?.agent ?? (body.agent === undefined
701
- ? cliDefault ?? task.agent ?? parseWandTaskAgent(JSON.stringify(body))
706
+ ? cliDefault ?? task.agent ?? fallbackAgent ?? parseWandTaskAgent(JSON.stringify(body))
702
707
  : parseTaskAgent(body.agent, task.agent?.mode, task.agent?.kind));
703
708
  if (!agent)
704
709
  throw new Error("请先为该任务选择 CLI 工具。");
@@ -0,0 +1,9 @@
1
+ import type { Express, RequestHandler } from "express";
2
+ import type { WandStorage } from "./storage.js";
3
+ import { type UserMemoryService } from "./user-memory.js";
4
+ export declare function userMemoryOperationLog(storage: WandStorage): RequestHandler;
5
+ export declare function registerUserMemoryRoutes(app: Express, deps: {
6
+ storage: WandStorage;
7
+ service: UserMemoryService;
8
+ notifyChanged?: (id: string) => void;
9
+ }): void;
@@ -0,0 +1,96 @@
1
+ import { asyncRoute } from "./express-async.js";
2
+ import { bodyObject, sendRouteError } from "./server-request.js";
3
+ import { recordUserMemory } from "./user-memory.js";
4
+ import { DEFAULT_EMPLOYEE_ID } from "./ai-team-types.js";
5
+ import { isTaskExecutionSubject } from "./task-types.js";
6
+ import { shouldGenerateSessionTopicFromInput } from "./session-topic.js";
7
+ /** Explicit allowlist: never collect GET polling, auth, vault, config, files or tool bodies. */
8
+ const OPERATIONS = [
9
+ { method: "POST", path: /^\/api\/(?:wand-tasks|tasks|workspaces\/[^/]+\/tasks)$/, feature: "task.create", fields: ["description", "title", "name"] },
10
+ { method: "PATCH", path: /^\/api\/(?:wand-tasks|workspace-tasks)\/[^/]+$/, feature: "task.edit", fields: ["description", "title", "name"] },
11
+ { method: "POST", path: /^\/api\/wand-tasks\/[^/]+\/dispatch$/, feature: "task.dispatch", fields: ["prompt"] },
12
+ { method: "POST", path: /^\/api\/(?:ai-teams\/[^/]+\/runs|wand-tasks\/[^/]+\/team-runs)$/, feature: "team.start", fields: ["note"] },
13
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/model$/, feature: "session.model" },
14
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/thinking-effort$/, feature: "session.thinking" },
15
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/mode$/, feature: "session.mode" },
16
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/quick-commit$/, feature: "git.quick-commit" },
17
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/upload$/, feature: "file.upload" },
18
+ { method: "POST", path: /^\/api\/sessions\/[^/]+\/worktree\/merge$/, feature: "worktree.merge" },
19
+ { method: "POST", path: /^\/api\/optimize-prompt$/, feature: "prompt.optimize", fields: ["text"] },
20
+ { method: "POST", path: /^\/api\/(?:sessions\/[^/]+\/input|structured-sessions\/[^/]+\/messages)$/, feature: "session.prompt", fields: ["input"] },
21
+ ];
22
+ export function userMemoryOperationLog(storage) {
23
+ return (req, res, next) => {
24
+ const operation = OPERATIONS.find((entry) => entry.method === req.method && entry.path.test(req.path));
25
+ if (operation) {
26
+ const epoch = storage.userMemoryCaptureState();
27
+ const body = bodyObject(req.body);
28
+ const subject = body.executionSubject ?? body.subject;
29
+ const privateEmployee = isTaskExecutionSubject(subject) && subject.type === "employee"
30
+ && subject.id !== DEFAULT_EMPLOYEE_ID;
31
+ const observation = privateEmployee ? "" : (operation.fields ?? [])
32
+ .map((field) => typeof body[field] === "string" ? body[field] : "").filter(Boolean).join("\n");
33
+ // Only the successful user action is evidence. IDs/URLs and arbitrary request fields aren't logged.
34
+ res.once("finish", () => {
35
+ if (epoch.enabled && storage.userMemoryCaptureState().enabled
36
+ && storage.userMemoryCaptureState().revision === epoch.revision
37
+ && res.statusCode >= 200 && res.statusCode < 300) {
38
+ if (operation.feature === "session.prompt") {
39
+ // Team-generated instructions never pass through these authenticated input requests.
40
+ // Only collect direct user replies here; interactive/wand-task runners already capture theirs.
41
+ const sessionId = req.path.split("/")[3];
42
+ const session = storage.getSessionSlim(sessionId);
43
+ if (session?.sessionKind === "structured" && session.automationId?.startsWith("ai-team")
44
+ && !/^[\/!]/.test(observation.trim()) && shouldGenerateSessionTopicFromInput(observation)) {
45
+ recordUserMemory(storage, operation.feature, observation, sessionId);
46
+ }
47
+ }
48
+ else {
49
+ const taskId = operation.feature === "task.dispatch" || operation.feature === "task.edit"
50
+ ? req.path.split("/")[3] : undefined;
51
+ const taskSubject = taskId ? (req.path.split("/")[2] === "workspace-tasks"
52
+ ? storage.getWandTaskByWorkspaceTaskId(taskId) : storage.getWandTask(taskId))?.executionSubject : null;
53
+ const text = taskSubject?.type === "employee" && taskSubject.id !== DEFAULT_EMPLOYEE_ID
54
+ ? "" : observation;
55
+ recordUserMemory(storage, operation.feature, text, req.path);
56
+ }
57
+ }
58
+ });
59
+ }
60
+ next();
61
+ };
62
+ }
63
+ export function registerUserMemoryRoutes(app, deps) {
64
+ const { storage, service, notifyChanged } = deps;
65
+ app.get("/api/user-memory", (_req, res) => {
66
+ res.setHeader("Cache-Control", "no-store");
67
+ res.json(service.view());
68
+ });
69
+ app.patch("/api/user-memory", (req, res) => {
70
+ try {
71
+ const body = bodyObject(req.body);
72
+ if (typeof body.enabled !== "boolean")
73
+ throw new Error("enabled 必须是布尔值。");
74
+ storage.setUserMemoryEnabled(body.enabled);
75
+ notifyChanged?.(DEFAULT_EMPLOYEE_ID);
76
+ res.json(service.view());
77
+ }
78
+ catch (error) {
79
+ sendRouteError(res, error, "无法调整短期记忆。");
80
+ }
81
+ });
82
+ app.delete("/api/user-memory", (_req, res) => {
83
+ storage.clearUserMemory();
84
+ notifyChanged?.(DEFAULT_EMPLOYEE_ID);
85
+ res.json(service.view());
86
+ });
87
+ app.post("/api/user-memory/refresh", asyncRoute(async (_req, res) => {
88
+ const updated = await service.refresh(true);
89
+ const view = service.view();
90
+ if (!updated && view.lastError) {
91
+ res.status(503).json({ error: view.lastError });
92
+ return;
93
+ }
94
+ res.json({ updated, ...view });
95
+ }));
96
+ }
package/dist/server.js CHANGED
@@ -33,6 +33,9 @@ import { Missions } from "./missions.js";
33
33
  import { createAiTeamRunner } from "./ai-team-runner.js";
34
34
  import { registerAiTeamRoutes } from "./server-ai-team-routes.js";
35
35
  import { registerSiliconEmployeeRoutes } from "./server-employee-routes.js";
36
+ import { defaultRoleForCli } from "./default-employee.js";
37
+ import { UserMemoryService } from "./user-memory.js";
38
+ import { registerUserMemoryRoutes, userMemoryOperationLog } from "./server-user-memory.js";
36
39
  import { registerAttentionRoutes } from "./server-attention-routes.js";
37
40
  import { refreshProviderCliUpdateState, registerAdminUpdateRoutes, registerPublicUpdateRoutes, ServerUpdateState, } from "./server-update-routes.js";
38
41
  import { parseSessionCreationOrigin, registerClaudeHistoryRoutes, registerSessionRoutes } from "./server-session-routes.js";
@@ -288,6 +291,7 @@ export async function startServer(config, configPath, options = {}) {
288
291
  }
289
292
  const app = express();
290
293
  let shuttingDown = false;
294
+ const testMode = process.env.WAND_TEST_MODE === "1";
291
295
  app.set("trust proxy", "loopback, 172.16.0.0/12");
292
296
  const storage = new WandStorage(resolveDatabasePath(configPath));
293
297
  const runtimeConfig = new RuntimeConfigState(config);
@@ -310,6 +314,7 @@ export async function startServer(config, configPath, options = {}) {
310
314
  inheritEnv: config.inheritEnv !== false,
311
315
  apiKey: process.env.ANTHROPIC_API_KEY,
312
316
  ...injected,
317
+ piEndpointDiscovery: injected.piEndpointDiscovery ?? { enabled: !testMode },
313
318
  configuredClaudeModels: [
314
319
  currentDefaults.claude,
315
320
  config.commitCli === "claude" ? (storage.getPreference("pref:commitModel", config.commitModel) ?? "") : undefined,
@@ -599,6 +604,7 @@ export async function startServer(config, configPath, options = {}) {
599
604
  "/api/session-directories",
600
605
  "/api/structured-sessions",
601
606
  "/api/commands",
607
+ "/api/user-memory",
602
608
  "/api/claude-history",
603
609
  "/api/codex-history",
604
610
  "/api/opencode-history",
@@ -635,6 +641,16 @@ export async function startServer(config, configPath, options = {}) {
635
641
  "/api/local-file",
636
642
  ], requireFiles);
637
643
  app.use("/api/browser-extension", requirePasswordVault);
644
+ app.use("/api/silicon-employees/:employeeId/knowledge", requireSessions);
645
+ app.use(userMemoryOperationLog(storage));
646
+ const userMemory = new UserMemoryService({
647
+ storage, config,
648
+ notifyChanged: (employeeId) => notifyAiTeamRun({ kind: "silicon-employee-definition", employeeId }),
649
+ });
650
+ registerUserMemoryRoutes(app, {
651
+ storage, service: userMemory,
652
+ notifyChanged: (employeeId) => notifyAiTeamRun({ kind: "silicon-employee-definition", employeeId }),
653
+ });
638
654
  // ── Config & Session info ──
639
655
  app.get("/api/config", asyncRoute(async (req, res) => {
640
656
  const structuredChatPersona = await buildStructuredChatPersonaPayload(configPath, config);
@@ -833,7 +849,9 @@ export async function startServer(config, configPath, options = {}) {
833
849
  cols: reqCols,
834
850
  rows: reqRows,
835
851
  thinkingEffort: body.thinkingEffort ?? config.defaultThinkingEffort,
836
- systemPrompt: body.systemPrompt,
852
+ systemPrompt: body.systemPrompt?.trim() || (origin.sessionSource === "interactive"
853
+ && (isSessionProvider(body.provider) || inferProviderFromCommand(command))
854
+ ? defaultRoleForCli(storage, provider).prompt : undefined),
837
855
  workspaceId,
838
856
  workspaceTaskId: body.workspaceTaskId,
839
857
  ...origin,
@@ -1049,8 +1067,9 @@ export async function startServer(config, configPath, options = {}) {
1049
1067
  if (!storage.hasCustomPassword() && config.password === "change-me") {
1050
1068
  wandWarn("正在使用默认密码(change-me),任何能访问本机的人都可以登录。", "修改方法:在界面右上角「设置」中修改密码,或运行:node dist/cli.js config:set password <你的新密码>");
1051
1069
  }
1052
- const testMode = process.env.WAND_TEST_MODE === "1";
1053
1070
  const updateChecksEnabled = !testMode && process.env.WAND_DISABLE_UPDATE_CHECK !== "1";
1071
+ if (!testMode)
1072
+ userMemory.start();
1054
1073
  // Start configured background sessions after the server is already reachable.
1055
1074
  if (!testMode) {
1056
1075
  void processes.runStartupCommands().catch((error) => {
@@ -1222,6 +1241,7 @@ export async function startServer(config, configPath, options = {}) {
1222
1241
  return closePromise;
1223
1242
  closePromise = (async () => {
1224
1243
  shuttingDown = true;
1244
+ await userMemory.dispose();
1225
1245
  if (updateCheckTimer) {
1226
1246
  clearInterval(updateCheckTimer);
1227
1247
  updateCheckTimer = null;
@@ -257,11 +257,12 @@ export async function generateSessionTopic(userMessages, cwd, language, ai = {})
257
257
  ].join("\n"),
258
258
  prompt: `按发送顺序排列的用户消息:\n${input}`,
259
259
  };
260
- const raw = await callConfiguredAiText(request, cwd ?? process.cwd(), language ?? "", ai);
261
- const topic = parseTopic(raw);
262
- if (!topic)
263
- throw new Error("模型返回的会话主题格式无效。");
264
- return topic;
260
+ return callConfiguredAiText(request, cwd ?? process.cwd(), language ?? "", ai, (raw) => {
261
+ const topic = parseTopic(raw);
262
+ if (!topic)
263
+ throw new Error("模型返回的会话主题格式无效。");
264
+ return topic;
265
+ });
265
266
  }
266
267
  /**
267
268
  * Coalesces title refreshes per session. A newer user message invalidates an
@@ -132,9 +132,8 @@ export async function generateSiliconEmployeeDraft(expectation, ai = {}, options
132
132
  const available = availableEmployeeProviders(options.preferredProvider, options.isProviderAvailable);
133
133
  const providers = available.length ? available : [options.preferredProvider ?? "claude", ...SESSION_PROVIDERS];
134
134
  const request = buildEmployeeDraftPrompt(trimmed, providers, options.existingNames);
135
- let raw;
136
135
  try {
137
- raw = await callConfiguredAiText(request, options.cwd || process.cwd(), options.language ?? "", ai);
136
+ return await callConfiguredAiText(request, options.cwd || process.cwd(), options.language ?? "", ai, (raw) => parseSiliconEmployeeDraft(raw, { allowedProviders: providers, fallbackProvider: providers[0] }));
138
137
  }
139
138
  catch (error) {
140
139
  if (error instanceof SiliconEmployeeDraftError)
@@ -142,5 +141,4 @@ export async function generateSiliconEmployeeDraft(expectation, ai = {}, options
142
141
  const message = error instanceof Error ? error.message : String(error);
143
142
  throw new SiliconEmployeeDraftError(message || "AI 生成员工配置失败。", "DRAFT_AI_FAILED");
144
143
  }
145
- return parseSiliconEmployeeDraft(raw, { allowedProviders: providers, fallbackProvider: providers[0] });
146
144
  }
package/dist/storage.d.ts CHANGED
@@ -2,6 +2,8 @@ import { SessionSnapshot, ConversationTurn, SessionProvider, StructuredSessionSt
2
2
  import type { AiTeam, AiTeamRun, AiTeamRunChatMarker, AiTeamRunStatus, AiTeamStep, AiTeamStepSessionMarker, CandidateFailureKind, SiliconEmployee, StepDispatchInfo } from "./ai-team-types.js";
3
3
  import type { WandTask, WandTaskAgent, WandTaskAgentKind, WandTaskTitleSource } from "./task-types.js";
4
4
  import { type SystemEmployeeSeed } from "./system-employee.js";
5
+ import { type EmployeeKnowledgeEntry } from "./employee-knowledge-types.js";
6
+ import { type UserMemoryEvent, type UserMemoryProfile, type UserMemoryState } from "./user-memory-types.js";
5
7
  import type { AgentActivityItem, Mission, MissionAttempt, MissionReviewComment, MissionReviewStatus, MissionStatus } from "./mission-types.js";
6
8
  import { type PasswordVault, type PasswordVaultItem, type PasswordVaultItemFilter, type PasswordVaultItemInput } from "./password-manager.js";
7
9
  /** `ai_team_runs.run_state_json`:本次运行的候选黑名单(§3.4 修正 B12 两层键值 + host-disabled)。 */
@@ -62,8 +64,10 @@ type WandTaskPatch = Partial<Pick<WandTask, "workspaceId" | "workspaceTaskId" |
62
64
  export declare class WandStorage {
63
65
  private readonly db;
64
66
  private readonly dbPath;
67
+ private memoryCapture;
65
68
  constructor(dbPath: string);
66
69
  directory(): string;
70
+ databasePath(): string;
67
71
  close(): void;
68
72
  /**
69
73
  * Run a synchronous group of storage operations atomically. Calls must not
@@ -315,7 +319,11 @@ export declare class WandStorage {
315
319
  listSiliconEmployees(options?: {
316
320
  includeArchived?: boolean;
317
321
  }): SiliconEmployee[];
322
+ private projectDefaultEmployee;
318
323
  getSiliconEmployee(id: string): SiliconEmployee | null;
324
+ getDefaultSiliconEmployee(): SiliconEmployee | null;
325
+ /** Seed once, preserve execution choices, and never reset learned preferences on restart. */
326
+ ensureDefaultSiliconEmployee(provider?: SessionProvider): SiliconEmployee;
319
327
  /** 内置「系统运维」员工;未创建(或被删除过)时返回 null。 */
320
328
  getSystemSiliconEmployee(key?: string): SiliconEmployee | null;
321
329
  /**
@@ -327,6 +335,36 @@ export declare class WandStorage {
327
335
  archiveSiliconEmployee(id: string, archivedAt?: string): void;
328
336
  unarchiveSiliconEmployee(id: string): void;
329
337
  deleteSiliconEmployee(id: string): void;
338
+ private requireKnowledgeEmployee;
339
+ listEmployeeKnowledge(employeeId: string, query?: string, limit?: number): EmployeeKnowledgeEntry[];
340
+ countEmployeeKnowledge(employeeId: string): number;
341
+ rememberEmployeeKnowledge(employeeId: string, value: string, accessToken?: string): EmployeeKnowledgeEntry;
342
+ forgetEmployeeKnowledge(employeeId: string, entryId: string, accessToken?: string): boolean;
343
+ clearEmployeeKnowledge(employeeId: string): void;
344
+ /** Opaque per-execution capability: no employee selector, app token or DB secret in model prompts. */
345
+ issueEmployeeKnowledgeAccess(sessionId: string, employeeId: string, now?: number): string;
346
+ resolveEmployeeKnowledgeAccess(token: string, now?: number): string | null;
347
+ revokeEmployeeKnowledgeAccess(token: string): void;
348
+ /** No IO on input hot paths; queued observations still CAS against the database before writing. */
349
+ userMemoryCaptureState(): Readonly<{
350
+ enabled: boolean;
351
+ revision: number;
352
+ }>;
353
+ stopUserMemoryCapture(): void;
354
+ getUserMemoryState(now?: number): UserMemoryState;
355
+ listUserMemoryEvents(now?: number, limit?: number): UserMemoryEvent[];
356
+ userMemoryFeatureCounts(now?: number): Array<{
357
+ feature: string;
358
+ count: number;
359
+ }>;
360
+ /** Only already-redacted, bounded observations reach this table. Queued writes use revision CAS. */
361
+ appendUserMemoryEvent(feature: string, text: string, dedupKey: string, revision: number, now?: number): void;
362
+ pruneUserMemory(now?: number): void;
363
+ setUserMemoryEnabled(enabled: boolean): void;
364
+ clearUserMemory(): void;
365
+ markUserMemoryAttempt(revision: number, now: number): boolean;
366
+ /** Read fresh candidates inside the transaction; a late model result cannot undo user edits/clear. */
367
+ applyUserMemoryProfile(profile: UserMemoryProfile, revision: number, sourceId: number, now?: number): boolean;
330
368
  listAiTeams(): AiTeam[];
331
369
  getAiTeam(id: string): AiTeam | null;
332
370
  saveAiTeam(team: AiTeam): void;