toc-ocra 0.2.13 → 0.2.14

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 CHANGED
@@ -23,7 +23,7 @@ node dist/src/index.js run
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
28
  **本机**(一键启用 / 关闭)
29
29
 
@@ -40,6 +40,12 @@ node dist/src/index.js run
40
40
  3. 「接收任务」开关调用 `PUT /api/devices/:id/enabled`:关闭即停用,保留配对、不再派发任务,重新打开立即恢复,不需要操作那台电脑。彻底卸载在那台电脑执行 `toc-ocra service:uninstall`。
41
41
  4. 服务器地址必须能被那台电脑访问,填 `127.0.0.1` / `localhost` 时插件会提示。
42
42
 
43
+ **TB Switch**(跨设备切换已配置项)
44
+
45
+ 1. 在页面上方选择工作空间中的设备;插件会记住每个工作空间上次选择的设备。
46
+ 2. 选择 Codex、Claude Code 或 Gemini CLI,查看并切换该设备上已配置的供应商模式、供应商或默认路由。
47
+ 3. 只允许设备所有者或工作空间管理员修改;离线、未配对或已暂停的设备显示状态并禁用操作。插件不负责安装或编辑供应商与路由。
48
+
43
49
  插件通过 `http://127.0.0.1:17339` 连接本机服务;手动启动的服务仍用 6 位连接码(`toc-ocra code` 查看)换取控制令牌。
44
50
 
45
51
  本机控制接口(`/control/*`)只接受 `127.0.0.1` / `localhost` 的 Host 和来源,除 `info`、`pair` 外都要 `Authorization: Bearer <控制令牌>`。控制令牌保存在数据目录的 `control-token`(0600),连接码在 `connection-code`(0600,使用后或连续输错 5 次后更换)。
