Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ User-facing changes to ConductLoop (the desktop app and its local server), newes

## Unreleased

- **Copy that is true on every system.** The welcome page said the AI key "is stored in the Keychain of this Mac", also on Linux and Windows (seen in the first Linux and Windows smoke tests). It now says the system keychain (the Keychain on a Mac) or an encrypted file. The same for the other "this Mac" / "este Mac" in the interface (Connectors, Learning, the feedback buttons, Servers, Media): "this computer" / "este ordenador". Nothing changes on the Mac except the wording.
- CI only: the "Windows bundles" workflow now runs `scripts/windows-smoke.ps1` on the NSIS installer: it installs it silently, starts the app as a new user, and checks the server, that `/api/platform` says Windows with the in-app browser and code execution off, the first run and welcome page, the window (with a screenshot), that the app and its server are still running 20 s later, that closing the window stops the server, and that **uninstalling keeps the user's data** (it lives in `%LOCALAPPDATA%\ConductLoop\data`, inside the install folder). Still informational (a runner has no real desktop session), but each failed check is now an error annotation on the run page, and the screenshot and log are kept for 3 days.
- CI only: the Linux bundles workflow now **starts the AppImage and the .deb** it builds, on Ubuntu 22.04 (the build image) and on ubuntu-latest, on a virtual display with an empty HOME and no keyring. `scripts/linux-smoke.sh` checks that the local server answers, that `/api/platform` says Linux with the in-app browser off, that it is a first run with the welcome page, that a ConductLoop window is on screen, and that closing the app stops the server; screenshots and logs are kept for 3 days. Until now the Linux packages were only built, never run. The script also works by hand on a Linux machine.
- CI only: a "Windows (compile and tests)" workflow checks on every relevant pull request that the desktop wrapper still compiles for Windows and that the Windows-safe part of the Python tests passes there. It builds no installer, signs nothing, publishes nothing and is not a required check. Windows is still not supported.
Expand Down
8 changes: 4 additions & 4 deletions ops_dashboard/web/connectors-guide.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
var UI = {
es: {
title: 'Guía: crea tu propia app OAuth (BYOK)',
intro: 'En esta versión cada conector usa el client ID de una app OAuth que creas tú en tu propia cuenta del proveedor. ConductLoop no tiene servidor ni app compartida: el token va del proveedor a este Mac y se guarda en el llavero.',
intro: 'En esta versión cada conector usa el client ID de una app OAuth que creas tú en tu propia cuenta del proveedor. ConductLoop no tiene servidor ni app compartida: el token va del proveedor a este ordenador y se guarda en el llavero.',
legend: '⚠️ = paso que no se ha podido confirmar en la documentación oficial del proveedor. Compruébalo en su consola antes de fiarte.',
steps: 'Pasos', redirect: 'Redirect (URI de redirección)', scopes: 'Permisos mínimos (scopes)',
read: 'lectura', write: 'escritura (más adelante, siempre con confirmación)', warnings: 'Advertencias',
sources: 'Documentación oficial', console: 'Abrir la consola del proveedor', manifest: 'Manifiesto para pegar'
},
en: {
title: 'Guide: create your own OAuth app (BYOK)',
intro: 'In this version every connector uses the client ID of an OAuth app you create in your own provider account. ConductLoop has no server and no shared app: the token goes from the provider to this Mac and is stored in the keychain.',
intro: 'In this version every connector uses the client ID of an OAuth app you create in your own provider account. ConductLoop has no server and no shared app: the token goes from the provider to this computer and is stored in the keychain.',
legend: '⚠️ = step that could not be confirmed in the provider\u2019s official documentation. Check it in their console before relying on it.',
steps: 'Steps', redirect: 'Redirect URI', scopes: 'Minimal permissions (scopes)',
read: 'read', write: 'write (later, always with confirmation)', warnings: 'Warnings',
Expand Down Expand Up @@ -84,8 +84,8 @@
warnings: [
{ es: 'Gmail: gmail.readonly (igual que gmail.compose, gmail.modify y gmail.metadata) es un scope RESTRINGIDO. Para publicar una app con él Google exige la verificación de scopes restringidos y, si los datos se guardan o transmiten en servidores, una evaluación de seguridad. Con tu propia app en «Testing» no hace falta verificarla, pero verás la pantalla de «app no verificada».',
en: 'Gmail: gmail.readonly (like gmail.compose, gmail.modify and gmail.metadata) is a RESTRICTED scope. Publishing an app with it requires restricted-scope verification and, if data is stored or transmitted on servers, a security assessment. Your own app in "Testing" needs no verification, but you will see the "unverified app" screen.' },
{ es: 'ConductLoop no envía tus correos a ningún servidor (todo se queda en este Mac). Si eso basta para que Google no exija la evaluación de seguridad a una app 100 % local no está documentado.',
en: 'ConductLoop does not send your email to any server (everything stays on this Mac). Whether that exempts a 100 % local app from the security assessment is not documented.', unverified: true },
{ es: 'ConductLoop no envía tus correos a ningún servidor (todo se queda en este ordenador). Si eso basta para que Google no exija la evaluación de seguridad a una app 100 % local no está documentado.',
en: 'ConductLoop does not send your email to any server (everything stays on this computer). Whether that exempts a 100 % local app from the security assessment is not documented.', unverified: true },
{ es: 'Tope de usuarios: en «Testing» caben como máximo 100 usuarios de prueba. Una app sin verificar que muestra la pantalla de «app no verificada» admite 100 usuarios nuevos en total durante toda la vida del proyecto, y ese tope no se puede reiniciar. Por eso cada usuario crea su propia app.',
en: 'User cap: "Testing" allows at most 100 test users. An unverified app that shows the "unverified app" screen accepts 100 new users in total over the whole life of the project, and the cap cannot be reset. That is why every user creates their own app.' },
{ es: 'En «Testing», la autorización (y el refresh token) caduca a los 7 días del consentimiento: tendrás que volver a pulsar «Conectar» cada semana.',
Expand Down
4 changes: 2 additions & 2 deletions ops_dashboard/web/connectors.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<header class="top">
<div>
<h1 data-i18n="title">Conectores</h1>
<p class="sub" data-i18n="subtitle">Conecta tus servicios. Los tokens se guardan solo en el llavero de este Mac.</p>
<p class="sub" data-i18n="subtitle">Conecta tus servicios. Los tokens se guardan solo en el llavero del sistema de este ordenador.</p>
</div>
<nav class="nav">
<a href="/" data-i18n="nav_home">Panel</a>
Expand All @@ -31,7 +31,7 @@ <h2 data-i18n="privacy">Privacidad y permisos</h2>
<li data-i18n="p_keychain">Tokens solo en el llavero del sistema; nunca en la base de datos ni en ficheros.</li>
<li data-i18n="p_scopes">Se piden los permisos mínimos: solo lectura salvo que actives la escritura.</li>
<li data-i18n="p_confirm">Cualquier escritura (enviar un correo, publicar un mensaje…) espera a que la confirmes aquí.</li>
<li data-i18n="p_telemetry">Sin telemetría: el registro de auditoría se queda en este Mac.</li>
<li data-i18n="p_telemetry">Sin telemetría: el registro de auditoría se queda en este ordenador.</li>
</ul>
<p class="hint" id="legacy-hint" hidden></p>
</div>
Expand Down
8 changes: 4 additions & 4 deletions ops_dashboard/web/connectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
var L = {
es: {
title: 'Conectores',
subtitle: 'Conecta tus servicios. Los tokens se guardan solo en el llavero de este Mac.',
subtitle: 'Conecta tus servicios. Los tokens se guardan solo en el llavero del sistema de este ordenador.',
nav_home: 'Panel',
keychain_off: 'No hay llavero del sistema disponible: no se puede conectar nada (los tokens nunca se guardan en un fichero).',
privacy: 'Privacidad y permisos',
p_keychain: 'Tokens solo en el llavero del sistema; nunca en la base de datos ni en ficheros.',
p_scopes: 'Se piden los permisos mínimos: solo lectura salvo que actives la escritura.',
p_confirm: 'Cualquier escritura (enviar un correo, publicar un mensaje…) espera a que la confirmes aquí.',
p_telemetry: 'Sin telemetría: el registro de auditoría se queda en este Mac.',
p_telemetry: 'Sin telemetría: el registro de auditoría se queda en este ordenador.',
legacy: 'Tienes {0} conexión(es) con token en la vista «Conexiones».',
pending: 'Pendiente de confirmar', no_pending: 'No hay escrituras pendientes.',
connectors: 'Conectores',
Expand Down Expand Up @@ -54,14 +54,14 @@
},
en: {
title: 'Connectors',
subtitle: 'Connect your services. Tokens are stored only in this Mac\u2019s keychain.',
subtitle: 'Connect your services. Tokens are stored only in the system keychain of this computer.',
nav_home: 'Dashboard',
keychain_off: 'No system keychain available: nothing can be connected (tokens are never stored in a file).',
privacy: 'Privacy & permissions',
p_keychain: 'Tokens only in the system keychain; never in the database or in files.',
p_scopes: 'Minimal permissions: read-only unless you enable write.',
p_confirm: 'Every write (sending an email, posting a message…) waits for your confirmation here.',
p_telemetry: 'No telemetry: the audit log stays on this Mac.',
p_telemetry: 'No telemetry: the audit log stays on this computer.',
legacy: 'You have {0} token connection(s) in the \u201cConnections\u201d view.',
pending: 'Waiting for confirmation', no_pending: 'No pending writes.',
connectors: 'Connectors',
Expand Down
8 changes: 4 additions & 4 deletions ops_dashboard/web/feedback-buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

var ES = /^es\b/i.test((navigator && navigator.language) || '');
var T = ES ? {
up: 'Útil', down: 'No útil', why: '¿Qué falló?', comment: 'Comentario (opcional, se queda en este Mac)',
send: 'Enviar', thanks: 'Gracias, guardado en este Mac.', lessons: 'Lecciones usadas: ', err: 'No se pudo guardar: ',
up: 'Útil', down: 'No útil', why: '¿Qué falló?', comment: 'Comentario (opcional, se queda en este ordenador)',
send: 'Enviar', thanks: 'Gracias, guardado en este ordenador.', lessons: 'Lecciones usadas: ', err: 'No se pudo guardar: ',
r_wrong: 'Incorrecta', r_missing_citation: 'Falta cita', r_bad_citation: 'Cita errónea',
r_outdated: 'Desactualizada', r_style: 'Estilo', r_unsafe: 'Insegura', r_other: 'Otro'
} : {
up: 'Helpful', down: 'Not helpful', why: 'What went wrong?', comment: 'Comment (optional, stays on this Mac)',
send: 'Send', thanks: 'Thanks, saved on this Mac.', lessons: 'Lessons used: ', err: 'Could not save: ',
up: 'Helpful', down: 'Not helpful', why: 'What went wrong?', comment: 'Comment (optional, stays on this computer)',
send: 'Send', thanks: 'Thanks, saved on this computer.', lessons: 'Lessons used: ', err: 'Could not save: ',
r_wrong: 'Wrong', r_missing_citation: 'Missing citation', r_bad_citation: 'Bad citation',
r_outdated: 'Outdated', r_style: 'Style', r_unsafe: 'Unsafe', r_other: 'Other'
};
Expand Down
6 changes: 3 additions & 3 deletions ops_dashboard/web/learning.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<header class="top">
<div>
<h1 data-i18n="title">Aprendizaje</h1>
<p class="sub" data-i18n="subtitle">Lo que le has dicho a ConductLoop sobre sus respuestas. Todo se guarda solo en este Mac.</p>
<p class="sub" data-i18n="subtitle">Lo que le has dicho a ConductLoop sobre sus respuestas. Todo se guarda solo en este ordenador.</p>
</div>
<nav class="nav">
<a href="/" data-i18n="nav_home">Panel</a>
Expand All @@ -38,7 +38,7 @@ <h2 data-i18n="privacy">Privacidad</h2>
<p class="hint" data-i18n="privacy_feedback">Las valoraciones 👍/👎 se guardan siempre en local cuando las pulsas. Nunca se envían a ningún sitio.</p>
<label class="check">
<input type="checkbox" id="failure-toggle" />
<span data-i18n="failure_toggle">Registrar fallos en este Mac</span>
<span data-i18n="failure_toggle">Registrar fallos en este ordenador</span>
</label>
<p class="hint" id="failure-hint" data-i18n="failure_hint">Desactivado por defecto. Solo guarda códigos de error (proveedor, modelo, tipo), nunca preguntas, respuestas ni notas. Se borran a los 30 días; al desactivarlo se borra todo.</p>
<div class="row">
Expand Down Expand Up @@ -196,7 +196,7 @@ <h2 data-i18n="m_title">¿Estoy aprendiendo bien?</h2>
<option value="90" data-i18n="m_90">90 días</option>
</select>
</div>
<p class="hint" data-i18n="m_hint">Calculado solo con los datos de este Mac. Con un único usuario son tendencias, no estadística: por debajo de 20 respuestas no se saca ninguna conclusión.</p>
<p class="hint" data-i18n="m_hint">Calculado solo con los datos de este ordenador. Con un único usuario son tendencias, no estadística: por debajo de 20 respuestas no se saca ninguna conclusión.</p>
<ul id="m-signals" class="list compact"></ul>
<div class="stats">
<div class="stat"><span class="num" id="m-down">—</span><span class="lbl" data-i18n="m_down">👎 por 100 respuestas</span></div>
Expand Down
12 changes: 6 additions & 6 deletions ops_dashboard/web/learning.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
var L = {
es: {
tab_metrics: '¿Aprendo bien?', m_title: '¿Estoy aprendiendo bien?', m_7: '7 días', m_30: '30 días', m_90: '90 días',
m_hint: 'Calculado solo con los datos de este Mac. Con un único usuario son tendencias, no estadística: por debajo de 20 respuestas no se saca ninguna conclusión.',
m_hint: 'Calculado solo con los datos de este ordenador. Con un único usuario son tendencias, no estadística: por debajo de 20 respuestas no se saca ninguna conclusión.',
m_down: '👎 por 100 respuestas', m_with: 'con lecciones', m_without: 'sin lecciones', m_details: 'Detalle', m_settings: 'Ajustes',
m_ab: 'Prueba A/B local: % de respuestas sin lecciones (0 = apagada)',
m_curator: 'Curador diario: proponer archivar skills sin uso en 60 días (nunca borra)',
Expand Down Expand Up @@ -82,11 +82,11 @@
trust_ph: '/ruta/al/repo', trust_add: 'Confiar', untrust: 'Quitar', no_trusted: 'Ningún repo marcado.',
s_vault: 'vault', s_agents_dir: '~/.agents', s_claude_dir: '~/.claude', s_project: 'proyecto',
title: 'Aprendizaje',
subtitle: 'Lo que le has dicho a ConductLoop sobre sus respuestas. Todo se guarda solo en este Mac.',
subtitle: 'Lo que le has dicho a ConductLoop sobre sus respuestas. Todo se guarda solo en este ordenador.',
nav_home: 'Panel', nav_ai: 'Conectar IA', summary: 'Resumen', failures_short: 'fallos',
privacy: 'Privacidad',
privacy_feedback: 'Las valoraciones 👍/👎 se guardan siempre en local cuando las pulsas. Nunca se envían a ningún sitio.',
failure_toggle: 'Registrar fallos en este Mac',
failure_toggle: 'Registrar fallos en este ordenador',
failure_hint: 'Desactivado por defecto. Solo guarda códigos de error (proveedor, modelo, tipo), nunca preguntas, respuestas ni notas. Se borran a los 30 días; al desactivarlo se borra todo.',
export: 'Exportar a un fichero local', export_comments: 'incluir comentarios',
exported: 'Exportado (no se ha enviado a ningún sitio): {0}',
Expand All @@ -103,7 +103,7 @@
},
en: {
tab_metrics: 'Am I learning?', m_title: 'Am I learning well?', m_7: '7 days', m_30: '30 days', m_90: '90 days',
m_hint: 'Computed only from the data on this Mac. With a single user these are trends, not statistics: below 20 answers no conclusion is drawn.',
m_hint: 'Computed only from the data on this computer. With a single user these are trends, not statistics: below 20 answers no conclusion is drawn.',
m_down: '👎 per 100 answers', m_with: 'with lessons', m_without: 'without lessons', m_details: 'Details', m_settings: 'Settings',
m_ab: 'Local A/B test: % of answers without lessons (0 = off)',
m_curator: 'Daily curator: propose archiving skills unused for 60 days (never deletes)',
Expand Down Expand Up @@ -172,11 +172,11 @@
trust_ph: '/path/to/repo', trust_add: 'Trust', untrust: 'Remove', no_trusted: 'No repo marked.',
s_vault: 'vault', s_agents_dir: '~/.agents', s_claude_dir: '~/.claude', s_project: 'project',
title: 'Learning',
subtitle: 'What you told ConductLoop about its answers. Everything stays on this Mac.',
subtitle: 'What you told ConductLoop about its answers. Everything stays on this computer.',
nav_home: 'Dashboard', nav_ai: 'Connect AI', summary: 'Summary', failures_short: 'failures',
privacy: 'Privacy',
privacy_feedback: '👍/👎 ratings are always stored locally when you click them. They are never sent anywhere.',
failure_toggle: 'Log failures on this Mac',
failure_toggle: 'Log failures on this computer',
failure_hint: 'Off by default. Stores error codes only (provider, model, kind), never questions, answers or notes. Deleted after 30 days; turning it off deletes everything.',
export: 'Export to a local file', export_comments: 'include comments',
exported: 'Exported (nothing was sent anywhere): {0}',
Expand Down
2 changes: 1 addition & 1 deletion ops_dashboard/web/media.html
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ <h1>Media</h1>
<div class="note">
ConductLoop asks for a <strong>capability</strong> — an image, a video, a voice —
and whichever provider is set up for it does the work. A provider can be a cloud
API or something running on this Mac; local ones are used first.
API or something running on this computer; local ones are used first.
</div>
<div class="providers" id="providerList"></div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions ops_dashboard/web/servers.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<body>
<div class="wrap">
<h1>🛰️ Servers</h1>
<p class="sub">What this app can talk to, and what is going to answer. The product asks for capabilities — chat, image, video, speech, search — never for a company: a server on this Mac, a service in the cloud or any OpenAI-compatible endpoint will do.</p>
<p class="sub">What this app can talk to, and what is going to answer. The product asks for capabilities — chat, image, video, speech, search — never for a company: a server on this computer, a service in the cloud or any OpenAI-compatible endpoint will do.</p>
<div style="display:flex;gap:14px;margin-bottom:18px;font-size:13px"><a href="/ai">Connect AI</a><a href="/media">Media</a><a href="/setup">Setup</a></div>

<div style="display:flex;gap:10px;margin-bottom:18px">
Expand Down Expand Up @@ -92,7 +92,7 @@ <h1>🛰️ Servers</h1>
const left = el('div');
const who = el('div', 'who');
who.appendChild(document.createTextNode(active.label || active.name));
if(active.local) who.appendChild(el('span', 'tag local', 'on this Mac'));
if(active.local) who.appendChild(el('span', 'tag local', 'on this computer'));
if(active.key && active.needs_key) who.appendChild(el('span', 'tag', 'key: ' + active.key));
left.appendChild(who);
const where = active.where || active.model || '';
Expand Down
2 changes: 1 addition & 1 deletion ops_dashboard/web/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h2 data-i18n="notes_title">1 · Your notes</h2>

<section class="card" id="step-key">
<h2 data-i18n="key_title">2 · AI key (optional)</h2>
<p class="hint" data-i18n="key_hint">Search and notes work without it. To chat and summarise, paste a key from your AI provider. It is stored in the Keychain of this Mac, or in an encrypted file if there is none, and it is never shown again.</p>
<p class="hint" data-i18n="key_hint">Search and notes work without it. To chat and summarise, paste a key from your AI provider. It is stored in the system keychain (the Keychain on a Mac), or in an encrypted file if there is none, and it is never shown again.</p>
<label for="provider" data-i18n="provider_label">Provider</label>
<select id="provider">
<option value="anthropic">Anthropic</option>
Expand Down
Loading
Loading