omnius 1.0.603 → 1.0.605
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/index.js +442 -158
- package/dist/update-worker.js +294690 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -363,6 +363,7 @@ __export(update_service_exports, {
|
|
|
363
363
|
UpdateInProgressError: () => UpdateInProgressError,
|
|
364
364
|
assertExactUpdateTarget: () => assertExactUpdateTarget,
|
|
365
365
|
inspectGlobalOmniusInstall: () => inspectGlobalOmniusInstall,
|
|
366
|
+
readReconciledUpdateState: () => readReconciledUpdateState,
|
|
366
367
|
readUpdateLogTail: () => readUpdateLogTail,
|
|
367
368
|
readUpdateState: () => readUpdateState,
|
|
368
369
|
releaseUpdateLock: () => releaseUpdateLock,
|
|
@@ -373,6 +374,7 @@ __export(update_service_exports, {
|
|
|
373
374
|
updateStateFileIsPrivate: () => updateStateFileIsPrivate,
|
|
374
375
|
updateStateIsFreshRunning: () => updateStateIsFreshRunning,
|
|
375
376
|
updateStatusSnapshot: () => updateStatusSnapshot,
|
|
377
|
+
waitForUpdateTransaction: () => waitForUpdateTransaction,
|
|
376
378
|
writeUpdateState: () => writeUpdateState
|
|
377
379
|
});
|
|
378
380
|
import { spawn, spawnSync } from "node:child_process";
|
|
@@ -613,6 +615,68 @@ function transition(current, patch, paths) {
|
|
|
613
615
|
function permissionRemediation(evidence) {
|
|
614
616
|
return /EACCES|EPERM|permission denied/i.test(evidence) ? "The discovered npm global prefix is not writable. Configure a user-owned npm prefix or rerun the explicit update from a privileged terminal; Omnius never silently elevates." : void 0;
|
|
615
617
|
}
|
|
618
|
+
function installGlobalPackageStreaming(input) {
|
|
619
|
+
return new Promise((resolve87) => {
|
|
620
|
+
const stderrTail = [];
|
|
621
|
+
let settled = false;
|
|
622
|
+
let timedOut = false;
|
|
623
|
+
const finish = (exitCode, error) => {
|
|
624
|
+
if (settled) return;
|
|
625
|
+
settled = true;
|
|
626
|
+
clearTimeout(timer);
|
|
627
|
+
resolve87({ exitCode, ...error ? { error } : {} });
|
|
628
|
+
};
|
|
629
|
+
const child = spawn(
|
|
630
|
+
input.npmPath,
|
|
631
|
+
[
|
|
632
|
+
"install",
|
|
633
|
+
"-g",
|
|
634
|
+
`omnius@${input.targetVersion}`,
|
|
635
|
+
"--prefer-online",
|
|
636
|
+
"--no-audit",
|
|
637
|
+
"--no-fund",
|
|
638
|
+
"--no-progress"
|
|
639
|
+
],
|
|
640
|
+
{
|
|
641
|
+
env: input.env,
|
|
642
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
643
|
+
windowsHide: true
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
child.stdout?.on("data", (chunk) => {
|
|
647
|
+
process.stdout.write(chunk);
|
|
648
|
+
});
|
|
649
|
+
child.stderr?.on("data", (chunk) => {
|
|
650
|
+
const text2 = String(chunk);
|
|
651
|
+
process.stderr.write(text2);
|
|
652
|
+
stderrTail.push(text2);
|
|
653
|
+
while (stderrTail.join("").length > 8e3 && stderrTail.length > 1) stderrTail.shift();
|
|
654
|
+
});
|
|
655
|
+
child.once("error", (error) => finish(-1, error.message));
|
|
656
|
+
child.once("close", (code8, signal) => {
|
|
657
|
+
const exitCode = code8 ?? -1;
|
|
658
|
+
const evidence = stderrTail.join("").trim();
|
|
659
|
+
finish(
|
|
660
|
+
exitCode,
|
|
661
|
+
exitCode === 0 ? void 0 : timedOut ? "npm install timed out after 5 minutes" : evidence || `npm install exited with ${signal ? `signal ${signal}` : `code ${exitCode}`}`
|
|
662
|
+
);
|
|
663
|
+
});
|
|
664
|
+
const timer = setTimeout(() => {
|
|
665
|
+
timedOut = true;
|
|
666
|
+
try {
|
|
667
|
+
child.kill("SIGTERM");
|
|
668
|
+
} catch {
|
|
669
|
+
}
|
|
670
|
+
const forceTimer = setTimeout(() => {
|
|
671
|
+
try {
|
|
672
|
+
child.kill("SIGKILL");
|
|
673
|
+
} catch {
|
|
674
|
+
}
|
|
675
|
+
}, 2500);
|
|
676
|
+
forceTimer.unref?.();
|
|
677
|
+
}, 5 * 6e4);
|
|
678
|
+
});
|
|
679
|
+
}
|
|
616
680
|
async function runVerifiedUpdateTransaction(initial, dependencies, paths = resolveUpdatePaths()) {
|
|
617
681
|
let state = initial;
|
|
618
682
|
const target = assertExactUpdateTarget(initial.target_version);
|
|
@@ -632,27 +696,7 @@ async function runVerifiedUpdateTransaction(initial, dependencies, paths = resol
|
|
|
632
696
|
npm_path: npmPath,
|
|
633
697
|
...prefixProbe.status === 0 && prefixProbe.stdout.trim() ? { npm_prefix: prefixProbe.stdout.trim() } : {}
|
|
634
698
|
}, paths);
|
|
635
|
-
const installer = dependencies.install ??
|
|
636
|
-
const result = runSync(
|
|
637
|
-
command,
|
|
638
|
-
[
|
|
639
|
-
"install",
|
|
640
|
-
"-g",
|
|
641
|
-
`omnius@${targetVersion}`,
|
|
642
|
-
"--prefer-online",
|
|
643
|
-
"--no-audit",
|
|
644
|
-
"--no-fund",
|
|
645
|
-
"--no-progress"
|
|
646
|
-
],
|
|
647
|
-
{ env: childEnv, timeout: 5 * 6e4 }
|
|
648
|
-
);
|
|
649
|
-
if (result.stdout) process.stdout.write(result.stdout);
|
|
650
|
-
if (result.stderr) process.stderr.write(result.stderr);
|
|
651
|
-
return {
|
|
652
|
-
exitCode: result.status ?? -1,
|
|
653
|
-
...result.error || result.status !== 0 ? { error: result.error?.message || result.stderr.trim() || `npm install exited with code ${result.status ?? -1}` } : {}
|
|
654
|
-
};
|
|
655
|
-
});
|
|
699
|
+
const installer = dependencies.install ?? installGlobalPackageStreaming;
|
|
656
700
|
const installResult = await installer({ npmPath, targetVersion: target, env: env2 });
|
|
657
701
|
state = transition(state, { installer_exit_code: installResult.exitCode }, paths);
|
|
658
702
|
if (installResult.exitCode !== 0) {
|
|
@@ -721,6 +765,13 @@ function startDetachedGlobalUpdate(input, paths = resolveUpdatePaths()) {
|
|
|
721
765
|
const operationId = randomUUID();
|
|
722
766
|
const lockFd = acquireUpdateLock(operationId, paths);
|
|
723
767
|
closeSync(lockFd);
|
|
768
|
+
const workerPath = fileURLToPath(new URL("./update-worker.js", import.meta.url));
|
|
769
|
+
if (!existsSync2(workerPath)) {
|
|
770
|
+
releaseUpdateLock(paths, operationId);
|
|
771
|
+
throw new Error(
|
|
772
|
+
`The coordinated update worker is missing at ${workerPath}. Reinstall Omnius from a package that ships dist/update-worker.js.`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
724
775
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
725
776
|
let state = {
|
|
726
777
|
schema_version: 1,
|
|
@@ -737,10 +788,15 @@ function startDetachedGlobalUpdate(input, paths = resolveUpdatePaths()) {
|
|
|
737
788
|
tray_restarted: false
|
|
738
789
|
};
|
|
739
790
|
writeUpdateState(state, paths);
|
|
740
|
-
const workerPath = fileURLToPath(new URL("./update-worker.js", import.meta.url));
|
|
741
791
|
rotateUpdateLog(paths);
|
|
742
792
|
const logFd = openSync(paths.logFile, "a", 384);
|
|
743
793
|
try {
|
|
794
|
+
writeSync(
|
|
795
|
+
logFd,
|
|
796
|
+
`
|
|
797
|
+
[omnius update ${operationId}] ${input.fromVersion} -> ${targetVersion} ${now2}
|
|
798
|
+
`
|
|
799
|
+
);
|
|
744
800
|
const child = spawn(
|
|
745
801
|
process.execPath,
|
|
746
802
|
[
|
|
@@ -805,6 +861,32 @@ function updateStatusSnapshot(paths = resolveUpdatePaths()) {
|
|
|
805
861
|
log_tail: readUpdateLogTail(paths)
|
|
806
862
|
};
|
|
807
863
|
}
|
|
864
|
+
function readReconciledUpdateState(paths = resolveUpdatePaths()) {
|
|
865
|
+
const snapshot = updateStatusSnapshot(paths).state;
|
|
866
|
+
return snapshot.status === "idle" ? null : snapshot;
|
|
867
|
+
}
|
|
868
|
+
async function waitForUpdateTransaction(operationId, options2 = {}, paths = resolveUpdatePaths()) {
|
|
869
|
+
const pollIntervalMs = Math.max(25, options2.pollIntervalMs ?? 300);
|
|
870
|
+
const timeoutMs = Math.max(pollIntervalMs, options2.timeoutMs ?? 10 * 6e4);
|
|
871
|
+
const deadline = Date.now() + timeoutMs;
|
|
872
|
+
while (Date.now() <= deadline) {
|
|
873
|
+
const snapshot = updateStatusSnapshot(paths);
|
|
874
|
+
if (snapshot.state.status !== "idle") {
|
|
875
|
+
if (snapshot.state.operation_id !== operationId) {
|
|
876
|
+
throw new Error(
|
|
877
|
+
`Update operation changed from ${operationId} to ${snapshot.state.operation_id}`
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
options2.onProgress?.({
|
|
881
|
+
state: snapshot.state,
|
|
882
|
+
log_tail: snapshot.log_tail
|
|
883
|
+
});
|
|
884
|
+
if (snapshot.state.status !== "running") return snapshot.state;
|
|
885
|
+
}
|
|
886
|
+
await new Promise((resolve87) => setTimeout(resolve87, pollIntervalMs));
|
|
887
|
+
}
|
|
888
|
+
throw new Error(`Update operation ${operationId} did not finish within ${timeoutMs}ms`);
|
|
889
|
+
}
|
|
808
890
|
function updateStateIsFreshRunning(state) {
|
|
809
891
|
if (!state || state.status !== "running") return false;
|
|
810
892
|
if (isPidAlive(state.pid)) return true;
|
|
@@ -679731,7 +679813,7 @@ async function runTrayForeground(explicitEndpoint) {
|
|
|
679731
679813
|
let updateView = trayUpdatePresentation(
|
|
679732
679814
|
health.version,
|
|
679733
679815
|
availableUpdate?.latestVersion,
|
|
679734
|
-
|
|
679816
|
+
readReconciledUpdateState()
|
|
679735
679817
|
);
|
|
679736
679818
|
const menuState = menuForHealth(health, endpoint, registered, updateView);
|
|
679737
679819
|
const SysTray = await loadSysTray();
|
|
@@ -679773,7 +679855,7 @@ async function runTrayForeground(explicitEndpoint) {
|
|
|
679773
679855
|
updateView = trayUpdatePresentation(
|
|
679774
679856
|
health.version,
|
|
679775
679857
|
availableUpdate?.latestVersion,
|
|
679776
|
-
|
|
679858
|
+
readReconciledUpdateState()
|
|
679777
679859
|
);
|
|
679778
679860
|
menuState.updateItem.title = updateView.title;
|
|
679779
679861
|
menuState.updateItem.tooltip = updateView.tooltip;
|
|
@@ -679842,7 +679924,7 @@ async function runTrayForeground(explicitEndpoint) {
|
|
|
679842
679924
|
endpoint,
|
|
679843
679925
|
trayWasRunning: true
|
|
679844
679926
|
});
|
|
679845
|
-
updateView = trayUpdatePresentation(currentVersion, targetVersion,
|
|
679927
|
+
updateView = trayUpdatePresentation(currentVersion, targetVersion, readReconciledUpdateState());
|
|
679846
679928
|
if (updateView.enabled) {
|
|
679847
679929
|
updateView = {
|
|
679848
679930
|
title: `Updating to v${targetVersion} — starting`,
|
|
@@ -679879,7 +679961,7 @@ async function runTrayForeground(explicitEndpoint) {
|
|
|
679879
679961
|
updateView = trayUpdatePresentation(
|
|
679880
679962
|
currentVersion,
|
|
679881
679963
|
availableUpdate?.latestVersion,
|
|
679882
|
-
|
|
679964
|
+
readReconciledUpdateState()
|
|
679883
679965
|
);
|
|
679884
679966
|
menuState.updateItem.title = updateView.title;
|
|
679885
679967
|
menuState.updateItem.tooltip = updateView.tooltip;
|
|
@@ -703755,6 +703837,90 @@ var init_ollama_gpu_policy = __esm({
|
|
|
703755
703837
|
}
|
|
703756
703838
|
});
|
|
703757
703839
|
|
|
703840
|
+
// packages/cli/src/session-quality.ts
|
|
703841
|
+
function withoutAnsi(text2) {
|
|
703842
|
+
return String(text2 || "").replace(ANSI_RE, "");
|
|
703843
|
+
}
|
|
703844
|
+
function normalizeSessionDisplayText(text2) {
|
|
703845
|
+
return withoutAnsi(text2).trim().replace(MARKER_PREFIX_RE, "").replace(SPEAKER_RE, "").replace(/\s+/g, " ").trim();
|
|
703846
|
+
}
|
|
703847
|
+
function isSessionControlText(text2) {
|
|
703848
|
+
const raw = withoutAnsi(text2).trim().replace(/^[∙•·‹›▹▸▶►◆◇❯❮>\-=_*#|\\.\s]+/, "").replace(SPEAKER_RE, "").trim();
|
|
703849
|
+
return CONTROL_ONLY_RE.test(raw);
|
|
703850
|
+
}
|
|
703851
|
+
function isSessionNoiseText(text2) {
|
|
703852
|
+
const raw = withoutAnsi(text2).trim();
|
|
703853
|
+
if (!raw || raw.length < 3 || isSessionControlText(raw)) return true;
|
|
703854
|
+
if (BOX_OR_TOOL_CHROME_RE.test(raw)) return true;
|
|
703855
|
+
const core = normalizeSessionDisplayText(raw);
|
|
703856
|
+
if (!core || core.length < 3 || CONTROL_ONLY_RE.test(core)) return true;
|
|
703857
|
+
return STATUS_RE.test(core);
|
|
703858
|
+
}
|
|
703859
|
+
function firstMeaningfulSessionLine(transcript) {
|
|
703860
|
+
const lines = withoutAnsi(transcript).split(/\r?\n/).map((line) => line.trim());
|
|
703861
|
+
for (const line of lines) {
|
|
703862
|
+
if (USER_LINE_RE.test(line) && !isSessionNoiseText(line)) {
|
|
703863
|
+
return normalizeSessionDisplayText(line);
|
|
703864
|
+
}
|
|
703865
|
+
}
|
|
703866
|
+
for (const line of lines) {
|
|
703867
|
+
if (!isSessionNoiseText(line)) return normalizeSessionDisplayText(line);
|
|
703868
|
+
}
|
|
703869
|
+
return "";
|
|
703870
|
+
}
|
|
703871
|
+
function hasMeaningfulSessionContent(transcript) {
|
|
703872
|
+
return firstMeaningfulSessionLine(transcript).length > 0;
|
|
703873
|
+
}
|
|
703874
|
+
function normalizedSessionFingerprint(transcript) {
|
|
703875
|
+
const semantic = [];
|
|
703876
|
+
let mode = "text";
|
|
703877
|
+
let inToolBox = false;
|
|
703878
|
+
for (const raw of withoutAnsi(transcript).split(/\r?\n/)) {
|
|
703879
|
+
const line = raw.trim();
|
|
703880
|
+
if (!line) continue;
|
|
703881
|
+
if (/^[╭┌]/.test(line)) {
|
|
703882
|
+
inToolBox = true;
|
|
703883
|
+
continue;
|
|
703884
|
+
}
|
|
703885
|
+
if (/^[╰└]/.test(line)) {
|
|
703886
|
+
inToolBox = false;
|
|
703887
|
+
continue;
|
|
703888
|
+
}
|
|
703889
|
+
if (inToolBox) continue;
|
|
703890
|
+
const user = line.match(/^(?:[▹▸►❯>]\s*|(?:User|You)\s*:\s*)(.+)$/i);
|
|
703891
|
+
if (user && !isSessionNoiseText(user[1] || "")) {
|
|
703892
|
+
mode = "user";
|
|
703893
|
+
semantic.push(`user:${normalizeSessionDisplayText(user[1] || "").toLowerCase()}`);
|
|
703894
|
+
continue;
|
|
703895
|
+
}
|
|
703896
|
+
const assistant = line.match(/^(?:(?:Assistant|Open Agent|Omnius)\s*:\s*|│\s?)(.*)$/i);
|
|
703897
|
+
if (assistant) {
|
|
703898
|
+
const content2 = normalizeSessionDisplayText((assistant[1] || "").replace(/\s?│$/, ""));
|
|
703899
|
+
if (content2) {
|
|
703900
|
+
mode = "assistant";
|
|
703901
|
+
semantic.push(`assistant:${content2.toLowerCase()}`);
|
|
703902
|
+
}
|
|
703903
|
+
continue;
|
|
703904
|
+
}
|
|
703905
|
+
if (isSessionNoiseText(line)) continue;
|
|
703906
|
+
const content = normalizeSessionDisplayText(line);
|
|
703907
|
+
if (content) semantic.push(`${mode}:${content.toLowerCase()}`);
|
|
703908
|
+
}
|
|
703909
|
+
return semantic.join("\n");
|
|
703910
|
+
}
|
|
703911
|
+
var ANSI_RE, SPEAKER_RE, MARKER_PREFIX_RE, USER_LINE_RE, CONTROL_ONLY_RE, BOX_OR_TOOL_CHROME_RE, STATUS_RE;
|
|
703912
|
+
var init_session_quality = __esm({
|
|
703913
|
+
"packages/cli/src/session-quality.ts"() {
|
|
703914
|
+
ANSI_RE = /\x1B\[[0-9;]*m|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
|
|
703915
|
+
SPEAKER_RE = /^(?:User|Assistant|You|Open Agent|Omnius)\s*:\s*/i;
|
|
703916
|
+
MARKER_PREFIX_RE = /^[∙•·‹›▹▸▶►◆◇❯❮>\-=_*#|/\\.\s]+/;
|
|
703917
|
+
USER_LINE_RE = /^(?:[▹▸►❯>]\s+\S|(?:User|You)\s*:\s*\S)/i;
|
|
703918
|
+
CONTROL_ONLY_RE = /^\/?(?:q|quit|exit)$/i;
|
|
703919
|
+
BOX_OR_TOOL_CHROME_RE = /^[╭╮╰╯├┤┬┴┌┐└┘─━═╿│▌▐█▒░●○◐◖✔✖$]/;
|
|
703920
|
+
STATUS_RE = /^(?:nexus|rest api|voice feedback|clone ref|connecting to|connected|http:\/\/|https:\/\/|last task:|\(manual save\)|good morning|good evening|good afternoon|cannot reach|could not|unable to|warning:|error:|loaded tui session|session restored|restored previous|using (?:expanded )?context model|using model|tui session\b|chat tui:|previous session found|context (?:auto-)?restored|context restored|recovered session|\[?new_task_intake\b|\[imported tui session transcript\]|title:|description:|project root:|user is asking\b|\[vram|vram |model_info|kv |arch[ -]capped|no context to restore|starting fresh|use \/endpoint|general session$|knowledge graph:|zettelkasten:|episodes captured:|current omnius_host:)/i;
|
|
703921
|
+
}
|
|
703922
|
+
});
|
|
703923
|
+
|
|
703758
703924
|
// packages/cli/src/tui/omnius-directory.ts
|
|
703759
703925
|
var omnius_directory_exports = {};
|
|
703760
703926
|
__export(omnius_directory_exports, {
|
|
@@ -705130,16 +705296,18 @@ function firstMeaningfulSessionHistoryLine(lines) {
|
|
|
705130
705296
|
const trimmed = line.trimStart();
|
|
705131
705297
|
if (!trimmed || VISUAL_CHROME_LINE.test(trimmed)) continue;
|
|
705132
705298
|
const clean7 = cleanSessionHistoryDisplayLine(line);
|
|
705133
|
-
if (!clean7 || SESSION_TITLE_STATUS_LINE.test(clean7)) continue;
|
|
705299
|
+
if (!clean7 || SESSION_TITLE_STATUS_LINE.test(clean7) || isSessionNoiseText(clean7)) continue;
|
|
705134
705300
|
return clean7;
|
|
705135
705301
|
}
|
|
705136
|
-
return "";
|
|
705302
|
+
return firstMeaningfulSessionLine(lines.slice(0, 120).join("\n"));
|
|
705137
705303
|
}
|
|
705138
|
-
function sanitizeSessionHistoryEntry(repoRoot, entry) {
|
|
705139
|
-
const
|
|
705140
|
-
const
|
|
705304
|
+
function sanitizeSessionHistoryEntry(repoRoot, entry, loadedLines) {
|
|
705305
|
+
const cleanName = cleanSessionHistoryDisplayLine(entry.name);
|
|
705306
|
+
const cleanDescription = cleanSessionHistoryDisplayLine(entry.description);
|
|
705307
|
+
const nameLooksAuthored = cleanName.length > 0 && !isSessionNoiseText(cleanName);
|
|
705308
|
+
const descriptionLooksAuthored = cleanDescription.length > 0 && !isSessionNoiseText(cleanDescription);
|
|
705141
705309
|
if (nameLooksAuthored && descriptionLooksAuthored) return entry;
|
|
705142
|
-
const lines = loadSessionHistory(repoRoot, entry.id)
|
|
705310
|
+
const lines = loadedLines ?? loadSessionHistory(repoRoot, entry.id) ?? [];
|
|
705143
705311
|
const fallback = firstMeaningfulSessionHistoryLine(lines);
|
|
705144
705312
|
return {
|
|
705145
705313
|
...entry,
|
|
@@ -705166,14 +705334,16 @@ function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
|
|
|
705166
705334
|
} catch {
|
|
705167
705335
|
}
|
|
705168
705336
|
const existing = index.findIndex((s2) => s2.id === sessionId);
|
|
705337
|
+
const previous = existing >= 0 ? index[existing] : void 0;
|
|
705169
705338
|
const record = {
|
|
705339
|
+
...previous ?? {},
|
|
705170
705340
|
id: sessionId,
|
|
705171
|
-
name: autoName,
|
|
705172
|
-
description: autoDesc,
|
|
705173
|
-
createdAt:
|
|
705341
|
+
name: !isSessionNoiseText(autoName) ? autoName : previous?.name ?? autoName,
|
|
705342
|
+
description: !isSessionNoiseText(autoDesc) ? autoDesc : previous?.description ?? autoDesc,
|
|
705343
|
+
createdAt: previous?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
705174
705344
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
705175
|
-
taskCount: meta.taskCount ?? 1,
|
|
705176
|
-
model: meta.model ?? "unknown"
|
|
705345
|
+
taskCount: meta.taskCount ?? previous?.taskCount ?? 1,
|
|
705346
|
+
model: meta.model ?? previous?.model ?? "unknown"
|
|
705177
705347
|
};
|
|
705178
705348
|
if (existing >= 0) {
|
|
705179
705349
|
index[existing] = record;
|
|
@@ -705186,6 +705356,15 @@ function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
|
|
|
705186
705356
|
unlinkSync28(join141(sessDir, `${removed.id}.jsonl`));
|
|
705187
705357
|
} catch {
|
|
705188
705358
|
}
|
|
705359
|
+
try {
|
|
705360
|
+
unlinkSync28(join141(sessDir, `${removed.id}${TUI_STATE_SUFFIX}`));
|
|
705361
|
+
} catch {
|
|
705362
|
+
}
|
|
705363
|
+
try {
|
|
705364
|
+
const mirrorId = `tui:${removed.id}`.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
705365
|
+
unlinkSync28(join141(homedir45(), ".omnius", "chat-sessions", `${mirrorId}.json`));
|
|
705366
|
+
} catch {
|
|
705367
|
+
}
|
|
705189
705368
|
}
|
|
705190
705369
|
writeFileSync70(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
705191
705370
|
}
|
|
@@ -705222,7 +705401,13 @@ function listSessions(repoRoot) {
|
|
|
705222
705401
|
try {
|
|
705223
705402
|
if (!existsSync130(indexPath)) return [];
|
|
705224
705403
|
const index = JSON.parse(readFileSync107(indexPath, "utf-8"));
|
|
705225
|
-
|
|
705404
|
+
const eligible = [];
|
|
705405
|
+
for (const entry of index) {
|
|
705406
|
+
const lines = loadSessionHistory(repoRoot, entry.id) ?? [];
|
|
705407
|
+
if (!hasMeaningfulSessionContent(lines.join("\n"))) continue;
|
|
705408
|
+
eligible.push(sanitizeSessionHistoryEntry(repoRoot, entry, lines));
|
|
705409
|
+
}
|
|
705410
|
+
return eligible.sort((a2, b) => b.updatedAt.localeCompare(a2.updatedAt));
|
|
705226
705411
|
} catch {
|
|
705227
705412
|
return [];
|
|
705228
705413
|
}
|
|
@@ -705244,6 +705429,9 @@ function deleteSession(repoRoot, sessionId) {
|
|
|
705244
705429
|
if (existsSync130(contentPath)) unlinkSync28(contentPath);
|
|
705245
705430
|
const statePath = join141(sessDir, `${sessionId}${TUI_STATE_SUFFIX}`);
|
|
705246
705431
|
if (existsSync130(statePath)) unlinkSync28(statePath);
|
|
705432
|
+
const mirrorId = `tui:${sessionId}`.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
705433
|
+
const mirrorPath = join141(homedir45(), ".omnius", "chat-sessions", `${mirrorId}.json`);
|
|
705434
|
+
if (existsSync130(mirrorPath)) unlinkSync28(mirrorPath);
|
|
705247
705435
|
if (existsSync130(indexPath)) {
|
|
705248
705436
|
let index = JSON.parse(readFileSync107(indexPath, "utf-8"));
|
|
705249
705437
|
index = index.filter((s2) => s2.id !== sessionId);
|
|
@@ -705481,6 +705669,7 @@ var init_omnius_directory = __esm({
|
|
|
705481
705669
|
"packages/cli/src/tui/omnius-directory.ts"() {
|
|
705482
705670
|
init_dist5();
|
|
705483
705671
|
init_task_complete_box();
|
|
705672
|
+
init_session_quality();
|
|
705484
705673
|
OMNIUS_DIR2 = ".omnius";
|
|
705485
705674
|
LEGACY_DIRS = [".oa", ".open-agents"];
|
|
705486
705675
|
SUBDIRS = ["memory", "index", "context", "history", "notes", "embedded", "provenance", "tools", "dreams"];
|
|
@@ -705596,29 +705785,12 @@ var init_omnius_directory = __esm({
|
|
|
705596
705785
|
});
|
|
705597
705786
|
|
|
705598
705787
|
// packages/cli/src/api/session-summary.ts
|
|
705599
|
-
function isNoiseLine(line) {
|
|
705600
|
-
const t2 = line.trim();
|
|
705601
|
-
if (t2.length < 3) return true;
|
|
705602
|
-
const core = t2.replace(TUI_MARKER_PREFIX, "").trim();
|
|
705603
|
-
if (core.length < 3) return true;
|
|
705604
|
-
return /^(nexus|rest api|voice feedback|clone ref|connecting to|connected|http:\/\/|https:\/\/|last task:|\(manual save\)|good morning|good evening|good afternoon|cannot reach|could not|unable to|warning:|error:|loaded tui session|session restored|restored previous|using (expanded )?context model|using model|tui session\b|chat tui:|previous session found|context (auto-)?restored|context restored|recovered session|\[vram|vram |model_info|kv |arch[ -]capped)/i.test(core);
|
|
705605
|
-
}
|
|
705606
|
-
function firstMeaningfulLine(transcript) {
|
|
705607
|
-
const lines = transcript.split("\n").map((r2) => r2.replace(ANSI_RE, "").trim());
|
|
705608
|
-
for (const line of lines) {
|
|
705609
|
-
if (/^[▹▸►❯>]\s+\S/.test(line) && !isNoiseLine(line)) return line;
|
|
705610
|
-
}
|
|
705611
|
-
for (const line of lines) {
|
|
705612
|
-
if (line && !isNoiseLine(line)) return line;
|
|
705613
|
-
}
|
|
705614
|
-
return "";
|
|
705615
|
-
}
|
|
705616
705788
|
function clamp9(value2, max) {
|
|
705617
705789
|
const v = value2.replace(/\s+/g, " ").trim();
|
|
705618
705790
|
return v.length > max ? v.slice(0, max - 1).trimEnd() + "…" : v;
|
|
705619
705791
|
}
|
|
705620
705792
|
function deterministicSummary(transcript) {
|
|
705621
|
-
const first2 =
|
|
705793
|
+
const first2 = firstMeaningfulSessionLine(transcript);
|
|
705622
705794
|
if (!first2) return { title: "Untitled session", summary: "Empty session." };
|
|
705623
705795
|
const cleaned = first2.replace(TUI_MARKER_PREFIX, "").replace(/^[>›$#\s]+/, "").trim();
|
|
705624
705796
|
const title = clamp9(cleaned, TITLE_MAX);
|
|
@@ -705640,7 +705812,7 @@ function parseSummaryReply(content) {
|
|
|
705640
705812
|
}
|
|
705641
705813
|
async function generateSessionSummary(args) {
|
|
705642
705814
|
const fallback = deterministicSummary(args.transcript);
|
|
705643
|
-
const transcript = (args.transcript || "").replace(
|
|
705815
|
+
const transcript = (args.transcript || "").replace(ANSI_RE2, "").trim();
|
|
705644
705816
|
if (!transcript || !args.config.model || !args.config.backendUrl) return fallback;
|
|
705645
705817
|
try {
|
|
705646
705818
|
const url = normalizeBaseUrl(args.config.backendUrl) + "/v1/chat/completions";
|
|
@@ -705673,8 +705845,9 @@ async function generateSessionSummary(args) {
|
|
|
705673
705845
|
const content = data?.choices?.[0]?.message?.content ?? "";
|
|
705674
705846
|
const parsed = parseSummaryReply(content);
|
|
705675
705847
|
if (!parsed) return fallback;
|
|
705848
|
+
const parsedTitle = clamp9(parsed.title, TITLE_MAX);
|
|
705676
705849
|
return {
|
|
705677
|
-
title:
|
|
705850
|
+
title: parsedTitle && !isSessionNoiseText(parsedTitle) ? parsedTitle : fallback.title,
|
|
705678
705851
|
summary: clamp9(parsed.summary, SUMMARY_MAX) || fallback.summary
|
|
705679
705852
|
};
|
|
705680
705853
|
} catch {
|
|
@@ -705685,7 +705858,7 @@ async function ensureSessionSummary(args) {
|
|
|
705685
705858
|
const entry = listSessions(args.repoRoot).find(
|
|
705686
705859
|
(e2) => e2.id === args.sessionId
|
|
705687
705860
|
);
|
|
705688
|
-
if (entry?.aiTitle && entry.aiSummary && !args.force) {
|
|
705861
|
+
if (entry?.aiTitle && entry.aiSummary && !isSessionNoiseText(entry.aiTitle) && !args.force) {
|
|
705689
705862
|
return { title: entry.aiTitle, summary: entry.aiSummary };
|
|
705690
705863
|
}
|
|
705691
705864
|
const lines = loadSessionHistory(args.repoRoot, args.sessionId);
|
|
@@ -705711,19 +705884,20 @@ async function ensureSessionSummary(args) {
|
|
|
705711
705884
|
_inflightSummaries.delete(key);
|
|
705712
705885
|
}
|
|
705713
705886
|
}
|
|
705714
|
-
function sessionDisplayTitle(entry) {
|
|
705715
|
-
if (entry.aiTitle && entry.aiTitle
|
|
705716
|
-
return deterministicSummary(entry.name
|
|
705887
|
+
function sessionDisplayTitle(entry, transcript = "") {
|
|
705888
|
+
if (entry.aiTitle && !isSessionNoiseText(entry.aiTitle)) return entry.aiTitle.trim();
|
|
705889
|
+
return deterministicSummary(transcript || [entry.name, entry.description].filter(Boolean).join("\n")).title;
|
|
705717
705890
|
}
|
|
705718
|
-
var TITLE_MAX, SUMMARY_MAX, TRANSCRIPT_CHARS,
|
|
705891
|
+
var TITLE_MAX, SUMMARY_MAX, TRANSCRIPT_CHARS, ANSI_RE2, TUI_MARKER_PREFIX, _inflightSummaries;
|
|
705719
705892
|
var init_session_summary = __esm({
|
|
705720
705893
|
"packages/cli/src/api/session-summary.ts"() {
|
|
705721
705894
|
init_dist6();
|
|
705722
705895
|
init_omnius_directory();
|
|
705896
|
+
init_session_quality();
|
|
705723
705897
|
TITLE_MAX = 56;
|
|
705724
705898
|
SUMMARY_MAX = 160;
|
|
705725
705899
|
TRANSCRIPT_CHARS = 6e3;
|
|
705726
|
-
|
|
705900
|
+
ANSI_RE2 = /\x1B\[[0-9;]*m|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
|
|
705727
705901
|
TUI_MARKER_PREFIX = /^[∙•·‹›▹▸▶►◆◇❯❮>\-=_*#|/\\.\s]+/;
|
|
705728
705902
|
_inflightSummaries = /* @__PURE__ */ new Set();
|
|
705729
705903
|
}
|
|
@@ -706617,7 +706791,7 @@ function paintBlockBorder(glyphs, stage2, phase, truecolor, startCol = 0) {
|
|
|
706617
706791
|
return `${out}\x1B[0m`;
|
|
706618
706792
|
}
|
|
706619
706793
|
function sanitizeSubAgentActivity(value2) {
|
|
706620
|
-
return value2.replace(
|
|
706794
|
+
return value2.replace(ANSI_RE3, "").replace(/[\x00-\x1F\x7F]/g, " ").replace(/\s+/g, " ").trim().slice(0, MAX_ACTIVITY_CHARS);
|
|
706621
706795
|
}
|
|
706622
706796
|
function appendSubAgentActivity(entry, value2, maxLines = 3) {
|
|
706623
706797
|
const line = sanitizeSubAgentActivity(value2);
|
|
@@ -706671,7 +706845,7 @@ function contentRow(value2, width, stage2, phase, truecolor) {
|
|
|
706671
706845
|
return `${left} ${fit2(value2, width)} ${right}`;
|
|
706672
706846
|
}
|
|
706673
706847
|
function fit2(value2, width) {
|
|
706674
|
-
const plain = value2.replace(
|
|
706848
|
+
const plain = value2.replace(ANSI_RE3, "").replace(/\s+$/g, "");
|
|
706675
706849
|
const chars = Array.from(plain);
|
|
706676
706850
|
if (chars.length > width) {
|
|
706677
706851
|
return `${chars.slice(0, Math.max(0, width - 1)).join("")}…`;
|
|
@@ -706691,11 +706865,11 @@ function statusIcon(status) {
|
|
|
706691
706865
|
return "●";
|
|
706692
706866
|
}
|
|
706693
706867
|
}
|
|
706694
|
-
var
|
|
706868
|
+
var ANSI_RE3, MAX_PREVIEW_AGENTS, MAX_ACTIVITY_CHARS, STAGE_FALLBACK_COLOR, BORDER_GRADIENT_SEG;
|
|
706695
706869
|
var init_sub_agent_live_block = __esm({
|
|
706696
706870
|
"packages/cli/src/tui/sub-agent-live-block.ts"() {
|
|
706697
706871
|
init_stageIndicator();
|
|
706698
|
-
|
|
706872
|
+
ANSI_RE3 = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\)/g;
|
|
706699
706873
|
MAX_PREVIEW_AGENTS = 4;
|
|
706700
706874
|
MAX_ACTIVITY_CHARS = 220;
|
|
706701
706875
|
STAGE_FALLBACK_COLOR = {
|
|
@@ -706815,19 +706989,19 @@ function row(value2, width, stage2, phase, truecolor) {
|
|
|
706815
706989
|
return `${left} ${fit3(value2, width)} ${right}`;
|
|
706816
706990
|
}
|
|
706817
706991
|
function fit3(value2, width) {
|
|
706818
|
-
const clean7 = value2.replace(
|
|
706992
|
+
const clean7 = value2.replace(ANSI_RE4, "").replace(/\s+/g, " ").trim();
|
|
706819
706993
|
const chars = Array.from(clean7);
|
|
706820
706994
|
if (chars.length > width) {
|
|
706821
706995
|
return `${chars.slice(0, Math.max(0, width - 1)).join("")}…`;
|
|
706822
706996
|
}
|
|
706823
706997
|
return clean7 + " ".repeat(Math.max(0, width - chars.length));
|
|
706824
706998
|
}
|
|
706825
|
-
var
|
|
706999
|
+
var ANSI_RE4;
|
|
706826
707000
|
var init_trajectory_live_block = __esm({
|
|
706827
707001
|
"packages/cli/src/tui/trajectory-live-block.ts"() {
|
|
706828
707002
|
init_stageIndicator();
|
|
706829
707003
|
init_sub_agent_live_block();
|
|
706830
|
-
|
|
707004
|
+
ANSI_RE4 = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\)/g;
|
|
706831
707005
|
}
|
|
706832
707006
|
});
|
|
706833
707007
|
|
|
@@ -719818,7 +719992,7 @@ export PATH="${binDir}:$PATH" # Added by omnius for nvim
|
|
|
719818
719992
|
} catch {
|
|
719819
719993
|
}
|
|
719820
719994
|
}
|
|
719821
|
-
var execAsync2, OMNIUS_FIRST_RUN_BANNER,
|
|
719995
|
+
var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE5, visibleLen2, SETUP_MODEL_VARIANTS, _toolSupportCache, EXPANDED_VARIANT_MIN_NUM_CTX, _cloudflaredInstallPromise;
|
|
719822
719996
|
var init_setup = __esm({
|
|
719823
719997
|
"packages/cli/src/tui/setup.ts"() {
|
|
719824
719998
|
init_model_picker();
|
|
@@ -719838,8 +720012,8 @@ var init_setup = __esm({
|
|
|
719838
720012
|
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ",
|
|
719839
720013
|
" ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░ "
|
|
719840
720014
|
].join("\n");
|
|
719841
|
-
|
|
719842
|
-
visibleLen2 = (value2) => Array.from(value2.replace(
|
|
720015
|
+
ANSI_RE5 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
720016
|
+
visibleLen2 = (value2) => Array.from(value2.replace(ANSI_RE5, "")).length;
|
|
719843
720017
|
SETUP_MODEL_VARIANTS = [
|
|
719844
720018
|
{ tag: "robit/ornith:9b", sizeGB: 6.6, label: "9B params (6.6 GB) - recommended minimum", cloud: false },
|
|
719845
720019
|
{ tag: "robit/ornith:35b", sizeGB: 24, label: "35B params (24 GB) - recommended on 32GB+ unified memory/VRAM", cloud: false }
|
|
@@ -747847,8 +748021,12 @@ async function handleUpdate(subcommand, ctx3) {
|
|
|
747847
748021
|
renderInfo(`Omnius v${currentVersion} is already up to date.`);
|
|
747848
748022
|
return;
|
|
747849
748023
|
}
|
|
748024
|
+
const updateOverlay = startInstallOverlay(info.latestVersion);
|
|
748025
|
+
updateOverlay.setPhase("Preparing");
|
|
748026
|
+
updateOverlay.setProgress(0, 6);
|
|
748027
|
+
updateOverlay.setStatus("starting coordinated global update");
|
|
747850
748028
|
try {
|
|
747851
|
-
const [{ startDetachedGlobalUpdate: startDetachedGlobalUpdate2 }, { getTrayStatus: getTrayStatus2 }] = await Promise.all([
|
|
748029
|
+
const [{ startDetachedGlobalUpdate: startDetachedGlobalUpdate2, waitForUpdateTransaction: waitForUpdateTransaction2 }, { getTrayStatus: getTrayStatus2 }] = await Promise.all([
|
|
747852
748030
|
Promise.resolve().then(() => (init_update_service(), update_service_exports)),
|
|
747853
748031
|
Promise.resolve().then(() => (init_tray(), tray_exports))
|
|
747854
748032
|
]);
|
|
@@ -747859,11 +748037,52 @@ async function handleUpdate(subcommand, ctx3) {
|
|
|
747859
748037
|
endpoint: trayStatus.endpoint,
|
|
747860
748038
|
trayWasRunning: trayStatus.running
|
|
747861
748039
|
});
|
|
748040
|
+
const phasePresentation = {
|
|
748041
|
+
queued: { label: "Preparing", progress: 0, status: "update worker queued" },
|
|
748042
|
+
installing: { label: "Package", progress: 1, status: `installing omnius@${info.latestVersion}` },
|
|
748043
|
+
package_verified: { label: "Verification", progress: 2, status: "global package and executable verified" },
|
|
748044
|
+
daemon_restarting: { label: "Daemon", progress: 3, status: "restarting shared daemon" },
|
|
748045
|
+
runtime_verified: { label: "Runtime", progress: 4, status: "daemon version and package hash verified" },
|
|
748046
|
+
tray_restarting: { label: "Indicator", progress: 5, status: "restarting system indicator" },
|
|
748047
|
+
completed: { label: "Complete", progress: 6, status: "global runtime update verified" },
|
|
748048
|
+
failed: { label: "Failed", progress: 6, status: "update verification failed" }
|
|
748049
|
+
};
|
|
748050
|
+
const marker = `[omnius update ${started.state.operation_id}]`;
|
|
748051
|
+
const terminal = await waitForUpdateTransaction2(
|
|
748052
|
+
started.state.operation_id,
|
|
748053
|
+
{
|
|
748054
|
+
pollIntervalMs: 250,
|
|
748055
|
+
timeoutMs: 10 * 6e4,
|
|
748056
|
+
onProgress(snapshot) {
|
|
748057
|
+
const view = phasePresentation[snapshot.state.phase];
|
|
748058
|
+
updateOverlay.setPhase(view.label);
|
|
748059
|
+
updateOverlay.setProgress(view.progress, 6);
|
|
748060
|
+
const operationLog = snapshot.log_tail.includes(marker) ? snapshot.log_tail.slice(snapshot.log_tail.lastIndexOf(marker) + marker.length) : snapshot.log_tail;
|
|
748061
|
+
const liveLine = operationLog.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !/^npm notice/i.test(line)).at(-1);
|
|
748062
|
+
updateOverlay.setStatus((liveLine || view.status).slice(0, 100));
|
|
748063
|
+
}
|
|
748064
|
+
}
|
|
748065
|
+
);
|
|
748066
|
+
if (terminal.status === "failed") {
|
|
748067
|
+
updateOverlay.dismiss();
|
|
748068
|
+
renderError(`Update to v${info.latestVersion} failed: ${terminal.error || "unknown error"}`);
|
|
748069
|
+
if (terminal.remediation) renderWarning(terminal.remediation);
|
|
748070
|
+
return;
|
|
748071
|
+
}
|
|
748072
|
+
updateOverlay.stop("Package, daemon, and indicator verified");
|
|
748073
|
+
await new Promise((resolve87) => setTimeout(resolve87, 1e3));
|
|
748074
|
+
updateOverlay.dismiss();
|
|
747862
748075
|
renderInfo(
|
|
747863
|
-
`
|
|
748076
|
+
`Updated Omnius v${currentVersion} → v${terminal.installed_version ?? info.latestVersion}; daemon v${terminal.daemon_version ?? info.latestVersion}${terminal.tray_was_running ? ", indicator restarted" : ""}.`
|
|
747864
748077
|
);
|
|
748078
|
+
ctx3.contextSave?.();
|
|
748079
|
+
ctx3.savePendingTaskState?.();
|
|
748080
|
+
if (ctx3.hasActiveTask?.()) ctx3.abortActiveTask?.();
|
|
748081
|
+
ctx3.killEphemeral?.({ preserveInfrastructure: true });
|
|
748082
|
+
process.exit(120);
|
|
747865
748083
|
} catch (error) {
|
|
747866
|
-
|
|
748084
|
+
updateOverlay.dismiss();
|
|
748085
|
+
renderError(`Update failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
747867
748086
|
}
|
|
747868
748087
|
return;
|
|
747869
748088
|
}
|
|
@@ -749568,21 +749787,13 @@ function stripAnsi6(text2) {
|
|
|
749568
749787
|
return String(text2 || "").replace(/\u001b\[[0-9;]*[a-zA-Z]/g, "");
|
|
749569
749788
|
}
|
|
749570
749789
|
function cleanSessionDisplayLine(line) {
|
|
749571
|
-
return stripAnsi6(line)
|
|
749790
|
+
return normalizeSessionDisplayText(stripAnsi6(line));
|
|
749572
749791
|
}
|
|
749573
749792
|
function isNoisySessionDisplayLine(line) {
|
|
749574
|
-
|
|
749575
|
-
if (!clean7) return true;
|
|
749576
|
-
return /^(?:Previous session found|REST API:|Nexus P2P network connected|No context to restore|Starting fresh|Use \/endpoint|Knowledge graph:|Zettelkasten:|Episodes captured:|Current OMNIUS_HOST:|Loaded TUI session|General session$|Chat tui:sess|\[Imported TUI session transcript\]|Title:|Description:|Project root:|i\s+)/i.test(clean7);
|
|
749793
|
+
return isSessionNoiseText(line || "") || /^(?:\[Imported TUI session transcript\]|Title:|Description:|Project root:|i\s+)/i.test(cleanSessionDisplayLine(line || ""));
|
|
749577
749794
|
}
|
|
749578
749795
|
function bestSessionDisplayLine(text2) {
|
|
749579
|
-
|
|
749580
|
-
for (const line of lines) {
|
|
749581
|
-
const clean7 = cleanSessionDisplayLine(line);
|
|
749582
|
-
if (!isNoisySessionDisplayLine(clean7)) return clean7;
|
|
749583
|
-
}
|
|
749584
|
-
const fallback = stripAnsi6(text2).replace(/\s+/g, " ").trim();
|
|
749585
|
-
return isNoisySessionDisplayLine(fallback) ? "" : fallback;
|
|
749796
|
+
return firstMeaningfulSessionLine(stripAnsi6(text2));
|
|
749586
749797
|
}
|
|
749587
749798
|
function makeTitle(text2) {
|
|
749588
749799
|
const clean7 = bestSessionDisplayLine(text2);
|
|
@@ -749796,7 +750007,7 @@ function importTranscriptSession(opts) {
|
|
|
749796
750007
|
"",
|
|
749797
750008
|
cappedTranscript || "(empty transcript)"
|
|
749798
750009
|
].filter(Boolean).join("\n");
|
|
749799
|
-
const
|
|
750010
|
+
const isImportedNotice = (message2) => message2.role === "assistant" && /^Loaded TUI session ".*"\. Its transcript is attached as context for this chat\.$/.test(message2.content);
|
|
749800
750011
|
const existing = lookupSession(id2);
|
|
749801
750012
|
if (existing) {
|
|
749802
750013
|
existing.projectRoot = projectRoot;
|
|
@@ -749806,14 +750017,12 @@ function importTranscriptSession(opts) {
|
|
|
749806
750017
|
existing.preview = preview;
|
|
749807
750018
|
existing.transcript = cappedTranscript || "(empty transcript)";
|
|
749808
750019
|
existing.lastActivity = opts.updatedAt ?? Date.now();
|
|
750020
|
+
existing.messages = existing.messages.filter((message2) => !isImportedNotice(message2));
|
|
749809
750021
|
const idx = existing.messages.findIndex(
|
|
749810
750022
|
(m2) => m2.role === "system" && m2.content.startsWith("[Imported TUI session transcript]")
|
|
749811
750023
|
);
|
|
749812
750024
|
if (idx >= 0) existing.messages[idx] = { role: "system", content: importedContext };
|
|
749813
750025
|
else existing.messages.splice(1, 0, { role: "system", content: importedContext });
|
|
749814
|
-
if (!existing.messages.some((m2) => m2.role === "assistant" && m2.content === visibleNotice)) {
|
|
749815
|
-
existing.messages.push({ role: "assistant", content: visibleNotice });
|
|
749816
|
-
}
|
|
749817
750026
|
persistSession(existing);
|
|
749818
750027
|
return existing;
|
|
749819
750028
|
}
|
|
@@ -749822,8 +750031,7 @@ function importTranscriptSession(opts) {
|
|
|
749822
750031
|
id: id2,
|
|
749823
750032
|
messages: [
|
|
749824
750033
|
{ role: "system", content: buildSystemPrompt(projectRoot) },
|
|
749825
|
-
{ role: "system", content: importedContext }
|
|
749826
|
-
{ role: "assistant", content: visibleNotice }
|
|
750034
|
+
{ role: "system", content: importedContext }
|
|
749827
750035
|
],
|
|
749828
750036
|
model: opts.model || "unknown",
|
|
749829
750037
|
createdAt: opts.createdAt ?? opts.updatedAt ?? now2,
|
|
@@ -749968,6 +750176,9 @@ function listSessions2(opts = {}) {
|
|
|
749968
750176
|
if (!root) return true;
|
|
749969
750177
|
if (!s2.projectRoot) return !!opts.includeUnscoped;
|
|
749970
750178
|
return normalizeRoot(s2.projectRoot) === root;
|
|
750179
|
+
}).filter((s2) => {
|
|
750180
|
+
const authoredTurns = s2.messages.filter((message2) => message2.role === "user").map((message2) => message2.content).join("\n");
|
|
750181
|
+
return hasMeaningfulSessionContent(authoredTurns) || hasMeaningfulSessionContent(s2.transcript || "") || !!s2.title && !isNoisySessionDisplayLine(s2.title);
|
|
749971
750182
|
}).sort((a2, b) => b.lastActivity - a2.lastActivity).map((s2) => ({
|
|
749972
750183
|
id: s2.id,
|
|
749973
750184
|
model: s2.model,
|
|
@@ -750076,6 +750287,7 @@ var sessions2, inFlight, SESSION_TTL_MS, INFERENCE_ROLES, PARTIAL_TAIL_BUDGET;
|
|
|
750076
750287
|
var init_chat_session = __esm({
|
|
750077
750288
|
"packages/cli/src/api/chat-session.ts"() {
|
|
750078
750289
|
init_secret_redactor();
|
|
750290
|
+
init_session_quality();
|
|
750079
750291
|
sessions2 = /* @__PURE__ */ new Map();
|
|
750080
750292
|
inFlight = /* @__PURE__ */ new Map();
|
|
750081
750293
|
SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -796406,8 +796618,10 @@ async function loadServerPrefs() {
|
|
|
796406
796618
|
function isNoisyChatSessionText(text) {
|
|
796407
796619
|
const clean = String(text || '').replace(/\\s+/g, ' ').trim();
|
|
796408
796620
|
if (!clean) return true;
|
|
796409
|
-
const
|
|
796410
|
-
|
|
796621
|
+
const raw = clean.replace(/^[>❯▹∙•\\-\\s]+/, '');
|
|
796622
|
+
if (/^\\/?(?:q|quit|exit)$/i.test(raw)) return true;
|
|
796623
|
+
const t = raw.replace(/^\\/+/, '');
|
|
796624
|
+
return /^(Previous session found|REST API:|Nexus P2P network connected|No context to restore|Starting fresh|Use \\/endpoint|General session$|Loaded TUI session|Chat tui:sess|Last task:|\\(manual save\\)|Using (?:expanded )?context model|Using model|TUI session\\b|\\[?NEW_TASK_INTAKE\\b|User is asking\\b|Context (?:auto-)?restored|Recovered session)/i.test(t);
|
|
796411
796625
|
}
|
|
796412
796626
|
|
|
796413
796627
|
function isGenericChatTitle(id, title) {
|
|
@@ -796424,10 +796638,11 @@ function sessionDisplayTitle(id, session) {
|
|
|
796424
796638
|
if (!isGenericChatTitle(id, candidate)) return String(candidate).trim();
|
|
796425
796639
|
}
|
|
796426
796640
|
if (Array.isArray(s.messages)) {
|
|
796427
|
-
for (
|
|
796428
|
-
const msg
|
|
796429
|
-
|
|
796430
|
-
|
|
796641
|
+
for (const preferredRole of ['user', 'assistant']) {
|
|
796642
|
+
for (const msg of s.messages) {
|
|
796643
|
+
const content = msg && msg.role === preferredRole && typeof msg.content === 'string' ? msg.content : '';
|
|
796644
|
+
if (!isGenericChatTitle(id, content)) return content.replace(/\\s+/g, ' ').trim().slice(0, 72);
|
|
796645
|
+
}
|
|
796431
796646
|
}
|
|
796432
796647
|
}
|
|
796433
796648
|
return String(id || '').startsWith('tui:') ? 'TUI session ' + String(id).slice(4, 16) : 'Chat ' + String(id || '').slice(0, 8);
|
|
@@ -796441,6 +796656,14 @@ function sessionDisplayPreview(session) {
|
|
|
796441
796656
|
return '';
|
|
796442
796657
|
}
|
|
796443
796658
|
|
|
796659
|
+
function isEligibleChatSession(id, session) {
|
|
796660
|
+
const s = session || {};
|
|
796661
|
+
if (![s.title, s.name, s.preview].every(candidate => isGenericChatTitle(id, candidate))) return true;
|
|
796662
|
+
return Array.isArray(s.messages) && s.messages.some(message =>
|
|
796663
|
+
message && message.role === 'user' && !isNoisyChatSessionText(message.content)
|
|
796664
|
+
);
|
|
796665
|
+
}
|
|
796666
|
+
|
|
796444
796667
|
async function loadServerChatSessions() {
|
|
796445
796668
|
const root = $currentProject.get()?.root || '';
|
|
796446
796669
|
if (!root) return;
|
|
@@ -796449,23 +796672,30 @@ async function loadServerChatSessions() {
|
|
|
796449
796672
|
if (!r.ok) return;
|
|
796450
796673
|
const data = await r.json();
|
|
796451
796674
|
const local = loadScopedSessions();
|
|
796452
|
-
|
|
796675
|
+
// A successful canonical load retires local TUI summaries that the server
|
|
796676
|
+
// no longer considers sessions. Keep eligible browser-native chats so an
|
|
796677
|
+
// unsent/local conversation is never lost during reconciliation.
|
|
796678
|
+
const merged = {};
|
|
796679
|
+
for (const [id, session] of Object.entries(local)) {
|
|
796680
|
+
const isTui = String(id).startsWith('tui:') || session?.source === 'tui';
|
|
796681
|
+
if (!isTui && isEligibleChatSession(id, session)) merged[id] = session;
|
|
796682
|
+
}
|
|
796453
796683
|
for (const sess of (data.sessions || [])) {
|
|
796454
796684
|
if (!sess || !sess.id) continue;
|
|
796455
|
-
const existing = merged[sess.id] || {};
|
|
796685
|
+
const existing = local[sess.id] || merged[sess.id] || {};
|
|
796456
796686
|
const serverTitle = sess.title || sess.preview || '';
|
|
796457
796687
|
const existingTitle = existing.title || existing.name || '';
|
|
796458
|
-
const title = !isGenericChatTitle(sess.id,
|
|
796459
|
-
?
|
|
796460
|
-
: (!isGenericChatTitle(sess.id,
|
|
796461
|
-
const preview = !isNoisyChatSessionText(
|
|
796462
|
-
?
|
|
796463
|
-
: (!isNoisyChatSessionText(
|
|
796688
|
+
const title = !isGenericChatTitle(sess.id, serverTitle)
|
|
796689
|
+
? serverTitle
|
|
796690
|
+
: (!isGenericChatTitle(sess.id, existingTitle) ? existingTitle : sessionDisplayTitle(sess.id, sess));
|
|
796691
|
+
const preview = !isNoisyChatSessionText(sess.preview)
|
|
796692
|
+
? sess.preview
|
|
796693
|
+
: (!isNoisyChatSessionText(existing.preview) ? existing.preview : sessionDisplayPreview(sess));
|
|
796464
796694
|
merged[sess.id] = {
|
|
796465
796695
|
...existing,
|
|
796466
796696
|
id: sess.id,
|
|
796467
796697
|
title,
|
|
796468
|
-
name:
|
|
796698
|
+
name: title,
|
|
796469
796699
|
preview,
|
|
796470
796700
|
model: existing.model || sess.model || '',
|
|
796471
796701
|
source: sess.source || existing.source || 'web',
|
|
@@ -796474,7 +796704,14 @@ async function loadServerChatSessions() {
|
|
|
796474
796704
|
messages: existing.messages || [],
|
|
796475
796705
|
};
|
|
796476
796706
|
}
|
|
796707
|
+
saveScopedSessions(merged);
|
|
796477
796708
|
$chatSessions.set(merged);
|
|
796709
|
+
if (chatSessionId && !merged[chatSessionId]) {
|
|
796710
|
+
$chatSessionId.set(null);
|
|
796711
|
+
messages = [];
|
|
796712
|
+
const conversation = document.getElementById('conversation');
|
|
796713
|
+
if (conversation) conversation.innerHTML = '';
|
|
796714
|
+
}
|
|
796478
796715
|
updateSessionSelect();
|
|
796479
796716
|
} catch {}
|
|
796480
796717
|
}
|
|
@@ -798918,7 +799155,7 @@ function chatSessionFromRouteSearch(search) {
|
|
|
798918
799155
|
}
|
|
798919
799156
|
function syncRouteForTab(tab, replace) {
|
|
798920
799157
|
const path = routePathForTab(tab);
|
|
798921
|
-
const query = tab === 'chat' && chatSessionId ? '?' + encodeURIComponent(chatSessionId) : '';
|
|
799158
|
+
const query = tab === 'chat' && chatSessionId ? '?session=' + encodeURIComponent(chatSessionId) : '';
|
|
798922
799159
|
const next = path + query;
|
|
798923
799160
|
if ((location.pathname + location.search) === next) return;
|
|
798924
799161
|
const method = replace ? 'replaceState' : 'pushState';
|
|
@@ -799519,6 +799756,7 @@ window.addEventListener('popstate', () => {
|
|
|
799519
799756
|
if (tab === 'chat') {
|
|
799520
799757
|
const sid = chatSessionFromRouteSearch(location.search);
|
|
799521
799758
|
if (sid && sid !== chatSessionId) switchSession(sid);
|
|
799759
|
+
else if (!sid && chatSessionId) switchSession('');
|
|
799522
799760
|
}
|
|
799523
799761
|
switchTab(tab, { fromRoute: true });
|
|
799524
799762
|
});
|
|
@@ -800418,6 +800656,7 @@ function updateSessionSelect() {
|
|
|
800418
800656
|
const storeSessions = ($chatSessions.get && $chatSessions.get()) || {};
|
|
800419
800657
|
const saved = { ...storeSessions, ...loadScopedSessions() };
|
|
800420
800658
|
const entries = Object.entries(saved)
|
|
800659
|
+
.filter(([id, session]) => isEligibleChatSession(id, session))
|
|
800421
800660
|
.sort((a, b) => (b[1].updatedAt || '').localeCompare(a[1].updatedAt || ''))
|
|
800422
800661
|
.slice(0, 20);
|
|
800423
800662
|
for (const sel of targets) {
|
|
@@ -800437,8 +800676,8 @@ function updateSessionSelect() {
|
|
|
800437
800676
|
// It delegates to the existing switchSession() so chat history restoration
|
|
800438
800677
|
// still works exactly as before.
|
|
800439
800678
|
function switchChatSession(id) {
|
|
800440
|
-
switchSession(id);
|
|
800441
800679
|
switchTab('chat', { replaceRoute: true });
|
|
800680
|
+
switchSession(id);
|
|
800442
800681
|
}
|
|
800443
800682
|
function newChatSession() {
|
|
800444
800683
|
switchSession('');
|
|
@@ -800615,7 +800854,8 @@ function switchSession(id) {
|
|
|
800615
800854
|
return;
|
|
800616
800855
|
}
|
|
800617
800856
|
const saved = loadScopedSessions();
|
|
800618
|
-
const
|
|
800857
|
+
const storeSessions = ($chatSessions.get && $chatSessions.get()) || {};
|
|
800858
|
+
const s = saved[id] || storeSessions[id];
|
|
800619
800859
|
if (s) {
|
|
800620
800860
|
chatSessionId = id;
|
|
800621
800861
|
messages = s.messages || [];
|
|
@@ -800667,6 +800907,9 @@ function switchSession(id) {
|
|
|
800667
800907
|
updateSessionSelect();
|
|
800668
800908
|
try { _renderSidebarChats(_lastSidebarFilter || ''); } catch {}
|
|
800669
800909
|
try { refreshTodos(id); } catch {}
|
|
800910
|
+
// Local entries are only a fast paint. Always re-fetch the canonical
|
|
800911
|
+
// session so summary-only or stale caches cannot suppress real history.
|
|
800912
|
+
void restoreChatSession();
|
|
800670
800913
|
} else {
|
|
800671
800914
|
// Server-backed sessions (including imported TUI sessions) may only be
|
|
800672
800915
|
// present in $chatSessions, not localStorage. Activate and let the daemon
|
|
@@ -800675,7 +800918,7 @@ function switchSession(id) {
|
|
|
800675
800918
|
syncRouteForTab('chat', true);
|
|
800676
800919
|
updateSessionSelect();
|
|
800677
800920
|
try { _renderSidebarChats(_lastSidebarFilter || ''); } catch {}
|
|
800678
|
-
restoreChatSession();
|
|
800921
|
+
void restoreChatSession();
|
|
800679
800922
|
}
|
|
800680
800923
|
}
|
|
800681
800924
|
|
|
@@ -802332,6 +802575,7 @@ function renderRecoveredTranscript(raw, conv, title) {
|
|
|
802332
802575
|
let mode = null; // 'user' | 'assistant'
|
|
802333
802576
|
let buf = [];
|
|
802334
802577
|
let toolCount = 0;
|
|
802578
|
+
let inToolBox = false;
|
|
802335
802579
|
const out = []; // [{role, text}] or {tools:n}
|
|
802336
802580
|
const flush = () => {
|
|
802337
802581
|
const text = buf.join(NL).trim();
|
|
@@ -802346,22 +802590,29 @@ function renderRecoveredTranscript(raw, conv, title) {
|
|
|
802346
802590
|
line = line.replace(sentRe, '');
|
|
802347
802591
|
const t = line.trim();
|
|
802348
802592
|
if (!t) continue;
|
|
802349
|
-
//
|
|
802350
|
-
|
|
802351
|
-
if (/^[
|
|
802593
|
+
// Tool/task panels also use │. Track their box boundaries so their labels,
|
|
802594
|
+
// commands, and output cannot be mistaken for assistant prose.
|
|
802595
|
+
if (/^[╭┌]/.test(t)) { flush(); inToolBox = true; continue; }
|
|
802596
|
+
if (/^[╰└]/.test(t)) { inToolBox = false; continue; }
|
|
802597
|
+
if (inToolBox) continue;
|
|
802598
|
+
if (/^[─━═╿\\s]+$/.test(t)) continue;
|
|
802599
|
+
const userMatch = t.match(/^(?:[▹❯>]\\s*|(?:User|You)\\s*:\\s*)(.+)$/i);
|
|
802600
|
+
if (userMatch) {
|
|
802601
|
+
if (isNoisyChatSessionText(userMatch[1])) { flush(); mode = null; continue; }
|
|
802352
802602
|
flush(); if (toolCount) { out.push({ tools: toolCount }); toolCount = 0; }
|
|
802353
|
-
|
|
802603
|
+
mode = 'user'; buf.push(userMatch[1]); continue;
|
|
802354
802604
|
}
|
|
802355
|
-
|
|
802605
|
+
const assistantMatch = t.match(/^(?:(?:Assistant|Open Agent|Omnius)\\s*:\\s*|│\\s?)(.*)$/i);
|
|
802606
|
+
if (assistantMatch) {
|
|
802356
802607
|
if (mode !== 'assistant') { flush(); mode = 'assistant'; }
|
|
802357
|
-
buf.push(
|
|
802608
|
+
buf.push(assistantMatch[1].replace(/\\s?│$/, '')); continue;
|
|
802358
802609
|
}
|
|
802359
|
-
if (/^[∙!]/.test(t)) continue;
|
|
802360
|
-
if (mode
|
|
802610
|
+
if (/^[∙!EW⚠]/.test(t) || isNoisyChatSessionText(t)) continue;
|
|
802611
|
+
if (mode) buf.push(t); // wrapped authored continuation
|
|
802361
802612
|
}
|
|
802362
802613
|
flush(); if (toolCount) out.push({ tools: toolCount });
|
|
802363
802614
|
|
|
802364
|
-
if (out.length === 0) return; // nothing meaningful — show nothing rather than garbage
|
|
802615
|
+
if (out.length === 0) return []; // nothing meaningful — show nothing rather than garbage
|
|
802365
802616
|
const note = document.createElement('div');
|
|
802366
802617
|
note.style.cssText = 'font-size:0.6rem;color:var(--color-fg-faint);margin:4px 0 8px;text-align:center';
|
|
802367
802618
|
note.textContent = 'recovered session' + (title ? ' — ' + title : '');
|
|
@@ -802376,6 +802627,9 @@ function renderRecoveredTranscript(raw, conv, title) {
|
|
|
802376
802627
|
addMessage(item.role, item.text);
|
|
802377
802628
|
}
|
|
802378
802629
|
}
|
|
802630
|
+
return out
|
|
802631
|
+
.filter(item => !item.tools && (item.role === 'user' || item.role === 'assistant'))
|
|
802632
|
+
.map(item => ({ role: item.role, content: item.text }));
|
|
802379
802633
|
}
|
|
802380
802634
|
window.renderRecoveredTranscript = renderRecoveredTranscript;
|
|
802381
802635
|
|
|
@@ -802389,6 +802643,7 @@ async function restoreChatSession() {
|
|
|
802389
802643
|
const root = $currentProject.get()?.root || '';
|
|
802390
802644
|
const query = root ? '?root=' + encodeURIComponent(root) : '';
|
|
802391
802645
|
const r = await fetch('/v1/chat/sessions/' + encodeURIComponent(sid) + query, { headers: headers() });
|
|
802646
|
+
if (chatSessionId !== sid) return;
|
|
802392
802647
|
if (!r.ok) {
|
|
802393
802648
|
if (r.status === 404) {
|
|
802394
802649
|
// Server lost the session (e.g. daemon restart) — clear via store
|
|
@@ -802398,16 +802653,17 @@ async function restoreChatSession() {
|
|
|
802398
802653
|
return;
|
|
802399
802654
|
}
|
|
802400
802655
|
const data = await r.json();
|
|
802656
|
+
if (chatSessionId !== sid) return;
|
|
802401
802657
|
if (!data || !data.id) return;
|
|
802402
802658
|
chatSessionId = data.id;
|
|
802403
802659
|
window.currentSessionId = data.id;
|
|
802404
802660
|
// Keep the in-memory messages array clean (only user/assistant) so
|
|
802405
802661
|
// the next inference call sees a valid conversation. Tool events
|
|
802406
802662
|
// are still rendered into the DOM via the dropdown helpers below.
|
|
802407
|
-
const allMessages = data.messages || []
|
|
802408
|
-
|
|
802409
|
-
|
|
802410
|
-
|
|
802663
|
+
const allMessages = (data.messages || []).filter(m => !(
|
|
802664
|
+
m.role === 'assistant' && /^Loaded TUI session ".*"\\. Its transcript is attached as context for this chat\\.$/.test(String(m.content || ''))
|
|
802665
|
+
));
|
|
802666
|
+
let recoveredMessages = [];
|
|
802411
802667
|
const conv = document.getElementById('conversation');
|
|
802412
802668
|
if (conv) {
|
|
802413
802669
|
conv.innerHTML = '';
|
|
@@ -802415,15 +802671,15 @@ async function restoreChatSession() {
|
|
|
802415
802671
|
// decisions, sub-agent activity — everything that scrolled past in the
|
|
802416
802672
|
// TUI) as a visible, scrollable block at the top so opening the session
|
|
802417
802673
|
// actually shows what happened, instead of just a "loaded" notice.
|
|
802418
|
-
if (data.transcript && String(data.transcript).trim()
|
|
802419
|
-
&&
|
|
802674
|
+
if (data.source === 'tui' && data.transcript && String(data.transcript).trim()
|
|
802675
|
+
&& data.transcript !== '(empty transcript)') {
|
|
802420
802676
|
// TUI/raw transcript: PARSE the rendered-TUI scrollback into real chat
|
|
802421
802677
|
// bubbles instead of dumping the raw log. The persisted log carries
|
|
802422
802678
|
// DYNBLOCK:<id> sentinels (dynamic blocks expanded only at TUI
|
|
802423
802679
|
// paint time — no content here) plus chrome (▹ user, │ assistant,
|
|
802424
802680
|
// ∙ status, ! internal). We strip the dead sentinels + noise and emit
|
|
802425
802681
|
// user/assistant messages so it reads like a GUI chat.
|
|
802426
|
-
renderRecoveredTranscript(String(data.transcript), conv, data.title || '');
|
|
802682
|
+
recoveredMessages = renderRecoveredTranscript(String(data.transcript), conv, data.title || '');
|
|
802427
802683
|
}
|
|
802428
802684
|
// WO-CHAT-RESUME-TOOLS — replay the FULL intermediate flow on
|
|
802429
802685
|
// restore: user/assistant text bubbles AND tool_call/tool_result
|
|
@@ -802471,6 +802727,12 @@ async function restoreChatSession() {
|
|
|
802471
802727
|
}
|
|
802472
802728
|
}
|
|
802473
802729
|
}
|
|
802730
|
+
messages = [
|
|
802731
|
+
...recoveredMessages,
|
|
802732
|
+
...allMessages
|
|
802733
|
+
.filter(m => m.role === 'user' || m.role === 'assistant')
|
|
802734
|
+
.map(m => ({ role: m.role, content: m.content })),
|
|
802735
|
+
];
|
|
802474
802736
|
try {
|
|
802475
802737
|
const saved = loadScopedSessions();
|
|
802476
802738
|
saved[data.id] = {
|
|
@@ -803632,7 +803894,7 @@ function _renderSidebarChats(filter) {
|
|
|
803632
803894
|
_renderSidebarFoldersToolbar();
|
|
803633
803895
|
|
|
803634
803896
|
const sessions = (typeof $chatSessions !== 'undefined' && $chatSessions.get) ? $chatSessions.get() : {};
|
|
803635
|
-
const allIds = Object.keys(sessions || {});
|
|
803897
|
+
const allIds = Object.keys(sessions || {}).filter(id => isEligibleChatSession(id, sessions[id]));
|
|
803636
803898
|
const q = (filter || '').trim().toLowerCase();
|
|
803637
803899
|
const activeId = chatSessionId || (($chatSessionId.get && $chatSessionId.get()) || null);
|
|
803638
803900
|
|
|
@@ -803644,8 +803906,8 @@ function _renderSidebarChats(filter) {
|
|
|
803644
803906
|
// Sort helper
|
|
803645
803907
|
const sortByRecency = (a, b) => {
|
|
803646
803908
|
const sa = sessions[a] || {}, sb = sessions[b] || {};
|
|
803647
|
-
const ta = sa.updated_at || sa.created_at || a;
|
|
803648
|
-
const tb = sb.updated_at || sb.created_at || b;
|
|
803909
|
+
const ta = sa.updatedAt || sa.updated_at || sa.createdAt || sa.created_at || a;
|
|
803910
|
+
const tb = sb.updatedAt || sb.updated_at || sb.createdAt || sb.created_at || b;
|
|
803649
803911
|
return String(tb).localeCompare(String(ta));
|
|
803650
803912
|
};
|
|
803651
803913
|
allIds.sort(sortByRecency);
|
|
@@ -803679,7 +803941,7 @@ function _renderSidebarChats(filter) {
|
|
|
803679
803941
|
const cls = 'sb-chat' + (id === activeId ? ' active' : '');
|
|
803680
803942
|
const safeId = String(id).replace(/'/g, "\\\\'");
|
|
803681
803943
|
const safeTitle = title.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
803682
|
-
return '<div class="' + cls + '" draggable="true" ondragstart="_onChatDragStart(event,\\'' + safeId + '\\')" onclick="
|
|
803944
|
+
return '<div class="' + cls + '" draggable="true" ondragstart="_onChatDragStart(event,\\'' + safeId + '\\')" onclick="switchChatSession(\\'' + safeId + '\\')" title="' + safeTitle + '">' +
|
|
803683
803945
|
'<span class="sb-chat-title">' + safeTitle + '</span>' +
|
|
803684
803946
|
'<button class="sb-chat-menu" onclick="_showChatRowMenu(event,\\'' + safeId + '\\')" title="More">⋮</button>' +
|
|
803685
803947
|
'</div>';
|
|
@@ -814360,17 +814622,30 @@ ${historyLines}
|
|
|
814360
814622
|
if (!checkAuth(req3, res, "read")) return;
|
|
814361
814623
|
const queriedRoot = urlObj.searchParams.get("root");
|
|
814362
814624
|
const targetRoot = queriedRoot && queriedRoot.trim() ? resolve82(queriedRoot.trim()) : getCurrentProject()?.root ?? process.cwd();
|
|
814363
|
-
const sessions3 = listSessions2({ projectRoot: targetRoot });
|
|
814364
814625
|
const includeTui = urlObj.searchParams.get("include_tui") !== "0";
|
|
814626
|
+
const tuiHistory = includeTui && targetRoot ? listSessions(targetRoot) : [];
|
|
814627
|
+
const canonicalTuiIds = new Set(tuiHistory.map((entry) => `tui:${entry.id}`));
|
|
814628
|
+
const sessions3 = listSessions2({ projectRoot: targetRoot }).filter((session) => {
|
|
814629
|
+
const isTui = session.source === "tui" || session.id.startsWith("tui:");
|
|
814630
|
+
return !isTui || includeTui && canonicalTuiIds.has(session.id);
|
|
814631
|
+
});
|
|
814365
814632
|
if (includeTui && targetRoot) {
|
|
814366
|
-
const
|
|
814633
|
+
const byId = new Map(sessions3.map((session) => [session.id, session]));
|
|
814634
|
+
const seenFingerprints = /* @__PURE__ */ new Set();
|
|
814367
814635
|
const cfg = loadConfig();
|
|
814368
814636
|
const needSummary = [];
|
|
814369
|
-
for (const t2 of
|
|
814637
|
+
for (const t2 of tuiHistory) {
|
|
814370
814638
|
const id2 = `tui:${t2.id}`;
|
|
814371
|
-
|
|
814372
|
-
|
|
814373
|
-
|
|
814639
|
+
const transcriptLines = loadSessionHistory(targetRoot, t2.id) ?? [];
|
|
814640
|
+
const transcript = transcriptLines.join("\n");
|
|
814641
|
+
const fingerprint3 = normalizedSessionFingerprint(transcript);
|
|
814642
|
+
if (fingerprint3 && seenFingerprints.has(fingerprint3)) continue;
|
|
814643
|
+
if (fingerprint3) seenFingerprints.add(fingerprint3);
|
|
814644
|
+
const fallback = deterministicSummary(transcript);
|
|
814645
|
+
const title = sessionDisplayTitle(t2, transcript);
|
|
814646
|
+
const preview = t2.aiSummary && !isSessionNoiseText(t2.aiSummary) ? t2.aiSummary : fallback.summary !== "Empty session." ? fallback.summary : t2.description;
|
|
814647
|
+
if (!t2.aiTitle || isSessionNoiseText(t2.aiTitle)) needSummary.push(t2.id);
|
|
814648
|
+
const canonical3 = {
|
|
814374
814649
|
id: id2,
|
|
814375
814650
|
model: t2.model,
|
|
814376
814651
|
messages: 0,
|
|
@@ -814379,9 +814654,15 @@ ${historyLines}
|
|
|
814379
814654
|
lastActivity: t2.updatedAt,
|
|
814380
814655
|
projectRoot: targetRoot,
|
|
814381
814656
|
source: "tui",
|
|
814382
|
-
title
|
|
814383
|
-
preview
|
|
814384
|
-
}
|
|
814657
|
+
title,
|
|
814658
|
+
preview
|
|
814659
|
+
};
|
|
814660
|
+
const existing = byId.get(id2);
|
|
814661
|
+
if (existing) Object.assign(existing, canonical3);
|
|
814662
|
+
else {
|
|
814663
|
+
sessions3.push(canonical3);
|
|
814664
|
+
byId.set(id2, canonical3);
|
|
814665
|
+
}
|
|
814385
814666
|
}
|
|
814386
814667
|
for (const sid of needSummary.slice(0, 6)) {
|
|
814387
814668
|
void ensureSessionSummary({
|
|
@@ -814559,23 +814840,23 @@ ${historyLines}
|
|
|
814559
814840
|
const sid = decodeURIComponent(chatSessionMatch[1]);
|
|
814560
814841
|
if (method === "GET") {
|
|
814561
814842
|
if (!checkAuth(req3, res, "read")) return;
|
|
814562
|
-
let session = lookupSession(sid);
|
|
814563
|
-
if (
|
|
814843
|
+
let session = sid.startsWith("tui:") ? null : lookupSession(sid);
|
|
814844
|
+
if (sid.startsWith("tui:")) {
|
|
814564
814845
|
const queriedRoot = urlObj.searchParams.get("root");
|
|
814565
814846
|
const targetRoot = queriedRoot && queriedRoot.trim() ? resolve82(queriedRoot.trim()) : getCurrentProject()?.root ?? process.cwd();
|
|
814566
814847
|
const tuiId = sid.slice("tui:".length);
|
|
814567
814848
|
const lines = loadSessionHistory(targetRoot, tuiId);
|
|
814568
|
-
|
|
814569
|
-
|
|
814849
|
+
const meta = listSessions(targetRoot).find((s2) => s2.id === tuiId);
|
|
814850
|
+
if (meta && lines && lines.length > 0) {
|
|
814570
814851
|
session = importTranscriptSession({
|
|
814571
814852
|
id: sid,
|
|
814572
814853
|
projectRoot: targetRoot,
|
|
814573
814854
|
model: meta?.model || loadConfig().model,
|
|
814574
|
-
title: meta
|
|
814575
|
-
description: meta
|
|
814855
|
+
title: sessionDisplayTitle(meta, lines.join("\n")),
|
|
814856
|
+
description: meta.aiSummary || meta.description,
|
|
814576
814857
|
transcriptLines: lines,
|
|
814577
|
-
createdAt: meta
|
|
814578
|
-
updatedAt: meta
|
|
814858
|
+
createdAt: meta.createdAt ? Date.parse(meta.createdAt) : void 0,
|
|
814859
|
+
updatedAt: meta.updatedAt ? Date.parse(meta.updatedAt) : void 0
|
|
814579
814860
|
});
|
|
814580
814861
|
}
|
|
814581
814862
|
}
|
|
@@ -817266,6 +817547,7 @@ var init_serve = __esm({
|
|
|
817266
817547
|
init_usage_tracker();
|
|
817267
817548
|
init_omnius_directory();
|
|
817268
817549
|
init_session_summary();
|
|
817550
|
+
init_session_quality();
|
|
817269
817551
|
init_chat_run_registry();
|
|
817270
817552
|
init_chat_followup();
|
|
817271
817553
|
init_omnius_directory();
|
|
@@ -822244,7 +822526,7 @@ async function startInteractive(config, repoPath2) {
|
|
|
822244
822526
|
const cleanupAndExit = (code8) => {
|
|
822245
822527
|
interactiveExiting = true;
|
|
822246
822528
|
try {
|
|
822247
|
-
saveVisualSessionSnapshotRef?.(
|
|
822529
|
+
saveVisualSessionSnapshotRef?.();
|
|
822248
822530
|
} catch {
|
|
822249
822531
|
}
|
|
822250
822532
|
if (_shellToolRef) _shellToolRef.killAll();
|
|
@@ -823931,15 +824213,16 @@ This is an independent background session started from /background.`
|
|
|
823931
824213
|
}
|
|
823932
824214
|
}
|
|
823933
824215
|
setDreamWriteContent(writeContent);
|
|
823934
|
-
function saveVisualSessionSnapshot(
|
|
824216
|
+
function saveVisualSessionSnapshot() {
|
|
823935
824217
|
try {
|
|
823936
824218
|
const historySessionId = process.env["OMNIUS_SESSION_ID"] || process.env["OMNIUS_TUI_SESSION_ID"] || `session-${Date.now().toString(36)}`;
|
|
823937
824219
|
const tuiState = statusBar.capturePersistedSessionState();
|
|
823938
824220
|
const contentLines = statusBar.capturePersistedSessionLines(100);
|
|
823939
824221
|
if (contentLines.length === 0) return;
|
|
823940
824222
|
const description = cleanPromptForDiary(
|
|
823941
|
-
lastSubmittedPrompt || lastCompletedSummary
|
|
823942
|
-
).slice(0, 240)
|
|
824223
|
+
lastSubmittedPrompt || lastCompletedSummary
|
|
824224
|
+
).slice(0, 240);
|
|
824225
|
+
if (!description || isSessionNoiseText(description)) return;
|
|
823943
824226
|
const historyTitle = description.slice(0, 80) || void 0;
|
|
823944
824227
|
saveSessionHistory(repoRoot, historySessionId, contentLines, {
|
|
823945
824228
|
name: historyTitle,
|
|
@@ -824699,7 +824982,7 @@ This is an independent background session started from /background.`
|
|
|
824699
824982
|
clearInterval(reminderDispatchTimer);
|
|
824700
824983
|
reminderDispatchTimer = null;
|
|
824701
824984
|
}
|
|
824702
|
-
saveVisualSessionSnapshot(
|
|
824985
|
+
saveVisualSessionSnapshot();
|
|
824703
824986
|
statusBar.deactivate();
|
|
824704
824987
|
if (carousel.isRunning) carousel.stop();
|
|
824705
824988
|
banner.stop();
|
|
@@ -827347,7 +827630,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
|
|
|
827347
827630
|
const quitMatch = input.trim().replace(/^\//, "").toLowerCase();
|
|
827348
827631
|
if (quitMatch === "quit" || quitMatch === "exit" || quitMatch === "q") {
|
|
827349
827632
|
interactiveExiting = true;
|
|
827350
|
-
saveVisualSessionSnapshot(
|
|
827633
|
+
saveVisualSessionSnapshot();
|
|
827351
827634
|
if (activeTask) activeTask.runner.abort();
|
|
827352
827635
|
idleMemoryMaintenance?.stop();
|
|
827353
827636
|
taskManager.stopAll();
|
|
@@ -827365,7 +827648,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
|
|
|
827365
827648
|
);
|
|
827366
827649
|
if (cmdResult === "exit") {
|
|
827367
827650
|
interactiveExiting = true;
|
|
827368
|
-
saveVisualSessionSnapshot(
|
|
827651
|
+
saveVisualSessionSnapshot();
|
|
827369
827652
|
if (activeTask) activeTask.runner.abort();
|
|
827370
827653
|
idleMemoryMaintenance?.stop();
|
|
827371
827654
|
taskManager.stopAll();
|
|
@@ -828237,7 +828520,7 @@ Rationale: ${proposal.rationale}${provenanceNote}${dmnDevDiscipline(proposal.cat
|
|
|
828237
828520
|
rl.on("close", () => {
|
|
828238
828521
|
if (interactiveExiting) return;
|
|
828239
828522
|
interactiveExiting = true;
|
|
828240
|
-
saveVisualSessionSnapshot(
|
|
828523
|
+
saveVisualSessionSnapshot();
|
|
828241
828524
|
if (peerMesh) {
|
|
828242
828525
|
peerMesh.stop().catch(() => {
|
|
828243
828526
|
});
|
|
@@ -828823,6 +829106,7 @@ var init_interactive = __esm({
|
|
|
828823
829106
|
init_project_context();
|
|
828824
829107
|
init_realtime();
|
|
828825
829108
|
init_chat_session();
|
|
829109
|
+
init_session_quality();
|
|
828826
829110
|
init_identity_memory_tool();
|
|
828827
829111
|
init_visual_identity_association();
|
|
828828
829112
|
init_dist();
|