@saadnvd1/agent-os 0.3.684 → 0.3.692

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 (130) hide show
  1. package/app/api/dev-servers/detect/route.ts +1 -2
  2. package/app/api/discovered-models/route.ts +34 -0
  3. package/app/api/projects/[id]/dev-servers/[dsId]/route.ts +2 -4
  4. package/app/page.tsx +1 -2
  5. package/components/Artifacts/ArtifactsPanel.tsx +1 -1
  6. package/components/Draft/DraftPanel.tsx +10 -2
  7. package/components/Draft/draftModels.test.ts +31 -0
  8. package/components/Draft/draftModels.ts +17 -0
  9. package/components/FileExplorer/FileTabs.tsx +1 -1
  10. package/components/Pane/DesktopTabBar.tsx +2 -2
  11. package/components/QuickSwitcher.tsx +24 -21
  12. package/components/SessionList/SessionRowMenu.tsx +0 -1
  13. package/components/Settings/ExperimentsSection.test.ts +7 -1
  14. package/components/Settings/NoApprovalsSection.test.ts +7 -1
  15. package/components/Terminal/TerminalToolbar.tsx +1 -1
  16. package/components/Terminal/VirtualKeyboard.tsx +1 -1
  17. package/components/WorkerCard.tsx +1 -7
  18. package/components/Workspaces/WorkspaceNameDialog.tsx +5 -3
  19. package/components/a/AButton.tsx +1 -6
  20. package/components/a/AIconButton.tsx +1 -5
  21. package/contexts/PaneContext.tsx +1 -6
  22. package/data/agents/index.ts +37 -0
  23. package/data/lumifyhub/index.ts +2 -4
  24. package/hooks/useDirectoryBrowser.ts +5 -4
  25. package/hooks/useDrawerAnimation.ts +11 -14
  26. package/hooks/useFileDrop.ts +2 -6
  27. package/hooks/useKeybarVisibility.ts +10 -29
  28. package/hooks/useSidebarPinned.ts +7 -23
  29. package/hooks/useSpeechRecognition.ts +19 -5
  30. package/hooks/useStoredFlag.ts +47 -0
  31. package/hooks/useViewport.ts +11 -17
  32. package/lib/approvals/no-approvals.ts +1 -7
  33. package/lib/artifacts/store.ts +1 -2
  34. package/lib/away/report.ts +1 -2
  35. package/lib/away/run.ts +1 -2
  36. package/lib/away/state.ts +1 -2
  37. package/lib/bookmarks/store.ts +1 -2
  38. package/lib/bus/delivery.ts +1 -2
  39. package/lib/bus/index.ts +1 -2
  40. package/lib/chat/compact-context.ts +1 -2
  41. package/lib/chat/discovered-models.ts +87 -0
  42. package/lib/chat/stop.ts +1 -2
  43. package/lib/chat/worker/host.ts +1 -1
  44. package/lib/code-health/reports.ts +1 -2
  45. package/lib/db/lumifyhub.ts +2 -4
  46. package/lib/db/schedules-move.ts +1 -2
  47. package/lib/db/session-parts/tasks.ts +1 -2
  48. package/lib/db/stacks.ts +3 -9
  49. package/lib/db/types.ts +1 -7
  50. package/lib/doctor/checks.ts +7 -9
  51. package/lib/done/archive.ts +1 -2
  52. package/lib/experiments/meter.ts +1 -7
  53. package/lib/health/env/classes.ts +0 -2
  54. package/lib/health/env/recordHit.ts +1 -2
  55. package/lib/health/spin.ts +1 -4
  56. package/lib/health/store.ts +1 -2
  57. package/lib/hosts/index.ts +1 -2
  58. package/lib/hosts/peer-sync.ts +2 -4
  59. package/lib/hosts/remote-api.ts +1 -2
  60. package/lib/lumifyhub/types.ts +2 -8
  61. package/lib/model-catalog.ts +9 -0
  62. package/lib/notify/index.ts +1 -2
  63. package/lib/notify/push/index.ts +2 -7
  64. package/lib/orchestrator/external-pr.ts +1 -2
  65. package/lib/orchestrator/gates.ts +1 -6
  66. package/lib/orchestrator/needs-you-items.ts +16 -20
  67. package/lib/orchestrator/pr-wake.ts +1 -2
  68. package/lib/orchestrator/rebase.ts +1 -2
  69. package/lib/orchestrator/review.ts +1 -2
  70. package/lib/orchestrator/usage.ts +1 -2
  71. package/lib/plans/claim.ts +1 -2
  72. package/lib/plans/features.ts +4 -11
  73. package/lib/plans/release.ts +2 -4
  74. package/lib/ports.ts +1 -2
  75. package/lib/program-status/records.ts +1 -1
  76. package/lib/project-config/database.ts +1 -2
  77. package/lib/projects.ts +1 -2
  78. package/lib/recipes/settle.ts +2 -4
  79. package/lib/recipes/store.ts +2 -4
  80. package/lib/schedules/store.ts +2 -4
  81. package/lib/search/conversations/backfill.ts +2 -4
  82. package/lib/security/auth.ts +1 -2
  83. package/lib/security/passkeys.ts +1 -2
  84. package/lib/security/presence.ts +1 -7
  85. package/lib/session-artifacts/types.ts +1 -8
  86. package/lib/session-audit/transcript.ts +1 -3
  87. package/lib/session-logs/index.ts +1 -2
  88. package/lib/sessions/launch.ts +13 -7
  89. package/lib/share/snapshot.ts +1 -7
  90. package/lib/share/store.ts +1 -2
  91. package/lib/sidebar/orchestrator-row.ts +1 -6
  92. package/lib/sidebar/row-menu.ts +1 -2
  93. package/lib/sidebar/shelves.ts +1 -6
  94. package/lib/simulator/index.ts +1 -2
  95. package/lib/simulator/lease.ts +1 -5
  96. package/lib/stacks/index.ts +1 -1
  97. package/lib/stacks/plan.ts +1 -1
  98. package/lib/stacks/restack.ts +1 -2
  99. package/lib/stacks/tick.ts +1 -2
  100. package/lib/status/socket.ts +1 -2
  101. package/lib/tasks/contract/authorize.ts +1 -2
  102. package/lib/tasks/contract/plan.ts +1 -2
  103. package/lib/tasks/contract/sync.ts +1 -2
  104. package/lib/tasks/holds.ts +1 -5
  105. package/lib/tasks/index.ts +1 -2
  106. package/lib/tasks/loop-types.ts +1 -6
  107. package/lib/tasks/move-guard.ts +1 -2
  108. package/lib/tasks/move.ts +1 -2
  109. package/lib/tasks/moved-away.ts +1 -2
  110. package/lib/tasks/pause-hold.ts +1 -2
  111. package/lib/tasks/pause.ts +3 -6
  112. package/lib/tasks/pr-activity.ts +1 -3
  113. package/lib/tasks/queue-rows.ts +2 -4
  114. package/lib/tasks/queue-types.ts +1 -5
  115. package/lib/tasks/queue.ts +1 -2
  116. package/lib/tasks/refresh-base.ts +1 -2
  117. package/lib/tasks/start.ts +2 -4
  118. package/lib/tasks/starter.ts +1 -2
  119. package/lib/tasks/state.ts +1 -6
  120. package/lib/theme-config.ts +1 -8
  121. package/lib/updates/banner.ts +1 -6
  122. package/lib/updates/run.ts +1 -2
  123. package/lib/usage/aggregate.ts +1 -1
  124. package/lib/usage/nightly.ts +1 -2
  125. package/lib/usage/rate-limits.ts +1 -2
  126. package/lib/usage/turns.ts +1 -2
  127. package/lib/usage/windows.ts +5 -7
  128. package/lib/workspaces.ts +1 -2
  129. package/lib/worktree-sweep/databases.ts +0 -1
  130. package/package.json +3 -3
