@gavinc-cn/touchstone-dsh 0.1.1 → 0.3.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 +39 -11
- package/README.zh.md +25 -10
- package/backend/lib/access.js +44 -0
- package/backend/lib/agents.js +341 -0
- package/backend/lib/args.js +94 -0
- package/backend/lib/auth.js +195 -0
- package/backend/lib/board.js +6154 -0
- package/backend/lib/builtin-assets.js +1177 -0
- package/backend/lib/casescan.js +456 -0
- package/backend/lib/chat.js +2053 -0
- package/backend/lib/cookie.js +76 -0
- package/backend/lib/db.js +2260 -0
- package/backend/lib/dshdriver.js +1148 -0
- package/backend/lib/dshevents.js +851 -0
- package/backend/lib/export-cases.js +261 -0
- package/backend/lib/feishu.js +1738 -0
- package/backend/lib/feishu_cfg.js +228 -0
- package/backend/lib/feishu_conv.js +1484 -0
- package/backend/lib/feishu_device.js +428 -0
- package/backend/lib/feishu_inbound.js +1674 -0
- package/backend/lib/feishu_provision.js +855 -0
- package/backend/lib/feishu_rest.js +398 -0
- package/backend/lib/feishu_slash.js +568 -0
- package/backend/lib/feishu_ws.js +950 -0
- package/backend/lib/http.js +312 -0
- package/backend/lib/lib.js +973 -0
- package/backend/lib/loadcase.js +749 -0
- package/backend/lib/loadgen.js +1407 -0
- package/backend/lib/localbus.js +164 -0
- package/backend/lib/lock.js +405 -0
- package/backend/lib/proc.js +278 -0
- package/backend/lib/prompts.js +1021 -0
- package/backend/lib/pybase64.js +114 -0
- package/backend/lib/pyjson.js +214 -0
- package/backend/lib/query.js +125 -0
- package/backend/lib/rag.js +1310 -0
- package/backend/lib/runner.js +4520 -0
- package/backend/lib/servercaps.js +182 -0
- package/backend/lib/serverstate.js +237 -0
- package/backend/lib/sessparse.js +1176 -0
- package/backend/lib/sse.js +207 -0
- package/backend/lib/static.js +84 -0
- package/backend/lib/taskjson.js +302 -0
- package/backend/lib/waitq.js +2114 -0
- package/backend/lib/worktree.js +588 -0
- package/backend/lib/zstd-frames.js +218 -0
- package/backend/routes/admin.js +553 -0
- package/backend/routes/agents.js +149 -0
- package/backend/routes/assets.js +145 -0
- package/backend/routes/board.js +1220 -0
- package/backend/routes/feishu.js +269 -0
- package/backend/routes/feishu_app.js +215 -0
- package/backend/routes/feishu_hook.js +358 -0
- package/backend/routes/index.js +297 -0
- package/backend/routes/projects.js +1059 -0
- package/backend/routes/sessions.js +946 -0
- package/backend/routes/tasks.js +1530 -0
- package/backend/schema/fixtures/ancient.sql +189 -0
- package/backend/schema/fixtures/pre_alter.sql +177 -0
- package/backend/schema/migrations.json +154 -0
- package/backend/schema/schema.json +1451 -0
- package/backend/schema/schema.sql +216 -0
- package/backend/server.js +498 -0
- package/board.py +805 -72
- package/chat.py +590 -17
- package/db.py +356 -140
- package/dsh-plugin/cordis.patch.yml +7 -3
- package/dsh-plugin/install.sh +28 -11
- package/dsh-plugin/lib/agent-driver.js +710 -89
- package/dsh-plugin/lib/client.bundle.js +94 -9
- package/dsh-plugin/lib/index.js +529 -39
- package/dsh-plugin/lib/pack-closure.mjs +291 -0
- package/dsh-plugin/scripts/prepack-check.mjs +30 -2
- package/dsh-plugin/src/client.js +94 -9
- package/dshdriver.py +74 -5
- package/dshevents.py +65 -3
- package/feishu.py +1197 -34
- package/feishu_conv.py +920 -0
- package/lifecycle.py +116 -13
- package/package.json +6 -1
- package/requirements.txt +2 -1
- package/server.py +218 -26
- package/sessparse.py +150 -44
- package/touchstone.py +6 -3
- package/waitq.py +23 -0
- package/webui/dist-plugin/assets/index-ChP3sg6y.css +1 -0
- package/webui/dist-plugin/assets/index-UrMyeAXF.js +484 -0
- package/webui/dist-plugin/index.html +2 -2
- package/webui/dist-plugin/assets/index-B0WoP1Qy.css +0 -1
- package/webui/dist-plugin/assets/index-DtwKoi1T.js +0 -473
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
-- 由 tools/export_schema.py 从 db.py 生成,请勿手改。改 db.py 后重跑导出。
|
|
2
|
+
-- 旧库夹具②:更老的年代
|
|
3
|
+
|
|
4
|
+
CREATE TABLE users (
|
|
5
|
+
id INTEGER PRIMARY KEY,
|
|
6
|
+
username TEXT NOT NULL,
|
|
7
|
+
pass_hash TEXT NOT NULL,
|
|
8
|
+
salt TEXT NOT NULL,
|
|
9
|
+
created_at TEXT NOT NULL,
|
|
10
|
+
UNIQUE (username)
|
|
11
|
+
);
|
|
12
|
+
CREATE TABLE sessions (
|
|
13
|
+
token TEXT PRIMARY KEY,
|
|
14
|
+
user_id INTEGER NOT NULL,
|
|
15
|
+
created_at TEXT NOT NULL,
|
|
16
|
+
expires_at TEXT NOT NULL
|
|
17
|
+
);
|
|
18
|
+
CREATE TABLE projects (
|
|
19
|
+
id INTEGER PRIMARY KEY,
|
|
20
|
+
user_id INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
name TEXT NOT NULL,
|
|
22
|
+
project_dir TEXT NOT NULL,
|
|
23
|
+
agent_path TEXT NOT NULL DEFAULT '',
|
|
24
|
+
work_dir TEXT NOT NULL,
|
|
25
|
+
bug_dir TEXT NOT NULL,
|
|
26
|
+
guide_text TEXT NOT NULL DEFAULT '',
|
|
27
|
+
commit_spec TEXT NOT NULL DEFAULT '',
|
|
28
|
+
deploy_spec TEXT NOT NULL DEFAULT '',
|
|
29
|
+
env_label TEXT NOT NULL DEFAULT '',
|
|
30
|
+
created_at TEXT NOT NULL,
|
|
31
|
+
UNIQUE (name)
|
|
32
|
+
);
|
|
33
|
+
CREATE TABLE tasks (
|
|
34
|
+
id INTEGER PRIMARY KEY,
|
|
35
|
+
project_id INTEGER NOT NULL,
|
|
36
|
+
name TEXT NOT NULL,
|
|
37
|
+
auto_fix INTEGER NOT NULL DEFAULT 0,
|
|
38
|
+
retest TEXT NOT NULL DEFAULT '不复测',
|
|
39
|
+
stop_type TEXT NOT NULL DEFAULT 'rounds',
|
|
40
|
+
stop_value TEXT NOT NULL DEFAULT '1',
|
|
41
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
42
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
43
|
+
current_round INTEGER NOT NULL DEFAULT 0,
|
|
44
|
+
new_bugs INTEGER NOT NULL DEFAULT 0,
|
|
45
|
+
created_at TEXT NOT NULL,
|
|
46
|
+
started_at TEXT,
|
|
47
|
+
ended_at TEXT,
|
|
48
|
+
error TEXT NOT NULL DEFAULT ''
|
|
49
|
+
);
|
|
50
|
+
CREATE TABLE rounds (
|
|
51
|
+
id INTEGER PRIMARY KEY,
|
|
52
|
+
task_id INTEGER NOT NULL,
|
|
53
|
+
round_no INTEGER NOT NULL,
|
|
54
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
55
|
+
exit_code INTEGER,
|
|
56
|
+
log_path TEXT NOT NULL DEFAULT '',
|
|
57
|
+
started_at TEXT NOT NULL,
|
|
58
|
+
ended_at TEXT,
|
|
59
|
+
summary TEXT NOT NULL DEFAULT ''
|
|
60
|
+
);
|
|
61
|
+
CREATE TABLE board_cards (
|
|
62
|
+
id INTEGER PRIMARY KEY,
|
|
63
|
+
project_id INTEGER NOT NULL,
|
|
64
|
+
title TEXT NOT NULL,
|
|
65
|
+
description TEXT NOT NULL DEFAULT '',
|
|
66
|
+
column_key TEXT NOT NULL DEFAULT 'todo',
|
|
67
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
68
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
69
|
+
sessions TEXT NOT NULL DEFAULT '[]',
|
|
70
|
+
block_kind TEXT,
|
|
71
|
+
block_text TEXT NOT NULL DEFAULT '',
|
|
72
|
+
parent_card_id INTEGER,
|
|
73
|
+
readonly INTEGER NOT NULL DEFAULT 0,
|
|
74
|
+
model TEXT NOT NULL DEFAULT '',
|
|
75
|
+
scheduled_at INTEGER,
|
|
76
|
+
jira_key TEXT NOT NULL DEFAULT '',
|
|
77
|
+
last_error TEXT NOT NULL DEFAULT '',
|
|
78
|
+
last_error_at INTEGER,
|
|
79
|
+
created_at TEXT NOT NULL,
|
|
80
|
+
updated_at TEXT NOT NULL
|
|
81
|
+
);
|
|
82
|
+
CREATE TABLE board_comments (
|
|
83
|
+
id INTEGER PRIMARY KEY,
|
|
84
|
+
card_id INTEGER NOT NULL,
|
|
85
|
+
text TEXT NOT NULL,
|
|
86
|
+
sent INTEGER NOT NULL DEFAULT 0,
|
|
87
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
88
|
+
sent_text TEXT NOT NULL DEFAULT '',
|
|
89
|
+
created_at TEXT NOT NULL
|
|
90
|
+
);
|
|
91
|
+
CREATE TABLE board_settings (
|
|
92
|
+
project_id INTEGER PRIMARY KEY,
|
|
93
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
94
|
+
);
|
|
95
|
+
CREATE TABLE app_settings (
|
|
96
|
+
key TEXT PRIMARY KEY,
|
|
97
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
98
|
+
);
|
|
99
|
+
CREATE TABLE user_prefs (
|
|
100
|
+
user_id INTEGER NOT NULL,
|
|
101
|
+
project_id INTEGER NOT NULL DEFAULT 0,
|
|
102
|
+
key TEXT NOT NULL,
|
|
103
|
+
value TEXT NOT NULL DEFAULT '{}',
|
|
104
|
+
updated_at TEXT NOT NULL,
|
|
105
|
+
PRIMARY KEY (user_id, project_id, key)
|
|
106
|
+
);
|
|
107
|
+
CREATE TABLE feishu_hooks (
|
|
108
|
+
project_id INTEGER PRIMARY KEY,
|
|
109
|
+
webhook_url TEXT NOT NULL DEFAULT '',
|
|
110
|
+
webhook_secret TEXT NOT NULL DEFAULT '',
|
|
111
|
+
events TEXT NOT NULL DEFAULT 'blocked_interaction,task_failed',
|
|
112
|
+
enabled INTEGER NOT NULL DEFAULT 1
|
|
113
|
+
);
|
|
114
|
+
CREATE TABLE feishu_outbox (
|
|
115
|
+
id INTEGER PRIMARY KEY,
|
|
116
|
+
target TEXT NOT NULL,
|
|
117
|
+
secret TEXT NOT NULL DEFAULT '',
|
|
118
|
+
payload TEXT NOT NULL,
|
|
119
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
120
|
+
retries INTEGER NOT NULL DEFAULT 0,
|
|
121
|
+
next_at REAL NOT NULL DEFAULT 0,
|
|
122
|
+
dedup_key TEXT NOT NULL DEFAULT '',
|
|
123
|
+
last_error TEXT NOT NULL DEFAULT '',
|
|
124
|
+
created_at TEXT NOT NULL
|
|
125
|
+
);
|
|
126
|
+
CREATE TABLE feishu_user_cfgs (
|
|
127
|
+
user_id INTEGER PRIMARY KEY,
|
|
128
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
129
|
+
);
|
|
130
|
+
CREATE TABLE feishu_bindings (
|
|
131
|
+
open_id TEXT PRIMARY KEY,
|
|
132
|
+
user_id INTEGER NOT NULL,
|
|
133
|
+
default_project_id INTEGER NOT NULL DEFAULT 0,
|
|
134
|
+
bound_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
|
|
135
|
+
UNIQUE (user_id)
|
|
136
|
+
);
|
|
137
|
+
CREATE TABLE wait_items (
|
|
138
|
+
id INTEGER PRIMARY KEY,
|
|
139
|
+
project_id INTEGER NOT NULL,
|
|
140
|
+
kind TEXT NOT NULL,
|
|
141
|
+
target_id TEXT NOT NULL,
|
|
142
|
+
state TEXT NOT NULL DEFAULT 'waiting',
|
|
143
|
+
seq INTEGER NOT NULL,
|
|
144
|
+
created_at TEXT NOT NULL,
|
|
145
|
+
claimed_at TEXT,
|
|
146
|
+
claimed_by TEXT,
|
|
147
|
+
ended_at TEXT,
|
|
148
|
+
not_before REAL NOT NULL DEFAULT 0,
|
|
149
|
+
retries INTEGER NOT NULL DEFAULT 0,
|
|
150
|
+
meta TEXT NOT NULL DEFAULT '{}'
|
|
151
|
+
);
|
|
152
|
+
CREATE TABLE chat_msgs (
|
|
153
|
+
id TEXT PRIMARY KEY,
|
|
154
|
+
project_id INTEGER NOT NULL,
|
|
155
|
+
sid TEXT NOT NULL,
|
|
156
|
+
task_id INTEGER,
|
|
157
|
+
card_id INTEGER,
|
|
158
|
+
message TEXT NOT NULL,
|
|
159
|
+
state TEXT NOT NULL,
|
|
160
|
+
error TEXT NOT NULL DEFAULT '',
|
|
161
|
+
inject INTEGER NOT NULL DEFAULT 0,
|
|
162
|
+
created_at INTEGER NOT NULL,
|
|
163
|
+
started_at INTEGER,
|
|
164
|
+
ended_at INTEGER
|
|
165
|
+
);
|
|
166
|
+
CREATE TABLE leases (
|
|
167
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
168
|
+
kind TEXT NOT NULL,
|
|
169
|
+
target_id TEXT NOT NULL,
|
|
170
|
+
acquired REAL NOT NULL DEFAULT 0,
|
|
171
|
+
note TEXT NOT NULL DEFAULT '{}'
|
|
172
|
+
);
|
|
173
|
+
CREATE INDEX idx_leases_project ON leases(target_id);
|
|
174
|
+
CREATE INDEX idx_tasks_project ON tasks(project_id);
|
|
175
|
+
CREATE INDEX idx_rounds_task ON rounds(task_id);
|
|
176
|
+
CREATE INDEX idx_board_cards_project ON board_cards(project_id);
|
|
177
|
+
CREATE INDEX idx_board_comments_card ON board_comments(card_id);
|
|
178
|
+
CREATE UNIQUE INDEX idx_wait_active ON wait_items(kind, target_id) WHERE state IN ('waiting','claimed','running','finishing');
|
|
179
|
+
CREATE INDEX idx_wait_pick ON wait_items(state, project_id, seq);
|
|
180
|
+
CREATE INDEX idx_chat_msgs_sid ON chat_msgs(sid, created_at);
|
|
181
|
+
|
|
182
|
+
-- 种子数据
|
|
183
|
+
INSERT INTO users(id, username, pass_hash, salt, created_at) VALUES(1, 'admin', 'd41d8cd98f00b204e9800998ecf8427e', '', '2026-01-01 00:00:00');
|
|
184
|
+
INSERT INTO projects(id, name, project_dir, work_dir, bug_dir, commit_spec, deploy_spec, created_at, user_id) VALUES(1, 'proj_one', '/tmp/ts-fixture/proj', '/tmp/ts-fixture/proj/free_style', '/tmp/ts-fixture/proj/free_style/bug_report', 'fix: 老规范', '部署:老说明', '2026-01-01 00:00:00', 0);
|
|
185
|
+
INSERT INTO tasks(id, project_id, name, created_at) VALUES(1, 1, 't1', '2026-01-01 00:00:00');
|
|
186
|
+
INSERT INTO board_cards(updated_at, id, project_id, title, created_at, column_key, block_kind, block_text, last_error) VALUES('x', 1, 1, 'legacy card', '2026-01-01 00:00:00', 'blocked', 'queue', '提交中:老机器文案', '阻塞让行提交失败 x');
|
|
187
|
+
INSERT INTO wait_items(seq, created_at, kind, target_id, project_id, state) VALUES(0, 'x', 'card', 'c:1', 1, 'claimed');
|
|
188
|
+
INSERT INTO leases(kind, target_id) VALUES('card', 'c:old');
|
|
189
|
+
INSERT INTO app_settings(key, json) VALUES('feishu', '{"app_id": "cli_legacy", "app_secret": "sec_legacy", "base_url": "https://open.feishu.cn"}');
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
-- 由 tools/export_schema.py 从 db.py 生成,请勿手改。改 db.py 后重跑导出。
|
|
2
|
+
-- 旧库夹具①:缺 ALTER 补列
|
|
3
|
+
|
|
4
|
+
CREATE TABLE users (
|
|
5
|
+
id INTEGER PRIMARY KEY,
|
|
6
|
+
username TEXT NOT NULL,
|
|
7
|
+
pass_hash TEXT NOT NULL,
|
|
8
|
+
salt TEXT NOT NULL,
|
|
9
|
+
created_at TEXT NOT NULL,
|
|
10
|
+
UNIQUE (username)
|
|
11
|
+
);
|
|
12
|
+
CREATE TABLE sessions (
|
|
13
|
+
token TEXT PRIMARY KEY,
|
|
14
|
+
user_id INTEGER NOT NULL,
|
|
15
|
+
created_at TEXT NOT NULL,
|
|
16
|
+
expires_at TEXT NOT NULL
|
|
17
|
+
);
|
|
18
|
+
CREATE TABLE projects (
|
|
19
|
+
id INTEGER PRIMARY KEY,
|
|
20
|
+
user_id INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
name TEXT NOT NULL,
|
|
22
|
+
project_dir TEXT NOT NULL,
|
|
23
|
+
agent_path TEXT NOT NULL DEFAULT '',
|
|
24
|
+
work_dir TEXT NOT NULL,
|
|
25
|
+
bug_dir TEXT NOT NULL,
|
|
26
|
+
guide_text TEXT NOT NULL DEFAULT '',
|
|
27
|
+
commit_spec TEXT NOT NULL DEFAULT '',
|
|
28
|
+
deploy_spec TEXT NOT NULL DEFAULT '',
|
|
29
|
+
env_label TEXT NOT NULL DEFAULT '',
|
|
30
|
+
created_at TEXT NOT NULL
|
|
31
|
+
);
|
|
32
|
+
CREATE TABLE tasks (
|
|
33
|
+
id INTEGER PRIMARY KEY,
|
|
34
|
+
project_id INTEGER NOT NULL,
|
|
35
|
+
name TEXT NOT NULL,
|
|
36
|
+
auto_fix INTEGER NOT NULL DEFAULT 0,
|
|
37
|
+
retest TEXT NOT NULL DEFAULT '不复测',
|
|
38
|
+
stop_type TEXT NOT NULL DEFAULT 'rounds',
|
|
39
|
+
stop_value TEXT NOT NULL DEFAULT '1',
|
|
40
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
41
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
42
|
+
current_round INTEGER NOT NULL DEFAULT 0,
|
|
43
|
+
new_bugs INTEGER NOT NULL DEFAULT 0,
|
|
44
|
+
created_at TEXT NOT NULL,
|
|
45
|
+
started_at TEXT,
|
|
46
|
+
ended_at TEXT,
|
|
47
|
+
error TEXT NOT NULL DEFAULT ''
|
|
48
|
+
);
|
|
49
|
+
CREATE TABLE rounds (
|
|
50
|
+
id INTEGER PRIMARY KEY,
|
|
51
|
+
task_id INTEGER NOT NULL,
|
|
52
|
+
round_no INTEGER NOT NULL,
|
|
53
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
54
|
+
exit_code INTEGER,
|
|
55
|
+
log_path TEXT NOT NULL DEFAULT '',
|
|
56
|
+
started_at TEXT NOT NULL,
|
|
57
|
+
ended_at TEXT,
|
|
58
|
+
summary TEXT NOT NULL DEFAULT ''
|
|
59
|
+
);
|
|
60
|
+
CREATE TABLE board_cards (
|
|
61
|
+
id INTEGER PRIMARY KEY,
|
|
62
|
+
project_id INTEGER NOT NULL,
|
|
63
|
+
title TEXT NOT NULL,
|
|
64
|
+
description TEXT NOT NULL DEFAULT '',
|
|
65
|
+
column_key TEXT NOT NULL DEFAULT 'todo',
|
|
66
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
67
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
68
|
+
sessions TEXT NOT NULL DEFAULT '[]',
|
|
69
|
+
block_kind TEXT,
|
|
70
|
+
block_text TEXT NOT NULL DEFAULT '',
|
|
71
|
+
parent_card_id INTEGER,
|
|
72
|
+
readonly INTEGER NOT NULL DEFAULT 0,
|
|
73
|
+
model TEXT NOT NULL DEFAULT '',
|
|
74
|
+
scheduled_at INTEGER,
|
|
75
|
+
jira_key TEXT NOT NULL DEFAULT '',
|
|
76
|
+
last_error TEXT NOT NULL DEFAULT '',
|
|
77
|
+
last_error_at INTEGER,
|
|
78
|
+
created_at TEXT NOT NULL,
|
|
79
|
+
updated_at TEXT NOT NULL
|
|
80
|
+
);
|
|
81
|
+
CREATE TABLE board_comments (
|
|
82
|
+
id INTEGER PRIMARY KEY,
|
|
83
|
+
card_id INTEGER NOT NULL,
|
|
84
|
+
text TEXT NOT NULL,
|
|
85
|
+
sent INTEGER NOT NULL DEFAULT 0,
|
|
86
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
87
|
+
sent_text TEXT NOT NULL DEFAULT '',
|
|
88
|
+
created_at TEXT NOT NULL
|
|
89
|
+
);
|
|
90
|
+
CREATE TABLE board_settings (
|
|
91
|
+
project_id INTEGER PRIMARY KEY,
|
|
92
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
93
|
+
);
|
|
94
|
+
CREATE TABLE app_settings (
|
|
95
|
+
key TEXT PRIMARY KEY,
|
|
96
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
97
|
+
);
|
|
98
|
+
CREATE TABLE user_prefs (
|
|
99
|
+
user_id INTEGER NOT NULL,
|
|
100
|
+
project_id INTEGER NOT NULL DEFAULT 0,
|
|
101
|
+
key TEXT NOT NULL,
|
|
102
|
+
value TEXT NOT NULL DEFAULT '{}',
|
|
103
|
+
updated_at TEXT NOT NULL,
|
|
104
|
+
PRIMARY KEY (user_id, project_id, key)
|
|
105
|
+
);
|
|
106
|
+
CREATE TABLE feishu_hooks (
|
|
107
|
+
project_id INTEGER PRIMARY KEY,
|
|
108
|
+
webhook_url TEXT NOT NULL DEFAULT '',
|
|
109
|
+
webhook_secret TEXT NOT NULL DEFAULT '',
|
|
110
|
+
events TEXT NOT NULL DEFAULT 'blocked_interaction,task_failed',
|
|
111
|
+
enabled INTEGER NOT NULL DEFAULT 1
|
|
112
|
+
);
|
|
113
|
+
CREATE TABLE feishu_outbox (
|
|
114
|
+
id INTEGER PRIMARY KEY,
|
|
115
|
+
target TEXT NOT NULL,
|
|
116
|
+
secret TEXT NOT NULL DEFAULT '',
|
|
117
|
+
payload TEXT NOT NULL,
|
|
118
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
119
|
+
retries INTEGER NOT NULL DEFAULT 0,
|
|
120
|
+
next_at REAL NOT NULL DEFAULT 0,
|
|
121
|
+
dedup_key TEXT NOT NULL DEFAULT '',
|
|
122
|
+
last_error TEXT NOT NULL DEFAULT '',
|
|
123
|
+
created_at TEXT NOT NULL
|
|
124
|
+
);
|
|
125
|
+
CREATE TABLE feishu_user_cfgs (
|
|
126
|
+
user_id INTEGER PRIMARY KEY,
|
|
127
|
+
json TEXT NOT NULL DEFAULT '{}'
|
|
128
|
+
);
|
|
129
|
+
CREATE TABLE feishu_bindings (
|
|
130
|
+
open_id TEXT PRIMARY KEY,
|
|
131
|
+
user_id INTEGER NOT NULL,
|
|
132
|
+
default_project_id INTEGER NOT NULL DEFAULT 0,
|
|
133
|
+
bound_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
|
|
134
|
+
UNIQUE (user_id)
|
|
135
|
+
);
|
|
136
|
+
CREATE TABLE wait_items (
|
|
137
|
+
id INTEGER PRIMARY KEY,
|
|
138
|
+
project_id INTEGER NOT NULL,
|
|
139
|
+
kind TEXT NOT NULL,
|
|
140
|
+
target_id TEXT NOT NULL,
|
|
141
|
+
state TEXT NOT NULL DEFAULT 'waiting',
|
|
142
|
+
seq INTEGER NOT NULL,
|
|
143
|
+
created_at TEXT NOT NULL,
|
|
144
|
+
claimed_at TEXT,
|
|
145
|
+
claimed_by TEXT,
|
|
146
|
+
ended_at TEXT,
|
|
147
|
+
not_before REAL NOT NULL DEFAULT 0,
|
|
148
|
+
retries INTEGER NOT NULL DEFAULT 0,
|
|
149
|
+
meta TEXT NOT NULL DEFAULT '{}'
|
|
150
|
+
);
|
|
151
|
+
CREATE TABLE chat_msgs (
|
|
152
|
+
id TEXT PRIMARY KEY,
|
|
153
|
+
project_id INTEGER NOT NULL,
|
|
154
|
+
sid TEXT NOT NULL,
|
|
155
|
+
task_id INTEGER,
|
|
156
|
+
card_id INTEGER,
|
|
157
|
+
message TEXT NOT NULL,
|
|
158
|
+
state TEXT NOT NULL,
|
|
159
|
+
error TEXT NOT NULL DEFAULT '',
|
|
160
|
+
inject INTEGER NOT NULL DEFAULT 0,
|
|
161
|
+
created_at INTEGER NOT NULL,
|
|
162
|
+
started_at INTEGER,
|
|
163
|
+
ended_at INTEGER
|
|
164
|
+
);
|
|
165
|
+
CREATE INDEX idx_tasks_project ON tasks(project_id);
|
|
166
|
+
CREATE INDEX idx_rounds_task ON rounds(task_id);
|
|
167
|
+
CREATE INDEX idx_board_cards_project ON board_cards(project_id);
|
|
168
|
+
CREATE INDEX idx_board_comments_card ON board_comments(card_id);
|
|
169
|
+
CREATE UNIQUE INDEX idx_wait_active ON wait_items(kind, target_id) WHERE state IN ('waiting','claimed','running','finishing');
|
|
170
|
+
CREATE INDEX idx_wait_pick ON wait_items(state, project_id, seq);
|
|
171
|
+
CREATE INDEX idx_chat_msgs_sid ON chat_msgs(sid, created_at);
|
|
172
|
+
|
|
173
|
+
-- 种子数据
|
|
174
|
+
INSERT INTO users(id, username, pass_hash, salt, created_at) VALUES(1, 'admin', 'd41d8cd98f00b204e9800998ecf8427e', '', '2026-01-01 00:00:00');
|
|
175
|
+
INSERT INTO projects(id, name, project_dir, work_dir, bug_dir, commit_spec, deploy_spec, created_at, user_id) VALUES(1, 'proj_one', '/tmp/ts-fixture/proj', '/tmp/ts-fixture/proj', '', '', '', '2026-01-01 00:00:00', 1);
|
|
176
|
+
INSERT INTO tasks(id, project_id, name, created_at) VALUES(1, 1, 't1', '2026-01-01 00:00:00');
|
|
177
|
+
INSERT INTO board_cards(updated_at, id, project_id, title, created_at, column_key) VALUES('x', 1, 1, 'legacy card', '2026-01-01 00:00:00', 'todo');
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": 1,
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"generatedBy": "tools/export_schema.py",
|
|
5
|
+
"note": "数据级/结构重建迁移:两版执行**同一份**清单。when=null 表示无条件执行(语句自身幂等);kind=rows 的 sql 是只读 SELECT,返回 ≥1 行才执行;kind=index_origin_unique 表示表上存在 UNIQUE 约束索引才执行。handler 需宿主语言实现(未知 handler 必须报错退出,不得静默跳过)。",
|
|
6
|
+
"guards": {
|
|
7
|
+
"rows": "SELECT 返回 ≥1 行才执行该步",
|
|
8
|
+
"index_origin_unique": "PRAGMA index_list(表) 里存在 origin='u' 的索引才执行"
|
|
9
|
+
},
|
|
10
|
+
"handlers": {
|
|
11
|
+
"projects_guide_text_merge": "废弃列 commit_spec/deploy_spec 的内容并入 guide_text 后清空两列",
|
|
12
|
+
"projects_work_dir_from_legacy_cases_root": "工作目录化:旧 work_dir(案例库根)改存工作目录,bug_dir 列废弃置空",
|
|
13
|
+
"feishu_appsettings_bridge": "飞书配置用户级化:旧全局 app_settings['feishu'] 迁给 admin 的用户级配置"
|
|
14
|
+
},
|
|
15
|
+
"handlerImpl": {
|
|
16
|
+
"python": "db.py MIGRATION_HANDLERS",
|
|
17
|
+
"node": "backend/lib/db.js HANDLERS"
|
|
18
|
+
},
|
|
19
|
+
"steps": [
|
|
20
|
+
{
|
|
21
|
+
"id": "2026-09-04_projects_guide_text_merge",
|
|
22
|
+
"desc": "废弃列 commit_spec/deploy_spec 的内容并入 guide_text 后清空两列",
|
|
23
|
+
"when": {
|
|
24
|
+
"kind": "rows",
|
|
25
|
+
"sql": "SELECT 1 FROM projects WHERE trim(coalesce(commit_spec,'')) != '' OR trim(coalesce(deploy_spec,'')) != '' LIMIT 1"
|
|
26
|
+
},
|
|
27
|
+
"handler": "projects_guide_text_merge"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "2026-09-04_projects_user_id_backfill",
|
|
31
|
+
"desc": "多用户隔离:存量项目(user_id=0)归 admin",
|
|
32
|
+
"when": {
|
|
33
|
+
"kind": "rows",
|
|
34
|
+
"sql": "SELECT 1 FROM projects WHERE user_id=0 LIMIT 1"
|
|
35
|
+
},
|
|
36
|
+
"sql": [
|
|
37
|
+
"UPDATE projects SET user_id= COALESCE((SELECT id FROM users WHERE username='admin'), 0) WHERE user_id=0"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "2026-09-13_board_cards_clear_commit_block_text",
|
|
42
|
+
"desc": "阻塞让行提交退场:清理存量卡片上的机器文案 block_text",
|
|
43
|
+
"when": {
|
|
44
|
+
"kind": "rows",
|
|
45
|
+
"sql": "SELECT 1 FROM board_cards WHERE block_text LIKE '提交中:%' OR block_text LIKE '提交失败:%' LIMIT 1"
|
|
46
|
+
},
|
|
47
|
+
"sql": [
|
|
48
|
+
"UPDATE board_cards SET block_text='' WHERE block_text LIKE '提交中:%' OR block_text LIKE '提交失败:%'"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "2026-09-13_board_cards_clear_commit_errors",
|
|
53
|
+
"desc": "阻塞让行提交退场:清理存量卡片上的提交失败 last_error",
|
|
54
|
+
"when": {
|
|
55
|
+
"kind": "rows",
|
|
56
|
+
"sql": "SELECT 1 FROM board_cards WHERE last_error LIKE '阻塞让行提交失败%' OR last_error LIKE '阻塞让行提交异常%' LIMIT 1"
|
|
57
|
+
},
|
|
58
|
+
"sql": [
|
|
59
|
+
"UPDATE board_cards SET last_error='', last_error_at=NULL WHERE last_error LIKE '阻塞让行提交失败%' OR last_error LIKE '阻塞让行提交异常%'"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "2026-09-04_projects_drop_global_unique_name",
|
|
64
|
+
"desc": "旧库 projects.name 全局 UNIQUE → (user_id,name) 用户内唯一:重建表",
|
|
65
|
+
"when": {
|
|
66
|
+
"kind": "index_origin_unique",
|
|
67
|
+
"table": "projects"
|
|
68
|
+
},
|
|
69
|
+
"sql": [
|
|
70
|
+
"ALTER TABLE projects RENAME TO projects_old",
|
|
71
|
+
"CREATE TABLE projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id INTEGER NOT NULL DEFAULT 0,\n name TEXT NOT NULL,\n project_dir TEXT NOT NULL,\n agent_path TEXT NOT NULL DEFAULT '',\n work_dir TEXT NOT NULL,\n bug_dir TEXT NOT NULL,\n guide_text TEXT NOT NULL DEFAULT '',\n commit_spec TEXT NOT NULL DEFAULT '',\n deploy_spec TEXT NOT NULL DEFAULT '',\n env_label TEXT NOT NULL DEFAULT '',\n created_at TEXT NOT NULL\n)",
|
|
72
|
+
"INSERT INTO projects(id, user_id, name, project_dir, agent_path, work_dir, bug_dir,\n guide_text, commit_spec, deploy_spec, env_label, created_at)\nSELECT id, user_id, name, project_dir, agent_path, work_dir, bug_dir,\n guide_text, commit_spec, deploy_spec, env_label, created_at\nFROM projects_old",
|
|
73
|
+
"DROP TABLE projects_old"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "2026-09-04_projects_user_name_unique_index",
|
|
78
|
+
"desc": "补建用户内唯一索引 idx_projects_user_name(重建之后执行)",
|
|
79
|
+
"when": null,
|
|
80
|
+
"sql": [
|
|
81
|
+
"CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_user_name ON projects(user_id, name)"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "2026-08-30_projects_work_dir_from_legacy_cases_root",
|
|
86
|
+
"desc": "工作目录化:旧 work_dir(案例库根)改存工作目录,bug_dir 列废弃置空",
|
|
87
|
+
"when": {
|
|
88
|
+
"kind": "rows",
|
|
89
|
+
"sql": "SELECT 1 FROM projects WHERE bug_dir != '' LIMIT 1"
|
|
90
|
+
},
|
|
91
|
+
"handler": "projects_work_dir_from_legacy_cases_root"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "2026-09-19_board_cards_queue_state_doing",
|
|
95
|
+
"desc": "P4 排队占位单态化:blocked+queue 归位 doing+queue",
|
|
96
|
+
"when": {
|
|
97
|
+
"kind": "rows",
|
|
98
|
+
"sql": "SELECT 1 FROM board_cards WHERE block_kind='queue' AND column_key='blocked' LIMIT 1"
|
|
99
|
+
},
|
|
100
|
+
"sql": [
|
|
101
|
+
"UPDATE board_cards SET column_key='doing' WHERE block_kind='queue' AND column_key='blocked'"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "2026-09-09_feishu_appsettings_bridge",
|
|
106
|
+
"desc": "飞书配置用户级化:旧全局 app_settings['feishu'] 迁给 admin 的用户级配置",
|
|
107
|
+
"when": {
|
|
108
|
+
"kind": "rows",
|
|
109
|
+
"sql": "SELECT 1 FROM app_settings WHERE key='feishu' LIMIT 1"
|
|
110
|
+
},
|
|
111
|
+
"handler": "feishu_appsettings_bridge"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "2026-09-24_drop_leases",
|
|
115
|
+
"desc": "v3d 租约层删除:DROP 存量 leases 表与索引(幂等)",
|
|
116
|
+
"when": null,
|
|
117
|
+
"sql": [
|
|
118
|
+
"DROP TABLE IF EXISTS leases",
|
|
119
|
+
"DROP INDEX IF EXISTS idx_leases_project"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "2026-09-21_wait_items_claimed_to_starting",
|
|
124
|
+
"desc": "v2a 状态机扩七枚举:claimed 行归一 starting",
|
|
125
|
+
"when": {
|
|
126
|
+
"kind": "rows",
|
|
127
|
+
"sql": "SELECT 1 FROM wait_items WHERE state='claimed' LIMIT 1"
|
|
128
|
+
},
|
|
129
|
+
"sql": [
|
|
130
|
+
"UPDATE wait_items SET state='starting' WHERE state='claimed'"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "2026-09-21_wait_items_rebuild_active_index",
|
|
135
|
+
"desc": "活跃唯一索引口径扩到四活跃态(旧库 WHERE 仍含 claimed 时重建)",
|
|
136
|
+
"when": {
|
|
137
|
+
"kind": "rows",
|
|
138
|
+
"sql": "SELECT 1 FROM sqlite_master WHERE type='index' AND name='idx_wait_active' AND coalesce(sql,'') NOT LIKE '%''starting''%' LIMIT 1"
|
|
139
|
+
},
|
|
140
|
+
"sql": [
|
|
141
|
+
"DROP INDEX idx_wait_active",
|
|
142
|
+
"CREATE UNIQUE INDEX idx_wait_active ON wait_items(kind, target_id) WHERE state IN ('waiting','starting','running','finishing')"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "2026-10-11_schema_version_stamp",
|
|
147
|
+
"desc": "M1:把 schema 版本号写入 app_settings['schema_version'](两侧对拍前置断言)",
|
|
148
|
+
"when": null,
|
|
149
|
+
"sql": [
|
|
150
|
+
"INSERT INTO app_settings(key, json) VALUES('schema_version', '1') ON CONFLICT(key) DO UPDATE SET json=excluded.json"
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|