@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
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
/** Additive schema only. Domain migrations and transactions remain owned by WandStorage. */
|
|
5
|
+
const INIT_SQL = `
|
|
6
|
+
CREATE TABLE IF NOT EXISTS auth_sessions (
|
|
7
|
+
token TEXT PRIMARY KEY,
|
|
8
|
+
expires_at INTEGER NOT NULL,
|
|
9
|
+
kind TEXT NOT NULL DEFAULT 'browser-admin',
|
|
10
|
+
scopes TEXT NOT NULL DEFAULT '["admin"]'
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS command_sessions (
|
|
14
|
+
id TEXT PRIMARY KEY,
|
|
15
|
+
session_source TEXT NOT NULL DEFAULT 'interactive',
|
|
16
|
+
automation_id TEXT,
|
|
17
|
+
command TEXT NOT NULL,
|
|
18
|
+
cwd TEXT NOT NULL,
|
|
19
|
+
mode TEXT NOT NULL,
|
|
20
|
+
status TEXT NOT NULL,
|
|
21
|
+
exit_code INTEGER,
|
|
22
|
+
started_at TEXT NOT NULL,
|
|
23
|
+
ended_at TEXT,
|
|
24
|
+
output TEXT NOT NULL,
|
|
25
|
+
pty_output_seq INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
archived INTEGER NOT NULL DEFAULT 0,
|
|
27
|
+
archived_at TEXT,
|
|
28
|
+
claude_session_id TEXT,
|
|
29
|
+
provider TEXT,
|
|
30
|
+
session_kind TEXT NOT NULL DEFAULT 'pty',
|
|
31
|
+
runner TEXT,
|
|
32
|
+
messages TEXT,
|
|
33
|
+
queued_messages TEXT,
|
|
34
|
+
queued_message_skills TEXT,
|
|
35
|
+
structured_state TEXT,
|
|
36
|
+
resumed_from_session_id TEXT,
|
|
37
|
+
resumed_to_session_id TEXT,
|
|
38
|
+
auto_recovered INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
worktree_enabled INTEGER NOT NULL DEFAULT 0,
|
|
40
|
+
worktree_info TEXT,
|
|
41
|
+
worktree_merge_status TEXT,
|
|
42
|
+
worktree_merge_info TEXT,
|
|
43
|
+
title TEXT,
|
|
44
|
+
description TEXT,
|
|
45
|
+
session_options TEXT NOT NULL DEFAULT '{"schemaVersion":1}'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE TABLE IF NOT EXISTS app_config (
|
|
49
|
+
key TEXT PRIMARY KEY,
|
|
50
|
+
value TEXT NOT NULL
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
CREATE TABLE IF NOT EXISTS session_directory_names (
|
|
54
|
+
path TEXT PRIMARY KEY,
|
|
55
|
+
name TEXT NOT NULL,
|
|
56
|
+
updated_at TEXT NOT NULL
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE TABLE IF NOT EXISTS password_vaults (
|
|
60
|
+
id TEXT PRIMARY KEY,
|
|
61
|
+
name TEXT NOT NULL,
|
|
62
|
+
created_at TEXT NOT NULL,
|
|
63
|
+
updated_at TEXT NOT NULL
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
CREATE TABLE IF NOT EXISTS connectors (
|
|
67
|
+
provider TEXT PRIMARY KEY,
|
|
68
|
+
token TEXT NOT NULL DEFAULT '',
|
|
69
|
+
api_url TEXT NOT NULL DEFAULT '',
|
|
70
|
+
username TEXT,
|
|
71
|
+
connected_at TEXT,
|
|
72
|
+
created_at TEXT NOT NULL,
|
|
73
|
+
updated_at TEXT NOT NULL
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
CREATE TABLE IF NOT EXISTS password_items (
|
|
77
|
+
id TEXT PRIMARY KEY,
|
|
78
|
+
vault_id TEXT NOT NULL,
|
|
79
|
+
type TEXT NOT NULL,
|
|
80
|
+
title TEXT NOT NULL,
|
|
81
|
+
username TEXT,
|
|
82
|
+
password TEXT,
|
|
83
|
+
urls TEXT NOT NULL DEFAULT '[]',
|
|
84
|
+
notes TEXT,
|
|
85
|
+
fields TEXT NOT NULL DEFAULT '{}',
|
|
86
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
87
|
+
favorite INTEGER NOT NULL DEFAULT 0,
|
|
88
|
+
archived INTEGER NOT NULL DEFAULT 0,
|
|
89
|
+
created_at TEXT NOT NULL,
|
|
90
|
+
updated_at TEXT NOT NULL,
|
|
91
|
+
last_used_at TEXT,
|
|
92
|
+
password_updated_at TEXT,
|
|
93
|
+
FOREIGN KEY(vault_id) REFERENCES password_vaults(id)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_password_items_vault ON password_items(vault_id);
|
|
97
|
+
CREATE INDEX IF NOT EXISTS idx_password_items_type ON password_items(type);
|
|
98
|
+
CREATE INDEX IF NOT EXISTS idx_password_items_updated ON password_items(updated_at);
|
|
99
|
+
|
|
100
|
+
CREATE TABLE IF NOT EXISTS missions (
|
|
101
|
+
id TEXT PRIMARY KEY,
|
|
102
|
+
title TEXT NOT NULL,
|
|
103
|
+
prompt TEXT NOT NULL,
|
|
104
|
+
cwd TEXT NOT NULL,
|
|
105
|
+
status TEXT NOT NULL,
|
|
106
|
+
task_id TEXT,
|
|
107
|
+
milestone_id TEXT,
|
|
108
|
+
base_ref TEXT,
|
|
109
|
+
shared_directories TEXT NOT NULL DEFAULT '[]',
|
|
110
|
+
copy_paths TEXT NOT NULL DEFAULT '[]',
|
|
111
|
+
created_at TEXT NOT NULL,
|
|
112
|
+
updated_at TEXT NOT NULL
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
CREATE TABLE IF NOT EXISTS mission_attempts (
|
|
116
|
+
id TEXT PRIMARY KEY,
|
|
117
|
+
mission_id TEXT NOT NULL,
|
|
118
|
+
session_id TEXT,
|
|
119
|
+
provider TEXT NOT NULL,
|
|
120
|
+
state TEXT NOT NULL,
|
|
121
|
+
branch TEXT,
|
|
122
|
+
worktree_path TEXT,
|
|
123
|
+
base_ref TEXT,
|
|
124
|
+
summary TEXT,
|
|
125
|
+
error TEXT,
|
|
126
|
+
created_at TEXT NOT NULL,
|
|
127
|
+
updated_at TEXT NOT NULL,
|
|
128
|
+
FOREIGN KEY(mission_id) REFERENCES missions(id)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
CREATE TABLE IF NOT EXISTS mission_review_comments (
|
|
132
|
+
id TEXT PRIMARY KEY,
|
|
133
|
+
mission_id TEXT NOT NULL,
|
|
134
|
+
attempt_id TEXT NOT NULL,
|
|
135
|
+
file_path TEXT NOT NULL,
|
|
136
|
+
line INTEGER,
|
|
137
|
+
side TEXT NOT NULL DEFAULT 'new',
|
|
138
|
+
body TEXT NOT NULL,
|
|
139
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
140
|
+
created_at TEXT NOT NULL,
|
|
141
|
+
sent_at TEXT,
|
|
142
|
+
resolved_at TEXT,
|
|
143
|
+
FOREIGN KEY(mission_id) REFERENCES missions(id),
|
|
144
|
+
FOREIGN KEY(attempt_id) REFERENCES mission_attempts(id)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
CREATE TABLE IF NOT EXISTS agent_activity (
|
|
148
|
+
session_id TEXT PRIMARY KEY,
|
|
149
|
+
mission_id TEXT,
|
|
150
|
+
attempt_id TEXT,
|
|
151
|
+
state TEXT NOT NULL,
|
|
152
|
+
title TEXT NOT NULL,
|
|
153
|
+
summary TEXT,
|
|
154
|
+
provider TEXT,
|
|
155
|
+
cwd TEXT,
|
|
156
|
+
updated_at TEXT NOT NULL,
|
|
157
|
+
read_at TEXT
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
CREATE INDEX IF NOT EXISTS idx_missions_updated ON missions(updated_at);
|
|
161
|
+
CREATE INDEX IF NOT EXISTS idx_mission_attempts_mission ON mission_attempts(mission_id);
|
|
162
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_mission_attempts_session ON mission_attempts(session_id) WHERE session_id IS NOT NULL;
|
|
163
|
+
CREATE INDEX IF NOT EXISTS idx_mission_comments_attempt ON mission_review_comments(attempt_id, status);
|
|
164
|
+
CREATE INDEX IF NOT EXISTS idx_agent_activity_state ON agent_activity(state, updated_at);
|
|
165
|
+
|
|
166
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
167
|
+
id TEXT PRIMARY KEY,
|
|
168
|
+
name TEXT NOT NULL,
|
|
169
|
+
cwd TEXT NOT NULL,
|
|
170
|
+
kind TEXT NOT NULL DEFAULT 'project',
|
|
171
|
+
default_provider TEXT,
|
|
172
|
+
layout_json TEXT,
|
|
173
|
+
created_at TEXT NOT NULL,
|
|
174
|
+
last_opened_at TEXT
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
CREATE INDEX IF NOT EXISTS idx_workspaces_cwd ON workspaces(cwd);
|
|
178
|
+
CREATE INDEX IF NOT EXISTS idx_workspaces_last_opened ON workspaces(last_opened_at);
|
|
179
|
+
|
|
180
|
+
CREATE TABLE IF NOT EXISTS workspace_tasks (
|
|
181
|
+
id TEXT PRIMARY KEY,
|
|
182
|
+
workspace_id TEXT NOT NULL,
|
|
183
|
+
name TEXT NOT NULL,
|
|
184
|
+
worktree_json TEXT,
|
|
185
|
+
layout_json TEXT,
|
|
186
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
187
|
+
cwd TEXT,
|
|
188
|
+
milestone_id TEXT,
|
|
189
|
+
created_at TEXT NOT NULL,
|
|
190
|
+
last_opened_at TEXT,
|
|
191
|
+
layout_revision INTEGER NOT NULL DEFAULT 0,
|
|
192
|
+
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_workspace_tasks_workspace ON workspace_tasks(workspace_id);
|
|
196
|
+
CREATE INDEX IF NOT EXISTS idx_workspace_tasks_last_opened ON workspace_tasks(last_opened_at);
|
|
197
|
+
|
|
198
|
+
CREATE TABLE IF NOT EXISTS github_issue_bindings (
|
|
199
|
+
owner TEXT NOT NULL,
|
|
200
|
+
repo TEXT NOT NULL,
|
|
201
|
+
issue_number INTEGER NOT NULL,
|
|
202
|
+
session_id TEXT NOT NULL,
|
|
203
|
+
bound_at TEXT NOT NULL,
|
|
204
|
+
PRIMARY KEY (owner, repo, issue_number, session_id),
|
|
205
|
+
FOREIGN KEY (session_id) REFERENCES command_sessions(id) ON DELETE CASCADE
|
|
206
|
+
);
|
|
207
|
+
CREATE INDEX IF NOT EXISTS idx_github_issue_bindings_session ON github_issue_bindings(session_id);
|
|
208
|
+
|
|
209
|
+
CREATE TABLE IF NOT EXISTS wand_milestones (
|
|
210
|
+
id TEXT PRIMARY KEY,
|
|
211
|
+
name TEXT NOT NULL,
|
|
212
|
+
due_date TEXT,
|
|
213
|
+
workspace_id TEXT,
|
|
214
|
+
is_default INTEGER NOT NULL DEFAULT 0,
|
|
215
|
+
created_at TEXT NOT NULL,
|
|
216
|
+
updated_at TEXT NOT NULL
|
|
217
|
+
);
|
|
218
|
+
CREATE INDEX IF NOT EXISTS idx_wand_milestones_created ON wand_milestones(created_at DESC);
|
|
219
|
+
|
|
220
|
+
-- 迭代提示词记录:用户在本轮迭代里发过的提示词标题,供 commit message / 汇报类生成复用。
|
|
221
|
+
-- 不建外键:删除迭代只把记录改挂到默认迭代,绝不删记录。
|
|
222
|
+
CREATE TABLE IF NOT EXISTS wand_iteration_prompts (
|
|
223
|
+
id TEXT PRIMARY KEY,
|
|
224
|
+
milestone_id TEXT NOT NULL,
|
|
225
|
+
workspace_id TEXT,
|
|
226
|
+
session_id TEXT,
|
|
227
|
+
task_id TEXT,
|
|
228
|
+
repo_key TEXT,
|
|
229
|
+
cwd TEXT NOT NULL,
|
|
230
|
+
title TEXT NOT NULL,
|
|
231
|
+
detail TEXT NOT NULL DEFAULT '',
|
|
232
|
+
source TEXT NOT NULL DEFAULT 'session',
|
|
233
|
+
consumed_at TEXT,
|
|
234
|
+
consumed_commit TEXT,
|
|
235
|
+
created_at TEXT NOT NULL
|
|
236
|
+
);
|
|
237
|
+
CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_iteration ON wand_iteration_prompts(milestone_id, created_at DESC);
|
|
238
|
+
CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_repo ON wand_iteration_prompts(repo_key, created_at DESC);
|
|
239
|
+
CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_session ON wand_iteration_prompts(session_id, created_at DESC);
|
|
240
|
+
|
|
241
|
+
CREATE TABLE IF NOT EXISTS wand_tasks (
|
|
242
|
+
id TEXT PRIMARY KEY,
|
|
243
|
+
identifier TEXT,
|
|
244
|
+
workspace_id TEXT,
|
|
245
|
+
title TEXT NOT NULL,
|
|
246
|
+
description TEXT NOT NULL DEFAULT '',
|
|
247
|
+
status TEXT NOT NULL DEFAULT 'todo',
|
|
248
|
+
priority TEXT NOT NULL DEFAULT 'none',
|
|
249
|
+
labels_json TEXT NOT NULL DEFAULT '[]',
|
|
250
|
+
due_date TEXT,
|
|
251
|
+
milestone_id TEXT,
|
|
252
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
253
|
+
agent_json TEXT,
|
|
254
|
+
execution_subject_json TEXT,
|
|
255
|
+
workspace_task_id TEXT,
|
|
256
|
+
parent_task_id TEXT,
|
|
257
|
+
title_source TEXT,
|
|
258
|
+
auto_title_signature TEXT,
|
|
259
|
+
archived_at TEXT,
|
|
260
|
+
created_at TEXT NOT NULL,
|
|
261
|
+
updated_at TEXT NOT NULL,
|
|
262
|
+
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE SET NULL
|
|
263
|
+
);
|
|
264
|
+
CREATE INDEX IF NOT EXISTS idx_wand_tasks_board ON wand_tasks(workspace_id, status, sort_order, updated_at);
|
|
265
|
+
CREATE TABLE IF NOT EXISTS wand_task_sessions (
|
|
266
|
+
task_id TEXT NOT NULL,
|
|
267
|
+
session_id TEXT NOT NULL,
|
|
268
|
+
bound_at TEXT NOT NULL,
|
|
269
|
+
PRIMARY KEY (task_id, session_id),
|
|
270
|
+
FOREIGN KEY (task_id) REFERENCES wand_tasks(id) ON DELETE CASCADE,
|
|
271
|
+
FOREIGN KEY (session_id) REFERENCES command_sessions(id) ON DELETE CASCADE
|
|
272
|
+
);
|
|
273
|
+
CREATE INDEX IF NOT EXISTS idx_wand_task_sessions_session ON wand_task_sessions(session_id);
|
|
274
|
+
|
|
275
|
+
CREATE TABLE IF NOT EXISTS ai_teams (
|
|
276
|
+
id TEXT PRIMARY KEY,
|
|
277
|
+
name TEXT NOT NULL,
|
|
278
|
+
description TEXT NOT NULL DEFAULT '',
|
|
279
|
+
instructions TEXT NOT NULL DEFAULT '',
|
|
280
|
+
members_json TEXT NOT NULL,
|
|
281
|
+
require_plan_approval INTEGER NOT NULL DEFAULT 1,
|
|
282
|
+
max_steps INTEGER NOT NULL DEFAULT 30,
|
|
283
|
+
created_at TEXT NOT NULL,
|
|
284
|
+
updated_at TEXT NOT NULL
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
CREATE TABLE IF NOT EXISTS silicon_employees (
|
|
288
|
+
id TEXT PRIMARY KEY,
|
|
289
|
+
name TEXT NOT NULL,
|
|
290
|
+
duty TEXT NOT NULL DEFAULT '',
|
|
291
|
+
prompt TEXT NOT NULL DEFAULT '',
|
|
292
|
+
avatar TEXT NOT NULL DEFAULT '',
|
|
293
|
+
agents_json TEXT NOT NULL,
|
|
294
|
+
system_key TEXT,
|
|
295
|
+
archived_at TEXT,
|
|
296
|
+
created_at TEXT NOT NULL,
|
|
297
|
+
updated_at TEXT NOT NULL
|
|
298
|
+
);
|
|
299
|
+
CREATE INDEX IF NOT EXISTS idx_silicon_employees_archived ON silicon_employees(archived_at);
|
|
300
|
+
|
|
301
|
+
CREATE TABLE IF NOT EXISTS employee_knowledge (
|
|
302
|
+
id TEXT PRIMARY KEY,
|
|
303
|
+
employee_id TEXT NOT NULL REFERENCES silicon_employees(id) ON DELETE CASCADE,
|
|
304
|
+
content TEXT NOT NULL,
|
|
305
|
+
content_hash TEXT NOT NULL,
|
|
306
|
+
created_at TEXT NOT NULL,
|
|
307
|
+
UNIQUE (employee_id, content_hash)
|
|
308
|
+
);
|
|
309
|
+
CREATE INDEX IF NOT EXISTS idx_employee_knowledge_owner ON employee_knowledge(employee_id, created_at);
|
|
310
|
+
CREATE TABLE IF NOT EXISTS employee_knowledge_access (
|
|
311
|
+
token_hash TEXT PRIMARY KEY,
|
|
312
|
+
employee_id TEXT NOT NULL REFERENCES silicon_employees(id) ON DELETE CASCADE,
|
|
313
|
+
session_id TEXT NOT NULL REFERENCES command_sessions(id) ON DELETE CASCADE,
|
|
314
|
+
expires_at INTEGER NOT NULL
|
|
315
|
+
);
|
|
316
|
+
CREATE INDEX IF NOT EXISTS idx_employee_knowledge_access_expiry ON employee_knowledge_access(expires_at);
|
|
317
|
+
|
|
318
|
+
CREATE TABLE IF NOT EXISTS decision_access (
|
|
319
|
+
token_hash TEXT PRIMARY KEY,
|
|
320
|
+
session_id TEXT NOT NULL REFERENCES command_sessions(id) ON DELETE CASCADE,
|
|
321
|
+
expires_at INTEGER NOT NULL
|
|
322
|
+
);
|
|
323
|
+
CREATE INDEX IF NOT EXISTS idx_decision_access_expiry ON decision_access(expires_at);
|
|
324
|
+
|
|
325
|
+
CREATE TABLE IF NOT EXISTS openrouter_free_access (
|
|
326
|
+
token_hash TEXT PRIMARY KEY,
|
|
327
|
+
session_id TEXT NOT NULL REFERENCES command_sessions(id) ON DELETE CASCADE,
|
|
328
|
+
selector TEXT NOT NULL,
|
|
329
|
+
requirements_json TEXT NOT NULL,
|
|
330
|
+
credential_hash TEXT NOT NULL,
|
|
331
|
+
expires_at INTEGER NOT NULL
|
|
332
|
+
);
|
|
333
|
+
CREATE INDEX IF NOT EXISTS idx_openrouter_free_access_expiry ON openrouter_free_access(expires_at);
|
|
334
|
+
|
|
335
|
+
CREATE TABLE IF NOT EXISTS user_memory_events (
|
|
336
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
337
|
+
feature TEXT NOT NULL,
|
|
338
|
+
text TEXT NOT NULL DEFAULT '',
|
|
339
|
+
dedup_key TEXT NOT NULL,
|
|
340
|
+
created_at INTEGER NOT NULL
|
|
341
|
+
);
|
|
342
|
+
CREATE INDEX IF NOT EXISTS idx_user_memory_events_created ON user_memory_events(created_at);
|
|
343
|
+
CREATE INDEX IF NOT EXISTS idx_user_memory_events_dedup ON user_memory_events(dedup_key, created_at);
|
|
344
|
+
CREATE TABLE IF NOT EXISTS user_memory_state (
|
|
345
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
346
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
347
|
+
revision INTEGER NOT NULL DEFAULT 0,
|
|
348
|
+
last_attempt_at INTEGER NOT NULL DEFAULT 0,
|
|
349
|
+
source_id INTEGER NOT NULL DEFAULT 0,
|
|
350
|
+
profile_json TEXT
|
|
351
|
+
);
|
|
352
|
+
INSERT OR IGNORE INTO user_memory_state (id) VALUES (1);
|
|
353
|
+
|
|
354
|
+
CREATE TABLE IF NOT EXISTS ai_team_runs (
|
|
355
|
+
id TEXT PRIMARY KEY,
|
|
356
|
+
team_id TEXT NOT NULL,
|
|
357
|
+
task_id TEXT NOT NULL,
|
|
358
|
+
team_json TEXT NOT NULL,
|
|
359
|
+
objective TEXT NOT NULL,
|
|
360
|
+
cwd TEXT NOT NULL,
|
|
361
|
+
status TEXT NOT NULL,
|
|
362
|
+
status_detail TEXT NOT NULL DEFAULT '',
|
|
363
|
+
steps_used INTEGER NOT NULL DEFAULT 0,
|
|
364
|
+
step_limit INTEGER NOT NULL,
|
|
365
|
+
format_retries INTEGER NOT NULL DEFAULT 0,
|
|
366
|
+
plan_approved INTEGER NOT NULL DEFAULT 0,
|
|
367
|
+
created_at TEXT NOT NULL,
|
|
368
|
+
updated_at TEXT NOT NULL
|
|
369
|
+
);
|
|
370
|
+
CREATE INDEX IF NOT EXISTS idx_ai_team_runs_task ON ai_team_runs(task_id, created_at);
|
|
371
|
+
CREATE INDEX IF NOT EXISTS idx_ai_team_runs_status ON ai_team_runs(status);
|
|
372
|
+
|
|
373
|
+
CREATE TABLE IF NOT EXISTS ai_team_steps (
|
|
374
|
+
id TEXT PRIMARY KEY,
|
|
375
|
+
run_id TEXT NOT NULL,
|
|
376
|
+
seq INTEGER NOT NULL,
|
|
377
|
+
kind TEXT NOT NULL,
|
|
378
|
+
member_id TEXT NOT NULL,
|
|
379
|
+
title TEXT NOT NULL,
|
|
380
|
+
instructions TEXT NOT NULL,
|
|
381
|
+
session_id TEXT,
|
|
382
|
+
status TEXT NOT NULL,
|
|
383
|
+
report TEXT NOT NULL DEFAULT '',
|
|
384
|
+
report_path TEXT NOT NULL,
|
|
385
|
+
depends_on_json TEXT NOT NULL DEFAULT '[]',
|
|
386
|
+
started_at TEXT,
|
|
387
|
+
ended_at TEXT,
|
|
388
|
+
UNIQUE (run_id, seq)
|
|
389
|
+
);
|
|
390
|
+
CREATE INDEX IF NOT EXISTS idx_ai_team_steps_session ON ai_team_steps(session_id, status);
|
|
391
|
+
`;
|
|
392
|
+
/** AI 团队表的后加列;只加不删,历史行取默认值。 */
|
|
393
|
+
function ensureAiTeamSchema(db) {
|
|
394
|
+
const teamColumns = new Set(db.prepare("PRAGMA table_info(ai_teams)").all().map((column) => column.name));
|
|
395
|
+
if (!teamColumns.has("instructions"))
|
|
396
|
+
db.exec("ALTER TABLE ai_teams ADD COLUMN instructions TEXT NOT NULL DEFAULT ''");
|
|
397
|
+
const stepColumns = new Set(db.prepare("PRAGMA table_info(ai_team_steps)").all().map((column) => column.name));
|
|
398
|
+
if (!stepColumns.has("depends_on_json"))
|
|
399
|
+
db.exec("ALTER TABLE ai_team_steps ADD COLUMN depends_on_json TEXT NOT NULL DEFAULT '[]'");
|
|
400
|
+
const runColumns = new Set(db.prepare("PRAGMA table_info(ai_team_runs)").all().map((column) => column.name));
|
|
401
|
+
if (!runColumns.has("chat_session_id"))
|
|
402
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN chat_session_id TEXT");
|
|
403
|
+
if (!runColumns.has("pending_notes_json"))
|
|
404
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN pending_notes_json TEXT NOT NULL DEFAULT '[]'");
|
|
405
|
+
// v2 多候选降级:步骤实际候选与跳过记录(StepDispatchInfo)、run 级状态(黑名单等)。只加列,旧行取默认 '{}'。
|
|
406
|
+
if (!stepColumns.has("dispatch_info_json"))
|
|
407
|
+
db.exec("ALTER TABLE ai_team_steps ADD COLUMN dispatch_info_json TEXT NOT NULL DEFAULT '{}'");
|
|
408
|
+
if (!runColumns.has("run_state_json"))
|
|
409
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN run_state_json TEXT NOT NULL DEFAULT '{}'");
|
|
410
|
+
// 硅基员工表结构保护(遵循只加不删)
|
|
411
|
+
db.exec(`
|
|
412
|
+
CREATE TABLE IF NOT EXISTS silicon_employees (
|
|
413
|
+
id TEXT PRIMARY KEY,
|
|
414
|
+
name TEXT NOT NULL,
|
|
415
|
+
duty TEXT NOT NULL DEFAULT '',
|
|
416
|
+
prompt TEXT NOT NULL DEFAULT '',
|
|
417
|
+
avatar TEXT NOT NULL DEFAULT '',
|
|
418
|
+
agents_json TEXT NOT NULL,
|
|
419
|
+
system_key TEXT,
|
|
420
|
+
archived_at TEXT,
|
|
421
|
+
created_at TEXT NOT NULL,
|
|
422
|
+
updated_at TEXT NOT NULL
|
|
423
|
+
);
|
|
424
|
+
CREATE INDEX IF NOT EXISTS idx_silicon_employees_archived ON silicon_employees(archived_at);
|
|
425
|
+
`);
|
|
426
|
+
// 内置员工标记(如 "wand-ops"):只加列,用户员工保持 NULL。
|
|
427
|
+
const employeeColumns = new Set(db.prepare("PRAGMA table_info(silicon_employees)").all().map((column) => column.name));
|
|
428
|
+
if (employeeColumns.size > 0 && !employeeColumns.has("system_key")) {
|
|
429
|
+
db.exec("ALTER TABLE silicon_employees ADD COLUMN system_key TEXT");
|
|
430
|
+
}
|
|
431
|
+
if (employeeColumns.size > 0 && !employeeColumns.has("tags_json")) {
|
|
432
|
+
db.exec("ALTER TABLE silicon_employees ADD COLUMN tags_json TEXT NOT NULL DEFAULT '[]'");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function ensureWandTaskSchema(db) {
|
|
436
|
+
const columns = db.prepare("PRAGMA table_info(wand_tasks)").all();
|
|
437
|
+
const names = new Set(columns.map((column) => column.name));
|
|
438
|
+
if (columns.length > 0 && !names.has("identifier"))
|
|
439
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN identifier TEXT");
|
|
440
|
+
if (columns.length > 0 && !names.has("due_date"))
|
|
441
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN due_date TEXT");
|
|
442
|
+
// 任务的默认派发配置(CLI 工具 / 模型 / 思考深度)。只加列,历史行保持 NULL。
|
|
443
|
+
if (columns.length > 0 && !names.has("agent_json"))
|
|
444
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN agent_json TEXT");
|
|
445
|
+
if (columns.length > 0 && !names.has("execution_subject_json"))
|
|
446
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN execution_subject_json TEXT");
|
|
447
|
+
if (columns.length > 0 && !names.has("workspace_task_id"))
|
|
448
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN workspace_task_id TEXT");
|
|
449
|
+
// 父任务归属只加列;历史任务仍然是顶层任务。
|
|
450
|
+
if (columns.length > 0 && !names.has("parent_task_id"))
|
|
451
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN parent_task_id TEXT");
|
|
452
|
+
// 标题来源:'user' = 用户手写,'auto' = 由描述/会话内容自动生成。只加列,历史行保持 NULL(读取时视为 user)。
|
|
453
|
+
if (columns.length > 0 && !names.has("title_source"))
|
|
454
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN title_source TEXT");
|
|
455
|
+
// 自动标题最近一次的输入指纹:内容没变就不再重复总结(也避免自动标题来回震荡)。只加列。
|
|
456
|
+
if (columns.length > 0 && !names.has("auto_title_signature"))
|
|
457
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN auto_title_signature TEXT");
|
|
458
|
+
// 里程碑:只加列,历史行保持 NULL;里程碑本体在 wand_milestones(INIT_SQL 建表)。
|
|
459
|
+
if (columns.length > 0 && !names.has("milestone_id"))
|
|
460
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN milestone_id TEXT");
|
|
461
|
+
// 归档时间(自动/手动归档都写它):任务自动删除按它起算;历史归档行保持 NULL。
|
|
462
|
+
if (columns.length > 0 && !names.has("archived_at"))
|
|
463
|
+
db.exec("ALTER TABLE wand_tasks ADD COLUMN archived_at TEXT");
|
|
464
|
+
if (columns.length > 0) {
|
|
465
|
+
// Index creation must wait until the column exists on legacy databases.
|
|
466
|
+
// INIT_SQL cannot create it: CREATE TABLE IF NOT EXISTS is a no-op on old
|
|
467
|
+
// wand_tasks, and CREATE INDEX would then fail with "no such column".
|
|
468
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_tasks_workspace_task ON wand_tasks(workspace_task_id)");
|
|
469
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_tasks_parent ON wand_tasks(parent_task_id)");
|
|
470
|
+
const rows = db.prepare("SELECT id FROM wand_tasks WHERE identifier IS NULL OR identifier = '' ORDER BY created_at, id").all();
|
|
471
|
+
const update = db.prepare("UPDATE wand_tasks SET identifier = ? WHERE id = ?");
|
|
472
|
+
rows.forEach((row, index) => update.run(`TASK-${index + 1}`, row.id));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function ensureWorkspaceSchema(db) {
|
|
476
|
+
const workspaceColumns = db.prepare("PRAGMA table_info(workspaces)").all();
|
|
477
|
+
const workspaceNames = new Set(workspaceColumns.map((column) => column.name));
|
|
478
|
+
if (workspaceColumns.length > 0 && !workspaceNames.has("kind")) {
|
|
479
|
+
db.exec("ALTER TABLE workspaces ADD COLUMN kind TEXT NOT NULL DEFAULT 'project'");
|
|
480
|
+
}
|
|
481
|
+
const taskColumns = db.prepare("PRAGMA table_info(workspace_tasks)").all();
|
|
482
|
+
const taskNames = new Set(taskColumns.map((column) => column.name));
|
|
483
|
+
if (taskColumns.length > 0 && !taskNames.has("cwd")) {
|
|
484
|
+
db.exec("ALTER TABLE workspace_tasks ADD COLUMN cwd TEXT");
|
|
485
|
+
}
|
|
486
|
+
if (taskColumns.length > 0 && !taskNames.has("layout_revision")) {
|
|
487
|
+
db.exec("ALTER TABLE workspace_tasks ADD COLUMN layout_revision INTEGER NOT NULL DEFAULT 0");
|
|
488
|
+
}
|
|
489
|
+
// 侧栏任务也记里程碑:建任务时把它带到看板卡片上,命名任务与未命名任务保持一致。
|
|
490
|
+
if (taskColumns.length > 0 && !taskNames.has("milestone_id")) {
|
|
491
|
+
db.exec("ALTER TABLE workspace_tasks ADD COLUMN milestone_id TEXT");
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function ensureWandMilestoneSchema(db) {
|
|
495
|
+
const columns = db.prepare("PRAGMA table_info(wand_milestones)").all();
|
|
496
|
+
const names = new Set(columns.map((column) => column.name));
|
|
497
|
+
// 里程碑归属工作区:只加列,历史行保持 NULL(读作全局里程碑,所有工作区可见)。
|
|
498
|
+
if (columns.length > 0 && !names.has("workspace_id")) {
|
|
499
|
+
db.exec("ALTER TABLE wand_milestones ADD COLUMN workspace_id TEXT");
|
|
500
|
+
}
|
|
501
|
+
// 默认迭代标记:只加列,历史行保持 0(读作普通迭代)。
|
|
502
|
+
if (columns.length > 0 && !names.has("is_default")) {
|
|
503
|
+
db.exec("ALTER TABLE wand_milestones ADD COLUMN is_default INTEGER NOT NULL DEFAULT 0");
|
|
504
|
+
}
|
|
505
|
+
if (columns.length > 0) {
|
|
506
|
+
// 索引必须等列存在后再建:老库的 CREATE TABLE IF NOT EXISTS 是空操作,
|
|
507
|
+
// 直接在 INIT_SQL 里建索引会因缺列报错。
|
|
508
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_milestones_workspace ON wand_milestones(workspace_id, created_at DESC)");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* 迭代提示词记录表:新库由 INIT_SQL 建好,老库在这里补建(只加表,不改表)。
|
|
513
|
+
* 空库(没建过任何表)时 PRAGMA 拿不到列,直接返回。
|
|
514
|
+
*/
|
|
515
|
+
function ensureIterationPromptSchema(db) {
|
|
516
|
+
const columns = db.prepare("PRAGMA table_info(wand_iteration_prompts)").all();
|
|
517
|
+
if (columns.length > 0)
|
|
518
|
+
return;
|
|
519
|
+
db.exec(`
|
|
520
|
+
CREATE TABLE IF NOT EXISTS wand_iteration_prompts (
|
|
521
|
+
id TEXT PRIMARY KEY,
|
|
522
|
+
milestone_id TEXT NOT NULL,
|
|
523
|
+
workspace_id TEXT,
|
|
524
|
+
session_id TEXT,
|
|
525
|
+
task_id TEXT,
|
|
526
|
+
repo_key TEXT,
|
|
527
|
+
cwd TEXT NOT NULL,
|
|
528
|
+
title TEXT NOT NULL,
|
|
529
|
+
detail TEXT NOT NULL DEFAULT '',
|
|
530
|
+
source TEXT NOT NULL DEFAULT 'session',
|
|
531
|
+
consumed_at TEXT,
|
|
532
|
+
consumed_commit TEXT,
|
|
533
|
+
created_at TEXT NOT NULL
|
|
534
|
+
)
|
|
535
|
+
`);
|
|
536
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_iteration ON wand_iteration_prompts(milestone_id, created_at DESC)");
|
|
537
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_repo ON wand_iteration_prompts(repo_key, created_at DESC)");
|
|
538
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_wand_iteration_prompts_session ON wand_iteration_prompts(session_id, created_at DESC)");
|
|
539
|
+
}
|
|
540
|
+
function ensureConnectorSchema(db) {
|
|
541
|
+
// The table is created by INIT_SQL for new databases; this repairs an
|
|
542
|
+
// existing wand.db that predates the connector feature (additive-only).
|
|
543
|
+
const columns = db.prepare("PRAGMA table_info(connectors)").all();
|
|
544
|
+
const names = new Set(columns.map((column) => column.name));
|
|
545
|
+
if (names.size === 0)
|
|
546
|
+
return;
|
|
547
|
+
const migrations = [
|
|
548
|
+
["api_url", "ALTER TABLE connectors ADD COLUMN api_url TEXT NOT NULL DEFAULT ''"],
|
|
549
|
+
["username", "ALTER TABLE connectors ADD COLUMN username TEXT"],
|
|
550
|
+
["connected_at", "ALTER TABLE connectors ADD COLUMN connected_at TEXT"],
|
|
551
|
+
];
|
|
552
|
+
for (const [column, sql] of migrations) {
|
|
553
|
+
if (!names.has(column))
|
|
554
|
+
db.exec(sql);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
const SCHEMA_MIGRATIONS = [
|
|
558
|
+
["session_source", "ALTER TABLE command_sessions ADD COLUMN session_source TEXT NOT NULL DEFAULT 'interactive'"],
|
|
559
|
+
["automation_id", "ALTER TABLE command_sessions ADD COLUMN automation_id TEXT"],
|
|
560
|
+
["archived", "ALTER TABLE command_sessions ADD COLUMN archived INTEGER NOT NULL DEFAULT 0"],
|
|
561
|
+
["archived_at", "ALTER TABLE command_sessions ADD COLUMN archived_at TEXT"],
|
|
562
|
+
["claude_session_id", "ALTER TABLE command_sessions ADD COLUMN claude_session_id TEXT"],
|
|
563
|
+
["provider", "ALTER TABLE command_sessions ADD COLUMN provider TEXT"],
|
|
564
|
+
["session_kind", "ALTER TABLE command_sessions ADD COLUMN session_kind TEXT NOT NULL DEFAULT 'pty'"],
|
|
565
|
+
["runner", "ALTER TABLE command_sessions ADD COLUMN runner TEXT"],
|
|
566
|
+
["messages", "ALTER TABLE command_sessions ADD COLUMN messages TEXT"],
|
|
567
|
+
["queued_messages", "ALTER TABLE command_sessions ADD COLUMN queued_messages TEXT"],
|
|
568
|
+
["queued_message_skills", "ALTER TABLE command_sessions ADD COLUMN queued_message_skills TEXT"],
|
|
569
|
+
["structured_state", "ALTER TABLE command_sessions ADD COLUMN structured_state TEXT"],
|
|
570
|
+
["resumed_from_session_id", "ALTER TABLE command_sessions ADD COLUMN resumed_from_session_id TEXT"],
|
|
571
|
+
// Legacy column: never written by current persist helpers. Kept because
|
|
572
|
+
// schema migrations are additive-only and must not DROP columns.
|
|
573
|
+
["resumed_to_session_id", "ALTER TABLE command_sessions ADD COLUMN resumed_to_session_id TEXT"],
|
|
574
|
+
["auto_recovered", "ALTER TABLE command_sessions ADD COLUMN auto_recovered INTEGER NOT NULL DEFAULT 0"],
|
|
575
|
+
["worktree_enabled", "ALTER TABLE command_sessions ADD COLUMN worktree_enabled INTEGER NOT NULL DEFAULT 0"],
|
|
576
|
+
["worktree_info", "ALTER TABLE command_sessions ADD COLUMN worktree_info TEXT"],
|
|
577
|
+
["worktree_merge_status", "ALTER TABLE command_sessions ADD COLUMN worktree_merge_status TEXT"],
|
|
578
|
+
["worktree_merge_info", "ALTER TABLE command_sessions ADD COLUMN worktree_merge_info TEXT"],
|
|
579
|
+
["title", "ALTER TABLE command_sessions ADD COLUMN title TEXT"],
|
|
580
|
+
["description", "ALTER TABLE command_sessions ADD COLUMN description TEXT"],
|
|
581
|
+
["pty_output_seq", "ALTER TABLE command_sessions ADD COLUMN pty_output_seq INTEGER NOT NULL DEFAULT 0"],
|
|
582
|
+
["session_options", `ALTER TABLE command_sessions ADD COLUMN session_options TEXT NOT NULL DEFAULT '{"schemaVersion":1}'`],
|
|
583
|
+
["workspace_id", "ALTER TABLE command_sessions ADD COLUMN workspace_id TEXT"],
|
|
584
|
+
["workspace_task_id", "ALTER TABLE command_sessions ADD COLUMN workspace_task_id TEXT"],
|
|
585
|
+
["completion_revision", "ALTER TABLE command_sessions ADD COLUMN completion_revision INTEGER NOT NULL DEFAULT 0"],
|
|
586
|
+
["viewed_completion_revision", "ALTER TABLE command_sessions ADD COLUMN viewed_completion_revision INTEGER NOT NULL DEFAULT 0"],
|
|
587
|
+
];
|
|
588
|
+
const AUTH_SESSION_MIGRATIONS = [
|
|
589
|
+
["kind", "ALTER TABLE auth_sessions ADD COLUMN kind TEXT NOT NULL DEFAULT 'browser-admin'"],
|
|
590
|
+
["scopes", `ALTER TABLE auth_sessions ADD COLUMN scopes TEXT NOT NULL DEFAULT '["admin"]'`],
|
|
591
|
+
];
|
|
592
|
+
function ensureAuthSessionSchema(db) {
|
|
593
|
+
const columns = db.prepare("PRAGMA table_info(auth_sessions)").all();
|
|
594
|
+
const names = new Set(columns.map((column) => column.name));
|
|
595
|
+
for (const [column, sql] of AUTH_SESSION_MIGRATIONS) {
|
|
596
|
+
if (!names.has(column))
|
|
597
|
+
db.exec(sql);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function ensureCommandSessionSchema(db) {
|
|
601
|
+
const columns = db.prepare("PRAGMA table_info(command_sessions)").all();
|
|
602
|
+
const names = new Set(columns.map((column) => column.name));
|
|
603
|
+
for (const [column, sql] of SCHEMA_MIGRATIONS) {
|
|
604
|
+
if (!names.has(column)) {
|
|
605
|
+
db.exec(sql);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (columns.length > 0) {
|
|
609
|
+
// 侧栏 / 任务面板按 workspace_task_id 反复拉会话:没有索引时每次都是
|
|
610
|
+
// 46MB 表全扫(单次 ~500ms),而 command_sessions 里有 10MB+ 的 output/
|
|
611
|
+
// messages 溢出行。索引只加不删,老库首次启动时建一次。
|
|
612
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_command_sessions_workspace_task ON command_sessions(workspace_task_id)");
|
|
613
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_command_sessions_workspace ON command_sessions(workspace_id)");
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
export function initializeStorageSchema(db) {
|
|
617
|
+
db.exec(INIT_SQL);
|
|
618
|
+
db.exec(`
|
|
619
|
+
CREATE TABLE IF NOT EXISTS scheduled_tasks (
|
|
620
|
+
id TEXT PRIMARY KEY, enabled INTEGER NOT NULL, next_run_at TEXT, revision INTEGER NOT NULL,
|
|
621
|
+
cancelled_at TEXT, task_json TEXT NOT NULL
|
|
622
|
+
);
|
|
623
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_due ON scheduled_tasks(enabled, next_run_at);
|
|
624
|
+
CREATE TABLE IF NOT EXISTS scheduled_task_runs (
|
|
625
|
+
id TEXT PRIMARY KEY, task_id TEXT NOT NULL, scheduled_at TEXT NOT NULL, run_json TEXT NOT NULL,
|
|
626
|
+
UNIQUE(task_id, scheduled_at)
|
|
627
|
+
);
|
|
628
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_task_runs ON scheduled_task_runs(task_id, scheduled_at DESC);
|
|
629
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_task_runs_session ON scheduled_task_runs(json_extract(run_json, '$.receipt.sessionId'));
|
|
630
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_task_runs_open ON scheduled_task_runs(json_extract(run_json, '$.executionFinishedAt'), json_extract(run_json, '$.state'));
|
|
631
|
+
`);
|
|
632
|
+
ensureAuthSessionSchema(db);
|
|
633
|
+
ensureCommandSessionSchema(db);
|
|
634
|
+
ensureWorkspaceSchema(db);
|
|
635
|
+
ensureWandTaskSchema(db);
|
|
636
|
+
ensureWandMilestoneSchema(db);
|
|
637
|
+
ensureIterationPromptSchema(db);
|
|
638
|
+
ensureAiTeamSchema(db);
|
|
639
|
+
db.exec(`
|
|
640
|
+
CREATE TABLE IF NOT EXISTS conversation_list_state (
|
|
641
|
+
conversation_id TEXT PRIMARY KEY,
|
|
642
|
+
pinned_at TEXT,
|
|
643
|
+
hidden_at TEXT, dissolved_at TEXT, dissolved_by TEXT, deleting INTEGER NOT NULL DEFAULT 0
|
|
644
|
+
);
|
|
645
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
646
|
+
id TEXT PRIMARY KEY, owner TEXT NOT NULL, kind TEXT NOT NULL,
|
|
647
|
+
peer_employee_id TEXT, session_id TEXT, instance_json TEXT NOT NULL
|
|
648
|
+
);
|
|
649
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_conversation_peer ON conversations(owner, peer_employee_id)
|
|
650
|
+
WHERE kind = 'dm';
|
|
651
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_conversation_session ON conversations(session_id)
|
|
652
|
+
WHERE session_id IS NOT NULL;
|
|
653
|
+
CREATE TABLE IF NOT EXISTS conversation_tasks (
|
|
654
|
+
conversation_id TEXT NOT NULL, task_id TEXT NOT NULL UNIQUE, linked_at TEXT NOT NULL,
|
|
655
|
+
PRIMARY KEY(conversation_id, task_id)
|
|
656
|
+
);
|
|
657
|
+
CREATE TABLE IF NOT EXISTS conversation_messages (
|
|
658
|
+
id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, turn_json TEXT NOT NULL, created_at TEXT NOT NULL
|
|
659
|
+
);
|
|
660
|
+
CREATE INDEX IF NOT EXISTS idx_conversation_messages ON conversation_messages(conversation_id, created_at);
|
|
661
|
+
CREATE TABLE IF NOT EXISTS conversation_requests (
|
|
662
|
+
id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, receipt_json TEXT NOT NULL, updated_at TEXT NOT NULL
|
|
663
|
+
);
|
|
664
|
+
`);
|
|
665
|
+
const conversationListColumns = new Set(db.prepare("PRAGMA table_info(conversation_list_state)").all().map(column => column.name));
|
|
666
|
+
for (const [name, type] of [["dissolved_at", "TEXT"], ["dissolved_by", "TEXT"], ["deleting", "INTEGER NOT NULL DEFAULT 0"]]) {
|
|
667
|
+
if (!conversationListColumns.has(name))
|
|
668
|
+
db.exec(`ALTER TABLE conversation_list_state ADD COLUMN ${name} ${type}`);
|
|
669
|
+
}
|
|
670
|
+
const conversationRunColumns = new Set(db.prepare("PRAGMA table_info(ai_team_runs)").all().map((column) => column.name));
|
|
671
|
+
if (!conversationRunColumns.has("conversation_id"))
|
|
672
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN conversation_id TEXT");
|
|
673
|
+
if (!conversationRunColumns.has("member_version"))
|
|
674
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN member_version INTEGER");
|
|
675
|
+
if (!conversationRunColumns.has("round_number"))
|
|
676
|
+
db.exec("ALTER TABLE ai_team_runs ADD COLUMN round_number INTEGER");
|
|
677
|
+
ensureConnectorSchema(db);
|
|
678
|
+
{
|
|
679
|
+
const missionColumns = db.prepare("PRAGMA table_info(missions)").all();
|
|
680
|
+
if (missionColumns.length > 0 && !missionColumns.some((column) => column.name === "task_id")) {
|
|
681
|
+
db.exec("ALTER TABLE missions ADD COLUMN task_id TEXT");
|
|
682
|
+
}
|
|
683
|
+
// 并行任务的里程碑与看板共用同一份列表;只加列,历史行保持 NULL。
|
|
684
|
+
if (missionColumns.length > 0 && !missionColumns.some((column) => column.name === "milestone_id")) {
|
|
685
|
+
db.exec("ALTER TABLE missions ADD COLUMN milestone_id TEXT");
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
export function ensureDatabaseFile(dbPath) {
|
|
690
|
+
const dir = path.dirname(dbPath);
|
|
691
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
692
|
+
chmodSync(dir, 0o700);
|
|
693
|
+
const created = !existsSync(dbPath);
|
|
694
|
+
const db = new DatabaseSync(dbPath);
|
|
695
|
+
// DDL below takes the write lock; without this a concurrent CLI/Server writer
|
|
696
|
+
// aborts startup with SQLITE_BUSY instead of waiting its turn.
|
|
697
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
698
|
+
initializeStorageSchema(db);
|
|
699
|
+
db.close();
|
|
700
|
+
chmodSync(dbPath, 0o600);
|
|
701
|
+
return created;
|
|
702
|
+
}
|