@@ -41,8 +41,7 @@ export { remotePlanPath };
41
41
 
42
42
  const getSession = (id: string) =>
43
43
  db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
44
- | Session
45
- | undefined;
44
+ Session | undefined;
46
45
 
47
46
  async function readCopy(id: string): Promise<string | null> {
48
47
  try {
@@ -33,8 +33,7 @@ const FINISHED: Record<string, TaskStatus> = {
33
33
 
34
34
  const getSession = (id: string) =>
35
35
  db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
36
- | Session
37
- | undefined;
36
+ Session | undefined;
38
37
 
39
38
  // The plan-written line a held task stored on its machine (plan-step.ts),
40
39
  // once per distinct plan: the mirror keeps the last one it told about.
@@ -56,11 +56,7 @@ export interface MachineView {
56
56
  }
57
57
 
58
58
  export type MachineCode =
59
- | "needs"
60
- | "load_red"
61
- | "load_amber"
62
- | "heavy"
63
- | "spacing";
59
+ "needs" | "load_red" | "load_amber" | "heavy" | "spacing";
64
60
 
65
61
  // A reason a task isn't starting. `code` is also what a queue row stores and
66
62
  // the client reads. A hold that rests on a machine says which one, and when
@@ -447,8 +447,7 @@ export async function shellOnly(tmuxName: string): Promise<boolean> {
447
447
 
448
448
  // A chat's turn as its worker says: "unknown" when it can't be reached.
449
449
  type ChatTurn =
450
- | NonNullable<Awaited<ReturnType<typeof chatStateNow>>>
451
- | "unknown";
450
+ NonNullable<Awaited<ReturnType<typeof chatStateNow>>> | "unknown";
452
451
 
453
452
  // A chat between turns waits on the next message, as a terminal at its
454
453
  // prompt does. One whose worker can't be reached counts as busy.
@@ -100,12 +100,7 @@ export interface TaskDiffPatch {
100
100
  // -- Checks and the review verdict ----------------------------------------
101
101
 
102
102
  export type CheckState =
103
- | "pass"
104
- | "fail"
105
- | "pending"
106
- | "skipped"
107
- | "cancelled"
108
- | "neutral";
103
+ "pass" | "fail" | "pending" | "skipped" | "cancelled" | "neutral";
109
104
 
110
105
  export interface TaskCheck {
111
106
  name: string;
@@ -52,8 +52,7 @@ export function moveRefusal(session: Session): string | null {
52
52
  FROM session_rows s WHERE id = ?`
53
53
  )
54
54
  .get(session.id) as
55
- | { lh_card_id: string | null; stacked: number }
56
- | undefined;
55
+ { lh_card_id: string | null; stacked: number } | undefined;
57
56
  if (row?.lh_card_id) return "Card tasks run on this machine only for now";
58
57
  if (row?.stacked) return "Stacked tasks run on this machine only for now";
59
58
  return null;
package/lib/tasks/move.ts CHANGED
@@ -127,8 +127,7 @@ function orchestratorOf(
127
127
  const by = starterOrchestrator(session.started_by);
128
128
  if (!by) return undefined;
129
129
  const o = db.prepare(`SELECT name FROM sessions WHERE id = ?`).get(by) as
130
- | { name: string }
131
- | undefined;
130
+ { name: string } | undefined;
132
131
  return o ? { id: by, name: o.name } : undefined;
133
132
  }
134
133
 
@@ -14,8 +14,7 @@ import { archiveSession } from "../done/archive";
14
14
 
15
15
  export async function cleanUpMovedAway(id: string): Promise<WorktreeFate> {
16
16
  const s = db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
17
- | Session
18
- | undefined;
17
+ Session | undefined;
19
18
  if (!s || s.task_status !== "moved" || !s.held_by_device)
20
19
  return { action: "none" };
21
20
  await endSessionAgent(s).catch((err) =>
@@ -16,8 +16,7 @@ export function pauseHoldOf(sessionId: string): PauseHold | null {
16
16
  WHERE id = ? AND pause_state IN ('pausing', 'paused') AND pause_id IS NOT NULL`
17
17
  )
18
18
  .get(sessionId) as
19
- | { pause_id: number; paused_until: string | null }
20
- | undefined;
19
+ { pause_id: number; paused_until: string | null } | undefined;
21
20
  return row ? { pauseId: row.pause_id, until: row.paused_until } : null;
22
21
  }
23
22
 
@@ -74,13 +74,11 @@ const nudge = () =>
74
74
 
75
75
  const sessionOf = (id: string) =>
76
76
  db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
77
- | Session
78
- | undefined;
77
+ Session | undefined;
79
78
 
80
79
  const pauseRow = (id: number) =>
81
80
  db.prepare(`SELECT * FROM task_pauses WHERE id = ?`).get(id) as
82
- | TaskPause
83
- | undefined;
81
+ TaskPause | undefined;
84
82
 
85
83
  // SQLite's datetime('now') is UTC without a zone.
86
84
  const ms = (v: string | null | undefined) =>
@@ -400,8 +398,7 @@ export function setPauseNote(sessionId: string, note: string | null): void {
400
398
  }
401
399
 
402
400
  export type ResumeOutcome =
403
- | { outcome: "resumed" | "cancelled" }
404
- | { outcome: "held"; note: string };
401
+ { outcome: "resumed" | "cancelled" } | { outcome: "held"; note: string };
405
402
 
406
403
  // A deliberate Resume, by a person or the orchestrator: starts at once, past
407
404
  // the slot limit, like Start now. A machine in the red still holds it: it is
@@ -59,9 +59,7 @@ export async function fingerprints(
59
59
  );
60
60
  for (const n of prs) {
61
61
  const pr = res.data?.repository?.[`p${n}`] as
62
- | { createdAt: string; reviews: Last; comments: Last }
63
- | null
64
- | undefined;
62
+ { createdAt: string; reviews: Last; comments: Last } | null | undefined;
65
63
  if (!pr) continue;
66
64
  const part = (l: Last) => `${l.totalCount}:${l.nodes[0]?.id ?? ""}`;
67
65
  out.set(n, {
@@ -14,13 +14,11 @@ export const IN_FLIGHT = ["running", "moving"];
14
14
 
15
15
  export const row = (id: string) =>
16
16
  db.prepare(`SELECT * FROM task_queue WHERE id = ?`).get(id) as
17
- | QueueRow
18
- | undefined;
17
+ QueueRow | undefined;
19
18
 
20
19
  export const sessionOf = (id: string) =>
21
20
  db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
22
- | Session
23
- | undefined;
21
+ Session | undefined;
24
22
 
25
23
  export function patch(id: string, fields: Partial<QueueRow>): void {
26
24
  const keys = Object.keys(fields);
@@ -6,11 +6,7 @@ import type { Priority, WaitCode } from "./schedule-types";
6
6
  import type { StartVia } from "./starter";
7
7
 
8
8
  export type QueueStatus =
9
- | "queued"
10
- | "starting"
11
- | "started"
12
- | "failed"
13
- | "removed";
9
+ "queued" | "starting" | "started" | "failed" | "removed";
14
10
 
15
11
  export interface QueueRow {
16
12
  id: string;
@@ -313,8 +313,7 @@ export function moveQueued(id: string, by: -1 | 1): void {
313
313
  ORDER BY q.position ${by < 0 ? "DESC" : "ASC"} LIMIT 1`
314
314
  )
315
315
  .get({ position: r.position, ws: workspaceId, project: r.project_id }) as
316
- | QueueRow
317
- | undefined;
316
+ QueueRow | undefined;
318
317
  if (!other) return;
319
318
  patch(r.id, { position: other.position });
320
319
  patch(other.id, { position: r.position });
@@ -16,8 +16,7 @@ import { restackBranch, outputOf, type Runner } from "../stacks/git";
16
16
  import { run } from "./gh";
17
17
 
18
18
  export type RefreshResult =
19
- | { moved: false; note?: string }
20
- | { moved: true; how: "reset" | "rebase" };
19
+ { moved: false; note?: string } | { moved: true; how: "reset" | "rebase" };
21
20
 
22
21
  export interface RefreshTarget {
23
22
  name: string;
@@ -60,8 +60,7 @@ export function launchHold(sessionId: string): string | null {
60
60
  LIMIT 1`
61
61
  )
62
62
  .get(sessionId, sessionId, sessionId) as
63
- | { workspace_id: string }
64
- | undefined;
63
+ { workspace_id: string } | undefined;
65
64
  if (!row) return null;
66
65
  if (isPaused(row.workspace_id)) return "the orchestrator is paused by Saad";
67
66
  const window = brakesEnabled() ? windowRefusal(readUsage()) : null;
@@ -135,8 +134,7 @@ export async function finishTaskStart(
135
134
  const now = db
136
135
  .prepare(`SELECT task_status, archived_at FROM session_rows WHERE id = ?`)
137
136
  .get(sessionId) as
138
- | { task_status: string | null; archived_at: string | null }
139
- | undefined;
137
+ { task_status: string | null; archived_at: string | null } | undefined;
140
138
  if (now?.task_status !== "running" || now.archived_at)
141
139
  return done({
142
140
  status: "failed",
@@ -102,8 +102,7 @@ export function orchestratorOf(startedBy: string | null | undefined) {
102
102
  const row = db
103
103
  .prepare(`SELECT role, started_by FROM sessions WHERE id = ?`)
104
104
  .get(id) as
105
- | { role: string | null; started_by: string | null }
106
- | undefined;
105
+ { role: string | null; started_by: string | null } | undefined;
107
106
  if (!row) return null;
108
107
  if (row.role === "orchestrator") return id;
109
108
  id = row.started_by;
@@ -1,12 +1,7 @@
1
1
  import type { AttributionKind } from "./code-review";
2
2
 
3
3
  export type TaskStatus =
4
- | "running"
5
- | "merged"
6
- | "dropped"
7
- | "done"
8
- | "moving"
9
- | "moved";
4
+ "running" | "merged" | "dropped" | "done" | "moving" | "moved";
10
5
 
11
6
  export type ChecksVerdict = "pass" | "fail" | "pending" | "none";
12
7
 
@@ -30,14 +30,7 @@ export type DarkThemeVariant =
30
30
  | "ocean"
31
31
  | "mocha";
32
32
  export type LightThemeVariant =
33
- | "default"
34
- | "warm"
35
- | "cool"
36
- | "soft"
37
- | "rose"
38
- | "lavender"
39
- | "mint"
40
- | "peach";
33
+ "default" | "warm" | "cool" | "soft" | "rose" | "lavender" | "mint" | "peach";
41
34
  export type Theme =
42
35
  | "light"
43
36
  | `light-${LightThemeVariant}`
@@ -68,12 +68,7 @@ export interface UpdateView {
68
68
  }
69
69
 
70
70
  export type BannerState =
71
- | "hidden"
72
- | "available"
73
- | "pending"
74
- | "running"
75
- | "failed"
76
- | "built";
71
+ "hidden" | "available" | "pending" | "running" | "failed" | "built";
77
72
 
78
73
  export const DISMISSED_VERSION_KEY = "agentos.update.dismissed";
79
74
  export const DISMISSED_RUN_KEY = "agentos.update.dismissedRun";
@@ -264,8 +264,7 @@ export async function preflight(
264
264
  // ── starting ─────────────────────────────────────────────────────────────
265
265
 
266
266
  export type StartResult =
267
- | { ok: true; pending: boolean }
268
- | ({ ok: false } & Refusal);
267
+ { ok: true; pending: boolean } | ({ ok: false } & Refusal);
269
268
 
270
269
  /** Takes the right to start, atomically, so two requests can't both run. */
271
270
  function claimStart(deps: Pick<RunDeps, "stateFile" | "now">): boolean {
@@ -76,7 +76,7 @@ export function aggregateUsage(
76
76
  const since = rangeStart(range, now);
77
77
  const total = acc();
78
78
  const days = new Map<string, Acc>();
79
- for (let t = since; t <= now; ) {
79
+ for (let t = since; t <= now;) {
80
80
  days.set(dayKey(t), acc());
81
81
  const next = new Date(t);
82
82
  next.setDate(next.getDate() + 1);
@@ -45,8 +45,7 @@ const addDays = (day: string, n: number) =>
45
45
 
46
46
  function setting(key: string): string | null {
47
47
  const r = db.prepare(`SELECT value FROM settings WHERE key = ?`).get(key) as
48
- | { value: string }
49
- | undefined;
48
+ { value: string } | undefined;
50
49
  return r?.value ?? null;
51
50
  }
52
51
 
@@ -160,8 +160,7 @@ export function lastReading(
160
160
  WHERE window = ? AND at <= ? ORDER BY at DESC, id DESC LIMIT 1`
161
161
  )
162
162
  .get(window, before) as
163
- | { at: number; utilization: number; resets_at: number | null }
164
- | undefined;
163
+ { at: number; utilization: number; resets_at: number | null } | undefined;
165
164
  return r
166
165
  ? { at: r.at, utilization: r.utilization, resetsAt: r.resets_at }
167
166
  : null;
@@ -111,8 +111,7 @@ export function recordCompaction(
111
111
  const current = db
112
112
  .prepare(`SELECT name, workspace_id FROM sessions WHERE id = ?`)
113
113
  .get(session.id) as
114
- | { name: string; workspace_id: string | null }
115
- | undefined;
114
+ { name: string; workspace_id: string | null } | undefined;
116
115
  db.prepare(
117
116
  `INSERT INTO chat_compactions (session_id, session_name, workspace_id, at, trigger, phase, before_tokens, after_tokens)
118
117
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
@@ -101,13 +101,11 @@ async function planLimits(): Promise<Cached> {
101
101
  if (cache && Date.now() - cache.at < TTL_MS) return cache;
102
102
  inflight ??= askAgent()
103
103
  .then((limits): Cached => ({ at: Date.now(), limits }))
104
- .catch(
105
- (error: unknown): Cached => ({
106
- at: Date.now(),
107
- limits: null,
108
- error: error instanceof Error ? error.message : String(error),
109
- })
110
- )
104
+ .catch((error: unknown): Cached => ({
105
+ at: Date.now(),
106
+ limits: null,
107
+ error: error instanceof Error ? error.message : String(error),
108
+ }))
111
109
  .then((c) => (cache = c))
112
110
  .finally(() => {
113
111
  inflight = null;
package/lib/workspaces.ts CHANGED
@@ -53,8 +53,7 @@ export function listWorkspaces(): Workspace[] {
53
53
 
54
54
  export function getWorkspace(id: string): Workspace | null {
55
55
  const row = db.prepare(`SELECT * FROM workspaces WHERE id = ?`).get(id) as
56
- | WorkspaceRow
57
- | undefined;
56
+ WorkspaceRow | undefined;
58
57
  return row ? toWorkspace(row) : null;
59
58
  }
60
59
 
@@ -22,7 +22,6 @@ import { loadProjectConfig } from "../project-config";
22
22
  import { expandHome } from "../project-config/session";
23
23
  import {
24
24
  LOCAL_HOSTS,
25
- MARK,
26
25
  SOCKET_DIR,
27
26
  pgEnv,
28
27
  pgRun,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saadnvd1/agent-os",
3
- "version": "0.3.684",
3
+ "version": "0.3.692",
4
4
  "description": "Self-hosted web UI for managing Claude Code sessions",
5
5
  "bin": {
6
6
  "agent-os": "scripts/agent-os"
@@ -157,7 +157,7 @@
157
157
  },
158
158
  "devDependencies": {
159
159
  "@tailwindcss/postcss": "^4.1.18",
160
- "@types/better-sqlite3": "^7.6.13",
160
+ "@types/better-sqlite3": "^9.6.0",
161
161
  "@types/hast": "^3.0.4",
162
162
  "@types/jsdom": "^30.0.0",
163
163
  "@types/mdast": "^4.0.4",
@@ -171,7 +171,7 @@
171
171
  "husky": "^9.1.7",
172
172
  "jsdom": "^30.1.2",
173
173
  "prettier": "^3.7.4",
174
- "prettier-plugin-tailwindcss": "^0.7.2",
174
+ "prettier-plugin-tailwindcss": "^0.8.1",
175
175
  "remark-parse": "^11.0.0",
176
176
  "sharp": "^0.35.5",
177
177
  "tailwindcss": "^4.1.18",