ultracontext 1.4.13 → 1.5.0
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/dist/cli/entry.mjs +3 -3
- package/dist/cli/sdk-sync.mjs +259 -33
- package/dist/cli/sdk-sync.mjs.map +1 -1
- package/dist/{ctl-CXfNEPN8.mjs → ctl-_C5oTsoT.mjs} +2 -2
- package/dist/{ctl-CXfNEPN8.mjs.map → ctl-_C5oTsoT.mjs.map} +1 -1
- package/dist/{launcher-BMMjzr5k.mjs → launcher-374b809z.mjs} +3 -3
- package/dist/{launcher-BMMjzr5k.mjs.map → launcher-374b809z.mjs.map} +1 -1
- package/dist/{lock-5aJnda81.mjs → lock-DtnsoNoW.mjs} +2 -2
- package/dist/{lock-5aJnda81.mjs.map → lock-DtnsoNoW.mjs.map} +1 -1
- package/dist/{tui-DZ1SDOH2.mjs → tui-zO1IZH_S.mjs} +206 -24
- package/dist/tui-zO1IZH_S.mjs.map +1 -0
- package/dist/{utils-CmuIYHtm.mjs → utils-BiZUI99i.mjs} +18 -2
- package/dist/utils-BiZUI99i.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/tui-DZ1SDOH2.mjs.map +0 -1
- package/dist/utils-CmuIYHtm.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as resolveDaemonInfoFile } from "./protocol-BI9ficcl.mjs";
|
|
2
|
-
import { n as resolveLockPath } from "./lock-
|
|
2
|
+
import { n as resolveLockPath } from "./lock-DtnsoNoW.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
@@ -118,4 +118,4 @@ if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/.*\//,
|
|
|
118
118
|
|
|
119
119
|
//#endregion
|
|
120
120
|
export { runCtl };
|
|
121
|
-
//# sourceMappingURL=ctl-
|
|
121
|
+
//# sourceMappingURL=ctl-_C5oTsoT.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ctl-
|
|
1
|
+
{"version":3,"file":"ctl-_C5oTsoT.mjs","names":[],"sources":["../../sync/src/ctl.mjs"],"sourcesContent":["// daemon ctl — status/stop commands, exported as runCtl()\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport process from \"node:process\";\n\nimport { resolveDaemonInfoFile } from \"./protocol.mjs\";\n\nimport { resolveLockPath } from \"./lock.mjs\";\n\nfunction isPidAlive(pid) {\n if (!Number.isInteger(pid) || pid <= 1) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if (error?.code === \"EPERM\") return true;\n if (error?.code === \"ESRCH\") return false;\n return false;\n }\n}\n\nasync function readJsonFile(filePath) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n}\n\nasync function removeFileIfExists(filePath) {\n try { await fs.unlink(filePath); } catch { /* ignore */ }\n}\n\nfunction pickPid(lock, info) {\n const lockPid = Number.parseInt(String(lock?.pid ?? \"\"), 10);\n if (Number.isInteger(lockPid) && lockPid > 1) return lockPid;\n const infoPid = Number.parseInt(String(info?.pid ?? \"\"), 10);\n if (Number.isInteger(infoPid) && infoPid > 1) return infoPid;\n return 0;\n}\n\n// ── ANSI helpers ────────────────────────────────────────────────\n\nconst isTTY = process.stdout.isTTY;\nconst esc = (code) => (isTTY ? `\\x1b[${code}m` : \"\");\nconst r = esc(0);\nconst b = esc(1);\nconst d = esc(2);\nconst blue = esc(\"38;2;47;111;179\");\nconst green = esc(\"38;2;80;200;120\");\nconst red = esc(\"38;2;220;80;80\");\nconst gray = esc(\"38;5;245\");\n\n// ── commands ────────────────────────────────────────────────────\n\nasync function status({ lockPath, infoPath }) {\n const lock = await readJsonFile(lockPath);\n const info = await readJsonFile(infoPath);\n const pid = pickPid(lock, info);\n\n console.log(\"\");\n console.log(` ${blue}${b}UltraContext${r} ${d}Daemon${r}`);\n console.log(\"\");\n\n if (!isPidAlive(pid)) {\n console.log(` ${gray}○${r} ${d}Offline${r}`);\n console.log(\"\");\n return 0;\n }\n\n const port = Number.parseInt(String(info?.port ?? \"\"), 10);\n const portStr = Number.isInteger(port) && port > 0 ? ` ${gray}Port ${port}${r}` : \"\";\n const sinceStr = info?.startedAt ? ` ${gray}Since ${info.startedAt}${r}` : \"\";\n console.log(` ${green}●${r} ${b}Online${r} ${gray}PID ${pid}${r}${portStr}`);\n if (sinceStr) console.log(` ${sinceStr}`);\n console.log(\"\");\n return 0;\n}\n\nasync function stop({ lockPath, infoPath }) {\n const lock = await readJsonFile(lockPath);\n const info = await readJsonFile(infoPath);\n const pid = pickPid(lock, info);\n\n console.log(\"\");\n console.log(` ${blue}${b}UltraContext${r} ${d}Daemon${r}`);\n console.log(\"\");\n\n if (!isPidAlive(pid)) {\n await removeFileIfExists(lockPath);\n await removeFileIfExists(infoPath);\n console.log(` ${gray}○${r} ${d}Already stopped${r}`);\n console.log(\"\");\n return 0;\n }\n\n process.kill(pid, \"SIGTERM\");\n\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n if (!isPidAlive(pid)) break;\n await new Promise((resolve) => setTimeout(resolve, 120));\n }\n\n if (isPidAlive(pid)) {\n console.error(` ${red}✕${r} ${b}Timed out${r} ${gray}PID ${pid} still running${r}`);\n console.error(\"\");\n return 1;\n }\n\n await removeFileIfExists(lockPath);\n await removeFileIfExists(infoPath);\n console.log(` ${green}✓${r} ${b}Stopped${r} ${gray}PID ${pid}${r}`);\n console.log(\"\");\n return 0;\n}\n\n// ── exported entry point ────────────────────────────────────────\n\nexport async function runCtl() {\n const cmd = String(process.argv[2] ?? \"status\").trim().toLowerCase();\n const lockPath = path.resolve(resolveLockPath(process.env));\n const infoPath = path.resolve(resolveDaemonInfoFile(process.env));\n\n if (cmd === \"status\") return status({ lockPath, infoPath });\n if (cmd === \"stop\") return stop({ lockPath, infoPath });\n\n console.error(`Invalid command: ${cmd}`);\n console.error(\"Use: ultracontext [status|stop]\");\n return 1;\n}\n\n// auto-exec when run directly\nconst isDirectRun = process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/.*\\//, \"\"));\nif (isDirectRun) {\n runCtl().then((code) => process.exit(code)).catch((error) => {\n console.error(`Daemon control failed: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { s as expandHome } from "./utils-
|
|
2
|
-
import { n as resolveLockPath } from "./lock-
|
|
1
|
+
import { s as expandHome } from "./utils-BiZUI99i.mjs";
|
|
2
|
+
import { n as resolveLockPath } from "./lock-DtnsoNoW.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import path from "node:path";
|
|
@@ -137,4 +137,4 @@ if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/.*\//,
|
|
|
137
137
|
|
|
138
138
|
//#endregion
|
|
139
139
|
export { launchDaemon };
|
|
140
|
-
//# sourceMappingURL=launcher-
|
|
140
|
+
//# sourceMappingURL=launcher-374b809z.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launcher-
|
|
1
|
+
{"version":3,"file":"launcher-374b809z.mjs","names":["fs","fsSync"],"sources":["../../sync/src/launcher.mjs"],"sourcesContent":["// daemon launcher — spawns daemon in background, exported as launchDaemon()\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { spawn } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\n\n\nimport { resolveLockPath } from \"./lock.mjs\";\nimport { expandHome } from \"./utils.mjs\";\n\nconst DEFAULT_LOG_FILE = \"~/.ultracontext/daemon.log\";\n\n// ── ANSI helpers ────────────────────────────────────────────────\n\nconst isTTY = process.stdout.isTTY;\nconst esc = (code) => (isTTY ? `\\x1b[${code}m` : \"\");\nconst reset = esc(0);\nconst bold = esc(1);\nconst dim = esc(2);\nconst blue = esc(\"38;2;47;111;179\");\nconst cyan = esc(\"38;2;126;195;255\");\nconst green = esc(\"38;2;80;200;120\");\nconst red = esc(\"38;2;220;80;80\");\nconst gray = esc(\"38;5;245\");\n\n// ── process helpers ─────────────────────────────────────────────\n\nfunction isPidAlive(pid) {\n if (!Number.isInteger(pid) || pid <= 1) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if (error?.code === \"EPERM\") return true;\n if (error?.code === \"ESRCH\") return false;\n return false;\n }\n}\n\nasync function readJsonFile(filePath) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n}\n\nasync function readLogTail(logPath, lines = 12) {\n try {\n const raw = await fs.readFile(logPath, \"utf8\");\n const allLines = raw.split(\"\\n\").map((l) => l.trimEnd()).filter(Boolean);\n return allLines.length === 0 ? [] : allLines.slice(-Math.max(lines, 1));\n } catch {\n return [];\n }\n}\n\nfunction resolveDaemonLogFile(env = process.env) {\n return expandHome(env.ULTRACONTEXT_DAEMON_LOG_FILE ?? DEFAULT_LOG_FILE);\n}\n\nasync function resolveRunningProcess(lockPath) {\n const lock = await readJsonFile(lockPath);\n const lockPid = Number.parseInt(String(lock?.pid ?? \"\"), 10);\n if (isPidAlive(lockPid)) {\n return { pid: lockPid, startedAt: String(lock?.startedAt ?? \"\"), userId: String(lock?.userId ?? \"\"), host: String(lock?.host ?? \"\") };\n }\n return null;\n}\n\nasync function resolveWritableLogPath(preferredPath) {\n const primary = path.resolve(preferredPath);\n try {\n await fs.mkdir(path.dirname(primary), { recursive: true });\n fsSync.accessSync(path.dirname(primary), fsSync.constants.W_OK);\n return primary;\n } catch {\n const fallback = path.resolve(process.cwd(), \".ultracontext-daemon.log\");\n await fs.mkdir(path.dirname(fallback), { recursive: true });\n return fallback;\n }\n}\n\n// ── exported entry point ────────────────────────────────────────\n\nexport async function launchDaemon({ entryPath, diagnosticsHint } = {}) {\n const resolvedEntry = entryPath ?? fileURLToPath(new URL(\"./index.mjs\", import.meta.url));\n const hint = diagnosticsHint ?? \"pnpm --filter @ultracontext/sync run start\";\n\n const lockPath = path.resolve(resolveLockPath(process.env));\n const preferredLogPath = resolveDaemonLogFile(process.env);\n\n console.log(\"\");\n console.log(` ${blue}${bold}UltraContext${reset} ${dim}Daemon${reset}`);\n console.log(\"\");\n\n // already running\n const running = await resolveRunningProcess(lockPath);\n if (running) {\n console.log(` ${cyan}●${reset} ${bold}Already running${reset} ${gray}PID ${running.pid}${reset}`);\n console.log(\"\");\n process.exit(2);\n return;\n }\n\n // spawn daemon\n const logPath = await resolveWritableLogPath(preferredLogPath);\n const outFd = fsSync.openSync(logPath, \"a\");\n const errFd = fsSync.openSync(logPath, \"a\");\n\n let child;\n try {\n child = spawn(process.execPath, [resolvedEntry, \"--daemon\"], {\n env: process.env,\n detached: false,\n stdio: [\"ignore\", outFd, errFd],\n });\n child.unref();\n } finally {\n try { fsSync.closeSync(outFd); } catch { /* ignore */ }\n try { fsSync.closeSync(errFd); } catch { /* ignore */ }\n }\n\n await new Promise((resolve) => setTimeout(resolve, 350));\n\n // failed\n if (!isPidAlive(child.pid)) {\n console.log(` ${red}✕${reset} ${bold}Failed to start${reset}`);\n const tail = await readLogTail(logPath);\n if (tail.length > 0) {\n console.log(\"\");\n for (const line of tail) console.error(` ${gray}${line}${reset}`);\n }\n console.log(\"\");\n console.log(` ${dim}Try: ${hint}${reset}`);\n console.log(\"\");\n process.exit(1);\n return;\n }\n\n // success\n console.log(` ${green}✓${reset} ${bold}Started${reset} ${gray}PID ${child.pid}${reset}`);\n console.log(` ${gray}${logPath}${reset}`);\n console.log(\"\");\n}\n\n// auto-exec when run directly\nconst isDirectRun = process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/.*\\//, \"\"));\nif (isDirectRun) {\n launchDaemon().catch((error) => {\n console.error(` ${red}✕${reset} ${error instanceof Error ? error.message : String(error)}`);\n console.error(\"\");\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as expandHome } from "./utils-
|
|
1
|
+
import { s as expandHome } from "./utils-BiZUI99i.mjs";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
@@ -78,4 +78,4 @@ async function acquireFileLock({ lockPath = resolveLockPath(process.env), userId
|
|
|
78
78
|
|
|
79
79
|
//#endregion
|
|
80
80
|
export { resolveLockPath as n, acquireFileLock as t };
|
|
81
|
-
//# sourceMappingURL=lock-
|
|
81
|
+
//# sourceMappingURL=lock-DtnsoNoW.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-
|
|
1
|
+
{"version":3,"file":"lock-DtnsoNoW.mjs","names":[],"sources":["../../sync/src/lock.mjs"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport process from \"node:process\";\n\nimport { expandHome } from \"./utils.mjs\";\n\nconst DEFAULT_LOCK_PATH = \"~/.ultracontext/daemon.lock\";\n\nfunction isPidAlive(pid) {\n if (!Number.isInteger(pid) || pid <= 1) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if (error?.code === \"EPERM\") return true;\n if (error?.code === \"ESRCH\") return false;\n return false;\n }\n}\n\nasync function readExistingLock(lockPath) {\n try {\n const raw = await fs.readFile(lockPath, \"utf8\");\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function resolveLockPath(env = process.env) {\n return expandHome(env.ULTRACONTEXT_LOCK_FILE ?? DEFAULT_LOCK_PATH);\n}\n\nexport async function acquireFileLock({\n lockPath = resolveLockPath(process.env),\n userId = \"\",\n host = \"\",\n} = {}) {\n const resolved = path.resolve(lockPath);\n await fs.mkdir(path.dirname(resolved), { recursive: true });\n\n let handle;\n try {\n handle = await fs.open(resolved, \"wx\");\n } catch (error) {\n if (error?.code !== \"EEXIST\") throw error;\n\n const existing = await readExistingLock(resolved);\n const existingPid = Number.parseInt(String(existing?.pid ?? \"\"), 10);\n if (!isPidAlive(existingPid)) {\n try {\n await fs.unlink(resolved);\n } catch {\n // ignore\n }\n handle = await fs.open(resolved, \"wx\");\n } else {\n const reason = existingPid\n ? `UltraContext daemon already running (PID: ${existingPid})`\n : \"UltraContext daemon already running\";\n const lockError = new Error(reason);\n lockError.code = \"ELOCKED\";\n lockError.pid = existingPid;\n throw lockError;\n }\n }\n\n const payload = {\n pid: process.pid,\n host: String(host ?? \"\"),\n userId: String(userId ?? \"\"),\n startedAt: new Date().toISOString(),\n };\n await handle.writeFile(`${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n\n let released = false;\n const release = async () => {\n if (released) return;\n released = true;\n try {\n await handle.close();\n } catch {\n // ignore\n }\n try {\n await fs.unlink(resolved);\n } catch {\n // ignore\n }\n };\n\n return {\n lockPath: resolved,\n payload,\n release,\n };\n}\n"],"mappings":";;;;;;AAMA,MAAM,oBAAoB;AAE1B,SAAS,WAAW,KAAK;AACvB,KAAI,CAAC,OAAO,UAAU,IAAI,IAAI,OAAO,EAAG,QAAO;AAC/C,KAAI;AACF,UAAQ,KAAK,KAAK,EAAE;AACpB,SAAO;UACA,OAAO;AACd,MAAI,OAAO,SAAS,QAAS,QAAO;AACpC,MAAI,OAAO,SAAS,QAAS,QAAO;AACpC,SAAO;;;AAIX,eAAe,iBAAiB,UAAU;AACxC,KAAI;EACF,MAAM,MAAM,MAAM,GAAG,SAAS,UAAU,OAAO;EAC/C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAO,UAAU,OAAO,WAAW,WAAW,SAAS;SACjD;AACN,SAAO;;;AAIX,SAAgB,gBAAgB,MAAM,QAAQ,KAAK;AACjD,QAAO,WAAW,IAAI,0BAA0B,kBAAkB;;AAGpE,eAAsB,gBAAgB,EACpC,WAAW,gBAAgB,QAAQ,IAAI,EACvC,SAAS,IACT,OAAO,OACL,EAAE,EAAE;CACN,MAAM,WAAW,KAAK,QAAQ,SAAS;AACvC,OAAM,GAAG,MAAM,KAAK,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;CAE3D,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,GAAG,KAAK,UAAU,KAAK;UAC/B,OAAO;AACd,MAAI,OAAO,SAAS,SAAU,OAAM;EAEpC,MAAM,WAAW,MAAM,iBAAiB,SAAS;EACjD,MAAM,cAAc,OAAO,SAAS,OAAO,UAAU,OAAO,GAAG,EAAE,GAAG;AACpE,MAAI,CAAC,WAAW,YAAY,EAAE;AAC5B,OAAI;AACF,UAAM,GAAG,OAAO,SAAS;WACnB;AAGR,YAAS,MAAM,GAAG,KAAK,UAAU,KAAK;SACjC;GACL,MAAM,SAAS,cACX,6CAA6C,YAAY,KACzD;GACJ,MAAM,YAAY,IAAI,MAAM,OAAO;AACnC,aAAU,OAAO;AACjB,aAAU,MAAM;AAChB,SAAM;;;CAIV,MAAM,UAAU;EACd,KAAK,QAAQ;EACb,MAAM,OAAO,QAAQ,GAAG;EACxB,QAAQ,OAAO,UAAU,GAAG;EAC5B,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;AACD,OAAM,OAAO,UAAU,GAAG,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC,KAAK,OAAO;CAEvE,IAAI,WAAW;CACf,MAAM,UAAU,YAAY;AAC1B,MAAI,SAAU;AACd,aAAW;AACX,MAAI;AACF,SAAM,OAAO,OAAO;UACd;AAGR,MAAI;AACF,SAAM,GAAG,OAAO,SAAS;UACnB;;AAKV,QAAO;EACL,UAAU;EACV;EACA;EACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as UC_CLAUDE_ORANGE, c as heroArtForWidth, i as UC_BRAND_BLUE, n as MENU_TABS, o as UC_CODEX_BLUE, r as UC_BLUE_LIGHT, s as UC_OPENCLAW_RED, t as Spinner } from "./Spinner-CwBjkXHv.mjs";
|
|
2
|
-
import { i as toInt, s as expandHome, t as boolFromEnv } from "./utils-
|
|
2
|
+
import { i as toInt, s as expandHome, t as boolFromEnv } from "./utils-BiZUI99i.mjs";
|
|
3
3
|
import { n as normalizeBootstrapMode } from "./protocol-BI9ficcl.mjs";
|
|
4
4
|
import { i as writeClaudeSession, n as writeCodexSession, r as hasLocalClaudeSession, t as hasLocalCodexSession } from "./cli/sdk-sync.mjs";
|
|
5
5
|
import process$1 from "node:process";
|
|
@@ -210,6 +210,10 @@ function handleContextsViewInput({ input, key, actions, snapshot }) {
|
|
|
210
210
|
actions.moveResume(1);
|
|
211
211
|
return true;
|
|
212
212
|
}
|
|
213
|
+
if (input === "f") {
|
|
214
|
+
actions.cycleSourceFilter();
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
213
217
|
if (input === "r") {
|
|
214
218
|
actions.refreshResume();
|
|
215
219
|
return true;
|
|
@@ -333,7 +337,7 @@ function createInputHandler({ snapshot, actions, focusMode, menuIndex, selectedT
|
|
|
333
337
|
//#endregion
|
|
334
338
|
//#region ../sync/src/ui/format.mjs
|
|
335
339
|
function compact(value, max = 80) {
|
|
336
|
-
const raw = String(value ?? "");
|
|
340
|
+
const raw = String(value ?? "").replace(/[\r\n\t\v\f\x00-\x1f]+/g, " ");
|
|
337
341
|
if (raw.length <= max) return raw;
|
|
338
342
|
if (max <= 3) return raw.slice(0, max);
|
|
339
343
|
return `${raw.slice(0, max - 3)}...`;
|
|
@@ -413,7 +417,7 @@ function footerHelpText({ updatePromptActive, bootstrapActive, resumeTargetPicke
|
|
|
413
417
|
if (resumeTargetPickerActive) return "Resume target: choose Claude Code or Codex (↑/↓, 1/2, Enter), Esc/← cancel.";
|
|
414
418
|
if (focusMode !== "view") return "Controls: ↑/↓ navigate, Enter focus/open, ← back, q/Ctrl+C quit.";
|
|
415
419
|
if (selectedTab === "contexts" && detailViewActive) return "Detail: ↑/↓ messages, j/k lines, r refresh, Esc/← back.";
|
|
416
|
-
if (selectedTab === "contexts") return "Contexts: ↑/↓ select, Enter open, r refresh, ← back, q/Ctrl+C quit.";
|
|
420
|
+
if (selectedTab === "contexts") return "Contexts: ↑/↓ select, Enter open, f filter, r refresh, ← back, q/Ctrl+C quit.";
|
|
417
421
|
if (selectedTab === "configs") return "Controls: ↑/↓ select config, Enter/→ apply, ← back, q/Ctrl+C quit.";
|
|
418
422
|
return "Controls: ↑/↓ navigate, Enter focus/open, ← back, q/Ctrl+C quit.";
|
|
419
423
|
}
|
|
@@ -863,16 +867,60 @@ function renderHeader({ badge, dv, scrollInfo }) {
|
|
|
863
867
|
|
|
864
868
|
//#endregion
|
|
865
869
|
//#region ../sync/src/ui/panels/ContextsContent.mjs
|
|
870
|
+
function renderFilterBar(activeFilter) {
|
|
871
|
+
const parts = [
|
|
872
|
+
{
|
|
873
|
+
id: "all",
|
|
874
|
+
label: "All",
|
|
875
|
+
color: "white"
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
id: "claude",
|
|
879
|
+
label: "Claude",
|
|
880
|
+
color: UC_CLAUDE_ORANGE
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
id: "codex",
|
|
884
|
+
label: "Codex",
|
|
885
|
+
color: UC_CODEX_BLUE
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
id: "openclaw",
|
|
889
|
+
label: "OpenClaw",
|
|
890
|
+
color: UC_OPENCLAW_RED
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
id: "cursor",
|
|
894
|
+
label: "Cursor",
|
|
895
|
+
color: "cyan"
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
id: "gemini",
|
|
899
|
+
label: "Gemini",
|
|
900
|
+
color: "blue"
|
|
901
|
+
}
|
|
902
|
+
].map((f) => React.createElement(Text, {
|
|
903
|
+
key: `filter-${f.id}`,
|
|
904
|
+
color: activeFilter === f.id ? f.color : "gray",
|
|
905
|
+
bold: activeFilter === f.id,
|
|
906
|
+
dimColor: activeFilter !== f.id
|
|
907
|
+
}, activeFilter === f.id ? `[${f.label}]` : ` ${f.label} `));
|
|
908
|
+
return React.createElement(Box, {
|
|
909
|
+
key: "filter-bar",
|
|
910
|
+
flexDirection: "row",
|
|
911
|
+
gap: 1
|
|
912
|
+
}, ...parts);
|
|
913
|
+
}
|
|
866
914
|
function ContextsContent({ snapshot, viewFocused, maxRows, maxCols }) {
|
|
867
915
|
if (snapshot.detailView?.active) return React.createElement(ContextDetailContent, {
|
|
868
916
|
snapshot,
|
|
869
917
|
maxRows,
|
|
870
918
|
maxCols
|
|
871
919
|
});
|
|
872
|
-
const contexts = snapshot.resume.contexts;
|
|
920
|
+
const contexts = snapshot.resume.filteredContexts ?? snapshot.resume.contexts;
|
|
873
921
|
const total = contexts.length;
|
|
874
922
|
const selected = Math.max(Math.min(snapshot.resume.selectedIndex, Math.max(total - 1, 0)), 0);
|
|
875
|
-
const rows = [];
|
|
923
|
+
const rows = [renderFilterBar(snapshot.resume.sourceFilter ?? "all")];
|
|
876
924
|
const tailRows = [];
|
|
877
925
|
if (total > 0 && (snapshot.resume.notice || snapshot.resume.error || snapshot.resume.summaryPath || snapshot.resume.command)) {
|
|
878
926
|
const selectedContext = contexts[selected];
|
|
@@ -908,7 +956,7 @@ function ContextsContent({ snapshot, viewFocused, maxRows, maxCols }) {
|
|
|
908
956
|
color: "gray"
|
|
909
957
|
}, `command file: ${compact(snapshot.resume.commandPath, 120)}`));
|
|
910
958
|
const availableRows = Math.max(maxRows, 4);
|
|
911
|
-
const listCapacity = Math.max(availableRows - tailRows.length, 1);
|
|
959
|
+
const listCapacity = Math.max(availableRows - tailRows.length - 1, 1);
|
|
912
960
|
if (total === 0) rows.push(React.createElement(Text, {
|
|
913
961
|
key: "contexts-empty",
|
|
914
962
|
color: "yellow"
|
|
@@ -925,14 +973,14 @@ function ContextsContent({ snapshot, viewFocused, maxRows, maxCols }) {
|
|
|
925
973
|
const sourceInfo = contextBadge(md.source || "unknown");
|
|
926
974
|
const createdAt = formatContextDate(ctx?.created_at);
|
|
927
975
|
const user = compact(md.user_id ?? "-", 12);
|
|
928
|
-
const
|
|
976
|
+
const label = compact(md.title ?? md.session_id ?? "-", 48);
|
|
929
977
|
rows.push(React.createElement(Text, {
|
|
930
978
|
key: `contexts-row-${i}`,
|
|
931
979
|
color: rowColor
|
|
932
980
|
}, `${marker} `, React.createElement(Text, {
|
|
933
981
|
color: sourceInfo.color,
|
|
934
982
|
bold: true
|
|
935
|
-
}, `[${sourceInfo.text}]`), ` ${createdAt} ${user} ${
|
|
983
|
+
}, `[${sourceInfo.text}]`), ` ${createdAt} ${user} ${label}`));
|
|
936
984
|
}
|
|
937
985
|
}
|
|
938
986
|
rows.push(...tailRows);
|
|
@@ -1043,8 +1091,11 @@ function LogsContent({ snapshot, maxRows, maxCols = 100 }) {
|
|
|
1043
1091
|
wrap: "truncate-end"
|
|
1044
1092
|
}, fitToWidth("waiting for activity...", safeCols)));
|
|
1045
1093
|
else rows.push(...visibleLogs.map((entry, index) => {
|
|
1046
|
-
const category = classifyLog(entry);
|
|
1047
1094
|
const sourceTag = entry.source ? `[${sourceLabel(entry.source)}]` : "";
|
|
1095
|
+
const category = sourceTag ? {
|
|
1096
|
+
label: "",
|
|
1097
|
+
color: "gray"
|
|
1098
|
+
} : classifyLog(entry);
|
|
1048
1099
|
const timePrefix = `${String(entry.ts ?? "--:--:--")} `;
|
|
1049
1100
|
const typePrefix = category.label ? `[${category.label}] ` : "";
|
|
1050
1101
|
const sourcePrefix = sourceTag ? `${sourceTag} ` : "";
|
|
@@ -1411,7 +1462,7 @@ function DaemonTui({ snapshot, actions }) {
|
|
|
1411
1462
|
const left = fitToWidth(footerLeft, Math.max(footerWidth - quip.length - 2, 12));
|
|
1412
1463
|
const gap = " ".repeat(Math.max(footerWidth - left.length - quip.length, 1));
|
|
1413
1464
|
const footerRule = "─".repeat(Math.max(footerWidth, 1));
|
|
1414
|
-
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Box, { width: layout.containerWidth }, renderMainFrameTop(layout.containerWidth, snapshot.updateAvailable ? `UltraContext v${snapshot.currentVersion} ↑` : `UltraContext v${snapshot.currentVersion}`)), React.createElement(Box, {
|
|
1465
|
+
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Box, { width: layout.containerWidth }, renderMainFrameTop(layout.containerWidth, process.env.ULTRACONTEXT_DEV ? `UltraContext v${snapshot.currentVersion} [dev]` : snapshot.updateAvailable ? `UltraContext v${snapshot.currentVersion} ↑` : `UltraContext v${snapshot.currentVersion}`)), React.createElement(Box, {
|
|
1415
1466
|
borderStyle: "single",
|
|
1416
1467
|
borderTop: false,
|
|
1417
1468
|
borderColor: UC_BRAND_BLUE,
|
|
@@ -1538,6 +1589,14 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1538
1589
|
{
|
|
1539
1590
|
id: "warp",
|
|
1540
1591
|
label: "Warp"
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
id: "tmux",
|
|
1595
|
+
label: "tmux"
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
id: "cmux",
|
|
1599
|
+
label: "cmux"
|
|
1541
1600
|
}
|
|
1542
1601
|
];
|
|
1543
1602
|
const RESUME_TARGET_OPTIONS = [{
|
|
@@ -1551,6 +1610,14 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1551
1610
|
id: "inspect",
|
|
1552
1611
|
label: "Inspect messages"
|
|
1553
1612
|
};
|
|
1613
|
+
const SOURCE_FILTERS = [
|
|
1614
|
+
"all",
|
|
1615
|
+
"claude",
|
|
1616
|
+
"codex",
|
|
1617
|
+
"openclaw",
|
|
1618
|
+
"cursor",
|
|
1619
|
+
"gemini"
|
|
1620
|
+
];
|
|
1554
1621
|
const PERSISTED_CONFIG_FIELDS = [
|
|
1555
1622
|
"bootstrapMode",
|
|
1556
1623
|
"resumeTerminal",
|
|
@@ -1570,6 +1637,8 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1570
1637
|
const value = String(raw ?? "terminal").trim().toLowerCase();
|
|
1571
1638
|
if (value === "warp") return "warp";
|
|
1572
1639
|
if (value === "ghostty") return "ghostty";
|
|
1640
|
+
if (value === "tmux") return "tmux";
|
|
1641
|
+
if (value === "cmux") return "cmux";
|
|
1573
1642
|
return "terminal";
|
|
1574
1643
|
}
|
|
1575
1644
|
function resolveRuntimeConfigPath() {
|
|
@@ -1610,8 +1679,11 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1610
1679
|
};
|
|
1611
1680
|
function readTuiVersion() {
|
|
1612
1681
|
try {
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1682
|
+
const candidates = process$1.env.ULTRACONTEXT_DEV ? [path.resolve(APP_ROOT, "..", "js-sdk", "package.json"), path.resolve(APP_ROOT, "package.json")] : [path.resolve(APP_ROOT, "package.json")];
|
|
1683
|
+
for (const p of candidates) try {
|
|
1684
|
+
return JSON.parse(fs.readFileSync(p, "utf8")).version ?? "unknown";
|
|
1685
|
+
} catch {}
|
|
1686
|
+
return "unknown";
|
|
1615
1687
|
} catch {
|
|
1616
1688
|
return "unknown";
|
|
1617
1689
|
}
|
|
@@ -1637,6 +1709,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1637
1709
|
return false;
|
|
1638
1710
|
}
|
|
1639
1711
|
async function checkForUpdateSilent() {
|
|
1712
|
+
if (process$1.env.ULTRACONTEXT_DEV) return;
|
|
1640
1713
|
const current = readTuiVersion();
|
|
1641
1714
|
if (current === "unknown") return;
|
|
1642
1715
|
const notifyUpdate = (latest) => {
|
|
@@ -1674,6 +1747,8 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1674
1747
|
loading: false,
|
|
1675
1748
|
syncing: false,
|
|
1676
1749
|
contexts: [],
|
|
1750
|
+
filteredContexts: [],
|
|
1751
|
+
sourceFilter: "all",
|
|
1677
1752
|
selectedIndex: 0,
|
|
1678
1753
|
loadedAt: 0,
|
|
1679
1754
|
error: "",
|
|
@@ -1724,7 +1799,9 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
1724
1799
|
lastSnapshot: null,
|
|
1725
1800
|
cachedLogSlice: [],
|
|
1726
1801
|
cachedLogLen: 0,
|
|
1727
|
-
stopResolve: null
|
|
1802
|
+
stopResolve: null,
|
|
1803
|
+
titleCache: /* @__PURE__ */ new Map(),
|
|
1804
|
+
titleInflight: /* @__PURE__ */ new Set()
|
|
1728
1805
|
};
|
|
1729
1806
|
function applyDaemonStatus(status) {
|
|
1730
1807
|
if (!status) {
|
|
@@ -2036,7 +2113,49 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2036
2113
|
method: "ghostty_applescript"
|
|
2037
2114
|
};
|
|
2038
2115
|
}
|
|
2116
|
+
function resumeOpenCmuxTab(command) {
|
|
2117
|
+
return {
|
|
2118
|
+
...runAppleScriptLines([
|
|
2119
|
+
"set _uc_prev_clipboard to the clipboard",
|
|
2120
|
+
`set the clipboard to ${resumeAppleScriptString(command)}`,
|
|
2121
|
+
"tell application \"cmux\" to activate",
|
|
2122
|
+
"delay 0.4",
|
|
2123
|
+
"tell application \"System Events\"",
|
|
2124
|
+
"keystroke \"t\" using {command down}",
|
|
2125
|
+
"delay 0.3",
|
|
2126
|
+
"keystroke \"v\" using {command down}",
|
|
2127
|
+
"delay 0.15",
|
|
2128
|
+
"key code 36",
|
|
2129
|
+
"end tell",
|
|
2130
|
+
"delay 0.05",
|
|
2131
|
+
"set the clipboard to _uc_prev_clipboard"
|
|
2132
|
+
]),
|
|
2133
|
+
method: "cmux_applescript"
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function resumeOpenTmuxWindow(command) {
|
|
2137
|
+
if (!process$1.env.TMUX) return {
|
|
2138
|
+
ok: false,
|
|
2139
|
+
reason: "not inside a tmux session"
|
|
2140
|
+
};
|
|
2141
|
+
const out = spawnSync("tmux", ["new-window", command], {
|
|
2142
|
+
stdio: "pipe",
|
|
2143
|
+
encoding: "utf8",
|
|
2144
|
+
timeout: 5e3
|
|
2145
|
+
});
|
|
2146
|
+
if (out.status === 0) return {
|
|
2147
|
+
ok: true,
|
|
2148
|
+
method: "tmux"
|
|
2149
|
+
};
|
|
2150
|
+
return {
|
|
2151
|
+
ok: false,
|
|
2152
|
+
reason: out.stderr?.trim() || "tmux new-window failed",
|
|
2153
|
+
method: "tmux"
|
|
2154
|
+
};
|
|
2155
|
+
}
|
|
2039
2156
|
function resumeOpenTerminalTab(command) {
|
|
2157
|
+
if (cfg.resumeTerminal === "tmux") return resumeOpenTmuxWindow(command);
|
|
2158
|
+
if (cfg.resumeTerminal === "cmux") return resumeOpenCmuxTab(command);
|
|
2040
2159
|
if (process$1.platform !== "darwin") return {
|
|
2041
2160
|
ok: false,
|
|
2042
2161
|
reason: "open-tab is available only on macOS"
|
|
@@ -2110,6 +2229,21 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2110
2229
|
return true;
|
|
2111
2230
|
});
|
|
2112
2231
|
}
|
|
2232
|
+
function applySourceFilter() {
|
|
2233
|
+
const filter = ui.resume.sourceFilter;
|
|
2234
|
+
if (filter === "all") ui.resume.filteredContexts = ui.resume.contexts;
|
|
2235
|
+
else ui.resume.filteredContexts = ui.resume.contexts.filter((ctx) => {
|
|
2236
|
+
return String(ctx?.metadata?.source ?? "").toLowerCase() === filter;
|
|
2237
|
+
});
|
|
2238
|
+
if (ui.resume.selectedIndex >= ui.resume.filteredContexts.length) ui.resume.selectedIndex = Math.max(ui.resume.filteredContexts.length - 1, 0);
|
|
2239
|
+
}
|
|
2240
|
+
function cycleSourceFilter() {
|
|
2241
|
+
const current = ui.resume.sourceFilter;
|
|
2242
|
+
const idx = SOURCE_FILTERS.indexOf(current);
|
|
2243
|
+
ui.resume.sourceFilter = SOURCE_FILTERS[(idx + 1) % SOURCE_FILTERS.length];
|
|
2244
|
+
applySourceFilter();
|
|
2245
|
+
renderDashboard();
|
|
2246
|
+
}
|
|
2113
2247
|
function resumeSortContexts(contexts) {
|
|
2114
2248
|
const ts = (ctx) => {
|
|
2115
2249
|
const candidates = [
|
|
@@ -2201,6 +2335,42 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2201
2335
|
lines.push("", "## Resume Instructions", "1. Use the generated adapter command from the Contexts tab.", "2. Continue from the latest unresolved request.", "");
|
|
2202
2336
|
return lines.join("\n");
|
|
2203
2337
|
}
|
|
2338
|
+
function enrichContextTitles(contexts) {
|
|
2339
|
+
const missing = contexts.filter((ctx) => ctx?.id && !ctx?.metadata?.title && !runtime.titleCache.has(ctx.id) && !runtime.titleInflight.has(ctx.id)).slice(0, 20);
|
|
2340
|
+
if (!missing.length || !runtime.uc) return;
|
|
2341
|
+
for (const ctx of missing) {
|
|
2342
|
+
runtime.titleInflight.add(ctx.id);
|
|
2343
|
+
runtime.uc.get(ctx.id, { at: 30 }).then((res) => {
|
|
2344
|
+
const msgs = res?.data ?? [];
|
|
2345
|
+
const isRealUser = (m) => {
|
|
2346
|
+
if (m?.role !== "user") return false;
|
|
2347
|
+
if (m?.content?.event_type === "response_item.message") return false;
|
|
2348
|
+
const msg = typeof m?.content?.message === "string" ? m.content.message : "";
|
|
2349
|
+
if (msg.startsWith("A new session was started")) return false;
|
|
2350
|
+
if (msg.startsWith("[result]")) return false;
|
|
2351
|
+
if (msg.startsWith("<")) return false;
|
|
2352
|
+
return true;
|
|
2353
|
+
};
|
|
2354
|
+
const firstUser = msgs.find(isRealUser) ?? msgs.find((m) => m?.role === "user");
|
|
2355
|
+
if (!firstUser) {
|
|
2356
|
+
runtime.titleCache.set(ctx.id, null);
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
const text = firstUser?.content?.message ?? firstUser?.content ?? "";
|
|
2360
|
+
const title = (typeof text === "string" ? text : JSON.stringify(text)).replace(/[\r\n\t\v\f\x00-\x1f]+/g, " ").replace(/\s{2,}/g, " ").trim().slice(0, 120);
|
|
2361
|
+
runtime.titleCache.set(ctx.id, title || null);
|
|
2362
|
+
if (title) {
|
|
2363
|
+
ctx.metadata = {
|
|
2364
|
+
...ctx.metadata,
|
|
2365
|
+
title
|
|
2366
|
+
};
|
|
2367
|
+
markDirty();
|
|
2368
|
+
}
|
|
2369
|
+
}).catch(() => {
|
|
2370
|
+
runtime.titleCache.set(ctx.id, null);
|
|
2371
|
+
}).finally(() => runtime.titleInflight.delete(ctx.id));
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2204
2374
|
async function loadResumeContexts({ silent = false } = {}) {
|
|
2205
2375
|
if (!runtime.uc || ui.resume.loading) return;
|
|
2206
2376
|
ui.resume.loading = true;
|
|
@@ -2218,25 +2388,34 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2218
2388
|
}
|
|
2219
2389
|
runtime.resumeKnownContextIds = nextIds;
|
|
2220
2390
|
if (!runtime.resumeBaselineReady) runtime.resumeBaselineReady = true;
|
|
2391
|
+
for (const ctx of filtered) {
|
|
2392
|
+
const cached = runtime.titleCache.get(ctx.id);
|
|
2393
|
+
if (cached && !ctx.metadata?.title) ctx.metadata = {
|
|
2394
|
+
...ctx.metadata,
|
|
2395
|
+
title: cached
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2221
2398
|
ui.resume.contexts = filtered;
|
|
2222
|
-
|
|
2399
|
+
applySourceFilter();
|
|
2400
|
+
if (!silent) enrichContextTitles(filtered);
|
|
2223
2401
|
ui.resume.loadedAt = Date.now();
|
|
2224
2402
|
const sourceCounts = {
|
|
2225
2403
|
codex: 0,
|
|
2226
2404
|
claude: 0,
|
|
2227
2405
|
openclaw: 0,
|
|
2406
|
+
cursor: 0,
|
|
2407
|
+
gemini: 0,
|
|
2228
2408
|
other: 0
|
|
2229
2409
|
};
|
|
2230
2410
|
for (const ctx of filtered) {
|
|
2231
2411
|
const source = String(ctx?.metadata?.source ?? "").toLowerCase();
|
|
2232
|
-
if (source
|
|
2233
|
-
else if (source === "claude") sourceCounts.claude += 1;
|
|
2234
|
-
else if (source === "openclaw") sourceCounts.openclaw += 1;
|
|
2412
|
+
if (sourceCounts[source] !== void 0) sourceCounts[source] += 1;
|
|
2235
2413
|
else sourceCounts.other += 1;
|
|
2236
2414
|
}
|
|
2237
2415
|
if (!silent) {
|
|
2238
2416
|
const filterLabel = cfg.resumeSourceFilter === "all" ? "all sources" : cfg.resumeSourceFilter;
|
|
2239
|
-
|
|
2417
|
+
const counts = Object.entries(sourceCounts).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
2418
|
+
ui.resume.notice = `Loaded ${filtered.length} session contexts (${filterLabel}: ${counts})`;
|
|
2240
2419
|
if (filtered.length === 0) ui.resume.notice = `No contexts found for filter=${cfg.resumeSourceFilter}`;
|
|
2241
2420
|
}
|
|
2242
2421
|
} catch (error) {
|
|
@@ -2251,7 +2430,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2251
2430
|
}
|
|
2252
2431
|
}
|
|
2253
2432
|
function moveResumeSelection(delta) {
|
|
2254
|
-
const total = ui.resume.
|
|
2433
|
+
const total = ui.resume.filteredContexts.length;
|
|
2255
2434
|
if (!total) return;
|
|
2256
2435
|
const next = ui.resume.selectedIndex + delta;
|
|
2257
2436
|
if (next < 0) {
|
|
@@ -2271,7 +2450,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2271
2450
|
}
|
|
2272
2451
|
function openResumeTargetPicker() {
|
|
2273
2452
|
if (ui.resume.syncing) return false;
|
|
2274
|
-
const context = ui.resume.
|
|
2453
|
+
const context = ui.resume.filteredContexts[ui.resume.selectedIndex];
|
|
2275
2454
|
if (!context) {
|
|
2276
2455
|
ui.resume.notice = "No context selected";
|
|
2277
2456
|
renderDashboard();
|
|
@@ -2365,7 +2544,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2365
2544
|
}
|
|
2366
2545
|
async function resumeSelectedContext({ targetAgentOverride = "" } = {}) {
|
|
2367
2546
|
if (!runtime.uc || ui.resume.syncing) return;
|
|
2368
|
-
const context = ui.resume.
|
|
2547
|
+
const context = ui.resume.filteredContexts[ui.resume.selectedIndex];
|
|
2369
2548
|
if (!context) {
|
|
2370
2549
|
ui.resume.notice = "No context selected";
|
|
2371
2550
|
renderDashboard();
|
|
@@ -2669,7 +2848,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2669
2848
|
}
|
|
2670
2849
|
async function openContextDetail() {
|
|
2671
2850
|
if (ui.detailView.loading) return;
|
|
2672
|
-
const context = ui.resume.
|
|
2851
|
+
const context = ui.resume.filteredContexts[ui.resume.selectedIndex];
|
|
2673
2852
|
if (!context) return;
|
|
2674
2853
|
ui.detailView.active = true;
|
|
2675
2854
|
ui.detailView.contextId = context.id;
|
|
@@ -2733,7 +2912,7 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2733
2912
|
renderDashboard();
|
|
2734
2913
|
}
|
|
2735
2914
|
function enterContext() {
|
|
2736
|
-
const context = ui.resume.
|
|
2915
|
+
const context = ui.resume.filteredContexts[ui.resume.selectedIndex];
|
|
2737
2916
|
if (!context) {
|
|
2738
2917
|
ui.resume.notice = "No context selected";
|
|
2739
2918
|
renderDashboard();
|
|
@@ -2856,6 +3035,9 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2856
3035
|
refreshResume: () => {
|
|
2857
3036
|
loadResumeContexts();
|
|
2858
3037
|
},
|
|
3038
|
+
cycleSourceFilter: () => {
|
|
3039
|
+
cycleSourceFilter();
|
|
3040
|
+
},
|
|
2859
3041
|
promptResumeTarget: () => {
|
|
2860
3042
|
openResumeTargetPicker();
|
|
2861
3043
|
},
|
|
@@ -2949,4 +3131,4 @@ async function tuiBoot({ assetsRoot, onFatalError } = {}) {
|
|
|
2949
3131
|
|
|
2950
3132
|
//#endregion
|
|
2951
3133
|
export { tuiBoot };
|
|
2952
|
-
//# sourceMappingURL=tui-
|
|
3134
|
+
//# sourceMappingURL=tui-zO1IZH_S.mjs.map
|