@saadnvd1/agent-os 0.3.700 → 0.3.723
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/app/api/agent-roles/route.test.ts +67 -0
- package/app/api/agent-roles/route.ts +61 -0
- package/app/api/analyst/[id]/recommendations/[recId]/again/route.ts +15 -0
- package/app/api/analyst/[id]/recommendations/[recId]/dismiss/route.ts +13 -0
- package/app/api/analyst/[id]/recommendations/[recId]/send/route.ts +13 -0
- package/app/api/analyst/[id]/review/route.ts +22 -0
- package/app/api/analyst/[id]/route.ts +44 -0
- package/app/api/analyst/route.ts +10 -0
- package/app/api/bus/groups/route.ts +44 -0
- package/app/api/bus/spawn/route.ts +34 -2
- package/app/api/claims/[id]/route.ts +20 -0
- package/app/api/claims/check/route.ts +23 -0
- package/app/api/claims/check.test.ts +113 -0
- package/app/api/claims/exchange/route.ts +42 -0
- package/app/api/claims/outside.test.ts +90 -0
- package/app/api/claims/route.test.ts +193 -0
- package/app/api/claims/route.ts +73 -0
- package/app/api/hosts/[id]/route.ts +9 -1
- package/app/api/models/availability/route.ts +9 -0
- package/app/api/models/choices/route.ts +9 -0
- package/app/api/peer/unlink/route.ts +17 -0
- package/app/api/peers/[hostId]/audit/route.ts +14 -0
- package/app/api/peers/[hostId]/route.ts +20 -0
- package/app/api/peers/gate.test.ts +64 -1
- package/app/api/peers/pending/route.test.ts +37 -0
- package/app/api/peers/pending/route.ts +11 -4
- package/app/api/session-groups/[id]/restore/route.ts +11 -0
- package/app/api/session-groups/[id]/route.ts +25 -0
- package/app/api/session-groups/order/route.ts +15 -0
- package/app/api/session-groups/route.ts +21 -0
- package/app/api/sessions/[id]/analyst/route.ts +11 -0
- package/app/api/sessions/[id]/crew/route.ts +38 -0
- package/app/api/sessions/[id]/export/estimate/route.ts +23 -0
- package/app/api/sessions/[id]/export/route.test.ts +125 -0
- package/app/api/sessions/[id]/export/route.ts +34 -0
- package/app/api/sessions/[id]/fork/route.ts +3 -0
- package/app/api/sessions/[id]/group/route.ts +18 -0
- package/app/api/sessions/[id]/model/route.ts +49 -0
- package/app/api/sessions/[id]/route.ts +14 -4
- package/app/api/sessions/[id]/summarize/route.ts +2 -0
- package/app/api/sessions/claims.test.ts +122 -0
- package/app/api/sessions/group/route.ts +17 -0
- package/app/api/sessions/route.ts +31 -14
- package/app/page.tsx +10 -0
- package/components/Chat/Messages.tsx +104 -10
- package/components/Claims/ClaimFiles.tsx +38 -0
- package/components/Claims/ClaimRow.tsx +82 -0
- package/components/Claims/ClaimsSheet.tsx +176 -0
- package/components/Claims/OverlapPill.tsx +31 -0
- package/components/Claims/StartClaimsNotice.tsx +70 -0
- package/components/Claims/claims-ui.test.ts +161 -0
- package/components/Claims/format.ts +57 -0
- package/components/Claims/index.ts +3 -0
- package/components/Draft/DraftChips.tsx +6 -1
- package/components/Draft/DraftPanel.tsx +90 -3
- package/components/Draft/ModelUnavailableDialog.tsx +78 -0
- package/components/Draft/RoleChips.tsx +110 -0
- package/components/Export/ExportActions.tsx +136 -0
- package/components/Export/ExportSheet.tsx +217 -0
- package/components/Export/RangePicker.tsx +144 -0
- package/components/Export/Seg.tsx +38 -0
- package/components/Export/TurnSelectBar.tsx +45 -0
- package/components/Hosts/AccountMachines.tsx +32 -18
- package/components/Hosts/HostRow.tsx +155 -14
- package/components/Hosts/IncomingLinkSheet.tsx +28 -10
- package/components/Hosts/PeerActivitySheet.tsx +111 -0
- package/components/Models/AgentRoleCard.tsx +114 -0
- package/components/Models/AgentRolesSection.tsx +132 -0
- package/components/Models/ModelBadges.tsx +48 -0
- package/components/Models/ModelsSection.tsx +4 -2
- package/components/Models/RoleModelSelect.tsx +87 -0
- package/components/Pane/DesktopTabBar.tsx +2 -0
- package/components/Pane/MobileTabBar.tsx +12 -0
- package/components/Pane/PaneMenu.tsx +10 -0
- package/components/SessionList/GroupShelves.tsx +195 -0
- package/components/SessionList/MoveToGroupMenu.tsx +105 -0
- package/components/SessionList/RowSubtitle.tsx +7 -1
- package/components/SessionList/SelectionToolbar.tsx +52 -1
- package/components/SessionList/SessionRow.tsx +19 -7
- package/components/SessionList/SessionRowMenu.tsx +23 -0
- package/components/SessionList/SessionShelves.tsx +5 -0
- package/components/SessionList/SidebarBody.tsx +6 -0
- package/components/SessionList/SidebarContextMenu.test.ts +104 -0
- package/components/SessionList/SidebarContextMenu.tsx +59 -0
- package/components/SessionList/SidebarHeader.tsx +5 -0
- package/components/SessionList/WorkspaceSwitcher.tsx +23 -6
- package/components/SessionList/index.tsx +18 -14
- package/components/SessionList/useSidebarData.ts +10 -0
- package/components/Sessions/RolePill.tsx +196 -0
- package/components/Settings/SettingsDialog.tsx +9 -0
- package/components/Share/ShareDialog.tsx +13 -0
- package/components/ui/notice.tsx +46 -0
- package/components/ui/status-pill.tsx +39 -0
- package/data/analyst/index.ts +3 -0
- package/data/analyst/keys.ts +6 -0
- package/data/analyst/mutations.ts +116 -0
- package/data/analyst/queries.ts +35 -0
- package/data/claims/index.ts +2 -0
- package/data/claims/keys.ts +5 -0
- package/data/claims/queries.ts +47 -0
- package/data/exports/index.ts +2 -0
- package/data/exports/keys.ts +3 -0
- package/data/exports/queries.ts +51 -0
- package/data/models/index.ts +98 -0
- package/data/peers/keys.ts +1 -0
- package/data/peers/queries.ts +31 -0
- package/data/push/topics.ts +9 -0
- package/data/session-groups/index.ts +156 -0
- package/data/sessions/index.ts +0 -1
- package/data/sessions/pin.ts +2 -6
- package/data/sessions/queries.ts +36 -29
- package/data/sessions/shelf.ts +2 -6
- package/data/tasks/index.ts +2 -0
- package/hooks/useSessions.ts +0 -12
- package/lib/__fixtures__/peer-rpc.ts +65 -33
- package/lib/agents/brief.ts +1 -0
- package/lib/agents/spawn.ts +4 -0
- package/lib/analyst/__fixtures__/items.ts +57 -0
- package/lib/analyst/__fixtures__/mocks.ts +49 -0
- package/lib/analyst/brief.ts +17 -0
- package/lib/analyst/buildDigest.ts +204 -0
- package/lib/analyst/createLink.ts +98 -0
- package/lib/analyst/endLink.ts +31 -0
- package/lib/analyst/forward.ts +109 -0
- package/lib/analyst/index.ts +16 -0
- package/lib/analyst/linkView.ts +38 -0
- package/lib/analyst/onTurnEnd.ts +119 -0
- package/lib/analyst/parseReview.ts +41 -0
- package/lib/analyst/pushDigest.ts +143 -0
- package/lib/analyst/resume.ts +35 -0
- package/lib/analyst/route.ts +50 -0
- package/lib/analyst/signals.ts +121 -0
- package/lib/analyst/store.ts +303 -0
- package/lib/analyst/types.ts +140 -0
- package/lib/bus/condense.ts +5 -1
- package/lib/bus/index.ts +13 -0
- package/lib/bus/read-scope.ts +12 -0
- package/lib/bus/role-alias.ts +70 -0
- package/lib/bus/targets.ts +3 -0
- package/lib/chat/drivers/opencode-mapper.ts +55 -1
- package/lib/chat/drivers/pi-approvals.ts +7 -4
- package/lib/chat/drivers/pi-mapper.ts +38 -0
- package/lib/chat/drivers/pi-text-tools.ts +104 -0
- package/lib/chat/drivers/pi.ts +8 -3
- package/lib/chat/drivers/turn-items.ts +36 -11
- package/lib/chat/drivers/turn-outcome.ts +108 -0
- package/lib/chat/events.ts +8 -0
- package/lib/chat/registry.ts +13 -0
- package/lib/chat/store.ts +19 -0
- package/lib/chat/turns.ts +1 -0
- package/lib/chat/worker/extras.ts +4 -2
- package/lib/claims/collectLocal.ts +123 -0
- package/lib/claims/describe.ts +41 -0
- package/lib/claims/exchange.ts +91 -0
- package/lib/claims/goal.ts +45 -0
- package/lib/claims/index.ts +10 -0
- package/lib/claims/loop.ts +51 -0
- package/lib/claims/machine.ts +21 -0
- package/lib/claims/mine.ts +43 -0
- package/lib/claims/notifyOverlaps.ts +101 -0
- package/lib/claims/onMerged.ts +85 -0
- package/lib/claims/outside.ts +36 -0
- package/lib/claims/overlap.ts +87 -0
- package/lib/claims/overlapCache.ts +86 -0
- package/lib/claims/overlapText.ts +36 -0
- package/lib/claims/peers.ts +56 -0
- package/lib/claims/startCheck.ts +100 -0
- package/lib/claims/startWarning.ts +29 -0
- package/lib/claims/store.ts +366 -0
- package/lib/claims/types.ts +102 -0
- package/lib/claims/view.ts +80 -0
- package/lib/claims/yield.ts +24 -0
- package/lib/db/changes.ts +12 -0
- package/lib/db/migrations/20261020T1400_work_claims.ts +35 -0
- package/lib/db/migrations/20261020T1515_peer_unlinked.ts +22 -0
- package/lib/db/migrations/20261020T1700_clean_connect_names.ts +18 -0
- package/lib/db/migrations/20261020T1800_session_groups.ts +49 -0
- package/lib/db/migrations/20261020T1900_task_queue_after_claim.ts +13 -0
- package/lib/db/migrations/20261020T2000_claim_notices.ts +20 -0
- package/lib/db/migrations/20261020T2100_claims_via_host.ts +21 -0
- package/lib/db/migrations/20261020T2200_work_claims_watch.ts +10 -0
- package/lib/db/migrations/20261021T1400_session_agent_roles.ts +20 -0
- package/lib/db/migrations/20261021T1430_analyst_links.ts +52 -0
- package/lib/db/queries.ts +0 -40
- package/lib/db/session-parts/columns.ts +3 -0
- package/lib/db/types.ts +19 -8
- package/lib/doctor/checks.ts +64 -1
- package/lib/done/archive.ts +2 -0
- package/lib/drafts.ts +4 -0
- package/lib/export/build.ts +470 -0
- package/lib/export/compact.ts +156 -0
- package/lib/export/estimate.ts +83 -0
- package/lib/export/fixtures.ts +45 -0
- package/lib/export/html.tsx +195 -0
- package/lib/export/json.ts +39 -0
- package/lib/export/load.ts +64 -0
- package/lib/export/markdown.ts +127 -0
- package/lib/export/request.ts +36 -0
- package/lib/export/service.ts +142 -0
- package/lib/export/summary.ts +86 -0
- package/lib/export/turns.ts +63 -0
- package/lib/export/view.ts +173 -0
- package/lib/git-remote.ts +43 -0
- package/lib/hosts/index.ts +10 -1
- package/lib/models/agent-binding.ts +102 -0
- package/lib/models/agent-roles-view.ts +157 -0
- package/lib/models/agent-roles.ts +87 -0
- package/lib/models/availability-refs.ts +17 -0
- package/lib/models/availability.ts +91 -0
- package/lib/models/catalog.ts +156 -0
- package/lib/models/config.ts +27 -0
- package/lib/models/locality.ts +33 -0
- package/lib/models/providers.ts +11 -0
- package/lib/models/resolve.ts +50 -12
- package/lib/models/roles.ts +12 -0
- package/lib/needs-you.ts +1 -1
- package/lib/orchestration.ts +2 -0
- package/lib/orchestrator/act.ts +54 -4
- package/lib/orchestrator/brief.ts +2 -1
- package/lib/orchestrator/claim-wait.ts +71 -0
- package/lib/orchestrator/conditions.ts +28 -1
- package/lib/orchestrator/describe.ts +6 -1
- package/lib/orchestrator/facts.ts +12 -2
- package/lib/orchestrator/read.ts +5 -1
- package/lib/orchestrator/serve.ts +37 -2
- package/lib/orchestrator/tool-names.ts +1 -0
- package/lib/orchestrator/tool-schemas.ts +31 -1
- package/lib/orchestrator/tools.ts +3 -1
- package/lib/orchestrator/untrusted.ts +5 -0
- package/lib/orchestrator/watcher.ts +19 -1
- package/lib/peer/account.ts +74 -2
- package/lib/peer/allowlist.ts +1 -1
- package/lib/peer/client.ts +26 -1
- package/lib/peer/link-cli.ts +19 -4
- package/lib/peer/links.ts +117 -5
- package/lib/peer/machines.ts +14 -2
- package/lib/peer/name.ts +32 -0
- package/lib/peer/pairing.ts +34 -5
- package/lib/peer/pin.ts +10 -3
- package/lib/peer/reasons.ts +7 -0
- package/lib/peer/revoke.ts +75 -0
- package/lib/peer/rpc-server.ts +53 -5
- package/lib/peer/unlink.ts +62 -0
- package/lib/peer/unlinked-proof.ts +44 -0
- package/lib/projects.ts +6 -2
- package/lib/security/demo.ts +7 -0
- package/lib/session-artifacts/agentos-files.ts +94 -0
- package/lib/session-artifacts/collect.ts +17 -0
- package/lib/session-groups/assignSessions.ts +81 -0
- package/lib/session-groups/cli.ts +61 -0
- package/lib/session-groups/createGroup.ts +28 -0
- package/lib/session-groups/index.ts +21 -0
- package/lib/session-groups/removeGroup.ts +36 -0
- package/lib/session-groups/reorderGroups.ts +31 -0
- package/lib/session-groups/resolveGroup.ts +19 -0
- package/lib/session-groups/route.ts +32 -0
- package/lib/session-groups/store.ts +85 -0
- package/lib/session-groups/types.ts +25 -0
- package/lib/session-groups/updateGroup.ts +35 -0
- package/lib/session-groups/workspace.ts +21 -0
- package/lib/sessions/crew.ts +72 -0
- package/lib/sessions/launch.ts +54 -11
- package/lib/settings-url.ts +1 -0
- package/lib/share/markdown.ts +2 -2
- package/lib/share/redact.ts +16 -10
- package/lib/share/render.tsx +1 -1
- package/lib/share/snapshot.ts +2 -2
- package/lib/sidebar/rollup.ts +1 -0
- package/lib/sidebar/row-menu.ts +8 -1
- package/lib/sidebar/shelves.ts +90 -15
- package/lib/sidebar/visible-order.ts +5 -0
- package/lib/tasks/hold-checks.ts +3 -1
- package/lib/tasks/holds.ts +3 -0
- package/lib/tasks/index.ts +11 -0
- package/lib/tasks/queue-rows.ts +8 -1
- package/lib/tasks/queue-start.ts +1 -0
- package/lib/tasks/queue-types.ts +9 -1
- package/lib/tasks/queue.ts +15 -5
- package/lib/tasks/schedule-types.ts +1 -0
- package/lib/test-temp.ts +19 -3
- package/lib/workspaces.ts +11 -3
- package/lib/worktree-deps/caches.ts +3 -2
- package/lib/worktree-deps/clone.ts +3 -1
- package/lib/worktree-deps/paths.ts +26 -0
- package/lib/worktree-sweep/testTemp.ts +23 -106
- package/package.json +1 -1
- package/scripts/agent-os +1 -1
- package/scripts/autodeploy +2 -0
- package/scripts/autodeploy.test.ts +31 -1
- package/scripts/claim-hook.sh +31 -0
- package/scripts/claim-hook.test.ts +230 -0
- package/scripts/lib/cli-links.sh +36 -0
- package/scripts/lib/commands.sh +3 -0
- package/scripts/lib/machine.sh +27 -2
- package/scripts/lib/machine.test.ts +25 -3
- package/scripts/sync-cli-links +7 -0
- package/scripts/sync-cli-links.test.ts +69 -0
- package/server.ts +12 -1
- package/stores/claimsUi.ts +22 -0
- package/stores/exportUi.ts +87 -0
- package/app/api/groups/[...path]/route.ts +0 -136
- package/app/api/groups/route.ts +0 -93
- package/data/groups/index.ts +0 -1
- package/data/groups/mutations.ts +0 -95
- package/hooks/useGroups.ts +0 -37
package/data/models/index.ts
CHANGED
|
@@ -9,6 +9,9 @@ import type { ProviderTest } from "@/lib/models/test-provider";
|
|
|
9
9
|
import type { ResumeResult } from "@/lib/models/resume";
|
|
10
10
|
import type { ModelOverride } from "@/lib/models/resolve";
|
|
11
11
|
import type { Comparison } from "@/lib/usage/compare";
|
|
12
|
+
import type { ModelChoice } from "@/lib/models/catalog";
|
|
13
|
+
import type { RoleMap } from "@/lib/models/config";
|
|
14
|
+
import type { RoleScope, agentRolesView } from "@/lib/models/agent-roles-view";
|
|
12
15
|
|
|
13
16
|
// Model routing (lib/models): role models, providers, prices.
|
|
14
17
|
export const modelKeys = {
|
|
@@ -17,6 +20,29 @@ export const modelKeys = {
|
|
|
17
20
|
compare: (days: number) => [...modelKeys.all, "compare", days] as const,
|
|
18
21
|
};
|
|
19
22
|
|
|
23
|
+
export const agentRoleKeys = {
|
|
24
|
+
roles: (scope: RoleScope, id?: string | null) =>
|
|
25
|
+
[...modelKeys.all, "agent-roles", scope, id ?? null] as const,
|
|
26
|
+
choices: [...modelKeys.all, "choices"] as const,
|
|
27
|
+
crew: (sessionId: string) => ["sessions", sessionId, "crew"] as const,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type AgentRolesResponse = ReturnType<typeof agentRolesView>;
|
|
31
|
+
|
|
32
|
+
export interface CrewResponse {
|
|
33
|
+
agentRole: string | null;
|
|
34
|
+
crewId: string | null;
|
|
35
|
+
members: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
agentRole: string | null;
|
|
39
|
+
model: string | null;
|
|
40
|
+
ref: string | null;
|
|
41
|
+
locality: "local" | "cloud";
|
|
42
|
+
availability: "up" | "down" | "unknown";
|
|
43
|
+
}[];
|
|
44
|
+
}
|
|
45
|
+
|
|
20
46
|
export interface ModelsResponse {
|
|
21
47
|
saved: ModelSettings;
|
|
22
48
|
effective: EffectiveModels;
|
|
@@ -113,3 +139,75 @@ export function useCompareQuery(days: number, enabled = true) {
|
|
|
113
139
|
|
|
114
140
|
// Every model a role can be set to: each usable provider's, as references.
|
|
115
141
|
export { modelChoices } from "@/lib/models/choices";
|
|
142
|
+
|
|
143
|
+
// The agent roles (Developer, Analyst, Reviewer, Supervisor) at a scope:
|
|
144
|
+
// Settings, a workspace or a project.
|
|
145
|
+
export function useAgentRolesQuery(scope: RoleScope, id?: string | null) {
|
|
146
|
+
return useQuery({
|
|
147
|
+
queryKey: agentRoleKeys.roles(scope, id),
|
|
148
|
+
queryFn: async () =>
|
|
149
|
+
json<AgentRolesResponse>(
|
|
150
|
+
await fetch(
|
|
151
|
+
`/api/agent-roles?scope=${scope}${id ? `&id=${encodeURIComponent(id)}` : ""}`
|
|
152
|
+
)
|
|
153
|
+
),
|
|
154
|
+
staleTime: 20_000,
|
|
155
|
+
refetchInterval: 30_000,
|
|
156
|
+
enabled: scope === "settings" || !!id,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function useSaveAgentRoles(scope: RoleScope, id?: string | null) {
|
|
161
|
+
const queryClient = useQueryClient();
|
|
162
|
+
return useMutation({
|
|
163
|
+
mutationFn: async (input: { roles: RoleMap; fallbacks?: RoleMap }) =>
|
|
164
|
+
json<AgentRolesResponse>(
|
|
165
|
+
await send("/api/agent-roles", "PUT", { scope, id, ...input })
|
|
166
|
+
),
|
|
167
|
+
onSuccess: (data) => {
|
|
168
|
+
queryClient.invalidateQueries({ queryKey: modelKeys.all });
|
|
169
|
+
queryClient.setQueryData(agentRoleKeys.roles(scope, id), data);
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Every model a picker offers, with locality and availability.
|
|
175
|
+
export function useModelChoices(enabled = true) {
|
|
176
|
+
return useQuery({
|
|
177
|
+
queryKey: agentRoleKeys.choices,
|
|
178
|
+
queryFn: async () =>
|
|
179
|
+
(
|
|
180
|
+
await json<{ choices: ModelChoice[] }>(
|
|
181
|
+
await fetch("/api/models/choices")
|
|
182
|
+
)
|
|
183
|
+
).choices,
|
|
184
|
+
staleTime: 20_000,
|
|
185
|
+
refetchInterval: 30_000,
|
|
186
|
+
enabled,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function useCrewQuery(sessionId: string | undefined, enabled = true) {
|
|
191
|
+
return useQuery({
|
|
192
|
+
queryKey: agentRoleKeys.crew(sessionId ?? ""),
|
|
193
|
+
queryFn: async () =>
|
|
194
|
+
json<CrewResponse>(await fetch(`/api/sessions/${sessionId}/crew`)),
|
|
195
|
+
staleTime: 15_000,
|
|
196
|
+
refetchInterval: 30_000,
|
|
197
|
+
enabled: !!sessionId && enabled,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function useSwitchSessionModel(sessionId: string) {
|
|
202
|
+
const queryClient = useQueryClient();
|
|
203
|
+
return useMutation({
|
|
204
|
+
mutationFn: async (ref: string) =>
|
|
205
|
+
json<{ ok: true }>(
|
|
206
|
+
await send(`/api/sessions/${sessionId}/model`, "POST", { ref })
|
|
207
|
+
),
|
|
208
|
+
onSuccess: () => {
|
|
209
|
+
queryClient.invalidateQueries({ queryKey: ["sessions"] });
|
|
210
|
+
queryClient.invalidateQueries({ queryKey: modelKeys.all });
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
}
|
package/data/peers/keys.ts
CHANGED
|
@@ -3,4 +3,5 @@ export const peerKeys = {
|
|
|
3
3
|
account: () => [...peerKeys.all, "account"] as const,
|
|
4
4
|
pending: () => [...peerKeys.all, "pending"] as const,
|
|
5
5
|
link: (id: string) => [...peerKeys.all, "link", id] as const,
|
|
6
|
+
audit: (hostId: string) => [...peerKeys.all, "audit", hostId] as const,
|
|
6
7
|
};
|
package/data/peers/queries.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import type { AuditRow } from "@/lib/peer/audit";
|
|
2
3
|
import type { AccountMachines } from "@/lib/peer/machines";
|
|
3
4
|
import type { PendingView } from "@/lib/peer/pairing";
|
|
4
5
|
import type { Outgoing } from "@/lib/peer/pairing-out";
|
|
@@ -139,3 +140,33 @@ export function useAnswerLink() {
|
|
|
139
140
|
}),
|
|
140
141
|
};
|
|
141
142
|
}
|
|
143
|
+
|
|
144
|
+
/** Unlinks a machine linked through Connect, here and (if it answers) there. */
|
|
145
|
+
export function useUnlinkPeer() {
|
|
146
|
+
const queryClient = useQueryClient();
|
|
147
|
+
return useMutation({
|
|
148
|
+
mutationFn: async (hostId: string) =>
|
|
149
|
+
json<{ name: string; told: boolean; removed: boolean }>(
|
|
150
|
+
await fetch(`/api/peers/${hostId}`, { method: "DELETE" })
|
|
151
|
+
),
|
|
152
|
+
onSettled: () => {
|
|
153
|
+
void queryClient.invalidateQueries({ queryKey: hostKeys.all });
|
|
154
|
+
void queryClient.invalidateQueries({ queryKey: peerKeys.account() });
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Every call to and from a linked machine, newest first. */
|
|
160
|
+
export function usePeerAudit(hostId: string | null) {
|
|
161
|
+
return useQuery({
|
|
162
|
+
queryKey: peerKeys.audit(hostId ?? ""),
|
|
163
|
+
queryFn: async () =>
|
|
164
|
+
(
|
|
165
|
+
await json<{ rows: AuditRow[] }>(
|
|
166
|
+
await fetch(`/api/peers/${hostId}/audit`)
|
|
167
|
+
)
|
|
168
|
+
).rows,
|
|
169
|
+
enabled: !!hostId,
|
|
170
|
+
refetchInterval: 15_000,
|
|
171
|
+
});
|
|
172
|
+
}
|
package/data/push/topics.ts
CHANGED
|
@@ -18,6 +18,8 @@ import { archivedKeys } from "../done";
|
|
|
18
18
|
import { awayKeys } from "../away";
|
|
19
19
|
import { bookmarkKeys } from "../bookmarks/keys";
|
|
20
20
|
import { learningCardsKeys } from "../learning-cards";
|
|
21
|
+
import { claimKeys } from "../claims/keys";
|
|
22
|
+
import { analystKeys } from "../analyst/keys";
|
|
21
23
|
|
|
22
24
|
// What each pushed topic (a table that changed, lib/db/changes.ts, or a
|
|
23
25
|
// pushed view) means the browser should refetch. Only queries on screen
|
|
@@ -41,6 +43,7 @@ function keysFor(topic: string): QueryKey[] {
|
|
|
41
43
|
case "projects":
|
|
42
44
|
return [projectKeys.all, sessionKeys.all];
|
|
43
45
|
case "groups":
|
|
46
|
+
case "session_groups":
|
|
44
47
|
return [sessionKeys.all];
|
|
45
48
|
case "workspaces":
|
|
46
49
|
return [workspaceKeys.all, orchestratorKeys.all];
|
|
@@ -76,6 +79,12 @@ function keysFor(topic: string): QueryKey[] {
|
|
|
76
79
|
return [devServerKeys.all];
|
|
77
80
|
case "learning_cards":
|
|
78
81
|
return [learningCardsKeys.all, orchestratorKeys.all];
|
|
82
|
+
case "work_claims":
|
|
83
|
+
return [claimKeys.all, sessionKeys.all];
|
|
84
|
+
case "analyst_links":
|
|
85
|
+
return [analystKeys.all, sessionKeys.all];
|
|
86
|
+
case "analyst_recommendations":
|
|
87
|
+
return [analystKeys.all];
|
|
79
88
|
case "chat_bookmarks":
|
|
80
89
|
return [bookmarkKeys.all];
|
|
81
90
|
default:
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { toast } from "sonner";
|
|
3
|
+
import type { SessionGroup } from "@/lib/sidebar/shelves";
|
|
4
|
+
import { sessionKeys } from "@/data/sessions/keys";
|
|
5
|
+
import type { SessionsResponse } from "@/data/sessions/queries";
|
|
6
|
+
|
|
7
|
+
async function send<T>(
|
|
8
|
+
url: string,
|
|
9
|
+
method: string,
|
|
10
|
+
body?: unknown
|
|
11
|
+
): Promise<T> {
|
|
12
|
+
const res = await fetch(url, {
|
|
13
|
+
method,
|
|
14
|
+
headers: { "Content-Type": "application/json" },
|
|
15
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
16
|
+
});
|
|
17
|
+
const data = await res.json().catch(() => ({}));
|
|
18
|
+
if (!res.ok) throw new Error(data.error ?? "Could not change the group");
|
|
19
|
+
return data as T;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Groups ride along in the sessions response, so every edit patches that
|
|
23
|
+
// one cache entry and lets the change push settle the rest.
|
|
24
|
+
function useGroupCache() {
|
|
25
|
+
const queryClient = useQueryClient();
|
|
26
|
+
const key = sessionKeys.list();
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
refresh: () => queryClient.invalidateQueries({ queryKey: key }),
|
|
30
|
+
async patch(edit: (old: SessionsResponse) => SessionsResponse) {
|
|
31
|
+
await queryClient.cancelQueries({ queryKey: key });
|
|
32
|
+
const previous = queryClient.getQueryData<SessionsResponse>(key);
|
|
33
|
+
queryClient.setQueryData<SessionsResponse>(
|
|
34
|
+
key,
|
|
35
|
+
(old) => old && edit(old)
|
|
36
|
+
);
|
|
37
|
+
return { previous };
|
|
38
|
+
},
|
|
39
|
+
restore(previous?: SessionsResponse) {
|
|
40
|
+
if (previous) queryClient.setQueryData(key, previous);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function useCreateGroup() {
|
|
46
|
+
const cache = useGroupCache();
|
|
47
|
+
return useMutation({
|
|
48
|
+
mutationFn: (v: { name: string; workspaceId: string | null }) =>
|
|
49
|
+
send<{ sessionGroup: SessionGroup }>("/api/session-groups", "POST", v),
|
|
50
|
+
onSuccess: ({ sessionGroup }) =>
|
|
51
|
+
cache.patch((old) => ({
|
|
52
|
+
...old,
|
|
53
|
+
sessionGroups: [...old.sessionGroups, sessionGroup],
|
|
54
|
+
})),
|
|
55
|
+
onError: (e: Error) => toast.error(e.message),
|
|
56
|
+
onSettled: cache.refresh,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function useUpdateGroup() {
|
|
61
|
+
const cache = useGroupCache();
|
|
62
|
+
return useMutation({
|
|
63
|
+
mutationFn: ({
|
|
64
|
+
id,
|
|
65
|
+
...patch
|
|
66
|
+
}: {
|
|
67
|
+
id: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
collapsed?: boolean;
|
|
70
|
+
}) => send(`/api/session-groups/${id}`, "PATCH", patch),
|
|
71
|
+
onMutate: ({ id, ...patch }) =>
|
|
72
|
+
cache.patch((old) => ({
|
|
73
|
+
...old,
|
|
74
|
+
sessionGroups: old.sessionGroups.map((g) =>
|
|
75
|
+
g.id === id ? { ...g, ...patch } : g
|
|
76
|
+
),
|
|
77
|
+
})),
|
|
78
|
+
onError: (e: Error, _v, ctx) => {
|
|
79
|
+
cache.restore(ctx?.previous);
|
|
80
|
+
toast.error(e.message);
|
|
81
|
+
},
|
|
82
|
+
onSettled: cache.refresh,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function useReorderGroups() {
|
|
87
|
+
const cache = useGroupCache();
|
|
88
|
+
return useMutation({
|
|
89
|
+
mutationFn: (v: { workspaceId: string | null; ids: string[] }) =>
|
|
90
|
+
send("/api/session-groups/order", "POST", v),
|
|
91
|
+
onMutate: ({ ids }) =>
|
|
92
|
+
cache.patch((old) => ({
|
|
93
|
+
...old,
|
|
94
|
+
sessionGroups: old.sessionGroups.map((g) =>
|
|
95
|
+
ids.includes(g.id) ? { ...g, sort_order: ids.indexOf(g.id) } : g
|
|
96
|
+
),
|
|
97
|
+
})),
|
|
98
|
+
onError: (e: Error, _v, ctx) => {
|
|
99
|
+
cache.restore(ctx?.previous);
|
|
100
|
+
toast.error(e.message);
|
|
101
|
+
},
|
|
102
|
+
onSettled: cache.refresh,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Deleting is soft: the toast's Undo restores the group and its members.
|
|
107
|
+
export function useDeleteGroup() {
|
|
108
|
+
const cache = useGroupCache();
|
|
109
|
+
return useMutation({
|
|
110
|
+
mutationFn: (g: { id: string; name: string }) =>
|
|
111
|
+
send(`/api/session-groups/${g.id}`, "DELETE"),
|
|
112
|
+
onMutate: (g) =>
|
|
113
|
+
cache.patch((old) => ({
|
|
114
|
+
...old,
|
|
115
|
+
sessionGroups: old.sessionGroups.filter((x) => x.id !== g.id),
|
|
116
|
+
})),
|
|
117
|
+
onSuccess: (_d, g) =>
|
|
118
|
+
toast(`Deleted group ${g.name}`, {
|
|
119
|
+
description: "Its sessions went back to the shelves.",
|
|
120
|
+
duration: 10_000,
|
|
121
|
+
action: {
|
|
122
|
+
label: "Undo",
|
|
123
|
+
onClick: () =>
|
|
124
|
+
send(`/api/session-groups/${g.id}/restore`, "POST")
|
|
125
|
+
.catch((e: Error) => toast.error(e.message))
|
|
126
|
+
.finally(cache.refresh),
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
onError: (e: Error, _v, ctx) => {
|
|
130
|
+
cache.restore(ctx?.previous);
|
|
131
|
+
toast.error(e.message);
|
|
132
|
+
},
|
|
133
|
+
onSettled: cache.refresh,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// One or many sessions into a group, or out of it with groupId null.
|
|
138
|
+
export function useAssignGroup() {
|
|
139
|
+
const cache = useGroupCache();
|
|
140
|
+
return useMutation({
|
|
141
|
+
mutationFn: (v: { ids: string[]; groupId: string | null }) =>
|
|
142
|
+
send("/api/sessions/group", "POST", v),
|
|
143
|
+
onMutate: ({ ids, groupId }) =>
|
|
144
|
+
cache.patch((old) => ({
|
|
145
|
+
...old,
|
|
146
|
+
sessions: old.sessions.map((s) =>
|
|
147
|
+
ids.includes(s.id) ? { ...s, session_group_id: groupId } : s
|
|
148
|
+
),
|
|
149
|
+
})),
|
|
150
|
+
onError: (e: Error, _v, ctx) => {
|
|
151
|
+
cache.restore(ctx?.previous);
|
|
152
|
+
toast.error(e.message);
|
|
153
|
+
},
|
|
154
|
+
onSettled: cache.refresh,
|
|
155
|
+
});
|
|
156
|
+
}
|
package/data/sessions/index.ts
CHANGED
package/data/sessions/pin.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
import type { Session
|
|
2
|
+
import type { Session } from "@/lib/db";
|
|
3
3
|
import { sessionKeys } from "./keys";
|
|
4
|
-
|
|
5
|
-
interface SessionsResponse {
|
|
6
|
-
sessions: Session[];
|
|
7
|
-
groups: Group[];
|
|
8
|
-
}
|
|
4
|
+
import type { SessionsResponse } from "./queries";
|
|
9
5
|
|
|
10
6
|
export function usePinSession() {
|
|
11
7
|
const queryClient = useQueryClient();
|
package/data/sessions/queries.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import { toast } from "sonner";
|
|
1
2
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
import type { Session
|
|
3
|
+
import type { Session } from "@/lib/db";
|
|
4
|
+
import type { SessionGroup } from "@/lib/sidebar/shelves";
|
|
3
5
|
import type { AgentType } from "@/lib/providers";
|
|
4
6
|
import type { ChatAccess, ChatFile, ChatImage } from "@/lib/chat/events";
|
|
5
7
|
import { sessionKeys } from "./keys";
|
|
6
8
|
import { usePollWhenOffline, usePushConnected } from "../push/connection";
|
|
7
9
|
|
|
8
|
-
interface SessionsResponse {
|
|
10
|
+
export interface SessionsResponse {
|
|
9
11
|
sessions: Session[];
|
|
10
|
-
|
|
12
|
+
sessionGroups: SessionGroup[];
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
async function fetchSessions(): Promise<SessionsResponse> {
|
|
@@ -128,31 +130,6 @@ export function useSummarizeSession() {
|
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
export function useMoveSessionToGroup() {
|
|
132
|
-
const queryClient = useQueryClient();
|
|
133
|
-
|
|
134
|
-
return useMutation({
|
|
135
|
-
mutationFn: async ({
|
|
136
|
-
sessionId,
|
|
137
|
-
groupPath,
|
|
138
|
-
}: {
|
|
139
|
-
sessionId: string;
|
|
140
|
-
groupPath: string;
|
|
141
|
-
}) => {
|
|
142
|
-
const res = await fetch(`/api/sessions/${sessionId}`, {
|
|
143
|
-
method: "PATCH",
|
|
144
|
-
headers: { "Content-Type": "application/json" },
|
|
145
|
-
body: JSON.stringify({ groupPath }),
|
|
146
|
-
});
|
|
147
|
-
if (!res.ok) throw new Error("Failed to move session");
|
|
148
|
-
return res.json();
|
|
149
|
-
},
|
|
150
|
-
onSuccess: () => {
|
|
151
|
-
queryClient.invalidateQueries({ queryKey: sessionKeys.list() });
|
|
152
|
-
},
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
133
|
export function useMoveSessionToProject() {
|
|
157
134
|
const queryClient = useQueryClient();
|
|
158
135
|
|
|
@@ -172,7 +149,11 @@ export function useMoveSessionToProject() {
|
|
|
172
149
|
if (!res.ok) throw new Error("Failed to move session");
|
|
173
150
|
return res.json();
|
|
174
151
|
},
|
|
175
|
-
onSuccess: () => {
|
|
152
|
+
onSuccess: (data: { clearedGroup?: string | null }) => {
|
|
153
|
+
if (data.clearedGroup)
|
|
154
|
+
toast(`Removed from ${data.clearedGroup}`, {
|
|
155
|
+
description: "Groups stay inside one workspace.",
|
|
156
|
+
});
|
|
176
157
|
queryClient.invalidateQueries({ queryKey: sessionKeys.list() });
|
|
177
158
|
},
|
|
178
159
|
});
|
|
@@ -195,6 +176,25 @@ export interface LaunchSessionInput {
|
|
|
195
176
|
prompt: string;
|
|
196
177
|
images?: ChatImage[];
|
|
197
178
|
files?: ChatFile[];
|
|
179
|
+
// Start in an agent role (lib/models/agent-roles): its binding picks the
|
|
180
|
+
// model, and `model` (when not blank) overrides it for this session.
|
|
181
|
+
agentRole?: string;
|
|
182
|
+
// The crew it joins: the session that began it.
|
|
183
|
+
crewId?: string;
|
|
184
|
+
// When the role's model is down, run on the role's fallback.
|
|
185
|
+
onUnavailable?: "fallback";
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// The role's model server isn't answering (HTTP 409): nothing was started.
|
|
189
|
+
export class ModelUnavailableError extends Error {
|
|
190
|
+
constructor(
|
|
191
|
+
message: string,
|
|
192
|
+
readonly role: string,
|
|
193
|
+
readonly ref: string,
|
|
194
|
+
readonly fallback: string | null
|
|
195
|
+
) {
|
|
196
|
+
super(message);
|
|
197
|
+
}
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
interface LaunchSessionResponse {
|
|
@@ -218,6 +218,13 @@ export function useLaunchSession() {
|
|
|
218
218
|
body: JSON.stringify(input),
|
|
219
219
|
});
|
|
220
220
|
const data = await res.json();
|
|
221
|
+
if (res.status === 409 && data.code === "model_unavailable")
|
|
222
|
+
throw new ModelUnavailableError(
|
|
223
|
+
data.error,
|
|
224
|
+
data.role,
|
|
225
|
+
data.ref,
|
|
226
|
+
data.fallback ?? null
|
|
227
|
+
);
|
|
221
228
|
if (!res.ok || data.error)
|
|
222
229
|
throw new Error(data.error ?? "Couldn't start");
|
|
223
230
|
return data;
|
package/data/sessions/shelf.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
import type { Session
|
|
2
|
+
import type { Session } from "@/lib/db";
|
|
3
3
|
import { toSqliteTime } from "@/lib/session-meta";
|
|
4
4
|
import { sessionKeys } from "./keys";
|
|
5
|
-
|
|
6
|
-
interface SessionsResponse {
|
|
7
|
-
sessions: Session[];
|
|
8
|
-
groups: Group[];
|
|
9
|
-
}
|
|
5
|
+
import type { SessionsResponse } from "./queries";
|
|
10
6
|
|
|
11
7
|
async function post(url: string, body: object) {
|
|
12
8
|
const res = await fetch(url, {
|
package/data/tasks/index.ts
CHANGED
|
@@ -47,6 +47,8 @@ export function useCreateTask() {
|
|
|
47
47
|
priority?: Priority;
|
|
48
48
|
baseBranch?: string;
|
|
49
49
|
hostId?: string;
|
|
50
|
+
// Queue behind other work: a task, or "claim:<id>".
|
|
51
|
+
after?: string;
|
|
50
52
|
view?: "chat" | "terminal";
|
|
51
53
|
}) =>
|
|
52
54
|
// Over the workspace's running task limit it's queued instead.
|
package/hooks/useSessions.ts
CHANGED
|
@@ -6,20 +6,17 @@ import {
|
|
|
6
6
|
useRenameSession,
|
|
7
7
|
useForkSession,
|
|
8
8
|
useSummarizeSession,
|
|
9
|
-
useMoveSessionToGroup,
|
|
10
9
|
useMoveSessionToProject,
|
|
11
10
|
} from "@/data/sessions";
|
|
12
11
|
|
|
13
12
|
export function useSessions() {
|
|
14
13
|
const { data, refetch } = useSessionsQuery();
|
|
15
14
|
const sessions = data?.sessions ?? [];
|
|
16
|
-
const groups = data?.groups ?? [];
|
|
17
15
|
|
|
18
16
|
const deleteMutation = useDeleteSession();
|
|
19
17
|
const renameMutation = useRenameSession();
|
|
20
18
|
const forkMutation = useForkSession();
|
|
21
19
|
const summarizeMutation = useSummarizeSession();
|
|
22
|
-
const moveToGroupMutation = useMoveSessionToGroup();
|
|
23
20
|
const moveToProjectMutation = useMoveSessionToProject();
|
|
24
21
|
|
|
25
22
|
const fetchSessions = useCallback(async () => {
|
|
@@ -61,13 +58,6 @@ export function useSessions() {
|
|
|
61
58
|
[summarizeMutation]
|
|
62
59
|
);
|
|
63
60
|
|
|
64
|
-
const moveSessionToGroup = useCallback(
|
|
65
|
-
async (sessionId: string, groupPath: string) => {
|
|
66
|
-
await moveToGroupMutation.mutateAsync({ sessionId, groupPath });
|
|
67
|
-
},
|
|
68
|
-
[moveToGroupMutation]
|
|
69
|
-
);
|
|
70
|
-
|
|
71
61
|
const moveSessionToProject = useCallback(
|
|
72
62
|
async (sessionId: string, projectId: string) => {
|
|
73
63
|
await moveToProjectMutation.mutateAsync({ sessionId, projectId });
|
|
@@ -77,7 +67,6 @@ export function useSessions() {
|
|
|
77
67
|
|
|
78
68
|
return {
|
|
79
69
|
sessions,
|
|
80
|
-
groups,
|
|
81
70
|
loaded: data !== undefined,
|
|
82
71
|
summarizingSessionId: summarizeMutation.isPending
|
|
83
72
|
? (summarizeMutation.variables as string)
|
|
@@ -88,7 +77,6 @@ export function useSessions() {
|
|
|
88
77
|
renameSession,
|
|
89
78
|
forkSession,
|
|
90
79
|
summarizeSession,
|
|
91
|
-
moveSessionToGroup,
|
|
92
80
|
moveSessionToProject,
|
|
93
81
|
};
|
|
94
82
|
}
|