omnius 1.0.334 → 1.0.336
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 +379 -42
- package/docs/reference/rest-api.md +1 -0
- package/npm-shrinkwrap.json +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -555501,8 +555501,8 @@ var init_registry2 = __esm({
|
|
|
555501
555501
|
PluginContextImpl = class {
|
|
555502
555502
|
_registry;
|
|
555503
555503
|
_manifest;
|
|
555504
|
-
constructor(
|
|
555505
|
-
this._registry =
|
|
555504
|
+
constructor(_registry6, _manifest) {
|
|
555505
|
+
this._registry = _registry6;
|
|
555506
555506
|
this._manifest = _manifest;
|
|
555507
555507
|
}
|
|
555508
555508
|
get manifest() {
|
|
@@ -599736,8 +599736,8 @@ function codePreviewLines(output, maxLines) {
|
|
|
599736
599736
|
return [{ text: "(empty file)", mode: "wrap", kind: "dim" }];
|
|
599737
599737
|
let hlLines = null;
|
|
599738
599738
|
if (isAvailable()) {
|
|
599739
|
-
const
|
|
599740
|
-
const hl = highlightBlock(
|
|
599739
|
+
const codeBlock2 = shown.join("\n");
|
|
599740
|
+
const hl = highlightBlock(codeBlock2);
|
|
599741
599741
|
if (hl.length === shown.length) hlLines = hl;
|
|
599742
599742
|
}
|
|
599743
599743
|
const body = shown.map((line, i2) => ({
|
|
@@ -607196,7 +607196,7 @@ function cleanSessionHistoryDisplayLine(line) {
|
|
|
607196
607196
|
function isNoisySessionHistoryLine(line) {
|
|
607197
607197
|
const clean5 = cleanSessionHistoryDisplayLine(line || "");
|
|
607198
607198
|
if (!clean5) return true;
|
|
607199
|
-
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|i\s+)/i.test(clean5);
|
|
607199
|
+
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|TUI session\b|Using (?:expanded )?context model|Using model|Context (?:auto-)?restored|Context restored|Recovered session|Last task:|\(manual save\)|\[VRAM|VRAM |model_info|KV |arch[ -]capped|i\s+)/i.test(clean5);
|
|
607200
607200
|
}
|
|
607201
607201
|
function firstMeaningfulSessionHistoryLine(lines) {
|
|
607202
607202
|
for (const line of lines) {
|
|
@@ -607576,18 +607576,17 @@ var init_omnius_directory = __esm({
|
|
|
607576
607576
|
function isNoiseLine(line) {
|
|
607577
607577
|
const t2 = line.trim();
|
|
607578
607578
|
if (t2.length < 3) return true;
|
|
607579
|
-
const core = t2.replace(
|
|
607579
|
+
const core = t2.replace(TUI_MARKER_PREFIX, "").trim();
|
|
607580
607580
|
if (core.length < 3) return true;
|
|
607581
|
-
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)/i.test(core);
|
|
607581
|
+
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);
|
|
607582
607582
|
}
|
|
607583
607583
|
function firstMeaningfulLine(transcript) {
|
|
607584
|
-
|
|
607585
|
-
|
|
607586
|
-
if (line && !isNoiseLine(line)) return line;
|
|
607584
|
+
const lines = transcript.split("\n").map((r2) => r2.replace(ANSI_RE, "").trim());
|
|
607585
|
+
for (const line of lines) {
|
|
607586
|
+
if (/^[▹▸►❯>]\s+\S/.test(line) && !isNoiseLine(line)) return line;
|
|
607587
607587
|
}
|
|
607588
|
-
for (const
|
|
607589
|
-
|
|
607590
|
-
if (line) return line;
|
|
607588
|
+
for (const line of lines) {
|
|
607589
|
+
if (line && !isNoiseLine(line)) return line;
|
|
607591
607590
|
}
|
|
607592
607591
|
return "";
|
|
607593
607592
|
}
|
|
@@ -607598,8 +607597,9 @@ function clamp7(value2, max) {
|
|
|
607598
607597
|
function deterministicSummary(transcript) {
|
|
607599
607598
|
const first2 = firstMeaningfulLine(transcript);
|
|
607600
607599
|
if (!first2) return { title: "Untitled session", summary: "Empty session." };
|
|
607601
|
-
const
|
|
607602
|
-
|
|
607600
|
+
const cleaned = first2.replace(TUI_MARKER_PREFIX, "").replace(/^[>›$#\s]+/, "").trim();
|
|
607601
|
+
const title = clamp7(cleaned, TITLE_MAX);
|
|
607602
|
+
return { title: title || "Untitled session", summary: clamp7(cleaned || first2, SUMMARY_MAX) };
|
|
607603
607603
|
}
|
|
607604
607604
|
function parseSummaryReply(content) {
|
|
607605
607605
|
if (!content) return null;
|
|
@@ -607692,7 +607692,7 @@ function sessionDisplayTitle(entry) {
|
|
|
607692
607692
|
if (entry.aiTitle && entry.aiTitle.trim()) return entry.aiTitle.trim();
|
|
607693
607693
|
return deterministicSummary(entry.name || "").title;
|
|
607694
607694
|
}
|
|
607695
|
-
var TITLE_MAX, SUMMARY_MAX, TRANSCRIPT_CHARS, ANSI_RE, _inflightSummaries;
|
|
607695
|
+
var TITLE_MAX, SUMMARY_MAX, TRANSCRIPT_CHARS, ANSI_RE, TUI_MARKER_PREFIX, _inflightSummaries;
|
|
607696
607696
|
var init_session_summary = __esm({
|
|
607697
607697
|
"packages/cli/src/api/session-summary.ts"() {
|
|
607698
607698
|
"use strict";
|
|
@@ -607702,6 +607702,7 @@ var init_session_summary = __esm({
|
|
|
607702
607702
|
SUMMARY_MAX = 160;
|
|
607703
607703
|
TRANSCRIPT_CHARS = 6e3;
|
|
607704
607704
|
ANSI_RE = /\x1B\[[0-9;]*m|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
|
|
607705
|
+
TUI_MARKER_PREFIX = /^[∙•·‹›▹▸▶►◆◇❯❮>\-=_*#|/\\.\s]+/;
|
|
607705
607706
|
_inflightSummaries = /* @__PURE__ */ new Set();
|
|
607706
607707
|
}
|
|
607707
607708
|
});
|
|
@@ -610158,6 +610159,34 @@ var init_status_bar = __esm({
|
|
|
610158
610159
|
unregisterDynamicBlock(id) {
|
|
610159
610160
|
this._dynamicBlocks.delete(id);
|
|
610160
610161
|
}
|
|
610162
|
+
/**
|
|
610163
|
+
* Expand every dynamic-block sentinel in `lines` into its registered render
|
|
610164
|
+
* output. Used at SESSION-SAVE time so the persisted transcript carries the
|
|
610165
|
+
* REAL tool / shell / task-complete content instead of `\x01DYNBLOCK:<id>\x01`
|
|
610166
|
+
* sentinels whose content otherwise lives only in this in-memory store and is
|
|
610167
|
+
* lost on reload. Stale/unknown sentinels are dropped (not left as dead
|
|
610168
|
+
* markers). ANSI is stripped by the persistence layer afterwards.
|
|
610169
|
+
*/
|
|
610170
|
+
expandDynamicBlockSentinels(lines, width = 100) {
|
|
610171
|
+
const out = [];
|
|
610172
|
+
for (const line of lines) {
|
|
610173
|
+
if (typeof line === "string" && line.startsWith(this.DYNAMIC_BLOCK_MARK_PREFIX) && line.endsWith(this.DYNAMIC_BLOCK_MARK_SUFFIX) && line.length > this.DYNAMIC_BLOCK_MARK_PREFIX.length + this.DYNAMIC_BLOCK_MARK_SUFFIX.length) {
|
|
610174
|
+
const id = line.slice(
|
|
610175
|
+
this.DYNAMIC_BLOCK_MARK_PREFIX.length,
|
|
610176
|
+
line.length - this.DYNAMIC_BLOCK_MARK_SUFFIX.length
|
|
610177
|
+
);
|
|
610178
|
+
const renderer = this._dynamicBlocks.get(id);
|
|
610179
|
+
if (!renderer) continue;
|
|
610180
|
+
try {
|
|
610181
|
+
for (const seg of renderer(width)) out.push(seg);
|
|
610182
|
+
} catch {
|
|
610183
|
+
}
|
|
610184
|
+
} else {
|
|
610185
|
+
out.push(line);
|
|
610186
|
+
}
|
|
610187
|
+
}
|
|
610188
|
+
return out;
|
|
610189
|
+
}
|
|
610161
610190
|
/**
|
|
610162
610191
|
* Append a previously-registered dynamic block's sentinel to scrollback
|
|
610163
610192
|
* and trigger a repaint. The block's renderer fires immediately at the
|
|
@@ -654923,6 +654952,140 @@ var init_emotion_engine = __esm({
|
|
|
654923
654952
|
}
|
|
654924
654953
|
});
|
|
654925
654954
|
|
|
654955
|
+
// packages/cli/src/tui/telegram-format.ts
|
|
654956
|
+
function escapeHtml2(text2) {
|
|
654957
|
+
return String(text2 ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
654958
|
+
}
|
|
654959
|
+
function toolCallBlock(name10, args) {
|
|
654960
|
+
const header = `<b>Tool call</b> <code>${escapeHtml2(name10 || "tool")}</code>`;
|
|
654961
|
+
if (args == null || typeof args === "object" && Object.keys(args).length === 0) {
|
|
654962
|
+
return header;
|
|
654963
|
+
}
|
|
654964
|
+
const compact3 = typeof args === "string" ? args : safeJson(args, false);
|
|
654965
|
+
if (compact3.length <= 120 && !compact3.includes("\n")) {
|
|
654966
|
+
return `${header} <code>${escapeHtml2(compact3)}</code>`;
|
|
654967
|
+
}
|
|
654968
|
+
const pretty = typeof args === "string" ? args : safeJson(args, true);
|
|
654969
|
+
return `${header}
|
|
654970
|
+
${codeBlock(pretty, "json")}`;
|
|
654971
|
+
}
|
|
654972
|
+
function toolResultBlock(name10, ok3, output) {
|
|
654973
|
+
const header = `<b>Tool result</b> <code>${escapeHtml2(name10 || "tool")}</code>`;
|
|
654974
|
+
const body = String(output ?? "").trim();
|
|
654975
|
+
if (!body) return `${header}
|
|
654976
|
+
<i>${ok3 ? "completed" : "failed"}</i>`;
|
|
654977
|
+
if (body.length <= 160 && !body.includes("\n")) {
|
|
654978
|
+
return `${header}
|
|
654979
|
+
<blockquote>${escapeHtml2(body)}</blockquote>`;
|
|
654980
|
+
}
|
|
654981
|
+
return `${header}
|
|
654982
|
+
<blockquote expandable>${escapeHtml2(body)}</blockquote>`;
|
|
654983
|
+
}
|
|
654984
|
+
function codeBlock(code8, language = "") {
|
|
654985
|
+
const inner = escapeHtml2(String(code8 ?? "").replace(/\s+$/, ""));
|
|
654986
|
+
return language ? `<pre><code class="language-${escapeHtml2(language)}">${inner}</code></pre>` : `<pre>${inner}</pre>`;
|
|
654987
|
+
}
|
|
654988
|
+
function safeJson(v, pretty) {
|
|
654989
|
+
try {
|
|
654990
|
+
return pretty ? JSON.stringify(v, null, 2) : JSON.stringify(v);
|
|
654991
|
+
} catch {
|
|
654992
|
+
return String(v);
|
|
654993
|
+
}
|
|
654994
|
+
}
|
|
654995
|
+
function tokenizeTelegramHtml(html) {
|
|
654996
|
+
const tokens = [];
|
|
654997
|
+
const re = /<(\/?)([a-zA-Z][\w-]*)((?:\s[^>]*)?)>/g;
|
|
654998
|
+
let last2 = 0;
|
|
654999
|
+
let m2;
|
|
655000
|
+
while ((m2 = re.exec(html)) !== null) {
|
|
655001
|
+
if (m2.index > last2) tokens.push({ type: "text", raw: html.slice(last2, m2.index) });
|
|
655002
|
+
const closing = m2[1] === "/";
|
|
655003
|
+
const tag = (m2[2] || "").toLowerCase();
|
|
655004
|
+
if (SPAN_TAGS.has(tag)) {
|
|
655005
|
+
tokens.push(closing ? { type: "close", tag, raw: m2[0] } : { type: "open", tag, raw: m2[0] });
|
|
655006
|
+
} else {
|
|
655007
|
+
tokens.push({ type: "text", raw: m2[0] });
|
|
655008
|
+
}
|
|
655009
|
+
last2 = re.lastIndex;
|
|
655010
|
+
}
|
|
655011
|
+
if (last2 < html.length) tokens.push({ type: "text", raw: html.slice(last2) });
|
|
655012
|
+
return tokens;
|
|
655013
|
+
}
|
|
655014
|
+
function segmentTelegramHtml(html, maxLength = SAFE_LIMIT) {
|
|
655015
|
+
const text2 = String(html ?? "");
|
|
655016
|
+
if (text2.length <= maxLength) return text2.trim() ? [text2] : [];
|
|
655017
|
+
const tokens = tokenizeTelegramHtml(text2);
|
|
655018
|
+
const out = [];
|
|
655019
|
+
let cur = "";
|
|
655020
|
+
const stack = [];
|
|
655021
|
+
const closeAll = () => stack.slice().reverse().map((t2) => `</${t2.tag}>`).join("");
|
|
655022
|
+
const reopen = () => stack.map((t2) => t2.raw).join("");
|
|
655023
|
+
const closeLen = () => stack.reduce((n2, t2) => n2 + t2.tag.length + 3, 0);
|
|
655024
|
+
const flush3 = () => {
|
|
655025
|
+
const finished = cur + closeAll();
|
|
655026
|
+
if (finished.trim()) out.push(finished);
|
|
655027
|
+
cur = reopen();
|
|
655028
|
+
};
|
|
655029
|
+
for (const tok of tokens) {
|
|
655030
|
+
if (tok.type === "open") {
|
|
655031
|
+
if (cur.length + tok.raw.length + closeLen() > maxLength) flush3();
|
|
655032
|
+
cur += tok.raw;
|
|
655033
|
+
stack.push({ tag: tok.tag, raw: tok.raw });
|
|
655034
|
+
} else if (tok.type === "close") {
|
|
655035
|
+
cur += tok.raw;
|
|
655036
|
+
for (let i2 = stack.length - 1; i2 >= 0; i2--) {
|
|
655037
|
+
if (stack[i2].tag === tok.tag) {
|
|
655038
|
+
stack.splice(i2, 1);
|
|
655039
|
+
break;
|
|
655040
|
+
}
|
|
655041
|
+
}
|
|
655042
|
+
} else {
|
|
655043
|
+
let body = tok.raw;
|
|
655044
|
+
while (cur.length + body.length + closeLen() > maxLength) {
|
|
655045
|
+
const room = maxLength - cur.length - closeLen();
|
|
655046
|
+
if (room <= 1) {
|
|
655047
|
+
flush3();
|
|
655048
|
+
continue;
|
|
655049
|
+
}
|
|
655050
|
+
let bp = body.lastIndexOf("\n", room);
|
|
655051
|
+
if (bp < room * 0.5) bp = body.lastIndexOf(" ", room);
|
|
655052
|
+
if (bp < room * 0.5) bp = room;
|
|
655053
|
+
cur += body.slice(0, bp);
|
|
655054
|
+
flush3();
|
|
655055
|
+
body = body.slice(bp).replace(/^\s+/, "");
|
|
655056
|
+
}
|
|
655057
|
+
cur += body;
|
|
655058
|
+
}
|
|
655059
|
+
}
|
|
655060
|
+
const tail = cur + closeAll();
|
|
655061
|
+
if (tail.trim()) out.push(tail);
|
|
655062
|
+
return out;
|
|
655063
|
+
}
|
|
655064
|
+
var SAFE_LIMIT, SPAN_TAGS;
|
|
655065
|
+
var init_telegram_format = __esm({
|
|
655066
|
+
"packages/cli/src/tui/telegram-format.ts"() {
|
|
655067
|
+
"use strict";
|
|
655068
|
+
SAFE_LIMIT = 3900;
|
|
655069
|
+
SPAN_TAGS = /* @__PURE__ */ new Set([
|
|
655070
|
+
"b",
|
|
655071
|
+
"strong",
|
|
655072
|
+
"i",
|
|
655073
|
+
"em",
|
|
655074
|
+
"u",
|
|
655075
|
+
"ins",
|
|
655076
|
+
"s",
|
|
655077
|
+
"strike",
|
|
655078
|
+
"del",
|
|
655079
|
+
"code",
|
|
655080
|
+
"pre",
|
|
655081
|
+
"blockquote",
|
|
655082
|
+
"tg-spoiler",
|
|
655083
|
+
"a",
|
|
655084
|
+
"span"
|
|
655085
|
+
]);
|
|
655086
|
+
}
|
|
655087
|
+
});
|
|
655088
|
+
|
|
654926
655089
|
// packages/cli/src/tui/tool-policy.ts
|
|
654927
655090
|
function getDefaultPolicy(context2) {
|
|
654928
655091
|
switch (context2) {
|
|
@@ -660554,8 +660717,8 @@ function convertMarkdownToTelegramHTML(md) {
|
|
|
660554
660717
|
let html = normalizeTelegramOutboundLinks(md);
|
|
660555
660718
|
html = html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
660556
660719
|
html = html.replace(
|
|
660557
|
-
/```[\w]
|
|
660558
|
-
(_m, code8) => `<pre>${code8.trimEnd()}</pre>`
|
|
660720
|
+
/```([\w+-]*)\n?([\s\S]*?)```/g,
|
|
660721
|
+
(_m, lang, code8) => lang ? `<pre><code class="language-${lang}">${code8.trimEnd()}</code></pre>` : `<pre>${code8.trimEnd()}</pre>`
|
|
660559
660722
|
);
|
|
660560
660723
|
html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
660561
660724
|
html = html.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
@@ -660604,6 +660767,9 @@ function truncateTelegramUrlSafe(text2, maxLength, suffix = "...") {
|
|
|
660604
660767
|
function splitTelegramMessageText(text2, maxLength = 3900) {
|
|
660605
660768
|
const trimmed = text2.trim();
|
|
660606
660769
|
if (!trimmed) return [];
|
|
660770
|
+
if (/<\/?[a-zA-Z][\w-]*(?:\s[^>]*)?>/.test(trimmed)) {
|
|
660771
|
+
return segmentTelegramHtml(trimmed, maxLength);
|
|
660772
|
+
}
|
|
660607
660773
|
const chunks = [];
|
|
660608
660774
|
let remaining = trimmed;
|
|
660609
660775
|
while (remaining.length > maxLength) {
|
|
@@ -661052,20 +661218,12 @@ function formatTelegramProgressEvent(event) {
|
|
|
661052
661218
|
if (event.type === "tool_result" && event.toolName === "task_complete")
|
|
661053
661219
|
return null;
|
|
661054
661220
|
if (event.type === "tool_call") {
|
|
661055
|
-
return
|
|
661221
|
+
return toolCallBlock(event.toolName || "tool");
|
|
661056
661222
|
}
|
|
661057
661223
|
if (event.type === "tool_result") {
|
|
661058
|
-
const preview = sanitizeTelegramProgressText(event.content || "",
|
|
661224
|
+
const preview = sanitizeTelegramProgressText(event.content || "", 1500);
|
|
661059
661225
|
if (isTelegramInternalStatusText(preview)) return null;
|
|
661060
|
-
|
|
661061
|
-
if (preview) {
|
|
661062
|
-
return [
|
|
661063
|
-
`<b>Tool result</b> <code>${toolName}</code>`,
|
|
661064
|
-
`<blockquote>${escapeTelegramHTML(preview)}</blockquote>`
|
|
661065
|
-
].join("\n");
|
|
661066
|
-
}
|
|
661067
|
-
return `<b>Tool result</b> <code>${toolName}</code>
|
|
661068
|
-
<i>${event.success ? "completed" : "failed"}</i>`;
|
|
661226
|
+
return toolResultBlock(event.toolName || "tool", Boolean(event.success), preview);
|
|
661069
661227
|
}
|
|
661070
661228
|
if (event.type === "status") {
|
|
661071
661229
|
if (isCodebaseMemoryStatus(event.content || "")) {
|
|
@@ -662179,6 +662337,7 @@ var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTAT
|
|
|
662179
662337
|
var init_telegram_bridge = __esm({
|
|
662180
662338
|
"packages/cli/src/tui/telegram-bridge.ts"() {
|
|
662181
662339
|
"use strict";
|
|
662340
|
+
init_telegram_format();
|
|
662182
662341
|
init_dist8();
|
|
662183
662342
|
init_dist5();
|
|
662184
662343
|
init_project_context();
|
|
@@ -693960,6 +694119,64 @@ window.refreshTodos = refreshTodos;
|
|
|
693960
694119
|
// own process group)
|
|
693961
694120
|
// - Frontend re-attaches via this restore path and shows the partial
|
|
693962
694121
|
// output via partial_output_tail in the in_flight payload
|
|
694122
|
+
// Parse a raw rendered-TUI transcript into clean GUI chat bubbles. Strips the
|
|
694123
|
+
// DYNBLOCK:<id> sentinels (no content in the persisted log) and TUI
|
|
694124
|
+
// chrome, then emits user (▹/>) and assistant (│) messages.
|
|
694125
|
+
function renderRecoveredTranscript(raw, conv, title) {
|
|
694126
|
+
const SOH = String.fromCharCode(1);
|
|
694127
|
+
const NL = String.fromCharCode(10);
|
|
694128
|
+
const sentRe = new RegExp(SOH + 'DYNBLOCK:[^' + SOH + ']*' + SOH, 'g');
|
|
694129
|
+
const lines = String(raw).replace(new RegExp(String.fromCharCode(13), 'g'), '').split(NL);
|
|
694130
|
+
let mode = null; // 'user' | 'assistant'
|
|
694131
|
+
let buf = [];
|
|
694132
|
+
let toolCount = 0;
|
|
694133
|
+
const out = []; // [{role, text}] or {tools:n}
|
|
694134
|
+
const flush = () => {
|
|
694135
|
+
const text = buf.join(NL).trim();
|
|
694136
|
+
if (text && mode) out.push({ role: mode, text: text });
|
|
694137
|
+
buf = [];
|
|
694138
|
+
};
|
|
694139
|
+
for (let line of lines) {
|
|
694140
|
+
// Count + drop dynamic-block sentinels (tool/shell/etc. — their content is
|
|
694141
|
+
// not in the log; surface them as a compact "tool activity" marker).
|
|
694142
|
+
const sentinels = (line.match(sentRe) || []).length;
|
|
694143
|
+
if (sentinels) toolCount += sentinels;
|
|
694144
|
+
line = line.replace(sentRe, '');
|
|
694145
|
+
const t = line.trim();
|
|
694146
|
+
if (!t) continue;
|
|
694147
|
+
// Skip pure box-border lines from expanded tool/task boxes (╭─╮ ╰─╯ etc.).
|
|
694148
|
+
if (/^[─-╿s]+$/.test(t)) continue;
|
|
694149
|
+
if (/^[▹>]s?/.test(t)) { // user prompt
|
|
694150
|
+
flush(); if (toolCount) { out.push({ tools: toolCount }); toolCount = 0; }
|
|
694151
|
+
out.push({ role: 'user', text: t.replace(/^[▹>]s?/, '') }); mode = null; continue;
|
|
694152
|
+
}
|
|
694153
|
+
if (/^│/.test(t)) { // assistant / box content
|
|
694154
|
+
if (mode !== 'assistant') { flush(); mode = 'assistant'; }
|
|
694155
|
+
buf.push(t.replace(/^│s?/, '').replace(/s?│$/, '')); continue; // strip both borders
|
|
694156
|
+
}
|
|
694157
|
+
if (/^[∙!]/.test(t)) continue; // status / internal noise — drop
|
|
694158
|
+
if (mode === 'assistant') buf.push(t); // continuation
|
|
694159
|
+
}
|
|
694160
|
+
flush(); if (toolCount) out.push({ tools: toolCount });
|
|
694161
|
+
|
|
694162
|
+
if (out.length === 0) return; // nothing meaningful — show nothing rather than garbage
|
|
694163
|
+
const note = document.createElement('div');
|
|
694164
|
+
note.style.cssText = 'font-size:0.6rem;color:var(--color-fg-faint);margin:4px 0 8px;text-align:center';
|
|
694165
|
+
note.textContent = 'recovered session' + (title ? ' — ' + title : '');
|
|
694166
|
+
conv.appendChild(note);
|
|
694167
|
+
for (const item of out) {
|
|
694168
|
+
if (item.tools) {
|
|
694169
|
+
const td = document.createElement('div');
|
|
694170
|
+
td.style.cssText = 'font-size:0.6rem;color:var(--color-fg-faint);margin:2px 0 6px;padding-left:8px';
|
|
694171
|
+
td.textContent = '⚙ ' + item.tools + ' tool action' + (item.tools === 1 ? '' : 's');
|
|
694172
|
+
conv.appendChild(td);
|
|
694173
|
+
} else {
|
|
694174
|
+
addMessage(item.role, item.text);
|
|
694175
|
+
}
|
|
694176
|
+
}
|
|
694177
|
+
}
|
|
694178
|
+
window.renderRecoveredTranscript = renderRecoveredTranscript;
|
|
694179
|
+
|
|
693963
694180
|
async function restoreChatSession() {
|
|
693964
694181
|
// chatSessionId is the window-property shim → $chatSessionId.get().
|
|
693965
694182
|
// Project-scoped storage already hydrated this on $currentProject.set,
|
|
@@ -693996,18 +694213,15 @@ async function restoreChatSession() {
|
|
|
693996
694213
|
// decisions, sub-agent activity — everything that scrolled past in the
|
|
693997
694214
|
// TUI) as a visible, scrollable block at the top so opening the session
|
|
693998
694215
|
// actually shows what happened, instead of just a "loaded" notice.
|
|
693999
|
-
if (data.transcript && String(data.transcript).trim() && data.transcript !== '(empty transcript)'
|
|
694000
|
-
|
|
694001
|
-
|
|
694002
|
-
|
|
694003
|
-
|
|
694004
|
-
|
|
694005
|
-
|
|
694006
|
-
|
|
694007
|
-
|
|
694008
|
-
wrap.appendChild(head);
|
|
694009
|
-
wrap.appendChild(pre);
|
|
694010
|
-
conv.appendChild(wrap);
|
|
694216
|
+
if (data.transcript && String(data.transcript).trim() && data.transcript !== '(empty transcript)'
|
|
694217
|
+
&& (!allMessages || allMessages.length === 0)) {
|
|
694218
|
+
// TUI/raw transcript: PARSE the rendered-TUI scrollback into real chat
|
|
694219
|
+
// bubbles instead of dumping the raw log. The persisted log carries
|
|
694220
|
+
// DYNBLOCK:<id> sentinels (dynamic blocks expanded only at TUI
|
|
694221
|
+
// paint time — no content here) plus chrome (▹ user, │ assistant,
|
|
694222
|
+
// ∙ status, ! internal). We strip the dead sentinels + noise and emit
|
|
694223
|
+
// user/assistant messages so it reads like a GUI chat.
|
|
694224
|
+
renderRecoveredTranscript(String(data.transcript), conv, data.title || '');
|
|
694011
694225
|
}
|
|
694012
694226
|
// WO-CHAT-RESUME-TOOLS — replay the FULL intermediate flow on
|
|
694013
694227
|
// restore: user/assistant text bubbles AND tool_call/tool_result
|
|
@@ -696546,6 +696760,7 @@ function getOpenApiSpec() {
|
|
|
696546
696760
|
},
|
|
696547
696761
|
"/v1/chat/sessions": { get: { summary: "List active chat sessions", tags: ["Chat"], responses: { 200: { description: "Session list" } } } },
|
|
696548
696762
|
"/v1/chat/sessions/{id}/summarize": { post: { summary: "Generate + cache an inference-based title/summary for a session — body {force?, root?}", tags: ["Chat"], responses: { 200: { description: "Title + summary" }, 500: { description: "Generation failed" } } } },
|
|
696763
|
+
"/v1/chat/sessions/{id}/status": { get: { summary: "Reactive recall: is this session running right now + unseen deltas since ?since=<seq> (running, phase, seq, partial, deltas[])", tags: ["Chat"], responses: { 200: { description: "Live run status + catch-up deltas" } } } },
|
|
696549
696764
|
// ───── AIWG cascade ─────
|
|
696550
696765
|
"/v1/aiwg": { get: { summary: "AIWG installation root + control map", tags: ["AIWG"], responses: { 200: { description: "AIWG installation summary" } } } },
|
|
696551
696766
|
"/v1/aiwg/frameworks": { get: { summary: "List AIWG frameworks (paginated)", tags: ["AIWG"], responses: { 200: { description: "Framework list" } } } },
|
|
@@ -697310,6 +697525,96 @@ var init_usage_tracker = __esm({
|
|
|
697310
697525
|
}
|
|
697311
697526
|
});
|
|
697312
697527
|
|
|
697528
|
+
// packages/cli/src/api/chat-run-registry.ts
|
|
697529
|
+
function getChatRunRegistry() {
|
|
697530
|
+
if (!_registry5) _registry5 = new ChatRunRegistry();
|
|
697531
|
+
return _registry5;
|
|
697532
|
+
}
|
|
697533
|
+
var MAX_BUFFER2, ChatRunRegistry, _registry5;
|
|
697534
|
+
var init_chat_run_registry = __esm({
|
|
697535
|
+
"packages/cli/src/api/chat-run-registry.ts"() {
|
|
697536
|
+
"use strict";
|
|
697537
|
+
MAX_BUFFER2 = 400;
|
|
697538
|
+
ChatRunRegistry = class {
|
|
697539
|
+
runs = /* @__PURE__ */ new Map();
|
|
697540
|
+
/** Begin (or restart) a run for a session. Returns the fresh state. */
|
|
697541
|
+
start(sessionId, label) {
|
|
697542
|
+
const now2 = Date.now();
|
|
697543
|
+
const state = {
|
|
697544
|
+
sessionId,
|
|
697545
|
+
phase: "running",
|
|
697546
|
+
startedAt: now2,
|
|
697547
|
+
lastActivityMs: now2,
|
|
697548
|
+
seq: 0,
|
|
697549
|
+
buffer: [],
|
|
697550
|
+
partial: "",
|
|
697551
|
+
...label ? { label } : {}
|
|
697552
|
+
};
|
|
697553
|
+
this.runs.set(sessionId, state);
|
|
697554
|
+
return state;
|
|
697555
|
+
}
|
|
697556
|
+
/** Append a live delta to a running session; no-op if unknown. Returns the seq. */
|
|
697557
|
+
push(sessionId, delta) {
|
|
697558
|
+
const state = this.runs.get(sessionId);
|
|
697559
|
+
if (!state) return -1;
|
|
697560
|
+
const seq = ++state.seq;
|
|
697561
|
+
const entry = { seq, ts: Date.now(), ...delta };
|
|
697562
|
+
state.buffer.push(entry);
|
|
697563
|
+
if (state.buffer.length > MAX_BUFFER2) state.buffer.splice(0, state.buffer.length - MAX_BUFFER2);
|
|
697564
|
+
if (delta.kind === "assistant_delta" && delta.text) state.partial += delta.text;
|
|
697565
|
+
state.lastActivityMs = entry.ts;
|
|
697566
|
+
return seq;
|
|
697567
|
+
}
|
|
697568
|
+
/** Mark a run finished. Keeps the state briefly so late visitors see the result. */
|
|
697569
|
+
finish(sessionId, phase = "completed") {
|
|
697570
|
+
const state = this.runs.get(sessionId);
|
|
697571
|
+
if (!state) return;
|
|
697572
|
+
state.phase = phase;
|
|
697573
|
+
state.lastActivityMs = Date.now();
|
|
697574
|
+
this.push(sessionId, { kind: phase === "completed" ? "done" : "error" });
|
|
697575
|
+
}
|
|
697576
|
+
/** Current status for a session (null when never run this daemon lifetime). */
|
|
697577
|
+
status(sessionId) {
|
|
697578
|
+
const s2 = this.runs.get(sessionId);
|
|
697579
|
+
if (!s2) return null;
|
|
697580
|
+
return {
|
|
697581
|
+
running: s2.phase === "running",
|
|
697582
|
+
phase: s2.phase,
|
|
697583
|
+
lastActivityMs: s2.lastActivityMs,
|
|
697584
|
+
seq: s2.seq,
|
|
697585
|
+
...s2.label ? { label: s2.label } : {}
|
|
697586
|
+
};
|
|
697587
|
+
}
|
|
697588
|
+
/** Deltas the client hasn't seen yet (seq > sinceSeq), for live catch-up. */
|
|
697589
|
+
since(sessionId, sinceSeq) {
|
|
697590
|
+
const s2 = this.runs.get(sessionId);
|
|
697591
|
+
if (!s2) return null;
|
|
697592
|
+
return { deltas: s2.buffer.filter((d2) => d2.seq > sinceSeq), partial: s2.partial, phase: s2.phase };
|
|
697593
|
+
}
|
|
697594
|
+
/** True while a session is actively producing output. */
|
|
697595
|
+
isRunning(sessionId) {
|
|
697596
|
+
return this.runs.get(sessionId)?.phase === "running";
|
|
697597
|
+
}
|
|
697598
|
+
/** Drop a session's run state (e.g. on delete). */
|
|
697599
|
+
clear(sessionId) {
|
|
697600
|
+
this.runs.delete(sessionId);
|
|
697601
|
+
}
|
|
697602
|
+
/** Evict finished runs older than `maxAgeMs` to bound memory. */
|
|
697603
|
+
sweep(maxAgeMs = 30 * 60 * 1e3, now2 = Date.now()) {
|
|
697604
|
+
let removed = 0;
|
|
697605
|
+
for (const [id, s2] of this.runs) {
|
|
697606
|
+
if (s2.phase !== "running" && now2 - s2.lastActivityMs > maxAgeMs) {
|
|
697607
|
+
this.runs.delete(id);
|
|
697608
|
+
removed++;
|
|
697609
|
+
}
|
|
697610
|
+
}
|
|
697611
|
+
return removed;
|
|
697612
|
+
}
|
|
697613
|
+
};
|
|
697614
|
+
_registry5 = null;
|
|
697615
|
+
}
|
|
697616
|
+
});
|
|
697617
|
+
|
|
697313
697618
|
// packages/cli/src/docker.ts
|
|
697314
697619
|
import { execSync as execSync59, spawn as spawn32 } from "node:child_process";
|
|
697315
697620
|
import { existsSync as existsSync156, mkdirSync as mkdirSync98, writeFileSync as writeFileSync83 } from "node:fs";
|
|
@@ -704804,6 +705109,13 @@ data: ${JSON.stringify(data)}
|
|
|
704804
705109
|
const realtimeOpts = realtimeEnabled ? realtimeOptionsFromBody(chatBody, cwdPath, session.id) : null;
|
|
704805
705110
|
addUserMessage(session, chatBody.message);
|
|
704806
705111
|
compactSession(session);
|
|
705112
|
+
{
|
|
705113
|
+
const _runReg = getChatRunRegistry();
|
|
705114
|
+
_runReg.start(session.id, String(chatBody.message).slice(0, 80));
|
|
705115
|
+
res.on("close", () => {
|
|
705116
|
+
_runReg.finish(session.id, res.writableEnded ? "completed" : "aborted");
|
|
705117
|
+
});
|
|
705118
|
+
}
|
|
704807
705119
|
const streamMode = chatBody.stream !== false;
|
|
704808
705120
|
const toolsField = chatBody["tools"];
|
|
704809
705121
|
const isOpenAIToolsArray = Array.isArray(toolsField) && toolsField.length > 0 && toolsField.every(
|
|
@@ -705522,6 +705834,29 @@ ${historyLines}
|
|
|
705522
705834
|
});
|
|
705523
705835
|
return;
|
|
705524
705836
|
}
|
|
705837
|
+
const chatStatusMatch = pathname.match(/^\/v1\/chat\/sessions\/([^/]+)\/status$/);
|
|
705838
|
+
if (chatStatusMatch && method === "GET") {
|
|
705839
|
+
if (!checkAuth(req3, res, "read")) return;
|
|
705840
|
+
const sid = decodeURIComponent(chatStatusMatch[1]);
|
|
705841
|
+
const reg = getChatRunRegistry();
|
|
705842
|
+
const st = reg.status(sid);
|
|
705843
|
+
if (!st) {
|
|
705844
|
+
jsonResponse(res, 200, { session_id: sid, running: false, phase: "idle", seq: 0 });
|
|
705845
|
+
return;
|
|
705846
|
+
}
|
|
705847
|
+
const sinceSeq = Number(new URL(req3.url || "", "http://localhost").searchParams.get("since") ?? "0") || 0;
|
|
705848
|
+
const catchUp = reg.since(sid, sinceSeq);
|
|
705849
|
+
jsonResponse(res, 200, {
|
|
705850
|
+
session_id: sid,
|
|
705851
|
+
running: st.running,
|
|
705852
|
+
phase: st.phase,
|
|
705853
|
+
seq: st.seq,
|
|
705854
|
+
lastActivityMs: st.lastActivityMs,
|
|
705855
|
+
...st.label ? { label: st.label } : {},
|
|
705856
|
+
...catchUp ? { deltas: catchUp.deltas, partial: catchUp.partial } : {}
|
|
705857
|
+
});
|
|
705858
|
+
return;
|
|
705859
|
+
}
|
|
705525
705860
|
const chatSessionMatch = pathname.match(/^\/v1\/chat\/sessions\/([^/]+)$/);
|
|
705526
705861
|
if (chatSessionMatch) {
|
|
705527
705862
|
const sid = decodeURIComponent(chatSessionMatch[1]);
|
|
@@ -708175,6 +708510,7 @@ var init_serve = __esm({
|
|
|
708175
708510
|
init_usage_tracker();
|
|
708176
708511
|
init_omnius_directory();
|
|
708177
708512
|
init_session_summary();
|
|
708513
|
+
init_chat_run_registry();
|
|
708178
708514
|
init_omnius_directory();
|
|
708179
708515
|
init_command_registry();
|
|
708180
708516
|
init_profiles();
|
|
@@ -711992,7 +712328,8 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
711992
712328
|
}
|
|
711993
712329
|
try {
|
|
711994
712330
|
const historySessionId = process.env["OMNIUS_SESSION_ID"] || `session-${Date.now().toString(36)}`;
|
|
711995
|
-
const
|
|
712331
|
+
const rawContentLines = statusBar?._contentLines ?? [];
|
|
712332
|
+
const contentLines = typeof statusBar?.expandDynamicBlockSentinels === "function" ? statusBar.expandDynamicBlockSentinels(rawContentLines, 100) : rawContentLines;
|
|
711996
712333
|
if (contentLines.length > 0) {
|
|
711997
712334
|
const description = cleanPromptForDiary(task).slice(0, 240);
|
|
711998
712335
|
const historyTitle = description.slice(0, 80) || void 0;
|
|
@@ -52,6 +52,7 @@ pnpm docs:check
|
|
|
52
52
|
| `GET` | `/api/tags` | Ollama-compatible model tags |
|
|
53
53
|
| `GET` | `/v1/chat/sessions` | Active chat sessions |
|
|
54
54
|
| `POST` | `/v1/chat/sessions/{id}/summarize` | Generate + cache an inference-based session title/summary |
|
|
55
|
+
| `GET` | `/v1/chat/sessions/{id}/status` | Reactive recall: live run status + unseen deltas (`?since=<seq>`) |
|
|
55
56
|
| `POST` | `/v1/chat/check-in` | Steering check-in for active chat |
|
|
56
57
|
|
|
57
58
|
## Agentic Runs
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.336",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.336",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
|
@@ -3986,9 +3986,9 @@
|
|
|
3986
3986
|
}
|
|
3987
3987
|
},
|
|
3988
3988
|
"node_modules/hono": {
|
|
3989
|
-
"version": "4.12.
|
|
3990
|
-
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.
|
|
3991
|
-
"integrity": "sha512-
|
|
3989
|
+
"version": "4.12.27",
|
|
3990
|
+
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz",
|
|
3991
|
+
"integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==",
|
|
3992
3992
|
"license": "MIT",
|
|
3993
3993
|
"engines": {
|
|
3994
3994
|
"node": ">=16.9.0"
|
package/package.json
CHANGED