heyquilt 0.3.106 → 0.3.107
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/RELEASES.md +4 -0
- package/package.json +1 -1
- package/src/api/memory-store.js +1 -1
- package/src/api/routes/ai-vm.js +5 -4
- package/src/api/supabase-store.js +1 -1
- package/src/ui-server.js +4 -1
package/RELEASES.md
CHANGED
|
@@ -11,6 +11,10 @@ Format: `## <version> — <YYYY-MM-DD>`, an optional one-line summary, then bull
|
|
|
11
11
|
Lead each bullet with a short bold phrase. Inline `code` and **bold** are rendered;
|
|
12
12
|
nothing else is.
|
|
13
13
|
|
|
14
|
+
## 0.3.107 — 2026-10-19
|
|
15
|
+
|
|
16
|
+
- **Your cloud AI's sessions stay listed.** Settings → Your AI shows the sessions your cloud AI is in while its machine sleeps and after Quilt's servers restart, instead of "In no session yet". A session nobody named shows as your folder's name, as the rest of the app shows it.
|
|
17
|
+
|
|
14
18
|
## 0.3.106 — 2026-10-19
|
|
15
19
|
|
|
16
20
|
0.3.105 didn't publish (GitHub didn't run its builds), so it comes with this one.
|
package/package.json
CHANGED
package/src/api/memory-store.js
CHANGED
|
@@ -1013,7 +1013,7 @@ export function createMemoryStore ({ now = Date.now } = {}) {
|
|
|
1013
1013
|
async createAiVm ({ userId, tool, model = '', prompt = '', cap = 0, region = '' }) {
|
|
1014
1014
|
if (!profiles.has(userId)) throw fkViolation('person', 'does not exist')
|
|
1015
1015
|
if (aiVms.has(userId)) throw duplicate('cloud AI machine')
|
|
1016
|
-
const row = { userId, tool, model, prompt, cap, agentId: null, inviteId: null, machineId: null, volumeId: null, region, state: 'creating', error: '', signedIn: false, usageToday: {}, lastReportAt: null, createdAt: now(), updatedAt: now() }
|
|
1016
|
+
const row = { userId, tool, model, prompt, cap, agentId: null, inviteId: null, machineId: null, volumeId: null, region, state: 'creating', error: '', signedIn: false, usageToday: {}, sessions: [], lastReportAt: null, createdAt: now(), updatedAt: now() }
|
|
1017
1017
|
aiVms.set(userId, row); return copy(row)
|
|
1018
1018
|
},
|
|
1019
1019
|
async aiVmOf (userId) { return copy(aiVms.get(userId)) },
|
package/src/api/routes/ai-vm.js
CHANGED
|
@@ -69,14 +69,14 @@ export async function cloudAiOf (store, agent) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export function aiVmRoutes ({ store, person, agentAuth, bearer, now, apiUrl, log = () => {}, limit, relaySecret = '', relayUrl = HOSTED_RELAY, fly = null, waitMs = WAIT_MS, sparesEveryMs = SPARES_EVERY_MS, spareSuspendMs = 1000 }) {
|
|
72
|
-
// user id -> { version, signIn,
|
|
72
|
+
// user id -> { version, signIn, waiters, forVm: { follow, leave, signIn, code, config, waiters } }
|
|
73
73
|
const live = new Map()
|
|
74
74
|
const ownRelay = String(relayUrl).replace(/\/+$/, '').replace(/^http(s?):\/\//, 'ws$1://')
|
|
75
75
|
const relayWokeAt = new Map()
|
|
76
76
|
|
|
77
77
|
const liveOf = (userId) => {
|
|
78
78
|
let l = live.get(userId)
|
|
79
|
-
if (!l) { l = { version: 1, signIn: null,
|
|
79
|
+
if (!l) { l = { version: 1, signIn: null, waiters: new Set(), forVm: { follow: [], leave: [], signIn: false, code: null, config: false, waiters: new Set() } }; live.set(userId, l) }
|
|
80
80
|
return l
|
|
81
81
|
}
|
|
82
82
|
const wakeWaiters = (set) => { for (const w of [...set]) w(); set.clear() }
|
|
@@ -210,7 +210,8 @@ export function aiVmRoutes ({ store, person, agentAuth, bearer, now, apiUrl, log
|
|
|
210
210
|
error: vm.error,
|
|
211
211
|
signedIn: vm.signedIn,
|
|
212
212
|
signIn: l.signIn,
|
|
213
|
-
|
|
213
|
+
// Kept with the record: shown while the machine sleeps, and after the API restarts.
|
|
214
|
+
sessions: Array.isArray(vm.sessions) ? vm.sessions : [],
|
|
214
215
|
usageToday: vm.usageToday || {},
|
|
215
216
|
region: vm.region,
|
|
216
217
|
lastReportAt: vm.lastReportAt,
|
|
@@ -421,7 +422,7 @@ export function aiVmRoutes ({ store, person, agentAuth, bearer, now, apiUrl, log
|
|
|
421
422
|
if (typeof body.signedIn === 'boolean') patch.signedIn = body.signedIn
|
|
422
423
|
if (body.usageToday !== undefined) patch.usageToday = cleanUsage(body.usageToday)
|
|
423
424
|
if (body.signIn !== undefined) l.signIn = cleanSignIn(body.signIn)
|
|
424
|
-
if (body.sessions !== undefined)
|
|
425
|
+
if (body.sessions !== undefined) patch.sessions = cleanSessions(body.sessions)
|
|
425
426
|
await store.updateAiVm(vm.userId, patch)
|
|
426
427
|
bump(vm.userId)
|
|
427
428
|
return { ok: true }
|
|
@@ -38,7 +38,7 @@ const AGENT_PLACEMENT = 'agent_id, reach, workspace_ids, sessions, access, scope
|
|
|
38
38
|
const WORKSPACE_AGENT_OVERRIDE = 'workspace_id, agent_id, sessions, excluded'
|
|
39
39
|
const SESSION_AGENT_EXCLUSION = 'room, agent_id, excluded_by, created_at'
|
|
40
40
|
const AGENT_WEBHOOK = 'agent_id, url, secret, created_at, updated_at'
|
|
41
|
-
const AI_VM = 'user_id, tool, model, prompt, cap, agent_id, invite_id, machine_id, volume_id, region, state, error, signed_in, usage_today, last_report_at, created_at, updated_at'
|
|
41
|
+
const AI_VM = 'user_id, tool, model, prompt, cap, agent_id, invite_id, machine_id, volume_id, region, state, error, signed_in, usage_today, sessions, last_report_at, created_at, updated_at'
|
|
42
42
|
const RELAY_MACHINE = 'id, region, capacity, state, dedicated_room, load, hot_at, over_at, empty_at, hello_at, reported_at, created_at'
|
|
43
43
|
const RELAY_ROOM = 'room, machine_id, state, stats, busy_minutes, heavy, placed_at, reported_at, moved_at'
|
|
44
44
|
const RELAY_JOB = 'key, state, detail, started_at, finished_at'
|
package/src/ui-server.js
CHANGED
|
@@ -555,7 +555,10 @@ export async function startUi ({ port = 7420, onShutdown, preview = false, repor
|
|
|
555
555
|
if (!vm) { handed.clear(); return { vm: null } }
|
|
556
556
|
followOpen(vm)
|
|
557
557
|
const person = readAccount()?.account?.name || profile().name || 'You'
|
|
558
|
-
|
|
558
|
+
// A session nobody named is shown as the app shows it: by this computer's folder for it.
|
|
559
|
+
const local = new Map([...runs.values()].filter((e) => e.run && e.run.session).map((e) => [e.run.session.room, e.run.session.sessionName || path.basename(e.run.dir || '')]))
|
|
560
|
+
const sessions = (vm.sessions || []).map((x) => (x.name ? x : { ...x, name: local.get(x.room) || '' }))
|
|
561
|
+
return { vm: { ...vm, sessions, name: personaName(person, CLOUD_LABEL) } }
|
|
559
562
|
}
|
|
560
563
|
const cloudNone = (err) => { if (err.status === 404) return cloudView(null); throw err }
|
|
561
564
|
/** What Settings may change: the tool, model, instructions and daily cap (blank is no cap). */
|