libero3 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/COLD_START.md +31 -0
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/data/migrations/001_initial_schema.sql +43 -0
- package/data/migrations/002_seed_categories.sql +18 -0
- package/data/migrations/003_add_rating.sql +4 -0
- package/data/migrations/004_timer_sessions.sql +21 -0
- package/data/migrations/005_profile_settings.sql +5 -0
- package/data/migrations/006_add_timeblock_status.sql +1 -0
- package/data/migrations/007_reminders.sql +17 -0
- package/data/migrations/008_timer_target_ms.sql +5 -0
- package/data/migrations/009_tasks.sql +22 -0
- package/data/migrations/010_timer_task_id.sql +4 -0
- package/data/migrations/011_profile_default_confirmed.sql +4 -0
- package/data/migrations/012_identity_tables.sql +68 -0
- package/data/migrations/013_identity_managed_by.sql +3 -0
- package/data/migrations/014_task_difficulty_priority.sql +6 -0
- package/data/migrations/015_timeblock_asked_at.sql +5 -0
- package/data/migrations/016_intent_columns.sql +8 -0
- package/data/migrations/017_ap_wallet.sql +25 -0
- package/data/migrations/018_ap_rewards.sql +21 -0
- package/data/migrations/019_ap_bounty.sql +10 -0
- package/data/migrations/020_chat_turns.sql +10 -0
- package/data/migrations/021_portrait.sql +4 -0
- package/data/migrations/022_family_emoji_single.sql +3 -0
- package/data/migrations/023_ap_balance_view_log.sql +9 -0
- package/data/schema.sql +75 -0
- package/dist/data/db.js +83 -0
- package/dist/data/migrations/001_initial_schema.sql +43 -0
- package/dist/data/migrations/002_seed_categories.sql +18 -0
- package/dist/data/migrations/003_add_rating.sql +4 -0
- package/dist/data/migrations/004_timer_sessions.sql +21 -0
- package/dist/data/migrations/005_profile_settings.sql +5 -0
- package/dist/data/migrations/006_add_timeblock_status.sql +1 -0
- package/dist/data/migrations/007_reminders.sql +17 -0
- package/dist/data/migrations/008_timer_target_ms.sql +5 -0
- package/dist/data/migrations/009_tasks.sql +22 -0
- package/dist/data/migrations/010_timer_task_id.sql +4 -0
- package/dist/data/migrations/011_profile_default_confirmed.sql +4 -0
- package/dist/data/migrations/012_identity_tables.sql +68 -0
- package/dist/data/migrations/013_identity_managed_by.sql +3 -0
- package/dist/data/migrations/014_task_difficulty_priority.sql +6 -0
- package/dist/data/migrations/015_timeblock_asked_at.sql +5 -0
- package/dist/data/migrations/016_intent_columns.sql +8 -0
- package/dist/data/migrations/017_ap_wallet.sql +25 -0
- package/dist/data/migrations/018_ap_rewards.sql +21 -0
- package/dist/data/migrations/019_ap_bounty.sql +10 -0
- package/dist/data/migrations/020_chat_turns.sql +10 -0
- package/dist/data/migrations/021_portrait.sql +4 -0
- package/dist/data/migrations/022_family_emoji_single.sql +3 -0
- package/dist/data/migrations/023_ap_balance_view_log.sql +9 -0
- package/dist/data/schema.sql +75 -0
- package/dist/knowledge/_registry/dimensions.yaml +10 -0
- package/dist/knowledge/_registry/personas.yaml +7 -0
- package/dist/knowledge/_schema/analysis-model.schema.js +32 -0
- package/dist/knowledge/_schema/entry.schema.js +45 -0
- package/dist/knowledge/_schema/persona.schema.js +23 -0
- package/dist/knowledge/_schema/scenario-pack.schema.js +29 -0
- package/dist/knowledge/analysis-models/review-default.yaml +16 -0
- package/dist/knowledge/analysis-models/review-summer-plan.yaml +15 -0
- package/dist/knowledge/brain-science/brain-deep-warmup.yaml +22 -0
- package/dist/knowledge/brain-science/brain-emotion-granularity.yaml +22 -0
- package/dist/knowledge/brain-science/brain-env-engineering.yaml +22 -0
- package/dist/knowledge/brain-science/brain-extended-mind.yaml +22 -0
- package/dist/knowledge/brain-science/brain-friction-barrier.yaml +22 -0
- package/dist/knowledge/brain-science/brain-peak-end.yaml +29 -0
- package/dist/knowledge/brain-science/brain-pomodoro.yaml +31 -0
- package/dist/knowledge/brain-science/brain-revenge-bedtime.yaml +22 -0
- package/dist/knowledge/brain-science/brain-single-variable.yaml +15 -0
- package/dist/knowledge/brain-science/brain-tiny-habits.yaml +22 -0
- package/dist/knowledge/energy/energy-active-recovery.yaml +22 -0
- package/dist/knowledge/energy/energy-deliberate-rest.yaml +22 -0
- package/dist/knowledge/energy/energy-exercise-embedded.yaml +22 -0
- package/dist/knowledge/energy/energy-fixed-wake-time.yaml +22 -0
- package/dist/knowledge/energy/energy-four-energy-radar.yaml +22 -0
- package/dist/knowledge/energy/energy-intensity-recovery.yaml +22 -0
- package/dist/knowledge/scenario-packs/pack-summer-kid.yaml +12 -0
- package/dist/knowledge/src/repo/fs-yaml.js +252 -0
- package/dist/knowledge/src/repo/types.js +1 -0
- package/dist/knowledge/time/time-batch-windows.yaml +22 -0
- package/dist/knowledge/time/time-conscious-abandon.yaml +22 -0
- package/dist/knowledge/time/time-deep-work-block.yaml +22 -0
- package/dist/knowledge/time/time-finite-commitment.yaml +22 -0
- package/dist/knowledge/time/time-forced-whitespace.yaml +22 -0
- package/dist/knowledge/time/time-gtd-next-action.yaml +22 -0
- package/dist/knowledge/time/time-three-tier-list.yaml +22 -0
- package/dist/mcp/cold-start.js +43 -0
- package/dist/mcp/contract/v1/rest.js +56 -0
- package/dist/mcp/rest-server.js +52 -0
- package/dist/mcp/server-core.js +1334 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/src/ap/index.js +14 -0
- package/dist/mcp/src/ap/rewards.js +44 -0
- package/dist/mcp/src/categories/index.js +12 -0
- package/dist/mcp/src/chat/from-env.js +111 -0
- package/dist/mcp/src/chat/history.js +35 -0
- package/dist/mcp/src/chat/loop.js +131 -0
- package/dist/mcp/src/chat/portrait.js +133 -0
- package/dist/mcp/src/chat/system-prompt.js +23 -0
- package/dist/mcp/src/chat/tool-names.js +27 -0
- package/dist/mcp/src/chat/tool-schema.js +20 -0
- package/dist/mcp/src/chat/types.js +1 -0
- package/dist/mcp/src/clock/index.js +78 -0
- package/dist/mcp/src/coachmod/index.js +135 -0
- package/dist/mcp/src/host-adapters/hermes-cron.js +185 -0
- package/dist/mcp/src/host-adapters/index.js +61 -0
- package/dist/mcp/src/host-adapters/types.js +7 -0
- package/dist/mcp/src/identity/equivalent-ids.js +41 -0
- package/dist/mcp/src/identity/in-memory.js +100 -0
- package/dist/mcp/src/identity/resolve.js +60 -0
- package/dist/mcp/src/identity/types.js +4 -0
- package/dist/mcp/src/matrix/index.js +15 -0
- package/dist/mcp/src/profile/confirm-default.js +48 -0
- package/dist/mcp/src/profile/index.js +298 -0
- package/dist/mcp/src/profile-confirm.js +28 -0
- package/dist/mcp/src/profile-helpers.js +109 -0
- package/dist/mcp/src/reminder/hermes-channel.js +40 -0
- package/dist/mcp/src/reminder/index.js +70 -0
- package/dist/mcp/src/reminder/push-channel.js +10 -0
- package/dist/mcp/src/repo/factory.js +34 -0
- package/dist/mcp/src/repo/in-memory.js +469 -0
- package/dist/mcp/src/repo/sqlite-ap.js +188 -0
- package/dist/mcp/src/repo/sqlite-helpers.js +39 -0
- package/dist/mcp/src/repo/sqlite-identity.js +129 -0
- package/dist/mcp/src/repo/sqlite.js +754 -0
- package/dist/mcp/src/repo/types.js +4 -0
- package/dist/mcp/src/rest/app.js +121 -0
- package/dist/mcp/src/rest/invoke-tool.js +98 -0
- package/dist/mcp/src/rest/short-token.js +38 -0
- package/dist/mcp/src/rest/tokens.js +55 -0
- package/dist/mcp/src/scheduler/index.js +319 -0
- package/dist/mcp/src/stats/index.js +29 -0
- package/dist/mcp/src/stickiness/report.js +174 -0
- package/dist/mcp/src/stickiness/types.js +1 -0
- package/dist/mcp/src/task/index.js +412 -0
- package/dist/mcp/src/timeblock/index.js +206 -0
- package/dist/mcp/src/timeline/index.js +705 -0
- package/dist/mcp/src/timer/index.js +234 -0
- package/dist/mcp/src/user-id-resolver.js +30 -0
- package/dist/mcp/src/weixin/app.js +97 -0
- package/dist/mcp/src/weixin/custom-send.js +82 -0
- package/dist/mcp/src/weixin/handle-text.js +49 -0
- package/dist/mcp/src/weixin/reminder-loop.js +39 -0
- package/dist/mcp/src/weixin/signature.js +13 -0
- package/dist/mcp/src/weixin/tencent-asr.js +101 -0
- package/dist/mcp/src/weixin/xml.js +37 -0
- package/dist/mcp/weixin-server.js +158 -0
- package/knowledge/_registry/dimensions.yaml +10 -0
- package/knowledge/_registry/personas.yaml +7 -0
- package/knowledge/_schema/analysis-model.schema.ts +36 -0
- package/knowledge/_schema/entry.schema.ts +50 -0
- package/knowledge/_schema/persona.schema.ts +30 -0
- package/knowledge/_schema/scenario-pack.schema.ts +33 -0
- package/knowledge/analysis-models/review-default.yaml +16 -0
- package/knowledge/analysis-models/review-summer-plan.yaml +15 -0
- package/knowledge/brain-science/brain-deep-warmup.yaml +22 -0
- package/knowledge/brain-science/brain-emotion-granularity.yaml +22 -0
- package/knowledge/brain-science/brain-env-engineering.yaml +22 -0
- package/knowledge/brain-science/brain-extended-mind.yaml +22 -0
- package/knowledge/brain-science/brain-friction-barrier.yaml +22 -0
- package/knowledge/brain-science/brain-peak-end.yaml +29 -0
- package/knowledge/brain-science/brain-pomodoro.yaml +31 -0
- package/knowledge/brain-science/brain-revenge-bedtime.yaml +22 -0
- package/knowledge/brain-science/brain-single-variable.yaml +15 -0
- package/knowledge/brain-science/brain-tiny-habits.yaml +22 -0
- package/knowledge/energy/energy-active-recovery.yaml +22 -0
- package/knowledge/energy/energy-deliberate-rest.yaml +22 -0
- package/knowledge/energy/energy-exercise-embedded.yaml +22 -0
- package/knowledge/energy/energy-fixed-wake-time.yaml +22 -0
- package/knowledge/energy/energy-four-energy-radar.yaml +22 -0
- package/knowledge/energy/energy-intensity-recovery.yaml +22 -0
- package/knowledge/scenario-packs/pack-summer-kid.yaml +12 -0
- package/knowledge/src/repo/fs-yaml.ts +282 -0
- package/knowledge/src/repo/types.ts +24 -0
- package/knowledge/tests/fixtures/base/_registry/dimensions.yaml +4 -0
- package/knowledge/tests/fixtures/base/time/valid-entry.yaml +24 -0
- package/knowledge/tests/fixtures/dup/_registry/dimensions.yaml +4 -0
- package/knowledge/tests/fixtures/dup/time/entry-a.yaml +13 -0
- package/knowledge/tests/fixtures/dup/time/entry-b.yaml +13 -0
- package/knowledge/tests/fixtures/unregistered/_registry/dimensions.yaml +7 -0
- package/knowledge/tests/fixtures/unregistered/time/anxiety-entry.yaml +13 -0
- package/knowledge/tests/repo/fs-yaml-knowledge-repo.test.ts +333 -0
- package/knowledge/time/time-batch-windows.yaml +22 -0
- package/knowledge/time/time-conscious-abandon.yaml +22 -0
- package/knowledge/time/time-deep-work-block.yaml +22 -0
- package/knowledge/time/time-finite-commitment.yaml +22 -0
- package/knowledge/time/time-forced-whitespace.yaml +22 -0
- package/knowledge/time/time-gtd-next-action.yaml +22 -0
- package/knowledge/time/time-three-tier-list.yaml +22 -0
- package/knowledge/validate.ts +50 -0
- package/package.json +76 -0
- package/scripts/postinstall-cold-start.js +45 -0
package/COLD_START.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# libero 冷启动(host agent 专用,不是用户手册)
|
|
2
|
+
|
|
3
|
+
> **禁止**把本文当成用户步骤(「请你让 agent 读这个文件」= 产品失败)。
|
|
4
|
+
> 用户只说「帮我装 libero」或跑 `npm i -g libero-mcp@latest`。欢迎必须由 host **自动**发出。
|
|
5
|
+
|
|
6
|
+
## Host 在装机时自动做
|
|
7
|
+
|
|
8
|
+
1. 跑 `npm i -g libero-mcp@latest`(postinstall 会在 stderr 打印 `LIBERO_HOST_ACTION` + 欢迎原文)
|
|
9
|
+
2. **立刻**把欢迎原文作为下一条对用户的回复发出(不要列工具、不要问 user_id)
|
|
10
|
+
3. 再写 `mcp_servers.libero.command: libero-mcp`(如需)并 `/reload-mcp`
|
|
11
|
+
|
|
12
|
+
## 欢迎原文
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
你好,我是 libero,帮你管时间和精力。
|
|
16
|
+
|
|
17
|
+
常用这几件事,直接说就行:
|
|
18
|
+
• 计时:「开始计时写代码」/「开个 25 分钟番茄钟」
|
|
19
|
+
• 日程:「明天 9 点到 11 点写报告」
|
|
20
|
+
• 拆任务:「这个太大了,帮我拆一下」
|
|
21
|
+
• 看数据:「这周时间都花哪儿了」
|
|
22
|
+
• 复盘:「帮我复盘一下这周」
|
|
23
|
+
|
|
24
|
+
想先试哪一句?
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 硬规矩
|
|
28
|
+
|
|
29
|
+
- **禁止问 user_id**(从会话上下文静默取;取不到用 `local:default`)
|
|
30
|
+
- 不要提 MCP / 工具表 / DB / YAML
|
|
31
|
+
- 用户选了例句 → 直接执行,不要重复整段介绍
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 amosyuan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# libero
|
|
2
|
+
|
|
3
|
+
AI 辅助的精力管理教练:观察实绩 → 发现问题 → 对齐方案 → AI 辅助达成。
|
|
4
|
+
|
|
5
|
+
> 2.0 = 一组 Skills(脑)+ 一层 MCP 工具(手)+ 一个数据后端(记忆),骑 Hermes / OpenClaw,本地优先。
|
|
6
|
+
|
|
7
|
+
## 快速开始
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -g libero-mcp@latest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
或对你的 agent 说一句:**帮我装 libero**。
|
|
14
|
+
|
|
15
|
+
装完后你会直接看到欢迎与试用例句(计时 / 日程 / 拆任务 / 看数据 / 复盘)。
|
|
16
|
+
不需要再配置、不需要起 user_id、不需要提醒 agent「去读某个文件」。
|
|
17
|
+
|
|
18
|
+
试试说:
|
|
19
|
+
|
|
20
|
+
> 开始计时写代码
|
|
21
|
+
|
|
22
|
+
## 能说什么
|
|
23
|
+
|
|
24
|
+
| 想做的事 | 这样说 |
|
|
25
|
+
|---|---|
|
|
26
|
+
| 开始一段专注 | "开始计时写代码" / "开个 25 分钟番茄钟读书" |
|
|
27
|
+
| 停下来 | "停一下" / "看看今天计了多久" |
|
|
28
|
+
| 安排日程 | "明天 9 点到 11 点写报告" |
|
|
29
|
+
| 看时间分布 | "这周时间都花哪儿了" |
|
|
30
|
+
| 复盘 | "复盘一下这周" |
|
|
31
|
+
| 拆任务 | "这个任务太大,帮我拆一下" |
|
|
32
|
+
|
|
33
|
+
## 升级
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm update -g libero-mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 给开发者 / host 实现者
|
|
40
|
+
|
|
41
|
+
- Host 装机自动行为见 [COLD_START.md](COLD_START.md)(**不是**用户步骤)
|
|
42
|
+
- 协作宪法:[AGENTS.md](AGENTS.md)
|
|
43
|
+
- 排查:[docs/operations/deploy-to-hermes.md](docs/operations/deploy-to-hermes.md)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-- 001_initial_schema: libero 2.0 核心表
|
|
2
|
+
-- K1 合规:所有业务表带 UUID PK + created_at + updated_at + deleted_at(软删除)
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS user_profile (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
display_name TEXT NOT NULL DEFAULT '',
|
|
7
|
+
expectations TEXT,
|
|
8
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
9
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
10
|
+
deleted_at TEXT
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS time_blocks (
|
|
14
|
+
id TEXT PRIMARY KEY,
|
|
15
|
+
user_id TEXT NOT NULL,
|
|
16
|
+
title TEXT NOT NULL,
|
|
17
|
+
category_id TEXT,
|
|
18
|
+
start_time TEXT NOT NULL,
|
|
19
|
+
end_time TEXT NOT NULL,
|
|
20
|
+
duration_minutes INTEGER,
|
|
21
|
+
notes TEXT,
|
|
22
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
23
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
24
|
+
deleted_at TEXT,
|
|
25
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE TABLE IF NOT EXISTS categories (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
name TEXT NOT NULL,
|
|
31
|
+
emoji TEXT DEFAULT '',
|
|
32
|
+
color TEXT DEFAULT '',
|
|
33
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
34
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
35
|
+
deleted_at TEXT,
|
|
36
|
+
UNIQUE(name)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
40
|
+
version INTEGER PRIMARY KEY,
|
|
41
|
+
name TEXT NOT NULL,
|
|
42
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
43
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- 002_seed_categories: libero 2.0 默认 15 分类
|
|
2
|
+
|
|
3
|
+
INSERT INTO categories (id, name, emoji, color) VALUES
|
|
4
|
+
('cat-work', '工作', '💼', '#4A90D9'),
|
|
5
|
+
('cat-study', '学习', '📚', '#7B68EE'),
|
|
6
|
+
('cat-create', '创作', '✍️', '#E67E22'),
|
|
7
|
+
('cat-sleep', '睡眠', '😴', '#34495E'),
|
|
8
|
+
('cat-eat', '餐饮', '🍽️', '#E74C3C'),
|
|
9
|
+
('cat-chore', '内务', '🏠', '#95A5A6'),
|
|
10
|
+
('cat-commute', '通勤', '🚗', '#1ABC9C'),
|
|
11
|
+
('cat-exercise', '运动', '🏃', '#2ECC71'),
|
|
12
|
+
('cat-meditate', '冥想', '🧘', '#9B59B6'),
|
|
13
|
+
('cat-medical', '医疗', '🏥', '#E91E63'),
|
|
14
|
+
('cat-social', '社交', '👥', '#FF6F00'),
|
|
15
|
+
('cat-family', '陪伴', '👨👩👧', '#00BCD4'),
|
|
16
|
+
('cat-play', '娱乐', '🎮', '#F39C12'),
|
|
17
|
+
('cat-idle', '闲散', '☕', '#BDC3C7'),
|
|
18
|
+
('cat-other', '其他', '❓', '#7F8C8D');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- 004_timer_sessions: multi-user persistent timer state
|
|
2
|
+
-- Eliminates module-level global `let state` (architecture pitfall A2).
|
|
3
|
+
-- Stores started_at + accumulated_ms invariants; elapsed is always recomputed.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS timer_sessions (
|
|
6
|
+
id TEXT PRIMARY KEY,
|
|
7
|
+
user_id TEXT NOT NULL,
|
|
8
|
+
event TEXT NOT NULL,
|
|
9
|
+
category_id TEXT,
|
|
10
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
11
|
+
started_at TEXT NOT NULL,
|
|
12
|
+
accumulated_ms INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
ended_at TEXT,
|
|
14
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
15
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
16
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- Speed up "find active session for user" (at most one running/paused per user)
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_timer_active
|
|
21
|
+
ON timer_sessions (user_id, status);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE time_blocks ADD COLUMN status TEXT NOT NULL DEFAULT 'completed';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS reminders (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
user_id TEXT NOT NULL,
|
|
4
|
+
timeblock_id TEXT,
|
|
5
|
+
content TEXT NOT NULL,
|
|
6
|
+
remind_at TEXT NOT NULL,
|
|
7
|
+
channel TEXT NOT NULL DEFAULT 'session',
|
|
8
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
9
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
sent_at TEXT,
|
|
11
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
12
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
13
|
+
deleted_at TEXT,
|
|
14
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id)
|
|
15
|
+
);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_reminders_due
|
|
17
|
+
ON reminders (status, remind_at) WHERE deleted_at IS NULL;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- 009_tasks: 任务拆解(P2-3, S29 §3.1)
|
|
2
|
+
-- coaching 制品:低摩擦冷启动 + ≤25min 子任务方案
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
user_id TEXT NOT NULL,
|
|
7
|
+
parent_id TEXT, -- NULL=根任务, 否则子任务(自引用)
|
|
8
|
+
title TEXT NOT NULL,
|
|
9
|
+
status TEXT NOT NULL DEFAULT 'draft', -- draft/aligned/executing/done/abandoned
|
|
10
|
+
est_minutes INTEGER, -- 预估(冷启动不限, 其余≤25min)
|
|
11
|
+
category_id TEXT,
|
|
12
|
+
linked_timeblock_id TEXT, -- 排/执行时关联 time_block
|
|
13
|
+
order_index INTEGER DEFAULT 0, -- 同级顺序
|
|
14
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
15
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
16
|
+
deleted_at TEXT,
|
|
17
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id),
|
|
18
|
+
FOREIGN KEY (parent_id) REFERENCES tasks(id),
|
|
19
|
+
FOREIGN KEY (category_id) REFERENCES categories(id),
|
|
20
|
+
FOREIGN KEY (linked_timeblock_id) REFERENCES time_blocks(id)
|
|
21
|
+
);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_user_parent ON tasks (user_id, parent_id);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
-- 012_identity_tables: S40 跨平台身份层
|
|
2
|
+
-- 新建 user_identity(1 真人 = 1 行)+ user_platform_alias(1 用户 ↔ N 平台 chat_id)表
|
|
3
|
+
-- 为每个现存 user_profile.id(旧 chat_id)自动建对应 libero_user_id + alias 兜底行
|
|
4
|
+
--
|
|
5
|
+
-- §4.5 静默折叠声明:
|
|
6
|
+
-- 1. 现有 user_profile.id 字段值不立刻改成 libero_user_id(保持 chat_id 不动)
|
|
7
|
+
-- 折叠意图:靠 mcp/src/identity/resolve.ts 的 resolveUserId 在运行时透明解析
|
|
8
|
+
-- 副作用:业务表(timeblock/timer/scheduler/reminder)的 user_id 字段也仍是 chat_id
|
|
9
|
+
-- slice 2 才全量 update 这些字段到 libero_user_id
|
|
10
|
+
-- 2. 现有用户的 alias.platform 默认 'unknown'(migration 不猜平台)
|
|
11
|
+
-- 折叠意图:避免猜测出错(wecom chat_id vs feishu open_id 长得像)
|
|
12
|
+
-- 副作用:listMyChannels 第一次会看到 platform=unknown,主会话首次接触时问用户确认后调 bindAlias 修正
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS user_identity (
|
|
15
|
+
libero_user_id TEXT PRIMARY KEY, -- 'u_libero_xxxxxxxx' (UUID v4 截断)
|
|
16
|
+
display_name TEXT,
|
|
17
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
18
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS user_platform_alias (
|
|
22
|
+
libero_user_id TEXT NOT NULL,
|
|
23
|
+
platform TEXT NOT NULL, -- 'wecom' / 'feishu' / 'telegram' / 'unknown'
|
|
24
|
+
platform_user_id TEXT NOT NULL, -- 平台的 user/open id
|
|
25
|
+
chat_id TEXT, -- 投递用 chat_id(可等于 platform_user_id)
|
|
26
|
+
bound_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
27
|
+
PRIMARY KEY (platform, platform_user_id),
|
|
28
|
+
FOREIGN KEY (libero_user_id) REFERENCES user_identity(libero_user_id)
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_alias_libero ON user_platform_alias(libero_user_id);
|
|
32
|
+
|
|
33
|
+
-- 为现有每个 user_profile 行建对应 libero_user_id + alias 兜底行
|
|
34
|
+
-- 用 substr(hex(randomblob(...))) 生成稳定长度的伪 UUID(避免依赖外部 UUID 函数)
|
|
35
|
+
INSERT OR IGNORE INTO user_identity (libero_user_id, display_name, created_at, updated_at)
|
|
36
|
+
SELECT
|
|
37
|
+
'u_libero_' || substr(hex(randomblob(8)), 1, 16),
|
|
38
|
+
CASE
|
|
39
|
+
WHEN LENGTH(id) <= 16 THEN id
|
|
40
|
+
ELSE SUBSTR(id, 1, 16)
|
|
41
|
+
END,
|
|
42
|
+
COALESCE(created_at, datetime('now')),
|
|
43
|
+
COALESCE(updated_at, datetime('now'))
|
|
44
|
+
FROM user_profile
|
|
45
|
+
WHERE id NOT LIKE 'u_libero_%';
|
|
46
|
+
|
|
47
|
+
-- 为上面建的 identity 加 alias 兜底(platform='unknown',主会话首次接触时修正)
|
|
48
|
+
-- 用 user_profile.id + created_at 双键匹配(display_name 可能撞)
|
|
49
|
+
INSERT OR IGNORE INTO user_platform_alias (libero_user_id, platform, platform_user_id, chat_id, bound_at)
|
|
50
|
+
SELECT
|
|
51
|
+
(
|
|
52
|
+
SELECT ui.libero_user_id FROM user_identity ui
|
|
53
|
+
WHERE ui.display_name = CASE
|
|
54
|
+
WHEN LENGTH(up.id) <= 16 THEN up.id
|
|
55
|
+
ELSE SUBSTR(up.id, 1, 16)
|
|
56
|
+
END
|
|
57
|
+
ORDER BY ui.created_at LIMIT 1
|
|
58
|
+
),
|
|
59
|
+
'unknown',
|
|
60
|
+
up.id,
|
|
61
|
+
up.id,
|
|
62
|
+
COALESCE(up.updated_at, datetime('now'))
|
|
63
|
+
FROM user_profile up
|
|
64
|
+
WHERE up.id NOT LIKE 'u_libero_%'
|
|
65
|
+
AND NOT EXISTS (
|
|
66
|
+
SELECT 1 FROM user_platform_alias upa
|
|
67
|
+
WHERE upa.platform = 'unknown' AND upa.platform_user_id = up.id
|
|
68
|
+
);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- S46 (2026-08-07): task difficulty/priority 持久化
|
|
2
|
+
-- 用于"快速启动 + 峰终"智能排程
|
|
3
|
+
-- 难度(easy/medium/hard,默认 medium)
|
|
4
|
+
ALTER TABLE tasks ADD COLUMN difficulty TEXT DEFAULT 'medium';
|
|
5
|
+
-- 优先级(high/medium/low,默认 medium)
|
|
6
|
+
ALTER TABLE tasks ADD COLUMN priority TEXT DEFAULT 'medium';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- MV-COACH-5 slice 1 (2026-08-12): reminders 表升格为意图队列
|
|
2
|
+
-- 用于 3F 架构:脑说意图 → 手记意图 + 调 adapter → adapter 翻译成宿主机制
|
|
3
|
+
-- 复用现有列:remind_at(时间)、content(action_prompt)、timeblock_id(schedule_id)、status
|
|
4
|
+
ALTER TABLE reminders ADD COLUMN intent_type TEXT; -- pre_start_reminder / missed_check / daily_review / one_off_reminder
|
|
5
|
+
ALTER TABLE reminders ADD COLUMN trigger_kind TEXT; -- relative / absolute / recurring
|
|
6
|
+
ALTER TABLE reminders ADD COLUMN trigger_payload TEXT; -- JSON: {offset:"-15m", relative_to:"schedule.start"} 等
|
|
7
|
+
ALTER TABLE reminders ADD COLUMN host_job_id TEXT; -- adapter 写回(hermes cron job id)
|
|
8
|
+
ALTER TABLE reminders ADD COLUMN host_kind TEXT; -- "hermes_cron" / "openclaw" / "cc_pending"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- INT-AP-tools R2 (2026-08-14): AP 账真源在 libero.db
|
|
2
|
+
-- 契约: libero-homm/docs/specs/INT-AP-tools.md §3
|
|
3
|
+
CREATE TABLE IF NOT EXISTS ap_wallet (
|
|
4
|
+
user_id TEXT PRIMARY KEY,
|
|
5
|
+
balance INTEGER NOT NULL DEFAULT 0,
|
|
6
|
+
updated_at TEXT NOT NULL
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS ap_credit_log (
|
|
10
|
+
user_id TEXT NOT NULL,
|
|
11
|
+
idempotency_key TEXT NOT NULL,
|
|
12
|
+
amount INTEGER NOT NULL,
|
|
13
|
+
source TEXT NOT NULL,
|
|
14
|
+
created_at TEXT NOT NULL,
|
|
15
|
+
UNIQUE(user_id, idempotency_key)
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
-- spend 幂等同 credit:同 key 只扣一次(spec §2b)
|
|
19
|
+
CREATE TABLE IF NOT EXISTS ap_spend_log (
|
|
20
|
+
user_id TEXT NOT NULL,
|
|
21
|
+
idempotency_key TEXT NOT NULL,
|
|
22
|
+
amount INTEGER NOT NULL,
|
|
23
|
+
created_at TEXT NOT NULL,
|
|
24
|
+
UNIQUE(user_id, idempotency_key)
|
|
25
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- INT-ap-rewards (2026-08-19): AP 换算引擎计数与事件幂等
|
|
2
|
+
-- 契约: libero-homm/docs/specs/INT-ap-rewards.md §4
|
|
3
|
+
CREATE TABLE IF NOT EXISTS ap_reward_log (
|
|
4
|
+
user_id TEXT NOT NULL,
|
|
5
|
+
event_id TEXT NOT NULL,
|
|
6
|
+
action_type TEXT NOT NULL,
|
|
7
|
+
period_key TEXT NOT NULL,
|
|
8
|
+
nth INTEGER NOT NULL,
|
|
9
|
+
amount INTEGER NOT NULL,
|
|
10
|
+
created_at TEXT NOT NULL,
|
|
11
|
+
UNIQUE(user_id, event_id)
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS ap_reward_counter (
|
|
15
|
+
user_id TEXT NOT NULL,
|
|
16
|
+
action_type TEXT NOT NULL,
|
|
17
|
+
period_key TEXT NOT NULL,
|
|
18
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
19
|
+
updated_at TEXT NOT NULL,
|
|
20
|
+
PRIMARY KEY (user_id, action_type, period_key)
|
|
21
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- INT-ap-rewards 悬赏(方案 A,2026-08-19):每日任务完成奖金,一日一任务只发一次
|
|
2
|
+
-- 契约: libero-homm/docs/specs/INT-ap-rewards.md §悬赏
|
|
3
|
+
CREATE TABLE IF NOT EXISTS ap_bounty_log (
|
|
4
|
+
user_id TEXT NOT NULL,
|
|
5
|
+
date_key TEXT NOT NULL,
|
|
6
|
+
quest_id TEXT NOT NULL,
|
|
7
|
+
bonus INTEGER NOT NULL,
|
|
8
|
+
created_at TEXT NOT NULL,
|
|
9
|
+
UNIQUE(user_id, date_key, quest_id)
|
|
10
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- 微信/REST chat 多轮上下文(2026-08-19)
|
|
2
|
+
-- 只存 user/assistant 正文;tool 轮次不落盘
|
|
3
|
+
CREATE TABLE IF NOT EXISTS chat_turns (
|
|
4
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5
|
+
conversation_key TEXT NOT NULL,
|
|
6
|
+
role TEXT NOT NULL,
|
|
7
|
+
content TEXT NOT NULL,
|
|
8
|
+
created_at TEXT NOT NULL
|
|
9
|
+
);
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_chat_turns_key_id ON chat_turns (conversation_key, id);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- S3:看余额埋点(INT-mvp-100 游戏拉动信号)。只追加,不幂等去重——每次查询都是一次「看」。
|
|
2
|
+
CREATE TABLE IF NOT EXISTS ap_balance_view_log (
|
|
3
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
user_id TEXT NOT NULL,
|
|
5
|
+
balance INTEGER NOT NULL,
|
|
6
|
+
created_at TEXT NOT NULL
|
|
7
|
+
);
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_ap_balance_view_user_created
|
|
9
|
+
ON ap_balance_view_log (user_id, created_at);
|
package/data/schema.sql
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
-- 001_initial_schema: libero 2.0 核心表
|
|
2
|
+
-- K1 合规:所有业务表带 UUID PK + created_at + updated_at + deleted_at(软删除)
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS user_profile (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
display_name TEXT NOT NULL DEFAULT '',
|
|
7
|
+
expectations TEXT,
|
|
8
|
+
-- 005_profile_settings: 结构化约定存为 JSON
|
|
9
|
+
settings TEXT,
|
|
10
|
+
-- 011_profile_default_confirmed: MV-COACH-1 首次确认时间戳
|
|
11
|
+
default_confirmed_at TEXT,
|
|
12
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
13
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
14
|
+
deleted_at TEXT
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS time_blocks (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
user_id TEXT NOT NULL,
|
|
20
|
+
title TEXT NOT NULL,
|
|
21
|
+
category_id TEXT,
|
|
22
|
+
start_time TEXT NOT NULL,
|
|
23
|
+
end_time TEXT NOT NULL,
|
|
24
|
+
duration_minutes INTEGER,
|
|
25
|
+
notes TEXT,
|
|
26
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
27
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
28
|
+
deleted_at TEXT,
|
|
29
|
+
-- status/rating/rating_reason 由后续 migration 加;此处不显式列(IF NOT EXISTS 不重建表)
|
|
30
|
+
-- asked_at(migration 015,S48):扫描追问幂等标记,每条只主动问一次
|
|
31
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS categories (
|
|
35
|
+
id TEXT PRIMARY KEY,
|
|
36
|
+
name TEXT NOT NULL,
|
|
37
|
+
emoji TEXT DEFAULT '',
|
|
38
|
+
color TEXT DEFAULT '',
|
|
39
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
40
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
41
|
+
deleted_at TEXT,
|
|
42
|
+
UNIQUE(name)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
46
|
+
version INTEGER PRIMARY KEY,
|
|
47
|
+
name TEXT NOT NULL,
|
|
48
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
-- 012_identity_tables: S40 跨平台身份层
|
|
52
|
+
-- 1 真人 = 1 user_identity 行;N 平台 chat_id = N user_platform_alias 行
|
|
53
|
+
CREATE TABLE IF NOT EXISTS user_identity (
|
|
54
|
+
libero_user_id TEXT PRIMARY KEY,
|
|
55
|
+
display_name TEXT,
|
|
56
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
57
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE TABLE IF NOT EXISTS user_platform_alias (
|
|
61
|
+
libero_user_id TEXT NOT NULL,
|
|
62
|
+
platform TEXT NOT NULL,
|
|
63
|
+
platform_user_id TEXT NOT NULL,
|
|
64
|
+
chat_id TEXT,
|
|
65
|
+
bound_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
66
|
+
PRIMARY KEY (platform, platform_user_id),
|
|
67
|
+
FOREIGN KEY (libero_user_id) REFERENCES user_identity(libero_user_id)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_alias_libero ON user_platform_alias(libero_user_id);
|
|
71
|
+
|
|
72
|
+
-- reminders 表由 007 migration 建,此处不显式列(IF NOT EXISTS 不重建表)
|
|
73
|
+
-- MV-COACH-5 slice 1(migration 016):reminders 升格为意图队列,加 5 列:
|
|
74
|
+
-- intent_type / trigger_kind / trigger_payload / host_job_id / host_kind
|
|
75
|
+
-- 详见 data/migrations/016_intent_columns.sql
|
package/dist/data/db.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
let instance = null;
|
|
7
|
+
function runMigrations(db) {
|
|
8
|
+
db.exec(`
|
|
9
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
10
|
+
version INTEGER PRIMARY KEY,
|
|
11
|
+
name TEXT NOT NULL,
|
|
12
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
13
|
+
);
|
|
14
|
+
`);
|
|
15
|
+
const migrationsDir = join(import.meta.dirname, "migrations");
|
|
16
|
+
const files = readdirSync(migrationsDir)
|
|
17
|
+
.filter((f) => f.endsWith(".sql"))
|
|
18
|
+
.sort();
|
|
19
|
+
const applied = new Set(db.prepare("SELECT version FROM _migrations").all().map((r) => r.version));
|
|
20
|
+
for (const file of files) {
|
|
21
|
+
const match = file.match(/^(\d+)_/);
|
|
22
|
+
if (!match)
|
|
23
|
+
continue;
|
|
24
|
+
const version = parseInt(match[1], 10);
|
|
25
|
+
if (applied.has(version))
|
|
26
|
+
continue;
|
|
27
|
+
const sql = readFileSync(join(migrationsDir, file), "utf-8");
|
|
28
|
+
try {
|
|
29
|
+
db.exec(sql);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
// §4.5 显式折叠声明:手动改过生产 DB(如 ALTER TABLE 加字段)但忘了在
|
|
33
|
+
// _migrations 补记,下次启动 runMigrations 重跑会撞"已存在"错误。
|
|
34
|
+
// 这类错误 = 字段/表/索引已在那,migration 的目标其实达成了 → 容错记为已应用,
|
|
35
|
+
// 不让 gateway 启动卡死。其他错误(语法错、真缺字段)仍真抛。
|
|
36
|
+
//
|
|
37
|
+
// 2026-08-11 S48 教训:手动 ALTER TABLE time_blocks ADD asked_at 后没补 _migrations,
|
|
38
|
+
// gateway 重启跑 015 撞 duplicate column → MCP 崩 → hermes parking。
|
|
39
|
+
const msg = e.message ?? "";
|
|
40
|
+
const isAlreadyExists = msg.includes("duplicate column name") ||
|
|
41
|
+
msg.includes("already exists") ||
|
|
42
|
+
msg.includes("duplicate object");
|
|
43
|
+
if (!isAlreadyExists)
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
db.prepare("INSERT INTO _migrations (version, name) VALUES (?, ?)").run(version, file);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function initDb(dbPath) {
|
|
50
|
+
if (instance) {
|
|
51
|
+
instance.close();
|
|
52
|
+
instance = null;
|
|
53
|
+
}
|
|
54
|
+
// 父目录不存在时自动创建(recursive),避免 SQLITE_CANTOPEN
|
|
55
|
+
// 2026-07-17:hermes 装机后默认 cwd 无 ./data/ → 用户看到"缺少数据库目录"
|
|
56
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
57
|
+
const db = new Database(dbPath);
|
|
58
|
+
db.pragma("journal_mode = WAL");
|
|
59
|
+
db.pragma("foreign_keys = ON");
|
|
60
|
+
runMigrations(db);
|
|
61
|
+
instance = db;
|
|
62
|
+
return db;
|
|
63
|
+
}
|
|
64
|
+
export function getDb() {
|
|
65
|
+
if (!instance) {
|
|
66
|
+
throw new Error("Database not initialized. Call initDb() first.");
|
|
67
|
+
}
|
|
68
|
+
return instance;
|
|
69
|
+
}
|
|
70
|
+
export function closeDb() {
|
|
71
|
+
if (instance) {
|
|
72
|
+
instance.close();
|
|
73
|
+
instance = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const entry = process.argv[1];
|
|
77
|
+
if (entry && fileURLToPath(import.meta.url) === entry) {
|
|
78
|
+
// CLI 模式:默认 ~/.libero/libero.db(与 server.ts 保持一致)
|
|
79
|
+
const dbPath = process.env.DB_PATH ?? join(homedir(), ".libero", "libero.db");
|
|
80
|
+
initDb(dbPath);
|
|
81
|
+
console.log(`DB initialized at ${dbPath}`);
|
|
82
|
+
closeDb();
|
|
83
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-- 001_initial_schema: libero 2.0 核心表
|
|
2
|
+
-- K1 合规:所有业务表带 UUID PK + created_at + updated_at + deleted_at(软删除)
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS user_profile (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
display_name TEXT NOT NULL DEFAULT '',
|
|
7
|
+
expectations TEXT,
|
|
8
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
9
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
10
|
+
deleted_at TEXT
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS time_blocks (
|
|
14
|
+
id TEXT PRIMARY KEY,
|
|
15
|
+
user_id TEXT NOT NULL,
|
|
16
|
+
title TEXT NOT NULL,
|
|
17
|
+
category_id TEXT,
|
|
18
|
+
start_time TEXT NOT NULL,
|
|
19
|
+
end_time TEXT NOT NULL,
|
|
20
|
+
duration_minutes INTEGER,
|
|
21
|
+
notes TEXT,
|
|
22
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
23
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
24
|
+
deleted_at TEXT,
|
|
25
|
+
FOREIGN KEY (user_id) REFERENCES user_profile(id)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE TABLE IF NOT EXISTS categories (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
name TEXT NOT NULL,
|
|
31
|
+
emoji TEXT DEFAULT '',
|
|
32
|
+
color TEXT DEFAULT '',
|
|
33
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
34
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
35
|
+
deleted_at TEXT,
|
|
36
|
+
UNIQUE(name)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
40
|
+
version INTEGER PRIMARY KEY,
|
|
41
|
+
name TEXT NOT NULL,
|
|
42
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
43
|
+
);
|