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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WeChat 服务号入口。公网 80 + 443。只挂 /wechat。
|
|
4
|
+
* 凭证:WECHAT_TOKEN / WECHAT_APP_ID / WECHAT_APP_SECRET(可来自 /root/.libero/weixin.env)
|
|
5
|
+
*/
|
|
6
|
+
import { serve } from "@hono/node-server";
|
|
7
|
+
import { createServer as createHttpsServer } from "node:https";
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { initDb, closeDb } from "../data/db.js";
|
|
12
|
+
import { createToolRuntime } from "./server-core.js";
|
|
13
|
+
import { createRepos } from "./src/repo/factory.js";
|
|
14
|
+
import { issueShortToken } from "./src/rest/short-token.js";
|
|
15
|
+
import { tickReminderPush } from "./src/weixin/reminder-loop.js";
|
|
16
|
+
import { chatLlmFromEnv } from "./src/chat/from-env.js";
|
|
17
|
+
import { createWeixinApp } from "./src/weixin/app.js";
|
|
18
|
+
import { createWeixinSender } from "./src/weixin/custom-send.js";
|
|
19
|
+
import { handleWeixinText } from "./src/weixin/handle-text.js";
|
|
20
|
+
import { tencentAsrFromEnv } from "./src/weixin/tencent-asr.js";
|
|
21
|
+
function loadEnvFile(path) {
|
|
22
|
+
if (!existsSync(path))
|
|
23
|
+
return;
|
|
24
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
25
|
+
const t = line.trim();
|
|
26
|
+
if (!t || t.startsWith("#"))
|
|
27
|
+
continue;
|
|
28
|
+
const i = t.indexOf("=");
|
|
29
|
+
if (i < 1)
|
|
30
|
+
continue;
|
|
31
|
+
const k = t.slice(0, i);
|
|
32
|
+
const v = t.slice(i + 1);
|
|
33
|
+
if (!process.env[k])
|
|
34
|
+
process.env[k] = v;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
loadEnvFile("/root/.libero/weixin.env");
|
|
38
|
+
const TOKEN = process.env.WECHAT_TOKEN?.trim();
|
|
39
|
+
if (!TOKEN) {
|
|
40
|
+
console.error("[libero-weixin] FATAL: WECHAT_TOKEN is required");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const APP_ID = process.env.WECHAT_APP_ID?.trim();
|
|
44
|
+
const APP_SECRET = process.env.WECHAT_APP_SECRET?.trim();
|
|
45
|
+
const DEFAULT_USER = process.env.WECHAT_DEFAULT_USER_ID?.trim() || "libero";
|
|
46
|
+
const DB_PATH = process.env.DB_PATH ?? join(homedir(), ".libero", "libero.db");
|
|
47
|
+
const HTTP_PORT = Number(process.env.LIBERO_WEIXIN_PORT ?? "80");
|
|
48
|
+
const HTTPS_PORT = Number(process.env.LIBERO_WEIXIN_HTTPS_PORT ?? "443");
|
|
49
|
+
const HOST = process.env.LIBERO_WEIXIN_HOST ?? "0.0.0.0";
|
|
50
|
+
const CERT_DIR = process.env.LIBERO_WEIXIN_CERT_DIR ??
|
|
51
|
+
"/etc/letsencrypt/live/libero.kuibu.studio";
|
|
52
|
+
const db = initDb(DB_PATH);
|
|
53
|
+
const { registry } = createToolRuntime(db);
|
|
54
|
+
const llm = chatLlmFromEnv(process.env);
|
|
55
|
+
const asr = tencentAsrFromEnv(process.env);
|
|
56
|
+
// S2(INT-link-auth):秘钥已配则逐用户签发 homm 只读链接;未配回退 tk_main(零行为变化)。
|
|
57
|
+
const linkSecret = process.env.LIBERO_LINK_TOKEN_SECRET?.trim() || undefined;
|
|
58
|
+
const linkBaseUrl = process.env.LIBERO_HOMM_LINK_BASE?.trim() || "https://homm.kuibu.studio/camp.html";
|
|
59
|
+
const linkTtlSec = process.env.LIBERO_LINK_TOKEN_TTL_SEC ? Number(process.env.LIBERO_LINK_TOKEN_TTL_SEC) : 86400;
|
|
60
|
+
if (!linkSecret)
|
|
61
|
+
console.warn("[libero-weixin] LIBERO_LINK_TOKEN_SECRET 未配置:homm 链接回退 tk_main(无逐用户短 token)");
|
|
62
|
+
const mintLink = linkSecret
|
|
63
|
+
? (userId) => `${linkBaseUrl}?t=${issueShortToken({ userId, scope: "read", ttlSec: linkTtlSec }, linkSecret)}`
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!llm) {
|
|
66
|
+
console.error("[libero-weixin] chat disabled: set LIBERO_CHAT_BASE_URL / API_KEY / MODEL");
|
|
67
|
+
}
|
|
68
|
+
if (!asr) {
|
|
69
|
+
console.error("[libero-weixin] voice asr disabled: set TENCENT_SECRET_ID / TENCENT_SECRET_KEY");
|
|
70
|
+
}
|
|
71
|
+
if (!APP_ID || !APP_SECRET) {
|
|
72
|
+
console.error("[libero-weixin] WECHAT_APP_ID/SECRET missing; cannot push replies");
|
|
73
|
+
}
|
|
74
|
+
const sender = APP_ID && APP_SECRET
|
|
75
|
+
? createWeixinSender({ appId: APP_ID, appSecret: APP_SECRET })
|
|
76
|
+
: {
|
|
77
|
+
async sendText() {
|
|
78
|
+
throw new Error("weixin sender not configured");
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
// INT-weixin 提醒推送(2026-08-21):到点提醒经客服消息真推送(48h 窗口内)。
|
|
82
|
+
// 背景:8/20 用户设"午睡后叫我"没被叫——提醒只落库没人发。
|
|
83
|
+
const reminderRepos = createRepos(db);
|
|
84
|
+
const recentOpenids = new Map(); // openid → lastSeenMs
|
|
85
|
+
async function activeOpenids() {
|
|
86
|
+
const cutoff = Date.now() - 48 * 3600_000;
|
|
87
|
+
const fromMemory = [...recentOpenids.entries()]
|
|
88
|
+
.filter(([, t]) => t >= cutoff)
|
|
89
|
+
.sort((a, b) => b[1] - a[1])
|
|
90
|
+
.map(([o]) => o);
|
|
91
|
+
// 重启后内存丢失 → 从 chat_turns 找近 48h 会话兜底
|
|
92
|
+
const fromDb = db
|
|
93
|
+
.prepare("SELECT DISTINCT conversation_key FROM chat_turns WHERE conversation_key LIKE 'weixin:%' AND created_at > ? ORDER BY id DESC")
|
|
94
|
+
.all(new Date(cutoff).toISOString()).map((r) => r.conversation_key.slice("weixin:".length));
|
|
95
|
+
return [...new Set([...fromMemory, ...fromDb])];
|
|
96
|
+
}
|
|
97
|
+
const reminderTick = async () => {
|
|
98
|
+
try {
|
|
99
|
+
const r = await tickReminderPush({
|
|
100
|
+
userId: DEFAULT_USER,
|
|
101
|
+
getDue: (uid, until) => reminderRepos.reminderRepo.getDueReminders({ user_id: uid, until }),
|
|
102
|
+
markSent: (id) => reminderRepos.reminderRepo.markSent(id),
|
|
103
|
+
sendText: (openid, text) => sender.sendText(openid, text),
|
|
104
|
+
openids: await activeOpenids(),
|
|
105
|
+
});
|
|
106
|
+
if (r.sent || r.failed) {
|
|
107
|
+
console.error(`[libero-weixin] reminder tick: sent=${r.sent} undelivered=${r.failed}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
console.error("[libero-weixin] reminder tick failed:", e instanceof Error ? e.message : e);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
setInterval(reminderTick, 30_000);
|
|
115
|
+
const app = createWeixinApp({
|
|
116
|
+
token: TOKEN,
|
|
117
|
+
onText: (msg) => {
|
|
118
|
+
recentOpenids.set(msg.openid, Date.now());
|
|
119
|
+
return handleWeixinText({
|
|
120
|
+
msg,
|
|
121
|
+
userId: DEFAULT_USER,
|
|
122
|
+
registry,
|
|
123
|
+
llm,
|
|
124
|
+
sender,
|
|
125
|
+
asr,
|
|
126
|
+
mintLink,
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
logPath: "/tmp/libero-weixin.log",
|
|
130
|
+
});
|
|
131
|
+
serve({ fetch: app.fetch, port: HTTP_PORT, hostname: HOST }, (info) => {
|
|
132
|
+
console.error(`[libero-weixin] http://${info.address}:${info.port}/wechat`);
|
|
133
|
+
});
|
|
134
|
+
const keyPath = join(CERT_DIR, "privkey.pem");
|
|
135
|
+
const certPath = join(CERT_DIR, "fullchain.pem");
|
|
136
|
+
if (existsSync(keyPath) && existsSync(certPath)) {
|
|
137
|
+
serve({
|
|
138
|
+
fetch: app.fetch,
|
|
139
|
+
port: HTTPS_PORT,
|
|
140
|
+
hostname: HOST,
|
|
141
|
+
createServer: createHttpsServer,
|
|
142
|
+
serverOptions: {
|
|
143
|
+
key: readFileSync(keyPath),
|
|
144
|
+
cert: readFileSync(certPath),
|
|
145
|
+
},
|
|
146
|
+
}, (info) => {
|
|
147
|
+
console.error(`[libero-weixin] https://${info.address}:${info.port}/wechat`);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.error(`[libero-weixin] no TLS cert in ${CERT_DIR}; HTTPS not listening`);
|
|
152
|
+
}
|
|
153
|
+
function shutdown() {
|
|
154
|
+
closeDb();
|
|
155
|
+
process.exit(0);
|
|
156
|
+
}
|
|
157
|
+
process.on("SIGINT", shutdown);
|
|
158
|
+
process.on("SIGTERM", shutdown);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* COACH-MOD §3.2 — 复盘分析模型 schema。
|
|
5
|
+
* 与 entry.schema.ts 解耦:分析模型不属于 prescription/principle/research,
|
|
6
|
+
* 是复盘时脑装载的"分析框架/步骤"。全库唯一一个 is_default:true 作基线。
|
|
7
|
+
*/
|
|
8
|
+
export const analysisModelSchema = z.object({
|
|
9
|
+
id: z.string().regex(/^[a-z0-9-]+$/),
|
|
10
|
+
kind: z.literal("analysis-model"),
|
|
11
|
+
title: z.string().min(1),
|
|
12
|
+
is_default: z.boolean().optional().default(false),
|
|
13
|
+
triggers: z
|
|
14
|
+
.object({
|
|
15
|
+
// 手层粗筛用的情境标签(coachmod.suggest 匹配)
|
|
16
|
+
context_tags: z.array(z.string()).optional().default([]),
|
|
17
|
+
})
|
|
18
|
+
.optional()
|
|
19
|
+
.default({ context_tags: [] }),
|
|
20
|
+
description: z.string().min(1),
|
|
21
|
+
// 分析框架/步骤(脑装载后据此复盘)
|
|
22
|
+
method: z.array(z.string()).min(1, { message: "method 至少一步" }),
|
|
23
|
+
output_shape: z.array(z.string()).optional().default([]),
|
|
24
|
+
source: z.object({
|
|
25
|
+
ref: z.string().min(1),
|
|
26
|
+
evidence_level: z
|
|
27
|
+
.enum(["research-rct", "research-observational", "book", "framework", "folk"])
|
|
28
|
+
.optional(),
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export type AnalysisModel = z.infer<typeof analysisModelSchema>;
|
|
33
|
+
|
|
34
|
+
export function validateAnalysisModel(data: unknown): AnalysisModel {
|
|
35
|
+
return analysisModelSchema.parse(data);
|
|
36
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const triggerSignalSchema = z.object({
|
|
4
|
+
quadrant: z.enum(["能耗黑洞", "可放弃", "保持区", "亮点区"]).optional(),
|
|
5
|
+
daily_total_minutes: z.string().optional(), // like ">600"
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const knowledgeEntrySchema = z.object({
|
|
9
|
+
id: z.string().regex(/^[a-z0-9-]+$/),
|
|
10
|
+
kind: z.enum(["prescription", "principle", "research"]),
|
|
11
|
+
dimension: z.string().min(1),
|
|
12
|
+
title: z.string().min(1),
|
|
13
|
+
triggers: z.object({
|
|
14
|
+
signals: z.array(triggerSignalSchema).optional().default([]),
|
|
15
|
+
symptoms: z.array(z.string()).optional().default([]),
|
|
16
|
+
}).refine(v => (v.signals?.length || 0) + (v.symptoms?.length || 0) > 0, {
|
|
17
|
+
message: "triggers: signals 与 symptoms 至少有一个非空(否则永远召不回)",
|
|
18
|
+
}),
|
|
19
|
+
prescription: z.object({
|
|
20
|
+
one_liner: z.string(),
|
|
21
|
+
steps: z.array(z.string()).optional(),
|
|
22
|
+
micro_experiment: z.string(),
|
|
23
|
+
verify: z.string().optional(),
|
|
24
|
+
}).optional(),
|
|
25
|
+
source: z.object({
|
|
26
|
+
ref: z.string().min(1),
|
|
27
|
+
cite_url: z.string().optional(),
|
|
28
|
+
}),
|
|
29
|
+
evidence_level: z.enum(["research-rct", "research-observational", "book", "framework", "folk"]),
|
|
30
|
+
evidence_note: z.string().optional(),
|
|
31
|
+
applicability: z.object({
|
|
32
|
+
personas_fit: z.array(z.string()).default([]),
|
|
33
|
+
personas_avoid: z.array(z.string()).default([]),
|
|
34
|
+
boundaries: z.array(z.string()).default([]),
|
|
35
|
+
}).optional().default({ personas_fit: [], personas_avoid: [], boundaries: [] }),
|
|
36
|
+
tags: z.array(z.string()).optional().default([]),
|
|
37
|
+
}).refine(data => {
|
|
38
|
+
if (data.kind === "prescription") {
|
|
39
|
+
return data.prescription !== undefined
|
|
40
|
+
&& data.prescription.one_liner.length > 0
|
|
41
|
+
&& data.prescription.micro_experiment.length > 0;
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}, { message: "kind=prescription 时 prescription.one_liner 与 micro_experiment 必填" });
|
|
45
|
+
|
|
46
|
+
export type KnowledgeEntry = z.infer<typeof knowledgeEntrySchema>;
|
|
47
|
+
|
|
48
|
+
export function validateEntry(data: unknown): KnowledgeEntry {
|
|
49
|
+
return knowledgeEntrySchema.parse(data);
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* COACH-MOD §3.4 — 画像 schema。
|
|
5
|
+
* 画像驱动语气/视角自适应(呼应 S15 §6)。存于 _registry/personas.yaml 的 personas 列表。
|
|
6
|
+
*/
|
|
7
|
+
export const personaSchema = z.object({
|
|
8
|
+
id: z.string().regex(/^[a-z0-9-]+$/),
|
|
9
|
+
label: z.string().min(1),
|
|
10
|
+
traits: z.array(z.string()).optional().default([]),
|
|
11
|
+
constraints: z.array(z.string()).optional().default([]),
|
|
12
|
+
// 语气自适应说明(S15 §6)
|
|
13
|
+
tone_adjust: z.string().optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/** _registry/personas.yaml 顶层结构:{ personas: [...] } */
|
|
17
|
+
export const personaRegistrySchema = z.object({
|
|
18
|
+
personas: z.array(personaSchema).optional().default([]),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export type Persona = z.infer<typeof personaSchema>;
|
|
22
|
+
export type PersonaRegistry = z.infer<typeof personaRegistrySchema>;
|
|
23
|
+
|
|
24
|
+
export function validatePersona(data: unknown): Persona {
|
|
25
|
+
return personaSchema.parse(data);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function validatePersonaRegistry(data: unknown): PersonaRegistry {
|
|
29
|
+
return personaRegistrySchema.parse(data);
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* COACH-MOD §3.3 — 场景包 schema。
|
|
5
|
+
* 场景包 = 一个情境入口,内含推荐画像 + 推荐分析模型 + 场景专属提示。
|
|
6
|
+
* 装一个全来(recommends 展开),仍可单换(coachmod.load 单 id)。
|
|
7
|
+
*/
|
|
8
|
+
export const scenarioPackSchema = z.object({
|
|
9
|
+
id: z.string().regex(/^[a-z0-9-]+$/),
|
|
10
|
+
kind: z.literal("scenario-pack"),
|
|
11
|
+
title: z.string().min(1),
|
|
12
|
+
triggers: z.object({
|
|
13
|
+
// 手层粗筛用的情境标签(coachmod.suggest 匹配),至少一个否则永远召不回
|
|
14
|
+
context_tags: z
|
|
15
|
+
.array(z.string())
|
|
16
|
+
.min(1, { message: "triggers.context_tags 至少一个(否则永远召不回)" }),
|
|
17
|
+
}),
|
|
18
|
+
recommends: z.object({
|
|
19
|
+
persona_id: z.string().min(1),
|
|
20
|
+
analysis_model_ids: z
|
|
21
|
+
.array(z.string())
|
|
22
|
+
.min(1, { message: "recommends.analysis_model_ids 至少一个" }),
|
|
23
|
+
// 场景专属提示(脑装载后遵循)
|
|
24
|
+
subskill_prompt: z.string().min(1),
|
|
25
|
+
}),
|
|
26
|
+
description: z.string().min(1),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export type ScenarioPack = z.infer<typeof scenarioPackSchema>;
|
|
30
|
+
|
|
31
|
+
export function validateScenarioPack(data: unknown): ScenarioPack {
|
|
32
|
+
return scenarioPackSchema.parse(data);
|
|
33
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
id: review-default
|
|
2
|
+
kind: analysis-model
|
|
3
|
+
title: 通用复盘基线模型
|
|
4
|
+
is_default: true
|
|
5
|
+
triggers:
|
|
6
|
+
context_tags: []
|
|
7
|
+
description: 复盘默认基线——不假设特定人群/场景,只按"事实-感受-模式-下一步"四段温和过一遍
|
|
8
|
+
method:
|
|
9
|
+
- 先摆事实:这段时间实际发生了什么(记录/数据说了什么,不加评判)
|
|
10
|
+
- 再看感受:哪些让你有能量、哪些消耗你(对齐评分/情绪)
|
|
11
|
+
- 找模式:反复出现的黑洞或亮点是什么(不是单次波动)
|
|
12
|
+
- 落一步:只挑一个最小可动的下一步,别一次改太多
|
|
13
|
+
output_shape: [关键事实, 能量分布, 反复模式, 下一步微调]
|
|
14
|
+
source:
|
|
15
|
+
ref: libero coach 通用复盘框架(内置基线)
|
|
16
|
+
evidence_level: framework
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
id: review-summer-plan
|
|
2
|
+
kind: analysis-model
|
|
3
|
+
title: 暑期规划复盘模型
|
|
4
|
+
is_default: false
|
|
5
|
+
triggers:
|
|
6
|
+
context_tags: [暑假, 假期计划, 学生, 暑期]
|
|
7
|
+
description: 面向假期长周期的"目标-节律-弹性"三段复盘
|
|
8
|
+
method:
|
|
9
|
+
- 先看整段假期的目标锚点(学/玩/习惯各占多少,是否失衡)
|
|
10
|
+
- 再看每日节律是否可持续(是塞满还是留白,能不能天天照做)
|
|
11
|
+
- 留弹性缓冲,防计划一崩全崩(预设"崩了怎么接回")
|
|
12
|
+
output_shape: [目标达成度, 节律可持续性, 弹性评估, 下一步微调]
|
|
13
|
+
source:
|
|
14
|
+
ref: libero coach 假期规划框架(目标-节律-弹性)
|
|
15
|
+
evidence_level: framework
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-deep-warmup
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 深度预热仪式
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 任务启动困难
|
|
10
|
+
- 不知道从哪开始
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 固定开工动作:清理桌面 → 写 3 个子问题 → 关通知 → 全屏
|
|
13
|
+
steps:
|
|
14
|
+
- 清理桌面
|
|
15
|
+
- 写下 3 个子问题
|
|
16
|
+
- 关通知 + 全屏
|
|
17
|
+
micro_experiment: 明天开工前执行预热仪式(清理桌面+写3个子问题+关通知+全屏)
|
|
18
|
+
verify: 从坐下到进入状态的时长
|
|
19
|
+
source:
|
|
20
|
+
ref: 《深度工作》(Deep Work, Cal Newport)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [专注, 仪式]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-emotion-granularity
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 提升情绪词汇颗粒度
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 情绪波动影响工作
|
|
10
|
+
- 说不清什么感觉
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 把"我很糟"细分为"焦虑 / 失望 / 疲惫",然后先调身体(睡眠/进食/运动)
|
|
13
|
+
steps:
|
|
14
|
+
- 当感觉"很糟"时停下来
|
|
15
|
+
- 用更精确的词描述(焦虑/失望/疲惫/无聊)
|
|
16
|
+
- 先检查身体需求(睡眠/进食/运动)
|
|
17
|
+
micro_experiment: 下次感觉"很糟"时,用 3 个精确词描述,先喝杯水或走一走
|
|
18
|
+
verify: 情绪精确描述后是否更容易找到应对方法
|
|
19
|
+
source:
|
|
20
|
+
ref: 《情绪的解析》(How Emotions Are Made, Lisa Feldman Barrett)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [情绪, 自我觉察]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-env-engineering
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 环境工程四法则
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 分心频繁
|
|
10
|
+
- 环境干扰
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 让好习惯显而易见(如运动鞋放门口)+ 让坏习惯变难(App 移出主屏)
|
|
13
|
+
steps:
|
|
14
|
+
- 选一个好习惯,让它显而易见
|
|
15
|
+
- 选一个坏习惯,让它变困难
|
|
16
|
+
- 每天观察效果
|
|
17
|
+
micro_experiment: 运动鞋放门口 + 最分心的 App 移出主屏
|
|
18
|
+
verify: 好习惯被触发的次数、坏习惯被阻挡的次数
|
|
19
|
+
source:
|
|
20
|
+
ref: 《掌控习惯》(Atomic Habits, James Clear)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [环境, 习惯设计]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-extended-mind
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 用身体思考
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 卡壳
|
|
10
|
+
- 灵感枯竭
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 卡住时立刻起身走 10 分钟 + 手写关键问题 + 找人讲一遍
|
|
13
|
+
steps:
|
|
14
|
+
- 卡住时立刻起身
|
|
15
|
+
- 走 10 分钟(不戴耳机)
|
|
16
|
+
- 手写关键问题或找人讲一遍
|
|
17
|
+
micro_experiment: 下次卡壳时起身走 10 分钟
|
|
18
|
+
verify: 走动后是否能突破卡壳点
|
|
19
|
+
source:
|
|
20
|
+
ref: The Extended Mind (Annie Murphy Paul)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [认知, 身体]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-friction-barrier
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 增加行为摩擦力
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 刷视频/游戏过度
|
|
10
|
+
- 失控刷手机
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 手机放另一个房间充电 + App 设时间限制 + 卸载最常刷的那个
|
|
13
|
+
steps:
|
|
14
|
+
- 手机放另一个房间充电
|
|
15
|
+
- 给最常刷的 App 设时间限制
|
|
16
|
+
- 考虑卸载最常刷的那个
|
|
17
|
+
micro_experiment: 今晚手机放客厅充电,卧室不放手机
|
|
18
|
+
verify: 一天中无意识刷手机的时长变化
|
|
19
|
+
source:
|
|
20
|
+
ref: 《多巴胺国度》(Dopamine Nation, Anna Lembke)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [多巴胺, 行为设计]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: brain-peak-end
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 峰终定律——用峰值体验+强收尾设计子任务序列
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 长时间无正反馈
|
|
10
|
+
- 任务中途放弃
|
|
11
|
+
- 做完一大块却没成就感
|
|
12
|
+
prescription:
|
|
13
|
+
one_liner: 把子任务序列排成 前置一个快速小胜做峰 + 结尾一个可庆祝收尾做终
|
|
14
|
+
steps:
|
|
15
|
+
- 前端放一个 ≤5 分钟就能拿下的冷启动小胜,制造正反馈峰值
|
|
16
|
+
- 中段按循序渐进排,单块 ≤25 分钟
|
|
17
|
+
- 收尾子任务设计成明确完成、可庆祝的形态(如产出草稿或提交一次)
|
|
18
|
+
- 每完成一块立刻标记加一句鼓励,强化峰终记忆
|
|
19
|
+
micro_experiment: 选一个大任务,把第一块拆成 5 分钟内能拿下的小胜,做完立刻庆祝,观察后续启动阻力
|
|
20
|
+
verify: 序列完成后,主观成就感与干劲是否高于平铺直叙地做
|
|
21
|
+
source:
|
|
22
|
+
ref: 峰终定律(Kahneman, Fredrickson, Schreiber & Redelmeier, 1993)
|
|
23
|
+
evidence_level: research-observational
|
|
24
|
+
evidence_note: 原研究针对事后体验评价(痛觉与噪声实验);此处正向迁移到前向设计子任务序列,属合理外推而非直接 RCT
|
|
25
|
+
applicability:
|
|
26
|
+
boundaries:
|
|
27
|
+
- 原理讲事后回忆,用于事前设计是外推,别当铁律
|
|
28
|
+
- 若任务本身无明确胜利点(纯重复劳动),峰终设计收益有限
|
|
29
|
+
tags: [峰终定律, 正反馈, 子任务排序, 任务拆解]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: brain-pomodoro
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 番茄工作法
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 碎片化严重
|
|
10
|
+
- 频繁切换
|
|
11
|
+
- 任务启动困难
|
|
12
|
+
prescription:
|
|
13
|
+
one_liner: 25 分钟专注 + 5 分钟休息,休息期间集中回消息——既清了消息又不干扰专注
|
|
14
|
+
steps:
|
|
15
|
+
- 设定 25 分钟专注时段,只做一件事
|
|
16
|
+
- 时段内不切任务、不回消息(记到便签,不立刻处理)
|
|
17
|
+
- 5 分钟休息时集中处理积累的消息
|
|
18
|
+
- 循环
|
|
19
|
+
micro_experiment: 明天用一次番茄钟——25 分钟只做一件事,休息 5 分钟集中回消息
|
|
20
|
+
verify: 一天中任务切换次数是否下降、专注时段产出感知是否提升
|
|
21
|
+
source:
|
|
22
|
+
ref: 番茄工作法 (The Pomodoro Technique, Francesco Cirillo)
|
|
23
|
+
evidence_level: framework
|
|
24
|
+
evidence_note: 方法论框架,非单一 RCT 证据;P4 碎片化诊断的三个标准选项之一(另两个为环境工程/深度工作块)
|
|
25
|
+
applicability:
|
|
26
|
+
personas_fit: []
|
|
27
|
+
personas_avoid: []
|
|
28
|
+
boundaries:
|
|
29
|
+
- 对被强同步约束岗位(如客服、即时响应),25 分钟不可达窗口可能不现实
|
|
30
|
+
- 专注时长可按个人调整(部分人更适合 50/10 配比)
|
|
31
|
+
tags: [专注, 切换成本, 碎片化]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-revenge-bedtime
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 给转场时刻设替代动作
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 报复性熬夜
|
|
10
|
+
- 不想结束这一天
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 睡前 1 小时启动固定流程:断屏 → 洗漱 → 读纸质书 10 页
|
|
13
|
+
steps:
|
|
14
|
+
- 设定睡前 1 小时的闹钟
|
|
15
|
+
- 断屏(手机放客厅)
|
|
16
|
+
- 洗漱 → 读纸质书 10 页
|
|
17
|
+
micro_experiment: 今晚睡前 1 小时断屏+洗漱+读纸质书 10 页
|
|
18
|
+
verify: 实际入睡时间是否提前
|
|
19
|
+
source:
|
|
20
|
+
ref: Indistractable (Nir Eyal)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [睡眠, 习惯设计]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
id: brain-single-variable
|
|
2
|
+
kind: principle
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: 单一动作原则
|
|
5
|
+
triggers:
|
|
6
|
+
symptoms:
|
|
7
|
+
- 想全部改
|
|
8
|
+
- 多个痛点同时存在
|
|
9
|
+
prescription:
|
|
10
|
+
one_liner: 一个微实验只含一个核心动作,等复查确认稳了再加第二个
|
|
11
|
+
micro_experiment: 每次只执行一个微实验
|
|
12
|
+
source:
|
|
13
|
+
ref: libero 内部设计原则(来自 coaching-framework §5.3)
|
|
14
|
+
evidence_level: framework
|
|
15
|
+
tags: [方法论, 单一变量]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: brain-tiny-habits
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: brain-science
|
|
4
|
+
title: B=MAP 微习惯配方
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 拖延
|
|
10
|
+
- 任务反复无进展
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: "After 我[现有行为], I will [30秒微动作] + 完成立刻握拳庆祝"
|
|
13
|
+
steps:
|
|
14
|
+
- 找到锚点行为(你已经在做的事)
|
|
15
|
+
- 设计 ≤30 秒的微动作
|
|
16
|
+
- 完成立刻庆祝
|
|
17
|
+
micro_experiment: 设计一个 B=MAP 微习惯配方,试 3 天
|
|
18
|
+
verify: 微习惯的连续完成天数
|
|
19
|
+
source:
|
|
20
|
+
ref: 《福格行为模型》(Tiny Habits, BJ Fogg)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [习惯, 微习惯]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: energy-active-recovery
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: energy
|
|
4
|
+
title: 活动性恢复
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 能耗黑洞
|
|
8
|
+
symptoms:
|
|
9
|
+
- 午后低效
|
|
10
|
+
- 下午犯困
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 每天下午安排一次 15 分钟散步/拉伸——不戴耳机,观察环境
|
|
13
|
+
steps:
|
|
14
|
+
- 下午 2-3 点安排 15 分钟恢复
|
|
15
|
+
- 散步或拉伸,不戴耳机
|
|
16
|
+
- 观察周围环境而非思考工作
|
|
17
|
+
micro_experiment: 明天下午安排 15 分钟不戴耳机的散步
|
|
18
|
+
verify: 散步后的精神状态和下午工作效率
|
|
19
|
+
source:
|
|
20
|
+
ref: 《倦怠》(Burnout, Emily & Amelia Nagoski)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [恢复, 精力循环]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: energy-deliberate-rest
|
|
2
|
+
kind: prescription
|
|
3
|
+
dimension: energy
|
|
4
|
+
title: 刻意休息
|
|
5
|
+
triggers:
|
|
6
|
+
signals:
|
|
7
|
+
- quadrant: 可放弃
|
|
8
|
+
symptoms:
|
|
9
|
+
- 周末恢复失效
|
|
10
|
+
- 刷屏式休息
|
|
11
|
+
prescription:
|
|
12
|
+
one_liner: 用散步/手工/园艺等"活动性恢复"替代刷屏式休息
|
|
13
|
+
steps:
|
|
14
|
+
- 识别你的"假休息"行为(刷手机/追剧等)
|
|
15
|
+
- 替换为活动性恢复(散步/手工/园艺)
|
|
16
|
+
- 周末至少一次刻意休息
|
|
17
|
+
micro_experiment: 这个周末用一次散步替代一次刷手机
|
|
18
|
+
verify: 活动性恢复后的精力感知 vs 刷屏后的精力感知
|
|
19
|
+
source:
|
|
20
|
+
ref: 《休息的艺术》(The Art of Rest, Claudia Hammond)
|
|
21
|
+
evidence_level: book
|
|
22
|
+
tags: [休息, 恢复]
|