@hoilab/ada-cli 0.84.10 → 0.84.11
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,CAmI9B;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(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 \" }).map((l) => center(l)));\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(boxW - 2, width - 4))),\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.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,24 +256,23 @@ export class HomeScreenComponent extends Container {
|
|
|
256
256
|
return this.finishRender(lines, width);
|
|
257
257
|
}
|
|
258
258
|
// ---- Home screen ------------------------------------------------
|
|
259
|
-
const boxW = Math.min(
|
|
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
|
-
|
|
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
|
-
|
|
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 = [""];
|
|
@@ -306,7 +305,7 @@ export class HomeScreenComponent extends Container {
|
|
|
306
305
|
}
|
|
307
306
|
}
|
|
308
307
|
convLines.push("");
|
|
309
|
-
lines.push(...box(convLines, boxW, { title: " Conversaciones " }));
|
|
308
|
+
lines.push(...box(convLines, boxW, { title: " Conversaciones " }).map((l) => center(l)));
|
|
310
309
|
lines.push("");
|
|
311
310
|
// Search + hints
|
|
312
311
|
lines.push(center(accent("🔎") + dim(` Buscar: ${this.query}${this.searchInput.focused ? "▍" : ""}`)));
|
|
@@ -319,7 +318,7 @@ export class HomeScreenComponent extends Container {
|
|
|
319
318
|
"escribir para buscar",
|
|
320
319
|
"q salir",
|
|
321
320
|
].filter((h) => h !== null);
|
|
322
|
-
lines.push(border("─".repeat(Math.min(
|
|
321
|
+
lines.push(border("─".repeat(Math.min(boxW - 2, width - 4))));
|
|
323
322
|
lines.push(center(muted(hints.join(" · "))));
|
|
324
323
|
return this.finishRender(lines, width);
|
|
325
324
|
}
|
|
@@ -327,7 +326,7 @@ export class HomeScreenComponent extends Container {
|
|
|
327
326
|
finishRender(lines, width) {
|
|
328
327
|
const rows = process.stdout.rows ?? 24;
|
|
329
328
|
const contentHeight = lines.length;
|
|
330
|
-
const topPad = Math.max(0, Math.floor((rows - contentHeight) /
|
|
329
|
+
const topPad = Math.min(3, Math.max(0, Math.floor((rows - contentHeight) / 3)));
|
|
331
330
|
return [...Array(topPad).fill(""), ...lines.map((line) => truncateToWidth(line, width))];
|
|
332
331
|
}
|
|
333
332
|
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(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 \" }).map((l) => center(l)));\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(boxW - 2, width - 4))),\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.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"]}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hoilab/ada-cli",
|
|
3
|
-
"version": "0.84.
|
|
3
|
+
"version": "0.84.11",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@hoilab/ada-cli",
|
|
9
|
-
"version": "0.84.
|
|
9
|
+
"version": "0.84.11",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-agent-core": "^0.84.2",
|
package/package.json
CHANGED