skill-memo-ilife 0.3.2 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/SKILL.md +33 -34
  2. package/dist/checkin/index.d.ts +8 -0
  3. package/dist/checkin/index.d.ts.map +1 -0
  4. package/dist/checkin/index.js +8 -0
  5. package/dist/checkin/index.js.map +1 -0
  6. package/dist/checkin/receipt.d.ts +17 -0
  7. package/dist/checkin/receipt.d.ts.map +1 -0
  8. package/dist/checkin/receipt.js +63 -0
  9. package/dist/checkin/receipt.js.map +1 -0
  10. package/dist/checkin/routes.d.ts +4 -0
  11. package/dist/checkin/routes.d.ts.map +1 -1
  12. package/dist/checkin/routes.js +2 -2
  13. package/dist/checkin/routes.js.map +1 -1
  14. package/dist/cli/cmd_read.js +19 -53
  15. package/dist/cli/cmd_read.js.map +1 -1
  16. package/dist/cli/config.d.ts +4 -4
  17. package/dist/cli/config.d.ts.map +1 -1
  18. package/dist/cli/config.js +25 -4
  19. package/dist/cli/config.js.map +1 -1
  20. package/dist/cli/health/items.js +2 -2
  21. package/dist/cli/health/items.js.map +1 -1
  22. package/dist/cli/health.d.ts.map +1 -1
  23. package/dist/cli/health.js +3 -2
  24. package/dist/cli/health.js.map +1 -1
  25. package/dist/cli/keys.d.ts +6 -3
  26. package/dist/cli/keys.d.ts.map +1 -1
  27. package/dist/cli/keys.js +2 -5
  28. package/dist/cli/keys.js.map +1 -1
  29. package/dist/cli/registry.d.ts +1 -1
  30. package/dist/{fetch/db.d.ts → db/readonly.d.ts} +1 -1
  31. package/dist/db/readonly.d.ts.map +1 -0
  32. package/dist/{fetch/db.js → db/readonly.js} +5 -5
  33. package/dist/db/readonly.js.map +1 -0
  34. package/dist/help/lookup.d.ts +18 -1
  35. package/dist/help/lookup.d.ts.map +1 -1
  36. package/dist/help/lookup.js +53 -37
  37. package/dist/help/lookup.js.map +1 -1
  38. package/dist/help/sceneData.js +1 -1
  39. package/dist/help/scenes/checkin.d.ts +1 -1
  40. package/dist/help/scenes/checkin.js +1 -1
  41. package/dist/help/scenes/init.d.ts +1 -1
  42. package/dist/help/scenes/init.js +1 -1
  43. package/dist/help/scenes/memo.d.ts +1 -1
  44. package/dist/help/scenes/memo.js +1 -1
  45. package/dist/help/scenes/mood.d.ts +1 -1
  46. package/dist/help/scenes/mood.js +1 -1
  47. package/dist/help/scenes/remind.d.ts +1 -1
  48. package/dist/help/scenes/remind.js +2 -2
  49. package/dist/help/scenes/remind.js.map +1 -1
  50. package/dist/help/scenes/search.d.ts +1 -1
  51. package/dist/help/scenes/search.js +1 -1
  52. package/dist/help/scenes/sync.d.ts +1 -1
  53. package/dist/help/scenes/sync.js +1 -1
  54. package/dist/help/scenes/wish.d.ts +1 -1
  55. package/dist/help/scenes/wish.js +1 -1
  56. package/dist/index.d.ts +11 -4
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +11 -5
  59. package/dist/index.js.map +1 -1
  60. package/dist/init/diagnosis.d.ts +2 -1
  61. package/dist/init/diagnosis.d.ts.map +1 -1
  62. package/dist/init/diagnosis.js.map +1 -1
  63. package/dist/init/page.d.ts +3 -2
  64. package/dist/init/page.d.ts.map +1 -1
  65. package/dist/init/page.js +20 -10
  66. package/dist/init/page.js.map +1 -1
  67. package/dist/init/routes.d.ts +4 -1
  68. package/dist/init/routes.d.ts.map +1 -1
  69. package/dist/init/routes.js +14 -0
  70. package/dist/init/routes.js.map +1 -1
  71. package/dist/init/run.d.ts.map +1 -1
  72. package/dist/init/run.js +7 -1
  73. package/dist/init/run.js.map +1 -1
  74. package/dist/{fetch → memo}/batch.d.ts +6 -2
  75. package/dist/memo/batch.d.ts.map +1 -0
  76. package/dist/{fetch → memo}/batch.js +8 -4
  77. package/dist/memo/batch.js.map +1 -0
  78. package/dist/memo/category.d.ts.map +1 -0
  79. package/dist/{policy → memo}/category.js +1 -1
  80. package/dist/memo/category.js.map +1 -0
  81. package/dist/memo/commands.d.ts +3 -12
  82. package/dist/memo/commands.d.ts.map +1 -1
  83. package/dist/memo/commands.js +1 -9
  84. package/dist/memo/commands.js.map +1 -1
  85. package/dist/{policy → memo}/crud.d.ts +1 -1
  86. package/dist/memo/crud.d.ts.map +1 -0
  87. package/dist/{policy → memo}/crud.js +22 -7
  88. package/dist/memo/crud.js.map +1 -0
  89. package/dist/memo/index.d.ts +4 -2
  90. package/dist/memo/index.d.ts.map +1 -1
  91. package/dist/memo/index.js +4 -2
  92. package/dist/memo/index.js.map +1 -1
  93. package/dist/memo/media.d.ts.map +1 -0
  94. package/dist/{policy → memo}/media.js +2 -2
  95. package/dist/memo/media.js.map +1 -0
  96. package/dist/memo/receipt.d.ts +35 -0
  97. package/dist/memo/receipt.d.ts.map +1 -0
  98. package/dist/memo/receipt.js +62 -0
  99. package/dist/memo/receipt.js.map +1 -0
  100. package/dist/memo/receiptPage.d.ts +44 -0
  101. package/dist/memo/receiptPage.d.ts.map +1 -0
  102. package/dist/memo/receiptPage.js +50 -0
  103. package/dist/memo/receiptPage.js.map +1 -0
  104. package/dist/memo/routes.d.ts.map +1 -1
  105. package/dist/memo/routes.js +32 -0
  106. package/dist/memo/routes.js.map +1 -1
  107. package/dist/memo/run.d.ts +9 -8
  108. package/dist/memo/run.d.ts.map +1 -1
  109. package/dist/memo/run.js +140 -97
  110. package/dist/memo/run.js.map +1 -1
  111. package/dist/mood/routes.d.ts.map +1 -1
  112. package/dist/mood/routes.js +36 -0
  113. package/dist/mood/routes.js.map +1 -1
  114. package/dist/remind/index.d.ts +5 -2
  115. package/dist/remind/index.d.ts.map +1 -1
  116. package/dist/remind/index.js +5 -2
  117. package/dist/remind/index.js.map +1 -1
  118. package/dist/{policy/reminder.d.ts → remind/policy.d.ts} +1 -1
  119. package/dist/remind/policy.d.ts.map +1 -0
  120. package/dist/{policy/reminder.js → remind/policy.js} +2 -2
  121. package/dist/remind/policy.js.map +1 -0
  122. package/dist/remind/routes.d.ts +1 -2
  123. package/dist/remind/routes.d.ts.map +1 -1
  124. package/dist/remind/routes.js +32 -2
  125. package/dist/remind/routes.js.map +1 -1
  126. package/dist/remind/run.d.ts +1 -1
  127. package/dist/remind/run.d.ts.map +1 -1
  128. package/dist/remind/run.js +112 -7
  129. package/dist/remind/run.js.map +1 -1
  130. package/dist/{fetch/reminders.d.ts → remind/store.d.ts} +2 -2
  131. package/dist/remind/store.d.ts.map +1 -0
  132. package/dist/{fetch/reminders.js → remind/store.js} +3 -3
  133. package/dist/remind/store.js.map +1 -0
  134. package/dist/render/envelope.d.ts.map +1 -1
  135. package/dist/render/envelope.js +3 -2
  136. package/dist/render/envelope.js.map +1 -1
  137. package/dist/render/html.js +1 -1
  138. package/dist/render/html.js.map +1 -1
  139. package/dist/render/index.d.ts +4 -1
  140. package/dist/render/index.d.ts.map +1 -1
  141. package/dist/render/index.js +5 -3
  142. package/dist/render/index.js.map +1 -1
  143. package/dist/render/listPage.d.ts +34 -0
  144. package/dist/render/listPage.d.ts.map +1 -0
  145. package/dist/render/listPage.js +39 -0
  146. package/dist/render/listPage.js.map +1 -0
  147. package/dist/render/memoPageAssets.d.ts +32 -0
  148. package/dist/render/memoPageAssets.d.ts.map +1 -0
  149. package/dist/render/memoPageAssets.js +320 -0
  150. package/dist/render/memoPageAssets.js.map +1 -0
  151. package/dist/render/pageAssets.js +3 -3
  152. package/dist/render/pageAssets.js.map +1 -1
  153. package/dist/render/pages.d.ts +9 -2
  154. package/dist/render/pages.d.ts.map +1 -1
  155. package/dist/render/pages.js +8 -16
  156. package/dist/render/pages.js.map +1 -1
  157. package/dist/render/receipt.d.ts +12 -3
  158. package/dist/render/receipt.d.ts.map +1 -1
  159. package/dist/render/receipt.js +55 -10
  160. package/dist/render/receipt.js.map +1 -1
  161. package/dist/search/routes.d.ts.map +1 -1
  162. package/dist/search/routes.js +1 -0
  163. package/dist/search/routes.js.map +1 -1
  164. package/dist/search/run.d.ts +11 -3
  165. package/dist/search/run.d.ts.map +1 -1
  166. package/dist/search/run.js +130 -11
  167. package/dist/search/run.js.map +1 -1
  168. package/dist/shared/commandSpec.d.ts +4 -5
  169. package/dist/shared/commandSpec.d.ts.map +1 -1
  170. package/dist/shared/errors.d.ts.map +1 -0
  171. package/dist/shared/errors.js.map +1 -0
  172. package/dist/{fetch → shared}/paths.d.ts +1 -1
  173. package/dist/shared/paths.d.ts.map +1 -0
  174. package/dist/{fetch → shared}/paths.js +3 -3
  175. package/dist/shared/paths.js.map +1 -0
  176. package/dist/shared/validators.d.ts +3 -0
  177. package/dist/shared/validators.d.ts.map +1 -0
  178. package/dist/shared/validators.js +15 -0
  179. package/dist/shared/validators.js.map +1 -0
  180. package/dist/sync/auth.d.ts.map +1 -0
  181. package/dist/{fetch → sync}/auth.js +3 -3
  182. package/dist/sync/auth.js.map +1 -0
  183. package/dist/sync/commands.d.ts.map +1 -1
  184. package/dist/sync/commands.js.map +1 -1
  185. package/dist/sync/feishu.d.ts.map +1 -0
  186. package/dist/{fetch → sync}/feishu.js +9 -9
  187. package/dist/sync/feishu.js.map +1 -0
  188. package/dist/sync/index.d.ts +5 -2
  189. package/dist/sync/index.d.ts.map +1 -1
  190. package/dist/sync/index.js +4 -2
  191. package/dist/sync/index.js.map +1 -1
  192. package/dist/sync/run.d.ts +1 -1
  193. package/dist/sync/run.d.ts.map +1 -1
  194. package/dist/sync/run.js +2 -1
  195. package/dist/sync/run.js.map +1 -1
  196. package/dist/{fetch → sync}/sentinel.d.ts +1 -1
  197. package/dist/sync/sentinel.d.ts.map +1 -0
  198. package/dist/{fetch → sync}/sentinel.js +1 -2
  199. package/dist/sync/sentinel.js.map +1 -0
  200. package/dist/triggers/routes.generated.d.ts +1 -1
  201. package/dist/triggers/routes.generated.d.ts.map +1 -1
  202. package/dist/triggers/routes.generated.js +19 -6
  203. package/dist/triggers/routes.generated.js.map +1 -1
  204. package/dist/triggers/routing.d.ts +7 -0
  205. package/dist/triggers/routing.d.ts.map +1 -0
  206. package/dist/triggers/routing.js +35 -0
  207. package/dist/triggers/routing.js.map +1 -0
  208. package/dist/wish/complete.d.ts +1 -1
  209. package/dist/wish/complete.d.ts.map +1 -1
  210. package/dist/wish/complete.js +1 -1
  211. package/dist/wish/complete.js.map +1 -1
  212. package/dist/wish/due.d.ts +1 -1
  213. package/dist/wish/due.d.ts.map +1 -1
  214. package/dist/wish/due.js +1 -1
  215. package/dist/wish/due.js.map +1 -1
  216. package/dist/wish/ensure.d.ts +2 -2
  217. package/dist/wish/ensure.d.ts.map +1 -1
  218. package/dist/wish/ensure.js +2 -2
  219. package/dist/wish/ensure.js.map +1 -1
  220. package/dist/wish/gate.d.ts +1 -1
  221. package/dist/wish/gate.d.ts.map +1 -1
  222. package/dist/wish/gate.js +1 -1
  223. package/dist/wish/gate.js.map +1 -1
  224. package/dist/wish/index.d.ts +4 -0
  225. package/dist/wish/index.d.ts.map +1 -1
  226. package/dist/wish/index.js +7 -0
  227. package/dist/wish/index.js.map +1 -1
  228. package/dist/{policy/wish.d.ts → wish/policy.d.ts} +1 -1
  229. package/dist/wish/policy.d.ts.map +1 -0
  230. package/dist/{policy/wish.js → wish/policy.js} +3 -3
  231. package/dist/wish/policy.js.map +1 -0
  232. package/dist/wish/receipt.d.ts +45 -0
  233. package/dist/wish/receipt.d.ts.map +1 -0
  234. package/dist/wish/receipt.js +68 -0
  235. package/dist/wish/receipt.js.map +1 -0
  236. package/dist/wish/reconcile.d.ts +1 -1
  237. package/dist/wish/reconcile.d.ts.map +1 -1
  238. package/dist/wish/reconcile.js +2 -2
  239. package/dist/wish/reconcile.js.map +1 -1
  240. package/dist/wish/routes.d.ts.map +1 -1
  241. package/dist/wish/routes.js +11 -1
  242. package/dist/wish/routes.js.map +1 -1
  243. package/dist/wish/run.d.ts +11 -3
  244. package/dist/wish/run.d.ts.map +1 -1
  245. package/dist/wish/run.js +75 -7
  246. package/dist/wish/run.js.map +1 -1
  247. package/dist/wish/taskRemove.js +2 -2
  248. package/dist/wish/taskRemove.js.map +1 -1
  249. package/dist/wish/taskSync.d.ts +1 -1
  250. package/dist/wish/taskSync.d.ts.map +1 -1
  251. package/dist/wish/taskSync.js +3 -3
  252. package/dist/wish/taskSync.js.map +1 -1
  253. package/dist/wish/taskWrite.d.ts.map +1 -0
  254. package/dist/{fetch → wish}/taskWrite.js +2 -2
  255. package/dist/wish/taskWrite.js.map +1 -0
  256. package/dist/wish/tasks.d.ts.map +1 -0
  257. package/dist/{fetch → wish}/tasks.js +2 -2
  258. package/dist/wish/tasks.js.map +1 -0
  259. package/dist/wish/wizards.d.ts +1 -1
  260. package/dist/wish/wizards.d.ts.map +1 -1
  261. package/dist/wish/wizards.js +1 -1
  262. package/dist/wish/wizards.js.map +1 -1
  263. package/package.json +4 -7
  264. package/templates/change_category.html +52 -28
  265. package/templates/init_report.html +15 -14
  266. package/templates/memo_query.html +59 -24
  267. package/templates/receipt.html +97 -27
  268. package/templates/sync_report.html +106 -98
  269. package/templates/wish_complete.html +48 -30
  270. package/templates/wish_plan.html +35 -20
  271. package/dist/fetch/auth.d.ts.map +0 -1
  272. package/dist/fetch/auth.js.map +0 -1
  273. package/dist/fetch/batch.d.ts.map +0 -1
  274. package/dist/fetch/batch.js.map +0 -1
  275. package/dist/fetch/db.d.ts.map +0 -1
  276. package/dist/fetch/db.js.map +0 -1
  277. package/dist/fetch/errors.d.ts.map +0 -1
  278. package/dist/fetch/errors.js.map +0 -1
  279. package/dist/fetch/feishu.d.ts.map +0 -1
  280. package/dist/fetch/feishu.js.map +0 -1
  281. package/dist/fetch/index.d.ts +0 -19
  282. package/dist/fetch/index.d.ts.map +0 -1
  283. package/dist/fetch/index.js +0 -13
  284. package/dist/fetch/index.js.map +0 -1
  285. package/dist/fetch/paths.d.ts.map +0 -1
  286. package/dist/fetch/paths.js.map +0 -1
  287. package/dist/fetch/reminders.d.ts.map +0 -1
  288. package/dist/fetch/reminders.js.map +0 -1
  289. package/dist/fetch/sentinel.d.ts.map +0 -1
  290. package/dist/fetch/sentinel.js.map +0 -1
  291. package/dist/fetch/taskWrite.d.ts.map +0 -1
  292. package/dist/fetch/taskWrite.js.map +0 -1
  293. package/dist/fetch/tasks.d.ts.map +0 -1
  294. package/dist/fetch/tasks.js.map +0 -1
  295. package/dist/policy/category.d.ts.map +0 -1
  296. package/dist/policy/category.js.map +0 -1
  297. package/dist/policy/crud.d.ts.map +0 -1
  298. package/dist/policy/crud.js.map +0 -1
  299. package/dist/policy/index.d.ts +0 -11
  300. package/dist/policy/index.d.ts.map +0 -1
  301. package/dist/policy/index.js +0 -8
  302. package/dist/policy/index.js.map +0 -1
  303. package/dist/policy/media.d.ts.map +0 -1
  304. package/dist/policy/media.js.map +0 -1
  305. package/dist/policy/reminder.d.ts.map +0 -1
  306. package/dist/policy/reminder.js.map +0 -1
  307. package/dist/policy/wakewords.d.ts +0 -14
  308. package/dist/policy/wakewords.d.ts.map +0 -1
  309. package/dist/policy/wakewords.js +0 -68
  310. package/dist/policy/wakewords.js.map +0 -1
  311. package/dist/policy/wish.d.ts.map +0 -1
  312. package/dist/policy/wish.js.map +0 -1
  313. /package/dist/{policy → memo}/category.d.ts +0 -0
  314. /package/dist/{policy → memo}/media.d.ts +0 -0
  315. /package/dist/{fetch → shared}/errors.d.ts +0 -0
  316. /package/dist/{fetch → shared}/errors.js +0 -0
  317. /package/dist/{fetch → sync}/auth.d.ts +0 -0
  318. /package/dist/{fetch → sync}/feishu.d.ts +0 -0
  319. /package/dist/{fetch → wish}/taskWrite.d.ts +0 -0
  320. /package/dist/{fetch → wish}/tasks.d.ts +0 -0
