@saadnvd1/agent-os 0.3.836 → 0.3.839

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 (54) hide show
  1. package/app/api/fresh-start/route.test.ts +33 -0
  2. package/app/api/fresh-start/route.ts +3 -0
  3. package/components/Devices/DeviceRow.tsx +83 -69
  4. package/components/Devices/PasskeysSection.test.ts +89 -0
  5. package/components/Devices/PasskeysSection.tsx +36 -26
  6. package/components/Health/HealthPanel.tsx +41 -16
  7. package/components/Merge/GlobalMergeSection.tsx +2 -5
  8. package/components/Merge/MergeSettingsFields.tsx +39 -77
  9. package/components/Merge/ProjectMergeSection.tsx +2 -6
  10. package/components/Merge/WorktreeSweepSection.tsx +40 -14
  11. package/components/Models/AgentRoleCard.tsx +61 -66
  12. package/components/Models/AgentRolesSection.tsx +5 -8
  13. package/components/Models/ModelsSection.tsx +7 -18
  14. package/components/Models/PriceInput.tsx +59 -0
  15. package/components/PhoneNotify/PhoneNotifyForm.tsx +37 -58
  16. package/components/Settings/AppWideLimits.tsx +61 -0
  17. package/components/Settings/ContextSection.tsx +96 -0
  18. package/components/Settings/ExperimentsSection.test.ts +9 -7
  19. package/components/Settings/ExperimentsSection.tsx +22 -23
  20. package/components/Settings/InlineConfirm.tsx +51 -0
  21. package/components/Settings/OwnerNameRow.tsx +10 -40
  22. package/components/Settings/PickerSetting.tsx +59 -0
  23. package/components/Settings/SettingRow.tsx +131 -0
  24. package/components/Settings/SettingsDialog.test.ts +1 -0
  25. package/components/Settings/SettingsDialog.tsx +47 -2
  26. package/components/Settings/settings-fields.test.ts +103 -0
  27. package/components/Settings/settings-fields.tsx +427 -0
  28. package/components/Shares/SharedLinksPanel.tsx +62 -53
  29. package/components/Workspaces/HqFolderForm.tsx +21 -54
  30. package/components/Workspaces/McpServersForm.tsx +20 -19
  31. package/components/Workspaces/ProjectTiersForm.tsx +10 -8
  32. package/components/Workspaces/RulesForm.test.ts +127 -0
  33. package/components/Workspaces/RulesForm.tsx +54 -126
  34. package/components/Workspaces/WorkspaceModelsForm.tsx +27 -26
  35. package/components/Workspaces/WorkspaceSettings.tsx +61 -24
  36. package/content/whats-new.json +16 -0
  37. package/data/fresh-start/index.ts +1 -1
  38. package/data/workspaces/index.ts +9 -0
  39. package/hooks/useAutoSave.test.ts +116 -0
  40. package/hooks/useAutoSave.ts +98 -0
  41. package/lib/away/window-limits.ts +3 -1
  42. package/lib/chat/refresh.ts +10 -6
  43. package/lib/chat/stall-limits.ts +3 -1
  44. package/lib/settings/defaults.ts +27 -0
  45. package/lib/settings/parse.ts +17 -0
  46. package/lib/settings-url.ts +1 -0
  47. package/lib/worktree-sweep/limits.ts +3 -0
  48. package/lib/worktree-sweep/settings.ts +4 -2
  49. package/package.json +1 -1
  50. package/components/Away/AwayWindowForm.tsx +0 -91
  51. package/components/Workspaces/FreshStartForm.tsx +0 -177
  52. package/components/Workspaces/StallForm.tsx +0 -101
  53. package/components/Workspaces/TaskLimitForm.tsx +0 -84
  54. package/components/Workspaces/fresh-start.ts +0 -19
