@sealant/mend 0.17.0 → 0.19.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.
Files changed (51) hide show
  1. package/dist/dashboard-model.js +9 -1
  2. package/dist/dashboard.js +45 -1
  3. package/dist/help.js +824 -0
  4. package/dist/main.js +82 -116
  5. package/dist/version.js +48 -0
  6. package/man/mend-accounts.1 +11 -0
  7. package/man/mend-adopt.1 +27 -0
  8. package/man/mend-attach.1 +13 -0
  9. package/man/mend-codex.1 +60 -0
  10. package/man/mend-completions.1 +14 -0
  11. package/man/mend-connect.1 +25 -0
  12. package/man/mend-continue.1 +11 -0
  13. package/man/mend-doctor.1 +11 -0
  14. package/man/mend-dotfiles-sync.1 +15 -0
  15. package/man/mend-dotfiles.1 +11 -0
  16. package/man/mend-env-cluster.1 +26 -0
  17. package/man/mend-env-load.1 +21 -0
  18. package/man/mend-env-show.1 +15 -0
  19. package/man/mend-help.1 +11 -0
  20. package/man/mend-keys-init.1 +11 -0
  21. package/man/mend-keys-share.1 +11 -0
  22. package/man/mend-keys-show.1 +11 -0
  23. package/man/mend-login.1 +20 -0
  24. package/man/mend-logout.1 +11 -0
  25. package/man/mend-man.1 +11 -0
  26. package/man/mend-pair.1 +15 -0
  27. package/man/mend-projects.1 +11 -0
  28. package/man/mend-refresh.1 +11 -0
  29. package/man/mend-rejoin.1 +15 -0
  30. package/man/mend-resume.1 +15 -0
  31. package/man/mend-run.1 +18 -0
  32. package/man/mend-service-add.1 +21 -0
  33. package/man/mend-service-connect.1 +15 -0
  34. package/man/mend-service-init.1 +15 -0
  35. package/man/mend-service-list.1 +11 -0
  36. package/man/mend-service-logs.1 +15 -0
  37. package/man/mend-service-restart.1 +11 -0
  38. package/man/mend-service-run.1 +38 -0
  39. package/man/mend-service-stop.1 +11 -0
  40. package/man/mend-sessions.1 +27 -0
  41. package/man/mend-shell.1 +13 -0
  42. package/man/mend-skills-push.1 +21 -0
  43. package/man/mend-skills.1 +15 -0
  44. package/man/mend-ssh-setup.1 +15 -0
  45. package/man/mend-ssh.1 +11 -0
  46. package/man/mend-stop.1 +22 -0
  47. package/man/mend-ui.1 +13 -0
  48. package/man/mend-version.1 +11 -0
  49. package/man/mend-worktrees.1 +18 -0
  50. package/man/mend.1 +165 -0
  51. package/package.json +8 -3
@@ -92,6 +92,12 @@ export const toSessionItem = (data, detail) => (session) => ({
92
92
  services: data.servicesBySession.get(session.id) ?? [],
93
93
  processes: data.processesBySession.get(session.id) ?? [],
94
94
  });
95
+ /**
96
+ * A settled session that never had a conversation — no transcript captured, none in the harness
97
+ * home — cannot be resumed or handed off. The dashboard hides it; `mend sessions --all` still
98
+ * lists it, and removing the worktree takes it along.
99
+ */
100
+ export const isDeadEnd = (session) => !LIVE_STATUSES.has(session.status) && session.hasTranscript === false;
95
101
  export const deriveWorktrees = (data, projectId) => {
96
102
  if (data === undefined || projectId === null)
97
103
  return [];
@@ -99,7 +105,9 @@ export const deriveWorktrees = (data, projectId) => {
99
105
  if (detail === undefined)
100
106
  return [];
101
107
  const item = toSessionItem(data, detail);
102
- const sorted = detail.sessions.toSorted(bySessionRecency);
108
+ const sorted = detail.sessions
109
+ .filter((session) => !isDeadEnd(session))
110
+ .toSorted(bySessionRecency);
103
111
  const groups = [];
104
112
  if (detail.worktrees !== undefined) {
105
113
  const claimed = new Set();
package/dist/dashboard.js CHANGED
@@ -35,6 +35,8 @@ const timeAgo = (iso) => {
35
35
  return `${Math.floor(hours / 24)}d ago`;
36
36
  };
37
37
  import { createSseParser, eventFamilies } from "./workbench-events.js";
38
+ /** The agent itself is still working: never remove from under it. Idle (agent gone) may go. */
39
+ const AGENT_LIVE_STATUSES = new Set(["starting", "running", "waiting"]);
38
40
  // ─── panes and rows ─────────────────────────────────────────────────────────
39
41
  const Gutter = ({ selected }) => (_jsx("span", { fg: selected ? COBALT : FAINT, children: selected ? "▌ " : " " }));
40
42
  /**
@@ -532,9 +534,51 @@ const App = ({ ctx, onQuit }) => {
532
534
  },
533
535
  onSettled: settleRefetch,
534
536
  });
535
- /** Worktree removal is armed like stops: the first press states the facts. */
537
+ /**
538
+ * One session leaves; the worktree stays. The server stops an idle session's shells and
539
+ * settles it on the way out, so a session killed a moment ago removes without a second stop.
540
+ */
541
+ const removeSessionMutation = useMutation({
542
+ mutationFn: (session) => ctx.api("DELETE", `/sessions/${session.id}`),
543
+ onMutate: async (session) => {
544
+ await queryClient.cancelQueries({ queryKey: WORKBENCH_KEY });
545
+ const projectId = selectedProject?.project.id;
546
+ if (projectId !== undefined) {
547
+ patchWorkbench((current) => removeSession(current, projectId, session.id));
548
+ }
549
+ say(`removing session · ${worktreeDisplayName(session)}`);
550
+ },
551
+ onError: (error) => {
552
+ say(errorText(error));
553
+ refetch();
554
+ },
555
+ onSuccess: (_result, session) => {
556
+ say(`removed · ${worktreeDisplayName(session)} — the worktree remains`);
557
+ refetch();
558
+ },
559
+ onSettled: settleRefetch,
560
+ });
561
+ /** Removal is armed like stops: the first press states the facts. */
536
562
  const [removeArmed, setRemoveArmed] = useState(null);
537
563
  const armRemove = () => {
564
+ // A session row removes THAT session; a worktree header removes the whole worktree.
565
+ if (selectedRow?.kind === "session") {
566
+ const session = selectedRow.item.session;
567
+ if (isPendingId(session.id))
568
+ return;
569
+ if (AGENT_LIVE_STATUSES.has(session.status)) {
570
+ say(`the agent is still working — kill it first (⇧K) · ${worktreeDisplayName(session)}`);
571
+ return;
572
+ }
573
+ if (removeArmed === session.id) {
574
+ setRemoveArmed(null);
575
+ removeSessionMutation.mutate(session);
576
+ return;
577
+ }
578
+ setRemoveArmed(session.id);
579
+ say(`press again to remove session · ${worktreeDisplayName(session)} — its record goes, the worktree stays`);
580
+ return;
581
+ }
538
582
  const group = selectedGroup;
539
583
  if (group === null || group.sessions.some((item) => isPendingId(item.session.id)))
540
584
  return;