@@ -27,6 +27,10 @@
27
27
  --shadow-sm:0 1px 2px rgba(0,0,0,.04);
28
28
  --shadow-md:0 1px 3px rgba(0,0,0,.04),0 12px 36px rgba(0,0,0,.06);
29
29
  --shadow-lg:0 1px 3px rgba(0,0,0,.04),0 24px 48px rgba(0,0,0,.08);
30
+ /* #832 令牌收债:下面 7 个值原先散在规则里当字面色值用(t849 §2 禁令「色值只许用令牌」)。
31
+ 值逐字不变,只是搬进令牌定义地——规则里只剩 var()。 */
32
+ --ok-tint:#ebfaef;--warn-tint:#fff7e0;--err-tint:#ffe8e6;--idle-tint:#fafafa;
33
+ --idle-icon:#f0f0f2;--badge-neutral:#ececef;--desktop-bg:#ededf0;
30
34
  --font:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
31
35
  --font-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
32
36
  }
@@ -40,11 +44,15 @@ body{
40
44
  -moz-osx-font-smoothing:grayscale;
41
45
  padding:0 env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);
42
46
  }
47
+ /* #820 收尾:宽档版心对齐本批其余页(原来 480px,1280 下左右各空 415px;老技能同值沿用)。
48
+ 手机端不受影响(窄屏本来就是铺满)。 */
43
49
  .wrap{
44
- max-width:480px;
50
+ max-width:980px;
45
51
  margin:0 auto;
46
52
  padding:max(20px,env(safe-area-inset-top,0)) 16px calc(40px + env(safe-area-inset-bottom,0));
47
53
  }
