@hoilab/ada-cli 0.84.10 → 0.84.12

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.
@@ -1 +1 @@
1
- {"version":3,"file":"home-screen.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/home-screen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAwD,MAAM,wBAAwB,CAAC;AACzH,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAKzF,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC;AAEzF,KAAK,cAAc,GAAG,CAAC,UAAU,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAwDnF;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,SAAU,YAAW,SAAS;IACtE,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAAwB;IAExC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,kEAAkE;IAC3D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAEhC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExC;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEvC;IAED,YAAY,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAMxD;IAGD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAEK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAW5B;IAED,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,SAAS;YAQH,WAAW;IAczB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkD9B;IAED,UAAU,IAAI,IAAI,CAAG;IAErB,gBAAgB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAErC;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuI9B;IAED,8DAA8D;IAC9D,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;CAGnB","sourcesContent":["import { type Component, Container, Input, getKeybindings, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { SessionInfo, SessionListProgress } from \"../../../core/session-manager.ts\";\nimport { checkForNewPiVersion } from \"../../../utils/version-check.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { filterAndSortSessions } from \"./session-selector-search.ts\";\n\nexport type HomeScreenResult = { kind: \"new\" } | { kind: \"resume\"; path: string } | null;\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst ASCII_LOGO = [\n\t\" █████╗ ██████╗ █████╗\",\n\t\" ██╔══██╗██╔══██╗██╔══██╗\",\n\t\" ███████║██║ ██║███████║\",\n\t\" ██╔══██║██║ ██║██╔══██║\",\n\t\" ██║ ██║██████╔╝██║ ██║\",\n\t\" ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝\",\n].join(\"\\n\");\n\n/** Vertical teal-to-gray gradient for the ASCII logo. */\nconst LOGO_GRADIENT = [\"accent\", \"accent\", \"borderAccent\", \"border\", \"borderMuted\", \"muted\"] as const;\n\n/** Draw a rounded box around centered content with an optional title. */\nfunction box(\n\tcontentLines: string[],\n\twidth: number,\n\toptions: { title?: string; color?: (str: string) => string } = {},\n): string[] {\n\tconst color = options.color ?? ((str: string) => theme.fg(\"border\", str));\n\tconst innerWidth = Math.max(10, width - 4);\n\tconst top =\n\t\toptions.title !== undefined\n\t\t\t? color(`╭─ ${options.title} `) + \"─\".repeat(Math.max(1, innerWidth - options.title.length - 2)) + color(\"─╮\")\n\t\t\t: color(`╭${\"─\".repeat(innerWidth)}╮`);\n\tconst bottom = color(`╰${\"─\".repeat(innerWidth)}╯`);\n\tconst pad = (line: string) => {\n\t\tconst visible = visibleWidth(line);\n\t\tconst left = Math.max(0, Math.floor((innerWidth - visible) / 2));\n\t\tconst right = Math.max(0, innerWidth - visible - left);\n\t\treturn color(\"│ \") + \" \".repeat(left) + line + \" \".repeat(right) + color(\" │\");\n\t};\n\treturn [top, ...contentLines.map(pad), bottom];\n}\n\nfunction sessionTitle(session: SessionInfo): string {\n\tif (session.name) return session.name;\n\tconst first = (session.firstMessage ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (first.length > 0) return first.length > 60 ? `${first.slice(0, 60)}…` : first;\n\treturn \"Conversation\";\n}\n\nfunction relativeTime(iso: string): string {\n\tconst diffMs = Date.now() - new Date(iso).getTime();\n\tconst mins = Math.floor(diffMs / 60000);\n\tif (mins < 1) return \"now\";\n\tif (mins < 60) return `${mins}m`;\n\tconst hours = Math.floor(mins / 60);\n\tif (hours < 24) return `${hours}h`;\n\tconst days = Math.floor(hours / 24);\n\tif (days < 7) return `${days}d`;\n\tif (days < 30) return `${Math.floor(days / 7)}w`;\n\treturn `${Math.floor(days / 30)}mo`;\n}\n\n/**\n * Central welcome flow (opencode style) shown when the CLI starts:\n * 1) entry screen: \"Enter as guest\" (login is disabled for now)\n * 2) home screen: welcome banner, update notice, recent conversations and\n * a \"New conversation\" action.\n */\nexport class HomeScreenComponent extends Container implements Component {\n\tprivate phase: \"login\" | \"home\" = \"login\";\n\tprivate sessions: SessionInfo[] = [];\n\tprivate filtered: SessionInfo[] = [];\n\tprivate selectedIndex = 0; // 0 = \"New conversation\", then sessions\n\tprivate query = \"\";\n\tprivate loading = false;\n\tprivate updateAvailable: string | null = null;\n\tprivate updateChecked = false;\n\tprivate searchInput: Input;\n\tprivate loadSessions: SessionsLoader;\n\tprivate version: string;\n\tprivate modelLabel: string | null = null;\n\tprivate cwdLabelValue: string | null = null;\n\tprivate memoryEnabled = true;\n\tprivate _focused = false;\n\tprivate requestRenderFn: () => void = () => {};\n\n\tpublic onNew?: () => void;\n\tpublic onResume?: (path: string) => void;\n\tpublic onExit?: () => void;\n\tpublic onUpdate?: () => void;\n\t/** Fired when the entry screen transitions to the home screen. */\n\tpublic onEnterHome?: () => void;\n\n\tsetModelLabel(label: string | null): void {\n\t\tthis.modelLabel = label;\n\t}\n\n\tsetCwdLabel(label: string): void {\n\t\tthis.cwdLabelValue = label;\n\t}\n\n\tsetMemoryEnabled(enabled: boolean): void {\n\t\tthis.memoryEnabled = enabled;\n\t}\n\n\tconstructor(loadSessions: SessionsLoader, version: string) {\n\t\tsuper();\n\t\tthis.loadSessions = loadSessions;\n\t\tthis.version = version;\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.confirmSelection();\n\t}\n\n\t// Focusable\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tthis.loading = true;\n\t\tthis.requestRenderFn();\n\t\ttry {\n\t\t\tthis.sessions = await this.loadSessions();\n\t\t} catch {\n\t\t\tthis.sessions = [];\n\t\t}\n\t\tthis.loading = false;\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tprivate applyFilter(): void {\n\t\tconst q = this.query.trim();\n\t\tthis.filtered = q\n\t\t\t? filterAndSortSessions(this.sessions, q, \"recent\", \"all\")\n\t\t\t: [...this.sessions].sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, this.filtered.length);\n\t}\n\n\tprivate confirmSelection(): void {\n\t\tif (this.phase === \"login\") {\n\t\t\tthis.enterHome();\n\t\t\treturn;\n\t\t}\n\t\tif (this.selectedIndex === 0) {\n\t\t\tthis.onNew?.();\n\t\t} else {\n\t\t\tconst session = this.filtered[this.selectedIndex - 1];\n\t\t\tif (session) this.onResume?.(session.path);\n\t\t}\n\t}\n\n\tprivate enterHome(): void {\n\t\tthis.phase = \"home\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.onEnterHome?.();\n\t\tvoid this.reload();\n\t\tvoid this.checkUpdate();\n\t}\n\n\tprivate async checkUpdate(): Promise<void> {\n\t\tif (this.updateChecked) return;\n\t\tthis.updateChecked = true;\n\t\ttry {\n\t\t\tconst release = await checkForNewPiVersion(this.version);\n\t\t\tif (release) {\n\t\t\t\tthis.updateAvailable = release.version;\n\t\t\t\tthis.requestRenderFn();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Offline or unreachable — ignore silently.\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (this.phase === \"login\") {\n\t\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\t\tthis.enterHome();\n\t\t\t} else if (kb.matches(data, \"tui.select.cancel\") || data === \"q\" || data === \"Q\") {\n\t\t\t\tthis.onExit?.();\n\t\t\t} else if (kb.matches(data, \"tui.select.down\")) {\n\t\t\t\t// Only one actionable option on the login screen; ignore.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = Math.min(this.filtered.length, this.selectedIndex + 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\tthis.confirmSelection();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"n\" || data === \"N\") {\n\t\t\tthis.onNew?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"u\" || data === \"U\") {\n\t\t\tif (this.updateAvailable) {\n\t\t\t\tthis.onUpdate?.();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (data === \"q\" || data === \"Q\") {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\t// Anything else goes to the search input (filters sessions)\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.query = this.searchInput.getValue();\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tinvalidate(): void {}\n\n\tsetRequestRender(fn: () => void): void {\n\t\tthis.requestRenderFn = fn;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst center = (text: string) => {\n\t\t\tconst pad = Math.max(0, Math.floor((width - visibleWidth(text)) / 2));\n\t\t\treturn \" \".repeat(pad) + text;\n\t\t};\n\t\tconst dim = (t: string) => theme.fg(\"dim\", t);\n\t\tconst muted = (t: string) => theme.fg(\"muted\", t);\n\t\tconst accent = (t: string) => theme.fg(\"accent\", t);\n\t\tconst border = (t: string) => theme.fg(\"border\", t);\n\t\tconst success = (t: string) => theme.fg(\"success\", t);\n\t\tconst warning = (t: string) => theme.fg(\"warning\", t);\n\n\t\t// Gradient logo (teal -> gray)\n\t\tconst logoLines = ASCII_LOGO.split(\"\\n\").map((line, i) =>\n\t\t\ttheme.fg(LOGO_GRADIENT[Math.min(i, LOGO_GRADIENT.length - 1)], line),\n\t\t);\n\t\tconst tagline =\n\t\t\taccent(\"Ada\") + dim(\" · coding agent · HOILAB TECH\") + muted(` v${this.version}`);\n\n\t\tlines.push(\"\");\n\n\t\tif (this.phase === \"login\") {\n\t\t\t// ---- Entry screen -------------------------------------------\n\t\t\tconst boxW = Math.min(56, width - 4);\n\t\t\tconst boxLines = box(\n\t\t\t\t[\n\t\t\t\t\t\"\",\n\t\t\t\t\t...logoLines,\n\t\t\t\t\ttagline,\n\t\t\t\t\t\"\",\n\t\t\t\t\tdim(\"Bienvenido a Ada — el agente de codificación de HOILAB TECH\"),\n\t\t\t\t\t\"\",\n\t\t\t\t\taccent(\"▸ \") + theme.bold(\"Entrar como invitado\"),\n\t\t\t\t\tmuted(\" Loguearme\") + dim(\" (próximamente)\"),\n\t\t\t\t\t\"\",\n\t\t\t\t],\n\t\t\t\tboxW,\n\t\t\t\t{ title: \" ✦ HOILAB TECH ✦ \" },\n\t\t\t);\n\t\t\tlines.push(...boxLines);\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(center(success(\"●\") + dim(\" En línea · sin conexión a cuentas\") + muted(\" · todo queda en tu máquina\")));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\n\t\t\t\tcenter(muted([\"Enter para continuar\", \"q para salir\"].join(\" · \"))),\n\t\t\t);\n\t\t\treturn this.finishRender(lines, width);\n\t\t}\n\n\t\t// ---- Home screen ------------------------------------------------\n\t\tconst boxW = Math.min(58, width - 4);\n\n\t\t// Header box: logo + status\n\t\tconst statusParts = [\n\t\t\tdim(`model: ${this.defaultModelLabel()}`),\n\t\t\tdim(`cwd: ${this.cwdLabel()}`),\n\t\t\tdim(`memoria: ${this.memoryLabel()}`),\n\t\t];\n\t\tlines.push(...box([\"\", ...logoLines, tagline, \"\", ...statusParts, \"\"], boxW, { title: \" ✦ HOILAB TECH ✦ \" }));\n\t\tlines.push(\"\");\n\n\t\t// Update notice\n\t\tif (this.updateAvailable) {\n\t\t\tlines.push(\n\t\t\t\tcenter(\n\t\t\t\t\twarning(\n\t\t\t\t\t\t`⚠ Nueva versión disponible: v${this.updateAvailable} ` +\n\t\t\t\t\t\t\taccent(\"[u] actualizar\") +\n\t\t\t\t\t\t\tdim(\" · q para ignorar\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (this.updateChecked) {\n\t\t\tlines.push(center(success(\"✓ Sistema actualizado\")));\n\t\t}\n\t\tlines.push(\"\");\n\n\t\t// Conversations box\n\t\tconst convLines: string[] = [\"\"];\n\t\tconst isNew = this.selectedIndex === 0;\n\t\tconvLines.push(\n\t\t\t`${isNew ? accent(\"▸ \") : \" \"}${accent(\"✦\")} ${isNew ? theme.bold(\"Nueva conversación\") : \"Nueva conversación\"}`,\n\t\t);\n\t\tconvLines.push(dim(\"─\".repeat(Math.max(4, boxW - 6))));\n\t\tconvLines.push(\"\");\n\n\t\tif (this.loading) {\n\t\t\tconvLines.push(dim(\"Cargando conversaciones…\"));\n\t\t} else if (this.filtered.length === 0) {\n\t\t\tconvLines.push(\n\t\t\t\tmuted(\n\t\t\t\t\tthis.query\n\t\t\t\t\t\t? \"No hay conversaciones que coincidan con tu búsqueda\"\n\t\t\t\t\t\t: \"Todavía no hay conversaciones anteriores\",\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tconst maxVisible = Math.max(1, Math.min(12, Math.floor((width * 2) / 3)));\n\t\t\tconst visible = this.filtered.slice(0, maxVisible);\n\t\t\tfor (let i = 0; i < visible.length; i++) {\n\t\t\t\tconst session = visible[i];\n\t\t\t\tconst isSelected = this.selectedIndex === i + 1;\n\t\t\t\tconst title = sessionTitle(session);\n\t\t\t\tconst meta = muted(\n\t\t\t\t\t`${relativeTime(session.modified.toISOString())} · ${session.messageCount} msgs`,\n\t\t\t\t);\n\t\t\t\tconst arrow = isSelected ? accent(\"▸ \") : \" \";\n\t\t\t\tconst titleStyled = isSelected ? theme.bold(accent(title)) : title;\n\t\t\t\tconvLines.push(`${arrow}${titleStyled} ${meta}`);\n\t\t\t}\n\t\t\tif (this.filtered.length > maxVisible) {\n\t\t\t\tconvLines.push(dim(`… y ${this.filtered.length - maxVisible} más`));\n\t\t\t}\n\t\t}\n\t\tconvLines.push(\"\");\n\t\tlines.push(...box(convLines, boxW, { title: \" Conversaciones \" }));\n\t\tlines.push(\"\");\n\n\t\t// Search + hints\n\t\tlines.push(center(accent(\"🔎\") + dim(` Buscar: ${this.query}${this.searchInput.focused ? \"▍\" : \"\"}`)));\n\t\tlines.push(\"\");\n\t\tconst hints = [\n\t\t\t\"↑/↓ navegar\",\n\t\t\t\"Enter seleccionar\",\n\t\t\t\"n nueva\",\n\t\t\tthis.updateAvailable ? \"u actualizar\" : null,\n\t\t\t\"escribir para buscar\",\n\t\t\t\"q salir\",\n\t\t].filter((h): h is string => h !== null);\n\t\tlines.push(\n\t\t\tborder(\"─\".repeat(Math.min(52, width - 8))) ,\n\t\t);\n\t\tlines.push(center(muted(hints.join(\" · \"))));\n\t\treturn this.finishRender(lines, width);\n\t}\n\n\t/** Vertical centering + truncation of every rendered line. */\n\tprivate finishRender(lines: string[], width: number): string[] {\n\t\tconst rows = process.stdout.rows ?? 24;\n\t\tconst contentHeight = lines.length;\n\t\tconst topPad = Math.max(0, Math.floor((rows - contentHeight) / 2) - 1);\n\t\treturn [...Array<string>(topPad).fill(\"\"), ...lines.map((line) => truncateToWidth(line, width))];\n\t}\n\n\tprivate defaultModelLabel(): string {\n\t\treturn this.modelLabel ?? \"no configurado (/model)\";\n\t}\n\n\tprivate cwdLabel(): string {\n\t\treturn this.cwdLabelValue ?? process.cwd();\n\t}\n\n\tprivate memoryLabel(): string {\n\t\treturn this.memoryEnabled ? \"activada\" : \"desactivada\";\n\t}\n}\n"]}
1
+ {"version":3,"file":"home-screen.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/home-screen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAwD,MAAM,wBAAwB,CAAC;AACzH,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAKzF,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC;AAEzF,KAAK,cAAc,GAAG,CAAC,UAAU,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAwDnF;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,SAAU,YAAW,SAAS;IACtE,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAAwB;IAExC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,kEAAkE;IAC3D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAEhC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExC;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEvC;IAED,YAAY,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAMxD;IAGD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAEK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAW5B;IAED,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,SAAS;YAQH,WAAW;IAczB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkD9B;IAED,UAAU,IAAI,IAAI,CAAG;IAErB,gBAAgB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAErC;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2H9B;IAED,8DAA8D;IAC9D,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;CAGnB","sourcesContent":["import { type Component, Container, Input, getKeybindings, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { SessionInfo, SessionListProgress } from \"../../../core/session-manager.ts\";\nimport { checkForNewPiVersion } from \"../../../utils/version-check.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { filterAndSortSessions } from \"./session-selector-search.ts\";\n\nexport type HomeScreenResult = { kind: \"new\" } | { kind: \"resume\"; path: string } | null;\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst ASCII_LOGO = [\n\t\" █████╗ ██████╗ █████╗\",\n\t\" ██╔══██╗██╔══██╗██╔══██╗\",\n\t\" ███████║██║ ██║███████║\",\n\t\" ██╔══██║██║ ██║██╔══██║\",\n\t\" ██║ ██║██████╔╝██║ ██║\",\n\t\" ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝\",\n].join(\"\\n\");\n\n/** Vertical teal-to-gray gradient for the ASCII logo. */\nconst LOGO_GRADIENT = [\"accent\", \"accent\", \"borderAccent\", \"border\", \"borderMuted\", \"muted\"] as const;\n\n/** Draw a rounded box around centered content with an optional title. */\nfunction box(\n\tcontentLines: string[],\n\twidth: number,\n\toptions: { title?: string; color?: (str: string) => string } = {},\n): string[] {\n\tconst color = options.color ?? ((str: string) => theme.fg(\"border\", str));\n\tconst innerWidth = Math.max(10, width - 4);\n\tconst top =\n\t\toptions.title !== undefined\n\t\t\t? color(`╭─ ${options.title} `) + \"─\".repeat(Math.max(1, innerWidth - options.title.length - 2)) + color(\"─╮\")\n\t\t\t: color(`╭${\"─\".repeat(innerWidth)}╮`);\n\tconst bottom = color(`╰${\"─\".repeat(innerWidth)}╯`);\n\tconst pad = (line: string) => {\n\t\tconst visible = visibleWidth(line);\n\t\tconst left = Math.max(0, Math.floor((innerWidth - visible) / 2));\n\t\tconst right = Math.max(0, innerWidth - visible - left);\n\t\treturn color(\"│ \") + \" \".repeat(left) + line + \" \".repeat(right) + color(\" │\");\n\t};\n\treturn [top, ...contentLines.map(pad), bottom];\n}\n\nfunction sessionTitle(session: SessionInfo): string {\n\tif (session.name) return session.name;\n\tconst first = (session.firstMessage ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (first.length > 0) return first.length > 60 ? `${first.slice(0, 60)}…` : first;\n\treturn \"Conversation\";\n}\n\nfunction relativeTime(iso: string): string {\n\tconst diffMs = Date.now() - new Date(iso).getTime();\n\tconst mins = Math.floor(diffMs / 60000);\n\tif (mins < 1) return \"now\";\n\tif (mins < 60) return `${mins}m`;\n\tconst hours = Math.floor(mins / 60);\n\tif (hours < 24) return `${hours}h`;\n\tconst days = Math.floor(hours / 24);\n\tif (days < 7) return `${days}d`;\n\tif (days < 30) return `${Math.floor(days / 7)}w`;\n\treturn `${Math.floor(days / 30)}mo`;\n}\n\n/**\n * Central welcome flow (opencode style) shown when the CLI starts:\n * 1) entry screen: \"Enter as guest\" (login is disabled for now)\n * 2) home screen: welcome banner, update notice, recent conversations and\n * a \"New conversation\" action.\n */\nexport class HomeScreenComponent extends Container implements Component {\n\tprivate phase: \"login\" | \"home\" = \"login\";\n\tprivate sessions: SessionInfo[] = [];\n\tprivate filtered: SessionInfo[] = [];\n\tprivate selectedIndex = 0; // 0 = \"New conversation\", then sessions\n\tprivate query = \"\";\n\tprivate loading = false;\n\tprivate updateAvailable: string | null = null;\n\tprivate updateChecked = false;\n\tprivate searchInput: Input;\n\tprivate loadSessions: SessionsLoader;\n\tprivate version: string;\n\tprivate modelLabel: string | null = null;\n\tprivate cwdLabelValue: string | null = null;\n\tprivate memoryEnabled = true;\n\tprivate _focused = false;\n\tprivate requestRenderFn: () => void = () => {};\n\n\tpublic onNew?: () => void;\n\tpublic onResume?: (path: string) => void;\n\tpublic onExit?: () => void;\n\tpublic onUpdate?: () => void;\n\t/** Fired when the entry screen transitions to the home screen. */\n\tpublic onEnterHome?: () => void;\n\n\tsetModelLabel(label: string | null): void {\n\t\tthis.modelLabel = label;\n\t}\n\n\tsetCwdLabel(label: string): void {\n\t\tthis.cwdLabelValue = label;\n\t}\n\n\tsetMemoryEnabled(enabled: boolean): void {\n\t\tthis.memoryEnabled = enabled;\n\t}\n\n\tconstructor(loadSessions: SessionsLoader, version: string) {\n\t\tsuper();\n\t\tthis.loadSessions = loadSessions;\n\t\tthis.version = version;\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.confirmSelection();\n\t}\n\n\t// Focusable\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tthis.loading = true;\n\t\tthis.requestRenderFn();\n\t\ttry {\n\t\t\tthis.sessions = await this.loadSessions();\n\t\t} catch {\n\t\t\tthis.sessions = [];\n\t\t}\n\t\tthis.loading = false;\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tprivate applyFilter(): void {\n\t\tconst q = this.query.trim();\n\t\tthis.filtered = q\n\t\t\t? filterAndSortSessions(this.sessions, q, \"recent\", \"all\")\n\t\t\t: [...this.sessions].sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, this.filtered.length);\n\t}\n\n\tprivate confirmSelection(): void {\n\t\tif (this.phase === \"login\") {\n\t\t\tthis.enterHome();\n\t\t\treturn;\n\t\t}\n\t\tif (this.selectedIndex === 0) {\n\t\t\tthis.onNew?.();\n\t\t} else {\n\t\t\tconst session = this.filtered[this.selectedIndex - 1];\n\t\t\tif (session) this.onResume?.(session.path);\n\t\t}\n\t}\n\n\tprivate enterHome(): void {\n\t\tthis.phase = \"home\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.onEnterHome?.();\n\t\tvoid this.reload();\n\t\tvoid this.checkUpdate();\n\t}\n\n\tprivate async checkUpdate(): Promise<void> {\n\t\tif (this.updateChecked) return;\n\t\tthis.updateChecked = true;\n\t\ttry {\n\t\t\tconst release = await checkForNewPiVersion(this.version);\n\t\t\tif (release) {\n\t\t\t\tthis.updateAvailable = release.version;\n\t\t\t\tthis.requestRenderFn();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Offline or unreachable — ignore silently.\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (this.phase === \"login\") {\n\t\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\t\tthis.enterHome();\n\t\t\t} else if (kb.matches(data, \"tui.select.cancel\") || data === \"q\" || data === \"Q\") {\n\t\t\t\tthis.onExit?.();\n\t\t\t} else if (kb.matches(data, \"tui.select.down\")) {\n\t\t\t\t// Only one actionable option on the login screen; ignore.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = Math.min(this.filtered.length, this.selectedIndex + 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\tthis.confirmSelection();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"n\" || data === \"N\") {\n\t\t\tthis.onNew?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"u\" || data === \"U\") {\n\t\t\tif (this.updateAvailable) {\n\t\t\t\tthis.onUpdate?.();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (data === \"q\" || data === \"Q\") {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\t// Anything else goes to the search input (filters sessions)\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.query = this.searchInput.getValue();\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tinvalidate(): void {}\n\n\tsetRequestRender(fn: () => void): void {\n\t\tthis.requestRenderFn = fn;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst center = (text: string) => {\n\t\t\tconst pad = Math.max(0, Math.floor((width - visibleWidth(text)) / 2));\n\t\t\treturn \" \".repeat(pad) + text;\n\t\t};\n\t\tconst dim = (t: string) => theme.fg(\"dim\", t);\n\t\tconst muted = (t: string) => theme.fg(\"muted\", t);\n\t\tconst accent = (t: string) => theme.fg(\"accent\", t);\n\t\tconst border = (t: string) => theme.fg(\"border\", t);\n\t\tconst success = (t: string) => theme.fg(\"success\", t);\n\t\tconst warning = (t: string) => theme.fg(\"warning\", t);\n\n\t\t// Gradient logo (teal -> gray)\n\t\tconst logoLines = ASCII_LOGO.split(\"\\n\").map((line, i) =>\n\t\t\ttheme.fg(LOGO_GRADIENT[Math.min(i, LOGO_GRADIENT.length - 1)], line),\n\t\t);\n\t\tconst tagline =\n\t\t\taccent(\"Ada\") + dim(\" · coding agent · HOILAB TECH\") + muted(` v${this.version}`);\n\n\t\tlines.push(\"\");\n\n\t\tif (this.phase === \"login\") {\n\t\t\t// ---- Entry screen -------------------------------------------\n\t\t\tconst boxW = Math.min(56, width - 4);\n\t\t\tconst boxLines = box(\n\t\t\t\t[\n\t\t\t\t\t\"\",\n\t\t\t\t\t...logoLines,\n\t\t\t\t\ttagline,\n\t\t\t\t\t\"\",\n\t\t\t\t\tdim(\"Bienvenido a Ada — el agente de codificación de HOILAB TECH\"),\n\t\t\t\t\t\"\",\n\t\t\t\t\taccent(\"▸ \") + theme.bold(\"Entrar como invitado\"),\n\t\t\t\t\tmuted(\" Loguearme\") + dim(\" (próximamente)\"),\n\t\t\t\t\t\"\",\n\t\t\t\t],\n\t\t\t\tboxW,\n\t\t\t\t{ title: \" ✦ HOILAB TECH ✦ \" },\n\t\t\t);\n\t\t\tlines.push(...boxLines.map((l) => center(l)));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(center(success(\"●\") + dim(\" En línea · sin conexión a cuentas\") + muted(\" · todo queda en tu máquina\")));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\n\t\t\t\tcenter(muted([\"Enter para continuar\", \"q para salir\"].join(\" · \"))),\n\t\t\t);\n\t\t\treturn this.finishRender(lines, width);\n\t\t}\n\n\t\t// ---- Home screen ------------------------------------------------\n\t\tconst boxW = Math.min(width - 4, 72);\n\n\t\t// Header box: logo + status\n\t\tconst statusParts = [\n\t\t\tdim(`model: ${this.defaultModelLabel()}`),\n\t\t\tdim(`cwd: ${this.cwdLabel()}`),\n\t\t\tdim(`memoria: ${this.memoryLabel()}`),\n\t\t\t\"\",\n\t\t];\n\t\tif (this.updateAvailable) {\n\t\t\tstatusParts.push(\n\t\t\t\twarning(\n\t\t\t\t\t`⚠ Nueva versión disponible: v${this.updateAvailable} ` +\n\t\t\t\t\t\taccent(\"[u] actualizar\") +\n\t\t\t\t\t\tdim(\" · q para ignorar\"),\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (this.updateChecked) {\n\t\t\tstatusParts.push(success(\"✓ Sistema actualizado\"));\n\t\t}\n\t\tlines.push(...box([\"\", ...logoLines, tagline, \"\", ...statusParts], boxW, { title: \" ✦ HOILAB TECH ✦ \" }).map((l) => center(l)));\n\t\tlines.push(\"\");\n\n\t\t// Conversations box\n\t\tconst convLines: string[] = [\"\"];\n\t\tconst isNew = this.selectedIndex === 0;\n\t\tconvLines.push(\n\t\t\t`${isNew ? accent(\"▸ \") : \" \"}${accent(\"✦\")} ${isNew ? theme.bold(\"Nueva conversación\") : \"Nueva conversación\"}`,\n\t\t);\n\t\tconvLines.push(\"\");\n\n\t\tif (this.loading) {\n\t\t\tconvLines.push(dim(\"Cargando conversaciones…\"));\n\t\t} else if (this.filtered.length === 0) {\n\t\t\tconvLines.push(\n\t\t\t\tmuted(\n\t\t\t\t\tthis.query\n\t\t\t\t\t\t? \"No hay conversaciones que coincidan con tu búsqueda\"\n\t\t\t\t\t\t: \"Todavía no hay conversaciones anteriores\",\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tconst maxVisible = Math.max(1, Math.min(12, Math.floor((width * 2) / 3)));\n\t\t\tconst visible = this.filtered.slice(0, maxVisible);\n\t\t\tfor (let i = 0; i < visible.length; i++) {\n\t\t\t\tconst session = visible[i];\n\t\t\t\tconst isSelected = this.selectedIndex === i + 1;\n\t\t\t\tconst title = sessionTitle(session);\n\t\t\t\tconst meta = muted(\n\t\t\t\t\t`${relativeTime(session.modified.toISOString())} · ${session.messageCount} msgs`,\n\t\t\t\t);\n\t\t\t\tconst arrow = isSelected ? accent(\"▸ \") : \" \";\n\t\t\t\tconst titleStyled = isSelected ? theme.bold(accent(title)) : title;\n\t\t\t\tconvLines.push(`${arrow}${titleStyled} ${meta}`);\n\t\t\t}\n\t\t\tif (this.filtered.length > maxVisible) {\n\t\t\t\tconvLines.push(dim(`… y ${this.filtered.length - maxVisible} más`));\n\t\t\t}\n\t\t}\n\t\tconvLines.push(\"\");\n\t\tlines.push(...box(convLines, boxW, { title: \" Conversaciones \" }).map((l) => center(l)));\n\t\tlines.push(\"\");\n\n\t\tconst hints = [\n\t\t\t\"↑/↓ navegar\",\n\t\t\t\"Enter seleccionar\",\n\t\t\t\"n nueva\",\n\t\t\tthis.updateAvailable ? \"u actualizar\" : null,\n\t\t\t\"q salir\",\n\t\t].filter((h): h is string => h !== null);\n\t\tlines.push(center(muted(hints.join(\" · \"))));\n\t\treturn this.finishRender(lines, width);\n\t}\n\n\t/** Vertical centering + truncation of every rendered line. */\n\tprivate finishRender(lines: string[], width: number): string[] {\n\t\tconst rows = process.stdout.rows ?? 24;\n\t\tconst contentHeight = lines.length;\n\t\tconst topPad = Math.min(3, Math.max(0, Math.floor((rows - contentHeight) / 3)));\n\t\treturn [...Array<string>(topPad).fill(\"\"), ...lines.map((line) => truncateToWidth(line, width))];\n\t}\n\n\tprivate defaultModelLabel(): string {\n\t\treturn this.modelLabel ?? \"no configurado (/model)\";\n\t}\n\n\tprivate cwdLabel(): string {\n\t\treturn this.cwdLabelValue ?? process.cwd();\n\t}\n\n\tprivate memoryLabel(): string {\n\t\treturn this.memoryEnabled ? \"activada\" : \"desactivada\";\n\t}\n}\n"]}
@@ -248,7 +248,7 @@ export class HomeScreenComponent extends Container {
248
248
  muted(" Loguearme") + dim(" (próximamente)"),
249
249
  "",
250
250
  ], boxW, { title: " ✦ HOILAB TECH ✦ " });
