@saadnvd1/agent-os 0.3.637 → 0.3.639
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/sessions/[id]/pr/route.ts +3 -3
- package/app/api/sessions/[id]/setup/route.ts +3 -3
- package/app/api/tasks/[id]/approve-plan/route.ts +3 -4
- package/app/api/tasks/[id]/arm/route.ts +6 -5
- package/app/api/tasks/[id]/chat-facts/route.ts +2 -2
- package/app/api/tasks/[id]/chat-tail/route.ts +2 -2
- package/app/api/tasks/[id]/checks/route.ts +1 -1
- package/app/api/tasks/[id]/diff/route.ts +1 -1
- package/app/api/tasks/[id]/done/route.ts +2 -2
- package/app/api/tasks/[id]/drop/route.ts +6 -2
- package/app/api/tasks/[id]/export/route.ts +3 -5
- package/app/api/tasks/[id]/merge/route.ts +3 -3
- package/app/api/tasks/[id]/message/route.ts +2 -2
- package/app/api/tasks/[id]/model/route.ts +5 -1
- package/app/api/tasks/[id]/move/route.ts +5 -1
- package/app/api/tasks/[id]/moved/route.ts +6 -8
- package/app/api/tasks/[id]/plan/route.ts +4 -6
- package/app/api/tasks/[id]/plan-edits/route.ts +6 -5
- package/app/api/tasks/[id]/priority/route.ts +4 -1
- package/app/api/tasks/[id]/resume/route.ts +3 -4
- package/app/api/tasks/[id]/stop/route.ts +2 -2
- package/app/api/tasks/route.ts +1 -1
- package/lib/approvals/enable.ts +1 -1
- package/lib/away/report.ts +4 -4
- package/lib/away/run.ts +2 -2
- package/lib/bookmarks/store.ts +3 -3
- package/lib/bus/held-reply.ts +2 -2
- package/lib/bus/index.ts +3 -3
- package/lib/chat/compact-context.ts +1 -1
- package/lib/chat/hold.ts +3 -3
- package/lib/chat/refresh.ts +1 -1
- package/lib/chat/registry.ts +3 -3
- package/lib/chat/runner.ts +1 -1
- package/lib/chat/worker/main.ts +1 -1
- package/lib/db/index.ts +5 -1
- package/lib/db/lumifyhub.ts +8 -9
- package/lib/db/machine-scope.ts +12 -0
- package/lib/db/migrations/20261015T1800_split_sessions_tables.ts +172 -0
- package/lib/db/migrations/README.md +7 -0
- package/lib/db/queries.ts +16 -31
- package/lib/db/session-parts/columns.ts +186 -0
- package/lib/db/session-parts/fill.ts +33 -0
- package/lib/db/session-parts/index.ts +9 -0
- package/lib/db/session-parts/pauses.ts +11 -0
- package/lib/db/session-parts/placement.ts +11 -0
- package/lib/db/session-parts/plans.ts +31 -0
- package/lib/db/session-parts/prs.ts +31 -0
- package/lib/db/session-parts/tasks.ts +27 -0
- package/lib/db/session-parts/view.ts +43 -0
- package/lib/db/session-parts/write.ts +69 -0
- package/lib/done/archive.ts +2 -2
- package/lib/done/auto-archive.ts +1 -1
- package/lib/done/bulk.ts +1 -1
- package/lib/done/index.ts +8 -14
- package/lib/health/evidence.ts +1 -1
- package/lib/health/facts.ts +1 -1
- package/lib/health/pieces.ts +1 -1
- package/lib/hosts/peer-actions.ts +2 -2
- package/lib/hosts/peer-mirror.ts +2 -2
- package/lib/hosts/peer-sync.ts +69 -32
- package/lib/learning-cards/input.ts +1 -1
- package/lib/learning-cards/store.ts +1 -1
- package/lib/models/plan-step.ts +10 -24
- package/lib/models/resume.ts +5 -7
- package/lib/notify/index.ts +1 -1
- package/lib/notify/push/events.ts +1 -1
- package/lib/notify/push/index.ts +1 -1
- package/lib/orchestrator/act.ts +1 -1
- package/lib/orchestrator/armed.ts +17 -15
- package/lib/orchestrator/ask-approvals.ts +1 -1
- package/lib/orchestrator/ask-heads.ts +1 -1
- package/lib/orchestrator/ask-settle.ts +1 -1
- package/lib/orchestrator/brakes.ts +1 -1
- package/lib/orchestrator/digest.ts +2 -2
- package/lib/orchestrator/external-pr.ts +2 -2
- package/lib/orchestrator/facts.ts +4 -28
- package/lib/orchestrator/held-asks.ts +3 -3
- package/lib/orchestrator/home.ts +2 -2
- package/lib/orchestrator/overview.ts +1 -1
- package/lib/orchestrator/pr-wake.ts +3 -5
- package/lib/orchestrator/questions.ts +1 -1
- package/lib/orchestrator/quick-store.ts +1 -1
- package/lib/orchestrator/quick.ts +10 -7
- package/lib/orchestrator/read.ts +1 -1
- package/lib/orchestrator/rebase.ts +8 -11
- package/lib/orchestrator/reconcile.ts +2 -2
- package/lib/orchestrator/signoff.ts +3 -1
- package/lib/orchestrator/targets.ts +1 -1
- package/lib/orchestrator/task-state.ts +4 -2
- package/lib/plans/features.ts +1 -1
- package/lib/plans/release.ts +1 -1
- package/lib/ports.ts +1 -1
- package/lib/resurrect/find.ts +1 -1
- package/lib/resurrect/index.ts +24 -18
- package/lib/schedules/store.ts +1 -1
- package/lib/session-audit/sources.ts +3 -3
- package/lib/session-logs/index.ts +1 -1
- package/lib/session-titles.ts +1 -1
- package/lib/sessions/setup-progress.ts +1 -1
- package/lib/sessions/stop.ts +1 -1
- package/lib/sessions/worktree-setup.ts +2 -1
- package/lib/simulator/index.ts +1 -1
- package/lib/simulator/task-devices.ts +1 -1
- package/lib/stacks/board.ts +1 -1
- package/lib/stacks/land.ts +1 -1
- package/lib/stacks/restack.ts +1 -1
- package/lib/stacks/start.ts +2 -2
- package/lib/stacks/tick.ts +1 -1
- package/lib/stacks/view.ts +1 -1
- package/lib/status/incremental.ts +1 -1
- package/lib/tasks/contract/actions.ts +35 -0
- package/lib/tasks/contract/authorize.ts +82 -0
- package/lib/tasks/contract/client.ts +296 -0
- package/lib/tasks/{held-remote.ts → contract/held-calls.ts} +35 -66
- package/lib/tasks/contract/index.ts +28 -0
- package/lib/tasks/{remote-plan-path.ts → contract/plan-path.ts} +2 -2
- package/lib/tasks/{remote-plan.ts → contract/plan.ts} +76 -110
- package/lib/tasks/contract/routes.ts +26 -0
- package/lib/tasks/contract/start.ts +122 -0
- package/lib/tasks/contract/sync.ts +126 -0
- package/lib/tasks/contract/types.ts +41 -0
- package/lib/tasks/{remote-views.ts → contract/views.ts} +11 -18
- package/lib/tasks/finish.ts +10 -9
- package/lib/tasks/held-replies.ts +7 -13
- package/lib/tasks/held.ts +14 -18
- package/lib/tasks/import.ts +19 -15
- package/lib/tasks/index.ts +34 -22
- package/lib/tasks/launch-gate.ts +1 -1
- package/lib/tasks/move-carry.ts +15 -7
- package/lib/tasks/move-flow.ts +29 -36
- package/lib/tasks/move-guard.ts +1 -1
- package/lib/tasks/move-recover.ts +6 -25
- package/lib/tasks/move.ts +23 -23
- package/lib/tasks/moved-away.ts +1 -1
- package/lib/tasks/pause-hold.ts +13 -5
- package/lib/tasks/pause.ts +19 -23
- package/lib/tasks/plan-view.ts +1 -1
- package/lib/tasks/queue-placement.ts +1 -1
- package/lib/tasks/queue-rows.ts +4 -4
- package/lib/tasks/queue-start.ts +5 -3
- package/lib/tasks/queue-tick.ts +2 -2
- package/lib/tasks/queue.ts +14 -6
- package/lib/tasks/session.ts +7 -4
- package/lib/tasks/start.ts +4 -4
- package/lib/tasks/starter.ts +8 -11
- package/lib/usage/calls.ts +1 -1
- package/lib/usage/compare.ts +1 -1
- package/lib/usage/quality.ts +1 -1
- package/lib/usage/turns.ts +1 -1
- package/lib/voice/vocab.ts +1 -1
- package/package.json +1 -1
- package/scripts/backfill-session-logs.ts +1 -1
- package/lib/tasks/held-routes.ts +0 -33
- package/lib/tasks/remote.ts +0 -255
package/lib/tasks/remote.ts
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tasks that run on another machine's AgentOS. That machine schedules them;
|
|
3
|
-
* this one keeps a mirror row (same id, the host's id) so the sidebar lists
|
|
4
|
-
* them and the terminal attaches through that machine's AgentOS, and asks it for their
|
|
5
|
-
* state, sign-off and drop.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { MERGE_METHODS, type MergeMethod } from "./merge-methods";
|
|
9
|
-
import { db, type Project, type Session } from "../db";
|
|
10
|
-
import {
|
|
11
|
-
HostApiError,
|
|
12
|
-
hostApi,
|
|
13
|
-
requireHostLink,
|
|
14
|
-
type HostLink,
|
|
15
|
-
} from "../hosts/remote-api";
|
|
16
|
-
import { isRemoteHost } from "../hosts";
|
|
17
|
-
import { projectRef } from "./project-ref";
|
|
18
|
-
import { orchestratedStart } from "./held";
|
|
19
|
-
import type { TaskStatus } from "./state";
|
|
20
|
-
import type { TaskView } from "./index";
|
|
21
|
-
import { orchestratorOf } from "./starter";
|
|
22
|
-
|
|
23
|
-
// What this machine's task API does, for another machine deciding whether
|
|
24
|
-
// it can trust it with a pinned merge or a move; keyed-start: a session
|
|
25
|
-
// start takes a key, so it's safe to retry (lib/sessions/launch.ts).
|
|
26
|
-
export const TASK_CAPABILITIES = [
|
|
27
|
-
"pinned-merge",
|
|
28
|
-
"move",
|
|
29
|
-
"chat-turn",
|
|
30
|
-
"keyed-start",
|
|
31
|
-
"chat-move",
|
|
32
|
-
// Holds an orchestrator's task for the machine that sent it, and answers
|
|
33
|
-
// its messages, reads, stops and done (lib/tasks/held.ts).
|
|
34
|
-
"orchestrated-move",
|
|
35
|
-
// A held task's chat facts and its messages for its orchestrator.
|
|
36
|
-
"held-chat-facts",
|
|
37
|
-
"held-replies",
|
|
38
|
-
// A keyed start that carries an orchestrator's description holds the task
|
|
39
|
-
// for the device that sent it, as a move does (lib/tasks/held.ts).
|
|
40
|
-
"held-start",
|
|
41
|
-
// A plan placed here by another machine stops at the plan for that machine
|
|
42
|
-
// to decide what follows (lib/tasks/remote-plan.ts).
|
|
43
|
-
"remote-plan",
|
|
44
|
-
] as const;
|
|
45
|
-
|
|
46
|
-
export interface HostTasks {
|
|
47
|
-
tasks: TaskView[];
|
|
48
|
-
moved?: { id: string; movedTo: string | null }[];
|
|
49
|
-
capabilities?: string[];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function isMirror(session: Session): boolean {
|
|
53
|
-
return isRemoteHost(session.host_id);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function mirrorTask(
|
|
57
|
-
hostId: string,
|
|
58
|
-
projectId: string | null,
|
|
59
|
-
remote: Session,
|
|
60
|
-
startedBy?: string | null
|
|
61
|
-
): void {
|
|
62
|
-
db.prepare(
|
|
63
|
-
`INSERT INTO sessions (id, name, tmux_name, working_directory, model, group_path,
|
|
64
|
-
agent_type, auto_approve, project_id, host_id, worktree_path, branch_name,
|
|
65
|
-
base_branch, task_prompt, task_status, name_source, view)
|
|
66
|
-
VALUES (?, ?, ?, ?, ?, 'sessions', 'claude', 1, ?, ?, ?, ?, ?, ?, 'running', 'user', ?)
|
|
67
|
-
ON CONFLICT(id) DO NOTHING`
|
|
68
|
-
).run(
|
|
69
|
-
remote.id,
|
|
70
|
-
remote.name,
|
|
71
|
-
remote.tmux_name,
|
|
72
|
-
remote.working_directory,
|
|
73
|
-
remote.model,
|
|
74
|
-
projectId,
|
|
75
|
-
hostId,
|
|
76
|
-
remote.worktree_path,
|
|
77
|
-
remote.branch_name,
|
|
78
|
-
remote.base_branch,
|
|
79
|
-
remote.task_prompt,
|
|
80
|
-
// As that machine runs it: one that predates chat tasks says terminal.
|
|
81
|
-
remote.view === "chat" ? "chat" : "terminal"
|
|
82
|
-
);
|
|
83
|
-
// What carryTaskState gives a moved task's mirror: the orchestrator that
|
|
84
|
-
// holds it, and when it began (so its PR is judged from then).
|
|
85
|
-
if (startedBy)
|
|
86
|
-
db.prepare(
|
|
87
|
-
`UPDATE sessions SET started_by = COALESCE(started_by, ?),
|
|
88
|
-
task_since = COALESCE(task_since, created_at) WHERE id = ?`
|
|
89
|
-
).run(startedBy, remote.id);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* A machine on an older AgentOS would take a chat task as a terminal one,
|
|
94
|
-
* or an orchestrator's task as a plain one that anyone there could merge, or
|
|
95
|
-
* refuse to hand one over.
|
|
96
|
-
*/
|
|
97
|
-
export async function requireCapability(
|
|
98
|
-
link: HostLink,
|
|
99
|
-
capability: string,
|
|
100
|
-
what: string,
|
|
101
|
-
verb = "move"
|
|
102
|
-
): Promise<void> {
|
|
103
|
-
const { capabilities = [] } = await hostTasks(link, true).catch((err) => {
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Can't ask ${link.hostName} whether it takes ${what}: ${(err as Error).message}`
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
if (!capabilities.includes(capability))
|
|
109
|
-
throw new Error(
|
|
110
|
-
`${link.hostName}'s AgentOS can't ${verb} ${what} yet; update it first`
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export const unknownOutcome = (err: unknown) =>
|
|
115
|
-
err instanceof HostApiError && !err.refused;
|
|
116
|
-
|
|
117
|
-
/** POST a call that's safe to repeat; once more if we can't tell it landed. */
|
|
118
|
-
export async function postIdempotent<T>(
|
|
119
|
-
link: HostLink,
|
|
120
|
-
path: string,
|
|
121
|
-
body: unknown,
|
|
122
|
-
timeout: number
|
|
123
|
-
): Promise<T> {
|
|
124
|
-
try {
|
|
125
|
-
return await hostApi<T>(link, path, { body, timeout });
|
|
126
|
-
} catch (err) {
|
|
127
|
-
if (!unknownOutcome(err)) throw err;
|
|
128
|
-
return hostApi<T>(link, path, { body, timeout });
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export async function startRemoteTask(
|
|
133
|
-
hostId: string,
|
|
134
|
-
project: Project,
|
|
135
|
-
opts: {
|
|
136
|
-
id: string;
|
|
137
|
-
prompt: string;
|
|
138
|
-
name?: string;
|
|
139
|
-
model?: string;
|
|
140
|
-
baseBranch?: string;
|
|
141
|
-
view?: "chat" | "terminal";
|
|
142
|
-
// The orchestrator that started it: that machine holds the task for it.
|
|
143
|
-
startedBy?: string | null;
|
|
144
|
-
// It plans first: there it plans, stops, and waits for this machine.
|
|
145
|
-
plan?: { only: boolean; reason: string | null };
|
|
146
|
-
}
|
|
147
|
-
): Promise<Session> {
|
|
148
|
-
const link = requireHostLink(hostId);
|
|
149
|
-
const { startedBy: by, plan, ...rest } = opts;
|
|
150
|
-
const startedBy = orchestratorOf(by);
|
|
151
|
-
if (startedBy)
|
|
152
|
-
await requireCapability(
|
|
153
|
-
link,
|
|
154
|
-
"held-start",
|
|
155
|
-
"an orchestrator's task",
|
|
156
|
-
"hold"
|
|
157
|
-
);
|
|
158
|
-
if (plan) await requireCapability(link, "remote-plan", "a plan step", "plan");
|
|
159
|
-
const { session } = await postIdempotent<{ session: Session }>(
|
|
160
|
-
link,
|
|
161
|
-
"/api/tasks",
|
|
162
|
-
{
|
|
163
|
-
project: await projectRef(project),
|
|
164
|
-
...rest,
|
|
165
|
-
...(plan && {
|
|
166
|
-
plan: true,
|
|
167
|
-
plan_only: true,
|
|
168
|
-
plan_waits: true,
|
|
169
|
-
plan_reason: plan.reason ?? undefined,
|
|
170
|
-
}),
|
|
171
|
-
orchestrated: startedBy ? orchestratedStart(startedBy) : undefined,
|
|
172
|
-
},
|
|
173
|
-
180000
|
|
174
|
-
);
|
|
175
|
-
mirrorTask(hostId, project.id, session, startedBy);
|
|
176
|
-
if (plan)
|
|
177
|
-
db.prepare(
|
|
178
|
-
`UPDATE sessions SET plan_phase = 'planning', plan_only = ?, plan_decided = 1,
|
|
179
|
-
plan_reason = ?, plan_waits_for_caller = 1 WHERE id = ?`
|
|
180
|
-
).run(plan.only ? 1 : null, plan.reason, session.id);
|
|
181
|
-
forgetHostTasks(hostId);
|
|
182
|
-
return db
|
|
183
|
-
.prepare(`SELECT * FROM sessions WHERE id = ?`)
|
|
184
|
-
.get(session.id) as Session;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const cache = new Map<string, { at: number; list: Promise<HostTasks> }>();
|
|
188
|
-
|
|
189
|
-
export function hostTasks(link: HostLink, fresh = false): Promise<HostTasks> {
|
|
190
|
-
const hit = cache.get(link.hostId);
|
|
191
|
-
if (!fresh && hit && Date.now() - hit.at < 3000) return hit.list;
|
|
192
|
-
const list = hostApi<HostTasks>(link, "/api/tasks", { timeout: 8000 });
|
|
193
|
-
cache.set(link.hostId, { at: Date.now(), list });
|
|
194
|
-
list.catch(() => cache.delete(link.hostId));
|
|
195
|
-
return list;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export const forgetHostTasks = (hostId: string) => cache.delete(hostId);
|
|
199
|
-
|
|
200
|
-
export function setMirrorStatus(id: string, status: TaskStatus): void {
|
|
201
|
-
db.prepare(
|
|
202
|
-
`UPDATE sessions SET task_status = ? WHERE id = ? AND task_status = 'running'`
|
|
203
|
-
).run(status, id);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Sign off or drop on the machine that runs it. A merge returns the method
|
|
208
|
-
* that machine merged with; null when it doesn't say (an older AgentOS).
|
|
209
|
-
*/
|
|
210
|
-
export async function remoteTaskAction(
|
|
211
|
-
session: Session,
|
|
212
|
-
action: "merge" | "drop",
|
|
213
|
-
head?: string,
|
|
214
|
-
base?: string | null
|
|
215
|
-
): Promise<MergeMethod | null> {
|
|
216
|
-
const link = requireHostLink(session.host_id);
|
|
217
|
-
// An AgentOS that predates pinned merges would ignore the head and merge
|
|
218
|
-
// whatever the PR is at: refuse before asking it.
|
|
219
|
-
if (head) {
|
|
220
|
-
const { capabilities = [] } = await hostTasks(link, true);
|
|
221
|
-
if (!capabilities.includes("pinned-merge"))
|
|
222
|
-
throw new Error(
|
|
223
|
-
`${link.hostName}'s AgentOS can't pin a merge to a commit; update it first`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
// base: what the gates here were judged against; the machine that merges
|
|
227
|
-
// compares the PR with it, not with a base only it recorded.
|
|
228
|
-
const res = await hostApi<{ head?: string | null; method?: unknown }>(
|
|
229
|
-
link,
|
|
230
|
-
`/api/tasks/${encodeURIComponent(session.id)}/${action}`,
|
|
231
|
-
{
|
|
232
|
-
body: { ...(head && { head }), ...(head && base && { base }) },
|
|
233
|
-
timeout: 300000,
|
|
234
|
-
}
|
|
235
|
-
).catch(async (err) => {
|
|
236
|
-
if (action !== "merge" || !unknownOutcome(err)) throw err;
|
|
237
|
-
// A proxy or a dropped connection after the merge ran answers 502 with
|
|
238
|
-
// nothing from AgentOS: ask what state the task is in before failing.
|
|
239
|
-
const merged = await hostTasks(link, true)
|
|
240
|
-
.then((l) => l.tasks.find((t) => t.id === session.id)?.state === "merged")
|
|
241
|
-
.catch(() => false);
|
|
242
|
-
if (!merged)
|
|
243
|
-
throw new Error(
|
|
244
|
-
`${(err as Error).message}: couldn't confirm whether ${link.hostName} merged ${session.name}; check its PR before signing off again`
|
|
245
|
-
);
|
|
246
|
-
return { head: head ?? null, method: undefined };
|
|
247
|
-
});
|
|
248
|
-
forgetHostTasks(link.hostId);
|
|
249
|
-
setMirrorStatus(session.id, action === "merge" ? "merged" : "dropped");
|
|
250
|
-
if (head && res.head !== head)
|
|
251
|
-
throw new Error(
|
|
252
|
-
`${link.hostName} merged without confirming it was ${head.slice(0, 7)}`
|
|
253
|
-
);
|
|
254
|
-
return MERGE_METHODS.find((m) => m === res.method) ?? null;
|
|
255
|
-
}
|