omnius 1.0.327 → 1.0.328

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 CHANGED
@@ -1699,12 +1699,12 @@ var init_model_broker = __esm({
1699
1699
  // packages/execution/dist/broker-mediated-backend.js
1700
1700
  function wrapWithBroker(backend, options2) {
1701
1701
  const broker = getModelBroker();
1702
- const clamp9 = options2.clampNumCtx !== false;
1702
+ const clamp10 = options2.clampNumCtx !== false;
1703
1703
  const wrapped = Object.create(backend);
1704
1704
  wrapped.chatCompletion = async (request) => {
1705
1705
  const model = backend.model || request.model || "unknown";
1706
1706
  let effectiveRequest = request;
1707
- if (clamp9) {
1707
+ if (clamp10) {
1708
1708
  const trainCtx = await broker.getNctxTrain(model).catch(() => null);
1709
1709
  const requestedNumCtx = request.numCtx;
1710
1710
  if (trainCtx && trainCtx > 0) {
@@ -1738,7 +1738,7 @@ function wrapWithBroker(backend, options2) {
1738
1738
  wrapped.chatCompletionStream = async function* (request) {
1739
1739
  const model = backend.model || request.model || "unknown";
1740
1740
  let effectiveRequest = request;
1741
- if (clamp9) {
1741
+ if (clamp10) {
1742
1742
  const trainCtx = await broker.getNctxTrain(model).catch(() => null);
1743
1743
  const requestedNumCtx = request.numCtx;
1744
1744
  if (trainCtx && trainCtx > 0) {
@@ -568169,7 +568169,7 @@ ${context2 ?? ""}`;
568169
568169
  }
568170
568170
  }
568171
568171
  _applyTaskAffectFromResult(result, events) {
568172
- const clamp9 = (n2) => Math.max(0, Math.min(1, n2));
568172
+ const clamp10 = (n2) => Math.max(0, Math.min(1, n2));
568173
568173
  let uncertainty = this._taskAffectState.uncertainty * 0.94;
568174
568174
  let frustration = this._taskAffectState.frustration * 0.94;
568175
568175
  let confidence2 = this._taskAffectState.confidence * 0.94;
@@ -568202,11 +568202,11 @@ ${context2 ?? ""}`;
568202
568202
  }
568203
568203
  const level = frustration >= 0.72 || uncertainty >= 0.78 ? 4 : frustration >= 0.52 || uncertainty >= 0.58 ? 3 : frustration >= 0.32 || uncertainty >= 0.38 ? 2 : frustration >= 0.18 || uncertainty >= 0.22 ? 1 : 0;
568204
568204
  this._taskAffectState = {
568205
- uncertainty: clamp9(uncertainty),
568206
- frustration: clamp9(frustration),
568207
- confidence: clamp9(confidence2),
568208
- novelty: clamp9(novelty),
568209
- momentum: clamp9(momentum),
568205
+ uncertainty: clamp10(uncertainty),
568206
+ frustration: clamp10(frustration),
568207
+ confidence: clamp10(confidence2),
568208
+ novelty: clamp10(novelty),
568209
+ momentum: clamp10(momentum),
568210
568210
  adversaryLevel: level,
568211
568211
  lastUpdatedIso: (/* @__PURE__ */ new Date()).toISOString()
568212
568212
  };
@@ -596755,6 +596755,7 @@ __export(render_exports, {
596755
596755
  renderBoxedBlock: () => renderBoxedBlock,
596756
596756
  renderCompactHeader: () => renderCompactHeader,
596757
596757
  renderConfig: () => renderConfig,
596758
+ renderContentBlock: () => renderContentBlock,
596758
596759
  renderContextIntakeBox: () => renderContextIntakeBox,
596759
596760
  renderError: () => renderError,
596760
596761
  renderHeader: () => renderHeader,
@@ -598194,6 +598195,18 @@ ${lines.map((l2) => l2 + "\x1B[0m").join("\n")}
598194
598195
  process.stdout.write(text2);
598195
598196
  _contentWriteHook?.end();
598196
598197
  }
598198
+ function renderContentBlock(text2) {
598199
+ breakTelegramCoalesce();
598200
+ const body = text2.endsWith("\n") ? text2 : text2 + "\n";
598201
+ const redir = _contentWriteHook?.redirect?.();
598202
+ if (redir) {
598203
+ redir(body);
598204
+ return;
598205
+ }
598206
+ _contentWriteHook?.begin();
598207
+ process.stdout.write(body);
598208
+ _contentWriteHook?.end();
598209
+ }
598197
598210
  function renderInfo(message2) {
598198
598211
  breakTelegramCoalesce();
598199
598212
  const redir = _contentWriteHook?.redirect?.();
@@ -604388,623 +604401,6 @@ var init_profiles = __esm({
604388
604401
  }
604389
604402
  });
604390
604403
 
604391
- // packages/cli/src/tui/cad-model-viewer.ts
604392
- import { createServer as createServer7 } from "node:http";
604393
- import { existsSync as existsSync107, readFileSync as readFileSync86, statSync as statSync41 } from "node:fs";
604394
- import { basename as basename22, extname as extname15, resolve as resolve52 } from "node:path";
604395
- function getCurrentCadModelViewer() {
604396
- return currentViewer;
604397
- }
604398
- async function startCadModelViewer(filePath) {
604399
- const resolved = filePath ? resolve52(filePath) : void 0;
604400
- if (resolved && (!existsSync107(resolved) || !statSync41(resolved).isFile())) {
604401
- throw new Error(`3D model file not found: ${resolved}`);
604402
- }
604403
- if (currentViewer) {
604404
- await currentViewer.close().catch(() => {
604405
- });
604406
- currentViewer = null;
604407
- }
604408
- const server2 = createServer7((req3, res) => handleViewerRequest(req3, res, resolved));
604409
- const port = await listenOnEphemeralPort(server2);
604410
- const session = {
604411
- url: `http://127.0.0.1:${port}/`,
604412
- port,
604413
- filePath: resolved,
604414
- close: () => new Promise((resolveClose) => server2.close(() => resolveClose()))
604415
- };
604416
- currentViewer = session;
604417
- server2.on("close", () => {
604418
- if (currentViewer === session) currentViewer = null;
604419
- });
604420
- return session;
604421
- }
604422
- function listenOnEphemeralPort(server2) {
604423
- return new Promise((resolveListen, reject) => {
604424
- server2.once("error", reject);
604425
- server2.listen(0, "127.0.0.1", () => {
604426
- server2.off("error", reject);
604427
- const addr = server2.address();
604428
- if (!addr || typeof addr === "string") {
604429
- reject(new Error("viewer server did not bind to a TCP port"));
604430
- return;
604431
- }
604432
- resolveListen(addr.port);
604433
- });
604434
- });
604435
- }
604436
- function handleViewerRequest(req3, res, filePath) {
604437
- const url = new URL(req3.url || "/", "http://127.0.0.1");
604438
- if (url.pathname === "/health") {
604439
- sendJson(res, 200, { ok: true, file: filePath ?? null });
604440
- return;
604441
- }
604442
- if (url.pathname === "/asset") {
604443
- if (!filePath) {
604444
- sendText(res, 404, "No model file attached to this viewer.");
604445
- return;
604446
- }
604447
- try {
604448
- res.writeHead(200, {
604449
- "Content-Type": contentTypeFor(filePath),
604450
- "Content-Disposition": `inline; filename="${basename22(filePath).replace(/"/g, "")}"`,
604451
- "Cache-Control": "no-store"
604452
- });
604453
- res.end(readFileSync86(filePath));
604454
- } catch (err) {
604455
- sendText(res, 500, err instanceof Error ? err.message : String(err));
604456
- }
604457
- return;
604458
- }
604459
- if (url.pathname !== "/") {
604460
- sendText(res, 404, "Not found");
604461
- return;
604462
- }
604463
- sendHtml(res, viewerHtml(filePath));
604464
- }
604465
- function contentTypeFor(path12) {
604466
- const ext = extname15(path12).toLowerCase();
604467
- if (ext === ".glb") return "model/gltf-binary";
604468
- if (ext === ".gltf") return "model/gltf+json";
604469
- if (ext === ".obj") return "text/plain; charset=utf-8";
604470
- if (ext === ".stl") return "model/stl";
604471
- if (ext === ".ply") return "application/octet-stream";
604472
- return "application/octet-stream";
604473
- }
604474
- function sendJson(res, status, value2) {
604475
- res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
604476
- res.end(JSON.stringify(value2));
604477
- }
604478
- function sendText(res, status, text2) {
604479
- res.writeHead(status, { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" });
604480
- res.end(text2);
604481
- }
604482
- function sendHtml(res, html) {
604483
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
604484
- res.end(html);
604485
- }
604486
- function viewerHtml(filePath) {
604487
- const fileName = filePath ? basename22(filePath) : "";
604488
- const ext = filePath ? extname15(filePath).toLowerCase().replace(/^\./, "") : "";
604489
- return `<!doctype html>
604490
- <html lang="en">
604491
- <head>
604492
- <meta charset="utf-8">
604493
- <meta name="viewport" content="width=device-width,initial-scale=1">
604494
- <title>Omnius CAD/3D Viewer</title>
604495
- <style>
604496
- :root { color-scheme: dark; --bg:#101214; --panel:#181b1f; --line:#2a3037; --fg:#e7edf3; --muted:#9aa7b5; --accent:#5ec6a8; }
604497
- * { box-sizing: border-box; }
604498
- body { margin:0; min-height:100vh; background:var(--bg); color:var(--fg); font:14px/1.4 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; display:grid; grid-template-columns:minmax(280px,360px) 1fr; }
604499
- aside { border-right:1px solid var(--line); background:var(--panel); padding:14px; display:flex; flex-direction:column; gap:12px; min-height:100vh; }
604500
- main { position:relative; min-height:100vh; overflow:hidden; }
604501
- h1 { margin:0; font-size:16px; font-weight:650; }
604502
- .meta { color:var(--muted); font-size:12px; word-break:break-word; }
604503
- textarea { width:100%; min-height:280px; resize:vertical; border:1px solid var(--line); border-radius:6px; background:#0c0e10; color:var(--fg); padding:10px; font:12px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; }
604504
- button { border:1px solid var(--line); border-radius:6px; background:#20262d; color:var(--fg); padding:8px 10px; cursor:pointer; }
604505
- button:hover { border-color:var(--accent); }
604506
- #status { color:var(--muted); min-height:20px; font-size:12px; }
604507
- canvas { display:block; width:100%; height:100%; }
604508
- .row { display:flex; gap:8px; flex-wrap:wrap; }
604509
- @media (max-width: 760px) { body { grid-template-columns:1fr; grid-template-rows:auto 60vh; } aside { min-height:auto; border-right:0; border-bottom:1px solid var(--line); } }
604510
- </style>
604511
- </head>
604512
- <body>
604513
- <aside>
604514
- <div>
604515
- <h1>Omnius CAD/3D Viewer</h1>
604516
- <div class="meta">${escapeHtml(fileName ? `Viewing ${fileName}` : "No file attached. Rendering Compact IR sample.")}</div>
604517
- </div>
604518
- <textarea id="ir">C 50 30 5
604519
- Y 3 8
604520
- T 1 -18 -10 2.5
604521
- Y 3 8
604522
- T 3 18 -10 2.5
604523
- Y 3 8
604524
- T 5 -18 10 2.5
604525
- Y 3 8
604526
- T 7 18 10 2.5</textarea>
604527
- <div class="row">
604528
- <button id="render-ir">Render Compact IR</button>
604529
- <button id="reset-camera">Reset Camera</button>
604530
- </div>
604531
- <div id="status"></div>
604532
- </aside>
604533
- <main id="viewport"></main>
604534
- <script type="module">
604535
- import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.164.1/build/three.module.js';
604536
- import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/controls/OrbitControls.js';
604537
- import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/GLTFLoader.js';
604538
- import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/STLLoader.js';
604539
- import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/OBJLoader.js';
604540
- import { PLYLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/PLYLoader.js';
604541
-
604542
- const assetUrl = ${JSON.stringify(filePath ? "/asset" : "")};
604543
- const assetExt = ${JSON.stringify(ext)};
604544
- const viewport = document.getElementById('viewport');
604545
- const status = document.getElementById('status');
604546
- const scene = new THREE.Scene();
604547
- scene.background = new THREE.Color(0x101214);
604548
- const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 5000);
604549
- const renderer = new THREE.WebGLRenderer({ antialias:true });
604550
- renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
604551
- viewport.appendChild(renderer.domElement);
604552
- const controls = new OrbitControls(camera, renderer.domElement);
604553
- controls.enableDamping = true;
604554
- scene.add(new THREE.HemisphereLight(0xffffff, 0x223344, 1.7));
604555
- const key = new THREE.DirectionalLight(0xffffff, 2.2);
604556
- key.position.set(120, 160, 100);
604557
- scene.add(key);
604558
- const grid = new THREE.GridHelper(160, 32, 0x31404a, 0x253039);
604559
- scene.add(grid);
604560
- let objectRoot = new THREE.Group();
604561
- scene.add(objectRoot);
604562
-
604563
- function setStatus(text) { status.textContent = text || ''; }
604564
- function clearObject() {
604565
- scene.remove(objectRoot);
604566
- objectRoot.traverse((o) => {
604567
- if (o.geometry) o.geometry.dispose?.();
604568
- if (o.material) {
604569
- if (Array.isArray(o.material)) o.material.forEach((m) => m.dispose?.());
604570
- else o.material.dispose?.();
604571
- }
604572
- });
604573
- objectRoot = new THREE.Group();
604574
- scene.add(objectRoot);
604575
- }
604576
- function frameObject() {
604577
- const box = new THREE.Box3().setFromObject(objectRoot);
604578
- if (box.isEmpty()) {
604579
- camera.position.set(70, 70, 70);
604580
- controls.target.set(0, 0, 0);
604581
- return;
604582
- }
604583
- const size = box.getSize(new THREE.Vector3());
604584
- const center = box.getCenter(new THREE.Vector3());
604585
- const max = Math.max(size.x, size.y, size.z, 1);
604586
- camera.position.copy(center).add(new THREE.Vector3(max * 1.35, max * 1.05, max * 1.35));
604587
- controls.target.copy(center);
604588
- camera.near = Math.max(0.01, max / 1000);
604589
- camera.far = Math.max(1000, max * 20);
604590
- camera.updateProjectionMatrix();
604591
- controls.update();
604592
- }
604593
- function makeMaterial(index) {
604594
- const colors = [0x5ec6a8, 0xf0b35a, 0x87a8ff, 0xdc6f7e, 0xb6d96a];
604595
- return new THREE.MeshStandardMaterial({ color: colors[index % colors.length], metalness:0.05, roughness:0.48 });
604596
- }
604597
- function renderCompactIr(text) {
604598
- clearObject();
604599
- const nodes = [];
604600
- const lines = String(text || '').split(/\\r?\\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
604601
- for (const line of lines) {
604602
- const parts = line.split(/\\s+/);
604603
- const op = parts[0].toUpperCase();
604604
- const nums = parts.slice(1).map(Number);
604605
- let mesh = null;
604606
- if (op === 'C' && nums.length >= 3) {
604607
- mesh = new THREE.Mesh(new THREE.BoxGeometry(nums[0], nums[1], nums[2]), makeMaterial(nodes.length));
604608
- } else if (op === 'Y' && nums.length >= 2) {
604609
- mesh = new THREE.Mesh(new THREE.CylinderGeometry(nums[0], nums[0], nums[1], 48), makeMaterial(nodes.length));
604610
- mesh.rotation.x = Math.PI / 2;
604611
- } else if (op === 'S' && nums.length >= 1) {
604612
- mesh = new THREE.Mesh(new THREE.SphereGeometry(nums[0], 48, 24), makeMaterial(nodes.length));
604613
- } else if (op === 'K' && nums.length >= 3) {
604614
- mesh = new THREE.Mesh(new THREE.CylinderGeometry(nums[1], nums[0], nums[2], 48), makeMaterial(nodes.length));
604615
- mesh.rotation.x = Math.PI / 2;
604616
- } else if ((op === 'U' || op === 'D' || op === 'I') && nums.length >= 2) {
604617
- const group = new THREE.Group();
604618
- const a = nodes[nums[0]]?.clone();
604619
- const b = nodes[nums[1]]?.clone();
604620
- if (a) group.add(a);
604621
- if (b) {
604622
- if (op === 'D') b.traverse((o) => { if (o.material) o.material = new THREE.MeshStandardMaterial({ color:0xff5570, wireframe:true }); });
604623
- group.add(b);
604624
- }
604625
- mesh = group;
604626
- } else if ((op === 'T' || op === 'R' || op === 'X') && nums.length >= 4) {
604627
- const target = nodes[nums[0]];
604628
- if (target) {
604629
- if (op === 'T') target.position.add(new THREE.Vector3(nums[1], nums[2], nums[3]));
604630
- if (op === 'R') target.rotation.set(THREE.MathUtils.degToRad(nums[1]), THREE.MathUtils.degToRad(nums[2]), THREE.MathUtils.degToRad(nums[3]));
604631
- if (op === 'X') target.scale.multiply(new THREE.Vector3(nums[1], nums[2], nums[3]));
604632
- }
604633
- nodes.push(target ? target.clone() : new THREE.Group());
604634
- continue;
604635
- } else if ((op === 'F' || op === 'CH' || op === 'SH') && nums.length >= 1) {
604636
- const target = nodes[nums[0]];
604637
- nodes.push(target ? target.clone() : new THREE.Group());
604638
- continue;
604639
- }
604640
- if (mesh) {
604641
- nodes.push(mesh);
604642
- objectRoot.add(mesh);
604643
- }
604644
- }
604645
- if (nodes.length === 0) setStatus('No renderable Compact IR primitives found.');
604646
- else setStatus('Rendered ' + nodes.length + ' Compact IR node(s). Boolean difference is shown as wireframe preview.');
604647
- frameObject();
604648
- }
604649
- async function loadAsset() {
604650
- if (!assetUrl) {
604651
- renderCompactIr(document.getElementById('ir').value);
604652
- return;
604653
- }
604654
- setStatus('Loading attached model...');
604655
- clearObject();
604656
- const done = (obj) => {
604657
- objectRoot.add(obj);
604658
- setStatus('Loaded attached model.');
604659
- frameObject();
604660
- };
604661
- if (assetExt === 'glb' || assetExt === 'gltf') {
604662
- new GLTFLoader().load(assetUrl, (gltf) => done(gltf.scene), undefined, (e) => setStatus(e.message || String(e)));
604663
- } else if (assetExt === 'stl') {
604664
- new STLLoader().load(assetUrl, (geo) => done(new THREE.Mesh(geo, makeMaterial(0))), undefined, (e) => setStatus(e.message || String(e)));
604665
- } else if (assetExt === 'obj') {
604666
- new OBJLoader().load(assetUrl, done, undefined, (e) => setStatus(e.message || String(e)));
604667
- } else if (assetExt === 'ply') {
604668
- new PLYLoader().load(assetUrl, (geo) => done(new THREE.Mesh(geo, makeMaterial(0))), undefined, (e) => setStatus(e.message || String(e)));
604669
- } else {
604670
- setStatus('Unsupported file extension for browser preview. Use GLB, GLTF, OBJ, STL, or PLY.');
604671
- renderCompactIr(document.getElementById('ir').value);
604672
- }
604673
- }
604674
- function resize() {
604675
- const rect = viewport.getBoundingClientRect();
604676
- renderer.setSize(rect.width, rect.height, false);
604677
- camera.aspect = Math.max(1, rect.width) / Math.max(1, rect.height);
604678
- camera.updateProjectionMatrix();
604679
- }
604680
- window.addEventListener('resize', resize);
604681
- document.getElementById('render-ir').addEventListener('click', () => renderCompactIr(document.getElementById('ir').value));
604682
- document.getElementById('reset-camera').addEventListener('click', frameObject);
604683
- renderer.setAnimationLoop(() => { controls.update(); renderer.render(scene, camera); });
604684
- resize();
604685
- loadAsset();
604686
- </script>
604687
- </body>
604688
- </html>`;
604689
- }
604690
- function escapeHtml(value2) {
604691
- return value2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
604692
- }
604693
- var currentViewer;
604694
- var init_cad_model_viewer = __esm({
604695
- "packages/cli/src/tui/cad-model-viewer.ts"() {
604696
- "use strict";
604697
- currentViewer = null;
604698
- }
604699
- });
604700
-
604701
- // packages/cli/src/tui/hf-token-prompt.ts
604702
- import * as fs9 from "node:fs";
604703
- import * as os8 from "node:os";
604704
- import * as path10 from "node:path";
604705
- function loadHfToken() {
604706
- const fromEnv = process.env["HF_TOKEN"]?.trim() || process.env["HUGGING_FACE_HUB_TOKEN"]?.trim() || "";
604707
- if (fromEnv) return fromEnv;
604708
- try {
604709
- if (fs9.existsSync(TOKEN_FILE)) {
604710
- const fromFile = fs9.readFileSync(TOKEN_FILE, "utf8").trim();
604711
- if (fromFile) {
604712
- process.env["HF_TOKEN"] = fromFile;
604713
- return fromFile;
604714
- }
604715
- }
604716
- } catch {
604717
- }
604718
- return null;
604719
- }
604720
- function saveHfToken(token) {
604721
- const trimmed = token.trim();
604722
- if (!trimmed) throw new Error("HF token cannot be empty");
604723
- fs9.mkdirSync(TOKEN_DIR, { recursive: true, mode: 448 });
604724
- fs9.writeFileSync(TOKEN_FILE, trimmed + "\n", { mode: 384 });
604725
- try {
604726
- fs9.chmodSync(TOKEN_FILE, 384);
604727
- } catch {
604728
- }
604729
- process.env["HF_TOKEN"] = trimmed;
604730
- }
604731
- function clearHfToken() {
604732
- try {
604733
- if (fs9.existsSync(TOKEN_FILE)) fs9.unlinkSync(TOKEN_FILE);
604734
- } catch {
604735
- }
604736
- delete process.env["HF_TOKEN"];
604737
- }
604738
- function isHfTokenPromptPending() {
604739
- return pending !== null;
604740
- }
604741
- function describePendingHfTokenPrompt() {
604742
- if (!pending) return null;
604743
- return { model: pending.model, ageMs: Date.now() - pending.startedAt };
604744
- }
604745
- function requestHfToken(opts) {
604746
- const existing = loadHfToken();
604747
- if (existing) return Promise.resolve(existing);
604748
- if (pending) {
604749
- opts.onMessage(
604750
- `Another HF token prompt is already active (for ${pending.model}). Run \`/hf <token>\` to satisfy both, or wait for the existing prompt to time out.`
604751
- );
604752
- return Promise.resolve(null);
604753
- }
604754
- const timeoutMs = Math.max(1e3, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
604755
- const timeoutSec = Math.round(timeoutMs / 1e3);
604756
- const fallbackBit = opts.fallbackModel ? `
604757
- If you don't supply one within ${timeoutSec}s, I will fall back to ${opts.fallbackModel} (no token needed).` : `
604758
- If you don't supply one within ${timeoutSec}s, I will fall back to a non-gated alternative.`;
604759
- opts.onMessage(
604760
- [
604761
- `Hugging Face model "${opts.model}" is gated and needs an access token.`,
604762
- `Get one at https://huggingface.co/settings/tokens (read-only is fine),`,
604763
- `accept the model license at https://huggingface.co/${opts.model},`,
604764
- `then run: /hf <your-token>`,
604765
- fallbackBit.trim()
604766
- ].join("\n")
604767
- );
604768
- return new Promise((resolve71) => {
604769
- const timer = setTimeout(() => {
604770
- const ref = pending;
604771
- pending = null;
604772
- if (ref) {
604773
- ref.onMessage(
604774
- `No HF token supplied within ${timeoutSec}s — falling back to a non-gated alternative for ${opts.model}.`
604775
- );
604776
- }
604777
- resolve71(null);
604778
- }, timeoutMs);
604779
- if (typeof timer.unref === "function") timer.unref();
604780
- pending = {
604781
- model: opts.model,
604782
- onMessage: opts.onMessage,
604783
- resolve: resolve71,
604784
- timer,
604785
- startedAt: Date.now()
604786
- };
604787
- });
604788
- }
604789
- function fulfillHfTokenPrompt(token) {
604790
- const trimmed = token.trim();
604791
- if (!trimmed) return false;
604792
- saveHfToken(trimmed);
604793
- if (!pending) return false;
604794
- const ref = pending;
604795
- pending = null;
604796
- clearTimeout(ref.timer);
604797
- ref.resolve(trimmed);
604798
- return true;
604799
- }
604800
- function cancelHfTokenPrompt() {
604801
- if (!pending) return false;
604802
- const ref = pending;
604803
- pending = null;
604804
- clearTimeout(ref.timer);
604805
- ref.resolve(null);
604806
- return true;
604807
- }
604808
- function isHfGatedError(blob) {
604809
- if (!blob) return false;
604810
- const text2 = blob.toLowerCase();
604811
- if (text2.includes("[hf_token_required")) return true;
604812
- if (text2.includes("gatedrepoerror")) return true;
604813
- if (text2.includes("access to model")) return true;
604814
- if (text2.includes("you need to accept")) return true;
604815
- if (text2.includes("you must be authenticated")) return true;
604816
- if (/(401|403)/.test(text2) && /(gated|access|unauthor|forbid|auth)/.test(text2)) {
604817
- return true;
604818
- }
604819
- return false;
604820
- }
604821
- function extractGatedRepoId(blob) {
604822
- if (!blob) return null;
604823
- const tokenMarker = blob.match(/\[HF_TOKEN_REQUIRED:([^\]\s]+)\]/);
604824
- if (tokenMarker?.[1]) return tokenMarker[1].trim();
604825
- const hfUrl = blob.match(/huggingface\.co\/([A-Za-z0-9._-]+\/[A-Za-z0-9._-]+)/);
604826
- if (hfUrl?.[1]) return hfUrl[1];
604827
- const genericRepo = blob.match(/['"`]([A-Za-z0-9._-]+\/[A-Za-z0-9._-]+)['"`]/);
604828
- if (genericRepo?.[1] && /\/(.+)/.test(genericRepo[1])) return genericRepo[1];
604829
- return null;
604830
- }
604831
- var TOKEN_DIR, TOKEN_FILE, DEFAULT_TIMEOUT_MS4, pending;
604832
- var init_hf_token_prompt = __esm({
604833
- "packages/cli/src/tui/hf-token-prompt.ts"() {
604834
- "use strict";
604835
- TOKEN_DIR = path10.join(os8.homedir(), ".omnius");
604836
- TOKEN_FILE = path10.join(TOKEN_DIR, "hf_token");
604837
- DEFAULT_TIMEOUT_MS4 = 3e4;
604838
- pending = null;
604839
- }
604840
- });
604841
-
604842
- // packages/prompts/dist/loader.js
604843
- var init_loader = __esm({
604844
- "packages/prompts/dist/loader.js"() {
604845
- "use strict";
604846
- }
604847
- });
604848
-
604849
- // packages/prompts/dist/render.js
604850
- var init_render2 = __esm({
604851
- "packages/prompts/dist/render.js"() {
604852
- "use strict";
604853
- }
604854
- });
604855
-
604856
- // packages/prompts/dist/promptLoader.js
604857
- import { readFileSync as readFileSync88, existsSync as existsSync109 } from "node:fs";
604858
- import { join as join123, dirname as dirname38 } from "node:path";
604859
- import { fileURLToPath as fileURLToPath13 } from "node:url";
604860
- function loadPrompt2(promptPath, vars) {
604861
- let content = cache6.get(promptPath);
604862
- if (content === void 0) {
604863
- const fullPath = join123(PROMPTS_DIR2, promptPath);
604864
- if (!existsSync109(fullPath)) {
604865
- throw new Error(`Prompt file not found: ${fullPath}`);
604866
- }
604867
- content = readFileSync88(fullPath, "utf-8");
604868
- cache6.set(promptPath, content);
604869
- }
604870
- if (!vars)
604871
- return content;
604872
- return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
604873
- }
604874
- var __filename4, __dirname5, devPath, publishedPath, PROMPTS_DIR2, cache6;
604875
- var init_promptLoader2 = __esm({
604876
- "packages/prompts/dist/promptLoader.js"() {
604877
- "use strict";
604878
- __filename4 = fileURLToPath13(import.meta.url);
604879
- __dirname5 = dirname38(__filename4);
604880
- devPath = join123(__dirname5, "..", "templates");
604881
- publishedPath = join123(__dirname5, "..", "prompts", "templates");
604882
- PROMPTS_DIR2 = existsSync109(devPath) ? devPath : publishedPath;
604883
- cache6 = /* @__PURE__ */ new Map();
604884
- }
604885
- });
604886
-
604887
- // packages/prompts/dist/task-templates.js
604888
- function getTaskTemplate(type) {
604889
- return TEMPLATES[type];
604890
- }
604891
- function getTaskTypes() {
604892
- return Object.keys(TEMPLATES);
604893
- }
604894
- function buildTaskContext(type) {
604895
- const template = TEMPLATES[type];
604896
- return `${template.systemPromptAddition}
604897
-
604898
- ### Output Guidance
604899
- ${template.outputGuidance}`;
604900
- }
604901
- var TEMPLATES;
604902
- var init_task_templates = __esm({
604903
- "packages/prompts/dist/task-templates.js"() {
604904
- "use strict";
604905
- init_promptLoader2();
604906
- TEMPLATES = {
604907
- code: {
604908
- type: "code",
604909
- label: "Software Development",
604910
- description: "Writing, debugging, refactoring, or reviewing code.",
604911
- systemPromptAddition: loadPrompt2("code.md"),
604912
- recommendedTools: [
604913
- "file_read",
604914
- "file_write",
604915
- "file_edit",
604916
- "shell",
604917
- "grep_search",
604918
- "glob_find",
604919
- "git_info",
604920
- "codebase_map"
604921
- ],
604922
- outputGuidance: "Deliver working code with tests passing. Summarize what was changed and why."
604923
- },
604924
- document: {
604925
- type: "document",
604926
- label: "Document Drafting",
604927
- description: "Creating reports, specifications, guides, proposals, or other professional documents.",
604928
- systemPromptAddition: loadPrompt2("document.md"),
604929
- recommendedTools: [
604930
- "file_read",
604931
- "file_write",
604932
- "web_search",
604933
- "web_fetch",
604934
- "create_structured_file",
604935
- "memory_read"
604936
- ],
604937
- outputGuidance: "Deliver a complete, well-structured document. Specify the output format (Markdown, PDF, etc.)."
604938
- },
604939
- analysis: {
604940
- type: "analysis",
604941
- label: "Analysis & Research",
604942
- description: "Analyzing data, evaluating options, conducting research, or producing insights.",
604943
- systemPromptAddition: loadPrompt2("analysis.md"),
604944
- recommendedTools: [
604945
- "file_read",
604946
- "grep_search",
604947
- "glob_find",
604948
- "web_search",
604949
- "web_fetch",
604950
- "codebase_map",
604951
- "create_structured_file",
604952
- "shell"
604953
- ],
604954
- outputGuidance: "Deliver a structured analysis with findings, data tables, and actionable recommendations."
604955
- },
604956
- plan: {
604957
- type: "plan",
604958
- label: "Planning & Design",
604959
- description: "Creating project plans, system designs, architecture proposals, or roadmaps.",
604960
- systemPromptAddition: loadPrompt2("plan.md"),
604961
- recommendedTools: [
604962
- "file_read",
604963
- "grep_search",
604964
- "glob_find",
604965
- "codebase_map",
604966
- "web_search",
604967
- "create_structured_file",
604968
- "file_write",
604969
- "git_info"
604970
- ],
604971
- outputGuidance: "Deliver a structured plan with phases, milestones, risks, and action items."
604972
- },
604973
- general: {
604974
- type: "general",
604975
- label: "General Task",
604976
- description: "Tasks that don't clearly fit another category.",
604977
- systemPromptAddition: loadPrompt2("general.md"),
604978
- recommendedTools: [
604979
- "file_read",
604980
- "file_write",
604981
- "shell",
604982
- "grep_search",
604983
- "web_search",
604984
- "memory_read"
604985
- ],
604986
- outputGuidance: "Deliver complete results with a clear summary of what was done."
604987
- }
604988
- };
604989
- }
604990
- });
604991
-
604992
- // packages/prompts/dist/index.js
604993
- import { join as join124, dirname as dirname39 } from "node:path";
604994
- import { fileURLToPath as fileURLToPath14 } from "node:url";
604995
- var _dir, _packageRoot;
604996
- var init_dist9 = __esm({
604997
- "packages/prompts/dist/index.js"() {
604998
- "use strict";
604999
- init_loader();
605000
- init_render2();
605001
- init_task_templates();
605002
- init_render2();
605003
- _dir = dirname39(fileURLToPath14(import.meta.url));
605004
- _packageRoot = join124(_dir, "..");
605005
- }
605006
- });
605007
-
605008
604404
  // packages/cli/src/tui/omnius-directory.ts
605009
604405
  var omnius_directory_exports = {};
605010
604406
  __export(omnius_directory_exports, {
@@ -605043,24 +604439,25 @@ __export(omnius_directory_exports, {
605043
604439
  saveSessionHistory: () => saveSessionHistory,
605044
604440
  sessionContextToHistoryBoxData: () => sessionContextToHistoryBoxData,
605045
604441
  stopOmniusGitignoreWatcher: () => stopOmniusGitignoreWatcher,
604442
+ updateSessionEntry: () => updateSessionEntry,
605046
604443
  writeIndexData: () => writeIndexData,
605047
604444
  writeIndexMeta: () => writeIndexMeta,
605048
604445
  writeTaskHandoff: () => writeTaskHandoff2
605049
604446
  });
605050
- import { appendFileSync as appendFileSync9, cpSync as cpSync2, existsSync as existsSync110, mkdirSync as mkdirSync66, readFileSync as readFileSync89, writeFileSync as writeFileSync56, readdirSync as readdirSync37, statSync as statSync42, unlinkSync as unlinkSync22, openSync as openSync2, closeSync as closeSync2, renameSync as renameSync8, watch as fsWatch2 } from "node:fs";
605051
- import { join as join125, relative as relative12, basename as basename23, dirname as dirname40, resolve as resolve53 } from "node:path";
605052
- import { homedir as homedir38 } from "node:os";
604447
+ import { appendFileSync as appendFileSync9, cpSync as cpSync2, existsSync as existsSync107, mkdirSync as mkdirSync65, readFileSync as readFileSync86, writeFileSync as writeFileSync55, readdirSync as readdirSync37, statSync as statSync41, unlinkSync as unlinkSync21, openSync as openSync2, closeSync as closeSync2, renameSync as renameSync8, watch as fsWatch2 } from "node:fs";
604448
+ import { join as join122, relative as relative12, basename as basename22, dirname as dirname38, resolve as resolve52 } from "node:path";
604449
+ import { homedir as homedir37 } from "node:os";
605053
604450
  import { createHash as createHash34 } from "node:crypto";
605054
604451
  function isGitRoot(dir) {
605055
- const gitPath = join125(dir, ".git");
605056
- if (!existsSync110(gitPath)) return false;
604452
+ const gitPath = join122(dir, ".git");
604453
+ if (!existsSync107(gitPath)) return false;
605057
604454
  try {
605058
- const stat8 = statSync42(gitPath);
604455
+ const stat8 = statSync41(gitPath);
605059
604456
  if (stat8.isFile()) {
605060
- return readFileSync89(gitPath, "utf-8").trim().startsWith("gitdir:");
604457
+ return readFileSync86(gitPath, "utf-8").trim().startsWith("gitdir:");
605061
604458
  }
605062
604459
  if (!stat8.isDirectory()) return false;
605063
- return existsSync110(join125(gitPath, "HEAD")) || existsSync110(join125(gitPath, "config")) || existsSync110(join125(gitPath, "commondir"));
604460
+ return existsSync107(join122(gitPath, "HEAD")) || existsSync107(join122(gitPath, "config")) || existsSync107(join122(gitPath, "commondir"));
605064
604461
  } catch {
605065
604462
  return false;
605066
604463
  }
@@ -605071,7 +604468,7 @@ function findGitRoot(startDir) {
605071
604468
  while (dir && !visited.has(dir)) {
605072
604469
  visited.add(dir);
605073
604470
  if (isGitRoot(dir)) return dir;
605074
- const parent = join125(dir, "..");
604471
+ const parent = join122(dir, "..");
605075
604472
  if (parent === dir) break;
605076
604473
  dir = parent;
605077
604474
  }
@@ -605082,10 +604479,10 @@ function findNearestExistingGitignore(startDir, gitRoot) {
605082
604479
  const visited = /* @__PURE__ */ new Set();
605083
604480
  while (dir && !visited.has(dir)) {
605084
604481
  visited.add(dir);
605085
- const candidate = join125(dir, ".gitignore");
605086
- if (existsSync110(candidate)) return candidate;
604482
+ const candidate = join122(dir, ".gitignore");
604483
+ if (existsSync107(candidate)) return candidate;
605087
604484
  if (dir === gitRoot) break;
605088
- const parent = join125(dir, "..");
604485
+ const parent = join122(dir, "..");
605089
604486
  if (parent === dir) break;
605090
604487
  dir = parent;
605091
604488
  }
@@ -605099,7 +604496,7 @@ function candidateGitignoreDirs(startDir, gitRoot) {
605099
604496
  visited.add(dir);
605100
604497
  dirs.push(dir);
605101
604498
  if (dir === gitRoot) break;
605102
- const parent = join125(dir, "..");
604499
+ const parent = join122(dir, "..");
605103
604500
  if (parent === dir) break;
605104
604501
  dir = parent;
605105
604502
  }
@@ -605113,10 +604510,10 @@ function ensureOmniusIgnored(repoRoot) {
605113
604510
  if (!gitRoot) return;
605114
604511
  const gitignorePath = findNearestExistingGitignore(repoRoot, gitRoot);
605115
604512
  if (!gitignorePath) return;
605116
- const gitignoreDir = dirname40(gitignorePath);
604513
+ const gitignoreDir = dirname38(gitignorePath);
605117
604514
  const relDir = relative12(gitignoreDir || ".", repoRoot).replace(/\\/g, "/");
605118
604515
  const ignorePattern = relDir && relDir !== "." ? `${relDir}/.omnius/` : ".omnius/";
605119
- const content = readFileSync89(gitignorePath, "utf-8");
604516
+ const content = readFileSync86(gitignorePath, "utf-8");
605120
604517
  const normalizedTarget = normalizeIgnoreRule(ignorePattern);
605121
604518
  const alreadyIgnored = content.split(/\r?\n/).some((line) => {
605122
604519
  const trimmed = line.trim();
@@ -605124,7 +604521,7 @@ function ensureOmniusIgnored(repoRoot) {
605124
604521
  return normalizeIgnoreRule(trimmed) === normalizedTarget;
605125
604522
  });
605126
604523
  if (alreadyIgnored) return;
605127
- writeFileSync56(
604524
+ writeFileSync55(
605128
604525
  gitignorePath,
605129
604526
  (content.trimEnd() ? `${content.trimEnd()}
605130
604527
  ` : "") + `${ignorePattern}
@@ -605135,7 +604532,7 @@ function ensureOmniusIgnored(repoRoot) {
605135
604532
  function watchForOmniusGitignore(repoRoot) {
605136
604533
  const gitRoot = findGitRoot(repoRoot);
605137
604534
  if (!gitRoot) return;
605138
- const key = resolve53(repoRoot);
604535
+ const key = resolve52(repoRoot);
605139
604536
  if (gitignoreWatchers.has(key)) return;
605140
604537
  const watchers = [];
605141
604538
  for (const dir of candidateGitignoreDirs(repoRoot, gitRoot)) {
@@ -605161,7 +604558,7 @@ function watchForOmniusGitignore(repoRoot) {
605161
604558
  if (watchers.length > 0) gitignoreWatchers.set(key, watchers);
605162
604559
  }
605163
604560
  function stopOmniusGitignoreWatcher(repoRoot) {
605164
- const keys = repoRoot ? [resolve53(repoRoot)] : Array.from(gitignoreWatchers.keys());
604561
+ const keys = repoRoot ? [resolve52(repoRoot)] : Array.from(gitignoreWatchers.keys());
605165
604562
  for (const key of keys) {
605166
604563
  const watchers = gitignoreWatchers.get(key) ?? [];
605167
604564
  for (const watcher of watchers) {
@@ -605175,8 +604572,8 @@ function stopOmniusGitignoreWatcher(repoRoot) {
605175
604572
  }
605176
604573
  function migrateLegacyDirectories(repoRoot, omniusPath) {
605177
604574
  for (const legacyDir of LEGACY_DIRS) {
605178
- const legacyPath = join125(repoRoot, legacyDir);
605179
- if (!existsSync110(legacyPath) || legacyPath === omniusPath) continue;
604575
+ const legacyPath = join122(repoRoot, legacyDir);
604576
+ if (!existsSync107(legacyPath) || legacyPath === omniusPath) continue;
605180
604577
  try {
605181
604578
  cpSync2(legacyPath, omniusPath, {
605182
604579
  recursive: true,
@@ -605188,11 +604585,11 @@ function migrateLegacyDirectories(repoRoot, omniusPath) {
605188
604585
  }
605189
604586
  }
605190
604587
  function initOmniusDirectory(repoRoot) {
605191
- const omniusPath = join125(repoRoot, OMNIUS_DIR);
605192
- mkdirSync66(omniusPath, { recursive: true });
604588
+ const omniusPath = join122(repoRoot, OMNIUS_DIR);
604589
+ mkdirSync65(omniusPath, { recursive: true });
605193
604590
  migrateLegacyDirectories(repoRoot, omniusPath);
605194
604591
  for (const sub2 of SUBDIRS) {
605195
- mkdirSync66(join125(omniusPath, sub2), { recursive: true });
604592
+ mkdirSync65(join122(omniusPath, sub2), { recursive: true });
605196
604593
  }
605197
604594
  try {
605198
604595
  ensureOmniusIgnored(repoRoot);
@@ -605205,41 +604602,41 @@ function initOmniusDirectory(repoRoot) {
605205
604602
  return omniusPath;
605206
604603
  }
605207
604604
  function hasOmniusDirectory(repoRoot) {
605208
- return existsSync110(join125(repoRoot, OMNIUS_DIR, "index"));
604605
+ return existsSync107(join122(repoRoot, OMNIUS_DIR, "index"));
605209
604606
  }
605210
604607
  function loadProjectSettings(repoRoot) {
605211
- const settingsPath = join125(repoRoot, OMNIUS_DIR, "settings.json");
604608
+ const settingsPath = join122(repoRoot, OMNIUS_DIR, "settings.json");
605212
604609
  try {
605213
- if (existsSync110(settingsPath)) {
605214
- return JSON.parse(readFileSync89(settingsPath, "utf-8"));
604610
+ if (existsSync107(settingsPath)) {
604611
+ return JSON.parse(readFileSync86(settingsPath, "utf-8"));
605215
604612
  }
605216
604613
  } catch {
605217
604614
  }
605218
604615
  return {};
605219
604616
  }
605220
604617
  function saveProjectSettings(repoRoot, settings) {
605221
- const omniusPath = join125(repoRoot, OMNIUS_DIR);
605222
- mkdirSync66(omniusPath, { recursive: true });
604618
+ const omniusPath = join122(repoRoot, OMNIUS_DIR);
604619
+ mkdirSync65(omniusPath, { recursive: true });
605223
604620
  const existing = loadProjectSettings(repoRoot);
605224
604621
  const merged = { ...existing, ...settings };
605225
- writeFileSync56(join125(omniusPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
604622
+ writeFileSync55(join122(omniusPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
605226
604623
  }
605227
604624
  function loadGlobalSettings() {
605228
- const settingsPath = join125(homedir38(), ".omnius", "settings.json");
604625
+ const settingsPath = join122(homedir37(), ".omnius", "settings.json");
605229
604626
  try {
605230
- if (existsSync110(settingsPath)) {
605231
- return JSON.parse(readFileSync89(settingsPath, "utf-8"));
604627
+ if (existsSync107(settingsPath)) {
604628
+ return JSON.parse(readFileSync86(settingsPath, "utf-8"));
605232
604629
  }
605233
604630
  } catch {
605234
604631
  }
605235
604632
  return {};
605236
604633
  }
605237
604634
  function saveGlobalSettings(settings) {
605238
- const dir = join125(homedir38(), ".omnius");
605239
- mkdirSync66(dir, { recursive: true });
604635
+ const dir = join122(homedir37(), ".omnius");
604636
+ mkdirSync65(dir, { recursive: true });
605240
604637
  const existing = loadGlobalSettings();
605241
604638
  const merged = { ...existing, ...settings };
605242
- writeFileSync56(join125(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
604639
+ writeFileSync55(join122(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
605243
604640
  }
605244
604641
  function resolveSettings(repoRoot) {
605245
604642
  const global2 = loadGlobalSettings();
@@ -605254,12 +604651,12 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
605254
604651
  while (dir && !visited.has(dir)) {
605255
604652
  visited.add(dir);
605256
604653
  for (const name10 of CONTEXT_FILES) {
605257
- const filePath = join125(dir, name10);
604654
+ const filePath = join122(dir, name10);
605258
604655
  const normalizedName = name10.toLowerCase();
605259
- if (existsSync110(filePath) && !seen.has(filePath)) {
604656
+ if (existsSync107(filePath) && !seen.has(filePath)) {
605260
604657
  seen.add(filePath);
605261
604658
  try {
605262
- let content = readFileSync89(filePath, "utf-8");
604659
+ let content = readFileSync86(filePath, "utf-8");
605263
604660
  if (content.length > maxContentLen) {
605264
604661
  content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
605265
604662
  }
@@ -605273,7 +604670,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
605273
604670
  }
605274
604671
  }
605275
604672
  }
605276
- const parent = join125(dir, "..");
604673
+ const parent = join122(dir, "..");
605277
604674
  if (parent === dir) break;
605278
604675
  dir = parent;
605279
604676
  }
@@ -605290,34 +604687,34 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
605290
604687
  return found;
605291
604688
  }
605292
604689
  function readIndexMeta(repoRoot) {
605293
- const metaPath = join125(repoRoot, OMNIUS_DIR, "index", "meta.json");
604690
+ const metaPath = join122(repoRoot, OMNIUS_DIR, "index", "meta.json");
605294
604691
  try {
605295
- return JSON.parse(readFileSync89(metaPath, "utf-8"));
604692
+ return JSON.parse(readFileSync86(metaPath, "utf-8"));
605296
604693
  } catch {
605297
604694
  return null;
605298
604695
  }
605299
604696
  }
605300
604697
  function writeIndexMeta(repoRoot, meta) {
605301
- const metaPath = join125(repoRoot, OMNIUS_DIR, "index", "meta.json");
605302
- mkdirSync66(join125(repoRoot, OMNIUS_DIR, "index"), { recursive: true });
605303
- writeFileSync56(metaPath, JSON.stringify(meta, null, 2), "utf-8");
604698
+ const metaPath = join122(repoRoot, OMNIUS_DIR, "index", "meta.json");
604699
+ mkdirSync65(join122(repoRoot, OMNIUS_DIR, "index"), { recursive: true });
604700
+ writeFileSync55(metaPath, JSON.stringify(meta, null, 2), "utf-8");
605304
604701
  }
605305
604702
  function readIndexData(repoRoot, filename) {
605306
- const filePath = join125(repoRoot, OMNIUS_DIR, "index", filename);
604703
+ const filePath = join122(repoRoot, OMNIUS_DIR, "index", filename);
605307
604704
  try {
605308
- return JSON.parse(readFileSync89(filePath, "utf-8"));
604705
+ return JSON.parse(readFileSync86(filePath, "utf-8"));
605309
604706
  } catch {
605310
604707
  return null;
605311
604708
  }
605312
604709
  }
605313
604710
  function writeIndexData(repoRoot, filename, data) {
605314
- const filePath = join125(repoRoot, OMNIUS_DIR, "index", filename);
605315
- mkdirSync66(join125(repoRoot, OMNIUS_DIR, "index"), { recursive: true });
605316
- writeFileSync56(filePath, JSON.stringify(data, null, 2), "utf-8");
604711
+ const filePath = join122(repoRoot, OMNIUS_DIR, "index", filename);
604712
+ mkdirSync65(join122(repoRoot, OMNIUS_DIR, "index"), { recursive: true });
604713
+ writeFileSync55(filePath, JSON.stringify(data, null, 2), "utf-8");
605317
604714
  }
605318
604715
  function generateProjectMap(repoRoot) {
605319
604716
  const sections = [];
605320
- const repoName2 = basename23(repoRoot);
604717
+ const repoName2 = basename22(repoRoot);
605321
604718
  sections.push(`# Project Map: ${repoName2}
605322
604719
  `);
605323
604720
  sections.push(`> Auto-generated by omnius. Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -605360,31 +604757,31 @@ ${tree2}\`\`\`
605360
604757
  sections.push("");
605361
604758
  }
605362
604759
  const content = sections.join("\n");
605363
- const contextDir = join125(repoRoot, OMNIUS_DIR, "context");
605364
- mkdirSync66(contextDir, { recursive: true });
605365
- writeFileSync56(join125(contextDir, "project-map.md"), content, "utf-8");
604760
+ const contextDir = join122(repoRoot, OMNIUS_DIR, "context");
604761
+ mkdirSync65(contextDir, { recursive: true });
604762
+ writeFileSync55(join122(contextDir, "project-map.md"), content, "utf-8");
605366
604763
  return content;
605367
604764
  }
605368
604765
  function saveSession(repoRoot, session) {
605369
- const historyDir = join125(repoRoot, OMNIUS_DIR, "history");
605370
- mkdirSync66(historyDir, { recursive: true });
605371
- writeFileSync56(
605372
- join125(historyDir, `${session.id}.json`),
604766
+ const historyDir = join122(repoRoot, OMNIUS_DIR, "history");
604767
+ mkdirSync65(historyDir, { recursive: true });
604768
+ writeFileSync55(
604769
+ join122(historyDir, `${session.id}.json`),
605373
604770
  JSON.stringify(session, null, 2),
605374
604771
  "utf-8"
605375
604772
  );
605376
604773
  }
605377
604774
  function loadRecentSessions(repoRoot, limit = 5) {
605378
- const historyDir = join125(repoRoot, OMNIUS_DIR, "history");
605379
- if (!existsSync110(historyDir)) return [];
604775
+ const historyDir = join122(repoRoot, OMNIUS_DIR, "history");
604776
+ if (!existsSync107(historyDir)) return [];
605380
604777
  try {
605381
604778
  const files = readdirSync37(historyDir).filter((f2) => f2.endsWith(".json") && f2 !== "pending-task.json").map((f2) => {
605382
- const stat8 = statSync42(join125(historyDir, f2));
604779
+ const stat8 = statSync41(join122(historyDir, f2));
605383
604780
  return { file: f2, mtime: stat8.mtimeMs };
605384
604781
  }).sort((a2, b) => b.mtime - a2.mtime).slice(0, limit);
605385
604782
  return files.map((f2) => {
605386
604783
  try {
605387
- return JSON.parse(readFileSync89(join125(historyDir, f2.file), "utf-8"));
604784
+ return JSON.parse(readFileSync86(join122(historyDir, f2.file), "utf-8"));
605388
604785
  } catch {
605389
604786
  return null;
605390
604787
  }
@@ -605396,21 +604793,21 @@ function loadRecentSessions(repoRoot, limit = 5) {
605396
604793
  }
605397
604794
  }
605398
604795
  function savePendingTask(repoRoot, task) {
605399
- const historyDir = join125(repoRoot, OMNIUS_DIR, "history");
605400
- mkdirSync66(historyDir, { recursive: true });
605401
- writeFileSync56(
605402
- join125(historyDir, PENDING_TASK_FILE),
604796
+ const historyDir = join122(repoRoot, OMNIUS_DIR, "history");
604797
+ mkdirSync65(historyDir, { recursive: true });
604798
+ writeFileSync55(
604799
+ join122(historyDir, PENDING_TASK_FILE),
605403
604800
  JSON.stringify(task, null, 2) + "\n",
605404
604801
  "utf-8"
605405
604802
  );
605406
604803
  }
605407
604804
  function loadPendingTask(repoRoot) {
605408
- const filePath = join125(repoRoot, OMNIUS_DIR, "history", PENDING_TASK_FILE);
604805
+ const filePath = join122(repoRoot, OMNIUS_DIR, "history", PENDING_TASK_FILE);
605409
604806
  try {
605410
- if (!existsSync110(filePath)) return null;
605411
- const data = JSON.parse(readFileSync89(filePath, "utf-8"));
604807
+ if (!existsSync107(filePath)) return null;
604808
+ const data = JSON.parse(readFileSync86(filePath, "utf-8"));
605412
604809
  try {
605413
- unlinkSync22(filePath);
604810
+ unlinkSync21(filePath);
605414
604811
  } catch {
605415
604812
  }
605416
604813
  return data;
@@ -605419,26 +604816,26 @@ function loadPendingTask(repoRoot) {
605419
604816
  }
605420
604817
  }
605421
604818
  function writeTaskHandoff2(repoRoot, handoff) {
605422
- const contextDir = join125(repoRoot, OMNIUS_DIR, "context");
605423
- mkdirSync66(contextDir, { recursive: true });
605424
- const filePath = join125(contextDir, HANDOFF_FILE);
604819
+ const contextDir = join122(repoRoot, OMNIUS_DIR, "context");
604820
+ mkdirSync65(contextDir, { recursive: true });
604821
+ const filePath = join122(contextDir, HANDOFF_FILE);
605425
604822
  const tempPath = filePath + ".tmp";
605426
- writeFileSync56(tempPath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
604823
+ writeFileSync55(tempPath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
605427
604824
  try {
605428
604825
  renameSync8(tempPath, filePath);
605429
604826
  } catch {
605430
- writeFileSync56(filePath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
604827
+ writeFileSync55(filePath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
605431
604828
  try {
605432
- unlinkSync22(tempPath);
604829
+ unlinkSync21(tempPath);
605433
604830
  } catch {
605434
604831
  }
605435
604832
  }
605436
604833
  }
605437
604834
  function readTaskHandoff2(repoRoot) {
605438
- const filePath = join125(repoRoot, OMNIUS_DIR, "context", HANDOFF_FILE);
604835
+ const filePath = join122(repoRoot, OMNIUS_DIR, "context", HANDOFF_FILE);
605439
604836
  try {
605440
- if (!existsSync110(filePath)) return null;
605441
- const data = JSON.parse(readFileSync89(filePath, "utf-8"));
604837
+ if (!existsSync107(filePath)) return null;
604838
+ const data = JSON.parse(readFileSync86(filePath, "utf-8"));
605442
604839
  const handoffTime = new Date(data.handoffAt).getTime();
605443
604840
  const now2 = Date.now();
605444
604841
  const ageMs = now2 - handoffTime;
@@ -605452,10 +604849,10 @@ function readTaskHandoff2(repoRoot) {
605452
604849
  }
605453
604850
  }
605454
604851
  function clearTaskHandoff(repoRoot) {
605455
- const filePath = join125(repoRoot, OMNIUS_DIR, "context", HANDOFF_FILE);
604852
+ const filePath = join122(repoRoot, OMNIUS_DIR, "context", HANDOFF_FILE);
605456
604853
  try {
605457
- if (existsSync110(filePath)) {
605458
- unlinkSync22(filePath);
604854
+ if (existsSync107(filePath)) {
604855
+ unlinkSync21(filePath);
605459
604856
  }
605460
604857
  } catch {
605461
604858
  }
@@ -605518,24 +604915,24 @@ function acquireLock(lockPath) {
605518
604915
  try {
605519
604916
  const fd = openSync2(lockPath, "wx");
605520
604917
  const lockData = JSON.stringify({ pid, acquiredAt: Date.now() });
605521
- writeFileSync56(fd, lockData);
604918
+ writeFileSync55(fd, lockData);
605522
604919
  closeSync2(fd);
605523
604920
  return true;
605524
604921
  } catch (err) {
605525
- if (existsSync110(lockPath)) {
604922
+ if (existsSync107(lockPath)) {
605526
604923
  try {
605527
- const lockContent = readFileSync89(lockPath, "utf-8");
604924
+ const lockContent = readFileSync86(lockPath, "utf-8");
605528
604925
  const lock = JSON.parse(lockContent);
605529
604926
  const lockAge = Date.now() - lock.acquiredAt;
605530
604927
  if (lockAge > LOCK_TIMEOUT_MS) {
605531
604928
  try {
605532
- unlinkSync22(lockPath);
604929
+ unlinkSync21(lockPath);
605533
604930
  } catch {
605534
604931
  }
605535
604932
  }
605536
604933
  } catch {
605537
604934
  try {
605538
- unlinkSync22(lockPath);
604935
+ unlinkSync21(lockPath);
605539
604936
  } catch {
605540
604937
  }
605541
604938
  }
@@ -605549,11 +604946,11 @@ function acquireLock(lockPath) {
605549
604946
  }
605550
604947
  function releaseLock(lockPath) {
605551
604948
  try {
605552
- if (existsSync110(lockPath)) {
605553
- const lockContent = readFileSync89(lockPath, "utf-8");
604949
+ if (existsSync107(lockPath)) {
604950
+ const lockContent = readFileSync86(lockPath, "utf-8");
605554
604951
  const lock = JSON.parse(lockContent);
605555
604952
  if (lock.pid === process.pid) {
605556
- unlinkSync22(lockPath);
604953
+ unlinkSync21(lockPath);
605557
604954
  }
605558
604955
  }
605559
604956
  } catch {
@@ -605639,29 +605036,29 @@ function mergeSessionContextEntry(previous, incoming) {
605639
605036
  }
605640
605037
  function pruneContextLedger(ledgerPath) {
605641
605038
  try {
605642
- if (!existsSync110(ledgerPath)) return;
605643
- const st = statSync42(ledgerPath);
605039
+ if (!existsSync107(ledgerPath)) return;
605040
+ const st = statSync41(ledgerPath);
605644
605041
  if (st.size <= MAX_CONTEXT_LEDGER_BYTES) return;
605645
- const lines = readFileSync89(ledgerPath, "utf-8").split(/\r?\n/).filter((line) => line.trim().length > 0);
605042
+ const lines = readFileSync86(ledgerPath, "utf-8").split(/\r?\n/).filter((line) => line.trim().length > 0);
605646
605043
  if (lines.length <= MAX_CONTEXT_LEDGER_LINES) return;
605647
605044
  const kept = lines.slice(-MAX_CONTEXT_LEDGER_LINES);
605648
- const archiveDir = join125(dirname40(ledgerPath), "archive");
605649
- mkdirSync66(archiveDir, { recursive: true });
605650
- const archivePath = join125(
605045
+ const archiveDir = join122(dirname38(ledgerPath), "archive");
605046
+ mkdirSync65(archiveDir, { recursive: true });
605047
+ const archivePath = join122(
605651
605048
  archiveDir,
605652
605049
  `session-context.events.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.jsonl`
605653
605050
  );
605654
- writeFileSync56(archivePath, lines.slice(0, -MAX_CONTEXT_LEDGER_LINES).join("\n") + "\n", "utf-8");
605655
- writeFileSync56(ledgerPath, kept.join("\n") + "\n", "utf-8");
605051
+ writeFileSync55(archivePath, lines.slice(0, -MAX_CONTEXT_LEDGER_LINES).join("\n") + "\n", "utf-8");
605052
+ writeFileSync55(ledgerPath, kept.join("\n") + "\n", "utf-8");
605656
605053
  } catch {
605657
605054
  }
605658
605055
  }
605659
605056
  function saveSessionContext(repoRoot, entry) {
605660
- const contextDir = join125(repoRoot, OMNIUS_DIR, "context");
605661
- mkdirSync66(contextDir, { recursive: true });
605662
- const filePath = join125(contextDir, CONTEXT_SAVE_FILE);
605663
- const ledgerPath = join125(contextDir, CONTEXT_LEDGER_FILE);
605664
- const lockPath = join125(contextDir, CONTEXT_SAVE_FILE + ".lock");
605057
+ const contextDir = join122(repoRoot, OMNIUS_DIR, "context");
605058
+ mkdirSync65(contextDir, { recursive: true });
605059
+ const filePath = join122(contextDir, CONTEXT_SAVE_FILE);
605060
+ const ledgerPath = join122(contextDir, CONTEXT_LEDGER_FILE);
605061
+ const lockPath = join122(contextDir, CONTEXT_SAVE_FILE + ".lock");
605665
605062
  const locked = acquireLock(lockPath);
605666
605063
  if (!locked) {
605667
605064
  console.warn("[saveSessionContext] Could not acquire lock, proceeding without mutex");
@@ -605669,8 +605066,8 @@ function saveSessionContext(repoRoot, entry) {
605669
605066
  try {
605670
605067
  let ctx3;
605671
605068
  try {
605672
- if (existsSync110(filePath)) {
605673
- ctx3 = JSON.parse(readFileSync89(filePath, "utf-8"));
605069
+ if (existsSync107(filePath)) {
605070
+ ctx3 = JSON.parse(readFileSync86(filePath, "utf-8"));
605674
605071
  } else {
605675
605072
  ctx3 = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
605676
605073
  }
@@ -605733,19 +605130,19 @@ function saveSessionContext(repoRoot, entry) {
605733
605130
  }
605734
605131
  ctx3.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
605735
605132
  const tempFilePath = filePath + ".tmp";
605736
- writeFileSync56(tempFilePath, JSON.stringify(ctx3, null, 2) + "\n", "utf-8");
605133
+ writeFileSync55(tempFilePath, JSON.stringify(ctx3, null, 2) + "\n", "utf-8");
605737
605134
  try {
605738
605135
  renameSync8(tempFilePath, filePath);
605739
605136
  } catch {
605740
- writeFileSync56(filePath, JSON.stringify(ctx3, null, 2) + "\n", "utf-8");
605137
+ writeFileSync55(filePath, JSON.stringify(ctx3, null, 2) + "\n", "utf-8");
605741
605138
  try {
605742
- unlinkSync22(tempFilePath);
605139
+ unlinkSync21(tempFilePath);
605743
605140
  } catch {
605744
605141
  }
605745
605142
  }
605746
605143
  try {
605747
- writeFileSync56(
605748
- join125(contextDir, "session-diary.md"),
605144
+ writeFileSync55(
605145
+ join122(contextDir, "session-diary.md"),
605749
605146
  renderSessionDiary(ctx3.entries.slice(-MAX_SESSION_DIARY_ENTRIES)),
605750
605147
  "utf-8"
605751
605148
  );
@@ -605829,10 +605226,10 @@ function renderSessionDiary(entries) {
605829
605226
  return lines.join("\n");
605830
605227
  }
605831
605228
  function loadSessionContext(repoRoot) {
605832
- const filePath = join125(repoRoot, OMNIUS_DIR, "context", CONTEXT_SAVE_FILE);
605229
+ const filePath = join122(repoRoot, OMNIUS_DIR, "context", CONTEXT_SAVE_FILE);
605833
605230
  try {
605834
- if (!existsSync110(filePath)) return null;
605835
- return JSON.parse(readFileSync89(filePath, "utf-8"));
605231
+ if (!existsSync107(filePath)) return null;
605232
+ return JSON.parse(readFileSync86(filePath, "utf-8"));
605836
605233
  } catch {
605837
605234
  return null;
605838
605235
  }
@@ -605916,6 +605313,20 @@ function getLastTaskSummary(repoRoot) {
605916
605313
  const clean5 = text2.replace(/^\[.*?\]\s*/, "").replace(/\s+/g, " ").trim();
605917
605314
  return clean5.length > 40 ? clean5.slice(0, 37) + "..." : clean5;
605918
605315
  }
605316
+ function updateSessionEntry(repoRoot, sessionId, patch) {
605317
+ const indexPath = join122(repoRoot, OMNIUS_DIR, SESSIONS_DIR, SESSIONS_INDEX);
605318
+ try {
605319
+ if (!existsSync107(indexPath)) return false;
605320
+ const index = JSON.parse(readFileSync86(indexPath, "utf-8"));
605321
+ const idx = index.findIndex((e2) => e2.id === sessionId);
605322
+ if (idx < 0) return false;
605323
+ index[idx] = { ...index[idx], ...patch };
605324
+ writeFileSync55(indexPath, JSON.stringify(index, null, 2), "utf-8");
605325
+ return true;
605326
+ } catch {
605327
+ return false;
605328
+ }
605329
+ }
605919
605330
  function cleanSessionHistoryDisplayLine(line) {
605920
605331
  return String(line || "").replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/^[>❯▹∙•*+\-\s]+/, "").replace(/^\[.*?\]\s*/, "").replace(/^(?:User|Assistant|You|Open Agent|Omnius)\s*:\s*/i, "").replace(/\s+/g, " ").trim();
605921
605332
  }
@@ -605942,20 +605353,20 @@ function sanitizeSessionHistoryEntry(repoRoot, entry) {
605942
605353
  };
605943
605354
  }
605944
605355
  function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
605945
- const sessDir = join125(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
605946
- mkdirSync66(sessDir, { recursive: true });
605356
+ const sessDir = join122(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
605357
+ mkdirSync65(sessDir, { recursive: true });
605947
605358
  const stripped = contentLines.map(
605948
605359
  (line) => typeof line === "string" ? line.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "") : ""
605949
605360
  );
605950
605361
  const autoName = meta.name || generateSessionName(stripped);
605951
605362
  const autoDesc = meta.description || generateSessionDescription(stripped);
605952
- const contentPath = join125(sessDir, `${sessionId}.jsonl`);
605953
- writeFileSync56(contentPath, stripped.join("\n"), "utf-8");
605954
- const indexPath = join125(sessDir, SESSIONS_INDEX);
605363
+ const contentPath = join122(sessDir, `${sessionId}.jsonl`);
605364
+ writeFileSync55(contentPath, stripped.join("\n"), "utf-8");
605365
+ const indexPath = join122(sessDir, SESSIONS_INDEX);
605955
605366
  let index = [];
605956
605367
  try {
605957
- if (existsSync110(indexPath)) {
605958
- index = JSON.parse(readFileSync89(indexPath, "utf-8"));
605368
+ if (existsSync107(indexPath)) {
605369
+ index = JSON.parse(readFileSync86(indexPath, "utf-8"));
605959
605370
  }
605960
605371
  } catch {
605961
605372
  }
@@ -605977,41 +605388,41 @@ function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
605977
605388
  if (index.length > 50) {
605978
605389
  const removed = index.shift();
605979
605390
  try {
605980
- unlinkSync22(join125(sessDir, `${removed.id}.jsonl`));
605391
+ unlinkSync21(join122(sessDir, `${removed.id}.jsonl`));
605981
605392
  } catch {
605982
605393
  }
605983
605394
  }
605984
- writeFileSync56(indexPath, JSON.stringify(index, null, 2), "utf-8");
605395
+ writeFileSync55(indexPath, JSON.stringify(index, null, 2), "utf-8");
605985
605396
  }
605986
605397
  function listSessions(repoRoot) {
605987
- const indexPath = join125(repoRoot, OMNIUS_DIR, SESSIONS_DIR, SESSIONS_INDEX);
605398
+ const indexPath = join122(repoRoot, OMNIUS_DIR, SESSIONS_DIR, SESSIONS_INDEX);
605988
605399
  try {
605989
- if (!existsSync110(indexPath)) return [];
605990
- const index = JSON.parse(readFileSync89(indexPath, "utf-8"));
605400
+ if (!existsSync107(indexPath)) return [];
605401
+ const index = JSON.parse(readFileSync86(indexPath, "utf-8"));
605991
605402
  return index.map((entry) => sanitizeSessionHistoryEntry(repoRoot, entry)).sort((a2, b) => b.updatedAt.localeCompare(a2.updatedAt));
605992
605403
  } catch {
605993
605404
  return [];
605994
605405
  }
605995
605406
  }
605996
605407
  function loadSessionHistory(repoRoot, sessionId) {
605997
- const contentPath = join125(repoRoot, OMNIUS_DIR, SESSIONS_DIR, `${sessionId}.jsonl`);
605408
+ const contentPath = join122(repoRoot, OMNIUS_DIR, SESSIONS_DIR, `${sessionId}.jsonl`);
605998
605409
  try {
605999
- if (!existsSync110(contentPath)) return null;
606000
- return readFileSync89(contentPath, "utf-8").split("\n");
605410
+ if (!existsSync107(contentPath)) return null;
605411
+ return readFileSync86(contentPath, "utf-8").split("\n");
606001
605412
  } catch {
606002
605413
  return null;
606003
605414
  }
606004
605415
  }
606005
605416
  function deleteSession(repoRoot, sessionId) {
606006
- const sessDir = join125(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
606007
- const indexPath = join125(sessDir, SESSIONS_INDEX);
605417
+ const sessDir = join122(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
605418
+ const indexPath = join122(sessDir, SESSIONS_INDEX);
606008
605419
  try {
606009
- const contentPath = join125(sessDir, `${sessionId}.jsonl`);
606010
- if (existsSync110(contentPath)) unlinkSync22(contentPath);
606011
- if (existsSync110(indexPath)) {
606012
- let index = JSON.parse(readFileSync89(indexPath, "utf-8"));
605420
+ const contentPath = join122(sessDir, `${sessionId}.jsonl`);
605421
+ if (existsSync107(contentPath)) unlinkSync21(contentPath);
605422
+ if (existsSync107(indexPath)) {
605423
+ let index = JSON.parse(readFileSync86(indexPath, "utf-8"));
606013
605424
  index = index.filter((s2) => s2.id !== sessionId);
606014
- writeFileSync56(indexPath, JSON.stringify(index, null, 2), "utf-8");
605425
+ writeFileSync55(indexPath, JSON.stringify(index, null, 2), "utf-8");
606015
605426
  }
606016
605427
  return true;
606017
605428
  } catch {
@@ -606061,12 +605472,12 @@ function detectManifests(repoRoot) {
606061
605472
  { file: "docker-compose.yaml", type: "Docker Compose" }
606062
605473
  ];
606063
605474
  for (const check of checks) {
606064
- const filePath = join125(repoRoot, check.file);
606065
- if (existsSync110(filePath)) {
605475
+ const filePath = join122(repoRoot, check.file);
605476
+ if (existsSync107(filePath)) {
606066
605477
  let name10;
606067
605478
  if (check.nameField) {
606068
605479
  try {
606069
- const data = JSON.parse(readFileSync89(filePath, "utf-8"));
605480
+ const data = JSON.parse(readFileSync86(filePath, "utf-8"));
606070
605481
  name10 = data[check.nameField];
606071
605482
  } catch {
606072
605483
  }
@@ -606095,7 +605506,7 @@ function findKeyFiles(repoRoot) {
606095
605506
  { pattern: "CLAUDE.md", description: "Claude Code context" }
606096
605507
  ];
606097
605508
  for (const check of checks) {
606098
- if (existsSync110(join125(repoRoot, check.pattern))) {
605509
+ if (existsSync107(join122(repoRoot, check.pattern))) {
606099
605510
  keyFiles.push({ path: check.pattern, description: check.description });
606100
605511
  }
606101
605512
  }
@@ -606104,7 +605515,7 @@ function findKeyFiles(repoRoot) {
606104
605515
  function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
606105
605516
  if (depth > maxDepth) return "";
606106
605517
  let result = "";
606107
- const isHomeRoot = depth === 0 && root === homedir38();
605518
+ const isHomeRoot = depth === 0 && root === homedir37();
606108
605519
  try {
606109
605520
  const entries = readdirSync37(root, { withFileTypes: true }).filter((e2) => !e2.name.startsWith(".") || e2.name === ".github").filter((e2) => !SKIP_DIRS3.has(e2.name)).filter((e2) => !(isHomeRoot && HOME_SKIP_DIRS.has(e2.name))).sort((a2, b) => {
606110
605521
  if (a2.isDirectory() && !b.isDirectory()) return -1;
@@ -606119,12 +605530,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
606119
605530
  if (entry.isDirectory()) {
606120
605531
  let fileCount = 0;
606121
605532
  try {
606122
- fileCount = readdirSync37(join125(root, entry.name)).filter((f2) => !f2.startsWith(".")).length;
605533
+ fileCount = readdirSync37(join122(root, entry.name)).filter((f2) => !f2.startsWith(".")).length;
606123
605534
  } catch {
606124
605535
  }
606125
605536
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
606126
605537
  `;
606127
- result += buildDirTree(join125(root, entry.name), maxDepth, childPrefix, depth + 1);
605538
+ result += buildDirTree(join122(root, entry.name), maxDepth, childPrefix, depth + 1);
606128
605539
  } else if (depth < maxDepth) {
606129
605540
  result += `${prefix}${connector}${entry.name}
606130
605541
  `;
@@ -606136,17 +605547,17 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
606136
605547
  }
606137
605548
  function loadUsageFile(filePath) {
606138
605549
  try {
606139
- if (existsSync110(filePath)) {
606140
- return JSON.parse(readFileSync89(filePath, "utf-8"));
605550
+ if (existsSync107(filePath)) {
605551
+ return JSON.parse(readFileSync86(filePath, "utf-8"));
606141
605552
  }
606142
605553
  } catch {
606143
605554
  }
606144
605555
  return { records: [] };
606145
605556
  }
606146
605557
  function saveUsageFile(filePath, data) {
606147
- const dir = join125(filePath, "..");
606148
- mkdirSync66(dir, { recursive: true });
606149
- writeFileSync56(filePath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
605558
+ const dir = join122(filePath, "..");
605559
+ mkdirSync65(dir, { recursive: true });
605560
+ writeFileSync55(filePath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
606150
605561
  }
606151
605562
  function recordUsage(kind, value2, opts) {
606152
605563
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
@@ -606173,15 +605584,15 @@ function recordUsage(kind, value2, opts) {
606173
605584
  }
606174
605585
  saveUsageFile(filePath, data);
606175
605586
  };
606176
- update2(join125(homedir38(), ".omnius", USAGE_HISTORY_FILE));
605587
+ update2(join122(homedir37(), ".omnius", USAGE_HISTORY_FILE));
606177
605588
  if (opts?.repoRoot) {
606178
- update2(join125(opts.repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
605589
+ update2(join122(opts.repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
606179
605590
  }
606180
605591
  }
606181
605592
  function loadUsageHistory(kind, repoRoot) {
606182
- const globalPath = join125(homedir38(), ".omnius", USAGE_HISTORY_FILE);
605593
+ const globalPath = join122(homedir37(), ".omnius", USAGE_HISTORY_FILE);
606183
605594
  const globalData = loadUsageFile(globalPath);
606184
- const localData = repoRoot ? loadUsageFile(join125(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE)) : { records: [] };
605595
+ const localData = repoRoot ? loadUsageFile(join122(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE)) : { records: [] };
606185
605596
  const map2 = /* @__PURE__ */ new Map();
606186
605597
  for (const r2 of globalData.records) {
606187
605598
  if (r2.kind !== kind) continue;
@@ -606210,9 +605621,9 @@ function deleteUsageRecord(kind, value2, repoRoot) {
606210
605621
  saveUsageFile(filePath, data);
606211
605622
  }
606212
605623
  };
606213
- remove(join125(homedir38(), ".omnius", USAGE_HISTORY_FILE));
605624
+ remove(join122(homedir37(), ".omnius", USAGE_HISTORY_FILE));
606214
605625
  if (repoRoot) {
606215
- remove(join125(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
605626
+ remove(join122(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
606216
605627
  }
606217
605628
  }
606218
605629
  var OMNIUS_DIR, LEGACY_DIRS, SUBDIRS, gitignoreWatchers, CONTEXT_FILES, PENDING_TASK_FILE, HANDOFF_FILE, CONTEXT_SAVE_FILE, CONTEXT_LEDGER_FILE, MAX_CONTEXT_ENTRIES, MAX_SESSION_DIARY_ENTRIES, MAX_SESSION_DIARY_DETAILED_ENTRIES, MAX_CONTEXT_LEDGER_LINES, MAX_CONTEXT_LEDGER_BYTES, SAME_TASK_REPLACE_WINDOW_MS, LOCK_TIMEOUT_MS, LOCK_RETRY_MS, LOCK_RETRY_MAX, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS3, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
@@ -606298,6 +605709,757 @@ var init_omnius_directory = __esm({
606298
605709
  }
606299
605710
  });
606300
605711
 
605712
+ // packages/cli/src/api/session-summary.ts
605713
+ function isNoiseLine(line) {
605714
+ const t2 = line.trim();
605715
+ if (t2.length < 3) return true;
605716
+ const core = t2.replace(/^[∙•·›>\-=_*#|/\\.\s]+/, "").trim();
605717
+ if (core.length < 3) return true;
605718
+ 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);
605719
+ }
605720
+ function firstMeaningfulLine(transcript) {
605721
+ for (const raw of transcript.split("\n")) {
605722
+ const line = raw.replace(ANSI_RE, "").trim();
605723
+ if (line && !isNoiseLine(line)) return line;
605724
+ }
605725
+ for (const raw of transcript.split("\n")) {
605726
+ const line = raw.replace(ANSI_RE, "").trim();
605727
+ if (line) return line;
605728
+ }
605729
+ return "";
605730
+ }
605731
+ function clamp7(value2, max) {
605732
+ const v = value2.replace(/\s+/g, " ").trim();
605733
+ return v.length > max ? v.slice(0, max - 1).trimEnd() + "…" : v;
605734
+ }
605735
+ function deterministicSummary(transcript) {
605736
+ const first2 = firstMeaningfulLine(transcript);
605737
+ if (!first2) return { title: "Untitled session", summary: "Empty session." };
605738
+ const title = clamp7(first2.replace(/^[>›$#\s]+/, ""), TITLE_MAX);
605739
+ return { title: title || "Untitled session", summary: clamp7(first2, SUMMARY_MAX) };
605740
+ }
605741
+ function parseSummaryReply(content) {
605742
+ if (!content) return null;
605743
+ const match = content.match(/\{[\s\S]*\}/);
605744
+ if (!match) return null;
605745
+ try {
605746
+ const obj = JSON.parse(match[0]);
605747
+ const title = typeof obj.title === "string" ? obj.title.trim() : "";
605748
+ const summary = typeof obj.summary === "string" ? obj.summary.trim() : "";
605749
+ if (!title && !summary) return null;
605750
+ return { title, summary };
605751
+ } catch {
605752
+ return null;
605753
+ }
605754
+ }
605755
+ async function generateSessionSummary(args) {
605756
+ const fallback = deterministicSummary(args.transcript);
605757
+ const transcript = (args.transcript || "").replace(ANSI_RE, "").trim();
605758
+ if (!transcript || !args.config.model || !args.config.backendUrl) return fallback;
605759
+ try {
605760
+ const url = normalizeBaseUrl(args.config.backendUrl) + "/v1/chat/completions";
605761
+ const headers = { "Content-Type": "application/json" };
605762
+ if (args.config.apiKey) headers["Authorization"] = `Bearer ${args.config.apiKey}`;
605763
+ const body = {
605764
+ model: args.config.model,
605765
+ messages: [
605766
+ {
605767
+ role: "system",
605768
+ content: 'You name and summarize AI coding/agent terminal sessions. Reply with ONLY compact JSON and nothing else: {"title":"<3-6 word title>","summary":"<one concise sentence>"}. No markdown, no code fences, no preamble.'
605769
+ },
605770
+ {
605771
+ role: "user",
605772
+ content: "Summarize this session transcript (may include tool calls, sub-agent activity, and logs):\n\n" + transcript.slice(0, TRANSCRIPT_CHARS)
605773
+ }
605774
+ ],
605775
+ temperature: 0.2,
605776
+ max_tokens: 160,
605777
+ stream: false
605778
+ };
605779
+ const resp = await fetch(url, {
605780
+ method: "POST",
605781
+ headers,
605782
+ body: JSON.stringify(body),
605783
+ signal: AbortSignal.timeout(args.timeoutMs ?? 25e3)
605784
+ });
605785
+ if (!resp.ok) return fallback;
605786
+ const data = await resp.json();
605787
+ const content = data?.choices?.[0]?.message?.content ?? "";
605788
+ const parsed = parseSummaryReply(content);
605789
+ if (!parsed) return fallback;
605790
+ return {
605791
+ title: clamp7(parsed.title, TITLE_MAX) || fallback.title,
605792
+ summary: clamp7(parsed.summary, SUMMARY_MAX) || fallback.summary
605793
+ };
605794
+ } catch {
605795
+ return fallback;
605796
+ }
605797
+ }
605798
+ async function ensureSessionSummary(args) {
605799
+ const entry = listSessions(args.repoRoot).find(
605800
+ (e2) => e2.id === args.sessionId
605801
+ );
605802
+ if (entry?.aiTitle && entry.aiSummary && !args.force) {
605803
+ return { title: entry.aiTitle, summary: entry.aiSummary };
605804
+ }
605805
+ const lines = loadSessionHistory(args.repoRoot, args.sessionId);
605806
+ const transcript = (lines ?? []).join("\n").trim();
605807
+ if (!transcript) return deterministicSummary("");
605808
+ const key = `${args.repoRoot}::${args.sessionId}`;
605809
+ if (_inflightSummaries.has(key) && !args.force) {
605810
+ return deterministicSummary(transcript);
605811
+ }
605812
+ _inflightSummaries.add(key);
605813
+ try {
605814
+ const result = await generateSessionSummary({
605815
+ transcript,
605816
+ config: args.config,
605817
+ timeoutMs: args.timeoutMs
605818
+ });
605819
+ updateSessionEntry(args.repoRoot, args.sessionId, {
605820
+ aiTitle: result.title,
605821
+ aiSummary: result.summary
605822
+ });
605823
+ return result;
605824
+ } finally {
605825
+ _inflightSummaries.delete(key);
605826
+ }
605827
+ }
605828
+ function sessionDisplayTitle(entry) {
605829
+ if (entry.aiTitle && entry.aiTitle.trim()) return entry.aiTitle.trim();
605830
+ return deterministicSummary(entry.name || "").title;
605831
+ }
605832
+ var TITLE_MAX, SUMMARY_MAX, TRANSCRIPT_CHARS, ANSI_RE, _inflightSummaries;
605833
+ var init_session_summary = __esm({
605834
+ "packages/cli/src/api/session-summary.ts"() {
605835
+ "use strict";
605836
+ init_dist6();
605837
+ init_omnius_directory();
605838
+ TITLE_MAX = 56;
605839
+ SUMMARY_MAX = 160;
605840
+ TRANSCRIPT_CHARS = 6e3;
605841
+ ANSI_RE = /\x1B\[[0-9;]*m|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
605842
+ _inflightSummaries = /* @__PURE__ */ new Set();
605843
+ }
605844
+ });
605845
+
605846
+ // packages/cli/src/tui/cad-model-viewer.ts
605847
+ import { createServer as createServer7 } from "node:http";
605848
+ import { existsSync as existsSync108, readFileSync as readFileSync87, statSync as statSync42 } from "node:fs";
605849
+ import { basename as basename23, extname as extname16, resolve as resolve53 } from "node:path";
605850
+ function getCurrentCadModelViewer() {
605851
+ return currentViewer;
605852
+ }
605853
+ async function startCadModelViewer(filePath) {
605854
+ const resolved = filePath ? resolve53(filePath) : void 0;
605855
+ if (resolved && (!existsSync108(resolved) || !statSync42(resolved).isFile())) {
605856
+ throw new Error(`3D model file not found: ${resolved}`);
605857
+ }
605858
+ if (currentViewer) {
605859
+ await currentViewer.close().catch(() => {
605860
+ });
605861
+ currentViewer = null;
605862
+ }
605863
+ const server2 = createServer7((req3, res) => handleViewerRequest(req3, res, resolved));
605864
+ const port = await listenOnEphemeralPort(server2);
605865
+ const session = {
605866
+ url: `http://127.0.0.1:${port}/`,
605867
+ port,
605868
+ filePath: resolved,
605869
+ close: () => new Promise((resolveClose) => server2.close(() => resolveClose()))
605870
+ };
605871
+ currentViewer = session;
605872
+ server2.on("close", () => {
605873
+ if (currentViewer === session) currentViewer = null;
605874
+ });
605875
+ return session;
605876
+ }
605877
+ function listenOnEphemeralPort(server2) {
605878
+ return new Promise((resolveListen, reject) => {
605879
+ server2.once("error", reject);
605880
+ server2.listen(0, "127.0.0.1", () => {
605881
+ server2.off("error", reject);
605882
+ const addr = server2.address();
605883
+ if (!addr || typeof addr === "string") {
605884
+ reject(new Error("viewer server did not bind to a TCP port"));
605885
+ return;
605886
+ }
605887
+ resolveListen(addr.port);
605888
+ });
605889
+ });
605890
+ }
605891
+ function handleViewerRequest(req3, res, filePath) {
605892
+ const url = new URL(req3.url || "/", "http://127.0.0.1");
605893
+ if (url.pathname === "/health") {
605894
+ sendJson(res, 200, { ok: true, file: filePath ?? null });
605895
+ return;
605896
+ }
605897
+ if (url.pathname === "/asset") {
605898
+ if (!filePath) {
605899
+ sendText(res, 404, "No model file attached to this viewer.");
605900
+ return;
605901
+ }
605902
+ try {
605903
+ res.writeHead(200, {
605904
+ "Content-Type": contentTypeFor(filePath),
605905
+ "Content-Disposition": `inline; filename="${basename23(filePath).replace(/"/g, "")}"`,
605906
+ "Cache-Control": "no-store"
605907
+ });
605908
+ res.end(readFileSync87(filePath));
605909
+ } catch (err) {
605910
+ sendText(res, 500, err instanceof Error ? err.message : String(err));
605911
+ }
605912
+ return;
605913
+ }
605914
+ if (url.pathname !== "/") {
605915
+ sendText(res, 404, "Not found");
605916
+ return;
605917
+ }
605918
+ sendHtml(res, viewerHtml(filePath));
605919
+ }
605920
+ function contentTypeFor(path12) {
605921
+ const ext = extname16(path12).toLowerCase();
605922
+ if (ext === ".glb") return "model/gltf-binary";
605923
+ if (ext === ".gltf") return "model/gltf+json";
605924
+ if (ext === ".obj") return "text/plain; charset=utf-8";
605925
+ if (ext === ".stl") return "model/stl";
605926
+ if (ext === ".ply") return "application/octet-stream";
605927
+ return "application/octet-stream";
605928
+ }
605929
+ function sendJson(res, status, value2) {
605930
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
605931
+ res.end(JSON.stringify(value2));
605932
+ }
605933
+ function sendText(res, status, text2) {
605934
+ res.writeHead(status, { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" });
605935
+ res.end(text2);
605936
+ }
605937
+ function sendHtml(res, html) {
605938
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
605939
+ res.end(html);
605940
+ }
605941
+ function viewerHtml(filePath) {
605942
+ const fileName = filePath ? basename23(filePath) : "";
605943
+ const ext = filePath ? extname16(filePath).toLowerCase().replace(/^\./, "") : "";
605944
+ return `<!doctype html>
605945
+ <html lang="en">
605946
+ <head>
605947
+ <meta charset="utf-8">
605948
+ <meta name="viewport" content="width=device-width,initial-scale=1">
605949
+ <title>Omnius CAD/3D Viewer</title>
605950
+ <style>
605951
+ :root { color-scheme: dark; --bg:#101214; --panel:#181b1f; --line:#2a3037; --fg:#e7edf3; --muted:#9aa7b5; --accent:#5ec6a8; }
605952
+ * { box-sizing: border-box; }
605953
+ body { margin:0; min-height:100vh; background:var(--bg); color:var(--fg); font:14px/1.4 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; display:grid; grid-template-columns:minmax(280px,360px) 1fr; }
605954
+ aside { border-right:1px solid var(--line); background:var(--panel); padding:14px; display:flex; flex-direction:column; gap:12px; min-height:100vh; }
605955
+ main { position:relative; min-height:100vh; overflow:hidden; }
605956
+ h1 { margin:0; font-size:16px; font-weight:650; }
605957
+ .meta { color:var(--muted); font-size:12px; word-break:break-word; }
605958
+ textarea { width:100%; min-height:280px; resize:vertical; border:1px solid var(--line); border-radius:6px; background:#0c0e10; color:var(--fg); padding:10px; font:12px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; }
605959
+ button { border:1px solid var(--line); border-radius:6px; background:#20262d; color:var(--fg); padding:8px 10px; cursor:pointer; }
605960
+ button:hover { border-color:var(--accent); }
605961
+ #status { color:var(--muted); min-height:20px; font-size:12px; }
605962
+ canvas { display:block; width:100%; height:100%; }
605963
+ .row { display:flex; gap:8px; flex-wrap:wrap; }
605964
+ @media (max-width: 760px) { body { grid-template-columns:1fr; grid-template-rows:auto 60vh; } aside { min-height:auto; border-right:0; border-bottom:1px solid var(--line); } }
605965
+ </style>
605966
+ </head>
605967
+ <body>
605968
+ <aside>
605969
+ <div>
605970
+ <h1>Omnius CAD/3D Viewer</h1>
605971
+ <div class="meta">${escapeHtml(fileName ? `Viewing ${fileName}` : "No file attached. Rendering Compact IR sample.")}</div>
605972
+ </div>
605973
+ <textarea id="ir">C 50 30 5
605974
+ Y 3 8
605975
+ T 1 -18 -10 2.5
605976
+ Y 3 8
605977
+ T 3 18 -10 2.5
605978
+ Y 3 8
605979
+ T 5 -18 10 2.5
605980
+ Y 3 8
605981
+ T 7 18 10 2.5</textarea>
605982
+ <div class="row">
605983
+ <button id="render-ir">Render Compact IR</button>
605984
+ <button id="reset-camera">Reset Camera</button>
605985
+ </div>
605986
+ <div id="status"></div>
605987
+ </aside>
605988
+ <main id="viewport"></main>
605989
+ <script type="module">
605990
+ import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.164.1/build/three.module.js';
605991
+ import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/controls/OrbitControls.js';
605992
+ import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/GLTFLoader.js';
605993
+ import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/STLLoader.js';
605994
+ import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/OBJLoader.js';
605995
+ import { PLYLoader } from 'https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/loaders/PLYLoader.js';
605996
+
605997
+ const assetUrl = ${JSON.stringify(filePath ? "/asset" : "")};
605998
+ const assetExt = ${JSON.stringify(ext)};
605999
+ const viewport = document.getElementById('viewport');
606000
+ const status = document.getElementById('status');
606001
+ const scene = new THREE.Scene();
606002
+ scene.background = new THREE.Color(0x101214);
606003
+ const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 5000);
606004
+ const renderer = new THREE.WebGLRenderer({ antialias:true });
606005
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
606006
+ viewport.appendChild(renderer.domElement);
606007
+ const controls = new OrbitControls(camera, renderer.domElement);
606008
+ controls.enableDamping = true;
606009
+ scene.add(new THREE.HemisphereLight(0xffffff, 0x223344, 1.7));
606010
+ const key = new THREE.DirectionalLight(0xffffff, 2.2);
606011
+ key.position.set(120, 160, 100);
606012
+ scene.add(key);
606013
+ const grid = new THREE.GridHelper(160, 32, 0x31404a, 0x253039);
606014
+ scene.add(grid);
606015
+ let objectRoot = new THREE.Group();
606016
+ scene.add(objectRoot);
606017
+
606018
+ function setStatus(text) { status.textContent = text || ''; }
606019
+ function clearObject() {
606020
+ scene.remove(objectRoot);
606021
+ objectRoot.traverse((o) => {
606022
+ if (o.geometry) o.geometry.dispose?.();
606023
+ if (o.material) {
606024
+ if (Array.isArray(o.material)) o.material.forEach((m) => m.dispose?.());
606025
+ else o.material.dispose?.();
606026
+ }
606027
+ });
606028
+ objectRoot = new THREE.Group();
606029
+ scene.add(objectRoot);
606030
+ }
606031
+ function frameObject() {
606032
+ const box = new THREE.Box3().setFromObject(objectRoot);
606033
+ if (box.isEmpty()) {
606034
+ camera.position.set(70, 70, 70);
606035
+ controls.target.set(0, 0, 0);
606036
+ return;
606037
+ }
606038
+ const size = box.getSize(new THREE.Vector3());
606039
+ const center = box.getCenter(new THREE.Vector3());
606040
+ const max = Math.max(size.x, size.y, size.z, 1);
606041
+ camera.position.copy(center).add(new THREE.Vector3(max * 1.35, max * 1.05, max * 1.35));
606042
+ controls.target.copy(center);
606043
+ camera.near = Math.max(0.01, max / 1000);
606044
+ camera.far = Math.max(1000, max * 20);
606045
+ camera.updateProjectionMatrix();
606046
+ controls.update();
606047
+ }
606048
+ function makeMaterial(index) {
606049
+ const colors = [0x5ec6a8, 0xf0b35a, 0x87a8ff, 0xdc6f7e, 0xb6d96a];
606050
+ return new THREE.MeshStandardMaterial({ color: colors[index % colors.length], metalness:0.05, roughness:0.48 });
606051
+ }
606052
+ function renderCompactIr(text) {
606053
+ clearObject();
606054
+ const nodes = [];
606055
+ const lines = String(text || '').split(/\\r?\\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
606056
+ for (const line of lines) {
606057
+ const parts = line.split(/\\s+/);
606058
+ const op = parts[0].toUpperCase();
606059
+ const nums = parts.slice(1).map(Number);
606060
+ let mesh = null;
606061
+ if (op === 'C' && nums.length >= 3) {
606062
+ mesh = new THREE.Mesh(new THREE.BoxGeometry(nums[0], nums[1], nums[2]), makeMaterial(nodes.length));
606063
+ } else if (op === 'Y' && nums.length >= 2) {
606064
+ mesh = new THREE.Mesh(new THREE.CylinderGeometry(nums[0], nums[0], nums[1], 48), makeMaterial(nodes.length));
606065
+ mesh.rotation.x = Math.PI / 2;
606066
+ } else if (op === 'S' && nums.length >= 1) {
606067
+ mesh = new THREE.Mesh(new THREE.SphereGeometry(nums[0], 48, 24), makeMaterial(nodes.length));
606068
+ } else if (op === 'K' && nums.length >= 3) {
606069
+ mesh = new THREE.Mesh(new THREE.CylinderGeometry(nums[1], nums[0], nums[2], 48), makeMaterial(nodes.length));
606070
+ mesh.rotation.x = Math.PI / 2;
606071
+ } else if ((op === 'U' || op === 'D' || op === 'I') && nums.length >= 2) {
606072
+ const group = new THREE.Group();
606073
+ const a = nodes[nums[0]]?.clone();
606074
+ const b = nodes[nums[1]]?.clone();
606075
+ if (a) group.add(a);
606076
+ if (b) {
606077
+ if (op === 'D') b.traverse((o) => { if (o.material) o.material = new THREE.MeshStandardMaterial({ color:0xff5570, wireframe:true }); });
606078
+ group.add(b);
606079
+ }
606080
+ mesh = group;
606081
+ } else if ((op === 'T' || op === 'R' || op === 'X') && nums.length >= 4) {
606082
+ const target = nodes[nums[0]];
606083
+ if (target) {
606084
+ if (op === 'T') target.position.add(new THREE.Vector3(nums[1], nums[2], nums[3]));
606085
+ if (op === 'R') target.rotation.set(THREE.MathUtils.degToRad(nums[1]), THREE.MathUtils.degToRad(nums[2]), THREE.MathUtils.degToRad(nums[3]));
606086
+ if (op === 'X') target.scale.multiply(new THREE.Vector3(nums[1], nums[2], nums[3]));
606087
+ }
606088
+ nodes.push(target ? target.clone() : new THREE.Group());
606089
+ continue;
606090
+ } else if ((op === 'F' || op === 'CH' || op === 'SH') && nums.length >= 1) {
606091
+ const target = nodes[nums[0]];
606092
+ nodes.push(target ? target.clone() : new THREE.Group());
606093
+ continue;
606094
+ }
606095
+ if (mesh) {
606096
+ nodes.push(mesh);
606097
+ objectRoot.add(mesh);
606098
+ }
606099
+ }
606100
+ if (nodes.length === 0) setStatus('No renderable Compact IR primitives found.');
606101
+ else setStatus('Rendered ' + nodes.length + ' Compact IR node(s). Boolean difference is shown as wireframe preview.');
606102
+ frameObject();
606103
+ }
606104
+ async function loadAsset() {
606105
+ if (!assetUrl) {
606106
+ renderCompactIr(document.getElementById('ir').value);
606107
+ return;
606108
+ }
606109
+ setStatus('Loading attached model...');
606110
+ clearObject();
606111
+ const done = (obj) => {
606112
+ objectRoot.add(obj);
606113
+ setStatus('Loaded attached model.');
606114
+ frameObject();
606115
+ };
606116
+ if (assetExt === 'glb' || assetExt === 'gltf') {
606117
+ new GLTFLoader().load(assetUrl, (gltf) => done(gltf.scene), undefined, (e) => setStatus(e.message || String(e)));
606118
+ } else if (assetExt === 'stl') {
606119
+ new STLLoader().load(assetUrl, (geo) => done(new THREE.Mesh(geo, makeMaterial(0))), undefined, (e) => setStatus(e.message || String(e)));
606120
+ } else if (assetExt === 'obj') {
606121
+ new OBJLoader().load(assetUrl, done, undefined, (e) => setStatus(e.message || String(e)));
606122
+ } else if (assetExt === 'ply') {
606123
+ new PLYLoader().load(assetUrl, (geo) => done(new THREE.Mesh(geo, makeMaterial(0))), undefined, (e) => setStatus(e.message || String(e)));
606124
+ } else {
606125
+ setStatus('Unsupported file extension for browser preview. Use GLB, GLTF, OBJ, STL, or PLY.');
606126
+ renderCompactIr(document.getElementById('ir').value);
606127
+ }
606128
+ }
606129
+ function resize() {
606130
+ const rect = viewport.getBoundingClientRect();
606131
+ renderer.setSize(rect.width, rect.height, false);
606132
+ camera.aspect = Math.max(1, rect.width) / Math.max(1, rect.height);
606133
+ camera.updateProjectionMatrix();
606134
+ }
606135
+ window.addEventListener('resize', resize);
606136
+ document.getElementById('render-ir').addEventListener('click', () => renderCompactIr(document.getElementById('ir').value));
606137
+ document.getElementById('reset-camera').addEventListener('click', frameObject);
606138
+ renderer.setAnimationLoop(() => { controls.update(); renderer.render(scene, camera); });
606139
+ resize();
606140
+ loadAsset();
606141
+ </script>
606142
+ </body>
606143
+ </html>`;
606144
+ }
606145
+ function escapeHtml(value2) {
606146
+ return value2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
606147
+ }
606148
+ var currentViewer;
606149
+ var init_cad_model_viewer = __esm({
606150
+ "packages/cli/src/tui/cad-model-viewer.ts"() {
606151
+ "use strict";
606152
+ currentViewer = null;
606153
+ }
606154
+ });
606155
+
606156
+ // packages/cli/src/tui/hf-token-prompt.ts
606157
+ import * as fs9 from "node:fs";
606158
+ import * as os8 from "node:os";
606159
+ import * as path10 from "node:path";
606160
+ function loadHfToken() {
606161
+ const fromEnv = process.env["HF_TOKEN"]?.trim() || process.env["HUGGING_FACE_HUB_TOKEN"]?.trim() || "";
606162
+ if (fromEnv) return fromEnv;
606163
+ try {
606164
+ if (fs9.existsSync(TOKEN_FILE)) {
606165
+ const fromFile = fs9.readFileSync(TOKEN_FILE, "utf8").trim();
606166
+ if (fromFile) {
606167
+ process.env["HF_TOKEN"] = fromFile;
606168
+ return fromFile;
606169
+ }
606170
+ }
606171
+ } catch {
606172
+ }
606173
+ return null;
606174
+ }
606175
+ function saveHfToken(token) {
606176
+ const trimmed = token.trim();
606177
+ if (!trimmed) throw new Error("HF token cannot be empty");
606178
+ fs9.mkdirSync(TOKEN_DIR, { recursive: true, mode: 448 });
606179
+ fs9.writeFileSync(TOKEN_FILE, trimmed + "\n", { mode: 384 });
606180
+ try {
606181
+ fs9.chmodSync(TOKEN_FILE, 384);
606182
+ } catch {
606183
+ }
606184
+ process.env["HF_TOKEN"] = trimmed;
606185
+ }
606186
+ function clearHfToken() {
606187
+ try {
606188
+ if (fs9.existsSync(TOKEN_FILE)) fs9.unlinkSync(TOKEN_FILE);
606189
+ } catch {
606190
+ }
606191
+ delete process.env["HF_TOKEN"];
606192
+ }
606193
+ function isHfTokenPromptPending() {
606194
+ return pending !== null;
606195
+ }
606196
+ function describePendingHfTokenPrompt() {
606197
+ if (!pending) return null;
606198
+ return { model: pending.model, ageMs: Date.now() - pending.startedAt };
606199
+ }
606200
+ function requestHfToken(opts) {
606201
+ const existing = loadHfToken();
606202
+ if (existing) return Promise.resolve(existing);
606203
+ if (pending) {
606204
+ opts.onMessage(
606205
+ `Another HF token prompt is already active (for ${pending.model}). Run \`/hf <token>\` to satisfy both, or wait for the existing prompt to time out.`
606206
+ );
606207
+ return Promise.resolve(null);
606208
+ }
606209
+ const timeoutMs = Math.max(1e3, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
606210
+ const timeoutSec = Math.round(timeoutMs / 1e3);
606211
+ const fallbackBit = opts.fallbackModel ? `
606212
+ If you don't supply one within ${timeoutSec}s, I will fall back to ${opts.fallbackModel} (no token needed).` : `
606213
+ If you don't supply one within ${timeoutSec}s, I will fall back to a non-gated alternative.`;
606214
+ opts.onMessage(
606215
+ [
606216
+ `Hugging Face model "${opts.model}" is gated and needs an access token.`,
606217
+ `Get one at https://huggingface.co/settings/tokens (read-only is fine),`,
606218
+ `accept the model license at https://huggingface.co/${opts.model},`,
606219
+ `then run: /hf <your-token>`,
606220
+ fallbackBit.trim()
606221
+ ].join("\n")
606222
+ );
606223
+ return new Promise((resolve71) => {
606224
+ const timer = setTimeout(() => {
606225
+ const ref = pending;
606226
+ pending = null;
606227
+ if (ref) {
606228
+ ref.onMessage(
606229
+ `No HF token supplied within ${timeoutSec}s — falling back to a non-gated alternative for ${opts.model}.`
606230
+ );
606231
+ }
606232
+ resolve71(null);
606233
+ }, timeoutMs);
606234
+ if (typeof timer.unref === "function") timer.unref();
606235
+ pending = {
606236
+ model: opts.model,
606237
+ onMessage: opts.onMessage,
606238
+ resolve: resolve71,
606239
+ timer,
606240
+ startedAt: Date.now()
606241
+ };
606242
+ });
606243
+ }
606244
+ function fulfillHfTokenPrompt(token) {
606245
+ const trimmed = token.trim();
606246
+ if (!trimmed) return false;
606247
+ saveHfToken(trimmed);
606248
+ if (!pending) return false;
606249
+ const ref = pending;
606250
+ pending = null;
606251
+ clearTimeout(ref.timer);
606252
+ ref.resolve(trimmed);
606253
+ return true;
606254
+ }
606255
+ function cancelHfTokenPrompt() {
606256
+ if (!pending) return false;
606257
+ const ref = pending;
606258
+ pending = null;
606259
+ clearTimeout(ref.timer);
606260
+ ref.resolve(null);
606261
+ return true;
606262
+ }
606263
+ function isHfGatedError(blob) {
606264
+ if (!blob) return false;
606265
+ const text2 = blob.toLowerCase();
606266
+ if (text2.includes("[hf_token_required")) return true;
606267
+ if (text2.includes("gatedrepoerror")) return true;
606268
+ if (text2.includes("access to model")) return true;
606269
+ if (text2.includes("you need to accept")) return true;
606270
+ if (text2.includes("you must be authenticated")) return true;
606271
+ if (/(401|403)/.test(text2) && /(gated|access|unauthor|forbid|auth)/.test(text2)) {
606272
+ return true;
606273
+ }
606274
+ return false;
606275
+ }
606276
+ function extractGatedRepoId(blob) {
606277
+ if (!blob) return null;
606278
+ const tokenMarker = blob.match(/\[HF_TOKEN_REQUIRED:([^\]\s]+)\]/);
606279
+ if (tokenMarker?.[1]) return tokenMarker[1].trim();
606280
+ const hfUrl = blob.match(/huggingface\.co\/([A-Za-z0-9._-]+\/[A-Za-z0-9._-]+)/);
606281
+ if (hfUrl?.[1]) return hfUrl[1];
606282
+ const genericRepo = blob.match(/['"`]([A-Za-z0-9._-]+\/[A-Za-z0-9._-]+)['"`]/);
606283
+ if (genericRepo?.[1] && /\/(.+)/.test(genericRepo[1])) return genericRepo[1];
606284
+ return null;
606285
+ }
606286
+ var TOKEN_DIR, TOKEN_FILE, DEFAULT_TIMEOUT_MS4, pending;
606287
+ var init_hf_token_prompt = __esm({
606288
+ "packages/cli/src/tui/hf-token-prompt.ts"() {
606289
+ "use strict";
606290
+ TOKEN_DIR = path10.join(os8.homedir(), ".omnius");
606291
+ TOKEN_FILE = path10.join(TOKEN_DIR, "hf_token");
606292
+ DEFAULT_TIMEOUT_MS4 = 3e4;
606293
+ pending = null;
606294
+ }
606295
+ });
606296
+
606297
+ // packages/prompts/dist/loader.js
606298
+ var init_loader = __esm({
606299
+ "packages/prompts/dist/loader.js"() {
606300
+ "use strict";
606301
+ }
606302
+ });
606303
+
606304
+ // packages/prompts/dist/render.js
606305
+ var init_render2 = __esm({
606306
+ "packages/prompts/dist/render.js"() {
606307
+ "use strict";
606308
+ }
606309
+ });
606310
+
606311
+ // packages/prompts/dist/promptLoader.js
606312
+ import { readFileSync as readFileSync89, existsSync as existsSync110 } from "node:fs";
606313
+ import { join as join124, dirname as dirname39 } from "node:path";
606314
+ import { fileURLToPath as fileURLToPath13 } from "node:url";
606315
+ function loadPrompt2(promptPath, vars) {
606316
+ let content = cache6.get(promptPath);
606317
+ if (content === void 0) {
606318
+ const fullPath = join124(PROMPTS_DIR2, promptPath);
606319
+ if (!existsSync110(fullPath)) {
606320
+ throw new Error(`Prompt file not found: ${fullPath}`);
606321
+ }
606322
+ content = readFileSync89(fullPath, "utf-8");
606323
+ cache6.set(promptPath, content);
606324
+ }
606325
+ if (!vars)
606326
+ return content;
606327
+ return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
606328
+ }
606329
+ var __filename4, __dirname5, devPath, publishedPath, PROMPTS_DIR2, cache6;
606330
+ var init_promptLoader2 = __esm({
606331
+ "packages/prompts/dist/promptLoader.js"() {
606332
+ "use strict";
606333
+ __filename4 = fileURLToPath13(import.meta.url);
606334
+ __dirname5 = dirname39(__filename4);
606335
+ devPath = join124(__dirname5, "..", "templates");
606336
+ publishedPath = join124(__dirname5, "..", "prompts", "templates");
606337
+ PROMPTS_DIR2 = existsSync110(devPath) ? devPath : publishedPath;
606338
+ cache6 = /* @__PURE__ */ new Map();
606339
+ }
606340
+ });
606341
+
606342
+ // packages/prompts/dist/task-templates.js
606343
+ function getTaskTemplate(type) {
606344
+ return TEMPLATES[type];
606345
+ }
606346
+ function getTaskTypes() {
606347
+ return Object.keys(TEMPLATES);
606348
+ }
606349
+ function buildTaskContext(type) {
606350
+ const template = TEMPLATES[type];
606351
+ return `${template.systemPromptAddition}
606352
+
606353
+ ### Output Guidance
606354
+ ${template.outputGuidance}`;
606355
+ }
606356
+ var TEMPLATES;
606357
+ var init_task_templates = __esm({
606358
+ "packages/prompts/dist/task-templates.js"() {
606359
+ "use strict";
606360
+ init_promptLoader2();
606361
+ TEMPLATES = {
606362
+ code: {
606363
+ type: "code",
606364
+ label: "Software Development",
606365
+ description: "Writing, debugging, refactoring, or reviewing code.",
606366
+ systemPromptAddition: loadPrompt2("code.md"),
606367
+ recommendedTools: [
606368
+ "file_read",
606369
+ "file_write",
606370
+ "file_edit",
606371
+ "shell",
606372
+ "grep_search",
606373
+ "glob_find",
606374
+ "git_info",
606375
+ "codebase_map"
606376
+ ],
606377
+ outputGuidance: "Deliver working code with tests passing. Summarize what was changed and why."
606378
+ },
606379
+ document: {
606380
+ type: "document",
606381
+ label: "Document Drafting",
606382
+ description: "Creating reports, specifications, guides, proposals, or other professional documents.",
606383
+ systemPromptAddition: loadPrompt2("document.md"),
606384
+ recommendedTools: [
606385
+ "file_read",
606386
+ "file_write",
606387
+ "web_search",
606388
+ "web_fetch",
606389
+ "create_structured_file",
606390
+ "memory_read"
606391
+ ],
606392
+ outputGuidance: "Deliver a complete, well-structured document. Specify the output format (Markdown, PDF, etc.)."
606393
+ },
606394
+ analysis: {
606395
+ type: "analysis",
606396
+ label: "Analysis & Research",
606397
+ description: "Analyzing data, evaluating options, conducting research, or producing insights.",
606398
+ systemPromptAddition: loadPrompt2("analysis.md"),
606399
+ recommendedTools: [
606400
+ "file_read",
606401
+ "grep_search",
606402
+ "glob_find",
606403
+ "web_search",
606404
+ "web_fetch",
606405
+ "codebase_map",
606406
+ "create_structured_file",
606407
+ "shell"
606408
+ ],
606409
+ outputGuidance: "Deliver a structured analysis with findings, data tables, and actionable recommendations."
606410
+ },
606411
+ plan: {
606412
+ type: "plan",
606413
+ label: "Planning & Design",
606414
+ description: "Creating project plans, system designs, architecture proposals, or roadmaps.",
606415
+ systemPromptAddition: loadPrompt2("plan.md"),
606416
+ recommendedTools: [
606417
+ "file_read",
606418
+ "grep_search",
606419
+ "glob_find",
606420
+ "codebase_map",
606421
+ "web_search",
606422
+ "create_structured_file",
606423
+ "file_write",
606424
+ "git_info"
606425
+ ],
606426
+ outputGuidance: "Deliver a structured plan with phases, milestones, risks, and action items."
606427
+ },
606428
+ general: {
606429
+ type: "general",
606430
+ label: "General Task",
606431
+ description: "Tasks that don't clearly fit another category.",
606432
+ systemPromptAddition: loadPrompt2("general.md"),
606433
+ recommendedTools: [
606434
+ "file_read",
606435
+ "file_write",
606436
+ "shell",
606437
+ "grep_search",
606438
+ "web_search",
606439
+ "memory_read"
606440
+ ],
606441
+ outputGuidance: "Deliver complete results with a clear summary of what was done."
606442
+ }
606443
+ };
606444
+ }
606445
+ });
606446
+
606447
+ // packages/prompts/dist/index.js
606448
+ import { join as join125, dirname as dirname40 } from "node:path";
606449
+ import { fileURLToPath as fileURLToPath14 } from "node:url";
606450
+ var _dir, _packageRoot;
606451
+ var init_dist9 = __esm({
606452
+ "packages/prompts/dist/index.js"() {
606453
+ "use strict";
606454
+ init_loader();
606455
+ init_render2();
606456
+ init_task_templates();
606457
+ init_render2();
606458
+ _dir = dirname40(fileURLToPath14(import.meta.url));
606459
+ _packageRoot = join125(_dir, "..");
606460
+ }
606461
+ });
606462
+
606301
606463
  // packages/cli/src/tui/braille-spinner.ts
606302
606464
  function buildColorRamp(ramp) {
606303
606465
  return [...ramp, ...ramp.slice(1, -1).reverse()];
@@ -616701,7 +616863,7 @@ export PATH="${binDir}:$PATH" # Added by omnius for nvim
616701
616863
  } catch {
616702
616864
  }
616703
616865
  }
616704
- var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE, visibleLen2, QWEN_VARIANTS, _toolSupportCache, EXPANDED_VARIANT_MIN_NUM_CTX, _cloudflaredInstallPromise;
616866
+ var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE2, visibleLen2, QWEN_VARIANTS, _toolSupportCache, EXPANDED_VARIANT_MIN_NUM_CTX, _cloudflaredInstallPromise;
616705
616867
  var init_setup = __esm({
616706
616868
  "packages/cli/src/tui/setup.ts"() {
616707
616869
  "use strict";
@@ -616721,8 +616883,8 @@ var init_setup = __esm({
616721
616883
  "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ",
616722
616884
  " ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░ "
616723
616885
  ].join("\n");
616724
- ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g;
616725
- visibleLen2 = (value2) => Array.from(value2.replace(ANSI_RE, "")).length;
616886
+ ANSI_RE2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
616887
+ visibleLen2 = (value2) => Array.from(value2.replace(ANSI_RE2, "")).length;
616726
616888
  QWEN_VARIANTS = [
616727
616889
  { tag: "qwen3.5:0.8b", sizeGB: 1, label: "0.8B params (1.0 GB)", cloud: false },
616728
616890
  { tag: "qwen3.5:2b", sizeGB: 2.7, label: "2B params (2.7 GB)", cloud: false },
@@ -623929,16 +624091,16 @@ import { execFileSync as execFileSync8 } from "node:child_process";
623929
624091
  import { createRequire as createRequire6 } from "node:module";
623930
624092
  import { existsSync as existsSync125, readFileSync as readFileSync101, statSync as statSync46 } from "node:fs";
623931
624093
  import { resolve as resolve56 } from "node:path";
623932
- function clamp7(n2, min, max) {
624094
+ function clamp8(n2, min, max) {
623933
624095
  if (!Number.isFinite(n2)) return min;
623934
624096
  return Math.max(min, Math.min(max, Math.floor(n2)));
623935
624097
  }
623936
624098
  function defaultAsciiPreviewSize(dimensions) {
623937
624099
  const columns = process.stdout.columns || 100;
623938
624100
  const rows = process.stdout.rows || 32;
623939
- const width = clamp7(columns - 14, 42, 96);
624101
+ const width = clamp8(columns - 14, 42, 96);
623940
624102
  const imageAspect = dimensions && dimensions.width > 0 && dimensions.height > 0 ? dimensions.height / dimensions.width : 1;
623941
- const height = clamp7(Math.min(Math.round(width * imageAspect * TERMINAL_CELL_ASPECT), rows - 10), 8, 42);
624103
+ const height = clamp8(Math.min(Math.round(width * imageAspect * TERMINAL_CELL_ASPECT), rows - 10), 8, 42);
623942
624104
  return { width, height };
623943
624105
  }
623944
624106
  function readImageDimensions2(imagePath) {
@@ -624034,10 +624196,10 @@ function normalizeAscii(ascii2, width, height, options2 = {}) {
624034
624196
  }
624035
624197
  function byte(value2, fallback) {
624036
624198
  const n2 = Number(value2);
624037
- return Number.isFinite(n2) ? clamp7(n2, 0, 255) : fallback;
624199
+ return Number.isFinite(n2) ? clamp8(n2, 0, 255) : fallback;
624038
624200
  }
624039
624201
  function luminance(r2, g, b) {
624040
- return clamp7(Math.round(0.2126 * r2 + 0.7152 * g + 0.0722 * b), 0, 255);
624202
+ return clamp8(Math.round(0.2126 * r2 + 0.7152 * g + 0.0722 * b), 0, 255);
624041
624203
  }
624042
624204
  function matrixPixel(cell) {
624043
624205
  if (cell && typeof cell === "object") {
@@ -624201,9 +624363,9 @@ async function buildImageAsciiPreview(inputPath, options2 = {}) {
624201
624363
  }
624202
624364
  const dimensions = readImageDimensions2(imagePath);
624203
624365
  const defaults3 = defaultAsciiPreviewSize(dimensions);
624204
- const width = clamp7(options2.width ?? defaults3.width, 24, 140);
624205
- const height = clamp7(options2.height ?? defaults3.height, 6, 60);
624206
- const timeoutMs = clamp7(options2.timeoutMs ?? 5e3, 500, 3e4);
624366
+ const width = clamp8(options2.width ?? defaults3.width, 24, 140);
624367
+ const height = clamp8(options2.height ?? defaults3.height, 6, 60);
624368
+ const timeoutMs = clamp8(options2.timeoutMs ?? 5e3, 500, 3e4);
624207
624369
  if (options2.preferPackage !== false) {
624208
624370
  const result = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
624209
624371
  if (result.ascii) {
@@ -634702,7 +634864,7 @@ sleep 1
634702
634864
  return "handled";
634703
634865
  }
634704
634866
  if (arg.trim()) {
634705
- restoreNamedSession(ctx3, arg.trim());
634867
+ await restoreNamedSession(ctx3, arg.trim());
634706
634868
  return "handled";
634707
634869
  }
634708
634870
  const resumed = ctx3.resumeTask?.() ?? false;
@@ -635866,10 +636028,12 @@ async function showSessionsMenu(ctx3) {
635866
636028
  const items = sessions3.map((s2) => {
635867
636029
  const date = s2.updatedAt.slice(0, 16).replace("T", " ");
635868
636030
  const tasks = s2.taskCount > 1 ? `${s2.taskCount} tasks` : "1 task";
636031
+ const title = sessionDisplayTitle(s2);
636032
+ const summary = s2.aiSummary ? ` ${s2.aiSummary}` : "";
635869
636033
  return {
635870
636034
  key: s2.id,
635871
- label: `${s2.name}`,
635872
- detail: `${date} | ${tasks} | ${s2.model}`
636035
+ label: title,
636036
+ detail: `${date} | ${tasks} | ${s2.model}${summary}`
635873
636037
  };
635874
636038
  });
635875
636039
  items.push({
@@ -635891,45 +636055,59 @@ async function showSessionsMenu(ctx3) {
635891
636055
  else ctx3.clearScreen();
635892
636056
  return;
635893
636057
  }
635894
- const content = loadSessionHistory(ctx3.repoRoot, result.key);
636058
+ await replaySession(ctx3, result.key);
636059
+ }
636060
+ async function replaySession(ctx3, sessionId) {
636061
+ const content = loadSessionHistory(ctx3.repoRoot, sessionId);
635895
636062
  if (!content || content.length === 0) {
635896
636063
  renderWarning("Session content not found or empty.");
635897
636064
  return;
635898
636065
  }
635899
- const session = sessions3.find((s2) => s2.id === result.key);
635900
- renderInfo(
635901
- `Loading session: ${session?.name ?? result.key} (${content.length} lines)`
635902
- );
635903
- for (const line of content) {
635904
- process.stdout.write(` ${line}
635905
- `);
636066
+ const sessions3 = listSessions(ctx3.repoRoot);
636067
+ const session = sessions3.find((s2) => s2.id === sessionId);
636068
+ let title = session ? sessionDisplayTitle(session) : sessionId;
636069
+ let summary = session?.aiSummary ?? "";
636070
+ if (session && !session.aiTitle) {
636071
+ try {
636072
+ const gen = await ensureSessionSummary({
636073
+ repoRoot: ctx3.repoRoot,
636074
+ sessionId,
636075
+ config: {
636076
+ backendUrl: ctx3.config.backendUrl,
636077
+ model: ctx3.config.model,
636078
+ apiKey: ctx3.config.apiKey
636079
+ },
636080
+ timeoutMs: 2e4
636081
+ });
636082
+ title = gen.title;
636083
+ summary = gen.summary;
636084
+ } catch {
636085
+ }
635906
636086
  }
635907
- renderInfo("Session history loaded. Scroll up to review.");
636087
+ renderContentBlock(
636088
+ `
636089
+ ${c3.dim("╭─")} ${c3.bold("Recovered session")} ${c3.dim("·")} ${title} ${c3.dim(`(${content.length} lines)`)}
636090
+ ` + (summary ? `${c3.dim("│")} ${c3.dim(summary)}
636091
+ ` : "") + `${c3.dim("╰" + "─".repeat(40))}`
636092
+ );
636093
+ renderContentBlock(content.map((line) => ` ${line}`).join("\n"));
636094
+ renderContentBlock(
636095
+ `${c3.dim("─".repeat(20))} ${c3.dim("end of recovered session")} ${c3.dim("─".repeat(20))}`
636096
+ );
636097
+ renderInfo("Previous session fully restored above. Scroll up to review.");
635908
636098
  }
635909
- function restoreNamedSession(ctx3, query) {
636099
+ async function restoreNamedSession(ctx3, query) {
635910
636100
  const normalized = query.toLowerCase();
635911
636101
  const sessions3 = listSessions(ctx3.repoRoot);
635912
- const session = sessions3.find((s2) => s2.id === query) ?? sessions3.find((s2) => s2.name.toLowerCase() === normalized) ?? sessions3.find((s2) => s2.name.toLowerCase().includes(normalized));
636102
+ const session = sessions3.find((s2) => s2.id === query) ?? sessions3.find((s2) => sessionDisplayTitle(s2).toLowerCase() === normalized) ?? sessions3.find((s2) => s2.name.toLowerCase() === normalized) ?? sessions3.find((s2) => sessionDisplayTitle(s2).toLowerCase().includes(normalized)) ?? sessions3.find((s2) => s2.name.toLowerCase().includes(normalized));
635913
636103
  if (!session) {
635914
636104
  renderWarning(
635915
636105
  `No saved session matches "${query}". Use /sessions to browse.`
635916
636106
  );
635917
636107
  return;
635918
636108
  }
635919
- const content = loadSessionHistory(ctx3.repoRoot, session.id);
635920
- if (!content || content.length === 0) {
635921
- renderWarning(`Saved session "${session.name}" has no replayable history.`);
635922
- return;
635923
- }
635924
636109
  ctx3.clearScreen();
635925
- renderInfo(`Restored session: ${session.name} (${content.length} lines)`);
635926
- for (const line of content) {
635927
- process.stdout.write(` ${line}
635928
- `);
635929
- }
635930
- renderInfo(
635931
- "Session history loaded. New prompts continue in the current runtime session."
635932
- );
636110
+ await replaySession(ctx3, session.id);
635933
636111
  }
635934
636112
  async function showColorMenu(ctx3) {
635935
636113
  const currentConfig = getThemeConfig();
@@ -644215,6 +644393,7 @@ var init_commands = __esm({
644215
644393
  "use strict";
644216
644394
  init_model_picker();
644217
644395
  init_render();
644396
+ init_session_summary();
644218
644397
  init_generative_progress();
644219
644398
  init_cad_model_viewer();
644220
644399
  init_command_registry();
@@ -645892,6 +646071,7 @@ function importTranscriptSession(opts) {
645892
646071
  existing.model = opts.model || existing.model;
645893
646072
  existing.title = title;
645894
646073
  existing.preview = preview;
646074
+ existing.transcript = cappedTranscript || "(empty transcript)";
645895
646075
  existing.lastActivity = opts.updatedAt ?? Date.now();
645896
646076
  const idx = existing.messages.findIndex(
645897
646077
  (m2) => m2.role === "system" && m2.content.startsWith("[Imported TUI session transcript]")
@@ -645920,7 +646100,8 @@ function importTranscriptSession(opts) {
645920
646100
  projectRoot,
645921
646101
  source: "tui",
645922
646102
  title,
645923
- preview
646103
+ preview,
646104
+ transcript: cappedTranscript || "(empty transcript)"
645924
646105
  };
645925
646106
  sessions2.set(id, session);
645926
646107
  persistSession(session);
@@ -652363,7 +652544,7 @@ function appraiseEvent(event) {
652363
652544
  return null;
652364
652545
  }
652365
652546
  }
652366
- function clamp8(value2, min, max) {
652547
+ function clamp9(value2, min, max) {
652367
652548
  return Math.max(min, Math.min(max, value2));
652368
652549
  }
652369
652550
  var BASELINE_VALENCE, BASELINE_AROUSAL, DECAY_HALF_LIFE_MS, LABEL_UPDATE_INTERVAL_MS, DISTRESS_THRESHOLD, REFLECTION_COOLDOWN_MS, REFLECTION_MIN_EVENTS, LABEL_REGEN_THRESHOLD, EmotionEngine;
@@ -652502,8 +652683,8 @@ var init_emotion_engine = __esm({
652502
652683
  if (this.consecutiveFailures >= 2) {
652503
652684
  momentum = 1 + (this.consecutiveFailures - 1) * 0.25;
652504
652685
  }
652505
- this.state.valence = clamp8(this.state.valence + delta.valence * momentum, -1, 1);
652506
- this.state.arousal = clamp8(this.state.arousal + delta.arousal * momentum, 0, 1);
652686
+ this.state.valence = clamp9(this.state.valence + delta.valence * momentum, -1, 1);
652687
+ this.state.arousal = clamp9(this.state.arousal + delta.arousal * momentum, 0, 1);
652507
652688
  this.state.updatedAt = Date.now();
652508
652689
  const deterministicLabel = labelFromCoordinates(this.state.valence, this.state.arousal);
652509
652690
  this.state.label = deterministicLabel.label;
@@ -685556,6 +685737,10 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
685556
685737
  </div>
685557
685738
  <h3 style="color:var(--color-brand);font-size:0.7rem;margin:16px 0 8px">Inference Provider</h3>
685558
685739
  <div id="config-endpoint" style="font-size:0.78rem;color:var(--color-fg-muted);margin-bottom:8px"></div>
685740
+ <div id="config-recent-providers-section" style="display:none;margin-bottom:12px">
685741
+ <div style="font-size:0.66rem;color:var(--color-fg-muted);margin-bottom:6px;font-weight:500">Previously connected</div>
685742
+ <div id="config-recent-providers" class="settings-provider-module-grid"></div>
685743
+ </div>
685559
685744
  <div style="font-size:0.66rem;color:var(--color-fg-faint);margin-bottom:6px">Pick a provider to pre-fill the endpoint, then add your key and press <strong>set</strong>.</div>
685560
685745
  <div id="config-provider-modules" style="margin-bottom:10px"></div>
685561
685746
  <form onsubmit="event.preventDefault(); switchEndpoint();" autocomplete="off" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:4px">
@@ -688902,6 +689087,21 @@ async function loadConfig() {
688902
689087
  const pm = document.getElementById('config-provider-modules');
688903
689088
  if (pm) pm.innerHTML = renderSettingsProviderModules(settingsProviderIdForUrl(ep.url), ep.url, 'selectConfigProviderModule');
688904
689089
  } catch {}
689090
+ // Previously-connected providers — like the TUI /endpoint history, shown as
689091
+ // cards above the full provider list. Populated from endpoint usage history.
689092
+ try {
689093
+ const histR = await fetch('/v1/config/endpoint/history', { headers: headers() }).then(r => r.json()).catch(() => ({}));
689094
+ const history = (histR && Array.isArray(histR.endpoints)) ? histR.endpoints : [];
689095
+ const sect = document.getElementById('config-recent-providers-section');
689096
+ const grid = document.getElementById('config-recent-providers');
689097
+ if (grid && history.length > 0) {
689098
+ window.__omniusRecentEndpoints = history;
689099
+ grid.innerHTML = renderRecentProviderCards(history, ep.url);
689100
+ if (sect) sect.style.display = 'block';
689101
+ } else if (sect) {
689102
+ sect.style.display = 'none';
689103
+ }
689104
+ } catch {}
688905
689105
  // Populate model switcher
688906
689106
  const sel = document.getElementById('config-model-select');
688907
689107
  sel.innerHTML = '';
@@ -688973,6 +689173,54 @@ function selectConfigProviderModule(providerId) {
688973
689173
  }
688974
689174
  window.selectConfigProviderModule = selectConfigProviderModule;
688975
689175
 
689176
+ // Render "previously connected" provider cards from endpoint usage history.
689177
+ // Each card resolves to a known provider (for the favicon + label) and carries
689178
+ // its actual URL so clicking re-selects that exact endpoint.
689179
+ function renderRecentProviderCards(history, activeUrl) {
689180
+ const seen = new Set();
689181
+ return history.map(h => {
689182
+ const url = String(h.url || '');
689183
+ if (!url || seen.has(url)) return '';
689184
+ seen.add(url);
689185
+ const providerId = settingsProviderIdForUrl(url);
689186
+ const provider = settingsProviderById(providerId) || { id: providerId, label: providerId, domain: '' };
689187
+ const active = url === activeUrl;
689188
+ const cls = 'settings-provider-module' + (active ? ' active' : '');
689189
+ let host = url; try { host = new URL(url).host || url; } catch {}
689190
+ const label = (h.meta && h.meta.provider) ? h.meta.provider : provider.label;
689191
+ const uses = (h.useCount ? h.useCount + (h.useCount === 1 ? ' use' : ' uses') : '');
689192
+ const meta = [host, uses, h.authSet ? '🔑' : ''].filter(Boolean).join(' · ');
689193
+ return '<button type="button" class="' + cls + '" data-recent-url="' + escapeHtml(url) + '" onclick="selectRecentProvider(\\'' + escapeHtml(url).replace(/'/g, "&#39;") + '\\')" title="' + escapeHtml(url) + '">' +
689194
+ settingsProviderIcon(provider) +
689195
+ '<strong>' + escapeHtml(label) + '</strong>' +
689196
+ '<small>' + escapeHtml(meta) + '</small>' +
689197
+ '</button>';
689198
+ }).join('');
689199
+ }
689200
+
689201
+ // Click handler for a previously-connected provider card: fill the form with
689202
+ // that exact endpoint URL + detected backend type and focus the key field.
689203
+ function selectRecentProvider(url) {
689204
+ const urlInput = document.getElementById('config-ep-url');
689205
+ const typeSel = document.getElementById('config-ep-type');
689206
+ const keyInput = document.getElementById('config-ep-key');
689207
+ if (urlInput) urlInput.value = url;
689208
+ const providerId = settingsProviderIdForUrl(url);
689209
+ const provider = settingsProviderById(providerId);
689210
+ const bt = (provider && provider.backendType) ? provider.backendType : (url.includes('11434') ? 'ollama' : 'vllm');
689211
+ if (typeSel) {
689212
+ if (!Array.from(typeSel.options).some(o => o.value === bt)) {
689213
+ const opt = document.createElement('option'); opt.value = bt; opt.textContent = bt; typeSel.appendChild(opt);
689214
+ }
689215
+ typeSel.value = bt;
689216
+ }
689217
+ document.querySelectorAll('#config-recent-providers .settings-provider-module').forEach(btn => {
689218
+ btn.classList.toggle('active', btn.getAttribute('data-recent-url') === url);
689219
+ });
689220
+ if (keyInput) { try { keyInput.focus(); } catch {} }
689221
+ }
689222
+ window.selectRecentProvider = selectRecentProvider;
689223
+
688976
689224
  async function switchModel() {
688977
689225
  const model = document.getElementById('config-model-select').value;
688978
689226
  if (!model) return;
@@ -691288,6 +691536,23 @@ async function restoreChatSession() {
691288
691536
  const conv = document.getElementById('conversation');
691289
691537
  if (conv) {
691290
691538
  conv.innerHTML = '';
691539
+ // Imported TUI session: render its FULL recorded transcript (tool calls,
691540
+ // decisions, sub-agent activity — everything that scrolled past in the
691541
+ // TUI) as a visible, scrollable block at the top so opening the session
691542
+ // actually shows what happened, instead of just a "loaded" notice.
691543
+ if (data.transcript && String(data.transcript).trim() && data.transcript !== '(empty transcript)') {
691544
+ const wrap = document.createElement('div');
691545
+ wrap.style.cssText = 'margin:6px 0 14px';
691546
+ const head = document.createElement('div');
691547
+ head.style.cssText = 'font-size:0.66rem;color:var(--color-fg-muted);margin-bottom:4px;display:flex;justify-content:space-between;align-items:center';
691548
+ head.innerHTML = '<span>Recovered session transcript' + (data.title ? ' — ' + escapeHtml(data.title) : '') + '</span>';
691549
+ const pre = document.createElement('pre');
691550
+ pre.style.cssText = 'max-height:380px;overflow:auto;background:var(--color-bg-elevated);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:10px 12px;font-size:0.7rem;line-height:1.35;white-space:pre-wrap;word-break:break-word;color:var(--color-fg-muted);margin:0';
691551
+ pre.textContent = String(data.transcript);
691552
+ wrap.appendChild(head);
691553
+ wrap.appendChild(pre);
691554
+ conv.appendChild(wrap);
691555
+ }
691291
691556
  // WO-CHAT-RESUME-TOOLS — replay the FULL intermediate flow on
691292
691557
  // restore: user/assistant text bubbles AND tool_call/tool_result
691293
691558
  // dropdowns interleaved in original order. We track the current
@@ -693817,6 +694082,7 @@ function getOpenApiSpec() {
693817
694082
  }
693818
694083
  },
693819
694084
  "/v1/chat/sessions": { get: { summary: "List active chat sessions", tags: ["Chat"], responses: { 200: { description: "Session list" } } } },
694085
+ "/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" } } } },
693820
694086
  // ───── AIWG cascade ─────
693821
694087
  "/v1/aiwg": { get: { summary: "AIWG installation root + control map", tags: ["AIWG"], responses: { 200: { description: "AIWG installation summary" } } } },
693822
694088
  "/v1/aiwg/frameworks": { get: { summary: "List AIWG frameworks (paginated)", tags: ["AIWG"], responses: { 200: { description: "Framework list" } } } },
@@ -702645,9 +702911,12 @@ ${historyLines}
702645
702911
  const includeTui = urlObj.searchParams.get("include_tui") !== "0";
702646
702912
  if (includeTui && targetRoot) {
702647
702913
  const seen = new Set(sessions3.map((s2) => s2.id));
702914
+ const cfg = loadConfig();
702915
+ const needSummary = [];
702648
702916
  for (const t2 of listSessions(targetRoot)) {
702649
702917
  const id = `tui:${t2.id}`;
702650
702918
  if (seen.has(id)) continue;
702919
+ if (!t2.aiTitle) needSummary.push(t2.id);
702651
702920
  sessions3.push({
702652
702921
  id,
702653
702922
  model: t2.model,
@@ -702657,8 +702926,16 @@ ${historyLines}
702657
702926
  lastActivity: t2.updatedAt,
702658
702927
  projectRoot: targetRoot,
702659
702928
  source: "tui",
702660
- title: t2.name,
702661
- preview: t2.description
702929
+ title: sessionDisplayTitle(t2),
702930
+ preview: t2.aiSummary || t2.description
702931
+ });
702932
+ }
702933
+ for (const sid of needSummary.slice(0, 6)) {
702934
+ void ensureSessionSummary({
702935
+ repoRoot: targetRoot,
702936
+ sessionId: sid,
702937
+ config: { backendUrl: cfg.backendUrl, model: cfg.model, apiKey: cfg.apiKey }
702938
+ }).catch(() => {
702662
702939
  });
702663
702940
  }
702664
702941
  sessions3.sort((a2, b) => String(b.lastActivity).localeCompare(String(a2.lastActivity)));
@@ -702822,6 +703099,7 @@ ${historyLines}
702822
703099
  preview: session.preview ?? null,
702823
703100
  source: session.source ?? "web",
702824
703101
  projectRoot: session.projectRoot ?? null,
703102
+ transcript: session.transcript ?? null,
702825
703103
  messages: publicMessages,
702826
703104
  message_count: publicMessages.length,
702827
703105
  tokens_in: session.tokensIn,
@@ -702861,6 +703139,36 @@ ${historyLines}
702861
703139
  return;
702862
703140
  }
702863
703141
  }
703142
+ const summarizeMatch = pathname.match(
703143
+ /^\/v1\/chat\/sessions\/([^/]+)\/summarize$/
703144
+ );
703145
+ if (summarizeMatch && method === "POST") {
703146
+ if (!checkAuth(req3, res, "run")) {
703147
+ status = 401;
703148
+ return;
703149
+ }
703150
+ const sid = decodeURIComponent(summarizeMatch[1]);
703151
+ const body = await parseJsonBody(req3).catch(() => ({}));
703152
+ const queriedRoot = body.root || urlObj.searchParams.get("root");
703153
+ const targetRoot = queriedRoot && String(queriedRoot).trim() ? resolve66(String(queriedRoot).trim()) : getCurrentProject()?.root ?? process.cwd();
703154
+ const tuiId = sid.startsWith("tui:") ? sid.slice("tui:".length) : sid;
703155
+ const cfg = loadConfig();
703156
+ try {
703157
+ const result = await ensureSessionSummary({
703158
+ repoRoot: targetRoot,
703159
+ sessionId: tuiId,
703160
+ config: { backendUrl: cfg.backendUrl, model: cfg.model, apiKey: cfg.apiKey },
703161
+ force: body.force === true
703162
+ });
703163
+ jsonResponse(res, 200, { session_id: sid, title: result.title, summary: result.summary });
703164
+ } catch (err) {
703165
+ jsonResponse(res, 500, {
703166
+ error: err instanceof Error ? err.message : String(err),
703167
+ session_id: sid
703168
+ });
703169
+ }
703170
+ return;
703171
+ }
702864
703172
  if (pathname === "/v1/models" && method === "GET") {
702865
703173
  await handleV1Models(res, ollamaUrl);
702866
703174
  return;
@@ -705367,6 +705675,7 @@ var init_serve = __esm({
705367
705675
  init_chat_session();
705368
705676
  init_usage_tracker();
705369
705677
  init_omnius_directory();
705678
+ init_session_summary();
705370
705679
  init_omnius_directory();
705371
705680
  init_command_registry();
705372
705681
  init_profiles();