@@ -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}.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)}
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)}.da-provider-page{display:grid;gap:12px}.da-provider-toolbar,.da-provider-device{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px}.da-provider-device label,.da-provider-app-select label{font-size:12px;color:var(--da-muted)}.da-provider-device .da-select{width:min(380px,62vw)}.da-provider-heading{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:10px}.da-provider-heading>div:first-child{min-width:180px;flex:1}.da-provider-heading .da-text{margin:5px 0 0;color:var(--da-muted)}.da-provider-app-select{display:flex;flex-wrap:wrap;align-items:center;gap:7px}.da-provider-app-select .da-select{min-width:145px}.da-provider-message{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:11px 12px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);font-size:12.5px;line-height:1.6;color:var(--da-muted)}.da-provider-warn{border-color:color-mix(in srgb,var(--warn, #b45309) 35%,transparent);color:var(--warn, #b45309)}.da-provider-error{border-color:color-mix(in srgb,var(--da-danger) 35%,transparent);color:var(--da-danger)}.da-provider-notice{padding:8px 10px;border:1px solid color-mix(in srgb,var(--ok, #16a34a) 30%,transparent);border-radius:var(--radius-md, 8px);color:var(--ok, #16a34a);font-size:12px}.da-provider-controls{display:grid;gap:16px}.da-provider-section-title{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;font-size:12px;font-weight:600}.da-provider-mode-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.da-provider-mode{display:flex;min-height:66px;gap:10px;align-items:flex-start;padding:10px 12px;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px);background:transparent;color:inherit;text-align:left;cursor:pointer}.da-provider-mode:hover:not(:disabled),.da-provider-item:hover:not(:disabled){background:var(--bg-hover, rgba(127, 127, 127, .08))}.da-provider-mode:focus-visible,.da-provider-item:focus-visible{outline:2px solid var(--accent, #6366f1);outline-offset:2px}.da-provider-mode:disabled,.da-provider-item:disabled{opacity:.65;cursor:not-allowed}.da-provider-mode-active{border-color:var(--accent, #6366f1);background:color-mix(in srgb,var(--accent, #6366f1) 8%,transparent)}.da-provider-mode strong,.da-provider-mode small,.da-provider-item-copy strong,.da-provider-item-copy small{display:block}.da-provider-mode strong,.da-provider-item-copy strong{font-size:12.5px;font-weight:600}.da-provider-mode small,.da-provider-item-copy small{margin-top:3px;font-size:11.5px;line-height:1.5;color:var(--da-muted)}.da-provider-radio{display:inline-flex;width:15px;height:15px;flex:0 0 15px;align-items:center;justify-content:center;margin-top:1px;border:1px solid var(--da-border);border-radius:50%;color:#fff;font-size:10px}.da-provider-radio-active{border-color:var(--accent, #6366f1);background:var(--accent, #6366f1)}.da-provider-list{overflow:hidden;border:1px solid var(--da-border);border-radius:var(--radius-md, 8px)}.da-provider-item{display:flex;width:100%;min-height:50px;align-items:center;gap:10px;padding:8px 11px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}.da-provider-item+.da-provider-item{border-top:1px solid var(--da-border)}.da-provider-item-copy{min-width:0;flex:1}.da-provider-item-copy strong,.da-provider-item-copy small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.da-provider-warnings{padding:10px 12px;border:1px solid color-mix(in srgb,var(--warn, #b45309) 30%,transparent);border-radius:var(--radius-md, 8px);font-size:12px}.da-provider-warnings ul{margin:5px 0 0;padding-left:18px;color:var(--da-muted);line-height:1.6}@media(max-width:560px){.da-provider-device{flex:1;justify-content:flex-start}.da-provider-device .da-select{width:min(100%,62vw)}.da-provider-mode-grid{grid-template-columns:1fr}}
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.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": "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",
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.da-provider-page { display: grid; gap: 12px; }\n.da-provider-toolbar { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }\n.da-provider-device { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }\n.da-provider-device label, .da-provider-app-select label { font-size: 12px; color: var(--da-muted); }\n.da-provider-device .da-select { width: min(380px, 62vw); }\n.da-provider-heading { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 10px; }\n.da-provider-heading > div:first-child { min-width: 180px; flex: 1; }\n.da-provider-heading .da-text { margin: 5px 0 0; color: var(--da-muted); }\n.da-provider-app-select { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }\n.da-provider-app-select .da-select { min-width: 145px; }\n.da-provider-message { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 11px 12px; border: 1px solid var(--da-border); border-radius: var(--radius-md, 8px); font-size: 12.5px; line-height: 1.6; color: var(--da-muted); }\n.da-provider-warn { border-color: color-mix(in srgb, var(--warn, #b45309) 35%, transparent); color: var(--warn, #b45309); }\n.da-provider-error { border-color: color-mix(in srgb, var(--da-danger) 35%, transparent); color: var(--da-danger); }\n.da-provider-notice { padding: 8px 10px; border: 1px solid color-mix(in srgb, var(--ok, #16a34a) 30%, transparent); border-radius: var(--radius-md, 8px); color: var(--ok, #16a34a); font-size: 12px; }\n.da-provider-controls { display: grid; gap: 16px; }\n.da-provider-section-title { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12px; font-weight: 600; }\n.da-provider-mode-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\n.da-provider-mode { display: flex; min-height: 66px; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--da-border); border-radius: var(--radius-md, 8px); background: transparent; color: inherit; text-align: left; cursor: pointer; }\n.da-provider-mode:hover:not(:disabled), .da-provider-item:hover:not(:disabled) { background: var(--bg-hover, rgba(127, 127, 127, 0.08)); }\n.da-provider-mode:focus-visible, .da-provider-item:focus-visible { outline: 2px solid var(--accent, #6366f1); outline-offset: 2px; }\n.da-provider-mode:disabled, .da-provider-item:disabled { opacity: .65; cursor: not-allowed; }\n.da-provider-mode-active { border-color: var(--accent, #6366f1); background: color-mix(in srgb, var(--accent, #6366f1) 8%, transparent); }\n.da-provider-mode strong, .da-provider-mode small, .da-provider-item-copy strong, .da-provider-item-copy small { display: block; }\n.da-provider-mode strong, .da-provider-item-copy strong { font-size: 12.5px; font-weight: 600; }\n.da-provider-mode small, .da-provider-item-copy small { margin-top: 3px; font-size: 11.5px; line-height: 1.5; color: var(--da-muted); }\n.da-provider-radio { display: inline-flex; width: 15px; height: 15px; flex: 0 0 15px; align-items: center; justify-content: center; margin-top: 1px; border: 1px solid var(--da-border); border-radius: 50%; color: white; font-size: 10px; }\n.da-provider-radio-active { border-color: var(--accent, #6366f1); background: var(--accent, #6366f1); }\n.da-provider-list { overflow: hidden; border: 1px solid var(--da-border); border-radius: var(--radius-md, 8px); }\n.da-provider-item { display: flex; width: 100%; min-height: 50px; align-items: center; gap: 10px; padding: 8px 11px; border: 0; background: transparent; color: inherit; text-align: left; cursor: pointer; }\n.da-provider-item + .da-provider-item { border-top: 1px solid var(--da-border); }\n.da-provider-item-copy { min-width: 0; flex: 1; }\n.da-provider-item-copy strong, .da-provider-item-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.da-provider-warnings { padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--warn, #b45309) 30%, transparent); border-radius: var(--radius-md, 8px); font-size: 12px; }\n.da-provider-warnings ul { margin: 5px 0 0; padding-left: 18px; color: var(--da-muted); line-height: 1.6; }\n@media (max-width: 560px) {\n .da-provider-device { flex: 1; justify-content: flex-start; }\n .da-provider-device .da-select { width: min(100%, 62vw); }\n .da-provider-mode-grid { grid-template-columns: 1fr; }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- var Te=Object.create;var ie=Object.defineProperty;var Le=Object.getOwnPropertyDescriptor;var xe=Object.getOwnPropertyNames;var Ee=Object.getPrototypeOf,Be=Object.prototype.hasOwnProperty;var ne=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Ie=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of xe(t))!Be.call(e,c)&&c!==r&&ie(e,c,{get:()=>t[c],enumerable:!(o=Le(t,c))||o.enumerable});return e};var P=(e,t,r)=>(r=e!=null?Te(Ee(e)):{},Ie(t||!e||!e.__esModule?ie(r,"default",{value:e,enumerable:!0}):r,e));var W=ne((rt,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 G=ne((it,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=ne((ct,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(W(),1);var ce=P(W(),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 re(e,t){return(0,ce.useSyncExternalStore)(r=>e.core.onContextChange(t,r),()=>e.core.context(t))}var m=P(G(),1);var X="http://127.0.0.1:17339",x=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 x("offline","local service unreachable")}let h=await c.json().catch(()=>null);if(c.status===401)throw new x("unauthorized","unauthorized");if(!c.ok){let s=typeof h?.error=="string"?h.error:"",v=typeof h?.message=="string"?h.message:s||`HTTP ${c.status}`;throw new x("rejected",v,s)}return h}var I={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 Q(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(W(),1),b=P(G(),1);var he=P(W(),1),we=P(G(),1);var Y=P(M(),1),A="controlToken",Z="localUrl",F="autoBind",ee="localService";function j(e,t){return t instanceof x&&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,Y.jsxs)("div",{className:"da-command",children:[(0,Y.jsx)("code",{children:t}),(0,Y.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),ae=["linux","mac","win"],Re=1e4,Oe=3e3,te="remoteServerUrl",Ue=new Set(["127.0.0.1","localhost","[::1]","::1","0.0.0.0"]);function De(e){try{let t=new URL(e.trim());return t.protocol==="http:"||t.protocol==="https:"?t.origin:null}catch{return null}}function Ae(e){try{return Ue.has(new URL(e).hostname)}catch{return!1}}function ze(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)(b.Badge,{variant:"ok",children:e.t("remote.status.online")}):t.status==="disabled"?(0,n.jsx)(b.Badge,{variant:"warn",children:e.t("remote.status.disabled")}):t.status==="offline"?(0,n.jsx)(b.Badge,{variant:"err",children:e.t("remote.status.offline")}):(0,n.jsx)(b.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,v]=(0,C.useState)(""),[u,d]=(0,C.useState)(!1),[g,p]=(0,C.useState)(null),[E,R]=(0,C.useState)(!1),[O,U]=(0,C.useState)(""),[S,N]=(0,C.useState)("linux"),[_,f]=(0,C.useState)(()=>e.storage.get(te,"")||t?.origin||""),T=(0,C.useRef)(g);T.current=g;let B=(0,C.useRef)(!0);(0,C.useEffect)(()=>{!e.storage.get(te,"")&&t?.origin&&f(t.origin)},[e,t?.origin]);let z=(0,C.useCallback)(async()=>{if(r?.id)try{let i=await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices`);if(!B.current)return;let k=(i.items??[]).filter($=>$.is_mine&&$.id!==o);h(k);let D=T.current;if(D&&!D.matched){let $=k.find(Pe=>Pe.id===D.deviceId);$?.agent_id&&$.agent_id!==D.baseline&&$.terminal_online&&(p({...D,matched:!0}),e.notify({title:e.t("page.title"),body:e.t("remote.matchedNotice",{name:$.name})}))}}catch(i){B.current&&v(j(e,i))}},[e,o,r?.id]),V=!!(g&&!g.matched);(0,C.useEffect)(()=>{B.current=!0,z();let i=window.setInterval(()=>{z()},V?Oe:Re);return()=>{B.current=!1,window.clearInterval(i)}},[z,V]);let l=async i=>{d(!0),v("");try{await i()}catch(k){v(j(e,k))}finally{d(!1)}},w=De(_),L=i=>{f(i),i.trim()&&i.trim()!==t?.origin?e.storage.set(te,i.trim()):e.storage.remove(te)},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:ae.includes(i.platform)?i.platform:"linux",code:k.code,expiresAt:k.expires_at,baseline:i.agent_id??null,matched:!1})}),Se=()=>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}),R(!1),U(""),await z()}),Ne=(i,k)=>l(async()=>{await e.core.request(`/devices/${encodeURIComponent(i.id)}/enabled`,{method:"PUT",body:JSON.stringify({enabled:k})}),await z()});return(0,n.jsxs)(n.Fragment,{children:[s&&(0,n.jsx)("div",{role:"alert",className:"da-alert",children:s}),(0,n.jsxs)(b.Card,{children:[(0,n.jsx)(b.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)(b.Input,{value:_,onChange:i=>L(i.target.value),spellCheck:!1,className:"da-mono"})]}),!w&&(0,n.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.serverInvalid")}),w&&Ae(w)&&(0,n.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.loopback")}),!E&&(0,n.jsx)("div",{className:"da-row",children:(0,n.jsx)(b.Btn,{primary:!0,disabled:u||!r?.id,onClick:()=>R(!0),children:e.t("remote.add")})}),E&&(0,n.jsxs)("form",{className:"da-form",onSubmit:i=>{i.preventDefault(),Se()},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:ae.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)(b.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)(b.Btn,{primary:!0,type:"submit",disabled:u||!w,children:e.t(u?"remote.working":"remote.generate")}),(0,n.jsx)(b.Btn,{type:"button",disabled:u,onClick:()=>R(!1),children:e.t("remote.cancel")})]})]})]}),g&&w&&(0,n.jsx)(Me,{ctx:e,pending:g,origin:w,busy:u,onPlatform:i=>p({...g,platform:i}),onRegenerate:()=>{oe({id:g.deviceId,name:g.deviceName,platform:g.platform,agent_id:g.baseline})},onClose:()=>p(null)}),(0,n.jsxs)(b.Card,{children:[(0,n.jsx)(b.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.${ae.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)(b.Btn,{disabled:u||!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)(b.Toggle,{checked:!i.disabled,disabled:u,label:e.t("remote.enabled"),onChange:k=>{Ne(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 Me({ctx:e,pending:t,origin:r,busy:o,onPlatform:c,onRegenerate:h,onClose:s}){let[v,u]=(0,C.useState)(()=>Math.floor(Date.now()/1e3));(0,C.useEffect)(()=>{if(t.matched)return;let p=window.setInterval(()=>u(Math.floor(Date.now()/1e3)),1e3);return()=>window.clearInterval(p)},[t.matched]);let d=Math.max(0,t.expiresAt-v),g=!t.matched&&d===0;return(0,n.jsxs)(b.Card,{children:[(0,n.jsx)(b.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)(b.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)(b.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:ae.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:ze(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:g?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:g?"":e.t("remote.waiting")}),(0,n.jsxs)("div",{className:"da-row",children:[(0,n.jsx)(b.Btn,{disabled:o,onClick:h,children:e.t("remote.regenerate")}),(0,n.jsx)(b.Btn,{disabled:o,onClick:s,children:e.t("remote.cancel")})]})]})]})}var a=P(M(),1),Ke=3e3,qe=1e4,He=6e4,We=3,Ce="tab",Ye=new URL("../../assets/icon.svg",import.meta.url).href;function Fe(){return(0,a.jsx)("img",{src:Ye,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 J=e=>e?.state==="running"||e?.state==="starting";async function ke(e){try{return await I.info(e),!0}catch{return!1}}var H;function je({ctx:e}){let t=re(e,"server"),r=re(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(Z,X)),[v,u]=(0,y.useState)(()=>e.secureStorage.get(A,"")),[d,g]=(0,y.useState)({kind:"checking"}),[p,E]=(0,y.useState)(null),[R,O]=(0,y.useState)(""),[U,S]=(0,y.useState)(!1),N=(0,y.useRef)(!0),_=_e(e),f=(0,y.useCallback)(async()=>{let l=null;if(_)try{l=await _.status()}catch{l=null}if(!N.current)return;E(l);let w=v;J(l)&&l?.token&&(w=l.token,l.token!==v&&(e.secureStorage.set(A,l.token),u(l.token)));try{await I.info(s)}catch{N.current&&g({kind:J(l)?"starting":"offline"});return}if(!w){N.current&&g({kind:"needsCode"});return}try{let L=await I.status(s,w);N.current&&g({kind:"ready",status:L})}catch(L){if(!N.current)return;L instanceof x&&L.kind==="unauthorized"?(e.secureStorage.remove(A),u(""),g({kind:"needsCode"})):g({kind:"offline"})}},[e,s,_,v]);(0,y.useEffect)(()=>{N.current=!0,f();let l=window.setInterval(()=>{f()},Ke);return()=>{N.current=!1,window.clearInterval(l)}},[f]),(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 T=async l=>{S(!0),O("");try{await l()}catch(w){O(j(e,w))}finally{S(!1)}},B=l=>T(async()=>{if(!_)return;if(!l){e.storage.set(ee,"off"),E(await _.stop()),await f();return}if(e.storage.set(ee,"on"),e.storage.remove(F),!J(p)&&await ke(s)){H?.(),await f();return}let w=await _.start();E(w),w.token&&(e.secureStorage.set(A,w.token),u(w.token)),await Je(s,()=>N.current)&&H?.(),await f()}),z=p?.state==="exited"?p:null,V=!!_&&!J(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))}),R&&(0,a.jsx)("div",{role:"alert",className:"da-alert",children:R}),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)(Ve,{ctx:e,status:p,external:V,exit:z,busy:U,onToggle:l=>{B(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)(Ge,{ctx:e,localUrl:s}),d.kind==="needsCode"&&(0,a.jsx)(Xe,{ctx:e,busy:U,onPair:l=>T(async()=>{let w=await I.pair(s,l).catch(L=>{throw L instanceof x&&L.code==="code_wrong"?new Error(e.t("pair.wrong")):L instanceof x&&L.code==="locked"?new Error(e.t("pair.locked")):L});e.secureStorage.set(A,w.token),u(w.token)})}),d.kind==="ready"&&(0,a.jsx)(Qe,{ctx:e,status:d.status,server:t,workspace:r,busy:U,run:T,localUrl:s,token:v,onStatus:l=>g({kind:"ready",status:l})})]})]})}async function Je(e,t){for(let r=0;r<30&&t();r+=1)try{return await I.info(e),!0}catch{await new Promise(o=>window.setTimeout(o,500))}return!1}function Ve({ctx:e,status:t,external:r,exit:o,busy:c,onToggle:h}){let s=J(t),v=!s&&r,u=s||v,d=o?.exitCode===We;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(v?"service.onExternalBody":u?"service.onBody":"service.offBody")})]}),(0,a.jsx)(m.Toggle,{checked:u,disabled:c||v,label:e.t("service.title"),onChange:h})]}),s&&(0,a.jsx)("p",{className:"da-muted",children:e.t("service.followsApp")}),v&&(0,a.jsx)("p",{className:"da-muted",children:e.t("service.external")}),!u&&d&&(0,a.jsx)("p",{className:"da-muted",children:e.t("service.portTaken")}),o&&!d&&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 Ge({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 Xe({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 Qe({ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:v,onStatus:u}){let d=t.paired&&r&&!Q(t.server_url,r.origin),g=()=>h(async()=>{t.device_id&&r&&Q(t.server_url,r.origin)&&await e.core.request(`/devices/${encodeURIComponent(t.device_id)}/agent`,{method:"DELETE"}).catch(()=>{}),e.storage.set(F,"off"),u(await I.unpair(s,v))});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)(Ze,{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:()=>{g()},children:e.t("status.unpair")})})]}),(!t.paired||t.unauthorized||d)&&(0,a.jsx)(et,{ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:v,onStatus:u,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()=>u(await I.detect(s,v)))},children:e.t("cli.redetect")})})]})]})}function Ze({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 et({ctx:e,status:t,server:r,workspace:o,busy:c,run:h,localUrl:s,token:v,onStatus:u,rebind:d}){let[g,p]=(0,y.useState)([]),[E,R]=(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 f=!1;return e.core.request(`/workspaces/${encodeURIComponent(o.id)}/devices`).then(T=>{f||p((T.items??[]).filter(B=>B.is_mine))}).catch(()=>{f||p([])}),()=>{f=!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 f=E,T;if(E==="new"){if(!t.machine_id)throw new Error(e.t("bind.identityRequired"));let B=await e.core.request("/devices/machine/pairing-code",{method:"POST",body:JSON.stringify({machine_id:t.machine_id,hostname:O.trim()||t.hostname,platform:t.platform,current_device_id:t.paired?t.device_id:""})});f=B.device_id,R(f),T=B}else T=await e.core.request(`/devices/${encodeURIComponent(f)}/pairing-code`,{method:"POST"});u(await I.enroll(s,v,S.trim(),T.code)),e.storage.remove(F),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:f=>N(f.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:E,onChange:f=>R(f.target.value),children:[(0,a.jsx)("option",{value:"new",children:e.t("bind.newDevice")}),g.map(f=>(0,a.jsxs)("option",{value:f.id,children:[f.name,f.paired?` \xB7 ${e.t("bind.replaces")}`:""]},f.id))]})]}),E==="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:f=>U(f.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 tt(e){let t=!1,r="",o=new Map,c=async()=>{if(t||e.signal.aborted)return;let s=e.core.context("server"),v=e.secureStorage.get(A,"");if(!(!s?.origin||!v||e.storage.get(F,"on")==="off")&&!(Date.now()-(o.get(s.origin)??0)<He)){t=!0;try{let u=e.storage.get(Z,X),d=await I.status(u,v);if(!d.machine_id||d.token_from_env)return;if(d.paired&&(d.unauthorized||Q(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 g=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 I.enroll(u,v,s.origin,g.code),r="",o.delete(s.origin),e.notify({title:e.t("page.title"),body:e.t("auto.done",{server:s.name||s.origin,device:g.device_name})})}catch(u){(!(u instanceof x)||u.kind==="rejected")&&o.set(s.origin,Date.now())}finally{t=!1}}},h=window.setInterval(()=>{c()},qe);H=()=>{c()},e.registerDisposer(()=>{window.clearInterval(h),H=void 0}),e.registerDisposer(e.core.onContextChange("server",()=>{c()})),window.setTimeout(()=>{c()},1500)}function at(e){let t=_e(e);if(!t||e.storage.get(ee,"off")!=="on")return;let r=e.storage.get(Z,X);ke(r).then(o=>{if(o){window.setTimeout(()=>H?.(),3e3);return}return t.start()}).then(o=>{o&&(o.token&&e.secureStorage.set(A,o.token),window.setTimeout(()=>H?.(),3e3))}).catch(()=>{})}var yt=me({activate(e){e.registerNavigation("agent.nav",(0,a.jsx)(Fe,{})),e.registerRoute("agent.home",(0,a.jsx)(je,{ctx:e})),at(e),tt(e)}});export{yt as default};
1
+ var Ve=Object.create;var Se=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Xe=Object.getOwnPropertyNames;var Qe=Object.getPrototypeOf,Ze=Object.prototype.hasOwnProperty;var ye=(e,r)=>()=>{try{return r||e((r={exports:{}}).exports,r),r.exports}catch(i){throw r=0,i}};var er=(e,r,i,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let u of Xe(r))!Ze.call(e,u)&&u!==i&&Se(e,u,{get:()=>r[u],enumerable:!(n=Ge(r,u))||n.enumerable});return e};var D=(e,r,i)=>(i=e!=null?Ve(Qe(e)):{},er(r||!e||!e.__esModule?Se(i,"default",{value:e,enumerable:!0}):i,e));var X=ye((Tr,Te)=>{var Pe=globalThis.__TOC_PLUGIN_SHARED__,xe=Pe&&Pe.react;if(!xe)throw new Error("The host does not provide react; this plugin needs a newer app version.");Te.exports=xe});var ie=ye((Lr,Re)=>{var Ee=globalThis.__TOC_PLUGIN_SHARED__,Be=Ee&&Ee["@toc-starter/plugin-sdk/ui"];if(!Be)throw new Error("The host does not provide @toc-starter/plugin-sdk/ui; this plugin needs a newer app version.");Re.exports=Be});var H=ye((Dr,Ae)=>{var De=globalThis.__TOC_PLUGIN_SHARED__,Oe=De&&De["react/jsx-runtime"];if(!Oe)throw new Error("The host does not provide react/jsx-runtime; this plugin needs a newer app version.");Ae.exports=Oe});var S=D(X(),1);var Ie=D(X(),1);function Le(e){if(!e||typeof e.activate!="function")throw new TypeError("definePlugin() needs an object with an activate(context) function");return e}function we(e,r){return(0,Ie.useSyncExternalStore)(i=>e.core.onContextChange(r,i),()=>e.core.context(r))}var g=D(ie(),1);var pe="http://127.0.0.1:17339",z=class extends Error{constructor(i,n,u=""){super(n);this.kind=i;this.code=u}kind;code};async function Q(e,r,i={}){let n=new Headers(i.headers);i.token&&n.set("Authorization",`Bearer ${i.token}`),i.body&&n.set("Content-Type","application/json");let u;try{u=await fetch(`${e.replace(/\/+$/,"")}${r}`,{...i,headers:n,cache:"no-store"})}catch{throw new z("offline","local service unreachable")}let h=await u.json().catch(()=>null);if(u.status===401)throw new z("unauthorized","unauthorized");if(!u.ok){let c=typeof h?.error=="string"?h.error:"",f=typeof h?.message=="string"?h.message:c||`HTTP ${u.status}`;throw new z("rejected",f,c)}return h}var q={info:e=>Q(e,"/control/info"),pair:(e,r)=>Q(e,"/control/pair",{method:"POST",body:JSON.stringify({code:r})}),status:(e,r)=>Q(e,"/control/status",{token:r}),enroll:(e,r,i,n)=>Q(e,"/control/enroll",{method:"POST",token:r,body:JSON.stringify({server_url:i,code:n})}),unpair:(e,r)=>Q(e,"/control/unpair",{method:"POST",token:r}),detect:(e,r)=>Q(e,"/control/detect",{method:"POST",token:r})};function me(e,r){let i=n=>{try{return new URL(n).origin.toLowerCase()}catch{return n.trim().replace(/\/+$/,"").toLowerCase()}};return!!(e&&r)&&i(e)===i(r)}var E=D(X(),1),C=D(ie(),1);var Ue=D(X(),1),$e=D(ie(),1);var ae=D(H(),1),F="controlToken",ue="localUrl",oe="autoBind",ve="localService";function ne(e,r){return r instanceof z&&r.kind==="offline"?e.t("error.offline"):r instanceof Error?r.message:String(r)}function V({ctx:e,value:r}){let[i,n]=(0,Ue.useState)(!1);return(0,ae.jsxs)("div",{className:"da-command",children:[(0,ae.jsx)("code",{children:r}),(0,ae.jsx)($e.Btn,{onClick:()=>{navigator.clipboard.writeText(r).then(()=>{n(!0),window.setTimeout(()=>n(!1),1500)})},children:i?e.t("common.copied"):e.t("common.copy")})]})}var o=D(H(),1),fe=["linux","mac","win"],rr=1e4,tr=3e3,ge="remoteServerUrl",ir=new Set(["127.0.0.1","localhost","[::1]","::1","0.0.0.0"]);function ar(e){try{let r=new URL(e.trim());return r.protocol==="http:"||r.protocol==="https:"?r.origin:null}catch{return null}}function or(e){try{return ir.has(new URL(e).hostname)}catch{return!1}}function nr(e,r,i){let n=`toc-ocra setup --code ${r} --server ${i}`;return e==="win"?`npm install -g toc-ocra@latest; if ($?) { ${n} }`:`npm install -g toc-ocra@latest && ${n}`}function dr({ctx:e,device:r}){return r.status==="online"?(0,o.jsx)(C.Badge,{variant:"ok",children:e.t("remote.status.online")}):r.status==="disabled"?(0,o.jsx)(C.Badge,{variant:"warn",children:e.t("remote.status.disabled")}):r.status==="offline"?(0,o.jsx)(C.Badge,{variant:"err",children:e.t("remote.status.offline")}):(0,o.jsx)(C.Badge,{variant:"muted",children:e.t("remote.status.notConnected")})}function ze({ctx:e,server:r,workspace:i,localDeviceId:n}){let[u,h]=(0,E.useState)(null),[c,f]=(0,E.useState)(""),[v,l]=(0,E.useState)(!1),[b,d]=(0,E.useState)(null),[k,y]=(0,E.useState)(!1),[O,K]=(0,E.useState)(""),[L,B]=(0,E.useState)("linux"),[P,w]=(0,E.useState)(()=>e.storage.get(ge,"")||r?.origin||""),U=(0,E.useRef)(b);U.current=b;let R=(0,E.useRef)(!0);(0,E.useEffect)(()=>{!e.storage.get(ge,"")&&r?.origin&&w(r.origin)},[e,r?.origin]);let $=(0,E.useCallback)(async()=>{if(i?.id)try{let s=await e.core.request(`/workspaces/${encodeURIComponent(i.id)}/devices`);if(!R.current)return;let x=(s.items??[]).filter(M=>M.is_mine&&M.id!==n);h(x);let W=U.current;if(W&&!W.matched){let M=x.find(te=>te.id===W.deviceId);M?.agent_id&&M.agent_id!==W.baseline&&M.terminal_online&&(d({...W,matched:!0}),e.notify({title:e.t("page.title"),body:e.t("remote.matchedNotice",{name:M.name})}))}}catch(s){R.current&&f(ne(e,s))}},[e,n,i?.id]),Y=!!(b&&!b.matched);(0,E.useEffect)(()=>{R.current=!0,$();let s=window.setInterval(()=>{$()},Y?tr:rr);return()=>{R.current=!1,window.clearInterval(s)}},[$,Y]);let p=async s=>{l(!0),f("");try{await s()}catch(x){f(ne(e,x))}finally{l(!1)}},_=ar(P),A=s=>{w(s),s.trim()&&s.trim()!==r?.origin?e.storage.set(ge,s.trim()):e.storage.remove(ge)},j=s=>p(async()=>{if(!_)throw new Error(e.t("remote.serverInvalid"));let x=await e.core.request(`/devices/${encodeURIComponent(s.id)}/pairing-code`,{method:"POST"});d({deviceId:s.id,deviceName:s.name,platform:fe.includes(s.platform)?s.platform:"linux",code:x.code,expiresAt:x.expires_at,baseline:s.agent_id??null,matched:!1})}),J=()=>p(async()=>{if(!i?.id)throw new Error(e.t("bind.noWorkspace"));if(!_)throw new Error(e.t("remote.serverInvalid"));let s=O.trim()||e.t(`remote.platform.${L}`),x=await e.core.request(`/workspaces/${encodeURIComponent(i.id)}/devices`,{method:"POST",body:JSON.stringify({name:s,location:L==="linux"?"cloud":"local",platform:L,note:"",share_to_workspace:!1})}),W=await e.core.request(`/devices/${encodeURIComponent(x.id)}/pairing-code`,{method:"POST"});d({deviceId:x.id,deviceName:x.name||s,platform:L,code:W.code,expiresAt:W.expires_at,baseline:null,matched:!1}),y(!1),K(""),await $()}),re=(s,x)=>p(async()=>{await e.core.request(`/devices/${encodeURIComponent(s.id)}/enabled`,{method:"PUT",body:JSON.stringify({enabled:x})}),await $()});return(0,o.jsxs)(o.Fragment,{children:[c&&(0,o.jsx)("div",{role:"alert",className:"da-alert",children:c}),(0,o.jsxs)(C.Card,{children:[(0,o.jsx)(C.CardTitle,{children:e.t("remote.title")}),(0,o.jsx)("p",{className:"da-text",children:e.t("remote.body")}),(0,o.jsxs)("label",{className:"da-field",children:[(0,o.jsx)("span",{children:e.t("remote.server")}),(0,o.jsx)(C.Input,{value:P,onChange:s=>A(s.target.value),spellCheck:!1,className:"da-mono"})]}),!_&&(0,o.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.serverInvalid")}),_&&or(_)&&(0,o.jsx)("p",{className:"da-muted da-warn",children:e.t("remote.loopback")}),!k&&(0,o.jsx)("div",{className:"da-row",children:(0,o.jsx)(C.Btn,{primary:!0,disabled:v||!i?.id,onClick:()=>y(!0),children:e.t("remote.add")})}),k&&(0,o.jsxs)("form",{className:"da-form",onSubmit:s=>{s.preventDefault(),J()},children:[(0,o.jsxs)("label",{className:"da-field",children:[(0,o.jsx)("span",{children:e.t("remote.platformLabel")}),(0,o.jsx)("select",{className:"da-select",value:L,onChange:s=>B(s.target.value),children:fe.map(s=>(0,o.jsx)("option",{value:s,children:e.t(`remote.platform.${s}`)},s))})]}),(0,o.jsxs)("label",{className:"da-field",children:[(0,o.jsx)("span",{children:e.t("remote.name")}),(0,o.jsx)(C.Input,{value:O,onChange:s=>K(s.target.value),maxLength:100,placeholder:e.t("remote.namePlaceholder")})]}),(0,o.jsxs)("div",{className:"da-row",children:[(0,o.jsx)(C.Btn,{primary:!0,type:"submit",disabled:v||!_,children:e.t(v?"remote.working":"remote.generate")}),(0,o.jsx)(C.Btn,{type:"button",disabled:v,onClick:()=>y(!1),children:e.t("remote.cancel")})]})]})]}),b&&_&&(0,o.jsx)(sr,{ctx:e,pending:b,origin:_,busy:v,onPlatform:s=>d({...b,platform:s}),onRegenerate:()=>{j({id:b.deviceId,name:b.deviceName,platform:b.platform,agent_id:b.baseline})},onClose:()=>d(null)}),(0,o.jsxs)(C.Card,{children:[(0,o.jsx)(C.CardTitle,{children:e.t("remote.listTitle")}),u===null&&(0,o.jsx)("p",{className:"da-muted",children:e.t("common.checking")}),u?.length===0&&(0,o.jsx)("p",{className:"da-muted",children:e.t("remote.empty")}),u&&u.length>0&&(0,o.jsx)("ul",{className:"da-devices",children:u.map(s=>(0,o.jsxs)("li",{children:[(0,o.jsxs)("div",{className:"da-device-main",children:[(0,o.jsx)("span",{className:"da-device-name",children:s.name}),(0,o.jsxs)("span",{className:"da-muted",children:[e.t(`remote.platform.${fe.includes(s.platform)?s.platform:"linux"}`),s.agent_version?` \xB7 toc-ocra ${s.agent_version}`:""]})]}),(0,o.jsx)(dr,{ctx:e,device:s}),(0,o.jsxs)("div",{className:"da-device-actions",children:[(!s.paired||s.status==="offline"||s.status==="not_connected")&&(0,o.jsx)(C.Btn,{disabled:v||!_,onClick:()=>{j(s)},children:e.t(s.paired?"remote.repair":"remote.install")}),s.paired&&(0,o.jsxs)("label",{className:"da-toggle",children:[(0,o.jsx)("span",{children:e.t("remote.enabled")}),(0,o.jsx)(C.Toggle,{checked:!s.disabled,disabled:v,label:e.t("remote.enabled"),onChange:x=>{re(s,x)}})]})]})]},s.id))}),(0,o.jsx)("p",{className:"da-muted",children:e.t("remote.disableHint")}),(0,o.jsx)("div",{className:"da-step",children:e.t("remote.uninstall")}),(0,o.jsx)(V,{ctx:e,value:"toc-ocra service:uninstall"})]})]})}function sr({ctx:e,pending:r,origin:i,busy:n,onPlatform:u,onRegenerate:h,onClose:c}){let[f,v]=(0,E.useState)(()=>Math.floor(Date.now()/1e3));(0,E.useEffect)(()=>{if(r.matched)return;let d=window.setInterval(()=>v(Math.floor(Date.now()/1e3)),1e3);return()=>window.clearInterval(d)},[r.matched]);let l=Math.max(0,r.expiresAt-f),b=!r.matched&&l===0;return(0,o.jsxs)(C.Card,{children:[(0,o.jsx)(C.CardTitle,{children:e.t("remote.pendingTitle",{name:r.deviceName})}),r.matched?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("p",{className:"da-text",children:[(0,o.jsx)(C.Badge,{variant:"ok",children:e.t("remote.matched")})," ",e.t("remote.matchedBody",{name:r.deviceName})]}),(0,o.jsx)("div",{className:"da-row",children:(0,o.jsx)(C.Btn,{primary:!0,onClick:c,children:e.t("remote.done")})})]}):(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("p",{className:"da-text",children:e.t("remote.pendingBody")}),(0,o.jsx)("div",{className:"da-segment",role:"radiogroup","aria-label":e.t("remote.platformLabel"),children:fe.map(d=>(0,o.jsx)("button",{type:"button",role:"radio","aria-checked":r.platform===d,className:r.platform===d?"da-seg da-seg-active":"da-seg",onClick:()=>u(d),children:e.t(`remote.platform.${d}`)},d))}),(0,o.jsx)(V,{ctx:e,value:nr(r.platform,r.code,i)}),(0,o.jsxs)("ul",{className:"da-hints",children:[(0,o.jsx)("li",{children:e.t("remote.hintNode")}),r.platform==="linux"&&(0,o.jsx)("li",{children:e.t("remote.hintLinux")}),r.platform==="win"&&(0,o.jsx)("li",{children:e.t("remote.hintWindows")}),(0,o.jsx)("li",{children:b?e.t("remote.expired"):e.t("remote.expires",{minutes:Math.floor(l/60),seconds:String(l%60).padStart(2,"0")})})]}),(0,o.jsx)("p",{className:"da-muted",children:b?"":e.t("remote.waiting")}),(0,o.jsxs)("div",{className:"da-row",children:[(0,o.jsx)(C.Btn,{disabled:n,onClick:h,children:e.t("remote.regenerate")}),(0,o.jsx)(C.Btn,{disabled:n,onClick:c,children:e.t("remote.cancel")})]})]})]})}var T=D(X(),1),N=D(ie(),1),a=D(H(),1),Me=[{id:"codex",label:"Codex"},{id:"claude",label:"Claude Code"},{id:"gemini",label:"Gemini CLI"}],_e="tb-switch-device";function Z(e){return e.terminal_online??e.online??e.status==="online"}function qe(e){return!e.paired||e.status==="not_connected"?{key:"provider.status.notPaired",variant:"muted"}:e.disabled||e.status==="disabled"?{key:"provider.status.paused",variant:"warn"}:Z(e)?{key:"provider.status.online",variant:"ok"}:{key:"provider.status.offline",variant:"err"}}function lr(e,r){return e.find(i=>i.id===r&&i.paired&&!i.disabled&&Z(i))??e.find(i=>i.is_mine&&i.paired&&!i.disabled&&Z(i))??e.find(i=>i.paired&&!i.disabled&&Z(i))??e.find(i=>i.id===r)??e.find(i=>i.paired)??e[0]}function Ce(e){return e instanceof Error?e.message:String(e)}function Ke({ctx:e,workspace:r,localDeviceId:i}){let[n,u]=(0,T.useState)(null),[h,c]=(0,T.useState)(!1),[f,v]=(0,T.useState)(""),[l,b]=(0,T.useState)({workspaceId:"",deviceId:""}),d=(0,T.useRef)(l);d.current=l;let k=l.workspaceId===r?.id?l.deviceId:"",y=n?.find(m=>m.id===k)??null,[O,K]=(0,T.useState)("codex"),[L,B]=(0,T.useState)(null),[P,w]=(0,T.useState)(!1),[U,R]=(0,T.useState)(""),[$,Y]=(0,T.useState)(!1),[p,_]=(0,T.useState)(""),[A,j]=(0,T.useState)(null),J=(0,T.useRef)(0),re=!!(y&&(y.is_mine||r?.role==="owner"||r?.role==="admin")),s=!!(y?.paired&&!y.disabled&&y.status!=="disabled"&&Z(y)),x=(0,T.useCallback)(async(m=!1)=>{if(!r?.id){u([]);let I={workspaceId:"",deviceId:""};d.current=I,b(I);return}m||c(!0),v("");try{let G=(await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices`)).items??[];u(G);let le=d.current,je=le.workspaceId===r.id?le.deviceId:"";if(G.some(he=>he.id===je))return;let Ne="";try{Ne=e.storage.get(`${_e}:${r.id}`,"")}catch{}let Je=G.find(he=>he.id===Ne)??lr(G,i),ce={workspaceId:r.id,deviceId:Je?.id??""};if(d.current=ce,b(ce),ce.deviceId)try{e.storage.set(`${_e}:${r.id}`,ce.deviceId)}catch{}}catch(I){v(Ce(I))}finally{m||c(!1)}},[e,i,r?.id]);(0,T.useEffect)(()=>{x();let m=window.setInterval(()=>{x(!0)},15e3);return()=>window.clearInterval(m)},[x]);let W=m=>{let I={workspaceId:r?.id??"",deviceId:m};if(d.current=I,b(I),_(""),R(""),r?.id)try{e.storage.set(`${_e}:${r.id}`,m)}catch{}},M=y?.id??"",te=(0,T.useCallback)(async()=>{if(!r?.id||!M||!s)return;let m=++J.current;w(!0),R("");try{let I=await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices/${encodeURIComponent(M)}/cli-providers/control`,{method:"POST",body:JSON.stringify({app:O,action:"state"})});m===J.current&&B(I)}catch(I){m===J.current&&(B(null),R(Ce(I)))}finally{m===J.current&&w(!1)}},[O,e,s,M,r?.id]);(0,T.useEffect)(()=>{J.current+=1,w(!1),B(null),_(""),s&&te()},[te,s]);let se=async m=>{if(!(!r?.id||!y||!s||m.action!=="state"&&!re||$)){Y(!0),_(""),R("");try{let I=await e.core.request(`/workspaces/${encodeURIComponent(r.id)}/devices/${encodeURIComponent(y.id)}/cli-providers/control`,{method:"POST",body:JSON.stringify({app:O,...m})});B(I),_(m.action==="state"?e.t("provider.refreshed"):e.t("provider.updated"))}catch(I){R(Ce(I))}finally{Y(!1)}}},be=y?qe(y):null,Ye=r?.role==="owner"||r?.role==="admin",ke=n??[];return(0,a.jsxs)("div",{className:"da-provider-page",children:[(0,a.jsxs)("div",{className:"da-provider-toolbar",children:[(0,a.jsxs)("div",{className:"da-provider-device",children:[(0,a.jsx)("label",{htmlFor:"da-provider-device-select",children:e.t("provider.chooseDevice")}),(0,a.jsxs)("select",{id:"da-provider-device-select",className:"da-select",value:k,onChange:m=>W(m.target.value),disabled:h||ke.length===0||$,children:[(0,a.jsx)("option",{value:"",disabled:!0,children:e.t("provider.selectDevice")}),ke.map(m=>{let I=qe(m),G=m.is_mine?e.t("provider.myDevice"):e.t("provider.owner",{owner:m.owner_name||"\u2014"}),le=m.id===i?` \xB7 ${e.t("provider.thisDevice")}`:"";return(0,a.jsxs)("option",{value:m.id,children:[m.name," \xB7 ",e.t(I.key)," \xB7 ",G,le]},m.id)})]}),y&&be&&(0,a.jsx)(N.Badge,{variant:be.variant,children:e.t(be.key)})]}),(0,a.jsx)(N.Btn,{disabled:h,onClick:()=>{x()},children:h?e.t("provider.loading"):e.t("provider.refreshDevices")})]}),h&&n===null&&(0,a.jsx)(N.Card,{children:(0,a.jsx)("span",{className:"da-muted",children:e.t("provider.loadingDevices")})}),f&&(0,a.jsxs)("div",{role:"alert",className:"da-alert",children:[f,(0,a.jsx)(N.Btn,{disabled:h,onClick:()=>{x()},children:e.t("provider.retry")})]}),!r?.id&&(0,a.jsx)(N.Card,{children:(0,a.jsx)(N.CardTitle,{children:e.t("provider.noWorkspace")})}),r?.id&&n?.length===0&&!h&&(0,a.jsxs)(N.Card,{children:[(0,a.jsx)(N.CardTitle,{children:e.t("provider.noDevices")}),(0,a.jsx)("p",{className:"da-text",children:e.t("provider.noDevicesDescription")})]}),y&&(0,a.jsxs)(N.Card,{children:[(0,a.jsxs)("div",{className:"da-provider-heading",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)(N.CardTitle,{children:e.t("provider.title")}),(0,a.jsx)("p",{className:"da-text",children:e.t("provider.description",{name:y.name})})]}),(0,a.jsxs)("div",{className:"da-provider-app-select",children:[(0,a.jsx)("label",{htmlFor:"da-provider-app-select",children:e.t("provider.cli")}),(0,a.jsx)("select",{id:"da-provider-app-select",className:"da-select",value:O,onChange:m=>{K(m.target.value),_("")},disabled:!s||$,children:Me.map(m=>(0,a.jsx)("option",{value:m.id,children:m.label},m.id))}),(0,a.jsx)(N.Btn,{disabled:!s||P||$,onClick:()=>{se({action:"state"})},children:P||$?e.t("provider.loading"):e.t("provider.refresh")})]})]}),y.paired?y.disabled||y.status==="disabled"?(0,a.jsx)("div",{className:"da-provider-message da-provider-warn",children:e.t("provider.paused")}):Z(y)?P&&!L?(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.loadingState",{app:Me.find(m=>m.id===O)?.label})}):U?(0,a.jsxs)("div",{role:"alert",className:"da-provider-message da-provider-error",children:[U,(0,a.jsx)(N.Btn,{disabled:P,onClick:()=>{te()},children:e.t("provider.retry")})]}):L?(0,a.jsx)(cr,{ctx:e,state:L,canEdit:re,busy:$,onProvider:m=>{se({action:"switch_provider",provider_id:m})},onMode:m=>j(m),onRoute:m=>{se({action:"select_route",route_id:m})}}):(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.selectHint")}):(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.offline")}):(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.notPaired")}),y.paired&&!re&&(0,a.jsx)("p",{className:"da-muted",children:Ye?e.t("provider.readOnly"):e.t("provider.ownerOnly")}),p&&(0,a.jsx)("div",{role:"status",className:"da-provider-notice",children:p}),L?.warnings?.length?(0,a.jsxs)("div",{className:"da-provider-warnings",children:[(0,a.jsx)("strong",{children:e.t("provider.warnings")}),(0,a.jsx)("ul",{children:L.warnings.map((m,I)=>(0,a.jsx)("li",{children:m},`${I}:${m}`))})]}):null]}),(0,a.jsx)(N.SystemModal,{open:!!A,title:e.t("provider.confirmModeTitle"),description:A==="multi"?e.t("provider.confirmMulti"):e.t("provider.confirmSingle"),onClose:()=>j(null),footer:(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(N.Btn,{onClick:()=>j(null),children:e.t("provider.cancel")}),(0,a.jsx)(N.Btn,{primary:!0,disabled:$,onClick:()=>{let m=A;j(null),m&&se({action:"set_mode",mode:m})},children:e.t("provider.confirm")})]}),children:(0,a.jsx)("p",{className:"da-text",children:e.t("provider.confirmModeHelp")})})]})}function cr({ctx:e,state:r,canEdit:i,busy:n,onProvider:u,onMode:h,onRoute:c}){let f=r.routes.filter(d=>d.enabled),v=r.providers.find(d=>d.id===r.current_provider_id)?.name,l=d=>e.t(d==="single"?"provider.single":"provider.multi"),b=!r.multi_supported||f.length===0;return(0,a.jsxs)("div",{className:"da-provider-controls",children:[(0,a.jsxs)("section",{children:[(0,a.jsx)("div",{className:"da-provider-section-title",children:e.t("provider.mode")}),(0,a.jsx)("div",{className:"da-provider-mode-grid",children:["single","multi"].map(d=>{let k=r.mode===d;return(0,a.jsxs)("button",{type:"button",className:k?"da-provider-mode da-provider-mode-active":"da-provider-mode",disabled:!i||n||k||d==="multi"&&b,onClick:()=>h(d),children:[(0,a.jsx)("span",{className:k?"da-provider-radio da-provider-radio-active":"da-provider-radio",children:k?"\u2713":""}),(0,a.jsxs)("span",{children:[(0,a.jsx)("strong",{children:l(d)}),(0,a.jsx)("small",{children:e.t(d==="single"?"provider.singleDescription":"provider.multiDescription")})]})]},d)})}),!r.multi_supported&&(0,a.jsx)("p",{className:"da-muted",children:e.t("provider.multiUnsupported")}),r.multi_supported&&f.length===0&&(0,a.jsx)("p",{className:"da-muted",children:e.t("provider.noRoutes")})]}),r.mode==="multi"?(0,a.jsxs)("section",{children:[(0,a.jsxs)("div",{className:"da-provider-section-title",children:[e.t("provider.defaultRoute"),r.proxy_running&&(0,a.jsx)(N.Badge,{variant:"ok",children:e.t("provider.proxyRunning")})]}),f.length===0?(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.noRoutes")}):(0,a.jsx)("div",{className:"da-provider-list",children:f.map(d=>{let k=r.current_route_id===d.id,y=r.providers.find(O=>O.id===d.provider_id);return(0,a.jsxs)("button",{type:"button",className:"da-provider-item",disabled:!i||n||k,onClick:()=>c(d.id),children:[(0,a.jsxs)("span",{className:"da-provider-item-copy",children:[(0,a.jsx)("strong",{children:d.display_name||d.route_model}),(0,a.jsxs)("small",{children:[d.route_model," \u2192 ",y?.name??e.t("provider.providerRemoved")," \xB7 ",d.model]})]}),k&&(0,a.jsx)(N.Badge,{variant:"ok",children:e.t("provider.current")})]},d.id)})})]}):(0,a.jsxs)("section",{children:[(0,a.jsx)("div",{className:"da-provider-section-title",children:e.t("provider.configuredProviders")}),r.providers.length===0?(0,a.jsx)("div",{className:"da-provider-message",children:e.t("provider.noProviders")}):(0,a.jsx)("div",{className:"da-provider-list",children:r.providers.map(d=>{let k=r.current_provider_id===d.id;return(0,a.jsxs)("button",{type:"button",className:"da-provider-item",disabled:!i||n||k,onClick:()=>u(d.id),children:[(0,a.jsxs)("span",{className:"da-provider-item-copy",children:[(0,a.jsx)("strong",{children:d.name}),(0,a.jsx)("small",{children:e.t(d.category==="official"?"provider.official":"provider.custom")})]}),k&&(0,a.jsx)(N.Badge,{variant:"ok",children:e.t("provider.current")})]},d.id)})}),v&&(0,a.jsx)("p",{className:"da-muted",children:e.t("provider.currentProvider",{name:v})})]})]})}var t=D(H(),1),pr=3e3,mr=1e4,ur=6e4,vr=3,We="tab",gr=new URL("../../assets/icon.svg",import.meta.url).href;function fr(){return(0,t.jsx)("img",{src:gr,alt:"",width:16,height:16,draggable:!1})}function He(e){let r=e.core.service;try{return r&&r.available()?r:void 0}catch{return}}var de=e=>e?.state==="running"||e?.state==="starting";async function Fe(e){try{return await q.info(e),!0}catch{return!1}}var ee;function br({ctx:e}){let r=we(e,"server"),i=we(e,"workspace"),[n,u]=(0,S.useState)(()=>{let p=e.storage.get(We,"local");return p==="remote"||p==="providers"?p:"local"}),h=p=>{e.storage.set(We,p),u(p)},[c]=(0,S.useState)(()=>e.storage.get(ue,pe)),[f,v]=(0,S.useState)(()=>e.secureStorage.get(F,"")),[l,b]=(0,S.useState)({kind:"checking"}),[d,k]=(0,S.useState)(null),[y,O]=(0,S.useState)(""),[K,L]=(0,S.useState)(!1),B=(0,S.useRef)(!0),P=He(e),w=(0,S.useCallback)(async()=>{let p=null;if(P)try{p=await P.status()}catch{p=null}if(!B.current)return;k(p);let _=f;de(p)&&p?.token&&(_=p.token,p.token!==f&&(e.secureStorage.set(F,p.token),v(p.token)));try{await q.info(c)}catch{B.current&&b({kind:de(p)?"starting":"offline"});return}if(!_){B.current&&b({kind:"needsCode"});return}try{let A=await q.status(c,_);B.current&&b({kind:"ready",status:A})}catch(A){if(!B.current)return;A instanceof z&&A.kind==="unauthorized"?(e.secureStorage.remove(F),v(""),b({kind:"needsCode"})):b({kind:"offline"})}},[e,c,P,f]);(0,S.useEffect)(()=>{B.current=!0,w();let p=window.setInterval(()=>{w()},pr);return()=>{B.current=!1,window.clearInterval(p)}},[w]),(0,S.useEffect)(()=>{if(l.kind==="ready"){let p=l.status;e.reportHealth(p.paired&&p.connected?{status:"healthy",summary:e.t("health.online",{name:p.device_name})}:{status:"degraded",summary:e.t(p.paired?"health.disconnected":"health.unpaired")})}else l.kind==="offline"&&e.reportHealth({status:"degraded",summary:e.t(P?"health.disabled":"health.offline")})},[e,l,P]);let U=async p=>{L(!0),O("");try{await p()}catch(_){O(ne(e,_))}finally{L(!1)}},R=p=>U(async()=>{if(!P)return;if(!p){e.storage.set(ve,"off"),k(await P.stop()),await w();return}if(e.storage.set(ve,"on"),e.storage.remove(oe),!de(d)&&await Fe(c)){ee?.(),await w();return}let _=await P.start();k(_),_.token&&(e.secureStorage.set(F,_.token),v(_.token)),await hr(c,()=>B.current)&&ee?.(),await w()}),$=d?.state==="exited"?d:null,Y=!!P&&!de(d)&&(l.kind==="ready"||l.kind==="needsCode");return(0,t.jsxs)("div",{className:"da-app",children:[(0,t.jsx)(g.PageHeader,{title:e.t("page.title"),subtitle:e.t("page.subtitle")}),(0,t.jsx)("div",{className:"da-tabs",role:"tablist","aria-label":e.t("page.title"),children:["local","remote","providers"].map(p=>(0,t.jsx)("button",{type:"button",role:"tab","aria-selected":n===p,className:n===p?"da-tab da-tab-active":"da-tab",onClick:()=>h(p),children:e.t(`tabs.${p}`)},p))}),y&&(0,t.jsx)("div",{role:"alert",className:"da-alert",children:y}),n==="remote"&&(0,t.jsx)(ze,{ctx:e,server:r,workspace:i,localDeviceId:l.kind==="ready"&&l.status.paired?l.status.device_id:""}),n==="providers"&&(0,t.jsx)(Ke,{ctx:e,workspace:i,localDeviceId:l.kind==="ready"&&l.status.paired?l.status.device_id:""}),n==="local"&&(0,t.jsxs)(t.Fragment,{children:[P&&(0,t.jsx)(yr,{ctx:e,status:d,external:Y,exit:$,busy:K,onToggle:p=>{R(p)}}),l.kind==="checking"&&(0,t.jsx)(g.Card,{children:(0,t.jsx)("span",{className:"da-muted",children:e.t("common.checking")})}),l.kind==="starting"&&(0,t.jsx)(g.Card,{children:(0,t.jsx)("span",{className:"da-muted",children:e.t("service.starting")})}),l.kind==="offline"&&!P&&(0,t.jsx)(wr,{ctx:e,localUrl:c}),l.kind==="needsCode"&&(0,t.jsx)(_r,{ctx:e,busy:K,onPair:p=>U(async()=>{let _=await q.pair(c,p).catch(A=>{throw A instanceof z&&A.code==="code_wrong"?new Error(e.t("pair.wrong")):A instanceof z&&A.code==="locked"?new Error(e.t("pair.locked")):A});e.secureStorage.set(F,_.token),v(_.token)})}),l.kind==="ready"&&(0,t.jsx)(Cr,{ctx:e,status:l.status,server:r,workspace:i,busy:K,run:U,localUrl:c,token:f,onStatus:p=>b({kind:"ready",status:p})})]})]})}async function hr(e,r){for(let i=0;i<30&&r();i+=1)try{return await q.info(e),!0}catch{await new Promise(n=>window.setTimeout(n,500))}return!1}function yr({ctx:e,status:r,external:i,exit:n,busy:u,onToggle:h}){let c=de(r),f=!c&&i,v=c||f,l=n?.exitCode===vr;return(0,t.jsxs)(g.Card,{children:[(0,t.jsxs)("div",{className:"da-switch",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(g.CardTitle,{children:e.t("service.title")}),(0,t.jsx)("p",{className:"da-text",children:e.t(f?"service.onExternalBody":v?"service.onBody":"service.offBody")})]}),(0,t.jsx)(g.Toggle,{checked:v,disabled:u||f,label:e.t("service.title"),onChange:h})]}),c&&(0,t.jsx)("p",{className:"da-muted",children:e.t("service.followsApp")}),f&&(0,t.jsx)("p",{className:"da-muted",children:e.t("service.external")}),!v&&l&&(0,t.jsx)("p",{className:"da-muted",children:e.t("service.portTaken")}),n&&!l&&n.exitCode!==0&&(0,t.jsx)("div",{role:"alert",className:"da-alert",children:e.t("service.crashed",{error:n.error||`exit ${n.exitCode??n.signal??"?"}`})})]})}function wr({ctx:e,localUrl:r}){return(0,t.jsxs)(g.Card,{children:[(0,t.jsx)(g.CardTitle,{children:e.t("offline.title")}),(0,t.jsx)("p",{className:"da-text",children:e.t("offline.body",{url:r})}),(0,t.jsx)("div",{className:"da-step",children:e.t("offline.once")}),(0,t.jsx)(V,{ctx:e,value:"npx toc-ocra@latest run"}),(0,t.jsx)("div",{className:"da-step",children:e.t("offline.service")}),(0,t.jsx)(V,{ctx:e,value:"npm install -g toc-ocra@latest && toc-ocra service:install"}),(0,t.jsx)("p",{className:"da-muted",children:e.t("offline.node")})]})}function _r({ctx:e,busy:r,onPair:i}){let[n,u]=(0,S.useState)(""),h=/^\d{6}$/.test(n);return(0,t.jsxs)(g.Card,{children:[(0,t.jsx)(g.CardTitle,{children:e.t("pair.title")}),(0,t.jsx)("p",{className:"da-text",children:e.t("pair.body")}),(0,t.jsx)(V,{ctx:e,value:"toc-ocra code"}),(0,t.jsxs)("form",{className:"da-row",onSubmit:c=>{c.preventDefault(),h&&i(n)},children:[(0,t.jsx)(g.Input,{value:n,onChange:c=>u(c.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,t.jsx)(g.Btn,{primary:!0,type:"submit",disabled:!h||r,children:e.t("pair.submit")})]})]})}function Cr({ctx:e,status:r,server:i,workspace:n,busy:u,run:h,localUrl:c,token:f,onStatus:v}){let l=r.paired&&i&&!me(r.server_url,i.origin),b=()=>h(async()=>{r.device_id&&i&&me(r.server_url,i.origin)&&await e.core.request(`/devices/${encodeURIComponent(r.device_id)}/agent`,{method:"DELETE"}).catch(()=>{}),e.storage.set(oe,"off"),v(await q.unpair(c,f))});return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(g.Card,{children:[(0,t.jsx)(g.CardTitle,{children:e.t("status.title")}),(0,t.jsxs)("dl",{className:"da-grid",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:e.t("status.service")}),(0,t.jsxs)("dd",{children:["toc-ocra ",r.version," \xB7 ",r.hostname]})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:e.t("status.binding")}),(0,t.jsx)("dd",{children:(0,t.jsx)(kr,{ctx:e,status:r})})]}),r.paired&&(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:e.t("status.device")}),(0,t.jsx)("dd",{children:r.device_name})]}),r.paired&&(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:e.t("status.server")}),(0,t.jsx)("dd",{className:"da-mono",children:r.server_url})]}),r.paired&&(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:e.t("status.runs")}),(0,t.jsx)("dd",{children:r.active_runs})]})]}),r.paired&&!r.connected&&r.connection_error&&(0,t.jsx)("p",{className:"da-muted",children:e.t("status.lastError",{error:r.connection_error})}),r.token_from_env&&(0,t.jsx)("p",{className:"da-muted",children:e.t("status.tokenFromEnv")}),r.paired&&(0,t.jsx)("div",{className:"da-row",children:(0,t.jsx)(g.Btn,{danger:!0,disabled:u||r.token_from_env,onClick:()=>{b()},children:e.t("status.unpair")})})]}),(!r.paired||r.unauthorized||l)&&(0,t.jsx)(Nr,{ctx:e,status:r,server:i,workspace:n,busy:u,run:h,localUrl:c,token:f,onStatus:v,rebind:r.paired}),(0,t.jsxs)(g.Card,{children:[(0,t.jsx)(g.CardTitle,{children:e.t("cli.title")}),(0,t.jsxs)("ul",{className:"da-list",children:[r.providers.filter(d=>d.installed).map(d=>(0,t.jsxs)("li",{children:[(0,t.jsx)("span",{className:"da-mono",children:d.id}),(0,t.jsx)("span",{className:"da-muted",children:d.version}),d.runnable?(0,t.jsx)(g.Badge,{variant:"ok",children:e.t("cli.runnable")}):(0,t.jsx)(g.Badge,{variant:"muted",children:e.t("cli.detectOnly")})]},d.id)),!r.providers.some(d=>d.installed)&&(0,t.jsx)("li",{className:"da-muted",children:e.t("cli.none")})]}),(0,t.jsx)("div",{className:"da-row",children:(0,t.jsx)(g.Btn,{disabled:u,onClick:()=>{h(async()=>v(await q.detect(c,f)))},children:e.t("cli.redetect")})})]})]})}function kr({ctx:e,status:r}){return r.paired?r.unauthorized?(0,t.jsx)(g.Badge,{variant:"err",children:e.t("binding.revoked")}):r.connected?(0,t.jsx)(g.Badge,{variant:"ok",children:e.t("binding.online")}):(0,t.jsx)(g.Badge,{variant:"warn",children:e.t("binding.connecting")}):(0,t.jsx)(g.Badge,{variant:"muted",children:e.t("binding.unpaired")})}function Nr({ctx:e,status:r,server:i,workspace:n,busy:u,run:h,localUrl:c,token:f,onStatus:v,rebind:l}){let[b,d]=(0,S.useState)([]),[k,y]=(0,S.useState)("new"),[O,K]=(0,S.useState)(r.hostname),[L,B]=(0,S.useState)(i?.origin??"");(0,S.useEffect)(()=>{i?.origin&&B(i.origin)},[i?.origin]),(0,S.useEffect)(()=>{if(!n?.id)return;let w=!1;return e.core.request(`/workspaces/${encodeURIComponent(n.id)}/devices`).then(U=>{w||d((U.items??[]).filter(R=>R.is_mine))}).catch(()=>{w||d([])}),()=>{w=!0}},[e,n?.id]);let P=()=>h(async()=>{if(!n?.id)throw new Error(e.t("bind.noWorkspace"));if(!L.trim())throw new Error(e.t("bind.noServer"));let w=k,U;if(k==="new"){if(!r.machine_id)throw new Error(e.t("bind.identityRequired"));let R=await e.core.request("/devices/machine/pairing-code",{method:"POST",body:JSON.stringify({machine_id:r.machine_id,hostname:O.trim()||r.hostname,platform:r.platform,current_device_id:r.paired?r.device_id:""})});w=R.device_id,y(w),U=R}else U=await e.core.request(`/devices/${encodeURIComponent(w)}/pairing-code`,{method:"POST"});v(await q.enroll(c,f,L.trim(),U.code)),e.storage.remove(oe),e.notify({title:e.t("page.title"),body:e.t("bind.done",{server:i?.name??L})})});return(0,t.jsxs)(g.Card,{children:[(0,t.jsx)(g.CardTitle,{children:e.t(l?"bind.rebindTitle":"bind.title")}),l&&r.unauthorized&&(0,t.jsx)("p",{className:"da-text",children:e.t("bind.revoked")}),l&&!r.unauthorized&&(0,t.jsx)("p",{className:"da-text",children:e.t("bind.elsewhere",{bound:r.server_url,current:i?.origin??""})}),(0,t.jsx)("p",{className:"da-text",children:e.t("bind.body",{server:i?.name??"",workspace:n?.name??""})}),(0,t.jsxs)("label",{className:"da-field",children:[(0,t.jsx)("span",{children:e.t("bind.server")}),(0,t.jsx)(g.Input,{value:L,onChange:w=>B(w.target.value),spellCheck:!1,className:"da-mono"})]}),(0,t.jsxs)("label",{className:"da-field",children:[(0,t.jsx)("span",{children:e.t("bind.device")}),(0,t.jsxs)("select",{className:"da-select",value:k,onChange:w=>y(w.target.value),children:[(0,t.jsx)("option",{value:"new",children:e.t("bind.newDevice")}),b.map(w=>(0,t.jsxs)("option",{value:w.id,children:[w.name,w.paired?` \xB7 ${e.t("bind.replaces")}`:""]},w.id))]})]}),k==="new"&&(0,t.jsxs)("label",{className:"da-field",children:[(0,t.jsx)("span",{children:e.t("bind.name")}),(0,t.jsx)(g.Input,{value:O,onChange:w=>K(w.target.value),maxLength:100})]}),(0,t.jsx)("div",{className:"da-row",children:(0,t.jsx)(g.Btn,{primary:!0,disabled:u||!n?.id,onClick:()=>{P()},children:e.t(u?"bind.working":"bind.submit")})})]})}function Sr(e){let r=!1,i="",n=new Map,u=async()=>{if(r||e.signal.aborted)return;let c=e.core.context("server"),f=e.secureStorage.get(F,"");if(!(!c?.origin||!f||e.storage.get(oe,"on")==="off")&&!(Date.now()-(n.get(c.origin)??0)<ur)){r=!0;try{let v=e.storage.get(ue,pe),l=await q.status(v,f);if(!l.machine_id||l.token_from_env)return;if(l.paired&&(l.unauthorized||me(l.server_url,c.origin))){i="";return}if(l.active_runs>0){i!==c.origin&&(i=c.origin,e.notify({title:e.t("page.title"),body:e.t("auto.deferred",{server:c.name||c.origin})}));return}let b=await e.core.request("/devices/machine/pairing-code",{method:"POST",body:JSON.stringify({machine_id:l.machine_id,hostname:l.hostname,platform:l.platform,current_device_id:l.paired?l.device_id:""})});await q.enroll(v,f,c.origin,b.code),i="",n.delete(c.origin),e.notify({title:e.t("page.title"),body:e.t("auto.done",{server:c.name||c.origin,device:b.device_name})})}catch(v){(!(v instanceof z)||v.kind==="rejected")&&n.set(c.origin,Date.now())}finally{r=!1}}},h=window.setInterval(()=>{u()},mr);ee=()=>{u()},e.registerDisposer(()=>{window.clearInterval(h),ee=void 0}),e.registerDisposer(e.core.onContextChange("server",()=>{u()})),window.setTimeout(()=>{u()},1500)}function Pr(e){let r=He(e);if(!r||e.storage.get(ve,"off")!=="on")return;let i=e.storage.get(ue,pe);Fe(i).then(n=>{if(n){window.setTimeout(()=>ee?.(),3e3);return}return r.start()}).then(n=>{n&&(n.token&&e.secureStorage.set(F,n.token),window.setTimeout(()=>ee?.(),3e3))}).catch(()=>{})}var Yr=Le({activate(e){e.registerNavigation("agent.nav",(0,t.jsx)(fr,{})),e.registerRoute("agent.home",(0,t.jsx)(br,{ctx:e})),Pr(e),Sr(e)}});export{Yr 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", "../../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/** Another toc-ocra (background service, terminal) already answers on this computer. */\nasync function hasLocalInstance(localUrl: string): Promise<boolean> {\n try {\n await local.info(localUrl);\n return true;\n } catch {\n return false;\n }\n}\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 // A background service already runs the agent: use it, do not start a\n // second one that could only fail on the taken port.\n if (!isActive(service) && (await hasLocalInstance(localUrl))) {\n triggerAutoBind?.();\n await refresh();\n return;\n }\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 hosted = isActive(status);\n // Another toc-ocra (background service / terminal) already serves this\n // computer: the agent is on, it just is not owned by the desktop app.\n const viaExternal = !hosted && external;\n const on = hosted || viaExternal;\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(viaExternal ? \"service.onExternalBody\" : on ? \"service.onBody\" : \"service.offBody\")}</p>\n </div>\n <Toggle checked={on} disabled={busy || viaExternal} label={ctx.t(\"service.title\")} onChange={onToggle} />\n </div>\n {hosted && <p className=\"da-muted\">{ctx.t(\"service.followsApp\")}</p>}\n {viaExternal && <p className=\"da-muted\">{ctx.t(\"service.external\")}</p>}\n {!on && portTaken && <p className=\"da-muted\">{ctx.t(\"service.portTaken\")}</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 let pairing: { code: string };\n if (choice === \"new\") {\n if (!status.machine_id) throw new Error(ctx.t(\"bind.identityRequired\"));\n const matched = await ctx.core.request<{ device_id: string; code: string }>(\"/devices/machine/pairing-code\", {\n method: \"POST\",\n body: JSON.stringify({ machine_id: status.machine_id, hostname: name.trim() || status.hostname, platform: status.platform, current_device_id: status.paired ? status.device_id : \"\" }),\n });\n deviceId = matched.device_id;\n setChoice(deviceId);\n pairing = matched;\n } else {\n pairing = await ctx.core.request<{ code: string }>(`/devices/${encodeURIComponent(deviceId)}/pairing-code`, { method: \"POST\" });\n }\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 const localUrl = ctx.storage.get(LOCAL_URL_KEY, DEFAULT_LOCAL_URL);\n void hasLocalInstance(localUrl)\n .then(running => {\n if (running) {\n // Already served by a background service: nothing to start.\n window.setTimeout(() => triggerAutoBind?.(), 3_000);\n return undefined;\n }\n return svc.start();\n })\n .then(status => {\n if (!status) return;\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", "hasLocalInstance", "localUrl", "local", "triggerAutoBind", "AgentPage", "server", "useHostContext", "workspace", "tab", "setTabState", "setTab", "next", "LOCAL_URL_KEY", "DEFAULT_LOCAL_URL", "token", "setToken", "TOKEN_KEY", "phase", "setPhase", "setService", "error", "setError", "busy", "setBusy", "alive", "svc", "refresh", "hosted", "active", "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", "viaExternal", "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", "matched", "startAutoBind", "deferredFor", "failedAt", "tick", "startLocalServiceIfEnabled", "running", "index_default", "definePlugin"]
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", "../../plugin/providers.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 { ProvidersTab } from \"./providers\";\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\" | \"providers\";\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/** Another toc-ocra (background service, terminal) already answers on this computer. */\nasync function hasLocalInstance(localUrl: string): Promise<boolean> {\n try {\n await local.info(localUrl);\n return true;\n } catch {\n return false;\n }\n}\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>(() => {\n const stored = ctx.storage.get<string>(TAB_KEY, \"local\");\n return stored === \"remote\" || stored === \"providers\" ? stored : \"local\";\n });\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 // A background service already runs the agent: use it, do not start a\n // second one that could only fail on the taken port.\n if (!isActive(service) && (await hasLocalInstance(localUrl))) {\n triggerAutoBind?.();\n await refresh();\n return;\n }\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\", \"providers\"] 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 === \"providers\" && (\n <ProvidersTab ctx={ctx} 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 hosted = isActive(status);\n // Another toc-ocra (background service / terminal) already serves this\n // computer: the agent is on, it just is not owned by the desktop app.\n const viaExternal = !hosted && external;\n const on = hosted || viaExternal;\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(viaExternal ? \"service.onExternalBody\" : on ? \"service.onBody\" : \"service.offBody\")}</p>\n </div>\n <Toggle checked={on} disabled={busy || viaExternal} label={ctx.t(\"service.title\")} onChange={onToggle} />\n </div>\n {hosted && <p className=\"da-muted\">{ctx.t(\"service.followsApp\")}</p>}\n {viaExternal && <p className=\"da-muted\">{ctx.t(\"service.external\")}</p>}\n {!on && portTaken && <p className=\"da-muted\">{ctx.t(\"service.portTaken\")}</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 let pairing: { code: string };\n if (choice === \"new\") {\n if (!status.machine_id) throw new Error(ctx.t(\"bind.identityRequired\"));\n const matched = await ctx.core.request<{ device_id: string; code: string }>(\"/devices/machine/pairing-code\", {\n method: \"POST\",\n body: JSON.stringify({ machine_id: status.machine_id, hostname: name.trim() || status.hostname, platform: status.platform, current_device_id: status.paired ? status.device_id : \"\" }),\n });\n deviceId = matched.device_id;\n setChoice(deviceId);\n pairing = matched;\n } else {\n pairing = await ctx.core.request<{ code: string }>(`/devices/${encodeURIComponent(deviceId)}/pairing-code`, { method: \"POST\" });\n }\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 const localUrl = ctx.storage.get(LOCAL_URL_KEY, DEFAULT_LOCAL_URL);\n void hasLocalInstance(localUrl)\n .then(running => {\n if (running) {\n // Already served by a background service: nothing to start.\n window.setTimeout(() => triggerAutoBind?.(), 3_000);\n return undefined;\n }\n return svc.start();\n })\n .then(status => {\n if (!status) return;\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; role?: 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 owner_name?: string;\n /** Terminal agent credential id; only the owner sees it. Changes on every pairing. */\n agent_id?: string | null;\n terminal_online?: boolean;\n 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", "import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { PluginContext } from \"@toc-starter/plugin-sdk\";\nimport { Badge, Btn, Card, CardTitle, SystemModal } from \"@toc-starter/plugin-sdk/ui\";\nimport type { Device, WorkspaceContext } from \"./shared\";\n\ntype ProviderApp = \"codex\" | \"claude\" | \"gemini\";\ntype ProviderMode = \"single\" | \"multi\";\ntype ProviderAction = \"state\" | \"switch_provider\" | \"set_mode\" | \"select_route\";\ninterface ProviderInput {\n app: ProviderApp;\n action: ProviderAction;\n provider_id?: string;\n mode?: ProviderMode;\n route_id?: string;\n}\ninterface ProviderSummary { id: string; name: string; category: string }\ninterface ModelRoute { id: string; provider_id: string; route_model: string; model: string; display_name: string; enabled: boolean }\ninterface ProviderState {\n app: ProviderApp;\n mode: ProviderMode | string;\n multi_supported: boolean;\n current_provider_id?: string | null;\n providers: ProviderSummary[];\n routes: ModelRoute[];\n current_route_id?: string | null;\n proxy_running: boolean;\n warnings: string[];\n}\n\nconst APPS: ReadonlyArray<{ id: ProviderApp; label: string }> = [\n { id: \"codex\", label: \"Codex\" },\n { id: \"claude\", label: \"Claude Code\" },\n { id: \"gemini\", label: \"Gemini CLI\" },\n];\nconst DEVICE_KEY_PREFIX = \"tb-switch-device\";\n\nfunction online(device: Device) {\n return device.terminal_online ?? device.online ?? device.status === \"online\";\n}\n\nfunction statusOf(device: Device) {\n if (!device.paired || device.status === \"not_connected\") return { key: \"provider.status.notPaired\", variant: \"muted\" as const };\n if (device.disabled || device.status === \"disabled\") return { key: \"provider.status.paused\", variant: \"warn\" as const };\n if (online(device)) return { key: \"provider.status.online\", variant: \"ok\" as const };\n return { key: \"provider.status.offline\", variant: \"err\" as const };\n}\n\nfunction preferredDevice(devices: Device[], localDeviceId: string) {\n return devices.find(device => device.id === localDeviceId && device.paired && !device.disabled && online(device))\n ?? devices.find(device => device.is_mine && device.paired && !device.disabled && online(device))\n ?? devices.find(device => device.paired && !device.disabled && online(device))\n ?? devices.find(device => device.id === localDeviceId)\n ?? devices.find(device => device.paired)\n ?? devices[0];\n}\n\nfunction errorText(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function ProvidersTab({ ctx, workspace, localDeviceId }: {\n ctx: PluginContext;\n workspace: WorkspaceContext | undefined;\n localDeviceId: string;\n}) {\n const [devices, setDevices] = useState<Device[] | null>(null);\n const [devicesLoading, setDevicesLoading] = useState(false);\n const [devicesError, setDevicesError] = useState(\"\");\n const [selection, setSelection] = useState({ workspaceId: \"\", deviceId: \"\" });\n const selectionRef = useRef(selection);\n selectionRef.current = selection;\n const selectedId = selection.workspaceId === workspace?.id ? selection.deviceId : \"\";\n const selectedDevice = devices?.find(device => device.id === selectedId) ?? null;\n const [app, setApp] = useState<ProviderApp>(\"codex\");\n const [providerState, setProviderState] = useState<ProviderState | null>(null);\n const [stateLoading, setStateLoading] = useState(false);\n const [stateError, setStateError] = useState(\"\");\n const [actionBusy, setActionBusy] = useState(false);\n const [notice, setNotice] = useState(\"\");\n const [modeToConfirm, setModeToConfirm] = useState<ProviderMode | null>(null);\n const stateRequestRef = useRef(0);\n const canManage = Boolean(selectedDevice && (selectedDevice.is_mine || workspace?.role === \"owner\" || workspace?.role === \"admin\"));\n const deviceAvailable = Boolean(selectedDevice?.paired && !selectedDevice.disabled && selectedDevice.status !== \"disabled\" && online(selectedDevice));\n\n const loadDevices = useCallback(async (quiet = false) => {\n if (!workspace?.id) {\n setDevices([]);\n const next = { workspaceId: \"\", deviceId: \"\" };\n selectionRef.current = next;\n setSelection(next);\n return;\n }\n if (!quiet) setDevicesLoading(true);\n setDevicesError(\"\");\n try {\n const result = await ctx.core.request<{ items?: Device[] }>(`/workspaces/${encodeURIComponent(workspace.id)}/devices`);\n const items = result.items ?? [];\n setDevices(items);\n const previous = selectionRef.current;\n const currentId = previous.workspaceId === workspace.id ? previous.deviceId : \"\";\n if (items.some(device => device.id === currentId)) return;\n let savedId = \"\";\n try { savedId = ctx.storage.get<string>(`${DEVICE_KEY_PREFIX}:${workspace.id}`, \"\"); } catch { /* A selection can still be made for this visit. */ }\n const target = items.find(device => device.id === savedId) ?? preferredDevice(items, localDeviceId);\n const next = { workspaceId: workspace.id, deviceId: target?.id ?? \"\" };\n selectionRef.current = next;\n setSelection(next);\n if (next.deviceId) {\n try { ctx.storage.set(`${DEVICE_KEY_PREFIX}:${workspace.id}`, next.deviceId); } catch { /* Persisting selection is optional. */ }\n }\n } catch (error) {\n setDevicesError(errorText(error));\n } finally {\n if (!quiet) setDevicesLoading(false);\n }\n }, [ctx, localDeviceId, workspace?.id]);\n\n useEffect(() => {\n void loadDevices();\n const timer = window.setInterval(() => void loadDevices(true), 15_000);\n return () => window.clearInterval(timer);\n }, [loadDevices]);\n\n const chooseDevice = (deviceId: string) => {\n const next = { workspaceId: workspace?.id ?? \"\", deviceId };\n selectionRef.current = next;\n setSelection(next);\n setNotice(\"\");\n setStateError(\"\");\n if (workspace?.id) {\n try { ctx.storage.set(`${DEVICE_KEY_PREFIX}:${workspace.id}`, deviceId); } catch { /* Selection remains active for this visit. */ }\n }\n };\n\n const selectedDeviceId = selectedDevice?.id ?? \"\";\n const loadState = useCallback(async () => {\n if (!workspace?.id || !selectedDeviceId || !deviceAvailable) return;\n const requestId = ++stateRequestRef.current;\n setStateLoading(true);\n setStateError(\"\");\n try {\n const result = await ctx.core.request<ProviderState>(\n `/workspaces/${encodeURIComponent(workspace.id)}/devices/${encodeURIComponent(selectedDeviceId)}/cli-providers/control`,\n { method: \"POST\", body: JSON.stringify({ app, action: \"state\" } satisfies ProviderInput) },\n );\n if (requestId === stateRequestRef.current) setProviderState(result);\n } catch (error) {\n if (requestId === stateRequestRef.current) {\n setProviderState(null);\n setStateError(errorText(error));\n }\n } finally {\n if (requestId === stateRequestRef.current) setStateLoading(false);\n }\n }, [app, ctx, deviceAvailable, selectedDeviceId, workspace?.id]);\n\n useEffect(() => {\n stateRequestRef.current += 1;\n setStateLoading(false);\n setProviderState(null);\n setNotice(\"\");\n if (deviceAvailable) void loadState();\n }, [loadState, deviceAvailable]);\n\n const invoke = async (input: Omit<ProviderInput, \"app\">) => {\n if (!workspace?.id || !selectedDevice || !deviceAvailable || (input.action !== \"state\" && !canManage) || actionBusy) return;\n setActionBusy(true);\n setNotice(\"\");\n setStateError(\"\");\n try {\n const result = await ctx.core.request<ProviderState>(\n `/workspaces/${encodeURIComponent(workspace.id)}/devices/${encodeURIComponent(selectedDevice.id)}/cli-providers/control`,\n { method: \"POST\", body: JSON.stringify({ app, ...input } satisfies ProviderInput) },\n );\n setProviderState(result);\n setNotice(input.action === \"state\" ? ctx.t(\"provider.refreshed\") : ctx.t(\"provider.updated\"));\n } catch (error) {\n setStateError(errorText(error));\n } finally {\n setActionBusy(false);\n }\n };\n\n const selectedStatus = selectedDevice ? statusOf(selectedDevice) : null;\n const ownerAdmin = workspace?.role === \"owner\" || workspace?.role === \"admin\";\n const options = devices ?? [];\n\n return (\n <div className=\"da-provider-page\">\n <div className=\"da-provider-toolbar\">\n <div className=\"da-provider-device\">\n <label htmlFor=\"da-provider-device-select\">{ctx.t(\"provider.chooseDevice\")}</label>\n <select\n id=\"da-provider-device-select\"\n className=\"da-select\"\n value={selectedId}\n onChange={event => chooseDevice(event.target.value)}\n disabled={devicesLoading || options.length === 0 || actionBusy}\n >\n <option value=\"\" disabled>{ctx.t(\"provider.selectDevice\")}</option>\n {options.map(device => {\n const status = statusOf(device);\n const ownership = device.is_mine ? ctx.t(\"provider.myDevice\") : ctx.t(\"provider.owner\", { owner: device.owner_name || \"\u2014\" });\n const local = device.id === localDeviceId ? ` \u00B7 ${ctx.t(\"provider.thisDevice\")}` : \"\";\n return <option key={device.id} value={device.id}>{device.name} \u00B7 {ctx.t(status.key)} \u00B7 {ownership}{local}</option>;\n })}\n </select>\n {selectedDevice && selectedStatus && <Badge variant={selectedStatus.variant}>{ctx.t(selectedStatus.key)}</Badge>}\n </div>\n <Btn disabled={devicesLoading} onClick={() => void loadDevices()}>{devicesLoading ? ctx.t(\"provider.loading\") : ctx.t(\"provider.refreshDevices\")}</Btn>\n </div>\n\n {devicesLoading && devices === null && <Card><span className=\"da-muted\">{ctx.t(\"provider.loadingDevices\")}</span></Card>}\n {devicesError && <div role=\"alert\" className=\"da-alert\">{devicesError}<Btn disabled={devicesLoading} onClick={() => void loadDevices()}>{ctx.t(\"provider.retry\")}</Btn></div>}\n {!workspace?.id && <Card><CardTitle>{ctx.t(\"provider.noWorkspace\")}</CardTitle></Card>}\n {workspace?.id && devices?.length === 0 && !devicesLoading && <Card><CardTitle>{ctx.t(\"provider.noDevices\")}</CardTitle><p className=\"da-text\">{ctx.t(\"provider.noDevicesDescription\")}</p></Card>}\n\n {selectedDevice && <Card>\n <div className=\"da-provider-heading\">\n <div>\n <CardTitle>{ctx.t(\"provider.title\")}</CardTitle>\n <p className=\"da-text\">{ctx.t(\"provider.description\", { name: selectedDevice.name })}</p>\n </div>\n <div className=\"da-provider-app-select\">\n <label htmlFor=\"da-provider-app-select\">{ctx.t(\"provider.cli\")}</label>\n <select id=\"da-provider-app-select\" className=\"da-select\" value={app} onChange={event => { setApp(event.target.value as ProviderApp); setNotice(\"\"); }} disabled={!deviceAvailable || actionBusy}>\n {APPS.map(item => <option key={item.id} value={item.id}>{item.label}</option>)}\n </select>\n <Btn disabled={!deviceAvailable || stateLoading || actionBusy} onClick={() => void invoke({ action: \"state\" })}>{stateLoading || actionBusy ? ctx.t(\"provider.loading\") : ctx.t(\"provider.refresh\")}</Btn>\n </div>\n </div>\n\n {!selectedDevice.paired ? <div className=\"da-provider-message\">{ctx.t(\"provider.notPaired\")}</div>\n : selectedDevice.disabled || selectedDevice.status === \"disabled\" ? <div className=\"da-provider-message da-provider-warn\">{ctx.t(\"provider.paused\")}</div>\n : !online(selectedDevice) ? <div className=\"da-provider-message\">{ctx.t(\"provider.offline\")}</div>\n : stateLoading && !providerState ? <div className=\"da-provider-message\">{ctx.t(\"provider.loadingState\", { app: APPS.find(item => item.id === app)?.label })}</div>\n : stateError ? <div role=\"alert\" className=\"da-provider-message da-provider-error\">{stateError}<Btn disabled={stateLoading} onClick={() => void loadState()}>{ctx.t(\"provider.retry\")}</Btn></div>\n : providerState ? <ProviderControls ctx={ctx} state={providerState} canEdit={canManage} busy={actionBusy} onProvider={providerId => void invoke({ action: \"switch_provider\", provider_id: providerId })} onMode={mode => setModeToConfirm(mode)} onRoute={routeId => void invoke({ action: \"select_route\", route_id: routeId })} />\n : <div className=\"da-provider-message\">{ctx.t(\"provider.selectHint\")}</div>}\n\n {selectedDevice.paired && !canManage && <p className=\"da-muted\">{ownerAdmin ? ctx.t(\"provider.readOnly\") : ctx.t(\"provider.ownerOnly\")}</p>}\n {notice && <div role=\"status\" className=\"da-provider-notice\">{notice}</div>}\n {providerState?.warnings?.length ? <div className=\"da-provider-warnings\"><strong>{ctx.t(\"provider.warnings\")}</strong><ul>{providerState.warnings.map((warning, index) => <li key={`${index}:${warning}`}>{warning}</li>)}</ul></div> : null}\n </Card>}\n\n <SystemModal\n open={Boolean(modeToConfirm)}\n title={ctx.t(\"provider.confirmModeTitle\")}\n description={modeToConfirm === \"multi\" ? ctx.t(\"provider.confirmMulti\") : ctx.t(\"provider.confirmSingle\")}\n onClose={() => setModeToConfirm(null)}\n footer={<><Btn onClick={() => setModeToConfirm(null)}>{ctx.t(\"provider.cancel\")}</Btn><Btn primary disabled={actionBusy} onClick={() => { const mode = modeToConfirm; setModeToConfirm(null); if (mode) void invoke({ action: \"set_mode\", mode }); }}>{ctx.t(\"provider.confirm\")}</Btn></>}\n >\n <p className=\"da-text\">{ctx.t(\"provider.confirmModeHelp\")}</p>\n </SystemModal>\n </div>\n );\n}\n\nfunction ProviderControls({ ctx, state, canEdit, busy, onProvider, onMode, onRoute }: {\n ctx: PluginContext;\n state: ProviderState;\n canEdit: boolean;\n busy: boolean;\n onProvider: (id: string) => void;\n onMode: (mode: ProviderMode) => void;\n onRoute: (id: string) => void;\n}) {\n const routes = state.routes.filter(route => route.enabled);\n const currentProvider = state.providers.find(provider => provider.id === state.current_provider_id)?.name;\n const modeLabel = (mode: string) => ctx.t(mode === \"single\" ? \"provider.single\" : \"provider.multi\");\n const unavailableMulti = !state.multi_supported || routes.length === 0;\n return <div className=\"da-provider-controls\">\n <section>\n <div className=\"da-provider-section-title\">{ctx.t(\"provider.mode\")}</div>\n <div className=\"da-provider-mode-grid\">\n {([\"single\", \"multi\"] as const).map(mode => {\n const active = state.mode === mode;\n const disabled = !canEdit || busy || active || (mode === \"multi\" && unavailableMulti);\n return <button key={mode} type=\"button\" className={active ? \"da-provider-mode da-provider-mode-active\" : \"da-provider-mode\"} disabled={disabled} onClick={() => onMode(mode)}>\n <span className={active ? \"da-provider-radio da-provider-radio-active\" : \"da-provider-radio\"}>{active ? \"\u2713\" : \"\"}</span>\n <span><strong>{modeLabel(mode)}</strong><small>{ctx.t(mode === \"single\" ? \"provider.singleDescription\" : \"provider.multiDescription\")}</small></span>\n </button>;\n })}\n </div>\n {!state.multi_supported && <p className=\"da-muted\">{ctx.t(\"provider.multiUnsupported\")}</p>}\n {state.multi_supported && routes.length === 0 && <p className=\"da-muted\">{ctx.t(\"provider.noRoutes\")}</p>}\n </section>\n\n {state.mode === \"multi\" ? <section>\n <div className=\"da-provider-section-title\">{ctx.t(\"provider.defaultRoute\")}{state.proxy_running && <Badge variant=\"ok\">{ctx.t(\"provider.proxyRunning\")}</Badge>}</div>\n {routes.length === 0 ? <div className=\"da-provider-message\">{ctx.t(\"provider.noRoutes\")}</div> : <div className=\"da-provider-list\">\n {routes.map(route => {\n const current = state.current_route_id === route.id;\n const provider = state.providers.find(item => item.id === route.provider_id);\n return <button key={route.id} type=\"button\" className=\"da-provider-item\" disabled={!canEdit || busy || current} onClick={() => onRoute(route.id)}>\n <span className=\"da-provider-item-copy\"><strong>{route.display_name || route.route_model}</strong><small>{route.route_model} \u2192 {provider?.name ?? ctx.t(\"provider.providerRemoved\")} \u00B7 {route.model}</small></span>\n {current && <Badge variant=\"ok\">{ctx.t(\"provider.current\")}</Badge>}\n </button>;\n })}\n </div>}\n </section> : <section>\n <div className=\"da-provider-section-title\">{ctx.t(\"provider.configuredProviders\")}</div>\n {state.providers.length === 0 ? <div className=\"da-provider-message\">{ctx.t(\"provider.noProviders\")}</div> : <div className=\"da-provider-list\">\n {state.providers.map(provider => {\n const current = state.current_provider_id === provider.id;\n return <button key={provider.id} type=\"button\" className=\"da-provider-item\" disabled={!canEdit || busy || current} onClick={() => onProvider(provider.id)}>\n <span className=\"da-provider-item-copy\"><strong>{provider.name}</strong><small>{ctx.t(provider.category === \"official\" ? \"provider.official\" : \"provider.custom\")}</small></span>\n {current && <Badge variant=\"ok\">{ctx.t(\"provider.current\")}</Badge>}\n </button>;\n })}\n </div>}\n {currentProvider && <p className=\"da-muted\">{ctx.t(\"provider.currentProvider\", { name: currentProvider })}</p>}\n </section>}\n </div>;\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_react", "import_ui", "import_jsx_runtime", "APPS", "DEVICE_KEY_PREFIX", "online", "device", "statusOf", "preferredDevice", "devices", "localDeviceId", "errorText", "error", "ProvidersTab", "ctx", "workspace", "setDevices", "devicesLoading", "setDevicesLoading", "devicesError", "setDevicesError", "selection", "setSelection", "selectionRef", "selectedId", "selectedDevice", "app", "setApp", "providerState", "setProviderState", "stateLoading", "setStateLoading", "stateError", "setStateError", "actionBusy", "setActionBusy", "notice", "setNotice", "modeToConfirm", "setModeToConfirm", "stateRequestRef", "canManage", "deviceAvailable", "loadDevices", "quiet", "next", "items", "previous", "currentId", "savedId", "target", "timer", "chooseDevice", "deviceId", "selectedDeviceId", "loadState", "requestId", "result", "invoke", "input", "selectedStatus", "ownerAdmin", "options", "event", "status", "ownership", "local", "item", "ProviderControls", "providerId", "mode", "routeId", "warning", "index", "state", "canEdit", "busy", "onProvider", "onMode", "onRoute", "routes", "route", "currentProvider", "provider", "modeLabel", "unavailableMulti", "active", "current", "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", "hasLocalInstance", "localUrl", "local", "triggerAutoBind", "AgentPage", "server", "useHostContext", "workspace", "tab", "setTabState", "stored", "setTab", "next", "LOCAL_URL_KEY", "DEFAULT_LOCAL_URL", "token", "setToken", "TOKEN_KEY", "phase", "setPhase", "setService", "error", "setError", "busy", "setBusy", "alive", "svc", "refresh", "hosted", "active", "reason", "LocalError", "timer", "s", "run", "action", "errorText", "toggleService", "on", "LOCAL_SERVICE_KEY", "AUTO_BIND_KEY", "started", "waitForLocalService", "hostedExit", "external", "item", "RemoteTab", "ProvidersTab", "LocalServiceCard", "OfflineCard", "PairCard", "code", "result", "ReadyView", "attempt", "resolve", "exit", "onToggle", "viaExternal", "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", "matched", "startAutoBind", "deferredFor", "failedAt", "tick", "startLocalServiceIfEnabled", "running", "index_default", "definePlugin"]
7
7
  }
