@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.
- package/app/api/dev-servers/detect/route.ts +1 -2
- package/app/api/discovered-models/route.ts +34 -0
- package/app/api/projects/[id]/dev-servers/[dsId]/route.ts +2 -4
- package/app/page.tsx +1 -2
- package/components/Artifacts/ArtifactsPanel.tsx +1 -1
- package/components/Draft/DraftPanel.tsx +10 -2
- package/components/Draft/draftModels.test.ts +31 -0
- package/components/Draft/draftModels.ts +17 -0
- package/components/FileExplorer/FileTabs.tsx +1 -1
- package/components/Pane/DesktopTabBar.tsx +2 -2
- package/components/QuickSwitcher.tsx +24 -21
- package/components/SessionList/SessionRowMenu.tsx +0 -1
- package/components/Settings/ExperimentsSection.test.ts +7 -1
- package/components/Settings/NoApprovalsSection.test.ts +7 -1
- package/components/Terminal/TerminalToolbar.tsx +1 -1
- package/components/Terminal/VirtualKeyboard.tsx +1 -1
- package/components/WorkerCard.tsx +1 -7
- package/components/Workspaces/WorkspaceNameDialog.tsx +5 -3
- package/components/a/AButton.tsx +1 -6
- package/components/a/AIconButton.tsx +1 -5
- package/contexts/PaneContext.tsx +1 -6
- package/data/agents/index.ts +37 -0
- package/data/lumifyhub/index.ts +2 -4
- package/hooks/useDirectoryBrowser.ts +5 -4
- package/hooks/useDrawerAnimation.ts +11 -14
- package/hooks/useFileDrop.ts +2 -6
- package/hooks/useKeybarVisibility.ts +10 -29
- package/hooks/useSidebarPinned.ts +7 -23
- package/hooks/useSpeechRecognition.ts +19 -5
- package/hooks/useStoredFlag.ts +47 -0
- package/hooks/useViewport.ts +11 -17
- package/lib/approvals/no-approvals.ts +1 -7
- package/lib/artifacts/store.ts +1 -2
- package/lib/away/report.ts +1 -2
- package/lib/away/run.ts +1 -2
- package/lib/away/state.ts +1 -2
- package/lib/bookmarks/store.ts +1 -2
- package/lib/bus/delivery.ts +1 -2
- package/lib/bus/index.ts +1 -2
- package/lib/chat/compact-context.ts +1 -2
- package/lib/chat/discovered-models.ts +87 -0
- package/lib/chat/stop.ts +1 -2
- package/lib/chat/worker/host.ts +1 -1
- package/lib/code-health/reports.ts +1 -2
- package/lib/db/lumifyhub.ts +2 -4
- package/lib/db/schedules-move.ts +1 -2
- package/lib/db/session-parts/tasks.ts +1 -2
- package/lib/db/stacks.ts +3 -9
- package/lib/db/types.ts +1 -7
- package/lib/doctor/checks.ts +7 -9
- package/lib/done/archive.ts +1 -2
- package/lib/experiments/meter.ts +1 -7
- package/lib/health/env/classes.ts +0 -2
- package/lib/health/env/recordHit.ts +1 -2
- package/lib/health/spin.ts +1 -4
- package/lib/health/store.ts +1 -2
- package/lib/hosts/index.ts +1 -2
- package/lib/hosts/peer-sync.ts +2 -4
- package/lib/hosts/remote-api.ts +1 -2
- package/lib/lumifyhub/types.ts +2 -8
- package/lib/model-catalog.ts +9 -0
- package/lib/notify/index.ts +1 -2
- package/lib/notify/push/index.ts +2 -7
- package/lib/orchestrator/external-pr.ts +1 -2
- package/lib/orchestrator/gates.ts +1 -6
- package/lib/orchestrator/needs-you-items.ts +16 -20
- package/lib/orchestrator/pr-wake.ts +1 -2
- package/lib/orchestrator/rebase.ts +1 -2
- package/lib/orchestrator/review.ts +1 -2
- package/lib/orchestrator/usage.ts +1 -2
- package/lib/plans/claim.ts +1 -2
- package/lib/plans/features.ts +4 -11
- package/lib/plans/release.ts +2 -4
- package/lib/ports.ts +1 -2
- package/lib/program-status/records.ts +1 -1
- package/lib/project-config/database.ts +1 -2
- package/lib/projects.ts +1 -2
- package/lib/recipes/settle.ts +2 -4
- package/lib/recipes/store.ts +2 -4
- package/lib/schedules/store.ts +2 -4
- package/lib/search/conversations/backfill.ts +2 -4
- package/lib/security/auth.ts +1 -2
- package/lib/security/passkeys.ts +1 -2
- package/lib/security/presence.ts +1 -7
- package/lib/session-artifacts/types.ts +1 -8
- package/lib/session-audit/transcript.ts +1 -3
- package/lib/session-logs/index.ts +1 -2
- package/lib/sessions/launch.ts +13 -7
- package/lib/share/snapshot.ts +1 -7
- package/lib/share/store.ts +1 -2
- package/lib/sidebar/orchestrator-row.ts +1 -6
- package/lib/sidebar/row-menu.ts +1 -2
- package/lib/sidebar/shelves.ts +1 -6
- package/lib/simulator/index.ts +1 -2
- package/lib/simulator/lease.ts +1 -5
- package/lib/stacks/index.ts +1 -1
- package/lib/stacks/plan.ts +1 -1
- package/lib/stacks/restack.ts +1 -2
- package/lib/stacks/tick.ts +1 -2
- package/lib/status/socket.ts +1 -2
- package/lib/tasks/contract/authorize.ts +1 -2
- package/lib/tasks/contract/plan.ts +1 -2
- package/lib/tasks/contract/sync.ts +1 -2
- package/lib/tasks/holds.ts +1 -5
- package/lib/tasks/index.ts +1 -2
- package/lib/tasks/loop-types.ts +1 -6
- package/lib/tasks/move-guard.ts +1 -2
- package/lib/tasks/move.ts +1 -2
- package/lib/tasks/moved-away.ts +1 -2
- package/lib/tasks/pause-hold.ts +1 -2
- package/lib/tasks/pause.ts +3 -6
- package/lib/tasks/pr-activity.ts +1 -3
- package/lib/tasks/queue-rows.ts +2 -4
- package/lib/tasks/queue-types.ts +1 -5
- package/lib/tasks/queue.ts +1 -2
- package/lib/tasks/refresh-base.ts +1 -2
- package/lib/tasks/start.ts +2 -4
- package/lib/tasks/starter.ts +1 -2
- package/lib/tasks/state.ts +1 -6
- package/lib/theme-config.ts +1 -8
- package/lib/updates/banner.ts +1 -6
- package/lib/updates/run.ts +1 -2
- package/lib/usage/aggregate.ts +1 -1
- package/lib/usage/nightly.ts +1 -2
- package/lib/usage/rate-limits.ts +1 -2
- package/lib/usage/turns.ts +1 -2
- package/lib/usage/windows.ts +5 -7
- package/lib/workspaces.ts +1 -2
- package/lib/worktree-sweep/databases.ts +0 -1
- package/package.json +3 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { useStoredFlag } from "./useStoredFlag";
|
|
4
5
|
|
|
5
6
|
const STORAGE_KEY = "agentOS-sidebar-pinned";
|
|
6
7
|
|
|
@@ -11,29 +12,12 @@ const STORAGE_KEY = "agentOS-sidebar-pinned";
|
|
|
11
12
|
* reveals on hover near the left edge.
|
|
12
13
|
*/
|
|
13
14
|
export function useSidebarPinned() {
|
|
14
|
-
const [isPinned,
|
|
15
|
+
const [isPinned, setPinned] = useStoredFlag(STORAGE_KEY, true);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (stored === "false") {
|
|
21
|
-
setIsPinned(false);
|
|
22
|
-
}
|
|
23
|
-
}, []);
|
|
24
|
-
|
|
25
|
-
const setPinned = useCallback((pinned: boolean) => {
|
|
26
|
-
setIsPinned(pinned);
|
|
27
|
-
localStorage.setItem(STORAGE_KEY, String(pinned));
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
const togglePin = useCallback(() => {
|
|
31
|
-
setIsPinned((prev) => {
|
|
32
|
-
const next = !prev;
|
|
33
|
-
localStorage.setItem(STORAGE_KEY, String(next));
|
|
34
|
-
return next;
|
|
35
|
-
});
|
|
36
|
-
}, []);
|
|
17
|
+
const togglePin = useCallback(
|
|
18
|
+
() => setPinned(!isPinned),
|
|
19
|
+
[isPinned, setPinned]
|
|
20
|
+
);
|
|
37
21
|
|
|
38
22
|
return { isPinned, togglePin, setPinned };
|
|
39
23
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useState,
|
|
5
|
+
useRef,
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useSyncExternalStore,
|
|
9
|
+
} from "react";
|
|
4
10
|
|
|
5
11
|
// Web Speech API types
|
|
6
12
|
interface SpeechRecognitionEvent extends Event {
|
|
@@ -46,19 +52,27 @@ declare global {
|
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
|
|
55
|
+
const noopSubscribe = () => () => {};
|
|
56
|
+
|
|
57
|
+
function getSpeechRecognitionAPI() {
|
|
58
|
+
return window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
export function useSpeechRecognition(
|
|
50
62
|
onTranscript: (text: string, isFinal: boolean) => void
|
|
51
63
|
) {
|
|
52
64
|
const [isListening, setIsListening] = useState(false);
|
|
53
|
-
const
|
|
65
|
+
const isSupported = useSyncExternalStore(
|
|
66
|
+
noopSubscribe,
|
|
67
|
+
() => !!getSpeechRecognitionAPI(),
|
|
68
|
+
() => false
|
|
69
|
+
);
|
|
54
70
|
const recognitionRef = useRef<SpeechRecognition | null>(null);
|
|
55
71
|
const lastTranscriptRef = useRef("");
|
|
56
72
|
|
|
57
73
|
useEffect(() => {
|
|
58
74
|
// Check for browser support
|
|
59
|
-
const SpeechRecognitionAPI =
|
|
60
|
-
window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
61
|
-
setIsSupported(!!SpeechRecognitionAPI);
|
|
75
|
+
const SpeechRecognitionAPI = getSpeechRecognitionAPI();
|
|
62
76
|
|
|
63
77
|
if (SpeechRecognitionAPI) {
|
|
64
78
|
const recognition = new SpeechRecognitionAPI();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
4
|
+
|
|
5
|
+
const listeners = new Set<() => void>();
|
|
6
|
+
|
|
7
|
+
function subscribe(fn: () => void) {
|
|
8
|
+
listeners.add(fn);
|
|
9
|
+
window.addEventListener("storage", fn);
|
|
10
|
+
return () => {
|
|
11
|
+
listeners.delete(fn);
|
|
12
|
+
window.removeEventListener("storage", fn);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function read(key: string): string | null {
|
|
17
|
+
try {
|
|
18
|
+
return localStorage.getItem(key);
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// A boolean kept in localStorage, shared by every caller on the page. The
|
|
25
|
+
// server and the hydrating render see `fallback`; the stored value follows.
|
|
26
|
+
export function useStoredFlag(
|
|
27
|
+
key: string,
|
|
28
|
+
fallback: boolean
|
|
29
|
+
): [boolean, (next: boolean) => void] {
|
|
30
|
+
const value = useSyncExternalStore(
|
|
31
|
+
subscribe,
|
|
32
|
+
() => read(key),
|
|
33
|
+
() => null
|
|
34
|
+
);
|
|
35
|
+
const set = useCallback(
|
|
36
|
+
(next: boolean) => {
|
|
37
|
+
try {
|
|
38
|
+
localStorage.setItem(key, String(next));
|
|
39
|
+
} catch {
|
|
40
|
+
// Storage unavailable: the choice lasts until reload.
|
|
41
|
+
}
|
|
42
|
+
listeners.forEach((fn) => fn());
|
|
43
|
+
},
|
|
44
|
+
[key]
|
|
45
|
+
);
|
|
46
|
+
return [value === null ? fallback : value === "true", set];
|
|
47
|
+
}
|
package/hooks/useViewport.ts
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
import { useMediaQuery } from "./useMediaQuery";
|
|
5
|
+
|
|
6
|
+
const noop = () => () => {};
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Mobile-first viewport detection hook
|
|
7
10
|
* Breakpoint: 768px (md in Tailwind)
|
|
8
11
|
*/
|
|
9
12
|
export function useViewport() {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Initial check
|
|
19
|
-
checkViewport();
|
|
20
|
-
setIsHydrated(true);
|
|
21
|
-
|
|
22
|
-
// Listen for resize
|
|
23
|
-
window.addEventListener("resize", checkViewport);
|
|
24
|
-
return () => window.removeEventListener("resize", checkViewport);
|
|
25
|
-
}, []);
|
|
13
|
+
const isMobile = useMediaQuery("(max-width: 767.98px)");
|
|
14
|
+
// False on the server and while hydrating, true after.
|
|
15
|
+
const isHydrated = useSyncExternalStore(
|
|
16
|
+
noop,
|
|
17
|
+
() => true,
|
|
18
|
+
() => false
|
|
19
|
+
);
|
|
26
20
|
|
|
27
21
|
return {
|
|
28
22
|
isMobile,
|
|
@@ -14,13 +14,7 @@ import { markAllStatusDirty } from "../status/dirty";
|
|
|
14
14
|
export const NO_APPROVALS_KEY = "approvals.none";
|
|
15
15
|
|
|
16
16
|
export type AuditSource =
|
|
17
|
-
| "
|
|
18
|
-
| "brake"
|
|
19
|
-
| "plan"
|
|
20
|
-
| "chat"
|
|
21
|
-
| "terminal"
|
|
22
|
-
| "merge-approval"
|
|
23
|
-
| "mode";
|
|
17
|
+
"ask" | "brake" | "plan" | "chat" | "terminal" | "merge-approval" | "mode";
|
|
24
18
|
|
|
25
19
|
export interface AuditRow {
|
|
26
20
|
id: number;
|
package/lib/artifacts/store.ts
CHANGED
|
@@ -54,8 +54,7 @@ export function createArtifact(
|
|
|
54
54
|
export function getArtifact(id: string): Artifact | undefined {
|
|
55
55
|
if (!ID.test(id)) return undefined;
|
|
56
56
|
return db.prepare(`SELECT * FROM artifacts WHERE id = ?`).get(id) as
|
|
57
|
-
|
|
|
58
|
-
| undefined;
|
|
57
|
+
Artifact | undefined;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
export function listArtifacts(sessionId: string): Artifact[] {
|
package/lib/away/report.ts
CHANGED
|
@@ -150,8 +150,7 @@ function merged(
|
|
|
150
150
|
);
|
|
151
151
|
return rows.map((r) => {
|
|
152
152
|
const done = action.get(away.id, `deploy:${r.id}`) as
|
|
153
|
-
|
|
154
|
-
| undefined;
|
|
153
|
+
{ kind: string; detail: string | null } | undefined;
|
|
155
154
|
const deploy: DeployState =
|
|
156
155
|
done?.kind === "deploy_ok"
|
|
157
156
|
? "deployed"
|
package/lib/away/run.ts
CHANGED
|
@@ -70,8 +70,7 @@ function orchestrated(): { workspaceId: string; orchestratorId: string }[] {
|
|
|
70
70
|
|
|
71
71
|
const sessionRow = (id: string) =>
|
|
72
72
|
db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
|
|
73
|
-
|
|
|
74
|
-
| undefined;
|
|
73
|
+
Session | undefined;
|
|
75
74
|
|
|
76
75
|
// Away mode reaches a workspace only through an orchestrator that's been
|
|
77
76
|
// working inside the window: one left alone isn't told or woken.
|
package/lib/away/state.ts
CHANGED
|
@@ -43,8 +43,7 @@ export function activeAway(): AwayRow | null {
|
|
|
43
43
|
export function getAway(id: number): AwayRow | null {
|
|
44
44
|
return (
|
|
45
45
|
(db.prepare(`SELECT * FROM away_periods WHERE id = ?`).get(id) as
|
|
46
|
-
|
|
|
47
|
-
| undefined) ?? null
|
|
46
|
+
AwayRow | undefined) ?? null
|
|
48
47
|
);
|
|
49
48
|
}
|
|
50
49
|
|
package/lib/bookmarks/store.ts
CHANGED
|
@@ -83,8 +83,7 @@ function toBookmark(r: Joined): Bookmark {
|
|
|
83
83
|
|
|
84
84
|
export function getBookmark(id: string): Bookmark | null {
|
|
85
85
|
const r = db.prepare(`${SELECT} WHERE b.id = ?`).get(id) as
|
|
86
|
-
|
|
|
87
|
-
| undefined;
|
|
86
|
+
Joined | undefined;
|
|
88
87
|
return r ? toBookmark(r) : null;
|
|
89
88
|
}
|
|
90
89
|
|
package/lib/bus/delivery.ts
CHANGED
|
@@ -7,8 +7,7 @@ import { WORKING_LINE } from "../claude-working-line";
|
|
|
7
7
|
|
|
8
8
|
export type DeliveryState = "delivered" | "queued" | "failed";
|
|
9
9
|
export type Delivery =
|
|
10
|
-
|
|
11
|
-
| { state: "failed"; why: string };
|
|
10
|
+
{ state: "delivered" | "queued" } | { state: "failed"; why: string };
|
|
12
11
|
|
|
13
12
|
export interface PaneView {
|
|
14
13
|
text: string;
|
package/lib/bus/index.ts
CHANGED
|
@@ -70,8 +70,7 @@ function candidates(sessions: Session[]): Candidate[] {
|
|
|
70
70
|
const sessionById = (id: string | null | undefined) =>
|
|
71
71
|
id
|
|
72
72
|
? (db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
|
|
73
|
-
|
|
|
74
|
-
| undefined)
|
|
73
|
+
Session | undefined)
|
|
75
74
|
: undefined;
|
|
76
75
|
|
|
77
76
|
// A chat has no pane: its worker is the state, and it can always take a
|
|
@@ -31,8 +31,7 @@ export async function compactContext(sessionId: string): Promise<string> {
|
|
|
31
31
|
`SELECT working_directory, task_prompt, role FROM session_rows WHERE id = ?`
|
|
32
32
|
)
|
|
33
33
|
.get(sessionId) as
|
|
34
|
-
|
|
35
|
-
| undefined;
|
|
34
|
+
Pick<Session, "working_directory" | "task_prompt" | "role"> | undefined;
|
|
36
35
|
// An orchestrator starts fresh instead of compacting.
|
|
37
36
|
if (!session || session.role === "orchestrator") return "";
|
|
38
37
|
const tools = lastItems(sessionId, 400, "tool").filter(
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import { discoversModels } from "../model-catalog";
|
|
3
|
+
import { chatDriverFor } from "./drivers";
|
|
4
|
+
import type { ChatModel } from "./events";
|
|
5
|
+
|
|
6
|
+
const TTL_MS = 5 * 60_000;
|
|
7
|
+
const TIMEOUT_MS = 30_000;
|
|
8
|
+
|
|
9
|
+
interface Entry {
|
|
10
|
+
models: ChatModel[];
|
|
11
|
+
at: number;
|
|
12
|
+
}
|
|
13
|
+
const cache = new Map<string, Entry>();
|
|
14
|
+
const loading = new Map<string, Promise<ChatModel[]>>();
|
|
15
|
+
|
|
16
|
+
const expand = (p: string) => p.replace(/^~(?=$|\/)/, os.homedir());
|
|
17
|
+
|
|
18
|
+
async function discover(agentType: string, cwd: string): Promise<ChatModel[]> {
|
|
19
|
+
const driver = chatDriverFor(agentType);
|
|
20
|
+
if (!driver) return [];
|
|
21
|
+
const ac = new AbortController();
|
|
22
|
+
const timer = setTimeout(
|
|
23
|
+
() => ac.abort(new Error("Discovery timed out")),
|
|
24
|
+
TIMEOUT_MS
|
|
25
|
+
);
|
|
26
|
+
timer.unref?.();
|
|
27
|
+
try {
|
|
28
|
+
const found = await Promise.race([
|
|
29
|
+
driver.discover({ cwd, env: {}, signal: ac.signal }),
|
|
30
|
+
new Promise<never>((_, reject) =>
|
|
31
|
+
ac.signal.addEventListener("abort", () => reject(ac.signal.reason), {
|
|
32
|
+
once: true,
|
|
33
|
+
})
|
|
34
|
+
),
|
|
35
|
+
]);
|
|
36
|
+
return found.models;
|
|
37
|
+
} finally {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The models an agent reports for a folder, cached for a few minutes.
|
|
43
|
+
// `refresh` skips the cache; a failure throws and is never cached.
|
|
44
|
+
export async function discoveredModels(
|
|
45
|
+
agentType: string,
|
|
46
|
+
folder: string | null | undefined,
|
|
47
|
+
refresh = false
|
|
48
|
+
): Promise<ChatModel[]> {
|
|
49
|
+
if (!discoversModels(agentType)) return [];
|
|
50
|
+
const cwd = expand(folder?.trim() || "~");
|
|
51
|
+
const key = `${agentType}:${cwd}`;
|
|
52
|
+
const hit = cache.get(key);
|
|
53
|
+
if (!refresh && hit && Date.now() - hit.at < TTL_MS) return hit.models;
|
|
54
|
+
const running = loading.get(key);
|
|
55
|
+
if (running && !refresh) return running;
|
|
56
|
+
const run = discover(agentType, cwd)
|
|
57
|
+
.then((models) => {
|
|
58
|
+
cache.set(key, { models, at: Date.now() });
|
|
59
|
+
return models;
|
|
60
|
+
})
|
|
61
|
+
.finally(() => {
|
|
62
|
+
if (loading.get(key) === run) loading.delete(key);
|
|
63
|
+
});
|
|
64
|
+
loading.set(key, run);
|
|
65
|
+
return run;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function clearDiscoveredModels(): void {
|
|
69
|
+
cache.clear();
|
|
70
|
+
loading.clear();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Whether the agent reports this model. A failed discovery says no, so a
|
|
74
|
+
// launch falls back to the agent's default rather than failing.
|
|
75
|
+
export async function isDiscoveredModel(
|
|
76
|
+
agentType: string,
|
|
77
|
+
folder: string | null | undefined,
|
|
78
|
+
model: string
|
|
79
|
+
): Promise<boolean> {
|
|
80
|
+
try {
|
|
81
|
+
return (await discoveredModels(agentType, folder)).some(
|
|
82
|
+
(m) => m.value === model
|
|
83
|
+
);
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
package/lib/chat/stop.ts
CHANGED
|
@@ -70,8 +70,7 @@ export async function stopChatAtTurnEnd(
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export type TurnStop =
|
|
73
|
-
|
|
74
|
-
| { stopped: false; reason: string };
|
|
73
|
+
{ stopped: true; killed: boolean } | { stopped: false; reason: string };
|
|
75
74
|
|
|
76
75
|
export interface TurnStopOptions {
|
|
77
76
|
// How long the turn gets to end after the interrupt before its agent is
|
package/lib/chat/worker/host.ts
CHANGED
|
@@ -20,8 +20,7 @@ interface NpmVuln {
|
|
|
20
20
|
isDirect?: boolean;
|
|
21
21
|
via?: (string | { title?: string; source?: number })[];
|
|
22
22
|
fixAvailable?:
|
|
23
|
-
| boolean
|
|
24
|
-
| { name?: string; version?: string; isSemVerMajor?: boolean };
|
|
23
|
+
boolean | { name?: string; version?: string; isSemVerMajor?: boolean };
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
interface PnpmAdvisory {
|
package/lib/db/lumifyhub.ts
CHANGED
|
@@ -24,8 +24,7 @@ export const ATTEMPT_TTL_MINUTES = 10;
|
|
|
24
24
|
export const lumifyhubQueries = {
|
|
25
25
|
getConnection: (db: Database.Database) =>
|
|
26
26
|
(db.prepare(`SELECT * FROM lumifyhub_connection WHERE id = 1`).get() as
|
|
27
|
-
|
|
|
28
|
-
| undefined) ?? null,
|
|
27
|
+
LumifyHubConnection | undefined) ?? null,
|
|
29
28
|
|
|
30
29
|
saveConnection: (
|
|
31
30
|
db: Database.Database,
|
|
@@ -65,8 +64,7 @@ export const lumifyhubQueries = {
|
|
|
65
64
|
FROM lumifyhub_connect_attempts WHERE state = ?`
|
|
66
65
|
)
|
|
67
66
|
.get(`-${ATTEMPT_TTL_MINUTES} minutes`, state) as
|
|
68
|
-
|
|
69
|
-
| undefined;
|
|
67
|
+
(LumifyHubConnectAttempt & { fresh: number }) | undefined;
|
|
70
68
|
db.prepare(`DELETE FROM lumifyhub_connect_attempts WHERE state = ?`).run(
|
|
71
69
|
state
|
|
72
70
|
);
|
package/lib/db/schedules-move.ts
CHANGED
|
@@ -200,8 +200,7 @@ export function revertSchedulesMove(db: Database.Database): {
|
|
|
200
200
|
for (const s of moved) {
|
|
201
201
|
const r = s.recipe_id
|
|
202
202
|
? (recipe.get(s.recipe_id) as
|
|
203
|
-
|
|
204
|
-
| undefined)
|
|
203
|
+
{ brief: string; project_id: string } | undefined)
|
|
205
204
|
: undefined;
|
|
206
205
|
restore.run(
|
|
207
206
|
s.migrated_from_kind,
|
|
@@ -20,8 +20,7 @@ export function startTaskClock(
|
|
|
20
20
|
const row = db
|
|
21
21
|
.prepare(`SELECT created_at, task_since FROM session_rows WHERE id = ?`)
|
|
22
22
|
.get(sessionId) as
|
|
23
|
-
|
|
24
|
-
| undefined;
|
|
23
|
+
{ created_at: string; task_since: string | null } | undefined;
|
|
25
24
|
if (!row || row.task_since) return;
|
|
26
25
|
setTask(db, sessionId, { task_since: at ?? row.created_at });
|
|
27
26
|
}
|
package/lib/db/stacks.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type Database from "better-sqlite3";
|
|
2
2
|
|
|
3
3
|
export type StackStatus =
|
|
4
|
-
| "
|
|
5
|
-
| "paused"
|
|
6
|
-
| "landing"
|
|
7
|
-
| "landed"
|
|
8
|
-
| "failed";
|
|
4
|
+
"running" | "paused" | "landing" | "landed" | "failed";
|
|
9
5
|
|
|
10
6
|
export type StackItemStatus =
|
|
11
7
|
| "planned"
|
|
@@ -131,8 +127,7 @@ export const stackQueries = {
|
|
|
131
127
|
|
|
132
128
|
get: (db: Database.Database, id: string) =>
|
|
133
129
|
(db.prepare(`SELECT * FROM stacks WHERE id = ?`).get(id) as
|
|
134
|
-
|
|
|
135
|
-
| undefined) ?? null,
|
|
130
|
+
StackRow | undefined) ?? null,
|
|
136
131
|
|
|
137
132
|
// The board's stack that has not finished yet, if any.
|
|
138
133
|
openForBoard: (db: Database.Database, boardId: string) =>
|
|
@@ -150,8 +145,7 @@ export const stackQueries = {
|
|
|
150
145
|
|
|
151
146
|
item: (db: Database.Database, id: string) =>
|
|
152
147
|
(db.prepare(`SELECT * FROM stack_items WHERE id = ?`).get(id) as
|
|
153
|
-
|
|
|
154
|
-
| undefined) ?? null,
|
|
148
|
+
StackItemRow | undefined) ?? null,
|
|
155
149
|
|
|
156
150
|
itemForSession: (db: Database.Database, sessionId: string) =>
|
|
157
151
|
(db
|
package/lib/db/types.ts
CHANGED
|
@@ -42,13 +42,7 @@ export interface Session {
|
|
|
42
42
|
// done: finished without a merge (no PR, or its PR closed).
|
|
43
43
|
// moving: handing it to another machine (moved_to); moved: handed over.
|
|
44
44
|
task_status:
|
|
45
|
-
| "
|
|
46
|
-
| "merged"
|
|
47
|
-
| "dropped"
|
|
48
|
-
| "done"
|
|
49
|
-
| "moving"
|
|
50
|
-
| "moved"
|
|
51
|
-
| null;
|
|
45
|
+
"running" | "merged" | "dropped" | "done" | "moving" | "moved" | null;
|
|
52
46
|
moved_to: string | null;
|
|
53
47
|
// The session on another machine this task arrived from.
|
|
54
48
|
moved_from: string | null;
|
package/lib/doctor/checks.ts
CHANGED
|
@@ -207,15 +207,13 @@ export function runDoctor(
|
|
|
207
207
|
d
|
|
208
208
|
.probe(fresh)
|
|
209
209
|
.then(checkAgents)
|
|
210
|
-
.catch(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
})
|
|
218
|
-
),
|
|
210
|
+
.catch((): DoctorCheck => ({
|
|
211
|
+
id: "agents",
|
|
212
|
+
label: "Agent CLI",
|
|
213
|
+
status: "warn",
|
|
214
|
+
detail: "Couldn't check the agent CLIs",
|
|
215
|
+
fix: "Check again",
|
|
216
|
+
})),
|
|
219
217
|
]);
|
|
220
218
|
if (!custom) cache = { at: Date.now(), checks };
|
|
221
219
|
return checks;
|
package/lib/done/archive.ts
CHANGED
|
@@ -35,8 +35,7 @@ export function unarchiveSession(id: string): Session {
|
|
|
35
35
|
)
|
|
36
36
|
.run(id).changes;
|
|
37
37
|
const row = db.prepare(`SELECT * FROM session_rows WHERE id = ?`).get(id) as
|
|
38
|
-
|
|
|
39
|
-
| undefined;
|
|
38
|
+
Session | undefined;
|
|
40
39
|
if (!row) throw new Error("Session not found");
|
|
41
40
|
if (!changed) throw new Error(`${row.name} isn't archived`);
|
|
42
41
|
return row;
|
package/lib/experiments/meter.ts
CHANGED
|
@@ -18,13 +18,7 @@ import { experimentOn } from ".";
|
|
|
18
18
|
import { getExperiment, type ExperimentId } from "./registry";
|
|
19
19
|
|
|
20
20
|
export type ExperimentEvent =
|
|
21
|
-
| "
|
|
22
|
-
| "script"
|
|
23
|
-
| "shown"
|
|
24
|
-
| "accepted"
|
|
25
|
-
| "dismissed"
|
|
26
|
-
| "applied"
|
|
27
|
-
| "error";
|
|
21
|
+
"model" | "script" | "shown" | "accepted" | "dismissed" | "applied" | "error";
|
|
28
22
|
|
|
29
23
|
export interface MeterContext {
|
|
30
24
|
trigger: string;
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import type { EnvClass } from "./types";
|
|
9
9
|
|
|
10
|
-
const OLD_PYTHON =
|
|
11
|
-
/python3?\.[0-9]\b|Python3?\.framework\/Versions\/3\.[0-9]\b|Python\/3\.[0-9]\b/i;
|
|
12
10
|
const USE_ENV =
|
|
13
11
|
"run it through the repo's own environment (`uv run …` when it has a pyproject.toml or uv.lock, else its .venv/bin/python), not a bare `python3`";
|
|
14
12
|
|
|
@@ -19,8 +19,7 @@ export function recordHit(
|
|
|
19
19
|
WHERE r.id = ?`
|
|
20
20
|
)
|
|
21
21
|
.get(sessionId) as
|
|
22
|
-
|
|
23
|
-
| undefined;
|
|
22
|
+
{ project_id: string | null; ws: string | null } | undefined;
|
|
24
23
|
db.prepare(
|
|
25
24
|
`INSERT INTO env_failures
|
|
26
25
|
(session_id, class, project_id, workspace_id, command, line,
|
package/lib/health/spin.ts
CHANGED
|
@@ -45,10 +45,7 @@ export interface SpinSample {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export type SpinClass =
|
|
48
|
-
| "
|
|
49
|
-
| "sleeping"
|
|
50
|
-
| "busy-with-output"
|
|
51
|
-
| "spinning";
|
|
48
|
+
"warming" | "sleeping" | "busy-with-output" | "spinning";
|
|
52
49
|
|
|
53
50
|
export function classifySpin(samples: SpinSample[]): SpinClass {
|
|
54
51
|
if (samples.length < 2) return "warming";
|
package/lib/health/store.ts
CHANGED
|
@@ -29,8 +29,7 @@ export interface RecordResult {
|
|
|
29
29
|
|
|
30
30
|
const rowOf = (id: number) =>
|
|
31
31
|
db.prepare(`SELECT * FROM health_anomalies WHERE id = ?`).get(id) as
|
|
32
|
-
|
|
|
33
|
-
| undefined;
|
|
32
|
+
AnomalyRow | undefined;
|
|
34
33
|
|
|
35
34
|
export function anomaly(id: number): AnomalyRow | null {
|
|
36
35
|
return rowOf(id) ?? null;
|
package/lib/hosts/index.ts
CHANGED
|
@@ -39,8 +39,7 @@ export function getHost(hostId: string | null | undefined): Host | null {
|
|
|
39
39
|
if (!isRemoteHost(hostId)) return LOCAL_HOST;
|
|
40
40
|
return (
|
|
41
41
|
(getDb().prepare(`SELECT * FROM hosts WHERE id = ?`).get(hostId) as
|
|
42
|
-
|
|
|
43
|
-
| undefined) ?? null
|
|
42
|
+
Host | undefined) ?? null
|
|
44
43
|
);
|
|
45
44
|
}
|
|
46
45
|
|
package/lib/hosts/peer-sync.ts
CHANGED
|
@@ -95,8 +95,7 @@ export function syncPeerMirrors(
|
|
|
95
95
|
const [name, view, tmuxName, projectId, prUrl, prNumber, prStatus, at] =
|
|
96
96
|
fields;
|
|
97
97
|
const cur = current.get(peer.id, hostId) as
|
|
98
|
-
|
|
99
|
-
| undefined;
|
|
98
|
+
Record<string, string | number | null> | undefined;
|
|
100
99
|
if (!cur) return;
|
|
101
100
|
const same =
|
|
102
101
|
cur.name === name &&
|
|
@@ -126,8 +125,7 @@ export function syncPeerMirrors(
|
|
|
126
125
|
db.transaction(() => {
|
|
127
126
|
for (const peer of listed) {
|
|
128
127
|
const row = owner.get(peer.id) as
|
|
129
|
-
|
|
130
|
-
| undefined;
|
|
128
|
+
{ host_id: string; project_id: string | null } | undefined;
|
|
131
129
|
// One started here for a project here keeps it (lib/hosts/peer-actions.ts).
|
|
132
130
|
const kept =
|
|
133
131
|
row?.project_id && here.has(row.project_id) ? row.project_id : null;
|
package/lib/hosts/remote-api.ts
CHANGED
|
@@ -21,8 +21,7 @@ export function hostLink(hostId: string | null | undefined): HostLink | null {
|
|
|
21
21
|
JOIN hosts h ON h.id = l.host_id WHERE l.host_id = ?`
|
|
22
22
|
)
|
|
23
23
|
.get(hostId) as
|
|
24
|
-
|
|
25
|
-
| undefined;
|
|
24
|
+
{ host_id: string; url: string; token: string; name: string } | undefined;
|
|
26
25
|
return row
|
|
27
26
|
? {
|
|
28
27
|
hostId: row.host_id,
|
package/lib/lumifyhub/types.ts
CHANGED
|
@@ -23,11 +23,7 @@ export interface LhBoard {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type LhListCategory =
|
|
26
|
-
| "
|
|
27
|
-
| "unstarted"
|
|
28
|
-
| "started"
|
|
29
|
-
| "completed"
|
|
30
|
-
| "canceled";
|
|
26
|
+
"backlog" | "unstarted" | "started" | "completed" | "canceled";
|
|
31
27
|
|
|
32
28
|
export interface LhList {
|
|
33
29
|
id: string;
|
|
@@ -39,9 +35,7 @@ export interface LhList {
|
|
|
39
35
|
|
|
40
36
|
// A TipTap/ProseMirror document, or a bare string on older cards.
|
|
41
37
|
export type LhRichText =
|
|
42
|
-
| string
|
|
43
|
-
| { type?: string; text?: string; content?: LhRichText[] }
|
|
44
|
-
| null;
|
|
38
|
+
string | { type?: string; text?: string; content?: LhRichText[] } | null;
|
|
45
39
|
|
|
46
40
|
export interface LhCard {
|
|
47
41
|
id: string;
|