@songsid/agend 2.3.5-alpha.2 → 2.3.5-alpha.4

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.
Files changed (279) hide show
  1. package/dist/agend-home.d.ts +13 -0
  2. package/dist/agend-home.js +42 -0
  3. package/dist/agend-home.js.map +1 -1
  4. package/dist/agent-runtime-api.d.ts +4 -0
  5. package/dist/agent-runtime-api.js +59 -0
  6. package/dist/agent-runtime-api.js.map +1 -0
  7. package/dist/agent-runtime-change.d.ts +74 -0
  8. package/dist/agent-runtime-change.js +102 -0
  9. package/dist/agent-runtime-change.js.map +1 -0
  10. package/dist/auth-api.d.ts +21 -0
  11. package/dist/auth-api.js +95 -4
  12. package/dist/auth-api.js.map +1 -1
  13. package/dist/authority/web-authority.d.ts +12 -2
  14. package/dist/authority/web-authority.js +25 -4
  15. package/dist/authority/web-authority.js.map +1 -1
  16. package/dist/backend/claude-code.js +16 -1
  17. package/dist/backend/claude-code.js.map +1 -1
  18. package/dist/backend/codex-footer-hints.d.ts +4 -0
  19. package/dist/backend/codex-footer-hints.js +27 -0
  20. package/dist/backend/codex-footer-hints.js.map +1 -0
  21. package/dist/backend/codex.js +19 -11
  22. package/dist/backend/codex.js.map +1 -1
  23. package/dist/backend/kiro-identity.d.ts +2 -0
  24. package/dist/backend/kiro-identity.js +13 -6
  25. package/dist/backend/kiro-identity.js.map +1 -1
  26. package/dist/backend/kiro.js +18 -3
  27. package/dist/backend/kiro.js.map +1 -1
  28. package/dist/backend-availability.d.ts +6 -0
  29. package/dist/backend-availability.js +13 -5
  30. package/dist/backend-availability.js.map +1 -1
  31. package/dist/channel/mcp-tools.js +1 -1
  32. package/dist/channel/mcp-tools.js.map +1 -1
  33. package/dist/cli.js +6 -9
  34. package/dist/cli.js.map +1 -1
  35. package/dist/config-validator.js +12 -1
  36. package/dist/config-validator.js.map +1 -1
  37. package/dist/daemon.d.ts +5 -0
  38. package/dist/daemon.js +107 -30
  39. package/dist/daemon.js.map +1 -1
  40. package/dist/fleet-manager.d.ts +146 -8
  41. package/dist/fleet-manager.js +1030 -166
  42. package/dist/fleet-manager.js.map +1 -1
  43. package/dist/fleet-windows-runtime.d.ts +6 -1
  44. package/dist/fleet-windows-runtime.js +77 -1
  45. package/dist/fleet-windows-runtime.js.map +1 -1
  46. package/dist/fleet-yaml-patch.d.ts +3 -0
  47. package/dist/fleet-yaml-patch.js +103 -0
  48. package/dist/fleet-yaml-patch.js.map +1 -0
  49. package/dist/general-binding.d.ts +85 -0
  50. package/dist/general-binding.js +298 -0
  51. package/dist/general-binding.js.map +1 -0
  52. package/dist/general-host-owner.d.ts +8 -0
  53. package/dist/general-host-owner.js +26 -0
  54. package/dist/general-host-owner.js.map +1 -0
  55. package/dist/general-instance.d.ts +7 -0
  56. package/dist/general-instance.js +20 -3
  57. package/dist/general-instance.js.map +1 -1
  58. package/dist/general-knowledge/skills/model-discovery/SKILL.md +2 -0
  59. package/dist/general-role.d.ts +5 -0
  60. package/dist/general-role.js +26 -0
  61. package/dist/general-role.js.map +1 -0
  62. package/dist/instance-lifecycle.d.ts +1 -0
  63. package/dist/instance-lifecycle.js +26 -4
  64. package/dist/instance-lifecycle.js.map +1 -1
  65. package/dist/instructions.d.ts +2 -0
  66. package/dist/instructions.js +6 -0
  67. package/dist/instructions.js.map +1 -1
  68. package/dist/kiro-resume-summary.d.ts +37 -0
  69. package/dist/kiro-resume-summary.js +85 -0
  70. package/dist/kiro-resume-summary.js.map +1 -0
  71. package/dist/locale.js +59 -0
  72. package/dist/locale.js.map +1 -1
  73. package/dist/login-controller.js +9 -1
  74. package/dist/login-controller.js.map +1 -1
  75. package/dist/native-pane-lifecycle.js +4 -1
  76. package/dist/native-pane-lifecycle.js.map +1 -1
  77. package/dist/native-pane-manager.d.ts +1 -0
  78. package/dist/native-pane-manager.js +23 -2
  79. package/dist/native-pane-manager.js.map +1 -1
  80. package/dist/needs-you-hub.js +1 -1
  81. package/dist/needs-you-hub.js.map +1 -1
  82. package/dist/needs-you.d.ts +8 -1
  83. package/dist/needs-you.js +5 -2
  84. package/dist/needs-you.js.map +1 -1
  85. package/dist/office-share-page.js +1 -1
  86. package/dist/office-share-page.js.map +1 -1
  87. package/dist/package-preimage.js +27 -2
  88. package/dist/package-preimage.js.map +1 -1
  89. package/dist/pane-port.d.ts +11 -0
  90. package/dist/public-web-gateway.js +9 -0
  91. package/dist/public-web-gateway.js.map +1 -1
  92. package/dist/public-web-link.d.ts +11 -0
  93. package/dist/public-web-link.js +13 -0
  94. package/dist/public-web-link.js.map +1 -1
  95. package/dist/quickstart-api.js +9 -5
  96. package/dist/quickstart-api.js.map +1 -1
  97. package/dist/quickstart.d.ts +1 -0
  98. package/dist/quickstart.js +4 -1
  99. package/dist/quickstart.js.map +1 -1
  100. package/dist/reply-buttons-controller.js +10 -0
  101. package/dist/reply-buttons-controller.js.map +1 -1
  102. package/dist/runtime-api.js +84 -9
  103. package/dist/runtime-api.js.map +1 -1
  104. package/dist/runtime-build-info.d.ts +9 -0
  105. package/dist/runtime-build-info.js +57 -0
  106. package/dist/runtime-build-info.js.map +1 -0
  107. package/dist/runtime-bundle.d.ts +3 -1
  108. package/dist/runtime-bundle.js +17 -8
  109. package/dist/runtime-bundle.js.map +1 -1
  110. package/dist/runtime-cli.d.ts +6 -1
  111. package/dist/runtime-cli.js +46 -11
  112. package/dist/runtime-cli.js.map +1 -1
  113. package/dist/runtime-client-store.d.ts +20 -1
  114. package/dist/runtime-client-store.js +56 -4
  115. package/dist/runtime-client-store.js.map +1 -1
  116. package/dist/runtime-client.d.ts +12 -0
  117. package/dist/runtime-client.js +43 -7
  118. package/dist/runtime-client.js.map +1 -1
  119. package/dist/runtime-connection.d.ts +22 -0
  120. package/dist/runtime-connection.js +93 -0
  121. package/dist/runtime-connection.js.map +1 -0
  122. package/dist/runtime-coordinator.d.ts +9 -0
  123. package/dist/runtime-coordinator.js +81 -34
  124. package/dist/runtime-coordinator.js.map +1 -1
  125. package/dist/runtime-general-protocol.d.ts +22 -0
  126. package/dist/runtime-general-protocol.js +57 -0
  127. package/dist/runtime-general-protocol.js.map +1 -0
  128. package/dist/runtime-general-workspace.d.ts +17 -0
  129. package/dist/runtime-general-workspace.js +213 -0
  130. package/dist/runtime-general-workspace.js.map +1 -0
  131. package/dist/runtime-pane-assets.d.ts +1 -1
  132. package/dist/runtime-pane-assets.js +1 -1
  133. package/dist/runtime-pane-assets.js.map +1 -1
  134. package/dist/runtime-pane-boot.d.ts +7 -0
  135. package/dist/runtime-pane-boot.js +23 -0
  136. package/dist/runtime-pane-boot.js.map +1 -1
  137. package/dist/runtime-pane-host.d.ts +1 -0
  138. package/dist/runtime-pane-host.js +22 -1
  139. package/dist/runtime-pane-host.js.map +1 -1
  140. package/dist/runtime-pane-mcp.d.ts +8 -0
  141. package/dist/runtime-pane-mcp.js +15 -2
  142. package/dist/runtime-pane-mcp.js.map +1 -1
  143. package/dist/runtime-pane-port.d.ts +6 -1
  144. package/dist/runtime-pane-port.js +21 -0
  145. package/dist/runtime-pane-port.js.map +1 -1
  146. package/dist/runtime-pane-protocol.d.ts +4 -1
  147. package/dist/runtime-pane-protocol.js +7 -1
  148. package/dist/runtime-pane-protocol.js.map +1 -1
  149. package/dist/runtime-protocol.d.ts +13 -0
  150. package/dist/runtime-protocol.js +18 -0
  151. package/dist/runtime-protocol.js.map +1 -1
  152. package/dist/settings-api.d.ts +5 -0
  153. package/dist/settings-api.js +37 -1
  154. package/dist/settings-api.js.map +1 -1
  155. package/dist/settings-baseline.d.ts +1 -0
  156. package/dist/settings-baseline.js +1 -1
  157. package/dist/settings-baseline.js.map +1 -1
  158. package/dist/settings-confirmation.d.ts +1 -0
  159. package/dist/settings-confirmation.js +1 -0
  160. package/dist/settings-confirmation.js.map +1 -1
  161. package/dist/settings-effect.d.ts +4 -0
  162. package/dist/settings-effect.js +36 -1
  163. package/dist/settings-effect.js.map +1 -1
  164. package/dist/settings-http-confirmation.d.ts +4 -0
  165. package/dist/settings-http-confirmation.js +20 -1
  166. package/dist/settings-http-confirmation.js.map +1 -1
  167. package/dist/settings-request-capability.d.ts +2 -0
  168. package/dist/settings-request-capability.js +4 -0
  169. package/dist/settings-request-capability.js.map +1 -1
  170. package/dist/settings-route-lifetime.d.ts +14 -0
  171. package/dist/settings-route-lifetime.js +48 -0
  172. package/dist/settings-route-lifetime.js.map +1 -0
  173. package/dist/settings-transaction.d.ts +4 -0
  174. package/dist/settings-transaction.js +9 -0
  175. package/dist/settings-transaction.js.map +1 -1
  176. package/dist/setup-form.js +6 -3
  177. package/dist/setup-form.js.map +1 -1
  178. package/dist/setup-i18n.js +3 -0
  179. package/dist/setup-i18n.js.map +1 -1
  180. package/dist/stall-reporter.d.ts +21 -0
  181. package/dist/stall-reporter.js +82 -0
  182. package/dist/stall-reporter.js.map +1 -0
  183. package/dist/tmux-control.d.ts +2 -2
  184. package/dist/tmux-control.js +4 -2
  185. package/dist/tmux-control.js.map +1 -1
  186. package/dist/tmux-exec-helper.d.ts +6 -3
  187. package/dist/tmux-exec-helper.js +115 -53
  188. package/dist/tmux-exec-helper.js.map +1 -1
  189. package/dist/tool-permissions.js +2 -1
  190. package/dist/tool-permissions.js.map +1 -1
  191. package/dist/tunnel/cloudflared-install.d.ts +4 -0
  192. package/dist/tunnel/cloudflared-install.js +20 -1
  193. package/dist/tunnel/cloudflared-install.js.map +1 -1
  194. package/dist/tunnel/cloudflared.d.ts +8 -1
  195. package/dist/tunnel/cloudflared.js +34 -6
  196. package/dist/tunnel/cloudflared.js.map +1 -1
  197. package/dist/tunnel/lease.d.ts +3 -3
  198. package/dist/tunnel/lease.js +23 -19
  199. package/dist/tunnel/lease.js.map +1 -1
  200. package/dist/tunnel/manager.js +6 -7
  201. package/dist/tunnel/manager.js.map +1 -1
  202. package/dist/types.d.ts +2 -0
  203. package/dist/ui/agent-proposals.js +2 -2
  204. package/dist/ui/agent-runtime-settings.js +67 -0
  205. package/dist/ui/agent-runtime.js +20 -2
  206. package/dist/ui/backend-signin.js +36 -21
  207. package/dist/ui/general-location.js +71 -0
  208. package/dist/ui/native-instance-settings.js +5 -8
  209. package/dist/ui/native-pane-recovery.js +1 -1
  210. package/dist/ui/panel-chat.js +5 -2
  211. package/dist/ui/panel-fleet.js +4 -2
  212. package/dist/ui/panel-needs.js +2 -0
  213. package/dist/ui/panel-runtimes.js +136 -33
  214. package/dist/ui/panel-settings.js +227 -138
  215. package/dist/ui/panel-windows-cli.js +77 -41
  216. package/dist/ui/settings-agent-filters.js +94 -0
  217. package/dist/ui/settings-appearance.js +122 -23
  218. package/dist/ui/settings-dialogs.js +13 -7
  219. package/dist/ui/settings-guests.js +25 -11
  220. package/dist/ui/settings-layout.js +245 -0
  221. package/dist/ui/settings-model.js +10 -1
  222. package/dist/ui/settings-outside.js +176 -0
  223. package/dist/ui/settings-registry.js +6 -3
  224. package/dist/ui/settings-shortcuts.js +65 -0
  225. package/dist/ui/settings-strings.js +95 -0
  226. package/dist/ui/settings-web-authority.js +14 -11
  227. package/dist/ui/shared/app-i18n.js +2 -2
  228. package/dist/ui/shared/app-shell.js +17 -7
  229. package/dist/ui/shared/app.css +1038 -13
  230. package/dist/ui/shared/instance-nav.js +16 -5
  231. package/dist/ui/shared/machine-name.js +13 -0
  232. package/dist/ui/shared/panel-view.js +266 -17
  233. package/dist/ui/shared/qrcode.module.js +2237 -0
  234. package/dist/ui/shared/settings-width.js +31 -0
  235. package/dist/ui/shared/signin.js +39 -5
  236. package/dist/ui/shared/tokens.css +1 -0
  237. package/dist/ui/shared/ui-dialog.js +2 -2
  238. package/dist/ui/shared/ui-menu.js +3 -3
  239. package/dist/ui/shared/vendor/qrcode-generator.LICENSE +27 -0
  240. package/dist/ui/shared/vendor/vendor.json +19 -2
  241. package/dist/ui/shared/view-strings.js +28 -0
  242. package/dist/ui/windows-cli-catalog.js +41 -12
  243. package/dist/unattended-install.d.ts +1 -1
  244. package/dist/unattended-install.js +19 -5
  245. package/dist/unattended-install.js.map +1 -1
  246. package/dist/update-check.d.ts +2 -8
  247. package/dist/update-check.js +2 -5
  248. package/dist/update-check.js.map +1 -1
  249. package/dist/view-api.d.ts +15 -0
  250. package/dist/view-api.js +94 -33
  251. package/dist/view-api.js.map +1 -1
  252. package/dist/web-api.d.ts +13 -0
  253. package/dist/web-api.js +80 -0
  254. package/dist/web-api.js.map +1 -1
  255. package/dist/web-login.d.ts +4 -3
  256. package/dist/web-login.js +23 -14
  257. package/dist/web-login.js.map +1 -1
  258. package/dist/web-only-fleet.d.ts +20 -0
  259. package/dist/web-only-fleet.js +21 -0
  260. package/dist/web-only-fleet.js.map +1 -1
  261. package/dist/web-remote-access.d.ts +152 -0
  262. package/dist/web-remote-access.js +368 -0
  263. package/dist/web-remote-access.js.map +1 -0
  264. package/dist/web-session.d.ts +12 -0
  265. package/dist/web-session.js +22 -8
  266. package/dist/web-session.js.map +1 -1
  267. package/dist/windows-agents.d.ts +15 -1
  268. package/dist/windows-agents.js +37 -10
  269. package/dist/windows-agents.js.map +1 -1
  270. package/dist/windows-cli-api.js +2 -1
  271. package/dist/windows-cli-api.js.map +1 -1
  272. package/dist/windows-cli-worker.d.ts +1 -0
  273. package/dist/windows-cli-worker.js +2 -2
  274. package/dist/windows-cli-worker.js.map +1 -1
  275. package/dist/windows-cli.d.ts +1 -0
  276. package/dist/windows-cli.js +7 -2
  277. package/dist/windows-cli.js.map +1 -1
  278. package/launcher/agend-install.cjs +16 -2
  279. package/package.json +1 -1