package/locales/en.json CHANGED
@@ -84,7 +84,64 @@
84
84
  },
85
85
  "tabs": {
86
86
  "local": "This computer",
87
- "remote": "Other computers"
87
+ "remote": "Other computers",
88
+ "providers": "TB Switch"
89
+ },
90
+ "provider": {
91
+ "chooseDevice": "Manage device",
92
+ "selectDevice": "Select a device",
93
+ "myDevice": "My device",
94
+ "owner": "{{owner}}'s device",
95
+ "thisDevice": "This computer",
96
+ "refreshDevices": "Refresh devices",
97
+ "loadingDevices": "Loading workspace devices…",
98
+ "loading": "Loading…",
99
+ "retry": "Retry",
100
+ "noWorkspace": "Select a workspace first.",
101
+ "noDevices": "No devices are available in this workspace.",
102
+ "noDevicesDescription": "Devices available in the workspace will appear here.",
103
+ "status": {
104
+ "notPaired": "Not paired",
105
+ "online": "Online",
106
+ "offline": "Offline",
107
+ "paused": "Paused"
108
+ },
109
+ "title": "TB Switch settings",
110
+ "description": "View and switch configured providers and the default route on {{name}}.",
111
+ "cli": "CLI",
112
+ "refresh": "Refresh settings",
113
+ "notPaired": "This device is not paired with the device agent, so TB Switch settings cannot be read.",
114
+ "paused": "The device agent is paused. Resume it to read and change settings.",
115
+ "offline": "The device agent is offline. Settings will be available when it comes back online.",
116
+ "loadingState": "Loading {{app}} settings…",
117
+ "selectHint": "Choose a CLI to read its existing settings on the selected device.",
118
+ "readOnly": "You can view settings, but only the device owner or a workspace admin can change them.",
119
+ "ownerOnly": "Only the device owner or a workspace admin can change settings on this device.",
120
+ "refreshed": "Settings refreshed.",
121
+ "updated": "Device settings updated.",
122
+ "warnings": "Switching notes",
123
+ "mode": "Provider mode",
124
+ "single": "Single provider",
125
+ "multi": "Multi-provider routing",
126
+ "singleDescription": "Use one current provider for the entire CLI.",
127
+ "multiDescription": "Use configured providers based on model routes.",
128
+ "multiUnsupported": "This CLI does not support multi-provider routing.",
129
+ "noRoutes": "No routes are available. Configure them in the desktop TB Switch plugin first.",
130
+ "defaultRoute": "Default model route",
131
+ "proxyRunning": "Proxy running",
132
+ "providerRemoved": "Provider removed",
133
+ "configuredProviders": "Configured providers",
134
+ "noProviders": "No providers are configured. Configure them in the desktop TB Switch plugin first.",
135
+ "official": "Official login",
136
+ "custom": "Custom provider",
137
+ "current": "Current",
138
+ "currentProvider": "Current provider: {{name}}. Open CLI sessions may need to restart to use the new settings.",
139
+ "confirmModeTitle": "Change provider mode?",
140
+ "confirmMulti": "Configured providers will be selected by model route.",
141
+ "confirmSingle": "The CLI will use one current provider. Configured model routes will be kept.",
142
+ "confirmModeHelp": "This changes existing settings on the selected device. It does not add or edit providers or routes.",
143
+ "cancel": "Cancel",
144
+ "confirm": "Confirm"
88
145
  },
