@saadnvd1/agent-os 0.3.608 → 0.3.610

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.
@@ -0,0 +1,168 @@
1
+ import type { Session } from "@/lib/db/types";
2
+ import type { SidebarRow } from "./shelves";
3
+ import { finishActions } from "./row-actions";
4
+
5
+ // What a session row's ⋯ / right-click menu offers, as data: which items,
6
+ // in which sections, and which sit together in a submenu. The component only
7
+ // draws it. An item that doesn't apply is absent, never shown disabled.
8
+ export type RowMenuItem =
9
+ | "rename"
10
+ | "pin"
11
+ | "unpin"
12
+ | "select"
13
+ | "open-tab"
14
+ | "open-pr"
15
+ | "card"
16
+ | "open-recipe"
17
+ | "copy-link"
18
+ | "share"
19
+ | "fork"
20
+ | "fresh-start"
21
+ | "new-conversation"
22
+ | "move-machine"
23
+ | "move-project"
24
+ | "check-ins"
25
+ | "save-recipe"
26
+ | "run-again"
27
+ | "snooze"
28
+ | "unsnooze"
29
+ | "pause"
30
+ | "resume"
31
+ | "settle"
32
+ | "reopen"
33
+ | "done"
34
+ | "restore"
35
+ | "archive"
36
+ | "delete";
37
+
38
+ export type RowMenuGroup = "open" | "share" | "restart" | "move" | "automate";
39
+
40
+ export type RowMenuEntry =
41
+ | RowMenuItem
42
+ | { group: RowMenuGroup; items: RowMenuItem[] };
43
+
44
+ export interface RowMenuInput {
45
+ session: Pick<
46
+ Session,
47
+ | "role"
48
+ | "quick_of"
49
+ | "pinned"
50
+ | "view"
51
+ | "agent_type"
52
+ | "task_status"
53
+ | "pr_url"
54
+ | "has_brief"
55
+ | "archived_at"
56
+ | "pause_state"
57
+ >;
58
+ row?: Pick<SidebarRow, "task" | "wakesAt" | "settled">;
59
+ // A linked machine runs it: what can't reach it yet is left out.
60
+ remote: boolean;
61
+ canOpenInTab: boolean;
62
+ hasCard: boolean;
63
+ recipeRun: boolean;
64
+ hasWorkspace: boolean;
65
+ machineTargets: number;
66
+ otherProjects: number;
67
+ }
68
+
69
+ export interface RowMenuPlan {
70
+ sections: RowMenuEntry[][];
71
+ // Say once why Fork, Fresh start, project moves and check-ins are missing.
72
+ remoteNote: boolean;
73
+ }
74
+
75
+ const GROUP_LABEL: Record<RowMenuGroup, string> = {
76
+ open: "Open",
77
+ share: "Share",
78
+ restart: "Fork or restart",
79
+ move: "Move",
80
+ automate: "Automate",
81
+ };
82
+ export const groupLabel = (g: RowMenuGroup) => GROUP_LABEL[g];
83
+
84
+ // A group of one is just that item; an empty one is nothing.
85
+ function group(
86
+ g: RowMenuGroup,
87
+ items: (RowMenuItem | false)[]
88
+ ): RowMenuEntry[] {
89
+ const kept = items.filter((i): i is RowMenuItem => !!i);
90
+ if (kept.length === 0) return [];
91
+ return kept.length === 1 ? kept : [{ group: g, items: kept }];
92
+ }
93
+
94
+ export function rowMenu(input: RowMenuInput): RowMenuPlan {
95
+ const { session: s, row, remote } = input;
96
+ const plain = !!row && !row.task && !s.task_status;
97
+ const finish = finishActions(s, plain);
98
+ const sections: RowMenuEntry[][] = [];
99
+
100
+ // A quick change has no agent: its PR and the ways to finish it.
101
+ if (s.quick_of) {
102
+ sections.push(s.pr_url ? ["open-pr"] : []);
103
+ sections.push(finish.filter((a) => a !== "archive"));
104
+ sections.push(["archive", "delete"]);
105
+ return {
106
+ sections: sections.filter((x) => x.length),
107
+ remoteNote: false,
108
+ };
109
+ }
110
+
111
+ const orchestrator = s.role === "orchestrator";
112
+ const agentRow = !s.role;
113
+ const live = !remote;
114
+
115
+ sections.push(["rename", s.pinned ? "unpin" : "pin", "select"]);
116
+
117
+ sections.push([
118
+ ...group("open", [
119
+ input.canOpenInTab && "open-tab",
120
+ !!s.pr_url && "open-pr",
121
+ input.hasCard && "card",
122
+ input.recipeRun && "open-recipe",
123
+ ]),
124
+ ...group("share", ["copy-link", s.view === "chat" && "share"]),
125
+ ...group("restart", [
126
+ s.agent_type === "claude" && agentRow && live && "fork",
127
+ agentRow && live && "fresh-start",
128
+ (orchestrator || !!s.has_brief) &&
129
+ s.view === "chat" &&
130
+ !s.archived_at &&
131
+ live &&
132
+ "new-conversation",
133
+ ]),
134
+ ...group("move", [
135
+ input.machineTargets > 0 && "move-machine",
136
+ agentRow && input.otherProjects > 0 && live && "move-project",
137
+ ]),
138
+ ...group("automate", [
139
+ input.hasWorkspace &&
140
+ !orchestrator &&
141
+ (!s.task_status || s.task_status === "running") &&
142
+ live &&
143
+ "check-ins",
144
+ input.recipeRun ? "run-again" : agentRow && "save-recipe",
145
+ ]),
146
+ ]);
147
+
148
+ if (agentRow) {
149
+ const state: RowMenuEntry[] = [];
150
+ if (row?.wakesAt) state.push("unsnooze");
151
+ else if (!s.pinned && row) state.push("snooze");
152
+ const finished = !!s.task_status && s.task_status !== "running";
153
+ if ((s.task_status || s.view === "chat") && !finished) {
154
+ if (s.pause_state === "paused" || s.pause_state === "pausing")
155
+ state.push("resume");
156
+ else if (!s.pause_state) state.push("pause");
157
+ }
158
+ if (plain) state.push(row.settled ? "reopen" : "settle");
159
+ state.push(...finish.filter((a) => a !== "archive"));
160
+ sections.push(state);
161
+ sections.push(["archive", "delete"]);
162
+ }
163
+
164
+ return {
165
+ sections: sections.filter((x) => x.length),
166
+ remoteNote: remote && agentRow,
167
+ };
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saadnvd1/agent-os",
3
- "version": "0.3.608",
3
+ "version": "0.3.610",
4
4
  "description": "Self-hosted web UI for managing Claude Code sessions",
5
5
  "bin": {
6
6
  "agent-os": "scripts/agent-os"