cortico-world-screen-diary 0.2.0 → 0.6.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/CHANGELOG.md +55 -0
- package/README.md +77 -0
- package/describe.json +83 -2
- package/dist/webui.js +1 -1
- package/dist/webui.js.map +3 -3
- package/package.json +32 -8
- package/src/ENV_PROMPT.en.md +1 -1
- package/src/ENV_PROMPT.md +1 -1
- package/src/apps.ts +88 -0
- package/src/book.ts +14 -0
- package/src/config.ts +268 -212
- package/src/definition.ts +12 -1
- package/src/flow.ts +178 -0
- package/src/model-text.ts +58 -42
- package/src/state.ts +28 -1
- package/src/tokens.ts +286 -0
- package/src/webui/client.ts +483 -206
- package/src/world.ts +714 -369
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- 词袋正式参与状态计算:应用词(按覆盖后的类别)与标题词一起,按窗口出现频次与时间衰减投票出质心
|
|
6
|
+
- 新增 `useWords`(默认开)、`wordWindowMinutes`(15)、`wordHalfLifeMinutes`(5)配置;关闭时回退到原来的类别 EMA
|
|
7
|
+
- `diary_state` 与时间线面板显示当前窗口高频词;应用词坐标/权重跟随类型覆盖,标题词跟随内置词库
|
|
8
|
+
- 雷达轨迹改为词袋质心经 EMA 平滑后的结果
|
|
9
|
+
## 0.5.4
|
|
10
|
+
|
|
11
|
+
- 简介与 README 互相指路:把「窥屏助手」作为配套扩展放在显眼位置,说明安装顺序与可选关系
|
|
12
|
+
- keywords 增加 screen-sense,方便市场搜索
|
|
13
|
+
## 0.5.3
|
|
14
|
+
|
|
15
|
+
- flow 事件改用本地时区时间戳(此前 checkin/reengage 写成 UTC,日志里比实际早 9 小时)
|
|
16
|
+
- checkin 尚未投递时,若 2 分钟内马上 reengage,调用 `withdrawPending` 撤回,避免模型同时收到“可能离开”和“回来了”
|
|
17
|
+
## 0.5.2
|
|
18
|
+
|
|
19
|
+
- 词汇表改用 CSS Grid:表头与数据列对齐,数字列右对齐
|
|
20
|
+
- 应用词行显示类型/衰减控件;标题词行明确标注「标题词 · 只读」,不再看起来像缺控件
|
|
21
|
+
## 0.5.1
|
|
22
|
+
|
|
23
|
+
- 中文分词从 2-gram 改为 ICU `Intl.Segmenter`:不再产生 能体/体记/忆与 这类垃圾词
|
|
24
|
+
- 补充中文停用词与「智能/记忆/行为/解析」等词库坐标
|
|
25
|
+
- 词汇表默认隐藏权重 0.1 的未知词,可勾选「显示未知词」查看全部
|
|
26
|
+
## 0.5.0
|
|
27
|
+
|
|
28
|
+
- 阶段 1:应用表升级为统一「词汇与衰减」表,应用名与窗口标题词同权
|
|
29
|
+
- 新增极简分词器:进程名去 .exe、英文/数字切词、中文 2-gram、停用词过滤
|
|
30
|
+
- 词库含坐标 [工作/娱乐, 轻/重] 与置信权重;只读频次诊断,不改变现有分类行为
|
|
31
|
+
- 只保存 token 与计数,不保存标题原文;通讯类在分词前过滤
|
|
32
|
+
## 0.4.2
|
|
33
|
+
|
|
34
|
+
- 应用与衰减表增加表头:应用 / 次数 / 默认类型 / 类型覆盖 / 流枯竭窗口(分钟)/ 操作
|
|
35
|
+
- 「类别默认」输入改为「默认」,并在悬停说明:留空跟随类型默认窗口
|
|
36
|
+
- 新增「开发者选项」页:当前 flow、规则列表(reengage/checkin)、配置与计数诊断
|
|
37
|
+
## 0.4.1
|
|
38
|
+
|
|
39
|
+
- 修复「应用与衰减」面板读取失败:补上 `apps` / `setApp` 的 invoke 分支
|
|
40
|
+
## 0.4.0
|
|
41
|
+
|
|
42
|
+
- 新增「应用与衰减」面板:列出出现过的应用、默认分类、出现次数;逐行覆盖类型(词性)与流枯竭窗口
|
|
43
|
+
- 新工具 `diary_apps`(列出)与 `diary_set_app`(设置/清除覆盖),宠物也能改
|
|
44
|
+
- 覆盖写入 `apps.json`;不改窗口标题存储
|
|
45
|
+
- 覆盖分类会同时改变投影与过滤(例如把某个应用从过滤改为开发)
|
|
46
|
+
## 0.3.0
|
|
47
|
+
|
|
48
|
+
- 新增 flow 层:只用窗口切换的时间梯度判断 busy / settling / depleted / away,不监听键鼠
|
|
49
|
+
- 按应用类型的衰退窗口:开发/文书 20 分、视频 30、游戏 12、浏览器 8(基准可配)
|
|
50
|
+
- 事件:`screen-diary.reengage`(默认开,piggyback)与可选的 `screen-diary.checkin`(默认关闭,debounce,冷却 60 分钟)
|
|
51
|
+
- 雷达去掉象限文字标签,只保留抽象轨迹
|
|
52
|
+
- `casual` 挂机/轻娱乐分类
|
|
53
|
+
## 0.2.1
|
|
54
|
+
|
|
55
|
+
- 升级回填:首次启动 0.2.x 时,若还没有状态采样,把 0.1.x 的旧细节按同一投影/过滤重放为状态采样
|
|
56
|
+
- 隐私迁移:回填时删除 0.1.x 遗留的通讯类与模糊 AI 条目
|
|
57
|
+
- 英文简介改成状态空间描述
|
|
3
58
|
## 0.2.0
|
|
4
59
|
|
|
5
60
|
- 二维状态空间:技术轴(重度/轻度)× 办公轴(工作/娱乐),应用先投影再 EMA 平滑
|
package/README.md
CHANGED
|
@@ -18,6 +18,16 @@ cortico-world-screen-diary
|
|
|
18
18
|
|
|
19
19
|
装完重启 Core,在「World 总览」里启用「活动日记」。生产方没启用或还没事件时,面板会提示等待。
|
|
20
20
|
|
|
21
|
+
## 🧩 配套扩展:窥屏助手
|
|
22
|
+
|
|
23
|
+
本包不做任何采集:前台窗口、截图和视觉速写都来自 [窥屏助手](https://www.npmjs.com/package/cortico-world-screen-sense)(`cortico-world-screen-sense`)。它把 `screen-sense.focus` / `screen-sense.screenshot` 写进事件流,本包只读事件、做状态投影与记忆整理。
|
|
24
|
+
|
|
25
|
+
- 只用窥屏助手也能工作;本包是它的**可选消费方**,用来把事件变成可回顾的平滑记忆。
|
|
26
|
+
- 没装窥屏助手时,活动日记不会报错,只会提示等待事件源。
|
|
27
|
+
- 安装顺序:先窥屏助手,再活动日记。
|
|
28
|
+
|
|
29
|
+
GitHub:[cortico-world-screen-sense](https://github.com/Wwhois163wW/cortico-world-screen-sense) · [cortico-world-screen-diary](https://github.com/Wwhois163wW/cortico-world-screen-diary)
|
|
30
|
+
|
|
21
31
|
## 二维状态空间
|
|
22
32
|
|
|
23
33
|
- **纵轴 技术轴**:重度(开发/折腾)↔ 轻度(看视频/轻办公)
|
|
@@ -33,6 +43,37 @@ cortico-world-screen-diary
|
|
|
33
43
|
| 视频 | bilibili、YouTube、播放器 | -0.5 | -0.8 |
|
|
34
44
|
| 浏览器 | Chrome/Edge | 按标题推断,默认 (0,0) | |
|
|
35
45
|
|
|
46
|
+
## 词袋状态(已参与计算)
|
|
47
|
+
|
|
48
|
+
面板里的「词汇与衰减」把**应用名和窗口标题词放在同一张表**:
|
|
49
|
+
|
|
50
|
+
- 列:词、次数、坐标 `[工作/娱乐, 轻/重]`、权重、类型/衰减(仅应用词)
|
|
51
|
+
- 应用名去掉 `.exe` 后整体是一个 token;标题按英文/数字切词、中文 2-gram、停用词过滤
|
|
52
|
+
- 强特征词(如 `bilibili`、`deepseek`、`harness`)权重高;中性容器(如 `chrome`)权重低
|
|
53
|
+
- 应用词可覆盖类型与流枯竭窗口;标题词目前只读
|
|
54
|
+
- 只保存 token 与计数,不保存标题原文;通讯类在分词前过滤
|
|
55
|
+
|
|
56
|
+
这一阶段只做诊断,**不改变现有分类与投影**。下一步会用“切换事件 + 时间衰减”做加权词袋质心,与现有 EMA 轨迹并行对比,再决定是否转正。
|
|
57
|
+
|
|
58
|
+
词袋现在**正式参与状态计算**(`useWords: true`):
|
|
59
|
+
|
|
60
|
+
- 每个应用词带它覆盖后的类别坐标与权重;标题词用内置词库坐标与权重
|
|
61
|
+
- 窗口内每个词按出现次数与时间衰减(半衰期默认 5 分钟)投票,得到 `(工作, 技术)` 质心
|
|
62
|
+
- 质心再经 `smoothing` 的 EMA 平滑,写入轨迹与采样
|
|
63
|
+
- 关闭 `useWords` 时回退到原来的“应用类别投影 + EMA”
|
|
64
|
+
- `diary_state` 与面板显示当前窗口的高频词,作为语义指纹
|
|
65
|
+
|
|
66
|
+
## 流枯竭:搭话时机,不是监控
|
|
67
|
+
|
|
68
|
+
不使用键鼠钩子,也不做全局输入监听;只利用**前台窗口切换的时间梯度**:
|
|
69
|
+
|
|
70
|
+
- 切换密集 = `busy`,不打扰
|
|
71
|
+
- 静默超过该应用的**衰退窗口** = `depleted`(专注或离开,不强行区分)
|
|
72
|
+
- `depleted` 后出现新切换 = `screen-diary.reengage`(piggyback),Coo 可以说“回来啦”
|
|
73
|
+
- 进入 `depleted` 时若开启主动搭话,发 `screen-diary.checkin`(debounce,默认关闭,带冷却);之后仍无切换则内部确认 `away`,不再发事件
|
|
74
|
+
|
|
75
|
+
衰退窗口按应用类型乘倍率:开发/文书 20 分钟、视频 30 分钟、游戏 12 分钟、浏览器 8 分钟(基准可配)。flow 状态只服务当次交互,不进入雷达、不做长期画像。
|
|
76
|
+
|
|
36
77
|
## 隐私与遗忘
|
|
37
78
|
|
|
38
79
|
- **通讯类直接过滤**:微信、QQ、Discord、Telegram、Slack、Teams、Zoom、邮件客户端等不投影、不落盘、不进入状态。
|
|
@@ -40,6 +81,14 @@ cortico-world-screen-diary
|
|
|
40
81
|
- **细节会淡忘**:窗口标题、速写、正文只保留 `detailHours`(默认 72 小时);之后只剩平滑状态与日摘要,保留 `keepDays`(默认 30 天)。
|
|
41
82
|
- 状态是“大概在干什么”,允许不精确;需要精确回忆时才用显式搜索。
|
|
42
83
|
|
|
84
|
+
## 从 0.1 升级
|
|
85
|
+
|
|
86
|
+
0.2.0 之前只保存详细条目,没有状态采样。升级到 0.2.x 后第一次启动会自动回填:
|
|
87
|
+
|
|
88
|
+
- 旧条目按同一套投影与平滑重放成状态采样(每 1 分钟最多一个点)
|
|
89
|
+
- 回填时顺带删除旧数据里的通讯类与模糊 AI 条目
|
|
90
|
+
- 如果之前已经产生过 0.2 的采样,则不会重复回填
|
|
91
|
+
|
|
43
92
|
## 工具
|
|
44
93
|
|
|
45
94
|
| 工具 | 用途 |
|
|
@@ -50,6 +99,13 @@ cortico-world-screen-diary
|
|
|
50
99
|
| `diary_search` | **显式回忆**:在短期细节记录里搜应用/标题/速写,最多 5 条 |
|
|
51
100
|
| `diary_stats` | 覆盖天数、状态采样数、主要状态 |
|
|
52
101
|
|
|
102
|
+
## 事件
|
|
103
|
+
|
|
104
|
+
| 事件 | 触发 | 默认 |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `screen-diary.reengage` | 长静默后重新出现窗口切换 | 开(piggyback) |
|
|
107
|
+
| `screen-diary.checkin` | 流枯竭且开启主动搭话 | 关(debounce,冷却 60 分钟) |
|
|
108
|
+
|
|
53
109
|
## 配置(`worlds.screen-diary.*`)
|
|
54
110
|
|
|
55
111
|
| 键 | 默认 | 含义 |
|
|
@@ -63,8 +119,15 @@ cortico-world-screen-diary
|
|
|
63
119
|
| `ignoreApps` | `""` | 额外过滤的应用名片段 |
|
|
64
120
|
| `smoothing` | `0.25` | EMA 平滑强度,0.05 平滑、0.9 灵敏 |
|
|
65
121
|
| `sampleSec` | `30` | 两次状态采样最小间隔 |
|
|
122
|
+
| `useWords` | `true` | 是否用词袋质心计算状态(关闭回退类别 EMA) |
|
|
123
|
+
| `wordWindowMinutes` | `15` | 词袋窗口长度 |
|
|
124
|
+
| `wordHalfLifeMinutes` | `5` | 词权重衰减半衰期 |
|
|
66
125
|
| `source` | `screen-sense` | 生产方 World id |
|
|
67
126
|
| `maxEventsPerPoll` | `500` | 单次导入上限 |
|
|
127
|
+
| `flowDecayMinutes` | `20` | 流枯竭基准窗口,按应用类型乘倍率 |
|
|
128
|
+
| `checkInEnabled` | `false` | 流枯竭时是否允许 Coo 主动搭话 |
|
|
129
|
+
| `awayAfterMinutes` | `10` | 搭话后仍无切换,多久确认离开 |
|
|
130
|
+
| `checkInCooldownMinutes` | `60` | 两次主动搭话的最小间隔 |
|
|
68
131
|
|
|
69
132
|
## 隐私
|
|
70
133
|
|
|
@@ -89,6 +152,20 @@ pnpm describe:extension <本包目录>
|
|
|
89
152
|
pnpm check:extension <本包目录>
|
|
90
153
|
```
|
|
91
154
|
|
|
155
|
+
## 发布
|
|
156
|
+
|
|
157
|
+
本包目前**手动发布**,不依赖 tag / 可信发布:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
pnpm install
|
|
161
|
+
pnpm run typecheck
|
|
162
|
+
pnpm run test
|
|
163
|
+
pnpm run build
|
|
164
|
+
npm publish --access public
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> 仓库没有自动发布 workflow;不要给本包打 `v*` tag,直接 `npm publish` 即可,它会先跑 `prepublishOnly` 检查。
|
|
168
|
+
|
|
92
169
|
## 许可
|
|
93
170
|
|
|
94
171
|
AGPL-3.0-or-later。
|
package/describe.json
CHANGED
|
@@ -100,15 +100,96 @@
|
|
|
100
100
|
"zh": "报覆盖天数、状态采样数与主要状态。",
|
|
101
101
|
"en": "Reports days, state samples and dominant states."
|
|
102
102
|
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "diary_apps",
|
|
106
|
+
"description": "List the applications seen most recently, their category and their per-app flow-decay override (if any).",
|
|
107
|
+
"parameters": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"limit": {
|
|
111
|
+
"type": "integer",
|
|
112
|
+
"minimum": 1,
|
|
113
|
+
"maximum": 50,
|
|
114
|
+
"description": "Most apps to return; default 15."
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"tags": [
|
|
119
|
+
"read"
|
|
120
|
+
],
|
|
121
|
+
"summary": {
|
|
122
|
+
"zh": "列出最近见过的应用、默认分类与逐应用覆盖项。",
|
|
123
|
+
"en": "Lists recently seen apps, their default category and per-app overrides."
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "diary_set_app",
|
|
128
|
+
"description": "Set or clear the per-app category (word class) and flow-decay minutes when the default classification feels wrong for this person.",
|
|
129
|
+
"parameters": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"properties": {
|
|
132
|
+
"app": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"description": "Application name exactly as listed by diary_apps."
|
|
135
|
+
},
|
|
136
|
+
"category": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"enum": [
|
|
139
|
+
"develop",
|
|
140
|
+
"game",
|
|
141
|
+
"casual",
|
|
142
|
+
"office",
|
|
143
|
+
"video",
|
|
144
|
+
"browser",
|
|
145
|
+
"ai",
|
|
146
|
+
"neutral",
|
|
147
|
+
"filtered"
|
|
148
|
+
],
|
|
149
|
+
"description": "Override category; omit to leave unchanged."
|
|
150
|
+
},
|
|
151
|
+
"decayMinutes": {
|
|
152
|
+
"type": "integer",
|
|
153
|
+
"minimum": 1,
|
|
154
|
+
"maximum": 180,
|
|
155
|
+
"description": "Per-app flow-decay minutes; 0 clears the override."
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"required": [
|
|
159
|
+
"app"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
"tags": [
|
|
163
|
+
"write"
|
|
164
|
+
],
|
|
165
|
+
"summary": {
|
|
166
|
+
"zh": "设置某个应用的类型(词性)与流枯竭窗口;0 清除覆盖。",
|
|
167
|
+
"en": "Sets an app category or flow-decay override; 0 clears it."
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"events": [
|
|
172
|
+
{
|
|
173
|
+
"type": "screen-diary.reengage",
|
|
174
|
+
"description": {
|
|
175
|
+
"zh": "窗口切换打断了专注或离开:用户回来了,适合轻声搭话。",
|
|
176
|
+
"en": "A window switch interrupted focus or absence: the user is back, a good moment for a light greeting."
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"type": "screen-diary.checkin",
|
|
181
|
+
"description": {
|
|
182
|
+
"zh": "流枯竭后的可选主动搭话(默认关闭,有冷却)。",
|
|
183
|
+
"en": "An optional proactive check-in when the flow depletes (off by default, rate limited)."
|
|
184
|
+
}
|
|
103
185
|
}
|
|
104
186
|
],
|
|
105
|
-
"events": [],
|
|
106
187
|
"prompts": [
|
|
107
188
|
{
|
|
108
189
|
"key": "worlds.screen-diary.envPrompt",
|
|
109
190
|
"title": "活动日记",
|
|
110
191
|
"role": "envPrompt",
|
|
111
|
-
"content": "## 活动日记\n\n你有一条由另一个 World(窥屏助手)的事件流整理出的“活动记忆”:前台切换被投影到二维状态空间(技术重度/轻度 × 工作/娱乐),再做平滑;细节只短期保留。\n\n规则:\n\n- 想判断使用者现在在干什么,用 `diary_state`;想看最近变化,用 `diary_recent`。\n- 想粗略回顾某天,用 `diary_today`(半小时分桶);它是模糊的,不要拿它当精确时间表。\n- 只有需要精确细节时才用 `diary_search`。平时的反应与思考不需要精确回忆,允许概括与轻微出入。\n- 通讯类应用已被过滤,AI 对话默认模糊为中性;不要追问或猜测这些内容。\n- 日记不保存原图;需要画面细节时用窥屏助手的 `screen_photo_show`。\n- 日记为空说明窥屏助手未安装、未启用或还没产生事件;不要反复重试。\n"
|
|
192
|
+
"content": "## 活动日记\n\n你有一条由另一个 World(窥屏助手)的事件流整理出的“活动记忆”:前台切换被投影到二维状态空间(技术重度/轻度 × 工作/娱乐),再做平滑;细节只短期保留。\n\n规则:\n\n- 想判断使用者现在在干什么,用 `diary_state`;想看最近变化,用 `diary_recent`。\n- 想粗略回顾某天,用 `diary_today`(半小时分桶);它是模糊的,不要拿它当精确时间表。\n- 只有需要精确细节时才用 `diary_search`。平时的反应与思考不需要精确回忆,允许概括与轻微出入。\n- 通讯类应用已被过滤,AI 对话默认模糊为中性;不要追问或猜测这些内容。\n- 日记不保存原图;需要画面细节时用窥屏助手的 `screen_photo_show`。\n- screen-diary.reengage 表示对方在安静一段时间后回来了,适合轻声打招呼,不要连续追问。\\n- screen-diary.checkin 表示流枯竭、可能在专注或离开;可以提醒休息或轻声确认,一次就够。\\n- 日记为空说明窥屏助手未安装、未启用或还没产生事件;不要反复重试。\n"
|
|
112
193
|
}
|
|
113
194
|
]
|
|
114
195
|
}
|
package/dist/webui.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function U(r){return r==="zh"||r==="zh-Hant"?{title:"\u6D3B\u52A8\u65E5\u8BB0",description:"\u4E8C\u7EF4\u72B6\u6001\u7A7A\u95F4\uFF1A\u6280\u672F\u91CD\u5EA6\u4E0E\u529E\u516C/\u5A31\u4E50\u7684\u5E73\u6ED1\u8F68\u8FF9\uFF1B\u7EC6\u8282\u4F1A\u968F\u65F6\u95F4\u6DE1\u5FD8\u3002",refresh:"\u5237\u65B0",clear:"\u6E05\u7A7A\u65E5\u8BB0",clearConfirm:"\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1F\u4E0D\u4F1A\u5F71\u54CD\u7AA5\u5C4F\u52A9\u624B\u7684\u76F8\u518C\u3002",cleared:i=>`\u5DF2\u5220\u9664 ${i} \u6761\u8BB0\u5F55`,empty:"\u8FD8\u6CA1\u6709\u8BB0\u5F55\u3002\u5148\u5B89\u88C5\u5E76\u542F\u7528\u7AA5\u5C4F\u52A9\u624B\uFF0C\u5207\u51E0\u6B21\u5E94\u7528\u540E\u8FD9\u91CC\u4F1A\u51FA\u73B0\u72B6\u6001\u8F68\u8FF9\u3002",waitingProducer:i=>`\u8FD8\u6CA1\u6709\u6536\u5230\u6765\u81EA ${i} \u7684\u4E8B\u4EF6\uFF1B\u786E\u8BA4\u7AA5\u5C4F\u52A9\u624B\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\u3002`,loading:"\u8BFB\u53D6\u4E2D\u2026",failed:"\u8BFB\u53D6\u5931\u8D25",stateTitle:"\u5F53\u524D\u72B6\u6001",current:i=>`\u5F53\u524D\uFF1A${i}`,trend:"\u6700\u8FD1\u8F68\u8FF9",noTrend:"\u8FD8\u6CA1\u6709\u8DB3\u591F\u7684\u91C7\u6837\u70B9",details:"\u8BE6\u7EC6\u8BB0\u5F55\uFF08\u663E\u5F0F\u56DE\u5FC6\uFF09",detailsNote:"\u53EA\u4FDD\u7559\u6700\u8FD1\u4E00\u6BB5\u65F6\u95F4\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u4E0D\u5728\u6B64\u5217\u3002",search:"\u641C\u7D22",searchPlaceholder:"\u641C\u5E94\u7528\u540D\u3001\u7A97\u53E3\u6807\u9898\u6216\u901F\u5199",noResults:"\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55",privacyNote:"\u901A\u8BAF\u7C7B\u5E94\u7528\u5DF2\u8FC7\u6EE4\uFF1BAI \u5BF9\u8BDD\u9ED8\u8BA4\u6A21\u7CCA\u4E3A\u4E2D\u6027\uFF1B\u7A97\u53E3\u6807\u9898\u53EA\u77ED\u671F\u4FDD\u7559\u3002",axisTech:"\u6280\u672F\u91CD\u5EA6",axisWork:"\u5DE5\u4F5C"}:{title:"Activity diary",description:"A two-axis state space: technical weight and work/entertainment, smoothed over time; details fade.",refresh:"Refresh",clear:"Clear diary",clearConfirm:"Delete detail entries and smoothed state? The screen-sense album is untouched.",cleared:i=>`Deleted ${i} records`,empty:"No entries yet. Install and enable screen-sense, switch apps a few times, then come back.",waitingProducer:i=>`No events from ${i} yet; check that screen-sense is installed and enabled.`,loading:"Loading\u2026",failed:"Could not load",stateTitle:"Current state",current:i=>`Now: ${i}`,trend:"Recent trajectory",noTrend:"Not enough samples yet",details:"Detail entries (explicit recall)",detailsNote:"Kept briefly only; communication apps are excluded.",search:"Search",searchPlaceholder:"app, window title or caption",noResults:"No matching entries",privacyNote:"Communication apps are filtered; AI chats are blurred to neutral; titles are kept briefly.",axisTech:"Technical",axisWork:"Work"}}var F="http://www.w3.org/2000/svg",c=(r,t={})=>{let i=document.createElementNS(F,r);for(let[T,x]of Object.entries(t))i.setAttribute(T,String(x));return i},O={mount(r){let t=U(r.language),i=r.language==="zh"||r.language==="zh-Hant",T=e=>i?e.zh:e.en,x=document.createElement("div");x.style.cssText="display:flex;flex-direction:column;gap:12px;height:100%;box-sizing:border-box;padding:14px;overflow:auto";let f=(e,n=!1)=>{let s=document.createElement("button");return s.textContent=e,s.style.cssText=`font:inherit;font-size:13px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:${n?"rgba(200,60,60,.12)":"transparent"};color:inherit`,s},G=e=>{let n=document.createElement("input");return n.placeholder=e,n.style.cssText="font:inherit;font-size:13px;padding:4px 8px;border-radius:6px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.45);min-width:200px",n},k=document.createElement("div");k.style.cssText="display:flex;gap:8px;align-items:center;flex-wrap:wrap";let g=document.createElement("span");g.style.cssText="opacity:.75;font-size:13px";let N=document.createElement("span");N.style.flex="1";let W=f(t.refresh),M=f(t.clear,!0);k.append(g,N,W,M);let w=document.createElement("div");w.style.cssText="font-size:14px;font-weight:600";let d=c("svg",{viewBox:"0 0 420 300",width:"100%",height:"300",style:"max-width:520px;align-self:center"}),v=document.createElement("div");v.style.cssText="display:flex;flex-direction:column;gap:6px";let D=document.createElement("div");D.textContent=t.privacyNote,D.style.cssText="font-size:12px;opacity:.7;max-width:640px",v.append(d,D);let C=document.createElement("div");C.textContent=t.details,C.style.cssText="font-size:13px;font-weight:600;opacity:.85;margin-top:6px";let E=document.createElement("div");E.textContent=t.detailsNote,E.style.cssText="font-size:12px;opacity:.65";let $=document.createElement("div");$.style.cssText="display:flex;gap:8px;align-items:center;flex-wrap:wrap";let h=G(t.searchPlaceholder),L=f(t.search),R=f(t.refresh);$.append(h,L,R);let p=document.createElement("div");p.style.cssText="font-size:12px;opacity:.8;min-height:16px;white-space:pre-wrap";let y=document.createElement("div");y.style.cssText="display:flex;flex-direction:column;gap:6px";let K=e=>{d.replaceChildren();let n=420,s=300,a=n/2,l=s/2,o=40,A=m=>a+Math.max(-1,Math.min(1,m))*(a-o),P=m=>l-Math.max(-1,Math.min(1,m))*(l-o);d.append(c("line",{x1:o,y1:l,x2:n-o,y2:l,stroke:"currentColor","stroke-opacity":.35,"stroke-width":1}),c("line",{x1:a,y1:o,x2:a,y2:s-o,stroke:"currentColor","stroke-opacity":.35,"stroke-width":1}));for(let[m,u,V]of[[-1,1,"\u5F00\u53D1"],[1,1,"\u5DE5\u4F5C"],[-1,-1,"\u89C6\u9891"],[1,-1,"\u6E38\u620F"]]){let B=c("text",{x:m<0?o:n-o-20,y:u>0?o-12:s-o+16,fill:"currentColor","fill-opacity":.55,"font-size":11});B.textContent=V,d.append(B)}let H=c("text",{x:a+6,y:o-12,fill:"currentColor","fill-opacity":.5,"font-size":10});H.textContent=t.axisTech;let I=c("text",{x:n-o-24,y:l-6,fill:"currentColor","fill-opacity":.5,"font-size":10});I.textContent=t.axisWork,d.append(H,I);let S=e.samples.slice(-120).reverse();if(S.length>=2){let m=c("polyline",{points:S.map(u=>`${A(u.work)},${P(u.tech)}`).join(" "),fill:"none",stroke:"#5fd4c8","stroke-width":2,"stroke-opacity":.85});d.append(m);for(let u of S.slice(0,12))d.append(c("circle",{cx:A(u.work),cy:P(u.tech),r:3,fill:"#5fd4c8","fill-opacity":.5}))}d.append(c("circle",{cx:A(e.current.work),cy:P(e.current.tech),r:7,fill:"#5fd4c8"}))},j=e=>{let n=document.createElement("div");n.style.cssText="display:flex;gap:10px;align-items:baseline;font-size:13px;padding:3px 0;border-bottom:1px solid rgba(128,128,128,.12)";let s=document.createElement("span");s.textContent=e.clock,s.style.cssText="font-family:ui-monospace,monospace;opacity:.7;flex:none";let a=document.createElement("span");a.textContent=e.app??"",a.style.cssText="font-family:ui-monospace,monospace;opacity:.85;flex:none;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";let l=document.createElement("span");return l.textContent=e.caption??e.text,l.style.cssText="flex:1;line-height:1.45",n.append(s,a,l),n},b=async(e="")=>{y.replaceChildren(),p.textContent="";try{let n=e?await r.invoke("search",[e,20]):await r.invoke("list",[{limit:50}]);if(n.entries.length===0){p.textContent=e?t.noResults:t.detailsNote;return}for(let s of n.entries)y.append(j(s))}catch(n){p.textContent=`${t.failed}: ${n instanceof Error?n.message:String(n)}`}},z=async()=>{g.textContent=t.loading;try{let e=await r.invoke("state");g.textContent=`${e.days} \u5929 \xB7 ${e.samples.length} \u91C7\u6837`,w.textContent=t.current(T(e.current)),e.samples.length===0&&(p.textContent=t.waitingProducer(e.source)),K(e),await b()}catch(e){g.textContent=`${t.failed}: ${e instanceof Error?e.message:String(e)}`}};return W.addEventListener("click",()=>{z()}),R.addEventListener("click",()=>{h.value="",b()}),L.addEventListener("click",()=>{b(h.value.trim())}),h.addEventListener("keydown",e=>{e.key==="Enter"&&b(h.value.trim())}),M.addEventListener("click",()=>{window.confirm(t.clearConfirm)&&(async()=>{try{let e=await r.invoke("clear",[]);p.textContent=t.cleared(e.removed),await z()}catch(e){p.textContent=`${t.failed}: ${e instanceof Error?e.message:String(e)}`}})()}),x.append(k,w,v,C,E,$,p,y),r.root.append(x),z(),{dispose(){}}}},Y={panels:{timeline:O}},Z=Y;export{Z as default};
|
|
1
|
+
function B(c){return c==="zh"||c==="zh-Hant"?{title:"\u6D3B\u52A8\u65E5\u8BB0",description:"\u4E8C\u7EF4\u72B6\u6001\u7A7A\u95F4\uFF1A\u6280\u672F\u91CD\u5EA6\u4E0E\u529E\u516C/\u5A31\u4E50\u7684\u5E73\u6ED1\u8F68\u8FF9\uFF1B\u7EC6\u8282\u4F1A\u968F\u65F6\u95F4\u6DE1\u5FD8\u3002",refresh:"\u5237\u65B0",clear:"\u6E05\u7A7A\u65E5\u8BB0",clearConfirm:"\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1F\u4E0D\u4F1A\u5F71\u54CD\u7AA5\u5C4F\u52A9\u624B\u7684\u76F8\u518C\u3002",cleared:r=>`\u5DF2\u5220\u9664 ${r} \u6761\u8BB0\u5F55`,empty:"\u8FD8\u6CA1\u6709\u8BB0\u5F55\u3002\u5148\u5B89\u88C5\u5E76\u542F\u7528\u7AA5\u5C4F\u52A9\u624B\uFF0C\u5207\u51E0\u6B21\u5E94\u7528\u540E\u8FD9\u91CC\u4F1A\u51FA\u73B0\u72B6\u6001\u8F68\u8FF9\u3002",waitingProducer:r=>`\u8FD8\u6CA1\u6709\u6536\u5230\u6765\u81EA ${r} \u7684\u4E8B\u4EF6\uFF1B\u786E\u8BA4\u7AA5\u5C4F\u52A9\u624B\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\u3002`,loading:"\u8BFB\u53D6\u4E2D\u2026",failed:"\u8BFB\u53D6\u5931\u8D25",stateTitle:"\u5F53\u524D\u72B6\u6001",current:r=>`\u5F53\u524D\uFF1A${r}`,trend:"\u6700\u8FD1\u8F68\u8FF9",noTrend:"\u8FD8\u6CA1\u6709\u8DB3\u591F\u7684\u91C7\u6837\u70B9",details:"\u8BE6\u7EC6\u8BB0\u5F55\uFF08\u663E\u5F0F\u56DE\u5FC6\uFF09",detailsNote:"\u53EA\u4FDD\u7559\u6700\u8FD1\u4E00\u6BB5\u65F6\u95F4\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u4E0D\u5728\u6B64\u5217\u3002",search:"\u641C\u7D22",searchPlaceholder:"\u641C\u5E94\u7528\u540D\u3001\u7A97\u53E3\u6807\u9898\u6216\u901F\u5199",noResults:"\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55",privacyNote:"\u901A\u8BAF\u7C7B\u5E94\u7528\u5DF2\u8FC7\u6EE4\uFF1BAI \u5BF9\u8BDD\u9ED8\u8BA4\u6A21\u7CCA\u4E3A\u4E2D\u6027\uFF1B\u7A97\u53E3\u6807\u9898\u53EA\u77ED\u671F\u4FDD\u7559\u3002",axisTech:"\u6280\u672F\u91CD\u5EA6",axisWork:"\u5DE5\u4F5C"}:{title:"Activity diary",description:"A two-axis state space: technical weight and work/entertainment, smoothed over time; details fade.",refresh:"Refresh",clear:"Clear diary",clearConfirm:"Delete detail entries and smoothed state? The screen-sense album is untouched.",cleared:r=>`Deleted ${r} records`,empty:"No entries yet. Install and enable screen-sense, switch apps a few times, then come back.",waitingProducer:r=>`No events from ${r} yet; check that screen-sense is installed and enabled.`,loading:"Loading\u2026",failed:"Could not load",stateTitle:"Current state",current:r=>`Now: ${r}`,trend:"Recent trajectory",noTrend:"Not enough samples yet",details:"Detail entries (explicit recall)",detailsNote:"Kept briefly only; communication apps are excluded.",search:"Search",searchPlaceholder:"app, window title or caption",noResults:"No matching entries",privacyNote:"Communication apps are filtered; AI chats are blurred to neutral; titles are kept briefly.",axisTech:"Technical",axisWork:"Work"}}var G="http://www.w3.org/2000/svg",P=(c,e={})=>{let r=document.createElementNS(G,c);for(let[T,f]of Object.entries(e))r.setAttribute(T,String(f));return r},j={mount(c){let e=B(c.language),r=c.language==="zh"||c.language==="zh-Hant",T=t=>r?t.zh:t.en,f=document.createElement("div");f.style.cssText="display:flex;flex-direction:column;gap:12px;height:100%;box-sizing:border-box;padding:14px;overflow:auto";let d=(t,a=!1)=>{let w=document.createElement("button");return w.textContent=t,w.style.cssText=`font:inherit;font-size:13px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:${a?"rgba(200,60,60,.12)":"transparent"};color:inherit`,w},k=t=>{let a=document.createElement("input");return a.placeholder=t,a.style.cssText="font:inherit;font-size:13px;padding:4px 8px;border-radius:6px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.45);min-width:200px",a},v=document.createElement("div");v.style.cssText="display:flex;gap:8px;align-items:center;flex-wrap:wrap";let y=document.createElement("span");y.style.cssText="opacity:.75;font-size:13px";let E=document.createElement("span");E.style.flex="1";let z=d(e.refresh),u=d(e.clear,!0);v.append(y,E,z,u);let $=document.createElement("div");$.style.cssText="font-size:14px;font-weight:600";let C=document.createElement("div");C.style.cssText="font-size:12px;opacity:.7";let o=P("svg",{viewBox:"0 0 420 300",width:"100%",height:"300",style:"max-width:520px;align-self:center"}),n=document.createElement("div");n.style.cssText="display:flex;flex-direction:column;gap:6px";let i=document.createElement("div");i.textContent=e.privacyNote,i.style.cssText="font-size:12px;opacity:.7;max-width:640px",n.append(o,i);let s=document.createElement("div");s.textContent=e.details,s.style.cssText="font-size:13px;font-weight:600;opacity:.85;margin-top:6px";let x=document.createElement("div");x.textContent=e.detailsNote,x.style.cssText="font-size:12px;opacity:.65";let l=document.createElement("div");l.style.cssText="display:flex;gap:8px;align-items:center;flex-wrap:wrap";let h=k(e.searchPlaceholder),D=d(e.search),b=d(e.refresh);l.append(h,D,b);let p=document.createElement("div");p.style.cssText="font-size:12px;opacity:.8;min-height:16px;white-space:pre-wrap";let g=document.createElement("div");g.style.cssText="display:flex;flex-direction:column;gap:6px";let I=t=>{o.replaceChildren();let a=420,w=300,M=a/2,S=w/2,L=40,R=N=>M+Math.max(-1,Math.min(1,N))*(M-L),U=N=>S-Math.max(-1,Math.min(1,N))*(S-L);o.append(P("line",{x1:L,y1:S,x2:a-L,y2:S,stroke:"currentColor","stroke-opacity":.35,"stroke-width":1}),P("line",{x1:M,y1:L,x2:M,y2:w-L,stroke:"currentColor","stroke-opacity":.35,"stroke-width":1}));let F=t.samples.slice(-120).reverse();if(F.length>=2){let N=P("polyline",{points:F.map(H=>`${R(H.work)},${U(H.tech)}`).join(" "),fill:"none",stroke:"#5fd4c8","stroke-width":2,"stroke-opacity":.85});o.append(N);for(let H of F.slice(0,12))o.append(P("circle",{cx:R(H.work),cy:U(H.tech),r:3,fill:"#5fd4c8","fill-opacity":.5}))}o.append(P("circle",{cx:R(t.current.work),cy:U(t.current.tech),r:7,fill:"#5fd4c8"}))},W=t=>{let a=document.createElement("div");a.style.cssText="display:flex;gap:10px;align-items:baseline;font-size:13px;padding:3px 0;border-bottom:1px solid rgba(128,128,128,.12)";let w=document.createElement("span");w.textContent=t.clock,w.style.cssText="font-family:ui-monospace,monospace;opacity:.7;flex:none";let M=document.createElement("span");M.textContent=t.app??"",M.style.cssText="font-family:ui-monospace,monospace;opacity:.85;flex:none;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";let S=document.createElement("span");return S.textContent=t.caption??t.text,S.style.cssText="flex:1;line-height:1.45",a.append(w,M,S),a},m=async(t="")=>{g.replaceChildren(),p.textContent="";try{let a=t?await c.invoke("search",[t,20]):await c.invoke("list",[{limit:50}]);if(a.entries.length===0){p.textContent=t?e.noResults:e.detailsNote;return}for(let w of a.entries)g.append(W(w))}catch(a){p.textContent=`${e.failed}: ${a instanceof Error?a.message:String(a)}`}},A=async()=>{y.textContent=e.loading;try{let t=await c.invoke("state");y.textContent=`${t.days} \u5929 \xB7 ${t.samples.length} \u91C7\u6837`,$.textContent=e.current(T(t.current)),C.textContent=t.top&&t.top.length?(r?"\u9AD8\u9891\u8BCD\uFF1A":"Top tokens: ")+t.top.map(a=>a.token).join(" \xB7 "):"",t.samples.length===0&&(p.textContent=e.waitingProducer(t.source)),I(t),await m()}catch(t){y.textContent=`${e.failed}: ${t instanceof Error?t.message:String(t)}`}};return z.addEventListener("click",()=>{A()}),b.addEventListener("click",()=>{h.value="",m()}),D.addEventListener("click",()=>{m(h.value.trim())}),h.addEventListener("keydown",t=>{t.key==="Enter"&&m(h.value.trim())}),u.addEventListener("click",()=>{window.confirm(e.clearConfirm)&&(async()=>{try{let t=await c.invoke("clear",[]);p.textContent=e.cleared(t.removed),await A()}catch(t){p.textContent=`${e.failed}: ${t instanceof Error?t.message:String(t)}`}})()}),f.append(v,$,C,n,s,x,l,p,g),c.root.append(f),A(),{dispose(){}}}},O=[["develop","\u5F00\u53D1","Development"],["office","\u6587\u4E66","Documents"],["video","\u89C6\u9891","Video"],["game","\u6E38\u620F","Gaming"],["casual","\u6302\u673A/\u8F7B\u5A31\u4E50","Casual"],["browser","\u6D4F\u89C8\u5668","Browser"],["ai","AI","AI"],["neutral","\u4E2D\u6027","Neutral"],["filtered","\u8FC7\u6EE4","Filtered"]],K={mount(c){let e=c.language==="zh"||c.language==="zh-Hant",r=document.createElement("div");r.style.cssText="display:flex;flex-direction:column;gap:10px;height:100%;box-sizing:border-box;padding:14px;overflow:auto";let T=document.createElement("div");T.textContent=e?"\u8BCD\u6C47\u4E0E\u8870\u51CF":"Words and decay",T.style.cssText="font-size:14px;font-weight:600";let f=document.createElement("div");f.textContent=e?"\u5E94\u7528\u540D\u4E0E\u7A97\u53E3\u6807\u9898\u8BCD\u540C\u8868\uFF1B\u5750\u6807 = [\u5DE5\u4F5C/\u5A31\u4E50, \u8F7B/\u91CD]\uFF0C\u6743\u91CD\u8D8A\u9AD8\u8D8A\u80FD\u62C9\u52A8\u72B6\u6001\u3002\u6807\u9898\u53EA\u4EE5\u8BCD\u9891\u5F62\u5F0F\u4FDD\u7559\u3002\u901A\u8BAF\u7C7B\u9ED8\u8BA4\u8FC7\u6EE4\uFF1B\u5E94\u7528\u8BCD\u53EF\u8986\u76D6\u7C7B\u578B\u4E0E\u6D41\u67AF\u7AED\u7A97\u53E3\u3002":"App names and title words share one table; coordinates are [work/entertainment, light/heavy] and heavier words pull the state more. Titles are kept only as token counts. Communication apps are filtered by default; app tokens can override category and decay.",f.style.cssText="font-size:12px;opacity:.7;max-width:800px";let d=document.createElement("div");d.style.cssText="font-size:12px;opacity:.75;min-height:16px";let k=document.createElement("label");k.style.cssText="display:flex;gap:6px;align-items:center;font-size:12px;opacity:.75;cursor:pointer";let v=document.createElement("input");v.type="checkbox";let y=document.createElement("span");y.textContent=e?"\u663E\u793A\u672A\u77E5\u8BCD\uFF08\u6743\u91CD 0.1\uFF09":"Show unknown tokens (weight 0.1)",k.append(v,y),v.addEventListener("change",()=>{C()});let E=document.createElement("div");E.style.cssText="display:flex;flex-direction:column;gap:6px";let z="minmax(150px,1.6fr) 52px 56px 56px 52px minmax(150px,1fr) 96px",u=()=>{let o=document.createElement("div");o.style.cssText="display:grid;grid-template-columns:"+z+";gap:8px;align-items:center;font-size:11px;opacity:.55;padding:4px 0;border-bottom:1px solid rgba(128,128,128,.3)";let n=[e?"\u8BCD":"token",e?"\u6B21\u6570":"count",e?"\u5DE5\u4F5C":"work",e?"\u6280\u672F":"tech",e?"\u6743\u91CD":"weight",e?"\u7C7B\u578B / \u8870\u51CF":"type / decay",e?"\u64CD\u4F5C":"action"];for(let i=0;i<n.length;i+=1){let s=document.createElement("span");s.textContent=n[i],i>=1&&i<=4&&(s.style.textAlign="right"),i===6&&(s.style.textAlign="right"),o.append(s)}return o},$=o=>{let n=document.createElement("div");n.style.cssText="display:grid;grid-template-columns:"+z+";gap:8px;align-items:center;font-size:13px;padding:5px 0;border-bottom:1px solid rgba(128,128,128,.14)";let i=document.createElement("span");i.textContent=o.token,i.style.cssText="font-family:ui-monospace,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";let s=document.createElement("span");s.textContent=o.count+" \xD7",s.style.cssText="opacity:.65;font-size:12px;text-align:right";let x=document.createElement("span");x.textContent=o.coord[0].toFixed(2),x.style.cssText="opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace";let l=document.createElement("span");l.textContent=o.coord[1].toFixed(2),l.style.cssText="opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace";let h=document.createElement("span");if(h.textContent=o.weight.toFixed(1),h.style.cssText="opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace",n.append(i,s,x,l,h),o.kind!=="app"||!o.app){let m=document.createElement("span");m.textContent=e?"\u6807\u9898\u8BCD \xB7 \u53EA\u8BFB":"title word \xB7 read-only",m.style.cssText="font-size:11px;opacity:.45";let A=document.createElement("span");return A.textContent="\u2014",A.style.cssText="opacity:.3;text-align:right",n.append(m,A),n}let D=document.createElement("div");D.style.cssText="display:flex;gap:4px;align-items:center;min-width:0";let b=document.createElement("select");b.style.cssText="font:inherit;font-size:12px;padding:3px 4px;border-radius:5px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.4);min-width:0;flex:1";let p=document.createElement("option");p.value="",p.textContent=e?"\u8DDF\u968F\u9ED8\u8BA4":"default",b.append(p);for(let[m,A,t]of O){let a=document.createElement("option");a.value=m,a.textContent=e?A:t,b.append(a)}let g=document.createElement("input");g.type="number",g.min="1",g.max="180",g.placeholder=e?"\u9ED8\u8BA4":"def",g.title=e?"\u7559\u7A7A\u8DDF\u968F\u8BE5\u7C7B\u578B\u7684\u9ED8\u8BA4\u7A97\u53E3":"Empty follows the category default",g.style.cssText="width:62px;font:inherit;font-size:12px;padding:3px 4px;border-radius:5px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.4)",D.append(b,g);let I=document.createElement("div");I.style.cssText="display:flex;justify-content:flex-end";let W=document.createElement("button");return W.textContent=e?"\u4FDD\u5B58":"Save",W.style.cssText="font:inherit;font-size:12px;padding:3px 9px;border-radius:5px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:transparent;color:inherit",W.addEventListener("click",()=>{(async()=>{try{let m=g.value.trim()?Number(g.value):0;await c.invoke("setApp",[o.app,b.value||null,m]),d.textContent=e?"\u5DF2\u4FDD\u5B58 "+o.app:"Saved "+o.app}catch(m){d.textContent=(e?"\u4FDD\u5B58\u5931\u8D25":"Save failed")+": "+(m instanceof Error?m.message:String(m))}})()}),I.append(W),n.append(D,I),n},C=async()=>{E.replaceChildren(),d.textContent=e?"\u8BFB\u53D6\u4E2D\u2026":"Loading\u2026";try{let n=(await c.invoke("words")).words,i=v.checked?n:n.filter(s=>s.kind==="app"||s.weight>.1);d.textContent=i.length?`${i.length} / ${n.length} ${e?"\u4E2A\u8BCD":"tokens"}`:e?"\u8FD8\u6CA1\u6709\u91C7\u96C6\u5230\u6709\u4FE1\u53F7\u8BCD\uFF1B\u53EF\u52FE\u9009\u201C\u663E\u793A\u672A\u77E5\u8BCD\u201D\u67E5\u770B\u5168\u90E8":"No signal tokens yet; enable \u201CShow unknown tokens\u201D to see everything",E.append(u());for(let s of i)E.append($(s))}catch(o){d.textContent=`${e?"\u8BFB\u53D6\u5931\u8D25":"Failed"}: ${o instanceof Error?o.message:String(o)}`}};return r.append(T,f,k,d,E),c.root.append(r),C(),{dispose(){}}}},V={mount(c){let e=c.language==="zh"||c.language==="zh-Hant",r=document.createElement("div");r.style.cssText="display:flex;flex-direction:column;gap:10px;height:100%;box-sizing:border-box;padding:14px;overflow:auto";let T=document.createElement("div");T.textContent=e?"\u5F00\u53D1\u8005\u9009\u9879":"Developer options",T.style.cssText="font-size:14px;font-weight:600";let f=document.createElement("div");f.textContent=e?"\u8FD9\u91CC\u663E\u793A\u5F53\u524D\u89C4\u5219\u4E0E\u8BCA\u65AD\uFF1B\u4E0B\u4E00\u6B65\u7684\u89C4\u5219\u5F00\u5173\u3001\u9608\u503C\u4E0E\u89E6\u53D1\u539F\u56E0\u4F1A\u653E\u5728\u8FD9\u91CC\u3002":"Current rules and diagnostics; rule toggles, thresholds and reasons will live here next.",f.style.cssText="font-size:12px;opacity:.7;max-width:760px";let d=document.createElement("div");d.style.cssText="display:flex;flex-direction:column;gap:10px;font-size:13px";let k=document.createElement("div");k.style.cssText="font-size:12px;opacity:.75;min-height:16px";let v=document.createElement("label");v.style.cssText="display:flex;gap:6px;align-items:center;font-size:12px;opacity:.75;cursor:pointer";let y=document.createElement("input");y.type="checkbox";let E=document.createElement("span");E.textContent=e?"\u663E\u793A\u672A\u77E5\u8BCD\uFF08\u6743\u91CD 0.1\uFF09":"Show unknown tokens (weight 0.1)",v.append(y,E),y.addEventListener("change",()=>{$()});let z=n=>{let i=document.createElement("div");i.style.cssText="display:flex;flex-direction:column;gap:5px;padding:10px;border:1px solid rgba(128,128,128,.18);border-radius:8px";let s=document.createElement("div");return s.textContent=n,s.style.cssText="font-size:12px;font-weight:600;opacity:.8",i.append(s),i},u=(n,i)=>{let s=document.createElement("div");s.style.cssText="display:flex;gap:12px;font-size:12px";let x=document.createElement("span");x.textContent=n,x.style.cssText="opacity:.6;min-width:170px";let l=document.createElement("span");return l.textContent=i,l.style.cssText="font-family:ui-monospace,monospace;word-break:break-all",s.append(x,l),s},$=async()=>{d.replaceChildren(),k.textContent=e?"\u8BFB\u53D6\u4E2D\u2026":"Loading\u2026";try{let n=await c.invoke("diagnostics");k.textContent="";let i=z(e?"\u5F53\u524D flow":"Current flow");i.append(u(e?"\u72B6\u6001":"state",n.flow.state),u(e?"\u6700\u540E\u5207\u6362":"last switch",n.flow.lastSwitchAt?new Date(n.flow.lastSwitchAt).toLocaleString():"\u2014"),u(e?"\u9759\u9ED8 / \u9608\u503C":"gap / decay",`${Math.round(n.flow.gapMs/1e3)}s / ${Math.round(n.flow.decayMs/1e3)}s`),u(e?"\u6700\u540E\u7C7B\u578B":"last category",n.flow.category));let s=z(e?"\u89C4\u5219":"Rules");for(let l of n.rules){let h=document.createElement("div");h.style.cssText="display:flex;gap:10px;align-items:center;font-size:12px";let D=document.createElement("span");D.textContent=l.enabled?e?"\u5F00":"on":e?"\u5173":"off",D.style.cssText=`padding:1px 6px;border-radius:999px;border:1px solid ${l.enabled?"rgba(95,212,200,.6)":"rgba(128,128,128,.35)"};opacity:${l.enabled?1:.55};font-size:11px`;let b=document.createElement("span");b.textContent=`${l.id} \xB7 ${l.action}`,b.style.cssText="font-family:ui-monospace,monospace";let p=document.createElement("span");p.textContent=l.trigger,p.style.cssText="opacity:.55;margin-left:auto",h.append(D,b,p),s.append(h)}let x=z(e?"\u914D\u7F6E\u4E0E\u8BA1\u6570":"Config and counts");x.append(u("source",n.config.source),u("smoothing",String(n.config.smoothing)),u(e?"\u7EC6\u8282\u5C0F\u65F6":"detailHours",String(n.config.detailHours)),u(e?"\u4FDD\u7559\u5929\u6570":"keepDays",String(n.config.keepDays)),u(e?"\u5E94\u7528 / \u91C7\u6837 / \u7EC6\u8282":"apps / samples / entries",`${n.counts.apps} / ${n.counts.samples} / ${n.counts.entries}`),u(e?"\u6E38\u6807":"cursor",String(n.counts.cursor))),d.append(i,s,x)}catch(n){k.textContent=`${e?"\u8BFB\u53D6\u5931\u8D25":"Failed"}: ${n instanceof Error?n.message:String(n)}`}},C=document.createElement("div");C.style.cssText="display:flex;gap:8px;align-items:center";let o=document.createElement("button");return o.textContent=e?"\u5237\u65B0":"Refresh",o.style.cssText="font:inherit;font-size:12px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:transparent;color:inherit",o.addEventListener("click",()=>{$()}),C.append(o),r.append(T,f,C,k,d),c.root.append(r),$(),{dispose(){}}}},_={panels:{timeline:j,words:K,developer:V}},X=_;export{X as default};
|
|
2
2
|
//# sourceMappingURL=webui.js.map
|
package/dist/webui.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/config.ts", "../src/webui/client.ts"],
|
|
4
|
-
"sourcesContent": ["/** Config section `worlds.screen-diary`: event stream, privacy filter, smoothing and retention. */\nimport type { ConfigGroup } from 'cortico/core/config-schema.ts';\nimport type { Language } from 'cortico/core/language.ts';\n\nexport interface DiaryConfig {\n enabled: boolean;\n pollMs: number;\n lookbackMinutes: number;\n keepDays: number;\n source: string;\n maxEventsPerPoll: number;\n /** Blur AI chat apps to neutral instead of projecting them as development work. */\n blurAi: boolean;\n /** Extra app-name substrings to filter out, comma separated. */\n ignoreApps: string;\n /** EMA smoothing factor: higher reacts faster, lower is smoother. */\n smoothing: number;\n /** Detail entries (window titles, captions, text) are dropped after this many hours. */\n detailHours: number;\n /** Minimum gap between two stored state samples, seconds. */\n sampleSec: number;\n}\n\nexport const DIARY_DEFAULTS: DiaryConfig = {\n enabled: false,\n pollMs: 5000,\n lookbackMinutes: 60,\n keepDays: 30,\n source: 'screen-sense',\n maxEventsPerPoll: 500,\n blurAi: true,\n ignoreApps: '',\n smoothing: 0.25,\n detailHours: 72,\n sampleSec: 30,\n};\n\nexport type DiaryConfigSection = DiaryConfig;\n\nfunction diaryText(language: Language) {\n const zh = language === 'zh' || language === 'zh-Hant';\n return zh ? {\n group: '\u4E8B\u4EF6\u6D41\u4E0E\u8BB0\u5FC6',\n groupDesc: '\u4ECE\u54EA\u91CC\u8BFB\u4E8B\u4EF6\u3001\u600E\u4E48\u8FC7\u6EE4\u4E0E\u5E73\u6ED1\u3001\u7EC6\u8282\u4FDD\u7559\u591A\u4E45\u3002',\n enabledTitle: '\u8BFB\u53D6\u4E8B\u4EF6\u6D41',\n enabledDesc: '\u6253\u5F00\u540E\u6309\u56FA\u5B9A\u95F4\u9694\u589E\u91CF\u8BFB\u53D6\u751F\u4EA7\u65B9\u7684\u4E8B\u4EF6\u3002',\n pollTitle: '\u8F6E\u8BE2\u95F4\u9694',\n pollDesc: '\u6BCF\u9694\u8FD9\u4E48\u4E45\u68C0\u67E5\u4E00\u6B21\u65B0\u4E8B\u4EF6\u3002',\n lookbackTitle: '\u9996\u6B21\u56DE\u586B',\n lookbackDesc: '\u7B2C\u4E00\u6B21\u542F\u52A8\u65F6\u5BFC\u5165\u6700\u8FD1\u591A\u5C11\u5206\u949F\u5DF2\u6709\u7684\u5386\u53F2\u4E8B\u4EF6\u3002',\n keepTitle: '\u72B6\u6001\u4FDD\u7559\u5929\u6570',\n keepDesc: '\u5E73\u6ED1\u72B6\u6001\u4E0E\u65E5\u6458\u8981\u4FDD\u7559\u591A\u4E45\uFF1B\u8D85\u8FC7\u540E\u5220\u9664\u3002',\n sourceTitle: '\u4E8B\u4EF6\u6765\u6E90',\n sourceDesc: '\u751F\u4EA7\u65B9\u7684 World id\uFF0C\u9ED8\u8BA4 screen-sense\uFF08\u7AA5\u5C4F\u52A9\u624B\uFF09\u3002',\n maxTitle: '\u5355\u6B21\u5904\u7406\u4E0A\u9650',\n maxDesc: '\u4E00\u6B21\u6700\u591A\u5BFC\u5165\u591A\u5C11\u6761\uFF1B\u8D85\u51FA\u7684\u7559\u7ED9\u4E0B\u4E00\u62CD\u7EE7\u7EED\u3002',\n blurAiTitle: '\u6A21\u7CCA AI \u5BF9\u8BDD',\n blurAiDesc: 'AI \u804A\u5929\u7A97\u53E3\u9ED8\u8BA4\u6309\u4E2D\u6027\u5904\u7406\uFF0C\u4E0D\u8BB0\u5F55\u5177\u4F53\u7A97\u53E3\u6807\u9898\u3002',\n ignoreTitle: '\u989D\u5916\u8FC7\u6EE4',\n ignoreAppsDesc: '\u9017\u53F7\u5206\u9694\u7684\u5E94\u7528\u540D\u7247\u6BB5\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u9ED8\u8BA4\u5DF2\u8FC7\u6EE4\u3002',\n smoothingTitle: '\u5E73\u6ED1\u5F3A\u5EA6',\n smoothingDesc: '0.05 \u5F88\u5E73\u6ED1\uFF0C0.9 \u53CD\u5E94\u5F88\u5FEB\uFF1B\u9ED8\u8BA4 0.25\u3002',\n detailTitle: '\u7EC6\u8282\u4FDD\u7559\u5C0F\u65F6',\n detailDesc: '\u7A97\u53E3\u6807\u9898\u3001\u901F\u5199\u4E0E\u6B63\u6587\u53EA\u4FDD\u7559\u8FD9\u4E48\u4E45\uFF0C\u4E4B\u540E\u53EA\u7559\u4E0B\u5E73\u6ED1\u72B6\u6001\u3002',\n sampleTitle: '\u91C7\u6837\u95F4\u9694',\n sampleDesc: '\u4E24\u6B21\u72B6\u6001\u91C7\u6837\u81F3\u5C11\u9694\u8FD9\u4E48\u591A\u79D2\u3002',\n storage: {\n label: '\u6D3B\u52A8\u65E5\u8BB0',\n note: '\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1B\u4E0D\u4F1A\u5F71\u54CD\u751F\u4EA7\u65B9\u7684\u76F8\u518C\u4E0E\u914D\u7F6E\u3002',\n stat: (entries: string, samples: string) => `${entries} \u6761\u7EC6\u8282 \u00B7 ${samples} \u4E2A\u72B6\u6001\u91C7\u6837`,\n cleared: (n: number) => `\u5DF2\u5220\u9664 ${n} \u6761\u8BB0\u5F55`,\n },\n } : {\n group: 'Event stream and memory',\n groupDesc: 'Where events come from, how they are filtered and smoothed, and how long details last.',\n enabledTitle: 'Read the event stream',\n enabledDesc: 'When on, new events are imported at a fixed interval.',\n pollTitle: 'Poll interval',\n pollDesc: 'How often to check for new events.',\n lookbackTitle: 'First import',\n lookbackDesc: 'On the first run, import up to this many minutes of existing events.',\n keepTitle: 'State kept, days',\n keepDesc: 'Smoothed state and daily summaries are kept this many days.',\n sourceTitle: 'Event source',\n sourceDesc: 'The producer World id; `screen-sense` by default.',\n maxTitle: 'Events per poll',\n maxDesc: 'Most events imported at once; the rest wait for the next poll.',\n blurAiTitle: 'Blur AI chats',\n blurAiDesc: 'AI chat windows count as neutral and their titles are not stored.',\n ignoreTitle: 'Extra filters',\n ignoreAppsDesc: 'Comma separated app-name fragments; communication apps are filtered by default.',\n smoothingTitle: 'Smoothing',\n smoothingDesc: '0.05 is very smooth, 0.9 reacts fast; 0.25 by default.',\n detailTitle: 'Detail hours',\n detailDesc: 'Window titles, captions and text are kept this long, then only smoothed state remains.',\n sampleTitle: 'Sample interval',\n sampleDesc: 'At least this many seconds between two stored state samples.',\n storage: {\n label: 'Activity diary',\n note: 'Deletes detail entries and smoothed state; the producer album and settings are untouched.',\n stat: (entries: string, samples: string) => `${entries} entries \u00B7 ${samples} state samples`,\n cleared: (n: number) => `Deleted ${n} records`,\n },\n };\n}\n\nexport function diaryStorageText(language: Language) {\n return diaryText(language).storage;\n}\n\nexport interface DiaryPanelText {\n title: string;\n description: string;\n refresh: string;\n clear: string;\n clearConfirm: string;\n cleared: (n: number) => string;\n empty: string;\n waitingProducer: (source: string) => string;\n loading: string;\n failed: string;\n stateTitle: string;\n current: (label: string) => string;\n trend: string;\n noTrend: string;\n details: string;\n detailsNote: string;\n search: string;\n searchPlaceholder: string;\n noResults: string;\n privacyNote: string;\n axisTech: string;\n axisWork: string;\n}\n\nexport function diaryPanelText(language: Language): DiaryPanelText {\n const zh = language === 'zh' || language === 'zh-Hant';\n return zh ? {\n title: '\u6D3B\u52A8\u65E5\u8BB0',\n description: '\u4E8C\u7EF4\u72B6\u6001\u7A7A\u95F4\uFF1A\u6280\u672F\u91CD\u5EA6\u4E0E\u529E\u516C/\u5A31\u4E50\u7684\u5E73\u6ED1\u8F68\u8FF9\uFF1B\u7EC6\u8282\u4F1A\u968F\u65F6\u95F4\u6DE1\u5FD8\u3002',\n refresh: '\u5237\u65B0',\n clear: '\u6E05\u7A7A\u65E5\u8BB0',\n clearConfirm: '\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1F\u4E0D\u4F1A\u5F71\u54CD\u7AA5\u5C4F\u52A9\u624B\u7684\u76F8\u518C\u3002',\n cleared: (n) => `\u5DF2\u5220\u9664 ${n} \u6761\u8BB0\u5F55`,\n empty: '\u8FD8\u6CA1\u6709\u8BB0\u5F55\u3002\u5148\u5B89\u88C5\u5E76\u542F\u7528\u7AA5\u5C4F\u52A9\u624B\uFF0C\u5207\u51E0\u6B21\u5E94\u7528\u540E\u8FD9\u91CC\u4F1A\u51FA\u73B0\u72B6\u6001\u8F68\u8FF9\u3002',\n waitingProducer: (source) => `\u8FD8\u6CA1\u6709\u6536\u5230\u6765\u81EA ${source} \u7684\u4E8B\u4EF6\uFF1B\u786E\u8BA4\u7AA5\u5C4F\u52A9\u624B\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\u3002`,\n loading: '\u8BFB\u53D6\u4E2D\u2026',\n failed: '\u8BFB\u53D6\u5931\u8D25',\n stateTitle: '\u5F53\u524D\u72B6\u6001',\n current: (label) => `\u5F53\u524D\uFF1A${label}`,\n trend: '\u6700\u8FD1\u8F68\u8FF9',\n noTrend: '\u8FD8\u6CA1\u6709\u8DB3\u591F\u7684\u91C7\u6837\u70B9',\n details: '\u8BE6\u7EC6\u8BB0\u5F55\uFF08\u663E\u5F0F\u56DE\u5FC6\uFF09',\n detailsNote: '\u53EA\u4FDD\u7559\u6700\u8FD1\u4E00\u6BB5\u65F6\u95F4\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u4E0D\u5728\u6B64\u5217\u3002',\n search: '\u641C\u7D22',\n searchPlaceholder: '\u641C\u5E94\u7528\u540D\u3001\u7A97\u53E3\u6807\u9898\u6216\u901F\u5199',\n noResults: '\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55',\n privacyNote: '\u901A\u8BAF\u7C7B\u5E94\u7528\u5DF2\u8FC7\u6EE4\uFF1BAI \u5BF9\u8BDD\u9ED8\u8BA4\u6A21\u7CCA\u4E3A\u4E2D\u6027\uFF1B\u7A97\u53E3\u6807\u9898\u53EA\u77ED\u671F\u4FDD\u7559\u3002',\n axisTech: '\u6280\u672F\u91CD\u5EA6',\n axisWork: '\u5DE5\u4F5C',\n } : {\n title: 'Activity diary',\n description: 'A two-axis state space: technical weight and work/entertainment, smoothed over time; details fade.',\n refresh: 'Refresh',\n clear: 'Clear diary',\n clearConfirm: 'Delete detail entries and smoothed state? The screen-sense album is untouched.',\n cleared: (n) => `Deleted ${n} records`,\n empty: 'No entries yet. Install and enable screen-sense, switch apps a few times, then come back.',\n waitingProducer: (source) => `No events from ${source} yet; check that screen-sense is installed and enabled.`,\n loading: 'Loading\u2026',\n failed: 'Could not load',\n stateTitle: 'Current state',\n current: (label) => `Now: ${label}`,\n trend: 'Recent trajectory',\n noTrend: 'Not enough samples yet',\n details: 'Detail entries (explicit recall)',\n detailsNote: 'Kept briefly only; communication apps are excluded.',\n search: 'Search',\n searchPlaceholder: 'app, window title or caption',\n noResults: 'No matching entries',\n privacyNote: 'Communication apps are filtered; AI chats are blurred to neutral; titles are kept briefly.',\n axisTech: 'Technical',\n axisWork: 'Work',\n };\n}\n\nexport function diaryConfigGroup(language: Language = 'zh'): ConfigGroup {\n const t = diaryText(language);\n const K = 'worlds.screen-diary';\n return {\n id: 'world:screen-diary',\n owner: 'world:screen-diary',\n schema: {\n type: 'object',\n title: t.group,\n description: t.groupDesc,\n properties: {\n [`${K}.enabled`]: { type: 'boolean', title: t.enabledTitle, description: t.enabledDesc, 'x-hot': true },\n [`${K}.pollMs`]: { type: 'integer', title: t.pollTitle, description: t.pollDesc, minimum: 1000, maximum: 300000, 'x-suffix': 'ms', 'x-hot': true },\n [`${K}.lookbackMinutes`]: { type: 'integer', title: t.lookbackTitle, description: t.lookbackDesc, minimum: 0, maximum: 1440, 'x-suffix': 'min' },\n [`${K}.keepDays`]: { type: 'integer', title: t.keepTitle, description: t.keepDesc, minimum: 1, maximum: 3650, 'x-suffix': 'd' },\n [`${K}.detailHours`]: { type: 'integer', title: t.detailTitle, description: t.detailDesc, minimum: 1, maximum: 720, 'x-suffix': 'h', 'x-hot': true },\n [`${K}.blurAi`]: { type: 'boolean', title: t.blurAiTitle, description: t.blurAiDesc, 'x-hot': true },\n [`${K}.ignoreApps`]: { type: 'string', title: t.ignoreTitle, description: t.ignoreAppsDesc, 'x-hot': true },\n [`${K}.smoothing`]: { type: 'number', title: t.smoothingTitle, description: t.smoothingDesc, minimum: 0.05, maximum: 0.9, 'x-hot': true },\n [`${K}.sampleSec`]: { type: 'integer', title: t.sampleTitle, description: t.sampleDesc, minimum: 5, maximum: 600, 'x-suffix': 's' },\n [`${K}.source`]: { type: 'string', title: t.sourceTitle, description: t.sourceDesc },\n [`${K}.maxEventsPerPoll`]: { type: 'integer', title: t.maxTitle, description: t.maxDesc, minimum: 1, maximum: 5000 },\n },\n },\n };\n}\n", "/** The activity state panel: a two-axis trajectory plus short-lived detail entries. */\nimport type { WebUiClientBundle, WebUiPanel, WebUiPanelContext } from 'cortico/web/shared/client-panel.ts';\nimport { diaryPanelText } from '../config.ts';\nimport './style.css';\n\ninterface Point { ts: string; tech: number; work: number; zh: string; en: string }\ninterface State {\n enabled: boolean;\n source: string;\n current: { tech: number; work: number; zh: string; en: string; category: string };\n samples: Point[];\n entries: number;\n days: number;\n lastCursor: number;\n}\ninterface Entry {\n cursor: number;\n ts: string;\n type: string;\n text: string;\n app?: string;\n title?: string;\n caption?: string;\n clock: string;\n day: string;\n hour: string;\n}\n\nconst SVG = 'http://www.w3.org/2000/svg';\nconst el = <K extends keyof SVGElementTagNameMap>(name: K, attrs: Record<string, string | number> = {}): SVGElementTagNameMap[K] => {\n const node = document.createElementNS(SVG, name);\n for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, String(value));\n return node;\n};\n\nconst timelinePanel: WebUiPanel = {\n mount(ctx: WebUiPanelContext) {\n const t = diaryPanelText(ctx.language);\n const zh = ctx.language === 'zh' || ctx.language === 'zh-Hant';\n const label = (point: { zh: string; en: string }) => (zh ? point.zh : point.en);\n\n const root = document.createElement('div');\n root.style.cssText = 'display:flex;flex-direction:column;gap:12px;height:100%;box-sizing:border-box;padding:14px;overflow:auto';\n\n const button = (text: string, danger = false) => {\n const node = document.createElement('button');\n node.textContent = text;\n node.style.cssText = `font:inherit;font-size:13px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:${danger ? 'rgba(200,60,60,.12)' : 'transparent'};color:inherit`;\n return node;\n };\n const input = (placeholder: string) => {\n const node = document.createElement('input');\n node.placeholder = placeholder;\n node.style.cssText = 'font:inherit;font-size:13px;padding:4px 8px;border-radius:6px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.45);min-width:200px';\n return node;\n };\n\n const bar = document.createElement('div');\n bar.style.cssText = 'display:flex;gap:8px;align-items:center;flex-wrap:wrap';\n const count = document.createElement('span');\n count.style.cssText = 'opacity:.75;font-size:13px';\n const spacer = document.createElement('span');\n spacer.style.flex = '1';\n const refresh = button(t.refresh);\n const clear = button(t.clear, true);\n bar.append(count, spacer, refresh, clear);\n\n const current = document.createElement('div');\n current.style.cssText = 'font-size:14px;font-weight:600';\n\n const chart = el('svg', { viewBox: '0 0 420 300', width: '100%', height: '300', style: 'max-width:520px;align-self:center' });\n const chartBox = document.createElement('div');\n chartBox.style.cssText = 'display:flex;flex-direction:column;gap:6px';\n const privacy = document.createElement('div');\n privacy.textContent = t.privacyNote;\n privacy.style.cssText = 'font-size:12px;opacity:.7;max-width:640px';\n chartBox.append(chart, privacy);\n\n const detailsTitle = document.createElement('div');\n detailsTitle.textContent = t.details;\n detailsTitle.style.cssText = 'font-size:13px;font-weight:600;opacity:.85;margin-top:6px';\n const detailsNote = document.createElement('div');\n detailsNote.textContent = t.detailsNote;\n detailsNote.style.cssText = 'font-size:12px;opacity:.65';\n\n const detailBar = document.createElement('div');\n detailBar.style.cssText = 'display:flex;gap:8px;align-items:center;flex-wrap:wrap';\n const search = input(t.searchPlaceholder);\n const searchButton = button(t.search);\n const reset = button(t.refresh);\n detailBar.append(search, searchButton, reset);\n\n const notice = document.createElement('div');\n notice.style.cssText = 'font-size:12px;opacity:.8;min-height:16px;white-space:pre-wrap';\n const list = document.createElement('div');\n list.style.cssText = 'display:flex;flex-direction:column;gap:6px';\n\n const draw = (state: State) => {\n chart.replaceChildren();\n const w = 420, h = 300, cx = w / 2, cy = h / 2, pad = 40;\n const x = (work: number) => cx + Math.max(-1, Math.min(1, work)) * (cx - pad);\n const y = (tech: number) => cy - Math.max(-1, Math.min(1, tech)) * (cy - pad);\n chart.append(\n el('line', { x1: pad, y1: cy, x2: w - pad, y2: cy, stroke: 'currentColor', 'stroke-opacity': 0.35, 'stroke-width': 1 }),\n el('line', { x1: cx, y1: pad, x2: cx, y2: h - pad, stroke: 'currentColor', 'stroke-opacity': 0.35, 'stroke-width': 1 }),\n );\n for (const [dx, dy, text] of [[-1, 1, '\u5F00\u53D1'], [1, 1, '\u5DE5\u4F5C'], [-1, -1, '\u89C6\u9891'], [1, -1, '\u6E38\u620F']] as const) {\n const node = el('text', { x: dx < 0 ? pad : w - pad - 20, y: dy > 0 ? pad - 12 : h - pad + 16, fill: 'currentColor', 'fill-opacity': 0.55, 'font-size': 11 });\n node.textContent = text;\n chart.append(node);\n }\n const axisTech = el('text', { x: cx + 6, y: pad - 12, fill: 'currentColor', 'fill-opacity': 0.5, 'font-size': 10 });\n axisTech.textContent = t.axisTech;\n const axisWork = el('text', { x: w - pad - 24, y: cy - 6, fill: 'currentColor', 'fill-opacity': 0.5, 'font-size': 10 });\n axisWork.textContent = t.axisWork;\n chart.append(axisTech, axisWork);\n\n const points = state.samples.slice(-120).reverse();\n if (points.length >= 2) {\n const path = el('polyline', {\n points: points.map((point) => `${x(point.work)},${y(point.tech)}`).join(' '),\n fill: 'none', stroke: '#5fd4c8', 'stroke-width': 2, 'stroke-opacity': 0.85,\n });\n chart.append(path);\n for (const point of points.slice(0, 12)) {\n chart.append(el('circle', { cx: x(point.work), cy: y(point.tech), r: 3, fill: '#5fd4c8', 'fill-opacity': 0.5 }));\n }\n }\n chart.append(el('circle', { cx: x(state.current.work), cy: y(state.current.tech), r: 7, fill: '#5fd4c8' }));\n };\n\n const row = (entry: Entry): HTMLElement => {\n const box = document.createElement('div');\n box.style.cssText = 'display:flex;gap:10px;align-items:baseline;font-size:13px;padding:3px 0;border-bottom:1px solid rgba(128,128,128,.12)';\n const clock = document.createElement('span');\n clock.textContent = entry.clock;\n clock.style.cssText = 'font-family:ui-monospace,monospace;opacity:.7;flex:none';\n const app = document.createElement('span');\n app.textContent = entry.app ?? '';\n app.style.cssText = 'font-family:ui-monospace,monospace;opacity:.85;flex:none;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';\n const text = document.createElement('span');\n text.textContent = entry.caption ?? entry.text;\n text.style.cssText = 'flex:1;line-height:1.45';\n box.append(clock, app, text);\n return box;\n };\n\n const loadDetails = async (keyword = '') => {\n list.replaceChildren();\n notice.textContent = '';\n try {\n const data = keyword\n ? await ctx.invoke<{ entries: Entry[] }>('search', [keyword, 20])\n : await ctx.invoke<{ entries: Entry[] }>('list', [{ limit: 50 }]);\n if (data.entries.length === 0) {\n notice.textContent = keyword ? t.noResults : t.detailsNote;\n return;\n }\n for (const entry of data.entries) list.append(row(entry));\n } catch (err) {\n notice.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\n }\n };\n\n const load = async () => {\n count.textContent = t.loading;\n try {\n const state = await ctx.invoke<State>('state');\n count.textContent = `${state.days} \u5929 \u00B7 ${state.samples.length} \u91C7\u6837`;\n current.textContent = t.current(label(state.current));\n if (state.samples.length === 0) {\n notice.textContent = t.waitingProducer(state.source);\n }\n draw(state);\n await loadDetails();\n } catch (err) {\n count.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\n }\n };\n\n refresh.addEventListener('click', () => void load());\n reset.addEventListener('click', () => { search.value = ''; void loadDetails(); });\n searchButton.addEventListener('click', () => void loadDetails(search.value.trim()));\n search.addEventListener('keydown', (event) => { if (event.key === 'Enter') void loadDetails(search.value.trim()); });\n clear.addEventListener('click', () => {\n if (!window.confirm(t.clearConfirm)) return;\n void (async () => {\n try {\n const out = await ctx.invoke<{ removed: number }>('clear', []);\n notice.textContent = t.cleared(out.removed);\n await load();\n } catch (err) {\n notice.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\n }\n })();\n });\n\n root.append(bar, current, chartBox, detailsTitle, detailsNote, detailBar, notice, list);\n ctx.root.append(root);\n void load();\n return { dispose() {} };\n },\n};\n\nconst bundle: WebUiClientBundle = { panels: { timeline: timelinePanel } };\nexport default bundle;\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["diaryPanelText", "language", "n", "source", "label", "SVG", "el", "name", "attrs", "node", "key", "value", "timelinePanel", "ctx", "diaryPanelText", "zh", "label", "point", "root", "button", "text", "danger", "input", "placeholder", "bar", "count", "spacer", "refresh", "clear", "current", "chart", "chartBox", "privacy", "detailsTitle", "detailsNote", "detailBar", "search", "searchButton", "reset", "notice", "list", "draw", "state", "w", "h", "cx", "cy", "pad", "x", "work", "y", "tech", "
|
|
4
|
+
"sourcesContent": ["/** Config section `worlds.screen-diary`: event stream, privacy filter, smoothing and retention. */\r\nimport type { ConfigGroup } from 'cortico/core/config-schema.ts';\r\nimport type { Language } from 'cortico/core/language.ts';\r\n\r\nexport interface DiaryConfig {\r\n enabled: boolean;\r\n pollMs: number;\r\n lookbackMinutes: number;\r\n keepDays: number;\r\n source: string;\r\n maxEventsPerPoll: number;\r\n /** Blur AI chat apps to neutral instead of projecting them as development work. */\r\n blurAi: boolean;\r\n /** Extra app-name substrings to filter out, comma separated. */\r\n ignoreApps: string;\r\n /** EMA smoothing factor: higher reacts faster, lower is smoother. */\r\n smoothing: number;\r\n /** Detail entries (window titles, captions, text) are dropped after this many hours. */\r\n detailHours: number;\r\n /** Minimum gap between two stored state samples, seconds. */\r\n sampleSec: number;\r\n /** Blend app/title tokens into the state with a time-decayed word bag. */\r\n useWords: boolean;\r\n /** Word-bag sliding window in minutes. */\r\n wordWindowMinutes: number;\r\n /** Half-life of a token weight in minutes. */\r\n wordHalfLifeMinutes: number;\r\n /** Base flow-decay window in minutes (per-category multipliers apply). */\r\n flowDecayMinutes: number;\r\n /** Optional proactive check-in when the flow depletes; default off. */\r\n checkInEnabled: boolean;\r\n /** Silence after a check-in that confirms away, minutes. */\r\n awayAfterMinutes: number;\r\n /** At most one check-in per this many minutes. */\r\n checkInCooldownMinutes: number;\r\n}\r\n\r\nexport const DIARY_DEFAULTS: DiaryConfig = {\r\n enabled: false,\r\n pollMs: 5000,\r\n lookbackMinutes: 60,\r\n keepDays: 30,\r\n source: 'screen-sense',\r\n maxEventsPerPoll: 500,\r\n blurAi: true,\r\n ignoreApps: '',\r\n smoothing: 0.25,\r\n detailHours: 72,\r\n sampleSec: 30,\r\n useWords: true,\r\n wordWindowMinutes: 15,\r\n wordHalfLifeMinutes: 5,\r\n flowDecayMinutes: 20,\r\n checkInEnabled: false,\r\n awayAfterMinutes: 10,\r\n checkInCooldownMinutes: 60,\r\n};\r\n\r\nexport type DiaryConfigSection = DiaryConfig;\r\n\r\nfunction diaryText(language: Language) {\r\n const zh = language === 'zh' || language === 'zh-Hant';\r\n return zh ? {\r\n group: '\u4E8B\u4EF6\u6D41\u4E0E\u8BB0\u5FC6',\r\n groupDesc: '\u4ECE\u54EA\u91CC\u8BFB\u4E8B\u4EF6\u3001\u600E\u4E48\u8FC7\u6EE4\u4E0E\u5E73\u6ED1\u3001\u7EC6\u8282\u4FDD\u7559\u591A\u4E45\u3002',\r\n enabledTitle: '\u8BFB\u53D6\u4E8B\u4EF6\u6D41',\r\n enabledDesc: '\u6253\u5F00\u540E\u6309\u56FA\u5B9A\u95F4\u9694\u589E\u91CF\u8BFB\u53D6\u751F\u4EA7\u65B9\u7684\u4E8B\u4EF6\u3002',\r\n pollTitle: '\u8F6E\u8BE2\u95F4\u9694',\r\n pollDesc: '\u6BCF\u9694\u8FD9\u4E48\u4E45\u68C0\u67E5\u4E00\u6B21\u65B0\u4E8B\u4EF6\u3002',\r\n lookbackTitle: '\u9996\u6B21\u56DE\u586B',\r\n lookbackDesc: '\u7B2C\u4E00\u6B21\u542F\u52A8\u65F6\u5BFC\u5165\u6700\u8FD1\u591A\u5C11\u5206\u949F\u5DF2\u6709\u7684\u5386\u53F2\u4E8B\u4EF6\u3002',\r\n keepTitle: '\u72B6\u6001\u4FDD\u7559\u5929\u6570',\r\n keepDesc: '\u5E73\u6ED1\u72B6\u6001\u4E0E\u65E5\u6458\u8981\u4FDD\u7559\u591A\u4E45\uFF1B\u8D85\u8FC7\u540E\u5220\u9664\u3002',\r\n sourceTitle: '\u4E8B\u4EF6\u6765\u6E90',\r\n sourceDesc: '\u751F\u4EA7\u65B9\u7684 World id\uFF0C\u9ED8\u8BA4 screen-sense\uFF08\u7AA5\u5C4F\u52A9\u624B\uFF09\u3002',\r\n maxTitle: '\u5355\u6B21\u5904\u7406\u4E0A\u9650',\r\n maxDesc: '\u4E00\u6B21\u6700\u591A\u5BFC\u5165\u591A\u5C11\u6761\uFF1B\u8D85\u51FA\u7684\u7559\u7ED9\u4E0B\u4E00\u62CD\u7EE7\u7EED\u3002',\r\n blurAiTitle: '\u6A21\u7CCA AI \u5BF9\u8BDD',\r\n blurAiDesc: 'AI \u804A\u5929\u7A97\u53E3\u9ED8\u8BA4\u6309\u4E2D\u6027\u5904\u7406\uFF0C\u4E0D\u8BB0\u5F55\u5177\u4F53\u7A97\u53E3\u6807\u9898\u3002',\r\n ignoreTitle: '\u989D\u5916\u8FC7\u6EE4',\r\n ignoreAppsDesc: '\u9017\u53F7\u5206\u9694\u7684\u5E94\u7528\u540D\u7247\u6BB5\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u9ED8\u8BA4\u5DF2\u8FC7\u6EE4\u3002',\r\n smoothingTitle: '\u5E73\u6ED1\u5F3A\u5EA6',\r\n smoothingDesc: '0.05 \u5F88\u5E73\u6ED1\uFF0C0.9 \u53CD\u5E94\u5F88\u5FEB\uFF1B\u9ED8\u8BA4 0.25\u3002',\r\n detailTitle: '\u7EC6\u8282\u4FDD\u7559\u5C0F\u65F6',\r\n detailDesc: '\u7A97\u53E3\u6807\u9898\u3001\u901F\u5199\u4E0E\u6B63\u6587\u53EA\u4FDD\u7559\u8FD9\u4E48\u4E45\uFF0C\u4E4B\u540E\u53EA\u7559\u4E0B\u5E73\u6ED1\u72B6\u6001\u3002',\r\n sampleTitle: '\u91C7\u6837\u95F4\u9694',\r\n sampleDesc: '\u4E24\u6B21\u72B6\u6001\u91C7\u6837\u81F3\u5C11\u9694\u8FD9\u4E48\u591A\u79D2\u3002',\r\n wordsTitle: '\u7528\u8BCD\u888B\u8BA1\u7B97\u72B6\u6001',\r\n wordsDesc: '\u5E94\u7528\u8BCD\u7684\u5750\u6807\u4E0E\u6807\u9898\u8BCD\u4E00\u8D77\u6309\u65F6\u95F4\u8870\u51CF\u6295\u7968\uFF0C\u51B3\u5B9A\u72B6\u6001\u65B9\u5411\uFF1B\u5173\u95ED\u5219\u56DE\u9000\u5230\u5E94\u7528\u7C7B\u522B EMA\u3002',\r\n wordWindowTitle: '\u8BCD\u888B\u7A97\u53E3',\r\n wordWindowDesc: '\u53EA\u6709\u6700\u8FD1\u8FD9\u4E48\u591A\u5206\u949F\u5185\u7684\u8BCD\u53C2\u4E0E\u72B6\u6001\u8BA1\u7B97\u3002',\r\n halfLifeTitle: '\u8BCD\u8870\u51CF\u534A\u8870\u671F',\r\n halfLifeDesc: '\u4E00\u4E2A\u8BCD\u7684\u6743\u91CD\u591A\u4E45\u8870\u51CF\u4E00\u534A\uFF1B\u8D8A\u5C0F\u8D8A\u53EA\u770B\u5F53\u4E0B\u3002',\r\n flowTitle: '\u6D41\u67AF\u7AED\u7A97\u53E3',\r\n flowDesc: '\u591A\u4E45\u6CA1\u6709\u7A97\u53E3\u5207\u6362\u7B97\u4E13\u6CE8\u6216\u79BB\u5F00\uFF1B\u6309\u5E94\u7528\u7C7B\u578B\u4E58\u500D\u7387\uFF08\u5F00\u53D1/\u6587\u4E66 20 \u5206\u3001\u89C6\u9891 30\u3001\u6E38\u620F 12\u3001\u6D4F\u89C8\u5668 8\uFF09\u3002',\r\n checkInTitle: '\u67AF\u7AED\u65F6\u4E3B\u52A8\u642D\u8BDD',\r\n checkInDesc: '\u6D41\u67AF\u7AED\u65F6\u8BA9 Coo \u53EF\u4EE5\u4E3B\u52A8\u63D0\u9192\u4F11\u606F\u6216\u8F7B\u58F0\u786E\u8BA4\uFF1B\u9ED8\u8BA4\u5173\u95ED\u3002',\r\n awayTitle: '\u786E\u8BA4\u79BB\u5F00',\r\n awayDesc: '\u642D\u8BDD\u540E\u4ECD\u65E0\u7A97\u53E3\u5207\u6362\uFF0C\u591A\u4E45\u786E\u8BA4\u79BB\u5F00\uFF08\u53EA\u5F71\u54CD\u4EA4\u4E92\uFF0C\u4E0D\u8BB0\u5165\u753B\u50CF\uFF09\u3002',\r\n cooldownTitle: '\u642D\u8BDD\u51B7\u5374',\r\n cooldownDesc: '\u4E24\u6B21\u4E3B\u52A8\u642D\u8BDD\u81F3\u5C11\u9694\u591A\u5C11\u5206\u949F\u3002',\r\n storage: {\r\n label: '\u6D3B\u52A8\u65E5\u8BB0',\r\n note: '\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1B\u4E0D\u4F1A\u5F71\u54CD\u751F\u4EA7\u65B9\u7684\u76F8\u518C\u4E0E\u914D\u7F6E\u3002',\r\n stat: (entries: string, samples: string) => `${entries} \u6761\u7EC6\u8282 \u00B7 ${samples} \u4E2A\u72B6\u6001\u91C7\u6837`,\r\n cleared: (n: number) => `\u5DF2\u5220\u9664 ${n} \u6761\u8BB0\u5F55`,\r\n },\r\n } : {\r\n group: 'Event stream and memory',\r\n groupDesc: 'Where events come from, how they are filtered and smoothed, and how long details last.',\r\n enabledTitle: 'Read the event stream',\r\n enabledDesc: 'When on, new events are imported at a fixed interval.',\r\n pollTitle: 'Poll interval',\r\n pollDesc: 'How often to check for new events.',\r\n lookbackTitle: 'First import',\r\n lookbackDesc: 'On the first run, import up to this many minutes of existing events.',\r\n keepTitle: 'State kept, days',\r\n keepDesc: 'Smoothed state and daily summaries are kept this many days.',\r\n sourceTitle: 'Event source',\r\n sourceDesc: 'The producer World id; `screen-sense` by default.',\r\n maxTitle: 'Events per poll',\r\n maxDesc: 'Most events imported at once; the rest wait for the next poll.',\r\n blurAiTitle: 'Blur AI chats',\r\n blurAiDesc: 'AI chat windows count as neutral and their titles are not stored.',\r\n ignoreTitle: 'Extra filters',\r\n ignoreAppsDesc: 'Comma separated app-name fragments; communication apps are filtered by default.',\r\n smoothingTitle: 'Smoothing',\r\n smoothingDesc: '0.05 is very smooth, 0.9 reacts fast; 0.25 by default.',\r\n detailTitle: 'Detail hours',\r\n detailDesc: 'Window titles, captions and text are kept this long, then only smoothed state remains.',\r\n sampleTitle: 'Sample interval',\r\n sampleDesc: 'At least this many seconds between two stored state samples.',\r\n wordsTitle: 'Word-bag state',\r\n wordsDesc: 'App and title tokens vote with time decay; off falls back to the category EMA.',\r\n wordWindowTitle: 'Word window',\r\n wordWindowDesc: 'Only tokens from this many minutes back feed the state.',\r\n halfLifeTitle: 'Token half-life',\r\n halfLifeDesc: 'How fast a token weight halves; smaller looks at the present only.',\r\n flowTitle: 'Flow decay',\r\n flowDesc: 'Silence that counts as focus or away; each app type multiplies the base (dev/office 20m, video 30m, game 12m, browser 8m).',\r\n checkInTitle: 'Check in when depleted',\r\n checkInDesc: 'Lets Coo offer a break or a soft nudge when the flow depletes; off by default.',\r\n awayTitle: 'Confirm away',\r\n awayDesc: 'After a check-in, silence this long confirms away (interaction only, not profiling).',\r\n cooldownTitle: 'Check-in cooldown',\r\n cooldownDesc: 'Minimum minutes between two proactive check-ins.',\r\n storage: {\r\n label: 'Activity diary',\r\n note: 'Deletes detail entries and smoothed state; the producer album and settings are untouched.',\r\n stat: (entries: string, samples: string) => `${entries} entries \u00B7 ${samples} state samples`,\r\n cleared: (n: number) => `Deleted ${n} records`,\r\n },\r\n };\r\n}\r\n\r\nexport function diaryStorageText(language: Language) {\r\n return diaryText(language).storage;\r\n}\r\n\r\nexport interface DiaryPanelText {\r\n title: string;\r\n description: string;\r\n refresh: string;\r\n clear: string;\r\n clearConfirm: string;\r\n cleared: (n: number) => string;\r\n empty: string;\r\n waitingProducer: (source: string) => string;\r\n loading: string;\r\n failed: string;\r\n stateTitle: string;\r\n current: (label: string) => string;\r\n trend: string;\r\n noTrend: string;\r\n details: string;\r\n detailsNote: string;\r\n search: string;\r\n searchPlaceholder: string;\r\n noResults: string;\r\n privacyNote: string;\r\n axisTech: string;\r\n axisWork: string;\r\n}\r\n\r\nexport function diaryPanelText(language: Language): DiaryPanelText {\r\n const zh = language === 'zh' || language === 'zh-Hant';\r\n return zh ? {\r\n title: '\u6D3B\u52A8\u65E5\u8BB0',\r\n description: '\u4E8C\u7EF4\u72B6\u6001\u7A7A\u95F4\uFF1A\u6280\u672F\u91CD\u5EA6\u4E0E\u529E\u516C/\u5A31\u4E50\u7684\u5E73\u6ED1\u8F68\u8FF9\uFF1B\u7EC6\u8282\u4F1A\u968F\u65F6\u95F4\u6DE1\u5FD8\u3002',\r\n refresh: '\u5237\u65B0',\r\n clear: '\u6E05\u7A7A\u65E5\u8BB0',\r\n clearConfirm: '\u5220\u9664\u5168\u90E8\u7EC6\u8282\u8BB0\u5F55\u4E0E\u5E73\u6ED1\u72B6\u6001\uFF1F\u4E0D\u4F1A\u5F71\u54CD\u7AA5\u5C4F\u52A9\u624B\u7684\u76F8\u518C\u3002',\r\n cleared: (n) => `\u5DF2\u5220\u9664 ${n} \u6761\u8BB0\u5F55`,\r\n empty: '\u8FD8\u6CA1\u6709\u8BB0\u5F55\u3002\u5148\u5B89\u88C5\u5E76\u542F\u7528\u7AA5\u5C4F\u52A9\u624B\uFF0C\u5207\u51E0\u6B21\u5E94\u7528\u540E\u8FD9\u91CC\u4F1A\u51FA\u73B0\u72B6\u6001\u8F68\u8FF9\u3002',\r\n waitingProducer: (source) => `\u8FD8\u6CA1\u6709\u6536\u5230\u6765\u81EA ${source} \u7684\u4E8B\u4EF6\uFF1B\u786E\u8BA4\u7AA5\u5C4F\u52A9\u624B\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\u3002`,\r\n loading: '\u8BFB\u53D6\u4E2D\u2026',\r\n failed: '\u8BFB\u53D6\u5931\u8D25',\r\n stateTitle: '\u5F53\u524D\u72B6\u6001',\r\n current: (label) => `\u5F53\u524D\uFF1A${label}`,\r\n trend: '\u6700\u8FD1\u8F68\u8FF9',\r\n noTrend: '\u8FD8\u6CA1\u6709\u8DB3\u591F\u7684\u91C7\u6837\u70B9',\r\n details: '\u8BE6\u7EC6\u8BB0\u5F55\uFF08\u663E\u5F0F\u56DE\u5FC6\uFF09',\r\n detailsNote: '\u53EA\u4FDD\u7559\u6700\u8FD1\u4E00\u6BB5\u65F6\u95F4\uFF1B\u901A\u8BAF\u7C7B\u5E94\u7528\u4E0D\u5728\u6B64\u5217\u3002',\r\n search: '\u641C\u7D22',\r\n searchPlaceholder: '\u641C\u5E94\u7528\u540D\u3001\u7A97\u53E3\u6807\u9898\u6216\u901F\u5199',\r\n noResults: '\u6CA1\u6709\u5339\u914D\u7684\u8BB0\u5F55',\r\n privacyNote: '\u901A\u8BAF\u7C7B\u5E94\u7528\u5DF2\u8FC7\u6EE4\uFF1BAI \u5BF9\u8BDD\u9ED8\u8BA4\u6A21\u7CCA\u4E3A\u4E2D\u6027\uFF1B\u7A97\u53E3\u6807\u9898\u53EA\u77ED\u671F\u4FDD\u7559\u3002',\r\n axisTech: '\u6280\u672F\u91CD\u5EA6',\r\n axisWork: '\u5DE5\u4F5C',\r\n } : {\r\n title: 'Activity diary',\r\n description: 'A two-axis state space: technical weight and work/entertainment, smoothed over time; details fade.',\r\n refresh: 'Refresh',\r\n clear: 'Clear diary',\r\n clearConfirm: 'Delete detail entries and smoothed state? The screen-sense album is untouched.',\r\n cleared: (n) => `Deleted ${n} records`,\r\n empty: 'No entries yet. Install and enable screen-sense, switch apps a few times, then come back.',\r\n waitingProducer: (source) => `No events from ${source} yet; check that screen-sense is installed and enabled.`,\r\n loading: 'Loading\u2026',\r\n failed: 'Could not load',\r\n stateTitle: 'Current state',\r\n current: (label) => `Now: ${label}`,\r\n trend: 'Recent trajectory',\r\n noTrend: 'Not enough samples yet',\r\n details: 'Detail entries (explicit recall)',\r\n detailsNote: 'Kept briefly only; communication apps are excluded.',\r\n search: 'Search',\r\n searchPlaceholder: 'app, window title or caption',\r\n noResults: 'No matching entries',\r\n privacyNote: 'Communication apps are filtered; AI chats are blurred to neutral; titles are kept briefly.',\r\n axisTech: 'Technical',\r\n axisWork: 'Work',\r\n };\r\n}\r\n\r\nexport function diaryConfigGroup(language: Language = 'zh'): ConfigGroup {\r\n const t = diaryText(language);\r\n const K = 'worlds.screen-diary';\r\n return {\r\n id: 'world:screen-diary',\r\n owner: 'world:screen-diary',\r\n schema: {\r\n type: 'object',\r\n title: t.group,\r\n description: t.groupDesc,\r\n properties: {\r\n [`${K}.enabled`]: { type: 'boolean', title: t.enabledTitle, description: t.enabledDesc, 'x-hot': true },\r\n [`${K}.pollMs`]: { type: 'integer', title: t.pollTitle, description: t.pollDesc, minimum: 1000, maximum: 300000, 'x-suffix': 'ms', 'x-hot': true },\r\n [`${K}.lookbackMinutes`]: { type: 'integer', title: t.lookbackTitle, description: t.lookbackDesc, minimum: 0, maximum: 1440, 'x-suffix': 'min' },\r\n [`${K}.keepDays`]: { type: 'integer', title: t.keepTitle, description: t.keepDesc, minimum: 1, maximum: 3650, 'x-suffix': 'd' },\r\n [`${K}.detailHours`]: { type: 'integer', title: t.detailTitle, description: t.detailDesc, minimum: 1, maximum: 720, 'x-suffix': 'h', 'x-hot': true },\r\n [`${K}.blurAi`]: { type: 'boolean', title: t.blurAiTitle, description: t.blurAiDesc, 'x-hot': true },\r\n [`${K}.ignoreApps`]: { type: 'string', title: t.ignoreTitle, description: t.ignoreAppsDesc, 'x-hot': true },\r\n [`${K}.smoothing`]: { type: 'number', title: t.smoothingTitle, description: t.smoothingDesc, minimum: 0.05, maximum: 0.9, 'x-hot': true },\r\n [`${K}.sampleSec`]: { type: 'integer', title: t.sampleTitle, description: t.sampleDesc, minimum: 5, maximum: 600, 'x-suffix': 's' },\r\n [`${K}.flowDecayMinutes`]: { type: 'integer', title: t.flowTitle, description: t.flowDesc, minimum: 1, maximum: 180, 'x-suffix': 'min', 'x-hot': true },\r\n [`${K}.checkInEnabled`]: { type: 'boolean', title: t.checkInTitle, description: t.checkInDesc, 'x-hot': true },\r\n [`${K}.awayAfterMinutes`]: { type: 'integer', title: t.awayTitle, description: t.awayDesc, minimum: 1, maximum: 120, 'x-suffix': 'min' },\r\n [`${K}.checkInCooldownMinutes`]: { type: 'integer', title: t.cooldownTitle, description: t.cooldownDesc, minimum: 5, maximum: 1440, 'x-suffix': 'min' },\r\n [`${K}.useWords`]: { type: 'boolean', title: t.wordsTitle, description: t.wordsDesc, 'x-hot': true },\r\n [`${K}.wordWindowMinutes`]: { type: 'integer', title: t.wordWindowTitle, description: t.wordWindowDesc, minimum: 1, maximum: 240, 'x-suffix': 'min' },\r\n [`${K}.wordHalfLifeMinutes`]: { type: 'integer', title: t.halfLifeTitle, description: t.halfLifeDesc, minimum: 1, maximum: 120, 'x-suffix': 'min' },\r\n [`${K}.source`]: { type: 'string', title: t.sourceTitle, description: t.sourceDesc },\r\n [`${K}.maxEventsPerPoll`]: { type: 'integer', title: t.maxTitle, description: t.maxDesc, minimum: 1, maximum: 5000 },\r\n },\r\n },\r\n };\r\n}\r\n", "/** The activity state panel: a two-axis trajectory plus short-lived detail entries. */\r\nimport type { WebUiClientBundle, WebUiPanel, WebUiPanelContext } from 'cortico/web/shared/client-panel.ts';\r\nimport { diaryPanelText } from '../config.ts';\r\nimport './style.css';\r\n\r\ninterface Point { ts: string; tech: number; work: number; zh: string; en: string }\r\ninterface State {\r\n enabled: boolean;\r\n source: string;\r\n current: { tech: number; work: number; zh: string; en: string; category: string };\r\n samples: Point[];\r\n top: Array<{ token: string; weight: number }>;\r\n entries: number;\r\n days: number;\r\n lastCursor: number;\r\n flow: { state: string; gapMs: number; decayMs: number; category: string } | null;\r\n}\r\ninterface Entry {\r\n cursor: number;\r\n ts: string;\r\n type: string;\r\n text: string;\r\n app?: string;\r\n title?: string;\r\n caption?: string;\r\n clock: string;\r\n day: string;\r\n hour: string;\r\n}\r\n\r\nconst SVG = 'http://www.w3.org/2000/svg';\r\nconst el = <K extends keyof SVGElementTagNameMap>(name: K, attrs: Record<string, string | number> = {}): SVGElementTagNameMap[K] => {\r\n const node = document.createElementNS(SVG, name);\r\n for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, String(value));\r\n return node;\r\n};\r\n\r\nconst timelinePanel: WebUiPanel = {\r\n mount(ctx: WebUiPanelContext) {\r\n const t = diaryPanelText(ctx.language);\r\n const zh = ctx.language === 'zh' || ctx.language === 'zh-Hant';\r\n const label = (point: { zh: string; en: string }) => (zh ? point.zh : point.en);\r\n\r\n const root = document.createElement('div');\r\n root.style.cssText = 'display:flex;flex-direction:column;gap:12px;height:100%;box-sizing:border-box;padding:14px;overflow:auto';\r\n\r\n const button = (text: string, danger = false) => {\r\n const node = document.createElement('button');\r\n node.textContent = text;\r\n node.style.cssText = `font:inherit;font-size:13px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:${danger ? 'rgba(200,60,60,.12)' : 'transparent'};color:inherit`;\r\n return node;\r\n };\r\n const input = (placeholder: string) => {\r\n const node = document.createElement('input');\r\n node.placeholder = placeholder;\r\n node.style.cssText = 'font:inherit;font-size:13px;padding:4px 8px;border-radius:6px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.45);min-width:200px';\r\n return node;\r\n };\r\n\r\n const bar = document.createElement('div');\r\n bar.style.cssText = 'display:flex;gap:8px;align-items:center;flex-wrap:wrap';\r\n const count = document.createElement('span');\r\n count.style.cssText = 'opacity:.75;font-size:13px';\r\n const spacer = document.createElement('span');\r\n spacer.style.flex = '1';\r\n const refresh = button(t.refresh);\r\n const clear = button(t.clear, true);\r\n bar.append(count, spacer, refresh, clear);\r\n\r\n const current = document.createElement('div');\r\n current.style.cssText = 'font-size:14px;font-weight:600';\r\n const topLine = document.createElement('div');\r\n topLine.style.cssText = 'font-size:12px;opacity:.7';\r\n\r\n const chart = el('svg', { viewBox: '0 0 420 300', width: '100%', height: '300', style: 'max-width:520px;align-self:center' });\r\n const chartBox = document.createElement('div');\r\n chartBox.style.cssText = 'display:flex;flex-direction:column;gap:6px';\r\n const privacy = document.createElement('div');\r\n privacy.textContent = t.privacyNote;\r\n privacy.style.cssText = 'font-size:12px;opacity:.7;max-width:640px';\r\n chartBox.append(chart, privacy);\r\n\r\n const detailsTitle = document.createElement('div');\r\n detailsTitle.textContent = t.details;\r\n detailsTitle.style.cssText = 'font-size:13px;font-weight:600;opacity:.85;margin-top:6px';\r\n const detailsNote = document.createElement('div');\r\n detailsNote.textContent = t.detailsNote;\r\n detailsNote.style.cssText = 'font-size:12px;opacity:.65';\r\n\r\n const detailBar = document.createElement('div');\r\n detailBar.style.cssText = 'display:flex;gap:8px;align-items:center;flex-wrap:wrap';\r\n const search = input(t.searchPlaceholder);\r\n const searchButton = button(t.search);\r\n const reset = button(t.refresh);\r\n detailBar.append(search, searchButton, reset);\r\n\r\n const notice = document.createElement('div');\r\n notice.style.cssText = 'font-size:12px;opacity:.8;min-height:16px;white-space:pre-wrap';\r\n const list = document.createElement('div');\r\n list.style.cssText = 'display:flex;flex-direction:column;gap:6px';\r\n\r\n const draw = (state: State) => {\r\n chart.replaceChildren();\r\n const w = 420, h = 300, cx = w / 2, cy = h / 2, pad = 40;\r\n const x = (work: number) => cx + Math.max(-1, Math.min(1, work)) * (cx - pad);\r\n const y = (tech: number) => cy - Math.max(-1, Math.min(1, tech)) * (cy - pad);\r\n chart.append(\r\n el('line', { x1: pad, y1: cy, x2: w - pad, y2: cy, stroke: 'currentColor', 'stroke-opacity': 0.35, 'stroke-width': 1 }),\r\n el('line', { x1: cx, y1: pad, x2: cx, y2: h - pad, stroke: 'currentColor', 'stroke-opacity': 0.35, 'stroke-width': 1 }),\r\n );\r\n const points = state.samples.slice(-120).reverse();\r\n if (points.length >= 2) {\r\n const path = el('polyline', {\r\n points: points.map((point) => `${x(point.work)},${y(point.tech)}`).join(' '),\r\n fill: 'none', stroke: '#5fd4c8', 'stroke-width': 2, 'stroke-opacity': 0.85,\r\n });\r\n chart.append(path);\r\n for (const point of points.slice(0, 12)) {\r\n chart.append(el('circle', { cx: x(point.work), cy: y(point.tech), r: 3, fill: '#5fd4c8', 'fill-opacity': 0.5 }));\r\n }\r\n }\r\n chart.append(el('circle', { cx: x(state.current.work), cy: y(state.current.tech), r: 7, fill: '#5fd4c8' }));\r\n };\r\n\r\n const row = (entry: Entry): HTMLElement => {\r\n const box = document.createElement('div');\r\n box.style.cssText = 'display:flex;gap:10px;align-items:baseline;font-size:13px;padding:3px 0;border-bottom:1px solid rgba(128,128,128,.12)';\r\n const clock = document.createElement('span');\r\n clock.textContent = entry.clock;\r\n clock.style.cssText = 'font-family:ui-monospace,monospace;opacity:.7;flex:none';\r\n const app = document.createElement('span');\r\n app.textContent = entry.app ?? '';\r\n app.style.cssText = 'font-family:ui-monospace,monospace;opacity:.85;flex:none;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';\r\n const text = document.createElement('span');\r\n text.textContent = entry.caption ?? entry.text;\r\n text.style.cssText = 'flex:1;line-height:1.45';\r\n box.append(clock, app, text);\r\n return box;\r\n };\r\n\r\n const loadDetails = async (keyword = '') => {\r\n list.replaceChildren();\r\n notice.textContent = '';\r\n try {\r\n const data = keyword\r\n ? await ctx.invoke<{ entries: Entry[] }>('search', [keyword, 20])\r\n : await ctx.invoke<{ entries: Entry[] }>('list', [{ limit: 50 }]);\r\n if (data.entries.length === 0) {\r\n notice.textContent = keyword ? t.noResults : t.detailsNote;\r\n return;\r\n }\r\n for (const entry of data.entries) list.append(row(entry));\r\n } catch (err) {\r\n notice.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\r\n }\r\n };\r\n\r\n const load = async () => {\r\n count.textContent = t.loading;\r\n try {\r\n const state = await ctx.invoke<State>('state');\r\n count.textContent = `${state.days} \u5929 \u00B7 ${state.samples.length} \u91C7\u6837`;\r\n current.textContent = t.current(label(state.current));\r\n topLine.textContent = state.top && state.top.length ? (zh ? '\u9AD8\u9891\u8BCD\uFF1A' : 'Top tokens: ') + state.top.map((row) => row.token).join(' \u00B7 ') : '';\r\n if (state.samples.length === 0) {\r\n notice.textContent = t.waitingProducer(state.source);\r\n }\r\n draw(state);\r\n await loadDetails();\r\n } catch (err) {\r\n count.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\r\n }\r\n };\r\n\r\n refresh.addEventListener('click', () => void load());\r\n reset.addEventListener('click', () => { search.value = ''; void loadDetails(); });\r\n searchButton.addEventListener('click', () => void loadDetails(search.value.trim()));\r\n search.addEventListener('keydown', (event) => { if (event.key === 'Enter') void loadDetails(search.value.trim()); });\r\n clear.addEventListener('click', () => {\r\n if (!window.confirm(t.clearConfirm)) return;\r\n void (async () => {\r\n try {\r\n const out = await ctx.invoke<{ removed: number }>('clear', []);\r\n notice.textContent = t.cleared(out.removed);\r\n await load();\r\n } catch (err) {\r\n notice.textContent = `${t.failed}: ${err instanceof Error ? err.message : String(err)}`;\r\n }\r\n })();\r\n });\r\n\r\n root.append(bar, current, topLine, chartBox, detailsTitle, detailsNote, detailBar, notice, list);\r\n ctx.root.append(root);\r\n void load();\r\n return { dispose() {} };\r\n },\r\n};\r\n\r\ninterface WordRow {\r\n token: string;\r\n kind: 'app' | 'word';\r\n app?: string;\r\n count: number;\r\n lastSeen: string;\r\n coord: [number, number];\r\n weight: number;\r\n}\r\n\r\nconst APP_OPTIONS = [\r\n ['develop', '\u5F00\u53D1', 'Development'],\r\n ['office', '\u6587\u4E66', 'Documents'],\r\n ['video', '\u89C6\u9891', 'Video'],\r\n ['game', '\u6E38\u620F', 'Gaming'],\r\n ['casual', '\u6302\u673A/\u8F7B\u5A31\u4E50', 'Casual'],\r\n ['browser', '\u6D4F\u89C8\u5668', 'Browser'],\r\n ['ai', 'AI', 'AI'],\r\n ['neutral', '\u4E2D\u6027', 'Neutral'],\r\n ['filtered', '\u8FC7\u6EE4', 'Filtered'],\r\n] as const;\r\n\r\nconst wordsPanel: WebUiPanel = {\r\n mount(ctx: WebUiPanelContext) {\r\n const zh = ctx.language === 'zh' || ctx.language === 'zh-Hant';\r\n const root = document.createElement('div');\r\n root.style.cssText = 'display:flex;flex-direction:column;gap:10px;height:100%;box-sizing:border-box;padding:14px;overflow:auto';\r\n\r\n const title = document.createElement('div');\r\n title.textContent = zh ? '\u8BCD\u6C47\u4E0E\u8870\u51CF' : 'Words and decay';\r\n title.style.cssText = 'font-size:14px;font-weight:600';\r\n const note = document.createElement('div');\r\n note.textContent = zh\r\n ? '\u5E94\u7528\u540D\u4E0E\u7A97\u53E3\u6807\u9898\u8BCD\u540C\u8868\uFF1B\u5750\u6807 = [\u5DE5\u4F5C/\u5A31\u4E50, \u8F7B/\u91CD]\uFF0C\u6743\u91CD\u8D8A\u9AD8\u8D8A\u80FD\u62C9\u52A8\u72B6\u6001\u3002\u6807\u9898\u53EA\u4EE5\u8BCD\u9891\u5F62\u5F0F\u4FDD\u7559\u3002\u901A\u8BAF\u7C7B\u9ED8\u8BA4\u8FC7\u6EE4\uFF1B\u5E94\u7528\u8BCD\u53EF\u8986\u76D6\u7C7B\u578B\u4E0E\u6D41\u67AF\u7AED\u7A97\u53E3\u3002'\r\n : 'App names and title words share one table; coordinates are [work/entertainment, light/heavy] and heavier words pull the state more. Titles are kept only as token counts. Communication apps are filtered by default; app tokens can override category and decay.';\r\n note.style.cssText = 'font-size:12px;opacity:.7;max-width:800px';\r\n\r\n const status = document.createElement('div');\r\n status.style.cssText = 'font-size:12px;opacity:.75;min-height:16px';\r\n const controls = document.createElement('label');\r\n controls.style.cssText = 'display:flex;gap:6px;align-items:center;font-size:12px;opacity:.75;cursor:pointer';\r\n const showAll = document.createElement('input');\r\n showAll.type = 'checkbox';\r\n const showAllText = document.createElement('span');\r\n showAllText.textContent = zh ? '\u663E\u793A\u672A\u77E5\u8BCD\uFF08\u6743\u91CD 0.1\uFF09' : 'Show unknown tokens (weight 0.1)';\r\n controls.append(showAll, showAllText);\r\n showAll.addEventListener('change', () => void load());\r\n const table = document.createElement('div');\r\n table.style.cssText = 'display:flex;flex-direction:column;gap:6px';\r\n\r\n const COLUMNS = 'minmax(150px,1.6fr) 52px 56px 56px 52px minmax(150px,1fr) 96px';\r\n\r\n const header = (): HTMLElement => {\r\n const head = document.createElement('div');\r\n head.style.cssText = 'display:grid;grid-template-columns:' + COLUMNS + ';gap:8px;align-items:center;font-size:11px;opacity:.55;padding:4px 0;border-bottom:1px solid rgba(128,128,128,.3)';\r\n const labels = [\r\n zh ? '\u8BCD' : 'token',\r\n zh ? '\u6B21\u6570' : 'count',\r\n zh ? '\u5DE5\u4F5C' : 'work',\r\n zh ? '\u6280\u672F' : 'tech',\r\n zh ? '\u6743\u91CD' : 'weight',\r\n zh ? '\u7C7B\u578B / \u8870\u51CF' : 'type / decay',\r\n zh ? '\u64CD\u4F5C' : 'action',\r\n ];\r\n for (let i = 0; i < labels.length; i += 1) {\r\n const cell = document.createElement('span');\r\n cell.textContent = labels[i]!;\r\n if (i >= 1 && i <= 4) cell.style.textAlign = 'right';\r\n if (i === 6) cell.style.textAlign = 'right';\r\n head.append(cell);\r\n }\r\n return head;\r\n };\r\n\r\n const renderRow = (row: WordRow): HTMLElement => {\r\n const line = document.createElement('div');\r\n line.style.cssText = 'display:grid;grid-template-columns:' + COLUMNS + ';gap:8px;align-items:center;font-size:13px;padding:5px 0;border-bottom:1px solid rgba(128,128,128,.14)';\r\n const token = document.createElement('span');\r\n token.textContent = row.token;\r\n token.style.cssText = 'font-family:ui-monospace,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';\r\n const count = document.createElement('span');\r\n count.textContent = row.count + ' \u00D7';\r\n count.style.cssText = 'opacity:.65;font-size:12px;text-align:right';\r\n const work = document.createElement('span');\r\n work.textContent = row.coord[0].toFixed(2);\r\n work.style.cssText = 'opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace';\r\n const tech = document.createElement('span');\r\n tech.textContent = row.coord[1].toFixed(2);\r\n tech.style.cssText = 'opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace';\r\n const weight = document.createElement('span');\r\n weight.textContent = row.weight.toFixed(1);\r\n weight.style.cssText = 'opacity:.7;font-size:12px;text-align:right;font-family:ui-monospace,monospace';\r\n line.append(token, count, work, tech, weight);\r\n\r\n if (row.kind !== 'app' || !row.app) {\r\n const kind = document.createElement('span');\r\n kind.textContent = zh ? '\u6807\u9898\u8BCD \u00B7 \u53EA\u8BFB' : 'title word \u00B7 read-only';\r\n kind.style.cssText = 'font-size:11px;opacity:.45';\r\n const dash = document.createElement('span');\r\n dash.textContent = '\u2014';\r\n dash.style.cssText = 'opacity:.3;text-align:right';\r\n line.append(kind, dash);\r\n return line;\r\n }\r\n\r\n const controls = document.createElement('div');\r\n controls.style.cssText = 'display:flex;gap:4px;align-items:center;min-width:0';\r\n const select = document.createElement('select');\r\n select.style.cssText = 'font:inherit;font-size:12px;padding:3px 4px;border-radius:5px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.4);min-width:0;flex:1';\r\n const auto = document.createElement('option');\r\n auto.value = '';\r\n auto.textContent = zh ? '\u8DDF\u968F\u9ED8\u8BA4' : 'default';\r\n select.append(auto);\r\n for (const [value, labelZh, labelEn] of APP_OPTIONS) {\r\n const option = document.createElement('option');\r\n option.value = value;\r\n option.textContent = zh ? labelZh : labelEn;\r\n select.append(option);\r\n }\r\n const decay = document.createElement('input');\r\n decay.type = 'number';\r\n decay.min = '1';\r\n decay.max = '180';\r\n decay.placeholder = zh ? '\u9ED8\u8BA4' : 'def';\r\n decay.title = zh ? '\u7559\u7A7A\u8DDF\u968F\u8BE5\u7C7B\u578B\u7684\u9ED8\u8BA4\u7A97\u53E3' : 'Empty follows the category default';\r\n decay.style.cssText = 'width:62px;font:inherit;font-size:12px;padding:3px 4px;border-radius:5px;background:transparent;color:inherit;border:1px solid rgba(128,128,128,.4)';\r\n controls.append(select, decay);\r\n\r\n const action = document.createElement('div');\r\n action.style.cssText = 'display:flex;justify-content:flex-end';\r\n const save = document.createElement('button');\r\n save.textContent = zh ? '\u4FDD\u5B58' : 'Save';\r\n save.style.cssText = 'font:inherit;font-size:12px;padding:3px 9px;border-radius:5px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:transparent;color:inherit';\r\n save.addEventListener('click', () => {\r\n void (async () => {\r\n try {\r\n const minutes = decay.value.trim() ? Number(decay.value) : 0;\r\n await ctx.invoke('setApp', [row.app, select.value || null, minutes]);\r\n status.textContent = zh ? '\u5DF2\u4FDD\u5B58 ' + row.app : 'Saved ' + row.app;\r\n } catch (err) {\r\n status.textContent = (zh ? '\u4FDD\u5B58\u5931\u8D25' : 'Save failed') + ': ' + (err instanceof Error ? err.message : String(err));\r\n }\r\n })();\r\n });\r\n action.append(save);\r\n line.append(controls, action);\r\n return line;\r\n };\r\n const load = async () => {\r\n table.replaceChildren();\r\n status.textContent = zh ? '\u8BFB\u53D6\u4E2D\u2026' : 'Loading\u2026';\r\n try {\r\n const data = await ctx.invoke<{ words: WordRow[] }>('words');\r\n const rows = data.words;\r\n const visible = showAll.checked ? rows : rows.filter((row) => row.kind === 'app' || row.weight > 0.1);\r\n status.textContent = visible.length\r\n ? `${visible.length} / ${rows.length} ${zh ? '\u4E2A\u8BCD' : 'tokens'}`\r\n : (zh ? '\u8FD8\u6CA1\u6709\u91C7\u96C6\u5230\u6709\u4FE1\u53F7\u8BCD\uFF1B\u53EF\u52FE\u9009\u201C\u663E\u793A\u672A\u77E5\u8BCD\u201D\u67E5\u770B\u5168\u90E8' : 'No signal tokens yet; enable \u201CShow unknown tokens\u201D to see everything');\r\n table.append(header());\r\n for (const row of visible) table.append(renderRow(row));\r\n } catch (err) {\r\n status.textContent = `${zh ? '\u8BFB\u53D6\u5931\u8D25' : 'Failed'}: ${err instanceof Error ? err.message : String(err)}`;\r\n }\r\n };\r\n\r\n root.append(title, note, controls, status, table);\r\n ctx.root.append(root);\r\n void load();\r\n return { dispose() {} };\r\n },\r\n};\r\ninterface Diagnostics {\r\n flow: { state: string; lastSwitchAt: number; gapMs: number; decayMs: number; category: string; checkInEnabled: boolean; baseDecayMinutes: number; awayAfterMinutes: number; checkInCooldownMinutes: number };\r\n config: { source: string; sampleSec: number; detailHours: number; keepDays: number; smoothing: number; blurAi: boolean; ignoreApps: string };\r\n counts: { apps: number; samples: number; entries: number; cursor: number };\r\n rules: Array<{ id: string; enabled: boolean; action: string; trigger: string; title: string }>;\r\n}\r\n\r\nconst developerPanel: WebUiPanel = {\r\n mount(ctx: WebUiPanelContext) {\r\n const zh = ctx.language === 'zh' || ctx.language === 'zh-Hant';\r\n const root = document.createElement('div');\r\n root.style.cssText = 'display:flex;flex-direction:column;gap:10px;height:100%;box-sizing:border-box;padding:14px;overflow:auto';\r\n const title = document.createElement('div');\r\n title.textContent = zh ? '\u5F00\u53D1\u8005\u9009\u9879' : 'Developer options';\r\n title.style.cssText = 'font-size:14px;font-weight:600';\r\n const note = document.createElement('div');\r\n note.textContent = zh ? '\u8FD9\u91CC\u663E\u793A\u5F53\u524D\u89C4\u5219\u4E0E\u8BCA\u65AD\uFF1B\u4E0B\u4E00\u6B65\u7684\u89C4\u5219\u5F00\u5173\u3001\u9608\u503C\u4E0E\u89E6\u53D1\u539F\u56E0\u4F1A\u653E\u5728\u8FD9\u91CC\u3002' : 'Current rules and diagnostics; rule toggles, thresholds and reasons will live here next.';\r\n note.style.cssText = 'font-size:12px;opacity:.7;max-width:760px';\r\n const body = document.createElement('div');\r\n body.style.cssText = 'display:flex;flex-direction:column;gap:10px;font-size:13px';\r\n const status = document.createElement('div');\r\n status.style.cssText = 'font-size:12px;opacity:.75;min-height:16px';\r\n const controls = document.createElement('label');\r\n controls.style.cssText = 'display:flex;gap:6px;align-items:center;font-size:12px;opacity:.75;cursor:pointer';\r\n const showAll = document.createElement('input');\r\n showAll.type = 'checkbox';\r\n const showAllText = document.createElement('span');\r\n showAllText.textContent = zh ? '\u663E\u793A\u672A\u77E5\u8BCD\uFF08\u6743\u91CD 0.1\uFF09' : 'Show unknown tokens (weight 0.1)';\r\n controls.append(showAll, showAllText);\r\n showAll.addEventListener('change', () => void load());\r\n\r\n const section = (heading: string): HTMLElement => {\r\n const box = document.createElement('div');\r\n box.style.cssText = 'display:flex;flex-direction:column;gap:5px;padding:10px;border:1px solid rgba(128,128,128,.18);border-radius:8px';\r\n const h = document.createElement('div');\r\n h.textContent = heading;\r\n h.style.cssText = 'font-size:12px;font-weight:600;opacity:.8';\r\n box.append(h);\r\n return box;\r\n };\r\n const line = (text: string, value: string): HTMLElement => {\r\n const row = document.createElement('div');\r\n row.style.cssText = 'display:flex;gap:12px;font-size:12px';\r\n const left = document.createElement('span');\r\n left.textContent = text;\r\n left.style.cssText = 'opacity:.6;min-width:170px';\r\n const right = document.createElement('span');\r\n right.textContent = value;\r\n right.style.cssText = 'font-family:ui-monospace,monospace;word-break:break-all';\r\n row.append(left, right);\r\n return row;\r\n };\r\n\r\n const load = async () => {\r\n body.replaceChildren();\r\n status.textContent = zh ? '\u8BFB\u53D6\u4E2D\u2026' : 'Loading\u2026';\r\n try {\r\n const data = await ctx.invoke<Diagnostics>('diagnostics');\r\n status.textContent = '';\r\n const flow = section(zh ? '\u5F53\u524D flow' : 'Current flow');\r\n flow.append(\r\n line(zh ? '\u72B6\u6001' : 'state', data.flow.state),\r\n line(zh ? '\u6700\u540E\u5207\u6362' : 'last switch', data.flow.lastSwitchAt ? new Date(data.flow.lastSwitchAt).toLocaleString() : '\u2014'),\r\n line(zh ? '\u9759\u9ED8 / \u9608\u503C' : 'gap / decay', `${Math.round(data.flow.gapMs / 1000)}s / ${Math.round(data.flow.decayMs / 1000)}s`),\r\n line(zh ? '\u6700\u540E\u7C7B\u578B' : 'last category', data.flow.category),\r\n );\r\n const rules = section(zh ? '\u89C4\u5219' : 'Rules');\r\n for (const rule of data.rules) {\r\n const row = document.createElement('div');\r\n row.style.cssText = 'display:flex;gap:10px;align-items:center;font-size:12px';\r\n const badge = document.createElement('span');\r\n badge.textContent = rule.enabled ? (zh ? '\u5F00' : 'on') : (zh ? '\u5173' : 'off');\r\n badge.style.cssText = `padding:1px 6px;border-radius:999px;border:1px solid ${rule.enabled ? 'rgba(95,212,200,.6)' : 'rgba(128,128,128,.35)'};opacity:${rule.enabled ? 1 : 0.55};font-size:11px`;\r\n const name = document.createElement('span');\r\n name.textContent = `${rule.id} \u00B7 ${rule.action}`;\r\n name.style.cssText = 'font-family:ui-monospace,monospace';\r\n const trigger = document.createElement('span');\r\n trigger.textContent = rule.trigger;\r\n trigger.style.cssText = 'opacity:.55;margin-left:auto';\r\n row.append(badge, name, trigger);\r\n rules.append(row);\r\n }\r\n const config = section(zh ? '\u914D\u7F6E\u4E0E\u8BA1\u6570' : 'Config and counts');\r\n config.append(\r\n line('source', data.config.source),\r\n line('smoothing', String(data.config.smoothing)),\r\n line(zh ? '\u7EC6\u8282\u5C0F\u65F6' : 'detailHours', String(data.config.detailHours)),\r\n line(zh ? '\u4FDD\u7559\u5929\u6570' : 'keepDays', String(data.config.keepDays)),\r\n line(zh ? '\u5E94\u7528 / \u91C7\u6837 / \u7EC6\u8282' : 'apps / samples / entries', `${data.counts.apps} / ${data.counts.samples} / ${data.counts.entries}`),\r\n line(zh ? '\u6E38\u6807' : 'cursor', String(data.counts.cursor)),\r\n );\r\n body.append(flow, rules, config);\r\n } catch (err) {\r\n status.textContent = `${zh ? '\u8BFB\u53D6\u5931\u8D25' : 'Failed'}: ${err instanceof Error ? err.message : String(err)}`;\r\n }\r\n };\r\n\r\n const bar = document.createElement('div');\r\n bar.style.cssText = 'display:flex;gap:8px;align-items:center';\r\n const refresh = document.createElement('button');\r\n refresh.textContent = zh ? '\u5237\u65B0' : 'Refresh';\r\n refresh.style.cssText = 'font:inherit;font-size:12px;padding:4px 10px;border-radius:6px;cursor:pointer;border:1px solid rgba(128,128,128,.45);background:transparent;color:inherit';\r\n refresh.addEventListener('click', () => void load());\r\n bar.append(refresh);\r\n\r\n root.append(title, note, bar, status, body);\r\n ctx.root.append(root);\r\n void load();\r\n return { dispose() {} };\r\n },\r\n};\r\n\r\nconst bundle: WebUiClientBundle = { panels: { timeline: timelinePanel, words: wordsPanel, developer: developerPanel } };\r\nexport default bundle;\r\n"],
|
|
5
|
+
"mappings": "AAwLO,SAASA,EAAeC,EAAoC,CAEjE,OADWA,IAAa,MAAQA,IAAa,UACjC,CACV,MAAO,2BACP,YAAa,8LACb,QAAS,eACT,MAAO,2BACP,aAAc,+JACd,QAAUC,GAAM,sBAAOA,CAAC,sBACxB,MAAO,yMACP,gBAAkBC,GAAW,8CAAWA,CAAM,0GAC9C,QAAS,2BACT,OAAQ,2BACR,WAAY,2BACZ,QAAUC,GAAU,qBAAMA,CAAK,GAC/B,MAAO,2BACP,QAAS,yDACT,QAAS,+DACT,YAAa,2HACb,OAAQ,eACR,kBAAmB,2EACnB,UAAW,6CACX,YAAa,oLACb,SAAU,2BACV,SAAU,cACZ,EAAI,CACF,MAAO,iBACP,YAAa,qGACb,QAAS,UACT,MAAO,cACP,aAAc,iFACd,QAAUF,GAAM,WAAWA,CAAC,WAC5B,MAAO,4FACP,gBAAkBC,GAAW,kBAAkBA,CAAM,0DACrD,QAAS,gBACT,OAAQ,iBACR,WAAY,gBACZ,QAAUC,GAAU,QAAQA,CAAK,GACjC,MAAO,oBACP,QAAS,yBACT,QAAS,mCACT,YAAa,sDACb,OAAQ,SACR,kBAAmB,+BACnB,UAAW,sBACX,YAAa,6FACb,SAAU,YACV,SAAU,MACZ,CACF,CC3MA,IAAMC,EAAM,6BACNC,EAAK,CAAuCC,EAASC,EAAyC,CAAC,IAA+B,CAClI,IAAMC,EAAO,SAAS,gBAAgBJ,EAAKE,CAAI,EAC/C,OAAW,CAACG,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAK,EAAGC,EAAK,aAAaC,EAAK,OAAOC,CAAK,CAAC,EACtF,OAAOF,CACT,EAEMG,EAA4B,CAChC,MAAMC,EAAwB,CAC5B,IAAMC,EAAIC,EAAeF,EAAI,QAAQ,EAC/BG,EAAKH,EAAI,WAAa,MAAQA,EAAI,WAAa,UAC/CI,EAASC,GAAuCF,EAAKE,EAAM,GAAKA,EAAM,GAEtEC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,2GAErB,IAAMC,EAAS,CAACC,EAAcC,EAAS,KAAU,CAC/C,IAAMb,EAAO,SAAS,cAAc,QAAQ,EAC5C,OAAAA,EAAK,YAAcY,EACnBZ,EAAK,MAAM,QAAU,mIAAmIa,EAAS,sBAAwB,aAAa,iBAC/Lb,CACT,EACMc,EAASC,GAAwB,CACrC,IAAMf,EAAO,SAAS,cAAc,OAAO,EAC3C,OAAAA,EAAK,YAAce,EACnBf,EAAK,MAAM,QAAU,4JACdA,CACT,EAEMgB,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,yDACpB,IAAMC,EAAQ,SAAS,cAAc,MAAM,EAC3CA,EAAM,MAAM,QAAU,6BACtB,IAAMC,EAAS,SAAS,cAAc,MAAM,EAC5CA,EAAO,MAAM,KAAO,IACpB,IAAMC,EAAUR,EAAON,EAAE,OAAO,EAC1Be,EAAQT,EAAON,EAAE,MAAO,EAAI,EAClCW,EAAI,OAAOC,EAAOC,EAAQC,EAASC,CAAK,EAExC,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,MAAM,QAAU,iCACxB,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,MAAM,QAAU,4BAExB,IAAMC,EAAQ1B,EAAG,MAAO,CAAE,QAAS,cAAe,MAAO,OAAQ,OAAQ,MAAO,MAAO,mCAAoC,CAAC,EACtH2B,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,MAAM,QAAU,6CACzB,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,YAAcpB,EAAE,YACxBoB,EAAQ,MAAM,QAAU,4CACxBD,EAAS,OAAOD,EAAOE,CAAO,EAE9B,IAAMC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,YAAcrB,EAAE,QAC7BqB,EAAa,MAAM,QAAU,4DAC7B,IAAMC,EAAc,SAAS,cAAc,KAAK,EAChDA,EAAY,YAActB,EAAE,YAC5BsB,EAAY,MAAM,QAAU,6BAE5B,IAAMC,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,MAAM,QAAU,yDAC1B,IAAMC,EAASf,EAAMT,EAAE,iBAAiB,EAClCyB,EAAenB,EAAON,EAAE,MAAM,EAC9B0B,EAAQpB,EAAON,EAAE,OAAO,EAC9BuB,EAAU,OAAOC,EAAQC,EAAcC,CAAK,EAE5C,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,MAAM,QAAU,iEACvB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,6CAErB,IAAMC,EAAQC,GAAiB,CAC7BZ,EAAM,gBAAgB,EACtB,IAAMa,EAAI,IAAKC,EAAI,IAAKC,EAAKF,EAAI,EAAGG,EAAKF,EAAI,EAAGG,EAAM,GAChDC,EAAKC,GAAiBJ,EAAK,KAAK,IAAI,GAAI,KAAK,IAAI,EAAGI,CAAI,CAAC,GAAKJ,EAAKE,GACnEG,EAAKC,GAAiBL,EAAK,KAAK,IAAI,GAAI,KAAK,IAAI,EAAGK,CAAI,CAAC,GAAKL,EAAKC,GACzEjB,EAAM,OACJ1B,EAAG,OAAQ,CAAE,GAAI2C,EAAK,GAAID,EAAI,GAAIH,EAAII,EAAK,GAAID,EAAI,OAAQ,eAAgB,iBAAkB,IAAM,eAAgB,CAAE,CAAC,EACtH1C,EAAG,OAAQ,CAAE,GAAIyC,EAAI,GAAIE,EAAK,GAAIF,EAAI,GAAID,EAAIG,EAAK,OAAQ,eAAgB,iBAAkB,IAAM,eAAgB,CAAE,CAAC,CACxH,EACA,IAAMK,EAASV,EAAM,QAAQ,MAAM,IAAI,EAAE,QAAQ,EACjD,GAAIU,EAAO,QAAU,EAAG,CACtB,IAAMC,EAAOjD,EAAG,WAAY,CAC1B,OAAQgD,EAAO,IAAKpC,GAAU,GAAGgC,EAAEhC,EAAM,IAAI,CAAC,IAAIkC,EAAElC,EAAM,IAAI,CAAC,EAAE,EAAE,KAAK,GAAG,EAC3E,KAAM,OAAQ,OAAQ,UAAW,eAAgB,EAAG,iBAAkB,GACxE,CAAC,EACDc,EAAM,OAAOuB,CAAI,EACjB,QAAWrC,KAASoC,EAAO,MAAM,EAAG,EAAE,EACpCtB,EAAM,OAAO1B,EAAG,SAAU,CAAE,GAAI4C,EAAEhC,EAAM,IAAI,EAAG,GAAIkC,EAAElC,EAAM,IAAI,EAAG,EAAG,EAAG,KAAM,UAAW,eAAgB,EAAI,CAAC,CAAC,CAEnH,CACAc,EAAM,OAAO1B,EAAG,SAAU,CAAE,GAAI4C,EAAEN,EAAM,QAAQ,IAAI,EAAG,GAAIQ,EAAER,EAAM,QAAQ,IAAI,EAAG,EAAG,EAAG,KAAM,SAAU,CAAC,CAAC,CAC5G,EAEMY,EAAOC,GAA8B,CACzC,IAAMC,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,wHACpB,IAAMC,EAAQ,SAAS,cAAc,MAAM,EAC3CA,EAAM,YAAcF,EAAM,MAC1BE,EAAM,MAAM,QAAU,0DACtB,IAAMC,EAAM,SAAS,cAAc,MAAM,EACzCA,EAAI,YAAcH,EAAM,KAAO,GAC/BG,EAAI,MAAM,QAAU,qIACpB,IAAMvC,EAAO,SAAS,cAAc,MAAM,EAC1C,OAAAA,EAAK,YAAcoC,EAAM,SAAWA,EAAM,KAC1CpC,EAAK,MAAM,QAAU,0BACrBqC,EAAI,OAAOC,EAAOC,EAAKvC,CAAI,EACpBqC,CACT,EAEMG,EAAc,MAAOC,EAAU,KAAO,CAC1CpB,EAAK,gBAAgB,EACrBD,EAAO,YAAc,GACrB,GAAI,CACF,IAAMsB,EAAOD,EACT,MAAMjD,EAAI,OAA6B,SAAU,CAACiD,EAAS,EAAE,CAAC,EAC9D,MAAMjD,EAAI,OAA6B,OAAQ,CAAC,CAAE,MAAO,EAAG,CAAC,CAAC,EAClE,GAAIkD,EAAK,QAAQ,SAAW,EAAG,CAC7BtB,EAAO,YAAcqB,EAAUhD,EAAE,UAAYA,EAAE,YAC/C,MACF,CACA,QAAW2C,KAASM,EAAK,QAASrB,EAAK,OAAOc,EAAIC,CAAK,CAAC,CAC1D,OAASO,EAAK,CACZvB,EAAO,YAAc,GAAG3B,EAAE,MAAM,KAAKkD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACvF,CACF,EAEMC,EAAO,SAAY,CACvBvC,EAAM,YAAcZ,EAAE,QACtB,GAAI,CACF,IAAM8B,EAAQ,MAAM/B,EAAI,OAAc,OAAO,EAC7Ca,EAAM,YAAc,GAAGkB,EAAM,IAAI,gBAAQA,EAAM,QAAQ,MAAM,gBAC7Dd,EAAQ,YAAchB,EAAE,QAAQG,EAAM2B,EAAM,OAAO,CAAC,EACpDb,EAAQ,YAAca,EAAM,KAAOA,EAAM,IAAI,QAAU5B,EAAK,2BAAS,gBAAkB4B,EAAM,IAAI,IAAKY,GAAQA,EAAI,KAAK,EAAE,KAAK,QAAK,EAAI,GACnIZ,EAAM,QAAQ,SAAW,IAC3BH,EAAO,YAAc3B,EAAE,gBAAgB8B,EAAM,MAAM,GAErDD,EAAKC,CAAK,EACV,MAAMiB,EAAY,CACpB,OAASG,EAAK,CACZtC,EAAM,YAAc,GAAGZ,EAAE,MAAM,KAAKkD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACtF,CACF,EAEA,OAAApC,EAAQ,iBAAiB,QAAS,IAAG,CAAQqC,EAAK,EAAC,EACnDzB,EAAM,iBAAiB,QAAS,IAAM,CAAEF,EAAO,MAAQ,GAASuB,EAAY,CAAG,CAAC,EAChFtB,EAAa,iBAAiB,QAAS,IAAG,CAAQsB,EAAYvB,EAAO,MAAM,KAAK,CAAC,EAAC,EAClFA,EAAO,iBAAiB,UAAY4B,GAAU,CAAMA,EAAM,MAAQ,SAAcL,EAAYvB,EAAO,MAAM,KAAK,CAAC,CAAG,CAAC,EACnHT,EAAM,iBAAiB,QAAS,IAAM,CAC/B,OAAO,QAAQf,EAAE,YAAY,IAC5B,SAAY,CAChB,GAAI,CACF,IAAMqD,EAAM,MAAMtD,EAAI,OAA4B,QAAS,CAAC,CAAC,EAC7D4B,EAAO,YAAc3B,EAAE,QAAQqD,EAAI,OAAO,EAC1C,MAAMF,EAAK,CACb,OAASD,EAAK,CACZvB,EAAO,YAAc,GAAG3B,EAAE,MAAM,KAAKkD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACvF,CACF,GAAG,CACL,CAAC,EAED7C,EAAK,OAAOM,EAAKK,EAASC,EAASE,EAAUE,EAAcC,EAAaC,EAAWI,EAAQC,CAAI,EAC/F7B,EAAI,KAAK,OAAOM,CAAI,EACf8C,EAAK,EACH,CAAE,SAAU,CAAC,CAAE,CACxB,CACF,EAYMG,EAAc,CAClB,CAAC,UAAW,eAAM,aAAa,EAC/B,CAAC,SAAU,eAAM,WAAW,EAC5B,CAAC,QAAS,eAAM,OAAO,EACvB,CAAC,OAAQ,eAAM,QAAQ,EACvB,CAAC,SAAU,kCAAU,QAAQ,EAC7B,CAAC,UAAW,qBAAO,SAAS,EAC5B,CAAC,KAAM,KAAM,IAAI,EACjB,CAAC,UAAW,eAAM,SAAS,EAC3B,CAAC,WAAY,eAAM,UAAU,CAC/B,EAEMC,EAAyB,CAC7B,MAAMxD,EAAwB,CAC5B,IAAMG,EAAKH,EAAI,WAAa,MAAQA,EAAI,WAAa,UAC/CM,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,2GAErB,IAAMmD,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,YAActD,EAAK,iCAAU,kBACnCsD,EAAM,MAAM,QAAU,iCACtB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,YAAcvD,EACf,wZACA,oQACJuD,EAAK,MAAM,QAAU,4CAErB,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,MAAM,QAAU,6CACvB,IAAMC,EAAW,SAAS,cAAc,OAAO,EAC/CA,EAAS,MAAM,QAAU,oFACzB,IAAMC,EAAU,SAAS,cAAc,OAAO,EAC9CA,EAAQ,KAAO,WACf,IAAMC,EAAc,SAAS,cAAc,MAAM,EACjDA,EAAY,YAAc3D,EAAK,6DAAkB,mCACjDyD,EAAS,OAAOC,EAASC,CAAW,EACpCD,EAAQ,iBAAiB,SAAU,IAAG,CAAQT,EAAK,EAAC,EACpD,IAAMW,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,MAAM,QAAU,6CAEtB,IAAMC,EAAU,iEAEVC,EAAS,IAAmB,CAChC,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,sCAAwCF,EAAU,oHACvE,IAAMG,EAAS,CACbhE,EAAK,SAAM,QACXA,EAAK,eAAO,QACZA,EAAK,eAAO,OACZA,EAAK,eAAO,OACZA,EAAK,eAAO,SACZA,EAAK,8BAAY,eACjBA,EAAK,eAAO,QACd,EACA,QAAS,EAAI,EAAG,EAAIgE,EAAO,OAAQ,GAAK,EAAG,CACzC,IAAMC,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAAcD,EAAO,CAAC,EACvB,GAAK,GAAK,GAAK,IAAGC,EAAK,MAAM,UAAY,SACzC,IAAM,IAAGA,EAAK,MAAM,UAAY,SACpCF,EAAK,OAAOE,CAAI,CAClB,CACA,OAAOF,CACT,EAEMG,EAAa1B,GAA8B,CAC/C,IAAM2B,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,sCAAwCN,EAAU,yGACvE,IAAMO,EAAQ,SAAS,cAAc,MAAM,EAC3CA,EAAM,YAAc5B,EAAI,MACxB4B,EAAM,MAAM,QAAU,+FACtB,IAAM1D,EAAQ,SAAS,cAAc,MAAM,EAC3CA,EAAM,YAAc8B,EAAI,MAAQ,QAChC9B,EAAM,MAAM,QAAU,8CACtB,IAAMyB,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAAcK,EAAI,MAAM,CAAC,EAAE,QAAQ,CAAC,EACzCL,EAAK,MAAM,QAAU,gFACrB,IAAME,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAAcG,EAAI,MAAM,CAAC,EAAE,QAAQ,CAAC,EACzCH,EAAK,MAAM,QAAU,gFACrB,IAAMgC,EAAS,SAAS,cAAc,MAAM,EAK5C,GAJAA,EAAO,YAAc7B,EAAI,OAAO,QAAQ,CAAC,EACzC6B,EAAO,MAAM,QAAU,gFACvBF,EAAK,OAAOC,EAAO1D,EAAOyB,EAAME,EAAMgC,CAAM,EAExC7B,EAAI,OAAS,OAAS,CAACA,EAAI,IAAK,CAClC,IAAM8B,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAActE,EAAK,uCAAa,4BACrCsE,EAAK,MAAM,QAAU,6BACrB,IAAMC,EAAO,SAAS,cAAc,MAAM,EAC1C,OAAAA,EAAK,YAAc,SACnBA,EAAK,MAAM,QAAU,8BACrBJ,EAAK,OAAOG,EAAMC,CAAI,EACfJ,CACT,CAEA,IAAMV,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,MAAM,QAAU,sDACzB,IAAMe,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,MAAM,QAAU,8JACvB,IAAMC,EAAO,SAAS,cAAc,QAAQ,EAC5CA,EAAK,MAAQ,GACbA,EAAK,YAAczE,EAAK,2BAAS,UACjCwE,EAAO,OAAOC,CAAI,EAClB,OAAW,CAAC9E,EAAO+E,EAASC,CAAO,IAAKvB,EAAa,CACnD,IAAMwB,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,MAAQjF,EACfiF,EAAO,YAAc5E,EAAK0E,EAAUC,EACpCH,EAAO,OAAOI,CAAM,CACtB,CACA,IAAMC,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,KAAO,SACbA,EAAM,IAAM,IACZA,EAAM,IAAM,MACZA,EAAM,YAAc7E,EAAK,eAAO,MAChC6E,EAAM,MAAQ7E,EAAK,2EAAiB,qCACpC6E,EAAM,MAAM,QAAU,sJACtBpB,EAAS,OAAOe,EAAQK,CAAK,EAE7B,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,MAAM,QAAU,wCACvB,IAAMC,EAAO,SAAS,cAAc,QAAQ,EAC5C,OAAAA,EAAK,YAAc/E,EAAK,eAAO,OAC/B+E,EAAK,MAAM,QAAU,2JACrBA,EAAK,iBAAiB,QAAS,IAAM,EAC7B,SAAY,CAChB,GAAI,CACF,IAAMC,EAAUH,EAAM,MAAM,KAAK,EAAI,OAAOA,EAAM,KAAK,EAAI,EAC3D,MAAMhF,EAAI,OAAO,SAAU,CAAC2C,EAAI,IAAKgC,EAAO,OAAS,KAAMQ,CAAO,CAAC,EACnExB,EAAO,YAAcxD,EAAK,sBAASwC,EAAI,IAAM,SAAWA,EAAI,GAC9D,OAASQ,EAAK,CACZQ,EAAO,aAAexD,EAAK,2BAAS,eAAiB,MAAQgD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,EAC9G,CACF,GAAG,CACL,CAAC,EACD8B,EAAO,OAAOC,CAAI,EAClBZ,EAAK,OAAOV,EAAUqB,CAAM,EACrBX,CACT,EACMlB,EAAO,SAAY,CACvBW,EAAM,gBAAgB,EACtBJ,EAAO,YAAcxD,EAAK,2BAAS,gBACnC,GAAI,CAEF,IAAMiF,GADO,MAAMpF,EAAI,OAA6B,OAAO,GACzC,MACZqF,EAAUxB,EAAQ,QAAUuB,EAAOA,EAAK,OAAQzC,GAAQA,EAAI,OAAS,OAASA,EAAI,OAAS,EAAG,EACpGgB,EAAO,YAAc0B,EAAQ,OACzB,GAAGA,EAAQ,MAAM,MAAMD,EAAK,MAAM,IAAIjF,EAAK,eAAO,QAAQ,GACzDA,EAAK,yJAA8B,iFACxC4D,EAAM,OAAOE,EAAO,CAAC,EACrB,QAAWtB,KAAO0C,EAAStB,EAAM,OAAOM,EAAU1B,CAAG,CAAC,CACxD,OAASQ,EAAK,CACZQ,EAAO,YAAc,GAAGxD,EAAK,2BAAS,QAAQ,KAAKgD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACrG,CACF,EAEA,OAAA7C,EAAK,OAAOmD,EAAOC,EAAME,EAAUD,EAAQI,CAAK,EAChD/D,EAAI,KAAK,OAAOM,CAAI,EACf8C,EAAK,EACH,CAAE,SAAU,CAAC,CAAE,CACxB,CACF,EAQMkC,EAA6B,CACjC,MAAMtF,EAAwB,CAC5B,IAAMG,EAAKH,EAAI,WAAa,MAAQA,EAAI,WAAa,UAC/CM,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,2GACrB,IAAMmD,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,YAActD,EAAK,iCAAU,oBACnCsD,EAAM,MAAM,QAAU,iCACtB,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,YAAcvD,EAAK,+MAAuC,2FAC/DuD,EAAK,MAAM,QAAU,4CACrB,IAAM6B,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU,6DACrB,IAAM5B,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,MAAM,QAAU,6CACvB,IAAMC,EAAW,SAAS,cAAc,OAAO,EAC/CA,EAAS,MAAM,QAAU,oFACzB,IAAMC,EAAU,SAAS,cAAc,OAAO,EAC9CA,EAAQ,KAAO,WACf,IAAMC,EAAc,SAAS,cAAc,MAAM,EACjDA,EAAY,YAAc3D,EAAK,6DAAkB,mCACjDyD,EAAS,OAAOC,EAASC,CAAW,EACpCD,EAAQ,iBAAiB,SAAU,IAAG,CAAQT,EAAK,EAAC,EAEpD,IAAMoC,EAAWC,GAAiC,CAChD,IAAM5C,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,mHACpB,IAAMZ,EAAI,SAAS,cAAc,KAAK,EACtC,OAAAA,EAAE,YAAcwD,EAChBxD,EAAE,MAAM,QAAU,4CAClBY,EAAI,OAAOZ,CAAC,EACLY,CACT,EACMyB,EAAO,CAAC9D,EAAcV,IAA+B,CACzD,IAAM6C,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,uCACpB,IAAM+C,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAAclF,EACnBkF,EAAK,MAAM,QAAU,6BACrB,IAAMC,EAAQ,SAAS,cAAc,MAAM,EAC3C,OAAAA,EAAM,YAAc7F,EACpB6F,EAAM,MAAM,QAAU,0DACtBhD,EAAI,OAAO+C,EAAMC,CAAK,EACfhD,CACT,EAEMS,EAAO,SAAY,CACvBmC,EAAK,gBAAgB,EACrB5B,EAAO,YAAcxD,EAAK,2BAAS,gBACnC,GAAI,CACF,IAAM+C,EAAO,MAAMlD,EAAI,OAAoB,aAAa,EACxD2D,EAAO,YAAc,GACrB,IAAMiC,EAAOJ,EAAQrF,EAAK,oBAAY,cAAc,EACpDyF,EAAK,OACHtB,EAAKnE,EAAK,eAAO,QAAS+C,EAAK,KAAK,KAAK,EACzCoB,EAAKnE,EAAK,2BAAS,cAAe+C,EAAK,KAAK,aAAe,IAAI,KAAKA,EAAK,KAAK,YAAY,EAAE,eAAe,EAAI,QAAG,EAClHoB,EAAKnE,EAAK,8BAAY,cAAe,GAAG,KAAK,MAAM+C,EAAK,KAAK,MAAQ,GAAI,CAAC,OAAO,KAAK,MAAMA,EAAK,KAAK,QAAU,GAAI,CAAC,GAAG,EACxHoB,EAAKnE,EAAK,2BAAS,gBAAiB+C,EAAK,KAAK,QAAQ,CACxD,EACA,IAAM2C,EAAQL,EAAQrF,EAAK,eAAO,OAAO,EACzC,QAAW2F,KAAQ5C,EAAK,MAAO,CAC7B,IAAMP,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,0DACpB,IAAMoD,EAAQ,SAAS,cAAc,MAAM,EAC3CA,EAAM,YAAcD,EAAK,QAAW3F,EAAK,SAAM,KAASA,EAAK,SAAM,MACnE4F,EAAM,MAAM,QAAU,wDAAwDD,EAAK,QAAU,sBAAwB,uBAAuB,YAAYA,EAAK,QAAU,EAAI,GAAI,kBAC/K,IAAMpG,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,YAAc,GAAGoG,EAAK,EAAE,SAAMA,EAAK,MAAM,GAC9CpG,EAAK,MAAM,QAAU,qCACrB,IAAMsG,EAAU,SAAS,cAAc,MAAM,EAC7CA,EAAQ,YAAcF,EAAK,QAC3BE,EAAQ,MAAM,QAAU,+BACxBrD,EAAI,OAAOoD,EAAOrG,EAAMsG,CAAO,EAC/BH,EAAM,OAAOlD,CAAG,CAClB,CACA,IAAMsD,EAAST,EAAQrF,EAAK,iCAAU,mBAAmB,EACzD8F,EAAO,OACL3B,EAAK,SAAUpB,EAAK,OAAO,MAAM,EACjCoB,EAAK,YAAa,OAAOpB,EAAK,OAAO,SAAS,CAAC,EAC/CoB,EAAKnE,EAAK,2BAAS,cAAe,OAAO+C,EAAK,OAAO,WAAW,CAAC,EACjEoB,EAAKnE,EAAK,2BAAS,WAAY,OAAO+C,EAAK,OAAO,QAAQ,CAAC,EAC3DoB,EAAKnE,EAAK,6CAAiB,2BAA4B,GAAG+C,EAAK,OAAO,IAAI,MAAMA,EAAK,OAAO,OAAO,MAAMA,EAAK,OAAO,OAAO,EAAE,EAC9HoB,EAAKnE,EAAK,eAAO,SAAU,OAAO+C,EAAK,OAAO,MAAM,CAAC,CACvD,EACAqC,EAAK,OAAOK,EAAMC,EAAOI,CAAM,CACjC,OAAS9C,EAAK,CACZQ,EAAO,YAAc,GAAGxD,EAAK,2BAAS,QAAQ,KAAKgD,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACrG,CACF,EAEMvC,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,MAAM,QAAU,0CACpB,IAAMG,EAAU,SAAS,cAAc,QAAQ,EAC/C,OAAAA,EAAQ,YAAcZ,EAAK,eAAO,UAClCY,EAAQ,MAAM,QAAU,4JACxBA,EAAQ,iBAAiB,QAAS,IAAG,CAAQqC,EAAK,EAAC,EACnDxC,EAAI,OAAOG,CAAO,EAElBT,EAAK,OAAOmD,EAAOC,EAAM9C,EAAK+C,EAAQ4B,CAAI,EAC1CvF,EAAI,KAAK,OAAOM,CAAI,EACf8C,EAAK,EACH,CAAE,SAAU,CAAC,CAAE,CACxB,CACF,EAEM8C,EAA4B,CAAE,OAAQ,CAAE,SAAUnG,EAAe,MAAOyD,EAAY,UAAW8B,CAAe,CAAE,EAC/Ga,EAAQD",
|
|
6
|
+
"names": ["diaryPanelText", "language", "n", "source", "label", "SVG", "el", "name", "attrs", "node", "key", "value", "timelinePanel", "ctx", "t", "diaryPanelText", "zh", "label", "point", "root", "button", "text", "danger", "input", "placeholder", "bar", "count", "spacer", "refresh", "clear", "current", "topLine", "chart", "chartBox", "privacy", "detailsTitle", "detailsNote", "detailBar", "search", "searchButton", "reset", "notice", "list", "draw", "state", "w", "h", "cx", "cy", "pad", "x", "work", "y", "tech", "points", "path", "row", "entry", "box", "clock", "app", "loadDetails", "keyword", "data", "err", "load", "event", "out", "APP_OPTIONS", "wordsPanel", "title", "note", "status", "controls", "showAll", "showAllText", "table", "COLUMNS", "header", "head", "labels", "cell", "renderRow", "line", "token", "weight", "kind", "dash", "select", "auto", "labelZh", "labelEn", "option", "decay", "action", "save", "minutes", "rows", "visible", "developerPanel", "body", "section", "heading", "left", "right", "flow", "rules", "rule", "badge", "trigger", "config", "bundle", "client_default"]
|
|
7
7
|
}
|