251
- lines.push(...boxLines);
251
+ lines.push(...boxLines.map((l) => center(l)));
252
252
  lines.push("");
253
253
  lines.push(center(success("●") + dim(" En línea · sin conexión a cuentas") + muted(" · todo queda en tu máquina")));
254
254
  lines.push("");
@@ -256,30 +256,28 @@ export class HomeScreenComponent extends Container {
256
256
  return this.finishRender(lines, width);
257
257
  }
258
258
  // ---- Home screen ------------------------------------------------
259
- const boxW = Math.min(58, width - 4);
259
+ const boxW = Math.min(width - 4, 72);
260
260
  // Header box: logo + status
261
261
  const statusParts = [
262
262
  dim(`model: ${this.defaultModelLabel()}`),
263
263
  dim(`cwd: ${this.cwdLabel()}`),
264
264
  dim(`memoria: ${this.memoryLabel()}`),
265
+ "",
265
266
  ];
266
- lines.push(...box(["", ...logoLines, tagline, "", ...statusParts, ""], boxW, { title: " ✦ HOILAB TECH ✦ " }));
267
- lines.push("");
268
- // Update notice
269
267
  if (this.updateAvailable) {
270
- lines.push(center(warning(`⚠ Nueva versión disponible: v${this.updateAvailable} ` +
268
+ statusParts.push(warning(`⚠ Nueva versión disponible: v${this.updateAvailable} ` +
271
269
  accent("[u] actualizar") +
272
- dim(" · q para ignorar"))));
270
+ dim(" · q para ignorar")));
273
271
  }
