Skip to content

Commit ea845c2

Browse files
committed
feat: add public host file watch API
1 parent 9cd87f9 commit ea845c2

22 files changed

Lines changed: 207 additions & 16 deletions

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "haloforge-plugin-api"
3-
version = "0.2.17"
3+
version = "0.2.18"
44
edition = "2021"
55
description = "Plugin API for HaloForge — traits and types for building native HaloForge plugins"
66
license = "MIT"
@@ -10,6 +10,7 @@ documentation = "https://docs.rs/haloforge-plugin-api"
1010
keywords = ["haloforge", "plugin", "gamedev", "tauri"]
1111
categories = ["development-tools", "game-development"]
1212
readme = "README.md"
13+
include = ["/src/**", "/Cargo.toml", "/README.md", "/LICENSE"]
1314

1415
[workspace]
1516

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,14 @@ Permission names are strict. For AI Chat access, the only valid manifest permiss
7171
"homepage": "https://github.com/you/hello-plugin",
7272
"compatibility": {
7373
"min_app_version": "0.8.0",
74-
"min_host_api_version": "0.2.17"
74+
"min_host_api_version": "0.2.18"
7575
},
7676
"capability_levels": [2],
7777
"host_capabilities": [
7878
"navigation",
7979
"file_intents",
8080
"file_dialogs",
81+
"file_watch",
8182
"aichat",
8283
"theme_read"
8384
],

docs/plugin-development-guide.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Every plugin needs a `manifest.json` at the repository root.
6161
"author": "Example",
6262
"compatibility": {
6363
"min_app_version": "0.8.0",
64-
"min_host_api_version": "0.2.17"
64+
"min_host_api_version": "0.2.18"
6565
},
6666
"capability_levels": [0],
6767
"host_capabilities": ["navigation", "file_intents", "theme_read"],
@@ -115,6 +115,7 @@ Rules:
115115
- `id` is stable forever. Do not rename it after publishing.
116116
- `version` follows semver. Official plugins should start at `0.1.0`.
117117
- `host_capabilities` must match SDK helpers used by the frontend.
118+
- File watching must use `watchHostFile` or `useHostFileWatch` with `file_watch` and `host_file_watch`; do not hard-code host commands or events.
118119
- `permissions` must be the smallest set needed.
119120
- `entry.frontend` and `integration.*.panel_entry` should point to the built bundle.
120121
- Native command IDs in `commands` must match the names registered by the Rust backend before SDK prefixing.

