Skip to content

Commit 58207f5

Browse files
committed
feat: enhance policy firewall to block unsafe resource targets and add tests
feat: update usage data broker for improved session queries feat: add app handle setter in widget kernel chore: bump version to 2.2.0 in tauri configuration feat: implement dynamic background images for app and widgets feat: add skin settings for app and widget backgrounds in settings feat: add retry option for loading third-party widgets feat: implement widget refresh mechanism in widget window feat: enhance widget client to handle media loading and local API calls feat: add focus summary widget template for TimeLens Widget Runtime
1 parent 58e23af commit 58207f5

35 files changed

Lines changed: 965 additions & 142 deletions

.github/workflows/release.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ jobs:
3333

3434
env:
3535
CARGO_INCREMENTAL: "0"
36-
RUSTC_WRAPPER: "sccache"
37-
SCCACHE_GHA_ENABLED: "true"
38-
SCCACHE_GHA_VERSION: "${{ matrix.platform }}-release"
3936

4037
steps:
4138
- uses: actions/checkout@v4
@@ -133,9 +130,6 @@ jobs:
133130
- name: Setup Rust toolchain
134131
uses: dtolnay/rust-toolchain@stable
135132

136-
- name: Run sccache-cache
137-
uses: mozilla-actions/sccache-action@v0.0.7
138-
139133
- name: Cache Rust
140134
uses: Swatinem/rust-cache@v2
141135
with:
@@ -248,9 +242,6 @@ jobs:
248242

249243
env:
250244
CARGO_INCREMENTAL: "0"
251-
RUSTC_WRAPPER: "sccache"
252-
SCCACHE_GHA_ENABLED: "true"
253-
SCCACHE_GHA_VERSION: "windows-latest-release"
254245

255246
steps:
256247
- uses: actions/checkout@v4
@@ -308,9 +299,6 @@ jobs:
308299
- name: Setup Rust toolchain
309300
uses: dtolnay/rust-toolchain@stable
310301

311-
- name: Run sccache-cache
312-
uses: mozilla-actions/sccache-action@v0.0.7
313-
314302
- name: Cache Rust
315303
uses: Swatinem/rust-cache@v2
316304
with:

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,34 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
55

66
---
77

8+
## [2.2.0] - 2026-08-28
9+
10+
### Added
11+
12+
- **Widget Runtime Gateway** — widgets can now use governed local API calls, public HTTP(S) fetches, safe media loading, and native notifications with scoped permissions, policy checks, timeouts, and response-size limits.
13+
- **Widget Center controls** — per-widget pause/resume and refresh-now actions now work across Tauri windows.
14+
- **Risk-aware widget consent** — runtime consent prompts classify session, browser, network, media, API, and notification access by risk level.
15+
- **User skins** — Appearance settings can now select and clear separate local background images for the TimeLens interface and widget windows, with live cross-window synchronization.
16+
- **Developer resources** — added a read-only Focus Summary TypeScript widget template using the v4 `WidgetClient` contract.
17+
- **Cross-platform widget notifications** — widget notification requests now use the Tauri notification provider on Windows, macOS, and Linux.
18+
19+
### Changed
20+
21+
- **Pet widget** — promoted from a disabled placeholder to an importable `pet.json` resource-pack widget with state-aware display, avatar assets, interactions, and configurable size.
22+
- **Widget SDK**`WidgetClient.fetch()` now returns a real proxied `Response`; `loadMedia()` returns a safe data URL reference.
23+
- **Widget developer experience** — third-party widget failures now expose recovery guidance and a real remount/retry action; the Widget Dev Harness provides capability simulation, manifest/hash diagnostics, auto-reload, logs, and live preview.
24+
25+
### Fixed
26+
27+
- **Widget refresh** — Widget Center refresh no longer only reloads permission metadata; it now remounts the selected widget window.
28+
- **Runtime documentation drift** — marked completed pet and pause/refresh work consistently across release documentation.
29+
30+
### Notes
31+
32+
- Native notification delivery remains subject to the operating system's notification permission and desktop environment.
33+
34+
---
35+
836
## [2.1.0] - 2026-08-27
937

1038
### Added

docs/WIDGET_RUNTIME_REWRITE_IMPLEMENTATION_PLAN.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -710,21 +710,20 @@ After this plan is reviewed, the next artifact should be a narrow RFC that freez
710710

711711
### 当前限制
712712