@@ -44,8 +44,7 @@ export class ManagedTunnel {
44
44
  async reap() {
45
45
  const outcome = await reapStaleTunnel(this.opts.dataDir, this.opts);
46
46
  if (outcome.kind === "manual") {
47
- this.blocked = manualCleanupMessage(outcome);
48
- this.log(this.blocked);
47
+ this.log(manualCleanupMessage(outcome));
49
48
  }
50
49
  return outcome;
51
50
  }
@@ -82,7 +81,7 @@ export class ManagedTunnel {
82
81
  // Reserved before the spawn, not after: between these two writes a child
83
82
  // may come into existence, and a crash in that window must leave evidence
84
83
  // rather than silence.
85
- writeLease(this.opts.dataDir, {
84
+ await writeLease(this.opts.dataDir, {
86
85
  sid: ctx.sid,
87
86
  provider: provider.name,
88
87
  originPort: Number(ctx.origin.port),
@@ -105,7 +104,7 @@ export class ManagedTunnel {
105
104
  // Best effort, and never allowed to throw past the block below: a full disk here must not turn
106
105
  // "a child we cannot prove dead" into a rejected start with no block and no announcement.
107
106
  try {
108
- writeLease(this.opts.dataDir, {
107
+ await writeLease(this.opts.dataDir, {
109
108
  sid: ctx.sid,
110
109
  provider: provider.name,
111
110
  originPort: Number(ctx.origin.port),
@@ -132,7 +131,7 @@ export class ManagedTunnel {
132
131
  }
133
132
  // The provider proved its child is gone (or never made one), so the lease
134
133
  // describes nothing and may go.
135
- clearLease(this.opts.dataDir);
134
+ await clearLease(this.opts.dataDir);
136
135
  return {
137
136
  ok: false,
138
137
  errorKind: startError?.errorKind ?? "spawn-failed",
@@ -145,7 +144,7 @@ export class ManagedTunnel {
145
144
  // tunnel is stopped on proof — and if that cannot be proven the failure says so and blocks the next start.
146
145
  this.active = handle;
147
146
  try {
148
- writeLease(this.opts.dataDir, {
147
+ await writeLease(this.opts.dataDir, {
149
148
  sid: ctx.sid,
150
149
  provider: provider.name,
151
150
  originPort: Number(ctx.origin.port),
@@ -186,7 +185,7 @@ export class ManagedTunnel {
186
185
  const result = await handle.stop(reason);
187
186
  this.active = null;
188
187
  if (result.confirmed) {
189
- clearLease(this.opts.dataDir);
188
+ await clearLease(this.opts.dataDir);
190
189
  return result;
191
190
  }
192
191
  this.unconfirmed = { reason: result.reason, pid: result.pid, identity: result.identity };
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/tunnel/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,eAAe,EAAE,UAAU,EAAsC,MAAM,YAAY,CAAC;AAC/H,OAAO,EACL,gBAAgB,GAKjB,MAAM,YAAY,CAAC;AAWpB;;;;;;GAMG;AACH,MAAM,OAAO,aAAa;IAYK,IAAI;IAXzB,QAAQ,GAAuC,IAAI,CAAC;IACpD,MAAM,GAAwB,IAAI,CAAC;IAC3C,qFAAqF;IAC7E,OAAO,GAAkB,IAAI,CAAC;IACtC;;;;OAIG;IACK,WAAW,GAA2E,IAAI,CAAC;IAEnG,YAA6B,IAA0B;oBAA1B,IAAI;IAAyB,CAAC;IAEnD,GAAG,CAAC,OAAe,IAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9E,8EAA8E;IACtE,aAAa;QACnB,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED,IAAI,MAAM,KAA0B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEzD,gFAAgF;IAChF,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAwB,EAAE,GAAuB;QACrD,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACpB,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,QAAwB,EAAE,GAAuB;QACrE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACxF,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,qCAAqC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACjH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO;gBACL,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI;gBACnD,OAAO,EAAE,wBAAwB,OAAO,CAAC,QAAQ,mCAAmC;aACrF,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACzG,CAAC;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,uBAAuB;QACvB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAC5B,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YACnC,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,QAAQ,EAAE,OAAO,CAAC,GAAG;YACrB,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE;SACpC,CAAC,CAAC;QAEH,IAAI,MAAoB,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,UAAU,GAAG,GAAG,YAAY,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAChE,IAAI,UAAU,EAAE,WAAW,EAAE,CAAC;gBAC5B,wEAAwE;gBACxE,sEAAsE;gBACtE,2CAA2C;gBAC3C,+FAA+F;gBAC/F,0FAA0F;gBAC1F,IAAI,CAAC;oBACH,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;wBAC5B,GAAG,EAAE,GAAG,CAAC,GAAG;wBACZ,QAAQ,EAAE,QAAQ,CAAC,IAAI;wBACvB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;wBACnC,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG;wBACvC,cAAc,EAAE,UAAU,CAAC,WAAW,CAAC,QAAQ;wBAC/C,SAAS,EAAE,GAAG,CAAC,SAAS;wBACxB,QAAQ,EAAE,OAAO,CAAC,GAAG;wBACrB,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE;qBACpC,CAAC,CAAC;gBACL,CAAC;gBAAC,OAAO,QAAQ,EAAE,CAAC;oBAClB,IAAI,CAAC,GAAG,CAAC,yDAA0D,QAAkB,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnG,CAAC;gBACD,IAAI,CAAC,WAAW,GAAG;oBACjB,MAAM,EAAE,sEAAsE;oBAC9E,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG;oBAC/B,QAAQ,EAAE,UAAU,CAAC,WAAW,CAAC,QAAQ;iBAC1C,CAAC;gBACF,IAAI,CAAC,OAAO,GAAG,sEAAsE;sBACjF,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI;sBACxF,oDAAoD,CAAC;gBACzD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACvB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;YAChG,CAAC;YACD,0EAA0E;YAC1E,gCAAgC;YAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,SAAS,EAAE,UAAU,EAAE,SAAS,IAAI,cAAc;gBAClD,OAAO,EAAG,GAAa,CAAC,OAAO;gBAC/B,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAED,wGAAwG;QACxG,uGAAuG;QACvG,2GAA2G;QAC3G,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBAC5B,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,QAAQ,EAAE,QAAQ,CAAC,IAAI;gBACvB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;gBACnC,WAAW,EAAE,MAAM,CAAC,GAAG;gBACvB,cAAc,EAAE,MAAM,CAAC,QAAQ;gBAC/B,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,QAAQ,EAAE,OAAO,CAAC,GAAG;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,6CAA8C,QAAkB,CAAC,OAAO,EAAE,CAAC,CAAC;YACrF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YACnE,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,SAAS,EAAE,cAAc;gBACzB,OAAO,EAAE,6CAA8C,QAAkB,CAAC,OAAO,GAAG;sBAChF,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,iDAAiD,CAAC;gBACxG,SAAS,EAAE,CAAC,OAAO,CAAC,SAAS;aAC9B,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,4GAA4G;YAC5G,gGAAgG;YAChG,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5F,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzF,IAAI,CAAC,OAAO,GAAG,wCAAwC;cACnD,GAAG,MAAM,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,IAAI;cAC1E,oDAAoD,CAAC;QACzD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,qFAAqF;AACrF,MAAM,UAAU,YAAY;IAC1B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/tunnel/manager.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -102,6 +102,8 @@ export interface InstanceConfig {
102
102
  native_agent_id?: string;
103
103
  /** Persistent terminal opt-in. Unset/exec preserves the per-turn adapter and rollback. */
104
104
  native_adapter?: "exec" | "pane";
105
+ /** Internal administrator-created General binding; runner computes its dedicated workspace. */
106
+ native_general_binding?: string;
105
107
  /** Native CLI permission selection; independent of Linux terminal permissions. */
106
108
  native_sandbox?: "read-only" | "workspace-write";
107
109
  /** Proactive interrupted-work continuation; defaults true, inherited from fleet defaults. */
@@ -49,11 +49,11 @@ export function refreshProposals() {
49
49
  * Once per page: read once, then again on the stream's `agent_proposals` ping (live) and whenever a status frame shows a
50
50
  * revision the list was not read at yet (#2997 review: a page that polls /ui/poll, one that reconnected, and a tab from
51
51
  * before the upgrade — whose stream knows no `agent_proposals` event — all still apply status frames; r2: until a read
52
- * at that revision succeeds). Never on the public link.
52
+ * at that revision succeeds). #3008: on the public link too — this computer's admin signed in from outside decides there;
53
+ * anyone else over it reads an empty list (the server answers the owner only).
53
54
  */
54
55
  export function installProposals() {
55
56
  if (installed) return;
56
- if (typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1") return;
57
57
  installed = true;
58
58
  const on = appStore.get().streamOn;
59
59
  if (typeof on === "function") {
@@ -0,0 +1,67 @@
1
+ import {html,useEffect,useRef,useState} from "/assets/app-html.js";
2
+ import {useLease} from "/assets/app-ctx.js";
3
+ import {appStore,useStore} from "/assets/app-store.js";
4
+ import {register,t} from "/assets/app-i18n.js";
5
+ import {sectionPath} from "/assets/app-route.js";
6
+ import {Dialog} from "/assets/ui-dialog.js";
7
+ import {CliPicker,CliProductMark,cliLabel} from "./cli-picker.js";
8
+ import {RuntimePicker,tr} from "./agent-runtime.js";
9
+ import {useRuntimeCatalog,runtimeCliChoices} from "./runtime-catalog.js";
10
+ import {useWindowsCliCatalog} from "./windows-cli-catalog.js";
11
+ import {useBackendRows} from "./settings-catalog.js";
12
+ import {ModelSelect} from "./settings-dialogs.js";
13
+ import {machineLabel} from "./settings-agent-filters.js";
14
+ import {removedBackendReplacement} from "./settings-model.js";
15
+ register("runtimeChange",{
16
+ "zh-TW":{removed:"{0} 已從 AgEnD 移除,無法繼續使用。請改選其他 CLI,建議使用 {1}。",title:"切換 Runtime 與 CLI",change:"切換 Runtime/CLI",current:"執行環境與 CLI",lead:"保留同一個 Agent 與 AgEnD 聊天歷史,在選擇的電腦開始新的 CLI 對話。",configure:"設定新環境",next:"下一步",back:"上一步",cancel:"取消",apply:"儲存切換",loading:"正在讀取 Agent 與 Runtime 狀態…",busy:"正在準備新工作區並關閉舊 CLI…",fresh:"我了解切換後會開始新的 CLI 對話",freshHint:"原有 CLI 對話與檔案會留在原電腦;不會自動複製到新環境。",stopped:"切換後 Agent 會暫停,請從 Agent 列表啟動。",directoryHint:"更換電腦時請填目標電腦的路徑;留空會建立獨立工作區。",dirty:"請先儲存或取消其他編輯,再切換 Runtime。",unknown:"請重新讀取 Agent 狀態再操作,避免重複切換。",reload:"重新讀取狀態",failed:"無法切換 Runtime",noCli:"這台電腦尚無可用的 CLI。請先到 Runtime 偵測或更新清單。",generalMove:"General 的位置不在這裡切換。請到「Agent 預設值 → General 位置」,那裡會暫停投遞並確認舊程式已結束。",generalGo:"前往 General 位置"},
17
+ en:{removed:"{0} was removed from AgEnD and can no longer run. Choose another CLI; {1} is its replacement.",title:"Change runtime and CLI",change:"Change runtime / CLI",current:"Runtime and CLI",lead:"Keep this Agent and its AgEnD chat history. Start a fresh CLI conversation on the selected computer.",configure:"Configure the new environment",next:"Next",back:"Back",cancel:"Cancel",apply:"Save runtime change",loading:"Loading Agent and runtime state…",busy:"Preparing the new workspace and closing the old CLI…",fresh:"I understand this starts a new CLI conversation",freshHint:"Existing CLI conversations and files stay on the original computer. They are not copied to the new environment.",stopped:"The Agent will be paused after switching. Start it from the Agent list.",directoryHint:"Use a path on the target computer. Leave empty for a separate managed workspace.",dirty:"Save or cancel other edits before changing runtime.",unknown:"Read the Agent state again before another operation to avoid switching twice.",reload:"Read state again",failed:"Could not change runtime",noCli:"No runnable CLI is available on this computer. Detect or refresh its inventory in Runtime settings.",generalMove:"General is not moved from here. Use Agent defaults → General location, which holds deliveries and confirms the old process has exited.",generalGo:"Go to General location"}
18
+ });
19
+ const text=(key,...values)=>t(`runtimeChange.${key}`,...values);
20
+ export function AgentRuntimeSettings({name,inst,disabled=false,inherited=null,onChanged}){
21
+ const [open,setOpen]=useState(false),general=inst.general_topic===true||name==="general";
22
+ // The computer's name as the Runtime page shows it; a computer that is revoked or gone says so (with the start of its id), never the whole id.
23
+ const where=inst.runtime==="windows"?(inst.machine_id?machineLabel(inst.machine_id,inst.machine_name,inst.machine_status,inst.machine_missing!==true):null):null;
24
+ const place=inst.runtime==="windows"?(where?where.label:tr("windows")):tr("wsl");
25
+ return html`<section class="agent-runtime-settings"><div><span class="note">${text("current")}</span><p><${CliProductMark} id=${inst.backend} size=${20}/><strong class="agent-runtime-place" title=${where?.title||place}>${place}</strong><span class=${removedBackendReplacement(inst.backend)?"agent-runtime-removed":undefined}>· ${removedBackendReplacement(inst.backend)?t("settings.backendUnavailable",inst.backend):cliLabel(inst.backend)}</span></p>${inherited}</div>${general?html`<p class="note agent-runtime-general">${text("generalMove")} <a href=${`${sectionPath("agent-defaults")}#general-location`}>${text("generalGo")}</a></p>`:html`<button type="button" class="btn btn-sm" disabled=${disabled} title=${disabled?text("dirty"):undefined} onClick=${()=>setOpen(true)}>${text("change")}</button>`}${open&&!general?html`<${AgentRuntimeChangeDialog} name=${name} inst=${inst} onClose=${()=>setOpen(false)} onChanged=${onChanged}/>`:null}</section>`;
26
+ }
27
+ export function AgentRuntimeChangeDialog({name,inst,onClose,onChanged}){
28
+ const lease=useLease(`runtime-change:${name}`),claim=useRef(false);
29
+ const {windowsCli}=useStore(appStore),machinesState=useRuntimeCatalog(),rows=useBackendRows();
30
+ const [source,setSource]=useState(null),[step,setStep]=useState(1),[error,setError]=useState(""),[busy,setBusy]=useState(false),[uncertain,setUncertain]=useState(false);
31
+ const [f,setForm]=useState({runtime:inst.runtime==="windows"?"windows":"wsl",machineId:inst.machine_id||"",backend:inst.backend||"",directory:inst.working_directory||"",model:inst.model||"",access:inst.native_sandbox||"read-only",adapter:inst.native_adapter||"exec",fresh:false});
32
+ const local=useWindowsCliCatalog(windowsCli===true&&f.runtime==="windows"&&!f.machineId),machines=machinesState.data?.machines||[],machine=machines.find(row=>row.id===f.machineId);
33
+ const windows=f.runtime==="windows",inventory=f.machineId?machine?.inventory:local.data;
34
+ const native=windows?(f.machineId?runtimeCliChoices(machine):inventory?.clis||[]).filter(cli=>cli.path&&cli.supports?.execution!==false&&cli.supports?.resume!==false):[];
35
+ const choices=windows?native.map(cli=>({value:cli.id,label:cliLabel(cli.id),disabled:!cli.runnable})): (rows||[]).filter(row=>row.installed!==false).map(row=>({value:row.name,label:cliLabel(row.name),disabled:["not_installed","not_signed_in","too_old"].includes(source?.runtime==="wsl"&&source.backend===row.name?(source.backendState||row.state):row.state)}));
36
+ const selected=native.find(cli=>cli.id===f.backend),targetReady=!!choices.find(choice=>choice.value===f.backend&&!choice.disabled)&&(!f.machineId||machine?.status==="online");
37
+ const allowedRead=!windows||selected?.readOnlySupport!==false;
38
+ const set=(key,value)=>setForm(old=>({...old,[key]:value}));
39
+ const load=async()=>{
40
+ if(claim.current)return;setSource(null);setError("");
41
+ try{const response=await lease.fetch(`/ui/instances/${encodeURIComponent(name)}/runtime`),value=await response.json();if(!lease.current())return;if(!response.ok)throw Error(value.error||text("failed"));
42
+ const {sandbox:access}=value;setSource(value);setUncertain(false);setStep(1);setForm({runtime:value.runtime,machineId:value.machineId||"",backend:value.backend||inst.backend||"",directory:value.directory||"",model:value.model||"",access,adapter:value.adapter,fresh:false});
43
+ }catch(e){if(lease.current())setError(e.message);}
44
+ };
45
+ useEffect(()=>{void load();},[lease]);
46
+ useEffect(()=>{void machinesState.refresh();},[]);
47
+ const choose=(runtime,machineId="")=>setForm(old=>({...old,runtime,machineId,backend:"",model:"",directory:runtime===source?.runtime&&machineId===(source?.machineId||"")?source.directory:"",access:"read-only",adapter:"exec",fresh:false}));
48
+ useEffect(()=>{if(!f.backend&&choices.some(choice=>!choice.disabled))set("backend",choices.find(choice=>!choice.disabled).value);},[f.runtime,f.machineId,f.backend,choices.map(choice=>`${choice.value}:${choice.disabled}`).join(",")]);
49
+ const submit=async()=>{
50
+ if(claim.current||uncertain||!source||!f.fresh||!targetReady||(!allowedRead&&f.access==="read-only"))return;
51
+ claim.current=true;setBusy(true);setError("");
52
+ const body={requestId:crypto.randomUUID(),expectedRevision:source.revision,runtime:f.runtime,...(f.machineId?{machineId:f.machineId}:{}),backend:f.backend,model:f.model.trim(),directory:f.directory.trim(),sandbox:f.access,adapter:windows?f.adapter:"exec",startNewConversation:true};
53
+ try{const response=await lease.fetch(`/ui/instances/${encodeURIComponent(name)}/runtime`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)}),value=await response.json();if(!lease.current())return;
54
+ if(!response.ok||value?.ok!==true)throw Error(value.error||text("failed"));onChanged?.();onClose();
55
+ }catch(e){if(lease.current()){setError(e.message);setUncertain(true);}}
56
+ finally{claim.current=false;if(lease.current())setBusy(false);}
57
+ };
58
+ const close=()=>{if(!claim.current)onClose();};
59
+ return html`<${Dialog} title=${text("title")} cls="agent-runtime-change-dialog" busy=${busy} onClose=${close} wide=${true} actions=${html`<button type="button" class="btn" disabled=${busy} onClick=${close}>${text("cancel")}</button>${step===2?html`<button type="button" class="btn" disabled=${busy||uncertain} onClick=${()=>setStep(1)}>${text("back")}</button>`:null}<button type="button" class="btn btn-primary" disabled=${busy||uncertain||!source||!targetReady||(step===2&&(!f.fresh||!allowedRead&&f.access==="read-only"))} onClick=${step===1?()=>setStep(2):submit}>${text(step===1?"next":"apply")}</button>`}>
60
+ <div class="form agent-runtime-change" aria-busy=${busy}><p>${text("lead")}</p>${!source?html`<p role="status">${text("loading")}</p>`:null}
61
+ ${source&&step===1?html`<${RuntimePicker} value=${f.runtime} onChange=${runtime=>choose(runtime)} windowsEnabled=${windowsCli===true} machineId=${f.machineId} machines=${machines} onMachineChange=${id=>choose("windows",id)} onRefresh=${machinesState.refresh} loaded=${!!machinesState.data && !machinesState.error}/><div class="field"><label>${tr("backend")}</label><${CliPicker} value=${f.backend} choices=${choices} label=${tr("backend")} onChange=${backend=>setForm(old=>({...old,backend,model:"",fresh:false}))}/></div>${removedBackendReplacement(f.backend)?html`<p class="note" role="status">${text("removed",f.backend,removedBackendReplacement(f.backend))}</p>`:null}${!choices.length?html`<p class="note">${text("noCli")}</p>`:null}`:null}
62
+ ${source&&step===2?html`<h3>${text("configure")}</h3><p><strong>${machine?.name||(windows?tr("windows"):tr("wsl"))}</strong> · ${cliLabel(f.backend)}</p><label class="field"><span>${tr("directory")}</span><input value=${f.directory} disabled=${busy||uncertain} onInput=${event=>set("directory",event.target.value)}/></label><p class="note">${text("directoryHint")}</p><div class="field"><label for="runtime-change-model">${t("settings.model")}</label><${ModelSelect} id="runtime-change-model" disabled=${busy||uncertain} value=${f.model} onChange=${value=>set("model",value)} backend=${f.backend} instance=${!windows&&source.runtime==="wsl"&&source.backend===f.backend?name:undefined} runtime=${f.runtime} machineId=${f.machineId} inherit=${t("settings.modelCliDefault")}/></div>
63
+ ${windows?html`<label class="field"><span>${tr("access")}</span><select value=${f.access} disabled=${busy||uncertain} onChange=${event=>set("access",event.target.value)}><option value="read-only" disabled=${!allowedRead}>${tr("read")}</option><option value="workspace-write">${tr("write")}</option></select></label>${!allowedRead?html`<p class="note" role="status">${tr("noReadOnly")}</p>`:null}<label class="field"><span>${tr("adapter")}</span><select value=${f.adapter} disabled=${busy||uncertain} onChange=${event=>set("adapter",event.target.value)}><option value="exec">${tr("adapterExec")}</option><option value="pane" disabled=${!["codex","claude-code"].includes(f.backend)}>${tr("adapterPane")}</option></select></label>`:null}
64
+ <p class="note">${text("freshHint")}</p><p class="note">${text("stopped")}</p><label class="check"><input type="checkbox" checked=${f.fresh} disabled=${busy||uncertain} onChange=${event=>set("fresh",event.target.checked)}/><span>${text("fresh")}</span></label>`:null}
65
+ ${busy?html`<p role="status"><span class="out-spin" aria-hidden="true"></span> ${text("busy")}</p>`:null}${error?html`<p class="feedback error" role="alert">${error}</p>`:null}${uncertain?html`<p class="note">${text("unknown")}</p><button type="button" class="btn" onClick=${load}>${text("reload")}</button>`:null}</div>
66
+ </${Dialog}>`;
67
+ }
@@ -2,6 +2,7 @@ import { html, useEffect, useRef, useState } from "/assets/app-html.js";
2
2
  import { register, t } from "/assets/app-i18n.js";
3
3
  import { useLease } from "/assets/app-ctx.js";
4
4
  import { Icon } from "/assets/ui-icons.js";
5
+ import { runtimeCliChoices } from "./runtime-catalog.js";
5
6
 
6
7
  register("runtime", {
7
8
  "zh-TW": { title:"新增 Agent", choose:"1. 選擇 Runtime", wsl:"WSL / Linux", windows:"Windows 本機", wslHint:"使用 Linux CLI 與工作目錄", windowsHint:"使用 Windows 工具與本機登入", disabled:"需要先啟用 Windows CLI", configure:"2. 設定 Agent", backend:"CLI", directory:"工作目錄(選填)", nativeHint:"建立 Windows Codex Agent,保留獨立對話。Claude Code 目前僅支援偵測。", model:"使用 Windows Codex 的預設模型", access:"檔案存取", read:"唯讀", write:"工作目錄可寫入", required:"請填入 Agent 名稱,工作目錄可以留空。", created:"Windows Agent 已建立", assist:"讓 AI 幫我填寫", assistHint:"由已登入的 Windows Codex 產生草稿,填回下方後可編輯,再按「建立」。", noAi:"需要先有可用的 AI:請在設定 → Windows CLI 確認 Codex 已登入。", goal:"描述想建立的 Agent", placeholder:"例如:建立一個協助整理資料、回答問題的助手", generate:"產生設定草稿", generating:"AI 正在產生草稿…", cancel:"取消產生", draftError:"AI 沒有回傳有效的設定草稿,請調整描述後再試。", nativeBackend:"Codex — Windows", nativeClaude:"Claude Code — Windows(僅偵測)" },
@@ -25,6 +26,10 @@ register("runtime", {
25
26
  en: { computers:"Connected computers", online:"Online", offline:"Offline", pending:"Awaiting approval", revoked:"Revoked", machineLoading:"Loading connected computers…", machineFailed:"Could not update connected computers. Local choices are still available.", machineRetry:"Refresh computers", noRemoteCli:"This computer has not reported a task-capable CLI.", remoteDirectory:"Working directory on {0} (optional)", remoteDraft:"AI-assisted setup is currently available for the local runtime. You can enter this remote agent's settings below.", machine:"Computer", inventoryAt:"CLI inventory updated: {0}", remotePolicy:"Files and CLI permissions belong to the selected computer. Sign-ins remain on that computer.", manage:"Connect or manage computers in Settings → Runtime", noAvailableMachine:"Connect and approve a computer in Settings → Runtime to use its CLIs." },
26
27
  "zh-TW": { computers:"已連接的電腦", online:"在線", offline:"離線", pending:"等待核准", revoked:"已撤銷", machineLoading:"正在載入已連接的電腦…", machineFailed:"無法更新已連接的電腦,仍可使用本機選項。", machineRetry:"更新機器清單", noRemoteCli:"這台電腦尚未回報可派工的 CLI。", remoteDirectory:"{0} 上的工作目錄(選填)", remoteDraft:"AI 協助設定目前適用於本機 Runtime,你可以直接填寫下方遠端 Agent 設定。", machine:"電腦", inventoryAt:"CLI 清單更新:{0}", remotePolicy:"檔案與 CLI 權限屬於所選電腦,登入也保留在該電腦上。", manage:"前往設定 → Runtime 連接或管理電腦", noAvailableMachine:"在設定 → Runtime 連接並核准電腦後,即可使用它的 CLI。" },
27
28
  });
29
+ register("runtime", {
30
+ en: { machineOffline:"Offline: run connect-agend.bat on that computer.", machinePending:"Awaiting approval: choose Approve computer in Settings → Runtime.", machineNoInventory:"CLIs not detected yet: choose Refresh CLI inventory for it in Settings → Runtime.", machineNoCli:"No task-capable CLI reported: install one, then choose Refresh CLI inventory in Settings → Runtime.", machineNotReady:"No CLI is signed in and ready: sign in on that computer, then choose Refresh CLI inventory in Settings → Runtime." },
31
+ "zh-TW": { machineOffline:"離線:請在那台電腦執行 connect-agend.bat。", machinePending:"等待核准:請到設定 → Runtime 按「核准電腦」。", machineNoInventory:"尚未偵測 CLI:到設定 → Runtime 按該電腦的「更新 CLI 清單」。", machineNoCli:"沒有可派工的 CLI:請先安裝,再到設定 → Runtime 按「更新 CLI 清單」。", machineNotReady:"CLI 尚未登入或只能偵測:請在那台電腦登入,再到設定 → Runtime 按「更新 CLI 清單」。" },
32
+ });
28
33
  register("runtime", {
29
34
  "zh-TW": {
30
35
  agendQueries:"AgEnD 工具:唯讀模式可查詢 Agent、任務與派送狀態。",
@@ -44,9 +49,22 @@ export function NativeAgendToolsHint({ cli, sandbox }) {
44
49
  return html`<p class="note native-agend-tools">${tr(!supported ? "agendUnavailable" : sandbox === "read-only" ? "agendQueries" : "agendActions")}</p>`;
45
50
  }
46
51
  /** #2953 story 3 (S-35): with this PC's Windows CLIs switched off, "Native Windows" is not offered at all (paired PCs still are). */
47
- export function RuntimePicker({ value, onChange, windowsEnabled, disabled, machineId = "", machines = [], onMachineChange, legend = tr("choose") }) {
52
+ /** Why a connected computer cannot take a new agent yet ("" when it can). Offline, awaiting approval and no usable CLI are deliberate blocks; the picker says which. */
53
+ export function machineBlockReason(machine) {
54
+ if (machine.status === "pending") return "machinePending";
55
+ if (machine.status !== "online") return "machineOffline";
56
+ if (!machine.inventory) return "machineNoInventory";
57
+ const choices = runtimeCliChoices(machine);
58
+ // Same bar as the dialogs' "Next": a computer is usable once one of its task-capable CLIs is runnable.
59
+ return !choices.length ? "machineNoCli" : choices.some(cli => cli.runnable === true) ? "" : "machineNotReady";
60
+ }
61
+ export function RuntimePicker({ value, onChange, windowsEnabled, disabled, machineId = "", machines = [], onMachineChange, onRefresh, loaded = false, legend = tr("choose") }) {
62
+ const [refreshing, setRefreshing] = useState(false);
63
+ // Only a click on the button disables it, never the 5 s background poll (that would drop keyboard focus).
64
+ const refresh = async () => { setRefreshing(true); try { await onRefresh(); } finally { setRefreshing(false); } };
65
+ const listed = machines.filter(machine => machine.status !== "revoked");
48
66
  return html`<fieldset class="agent-runtime-picker" disabled=${disabled}><legend>${legend}</legend><div>${(windowsEnabled ? ["wsl","windows"] : ["wsl"]).map(runtime => html`<label key=${runtime} class=${`agent-runtime-choice${!machineId && value === runtime ? " selected" : ""}`}><input type="radio" name="agent-runtime" value=${runtime} checked=${!machineId && value === runtime} disabled=${runtime === "windows" && !windowsEnabled} onChange=${() => onChange(runtime)} /><${Icon} name=${runtime === "windows" ? "view" : "code"} size=${22} /><span><strong>${tr(runtime)}</strong><small>${tr(runtime === "windows" && !windowsEnabled ? "disabled" : `${runtime}Hint`)}</small></span></label>`)}</div>
49
- ${machines.length ? html`<section class="runtime-remote-targets" aria-label=${tr("computers")}><h4>${tr("computers")}</h4>${machines.filter(machine => machine.status !== "revoked").map(machine => html`<label key=${machine.id} class=${`agent-runtime-choice${machineId === machine.id ? " selected" : ""}`}><input type="radio" name="agent-runtime" value=${`machine:${machine.id}`} checked=${machineId === machine.id} disabled=${machine.status !== "online"} onChange=${() => onMachineChange?.(machine.id)} /><${Icon} name="view" size=${22} /><span><strong>${machine.name}</strong><small>${machine.platform || "Windows"} · ${tr(["online","offline","pending"].includes(machine.status) ? machine.status : "offline")}</small></span></label>`)}</section>` : null}
67
+ ${listed.length || onRefresh ? html`<section class="runtime-remote-targets" aria-label=${tr("computers")}><div class="runtime-remote-heading"><h4>${tr("computers")}</h4>${onRefresh ? html`<button type="button" class="btn btn-ghost btn-sm" disabled=${refreshing} onClick=${refresh}>${tr("machineRetry")}</button>` : null}</div>${listed.map(machine => { const reason = machineBlockReason(machine), status = ["online","offline","pending"].includes(machine.status) ? machine.status : "offline"; return html`<label key=${machine.id} class=${`agent-runtime-choice${machineId === machine.id ? " selected" : ""}${reason ? " blocked" : ""}`}><input type="radio" name="agent-runtime" value=${`machine:${machine.id}`} checked=${machineId === machine.id} disabled=${!!reason} aria-describedby=${reason ? `machine-reason-${machine.id}` : undefined} onChange=${() => onMachineChange?.(machine.id)} /><${Icon} name="view" size=${22} /><span><strong>${machine.name}</strong><small><span class="runtime-machine-platform">${machine.platform || "Windows"} · </span><span class=${`runtime-machine-status is-${status}`}>${tr(status)}</span></small>${reason ? html`<small class="runtime-machine-reason" id=${`machine-reason-${machine.id}`}>${tr(reason)}</small>` : null}</span></label>`; })}${loaded && !listed.length ? html`<p class="note">${tr("noAvailableMachine")}</p>` : null}</section>` : null}
50
68
  </fieldset>`;
51
69
  }
52
70
  export function parseAgentDraft(text, runtime) {
@@ -12,6 +12,7 @@ import { closeDialog, shellStore, showDialog } from "/assets/app-shell.js";
12
12
  import { Dialog } from "/assets/ui-dialog.js";
13
13
  import { toast } from "/assets/ui-toast.js";
14
14
  import { mountStructuredSignIns } from "./structured-signin.js";
15
+ import { CliProductMark, cliLabel } from "./cli-picker.js";
15
16
 
16
17
  register("signin", {
17
18
  en: {
@@ -231,11 +232,12 @@ export function BrowserSignInDialog({ backend, backends, onClose }) {
231
232
  if (!result.ok) { toast(tn("failed")); return; }
232
233
  showDialog(SignInDialog, { backend: chosen });
233
234
  };
234
- return html`<${Dialog} title=${backends ? tn("listTitle") : tn("title", backend)} onClose=${close}>
235
- <div ref=${root}></div>
235
+ const actions = html`<div class="signin-browser-actions">
236
236
  ${backends ? backends.filter(b => b !== "antigravity").map(b => html`<button type="button" class="btn" onClick=${() => fallback(b)}>${b} · ${tn("consoleFallback")}</button>`) : null}
237
- <div class="s-actions">${backend ? html`<button type="button" class="btn" onClick=${() => fallback(backend)}>${tn("consoleFallback")}</button>` : null}
238
- <button type="button" class="btn" onClick=${close}>${tn("close")}</button></div>
237
+ ${backend ? html`<button type="button" class="btn" onClick=${() => fallback(backend)}>${tn("consoleFallback")}</button>` : null}
238
+ <button type="button" class="btn" onClick=${close}>${tn("close")}</button></div>`;
239
+ return html`<${Dialog} title=${backends ? tn("listTitle") : tn("title", cliLabel(backend))} onClose=${close} actions=${actions}>
240
+ <div class="signin-browser" ref=${root}></div>
239
241
  </${Dialog}>`;
240
242
  }
241
243
 
@@ -327,28 +329,41 @@ export function SignInLine() {
327
329
 
328
330
  const STATE_KEY = { usable: "stUsable", not_signed_in: "stNotSignedIn", not_installed: "stNotInstalled", too_old: "stTooOld", unknown: "stUnknown" };
329
331
 
330
- /** Settings → Agents: each login on this machine, with Sign in where the dashboard can do it. */
332
+ register("signin", {
333
+ en: {
334
+ hostTitle: "CLI sign-ins", hostHint: "Accounts used by CLIs on the host running AgEnD.",
335
+ hostBadge: "AgEnD host", hostProfile: "Credential profile: {0}", hostLoading: "Reading CLI sign-ins…", hostEmpty: "No CLI sign-ins were reported on this host.",
336
+ installHelp: "Installation instructions", updateHelp: "Update instructions", hostHelp: "Sign-in instructions",
337
+ commandHint: "Run these instructions in a terminal on the host running AgEnD.",
338
+ },
339
+ "zh-TW": {
340
+ hostTitle: "CLI 登入", hostHint: "執行 AgEnD 的主機上,各個 CLI 使用的帳號。",
341
+ hostBadge: "AgEnD 主機", hostProfile: "憑證設定檔:{0}", hostLoading: "正在讀取 CLI 登入狀態…", hostEmpty: "這台主機尚未回報 CLI 登入項目。",
342
+ installHelp: "安裝說明", updateHelp: "更新說明", hostHelp: "登入說明",
343
+ commandHint: "請在執行 AgEnD 的主機終端機中操作。",
344
+ },
345
+ });
346
+
347
+ /** Settings → Agents: existing host sign-in actions, with commands disclosed only when needed. */
331
348
  export function SignInList() {
332
349
  const { targets, loaded, login, structured } = useStore(signInStore);
333
- // Not over the temporary public link: only the dashboard reached directly signs a backend in, and the link does not
334
- // serve this read (it was a 404 in the console there, found by smoke-1939-authorize-defaults).
350
+ // Public-link authority remains unchanged: this page neither reads nor offers host sign-in there.
335
351
  const offered = signInOffered();
336
352
  useEffect(() => { if (offered) void refreshSignIn(); }, []);
337
- if (!offered || !loaded || !targets.length) return null;
353
+ if (!offered) return null;
338
354
  const active = structured?.login;
339
355
  const running = (login && login.phase === "running") || (active && active.phase !== "done" && !(active.phase === "failed" && active.reason));
340
- return html`<section class="s-group signin-list" aria-label=${tn("listTitle")}>
341
- <div class="list-head"><span>${tn("listTitle")}</span></div>
342
- <p class="sub">${tn("listHint")}</p>
343
- ${targets.map((x) => html`<div key=${`${x.backend}:${x.profile || ""}`} class="s-row">
344
- <span class="s-name">${shownOf(x.backend, x.profile)}</span>
345
- <span class="tag">${tn(STATE_KEY[x.state] || "stUnknown")}</span>
346
- <span class="s-br" aria-hidden="true"></span>
347
- ${x.install ? html`<span class="s-meta"><code>${tn("install", x.install)}</code></span>` : null}
348
- ${x.update ? html`<span class="s-meta"><code>${tn("update", x.update)}</code></span>` : null}
349
- ${x.hostCommand ? html`<span class="s-meta"><code>${tn("onHost", x.hostCommand)}</code></span>` : null}
350
- <span class="s-actions">${x.signIn ? html`<button type="button" class=${x.state === "not_signed_in" ? "btn btn-sm btn-primary" : "btn btn-sm"} disabled=${!!running}
351
- onClick=${() => openSignIn(x)}>${x.state === "usable" ? tn("signInAgain") : tn("signIn")}</button>` : null}</span>
352
- </div>`)}
356
+ return html`<section class="s-group signin-list s-auth-section" aria-label=${tn("hostTitle")}>
357
+ <header class="s-auth-section-head"><div><h3>${tn("hostTitle")}</h3><p>${tn("hostHint")}</p></div><span class="s-auth-host-badge">${tn("hostBadge")}</span></header>
358
+ ${!loaded ? html`<p class="note" role="status">${tn("hostLoading")}</p>` : !targets.length ? html`<p class="note">${tn("hostEmpty")}</p>` : html`<div class="s-host-cli-list">${targets.map((x) => {
359
+ const commands = [["install", x.install], ["update", x.update], ["onHost", x.hostCommand]].filter(([, value]) => value);
360
+ return html`<div key=${`${x.backend}:${x.profile || ""}`} class="s-row s-host-cli-row" data-backend=${x.backend}>
361
+ <div class="s-host-cli-identity"><${CliProductMark} id=${x.backend} size=${24} /><div><strong class="s-name">${cliLabel(x.backend)}</strong>${x.profile ? html`<small>${tn("hostProfile", x.profile)}</small>` : null}</div></div>
362
+ <span class=${`tag s-auth-state is-${x.state || "unknown"}`}>${tn(STATE_KEY[x.state] || "stUnknown")}</span>
363
+ ${x.signIn ? html`<span class="s-actions"><button type="button" class=${x.state === "not_signed_in" ? "btn btn-sm btn-primary" : "btn btn-sm"} disabled=${!!running}
364
+ onClick=${() => openSignIn(x)}>${x.state === "usable" ? tn("signInAgain") : tn("signIn")}</button></span>` : null}
365
+ ${commands.length ? html`<details class="s-host-cli-help" data-inline-help=${x.signIn ? "false" : "true"}><summary>${tn(x.install ? "installHelp" : x.update ? "updateHelp" : "hostHelp")}</summary><div><p class="note">${tn("commandHint")}</p>${commands.map(([kind, command]) => html`<p class="s-host-cli-command"><code>${tn(kind, command)}</code></p>`)}</div></details>` : null}
366
+ </div>`;
367
+ })}</div>`}
353
368
  </section>`;
354
369
  }
@@ -0,0 +1,71 @@
1
+ // The location is a separate revision-bound Settings operation, never an agent-config patch.
2
+ import { html, useEffect, useRef, useState } from "/assets/app-html.js";
3
+ import { t, register } from "/assets/app-i18n.js";
4
+ import { appStore, useStore, guestPage } from "/assets/app-store.js";
5
+ import { useLease } from "/assets/app-ctx.js";
6
+ import { toast } from "/assets/ui-toast.js";
7
+ import { confirmedWrite, newKey } from "./settings-confirm.js";
8
+ import { ModelSelect } from "./settings-dialogs.js";
9
+ register("generalLocation", {
10
+ en: {
11
+ label: "Run General on", host: "This AgEnD host", windows: "Paired Windows PC",
12
+ offline: "General’s Windows PC is offline. AgEnD is still running here. Reconnect that PC, or switch General back to this host in Settings. Pending or uncertain requests will not be sent again automatically.",
13
+ exit: "General was not switched: the previous process has not been confirmed stopped. Reconnect its PC or use the existing stopped-process recovery, then try again. No replacement was started.",
14
+ start: "General’s location was saved, but it could not start. Check Needs you and choose Start or switch back. Its previous conversation is kept; no input was replayed.",
15
+ history: "Host and Windows conversations stay separate. Switching does not copy or merge their history.",
16
+ },
17
+ "zh-TW": {
18
+ label: "General 執行位置", host: "這台 AgEnD 主機", windows: "已配對的 Windows 電腦",
19
+ offline: "General 所在的 Windows 電腦已離線。AgEnD 仍在這台主機運作。請重新連線那台電腦,或到設定把 General 切回這台主機。待處理或結果不明的請求不會自動重送。",
20
+ exit: "General 尚未切換:還無法確認前一個程序已停止。請重新連線那台電腦,或完成現有的程序停止復原,再重試。沒有啟動替代程序。",
21
+ start: "General 的執行位置已儲存,但未能啟動。請查看「等你處理」,選擇啟動或切回原位置。先前的對話已保留,沒有重送輸入。",
22
+ history: "主機與 Windows 各自保留對話,切換時不會複製或合併對話紀錄。",
23
+ },
24
+ });
25
+ const tr = key => t(`generalLocation.${key}`);
26
+ export function GeneralLocation({ name, attentionOnly = false }) {
27
+ const app = useStore(appStore);
28
+ const attentionKey = JSON.stringify((app.needs || []).filter(item => item.generalLocation && (!name || item.instance === name)).map(item => item.id));
29
+ const lease = useLease("general-location"), [data, setData] = useState(null), [error, setError] = useState(null);
30
+ const read = async () => {
31
+ try { const response = await lease.fetch("/api/settings/general-location"); const result = await response.json();
32
+ if (lease.current()) { if (response.ok) { setData(result); setError(null); } else setError(result.error); }
33
+ } catch (err) { if (lease.current()) setError(err.message); }
34
+ };
35
+ useEffect(() => { if (!guestPage()) void read(); }, [name, attentionKey]);
36
+ if (guestPage()) return null;
37
+ return html`<section id="general-location" class="card general-location"><h2>${tr("label")}</h2>
38
+ ${error ? html`<p role="alert">${error}</p>` : null}
39
+ ${(data?.generals || []).filter(row => !name || row.name === name).map(row => html`<${LocationRow} key=${row.name + row.revision} row=${row} machines=${data.machines || []} attentionOnly=${attentionOnly} refresh=${read} />`)}
40
+ ${!attentionOnly ? html`<button type="button" class="btn btn-sm" onClick=${read}>${t("settings.refresh")}</button>` : null}
41
+ </section>`;
42
+ }
43
+ function LocationRow({ row, machines, attentionOnly, refresh }) {
44
+ const [target, setTarget] = useState("host"), [cli, setCli] = useState("claude-code"), [model, setModel] = useState("");
45
+ const [busy, setBusy] = useState(false), flight = useRef(false);
46
+ const lease = useLease("general-location-row");
47
+ const machine = machines.find(item => item.id === target);
48
+ // The rendered revision stays with this click. Never re-read and silently retry a stale proposal.
49
+ const propose = async next => {
50
+ if (flight.current || !lease.current()) return; flight.current = true; setBusy(true);
51
+ try { const result = await confirmedWrite("/api/settings/general-location", { body: { name: row.name, revision: row.revision, target: next }, key: newKey("general"), label: tr("label") });
52
+ if (lease.current()) { toast(result.body?.message || result.body?.error || t(result.ok ? "app.saved" : "app.failed"), result.ok); await refresh(); }
53
+ } catch (err) { if (lease.current()) toast(err.message, false); }
54
+ finally { flight.current = false; if (lease.current()) setBusy(false); }
55
+ };
56
+ if (attentionOnly && !row.offline && !row.hold) return null;
57
+ return html`<div class="general-location-row" data-general=${row.name}>
58
+ <strong>${row.displayName}</strong><p>${row.location === "host" ? tr("host") : `${machines.find(item => item.id === row.machineId)?.name || tr("windows")} · ${row.cli}`}</p>
59
+ ${row.offline || row.hold ? html`<p role="alert">${tr(row.hold || "offline")}</p>` : null}
60
+ <p class="note">${tr("history")}</p>
61
+ ${row.canSwitchBack ? html`<button type="button" class="btn" disabled=${busy || row.switching} onClick=${() => propose({ location: "host" })}>${tr("host")}</button>` : null}
62
+ ${row.hold === "start" ? html`<button type="button" class="btn" disabled=${busy || row.switching} onClick=${() => propose(row.retryTarget || (row.location === "host" ? { location: "host" } : { location: "windows", machineId: row.machineId, cli: row.cli, model: row.model }))}>${t("chat.start")}</button>` : null}
63
+ ${!attentionOnly ? html`<label>${tr("label")}<select value=${target} disabled=${busy || row.switching} onChange=${e => { setTarget(e.target.value); setModel(""); }}>
64
+ <option value="host">${tr("host")}</option>${machines.map(item => html`<option value=${item.id} disabled=${!item.online}>${item.name}</option>`)}
65
+ </select></label>
66
+ ${target !== "host" ? html`<label>${t("settings.backend")}<select value=${cli} onChange=${e => { setCli(e.target.value); setModel(""); }}>
67
+ ${["claude-code", "codex"].map(id => html`<option value=${id} disabled=${!machine?.clis.some(item => item.id === id)}>${id}</option>`)}
68
+ </select></label><${ModelSelect} value=${model} onChange=${setModel} backend=${cli} runtime="windows" machineId=${target} instance=${row.name} />` : null}
69
+ <button type="button" class="btn btn-primary" disabled=${busy || row.switching || target === "host" && !row.canSwitchBack || target !== "host" && (!machine?.online || !machine.clis.some(item => item.id === cli))} onClick=${() => propose(target === "host" ? { location: "host" } : { location: "windows", machineId: target, cli, model })}>${t("settings.save")}</button>` : null}
70
+ </div>`;
71
+ }
@@ -1,16 +1,12 @@
1
1
  // Windows uses the same staged instance settings flow, with its runtime's supported fields.
2
2
  import { html, useState } from "/assets/app-html.js";
3
- import { t, register } from "/assets/app-i18n.js";
3
+ import { t } from "/assets/app-i18n.js";
4
4
  import { Dialog } from "/assets/ui-dialog.js";
5
5
  import { ChipList, ModelSelect } from "./settings-dialogs.js";
6
- import { CliProductMark, cliLabel } from "./cli-picker.js";
7
6
  import { useWindowsCliCatalog } from "./windows-cli-catalog.js";
8
7
  import { useRuntimeCatalog, instanceMachineId } from "./runtime-catalog.js";
9
8
  import { NativeAgendToolsHint, tr } from "./agent-runtime.js";
10
- register("nativeInstance", {
11
- "zh-TW": { fixed:"Runtime 與 CLI 隨此對話保留。", workspace:"此 Agent 的對話會沿用這個工作區。" },
12
- en: { fixed:"This conversation keeps its runtime and CLI.", workspace:"This agent's conversation keeps this workspace." },
13
- });
9
+ import {AgentRuntimeSettings} from "./agent-runtime-settings.js";
14
10
  const tn = key => t(`settings.${key}`);
15
11
  export function NativeInstanceSettings({ name, inst, ctx, onClose }) {
16
12
  const machineId = instanceMachineId(inst);
@@ -19,6 +15,7 @@ export function NativeInstanceSettings({ name, inst, ctx, onClose }) {
19
15
  const native = (machineId ? machine?.inventory : catalog.data)?.clis?.find(cli => cli.id === inst.backend);
20
16
  const [form,setForm] = useState(() => ({display_name:inst.display_name || name,description:inst.description || "",model:inst.model || "",systemPrompt:inst.systemPrompt || "",native_sandbox:inst.native_sandbox || "read-only",tags:Array.isArray(inst.tags) ? [...inst.tags] : []}));
21
17
  const set = key => value => setForm(current => ({...current,[key]:value}));
18
+ const dirty=Object.entries(form).some(([key,value])=>JSON.stringify(typeof value==="string"?value.trim():value)!==JSON.stringify(key==="display_name"?inst.display_name||name:key==="native_sandbox"?inst.native_sandbox||"read-only":key==="tags"?inst.tags||[]:inst[key]||""));
22
19
  const ready = !!form.display_name.trim() && !(form.native_sandbox === "read-only" && native?.readOnlySupport === false);
23
20
  const stage = () => {
24
21
  if (!ready) return;
@@ -31,8 +28,8 @@ export function NativeInstanceSettings({ name, inst, ctx, onClose }) {
31
28
  if (Object.keys(patch).length) ctx.stageAgent(name,inst,patch);
32
29
  onClose();
33
30
  };
34
- return html`<${Dialog} title=${ctx.shortName(name,inst)} onClose=${onClose} wide=${true} actions=${html`<button type="button" class="btn" onClick=${onClose}>${tn("cancel")}</button><button type="button" class="btn btn-primary" disabled=${!ready} onClick=${stage}>${tn("modalDone")}</button>`}>
35
- <div class="form native-instance-settings"><p class="note"><${CliProductMark} id=${inst.backend} size=${20} /> Windows · ${cliLabel(inst.backend)} — ${t("nativeInstance.fixed")}</p>${machineId ? html`<p class="note runtime-instance-machine">${tr("machine")}: ${machine?.name || inst.machine_name || machineId}</p>` : null}
31
+ return html`<${Dialog} title=${ctx.shortName(name,inst)} onClose=${onClose} wide=${true} drawer=${true} actions=${html`<button type="button" class="btn" onClick=${onClose}>${tn("cancel")}</button><button type="button" class="btn btn-primary" disabled=${!ready} onClick=${stage}>${tn("modalDone")}</button>`}>
32
+ <div class="form native-instance-settings"><${AgentRuntimeSettings} name=${name} inst=${{...inst,machine_name:machine?.name||inst.machine_name,machine_status:machine?.status||inst.machine_status,machine_missing:!!machineId&&!!machines.data&&machines.data.enabled!==false&&!machine}} disabled=${dirty||ctx.staged?.size>0} onChanged=${()=>{ctx.reload();onClose();}}/>
36
33
  <label class="field"><span>${tn("displayName")}</span><input value=${form.display_name} maxLength=${64} onInput=${event => set("display_name")(event.target.value)} /></label>
37
34
  <label class="field"><span>${tn("description")}</span><input value=${form.description} maxLength=${512} onInput=${event => set("description")(event.target.value)} /></label>
38
35
  <div class="field"><label for="native-instance-model">${tn("model")}</label><${ModelSelect} id="native-instance-model" value=${form.model} onChange=${set("model")} backend=${inst.backend} instance=${name} runtime="windows" machineId=${machineId} inherit=${tr("model")} /></div>
@@ -23,7 +23,7 @@ export function NativePaneRecovery({ name, inst, lease }) {
23
23
  finally { inFlight.current = false; if (lease.current()) setBusy(false); }
24
24
  };
25
25
  if (guestPage() || inst.native_adapter !== "pane") return null;
26
- if (!recovery) return ["stopped", "crashed"].includes(inst.status)
26
+ if (!recovery) return !inst.general_topic && ["stopped", "crashed"].includes(inst.status)
27
27
  ? html`<div class="windows-agent-blocked"><button type="button" class="btn" disabled=${busy} onClick=${() => act(`/ui/start/${encodeURIComponent(name)}`)}>${t("chat.start")}</button></div>` : null;
28
28
  if (recovery.kind === "session-unconfirmed") return html`<div class="windows-agent-blocked" role="alert">
29
29
  <p>${t(recovery.provider === "codex" ? "chat.paneCodexSessionUnconfirmed" : "chat.paneSessionUnconfirmed")}</p>
@@ -1,4 +1,5 @@
1
1
  import { NativePaneRecovery } from "./native-pane-recovery.js";
2
+ import { GeneralLocation } from "./general-location.js";
2
3
  // #1408 step 1: the chat panel. Behind the session gate (/ui/js/), loaded by the app with a dynamic import in "full"
3
4
  // mode only. boot() runs once per page (the chat store must hear the stream from the first frame); <ChatPanel> mounts
4
5
  // for /ui and /ui/chat/<name>.
@@ -13,6 +14,7 @@ import { appStore, createStore, guestPage, guestTrusted, useStore } from "/asset
13
14
  import { ComposerAuth } from "/assets/web-authorize.js";
14
15
  import { useLease } from "/assets/app-ctx.js";
15
16
  import { modelText, namesOf, namesStore, navStore as instanceNavStore, supportsInstanceFeature } from "/assets/instance-nav.js";
17
+ import { machineName } from "/assets/machine-name.js";
16
18
  import { PanelHeader, onPanelKey, setTitle, statusClass, statusLabel, openDrawer, requestNewInstance } from "/assets/app-shell.js";
17
19
  import { detailsPath, textLinkSegments, sectionPath } from "/assets/app-route.js";
18
20
  import { InstanceSwitch } from "/assets/instance-switch.js";
@@ -353,7 +355,7 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
353
355
  const pick = (command) => store.runCommand(name, command, "", { alive: () => lease.current() });
354
356
  const sub = html`<span class="status"><span class=${`dot ${cls}`} aria-hidden="true"></span>${statusLabel(inst, exec, awaiting)}</span>
355
357
  ${inst.runtime === "windows" ? html`<span class="tag">Windows</span>` : null}
356
- ${inst.machine_id ? html`<span class="tag runtime-machine-tag" title=${t("chat.machineName",inst.machine_name || inst.machine_id)}>${inst.machine_name || inst.machine_id}</span>${inst.machine_status !== "online" ? html`<span class="tag runtime-machine-offline">${t(inst.machine_status === "revoked" ? "chat.machineRevoked" : "chat.machineOffline")}</span>` : null}` : null}
358
+ ${inst.machine_id ? html`<span class="tag runtime-machine-tag" title=${t("chat.machineName",machineName(inst.machine_id,inst.machine_name))}>${machineName(inst.machine_id,inst.machine_name)}</span>${inst.machine_status !== "online" ? html`<span class="tag runtime-machine-offline">${t(inst.machine_status === "revoked" ? "chat.machineRevoked" : "chat.machineOffline")}</span>` : null}` : null}
357
359
  ${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", modelText(inst))} aria-label=${t("chat.chipModel", modelText(inst))} onClick=${() => supportsInstanceFeature(inst,"commands") ? pick("model") : navigate(sectionPath("agents"))}>${modelText(inst)}</button>` : null}
358
360
  ${inst.effort && supportsInstanceFeature(inst,"effort") ? html`<button type="button" class="hd-chip" title=${t("chat.chipEffort", inst.effort)} aria-label=${t("chat.chipEffort", inst.effort)} onClick=${() => pick("effort")}>${inst.effort}</button>` : null}`;
359
361
  return html`<div class=${`panel p-chat${wrap ? " wrap-code" : ""}`} data-width=${wide ? "full" : undefined} ref=${view}>
@@ -365,6 +367,7 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
365
367
  ${theme && theme.background ? html`<img ref=${bg} class=${`th-bg th-bg-${theme.background.fit}`} src=${themeImageUrl(name, theme.background.image)} alt="" aria-hidden="true" decoding="async" />` : null}
366
368
  <${ChatAmbient} name=${name} surface=${effectSurface} part="layer" />
367
369
  <${AmbientMotionNote} name=${name} />
370
+ ${inst.general_topic ? html`<${GeneralLocation} name=${name} attentionOnly=${true} />` : null}
368
371
  <${NativePaneRecovery} name=${name} inst=${inst} lease=${lease} />
369
372
  ${inst.native_blocked ? html`<div class="windows-agent-blocked" role="alert"><p>${t("chat.nativeBlocked")}</p><button type="button" class="btn" disabled=${recovering} onClick=${recoverNative}>${t("chat.nativeRecover")}</button></div>` : null}
370
373
  <${Thread} name=${name} label=${inst.runtime === "windows" ? inst.display_name || name : name} th=${thread} />
@@ -751,7 +754,7 @@ function Composer({ name, inst, label = name, lease, busy }) {
751
754
  };
752
755
  const optId = (c) => `cmd-${c.name}`;
753
756
  return html`<div class="composer-box">
754
- ${machineUnavailable ? html`<p class="note runtime-machine-unavailable" role="status">${t(inst.machine_status === "revoked" ? "chat.machineRevokedHint" : "chat.machineUnavailable",inst.machine_name || inst.machine_id)}</p>` : null}
757
+ ${machineUnavailable ? html`<p class="note runtime-machine-unavailable" role="status">${t(inst.machine_status === "revoked" ? "chat.machineRevokedHint" : "chat.machineUnavailable",machineName(inst.machine_id,inst.machine_name))}</p>` : null}
755
758
  ${inst?.native_busy && !busy && !inst?.native_blocked ? html`<p class="note" role="status">${t("chat.nativeBusy")}</p>` : null}
756
759
  ${palette ? html`<ul data-trust="palette" class="cmd-palette" id="cmdPalette" role="listbox" aria-label=${t("chat.cmdCommands")}>
757
760
  ${palette.length ? palette.map((c) => html`<li key=${c.name} id=${optId(c)} role="option" aria-selected=${c === pick ? "true" : "false"}
@@ -429,6 +429,8 @@ export function CreateInstanceDialog({ onClose }) {
429
429
  const [machineId,setMachineId] = useState("");
430
430
  const [nativeAdapter,setNativeAdapter]=useState("exec");
431
431
  const machineCatalog = useRuntimeCatalog();
432
+ // A computer paired a moment ago must show up: ask for a fresh list whenever the dialog opens (the hook then keeps polling).
433
+ useEffect(() => { void machineCatalog.refresh(); },[]);
432
434
  const machines = machineCatalog.data?.machines || [];
433
435
  const machine = machines.find(item => item.id === machineId);
434
436
  const [step,setStep] = useState(1), [created,setCreated] = useState(null);
@@ -524,9 +526,9 @@ export function CreateInstanceDialog({ onClose }) {
524
526
  <div class="agent-create-wizard" data-step=${step}>
525
527
  <ol class="agent-create-steps" aria-label=${tr("progress")}>${["runtimeStep","configureStep","doneStep"].map((label,index) => html`<li key=${label} class=${index+1 === step ? "current" : index+1 < step ? "complete" : ""} aria-current=${index+1 === step ? "step" : undefined}><span class="agent-create-step-number">${index+1 < step ? html`<${Icon} name="check" size=${13} />` : index+1}</span><span>${tr(label)}</span></li>`)}</ol>
526
528
  ${step === 1 ? html`<section class="agent-create-stage"><h3 ref=${heading} tabindex="-1">${tr("where")}</h3><p class="note">${tr("runtimeLead")}</p>
527
- <${RuntimePicker} value=${runtime} onChange=${chooseRuntime} windowsEnabled=${windowsCli} legend=${tr("environment")} machineId=${machineId} machines=${machines} onMachineChange=${id => chooseRuntime("windows",id)} />
529
+ <${RuntimePicker} value=${runtime} onChange=${chooseRuntime} windowsEnabled=${windowsCli} legend=${tr("environment")} machineId=${machineId} machines=${machines} onMachineChange=${id => chooseRuntime("windows",id)} onRefresh=${machineCatalog.refresh} loaded=${!!machineCatalog.data && !machineCatalog.error} />
528
530
  ${machineCatalog.loading && !machineCatalog.data ? html`<p class="note" role="status">${tr("machineLoading")}</p>` : null}
529
- ${machineCatalog.error ? html`<p class="note" role="alert">${tr("machineFailed")} <button type="button" class="btn btn-ghost btn-sm" onClick=${machineCatalog.refresh}>${tr("machineRetry")}</button></p>` : null}
531
+ ${machineCatalog.error ? html`<p class="note" role="alert">${tr("machineFailed")}</p>` : null}
530
532
  <a class="note runtime-manage-link" href="/settings/runtimes">${tr("manage")}</a>
531
533
  ${runtime ? html`<div class="agent-create-cli">${backendField}</div>` : null}
532
534
  </section>` : step === 2 ? html`<section class="agent-create-stage"><h3 ref=${heading} tabindex="-1">${tr("configureStep")}</h3><p class="note">${tr("configureLead")}</p>
@@ -25,6 +25,7 @@ import { toast } from "/assets/ui-toast.js";
25
25
  import { notifyStore, notifySupport, configDetail, reasonText, refreshNotify, setNotify } from "/assets/app-needs.js";
26
26
  import { openSignIn, signInOffered } from "./backend-signin.js";
27
27
  import { decideProposal, installProposals } from "./agent-proposals.js";
28
+ import { GeneralLocation } from "./general-location.js";
28
29
 
29
30
  register("needs", {
30
31
  en: {
@@ -242,6 +243,7 @@ function NeedsItem({ item, nowMs, owner }) {
242
243
  <div class="n-body">
243
244
  <div class="n-title"><strong>${reasonText(item)}</strong><span class="n-age">${age(item.since, nowMs)}</span></div>
244
245
  ${detailOf(item) ? html`<p class="n-detail">${detailOf(item)}</p>` : null}
246
+ ${item.generalLocation ? html`<${GeneralLocation} name=${item.instance} attentionOnly=${true} />` : null}
245
247
  <div class="n-actions">
246
248
  ${item.type === "prompt" && Array.isArray(item.actions) ? item.actions.filter((a) => !a.input).map((a) => html`<button key=${a.id} type="button" class="btn btn-sm"
247
249
  disabled=${promptBusy} onClick=${() => answer(a.id)}>${(p ? p.busy : fallback === "busy") ? tn("answering") : a.label}</button>`) : null}