54
+ /* 页级标题:本页原先没有 h1(视觉审查:34 页里唯一一页第一个元素就是导航胶囊)。 */
55
+ h1{font-size:34px;line-height:1.15;letter-spacing:-.035em;margin:0 0 12px}
48
56
 
49
57
  /* ===== 状态卡(首屏 · 结论优先) ===== */
50
58
  .status-card{
@@ -57,10 +65,10 @@ body{
57
65
  position:relative;
58
66
  overflow:hidden;
59
67
  }
60
- .status-card.ok{background:linear-gradient(180deg,#fff 0%,#ebfaef 100%)}
61
- .status-card.warn{background:linear-gradient(180deg,#fff 0%,#fff7e0 100%)}
62
- .status-card.err{background:linear-gradient(180deg,#fff 0%,#ffe8e6 100%)}
63
- .status-card.idle{background:linear-gradient(180deg,#fff 0%,#fafafa 100%)}
68
+ .status-card.ok{background:linear-gradient(180deg,var(--card) 0%,var(--ok-tint) 100%)}
69
+ .status-card.warn{background:linear-gradient(180deg,var(--card) 0%,var(--warn-tint) 100%)}
70
+ .status-card.err{background:linear-gradient(180deg,var(--card) 0%,var(--err-tint) 100%)}
71
+ .status-card.idle{background:linear-gradient(180deg,var(--card) 0%,var(--idle-tint) 100%)}
64
72
 
65
73
  .status-icon{
66
74
  width:56px;height:56px;
@@ -73,7 +81,7 @@ body{
73
81
  .status-card.ok .status-icon{background:var(--ok-soft);color:var(--ok)}
74
82
  .status-card.warn .status-icon{background:var(--warn-soft);color:var(--warn)}
75
83
  .status-card.err .status-icon{background:var(--err-soft);color:var(--err)}
76
- .status-card.idle .status-icon{background:#f0f0f2;color:var(--fg3)}
84
+ .status-card.idle .status-icon{background:var(--idle-icon);color:var(--fg3)}
77
85
 
78
86
  .status-title{
79
87
  font-size:22px;font-weight:700;
@@ -95,8 +103,12 @@ body{
95
103
  font-size:12px;
96
104
  color:var(--fg3);
97
105
  font-variant-numeric:tabular-nums;
106
+ /* 状态卡整体居中(`.status-card{text-align:center}`),这条 meta 带沿用居中:把键值行整体摆在
107
+ 带子中间——改前那句 `22:35 · 同步飞书` 也是居中的,本票只换形状、不改这条带的版式语法。 */
108
+ display:flex;justify-content:center;
98
109
  }
99
- .status-meta span+span::before{content:"·";margin:0 8px;color:var(--fg4)}
110
+ /* #878:状态行那枚 `·` 原本由伪元素生成(`.status-meta span+span::before{content:"·"}`),
111
+ 判据读不到、屏上却看得见;分隔改由版式承担 —— 状态行落成公共层的键值行(`ilife-block-fact-strip`)。 */
100
112
 
101
113
  /* ===== KPI 网格(第二屏 · 数字概览) ===== */
102
114
  .kpis{
@@ -130,7 +142,7 @@ body{
130
142
  }
131
143
  .kpi-num.zero{color:var(--fg4);font-weight:600}
132
144
  .kpi-label{font-size:13px;color:var(--fg2);font-weight:500}
133
- .kpi-hint{font-size:11px;color:var(--fg3);margin-top:3px;line-height:1.4}
145
+ .kpi-hint{font-size:12px;color:var(--fg3);margin-top:3px;line-height:1.4}
134
146
 
135
147
  /* ===== 明细卡(<details> 原生折叠) ===== */
136
148
  .detail{
@@ -171,7 +183,7 @@ body{
171
183
  min-width:22px;height:22px;padding:0 7px;
172
184
  border-radius:999px;
173
185
  font-size:12px;font-weight:700;
174
- background:#ececef;color:var(--fg2);
186
+ background:var(--badge-neutral);color:var(--fg2);
175
187
  font-variant-numeric:tabular-nums;
176
188
  }
177
189
  .detail-badge.ok{background:var(--ok-soft);color:var(--ok-fg)}
@@ -255,44 +267,40 @@ body{
255
267
  }
256
268
  .err-list li:last-child{margin-bottom:0}
257
269
 
258
- /* ===== 数据与日志 ===== */
259
- .data-panel{
260
- background:var(--card);
261
- border-radius:16px;
262
- box-shadow:var(--shadow-sm);
263
- padding:16px 18px;
264
- margin-top:14px;
265
- }
266
- .data-panel strong{font-size:14.5px}
267
- .data-panel .hint{font-size:12px;color:var(--fg3);margin-top:6px}
268
-
269
- /* ===== 移动端微调(已经在 480 内,只处理超小屏) ===== */
270
- @media(max-width:360px){
271
- .wrap{padding:14px 12px 32px}
272
- .status-card{padding:20px 16px}
273
- .status-title{font-size:20px}
274
- .kpi{padding:14px 12px}
275
- .kpi-num{font-size:22px}
276
- .detail summary{padding:13px 14px;font-size:14px}
277
- .detail-body{padding:0 14px 14px}
278
- }
270
+ /* ===== 页内导航(公共层目录形状 `ilife-block-toc`;#832 补:本页三屏,长页需定位) ===== */
271
+ #statusCard,#kpis,#details,#dataPanel{scroll-margin-top:20px}
272
+
273
+ /* ===== 超小屏微调已并入基样式 =====
274
+ #832:原先有一段 `@media(max-width:360px)` 的「超小屏微调」,而 360 不在仓内既有断点集合
275
+ (400/640/820/1001/1200,`t849-视觉基准.md` §2 禁令「零新断点」)里。本页是 mobile-first、
276
+ 基样式本来就是移动优先,那段括号只是把 320 档的内距再收 4px、把页题从 22px 降到 20px——
277
+ 删掉即回落到基样式(正文 ≥12px、安全区照旧由 body 的 `env(safe-area-inset-*)` 避让),
278
+ 三档验收宽(390/768/1440)读数一字不变。 */
279
279
 
280
280
  /* ===== PC 端:480 居中,背景留白(类 Apple Mail) ===== */
281
- @media(min-width:600px){
281
+ @media(min-width:640px){
282
282
  .wrap{padding-top:40px}
283
- body{background:#ededf0}
283
+ body{background:var(--desktop-bg)}
284
284
  }
285
285
 
286
286
  /* ===== reduce motion ===== */
287
287
  @media(prefers-reduced-motion:reduce){
288
288
  *{transition:none!important;animation:none!important}
289
289
  }
290
+
291
+ /* #870 · 表单控件命中区 ≥44×44px(t849 §2 硬线;实测基线 33 处不足全在这一族) */
292
+ input[type=text],input[type=date],input[type=search],input:not([type]),select{min-height:44px;box-sizing:border-box}
290
293
  </style>
291
294
  </head>
292
295
  <body>
293
- <div class="wrap">
296
+ <div class="wrap ilife-page-ui">
294
297
  <section id="injectError" style="display:none"></section>
295
298
 
299
+ <h1 id="title">备忘录同步</h1>
300
+
301
+ <!-- ===== 页内导航(公共层目录形状;#832:本页三屏,长页给定位) ===== -->
302
+ <nav class="ilife-block-toc jump" aria-label="页内导航"><a href="#statusCard">结论</a><a href="#kpis">统计</a><a href="#details">明细</a><a href="#dataPanel">数据</a></nav>
303
+
296
304
  <!-- ===== 状态卡(首屏 · 结论) ===== -->
297
305
  <section class="status-card" id="statusCard">
298
306
  <div class="status-icon" id="statusIcon">✓</div>
@@ -310,13 +318,19 @@ body{
310
318
  <!-- ===== 明细区(按需展开 · 原生 details) ===== -->
311
319
  <div id="details"></div>
312
320
 
313
- <!-- ===== 数据与日志(#299 08 硬标准) ===== -->
314
- <section class="data-panel" id="dataPanel">
315
- <strong>数据与日志</strong>
316
- <div class="hint">点复制数据保存本次同步结果 · 点复制日志用于反馈问题</div>
317
- <div class="hm-actions">
318
- <button class="copy ghost" onclick="copyData()">复制数据</button>
319
- <button class="copy ghost" onclick="copyLog()">复制日志</button>
321
+ <section class="ilife-block ilife-block-copy-block" id="dataPanel">
322
+ <div class="ilife-action-bar">
323
+ <div class="ilife-action-row ilife-action-row-ghost">
324
+ <div class="ilife-copy-menu-wrap">
325
+ <button type="button" class="ilife-copy-btn ilife-copy-btn-ghost" data-fmt-open="1" aria-haspopup="menu" aria-expanded="false" aria-label="复制数据(点开选格式)">复制数据</button>
326
+ <div class="ilife-copy-menu" role="menu">
327
+ <button type="button" class="ilife-copy-menu-item" data-fmt="text" data-t=""><span class="ilife-copy-menu-label">纯文本</span></button>
328
+ <button type="button" class="ilife-copy-menu-item" data-fmt="json" data-t=""><span class="ilife-copy-menu-label">JSON</span></button>
329
+ <button type="button" class="ilife-copy-menu-item" data-fmt="csv" data-t=""><span class="ilife-copy-menu-label">CSV</span></button>
330
+ </div>
331
+ </div>
332
+ <button type="button" class="ilife-copy-btn ilife-copy-btn-ghost" data-action-id="memo-copy-log">复制日志</button>
333
+ </div>
320
334
  </div>
321
335
  </section>
322
336
  </div>
@@ -330,7 +344,7 @@ var raw=document.getElementById("payload");
330
344
  var payload=null,perr=null;
331
345
  try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
332
346
  if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
333
- if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行备忘录同步(唤醒词:备忘录同步)",payload:null});return;}
347
+ if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行备忘录同步(唤醒词:备忘录同步)",payload:null});return;}
334
348
  window.__hmPayload=payload;
335
349
 
336
350
  function num(v){return (typeof v==='number'&&isFinite(v))?v:0}
@@ -351,13 +365,15 @@ function init(){
351
365
  // success: 同步报告已渲染(4 状态 fallback · success 路径)
352
366
  var synced = num(d.synced);
353
367
  var backfilled = num(d.backfilled);
354
- var dueAdded = num(d.due_added);
355
- var dueOverridden = num(d.due_overridden);
356
- var dueRemoved = num(d.due_removed);
368
+ // #832:载荷是回执对象原样(`runSync` 的 `extra`),键名一律驼峰——旧世代那份下划线写法
369
+ // 与本页的载荷对不上,六项统计全部读成 0(页面把「排期变更 3 条」印成 0)。此处照载荷改齐。
370
+ var dueAdded = num(d.dueAdded);
371
+ var dueOverridden = num(d.dueOverridden);
372
+ var dueRemoved = num(d.dueRemoved);
357
373
  var dueChanged = dueAdded + dueOverridden + dueRemoved;
358
- var skippedNoLocal = num(d.skipped_no_local_note);
359
- var skippedNoMemo = num(d.skipped_no_memo_id);
360
- var skippedAlready = num(d.skipped_already_done);
374
+ var skippedNoLocal = num(d.skippedNoLocalNote);
375
+ var skippedNoMemo = num(d.skippedNoMark);
376
+ var skippedAlready = num(d.skippedAlreadyDone);
361
377
  var totalSkipped = skippedNoLocal + skippedNoMemo + skippedAlready;
362
378
  var errs = (d.errors || []).length;
363
379
  var totalChanged = synced + backfilled + dueChanged;
@@ -366,48 +382,51 @@ function init(){
366
382
  if(errs > 0){
367
383
  card.className = 'status-card err';
368
384
  icon.textContent = '!';
369
- title.textContent = '同步完成 · ' + errs + ' 个错误';
370
- desc.innerHTML = '同步已执行,但有 <b>' + errs + '</b> 个错误需要关注。展开下方错误明细查看详情。';
385
+ title.textContent = '同步完成,' + errs + ' 个错误';
386
+ desc.innerHTML = '同步已执行,但有 <b>' + errs + '</b> 个错误需要关注。展开下方错误明细查看详情。';
371
387
  // #299:err 态 → Base errorReceipt(修正重试 = 重新同步)
372
388
  var er = document.getElementById('errorReceipt');
373
389
  er.style.display = 'block';
374
390
  er.innerHTML = window.errorReceipt({
375
- message: '同步完成 · ' + errs + ' 个错误',
376
- retryPrompt: '请重新运行备忘录同步(唤醒词:备忘录同步)',
391
+ message: '同步完成,' + errs + ' 个错误',
392
+ retryPrompt: '请重新运行备忘录同步(唤醒词:备忘录同步)',
377
393
  payload: null
378
394
  });
379
395
  }else if(totalChanged === 0 && totalSkipped === 0){
380
396
  card.className = 'status-card idle';
381
397
  icon.textContent = '—';
382
- title.textContent = '完全一致 · 无变化';
383
- desc.textContent = '本机与飞书已同步,本次没有需要处理的变更。';
398
+ title.textContent = '完全一致,无变化';
399
+ desc.textContent = '本机与飞书已同步,本次没有需要处理的变更。';
384
400
  }else if(synced > 0 || backfilled > 0){
385
401
  card.className = 'status-card ok';
386
402
  icon.textContent = '✓';
387
403
  title.textContent = '同步完成';
388
404
  var parts = [];
389
- if(synced > 0) parts.push('<b>' + synced + '</b> 条心愿在飞书勾选,本机已转打卡');
405
+ if(synced > 0) parts.push('<b>' + synced + '</b> 条心愿在飞书勾选,本机已转打卡');
390
406
  if(backfilled > 0) parts.push('<b>' + backfilled + '</b> 条本机心愿补建到飞书');
391
407
  if(dueChanged > 0) parts.push('<b>' + dueChanged + '</b> 条排期已按飞书更新');
392
- desc.innerHTML = parts.join('<br>') + '。';
408
+ // #820 收尾:这串是**并列的计数行**,不是一句话 —— 原先 join('<br>') 后再补一个「。」,
409
+ // 句号只挂在最后一行,读起来像「第一行没写完」(同两行标点不一)。并列行一律不带句尾标点。
410
+ desc.innerHTML = parts.join('<br>');
393
411
  }else{
394
412
  card.className = 'status-card warn';
395
- icon.textContent = '·';
396
- title.textContent = '同步完成 · 无变更';
397
- desc.innerHTML = '扫到飞书数据但本次没有实际变更。' + (totalSkipped > 0 ? '有 ' + totalSkipped + ' 条跳过,可展开查看。' : '');
413
+ // #820 收尾:状态图标原先是一枚「·」(拿标点当图标)——与「完全一致」那一档的破折号统一。
414
+ icon.textContent = '—';
415
+ title.textContent = '同步完成,无变更';
416
+ desc.innerHTML = '扫到飞书数据但本次没有实际变更。' + (totalSkipped > 0 ? '有 ' + totalSkipped + ' 条跳过,可展开查看。' : '');
398
417
  }
399
418
 
400
- /* ----- meta 行 ----- */
419
+ /* ----- meta 行(#878:`22:35 · 同步飞书` 那串改键值行,事实一条不减) ----- */
401
420
  function commandToChinese(c){return c==='sync-from-feishu'?'同步飞书':c}
402
- var metaParts = [];
403
- if(d.generated_at) metaParts.push('<span>' + fmtTime(d.generated_at) + '</span>');
404
- if(d.command) metaParts.push('<span>' + esc(commandToChinese(d.command)) + '</span>');
405
- meta.innerHTML = metaParts.join('');
421
+ var metaFacts = [];
422
+ if(d.generated_at) metaFacts.push({label:'生成时间', value:fmtTime(d.generated_at)});
423
+ if(d.scene&&d.scene.scene_id) metaFacts.push({label:'场景', value:commandToChinese(d.scene.scene_id)});
424
+ meta.innerHTML = window.factStrip(metaFacts);
406
425
 
407
426
  /* ----- KPI 网格 ----- */
408
427
  var kpis = [
409
- {n:synced, label:'完成同步', hint:'飞书上勾选的,本机已记为打卡', bar: synced>0?'ok':'', z:synced===0},
410
- {n:backfilled, label:'补建到飞书', hint:'本机心愿 → 飞书任务', bar: backfilled>0?'ok':'', z:backfilled===0},
428
+ {n:synced, label:'完成同步', hint:'飞书上勾选的,本机已记为打卡', bar: synced>0?'ok':'', z:synced===0},
429
+ {n:backfilled, label:'补建到飞书', hint:'本机心愿已建到飞书任务', bar: backfilled>0?'ok':'', z:backfilled===0},
411
430
  {n:dueChanged, label:'排期变更', hint:'已按飞书最新日期调整', bar: dueChanged>0?'warn':'', z:dueChanged===0},
412
431
  {n:totalSkipped, label:'跳过', hint:'未匹配到本机心愿', bar: totalSkipped>0?'warn':'', z:totalSkipped===0},
413
432
  ];
@@ -423,54 +442,42 @@ function init(){
423
442
  /* ----- 明细区(原生 details,按需展示) ----- */
424
443
  var details = [];
425
444
 
426
- // 1. 完成同步明细
445
+ // 1. 完成同步明细(D-29:回执只带计数、不带逐条明细,故只出这一种正文)
427
446
  if(synced > 0){
428
- var items = d.synced_items || [];
429
- var body = '';
430
- if(items.length > 0){
431
- body = '<ul class="item-list">' + items.map(function(it){
432
- return '<li>' +
433
- '<span class="item-id">#' + esc(it.id) + '</span>' +
434
- '<span class="item-content">' + esc(it.content) + '</span>' +
435
- '<span class="item-mark">✓</span>' +
436
- '</li>';
437
- }).join('') + '</ul>';
438
- }else{
439
- body = '<p>本次有 <b>' + synced + '</b> 条心愿在飞书勾选完成,本机已转为打卡记录。</p>' +
440
- '<p class="note">如需查看具体心愿,可用「查心愿」唤醒词查看本机心愿清单。</p>';
441
- }
442
- details.push(makeDetail('✓ 完成同步', 'ok', synced, body, true));
447
+ var body = '<p>本次有 <b>' + synced + '</b> 条心愿在飞书勾选完成,本机已转为打卡记录。</p>' +
448
+ '<p class="note">如需查看具体心愿,可用「查心愿」唤醒词查看本机心愿清单。</p>';
449
+ details.push(makeDetail('完成同步', 'ok', synced, body, true));
443
450
  }
444
451
 
445
452
  // 2. 补建明细
446
453
  if(backfilled > 0){
447
- var body2 = '<p>本次有 <b>' + backfilled + '</b> 条本机心愿补建到飞书 task,已建立双向关联。</p>';
448
- details.push(makeDetail('+ 补建到飞书', 'ok', backfilled, body2));
454
+ var body2 = '<p>本次有 <b>' + backfilled + '</b> 条本机心愿补建到飞书任务,已建立双向关联。</p>';
455
+ details.push(makeDetail('补建到飞书', 'ok', backfilled, body2));
449
456
  }
450
457
 
451
458
  // 3. 排期变更明细
452
459
  if(dueChanged > 0){
453
460
  var parts3 = [];
454
- if(dueAdded > 0) parts3.push('新增 due ' + dueAdded + ' 条');
455
- if(dueOverridden > 0) parts3.push('覆盖 due ' + dueOverridden + ' 条');
456
- if(dueRemoved > 0) parts3.push('清除 due ' + dueRemoved + ' 条');
457
- var body3 = '<p>本次排期变更:<b>' + parts3.join(' · ') + '</b>。</p>' +
458
- '<p class="note">飞书 task 的 due 时间已同步到本机心愿。飞书优先,本机跟随。</p>';
459
- details.push(makeDetail('📅 排期变更', 'warn', dueChanged, body3));
461
+ if(dueAdded > 0) parts3.push('新增排期 ' + dueAdded + ' 条');
462
+ if(dueOverridden > 0) parts3.push('覆盖排期 ' + dueOverridden + ' 条');
463
+ if(dueRemoved > 0) parts3.push('清除排期 ' + dueRemoved + ' 条');
464
+ var body3 = '<p>本次排期变更:<b>' + parts3.join(',') + '</b>。</p>' +
465
+ '<p class="note">飞书任务的排期已同步到本机心愿。飞书优先,本机跟随。</p>';
466
+ details.push(makeDetail('排期变更', 'warn', dueChanged, body3));
460
467
  }
461
468
 
462
469
  // 4. 跳过明细(平静展示)
463
470
  if(totalSkipped > 0){
464
471
  var skipParts = [];
465
- if(skippedNoLocal > 0) skipParts.push('<b>' + skippedNoLocal + '</b> 条在飞书已完成,但本机找不到对应心愿');
466
- if(skippedNoMemo > 0) skipParts.push('<b>' + skippedNoMemo + '</b> 条飞书 task 缺少 memo_id 字段');
472
+ if(skippedNoLocal > 0) skipParts.push('<b>' + skippedNoLocal + '</b> 条在飞书已完成,但本机找不到对应心愿');
473
+ if(skippedNoMemo > 0) skipParts.push('<b>' + skippedNoMemo + '</b> 条飞书任务缺少本机笔记编号');
467
474
  if(skippedAlready > 0) skipParts.push('<b>' + skippedAlready + '</b> 条之前已处理过');
468
- var body4 = '<p>本次跳过 ' + totalSkipped + ' 条:</p>' +
469
- '<p>' + skipParts.join(';<br>') + '。</p>';
475
+ var body4 = '<p>本次跳过 ' + totalSkipped + ' 条:</p>' +
476
+ '<p>' + skipParts.join('<br>') + '。</p>';
470
477
  if(skippedNoLocal > 0){
471
- body4 += '<p class="note">可能你最近清理过本机库,或这些 task 是飞书原生建的。通常无需操作。如需排查可用「查心愿」唤醒词查看本机心愿清单。</p>';
478
+ body4 += '<p class="note">可能你最近清理过本机库,或这些任务是飞书原生建的。通常无需操作。如需排查可用「查心愿」唤醒词查看本机心愿清单。</p>';
472
479
  }
473
- details.push(makeDetail('○ 跳过', 'warn', totalSkipped, body4));
480
+ details.push(makeDetail('跳过', 'warn', totalSkipped, body4));
474
481
  }
475
482
 
476
483
  // 5. 错误明细
@@ -478,7 +485,7 @@ function init(){
478
485
  var body5 = '<ul class="err-list">' + (d.errors||[]).map(function(e){
479
486
  return '<li>' + esc(e) + '</li>';
480
487
  }).join('') + '</ul>';
481
- details.push(makeDetail('⚠ 错误', 'err', errs, body5));
488
+ details.push(makeDetail('错误', 'err', errs, body5));
482
489
  }
483
490
 
484
491
  // 6. 全空兜底(empty 状态 · #299 Base emptyState)
@@ -501,10 +508,11 @@ function makeDetail(label, badgeClass, count, body, open){
501
508
  '</details>';
502
509
  }
503
510
 
504
- function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
505
- function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
511
+ function copyData(){window.memoAttachCopyArea();window.toast('数据已复制','人类可读快照,可粘贴到笔记存档',{icon:'copy'});}
512
+ function copyLog(){window.memoAttachCopyArea();window.toast('日志已复制','诊断信息,有异常时粘贴给开发者排查',{icon:'copy'});}
506
513
  window.copyData=copyData;
507
514
  window.copyLog=copyLog;
515
+ window.memoAttachCopyArea();
508
516
  init();
509
517
  })();
510
518
  </script>
@@ -13,7 +13,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei
13
13
  .eyebrow{font-size:13px;color:var(--blue);font-weight:800;letter-spacing:.08em;text-transform:uppercase;margin-bottom:10px}
14
14
  h1{font-size:36px;line-height:1.15;letter-spacing:-.035em;margin-bottom:12px}
15
15
  .lead{color:var(--fg2);font-size:17px}
16
- .meta{margin-top:14px;color:var(--fg3);font-size:13px}
16
+ /* #878:页头时刻行不再拿 `·` 顶版式,改落公共层的键值行(`#meta` 里装 `ilife-block-fact-strip`)。 */
17
17
  .badge{display:inline-block;background:var(--soft,#f5f8ff);color:var(--blue);padding:4px 11px;border-radius:999px;font-size:13px;font-weight:700;margin:2px 6px 2px 0}
18
18
  .badge.ok{background:#ecfff2;color:#178a3a}
19
19
  .badge.warn{background:#fff7e8;color:#b25b00}
@@ -42,24 +42,28 @@ pre{white-space:pre-wrap;background:#f5f5f7;color:var(--fg);border:1px solid var
42
42
  .notice{padding:12px 16px;border-radius:14px;margin:10px 0;font-size:14px}
43
43
  .notice.warn{background:#fff7e8;color:#b25b00}
44
44
  .notice.err{background:#fff5f5;color:#ff3b30}
45
- @media(max-width:800px){.wrap{padding:28px 14px 70px}.hero{padding:26px 20px}h1{font-size:30px}.kpi .stat{padding:12px}}
45
+ /* #820 收尾:断点取仓内既有集合(help 模板同档 820);原写 800 是新造的档位。 */
46
+ @media(max-width:820px){.wrap{padding:28px 14px 70px}.hero{padding:26px 20px}h1{font-size:30px}.kpi .stat{padding:12px}}
47
+
48
+ /* #870 · 表单控件命中区 ≥44×44px(t849 §2 硬线;实测基线 33 处不足全在这一族) */
49
+ input[type=text],input[type=date],input[type=search],input:not([type]),select{min-height:44px;box-sizing:border-box}
46
50
  </style>
47
51
  </head>
48
52
  <body>
49
- <div class="wrap">
53
+ <div class="wrap ilife-page-ui">
50
54
  <header class="hero">
51
55
  <h1 id="title">心愿完成向导</h1>
52
56
  <p class="lead" id="subtitle">数据加载中</p>
53
- <p class="meta" id="meta"></p>
57
+ <div id="meta"></div>
54
58
  </header>
55
59
  <section id="injectError" style="display:none"></section>
56
60
 
57
61
  <section class="kpi" id="kpis"></section>
58
62
 
59
63
  <section class="panel">
60
- <div style="font-weight:700;margin-bottom:10px">✏️ 默认打卡内容(可选)</div>
61
- <p style="color:var(--fg2);font-size:13px;margin-bottom:10px">填了会应用到所有勾选的心愿,也能每条单独改;不填就用心愿原本的内容当打卡内容。</p>
62
- <input type="text" id="globalContent" placeholder="如:今天完成了 / 2026-07-03 已打卡" />
64
+ <div style="font-weight:700;margin-bottom:10px">默认打卡内容(可选)</div>
65
+ <p style="color:var(--fg2);font-size:13px;margin-bottom:10px">填了会应用到所有勾选的心愿,也能每条单独改。不填就用心愿原本的内容当打卡内容。</p>
66
+ <input type="text" id="globalContent" placeholder="如:今天完成了 / 2026-07-03 已打卡" />
63
67
  <div class="toolbar" style="margin-top:14px">
64
68
  <button class="ghost" onclick="applyGlobalContent()">应用到所有勾选</button>
65
69
  <button class="ghost" onclick="selectAll(true)">全选</button>
@@ -70,21 +74,29 @@ pre{white-space:pre-wrap;background:#f5f5f7;color:var(--fg);border:1px solid var
70
74
  <section id="wishList"></section>
71
75
 
72
76
  <section class="panel">
73
- <div style="font-weight:700;margin-bottom:8px">📋 发给 AI 的指令</div>
74
- <p style="color:var(--fg2);font-size:13px;margin-bottom:12px">复制指令发给 AI,它会把这些心愿标记为完成(心愿转成一条打卡),改完给你回执。</p>
77
+ <div style="font-weight:700;margin-bottom:8px">发给助手的指令</div>
78
+ <p style="color:var(--fg2);font-size:13px;margin-bottom:12px">复制指令发给助手,它会把这些心愿标记为完成(心愿转成一条打卡),改完给你回执。</p>
75
79
  <div class="toolbar">
76
- <button class="primary" onclick="adopt()">📋 复制修改指令</button>
80
+ <button class="primary" onclick="adopt()">复制修改指令</button>
77
81
  </div>
78
82
  <div id="warnArea"></div>
83
+ <p class="small" id="previewNote" style="display:none">下面是复制出去的原文,里面的符号留给 AI 解析。</p>
79
84
  <pre id="promptOut" style="display:none"></pre>
80
85
  </section>
81
86
 
82
- <section class="panel">
83
- <strong>数据与日志</strong>
84
- <div class="hint">点复制数据保存当前心愿列表 · 点复制日志用于反馈问题(日志不含隐私内容)</div>
85
- <div class="hm-actions">
86
- <button class="copy ghost" onclick="copyData()">复制数据</button>
87
- <button class="copy ghost" onclick="copyLog()">复制日志</button>
87
+ <section class="ilife-block ilife-block-copy-block">
88
+ <div class="ilife-action-bar">
89
+ <div class="ilife-action-row ilife-action-row-ghost">
90
+ <div class="ilife-copy-menu-wrap">
91
+ <button type="button" class="ilife-copy-btn ilife-copy-btn-ghost" data-fmt-open="1" aria-haspopup="menu" aria-expanded="false" aria-label="复制数据(点开选格式)">复制数据</button>
92
+ <div class="ilife-copy-menu" role="menu">
93
+ <button type="button" class="ilife-copy-menu-item" data-fmt="text" data-t=""><span class="ilife-copy-menu-label">纯文本</span></button>
94
+ <button type="button" class="ilife-copy-menu-item" data-fmt="json" data-t=""><span class="ilife-copy-menu-label">JSON</span></button>
95
+ <button type="button" class="ilife-copy-menu-item" data-fmt="csv" data-t=""><span class="ilife-copy-menu-label">CSV</span></button>
96
+ </div>
97
+ </div>
98
+ <button type="button" class="ilife-copy-btn ilife-copy-btn-ghost" data-action-id="memo-copy-log">复制日志</button>
99
+ </div>
88
100
  </div>
89
101
  </section>
90
102
  </div>
@@ -98,7 +110,7 @@ var raw=document.getElementById("payload");
98
110
  var payload=null,perr=null;
99
111
  try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
100
112
  if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
101
- if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行心愿完成(唤醒词:心愿完成)",payload:null});return;}
113
+ if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行心愿完成(唤醒词:心愿完成)",payload:null});return;}
102
114
  window.__hmPayload=payload;
103
115
  function data(){return payload.data}
104
116
  function items(){return data().items||[]}
@@ -108,7 +120,10 @@ function init(){
108
120
  document.getElementById('title').textContent=d.title||'心愿完成向导';
109
121
  document.getElementById('subtitle').textContent=payload.message||'勾选要完成的心愿';
110
122
  var meta=d.meta||{};
111
- document.getElementById('meta').textContent=`生成时间:${d.generated_at||''} · 场景:${meta.command_cn||d.command||'wish-complete'}`;
123
+ document.getElementById('meta').innerHTML=window.factStrip([
124
+ {label:'生成时间', value:d.generated_at||''},
125
+ {label:'场景', value:meta.command_cn||d.command||'wish-complete'}
126
+ ]);
112
127
  if(d.default_content){document.getElementById('globalContent').value=d.default_content}
113
128
  renderKPIs();renderList();
114
129
  // success: 心愿列表已加载,等待用户勾选完成
@@ -120,7 +135,7 @@ function renderKPIs(){
120
135
  document.getElementById('kpis').innerHTML=[
121
136
  ['待完成',all.length,'勾选后转打卡'],
122
137
  ['已同步飞书',withFeishu,'完成后飞书任务同步标记完成'],
123
- ['其他',all.length-withFeishu,'没有飞书任务,只在本机完成'],
138
+ ['其他',all.length-withFeishu,'没有飞书任务,只在本机完成'],
124
139
  ].map(x=>`<div class="stat"><b>${x[1]}</b><span>${x[0]}</span><div style="color:var(--fg3);font-size:12px;margin-top:4px">${esc(x[2])}</div></div>`).join('');
125
140
  }
126
141
 
@@ -151,8 +166,8 @@ ${w.feishu_task_guid?`<span class="badge ok">已同步飞书</span>`:'<span clas
151
166
  ${w.due?`<span class="badge warn">原排期:${esc(w.due)}</span>`:''}
152
167
  </div>
153
168
  <div class="wish-content-input">
154
- <label style="color:var(--fg2);font-size:13px;display:block;margin-bottom:6px">打卡内容(覆盖)</label>
155
- <textarea id="content_${w.id}" placeholder="默认使用:${esc(w.content).slice(0,20)}${w.content.length>20?'…':''}"></textarea>
169
+ <label style="color:var(--fg2);font-size:13px;display:block;margin-bottom:6px">打卡内容(覆盖)</label>
170
+ <textarea id="content_${w.id}" placeholder="默认使用:${esc(w.content).slice(0,20)}${w.content.length>20?'…':''}"></textarea>
156
171
  </div>
157
172
  </article>`;
158
173
  }
@@ -191,21 +206,21 @@ function selectedRows(){
191
206
  function buildPrompt(rows,ctx){
192
207
  if(!rows.length) return '未选择任何心愿';
193
208
  return [
194
- '① 场景: 我用心愿完成向导,标记 '+rows.length+' 个心愿为已完成',
209
+ '① 场景: 我用心愿完成向导,标记 '+rows.length+' 个心愿为已完成',
195
210
  '',
196
- '② 数据(要完成的心愿):',
197
- ...rows.map(r=>` · 心愿 #${r.id} "${r.content}" → 打卡内容: "${r.override||r.content}"${r.has_feishu?' (飞书任务同步完成)':''}`),
211
+ '② 数据(要完成的心愿):',
212
+ ...rows.map(r=>` · 心愿 #${r.id} "${r.content}" → 打卡内容: "${r.override||r.content}"${r.has_feishu?' (飞书任务同步完成)':''}`),
198
213
  '',
199
- '③ 期望: 请把这些心愿标记为完成(每个心愿转成一条打卡),有飞书任务的心愿同步标记完成;完成后给我回执。',
214
+ '③ 期望: 请把这些心愿标记为完成(每个心愿转成一条打卡),有飞书任务的心愿同步标记完成;完成后给我回执。',
200
215
  '',
201
- '④ 来源: 心愿完成向导 · '+ctx.generated_at,
216
+ '④ 来源: 心愿完成向导 · '+ctx.generated_at,
202
217
  ].join('\n');
203
218
  }
204
219
 
205
220
  function warnIfAny(rows){
206
221
  var nofb=rows.filter(r=>!r.has_feishu);
207
222
  if(nofb.length){
208
- document.getElementById('warnArea').innerHTML=`<div class="notice warn">ℹ️ ${nofb.length} 条心愿未同步飞书,完成时不会触发飞书联动</div>`;
223
+ document.getElementById('warnArea').innerHTML=`<div class="notice warn">ℹ️ ${nofb.length} 条心愿未同步飞书,完成时不会触发飞书联动</div>`;
209
224
  } else {
210
225
  document.getElementById('warnArea').innerHTML='';
211
226
  }
@@ -221,17 +236,20 @@ function adopt(){
221
236
  var text=buildPrompt(rows,ctx);
222
237
  var out=document.getElementById('promptOut');
223
238
  out.textContent=text;out.style.display='block';
239
+ // 说明与预览一起出现(#820 收尾:原先它挂在按钮上方的说明里,讲的是点完才看得到的东西)
240
+ document.getElementById('previewNote').style.display='block';
224
241
  window.copyText(text,{silent:true});
225
- window.toast('指令已复制','粘贴发给 AI 即可执行',{icon:'ok'});
242
+ window.toast('指令已复制','粘贴发给助手 即可执行',{icon:'ok'});
226
243
  }
227
244
 
228
- function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
229
- function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
245
+ function copyData(){window.memoAttachCopyArea();window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
246
+ function copyLog(){window.memoAttachCopyArea();window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
230
247
  window.applyGlobalContent=applyGlobalContent;
231
248
  window.selectAll=selectAll;
232
249
  window.adopt=adopt;
233
250
  window.copyData=copyData;
234
251
  window.copyLog=copyLog;
252
+ window.memoAttachCopyArea();
235
253
  init();
236
254
  })();
237
255
  </script>