toc-ocra 0.2.0 → 0.2.2
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/README.md +19 -6
- package/dist/plugin/renderer.css +1 -1
- package/dist/plugin/renderer.css.map +2 -2
- package/dist/plugin/renderer.js +1 -1
- package/dist/plugin/renderer.js.map +4 -4
- package/dist/service/agent.mjs +17842 -0
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.js +27 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/control/pairing.d.ts +6 -1
- package/dist/src/control/pairing.js +12 -2
- package/dist/src/control/pairing.js.map +1 -1
- package/dist/src/index.js +28 -39
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin-service.d.ts +1 -0
- package/dist/src/plugin-service.js +70 -0
- package/dist/src/plugin-service.js.map +1 -0
- package/dist/src/runtime/agent-service.d.ts +17 -1
- package/dist/src/runtime/agent-service.js +14 -2
- package/dist/src/runtime/agent-service.js.map +1 -1
- package/dist/src/runtime/run-service.d.ts +10 -0
- package/dist/src/runtime/run-service.js +51 -0
- package/dist/src/runtime/run-service.js.map +1 -0
- package/locales/en.json +83 -7
- package/locales/zh-CN.json +83 -7
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -17,21 +17,34 @@ node dist/src/index.js enroll --code ABCD-EFGH
|
|
|
17
17
|
node dist/src/index.js run
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
全局安装后命令是 `toc-ocra`:`toc-ocra enroll --code …`、`toc-ocra run`、`toc-ocra service:install`(安装为后台服务)。
|
|
20
|
+
全局安装后命令是 `toc-ocra`:`toc-ocra setup --code … --server …`(配对 + 安装后台服务,一步完成)、`toc-ocra enroll --code …`、`toc-ocra run`、`toc-ocra service:install`(安装为后台服务)。
|
|
21
21
|
|
|
22
22
|
其它命令:`toc-ocra code`(查看插件连接码)、`toc-ocra detect`(本机 CLI 探测)、`toc-ocra doctor`(配置 + 探测)、`toc-ocra version`。
|
|
23
23
|
|
|
24
24
|
## 桌面插件「设备代理」
|
|
25
25
|
|
|
26
|
-
同一个 npm 包也是 Echo 桌面插件 `echo.device-agent`(`package.json › tocPlugin`,界面源码在 `plugin/`,构建产物 `dist/plugin/renderer.js
|
|
26
|
+
同一个 npm 包也是 Echo 桌面插件 `echo.device-agent`(`package.json › tocPlugin`,界面源码在 `plugin/`,构建产物 `dist/plugin/renderer.js`)。页面分两个页签:
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
**本机**(一键启用 / 关闭)
|
|
29
|
+
|
|
30
|
+
1. 打开「本机设备代理」开关:桌面端用自带的 Node 运行插件包里的 `dist/service/agent.mjs`(`tocPlugin.entries.service`,权限 `service:local`),不需要终端,也不需要另装 Node。
|
|
31
|
+
2. 桌面端给这次启动生成令牌(`TOC_PLUGIN_SERVICE_TOKEN`)并交给插件,插件直接用它访问本机控制接口,不再输入 6 位连接码,随后自动绑定到当前登录的服务器。
|
|
32
|
+
3. 设备代理跟随桌面端:开关保持打开时,下次打开桌面端自动启动;退出桌面端、关闭开关、禁用或卸载插件时停止。
|
|
33
|
+
4. 这台电脑已有 toc-ocra 在运行(后台服务或终端启动)时,桌面端启动的实例因端口被占用而退出(退出码 3),插件改为连接已有实例(首次输入连接码),保证一台设备只有一个 Agent。
|
|
34
|
+
5. 旧版桌面端没有这个能力时,插件仍显示终端命令:`npx toc-ocra@latest run`,或 `npm i -g toc-ocra && toc-ocra service:install`。
|
|
35
|
+
|
|
36
|
+
**其他电脑**(一条命令接入)
|
|
37
|
+
|
|
38
|
+
1. 选择系统(Linux / macOS / Windows)和设备名,插件在当前工作空间创建设备、生成配对码,并给出一条命令,例如 `npm install -g toc-ocra@latest && toc-ocra setup --code ABCD-EFGH --server https://echo.example.com`(Windows PowerShell:`npm install -g toc-ocra@latest; if ($?) { toc-ocra setup ... }`)。
|
|
39
|
+
2. `toc-ocra setup` = 配对 + 安装后台服务(macOS LaunchAgent / Linux systemd 用户服务 / Windows 计划任务),执行完设备即上线;插件轮询到新凭据且在线后显示「已匹配」。
|
|
40
|
+
3. 「接收任务」开关调用 `PUT /api/devices/:id/enabled`:关闭即停用,保留配对、不再派发任务,重新打开立即恢复,不需要操作那台电脑。彻底卸载在那台电脑执行 `toc-ocra service:uninstall`。
|
|
41
|
+
4. 服务器地址必须能被那台电脑访问,填 `127.0.0.1` / `localhost` 时插件会提示。
|
|
42
|
+
|
|
43
|
+
插件通过 `http://127.0.0.1:17339` 连接本机服务;手动启动的服务仍用 6 位连接码(`toc-ocra code` 查看)换取控制令牌。
|
|
31
44
|
|
|
32
45
|
本机控制接口(`/control/*`)只接受 `127.0.0.1` / `localhost` 的 Host 和来源,除 `info`、`pair` 外都要 `Authorization: Bearer <控制令牌>`。控制令牌保存在数据目录的 `control-token`(0600),连接码在 `connection-code`(0600,使用后或连续输错 5 次后更换)。
|
|
33
46
|
|
|
34
|
-
|
|
47
|
+
发布:`./publish-latest.sh`(或 `npm run publish:latest`)。脚本会构建、校验插件包,本地版本不高于 npm 上的版本时自动升一个补丁号,再发布到 npm;npm 令牌在终端里输入,或通过环境变量 `NPM_TOKEN` 传入。管理员在「系统管理 › 插件目录」收录包名 `toc-ocra` 并批准版本后,用户即可在插件市场安装。
|
|
35
48
|
|
|
36
49
|
## 配置
|
|
37
50
|
|
package/dist/plugin/renderer.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.da-app{--da-border: var(--border, rgba(127, 127, 127, .25));--da-muted: var(--muted, #888);--da-danger: var(--danger, #dc2626);display:grid;gap:12px;padding:20px 24px 40px;max-width:880px;color:var(--text)}.da-app>*{min-width:0}.da-text{margin:6px 0 10px;font-size:13px;line-height:1.6}.da-muted{margin:6px 0 0;font-size:12px;line-height:1.6;color:var(--da-muted)}.da-step{margin:10px 0 6px;font-size:12px;font-weight:600}.da-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all}.da-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:10px}.da-command{display:flex;gap:8px;align-items:center}.da-command code{flex:1;min-width:0;overflow-x:auto;white-space:nowrap;padding:7px 10px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.da-code-input{width:160px;letter-spacing:.3em;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.da-alert{padding:8px 12px;border:1px solid var(--da-danger);border-radius:var(--radius-md, 8px);color:var(--da-danger);font-size:12.5px}.da-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px 16px;margin:8px 0 0}.da-grid dt{font-size:11.5px;color:var(--da-muted)}.da-grid dd{margin:3px 0 0;font-size:13px}.da-list{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:6px}.da-list li{display:flex;gap:10px;align-items:center;font-size:13px}.da-field{display:grid;gap:4px;margin-top:10px;font-size:12px}.da-field>span{color:var(--da-muted)}.da-select{height:32px;padding:0 8px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);background:transparent;color:inherit;font:inherit;font-size:13px}
|
|
1
|
+
.da-app{--da-border: var(--border, rgba(127, 127, 127, .25));--da-muted: var(--muted, #888);--da-danger: var(--danger, #dc2626);display:grid;gap:12px;padding:20px 24px 40px;max-width:880px;color:var(--text)}.da-app>*{min-width:0}.da-text{margin:6px 0 10px;font-size:13px;line-height:1.6}.da-muted{margin:6px 0 0;font-size:12px;line-height:1.6;color:var(--da-muted)}.da-step{margin:10px 0 6px;font-size:12px;font-weight:600}.da-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all}.da-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:10px}.da-command{display:flex;gap:8px;align-items:center}.da-command code{flex:1;min-width:0;overflow-x:auto;white-space:nowrap;padding:7px 10px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.da-code-input{width:160px;letter-spacing:.3em;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.da-alert{padding:8px 12px;border:1px solid var(--da-danger);border-radius:var(--radius-md, 8px);color:var(--da-danger);font-size:12.5px}.da-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px 16px;margin:8px 0 0}.da-grid dt{font-size:11.5px;color:var(--da-muted)}.da-grid dd{margin:3px 0 0;font-size:13px}.da-list{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:6px}.da-list li{display:flex;gap:10px;align-items:center;font-size:13px}.da-field{display:grid;gap:4px;margin-top:10px;font-size:12px}.da-field>span{color:var(--da-muted)}.da-select{height:32px;padding:0 8px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);background:transparent;color:inherit;font:inherit;font-size:13px}.da-tabs{display:flex;gap:4px;border-bottom:1px solid var(--da-border)}.da-tab{padding:7px 14px;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--da-muted);font:inherit;font-size:13px;cursor:pointer}.da-tab:hover{color:var(--text)}.da-tab-active{color:var(--text);border-bottom-color:var(--accent, currentColor);font-weight:600}.da-tab:focus-visible,.da-seg:focus-visible{outline:2px solid var(--accent, currentColor);outline-offset:2px}.da-switch{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.da-switch>div{min-width:0}.da-warn{color:var(--warn, #b45309)}.da-form{display:grid;gap:2px;margin-top:6px;max-width:420px}.da-devices{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:2px}.da-devices li{display:flex;flex-wrap:wrap;gap:10px;align-items:center;padding:8px 0;border-bottom:1px solid var(--da-border)}.da-devices li:last-child{border-bottom:0}.da-device-main{display:grid;gap:2px;flex:1;min-width:160px}.da-device-main .da-muted{margin:0}.da-device-name{font-size:13px;font-weight:600}.da-device-actions{display:flex;gap:10px;align-items:center}.da-toggle{display:flex;gap:6px;align-items:center;font-size:12px;color:var(--da-muted)}.da-segment{display:inline-flex;margin:4px 0 10px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);overflow:hidden}.da-seg{padding:5px 12px;border:0;background:transparent;color:var(--da-muted);font:inherit;font-size:12px;cursor:pointer}.da-seg+.da-seg{border-left:1px solid var(--da-border)}.da-seg-active{background:var(--bg-elevated, rgba(127, 127, 127, .12));color:var(--text);font-weight:600}.da-hints{margin:10px 0 0;padding-left:18px;font-size:12px;line-height:1.7;color:var(--da-muted)}
|
|
2
2
|
/*# sourceMappingURL=renderer.css.map */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../plugin/styles.css"],
|
|
4
|
-
"sourcesContent": ["/* Device agent plugin. Every class is prefixed `da-`; colors come from host variables. */\n.da-app {\n --da-border: var(--border, rgba(127, 127, 127, 0.25));\n --da-muted: var(--muted, #888);\n --da-danger: var(--danger, #dc2626);\n display: grid;\n gap: 12px;\n padding: 20px 24px 40px;\n max-width: 880px;\n color: var(--text);\n}\n.da-app > * { min-width: 0; }\n.da-text { margin: 6px 0 10px; font-size: 13px; line-height: 1.6; }\n.da-muted { margin: 6px 0 0; font-size: 12px; line-height: 1.6; color: var(--da-muted); }\n.da-step { margin: 10px 0 6px; font-size: 12px; font-weight: 600; }\n.da-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; word-break: break-all; }\n.da-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; }\n.da-command { display: flex; gap: 8px; align-items: center; }\n.da-command code {\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n white-space: nowrap;\n padding: 7px 10px;\n border: 1px solid var(--da-border);\n border-radius: var(--radius-md, 8px);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n.da-code-input { width: 160px; letter-spacing: 0.3em; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }\n.da-alert {\n padding: 8px 12px;\n border: 1px solid var(--da-danger);\n border-radius: var(--radius-md, 8px);\n color: var(--da-danger);\n font-size: 12.5px;\n}\n.da-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px 16px; margin: 8px 0 0; }\n.da-grid dt { font-size: 11.5px; color: var(--da-muted); }\n.da-grid dd { margin: 3px 0 0; font-size: 13px; }\n.da-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }\n.da-list li { display: flex; gap: 10px; align-items: center; font-size: 13px; }\n.da-field { display: grid; gap: 4px; margin-top: 10px; font-size: 12px; }\n.da-field > span { color: var(--da-muted); }\n.da-select {\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--da-border);\n border-radius: var(--radius-md, 8px);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: 13px;\n}\n"],
|
|
5
|
-
"mappings": "AACA,CAAC,OACC,aAAa,IAAI,QAAQ,EAAE,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAC/C,YAAY,IAAI,OAAO,EAAE,MACzB,aAAa,IAAI,QAAQ,EAAE,SAC3B,QAAS,KACT,IAAK,KANP,QAOW,KAAK,KAAK,KACnB,UAAW,MACX,MAAO,IAAI,OACb,CACA,CAVC,MAUO,CAAE,EAAI,UAAW,CAAG,CAC5B,CAAC,QAZD,OAYmB,IAAI,EAAE,KAAM,UAAW,KAAM,YAAa,GAAK,CAClE,CAAC,SAbD,OAaoB,IAAI,EAAE,EAAG,UAAW,KAAM,YAAa,IAAK,MAAO,IAAI,WAAa,CACxF,CAAC,QAdD,OAcmB,KAAK,EAAE,IAAK,UAAW,KAAM,YAAa,GAAK,CAClE,CAAC,QAAU,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,UAAW,UAAW,KAAM,WAAY,SAAW,CAChH,CAAC,OAAS,QAAS,KAAM,UAAW,KAAM,IAAK,IAAK,YAAa,OAAQ,WAAY,IAAM,CAC3F,CAAC,WAAa,QAAS,KAAM,IAAK,IAAK,YAAa,MAAQ,CAC5D,CADC,WACW,KACV,KAAM,EACN,UAAW,EACX,WAAY,KACZ,YAAa,OAtBf,QAuBW,IAAI,KACb,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,UAClD,UAAW,IACb,CACA,CAAC,cAAgB,MAAO,MAAO,eAAgB,KAAO,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,SAAW,CACnH,CAAC,SA9BD,QA+BW,IAAI,KACb,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,MAAO,IAAI,aACX,UAAW,MACb,CACA,CAAC,QAAU,QAAS,KAAM,sBAAuB,OAAO,SAAS,CAAE,OAAO,KAAK,CAAE,MAAO,IAAK,KAAK,KArClG,OAqCgH,IAAI,EAAE,CAAG,CACzH,CADC,QACQ,GAAK,UAAW,OAAQ,MAAO,IAAI,WAAa,CACzD,CAFC,QAEQ,GAvCT,OAuCsB,IAAI,EAAE,EAAG,UAAW,IAAM,CAChD,CAAC,QAAU,WAAY,KAxCvB,OAwCqC,IAAI,EAAE,EAxC3C,QAwCuD,EAAG,QAAS,KAAM,IAAK,GAAK,CACnF,CADC,QACQ,GAAK,QAAS,KAAM,IAAK,KAAM,YAAa,OAAQ,UAAW,IAAM,CAC9E,CAAC,SAAW,QAAS,KAAM,IAAK,IAAK,WAAY,KAAM,UAAW,IAAM,CACxE,CADC,QACS,CAAE,KAAO,MAAO,IAAI,WAAa,CAC3C,CAAC,UACC,OAAQ,KA7CV,QA8CW,EAAE,IACX,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,WAAY,YACZ,MAAO,QACP,KAAM,QACN,UAAW,IACb",
|
|
4
|
+
"sourcesContent": ["/* Device agent plugin. Every class is prefixed `da-`; colors come from host variables. */\n.da-app {\n --da-border: var(--border, rgba(127, 127, 127, 0.25));\n --da-muted: var(--muted, #888);\n --da-danger: var(--danger, #dc2626);\n display: grid;\n gap: 12px;\n padding: 20px 24px 40px;\n max-width: 880px;\n color: var(--text);\n}\n.da-app > * { min-width: 0; }\n.da-text { margin: 6px 0 10px; font-size: 13px; line-height: 1.6; }\n.da-muted { margin: 6px 0 0; font-size: 12px; line-height: 1.6; color: var(--da-muted); }\n.da-step { margin: 10px 0 6px; font-size: 12px; font-weight: 600; }\n.da-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; word-break: break-all; }\n.da-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; }\n.da-command { display: flex; gap: 8px; align-items: center; }\n.da-command code {\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n white-space: nowrap;\n padding: 7px 10px;\n border: 1px solid var(--da-border);\n border-radius: var(--radius-md, 8px);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n.da-code-input { width: 160px; letter-spacing: 0.3em; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }\n.da-alert {\n padding: 8px 12px;\n border: 1px solid var(--da-danger);\n border-radius: var(--radius-md, 8px);\n color: var(--da-danger);\n font-size: 12.5px;\n}\n.da-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px 16px; margin: 8px 0 0; }\n.da-grid dt { font-size: 11.5px; color: var(--da-muted); }\n.da-grid dd { margin: 3px 0 0; font-size: 13px; }\n.da-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }\n.da-list li { display: flex; gap: 10px; align-items: center; font-size: 13px; }\n.da-field { display: grid; gap: 4px; margin-top: 10px; font-size: 12px; }\n.da-field > span { color: var(--da-muted); }\n.da-select {\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--da-border);\n border-radius: var(--radius-md, 8px);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: 13px;\n}\n.da-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--da-border); }\n.da-tab {\n padding: 7px 14px;\n border: 0;\n border-bottom: 2px solid transparent;\n background: transparent;\n color: var(--da-muted);\n font: inherit;\n font-size: 13px;\n cursor: pointer;\n}\n.da-tab:hover { color: var(--text); }\n.da-tab-active { color: var(--text); border-bottom-color: var(--accent, currentColor); font-weight: 600; }\n.da-tab:focus-visible, .da-seg:focus-visible { outline: 2px solid var(--accent, currentColor); outline-offset: 2px; }\n.da-switch { display: flex; gap: 16px; align-items: flex-start; justify-content: space-between; }\n.da-switch > div { min-width: 0; }\n.da-warn { color: var(--warn, #b45309); }\n.da-form { display: grid; gap: 2px; margin-top: 6px; max-width: 420px; }\n.da-devices { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 2px; }\n.da-devices li {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n align-items: center;\n padding: 8px 0;\n border-bottom: 1px solid var(--da-border);\n}\n.da-devices li:last-child { border-bottom: 0; }\n.da-device-main { display: grid; gap: 2px; flex: 1; min-width: 160px; }\n.da-device-main .da-muted { margin: 0; }\n.da-device-name { font-size: 13px; font-weight: 600; }\n.da-device-actions { display: flex; gap: 10px; align-items: center; }\n.da-toggle { display: flex; gap: 6px; align-items: center; font-size: 12px; color: var(--da-muted); }\n.da-segment { display: inline-flex; margin: 4px 0 10px; border: 1px solid var(--da-border); border-radius: var(--radius-md, 8px); overflow: hidden; }\n.da-seg { padding: 5px 12px; border: 0; background: transparent; color: var(--da-muted); font: inherit; font-size: 12px; cursor: pointer; }\n.da-seg + .da-seg { border-left: 1px solid var(--da-border); }\n.da-seg-active { background: var(--bg-elevated, rgba(127, 127, 127, 0.12)); color: var(--text); font-weight: 600; }\n.da-hints { margin: 10px 0 0; padding-left: 18px; font-size: 12px; line-height: 1.7; color: var(--da-muted); }\n"],
|
|
5
|
+
"mappings": "AACA,CAAC,OACC,aAAa,IAAI,QAAQ,EAAE,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAC/C,YAAY,IAAI,OAAO,EAAE,MACzB,aAAa,IAAI,QAAQ,EAAE,SAC3B,QAAS,KACT,IAAK,KANP,QAOW,KAAK,KAAK,KACnB,UAAW,MACX,MAAO,IAAI,OACb,CACA,CAVC,MAUO,CAAE,EAAI,UAAW,CAAG,CAC5B,CAAC,QAZD,OAYmB,IAAI,EAAE,KAAM,UAAW,KAAM,YAAa,GAAK,CAClE,CAAC,SAbD,OAaoB,IAAI,EAAE,EAAG,UAAW,KAAM,YAAa,IAAK,MAAO,IAAI,WAAa,CACxF,CAAC,QAdD,OAcmB,KAAK,EAAE,IAAK,UAAW,KAAM,YAAa,GAAK,CAClE,CAAC,QAAU,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,UAAW,UAAW,KAAM,WAAY,SAAW,CAChH,CAAC,OAAS,QAAS,KAAM,UAAW,KAAM,IAAK,IAAK,YAAa,OAAQ,WAAY,IAAM,CAC3F,CAAC,WAAa,QAAS,KAAM,IAAK,IAAK,YAAa,MAAQ,CAC5D,CADC,WACW,KACV,KAAM,EACN,UAAW,EACX,WAAY,KACZ,YAAa,OAtBf,QAuBW,IAAI,KACb,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,UAClD,UAAW,IACb,CACA,CAAC,cAAgB,MAAO,MAAO,eAAgB,KAAO,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,SAAW,CACnH,CAAC,SA9BD,QA+BW,IAAI,KACb,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,MAAO,IAAI,aACX,UAAW,MACb,CACA,CAAC,QAAU,QAAS,KAAM,sBAAuB,OAAO,SAAS,CAAE,OAAO,KAAK,CAAE,MAAO,IAAK,KAAK,KArClG,OAqCgH,IAAI,EAAE,CAAG,CACzH,CADC,QACQ,GAAK,UAAW,OAAQ,MAAO,IAAI,WAAa,CACzD,CAFC,QAEQ,GAvCT,OAuCsB,IAAI,EAAE,EAAG,UAAW,IAAM,CAChD,CAAC,QAAU,WAAY,KAxCvB,OAwCqC,IAAI,EAAE,EAxC3C,QAwCuD,EAAG,QAAS,KAAM,IAAK,GAAK,CACnF,CADC,QACQ,GAAK,QAAS,KAAM,IAAK,KAAM,YAAa,OAAQ,UAAW,IAAM,CAC9E,CAAC,SAAW,QAAS,KAAM,IAAK,IAAK,WAAY,KAAM,UAAW,IAAM,CACxE,CADC,QACS,CAAE,KAAO,MAAO,IAAI,WAAa,CAC3C,CAAC,UACC,OAAQ,KA7CV,QA8CW,EAAE,IACX,OAAQ,IAAI,MAAM,IAAI,aACtB,cAAe,IAAI,WAAW,EAAE,KAChC,WAAY,YACZ,MAAO,QACP,KAAM,QACN,UAAW,IACb,CACA,CAAC,QAAU,QAAS,KAAM,IAAK,IAAK,cAAe,IAAI,MAAM,IAAI,YAAc,CAC/E,CAAC,OAvDD,QAwDW,IAAI,KACb,OAAQ,EACR,cAAe,IAAI,MAAM,YACzB,WAAY,YACZ,MAAO,IAAI,YACX,KAAM,QACN,UAAW,KACX,OAAQ,OACV,CACA,CAVC,MAUM,OAAS,MAAO,IAAI,OAAS,CACpC,CAAC,cAAgB,MAAO,IAAI,QAAS,oBAAqB,IAAI,QAAQ,EAAE,cAAe,YAAa,GAAK,CACzG,CAZC,MAYM,eAAgB,CAAC,MAAM,eAAiB,QAAS,IAAI,MAAM,IAAI,QAAQ,EAAE,cAAe,eAAgB,GAAK,CACpH,CAAC,UAAY,QAAS,KAAM,IAAK,KAAM,YAAa,WAAY,gBAAiB,aAAe,CAChG,CADC,SACU,CAAE,IAAM,UAAW,CAAG,CACjC,CAAC,QAAU,MAAO,IAAI,MAAM,EAAE,QAAU,CACxC,CAAC,QAAU,QAAS,KAAM,IAAK,IAAK,WAAY,IAAK,UAAW,KAAO,CACvE,CAAC,WAAa,WAAY,KAxE1B,OAwEwC,IAAI,EAAE,EAxE9C,QAwE0D,EAAG,QAAS,KAAM,IAAK,GAAK,CACtF,CADC,WACW,GACV,QAAS,KACT,UAAW,KACX,IAAK,KACL,YAAa,OA7Ef,QA8EW,IAAI,EACb,cAAe,IAAI,MAAM,IAAI,YAC/B,CACA,CATC,WASW,EAAE,YAAc,cAAe,CAAG,CAC9C,CAAC,eAAiB,QAAS,KAAM,IAAK,IAAK,KAAM,EAAG,UAAW,KAAO,CACtE,CADC,eACe,CAtEf,SAbD,OAmFoC,CAAG,CACvC,CAAC,eAAiB,UAAW,KAAM,YAAa,GAAK,CACrD,CAAC,kBAAoB,QAAS,KAAM,IAAK,KAAM,YAAa,MAAQ,CACpE,CAAC,UAAY,QAAS,KAAM,IAAK,IAAK,YAAa,OAAQ,UAAW,KAAM,MAAO,IAAI,WAAa,CACpG,CAAC,WAAa,QAAS,YAvFvB,OAuF4C,IAAI,EAAE,KAAM,OAAQ,IAAI,MAAM,IAAI,aAAc,cAAe,IAAI,WAAW,EAAE,KAAM,SAAU,MAAQ,CACpJ,CArBwB,OAnExB,QAwFmB,IAAI,KAAM,OAAQ,EAAG,WAAY,YAAa,MAAO,IAAI,YAAa,KAAM,QAAS,UAAW,KAAM,OAAQ,OAAS,CAC1I,CAtBwB,MAsBhB,CAAE,CAtBc,OAsBJ,YAAa,IAAI,MAAM,IAAI,YAAc,CAC7D,CAAC,cAAgB,WAAY,IAAI,aAAa,EAAE,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAQ,MAAO,IAAI,QAAS,YAAa,GAAK,CAClH,CAAC,SA3FD,OA2FoB,KAAK,EAAE,EAAG,aAAc,KAAM,UAAW,KAAM,YAAa,IAAK,MAAO,IAAI,WAAa",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/plugin/renderer.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var Y=Object.create;var B=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,ee=Object.prototype.hasOwnProperty;var P=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var ne=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of X(t))!ee.call(e,i)&&i!==r&&B(e,i,{get:()=>t[i],enumerable:!(a=Q(t,i))||a.enumerable});return e};var S=(e,t,r)=>(r=e!=null?Y(Z(e)):{},ne(t||!e||!e.__esModule?B(r,"default",{value:e,enumerable:!0}):r,e));var L=P((me,$)=>{var I=globalThis.__TOC_PLUGIN_SHARED__,D=I&&I.react;if(!D)throw new Error("The host does not provide react; this plugin needs a newer app version.");$.exports=D});var q=P((ve,F)=>{var M=globalThis.__TOC_PLUGIN_SHARED__,j=M&&M["@toc-starter/plugin-sdk/ui"];if(!j)throw new Error("The host does not provide @toc-starter/plugin-sdk/ui; this plugin needs a newer app version.");F.exports=j});var U=P((ye,K)=>{var G=globalThis.__TOC_PLUGIN_SHARED__,J=G&&G["react/jsx-runtime"];if(!J)throw new Error("The host does not provide react/jsx-runtime; this plugin needs a newer app version.");K.exports=J});var s=S(L(),1);var A=S(L(),1);function H(e){if(!e||typeof e.activate!="function")throw new TypeError("definePlugin() needs an object with an activate(context) function");return e}function T(e,t){return(0,A.useSyncExternalStore)(r=>e.core.onContextChange(t,r),()=>e.core.context(t))}var o=S(q(),1);var W="http://127.0.0.1:17339",f=class extends Error{constructor(r,a,i=""){super(a);this.kind=r;this.code=i}kind;code};async function _(e,t,r={}){let a=new Headers(r.headers);r.token&&a.set("Authorization",`Bearer ${r.token}`),r.body&&a.set("Content-Type","application/json");let i;try{i=await fetch(`${e.replace(/\/+$/,"")}${t}`,{...r,headers:a,cache:"no-store"})}catch{throw new f("offline","local service unreachable")}let p=await i.json().catch(()=>null);if(i.status===401)throw new f("unauthorized","unauthorized");if(!i.ok){let d=typeof p?.error=="string"?p.error:"",u=typeof p?.message=="string"?p.message:d||`HTTP ${i.status}`;throw new f("rejected",u,d)}return p}var y={info:e=>_(e,"/control/info"),pair:(e,t)=>_(e,"/control/pair",{method:"POST",body:JSON.stringify({code:t})}),status:(e,t)=>_(e,"/control/status",{token:t}),enroll:(e,t,r,a)=>_(e,"/control/enroll",{method:"POST",token:t,body:JSON.stringify({server_url:r,code:a})}),unpair:(e,t)=>_(e,"/control/unpair",{method:"POST",token:t}),detect:(e,t)=>_(e,"/control/detect",{method:"POST",token:t})};function E(e,t){let r=a=>{try{return new URL(a).origin.toLowerCase()}catch{return a.trim().replace(/\/+$/,"").toLowerCase()}};return!!(e&&t)&&r(e)===r(t)}var n=S(U(),1),z="controlToken",te="localUrl",re=3e3,ae=new URL("../../assets/icon.svg",import.meta.url).href;function oe(){return(0,n.jsx)("img",{src:ae,alt:"",width:16,height:16,draggable:!1})}function ie(e,t){return t instanceof f&&t.kind==="offline"?e.t("error.offline"):t instanceof Error?t.message:String(t)}function R({ctx:e,value:t}){let[r,a]=(0,s.useState)(!1);return(0,n.jsxs)("div",{className:"da-command",children:[(0,n.jsx)("code",{children:t}),(0,n.jsx)(o.Btn,{onClick:()=>{navigator.clipboard.writeText(t).then(()=>{a(!0),window.setTimeout(()=>a(!1),1500)})},children:r?e.t("common.copied"):e.t("common.copy")})]})}function de({ctx:e}){let t=T(e,"server"),r=T(e,"workspace"),[a]=(0,s.useState)(()=>e.storage.get(te,W)),[i,p]=(0,s.useState)(()=>e.secureStorage.get(z,"")),[d,u]=(0,s.useState)({kind:"checking"}),[h,b]=(0,s.useState)(""),[k,g]=(0,s.useState)(!1),m=(0,s.useRef)(!0),C=(0,s.useCallback)(async()=>{try{await y.info(a)}catch{m.current&&u({kind:"offline"});return}if(!i){m.current&&u({kind:"needsCode"});return}try{let l=await y.status(a,i);m.current&&u({kind:"ready",status:l})}catch(l){if(!m.current)return;l instanceof f&&l.kind==="unauthorized"?(e.secureStorage.remove(z),p(""),u({kind:"needsCode"})):u({kind:"offline"})}},[e,a,i]);(0,s.useEffect)(()=>{m.current=!0,C();let l=window.setInterval(()=>{C()},re);return()=>{m.current=!1,window.clearInterval(l)}},[C]),(0,s.useEffect)(()=>{if(d.kind==="ready"){let l=d.status;e.reportHealth(l.paired&&l.connected?{status:"healthy",summary:e.t("health.online",{name:l.device_name})}:{status:"degraded",summary:e.t(l.paired?"health.disconnected":"health.unpaired")})}else d.kind==="offline"&&e.reportHealth({status:"degraded",summary:e.t("health.offline")})},[e,d]);let x=async l=>{g(!0),b("");try{await l()}catch(v){b(ie(e,v))}finally{g(!1)}};return(0,n.jsxs)("div",{className:"da-app",children:[(0,n.jsx)(o.PageHeader,{title:e.t("page.title"),subtitle:e.t("page.subtitle")}),h&&(0,n.jsx)("div",{role:"alert",className:"da-alert",children:h}),d.kind==="checking"&&(0,n.jsx)(o.Card,{children:(0,n.jsx)("span",{className:"da-muted",children:e.t("common.checking")})}),d.kind==="offline"&&(0,n.jsx)(se,{ctx:e,localUrl:a}),d.kind==="needsCode"&&(0,n.jsx)(le,{ctx:e,busy:k,onPair:l=>x(async()=>{let v=await y.pair(a,l).catch(w=>{throw w instanceof f&&w.code==="code_wrong"?new Error(e.t("pair.wrong")):w instanceof f&&w.code==="locked"?new Error(e.t("pair.locked")):w});e.secureStorage.set(z,v.token),p(v.token)})}),d.kind==="ready"&&(0,n.jsx)(ce,{ctx:e,status:d.status,server:t,workspace:r,busy:k,run:x,localUrl:a,token:i,onStatus:l=>u({kind:"ready",status:l})})]})}function se({ctx:e,localUrl:t}){return(0,n.jsxs)(o.Card,{children:[(0,n.jsx)(o.CardTitle,{children:e.t("offline.title")}),(0,n.jsx)("p",{className:"da-text",children:e.t("offline.body",{url:t})}),(0,n.jsx)("div",{className:"da-step",children:e.t("offline.once")}),(0,n.jsx)(R,{ctx:e,value:"npx toc-ocra@latest run"}),(0,n.jsx)("div",{className:"da-step",children:e.t("offline.service")}),(0,n.jsx)(R,{ctx:e,value:"npm install -g toc-ocra@latest && toc-ocra service:install"}),(0,n.jsx)("p",{className:"da-muted",children:e.t("offline.node")})]})}function le({ctx:e,busy:t,onPair:r}){let[a,i]=(0,s.useState)(""),p=/^\d{6}$/.test(a);return(0,n.jsxs)(o.Card,{children:[(0,n.jsx)(o.CardTitle,{children:e.t("pair.title")}),(0,n.jsx)("p",{className:"da-text",children:e.t("pair.body")}),(0,n.jsx)(R,{ctx:e,value:"toc-ocra code"}),(0,n.jsxs)("form",{className:"da-row",onSubmit:d=>{d.preventDefault(),p&&r(a)},children:[(0,n.jsx)(o.Input,{value:a,onChange:d=>i(d.target.value.replace(/\D/g,"").slice(0,6)),placeholder:e.t("pair.placeholder"),inputMode:"numeric",autoComplete:"one-time-code","aria-label":e.t("pair.placeholder"),className:"da-code-input"}),(0,n.jsx)(o.Btn,{primary:!0,type:"submit",disabled:!p||t,children:e.t("pair.submit")})]})]})}function ce({ctx:e,status:t,server:r,workspace:a,busy:i,run:p,localUrl:d,token:u,onStatus:h}){let b=t.paired&&r&&!E(t.server_url,r.origin),k=()=>p(async()=>{t.device_id&&r&&E(t.server_url,r.origin)&&await e.core.request(`/devices/${encodeURIComponent(t.device_id)}/agent`,{method:"DELETE"}).catch(()=>{}),h(await y.unpair(d,u))});return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(o.Card,{children:[(0,n.jsx)(o.CardTitle,{children:e.t("status.title")}),(0,n.jsxs)("dl",{className:"da-grid",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{children:e.t("status.service")}),(0,n.jsxs)("dd",{children:["toc-ocra ",t.version," \xB7 ",t.hostname]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{children:e.t("status.binding")}),(0,n.jsx)("dd",{children:(0,n.jsx)(pe,{ctx:e,status:t})})]}),t.paired&&(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{children:e.t("status.device")}),(0,n.jsx)("dd",{children:t.device_name})]}),t.paired&&(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{children:e.t("status.server")}),(0,n.jsx)("dd",{className:"da-mono",children:t.server_url})]}),t.paired&&(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{children:e.t("status.runs")}),(0,n.jsx)("dd",{children:t.active_runs})]})]}),t.paired&&!t.connected&&t.connection_error&&(0,n.jsx)("p",{className:"da-muted",children:e.t("status.lastError",{error:t.connection_error})}),t.token_from_env&&(0,n.jsx)("p",{className:"da-muted",children:e.t("status.tokenFromEnv")}),t.paired&&(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(o.Btn,{danger:!0,disabled:i||t.token_from_env,onClick:()=>{k()},children:e.t("status.unpair")})})]}),(!t.paired||t.unauthorized||b)&&(0,n.jsx)(ue,{ctx:e,status:t,server:r,workspace:a,busy:i,run:p,localUrl:d,token:u,onStatus:h,rebind:t.paired}),(0,n.jsxs)(o.Card,{children:[(0,n.jsx)(o.CardTitle,{children:e.t("cli.title")}),(0,n.jsxs)("ul",{className:"da-list",children:[t.providers.filter(g=>g.installed).map(g=>(0,n.jsxs)("li",{children:[(0,n.jsx)("span",{className:"da-mono",children:g.id}),(0,n.jsx)("span",{className:"da-muted",children:g.version}),g.runnable?(0,n.jsx)(o.Badge,{variant:"ok",children:e.t("cli.runnable")}):(0,n.jsx)(o.Badge,{variant:"muted",children:e.t("cli.detectOnly")})]},g.id)),!t.providers.some(g=>g.installed)&&(0,n.jsx)("li",{className:"da-muted",children:e.t("cli.none")})]}),(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(o.Btn,{disabled:i,onClick:()=>{p(async()=>h(await y.detect(d,u)))},children:e.t("cli.redetect")})})]})]})}function pe({ctx:e,status:t}){return t.paired?t.unauthorized?(0,n.jsx)(o.Badge,{variant:"err",children:e.t("binding.revoked")}):t.connected?(0,n.jsx)(o.Badge,{variant:"ok",children:e.t("binding.online")}):(0,n.jsx)(o.Badge,{variant:"warn",children:e.t("binding.connecting")}):(0,n.jsx)(o.Badge,{variant:"muted",children:e.t("binding.unpaired")})}function ue({ctx:e,status:t,server:r,workspace:a,busy:i,run:p,localUrl:d,token:u,onStatus:h,rebind:b}){let[k,g]=(0,s.useState)([]),[m,C]=(0,s.useState)("new"),[x,l]=(0,s.useState)(t.hostname),[v,w]=(0,s.useState)(r?.origin??"");(0,s.useEffect)(()=>{r?.origin&&w(r.origin)},[r?.origin]),(0,s.useEffect)(()=>{if(!a?.id)return;let c=!1;return e.core.request(`/workspaces/${encodeURIComponent(a.id)}/devices`).then(N=>{c||g((N.items??[]).filter(O=>O.is_mine))}).catch(()=>{c||g([])}),()=>{c=!0}},[e,a?.id]);let V=()=>p(async()=>{if(!a?.id)throw new Error(e.t("bind.noWorkspace"));if(!v.trim())throw new Error(e.t("bind.noServer"));let c=m;m==="new"&&(c=(await e.core.request(`/workspaces/${encodeURIComponent(a.id)}/devices`,{method:"POST",body:JSON.stringify({name:x.trim()||t.hostname,location:"local",platform:t.platform,note:"",share_to_workspace:!1})})).id,C(c));let N=await e.core.request(`/devices/${encodeURIComponent(c)}/pairing-code`,{method:"POST"});h(await y.enroll(d,u,v.trim(),N.code)),e.notify({title:e.t("page.title"),body:e.t("bind.done",{server:r?.name??v})})});return(0,n.jsxs)(o.Card,{children:[(0,n.jsx)(o.CardTitle,{children:e.t(b?"bind.rebindTitle":"bind.title")}),b&&t.unauthorized&&(0,n.jsx)("p",{className:"da-text",children:e.t("bind.revoked")}),b&&!t.unauthorized&&(0,n.jsx)("p",{className:"da-text",children:e.t("bind.elsewhere",{bound:t.server_url,current:r?.origin??""})}),(0,n.jsx)("p",{className:"da-text",children:e.t("bind.body",{server:r?.name??"",workspace:a?.name??""})}),(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("bind.server")}),(0,n.jsx)(o.Input,{value:v,onChange:c=>w(c.target.value),spellCheck:!1,className:"da-mono"})]}),(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("bind.device")}),(0,n.jsxs)("select",{className:"da-select",value:m,onChange:c=>C(c.target.value),children:[(0,n.jsx)("option",{value:"new",children:e.t("bind.newDevice")}),k.map(c=>(0,n.jsxs)("option",{value:c.id,children:[c.name,c.paired?` \xB7 ${e.t("bind.replaces")}`:""]},c.id))]})]}),m==="new"&&(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("bind.name")}),(0,n.jsx)(o.Input,{value:x,onChange:c=>l(c.target.value),maxLength:100})]}),(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(o.Btn,{primary:!0,disabled:i||!a?.id,onClick:()=>{V()},children:e.t(i?"bind.working":"bind.submit")})})]})}var xe=H({activate(e){e.registerNavigation("agent.nav",(0,n.jsx)(oe,{})),e.registerRoute("agent.home",(0,n.jsx)(de,{ctx:e}))}});export{xe as default};
|
|
1
|
+
var Pe=Object.create;var ie=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var Le=Object.getOwnPropertyNames;var xe=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var te=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Be=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of Le(t))!Ee.call(e,c)&&c!==r&&ie(e,c,{get:()=>t[c],enumerable:!(o=Te(t,c))||o.enumerable});return e};var P=(e,t,r)=>(r=e!=null?Pe(xe(e)):{},Be(t||!e||!e.__esModule?ie(r,"default",{value:e,enumerable:!0}):r,e));var H=te((nt,le)=>{var se=globalThis.__TOC_PLUGIN_SHARED__,de=se&&se.react;if(!de)throw new Error("The host does not provide react; this plugin needs a newer app version.");le.exports=de});var J=te((ot,ge)=>{var pe=globalThis.__TOC_PLUGIN_SHARED__,ue=pe&&pe["@toc-starter/plugin-sdk/ui"];if(!ue)throw new Error("The host does not provide @toc-starter/plugin-sdk/ui; this plugin needs a newer app version.");ge.exports=ue});var M=te((lt,be)=>{var fe=globalThis.__TOC_PLUGIN_SHARED__,ve=fe&&fe["react/jsx-runtime"];if(!ve)throw new Error("The host does not provide react/jsx-runtime; this plugin needs a newer app version.");be.exports=ve});var y=P(H(),1);var ce=P(H(),1);function me(e){if(!e||typeof e.activate!="function")throw new TypeError("definePlugin() needs an object with an activate(context) function");return e}function ae(e,t){return(0,ce.useSyncExternalStore)(r=>e.core.onContextChange(t,r),()=>e.core.context(t))}var m=P(J(),1);var ne="http://127.0.0.1:17339",L=class extends Error{constructor(r,o,c=""){super(o);this.kind=r;this.code=c}kind;code};async function q(e,t,r={}){let o=new Headers(r.headers);r.token&&o.set("Authorization",`Bearer ${r.token}`),r.body&&o.set("Content-Type","application/json");let c;try{c=await fetch(`${e.replace(/\/+$/,"")}${t}`,{...r,headers:o,cache:"no-store"})}catch{throw new L("offline","local service unreachable")}let h=await c.json().catch(()=>null);if(c.status===401)throw new L("unauthorized","unauthorized");if(!c.ok){let s=typeof h?.error=="string"?h.error:"",b=typeof h?.message=="string"?h.message:s||`HTTP ${c.status}`;throw new L("rejected",b,s)}return h}var B={info:e=>q(e,"/control/info"),pair:(e,t)=>q(e,"/control/pair",{method:"POST",body:JSON.stringify({code:t})}),status:(e,t)=>q(e,"/control/status",{token:t}),enroll:(e,t,r,o)=>q(e,"/control/enroll",{method:"POST",token:t,body:JSON.stringify({server_url:r,code:o})}),unpair:(e,t)=>q(e,"/control/unpair",{method:"POST",token:t}),detect:(e,t)=>q(e,"/control/detect",{method:"POST",token:t})};function V(e,t){let r=o=>{try{return new URL(o).origin.toLowerCase()}catch{return o.trim().replace(/\/+$/,"").toLowerCase()}};return!!(e&&t)&&r(e)===r(t)}var C=P(H(),1),f=P(J(),1);var he=P(H(),1),we=P(J(),1);var W=P(M(),1),A="controlToken",re="localUrl",Y="autoBind",G="localService";function F(e,t){return t instanceof L&&t.kind==="offline"?e.t("error.offline"):t instanceof Error?t.message:String(t)}function K({ctx:e,value:t}){let[r,o]=(0,he.useState)(!1);return(0,W.jsxs)("div",{className:"da-command",children:[(0,W.jsx)("code",{children:t}),(0,W.jsx)(we.Btn,{onClick:()=>{navigator.clipboard.writeText(t).then(()=>{o(!0),window.setTimeout(()=>o(!1),1500)})},children:r?e.t("common.copied"):e.t("common.copy")})]})}var n=P(M(),1),Q=["linux","mac","win"],Ie=1e4,Re=3e3,X="remoteServerUrl",Oe=new Set(["127.0.0.1","localhost","[::1]","::1","0.0.0.0"]);function Ue(e){try{let t=new URL(e.trim());return t.protocol==="http:"||t.protocol==="https:"?t.origin:null}catch{return null}}function De(e){try{return Oe.has(new URL(e).hostname)}catch{return!1}}function Ae(e,t,r){let o=`toc-ocra setup --code ${t} --server ${r}`;return e==="win"?`npm install -g toc-ocra@latest; if ($?) { ${o} }`:`npm install -g toc-ocra@latest && ${o}`}function $e({ctx:e,device:t}){return t.status==="online"?(0,n.jsx)(f.Badge,{variant:"ok",children:e.t("remote.status.online")}):t.status==="disabled"?(0,n.jsx)(f.Badge,{variant:"warn",children:e.t("remote.status.disabled")}):t.status==="offline"?(0,n.jsx)(f.Badge,{variant:"err",children:e.t("remote.status.offline")}):(0,n.jsx)(f.Badge,{variant:"muted",children:e.t("remote.status.notConnected")})}function ye({ctx:e,server:t,workspace:r,localDeviceId:o}){let[c,h]=(0,C.useState)(null),[s,b]=(0,C.useState)(""),[v,d]=(0,C.useState)(!1),[u,p]=(0,C.useState)(null),[x,I]=(0,C.useState)(!1),[O,U]=(0,C.useState)(""),[S,N]=(0,C.useState)("linux"),[_,g]=(0,C.useState)(()=>e.storage.get(X,"")||t?.origin||""),E=(0,C.useRef)(u);E.current=u;let R=(0,C.useRef)(!0);(0,C.useEffect)(()=>{!e.storage.get(X,"")&&t?.origin&&g(t.origin)},[e,t?.origin]);let $=(0,C.useCallback)(async()=>{if(r?.id)try{let i=await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices`);if(!R.current)return;let k=(i.items??[]).filter(z=>z.is_mine&&z.id!==o);h(k);let D=E.current;if(D&&!D.matched){let z=k.find(Ne=>Ne.id===D.deviceId);z?.agent_id&&z.agent_id!==D.baseline&&z.terminal_online&&(p({...D,matched:!0}),e.notify({title:e.t("page.title"),body:e.t("remote.matchedNotice",{name:z.name})}))}}catch(i){R.current&&b(F(e,i))}},[e,o,r?.id]),j=!!(u&&!u.matched);(0,C.useEffect)(()=>{R.current=!0,$();let i=window.setInterval(()=>{$()},j?Re:Ie);return()=>{R.current=!1,window.clearInterval(i)}},[$,j]);let l=async i=>{d(!0),b("");try{await i()}catch(k){b(F(e,k))}finally{d(!1)}},w=Ue(_),T=i=>{g(i),i.trim()&&i.trim()!==t?.origin?e.storage.set(X,i.trim()):e.storage.remove(X)},oe=i=>l(async()=>{if(!w)throw new Error(e.t("remote.serverInvalid"));let k=await e.core.request(`/devices/${encodeURIComponent(i.id)}/pairing-code`,{method:"POST"});p({deviceId:i.id,deviceName:i.name,platform:Q.includes(i.platform)?i.platform:"linux",code:k.code,expiresAt:k.expires_at,baseline:i.agent_id??null,matched:!1})}),ke=()=>l(async()=>{if(!r?.id)throw new Error(e.t("bind.noWorkspace"));if(!w)throw new Error(e.t("remote.serverInvalid"));let i=O.trim()||e.t(`remote.platform.${S}`),k=await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices`,{method:"POST",body:JSON.stringify({name:i,location:S==="linux"?"cloud":"local",platform:S,note:"",share_to_workspace:!1})}),D=await e.core.request(`/devices/${encodeURIComponent(k.id)}/pairing-code`,{method:"POST"});p({deviceId:k.id,deviceName:k.name||i,platform:S,code:D.code,expiresAt:D.expires_at,baseline:null,matched:!1}),I(!1),U(""),await $()}),Se=(i,k)=>l(async()=>{await e.core.request(`/devices/${encodeURIComponent(i.id)}/enabled`,{method:"PUT",body:JSON.stringify({enabled:k})}),await $()});return(0,n.jsxs)(n.Fragment,{children:[s&&(0,n.jsx)("div",{role:"alert",className:"da-alert",children:s}),(0,n.jsxs)(f.Card,{children:[(0,n.jsx)(f.CardTitle,{children:e.t("remote.title")}),(0,n.jsx)("p",{className:"da-text",children:e.t("remote.body")}),(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("remote.server")}),(0,n.jsx)(f.Input,{value:_,onChange:i=>T(i.target.value),spellCheck:!1,className:"da-mono"})]}),!w&&(0,n.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.serverInvalid")}),w&&De(w)&&(0,n.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.loopback")}),!x&&(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(f.Btn,{primary:!0,disabled:v||!r?.id,onClick:()=>I(!0),children:e.t("remote.add")})}),x&&(0,n.jsxs)("form",{className:"da-form",onSubmit:i=>{i.preventDefault(),ke()},children:[(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("remote.platformLabel")}),(0,n.jsx)("select",{className:"da-select",value:S,onChange:i=>N(i.target.value),children:Q.map(i=>(0,n.jsx)("option",{value:i,children:e.t(`remote.platform.${i}`)},i))})]}),(0,n.jsxs)("label",{className:"da-field",children:[(0,n.jsx)("span",{children:e.t("remote.name")}),(0,n.jsx)(f.Input,{value:O,onChange:i=>U(i.target.value),maxLength:100,placeholder:e.t("remote.namePlaceholder")})]}),(0,n.jsxs)("div",{className:"da-row",children:[(0,n.jsx)(f.Btn,{primary:!0,type:"submit",disabled:v||!w,children:e.t(v?"remote.working":"remote.generate")}),(0,n.jsx)(f.Btn,{type:"button",disabled:v,onClick:()=>I(!1),children:e.t("remote.cancel")})]})]})]}),u&&w&&(0,n.jsx)(ze,{ctx:e,pending:u,origin:w,busy:v,onPlatform:i=>p({...u,platform:i}),onRegenerate:()=>{oe({id:u.deviceId,name:u.deviceName,platform:u.platform,agent_id:u.baseline})},onClose:()=>p(null)}),(0,n.jsxs)(f.Card,{children:[(0,n.jsx)(f.CardTitle,{children:e.t("remote.listTitle")}),c===null&&(0,n.jsx)("p",{className:"da-muted",children:e.t("common.checking")}),c?.length===0&&(0,n.jsx)("p",{className:"da-muted",children:e.t("remote.empty")}),c&&c.length>0&&(0,n.jsx)("ul",{className:"da-devices",children:c.map(i=>(0,n.jsxs)("li",{children:[(0,n.jsxs)("div",{className:"da-device-main",children:[(0,n.jsx)("span",{className:"da-device-name",children:i.name}),(0,n.jsxs)("span",{className:"da-muted",children:[e.t(`remote.platform.${Q.includes(i.platform)?i.platform:"linux"}`),i.agent_version?` \xB7 toc-ocra ${i.agent_version}`:""]})]}),(0,n.jsx)($e,{ctx:e,device:i}),(0,n.jsxs)("div",{className:"da-device-actions",children:[(!i.paired||i.status==="offline"||i.status==="not_connected")&&(0,n.jsx)(f.Btn,{disabled:v||!w,onClick:()=>{oe(i)},children:e.t(i.paired?"remote.repair":"remote.install")}),i.paired&&(0,n.jsxs)("label",{className:"da-toggle",children:[(0,n.jsx)("span",{children:e.t("remote.enabled")}),(0,n.jsx)(f.Toggle,{checked:!i.disabled,disabled:v,label:e.t("remote.enabled"),onChange:k=>{Se(i,k)}})]})]})]},i.id))}),(0,n.jsx)("p",{className:"da-muted",children:e.t("remote.disableHint")}),(0,n.jsx)("div",{className:"da-step",children:e.t("remote.uninstall")}),(0,n.jsx)(K,{ctx:e,value:"toc-ocra service:uninstall"})]})]})}function ze({ctx:e,pending:t,origin:r,busy:o,onPlatform:c,onRegenerate:h,onClose:s}){let[b,v]=(0,C.useState)(()=>Math.floor(Date.now()/1e3));(0,C.useEffect)(()=>{if(t.matched)return;let p=window.setInterval(()=>v(Math.floor(Date.now()/1e3)),1e3);return()=>window.clearInterval(p)},[t.matched]);let d=Math.max(0,t.expiresAt-b),u=!t.matched&&d===0;return(0,n.jsxs)(f.Card,{children:[(0,n.jsx)(f.CardTitle,{children:e.t("remote.pendingTitle",{name:t.deviceName})}),t.matched?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{className:"da-text",children:[(0,n.jsx)(f.Badge,{variant:"ok",children:e.t("remote.matched")})," ",e.t("remote.matchedBody",{name:t.deviceName})]}),(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(f.Btn,{primary:!0,onClick:s,children:e.t("remote.done")})})]}):(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{className:"da-text",children:e.t("remote.pendingBody")}),(0,n.jsx)("div",{className:"da-segment",role:"radiogroup","aria-label":e.t("remote.platformLabel"),children:Q.map(p=>(0,n.jsx)("button",{type:"button",role:"radio","aria-checked":t.platform===p,className:t.platform===p?"da-seg da-seg-active":"da-seg",onClick:()=>c(p),children:e.t(`remote.platform.${p}`)},p))}),(0,n.jsx)(K,{ctx:e,value:Ae(t.platform,t.code,r)}),(0,n.jsxs)("ul",{className:"da-hints",children:[(0,n.jsx)("li",{children:e.t("remote.hintNode")}),t.platform==="linux"&&(0,n.jsx)("li",{children:e.t("remote.hintLinux")}),t.platform==="win"&&(0,n.jsx)("li",{children:e.t("remote.hintWindows")}),(0,n.jsx)("li",{children:u?e.t("remote.expired"):e.t("remote.expires",{minutes:Math.floor(d/60),seconds:String(d%60).padStart(2,"0")})})]}),(0,n.jsx)("p",{className:"da-muted",children:u?"":e.t("remote.waiting")}),(0,n.jsxs)("div",{className:"da-row",children:[(0,n.jsx)(f.Btn,{disabled:o,onClick:h,children:e.t("remote.regenerate")}),(0,n.jsx)(f.Btn,{disabled:o,onClick:s,children:e.t("remote.cancel")})]})]})]})}var a=P(M(),1),Me=3e3,Ke=1e4,qe=6e4,He=3,Ce="tab",We=new URL("../../assets/icon.svg",import.meta.url).href;function Ye(){return(0,a.jsx)("img",{src:We,alt:"",width:16,height:16,draggable:!1})}function _e(e){let t=e.core.service;try{return t&&t.available()?t:void 0}catch{return}}var Z=e=>e?.state==="running"||e?.state==="starting",ee;function Fe({ctx:e}){let t=ae(e,"server"),r=ae(e,"workspace"),[o,c]=(0,y.useState)(()=>e.storage.get(Ce,"local")==="remote"?"remote":"local"),h=l=>{e.storage.set(Ce,l),c(l)},[s]=(0,y.useState)(()=>e.storage.get(re,ne)),[b,v]=(0,y.useState)(()=>e.secureStorage.get(A,"")),[d,u]=(0,y.useState)({kind:"checking"}),[p,x]=(0,y.useState)(null),[I,O]=(0,y.useState)(""),[U,S]=(0,y.useState)(!1),N=(0,y.useRef)(!0),_=_e(e),g=(0,y.useCallback)(async()=>{let l=null;if(_)try{l=await _.status()}catch{l=null}if(!N.current)return;x(l);let w=b;Z(l)&&l?.token&&(w=l.token,l.token!==b&&(e.secureStorage.set(A,l.token),v(l.token)));try{await B.info(s)}catch{N.current&&u({kind:Z(l)?"starting":"offline"});return}if(!w){N.current&&u({kind:"needsCode"});return}try{let T=await B.status(s,w);N.current&&u({kind:"ready",status:T})}catch(T){if(!N.current)return;T instanceof L&&T.kind==="unauthorized"?(e.secureStorage.remove(A),v(""),u({kind:"needsCode"})):u({kind:"offline"})}},[e,s,_,b]);(0,y.useEffect)(()=>{N.current=!0,g();let l=window.setInterval(()=>{g()},Me);return()=>{N.current=!1,window.clearInterval(l)}},[g]),(0,y.useEffect)(()=>{if(d.kind==="ready"){let l=d.status;e.reportHealth(l.paired&&l.connected?{status:"healthy",summary:e.t("health.online",{name:l.device_name})}:{status:"degraded",summary:e.t(l.paired?"health.disconnected":"health.unpaired")})}else d.kind==="offline"&&e.reportHealth({status:"degraded",summary:e.t(_?"health.disabled":"health.offline")})},[e,d,_]);let E=async l=>{S(!0),O("");try{await l()}catch(w){O(F(e,w))}finally{S(!1)}},R=l=>E(async()=>{if(!_)return;if(!l){e.storage.set(G,"off"),x(await _.stop()),await g();return}e.storage.set(G,"on"),e.storage.remove(Y);let w=await _.start();x(w),w.token&&(e.secureStorage.set(A,w.token),v(w.token)),await je(s,()=>N.current)&&ee?.(),await g()}),$=p?.state==="exited"?p:null,j=!!_&&!Z(p)&&(d.kind==="ready"||d.kind==="needsCode");return(0,a.jsxs)("div",{className:"da-app",children:[(0,a.jsx)(m.PageHeader,{title:e.t("page.title"),subtitle:e.t("page.subtitle")}),(0,a.jsx)("div",{className:"da-tabs",role:"tablist","aria-label":e.t("page.title"),children:["local","remote"].map(l=>(0,a.jsx)("button",{type:"button",role:"tab","aria-selected":o===l,className:o===l?"da-tab da-tab-active":"da-tab",onClick:()=>h(l),children:e.t(`tabs.${l}`)},l))}),I&&(0,a.jsx)("div",{role:"alert",className:"da-alert",children:I}),o==="remote"&&(0,a.jsx)(ye,{ctx:e,server:t,workspace:r,localDeviceId:d.kind==="ready"&&d.status.paired?d.status.device_id:""}),o==="local"&&(0,a.jsxs)(a.Fragment,{children:[_&&(0,a.jsx)(Je,{ctx:e,status:p,external:j,exit:$,busy:U,onToggle:l=>{R(l)}}),d.kind==="checking"&&(0,a.jsx)(m.Card,{children:(0,a.jsx)("span",{className:"da-muted",children:e.t("common.checking")})}),d.kind==="starting"&&(0,a.jsx)(m.Card,{children:(0,a.jsx)("span",{className:"da-muted",children:e.t("service.starting")})}),d.kind==="offline"&&!_&&(0,a.jsx)(Ve,{ctx:e,localUrl:s}),d.kind==="needsCode"&&(0,a.jsx)(Ge,{ctx:e,busy:U,onPair:l=>E(async()=>{let w=await B.pair(s,l).catch(T=>{throw T instanceof L&&T.code==="code_wrong"?new Error(e.t("pair.wrong")):T instanceof L&&T.code==="locked"?new Error(e.t("pair.locked")):T});e.secureStorage.set(A,w.token),v(w.token)})}),d.kind==="ready"&&(0,a.jsx)(Xe,{ctx:e,status:d.status,server:t,workspace:r,busy:U,run:E,localUrl:s,token:b,onStatus:l=>u({kind:"ready",status:l})})]})]})}async function je(e,t){for(let r=0;r<30&&t();r+=1)try{return await B.info(e),!0}catch{await new Promise(o=>window.setTimeout(o,500))}return!1}function Je({ctx:e,status:t,external:r,exit:o,busy:c,onToggle:h}){let s=Z(t),b=o?.exitCode===He;return(0,a.jsxs)(m.Card,{children:[(0,a.jsxs)("div",{className:"da-switch",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(m.CardTitle,{children:e.t("service.title")}),(0,a.jsx)("p",{className:"da-text",children:e.t(s?"service.onBody":"service.offBody")})]}),(0,a.jsx)(m.Toggle,{checked:s,disabled:c,label:e.t("service.title"),onChange:h})]}),s&&(0,a.jsx)("p",{className:"da-muted",children:e.t("service.followsApp")}),!s&&(r||b)&&(0,a.jsx)("p",{className:"da-muted",children:e.t("service.external")}),o&&!b&&o.exitCode!==0&&(0,a.jsx)("div",{role:"alert",className:"da-alert",children:e.t("service.crashed",{error:o.error||`exit ${o.exitCode??o.signal??"?"}`})})]})}function Ve({ctx:e,localUrl:t}){return(0,a.jsxs)(m.Card,{children:[(0,a.jsx)(m.CardTitle,{children:e.t("offline.title")}),(0,a.jsx)("p",{className:"da-text",children:e.t("offline.body",{url:t})}),(0,a.jsx)("div",{className:"da-step",children:e.t("offline.once")}),(0,a.jsx)(K,{ctx:e,value:"npx toc-ocra@latest run"}),(0,a.jsx)("div",{className:"da-step",children:e.t("offline.service")}),(0,a.jsx)(K,{ctx:e,value:"npm install -g toc-ocra@latest && toc-ocra service:install"}),(0,a.jsx)("p",{className:"da-muted",children:e.t("offline.node")})]})}function Ge({ctx:e,busy:t,onPair:r}){let[o,c]=(0,y.useState)(""),h=/^\d{6}$/.test(o);return(0,a.jsxs)(m.Card,{children:[(0,a.jsx)(m.CardTitle,{children:e.t("pair.title")}),(0,a.jsx)("p",{className:"da-text",children:e.t("pair.body")}),(0,a.jsx)(K,{ctx:e,value:"toc-ocra code"}),(0,a.jsxs)("form",{className:"da-row",onSubmit:s=>{s.preventDefault(),h&&r(o)},children:[(0,a.jsx)(m.Input,{value:o,onChange:s=>c(s.target.value.replace(/\D/g,"").slice(0,6)),placeholder:e.t("pair.placeholder"),inputMode:"numeric",autoComplete:"one-time-code","aria-label":e.t("pair.placeholder"),className:"da-code-input"}),(0,a.jsx)(m.Btn,{primary:!0,type:"submit",disabled:!h||t,children:e.t("pair.submit")})]})]})}function Xe({ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:b,onStatus:v}){let d=t.paired&&r&&!V(t.server_url,r.origin),u=()=>h(async()=>{t.device_id&&r&&V(t.server_url,r.origin)&&await e.core.request(`/devices/${encodeURIComponent(t.device_id)}/agent`,{method:"DELETE"}).catch(()=>{}),e.storage.set(Y,"off"),v(await B.unpair(s,b))});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(m.Card,{children:[(0,a.jsx)(m.CardTitle,{children:e.t("status.title")}),(0,a.jsxs)("dl",{className:"da-grid",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:e.t("status.service")}),(0,a.jsxs)("dd",{children:["toc-ocra ",t.version," \xB7 ",t.hostname]})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:e.t("status.binding")}),(0,a.jsx)("dd",{children:(0,a.jsx)(Qe,{ctx:e,status:t})})]}),t.paired&&(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:e.t("status.device")}),(0,a.jsx)("dd",{children:t.device_name})]}),t.paired&&(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:e.t("status.server")}),(0,a.jsx)("dd",{className:"da-mono",children:t.server_url})]}),t.paired&&(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:e.t("status.runs")}),(0,a.jsx)("dd",{children:t.active_runs})]})]}),t.paired&&!t.connected&&t.connection_error&&(0,a.jsx)("p",{className:"da-muted",children:e.t("status.lastError",{error:t.connection_error})}),t.token_from_env&&(0,a.jsx)("p",{className:"da-muted",children:e.t("status.tokenFromEnv")}),t.paired&&(0,a.jsx)("div",{className:"da-row",children:(0,a.jsx)(m.Btn,{danger:!0,disabled:c||t.token_from_env,onClick:()=>{u()},children:e.t("status.unpair")})})]}),(!t.paired||t.unauthorized||d)&&(0,a.jsx)(Ze,{ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:b,onStatus:v,rebind:t.paired}),(0,a.jsxs)(m.Card,{children:[(0,a.jsx)(m.CardTitle,{children:e.t("cli.title")}),(0,a.jsxs)("ul",{className:"da-list",children:[t.providers.filter(p=>p.installed).map(p=>(0,a.jsxs)("li",{children:[(0,a.jsx)("span",{className:"da-mono",children:p.id}),(0,a.jsx)("span",{className:"da-muted",children:p.version}),p.runnable?(0,a.jsx)(m.Badge,{variant:"ok",children:e.t("cli.runnable")}):(0,a.jsx)(m.Badge,{variant:"muted",children:e.t("cli.detectOnly")})]},p.id)),!t.providers.some(p=>p.installed)&&(0,a.jsx)("li",{className:"da-muted",children:e.t("cli.none")})]}),(0,a.jsx)("div",{className:"da-row",children:(0,a.jsx)(m.Btn,{disabled:c,onClick:()=>{h(async()=>v(await B.detect(s,b)))},children:e.t("cli.redetect")})})]})]})}function Qe({ctx:e,status:t}){return t.paired?t.unauthorized?(0,a.jsx)(m.Badge,{variant:"err",children:e.t("binding.revoked")}):t.connected?(0,a.jsx)(m.Badge,{variant:"ok",children:e.t("binding.online")}):(0,a.jsx)(m.Badge,{variant:"warn",children:e.t("binding.connecting")}):(0,a.jsx)(m.Badge,{variant:"muted",children:e.t("binding.unpaired")})}function Ze({ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:b,onStatus:v,rebind:d}){let[u,p]=(0,y.useState)([]),[x,I]=(0,y.useState)("new"),[O,U]=(0,y.useState)(t.hostname),[S,N]=(0,y.useState)(r?.origin??"");(0,y.useEffect)(()=>{r?.origin&&N(r.origin)},[r?.origin]),(0,y.useEffect)(()=>{if(!o?.id)return;let g=!1;return e.core.request(`/workspaces/${encodeURIComponent(o.id)}/devices`).then(E=>{g||p((E.items??[]).filter(R=>R.is_mine))}).catch(()=>{g||p([])}),()=>{g=!0}},[e,o?.id]);let _=()=>h(async()=>{if(!o?.id)throw new Error(e.t("bind.noWorkspace"));if(!S.trim())throw new Error(e.t("bind.noServer"));let g=x;x==="new"&&(g=(await e.core.request(`/workspaces/${encodeURIComponent(o.id)}/devices`,{method:"POST",body:JSON.stringify({name:O.trim()||t.hostname,location:"local",platform:t.platform,note:"",share_to_workspace:!1})})).id,I(g));let E=await e.core.request(`/devices/${encodeURIComponent(g)}/pairing-code`,{method:"POST"});v(await B.enroll(s,b,S.trim(),E.code)),e.storage.remove(Y),e.notify({title:e.t("page.title"),body:e.t("bind.done",{server:r?.name??S})})});return(0,a.jsxs)(m.Card,{children:[(0,a.jsx)(m.CardTitle,{children:e.t(d?"bind.rebindTitle":"bind.title")}),d&&t.unauthorized&&(0,a.jsx)("p",{className:"da-text",children:e.t("bind.revoked")}),d&&!t.unauthorized&&(0,a.jsx)("p",{className:"da-text",children:e.t("bind.elsewhere",{bound:t.server_url,current:r?.origin??""})}),(0,a.jsx)("p",{className:"da-text",children:e.t("bind.body",{server:r?.name??"",workspace:o?.name??""})}),(0,a.jsxs)("label",{className:"da-field",children:[(0,a.jsx)("span",{children:e.t("bind.server")}),(0,a.jsx)(m.Input,{value:S,onChange:g=>N(g.target.value),spellCheck:!1,className:"da-mono"})]}),(0,a.jsxs)("label",{className:"da-field",children:[(0,a.jsx)("span",{children:e.t("bind.device")}),(0,a.jsxs)("select",{className:"da-select",value:x,onChange:g=>I(g.target.value),children:[(0,a.jsx)("option",{value:"new",children:e.t("bind.newDevice")}),u.map(g=>(0,a.jsxs)("option",{value:g.id,children:[g.name,g.paired?` \xB7 ${e.t("bind.replaces")}`:""]},g.id))]})]}),x==="new"&&(0,a.jsxs)("label",{className:"da-field",children:[(0,a.jsx)("span",{children:e.t("bind.name")}),(0,a.jsx)(m.Input,{value:O,onChange:g=>U(g.target.value),maxLength:100})]}),(0,a.jsx)("div",{className:"da-row",children:(0,a.jsx)(m.Btn,{primary:!0,disabled:c||!o?.id,onClick:()=>{_()},children:e.t(c?"bind.working":"bind.submit")})})]})}function et(e){let t=!1,r="",o=new Map,c=async()=>{if(t||e.signal.aborted)return;let s=e.core.context("server"),b=e.secureStorage.get(A,"");if(!(!s?.origin||!b||e.storage.get(Y,"on")==="off")&&!(Date.now()-(o.get(s.origin)??0)<qe)){t=!0;try{let v=e.storage.get(re,ne),d=await B.status(v,b);if(!d.machine_id||d.token_from_env)return;if(d.paired&&(d.unauthorized||V(d.server_url,s.origin))){r="";return}if(d.active_runs>0){r!==s.origin&&(r=s.origin,e.notify({title:e.t("page.title"),body:e.t("auto.deferred",{server:s.name||s.origin})}));return}let u=await e.core.request("/devices/machine/pairing-code",{method:"POST",body:JSON.stringify({machine_id:d.machine_id,hostname:d.hostname,platform:d.platform,current_device_id:d.paired?d.device_id:""})});await B.enroll(v,b,s.origin,u.code),r="",o.delete(s.origin),e.notify({title:e.t("page.title"),body:e.t("auto.done",{server:s.name||s.origin,device:u.device_name})})}catch(v){(!(v instanceof L)||v.kind==="rejected")&&o.set(s.origin,Date.now())}finally{t=!1}}},h=window.setInterval(()=>{c()},Ke);ee=()=>{c()},e.registerDisposer(()=>{window.clearInterval(h),ee=void 0}),e.registerDisposer(e.core.onContextChange("server",()=>{c()})),window.setTimeout(()=>{c()},1500)}function tt(e){let t=_e(e);!t||e.storage.get(G,"off")!=="on"||t.start().then(r=>{r.token&&e.secureStorage.set(A,r.token),window.setTimeout(()=>ee?.(),3e3)}).catch(()=>{})}var wt=me({activate(e){e.registerNavigation("agent.nav",(0,a.jsx)(Ye,{})),e.registerRoute("agent.home",(0,a.jsx)(Fe,{ctx:e})),tt(e),et(e)}});export{wt as default};
|
|
2
2
|
//# sourceMappingURL=renderer.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["toc-shared:react", "toc-shared:@toc-starter/plugin-sdk/ui", "toc-shared:react/jsx-runtime", "../../plugin/index.tsx", "../../node_modules/@toc-starter/plugin-sdk/index.js", "../../plugin/local.ts"],
|
|
4
|
-
"sourcesContent": ["var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"react\"];\nif (!shared) throw new Error(\"The host does not provide react; this plugin needs a newer app version.\");\nmodule.exports = shared;", "var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"@toc-starter/plugin-sdk/ui\"];\nif (!shared) throw new Error(\"The host does not provide @toc-starter/plugin-sdk/ui; this plugin needs a newer app version.\");\nmodule.exports = shared;", "var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"react/jsx-runtime\"];\nif (!shared) throw new Error(\"The host does not provide react/jsx-runtime; this plugin needs a newer app version.\");\nmodule.exports = shared;", "import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { definePlugin, useHostContext, type PluginContext } from \"@toc-starter/plugin-sdk\";\nimport { Badge, Btn, Card, CardTitle, Input, PageHeader } from \"@toc-starter/plugin-sdk/ui\";\nimport \"./styles.css\";\nimport { DEFAULT_LOCAL_URL, LocalError, local, sameServer, type LocalStatus } from \"./local\";\n\nconst TOKEN_KEY = \"controlToken\";\nconst LOCAL_URL_KEY = \"localUrl\";\nconst POLL_MS = 3_000;\n\n/** Resolved against dist/plugin/renderer.js. */\nconst iconUrl = new URL(\"../../assets/icon.svg\", import.meta.url).href;\n\ninterface ServerContext { kind: \"cloud\" | \"lan\"; name: string; origin: string }\ninterface WorkspaceContext { id: string; name: string }\ninterface Device { id: string; name: string; platform: string; paired: boolean; status: string; is_mine: boolean }\n\ntype Phase =\n | { kind: \"checking\" }\n | { kind: \"offline\" }\n | { kind: \"needsCode\" }\n | { kind: \"ready\"; status: LocalStatus };\n\nfunction Icon() {\n return <img src={iconUrl} alt=\"\" width={16} height={16} draggable={false} />;\n}\n\nfunction errorText(ctx: PluginContext, error: unknown): string {\n if (error instanceof LocalError && error.kind === \"offline\") return ctx.t(\"error.offline\");\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction Command({ ctx, value }: { ctx: PluginContext; value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"da-command\">\n <code>{value}</code>\n <Btn onClick={() => void navigator.clipboard.writeText(value).then(() => { setCopied(true); window.setTimeout(() => setCopied(false), 1500); })}>\n {copied ? ctx.t(\"common.copied\") : ctx.t(\"common.copy\")}\n </Btn>\n </div>\n );\n}\n\nfunction AgentPage({ ctx }: { ctx: PluginContext }) {\n const server = useHostContext<ServerContext>(ctx, \"server\");\n const workspace = useHostContext<WorkspaceContext>(ctx, \"workspace\");\n const [localUrl] = useState(() => ctx.storage.get(LOCAL_URL_KEY, DEFAULT_LOCAL_URL));\n const [token, setToken] = useState(() => ctx.secureStorage.get(TOKEN_KEY, \"\"));\n const [phase, setPhase] = useState<Phase>({ kind: \"checking\" });\n const [error, setError] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const alive = useRef(true);\n\n const refresh = useCallback(async () => {\n try {\n await local.info(localUrl);\n } catch {\n if (alive.current) setPhase({ kind: \"offline\" });\n return;\n }\n if (!token) {\n if (alive.current) setPhase({ kind: \"needsCode\" });\n return;\n }\n try {\n const status = await local.status(localUrl, token);\n if (alive.current) setPhase({ kind: \"ready\", status });\n } catch (reason) {\n if (!alive.current) return;\n if (reason instanceof LocalError && reason.kind === \"unauthorized\") {\n // The service was reinstalled (new control token): pair again.\n ctx.secureStorage.remove(TOKEN_KEY);\n setToken(\"\");\n setPhase({ kind: \"needsCode\" });\n } else {\n setPhase({ kind: \"offline\" });\n }\n }\n }, [ctx, localUrl, token]);\n\n useEffect(() => {\n alive.current = true;\n void refresh();\n const timer = window.setInterval(() => void refresh(), POLL_MS);\n return () => { alive.current = false; window.clearInterval(timer); };\n }, [refresh]);\n\n useEffect(() => {\n if (phase.kind === \"ready\") {\n const s = phase.status;\n ctx.reportHealth(s.paired && s.connected ? { status: \"healthy\", summary: ctx.t(\"health.online\", { name: s.device_name }) } : { status: \"degraded\", summary: ctx.t(s.paired ? \"health.disconnected\" : \"health.unpaired\") });\n } else if (phase.kind === \"offline\") {\n ctx.reportHealth({ status: \"degraded\", summary: ctx.t(\"health.offline\") });\n }\n }, [ctx, phase]);\n\n const run = async (action: () => Promise<void>) => {\n setBusy(true);\n setError(\"\");\n try {\n await action();\n } catch (reason) {\n setError(errorText(ctx, reason));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"da-app\">\n <PageHeader title={ctx.t(\"page.title\")} subtitle={ctx.t(\"page.subtitle\")} />\n {error && <div role=\"alert\" className=\"da-alert\">{error}</div>}\n {phase.kind === \"checking\" && <Card><span className=\"da-muted\">{ctx.t(\"common.checking\")}</span></Card>}\n {phase.kind === \"offline\" && <OfflineCard ctx={ctx} localUrl={localUrl} />}\n {phase.kind === \"needsCode\" && (\n <PairCard ctx={ctx} busy={busy} onPair={code => run(async () => {\n const result = await local.pair(localUrl, code).catch((reason: unknown) => {\n if (reason instanceof LocalError && reason.code === \"code_wrong\") throw new Error(ctx.t(\"pair.wrong\"));\n if (reason instanceof LocalError && reason.code === \"locked\") throw new Error(ctx.t(\"pair.locked\"));\n throw reason;\n });\n ctx.secureStorage.set(TOKEN_KEY, result.token);\n setToken(result.token);\n })} />\n )}\n {phase.kind === \"ready\" && (\n <ReadyView\n ctx={ctx}\n status={phase.status}\n server={server}\n workspace={workspace}\n busy={busy}\n run={run}\n localUrl={localUrl}\n token={token}\n onStatus={status => setPhase({ kind: \"ready\", status })}\n />\n )}\n </div>\n );\n}\n\nfunction OfflineCard({ ctx, localUrl }: { ctx: PluginContext; localUrl: string }) {\n return (\n <Card>\n <CardTitle>{ctx.t(\"offline.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"offline.body\", { url: localUrl })}</p>\n <div className=\"da-step\">{ctx.t(\"offline.once\")}</div>\n <Command ctx={ctx} value=\"npx toc-ocra@latest run\" />\n <div className=\"da-step\">{ctx.t(\"offline.service\")}</div>\n <Command ctx={ctx} value=\"npm install -g toc-ocra@latest && toc-ocra service:install\" />\n <p className=\"da-muted\">{ctx.t(\"offline.node\")}</p>\n </Card>\n );\n}\n\nfunction PairCard({ ctx, busy, onPair }: { ctx: PluginContext; busy: boolean; onPair: (code: string) => void }) {\n const [code, setCode] = useState(\"\");\n const valid = /^\\d{6}$/.test(code);\n return (\n <Card>\n <CardTitle>{ctx.t(\"pair.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"pair.body\")}</p>\n <Command ctx={ctx} value=\"toc-ocra code\" />\n <form className=\"da-row\" onSubmit={event => { event.preventDefault(); if (valid) onPair(code); }}>\n <Input\n value={code}\n onChange={event => setCode(event.target.value.replace(/\\D/g, \"\").slice(0, 6))}\n placeholder={ctx.t(\"pair.placeholder\")}\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n aria-label={ctx.t(\"pair.placeholder\")}\n className=\"da-code-input\"\n />\n <Btn primary type=\"submit\" disabled={!valid || busy}>{ctx.t(\"pair.submit\")}</Btn>\n </form>\n </Card>\n );\n}\n\nfunction ReadyView({ ctx, status, server, workspace, busy, run, localUrl, token, onStatus }: {\n ctx: PluginContext;\n status: LocalStatus;\n server: ServerContext | undefined;\n workspace: WorkspaceContext | undefined;\n busy: boolean;\n run: (action: () => Promise<void>) => Promise<void>;\n localUrl: string;\n token: string;\n onStatus: (status: LocalStatus) => void;\n}) {\n const boundElsewhere = status.paired && server && !sameServer(status.server_url, server.origin);\n const unpair = () => run(async () => {\n // Revoke on the server too when the device belongs to the server shown.\n if (status.device_id && server && sameServer(status.server_url, server.origin)) {\n await ctx.core.request(`/devices/${encodeURIComponent(status.device_id)}/agent`, { method: \"DELETE\" }).catch(() => undefined);\n }\n onStatus(await local.unpair(localUrl, token));\n });\n return (\n <>\n <Card>\n <CardTitle>{ctx.t(\"status.title\")}</CardTitle>\n <dl className=\"da-grid\">\n <div><dt>{ctx.t(\"status.service\")}</dt><dd>toc-ocra {status.version} \u00B7 {status.hostname}</dd></div>\n <div><dt>{ctx.t(\"status.binding\")}</dt><dd><BindingBadge ctx={ctx} status={status} /></dd></div>\n {status.paired && <div><dt>{ctx.t(\"status.device\")}</dt><dd>{status.device_name}</dd></div>}\n {status.paired && <div><dt>{ctx.t(\"status.server\")}</dt><dd className=\"da-mono\">{status.server_url}</dd></div>}\n {status.paired && <div><dt>{ctx.t(\"status.runs\")}</dt><dd>{status.active_runs}</dd></div>}\n </dl>\n {status.paired && !status.connected && status.connection_error && <p className=\"da-muted\">{ctx.t(\"status.lastError\", { error: status.connection_error })}</p>}\n {status.token_from_env && <p className=\"da-muted\">{ctx.t(\"status.tokenFromEnv\")}</p>}\n {status.paired && (\n <div className=\"da-row\">\n <Btn danger disabled={busy || status.token_from_env} onClick={() => void unpair()}>{ctx.t(\"status.unpair\")}</Btn>\n </div>\n )}\n </Card>\n\n {(!status.paired || status.unauthorized || boundElsewhere) && (\n <BindCard ctx={ctx} status={status} server={server} workspace={workspace} busy={busy} run={run} localUrl={localUrl} token={token} onStatus={onStatus} rebind={status.paired} />\n )}\n\n <Card>\n <CardTitle>{ctx.t(\"cli.title\")}</CardTitle>\n <ul className=\"da-list\">\n {status.providers.filter(provider => provider.installed).map(provider => (\n <li key={provider.id}>\n <span className=\"da-mono\">{provider.id}</span>\n <span className=\"da-muted\">{provider.version}</span>\n {provider.runnable ? <Badge variant=\"ok\">{ctx.t(\"cli.runnable\")}</Badge> : <Badge variant=\"muted\">{ctx.t(\"cli.detectOnly\")}</Badge>}\n </li>\n ))}\n {!status.providers.some(provider => provider.installed) && <li className=\"da-muted\">{ctx.t(\"cli.none\")}</li>}\n </ul>\n <div className=\"da-row\">\n <Btn disabled={busy} onClick={() => void run(async () => onStatus(await local.detect(localUrl, token)))}>{ctx.t(\"cli.redetect\")}</Btn>\n </div>\n </Card>\n </>\n );\n}\n\nfunction BindingBadge({ ctx, status }: { ctx: PluginContext; status: LocalStatus }) {\n if (!status.paired) return <Badge variant=\"muted\">{ctx.t(\"binding.unpaired\")}</Badge>;\n if (status.unauthorized) return <Badge variant=\"err\">{ctx.t(\"binding.revoked\")}</Badge>;\n if (status.connected) return <Badge variant=\"ok\">{ctx.t(\"binding.online\")}</Badge>;\n return <Badge variant=\"warn\">{ctx.t(\"binding.connecting\")}</Badge>;\n}\n\nfunction BindCard({ ctx, status, server, workspace, busy, run, localUrl, token, onStatus, rebind }: {\n ctx: PluginContext;\n status: LocalStatus;\n server: ServerContext | undefined;\n workspace: WorkspaceContext | undefined;\n busy: boolean;\n run: (action: () => Promise<void>) => Promise<void>;\n localUrl: string;\n token: string;\n onStatus: (status: LocalStatus) => void;\n rebind: boolean;\n}) {\n const [devices, setDevices] = useState<Device[]>([]);\n const [choice, setChoice] = useState(\"new\");\n const [name, setName] = useState(status.hostname);\n const [serverUrl, setServerUrl] = useState(server?.origin ?? \"\");\n useEffect(() => { if (server?.origin) setServerUrl(server.origin); }, [server?.origin]);\n\n useEffect(() => {\n if (!workspace?.id) return;\n let cancelled = false;\n ctx.core.request<{ items?: Device[] }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`)\n .then(result => { if (!cancelled) setDevices((result.items ?? []).filter(device => device.is_mine)); })\n .catch(() => { if (!cancelled) setDevices([]); });\n return () => { cancelled = true; };\n }, [ctx, workspace?.id]);\n\n const bind = () => run(async () => {\n if (!workspace?.id) throw new Error(ctx.t(\"bind.noWorkspace\"));\n if (!serverUrl.trim()) throw new Error(ctx.t(\"bind.noServer\"));\n let deviceId = choice;\n if (choice === \"new\") {\n const created = await ctx.core.request<{ id: string }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`, {\n method: \"POST\",\n body: JSON.stringify({ name: name.trim() || status.hostname, location: \"local\", platform: status.platform, note: \"\", share_to_workspace: false }),\n });\n deviceId = created.id;\n setChoice(deviceId);\n }\n const pairing = await ctx.core.request<{ code: string }>(`/devices/${encodeURIComponent(deviceId)}/pairing-code`, { method: \"POST\" });\n onStatus(await local.enroll(localUrl, token, serverUrl.trim(), pairing.code));\n ctx.notify({ title: ctx.t(\"page.title\"), body: ctx.t(\"bind.done\", { server: server?.name ?? serverUrl }) });\n });\n\n return (\n <Card>\n <CardTitle>{ctx.t(rebind ? \"bind.rebindTitle\" : \"bind.title\")}</CardTitle>\n {rebind && status.unauthorized && <p className=\"da-text\">{ctx.t(\"bind.revoked\")}</p>}\n {rebind && !status.unauthorized && <p className=\"da-text\">{ctx.t(\"bind.elsewhere\", { bound: status.server_url, current: server?.origin ?? \"\" })}</p>}\n <p className=\"da-text\">{ctx.t(\"bind.body\", { server: server?.name ?? \"\", workspace: workspace?.name ?? \"\" })}</p>\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.server\")}</span>\n <Input value={serverUrl} onChange={event => setServerUrl(event.target.value)} spellCheck={false} className=\"da-mono\" />\n </label>\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.device\")}</span>\n <select className=\"da-select\" value={choice} onChange={event => setChoice(event.target.value)}>\n <option value=\"new\">{ctx.t(\"bind.newDevice\")}</option>\n {devices.map(device => (\n <option key={device.id} value={device.id}>{device.name}{device.paired ? ` \u00B7 ${ctx.t(\"bind.replaces\")}` : \"\"}</option>\n ))}\n </select>\n </label>\n {choice === \"new\" && (\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.name\")}</span>\n <Input value={name} onChange={event => setName(event.target.value)} maxLength={100} />\n </label>\n )}\n <div className=\"da-row\">\n <Btn primary disabled={busy || !workspace?.id} onClick={() => void bind()}>{ctx.t(busy ? \"bind.working\" : \"bind.submit\")}</Btn>\n </div>\n </Card>\n );\n}\n\nexport default definePlugin({\n activate(ctx) {\n ctx.registerNavigation(\"agent.nav\", <Icon />);\n ctx.registerRoute(\"agent.home\", <AgentPage ctx={ctx} />);\n },\n});\n", "/**\n * Runtime part of the SDK that ends up inside plugin bundles. Keep it tiny:\n * everything here is copied into every plugin. Build-time helpers live in lib/.\n * `react` resolves to the host's instance through `toc-plugin build`.\n */\nimport { useSyncExternalStore } from \"react\";\n\n/** Host contract this SDK targets. Must match PLUGIN_API_VERSION in lib/constants.mjs. */\nexport const PLUGIN_API_VERSION = \"1.0.0\";\n\n/**\n * Identity helper that gives a plugin module full type inference.\n *\n * @template {import(\"./index\").PluginModule} T\n * @param {T} plugin\n * @returns {T}\n */\nexport function definePlugin(plugin) {\n if (!plugin || typeof plugin.activate !== \"function\") {\n throw new TypeError(\"definePlugin() needs an object with an activate(context) function\");\n }\n return plugin;\n}\n\n/**\n * Re-renders when the app publishes a new value under `key`.\n *\n * @template T\n * @param {import(\"./index\").PluginContext} ctx\n * @param {string} key\n * @returns {T | undefined}\n */\nexport function useHostContext(ctx, key) {\n return useSyncExternalStore(\n listener => ctx.core.onContextChange(key, listener),\n () => ctx.core.context(key),\n );\n}\n", "/**\n * Client for the local toc-ocra service (`toc-ocra run`) on this computer.\n * The plugin pairs once with the 6-digit connection code and then sends the\n * control token as a bearer token.\n */\nexport const DEFAULT_LOCAL_URL = \"http://127.0.0.1:17339\";\n\nexport interface LocalInfo {\n name: string;\n version: string;\n protocol: number;\n paired: boolean;\n}\n\nexport interface LocalProvider {\n id: string;\n installed: boolean;\n runnable: boolean;\n version: string;\n}\n\nexport interface LocalStatus {\n version: string;\n hostname: string;\n platform: \"mac\" | \"win\" | \"linux\";\n paired: boolean;\n running: boolean;\n device_id: string;\n device_name: string;\n server_url: string;\n connected: boolean;\n unauthorized: boolean;\n connection_error: string;\n active_runs: number;\n allowed_roots: string[];\n token_from_env: boolean;\n providers: LocalProvider[];\n}\n\n/** Why a local call failed: the service is not running, the token is not accepted, or the service said no. */\nexport class LocalError extends Error {\n constructor(readonly kind: \"offline\" | \"unauthorized\" | \"rejected\", message: string, readonly code = \"\") {\n super(message);\n }\n}\n\nasync function call<T>(base: string, path: string, init: RequestInit & { token?: string } = {}): Promise<T> {\n const headers = new Headers(init.headers);\n if (init.token) headers.set(\"Authorization\", `Bearer ${init.token}`);\n if (init.body) headers.set(\"Content-Type\", \"application/json\");\n let response: Response;\n try {\n response = await fetch(`${base.replace(/\\/+$/, \"\")}${path}`, { ...init, headers, cache: \"no-store\" });\n } catch {\n throw new LocalError(\"offline\", \"local service unreachable\");\n }\n const body = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n if (response.status === 401) throw new LocalError(\"unauthorized\", \"unauthorized\");\n if (!response.ok) {\n const code = typeof body?.error === \"string\" ? body.error : \"\";\n const message = typeof body?.message === \"string\" ? body.message : code || `HTTP ${response.status}`;\n throw new LocalError(\"rejected\", message, code);\n }\n return body as T;\n}\n\nexport const local = {\n info: (base: string) => call<LocalInfo>(base, \"/control/info\"),\n pair: (base: string, code: string) => call<{ token: string }>(base, \"/control/pair\", { method: \"POST\", body: JSON.stringify({ code }) }),\n status: (base: string, token: string) => call<LocalStatus>(base, \"/control/status\", { token }),\n enroll: (base: string, token: string, serverUrl: string, code: string) =>\n call<LocalStatus>(base, \"/control/enroll\", { method: \"POST\", token, body: JSON.stringify({ server_url: serverUrl, code }) }),\n unpair: (base: string, token: string) => call<LocalStatus>(base, \"/control/unpair\", { method: \"POST\", token }),\n detect: (base: string, token: string) => call<LocalStatus>(base, \"/control/detect\", { method: \"POST\", token }),\n};\n\n/** Two backend addresses name the same server (trailing slash and case insensitive). */\nexport function sameServer(left: string, right: string): boolean {\n const normalize = (value: string) => {\n try {\n return new URL(value).origin.toLowerCase();\n } catch {\n return value.trim().replace(/\\/+$/, \"\").toLowerCase();\n }\n };\n return Boolean(left && right) && normalize(left) === normalize(right);\n}\n"],
|
|
5
|
-
"mappings": "8iBAAA,IAAAA,EAAAC,EAAA,CAAAC,GAAAC,IAAA,KAAIC,EAAW,WAAW,sBACtBC,EAASD,GAAYA,EAAS,MAClC,GAAI,CAACC,EAAQ,MAAM,IAAI,MAAM,yEAAyE,EACtGF,EAAO,QAAUE,ICHjB,IAAAC,EAAAC,EAAA,CAAAC,GAAAC,IAAA,KAAIC,EAAW,WAAW,sBACtBC,EAASD,GAAYA,EAAS,4BAA4B,EAC9D,GAAI,CAACC,EAAQ,MAAM,IAAI,MAAM,8FAA8F,EAC3HF,EAAO,QAAUE,ICHjB,IAAAC,EAAAC,EAAA,CAAAC,GAAAC,IAAA,KAAIC,EAAW,WAAW,sBACtBC,EAASD,GAAYA,EAAS,mBAAmB,EACrD,GAAI,CAACC,EAAQ,MAAM,IAAI,MAAM,qFAAqF,EAClHF,EAAO,QAAUE,ICHjB,IAAAC,EAAyD,SCKzD,IAAAC,EAAqC,SAY9B,SAASC,EAAaC,EAAQ,CACnC,GAAI,CAACA,GAAU,OAAOA,EAAO,UAAa,WACxC,MAAM,IAAI,UAAU,mEAAmE,EAEzF,OAAOA,CACT,CAUO,SAASC,EAAeC,EAAKC,EAAK,CACvC,SAAO,wBACLC,GAAYF,EAAI,KAAK,gBAAgBC,EAAKC,CAAQ,EAClD,IAAMF,EAAI,KAAK,QAAQC,CAAG,CAC5B,CACF,CDnCA,IAAAE,EAA+D,SEGxD,IAAMC,EAAoB,yBAmCpBC,EAAN,cAAyB,KAAM,CACpC,YAAqBC,EAA+CC,EAA0BC,EAAO,GAAI,CACvG,MAAMD,CAAO,EADM,UAAAD,EAAyE,UAAAE,CAE9F,CAFqB,KAAyE,IAGhG,EAEA,eAAeC,EAAQC,EAAcC,EAAcC,EAAyC,CAAC,EAAe,CAC1G,IAAMC,EAAU,IAAI,QAAQD,EAAK,OAAO,EACpCA,EAAK,OAAOC,EAAQ,IAAI,gBAAiB,UAAUD,EAAK,KAAK,EAAE,EAC/DA,EAAK,MAAMC,EAAQ,IAAI,eAAgB,kBAAkB,EAC7D,IAAIC,EACJ,GAAI,CACFA,EAAW,MAAM,MAAM,GAAGJ,EAAK,QAAQ,OAAQ,EAAE,CAAC,GAAGC,CAAI,GAAI,CAAE,GAAGC,EAAM,QAAAC,EAAS,MAAO,UAAW,CAAC,CACtG,MAAQ,CACN,MAAM,IAAIR,EAAW,UAAW,2BAA2B,CAC7D,CACA,IAAMU,EAAQ,MAAMD,EAAS,KAAK,EAAE,MAAM,IAAM,IAAI,EACpD,GAAIA,EAAS,SAAW,IAAK,MAAM,IAAIT,EAAW,eAAgB,cAAc,EAChF,GAAI,CAACS,EAAS,GAAI,CAChB,IAAMN,EAAO,OAAOO,GAAM,OAAU,SAAWA,EAAK,MAAQ,GACtDR,EAAU,OAAOQ,GAAM,SAAY,SAAWA,EAAK,QAAUP,GAAQ,QAAQM,EAAS,MAAM,GAClG,MAAM,IAAIT,EAAW,WAAYE,EAASC,CAAI,CAChD,CACA,OAAOO,CACT,CAEO,IAAMC,EAAQ,CACnB,KAAON,GAAiBD,EAAgBC,EAAM,eAAe,EAC7D,KAAM,CAACA,EAAcF,IAAiBC,EAAwBC,EAAM,gBAAiB,CAAE,OAAQ,OAAQ,KAAM,KAAK,UAAU,CAAE,KAAAF,CAAK,CAAC,CAAE,CAAC,EACvI,OAAQ,CAACE,EAAcO,IAAkBR,EAAkBC,EAAM,kBAAmB,CAAE,MAAAO,CAAM,CAAC,EAC7F,OAAQ,CAACP,EAAcO,EAAeC,EAAmBV,IACvDC,EAAkBC,EAAM,kBAAmB,CAAE,OAAQ,OAAQ,MAAAO,EAAO,KAAM,KAAK,UAAU,CAAE,WAAYC,EAAW,KAAAV,CAAK,CAAC,CAAE,CAAC,EAC7H,OAAQ,CAACE,EAAcO,IAAkBR,EAAkBC,EAAM,kBAAmB,CAAE,OAAQ,OAAQ,MAAAO,CAAM,CAAC,EAC7G,OAAQ,CAACP,EAAcO,IAAkBR,EAAkBC,EAAM,kBAAmB,CAAE,OAAQ,OAAQ,MAAAO,CAAM,CAAC,CAC/G,EAGO,SAASE,EAAWC,EAAcC,EAAwB,CAC/D,IAAMC,EAAaC,GAAkB,CACnC,GAAI,CACF,OAAO,IAAI,IAAIA,CAAK,EAAE,OAAO,YAAY,CAC3C,MAAQ,CACN,OAAOA,EAAM,KAAK,EAAE,QAAQ,OAAQ,EAAE,EAAE,YAAY,CACtD,CACF,EACA,MAAO,GAAQH,GAAQC,IAAUC,EAAUF,CAAI,IAAME,EAAUD,CAAK,CACtE,CF9DS,IAAAG,EAAA,SAlBHC,EAAY,eACZC,GAAgB,WAChBC,GAAU,IAGVC,GAAU,IAAI,IAAI,wBAAyB,YAAY,GAAG,EAAE,KAYlE,SAASC,IAAO,CACd,SAAO,OAAC,OAAI,IAAKD,GAAS,IAAI,GAAG,MAAO,GAAI,OAAQ,GAAI,UAAW,GAAO,CAC5E,CAEA,SAASE,GAAUC,EAAoBC,EAAwB,CAC7D,OAAIA,aAAiBC,GAAcD,EAAM,OAAS,UAAkBD,EAAI,EAAE,eAAe,EAClFC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CAEA,SAASE,EAAQ,CAAE,IAAAH,EAAK,MAAAI,CAAM,EAA0C,CACtE,GAAM,CAACC,EAAQC,CAAS,KAAI,YAAS,EAAK,EAC1C,SACE,QAAC,OAAI,UAAU,aACb,oBAAC,QAAM,SAAAF,EAAM,KACb,OAAC,OAAI,QAAS,IAAG,CAAQ,UAAU,UAAU,UAAUA,CAAK,EAAE,KAAK,IAAM,CAAEE,EAAU,EAAI,EAAG,OAAO,WAAW,IAAMA,EAAU,EAAK,EAAG,IAAI,CAAG,CAAC,GAC3I,SAAAD,EAASL,EAAI,EAAE,eAAe,EAAIA,EAAI,EAAE,aAAa,EACxD,GACF,CAEJ,CAEA,SAASO,GAAU,CAAE,IAAAP,CAAI,EAA2B,CAClD,IAAMQ,EAASC,EAA8BT,EAAK,QAAQ,EACpDU,EAAYD,EAAiCT,EAAK,WAAW,EAC7D,CAACW,CAAQ,KAAI,YAAS,IAAMX,EAAI,QAAQ,IAAIL,GAAeiB,CAAiB,CAAC,EAC7E,CAACC,EAAOC,CAAQ,KAAI,YAAS,IAAMd,EAAI,cAAc,IAAIN,EAAW,EAAE,CAAC,EACvE,CAACqB,EAAOC,CAAQ,KAAI,YAAgB,CAAE,KAAM,UAAW,CAAC,EACxD,CAACf,EAAOgB,CAAQ,KAAI,YAAS,EAAE,EAC/B,CAACC,EAAMC,CAAO,KAAI,YAAS,EAAK,EAChCC,KAAQ,UAAO,EAAI,EAEnBC,KAAU,eAAY,SAAY,CACtC,GAAI,CACF,MAAMC,EAAM,KAAKX,CAAQ,CAC3B,MAAQ,CACFS,EAAM,SAASJ,EAAS,CAAE,KAAM,SAAU,CAAC,EAC/C,MACF,CACA,GAAI,CAACH,EAAO,CACNO,EAAM,SAASJ,EAAS,CAAE,KAAM,WAAY,CAAC,EACjD,MACF,CACA,GAAI,CACF,IAAMO,EAAS,MAAMD,EAAM,OAAOX,EAAUE,CAAK,EAC7CO,EAAM,SAASJ,EAAS,CAAE,KAAM,QAAS,OAAAO,CAAO,CAAC,CACvD,OAASC,EAAQ,CACf,GAAI,CAACJ,EAAM,QAAS,OAChBI,aAAkBtB,GAAcsB,EAAO,OAAS,gBAElDxB,EAAI,cAAc,OAAON,CAAS,EAClCoB,EAAS,EAAE,EACXE,EAAS,CAAE,KAAM,WAAY,CAAC,GAE9BA,EAAS,CAAE,KAAM,SAAU,CAAC,CAEhC,CACF,EAAG,CAAChB,EAAKW,EAAUE,CAAK,CAAC,KAEzB,aAAU,IAAM,CACdO,EAAM,QAAU,GACXC,EAAQ,EACb,IAAMI,EAAQ,OAAO,YAAY,IAAG,CAAQJ,EAAQ,GAAGzB,EAAO,EAC9D,MAAO,IAAM,CAAEwB,EAAM,QAAU,GAAO,OAAO,cAAcK,CAAK,CAAG,CACrE,EAAG,CAACJ,CAAO,CAAC,KAEZ,aAAU,IAAM,CACd,GAAIN,EAAM,OAAS,QAAS,CAC1B,IAAMW,EAAIX,EAAM,OAChBf,EAAI,aAAa0B,EAAE,QAAUA,EAAE,UAAY,CAAE,OAAQ,UAAW,QAAS1B,EAAI,EAAE,gBAAiB,CAAE,KAAM0B,EAAE,WAAY,CAAC,CAAE,EAAI,CAAE,OAAQ,WAAY,QAAS1B,EAAI,EAAE0B,EAAE,OAAS,sBAAwB,iBAAiB,CAAE,CAAC,CAC3N,MAAWX,EAAM,OAAS,WACxBf,EAAI,aAAa,CAAE,OAAQ,WAAY,QAASA,EAAI,EAAE,gBAAgB,CAAE,CAAC,CAE7E,EAAG,CAACA,EAAKe,CAAK,CAAC,EAEf,IAAMY,EAAM,MAAOC,GAAgC,CACjDT,EAAQ,EAAI,EACZF,EAAS,EAAE,EACX,GAAI,CACF,MAAMW,EAAO,CACf,OAASJ,EAAQ,CACfP,EAASlB,GAAUC,EAAKwB,CAAM,CAAC,CACjC,QAAE,CACAL,EAAQ,EAAK,CACf,CACF,EAEA,SACE,QAAC,OAAI,UAAU,SACb,oBAAC,cAAW,MAAOnB,EAAI,EAAE,YAAY,EAAG,SAAUA,EAAI,EAAE,eAAe,EAAG,EACzEC,MAAS,OAAC,OAAI,KAAK,QAAQ,UAAU,WAAY,SAAAA,EAAM,EACvDc,EAAM,OAAS,eAAc,OAAC,QAAK,mBAAC,QAAK,UAAU,WAAY,SAAAf,EAAI,EAAE,iBAAiB,EAAE,EAAO,EAC/Fe,EAAM,OAAS,cAAa,OAACc,GAAA,CAAY,IAAK7B,EAAK,SAAUW,EAAU,EACvEI,EAAM,OAAS,gBACd,OAACe,GAAA,CAAS,IAAK9B,EAAK,KAAMkB,EAAM,OAAQa,GAAQJ,EAAI,SAAY,CAC9D,IAAMK,EAAS,MAAMV,EAAM,KAAKX,EAAUoB,CAAI,EAAE,MAAOP,GAAoB,CACzE,MAAIA,aAAkBtB,GAAcsB,EAAO,OAAS,aAAoB,IAAI,MAAMxB,EAAI,EAAE,YAAY,CAAC,EACjGwB,aAAkBtB,GAAcsB,EAAO,OAAS,SAAgB,IAAI,MAAMxB,EAAI,EAAE,aAAa,CAAC,EAC5FwB,CACR,CAAC,EACDxB,EAAI,cAAc,IAAIN,EAAWsC,EAAO,KAAK,EAC7ClB,EAASkB,EAAO,KAAK,CACvB,CAAC,EAAG,EAELjB,EAAM,OAAS,YACd,OAACkB,GAAA,CACC,IAAKjC,EACL,OAAQe,EAAM,OACd,OAAQP,EACR,UAAWE,EACX,KAAMQ,EACN,IAAKS,EACL,SAAUhB,EACV,MAAOE,EACP,SAAUU,GAAUP,EAAS,CAAE,KAAM,QAAS,OAAAO,CAAO,CAAC,EACxD,GAEJ,CAEJ,CAEA,SAASM,GAAY,CAAE,IAAA7B,EAAK,SAAAW,CAAS,EAA6C,CAChF,SACE,QAAC,QACC,oBAAC,aAAW,SAAAX,EAAI,EAAE,eAAe,EAAE,KACnC,OAAC,KAAE,UAAU,UAAW,SAAAA,EAAI,EAAE,eAAgB,CAAE,IAAKW,CAAS,CAAC,EAAE,KACjE,OAAC,OAAI,UAAU,UAAW,SAAAX,EAAI,EAAE,cAAc,EAAE,KAChD,OAACG,EAAA,CAAQ,IAAKH,EAAK,MAAM,0BAA0B,KACnD,OAAC,OAAI,UAAU,UAAW,SAAAA,EAAI,EAAE,iBAAiB,EAAE,KACnD,OAACG,EAAA,CAAQ,IAAKH,EAAK,MAAM,6DAA6D,KACtF,OAAC,KAAE,UAAU,WAAY,SAAAA,EAAI,EAAE,cAAc,EAAE,GACjD,CAEJ,CAEA,SAAS8B,GAAS,CAAE,IAAA9B,EAAK,KAAAkB,EAAM,OAAAgB,CAAO,EAA0E,CAC9G,GAAM,CAACH,EAAMI,CAAO,KAAI,YAAS,EAAE,EAC7BC,EAAQ,UAAU,KAAKL,CAAI,EACjC,SACE,QAAC,QACC,oBAAC,aAAW,SAAA/B,EAAI,EAAE,YAAY,EAAE,KAChC,OAAC,KAAE,UAAU,UAAW,SAAAA,EAAI,EAAE,WAAW,EAAE,KAC3C,OAACG,EAAA,CAAQ,IAAKH,EAAK,MAAM,gBAAgB,KACzC,QAAC,QAAK,UAAU,SAAS,SAAUqC,GAAS,CAAEA,EAAM,eAAe,EAAOD,GAAOF,EAAOH,CAAI,CAAG,EAC7F,oBAAC,SACC,MAAOA,EACP,SAAUM,GAASF,EAAQE,EAAM,OAAO,MAAM,QAAQ,MAAO,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,EAC5E,YAAarC,EAAI,EAAE,kBAAkB,EACrC,UAAU,UACV,aAAa,gBACb,aAAYA,EAAI,EAAE,kBAAkB,EACpC,UAAU,gBACZ,KACA,OAAC,OAAI,QAAO,GAAC,KAAK,SAAS,SAAU,CAACoC,GAASlB,EAAO,SAAAlB,EAAI,EAAE,aAAa,EAAE,GAC7E,GACF,CAEJ,CAEA,SAASiC,GAAU,CAAE,IAAAjC,EAAK,OAAAuB,EAAQ,OAAAf,EAAQ,UAAAE,EAAW,KAAAQ,EAAM,IAAAS,EAAK,SAAAhB,EAAU,MAAAE,EAAO,SAAAyB,CAAS,EAUvF,CACD,IAAMC,EAAiBhB,EAAO,QAAUf,GAAU,CAACgC,EAAWjB,EAAO,WAAYf,EAAO,MAAM,EACxFiC,EAAS,IAAMd,EAAI,SAAY,CAE/BJ,EAAO,WAAaf,GAAUgC,EAAWjB,EAAO,WAAYf,EAAO,MAAM,GAC3E,MAAMR,EAAI,KAAK,QAAQ,YAAY,mBAAmBuB,EAAO,SAAS,CAAC,SAAU,CAAE,OAAQ,QAAS,CAAC,EAAE,MAAM,IAAG,EAAY,EAE9He,EAAS,MAAMhB,EAAM,OAAOX,EAAUE,CAAK,CAAC,CAC9C,CAAC,EACD,SACE,oBACE,qBAAC,QACC,oBAAC,aAAW,SAAAb,EAAI,EAAE,cAAc,EAAE,KAClC,QAAC,MAAG,UAAU,UACZ,qBAAC,OAAI,oBAAC,MAAI,SAAAA,EAAI,EAAE,gBAAgB,EAAE,KAAK,QAAC,MAAG,sBAAUuB,EAAO,QAAQ,SAAIA,EAAO,UAAS,GAAK,KAC7F,QAAC,OAAI,oBAAC,MAAI,SAAAvB,EAAI,EAAE,gBAAgB,EAAE,KAAK,OAAC,MAAG,mBAAC0C,GAAA,CAAa,IAAK1C,EAAK,OAAQuB,EAAQ,EAAE,GAAK,EACzFA,EAAO,WAAU,QAAC,OAAI,oBAAC,MAAI,SAAAvB,EAAI,EAAE,eAAe,EAAE,KAAK,OAAC,MAAI,SAAAuB,EAAO,YAAY,GAAK,EACpFA,EAAO,WAAU,QAAC,OAAI,oBAAC,MAAI,SAAAvB,EAAI,EAAE,eAAe,EAAE,KAAK,OAAC,MAAG,UAAU,UAAW,SAAAuB,EAAO,WAAW,GAAK,EACvGA,EAAO,WAAU,QAAC,OAAI,oBAAC,MAAI,SAAAvB,EAAI,EAAE,aAAa,EAAE,KAAK,OAAC,MAAI,SAAAuB,EAAO,YAAY,GAAK,GACrF,EACCA,EAAO,QAAU,CAACA,EAAO,WAAaA,EAAO,qBAAoB,OAAC,KAAE,UAAU,WAAY,SAAAvB,EAAI,EAAE,mBAAoB,CAAE,MAAOuB,EAAO,gBAAiB,CAAC,EAAE,EACxJA,EAAO,mBAAkB,OAAC,KAAE,UAAU,WAAY,SAAAvB,EAAI,EAAE,qBAAqB,EAAE,EAC/EuB,EAAO,WACN,OAAC,OAAI,UAAU,SACb,mBAAC,OAAI,OAAM,GAAC,SAAUL,GAAQK,EAAO,eAAgB,QAAS,IAAG,CAAQkB,EAAO,GAAI,SAAAzC,EAAI,EAAE,eAAe,EAAE,EAC7G,GAEJ,GAEE,CAACuB,EAAO,QAAUA,EAAO,cAAgBgB,OACzC,OAACI,GAAA,CAAS,IAAK3C,EAAK,OAAQuB,EAAQ,OAAQf,EAAQ,UAAWE,EAAW,KAAMQ,EAAM,IAAKS,EAAK,SAAUhB,EAAU,MAAOE,EAAO,SAAUyB,EAAU,OAAQf,EAAO,OAAQ,KAG/K,QAAC,QACC,oBAAC,aAAW,SAAAvB,EAAI,EAAE,WAAW,EAAE,KAC/B,QAAC,MAAG,UAAU,UACX,UAAAuB,EAAO,UAAU,OAAOqB,GAAYA,EAAS,SAAS,EAAE,IAAIA,MAC3D,QAAC,MACC,oBAAC,QAAK,UAAU,UAAW,SAAAA,EAAS,GAAG,KACvC,OAAC,QAAK,UAAU,WAAY,SAAAA,EAAS,QAAQ,EAC5CA,EAAS,YAAW,OAAC,SAAM,QAAQ,KAAM,SAAA5C,EAAI,EAAE,cAAc,EAAE,KAAW,OAAC,SAAM,QAAQ,QAAS,SAAAA,EAAI,EAAE,gBAAgB,EAAE,IAHpH4C,EAAS,EAIlB,CACD,EACA,CAACrB,EAAO,UAAU,KAAKqB,GAAYA,EAAS,SAAS,MAAK,OAAC,MAAG,UAAU,WAAY,SAAA5C,EAAI,EAAE,UAAU,EAAE,GACzG,KACA,OAAC,OAAI,UAAU,SACb,mBAAC,OAAI,SAAUkB,EAAM,QAAS,IAAG,CAAQS,EAAI,SAAYW,EAAS,MAAMhB,EAAM,OAAOX,EAAUE,CAAK,CAAC,CAAC,GAAI,SAAAb,EAAI,EAAE,cAAc,EAAE,EAClI,GACF,GACF,CAEJ,CAEA,SAAS0C,GAAa,CAAE,IAAA1C,EAAK,OAAAuB,CAAO,EAAgD,CAClF,OAAKA,EAAO,OACRA,EAAO,gBAAqB,OAAC,SAAM,QAAQ,MAAO,SAAAvB,EAAI,EAAE,iBAAiB,EAAE,EAC3EuB,EAAO,aAAkB,OAAC,SAAM,QAAQ,KAAM,SAAAvB,EAAI,EAAE,gBAAgB,EAAE,KACnE,OAAC,SAAM,QAAQ,OAAQ,SAAAA,EAAI,EAAE,oBAAoB,EAAE,KAH/B,OAAC,SAAM,QAAQ,QAAS,SAAAA,EAAI,EAAE,kBAAkB,EAAE,CAI/E,CAEA,SAAS2C,GAAS,CAAE,IAAA3C,EAAK,OAAAuB,EAAQ,OAAAf,EAAQ,UAAAE,EAAW,KAAAQ,EAAM,IAAAS,EAAK,SAAAhB,EAAU,MAAAE,EAAO,SAAAyB,EAAU,OAAAO,CAAO,EAW9F,CACD,GAAM,CAACC,EAASC,CAAU,KAAI,YAAmB,CAAC,CAAC,EAC7C,CAACC,EAAQC,CAAS,KAAI,YAAS,KAAK,EACpC,CAACC,EAAMC,CAAO,KAAI,YAAS5B,EAAO,QAAQ,EAC1C,CAAC6B,EAAWC,CAAY,KAAI,YAAS7C,GAAQ,QAAU,EAAE,KAC/D,aAAU,IAAM,CAAMA,GAAQ,QAAQ6C,EAAa7C,EAAO,MAAM,CAAG,EAAG,CAACA,GAAQ,MAAM,CAAC,KAEtF,aAAU,IAAM,CACd,GAAI,CAACE,GAAW,GAAI,OACpB,IAAI4C,EAAY,GAChB,OAAAtD,EAAI,KAAK,QAA8B,eAAe,mBAAmBU,EAAU,EAAE,CAAC,UAAU,EAC7F,KAAKsB,GAAU,CAAOsB,GAAWP,GAAYf,EAAO,OAAS,CAAC,GAAG,OAAOuB,GAAUA,EAAO,OAAO,CAAC,CAAG,CAAC,EACrG,MAAM,IAAM,CAAOD,GAAWP,EAAW,CAAC,CAAC,CAAG,CAAC,EAC3C,IAAM,CAAEO,EAAY,EAAM,CACnC,EAAG,CAACtD,EAAKU,GAAW,EAAE,CAAC,EAEvB,IAAM8C,EAAO,IAAM7B,EAAI,SAAY,CACjC,GAAI,CAACjB,GAAW,GAAI,MAAM,IAAI,MAAMV,EAAI,EAAE,kBAAkB,CAAC,EAC7D,GAAI,CAACoD,EAAU,KAAK,EAAG,MAAM,IAAI,MAAMpD,EAAI,EAAE,eAAe,CAAC,EAC7D,IAAIyD,EAAWT,EACXA,IAAW,QAKbS,GAJgB,MAAMzD,EAAI,KAAK,QAAwB,eAAe,mBAAmBU,EAAU,EAAE,CAAC,WAAY,CAChH,OAAQ,OACR,KAAM,KAAK,UAAU,CAAE,KAAMwC,EAAK,KAAK,GAAK3B,EAAO,SAAU,SAAU,QAAS,SAAUA,EAAO,SAAU,KAAM,GAAI,mBAAoB,EAAM,CAAC,CAClJ,CAAC,GACkB,GACnB0B,EAAUQ,CAAQ,GAEpB,IAAMC,EAAU,MAAM1D,EAAI,KAAK,QAA0B,YAAY,mBAAmByD,CAAQ,CAAC,gBAAiB,CAAE,OAAQ,MAAO,CAAC,EACpInB,EAAS,MAAMhB,EAAM,OAAOX,EAAUE,EAAOuC,EAAU,KAAK,EAAGM,EAAQ,IAAI,CAAC,EAC5E1D,EAAI,OAAO,CAAE,MAAOA,EAAI,EAAE,YAAY,EAAG,KAAMA,EAAI,EAAE,YAAa,CAAE,OAAQQ,GAAQ,MAAQ4C,CAAU,CAAC,CAAE,CAAC,CAC5G,CAAC,EAED,SACE,QAAC,QACC,oBAAC,aAAW,SAAApD,EAAI,EAAE6C,EAAS,mBAAqB,YAAY,EAAE,EAC7DA,GAAUtB,EAAO,iBAAgB,OAAC,KAAE,UAAU,UAAW,SAAAvB,EAAI,EAAE,cAAc,EAAE,EAC/E6C,GAAU,CAACtB,EAAO,iBAAgB,OAAC,KAAE,UAAU,UAAW,SAAAvB,EAAI,EAAE,iBAAkB,CAAE,MAAOuB,EAAO,WAAY,QAASf,GAAQ,QAAU,EAAG,CAAC,EAAE,KAChJ,OAAC,KAAE,UAAU,UAAW,SAAAR,EAAI,EAAE,YAAa,CAAE,OAAQQ,GAAQ,MAAQ,GAAI,UAAWE,GAAW,MAAQ,EAAG,CAAC,EAAE,KAC7G,QAAC,SAAM,UAAU,WACf,oBAAC,QAAM,SAAAV,EAAI,EAAE,aAAa,EAAE,KAC5B,OAAC,SAAM,MAAOoD,EAAW,SAAUf,GAASgB,EAAahB,EAAM,OAAO,KAAK,EAAG,WAAY,GAAO,UAAU,UAAU,GACvH,KACA,QAAC,SAAM,UAAU,WACf,oBAAC,QAAM,SAAArC,EAAI,EAAE,aAAa,EAAE,KAC5B,QAAC,UAAO,UAAU,YAAY,MAAOgD,EAAQ,SAAUX,GAASY,EAAUZ,EAAM,OAAO,KAAK,EAC1F,oBAAC,UAAO,MAAM,MAAO,SAAArC,EAAI,EAAE,gBAAgB,EAAE,EAC5C8C,EAAQ,IAAIS,MACX,QAAC,UAAuB,MAAOA,EAAO,GAAK,UAAAA,EAAO,KAAMA,EAAO,OAAS,SAAMvD,EAAI,EAAE,eAAe,CAAC,GAAK,KAA5FuD,EAAO,EAAwF,CAC7G,GACH,GACF,EACCP,IAAW,UACV,QAAC,SAAM,UAAU,WACf,oBAAC,QAAM,SAAAhD,EAAI,EAAE,WAAW,EAAE,KAC1B,OAAC,SAAM,MAAOkD,EAAM,SAAUb,GAASc,EAAQd,EAAM,OAAO,KAAK,EAAG,UAAW,IAAK,GACtF,KAEF,OAAC,OAAI,UAAU,SACb,mBAAC,OAAI,QAAO,GAAC,SAAUnB,GAAQ,CAACR,GAAW,GAAI,QAAS,IAAG,CAAQ8C,EAAK,GAAI,SAAAxD,EAAI,EAAEkB,EAAO,eAAiB,aAAa,EAAE,EAC3H,GACF,CAEJ,CAEA,IAAOyC,GAAQC,EAAa,CAC1B,SAAS5D,EAAK,CACZA,EAAI,mBAAmB,eAAa,OAACF,GAAA,EAAK,CAAE,EAC5CE,EAAI,cAAc,gBAAc,OAACO,GAAA,CAAU,IAAKP,EAAK,CAAE,CACzD,CACF,CAAC",
|
|
6
|
-
"names": ["require_react", "__commonJSMin", "exports", "module", "registry", "shared", "require_ui", "__commonJSMin", "exports", "module", "registry", "shared", "require_jsx_runtime", "__commonJSMin", "exports", "module", "registry", "shared", "import_react", "import_react", "definePlugin", "plugin", "useHostContext", "ctx", "key", "listener", "import_ui", "DEFAULT_LOCAL_URL", "LocalError", "kind", "message", "code", "call", "base", "path", "init", "headers", "response", "body", "local", "token", "serverUrl", "sameServer", "left", "right", "normalize", "value", "
|
|
3
|
+
"sources": ["toc-shared:react", "toc-shared:@toc-starter/plugin-sdk/ui", "toc-shared:react/jsx-runtime", "../../plugin/index.tsx", "../../node_modules/@toc-starter/plugin-sdk/index.js", "../../plugin/local.ts", "../../plugin/remote.tsx", "../../plugin/shared.tsx"],
|
|
4
|
+
"sourcesContent": ["var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"react\"];\nif (!shared) throw new Error(\"The host does not provide react; this plugin needs a newer app version.\");\nmodule.exports = shared;", "var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"@toc-starter/plugin-sdk/ui\"];\nif (!shared) throw new Error(\"The host does not provide @toc-starter/plugin-sdk/ui; this plugin needs a newer app version.\");\nmodule.exports = shared;", "var registry = globalThis[\"__TOC_PLUGIN_SHARED__\"];\nvar shared = registry && registry[\"react/jsx-runtime\"];\nif (!shared) throw new Error(\"The host does not provide react/jsx-runtime; this plugin needs a newer app version.\");\nmodule.exports = shared;", "import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { definePlugin, useHostContext, type LocalServiceApi, type LocalServiceStatus, type PluginContext } from \"@toc-starter/plugin-sdk\";\nimport { Badge, Btn, Card, CardTitle, Input, PageHeader, Toggle } from \"@toc-starter/plugin-sdk/ui\";\nimport \"./styles.css\";\nimport { DEFAULT_LOCAL_URL, LocalError, local, sameServer, type LocalStatus } from \"./local\";\nimport { RemoteTab } from \"./remote\";\nimport { AUTO_BIND_KEY, Command, LOCAL_SERVICE_KEY, LOCAL_URL_KEY, TOKEN_KEY, errorText, type Device, type ServerContext, type WorkspaceContext } from \"./shared\";\n\nconst POLL_MS = 3_000;\nconst AUTO_BIND_MS = 10_000;\nconst AUTO_BIND_RETRY_MS = 60_000;\n/** toc-ocra's service entry exits with this when another toc-ocra holds the local port. */\nconst EXIT_PORT_IN_USE = 3;\nconst TAB_KEY = \"tab\";\n\n/** Resolved against dist/plugin/renderer.js. */\nconst iconUrl = new URL(\"../../assets/icon.svg\", import.meta.url).href;\n\ntype Phase =\n | { kind: \"checking\" }\n | { kind: \"offline\" }\n | { kind: \"starting\" }\n | { kind: \"needsCode\" }\n | { kind: \"ready\"; status: LocalStatus };\n\ntype Tab = \"local\" | \"remote\";\n\nfunction Icon() {\n return <img src={iconUrl} alt=\"\" width={16} height={16} draggable={false} />;\n}\n\n/** The desktop app's service API; undefined on hosts that predate it. */\nfunction localService(ctx: PluginContext): LocalServiceApi | undefined {\n const service = (ctx.core as { service?: LocalServiceApi }).service;\n try {\n return service && service.available() ? service : undefined;\n } catch {\n return undefined;\n }\n}\n\nconst isActive = (status: LocalServiceStatus | null | undefined) => status?.state === \"running\" || status?.state === \"starting\";\n\n/** Runs the auto-bind check right away (set by {@link startAutoBind}). */\nlet triggerAutoBind: (() => void) | undefined;\n\nfunction AgentPage({ ctx }: { ctx: PluginContext }) {\n const server = useHostContext<ServerContext>(ctx, \"server\");\n const workspace = useHostContext<WorkspaceContext>(ctx, \"workspace\");\n const [tab, setTabState] = useState<Tab>(() => (ctx.storage.get<string>(TAB_KEY, \"local\") === \"remote\" ? \"remote\" : \"local\"));\n const setTab = (next: Tab) => {\n ctx.storage.set(TAB_KEY, next);\n setTabState(next);\n };\n const [localUrl] = useState(() => ctx.storage.get(LOCAL_URL_KEY, DEFAULT_LOCAL_URL));\n const [token, setToken] = useState(() => ctx.secureStorage.get(TOKEN_KEY, \"\"));\n const [phase, setPhase] = useState<Phase>({ kind: \"checking\" });\n const [service, setService] = useState<LocalServiceStatus | null>(null);\n const [error, setError] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const alive = useRef(true);\n const svc = localService(ctx);\n\n const refresh = useCallback(async () => {\n let hosted: LocalServiceStatus | null = null;\n if (svc) {\n try {\n hosted = await svc.status();\n } catch {\n hosted = null;\n }\n }\n if (!alive.current) return;\n setService(hosted);\n // A service the app started brings its own control token.\n let active = token;\n if (isActive(hosted) && hosted?.token) {\n active = hosted.token;\n if (hosted.token !== token) {\n ctx.secureStorage.set(TOKEN_KEY, hosted.token);\n setToken(hosted.token);\n }\n }\n try {\n await local.info(localUrl);\n } catch {\n if (alive.current) setPhase({ kind: isActive(hosted) ? \"starting\" : \"offline\" });\n return;\n }\n if (!active) {\n if (alive.current) setPhase({ kind: \"needsCode\" });\n return;\n }\n try {\n const status = await local.status(localUrl, active);\n if (alive.current) setPhase({ kind: \"ready\", status });\n } catch (reason) {\n if (!alive.current) return;\n if (reason instanceof LocalError && reason.kind === \"unauthorized\") {\n // Reinstalled service (new control token), or another toc-ocra holds the port: pair again.\n ctx.secureStorage.remove(TOKEN_KEY);\n setToken(\"\");\n setPhase({ kind: \"needsCode\" });\n } else {\n setPhase({ kind: \"offline\" });\n }\n }\n }, [ctx, localUrl, svc, token]);\n\n useEffect(() => {\n alive.current = true;\n void refresh();\n const timer = window.setInterval(() => void refresh(), POLL_MS);\n return () => { alive.current = false; window.clearInterval(timer); };\n }, [refresh]);\n\n useEffect(() => {\n if (phase.kind === \"ready\") {\n const s = phase.status;\n ctx.reportHealth(s.paired && s.connected ? { status: \"healthy\", summary: ctx.t(\"health.online\", { name: s.device_name }) } : { status: \"degraded\", summary: ctx.t(s.paired ? \"health.disconnected\" : \"health.unpaired\") });\n } else if (phase.kind === \"offline\") {\n ctx.reportHealth({ status: \"degraded\", summary: ctx.t(svc ? \"health.disabled\" : \"health.offline\") });\n }\n }, [ctx, phase, svc]);\n\n const run = async (action: () => Promise<void>) => {\n setBusy(true);\n setError(\"\");\n try {\n await action();\n } catch (reason) {\n setError(errorText(ctx, reason));\n } finally {\n setBusy(false);\n }\n };\n\n const toggleService = (on: boolean) => run(async () => {\n if (!svc) return;\n if (!on) {\n ctx.storage.set(LOCAL_SERVICE_KEY, \"off\");\n setService(await svc.stop());\n await refresh();\n return;\n }\n ctx.storage.set(LOCAL_SERVICE_KEY, \"on\");\n // Turning it on means \"take tasks here\": undo a manual unbind.\n ctx.storage.remove(AUTO_BIND_KEY);\n const started = await svc.start();\n setService(started);\n if (started.token) {\n ctx.secureStorage.set(TOKEN_KEY, started.token);\n setToken(started.token);\n }\n if (await waitForLocalService(localUrl, () => alive.current)) triggerAutoBind?.();\n await refresh();\n });\n\n const hostedExit = service?.state === \"exited\" ? service : null;\n const external = Boolean(svc) && !isActive(service) && (phase.kind === \"ready\" || phase.kind === \"needsCode\");\n\n return (\n <div className=\"da-app\">\n <PageHeader title={ctx.t(\"page.title\")} subtitle={ctx.t(\"page.subtitle\")} />\n <div className=\"da-tabs\" role=\"tablist\" aria-label={ctx.t(\"page.title\")}>\n {([\"local\", \"remote\"] as const).map(item => (\n <button key={item} type=\"button\" role=\"tab\" aria-selected={tab === item} className={tab === item ? \"da-tab da-tab-active\" : \"da-tab\"} onClick={() => setTab(item)}>\n {ctx.t(`tabs.${item}`)}\n </button>\n ))}\n </div>\n {error && <div role=\"alert\" className=\"da-alert\">{error}</div>}\n\n {tab === \"remote\" && (\n <RemoteTab ctx={ctx} server={server} workspace={workspace} localDeviceId={phase.kind === \"ready\" && phase.status.paired ? phase.status.device_id : \"\"} />\n )}\n\n {tab === \"local\" && (\n <>\n {svc && (\n <LocalServiceCard\n ctx={ctx}\n status={service}\n external={external}\n exit={hostedExit}\n busy={busy}\n onToggle={on => void toggleService(on)}\n />\n )}\n {phase.kind === \"checking\" && <Card><span className=\"da-muted\">{ctx.t(\"common.checking\")}</span></Card>}\n {phase.kind === \"starting\" && <Card><span className=\"da-muted\">{ctx.t(\"service.starting\")}</span></Card>}\n {phase.kind === \"offline\" && !svc && <OfflineCard ctx={ctx} localUrl={localUrl} />}\n {phase.kind === \"needsCode\" && (\n <PairCard ctx={ctx} busy={busy} onPair={code => run(async () => {\n const result = await local.pair(localUrl, code).catch((reason: unknown) => {\n if (reason instanceof LocalError && reason.code === \"code_wrong\") throw new Error(ctx.t(\"pair.wrong\"));\n if (reason instanceof LocalError && reason.code === \"locked\") throw new Error(ctx.t(\"pair.locked\"));\n throw reason;\n });\n ctx.secureStorage.set(TOKEN_KEY, result.token);\n setToken(result.token);\n })} />\n )}\n {phase.kind === \"ready\" && (\n <ReadyView\n ctx={ctx}\n status={phase.status}\n server={server}\n workspace={workspace}\n busy={busy}\n run={run}\n localUrl={localUrl}\n token={token}\n onStatus={status => setPhase({ kind: \"ready\", status })}\n />\n )}\n </>\n )}\n </div>\n );\n}\n\n/** Waits up to 15 s for the local service to answer. */\nasync function waitForLocalService(localUrl: string, alive: () => boolean): Promise<boolean> {\n for (let attempt = 0; attempt < 30 && alive(); attempt += 1) {\n try {\n await local.info(localUrl);\n return true;\n } catch {\n await new Promise(resolve => window.setTimeout(resolve, 500));\n }\n }\n return false;\n}\n\nfunction LocalServiceCard({ ctx, status, external, exit, busy, onToggle }: {\n ctx: PluginContext;\n status: LocalServiceStatus | null;\n external: boolean;\n exit: LocalServiceStatus | null;\n busy: boolean;\n onToggle: (on: boolean) => void;\n}) {\n const on = isActive(status);\n const portTaken = exit?.exitCode === EXIT_PORT_IN_USE;\n return (\n <Card>\n <div className=\"da-switch\">\n <div>\n <CardTitle>{ctx.t(\"service.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(on ? \"service.onBody\" : \"service.offBody\")}</p>\n </div>\n <Toggle checked={on} disabled={busy} label={ctx.t(\"service.title\")} onChange={onToggle} />\n </div>\n {on && <p className=\"da-muted\">{ctx.t(\"service.followsApp\")}</p>}\n {!on && (external || portTaken) && <p className=\"da-muted\">{ctx.t(\"service.external\")}</p>}\n {exit && !portTaken && exit.exitCode !== 0 && (\n <div role=\"alert\" className=\"da-alert\">{ctx.t(\"service.crashed\", { error: exit.error || `exit ${exit.exitCode ?? exit.signal ?? \"?\"}` })}</div>\n )}\n </Card>\n );\n}\n\nfunction OfflineCard({ ctx, localUrl }: { ctx: PluginContext; localUrl: string }) {\n return (\n <Card>\n <CardTitle>{ctx.t(\"offline.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"offline.body\", { url: localUrl })}</p>\n <div className=\"da-step\">{ctx.t(\"offline.once\")}</div>\n <Command ctx={ctx} value=\"npx toc-ocra@latest run\" />\n <div className=\"da-step\">{ctx.t(\"offline.service\")}</div>\n <Command ctx={ctx} value=\"npm install -g toc-ocra@latest && toc-ocra service:install\" />\n <p className=\"da-muted\">{ctx.t(\"offline.node\")}</p>\n </Card>\n );\n}\n\nfunction PairCard({ ctx, busy, onPair }: { ctx: PluginContext; busy: boolean; onPair: (code: string) => void }) {\n const [code, setCode] = useState(\"\");\n const valid = /^\\d{6}$/.test(code);\n return (\n <Card>\n <CardTitle>{ctx.t(\"pair.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"pair.body\")}</p>\n <Command ctx={ctx} value=\"toc-ocra code\" />\n <form className=\"da-row\" onSubmit={event => { event.preventDefault(); if (valid) onPair(code); }}>\n <Input\n value={code}\n onChange={event => setCode(event.target.value.replace(/\\D/g, \"\").slice(0, 6))}\n placeholder={ctx.t(\"pair.placeholder\")}\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n aria-label={ctx.t(\"pair.placeholder\")}\n className=\"da-code-input\"\n />\n <Btn primary type=\"submit\" disabled={!valid || busy}>{ctx.t(\"pair.submit\")}</Btn>\n </form>\n </Card>\n );\n}\n\nfunction ReadyView({ ctx, status, server, workspace, busy, run, localUrl, token, onStatus }: {\n ctx: PluginContext;\n status: LocalStatus;\n server: ServerContext | undefined;\n workspace: WorkspaceContext | undefined;\n busy: boolean;\n run: (action: () => Promise<void>) => Promise<void>;\n localUrl: string;\n token: string;\n onStatus: (status: LocalStatus) => void;\n}) {\n const boundElsewhere = status.paired && server && !sameServer(status.server_url, server.origin);\n const unpair = () => run(async () => {\n // Revoke on the server too when the device belongs to the server shown.\n if (status.device_id && server && sameServer(status.server_url, server.origin)) {\n await ctx.core.request(`/devices/${encodeURIComponent(status.device_id)}/agent`, { method: \"DELETE\" }).catch(() => undefined);\n }\n ctx.storage.set(AUTO_BIND_KEY, \"off\");\n onStatus(await local.unpair(localUrl, token));\n });\n return (\n <>\n <Card>\n <CardTitle>{ctx.t(\"status.title\")}</CardTitle>\n <dl className=\"da-grid\">\n <div><dt>{ctx.t(\"status.service\")}</dt><dd>toc-ocra {status.version} \u00B7 {status.hostname}</dd></div>\n <div><dt>{ctx.t(\"status.binding\")}</dt><dd><BindingBadge ctx={ctx} status={status} /></dd></div>\n {status.paired && <div><dt>{ctx.t(\"status.device\")}</dt><dd>{status.device_name}</dd></div>}\n {status.paired && <div><dt>{ctx.t(\"status.server\")}</dt><dd className=\"da-mono\">{status.server_url}</dd></div>}\n {status.paired && <div><dt>{ctx.t(\"status.runs\")}</dt><dd>{status.active_runs}</dd></div>}\n </dl>\n {status.paired && !status.connected && status.connection_error && <p className=\"da-muted\">{ctx.t(\"status.lastError\", { error: status.connection_error })}</p>}\n {status.token_from_env && <p className=\"da-muted\">{ctx.t(\"status.tokenFromEnv\")}</p>}\n {status.paired && (\n <div className=\"da-row\">\n <Btn danger disabled={busy || status.token_from_env} onClick={() => void unpair()}>{ctx.t(\"status.unpair\")}</Btn>\n </div>\n )}\n </Card>\n\n {(!status.paired || status.unauthorized || boundElsewhere) && (\n <BindCard ctx={ctx} status={status} server={server} workspace={workspace} busy={busy} run={run} localUrl={localUrl} token={token} onStatus={onStatus} rebind={status.paired} />\n )}\n\n <Card>\n <CardTitle>{ctx.t(\"cli.title\")}</CardTitle>\n <ul className=\"da-list\">\n {status.providers.filter(provider => provider.installed).map(provider => (\n <li key={provider.id}>\n <span className=\"da-mono\">{provider.id}</span>\n <span className=\"da-muted\">{provider.version}</span>\n {provider.runnable ? <Badge variant=\"ok\">{ctx.t(\"cli.runnable\")}</Badge> : <Badge variant=\"muted\">{ctx.t(\"cli.detectOnly\")}</Badge>}\n </li>\n ))}\n {!status.providers.some(provider => provider.installed) && <li className=\"da-muted\">{ctx.t(\"cli.none\")}</li>}\n </ul>\n <div className=\"da-row\">\n <Btn disabled={busy} onClick={() => void run(async () => onStatus(await local.detect(localUrl, token)))}>{ctx.t(\"cli.redetect\")}</Btn>\n </div>\n </Card>\n </>\n );\n}\n\nfunction BindingBadge({ ctx, status }: { ctx: PluginContext; status: LocalStatus }) {\n if (!status.paired) return <Badge variant=\"muted\">{ctx.t(\"binding.unpaired\")}</Badge>;\n if (status.unauthorized) return <Badge variant=\"err\">{ctx.t(\"binding.revoked\")}</Badge>;\n if (status.connected) return <Badge variant=\"ok\">{ctx.t(\"binding.online\")}</Badge>;\n return <Badge variant=\"warn\">{ctx.t(\"binding.connecting\")}</Badge>;\n}\n\nfunction BindCard({ ctx, status, server, workspace, busy, run, localUrl, token, onStatus, rebind }: {\n ctx: PluginContext;\n status: LocalStatus;\n server: ServerContext | undefined;\n workspace: WorkspaceContext | undefined;\n busy: boolean;\n run: (action: () => Promise<void>) => Promise<void>;\n localUrl: string;\n token: string;\n onStatus: (status: LocalStatus) => void;\n rebind: boolean;\n}) {\n const [devices, setDevices] = useState<Device[]>([]);\n const [choice, setChoice] = useState(\"new\");\n const [name, setName] = useState(status.hostname);\n const [serverUrl, setServerUrl] = useState(server?.origin ?? \"\");\n useEffect(() => { if (server?.origin) setServerUrl(server.origin); }, [server?.origin]);\n\n useEffect(() => {\n if (!workspace?.id) return;\n let cancelled = false;\n ctx.core.request<{ items?: Device[] }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`)\n .then(result => { if (!cancelled) setDevices((result.items ?? []).filter(device => device.is_mine)); })\n .catch(() => { if (!cancelled) setDevices([]); });\n return () => { cancelled = true; };\n }, [ctx, workspace?.id]);\n\n const bind = () => run(async () => {\n if (!workspace?.id) throw new Error(ctx.t(\"bind.noWorkspace\"));\n if (!serverUrl.trim()) throw new Error(ctx.t(\"bind.noServer\"));\n let deviceId = choice;\n if (choice === \"new\") {\n const created = await ctx.core.request<{ id: string }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`, {\n method: \"POST\",\n body: JSON.stringify({ name: name.trim() || status.hostname, location: \"local\", platform: status.platform, note: \"\", share_to_workspace: false }),\n });\n deviceId = created.id;\n setChoice(deviceId);\n }\n const pairing = await ctx.core.request<{ code: string }>(`/devices/${encodeURIComponent(deviceId)}/pairing-code`, { method: \"POST\" });\n onStatus(await local.enroll(localUrl, token, serverUrl.trim(), pairing.code));\n ctx.storage.remove(AUTO_BIND_KEY);\n ctx.notify({ title: ctx.t(\"page.title\"), body: ctx.t(\"bind.done\", { server: server?.name ?? serverUrl }) });\n });\n\n return (\n <Card>\n <CardTitle>{ctx.t(rebind ? \"bind.rebindTitle\" : \"bind.title\")}</CardTitle>\n {rebind && status.unauthorized && <p className=\"da-text\">{ctx.t(\"bind.revoked\")}</p>}\n {rebind && !status.unauthorized && <p className=\"da-text\">{ctx.t(\"bind.elsewhere\", { bound: status.server_url, current: server?.origin ?? \"\" })}</p>}\n <p className=\"da-text\">{ctx.t(\"bind.body\", { server: server?.name ?? \"\", workspace: workspace?.name ?? \"\" })}</p>\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.server\")}</span>\n <Input value={serverUrl} onChange={event => setServerUrl(event.target.value)} spellCheck={false} className=\"da-mono\" />\n </label>\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.device\")}</span>\n <select className=\"da-select\" value={choice} onChange={event => setChoice(event.target.value)}>\n <option value=\"new\">{ctx.t(\"bind.newDevice\")}</option>\n {devices.map(device => (\n <option key={device.id} value={device.id}>{device.name}{device.paired ? ` \u00B7 ${ctx.t(\"bind.replaces\")}` : \"\"}</option>\n ))}\n </select>\n </label>\n {choice === \"new\" && (\n <label className=\"da-field\">\n <span>{ctx.t(\"bind.name\")}</span>\n <Input value={name} onChange={event => setName(event.target.value)} maxLength={100} />\n </label>\n )}\n <div className=\"da-row\">\n <Btn primary disabled={busy || !workspace?.id} onClick={() => void bind()}>{ctx.t(busy ? \"bind.working\" : \"bind.submit\")}</Btn>\n </div>\n </Card>\n );\n}\n\n/**\n * Keeps this computer bound to the server the desktop app is signed in to\n * (public or LAN): when they differ, asks the server for this machine's device\n * (matched by machine id, so the same device is reused) and re-enrolls the\n * local service. Waits while tasks are running; stays out of the way after\n * the user unbinds by hand or when the server revoked the device.\n */\nfunction startAutoBind(ctx: PluginContext) {\n let busy = false;\n let deferredFor = \"\";\n const failedAt = new Map<string, number>();\n\n const tick = async () => {\n if (busy || ctx.signal.aborted) return;\n const server = ctx.core.context<ServerContext>(\"server\");\n const token = ctx.secureStorage.get(TOKEN_KEY, \"\");\n if (!server?.origin || !token || ctx.storage.get<string>(AUTO_BIND_KEY, \"on\") === \"off\") return;\n if (Date.now() - (failedAt.get(server.origin) ?? 0) < AUTO_BIND_RETRY_MS) return;\n busy = true;\n try {\n const localUrl = ctx.storage.get(LOCAL_URL_KEY, DEFAULT_LOCAL_URL);\n const status = await local.status(localUrl, token);\n if (!status.machine_id || status.token_from_env) return;\n if (status.paired && (status.unauthorized || sameServer(status.server_url, server.origin))) {\n deferredFor = \"\";\n return;\n }\n if (status.active_runs > 0) {\n if (deferredFor !== server.origin) {\n deferredFor = server.origin;\n ctx.notify({ title: ctx.t(\"page.title\"), body: ctx.t(\"auto.deferred\", { server: server.name || server.origin }) });\n }\n return;\n }\n const pairing = await ctx.core.request<{ code: string; device_name: string }>(\"/devices/machine/pairing-code\", {\n method: \"POST\",\n body: JSON.stringify({\n machine_id: status.machine_id,\n hostname: status.hostname,\n platform: status.platform,\n current_device_id: status.paired ? status.device_id : \"\",\n }),\n });\n await local.enroll(localUrl, token, server.origin, pairing.code);\n deferredFor = \"\";\n failedAt.delete(server.origin);\n ctx.notify({ title: ctx.t(\"page.title\"), body: ctx.t(\"auto.done\", { server: server.name || server.origin, device: pairing.device_name }) });\n } catch (reason) {\n // Local service offline / plugin not paired yet: just try again next tick.\n // A server or enroll failure backs off for this server.\n if (!(reason instanceof LocalError) || reason.kind === \"rejected\") failedAt.set(server.origin, Date.now());\n } finally {\n busy = false;\n }\n };\n\n const timer = window.setInterval(() => void tick(), AUTO_BIND_MS);\n triggerAutoBind = () => void tick();\n ctx.registerDisposer(() => {\n window.clearInterval(timer);\n triggerAutoBind = undefined;\n });\n ctx.registerDisposer(ctx.core.onContextChange(\"server\", () => void tick()));\n window.setTimeout(() => void tick(), 1_500);\n}\n\n/**\n * Follows the desktop app: when the user left the local agent on, start it\n * again with the app. The app stops it when it quits.\n */\nfunction startLocalServiceIfEnabled(ctx: PluginContext) {\n const svc = localService(ctx);\n if (!svc || ctx.storage.get<string>(LOCAL_SERVICE_KEY, \"off\") !== \"on\") return;\n void svc.start()\n .then(status => {\n if (status.token) ctx.secureStorage.set(TOKEN_KEY, status.token);\n window.setTimeout(() => triggerAutoBind?.(), 3_000);\n })\n .catch(() => undefined);\n}\n\nexport default definePlugin({\n activate(ctx) {\n ctx.registerNavigation(\"agent.nav\", <Icon />);\n ctx.registerRoute(\"agent.home\", <AgentPage ctx={ctx} />);\n startLocalServiceIfEnabled(ctx);\n startAutoBind(ctx);\n },\n});\n", "/**\n * Runtime part of the SDK that ends up inside plugin bundles. Keep it tiny:\n * everything here is copied into every plugin. Build-time helpers live in lib/.\n * `react` resolves to the host's instance through `toc-plugin build`.\n */\nimport { useSyncExternalStore } from \"react\";\n\n/** Host contract this SDK targets. Must match PLUGIN_API_VERSION in lib/constants.mjs. */\nexport const PLUGIN_API_VERSION = \"1.0.0\";\n\n/**\n * Identity helper that gives a plugin module full type inference.\n *\n * @template {import(\"./index\").PluginModule} T\n * @param {T} plugin\n * @returns {T}\n */\nexport function definePlugin(plugin) {\n if (!plugin || typeof plugin.activate !== \"function\") {\n throw new TypeError(\"definePlugin() needs an object with an activate(context) function\");\n }\n return plugin;\n}\n\n/**\n * Re-renders when the app publishes a new value under `key`.\n *\n * @template T\n * @param {import(\"./index\").PluginContext} ctx\n * @param {string} key\n * @returns {T | undefined}\n */\nexport function useHostContext(ctx, key) {\n return useSyncExternalStore(\n listener => ctx.core.onContextChange(key, listener),\n () => ctx.core.context(key),\n );\n}\n", "/**\n * Client for the local toc-ocra service (`toc-ocra run`) on this computer.\n * The plugin pairs once with the 6-digit connection code and then sends the\n * control token as a bearer token.\n */\nexport const DEFAULT_LOCAL_URL = \"http://127.0.0.1:17339\";\n\nexport interface LocalInfo {\n name: string;\n version: string;\n protocol: number;\n paired: boolean;\n}\n\nexport interface LocalProvider {\n id: string;\n installed: boolean;\n runnable: boolean;\n version: string;\n}\n\nexport interface LocalStatus {\n version: string;\n hostname: string;\n /** Stable id of this installation (older services omit it). */\n machine_id?: string;\n platform: \"mac\" | \"win\" | \"linux\";\n paired: boolean;\n running: boolean;\n device_id: string;\n device_name: string;\n server_url: string;\n connected: boolean;\n unauthorized: boolean;\n connection_error: string;\n active_runs: number;\n allowed_roots: string[];\n token_from_env: boolean;\n providers: LocalProvider[];\n}\n\n/** Why a local call failed: the service is not running, the token is not accepted, or the service said no. */\nexport class LocalError extends Error {\n constructor(readonly kind: \"offline\" | \"unauthorized\" | \"rejected\", message: string, readonly code = \"\") {\n super(message);\n }\n}\n\nasync function call<T>(base: string, path: string, init: RequestInit & { token?: string } = {}): Promise<T> {\n const headers = new Headers(init.headers);\n if (init.token) headers.set(\"Authorization\", `Bearer ${init.token}`);\n if (init.body) headers.set(\"Content-Type\", \"application/json\");\n let response: Response;\n try {\n response = await fetch(`${base.replace(/\\/+$/, \"\")}${path}`, { ...init, headers, cache: \"no-store\" });\n } catch {\n throw new LocalError(\"offline\", \"local service unreachable\");\n }\n const body = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n if (response.status === 401) throw new LocalError(\"unauthorized\", \"unauthorized\");\n if (!response.ok) {\n const code = typeof body?.error === \"string\" ? body.error : \"\";\n const message = typeof body?.message === \"string\" ? body.message : code || `HTTP ${response.status}`;\n throw new LocalError(\"rejected\", message, code);\n }\n return body as T;\n}\n\nexport const local = {\n info: (base: string) => call<LocalInfo>(base, \"/control/info\"),\n pair: (base: string, code: string) => call<{ token: string }>(base, \"/control/pair\", { method: \"POST\", body: JSON.stringify({ code }) }),\n status: (base: string, token: string) => call<LocalStatus>(base, \"/control/status\", { token }),\n enroll: (base: string, token: string, serverUrl: string, code: string) =>\n call<LocalStatus>(base, \"/control/enroll\", { method: \"POST\", token, body: JSON.stringify({ server_url: serverUrl, code }) }),\n unpair: (base: string, token: string) => call<LocalStatus>(base, \"/control/unpair\", { method: \"POST\", token }),\n detect: (base: string, token: string) => call<LocalStatus>(base, \"/control/detect\", { method: \"POST\", token }),\n};\n\n/** Two backend addresses name the same server (trailing slash and case insensitive). */\nexport function sameServer(left: string, right: string): boolean {\n const normalize = (value: string) => {\n try {\n return new URL(value).origin.toLowerCase();\n } catch {\n return value.trim().replace(/\\/+$/, \"\").toLowerCase();\n }\n };\n return Boolean(left && right) && normalize(left) === normalize(right);\n}\n", "import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { PluginContext } from \"@toc-starter/plugin-sdk\";\nimport { Badge, Btn, Card, CardTitle, Input, Toggle } from \"@toc-starter/plugin-sdk/ui\";\nimport { Command, errorText, type Device, type ServerContext, type WorkspaceContext } from \"./shared\";\n\n/**\n * \u5176\u4ED6\u7535\u8111: install the device agent on another machine (a Linux server,\n * another Mac, Windows). The page creates the device and a one-time pairing\n * code, shows one command to run there (install + pair + background\n * service), and polls until that machine comes online. Enabling / disabling\n * later is a server-side switch that keeps the pairing.\n */\n\ntype Platform = \"mac\" | \"linux\" | \"win\";\nconst PLATFORMS: readonly Platform[] = [\"linux\", \"mac\", \"win\"];\nconst IDLE_POLL_MS = 10_000;\nconst WAIT_POLL_MS = 3_000;\nconst REMOTE_SERVER_KEY = \"remoteServerUrl\";\n\ninterface Pending {\n deviceId: string;\n deviceName: string;\n platform: Platform;\n code: string;\n expiresAt: number;\n /** Credential id before pairing; a new one means the command ran. */\n baseline: string | null;\n matched: boolean;\n}\n\nconst LOOPBACK = new Set([\"127.0.0.1\", \"localhost\", \"[::1]\", \"::1\", \"0.0.0.0\"]);\n\n/** The server origin to put in the command, or null when it is not an http(s) URL. */\nfunction commandServer(value: string): string | null {\n try {\n const url = new URL(value.trim());\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? url.origin : null;\n } catch {\n return null;\n }\n}\n\nfunction isLoopback(origin: string): boolean {\n try {\n return LOOPBACK.has(new URL(origin).hostname);\n } catch {\n return false;\n }\n}\n\nexport function setupCommand(platform: Platform, code: string, server: string): string {\n const setup = `toc-ocra setup --code ${code} --server ${server}`;\n // PowerShell 5.1 has no `&&`; `if ($?)` runs setup only after a successful install.\n if (platform === \"win\") return `npm install -g toc-ocra@latest; if ($?) { ${setup} }`;\n return `npm install -g toc-ocra@latest && ${setup}`;\n}\n\nfunction DeviceBadge({ ctx, device }: { ctx: PluginContext; device: Device }) {\n if (device.status === \"online\") return <Badge variant=\"ok\">{ctx.t(\"remote.status.online\")}</Badge>;\n if (device.status === \"disabled\") return <Badge variant=\"warn\">{ctx.t(\"remote.status.disabled\")}</Badge>;\n if (device.status === \"offline\") return <Badge variant=\"err\">{ctx.t(\"remote.status.offline\")}</Badge>;\n return <Badge variant=\"muted\">{ctx.t(\"remote.status.notConnected\")}</Badge>;\n}\n\nexport function RemoteTab({ ctx, server, workspace, localDeviceId }: {\n ctx: PluginContext;\n server: ServerContext | undefined;\n workspace: WorkspaceContext | undefined;\n /** This computer's device, listed on the \u672C\u673A tab instead. */\n localDeviceId: string;\n}) {\n const [devices, setDevices] = useState<Device[] | null>(null);\n const [error, setError] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [pending, setPending] = useState<Pending | null>(null);\n const [adding, setAdding] = useState(false);\n const [name, setName] = useState(\"\");\n const [platform, setPlatform] = useState<Platform>(\"linux\");\n const [serverUrl, setServerUrl] = useState(() => ctx.storage.get<string>(REMOTE_SERVER_KEY, \"\") || server?.origin || \"\");\n const pendingRef = useRef(pending);\n pendingRef.current = pending;\n const alive = useRef(true);\n\n useEffect(() => {\n if (!ctx.storage.get<string>(REMOTE_SERVER_KEY, \"\") && server?.origin) setServerUrl(server.origin);\n }, [ctx, server?.origin]);\n\n const load = useCallback(async () => {\n if (!workspace?.id) return;\n try {\n const result = await ctx.core.request<{ items?: Device[] }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`);\n if (!alive.current) return;\n const mine = (result.items ?? []).filter(device => device.is_mine && device.id !== localDeviceId);\n setDevices(mine);\n const waiting = pendingRef.current;\n if (waiting && !waiting.matched) {\n const device = mine.find(item => item.id === waiting.deviceId);\n if (device?.agent_id && device.agent_id !== waiting.baseline && device.terminal_online) {\n setPending({ ...waiting, matched: true });\n ctx.notify({ title: ctx.t(\"page.title\"), body: ctx.t(\"remote.matchedNotice\", { name: device.name }) });\n }\n }\n } catch (reason) {\n if (alive.current) setError(errorText(ctx, reason));\n }\n }, [ctx, localDeviceId, workspace?.id]);\n\n const waiting = Boolean(pending && !pending.matched);\n useEffect(() => {\n alive.current = true;\n void load();\n const timer = window.setInterval(() => void load(), waiting ? WAIT_POLL_MS : IDLE_POLL_MS);\n return () => { alive.current = false; window.clearInterval(timer); };\n }, [load, waiting]);\n\n const run = async (action: () => Promise<void>) => {\n setBusy(true);\n setError(\"\");\n try {\n await action();\n } catch (reason) {\n setError(errorText(ctx, reason));\n } finally {\n setBusy(false);\n }\n };\n\n const origin = commandServer(serverUrl);\n const saveServer = (value: string) => {\n setServerUrl(value);\n if (value.trim() && value.trim() !== server?.origin) ctx.storage.set(REMOTE_SERVER_KEY, value.trim());\n else ctx.storage.remove(REMOTE_SERVER_KEY);\n };\n\n const pair = (device: Pick<Device, \"id\" | \"name\" | \"platform\" | \"agent_id\">) => run(async () => {\n if (!origin) throw new Error(ctx.t(\"remote.serverInvalid\"));\n const result = await ctx.core.request<{ code: string; expires_at: number }>(`/devices/${encodeURIComponent(device.id)}/pairing-code`, { method: \"POST\" });\n setPending({\n deviceId: device.id,\n deviceName: device.name,\n platform: PLATFORMS.includes(device.platform) ? device.platform : \"linux\",\n code: result.code,\n expiresAt: result.expires_at,\n baseline: device.agent_id ?? null,\n matched: false,\n });\n });\n\n const addComputer = () => run(async () => {\n if (!workspace?.id) throw new Error(ctx.t(\"bind.noWorkspace\"));\n if (!origin) throw new Error(ctx.t(\"remote.serverInvalid\"));\n const deviceName = name.trim() || ctx.t(`remote.platform.${platform}`);\n const created = await ctx.core.request<Device>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`, {\n method: \"POST\",\n body: JSON.stringify({ name: deviceName, location: platform === \"linux\" ? \"cloud\" : \"local\", platform, note: \"\", share_to_workspace: false }),\n });\n const result = await ctx.core.request<{ code: string; expires_at: number }>(`/devices/${encodeURIComponent(created.id)}/pairing-code`, { method: \"POST\" });\n setPending({ deviceId: created.id, deviceName: created.name || deviceName, platform, code: result.code, expiresAt: result.expires_at, baseline: null, matched: false });\n setAdding(false);\n setName(\"\");\n await load();\n });\n\n const setEnabled = (device: Device, enabled: boolean) => run(async () => {\n await ctx.core.request(`/devices/${encodeURIComponent(device.id)}/enabled`, { method: \"PUT\", body: JSON.stringify({ enabled }) });\n await load();\n });\n\n return (\n <>\n {error && <div role=\"alert\" className=\"da-alert\">{error}</div>}\n <Card>\n <CardTitle>{ctx.t(\"remote.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"remote.body\")}</p>\n <label className=\"da-field\">\n <span>{ctx.t(\"remote.server\")}</span>\n <Input value={serverUrl} onChange={event => saveServer(event.target.value)} spellCheck={false} className=\"da-mono\" />\n </label>\n {!origin && <p className=\"da-muted da-warn\">{ctx.t(\"remote.serverInvalid\")}</p>}\n {origin && isLoopback(origin) && <p className=\"da-muted da-warn\">{ctx.t(\"remote.loopback\")}</p>}\n {!adding && (\n <div className=\"da-row\">\n <Btn primary disabled={busy || !workspace?.id} onClick={() => setAdding(true)}>{ctx.t(\"remote.add\")}</Btn>\n </div>\n )}\n {adding && (\n <form className=\"da-form\" onSubmit={event => { event.preventDefault(); void addComputer(); }}>\n <label className=\"da-field\">\n <span>{ctx.t(\"remote.platformLabel\")}</span>\n <select className=\"da-select\" value={platform} onChange={event => setPlatform(event.target.value as Platform)}>\n {PLATFORMS.map(item => <option key={item} value={item}>{ctx.t(`remote.platform.${item}`)}</option>)}\n </select>\n </label>\n <label className=\"da-field\">\n <span>{ctx.t(\"remote.name\")}</span>\n <Input value={name} onChange={event => setName(event.target.value)} maxLength={100} placeholder={ctx.t(\"remote.namePlaceholder\")} />\n </label>\n <div className=\"da-row\">\n <Btn primary type=\"submit\" disabled={busy || !origin}>{ctx.t(busy ? \"remote.working\" : \"remote.generate\")}</Btn>\n <Btn type=\"button\" disabled={busy} onClick={() => setAdding(false)}>{ctx.t(\"remote.cancel\")}</Btn>\n </div>\n </form>\n )}\n </Card>\n\n {pending && origin && (\n <PendingCard ctx={ctx} pending={pending} origin={origin} busy={busy}\n onPlatform={value => setPending({ ...pending, platform: value })}\n onRegenerate={() => void pair({ id: pending.deviceId, name: pending.deviceName, platform: pending.platform, agent_id: pending.baseline })}\n onClose={() => setPending(null)} />\n )}\n\n <Card>\n <CardTitle>{ctx.t(\"remote.listTitle\")}</CardTitle>\n {devices === null && <p className=\"da-muted\">{ctx.t(\"common.checking\")}</p>}\n {devices?.length === 0 && <p className=\"da-muted\">{ctx.t(\"remote.empty\")}</p>}\n {devices && devices.length > 0 && (\n <ul className=\"da-devices\">\n {devices.map(device => (\n <li key={device.id}>\n <div className=\"da-device-main\">\n <span className=\"da-device-name\">{device.name}</span>\n <span className=\"da-muted\">{ctx.t(`remote.platform.${PLATFORMS.includes(device.platform) ? device.platform : \"linux\"}`)}{device.agent_version ? ` \u00B7 toc-ocra ${device.agent_version}` : \"\"}</span>\n </div>\n <DeviceBadge ctx={ctx} device={device} />\n <div className=\"da-device-actions\">\n {(!device.paired || device.status === \"offline\" || device.status === \"not_connected\") && (\n <Btn disabled={busy || !origin} onClick={() => void pair(device)}>{ctx.t(device.paired ? \"remote.repair\" : \"remote.install\")}</Btn>\n )}\n {device.paired && (\n <label className=\"da-toggle\">\n <span>{ctx.t(\"remote.enabled\")}</span>\n <Toggle checked={!device.disabled} disabled={busy} label={ctx.t(\"remote.enabled\")} onChange={value => void setEnabled(device, value)} />\n </label>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n <p className=\"da-muted\">{ctx.t(\"remote.disableHint\")}</p>\n <div className=\"da-step\">{ctx.t(\"remote.uninstall\")}</div>\n <Command ctx={ctx} value=\"toc-ocra service:uninstall\" />\n </Card>\n </>\n );\n}\n\nfunction PendingCard({ ctx, pending, origin, busy, onPlatform, onRegenerate, onClose }: {\n ctx: PluginContext;\n pending: Pending;\n origin: string;\n busy: boolean;\n onPlatform: (platform: Platform) => void;\n onRegenerate: () => void;\n onClose: () => void;\n}) {\n const [now, setNow] = useState(() => Math.floor(Date.now() / 1000));\n useEffect(() => {\n if (pending.matched) return;\n const timer = window.setInterval(() => setNow(Math.floor(Date.now() / 1000)), 1_000);\n return () => window.clearInterval(timer);\n }, [pending.matched]);\n const left = Math.max(0, pending.expiresAt - now);\n const expired = !pending.matched && left === 0;\n\n return (\n <Card>\n <CardTitle>{ctx.t(\"remote.pendingTitle\", { name: pending.deviceName })}</CardTitle>\n {pending.matched ? (\n <>\n <p className=\"da-text\"><Badge variant=\"ok\">{ctx.t(\"remote.matched\")}</Badge> {ctx.t(\"remote.matchedBody\", { name: pending.deviceName })}</p>\n <div className=\"da-row\"><Btn primary onClick={onClose}>{ctx.t(\"remote.done\")}</Btn></div>\n </>\n ) : (\n <>\n <p className=\"da-text\">{ctx.t(\"remote.pendingBody\")}</p>\n <div className=\"da-segment\" role=\"radiogroup\" aria-label={ctx.t(\"remote.platformLabel\")}>\n {PLATFORMS.map(item => (\n <button key={item} type=\"button\" role=\"radio\" aria-checked={pending.platform === item} className={pending.platform === item ? \"da-seg da-seg-active\" : \"da-seg\"} onClick={() => onPlatform(item)}>\n {ctx.t(`remote.platform.${item}`)}\n </button>\n ))}\n </div>\n <Command ctx={ctx} value={setupCommand(pending.platform, pending.code, origin)} />\n <ul className=\"da-hints\">\n <li>{ctx.t(\"remote.hintNode\")}</li>\n {pending.platform === \"linux\" && <li>{ctx.t(\"remote.hintLinux\")}</li>}\n {pending.platform === \"win\" && <li>{ctx.t(\"remote.hintWindows\")}</li>}\n <li>{expired ? ctx.t(\"remote.expired\") : ctx.t(\"remote.expires\", { minutes: Math.floor(left / 60), seconds: String(left % 60).padStart(2, \"0\") })}</li>\n </ul>\n <p className=\"da-muted\">{expired ? \"\" : ctx.t(\"remote.waiting\")}</p>\n <div className=\"da-row\">\n <Btn disabled={busy} onClick={onRegenerate}>{ctx.t(\"remote.regenerate\")}</Btn>\n <Btn disabled={busy} onClick={onClose}>{ctx.t(\"remote.cancel\")}</Btn>\n </div>\n </>\n )}\n </Card>\n );\n}\n", "import { useState } from \"react\";\nimport type { PluginContext } from \"@toc-starter/plugin-sdk\";\nimport { Btn } from \"@toc-starter/plugin-sdk/ui\";\nimport { LocalError } from \"./local\";\n\nexport const TOKEN_KEY = \"controlToken\";\nexport const LOCAL_URL_KEY = \"localUrl\";\n/** \"off\" after the user unbinds by hand; binding by hand turns it back on. */\nexport const AUTO_BIND_KEY = \"autoBind\";\n/** \"on\" while the user wants the desktop app to run the local agent. */\nexport const LOCAL_SERVICE_KEY = \"localService\";\n\nexport interface ServerContext { kind: \"cloud\" | \"lan\"; name: string; origin: string }\nexport interface WorkspaceContext { id: string; name: string }\n\n/** The fields of echo_admin's device view the plugin uses. */\nexport interface Device {\n id: string;\n name: string;\n platform: \"mac\" | \"win\" | \"linux\";\n location?: string;\n paired: boolean;\n status: \"not_connected\" | \"online\" | \"offline\" | \"disabled\";\n is_mine: boolean;\n /** Terminal agent credential id; only the owner sees it. Changes on every pairing. */\n agent_id?: string | null;\n terminal_online?: boolean;\n disabled?: boolean;\n agent_version?: string;\n last_seen_at?: number | null;\n}\n\nexport function errorText(ctx: PluginContext, error: unknown): string {\n if (error instanceof LocalError && error.kind === \"offline\") return ctx.t(\"error.offline\");\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function Command({ ctx, value }: { ctx: PluginContext; value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <div className=\"da-command\">\n <code>{value}</code>\n <Btn onClick={() => void navigator.clipboard.writeText(value).then(() => { setCopied(true); window.setTimeout(() => setCopied(false), 1500); })}>\n {copied ? ctx.t(\"common.copied\") : ctx.t(\"common.copy\")}\n </Btn>\n </div>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["require_react", "__commonJSMin", "exports", "module", "registry", "shared", "require_ui", "__commonJSMin", "exports", "module", "registry", "shared", "require_jsx_runtime", "__commonJSMin", "exports", "module", "registry", "shared", "import_react", "import_react", "definePlugin", "plugin", "useHostContext", "ctx", "key", "listener", "import_ui", "DEFAULT_LOCAL_URL", "LocalError", "kind", "message", "code", "call", "base", "path", "init", "headers", "response", "body", "local", "token", "serverUrl", "sameServer", "left", "right", "normalize", "value", "import_react", "import_ui", "import_react", "import_ui", "import_jsx_runtime", "TOKEN_KEY", "LOCAL_URL_KEY", "AUTO_BIND_KEY", "LOCAL_SERVICE_KEY", "errorText", "ctx", "error", "LocalError", "Command", "value", "copied", "setCopied", "import_jsx_runtime", "PLATFORMS", "IDLE_POLL_MS", "WAIT_POLL_MS", "REMOTE_SERVER_KEY", "LOOPBACK", "commandServer", "value", "url", "isLoopback", "origin", "setupCommand", "platform", "code", "server", "setup", "DeviceBadge", "ctx", "device", "RemoteTab", "workspace", "localDeviceId", "devices", "setDevices", "error", "setError", "busy", "setBusy", "pending", "setPending", "adding", "setAdding", "name", "setName", "setPlatform", "serverUrl", "setServerUrl", "pendingRef", "alive", "load", "result", "mine", "waiting", "item", "reason", "errorText", "timer", "run", "action", "saveServer", "pair", "addComputer", "deviceName", "created", "setEnabled", "enabled", "event", "PendingCard", "Command", "onPlatform", "onRegenerate", "onClose", "now", "setNow", "left", "expired", "import_jsx_runtime", "POLL_MS", "AUTO_BIND_MS", "AUTO_BIND_RETRY_MS", "EXIT_PORT_IN_USE", "TAB_KEY", "iconUrl", "Icon", "localService", "ctx", "service", "isActive", "status", "triggerAutoBind", "AgentPage", "server", "useHostContext", "workspace", "tab", "setTabState", "setTab", "next", "localUrl", "LOCAL_URL_KEY", "DEFAULT_LOCAL_URL", "token", "setToken", "TOKEN_KEY", "phase", "setPhase", "setService", "error", "setError", "busy", "setBusy", "alive", "svc", "refresh", "hosted", "active", "local", "reason", "LocalError", "timer", "s", "run", "action", "errorText", "toggleService", "on", "LOCAL_SERVICE_KEY", "AUTO_BIND_KEY", "started", "waitForLocalService", "hostedExit", "external", "item", "RemoteTab", "LocalServiceCard", "OfflineCard", "PairCard", "code", "result", "ReadyView", "attempt", "resolve", "exit", "onToggle", "portTaken", "Command", "onPair", "setCode", "valid", "event", "onStatus", "boundElsewhere", "sameServer", "unpair", "BindingBadge", "BindCard", "provider", "rebind", "devices", "setDevices", "choice", "setChoice", "name", "setName", "serverUrl", "setServerUrl", "cancelled", "device", "bind", "deviceId", "pairing", "startAutoBind", "deferredFor", "failedAt", "tick", "startLocalServiceIfEnabled", "index_default", "definePlugin"]
|
|
7
7
|
}
|