@agentprojectcontext/apx 1.40.0 → 1.41.0
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/package.json +1 -1
- package/src/interfaces/cli/commands/desktop.js +26 -0
- package/src/interfaces/cli/index.js +16 -3
- package/src/interfaces/desktop/main.js +7 -1
- package/src/interfaces/desktop/renderer.js +7 -0
- package/src/interfaces/desktop/style.css +21 -0
- package/src/interfaces/web/dist/assets/index-DW7j3cXB.js +646 -0
- package/src/interfaces/web/dist/assets/index-DW7j3cXB.js.map +1 -0
- package/src/interfaces/web/dist/index.html +1 -1
- package/src/interfaces/web/package-lock.json +188 -188
- package/src/interfaces/web/dist/assets/index-Cg-uHCex.js +0 -646
- package/src/interfaces/web/dist/assets/index-Cg-uHCex.js.map +0 -1
package/package.json
CHANGED
|
@@ -277,6 +277,32 @@ export async function cmdDesktopStop(_args = {}) {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
// True when the desktop Electron process is alive. Used by `apx restart` so it
|
|
281
|
+
// only re-launches the desktop if the user already had it running.
|
|
282
|
+
export function desktopRunning() {
|
|
283
|
+
return pidAlive(readPid());
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Stop (if running) then start — the only way the desktop picks up new
|
|
287
|
+
// renderer/main.js code after a pull, since the Electron process holds the
|
|
288
|
+
// old bundle in memory. Token re-sync after a daemon restart is handled
|
|
289
|
+
// automatically by the WS reconnect (it re-reads daemon.token), so this is
|
|
290
|
+
// purely about refreshing stale desktop CODE.
|
|
291
|
+
export async function cmdDesktopRestart(args = {}) {
|
|
292
|
+
const pid = readPid();
|
|
293
|
+
if (pidAlive(pid)) {
|
|
294
|
+
try { process.kill(pid, "SIGTERM"); } catch {}
|
|
295
|
+
clearPid();
|
|
296
|
+
// Give Electron a moment to release the tray/shortcut before relaunch.
|
|
297
|
+
await new Promise((r) => setTimeout(r, 600));
|
|
298
|
+
process.stderr.write("apx: restarting desktop...\n");
|
|
299
|
+
} else {
|
|
300
|
+
clearPid();
|
|
301
|
+
process.stderr.write("apx: desktop not running — starting...\n");
|
|
302
|
+
}
|
|
303
|
+
await cmdDesktopStart(args);
|
|
304
|
+
}
|
|
305
|
+
|
|
280
306
|
export async function cmdDesktopStatus(_args = {}) {
|
|
281
307
|
const pid = readPid();
|
|
282
308
|
const alive = pidAlive(pid);
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
cmdPermission,
|
|
100
100
|
} from "./commands/config.js";
|
|
101
101
|
import { cmdPluginsList, cmdPluginStatus } from "./commands/plugins.js";
|
|
102
|
-
import { cmdDesktopStart, cmdDesktopStop, cmdDesktopStatus, cmdDesktopInstall, cmdDesktopUninstall } from "./commands/desktop.js";
|
|
102
|
+
import { cmdDesktopStart, cmdDesktopStop, cmdDesktopRestart, cmdDesktopStatus, cmdDesktopInstall, cmdDesktopUninstall, desktopRunning } from "./commands/desktop.js";
|
|
103
103
|
import { cmdVoiceSay, cmdVoiceListen, cmdVoiceProviders } from "./commands/voice.js";
|
|
104
104
|
import { cmdSkillsAdd, cmdSkillsList, cmdSkillsStatus, cmdSkillsSync, cmdSkillsIndex, cmdSkillsInspect, cmdSkillsInspector } from "./commands/skills.js";
|
|
105
105
|
import { cmdIdentity } from "./commands/identity.js";
|
|
@@ -2615,6 +2615,18 @@ async function dispatch(cmd, rest) {
|
|
|
2615
2615
|
await cmdUpdate(parseArgs(rest), VERSION);
|
|
2616
2616
|
return; // skip checkForUpdate after an update
|
|
2617
2617
|
|
|
2618
|
+
// Refresh everything held in memory after a code change (e.g. a `git
|
|
2619
|
+
// pull` in a dev checkout): restart the daemon, and restart the desktop
|
|
2620
|
+
// too if it was running. The daemon picks up new code/prompts; the
|
|
2621
|
+
// desktop picks up its new renderer/main.js. Token re-sync is automatic
|
|
2622
|
+
// (the desktop WS re-reads daemon.token on reconnect).
|
|
2623
|
+
case "restart": {
|
|
2624
|
+
const a = parseArgs(rest);
|
|
2625
|
+
await cmdDaemonRestart(a);
|
|
2626
|
+
if (desktopRunning()) await cmdDesktopRestart(a);
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2618
2630
|
case "overlay":
|
|
2619
2631
|
console.error(" apx overlay has been renamed to apx desktop — forwarding.");
|
|
2620
2632
|
/* falls through */
|
|
@@ -2623,10 +2635,11 @@ async function dispatch(cmd, rest) {
|
|
|
2623
2635
|
const oArgs = parseArgs(oRest);
|
|
2624
2636
|
if (!sub || sub === "start") { await cmdDesktopStart(oArgs); return; }
|
|
2625
2637
|
if (sub === "stop") { await cmdDesktopStop(oArgs); return; }
|
|
2638
|
+
if (sub === "restart") { await cmdDesktopRestart(oArgs); return; }
|
|
2626
2639
|
if (sub === "status") { await cmdDesktopStatus(oArgs);return; }
|
|
2627
2640
|
if (sub === "install") { await cmdDesktopInstall(oArgs); return; }
|
|
2628
2641
|
if (sub === "uninstall") { await cmdDesktopUninstall(oArgs);return; }
|
|
2629
|
-
die(`unknown desktop sub-command: ${sub}\nUsage: apx desktop <start|stop|status|install|uninstall>`);
|
|
2642
|
+
die(`unknown desktop sub-command: ${sub}\nUsage: apx desktop <start|stop|restart|status|install|uninstall>`);
|
|
2630
2643
|
return;
|
|
2631
2644
|
}
|
|
2632
2645
|
|
|
@@ -2656,7 +2669,7 @@ const [topCmd, ...topRest] = argv;
|
|
|
2656
2669
|
// of the compact line.
|
|
2657
2670
|
// Suppress everything with APX_QUIET=1 / APX_NO_BANNER=1 (see branding.js).
|
|
2658
2671
|
const SELF_BRANDED = new Set([
|
|
2659
|
-
"status", "setup", "install", "daemon", "update", "upgrade", "help",
|
|
2672
|
+
"status", "setup", "install", "daemon", "update", "upgrade", "help", "restart",
|
|
2660
2673
|
]);
|
|
2661
2674
|
const BANNERED = new Set(["init"]);
|
|
2662
2675
|
|
|
@@ -561,10 +561,16 @@ function connectDaemon() {
|
|
|
561
561
|
return;
|
|
562
562
|
}
|
|
563
563
|
|
|
564
|
-
const token = readToken();
|
|
565
564
|
const url = `ws://${DAEMON_HOST}:${DAEMON_PORT}/desktop/ws`;
|
|
566
565
|
|
|
567
566
|
function connect() {
|
|
567
|
+
// Re-read the token on EVERY attempt — the daemon regenerates
|
|
568
|
+
// ~/.apx/daemon.token on each restart, so a token captured once at
|
|
569
|
+
// startup goes stale the moment the daemon is restarted (e.g. after a
|
|
570
|
+
// pull / `apx daemon restart`) and every reconnect 401s forever. Reading
|
|
571
|
+
// it fresh here lets the desktop self-heal: the next retry picks up the
|
|
572
|
+
// new token and reconnects on its own.
|
|
573
|
+
const token = readToken();
|
|
568
574
|
try {
|
|
569
575
|
wsConn = new WS(url, {
|
|
570
576
|
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
@@ -210,10 +210,17 @@
|
|
|
210
210
|
|
|
211
211
|
function initialCaption(shortcut) {
|
|
212
212
|
const sc = formatShortcut(shortcut);
|
|
213
|
+
// Empty-idle state has no other affordance to dismiss the floating window
|
|
214
|
+
// (the session bar's "Cerrar" only shows once a conversation exists, and
|
|
215
|
+
// the window doesn't auto-hide on blur). Pair the hint with a translucent
|
|
216
|
+
// "Cerrar ventana" pill in the same glass language so the user can always
|
|
217
|
+
// close it without hunting for the tray icon.
|
|
213
218
|
$captionSlot.innerHTML = `
|
|
214
219
|
<div class="caption">Mantené <span class="kbd">${sc}</span> para hablar
|
|
215
220
|
<span class="kbd">⌥ /</span> para escribir</div>
|
|
221
|
+
<button class="cap-pill" id="btn-close-idle" title="Cerrar ventana">${ICON.close()}<span>Cerrar ventana</span></button>
|
|
216
222
|
`;
|
|
223
|
+
$captionSlot.querySelector("#btn-close-idle")?.addEventListener("click", closeWindow);
|
|
217
224
|
}
|
|
218
225
|
|
|
219
226
|
// ── Render: capsule center + actions vary by mode ────────────────────────
|
|
@@ -193,6 +193,27 @@ button { font-family: inherit; }
|
|
|
193
193
|
}
|
|
194
194
|
[data-theme="dark"] .kbd { color: color-mix(in oklch, var(--accent) 60%, white); }
|
|
195
195
|
|
|
196
|
+
/* Stack the hint + the close pill, centered, in the empty-idle state.
|
|
197
|
+
render() toggles this slot's display between "" (→ flex) and "none". */
|
|
198
|
+
#caption-slot { display: flex; flex-direction: column; align-items: center; gap: 7px; }
|
|
199
|
+
|
|
200
|
+
/* Translucent "Cerrar ventana" pill — same glass language as .caption so the
|
|
201
|
+
empty-idle state always has a way to dismiss the window. */
|
|
202
|
+
.cap-pill {
|
|
203
|
+
display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
|
|
204
|
+
font: inherit; font-size: 11px; font-weight: 600; color: rgba(255,255,255,.92);
|
|
205
|
+
padding: 5px 12px; border-radius: 9px;
|
|
206
|
+
background: rgba(20,22,32,.28); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
207
|
+
border: 1px solid rgba(255,255,255,.14);
|
|
208
|
+
text-shadow: 0 0.5px 1.5px rgba(0,0,0,.3);
|
|
209
|
+
transition: transform .14s ease, background .15s ease;
|
|
210
|
+
animation: captionIn .4s ease both;
|
|
211
|
+
}
|
|
212
|
+
.cap-pill svg { width: 13px; height: 13px; opacity: .9; }
|
|
213
|
+
.cap-pill:hover { transform: translateY(-1px); background: rgba(20,22,32,.42); }
|
|
214
|
+
.cap-pill:active { transform: scale(.96); }
|
|
215
|
+
[data-theme="dark"] .cap-pill { background: rgba(0,0,0,.34); }
|
|
216
|
+
|
|
196
217
|
/* ============================================================
|
|
197
218
|
Conversation card
|
|
198
219
|
============================================================ */
|