713-
- Gateway 中的 `network_fetch``media_load``local_api_call``notification_send` 已占位,尚未实现完整代理逻辑,计划在 Phase D 补齐
713+
- Gateway 已实现 `network_fetch``media_load``local_api_call``notification_send` 的受限代理逻辑:公网 HTTP(S)、5 秒超时、2 MiB 响应上限、媒体 MIME 白名单、本地 API scope 校验和 Windows 原生通知
714714
- 旧 widget 的 `widget_permissions` 被 Gateway 视为已授权,保证迁移期兼容。
715-
- `WidgetClient.fetch` `loadMedia` 为占位实现,会抛出未实现错误
716-
- 同意提示目前统一按 `low` 风险等级记录;后续应结合 capability 风险分级自动映射 `low/medium/high`
715+
- `WidgetClient.fetch` 返回代理后的标准 `Response``loadMedia` 返回受限的 `data:` URL 引用
716+
- `notification_send` 已通过 Tauri notification provider 支持 Windows、macOS 和 Linux,实际显示仍受操作系统通知权限和桌面环境影响
717717
- TimerWidget、QuickCaptureWidget、BrowserActivityWidget 仍使用直接 `tauriApi` 调用,待 Gateway 暴露对应能力后再迁移;但其渲染与交互已纳入官方组件测试覆盖。
718718

719719
### 建议下一步
720720

721-
进入 **Phase D — Media 与 Sensitive Access Hardening**
721+
后续可选的 Runtime 强化工作
722722

723-
1. 实现 Gateway `network_fetch` 代理与域名策略防火墙。
724-
2. 实现 Gateway `media_load` 代理与本地/远程媒体白名单。
725-
3. 实现高风险数据访问的二次确认提示。
726-
4. 处理 widget 被撤销权限(revoked)后的降级 UI 与事件通知。
727-
5. 评估是否将 `buildLegacyChannel` 标记为 deprecated,并更新 `WIDGET_SDK_v2_MIGRATION.md`
723+
1. 为非 Windows 平台补充统一的原生通知 provider。
724+
2. 为高风险详细数据访问增加更细粒度的二次确认和降级 UI。
725+
3. 处理撤权后的长连接主动终止与显式 revoked 事件。
726+
4. 评估是否将 `buildLegacyChannel` 标记为 deprecated,并更新 `WIDGET_SDK_v2_MIGRATION.md`
728727

729728
---
730729

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Focus Summary Widget Template
2+
3+
A minimal TypeScript widget template for the TimeLens Widget Runtime v4.
4+
5+
It reads the `metrics` namespace through `WidgetClient`, displays today's tracked minutes, and refreshes every 30 seconds.
6+
7+
1. Copy this directory.
8+
2. Compile `index.ts` to `dist/index.js`.
9+
3. Import the directory from Widget Center.
10+
4. Use Widget Dev Harness to test permissions and reload behavior.
11+
12+
The template is intentionally read-only and requests only `screen-time:read`.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
interface WidgetClient {
2+
query<T>(namespace: string, payload?: Record<string, unknown>): Promise<T>;
3+
}
4+
5+
interface WidgetContext {
6+
client: WidgetClient;
7+
}
8+
9+
interface MetricsRow {
10+
app_name: string;
11+
total_seconds: number;
12+
}
13+
14+
export function createWidget() {
15+
let timer: number | undefined;
16+
17+
return {
18+
async mount(container: HTMLElement, context: WidgetContext) {
19+
const title = document.createElement("strong");
20+
const value = document.createElement("div");
21+
title.textContent = "Focus Summary";
22+
container.replaceChildren(title, value);
23+
24+
const refresh = async () => {
25+
const rows = await context.client.query<MetricsRow[]>("metrics");
26+
const total = rows.reduce((sum, row) => sum + row.total_seconds, 0);
27+
value.textContent = `${Math.round(total / 60)} minutes tracked today`;
28+
};
29+
30+
await refresh();
31+
timer = window.setInterval(() => void refresh(), 30000);
32+
},
33+
34+
unmount() {
35+
if (timer !== undefined) window.clearInterval(timer);
36+
},
37+
};
38+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"manifest_version": "v4",
3+
"widget_type": "focus_summary",
4+
"name": "Focus Summary",
5+
"publisher": "TimeLens Example",
6+
"entry": "dist/index.js",
7+
"runtime": {
8+
"language": "typescript",
9+
"version": "5.0",
10+
"entry": "dist/index.js"
11+
},
12+
"ui": { "model": "web-sandbox" },
13+
"capabilities": ["screen-time:read"]
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "timelens-focus-summary-widget",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"build": "tsc --target ES2022 --module ES2022 --moduleResolution Bundler --outDir dist index.ts"
7+
},
8+
"devDependencies": {
9+
"typescript": "^5.0.0"
10+
}
11+
}

examples/third-party-widget-template/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ This template is a complete TypeScript showcase for the rewritten TimeLens widge
3636

3737
In v4, capability strings are runtime scopes. The top-level `entry` must match
3838
`runtime.entry`. This example declares all implemented scopes because it
39-
demonstrates every available API. Network and media calls only demonstrate their
40-
current unimplemented response.
39+
demonstrates every available API. Network and media calls are mediated by the
40+
Gateway and are subject to public-target, MIME, timeout, and response-size policy.
4141

4242
## Build
4343

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "timelens",
33
"private": true,
4-
"version": "2.1.0",
4+
"version": "2.2.0",
55
"license": "MIT",
66
"authors": [
77
"Shan Wenxiao"

0 commit comments

Comments
 (0)