274
272
  else if (this.updateChecked) {
275
- lines.push(center(success("✓ Sistema actualizado")));
273
+ statusParts.push(success("✓ Sistema actualizado"));
276
274
  }
275
+ lines.push(...box(["", ...logoLines, tagline, "", ...statusParts], boxW, { title: " ✦ HOILAB TECH ✦ " }).map((l) => center(l)));
277
276
  lines.push("");
278
277
  // Conversations box
279
278
  const convLines = [""];
280
279
  const isNew = this.selectedIndex === 0;
281
280
  convLines.push(`${isNew ? accent("▸ ") : " "}${accent("✦")} ${isNew ? theme.bold("Nueva conversación") : "Nueva conversación"}`);
282
- convLines.push(dim("─".repeat(Math.max(4, boxW - 6))));
283
281
  convLines.push("");
284
282
  if (this.loading) {
285
283
  convLines.push(dim("Cargando conversaciones…"));
@@ -306,20 +304,15 @@ export class HomeScreenComponent extends Container {
306
304
  }
307
305
  }
308
306
  convLines.push("");
309
- lines.push(...box(convLines, boxW, { title: " Conversaciones " }));
310
- lines.push("");
311
- // Search + hints
312
- lines.push(center(accent("🔎") + dim(` Buscar: ${this.query}${this.searchInput.focused ? "▍" : ""}`)));
307
+ lines.push(...box(convLines, boxW, { title: " Conversaciones " }).map((l) => center(l)));
313
308
  lines.push("");