docs/public-host-api.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ Plugins can now declare:
2424
{
2525
"compatibility": {
2626
"min_app_version": "0.8.0",
27-
"min_host_api_version": "0.2.17"
27+
"min_host_api_version": "0.2.18"
2828
},
2929
"host_capabilities": [
3030
"navigation",
3131
"app_state",
3232
"file_intents",
3333
"file_dialogs",
34+
"file_watch",
3435
"aichat",
3536
"enterprise_gateway",
3637
"deep_links",
@@ -61,6 +62,7 @@ Plugins can now declare:
6162
- `app_state`
6263
- `file_intents`
6364
- `file_dialogs`
65+
- `file_watch`
6466
- `aichat`
6567
- `enterprise_gateway`
6668
- `deep_links`
@@ -97,6 +99,7 @@ The permission model also includes explicit host-facing permissions:
9799
- `host_app_state_read`
98100
- `host_file_intents`
99101
- `host_file_dialogs`
102+
- `host_file_watch`
100103
- `host_aichat_access`
101104
- `host_enterprise_gateway_access`
102105
- `host_deep_links`
@@ -115,6 +118,7 @@ import {
115118
definePlugin,
116119
useHostNavigation,
117120
useHostFileIntent,
121+
useHostFileWatch,
118122
useHostAI,
119123
usePluginDeepLink,
120124
usePluginNavigation,

docs/zh/plugin-development-guide.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ my-plugin/
6161
"author": "Example",
6262
"compatibility": {
6363
"min_app_version": "0.8.0",
64-
"min_host_api_version": "0.2.17"
64+
"min_host_api_version": "0.2.18"
6565
},
6666
"capability_levels": [0],
6767
"host_capabilities": ["navigation", "file_intents", "theme_read"],
@@ -115,6 +115,7 @@ my-plugin/
115115
- `id` 发布后必须保持稳定,不要改名。
116116
- `version` 使用 semver,官方插件初版从 `0.1.0` 开始。
117117
- `host_capabilities` 必须匹配前端实际使用的 SDK helper。
118+
- 文件监听必须使用 `watchHostFile``useHostFileWatch`,并声明 `file_watch``host_file_watch`;不要硬编码宿主命令或事件。
118119
- `permissions` 必须保持最小权限。
119120
- `entry.frontend``integration.*.panel_entry` 应指向构建后的 bundle。
120121
- `commands` 里的原生命令 ID 要和 Rust 后端注册的名字一致,不能包含 SDK 自动添加的前缀。

pack/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.

pack/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@haloforge/plugin-pack",
3-
"version": "0.2.17",
3+
"version": "0.2.18",
44
"description": "HaloForge plugin packager CLI — validate, build, and bundle plugins into .hfpkg archives",
55
"type": "module",
66
"bin": {

pack/src/core.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ const PERMISSION_SCHEMAS = new Map<string, { value: "none" | "string" | "string-
522522
["host_app_state_read", { value: "none" }],
523523
["host_file_intents", { value: "none" }],
524524
["host_file_dialogs", { value: "none" }],
525+
["host_file_watch", { value: "none" }],
525526
[HOST_AICHAT_ACCESS_PERMISSION, { value: "none" }],
526527
["host_enterprise_gateway_access", { value: "none" }],
527528
["host_deep_links", { value: "none" }],
@@ -1454,6 +1455,7 @@ const HOST_CAPABILITIES = new Set([
14541455
"app_state",
14551456
"file_intents",
14561457
"file_dialogs",
1458+
"file_watch",
14571459
"aichat",
14581460
"enterprise_gateway",
14591461
"deep_links",
@@ -1491,6 +1493,8 @@ const DIRECT_HOST_IPC_COMMANDS = [
14911493
"devkit_pick_file",
14921494
"devkit_pick_directory",
14931495
"devkit_save_file",
1496+
"plugin_watch_file",
1497+
"plugin_unwatch_file",
14941498
];
14951499

14961500
const IGNORED_PLUGIN_SOURCE_DIRS = new Set([

pack/tests/permissions.test.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ test("hf-pack check accepts plugin deep link host capability and permission", as
7777
);
7878
});
7979

80+
test("hf-pack check accepts host file watch capability and permission", async () => {
81+
await withPluginDir(
82+
{
83+
...BASE_MANIFEST,
84+
host_capabilities: ["file_watch"],
85+
permissions: [{ type: "host_file_watch" }],
86+
},
87+
async (pluginDir) => {
88+
await assert.doesNotReject(() => checkPlugin(pluginDir));
89+
},
90+
);
91+
});
92+
8093
test("hf-pack check accepts plugin window document handlers", async () => {
8194
await withPluginDir(
8295
{

sdk/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default registerPlugin("com.example.hello-plugin", definePlugin({
4545
- `pluginWindows`, `usePluginWindows`: ask HaloForge to open plugin routes/resources through the host multi-window dispatcher.
4646
- `pluginCurrentWindow`, `usePluginCurrentWindow`, `usePluginWindowTitle`: update or reset the native title for the active HaloForge window.
4747
- `pickHostFile`, `pickHostDirectory`, `saveHostFile`: stable host file dialog helpers.
48+
- `watchHostFile`, `useHostFileWatch`: host-managed cross-platform file change notifications.
4849
- `usePluginSettings`, `useHostData`, `useSlotContext`: read plugin and host state inside your React components.
4950
- `useAppTheme`: read HaloForge theme mode and CSS variables inside your plugin.
5051
- `enterpriseGateway`: call the host-managed image gateway without exposing cloud tokens. The function name is retained for compatibility; user-facing UI should say "HaloForge Cloud gateway" or "Managed gateway".
@@ -62,6 +63,7 @@ Prefer these host helpers over reading `window.__HF_HOST` directly:
6263
- `pluginWindows()` / `usePluginWindows()` for host-managed route/resource window opening
6364
- `pluginCurrentWindow()` / `usePluginWindowTitle()` for the current native window title
6465
- `pickHostFile()` / `pickHostDirectory()` / `saveHostFile()` for host-owned file dialogs
66+
- `watchHostFile()` / `useHostFileWatch()` for host-managed file change notifications
6567
- `useHostModels()` / `useAvailableModels()` for model lists and current selection
6668
- `useHostAI()` for AI transport, session creation, stream-state polling, and generation stop
6769
- `enterpriseGateway()` for host-managed image generation and image edits
@@ -71,6 +73,36 @@ Prefer these host helpers over reading `window.__HF_HOST` directly:
7173

7274
These helpers currently adapt to HaloForge's existing host bridge internally, but they give plugin authors one documented surface that can keep working as HaloForge evolves.
7375

76+
## File Watching
77+
78+
Declare the public capability and permission:
79+
80+
```json
81+
{
82+
"host_capabilities": ["file_watch"],
83+
"permissions": [
84+
{ "type": "host_file_watch" }
85+
]
86+
}
87+
```
88+
89+
React plugins can follow a file without polling or using host internals:
90+
91+
```tsx
92+
import { useCallback } from "react";
93+
import { useHostFileWatch } from "@haloforge/plugin-sdk";
94+
95+
export function DocumentPanel({ path }: { path: string }) {
96+
useHostFileWatch(path, useCallback((event) => {
97+
console.log(event.path, event.kind);
98+
}, []));
99+
100+
return null;
101+
}
102+
```
103+
104+
Outside React, call `watchHostFile(path, handler)` and await the returned stop function.
105+
74106
## Plugin Deep Links
75107

76108
Plugins can opt in to launch URLs such as:

0 commit comments

Comments
 (0)