@songsid/agend 2.2.0-alpha.1 → 2.2.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/README.zh-TW.md +2 -0
- package/dist/agent-cli.js +6 -1
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +68 -12
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-token-header.d.ts +13 -0
- package/dist/agent-token-header.js +16 -0
- package/dist/agent-token-header.js.map +1 -0
- package/dist/backend/antigravity.js +4 -3
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/grok.js +1 -1
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +7 -0
- package/dist/backend/kiro.js +82 -33
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.js +1 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +6 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/cache-analysis.d.ts +92 -0
- package/dist/cache-analysis.js +147 -0
- package/dist/cache-analysis.js.map +1 -0
- package/dist/cache-ledger.d.ts +108 -0
- package/dist/cache-ledger.js +230 -0
- package/dist/cache-ledger.js.map +1 -0
- package/dist/cache-prices.d.ts +32 -0
- package/dist/cache-prices.js +73 -0
- package/dist/cache-prices.js.map +1 -0
- package/dist/cache-scan.d.ts +39 -0
- package/dist/cache-scan.js +115 -0
- package/dist/cache-scan.js.map +1 -0
- package/dist/cache-service.d.ts +115 -0
- package/dist/cache-service.js +417 -0
- package/dist/cache-service.js.map +1 -0
- package/dist/cli-entry.d.ts +19 -0
- package/dist/cli-entry.js +36 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/cli.js +251 -24
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.js +90 -37
- package/dist/daemon.js.map +1 -1
- package/dist/event-log.d.ts +4 -1
- package/dist/event-log.js +6 -3
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-control-audit.d.ts +5 -0
- package/dist/fleet-control-audit.js +7 -0
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-level-config.js +22 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +46 -0
- package/dist/fleet-manager.js +287 -40
- package/dist/fleet-manager.js.map +1 -1
- package/dist/full-restart.js +2 -3
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +3 -1
- package/dist/install-lock.d.ts +49 -0
- package/dist/install-lock.js +200 -0
- package/dist/install-lock.js.map +1 -0
- package/dist/instance-config-impact.js +3 -2
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/locale.js +14 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/package-preimage.d.ts +26 -0
- package/dist/package-preimage.js +96 -0
- package/dist/package-preimage.js.map +1 -0
- package/dist/public-web-gateway.js +2 -2
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart.js +10 -4
- package/dist/quickstart.js.map +1 -1
- package/dist/restart-guard.d.ts +52 -0
- package/dist/restart-guard.js +109 -0
- package/dist/restart-guard.js.map +1 -0
- package/dist/scheduler/db.js +6 -2
- package/dist/scheduler/db.js.map +1 -1
- package/dist/service-activation.d.ts +47 -5
- package/dist/service-activation.js +156 -51
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +56 -1
- package/dist/service-installer.js +134 -12
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +65 -0
- package/dist/service-plan.js +108 -0
- package/dist/service-plan.js.map +1 -0
- package/dist/settings-api.js +46 -5
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +34 -6
- package/dist/settings-change.js.map +1 -1
- package/dist/setup-host.js +2 -3
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +2 -1
- package/dist/setup-wizard.js.map +1 -1
- package/dist/sqlite-open-errors.d.ts +12 -0
- package/dist/sqlite-open-errors.js +13 -0
- package/dist/sqlite-open-errors.js.map +1 -0
- package/dist/tmux-control.d.ts +22 -0
- package/dist/tmux-control.js +89 -5
- package/dist/tmux-control.js.map +1 -1
- package/dist/topic-commands.js +14 -5
- package/dist/topic-commands.js.map +1 -1
- package/dist/ui/chat-commands.js +43 -0
- package/dist/ui/chat-render.js +2 -2
- package/dist/ui/chat-store.js +30 -1
- package/dist/ui/chat-strings.js +22 -2
- package/dist/ui/chat-thread.js +47 -10
- package/dist/ui/fleet-cache.js +168 -0
- package/dist/ui/panel-chat.js +104 -18
- package/dist/ui/panel-fleet.js +26 -12
- package/dist/ui/panel-settings.js +12 -8
- package/dist/ui/preview-panel.js +202 -0
- package/dist/ui/preview.js +7 -3
- package/dist/ui/settings-strings.js +4 -2
- package/dist/ui/shared/app-route.js +1 -1
- package/dist/ui/shared/app-shell.js +6 -4
- package/dist/ui/shared/app.css +147 -3
- package/dist/ui/shared/signin.js +13 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/signin.html +2 -1
- package/dist/update-dispatch.d.ts +28 -0
- package/dist/update-dispatch.js +73 -0
- package/dist/update-dispatch.js.map +1 -0
- package/dist/update-install.d.ts +65 -7
- package/dist/update-install.js +126 -26
- package/dist/update-install.js.map +1 -1
- package/dist/web-api.d.ts +14 -0
- package/dist/web-api.js +65 -0
- package/dist/web-api.js.map +1 -1
- package/dist/web-commands.d.ts +77 -0
- package/dist/web-commands.js +81 -0
- package/dist/web-commands.js.map +1 -0
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/launcher/agend +110 -0
- package/launcher/agend-agent +110 -0
- package/launcher/agend-agent.cjs +4 -0
- package/launcher/agend.cjs +4 -0
- package/launcher/install-admission.cjs +105 -0
- package/launcher/launch.cjs +64 -0
- package/launcher/postinstall.cjs +114 -0
- package/launcher/run-in-process.cjs +13 -0
- package/launcher/runtime-platform.cjs +86 -0
- package/launcher/runtime-select.cjs +217 -0
- package/package.json +12 -4
- package/scripts/preinstall-guard.cjs +40 -21
- package/templates/launchd.plist.ejs +2 -2
- package/templates/systemd.service.ejs +1 -1
package/dist/ui/shared/app.css
CHANGED
|
@@ -127,7 +127,7 @@ a { color: inherit; text-decoration: none; }
|
|
|
127
127
|
.dot.warn { background: var(--warn); }
|
|
128
128
|
.dot.bad { background: var(--danger); }
|
|
129
129
|
.dot.off { background: var(--text-3); }
|
|
130
|
-
@keyframes pulse { 0%, 100% { opacity: 0.
|
|
130
|
+
@keyframes pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } } /* never near-invisible on a dark surface */
|
|
131
131
|
|
|
132
132
|
.scrim { display: none; }
|
|
133
133
|
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; position: relative; }
|
|
@@ -295,6 +295,48 @@ a { color: inherit; text-decoration: none; }
|
|
|
295
295
|
.pv-holder:empty { display: none; }
|
|
296
296
|
.pv-holder { margin-top: var(--s-2); }
|
|
297
297
|
.preview-frame { display: block; width: 100%; border: 2px solid var(--warn-line); border-radius: var(--r-sm); background: #ffffff; }
|
|
298
|
+
/* #1481: the preview beside the conversation. A split on a wide screen (width: --pv-w, set by the divider through
|
|
299
|
+
CSSOM), a full-screen sheet on a narrow one. The frame is the card's (preview.js), sized by the panel here. */
|
|
300
|
+
.chat-split { flex: 1; min-height: 0; display: flex; }
|
|
301
|
+
.chat-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
302
|
+
.pv-divider { flex: 0 0 8px; cursor: col-resize; background: var(--bg); border-left: 1px solid var(--border); touch-action: none; position: relative; }
|
|
303
|
+
.pv-divider::after { content: ""; position: absolute; top: 50%; left: 2px; width: 3px; height: 32px; margin-top: -16px; border-radius: 2px; background: var(--border-strong); }
|
|
304
|
+
.pv-divider:hover::after, .pv-divider:focus-visible::after, .chat-split.resizing .pv-divider::after { background: var(--accent); }
|
|
305
|
+
.pv-divider:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
306
|
+
.chat-split.resizing { cursor: col-resize; user-select: none; }
|
|
307
|
+
.chat-split.resizing .preview-frame { pointer-events: none; } /* a frame under the pointer would end the drag */
|
|
308
|
+
.pv-panel { flex: 0 0 var(--pv-w, 45%); width: var(--pv-w, 45%); min-width: 320px; max-width: calc(100% - 368px); min-height: 0;
|
|
309
|
+
display: flex; flex-direction: column; background: var(--bg); container-type: inline-size; }
|
|
310
|
+
.pv-panel-head { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--border); }
|
|
311
|
+
.pv-panel-title { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: var(--fs-sm); }
|
|
312
|
+
.pv-source { all: unset; cursor: pointer; font-size: var(--fs-xs); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
313
|
+
.pv-source:hover { color: var(--text); text-decoration: underline; }
|
|
314
|
+
.pv-source:focus-visible { outline: 2px solid var(--accent); border-radius: var(--r-sm); }
|
|
315
|
+
.pv-panel-bar { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3); flex-wrap: wrap; }
|
|
316
|
+
.pv-panel-bar .grow { flex: 1; }
|
|
317
|
+
.pv-panel > .pv-banner, .pv-panel > .pv-note, .pv-newer { margin: 0 var(--s-3) var(--s-2); }
|
|
318
|
+
.pv-panel > .pv-note { margin-top: 0; }
|
|
319
|
+
.pv-newer { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; padding: var(--s-2) var(--s-3); border-radius: var(--r-sm);
|
|
320
|
+
background: var(--surface); font-size: var(--fs-xs); }
|
|
321
|
+
.pv-newer > span { flex: 1; min-width: 0; }
|
|
322
|
+
.pv-panel-body { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 0 var(--s-3) var(--s-3); }
|
|
323
|
+
.pv-panel-body .pv-holder { flex: 1; min-height: 0; margin: 0; display: flex; flex-direction: column; }
|
|
324
|
+
.pv-panel-body.show-code .pv-holder { display: none; }
|
|
325
|
+
.preview-frame.fill { flex: 1; height: 100%; min-height: 0; }
|
|
326
|
+
.pv-code { flex: 1; min-height: 0; margin: 0; overflow: auto; font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.5;
|
|
327
|
+
background: var(--surface); border-radius: var(--r-sm); padding: var(--s-3); white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
|
|
328
|
+
.msg.flash { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--r-sm); transition: outline-color var(--t-med); }
|
|
329
|
+
@media (max-width: 899px) {
|
|
330
|
+
.only-wide { display: none; }
|
|
331
|
+
.pv-divider { display: none; }
|
|
332
|
+
.pv-panel { position: fixed; inset: 0; z-index: 37; width: auto; min-width: 0; max-width: none;
|
|
333
|
+
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
|
|
334
|
+
}
|
|
335
|
+
/* A narrow panel (a phone, or the divider dragged right): the run controls keep their icons, titles and screen-reader
|
|
336
|
+
names — except Preview, which the panel's note names. */
|
|
337
|
+
@container (max-width: 560px) {
|
|
338
|
+
.pv-panel-bar :not(.pv-panel-run) > .lbl { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
339
|
+
}
|
|
298
340
|
.pv-menu { position: relative; }
|
|
299
341
|
.pv-menu > summary { list-style: none; cursor: pointer; padding: 2px var(--s-2); border-radius: var(--r-sm); color: var(--text-3); }
|
|
300
342
|
.pv-menu > summary::-webkit-details-marker { display: none; }
|
|
@@ -334,6 +376,8 @@ a { color: inherit; text-decoration: none; }
|
|
|
334
376
|
.composer textarea::placeholder { color: var(--text-3); }
|
|
335
377
|
.btn-send { width: 36px; padding: 0; }
|
|
336
378
|
.btn-send .send-label { display: none; }
|
|
379
|
+
/* A narrow phone: Stop reply beside Send leaves the message box no room — the label is for screen readers there. */
|
|
380
|
+
@media (max-width: 479px) { .btn-stop .stop-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } }
|
|
337
381
|
.btn-stop { background: var(--bg); }
|
|
338
382
|
.hint { font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
|
|
339
383
|
.pending-files { display: flex; flex-wrap: wrap; gap: var(--s-2); padding: var(--s-2) var(--s-2) 0; }
|
|
@@ -401,7 +445,8 @@ a { color: inherit; text-decoration: none; }
|
|
|
401
445
|
.dlg-box { max-height: 90vh; }
|
|
402
446
|
.dlg-actions { padding-bottom: max(var(--s-5), env(safe-area-inset-bottom)); }
|
|
403
447
|
.dlg-actions .btn { flex: 1; min-height: var(--tap); }
|
|
404
|
-
.row-item .btn { min-height: var(--tap); }
|
|
448
|
+
.row-item .btn, .s-row .btn, .n-actions .btn { min-height: var(--tap); }
|
|
449
|
+
.s-row .icon-btn { min-width: var(--tap); min-height: var(--tap); }
|
|
405
450
|
.kv { flex-direction: column; align-items: flex-start; gap: 2px; }
|
|
406
451
|
}
|
|
407
452
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -511,6 +556,11 @@ a { color: inherit; text-decoration: none; }
|
|
|
511
556
|
.s-row.s-conn { grid-template-columns: minmax(0, 1fr) auto; }
|
|
512
557
|
.s-conn .s-facts { grid-column: 1 / -1; grid-row: 2; }
|
|
513
558
|
}
|
|
559
|
+
/* A narrow phone: the cluster (token, state, Settings) goes under the facts, so the name keeps its line (alpha.2 sweep). */
|
|
560
|
+
@media (max-width: 479px) {
|
|
561
|
+
.s-row.s-conn { grid-template-columns: minmax(0, 1fr); }
|
|
562
|
+
.s-conn .s-actions { grid-column: 1; grid-row: 3; flex-wrap: wrap; }
|
|
563
|
+
}
|
|
514
564
|
.s-state { font-size: var(--fs-xs); }
|
|
515
565
|
.s-state.ok { color: var(--ok); }
|
|
516
566
|
.s-state.bad { color: var(--danger); }
|
|
@@ -549,6 +599,30 @@ a { color: inherit; text-decoration: none; }
|
|
|
549
599
|
.s-yaml { font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.5; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: var(--s-3);
|
|
550
600
|
overflow: auto; max-height: 60vh; white-space: pre; margin: 0; color: var(--text); }
|
|
551
601
|
textarea.s-yaml { width: 100%; min-height: 50vh; resize: vertical; }
|
|
602
|
+
/* Lines too long for the box scroll sideways; a shadow at an edge says there is more that way (alpha.2 sweep). */
|
|
603
|
+
.s-yaml {
|
|
604
|
+
background:
|
|
605
|
+
linear-gradient(to right, var(--bg) 30%, transparent) left / 24px 100% no-repeat local,
|
|
606
|
+
linear-gradient(to left, var(--bg) 30%, transparent) right / 24px 100% no-repeat local,
|
|
607
|
+
radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--text) 22%, transparent), transparent) left / 10px 100% no-repeat scroll,
|
|
608
|
+
radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--text) 22%, transparent), transparent) right / 10px 100% no-repeat scroll,
|
|
609
|
+
var(--bg);
|
|
610
|
+
}
|
|
611
|
+
textarea.s-yaml { white-space: pre; overflow-x: auto; }
|
|
612
|
+
.s-br { display: none; }
|
|
613
|
+
@media (max-width: 479px) {
|
|
614
|
+
/* Settings → Developer: one toolbar row, icons only (names stay as titles and for screen readers). */
|
|
615
|
+
.s-dev-bar { flex-wrap: nowrap; }
|
|
616
|
+
.s-dev-bar .lbl { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
617
|
+
/* An agent's row: name and model on the first line, its tags and buttons from the second, on every row alike. */
|
|
618
|
+
.s-br { display: block; flex-basis: 100%; height: 0; }
|
|
619
|
+
/* View: the profile line wraps to two lines instead of hiding the model and context. */
|
|
620
|
+
.v-card-meta { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
|
|
621
|
+
/* A text button in Needs you lines up with the text above it, first in its row or wrapped onto a line of its own;
|
|
622
|
+
a row's trailing Delete sits at the right. */
|
|
623
|
+
.n-actions > .btn-ghost { padding-left: 0; padding-right: 0; margin-left: -1px; }
|
|
624
|
+
.row-item > .btn-ghost:last-child { margin-left: auto; margin-right: calc(-1 * var(--s-3) - 1px); }
|
|
625
|
+
}
|
|
552
626
|
.s-pending { position: sticky; bottom: 0; display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; padding: var(--s-3) var(--s-5);
|
|
553
627
|
background: var(--bg); border-top: 1px solid var(--border); box-shadow: var(--shadow-2); }
|
|
554
628
|
.s-pending .grow { flex: 1; }
|
|
@@ -575,6 +649,8 @@ textarea.s-yaml { width: 100%; min-height: 50vh; resize: vertical; }
|
|
|
575
649
|
.se-default { opacity: 0.7; }
|
|
576
650
|
/* #1423: requests waiting for a fleet admin, in any panel */
|
|
577
651
|
.pending-stack { position: fixed; right: var(--s-4); top: calc(var(--header-h) + var(--s-2)); z-index: 40; display: flex; flex-direction: column; gap: var(--s-2); width: min(360px, calc(100vw - 32px)); }
|
|
652
|
+
/* In Settings the cards sit in the column, right under the operation — every width (alpha.2 sweep). */
|
|
653
|
+
.pending-stack.inline, .shell:has(.s-pending) .pending-stack.inline { position: static; width: auto; margin-bottom: var(--s-4); }
|
|
578
654
|
.pending-card { background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--r-md); box-shadow: var(--shadow-2); padding: var(--s-3) var(--s-4); display: flex; flex-direction: column; gap: var(--s-1); font-size: var(--fs-sm); }
|
|
579
655
|
.pending-card.applied { border-color: var(--ok); }
|
|
580
656
|
.pending-card.rejected, .pending-card.expired, .pending-card.stale, .pending-card.failed { border-color: var(--danger-line); }
|
|
@@ -586,6 +662,8 @@ textarea.s-yaml { width: 100%; min-height: 50vh; resize: vertical; }
|
|
|
586
662
|
.pending-actions { display: flex; justify-content: flex-end; }
|
|
587
663
|
/* Settings' pending bar sits at the bottom of the page: toasts and request cards stand above it, never on its buttons. */
|
|
588
664
|
.shell:has(.s-pending) .toasts { bottom: calc(var(--s-6) + 64px); }
|
|
665
|
+
/* In a chat the composer owns the bottom (Stop reply, Send): toasts come in under the header instead (alpha.2 sweep). */
|
|
666
|
+
@media (min-width: 900px) { .shell:has(.p-chat) .toasts { top: calc(var(--header-h) + var(--s-2)); bottom: auto; } }
|
|
589
667
|
.op-line { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
|
|
590
668
|
.op-line.ok { color: var(--ok); }
|
|
591
669
|
.op-line.bad { color: var(--danger); }
|
|
@@ -672,5 +750,71 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
672
750
|
}
|
|
673
751
|
/* A phone: Fleet's five tabs fit when only the open one shows its label (the others keep theirs for screen readers). */
|
|
674
752
|
@media (max-width: 479px) {
|
|
675
|
-
.p-fleet .seg-item:not(.active) > span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
753
|
+
.p-fleet .seg-item:not(.active) > span, .p-settings .seg-item:not(.active) > span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/* ── Cache analysis (#1468): Fleet → Cache. Bars are SVG attributes; nothing here is an inline style. ── */
|
|
757
|
+
.ch { display: flex; flex-direction: column; gap: var(--s-4); }
|
|
758
|
+
.ch-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-2) var(--s-4); margin-top: var(--s-2); }
|
|
759
|
+
.ch-scan { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-2); }
|
|
760
|
+
.ch-fleet { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }
|
|
761
|
+
.ch-notes { display: flex; flex-direction: column; gap: var(--s-1); font-size: var(--fs-xs); }
|
|
762
|
+
.ch-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); gap: var(--s-4); align-items: start; }
|
|
763
|
+
.ch-card { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; padding: var(--s-4); border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg); }
|
|
764
|
+
.ch-card.on { border-color: var(--ok); }
|
|
765
|
+
.ch-head { display: flex; align-items: flex-start; gap: var(--s-3); }
|
|
766
|
+
.ch-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
767
|
+
.ch-id h3 { font-size: var(--fs-sm); font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
768
|
+
.ch-models { font-size: var(--fs-xs); color: var(--text-3); overflow-wrap: anywhere; }
|
|
769
|
+
.ch-rec { flex-shrink: 0; font-size: 11px; line-height: 20px; padding: 0 var(--s-2); border-radius: var(--r-full); border: 1px solid var(--border); color: var(--text-2); white-space: nowrap; }
|
|
770
|
+
.ch-rec.on { color: var(--ok); border-color: var(--ok); font-weight: var(--fw-semibold); }
|
|
771
|
+
.ch-reason { font-size: var(--fs-sm); color: var(--text-2); overflow-wrap: anywhere; }
|
|
772
|
+
.ch-tag { display: inline-block; font-size: 11px; line-height: 18px; padding: 0 var(--s-2); border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); }
|
|
773
|
+
.ch-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-2) var(--s-3); }
|
|
774
|
+
.ch-metric { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
775
|
+
.ch-metric dt { font-size: 11px; color: var(--text-3); line-height: var(--lh-xs); }
|
|
776
|
+
.ch-metric dd { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; display: flex; flex-direction: column; }
|
|
777
|
+
.ch-sub { font-size: 11px; font-weight: var(--fw-regular); color: var(--text-3); }
|
|
778
|
+
.ch-fleet .ch-metric dd { font-size: var(--fs-lg); }
|
|
779
|
+
.ch-hist { display: block; width: 100%; height: 96px; color: var(--text-2); }
|
|
780
|
+
.ch-col rect { fill: var(--accent); opacity: 0.55; }
|
|
781
|
+
.ch-col.past rect { fill: var(--warn); opacity: 0.85; }
|
|
782
|
+
.ch-n, .ch-l { font-size: 9px; fill: currentColor; }
|
|
783
|
+
.ch-ttl line { stroke: var(--danger); stroke-width: 1.5; stroke-dasharray: 3 3; }
|
|
784
|
+
.ch-ttl text { font-size: 9px; fill: var(--danger); }
|
|
785
|
+
.ch-rest .row-item { font-size: var(--fs-xs); }
|
|
786
|
+
@media (max-width: 899px) {
|
|
787
|
+
.ch-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
788
|
+
.ch-fleet { grid-template-columns: minmax(0, 1fr); }
|
|
789
|
+
.ch-bar .btn { min-height: var(--tap); }
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/* ── Chat commands and quick actions (#1269) ── */
|
|
793
|
+
.hd-chip { margin-left: var(--s-2); padding: 0 var(--s-2); border: 1px solid var(--border); border-radius: var(--r-full); background: transparent; color: var(--text-2);
|
|
794
|
+
font-size: var(--fs-xs); line-height: 20px; cursor: pointer; max-width: 16em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; }
|
|
795
|
+
.hd-chip:hover { background: var(--surface); color: var(--text); }
|
|
796
|
+
.composer-box { position: relative; }
|
|
797
|
+
.cmd-palette { position: absolute; left: 0; right: 0; bottom: calc(100% + var(--s-1)); z-index: 20; list-style: none; max-height: 280px; overflow-y: auto;
|
|
798
|
+
padding: var(--s-1); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg); box-shadow: var(--shadow-2); }
|
|
799
|
+
.cmd-palette li { display: flex; align-items: baseline; gap: var(--s-3); padding: var(--s-2) var(--s-3); border-radius: var(--r-sm); cursor: pointer; font-size: var(--fs-sm); }
|
|
800
|
+
.cmd-palette li.on, .cmd-palette li:hover { background: var(--surface-2); }
|
|
801
|
+
.cmd-palette .cmd-name { flex-shrink: 0; white-space: nowrap; }
|
|
802
|
+
.cmd-palette .cmd-desc { color: var(--text-3); font-size: var(--fs-xs); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
803
|
+
.cmd-palette .cmd-arg { color: var(--text-3); }
|
|
804
|
+
.cmd-palette .cmd-none { color: var(--text-3); cursor: default; }
|
|
805
|
+
.cmd-card { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-2); padding: var(--s-2) var(--s-3); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); }
|
|
806
|
+
.cmd-card.bad { border-left: 3px solid var(--danger); }
|
|
807
|
+
.cmd-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
|
|
808
|
+
.cmd-name { font-weight: var(--fw-semibold); }
|
|
809
|
+
.cmd-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--font-ui); color: var(--text-2); }
|
|
810
|
+
.cmd-choices { display: flex; flex-wrap: wrap; gap: var(--s-1); max-height: 180px; overflow-y: auto; }
|
|
811
|
+
.cmd-choices .btn.current { border-color: var(--accent); color: var(--accent); }
|
|
812
|
+
.quick-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2); font-size: var(--fs-xs); color: var(--text-2); }
|
|
813
|
+
/* A phone: the instance's name keeps the header; /model and /effort are a "/" away. */
|
|
814
|
+
@media (max-width: 479px) { .hd-chip { display: none; } }
|
|
815
|
+
@media (max-width: 899px) {
|
|
816
|
+
.hd-chip { max-width: 9em; }
|
|
817
|
+
.cmd-palette li { min-height: var(--tap); align-items: center; flex-wrap: wrap; row-gap: 0; }
|
|
818
|
+
.cmd-palette .cmd-desc { white-space: normal; flex-basis: 100%; }
|
|
819
|
+
.cmd-choices .btn, .quick-actions .btn { min-height: var(--tap); }
|
|
676
820
|
}
|
package/dist/ui/shared/signin.js
CHANGED
|
@@ -39,7 +39,17 @@
|
|
|
39
39
|
history.replaceState(null, "", here.pathname + here.search + here.hash);
|
|
40
40
|
}
|
|
41
41
|
} catch { /* nothing to clean */ }
|
|
42
|
-
|
|
42
|
+
// The command in the hint is a <code> that never breaks across lines (a break inside "--code" reads as two dashes
|
|
43
|
+
// and a word, alpha.2 sweep); the text around it is text.
|
|
44
|
+
const CMD = "agend web --code";
|
|
45
|
+
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
|
46
|
+
const text = t(el.getAttribute("data-i18n"));
|
|
47
|
+
const at = text.indexOf(CMD);
|
|
48
|
+
if (at < 0) { el.textContent = text; return; }
|
|
49
|
+
const code = document.createElement("code");
|
|
50
|
+
code.textContent = CMD;
|
|
51
|
+
el.replaceChildren(text.slice(0, at), code, text.slice(at + CMD.length));
|
|
52
|
+
});
|
|
43
53
|
|
|
44
54
|
// An old deep link, /ui#instance=<name> (#1408 §3): the fragment never reaches the server, and the sign-in page is
|
|
45
55
|
// served at the URL that was asked for, so it is still in location.hash here. Exactly that one form becomes the new
|
|
@@ -94,6 +104,8 @@
|
|
|
94
104
|
// navigation; going round again would loop, so stop and let the person type a code.
|
|
95
105
|
if (recentlyBounced()) return false;
|
|
96
106
|
try {
|
|
107
|
+
// Signed out, this answers 401 — and the browser logs that request in red in DevTools. That is expected: the
|
|
108
|
+
// probe asks "is there a session?", and no is a normal answer here (decided against reshaping the auth API).
|
|
97
109
|
const r = await fetch("/auth/session", { credentials: "same-origin", cache: "no-store" });
|
|
98
110
|
return r.ok;
|
|
99
111
|
} catch { return false; }
|
|
@@ -50,6 +50,8 @@ const P = {
|
|
|
50
50
|
pause: () => html`<path d="M8 5v14M16 5v14"/>`,
|
|
51
51
|
download: () => html`<path d="M12 3v12M7 10l5 5 5-5M5 21h14"/>`,
|
|
52
52
|
org: () => html`<rect x="9" y="2" width="6" height="5" rx="1"/><rect x="2" y="17" width="6" height="5" rx="1"/><rect x="16" y="17" width="6" height="5" rx="1"/><path d="M12 7v5M5 17v-5h14v5"/>`,
|
|
53
|
+
panel: () => html`<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M14 4v16"/>`,
|
|
54
|
+
back: () => html`<path d="M19 12H5M12 19l-7-7 7-7"/>`,
|
|
53
55
|
external: () => html`<path d="M14 4h6v6M20 4l-9 9"/><path d="M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/>`,
|
|
54
56
|
};
|
|
55
57
|
|
package/dist/ui/signin.html
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
button:disabled { opacity: .6; cursor: default; }
|
|
28
28
|
#msg { min-height: 1.5em; margin-top: 14px; font-size: var(--fs-sm); color: var(--danger); }
|
|
29
29
|
.hint { margin-top: 18px; font-size: var(--fs-xs); color: var(--text-3); }
|
|
30
|
+
.hint code { white-space: nowrap; font-family: var(--font-mono); }
|
|
30
31
|
[hidden] { display: none !important; }
|
|
31
32
|
</style>
|
|
32
33
|
</head>
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
autocorrect="off" spellcheck="false" maxlength="12" placeholder="XXXX-XXXX" required>
|
|
43
44
|
<button id="go" type="submit" data-i18n="submit">Sign in</button>
|
|
44
45
|
<div id="msg" role="alert" aria-live="polite"></div>
|
|
45
|
-
<div class="hint" data-i18n="hint">Send /dashboard to your AgEnD bot, or run
|
|
46
|
+
<div class="hint" data-i18n="hint">Send /dashboard to your AgEnD bot, or run “<code>agend web --code</code>” on the host. A code works once and expires in 5 minutes.</div>
|
|
46
47
|
</form>
|
|
47
48
|
<noscript>This page needs JavaScript to sign you in.</noscript>
|
|
48
49
|
</main>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface DispatchDeps {
|
|
2
|
+
run(command: string, args: string[], timeoutMs: number): Promise<{
|
|
3
|
+
status: number | null;
|
|
4
|
+
stdout: string;
|
|
5
|
+
}>;
|
|
6
|
+
readFile(path: string): Promise<string>;
|
|
7
|
+
realpath(path: string): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export declare const defaultDispatchDeps: DispatchDeps;
|
|
10
|
+
export type InstalledAgend = {
|
|
11
|
+
ok: true;
|
|
12
|
+
agend: string;
|
|
13
|
+
version: string;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
reason: string;
|
|
17
|
+
};
|
|
18
|
+
/** npm's global root and prefix → the installed package, its bin target, and the bin link that must lead to it. */
|
|
19
|
+
export declare function resolveInstalledAgend(deps?: DispatchDeps): Promise<InstalledAgend>;
|
|
20
|
+
/**
|
|
21
|
+
* `<installed agend> update`, 2 s from now, from a detached `sh` that outlives this fleet (the update restarts it). The
|
|
22
|
+
* path is a positional argument, never spliced into the script.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DELAYED_UPDATE_SCRIPT = "sleep 2 && exec \"$1\" update";
|
|
25
|
+
export declare function updateCommand(agend: string): {
|
|
26
|
+
command: string;
|
|
27
|
+
args: string[];
|
|
28
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1450 C5: chat `/update` runs the INSTALLED `agend` — the one npm put in its global prefix, verified by identity —
|
|
3
|
+
* by absolute path, never whichever `agend` comes first on the fleet's PATH (a checkout, another prefix). That keeps
|
|
4
|
+
* the deliberate choice "update what is installed, on its own channel" (the CLI picks the channel from the version it
|
|
5
|
+
* replaces). No unverified fallback: when npm cannot say where it installed AgEnD, or what it says does not hold
|
|
6
|
+
* together, `/update` refuses and says to run `agend update` from a shell.
|
|
7
|
+
*
|
|
8
|
+
* Runs on the fleet's event loop: every step is async and bounded.
|
|
9
|
+
*/
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { readFile, realpath } from "node:fs/promises";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { promisify } from "node:util";
|
|
14
|
+
export const defaultDispatchDeps = {
|
|
15
|
+
run: async (command, args, timeoutMs) => {
|
|
16
|
+
try {
|
|
17
|
+
const { stdout } = await promisify(execFile)(command, args, { encoding: "utf8", timeout: timeoutMs });
|
|
18
|
+
return { status: 0, stdout: String(stdout) };
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
const code = err.code;
|
|
22
|
+
return { status: typeof code === "number" ? code : null, stdout: "" };
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
readFile: path => readFile(path, "utf8"),
|
|
26
|
+
realpath: path => realpath(path),
|
|
27
|
+
};
|
|
28
|
+
/** npm's global root and prefix → the installed package, its bin target, and the bin link that must lead to it. */
|
|
29
|
+
export async function resolveInstalledAgend(deps = defaultDispatchDeps) {
|
|
30
|
+
const last = (text) => text.trim().split("\n").pop()?.trim() ?? "";
|
|
31
|
+
const [root, prefix] = await Promise.all([deps.run("npm", ["root", "-g"], 15_000), deps.run("npm", ["prefix", "-g"], 15_000)]);
|
|
32
|
+
if (root.status !== 0 || prefix.status !== 0 || !last(root.stdout) || !last(prefix.stdout)) {
|
|
33
|
+
return { ok: false, reason: "npm could not say where AgEnD is installed" };
|
|
34
|
+
}
|
|
35
|
+
const pkgDir = join(last(root.stdout), "@songsid", "agend");
|
|
36
|
+
const notAgend = { ok: false, reason: `${pkgDir} is not an installed AgEnD package` };
|
|
37
|
+
let parsed;
|
|
38
|
+
try {
|
|
39
|
+
parsed = JSON.parse(await deps.readFile(join(pkgDir, "package.json")));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return notAgend;
|
|
43
|
+
}
|
|
44
|
+
// Whatever parsed (null, an array, a string…) is judged by shape, never dereferenced blindly.
|
|
45
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
46
|
+
return notAgend;
|
|
47
|
+
const manifest = parsed;
|
|
48
|
+
const bin = manifest.bin;
|
|
49
|
+
const binRel = typeof bin === "string" ? bin
|
|
50
|
+
: typeof bin === "object" && bin !== null && !Array.isArray(bin) && typeof bin.agend === "string" ? bin.agend : null;
|
|
51
|
+
if (manifest.name !== "@songsid/agend" || typeof manifest.version !== "string" || !manifest.version || !binRel)
|
|
52
|
+
return notAgend;
|
|
53
|
+
const agend = join(last(prefix.stdout), "bin", "agend");
|
|
54
|
+
let target, linked;
|
|
55
|
+
try {
|
|
56
|
+
[target, linked] = await Promise.all([deps.realpath(join(pkgDir, binRel)), deps.realpath(agend)]);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { ok: false, reason: `${agend} does not lead to the installed package` };
|
|
60
|
+
}
|
|
61
|
+
if (target !== linked)
|
|
62
|
+
return { ok: false, reason: `${agend} leads to ${linked}, not the installed package's ${target}` };
|
|
63
|
+
return { ok: true, agend, version: manifest.version };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* `<installed agend> update`, 2 s from now, from a detached `sh` that outlives this fleet (the update restarts it). The
|
|
67
|
+
* path is a positional argument, never spliced into the script.
|
|
68
|
+
*/
|
|
69
|
+
export const DELAYED_UPDATE_SCRIPT = 'sleep 2 && exec "$1" update';
|
|
70
|
+
export function updateCommand(agend) {
|
|
71
|
+
return { command: "sh", args: ["-c", DELAYED_UPDATE_SCRIPT, "sh", agend] };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=update-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-dispatch.js","sourceRoot":"","sources":["../src/update-dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/update-install.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PackagePreimage } from "./package-preimage.js";
|
|
1
2
|
export interface CommandResult {
|
|
2
3
|
status: number | null;
|
|
3
4
|
signal: NodeJS.Signals | null;
|
|
@@ -5,10 +6,14 @@ export interface CommandResult {
|
|
|
5
6
|
stderr: string;
|
|
6
7
|
}
|
|
7
8
|
export interface CommandRunner {
|
|
8
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Run a program; `inherit` streams its output to the terminal (npm's progress), otherwise it is captured. `env` is
|
|
11
|
+
* added to this process's environment for that one program (the install token goes to npm and nothing else).
|
|
12
|
+
*/
|
|
9
13
|
run(command: string, args: string[], options?: {
|
|
10
14
|
inherit?: boolean;
|
|
11
15
|
timeoutMs?: number;
|
|
16
|
+
env?: Record<string, string>;
|
|
12
17
|
}): CommandResult;
|
|
13
18
|
/** Progress for the operator, printed when it happens. */
|
|
14
19
|
log(message: string): void;
|
|
@@ -22,6 +27,28 @@ export interface UpdateInstallPlan {
|
|
|
22
27
|
viaNvm: boolean;
|
|
23
28
|
/** `~/.nvm/nvm.sh`. */
|
|
24
29
|
nvmSh: string;
|
|
30
|
+
/**
|
|
31
|
+
* #1450 C1: take the prefix lock for the realpath'd npm prefix this install will change, before npm runs; its token
|
|
32
|
+
* is handed to npm as AGEND_INSTALL_TOKEN. Omitted: no lock (tests of the order alone).
|
|
33
|
+
*/
|
|
34
|
+
lock?(prefix: string): {
|
|
35
|
+
ok: true;
|
|
36
|
+
token: string;
|
|
37
|
+
} | {
|
|
38
|
+
ok: false;
|
|
39
|
+
reason: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* #1450 C6: copy the installed package aside before npm (requires `lock`), and put it back when the new one does not
|
|
43
|
+
* verify. The successful outcome carries the preimage, so a later service failure can restore it too.
|
|
44
|
+
*/
|
|
45
|
+
rollback?: boolean;
|
|
46
|
+
now?(): Date;
|
|
47
|
+
/**
|
|
48
|
+
* nvm's Node 22 bin directory, resolved ONCE (runUpdateInstall sets it): locking, installing and verifying then run
|
|
49
|
+
* on that exact selection, never on a fresh `nvm use 22` that could pick another Node 22 in between (#1472 review).
|
|
50
|
+
*/
|
|
51
|
+
nvmBin?: string;
|
|
25
52
|
}
|
|
26
53
|
export type UpdateInstallOutcome = {
|
|
27
54
|
ok: true;
|
|
@@ -29,10 +56,17 @@ export type UpdateInstallOutcome = {
|
|
|
29
56
|
version: string;
|
|
30
57
|
dir: string;
|
|
31
58
|
bin: string;
|
|
59
|
+
entry: string;
|
|
32
60
|
node: string;
|
|
61
|
+
rollback?: {
|
|
62
|
+
root: string;
|
|
63
|
+
prefix: string;
|
|
64
|
+
preimage: PackagePreimage | null;
|
|
65
|
+
}; /** nvm transition: retire the old system copy once activation settles. */
|
|
66
|
+
retireSystemCopy?: true;
|
|
33
67
|
} | {
|
|
34
68
|
ok: false;
|
|
35
|
-
stage: "install" | "verify";
|
|
69
|
+
stage: "lock" | "install" | "verify";
|
|
36
70
|
message: string;
|
|
37
71
|
};
|
|
38
72
|
/**
|
|
@@ -42,8 +76,12 @@ export type UpdateInstallOutcome = {
|
|
|
42
76
|
* arguments or switching to its default before `nvm use 22`.
|
|
43
77
|
*/
|
|
44
78
|
export declare const NVM_RUN_SCRIPT = "n=$1; shift; . \"$n\" --no-use >/dev/null 2>&1 && nvm use 22 >/dev/null 2>&1 && \"$@\"";
|
|
45
|
-
/**
|
|
46
|
-
export declare const
|
|
79
|
+
/** Getting nvm's Node 22, before its prefix can be locked and installed into: `$1` = nvm.sh, as data. */
|
|
80
|
+
export declare const NVM_PREPARE_SCRIPT = "n=$1; . \"$n\" --no-use && nvm install 22";
|
|
81
|
+
/** Which Node `nvm use 22` selects: its absolute path, printed once. `$1` = nvm.sh, as data. */
|
|
82
|
+
export declare const NVM_SELECT_SCRIPT = "n=$1; . \"$n\" --no-use >/dev/null 2>&1 && nvm use 22 >/dev/null 2>&1 && command -v node";
|
|
83
|
+
/** Run the remaining arguments with a frozen nvm bin directory first on PATH (`$1`, as data). */
|
|
84
|
+
export declare const NVM_BIN_SCRIPT = "d=$1; shift; PATH=\"$d:$PATH\"; export PATH; exec \"$@\"";
|
|
47
85
|
/**
|
|
48
86
|
* How to run the NEW `agend` after the install: directly, or — for an nvm install — inside nvm's Node 22, because its
|
|
49
87
|
* `#!/usr/bin/env node` would otherwise pick the parent's (old) Node from PATH (#1446 item 1). Append the subcommand.
|
|
@@ -55,11 +93,15 @@ export declare function newAgendInvocation(plan: Pick<UpdateInstallPlan, "viaNvm
|
|
|
55
93
|
/** `npm link` leaves a symlink to a source checkout outside any node_modules tree; a registry install is a directory. */
|
|
56
94
|
export declare function isLocalLinkTarget(entryIsSymlink: boolean, realTarget: string): boolean;
|
|
57
95
|
/**
|
|
58
|
-
* The identity of what npm installed: `$1` is the package directory in npm's global root. Prints its name, version
|
|
59
|
-
*
|
|
96
|
+
* The identity of what npm installed: `$1` is the package directory in npm's global root. Prints its name, version, the
|
|
97
|
+
* REAL path of its `agend` bin target, so PATH's `agend` can be held to that exact file, and of its canonical inner
|
|
98
|
+
* entry `dist/cli.js` (#1450 C4: what a service starts; since the launcher, not the bin).
|
|
60
99
|
*/
|
|
61
100
|
export declare const PACKAGE_IDENTITY_SCRIPT: string;
|
|
62
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Proves the native module loads AND works, in the main thread and in a worker (the fleet opens databases in both):
|
|
103
|
+
* on Node 20 better-sqlite3 13 imports fine and then SIGSEGVs on open. `$1` is the package directory.
|
|
104
|
+
*/
|
|
63
105
|
export declare const NATIVE_CHECK_SCRIPT: string;
|
|
64
106
|
/**
|
|
65
107
|
* Prove the package npm installed — read from npm's own global root and prefix in the install environment — is the
|
|
@@ -69,3 +111,19 @@ export declare const NATIVE_CHECK_SCRIPT: string;
|
|
|
69
111
|
*/
|
|
70
112
|
export declare function verifyInstalledPackage(plan: UpdateInstallPlan, runner: CommandRunner): UpdateInstallOutcome;
|
|
71
113
|
export declare function runUpdateInstall(plan: UpdateInstallPlan, runner: CommandRunner): UpdateInstallOutcome;
|
|
114
|
+
/**
|
|
115
|
+
* Has the activation POSITIVELY settled on the new install — the moment the old system copy may go? launchd: the new
|
|
116
|
+
* job was proven running. Otherwise only a restart that reported "restarted": "pending" (systemd still running the
|
|
117
|
+
* job) and "failed" keep the old copy, as does any failed activation (#1473 review).
|
|
118
|
+
*/
|
|
119
|
+
export declare function activationSettled(outcome: {
|
|
120
|
+
ok: true;
|
|
121
|
+
via: "restart" | "launchd-activation";
|
|
122
|
+
} | {
|
|
123
|
+
ok: false;
|
|
124
|
+
}, restart: "restarted" | "pending" | "failed" | null): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* After an nvm transition's activation SETTLED (the fleet runs the new install): remove the old system copy. Best
|
|
127
|
+
* effort, and never waits for a password. Before that point the old copy is the rollback for the old service.
|
|
128
|
+
*/
|
|
129
|
+
export declare function retireSystemCopy(runner: CommandRunner): void;
|