@@ -1,101 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { toast } from "sonner";
5
- import { Button } from "@/components/ui/button";
6
- import { Input } from "@/components/ui/input";
7
- import { Switch } from "@/components/ui/switch";
8
- import { useStallQuery, useUpdateStall } from "@/data/stall";
9
- import {
10
- DEFAULT_STALL_MINUTES,
11
- MAX_STALL_MINUTES,
12
- MIN_STALL_MINUTES,
13
- } from "@/lib/chat/stall-limits";
14
-
15
- // How long a turn may produce nothing before it's flagged stalled and the
16
- // workspace's orchestrator is told: app-wide.
17
- export function StallForm() {
18
- const { data, isPending, isError, error } = useStallQuery();
19
- if (isPending)
20
- return <div className="bg-muted/40 h-24 animate-pulse rounded-lg" />;
21
- if (isError)
22
- return <p className="text-destructive text-sm">{error.message}</p>;
23
- return <Form key={data.minutes} saved={data.minutes} />;
24
- }
25
-
26
- function Form({ saved }: { saved: number }) {
27
- const update = useUpdateStall();
28
- const [on, setOn] = useState(saved > 0);
29
- const [text, setText] = useState(
30
- String(saved > 0 ? saved : DEFAULT_STALL_MINUTES)
31
- );
32
- const n = Number(text);
33
- const valid =
34
- Number.isInteger(n) && n >= MIN_STALL_MINUTES && n <= MAX_STALL_MINUTES;
35
- const minutes = on ? n : 0;
36
- const error =
37
- on && !valid
38
- ? `Between ${MIN_STALL_MINUTES} and ${MAX_STALL_MINUTES} minutes`
39
- : null;
40
- const dirty = !error && minutes !== saved;
41
-
42
- return (
43
- <form
44
- onSubmit={(e) => {
45
- e.preventDefault();
46
- if (error) return;
47
- update.mutate(minutes, {
48
- onSuccess: () => toast.success("Stall alert saved"),
49
- onError: (err) => toast.error(err.message),
50
- });
51
- }}
52
- className="bg-muted/40 space-y-3 rounded-lg px-3 py-3"
53
- >
54
- <h3 className="text-sm font-medium">Stalled turns</h3>
55
- <p className="text-muted-foreground text-sm">
56
- A turn that produces nothing for this long (no text, tool call or
57
- result) shows as stalled, and the workspace&apos;s orchestrator is told
58
- once. A long command that is still printing, or a background command the
59
- agent is waiting on, isn&apos;t a stall.
60
- </p>
61
- <label className="flex min-h-11 items-center justify-between gap-3 text-sm md:min-h-9">
62
- Flag stalled turns
63
- <Switch
64
- checked={on}
65
- onCheckedChange={setOn}
66
- aria-label="Flag stalled turns"
67
- />
68
- </label>
69
- {on && (
70
- <label className="flex items-center justify-between gap-3 text-sm">
71
- <span className="text-muted-foreground">After</span>
72
- <span className="flex items-center gap-2">
73
- <Input
74
- type="number"
75
- inputMode="numeric"
76
- min={MIN_STALL_MINUTES}
77
- max={MAX_STALL_MINUTES}
78
- value={text}
79
- onChange={(e) => setText(e.target.value)}
80
- aria-label="Stall threshold, minutes"
81
- aria-invalid={!!error}
82
- className="h-11 w-24 text-base sm:h-9 md:text-sm"
83
- />
84
- <span className="text-muted-foreground">minutes</span>
85
- </span>
86
- </label>
87
- )}
88
- {error && <p className="text-destructive text-xs">{error}</p>}
89
- <div className="flex justify-end">
90
- <Button
91
- type="submit"
92
- size="sm"
93
- className="h-11 sm:h-8"
94
- disabled={!!error || !dirty || update.isPending}
95
- >
96
- Save
97
- </Button>
98
- </div>
99
- </form>
100
- );
101
- }
@@ -1,84 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { toast } from "sonner";
5
- import { Button } from "@/components/ui/button";
6
- import { Input } from "@/components/ui/input";
7
- import { Switch } from "@/components/ui/switch";
8
- import type { Workspace } from "@/lib/db";
9
- import { useUpdateWorkspace } from "@/data/workspaces";
10
- import { parseTaskLimit } from "./task-limit";
11
-
12
- // How many tasks the workspace runs at once. Off by default; over the limit
13
- // a new task is queued and starts by itself when one finishes.
14
- export function TaskLimitForm({ workspace }: { workspace: Workspace }) {
15
- const update = useUpdateWorkspace();
16
- const current = workspace.max_running_tasks;
17
- const [on, setOn] = useState(current !== null);
18
- const [text, setText] = useState(String(current ?? 3));
19
- const parsed = parseTaskLimit(on, text);
20
- const dirty = !("error" in parsed) && parsed.limit !== current;
21
-
22
- return (
23
- <form
24
- onSubmit={(e) => {
25
- e.preventDefault();
26
- if ("error" in parsed) return;
27
- update.mutate(
28
- { id: workspace.id, maxRunningTasks: parsed.limit },
29
- {
30
- onSuccess: () =>
31
- toast.success(
32
- parsed.limit
33
- ? `Up to ${parsed.limit} tasks run at once`
34
- : "No running task limit"
35
- ),
36
- onError: (error) => toast.error(error.message),
37
- }
38
- );
39
- }}
40
- className="space-y-4"
41
- >
42
- <label className="flex min-h-11 items-center justify-between gap-3 text-sm md:min-h-9">
43
- Limit running tasks
44
- <Switch
45
- checked={on}
46
- onCheckedChange={setOn}
47
- aria-label="Limit running tasks"
48
- />
49
- </label>
50
- {on && (
51
- <label className="flex items-center justify-between gap-3 text-sm">
52
- <span>At most</span>
53
- <span className="flex items-center gap-2">
54
- <Input
55
- type="number"
56
- inputMode="numeric"
57
- min={1}
58
- step={1}
59
- value={text}
60
- onChange={(e) => setText(e.target.value)}
61
- aria-label="Running task limit"
62
- aria-invalid={"error" in parsed}
63
- className="h-11 w-20 text-base sm:h-9 md:text-sm"
64
- />
65
- <span className="text-muted-foreground">at a time</span>
66
- </span>
67
- </label>
68
- )}
69
- {"error" in parsed && (
70
- <p className="text-destructive text-xs">{parsed.error}</p>
71
- )}
72
- <div className="flex justify-end">
73
- <Button
74
- type="submit"
75
- size="sm"
76
- className="h-11 sm:h-8"
77
- disabled={"error" in parsed || !dirty || update.isPending}
78
- >
79
- Save
80
- </Button>
81
- </div>
82
- </form>
83
- );
84
- }
@@ -1,19 +0,0 @@
1
- import {
2
- MAX_REFRESH_TOKENS,
3
- MIN_REFRESH_TOKENS,
4
- } from "@/lib/chat/refresh-limits";
5
-
6
- // A threshold's input, in thousands of tokens: off is 0; on takes a whole
7
- // number in the range the server holds (lib/chat/refresh).
8
- export function parseFreshStart(
9
- on: boolean,
10
- text: string
11
- ): { tokens: number } | { error: string } {
12
- if (!on) return { tokens: 0 };
13
- const k = Number(text.trim());
14
- const min = MIN_REFRESH_TOKENS / 1000;
15
- const max = MAX_REFRESH_TOKENS / 1000;
16
- if (!text.trim() || !Number.isInteger(k) || k < min || k > max)
17
- return { error: `A whole number from ${min} to ${max}` };
18
- return { tokens: k * 1000 };
19
- }