89
146
  "service": {
90
147
  "title": "Local device agent",
@@ -84,7 +84,64 @@
84
84
  },
85
85
  "tabs": {
86
86
  "local": "本机",
87
- "remote": "其他电脑"
87
+ "remote": "其他电脑",
88
+ "providers": "TB Switch"
89
+ },
90
+ "provider": {
91
+ "chooseDevice": "管理设备",
92
+ "selectDevice": "选择一台设备",
93
+ "myDevice": "我的设备",
94
+ "owner": "{{owner}} 的设备",
95
+ "thisDevice": "本机",
96
+ "refreshDevices": "刷新设备",
97
+ "loadingDevices": "正在读取工作空间设备…",
98
+ "loading": "读取中…",
99
+ "retry": "重试",
100
+ "noWorkspace": "请先选择一个工作空间。",
101
+ "noDevices": "当前工作空间没有可管理的设备。",
102
+ "noDevicesDescription": "已加入工作空间的设备会显示在这里。",
103
+ "status": {
104
+ "notPaired": "未配对",
105
+ "online": "在线",
106
+ "offline": "离线",
107
+ "paused": "已暂停"
108
+ },
109
+ "title": "TB Switch 设置",
110
+ "description": "查看并切换「{{name}}」上已配置的供应商与默认路由。",
111
+ "cli": "CLI",
112
+ "refresh": "刷新配置",
113
+ "notPaired": "这台设备尚未配对设备代理,无法读取 TB Switch 设置。",
114
+ "paused": "设备代理已暂停接收任务。恢复设备代理后即可读取和切换设置。",
115
+ "offline": "设备代理当前离线。设备重新上线后即可读取和切换设置。",
116
+ "loadingState": "正在读取 {{app}} 配置…",
117
+ "selectHint": "选择 CLI 后将读取所选设备上的现有配置。",
118
+ "readOnly": "你可以查看设置,但只有设备所有者或工作空间管理员可以切换。",
119
+ "ownerOnly": "只有设备所有者或工作空间管理员可以切换此设备的设置。",
120
+ "refreshed": "配置已刷新。",
121
+ "updated": "设备设置已更新。",
122
+ "warnings": "切换提示",
123
+ "mode": "供应商工作方式",
124
+ "single": "单供应商",
125
+ "multi": "多供应商路由",
126
+ "singleDescription": "整个 CLI 使用一个当前供应商。",
127
+ "multiDescription": "根据模型路由使用不同的已配置供应商。",
128
+ "multiUnsupported": "此 CLI 暂不支持多供应商路由。",
129
+ "noRoutes": "没有可用路由。请先在桌面 TB Switch 中配置。",
130
+ "defaultRoute": "默认模型路由",
131
+ "proxyRunning": "代理运行中",
132
+ "providerRemoved": "供应商已移除",
133
+ "configuredProviders": "已配置供应商",
134
+ "noProviders": "没有已配置的供应商。请先在桌面 TB Switch 中配置。",
135
+ "official": "官方登录",
136
+ "custom": "自定义供应商",
137
+ "current": "当前",
138
+ "currentProvider": "当前供应商:{{name}}。已打开的 CLI 会话可能需要重新启动后读取新配置。",
139
+ "confirmModeTitle": "切换供应商工作方式?",
140
+ "confirmMulti": "将改为按模型路由分配已配置的供应商。",
141
+ "confirmSingle": "将改为整个 CLI 使用一个当前供应商。已配置的模型路由会保留。",
142
+ "confirmModeHelp": "此操作会修改目标设备上的现有配置,不会新增或编辑供应商与路由。",
143
+ "cancel": "取消",
144
+ "confirm": "确认切换"
88
145
  },
89
146
  "service": {
90
147
  "title": "本机设备代理",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toc-ocra",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "Echo device agent: local CLI execution service plus its desktop plugin (heartbeat + long-poll, headless CLIs)",
5
5
  "type": "module",
6
6
  "bin": {