314
309
  const hints = [
315
310
  "↑/↓ navegar",
316
311
  "Enter seleccionar",
317
312
  "n nueva",
318
313
  this.updateAvailable ? "u actualizar" : null,
319
- "escribir para buscar",
320
314
  "q salir",
321
315
  ].filter((h) => h !== null);
322
- lines.push(border("─".repeat(Math.min(52, width - 8))));
323
316
  lines.push(center(muted(hints.join(" · "))));
324
317
  return this.finishRender(lines, width);
325
318
  }
@@ -327,7 +320,7 @@ export class HomeScreenComponent extends Container {
327
320
  finishRender(lines, width) {
328
321
  const rows = process.stdout.rows ?? 24;
329
322
  const contentHeight = lines.length;
330
- const topPad = Math.max(0, Math.floor((rows - contentHeight) / 2) - 1);
323
+ const topPad = Math.min(3, Math.max(0, Math.floor((rows - contentHeight) / 3)));
331
324
  return [...Array(topPad).fill(""), ...lines.map((line) => truncateToWidth(line, width))];
332
325
  }
333
326
  defaultModelLabel() {
@@ -1 +1 @@
1
- {"version":3,"file":"home-screen.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/home-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, Input, getKeybindings, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { SessionInfo, SessionListProgress } from \"../../../core/session-manager.ts\";\nimport { checkForNewPiVersion } from \"../../../utils/version-check.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { filterAndSortSessions } from \"./session-selector-search.ts\";\n\nexport type HomeScreenResult = { kind: \"new\" } | { kind: \"resume\"; path: string } | null;\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst ASCII_LOGO = [\n\t\" █████╗ ██████╗ █████╗\",\n\t\" ██╔══██╗██╔══██╗██╔══██╗\",\n\t\" ███████║██║ ██║███████║\",\n\t\" ██╔══██║██║ ██║██╔══██║\",\n\t\" ██║ ██║██████╔╝██║ ██║\",\n\t\" ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝\",\n].join(\"\\n\");\n\n/** Vertical teal-to-gray gradient for the ASCII logo. */\nconst LOGO_GRADIENT = [\"accent\", \"accent\", \"borderAccent\", \"border\", \"borderMuted\", \"muted\"] as const;\n\n/** Draw a rounded box around centered content with an optional title. */\nfunction box(\n\tcontentLines: string[],\n\twidth: number,\n\toptions: { title?: string; color?: (str: string) => string } = {},\n): string[] {\n\tconst color = options.color ?? ((str: string) => theme.fg(\"border\", str));\n\tconst innerWidth = Math.max(10, width - 4);\n\tconst top =\n\t\toptions.title !== undefined\n\t\t\t? color(`╭─ ${options.title} `) + \"─\".repeat(Math.max(1, innerWidth - options.title.length - 2)) + color(\"─╮\")\n\t\t\t: color(`╭${\"─\".repeat(innerWidth)}╮`);\n\tconst bottom = color(`╰${\"─\".repeat(innerWidth)}╯`);\n\tconst pad = (line: string) => {\n\t\tconst visible = visibleWidth(line);\n\t\tconst left = Math.max(0, Math.floor((innerWidth - visible) / 2));\n\t\tconst right = Math.max(0, innerWidth - visible - left);\n\t\treturn color(\"│ \") + \" \".repeat(left) + line + \" \".repeat(right) + color(\" │\");\n\t};\n\treturn [top, ...contentLines.map(pad), bottom];\n}\n\nfunction sessionTitle(session: SessionInfo): string {\n\tif (session.name) return session.name;\n\tconst first = (session.firstMessage ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (first.length > 0) return first.length > 60 ? `${first.slice(0, 60)}…` : first;\n\treturn \"Conversation\";\n}\n\nfunction relativeTime(iso: string): string {\n\tconst diffMs = Date.now() - new Date(iso).getTime();\n\tconst mins = Math.floor(diffMs / 60000);\n\tif (mins < 1) return \"now\";\n\tif (mins < 60) return `${mins}m`;\n\tconst hours = Math.floor(mins / 60);\n\tif (hours < 24) return `${hours}h`;\n\tconst days = Math.floor(hours / 24);\n\tif (days < 7) return `${days}d`;\n\tif (days < 30) return `${Math.floor(days / 7)}w`;\n\treturn `${Math.floor(days / 30)}mo`;\n}\n\n/**\n * Central welcome flow (opencode style) shown when the CLI starts:\n * 1) entry screen: \"Enter as guest\" (login is disabled for now)\n * 2) home screen: welcome banner, update notice, recent conversations and\n * a \"New conversation\" action.\n */\nexport class HomeScreenComponent extends Container implements Component {\n\tprivate phase: \"login\" | \"home\" = \"login\";\n\tprivate sessions: SessionInfo[] = [];\n\tprivate filtered: SessionInfo[] = [];\n\tprivate selectedIndex = 0; // 0 = \"New conversation\", then sessions\n\tprivate query = \"\";\n\tprivate loading = false;\n\tprivate updateAvailable: string | null = null;\n\tprivate updateChecked = false;\n\tprivate searchInput: Input;\n\tprivate loadSessions: SessionsLoader;\n\tprivate version: string;\n\tprivate modelLabel: string | null = null;\n\tprivate cwdLabelValue: string | null = null;\n\tprivate memoryEnabled = true;\n\tprivate _focused = false;\n\tprivate requestRenderFn: () => void = () => {};\n\n\tpublic onNew?: () => void;\n\tpublic onResume?: (path: string) => void;\n\tpublic onExit?: () => void;\n\tpublic onUpdate?: () => void;\n\t/** Fired when the entry screen transitions to the home screen. */\n\tpublic onEnterHome?: () => void;\n\n\tsetModelLabel(label: string | null): void {\n\t\tthis.modelLabel = label;\n\t}\n\n\tsetCwdLabel(label: string): void {\n\t\tthis.cwdLabelValue = label;\n\t}\n\n\tsetMemoryEnabled(enabled: boolean): void {\n\t\tthis.memoryEnabled = enabled;\n\t}\n\n\tconstructor(loadSessions: SessionsLoader, version: string) {\n\t\tsuper();\n\t\tthis.loadSessions = loadSessions;\n\t\tthis.version = version;\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.confirmSelection();\n\t}\n\n\t// Focusable\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tthis.loading = true;\n\t\tthis.requestRenderFn();\n\t\ttry {\n\t\t\tthis.sessions = await this.loadSessions();\n\t\t} catch {\n\t\t\tthis.sessions = [];\n\t\t}\n\t\tthis.loading = false;\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tprivate applyFilter(): void {\n\t\tconst q = this.query.trim();\n\t\tthis.filtered = q\n\t\t\t? filterAndSortSessions(this.sessions, q, \"recent\", \"all\")\n\t\t\t: [...this.sessions].sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, this.filtered.length);\n\t}\n\n\tprivate confirmSelection(): void {\n\t\tif (this.phase === \"login\") {\n\t\t\tthis.enterHome();\n\t\t\treturn;\n\t\t}\n\t\tif (this.selectedIndex === 0) {\n\t\t\tthis.onNew?.();\n\t\t} else {\n\t\t\tconst session = this.filtered[this.selectedIndex - 1];\n\t\t\tif (session) this.onResume?.(session.path);\n\t\t}\n\t}\n\n\tprivate enterHome(): void {\n\t\tthis.phase = \"home\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.onEnterHome?.();\n\t\tvoid this.reload();\n\t\tvoid this.checkUpdate();\n\t}\n\n\tprivate async checkUpdate(): Promise<void> {\n\t\tif (this.updateChecked) return;\n\t\tthis.updateChecked = true;\n\t\ttry {\n\t\t\tconst release = await checkForNewPiVersion(this.version);\n\t\t\tif (release) {\n\t\t\t\tthis.updateAvailable = release.version;\n\t\t\t\tthis.requestRenderFn();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Offline or unreachable — ignore silently.\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (this.phase === \"login\") {\n\t\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\t\tthis.enterHome();\n\t\t\t} else if (kb.matches(data, \"tui.select.cancel\") || data === \"q\" || data === \"Q\") {\n\t\t\t\tthis.onExit?.();\n\t\t\t} else if (kb.matches(data, \"tui.select.down\")) {\n\t\t\t\t// Only one actionable option on the login screen; ignore.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = Math.min(this.filtered.length, this.selectedIndex + 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\tthis.confirmSelection();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"n\" || data === \"N\") {\n\t\t\tthis.onNew?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"u\" || data === \"U\") {\n\t\t\tif (this.updateAvailable) {\n\t\t\t\tthis.onUpdate?.();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (data === \"q\" || data === \"Q\") {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\t// Anything else goes to the search input (filters sessions)\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.query = this.searchInput.getValue();\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tinvalidate(): void {}\n\n\tsetRequestRender(fn: () => void): void {\n\t\tthis.requestRenderFn = fn;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst center = (text: string) => {\n\t\t\tconst pad = Math.max(0, Math.floor((width - visibleWidth(text)) / 2));\n\t\t\treturn \" \".repeat(pad) + text;\n\t\t};\n\t\tconst dim = (t: string) => theme.fg(\"dim\", t);\n\t\tconst muted = (t: string) => theme.fg(\"muted\", t);\n\t\tconst accent = (t: string) => theme.fg(\"accent\", t);\n\t\tconst border = (t: string) => theme.fg(\"border\", t);\n\t\tconst success = (t: string) => theme.fg(\"success\", t);\n\t\tconst warning = (t: string) => theme.fg(\"warning\", t);\n\n\t\t// Gradient logo (teal -> gray)\n\t\tconst logoLines = ASCII_LOGO.split(\"\\n\").map((line, i) =>\n\t\t\ttheme.fg(LOGO_GRADIENT[Math.min(i, LOGO_GRADIENT.length - 1)], line),\n\t\t);\n\t\tconst tagline =\n\t\t\taccent(\"Ada\") + dim(\" · coding agent · HOILAB TECH\") + muted(` v${this.version}`);\n\n\t\tlines.push(\"\");\n\n\t\tif (this.phase === \"login\") {\n\t\t\t// ---- Entry screen -------------------------------------------\n\t\t\tconst boxW = Math.min(56, width - 4);\n\t\t\tconst boxLines = box(\n\t\t\t\t[\n\t\t\t\t\t\"\",\n\t\t\t\t\t...logoLines,\n\t\t\t\t\ttagline,\n\t\t\t\t\t\"\",\n\t\t\t\t\tdim(\"Bienvenido a Ada — el agente de codificación de HOILAB TECH\"),\n\t\t\t\t\t\"\",\n\t\t\t\t\taccent(\"▸ \") + theme.bold(\"Entrar como invitado\"),\n\t\t\t\t\tmuted(\" Loguearme\") + dim(\" (próximamente)\"),\n\t\t\t\t\t\"\",\n\t\t\t\t],\n\t\t\t\tboxW,\n\t\t\t\t{ title: \" ✦ HOILAB TECH ✦ \" },\n\t\t\t);\n\t\t\tlines.push(...boxLines);\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(center(success(\"●\") + dim(\" En línea · sin conexión a cuentas\") + muted(\" · todo queda en tu máquina\")));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\n\t\t\t\tcenter(muted([\"Enter para continuar\", \"q para salir\"].join(\" · \"))),\n\t\t\t);\n\t\t\treturn this.finishRender(lines, width);\n\t\t}\n\n\t\t// ---- Home screen ------------------------------------------------\n\t\tconst boxW = Math.min(58, width - 4);\n\n\t\t// Header box: logo + status\n\t\tconst statusParts = [\n\t\t\tdim(`model: ${this.defaultModelLabel()}`),\n\t\t\tdim(`cwd: ${this.cwdLabel()}`),\n\t\t\tdim(`memoria: ${this.memoryLabel()}`),\n\t\t];\n\t\tlines.push(...box([\"\", ...logoLines, tagline, \"\", ...statusParts, \"\"], boxW, { title: \" ✦ HOILAB TECH ✦ \" }));\n\t\tlines.push(\"\");\n\n\t\t// Update notice\n\t\tif (this.updateAvailable) {\n\t\t\tlines.push(\n\t\t\t\tcenter(\n\t\t\t\t\twarning(\n\t\t\t\t\t\t`⚠ Nueva versión disponible: v${this.updateAvailable} ` +\n\t\t\t\t\t\t\taccent(\"[u] actualizar\") +\n\t\t\t\t\t\t\tdim(\" · q para ignorar\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (this.updateChecked) {\n\t\t\tlines.push(center(success(\"✓ Sistema actualizado\")));\n\t\t}\n\t\tlines.push(\"\");\n\n\t\t// Conversations box\n\t\tconst convLines: string[] = [\"\"];\n\t\tconst isNew = this.selectedIndex === 0;\n\t\tconvLines.push(\n\t\t\t`${isNew ? accent(\"▸ \") : \" \"}${accent(\"✦\")} ${isNew ? theme.bold(\"Nueva conversación\") : \"Nueva conversación\"}`,\n\t\t);\n\t\tconvLines.push(dim(\"─\".repeat(Math.max(4, boxW - 6))));\n\t\tconvLines.push(\"\");\n\n\t\tif (this.loading) {\n\t\t\tconvLines.push(dim(\"Cargando conversaciones…\"));\n\t\t} else if (this.filtered.length === 0) {\n\t\t\tconvLines.push(\n\t\t\t\tmuted(\n\t\t\t\t\tthis.query\n\t\t\t\t\t\t? \"No hay conversaciones que coincidan con tu búsqueda\"\n\t\t\t\t\t\t: \"Todavía no hay conversaciones anteriores\",\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tconst maxVisible = Math.max(1, Math.min(12, Math.floor((width * 2) / 3)));\n\t\t\tconst visible = this.filtered.slice(0, maxVisible);\n\t\t\tfor (let i = 0; i < visible.length; i++) {\n\t\t\t\tconst session = visible[i];\n\t\t\t\tconst isSelected = this.selectedIndex === i + 1;\n\t\t\t\tconst title = sessionTitle(session);\n\t\t\t\tconst meta = muted(\n\t\t\t\t\t`${relativeTime(session.modified.toISOString())} · ${session.messageCount} msgs`,\n\t\t\t\t);\n\t\t\t\tconst arrow = isSelected ? accent(\"▸ \") : \" \";\n\t\t\t\tconst titleStyled = isSelected ? theme.bold(accent(title)) : title;\n\t\t\t\tconvLines.push(`${arrow}${titleStyled} ${meta}`);\n\t\t\t}\n\t\t\tif (this.filtered.length > maxVisible) {\n\t\t\t\tconvLines.push(dim(`… y ${this.filtered.length - maxVisible} más`));\n\t\t\t}\n\t\t}\n\t\tconvLines.push(\"\");\n\t\tlines.push(...box(convLines, boxW, { title: \" Conversaciones \" }));\n\t\tlines.push(\"\");\n\n\t\t// Search + hints\n\t\tlines.push(center(accent(\"🔎\") + dim(` Buscar: ${this.query}${this.searchInput.focused ? \"▍\" : \"\"}`)));\n\t\tlines.push(\"\");\n\t\tconst hints = [\n\t\t\t\"↑/↓ navegar\",\n\t\t\t\"Enter seleccionar\",\n\t\t\t\"n nueva\",\n\t\t\tthis.updateAvailable ? \"u actualizar\" : null,\n\t\t\t\"escribir para buscar\",\n\t\t\t\"q salir\",\n\t\t].filter((h): h is string => h !== null);\n\t\tlines.push(\n\t\t\tborder(\"─\".repeat(Math.min(52, width - 8))) ,\n\t\t);\n\t\tlines.push(center(muted(hints.join(\" · \"))));\n\t\treturn this.finishRender(lines, width);\n\t}\n\n\t/** Vertical centering + truncation of every rendered line. */\n\tprivate finishRender(lines: string[], width: number): string[] {\n\t\tconst rows = process.stdout.rows ?? 24;\n\t\tconst contentHeight = lines.length;\n\t\tconst topPad = Math.max(0, Math.floor((rows - contentHeight) / 2) - 1);\n\t\treturn [...Array<string>(topPad).fill(\"\"), ...lines.map((line) => truncateToWidth(line, width))];\n\t}\n\n\tprivate defaultModelLabel(): string {\n\t\treturn this.modelLabel ?? \"no configurado (/model)\";\n\t}\n\n\tprivate cwdLabel(): string {\n\t\treturn this.cwdLabelValue ?? process.cwd();\n\t}\n\n\tprivate memoryLabel(): string {\n\t\treturn this.memoryEnabled ? \"activada\" : \"desactivada\";\n\t}\n}\n"]}
1
+ {"version":3,"file":"home-screen.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/home-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, Input, getKeybindings, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { SessionInfo, SessionListProgress } from \"../../../core/session-manager.ts\";\nimport { checkForNewPiVersion } from \"../../../utils/version-check.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { filterAndSortSessions } from \"./session-selector-search.ts\";\n\nexport type HomeScreenResult = { kind: \"new\" } | { kind: \"resume\"; path: string } | null;\n\ntype SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;\n\nconst ASCII_LOGO = [\n\t\" █████╗ ██████╗ █████╗\",\n\t\" ██╔══██╗██╔══██╗██╔══██╗\",\n\t\" ███████║██║ ██║███████║\",\n\t\" ██╔══██║██║ ██║██╔══██║\",\n\t\" ██║ ██║██████╔╝██║ ██║\",\n\t\" ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝\",\n].join(\"\\n\");\n\n/** Vertical teal-to-gray gradient for the ASCII logo. */\nconst LOGO_GRADIENT = [\"accent\", \"accent\", \"borderAccent\", \"border\", \"borderMuted\", \"muted\"] as const;\n\n/** Draw a rounded box around centered content with an optional title. */\nfunction box(\n\tcontentLines: string[],\n\twidth: number,\n\toptions: { title?: string; color?: (str: string) => string } = {},\n): string[] {\n\tconst color = options.color ?? ((str: string) => theme.fg(\"border\", str));\n\tconst innerWidth = Math.max(10, width - 4);\n\tconst top =\n\t\toptions.title !== undefined\n\t\t\t? color(`╭─ ${options.title} `) + \"─\".repeat(Math.max(1, innerWidth - options.title.length - 2)) + color(\"─╮\")\n\t\t\t: color(`╭${\"─\".repeat(innerWidth)}╮`);\n\tconst bottom = color(`╰${\"─\".repeat(innerWidth)}╯`);\n\tconst pad = (line: string) => {\n\t\tconst visible = visibleWidth(line);\n\t\tconst left = Math.max(0, Math.floor((innerWidth - visible) / 2));\n\t\tconst right = Math.max(0, innerWidth - visible - left);\n\t\treturn color(\"│ \") + \" \".repeat(left) + line + \" \".repeat(right) + color(\" │\");\n\t};\n\treturn [top, ...contentLines.map(pad), bottom];\n}\n\nfunction sessionTitle(session: SessionInfo): string {\n\tif (session.name) return session.name;\n\tconst first = (session.firstMessage ?? \"\").replace(/\\s+/g, \" \").trim();\n\tif (first.length > 0) return first.length > 60 ? `${first.slice(0, 60)}…` : first;\n\treturn \"Conversation\";\n}\n\nfunction relativeTime(iso: string): string {\n\tconst diffMs = Date.now() - new Date(iso).getTime();\n\tconst mins = Math.floor(diffMs / 60000);\n\tif (mins < 1) return \"now\";\n\tif (mins < 60) return `${mins}m`;\n\tconst hours = Math.floor(mins / 60);\n\tif (hours < 24) return `${hours}h`;\n\tconst days = Math.floor(hours / 24);\n\tif (days < 7) return `${days}d`;\n\tif (days < 30) return `${Math.floor(days / 7)}w`;\n\treturn `${Math.floor(days / 30)}mo`;\n}\n\n/**\n * Central welcome flow (opencode style) shown when the CLI starts:\n * 1) entry screen: \"Enter as guest\" (login is disabled for now)\n * 2) home screen: welcome banner, update notice, recent conversations and\n * a \"New conversation\" action.\n */\nexport class HomeScreenComponent extends Container implements Component {\n\tprivate phase: \"login\" | \"home\" = \"login\";\n\tprivate sessions: SessionInfo[] = [];\n\tprivate filtered: SessionInfo[] = [];\n\tprivate selectedIndex = 0; // 0 = \"New conversation\", then sessions\n\tprivate query = \"\";\n\tprivate loading = false;\n\tprivate updateAvailable: string | null = null;\n\tprivate updateChecked = false;\n\tprivate searchInput: Input;\n\tprivate loadSessions: SessionsLoader;\n\tprivate version: string;\n\tprivate modelLabel: string | null = null;\n\tprivate cwdLabelValue: string | null = null;\n\tprivate memoryEnabled = true;\n\tprivate _focused = false;\n\tprivate requestRenderFn: () => void = () => {};\n\n\tpublic onNew?: () => void;\n\tpublic onResume?: (path: string) => void;\n\tpublic onExit?: () => void;\n\tpublic onUpdate?: () => void;\n\t/** Fired when the entry screen transitions to the home screen. */\n\tpublic onEnterHome?: () => void;\n\n\tsetModelLabel(label: string | null): void {\n\t\tthis.modelLabel = label;\n\t}\n\n\tsetCwdLabel(label: string): void {\n\t\tthis.cwdLabelValue = label;\n\t}\n\n\tsetMemoryEnabled(enabled: boolean): void {\n\t\tthis.memoryEnabled = enabled;\n\t}\n\n\tconstructor(loadSessions: SessionsLoader, version: string) {\n\t\tsuper();\n\t\tthis.loadSessions = loadSessions;\n\t\tthis.version = version;\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.confirmSelection();\n\t}\n\n\t// Focusable\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tthis.loading = true;\n\t\tthis.requestRenderFn();\n\t\ttry {\n\t\t\tthis.sessions = await this.loadSessions();\n\t\t} catch {\n\t\t\tthis.sessions = [];\n\t\t}\n\t\tthis.loading = false;\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tprivate applyFilter(): void {\n\t\tconst q = this.query.trim();\n\t\tthis.filtered = q\n\t\t\t? filterAndSortSessions(this.sessions, q, \"recent\", \"all\")\n\t\t\t: [...this.sessions].sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, this.filtered.length);\n\t}\n\n\tprivate confirmSelection(): void {\n\t\tif (this.phase === \"login\") {\n\t\t\tthis.enterHome();\n\t\t\treturn;\n\t\t}\n\t\tif (this.selectedIndex === 0) {\n\t\t\tthis.onNew?.();\n\t\t} else {\n\t\t\tconst session = this.filtered[this.selectedIndex - 1];\n\t\t\tif (session) this.onResume?.(session.path);\n\t\t}\n\t}\n\n\tprivate enterHome(): void {\n\t\tthis.phase = \"home\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.onEnterHome?.();\n\t\tvoid this.reload();\n\t\tvoid this.checkUpdate();\n\t}\n\n\tprivate async checkUpdate(): Promise<void> {\n\t\tif (this.updateChecked) return;\n\t\tthis.updateChecked = true;\n\t\ttry {\n\t\t\tconst release = await checkForNewPiVersion(this.version);\n\t\t\tif (release) {\n\t\t\t\tthis.updateAvailable = release.version;\n\t\t\t\tthis.requestRenderFn();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Offline or unreachable — ignore silently.\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (this.phase === \"login\") {\n\t\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\t\tthis.enterHome();\n\t\t\t} else if (kb.matches(data, \"tui.select.cancel\") || data === \"q\" || data === \"Q\") {\n\t\t\t\tthis.onExit?.();\n\t\t\t} else if (kb.matches(data, \"tui.select.down\")) {\n\t\t\t\t// Only one actionable option on the login screen; ignore.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = Math.min(this.filtered.length, this.selectedIndex + 1);\n\t\t\tthis.requestRenderFn();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\") || data === \"\\r\" || data === \"\\n\") {\n\t\t\tthis.confirmSelection();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"n\" || data === \"N\") {\n\t\t\tthis.onNew?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \"u\" || data === \"U\") {\n\t\t\tif (this.updateAvailable) {\n\t\t\t\tthis.onUpdate?.();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (data === \"q\" || data === \"Q\") {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\t// Anything else goes to the search input (filters sessions)\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.query = this.searchInput.getValue();\n\t\tthis.applyFilter();\n\t\tthis.requestRenderFn();\n\t}\n\n\tinvalidate(): void {}\n\n\tsetRequestRender(fn: () => void): void {\n\t\tthis.requestRenderFn = fn;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst center = (text: string) => {\n\t\t\tconst pad = Math.max(0, Math.floor((width - visibleWidth(text)) / 2));\n\t\t\treturn \" \".repeat(pad) + text;\n\t\t};\n\t\tconst dim = (t: string) => theme.fg(\"dim\", t);\n\t\tconst muted = (t: string) => theme.fg(\"muted\", t);\n\t\tconst accent = (t: string) => theme.fg(\"accent\", t);\n\t\tconst border = (t: string) => theme.fg(\"border\", t);\n\t\tconst success = (t: string) => theme.fg(\"success\", t);\n\t\tconst warning = (t: string) => theme.fg(\"warning\", t);\n\n\t\t// Gradient logo (teal -> gray)\n\t\tconst logoLines = ASCII_LOGO.split(\"\\n\").map((line, i) =>\n\t\t\ttheme.fg(LOGO_GRADIENT[Math.min(i, LOGO_GRADIENT.length - 1)], line),\n\t\t);\n\t\tconst tagline =\n\t\t\taccent(\"Ada\") + dim(\" · coding agent · HOILAB TECH\") + muted(` v${this.version}`);\n\n\t\tlines.push(\"\");\n\n\t\tif (this.phase === \"login\") {\n\t\t\t// ---- Entry screen -------------------------------------------\n\t\t\tconst boxW = Math.min(56, width - 4);\n\t\t\tconst boxLines = box(\n\t\t\t\t[\n\t\t\t\t\t\"\",\n\t\t\t\t\t...logoLines,\n\t\t\t\t\ttagline,\n\t\t\t\t\t\"\",\n\t\t\t\t\tdim(\"Bienvenido a Ada — el agente de codificación de HOILAB TECH\"),\n\t\t\t\t\t\"\",\n\t\t\t\t\taccent(\"▸ \") + theme.bold(\"Entrar como invitado\"),\n\t\t\t\t\tmuted(\" Loguearme\") + dim(\" (próximamente)\"),\n\t\t\t\t\t\"\",\n\t\t\t\t],\n\t\t\t\tboxW,\n\t\t\t\t{ title: \" ✦ HOILAB TECH ✦ \" },\n\t\t\t);\n\t\t\tlines.push(...boxLines.map((l) => center(l)));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(center(success(\"●\") + dim(\" En línea · sin conexión a cuentas\") + muted(\" · todo queda en tu máquina\")));\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\n\t\t\t\tcenter(muted([\"Enter para continuar\", \"q para salir\"].join(\" · \"))),\n\t\t\t);\n\t\t\treturn this.finishRender(lines, width);\n\t\t}\n\n\t\t// ---- Home screen ------------------------------------------------\n\t\tconst boxW = Math.min(width - 4, 72);\n\n\t\t// Header box: logo + status\n\t\tconst statusParts = [\n\t\t\tdim(`model: ${this.defaultModelLabel()}`),\n\t\t\tdim(`cwd: ${this.cwdLabel()}`),\n\t\t\tdim(`memoria: ${this.memoryLabel()}`),\n\t\t\t\"\",\n\t\t];\n\t\tif (this.updateAvailable) {\n\t\t\tstatusParts.push(\n\t\t\t\twarning(\n\t\t\t\t\t`⚠ Nueva versión disponible: v${this.updateAvailable} ` +\n\t\t\t\t\t\taccent(\"[u] actualizar\") +\n\t\t\t\t\t\tdim(\" · q para ignorar\"),\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (this.updateChecked) {\n\t\t\tstatusParts.push(success(\"✓ Sistema actualizado\"));\n\t\t}\n\t\tlines.push(...box([\"\", ...logoLines, tagline, \"\", ...statusParts], boxW, { title: \" ✦ HOILAB TECH ✦ \" }).map((l) => center(l)));\n\t\tlines.push(\"\");\n\n\t\t// Conversations box\n\t\tconst convLines: string[] = [\"\"];\n\t\tconst isNew = this.selectedIndex === 0;\n\t\tconvLines.push(\n\t\t\t`${isNew ? accent(\"▸ \") : \" \"}${accent(\"✦\")} ${isNew ? theme.bold(\"Nueva conversación\") : \"Nueva conversación\"}`,\n\t\t);\n\t\tconvLines.push(\"\");\n\n\t\tif (this.loading) {\n\t\t\tconvLines.push(dim(\"Cargando conversaciones…\"));\n\t\t} else if (this.filtered.length === 0) {\n\t\t\tconvLines.push(\n\t\t\t\tmuted(\n\t\t\t\t\tthis.query\n\t\t\t\t\t\t? \"No hay conversaciones que coincidan con tu búsqueda\"\n\t\t\t\t\t\t: \"Todavía no hay conversaciones anteriores\",\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tconst maxVisible = Math.max(1, Math.min(12, Math.floor((width * 2) / 3)));\n\t\t\tconst visible = this.filtered.slice(0, maxVisible);\n\t\t\tfor (let i = 0; i < visible.length; i++) {\n\t\t\t\tconst session = visible[i];\n\t\t\t\tconst isSelected = this.selectedIndex === i + 1;\n\t\t\t\tconst title = sessionTitle(session);\n\t\t\t\tconst meta = muted(\n\t\t\t\t\t`${relativeTime(session.modified.toISOString())} · ${session.messageCount} msgs`,\n\t\t\t\t);\n\t\t\t\tconst arrow = isSelected ? accent(\"▸ \") : \" \";\n\t\t\t\tconst titleStyled = isSelected ? theme.bold(accent(title)) : title;\n\t\t\t\tconvLines.push(`${arrow}${titleStyled} ${meta}`);\n\t\t\t}\n\t\t\tif (this.filtered.length > maxVisible) {\n\t\t\t\tconvLines.push(dim(`… y ${this.filtered.length - maxVisible} más`));\n\t\t\t}\n\t\t}\n\t\tconvLines.push(\"\");\n\t\tlines.push(...box(convLines, boxW, { title: \" Conversaciones \" }).map((l) => center(l)));\n\t\tlines.push(\"\");\n\n\t\tconst hints = [\n\t\t\t\"↑/↓ navegar\",\n\t\t\t\"Enter seleccionar\",\n\t\t\t\"n nueva\",\n\t\t\tthis.updateAvailable ? \"u actualizar\" : null,\n\t\t\t\"q salir\",\n\t\t].filter((h): h is string => h !== null);\n\t\tlines.push(center(muted(hints.join(\" · \"))));\n\t\treturn this.finishRender(lines, width);\n\t}\n\n\t/** Vertical centering + truncation of every rendered line. */\n\tprivate finishRender(lines: string[], width: number): string[] {\n\t\tconst rows = process.stdout.rows ?? 24;\n\t\tconst contentHeight = lines.length;\n\t\tconst topPad = Math.min(3, Math.max(0, Math.floor((rows - contentHeight) / 3)));\n\t\treturn [...Array<string>(topPad).fill(\"\"), ...lines.map((line) => truncateToWidth(line, width))];\n\t}\n\n\tprivate defaultModelLabel(): string {\n\t\treturn this.modelLabel ?? \"no configurado (/model)\";\n\t}\n\n\tprivate cwdLabel(): string {\n\t\treturn this.cwdLabelValue ?? process.cwd();\n\t}\n\n\tprivate memoryLabel(): string {\n\t\treturn this.memoryEnabled ? \"activada\" : \"desactivada\";\n\t}\n}\n"]}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@hoilab/ada-cli",
3
- "version": "0.84.10",
3
+ "version": "0.84.12",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@hoilab/ada-cli",
9
- "version": "0.84.10",
9
+ "version": "0.84.12",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-agent-core": "^0.84.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoilab/ada-cli",
3
- "version": "0.84.10",
3
+ "version": "0.84.12",
4
4
  "description": "Ada CLI - coding agent CLI (rebranded fork of pi.dev) with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {