shakers-cli 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -5
- package/bin/add-agent.js +12 -6
- package/bin/ai-usage.js +2 -1
- package/bin/apply.js +66 -0
- package/bin/command-audit-worker.js +19 -0
- package/bin/login.js +4 -8
- package/bin/mcp.js +32 -19
- package/bin/register.js +10 -29
- package/bin/shakers-cli.js +21 -12
- package/package.json +1 -1
- package/src/agents-client.js +1 -0
- package/src/ai-usage-review.js +5 -3
- package/src/apply-client.js +164 -0
- package/src/apply-flow.js +105 -0
- package/src/auth-client.js +7 -107
- package/src/auth-session-store.js +6 -12
- package/src/backend-request.js +1 -24
- package/src/cli-skill.js +77 -0
- package/src/command-audit.js +58 -5
- package/src/config.js +15 -16
- package/src/consent-flow.js +7 -2
- package/src/detect-repos.js +4 -8
- package/src/detected-agents.js +40 -0
- package/src/detectors.js +23 -0
- package/src/device-auth-store.js +2 -2
- package/src/device-login.js +11 -9
- package/src/env-paths.js +9 -1
- package/src/i18n.js +258 -88
- package/src/mcp-ai-usage-result-tool.js +6 -4
- package/src/mcp-ai-usage-tool.js +73 -47
- package/src/mcp-apply-tools.js +152 -0
- package/src/mcp-choice.js +171 -34
- package/src/mcp-detector.js +26 -2
- package/src/mcp-device-login-tools.js +40 -8
- package/src/mcp-install.js +15 -11
- package/src/mcp-instructions.js +43 -17
- package/src/mcp-onboarding-tools.js +90 -3
- package/src/mcp-prompts.js +6 -4
- package/src/mcp-register-tools.js +25 -14
- package/src/mcp-role-tools.js +35 -17
- package/src/mcp-server-name.js +7 -0
- package/src/mcp-server.js +35 -7
- package/src/mcp-signup-client.js +3 -6
- package/src/mcp-signup-flow.js +389 -0
- package/src/mcp-signup-tools.js +237 -126
- package/src/onboarding-flow.js +30 -125
- package/src/opencode-sessions.js +92 -0
- package/src/profile-agents.js +26 -0
- package/src/saved-positions-flow.js +3 -3
- package/src/scanner.js +104 -12
- package/src/session-gate.js +1 -4
- package/src/session-normalizers.js +114 -8
- package/src/session-refresh.js +5 -16
- package/src/session-scan.js +167 -22
- package/src/share-payload.js +4 -1
- package/src/share.js +2 -2
- package/src/signup-client.js +12 -39
- package/src/signup-copy.js +506 -68
- package/src/skill-install.js +102 -0
- package/src/start-add-agents.js +106 -3
- package/src/tier-engine.js +14 -2
- package/src/trust-narration.js +32 -0
- package/src/usage-run-steps.js +16 -4
- package/src/usage-scan.js +3 -0
- package/src/brand-svg.js +0 -9
- package/src/inter-fonts.js +0 -6
- package/src/mcp-auth-form.js +0 -484
package/src/i18n.js
CHANGED
|
@@ -15,13 +15,10 @@ const catalogs = {
|
|
|
15
15
|
askCv: 'Ruta a tu CV en PDF (opcional, Enter para omitir):',
|
|
16
16
|
askGithub: 'Tu URL de GitHub (opcional, Enter para omitir):',
|
|
17
17
|
askWebsite: 'Tu web personal (opcional, Enter para omitir):',
|
|
18
|
-
importStarted: 'Importando tu perfil en segundo plano mientras continuamos…',
|
|
19
|
-
importError: 'No se pudo iniciar la importacion de tu perfil.',
|
|
20
18
|
importUnavailable: 'No pudimos importar tu perfil ahora (servicio no disponible); seguimos con el registro, puedes reintentar el import mas tarde.',
|
|
21
19
|
importChecking: 'Importando tu perfil…',
|
|
22
20
|
importDone: 'Perfil importado correctamente.',
|
|
23
21
|
importFailed: 'No se pudo completar la importacion de tu perfil. Puedes reintentarla mas tarde desde tu perfil.',
|
|
24
|
-
importStillRunning: 'Tu perfil se sigue importando en segundo plano; estara listo en unos minutos.',
|
|
25
22
|
professionalTitle: 'Tu situacion laboral',
|
|
26
23
|
askWorkSituation: 'Cual es tu situacion laboral actual? Elige una opcion:',
|
|
27
24
|
workSituationLabels: {
|
|
@@ -54,27 +51,13 @@ const catalogs = {
|
|
|
54
51
|
professionalSaved: 'Situación laboral guardada.',
|
|
55
52
|
chooseMethodHeading: '¿Cómo quieres crear tu cuenta?',
|
|
56
53
|
signupTitle: 'Crea tu cuenta de Shakers',
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
askPassword: 'Contrasena (minimo 8 caracteres):',
|
|
61
|
-
askPasswordConfirm: 'Repite la contrasena:',
|
|
62
|
-
passwordMismatch: 'Las contrasenas no coinciden. Intentalo de nuevo.',
|
|
63
|
-
askFreelanceTypeSelect: 'Como trabajas? Elige una opcion:',
|
|
64
|
-
freelanceTypeLabels: {
|
|
65
|
-
FREELANCE: 'Freelance',
|
|
66
|
-
EMPLOYEE: 'Empleado/a',
|
|
67
|
-
AGENCY: 'Agencia o empresa',
|
|
68
|
-
POTENTIAL_FREELANCE: 'Me planteo ser freelance',
|
|
69
|
-
},
|
|
70
|
-
invalidChoice: 'Opcion no valida.',
|
|
71
|
-
askNewsletter: 'Quieres recibir la newsletter? (s/n):',
|
|
72
|
-
weakPassword: 'La contrasena no cumple los requisitos (minimo 8 caracteres).',
|
|
54
|
+
termsAsk: '¿Aceptas, para crear tu cuenta? [s/N]',
|
|
55
|
+
termsDeclined: 'Sin aceptar los Términos y la Política de Privacidad no se puede crear tu cuenta. No se ha creado nada ni se ha enviado nada a Shakers.',
|
|
56
|
+
newsletterAsk: (label) => `Opcional: ${label} [s/N]`,
|
|
73
57
|
signupError: 'No se pudo crear la cuenta.',
|
|
74
58
|
freelanceIntentRequired: 'Tu intencion freelance es obligatoria para ese tipo.',
|
|
75
|
-
accountExists: 'Ya
|
|
76
|
-
accountReady: 'Cuenta creada.
|
|
77
|
-
sessionError: 'La cuenta se creo pero no se pudo iniciar sesion. Ejecuta `shakers login`.',
|
|
59
|
+
accountExists: 'Ya tenías una cuenta en Shakers: has iniciado sesión con ella en este equipo.',
|
|
60
|
+
accountReady: 'Cuenta creada. Sesión iniciada solo en este equipo (~/.config/shakers); para cerrarla: `shakers logout`.',
|
|
78
61
|
pricingTitle: 'Tu precio por proyecto',
|
|
79
62
|
pricingSaved: 'Precio guardado.',
|
|
80
63
|
askPricingFullAmount: (cur) => `Precio por proyecto a jornada completa en ${cur} (numero, sin separadores de miles, p.ej. 60000):`,
|
|
@@ -149,7 +132,6 @@ const catalogs = {
|
|
|
149
132
|
repeatNotFound: 'No tienes un onboarding todavía. Haz `shakers onboarding` primero.',
|
|
150
133
|
repeatAuthError: 'Tu sesión no permite esta acción. Inicia sesión de nuevo: shakers login',
|
|
151
134
|
repeatFailed: (reason) => `No se pudo reiniciar el onboarding (${reason}). Inténtalo de nuevo.`,
|
|
152
|
-
interviewAnswer: 'Tu respuesta:',
|
|
153
135
|
questionHeading: (n) => `Pregunta ${n}`,
|
|
154
136
|
interviewTurnError: 'No se pudo continuar la entrevista.',
|
|
155
137
|
thinking: 'Alma esta pensando…',
|
|
@@ -207,7 +189,7 @@ const catalogs = {
|
|
|
207
189
|
t2Met: (n) => `Dispones de al menos un fichero de contexto persistente — instrucciones, configuración o reglas — para alguna herramienta (tienes ${n}).`,
|
|
208
190
|
t3Met: (n) => `Tienes al menos un servidor MCP conectado, dando a la IA acceso a datos o herramientas externas (tienes ${n}).`,
|
|
209
191
|
t4Met: (n) => `Has creado activos propios — skills, comandos o reglas personalizadas — más allá de la configuración por defecto (tienes ${n}).`,
|
|
210
|
-
t5Met: (hasAgentic, mcp, custom) => `Operas con una CLI agéntica (Claude Code, Aider, Gemini CLI, Codex CLI o Amazon Q Developer) combinada con MCP y activos propios (${mcp} servidores MCP y ${custom} activos propios).`,
|
|
192
|
+
t5Met: (hasAgentic, mcp, custom) => `Operas con una CLI agéntica (Claude Code, Aider, Gemini CLI, Codex CLI, Pi, OpenCode o Amazon Q Developer) combinada con MCP y activos propios (${mcp} servidores MCP y ${custom} activos propios).`,
|
|
211
193
|
t6Met: (n) => `Tienes un equipo de al menos 2 agentes especializados definidos (tienes ${n}).`,
|
|
212
194
|
t7Met: (n) => `Tienes automatización basada en hooks configurada (tienes ${n}).`,
|
|
213
195
|
t1Blocking: (n) => `Para subir a T1 (Primera herramienta) necesitas al menos una herramienta de IA detectada — ahora tienes ${n}.`,
|
|
@@ -216,7 +198,7 @@ const catalogs = {
|
|
|
216
198
|
t4Blocking: (n) => `Para subir a T4 (Herramienta propia) necesitas crear al menos un activo propio — skill, comando o regla — más allá de la configuración por defecto — ahora tienes ${n}.`,
|
|
217
199
|
t5Blocking: (hasAgentic, mcp, custom) => {
|
|
218
200
|
const missing = [];
|
|
219
|
-
if (!hasAgentic) missing.push('una CLI agéntica (Claude Code, Aider, Gemini CLI, Codex CLI o Amazon Q Developer)');
|
|
201
|
+
if (!hasAgentic) missing.push('una CLI agéntica (Claude Code, Aider, Gemini CLI, Codex CLI, Pi, OpenCode o Amazon Q Developer)');
|
|
220
202
|
if (mcp < 1) missing.push('al menos 1 servidor MCP');
|
|
221
203
|
if (custom < 1) missing.push('al menos 1 activo propio (skill, comando o regla)');
|
|
222
204
|
return `Para subir a T5 (Operador agéntico) te falta: ${missing.join('; ')}.`;
|
|
@@ -536,9 +518,9 @@ const catalogs = {
|
|
|
536
518
|
'Esto mide tu fluidez con IA en dos ejes: Setup (madurez de tu tooling, T0–T7, determinista) y Usage (cómo lo usas, evaluado en entrevista + código). Te sitúa en el mapa 3×3 (Explorer → AI Native). Completarlo posiciona tu perfil agéntico para los proyectos que valoran cómo trabajas con IA. Por defecto leo el uso de IA de todo este equipo y asumo que es tuyo (un equipo = tú).',
|
|
537
519
|
// Terminal progress feedback: stderr-only status
|
|
538
520
|
// during the two slow phases (see src/terminal-progress.js).
|
|
539
|
-
scanningLabel: '
|
|
521
|
+
scanningLabel: 'Leyendo en este equipo la configuración de tus herramientas de IA y tus proyectos (todavía no sale nada de tu equipo)…',
|
|
540
522
|
// Loader de la fase de agregación por repo seleccionado (git + sesiones + steering/decisiones + evidencia + org-chart de agentes).
|
|
541
|
-
aggregatingLabel: '
|
|
523
|
+
aggregatingLabel: 'Leyendo el historial de git y de sesiones de IA de los repos elegidos para sacar señales (todavía no sale nada de tu equipo)…',
|
|
542
524
|
reposScopePromptHeader: '¿Qué quieres evaluar?',
|
|
543
525
|
reposScopePromptHint: 'Flechas para moverte · enter para elegir',
|
|
544
526
|
reposScopeOptionMachine: 'Toda la máquina (todos los repos con actividad de IA)',
|
|
@@ -621,10 +603,20 @@ const catalogs = {
|
|
|
621
603
|
persistIntro:
|
|
622
604
|
'Este informe se ha generado y mostrado en tu equipo, siempre. '
|
|
623
605
|
+ 'Guardarlo en Shakers es opcional y revocable en cualquier momento '
|
|
624
|
-
+ '(usage --consent-revoke)
|
|
606
|
+
+ '(usage --consent-revoke). Se envían tu nivel/tier, señales '
|
|
625
607
|
+ 'estructuradas derivadas (herramientas, MCP, memoria, '
|
|
626
|
-
+ 'automatizaciones, agentes, tecnologías)
|
|
627
|
-
+ 'tus
|
|
608
|
+
+ 'automatizaciones, agentes, tecnologías) y texto literal: '
|
|
609
|
+
+ 'fragmentos de tus conversaciones con asistentes de IA (las de los '
|
|
610
|
+
+ 'repositorios analizados, o todas las de este equipo si lo analizas '
|
|
611
|
+
+ 'entero), comandos de muestra y las definiciones de tus agentes, '
|
|
612
|
+
+ 'tras quitar lo que parezca un secreto. Antes de cada subida verás '
|
|
613
|
+
+ 'qué se envía. Un '
|
|
614
|
+
+ 'modelo de IA de un proveedor externo (OpenAI, Google o Anthropic) '
|
|
615
|
+
+ 'lo analiza por encargo de Shakers para calcular tu evaluación y '
|
|
616
|
+
+ 'lo descarta: solo se guarda el resultado (niveles, puntuaciones, '
|
|
617
|
+
+ 'recuentos y los nombres de tus herramientas y agentes). No lo uses '
|
|
618
|
+
+ 'en equipos o conversaciones con datos que no puedas compartir (de clientes, '
|
|
619
|
+
+ 'de tu empresa o de terceros). '
|
|
628
620
|
+ 'Esta misma decisión también autoriza, solo si aceptas, que un '
|
|
629
621
|
+ 'proveedor externo de observabilidad (Datadog) capture el contenido '
|
|
630
622
|
+ 'que envían las llamadas de IA opcionales de este CLI (código '
|
|
@@ -657,6 +649,9 @@ const catalogs = {
|
|
|
657
649
|
nonInteractiveWarning:
|
|
658
650
|
'Entrada no interactiva (no-TTY) detectada: si no llega ninguna respuesta por stdin, '
|
|
659
651
|
+ 'el consentimiento no se guardará esta vez y se te volverá a preguntar la próxima vez.',
|
|
652
|
+
nonInteractiveUnanswered:
|
|
653
|
+
'No ha llegado ninguna respuesta, así que tu consentimiento sigue sin decidir y no se ha guardado ni enviado nada a Shakers. '
|
|
654
|
+
+ 'Ejecuta `shakers ai-usage` en tu propia terminal para responder.',
|
|
660
655
|
status: {
|
|
661
656
|
heading: 'Estado del consentimiento (guardado en Shakers)',
|
|
662
657
|
decisionGranted: 'Decisión: concedido (granted)',
|
|
@@ -828,6 +823,42 @@ const catalogs = {
|
|
|
828
823
|
faqsHeading: 'Preguntas frecuentes',
|
|
829
824
|
done: 'Detalle completado.',
|
|
830
825
|
},
|
|
826
|
+
apply: {
|
|
827
|
+
help:
|
|
828
|
+
'apply — aplica a un proyecto/posición con tu mensaje y tus respuestas a sus preguntas.\n\n'
|
|
829
|
+
+ 'Uso:\n apply <número|id> [--lang es|en]\n\n'
|
|
830
|
+
+ 'Requiere una sesión activa (shakers login) y una terminal interactiva.\n',
|
|
831
|
+
loginRequired: '"apply" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
|
|
832
|
+
needsInteractive: 'Aplicar necesita una terminal interactiva: te pido tu mensaje y tus respuestas, y que confirmes antes de enviar. Desde un asistente de IA, usa la herramienta MCP apply_to_project.',
|
|
833
|
+
idRequired: 'Falta el proyecto. Uso: apply <número|id>.',
|
|
834
|
+
refNoCache: 'No hay un listado reciente. Ejecuta primero shakers find-projects y usa el número que aparece (o pasa un id).',
|
|
835
|
+
refOutOfRange: (count) => `Ese número no está en el último listado (hay ${count}). Ejecuta shakers find-projects otra vez.`,
|
|
836
|
+
loading: 'Cargando las preguntas de la candidatura…',
|
|
837
|
+
fetchFailed: (reason) => `No se pudieron obtener las preguntas (${reason}). Inténtalo de nuevo en un momento.`,
|
|
838
|
+
notFound: 'No se encontró ese proyecto/posición.',
|
|
839
|
+
notOpen: 'Este proyecto no admite tu candidatura ahora mismo: ya aplicaste, está cerrado o no está disponible para ti.',
|
|
840
|
+
untitled: 'Sin título',
|
|
841
|
+
companyLine: (name) => `Empresa: ${name}`,
|
|
842
|
+
mainMotivationFallback: '¿Cuál es tu principal motivación para aplicar?',
|
|
843
|
+
askMessage: (question) => `${question} (tu mensaje para el equipo; enter para dejarlo en blanco):`,
|
|
844
|
+
askOpen: (question) => `${question} (enter para no responder):`,
|
|
845
|
+
choiceHint: 'Flechas ↑/↓ para moverte · enter para elegir',
|
|
846
|
+
skipChoice: 'No responder',
|
|
847
|
+
summaryTitle: 'Esto es lo que se enviará',
|
|
848
|
+
titleLine: (title) => `Proyecto: ${title}`,
|
|
849
|
+
messageLine: (message) => `Mensaje: ${message}`,
|
|
850
|
+
empty: '(vacío)',
|
|
851
|
+
answerLine: (question, answer) => `${question}: ${answer}`,
|
|
852
|
+
sendNotice: (title) => `Se envían tu mensaje y tus respuestas para «${title}»: el cliente verá tu perfil de Shakers y se abre un chat con el equipo. Tu perfil no cambia.`,
|
|
853
|
+
reviewNotice: 'En este proyecto Shakers revisa tu candidatura antes de que la vea el cliente.',
|
|
854
|
+
confirm: '¿Enviar la candidatura? (s/n):',
|
|
855
|
+
cancelled: 'Cancelado. No se ha enviado nada.',
|
|
856
|
+
sending: 'Enviando tu candidatura…',
|
|
857
|
+
sent: 'Candidatura enviada. Puedes seguirla con shakers applications.',
|
|
858
|
+
sentPending: 'Candidatura enviada. Shakers la revisa antes de que la vea el cliente; puedes seguirla con shakers applications.',
|
|
859
|
+
alreadyApplied: (status) => (status ? `Ya aplicaste a este proyecto (estado: ${status}).` : 'Ya aplicaste a este proyecto.'),
|
|
860
|
+
failed: (reason) => `No se pudo enviar la candidatura (${reason}). Inténtalo de nuevo en un momento.`,
|
|
861
|
+
},
|
|
831
862
|
savedPositions: {
|
|
832
863
|
helpSave: 'save-project — guarda un proyecto/posición en tus guardados.\n\nUso:\n save-project <número|id> [--json]\n\nRequiere una sesión activa (shakers login).',
|
|
833
864
|
helpUnsave: 'unsave-project — quita un proyecto/posición de tus guardados.\n\nUso:\n unsave-project <número|id> [--json]\n\nRequiere una sesión activa (shakers login).',
|
|
@@ -994,6 +1025,20 @@ const catalogs = {
|
|
|
994
1025
|
noneFound: 'No he encontrado ninguna app de IA compatible en esta máquina.',
|
|
995
1026
|
failedAll: 'No he podido conectar Shakers a tus apps de IA. Vuelve a ejecutar el instalador para reintentarlo.',
|
|
996
1027
|
},
|
|
1028
|
+
skillInstall: {
|
|
1029
|
+
title: 'Instalando la skill shakers-cli para tus agentes de IA',
|
|
1030
|
+
agents: { claudeCode: 'Claude Code', codex: 'Codex' },
|
|
1031
|
+
status: { installed: 'instalada', failed: 'no se pudo instalar' },
|
|
1032
|
+
found: (agents) => `He encontrado: ${agents}.`,
|
|
1033
|
+
confirm: '¿Instalo la skill para que tu agente sepa usar el CLI de Shakers? [S/n]',
|
|
1034
|
+
declined: 'No he tocado nada. Para instalarla más tarde: shakers skill install',
|
|
1035
|
+
noTerminal: 'No hay una terminal donde preguntarte, así que no he tocado nada.',
|
|
1036
|
+
yesHint: 'Para instalarla sin preguntar (por ejemplo, desde un asistente de IA): shakers skill install --yes',
|
|
1037
|
+
noneFound: 'No he encontrado Claude Code ni Codex en esta máquina; no he tocado nada.',
|
|
1038
|
+
done: (agents) => `Listo. Si ${agents} no ve la skill, abre una sesión nueva.`,
|
|
1039
|
+
failedAll: 'No he podido instalar la skill. Vuelve a ejecutar shakers skill install para reintentarlo.',
|
|
1040
|
+
help: 'skill install — instala la skill shakers-cli, que enseña a tu agente de IA (Claude Code, Codex) a usar este CLI.\n\nUso:\n shakers skill install pregunta en la terminal e instala en los agentes encontrados\n shakers skill install --yes instala sin preguntar (-y; para asistentes de IA y scripts)\n shakers skill install --json imprime el resultado como un único objeto JSON\n\nSin --yes y sin terminal no toca nada. Solo escribe ~/.claude/skills/shakers-cli/SKILL.md y <CODEX_HOME>/skills/shakers-cli/SKILL.md.',
|
|
1041
|
+
},
|
|
997
1042
|
rate: {
|
|
998
1043
|
help: 'rate — ver o fijar tu tarifa por proyecto.\n\nUso:\n rate [--lang es|en] [--json] ver tu tarifa\n rate --set [--lang es|en] fijarla (interactivo, con confirmación)\n\nRequiere una sesión activa (shakers login).',
|
|
999
1044
|
loginRequired: '"rate" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
|
|
@@ -1218,6 +1263,48 @@ const catalogs = {
|
|
|
1218
1263
|
remediationCopiedLabel: 'Copiado ✓',
|
|
1219
1264
|
},
|
|
1220
1265
|
},
|
|
1266
|
+
trust: {
|
|
1267
|
+
detectedAgents: 'Si confirmas, añado a tu perfil de Shakers los agentes marcados, solo su nombre y su descripción, y los clientes los verán en tu perfil. No leo ni subo nada más de este ordenador. Puedes quitarlos cuando quieras desde tu perfil en la web de Shakers.',
|
|
1268
|
+
uploadWarning: 'Antes de aprobar: se enviarían hasta 40 extractos literales de tus mensajes (correcciones y decisiones) y 20 comandos, de 200 caracteres como máximo cada uno, la configuración y la definición de tus agentes y recuentos de actividad. Se quita lo que parece un secreto, un email o una ruta, pero el filtro es aproximado: no lo apruebes si hay datos que no puedes compartir (de clientes, de tu empresa o de terceros).',
|
|
1269
|
+
cli: {
|
|
1270
|
+
'ai-usage': { before: 'Voy a analizar en este ordenador tus herramientas de IA, el historial de tus proyectos de código y tus conversaciones con asistentes de programación con IA (Claude Code, Codex, Gemini, Cursor, Continue, Cline/Roo, Aider, Pi, OpenCode). Si analizas un repo, solo cubre las conversaciones de ese repo; si eliges toda la máquina o es tu alta, todas las de este equipo. Antes de enviar nada a Shakers te enseño qué se enviaría y te pregunto. No lo uses en un equipo ni con conversaciones que tengan datos que no puedes compartir (de clientes, de tu empresa o de terceros).', after: 'Hecho. Si aprobaste la subida, un modelo de IA de un proveedor externo (OpenAI, Google o Anthropic) analiza lo enviado por encargo de Shakers para calcular tu evaluación y después se descarta; solo se guarda el resultado (niveles, puntuaciones, recuentos y los nombres de tus herramientas y agentes). Si no la aprobaste, no se ha subido nada a tu perfil. Revisión humana: «Solicitar revisión humana» en la web o talent@shakersworks.com; para pedir que se borre lo enviado, el mismo correo. Para dejar de enviar desde este equipo: `shakers ai-usage --consent-revoke`.' },
|
|
1271
|
+
certify: { before: 'Voy a preparar la certificación de tu rol principal con Shakers: te explico cada paso y te pregunto antes de enviar nada.', after: 'Hecho. Lo enviado queda en tu cuenta de Shakers.' },
|
|
1272
|
+
share: { before: 'Voy a crear en este ordenador una tarjeta con tu informe de IA para compartir. No envío nada.', after: 'Hecho. La tarjeta está en este ordenador; no se ha enviado nada.' },
|
|
1273
|
+
report: { before: 'Voy a leer tu informe de IA (de Shakers o de tu último análisis en este ordenador) y a guardarlo como archivo en este ordenador. No cambio tu perfil.' },
|
|
1274
|
+
'add-skill': { before: 'Voy a leer las skills de tu último análisis en Shakers y a añadir a tu perfil las que elijas.', after: 'Hecho. Tu perfil de Shakers tiene las skills que elegiste.' },
|
|
1275
|
+
'add-agent': { before: 'Voy a leer los agentes de tu último análisis en Shakers y a añadir a tu perfil el que elijas, con la descripción que apruebes, o todos los nuevos de una vez si lo eliges.', after: 'Hecho. Tu perfil de Shakers tiene los agentes que elegiste.' },
|
|
1276
|
+
'add-project': { before: 'Voy a leer el nombre de esta carpeta, la dirección web de su código y las fechas de su primer y último cambio, y te pregunto antes de enviarlos a tu portfolio de Shakers. No envío tu código.', after: 'Hecho. El proyecto está en tu portfolio de Shakers.' },
|
|
1277
|
+
'add-role': { before: 'Voy a leer los roles de Shakers y a añadir a tu perfil el que elijas.', after: 'Hecho. Tu perfil de Shakers tiene el rol que elegiste.' },
|
|
1278
|
+
'change-role': { before: 'Voy a leer tus roles de Shakers y a guardar como principal el que elijas.', after: 'Hecho. Tu rol principal está guardado en Shakers.' },
|
|
1279
|
+
'find-projects': { before: 'Solo leo de Shakers los proyectos que encajan contigo; no cambio nada.' },
|
|
1280
|
+
'show-project': { before: 'Solo leo de Shakers el detalle del proyecto; no cambio nada.' },
|
|
1281
|
+
apply: { before: 'Voy a leer de Shakers las preguntas de este proyecto y, si confirmas, enviar tu mensaje y tus respuestas: el cliente verá tu perfil de Shakers y se abre un chat con el equipo. Si el proyecto lo pide, Shakers revisa tu candidatura antes de que la vea el cliente. No cambio tu perfil.', after: 'Hecho. Tu candidatura está en Shakers; puedes seguirla con shakers applications.' },
|
|
1282
|
+
'save-project': { before: 'Voy a guardar este proyecto en tus proyectos guardados de Shakers.', after: 'Hecho. El proyecto está en tus guardados.' },
|
|
1283
|
+
'unsave-project': { before: 'Voy a quitar este proyecto de tus proyectos guardados de Shakers.', after: 'Hecho. El proyecto ya no está en tus guardados.' },
|
|
1284
|
+
invitations: { before: 'Solo leo tus invitaciones de Shakers; no cambio nada.' },
|
|
1285
|
+
applications: { before: 'Solo leo tus candidaturas de Shakers; no cambio nada.' },
|
|
1286
|
+
availability: { before: 'Solo leo tu disponibilidad de tu perfil de Shakers; no cambio nada.' },
|
|
1287
|
+
'availability:set': { before: 'Voy a cambiar tu disponibilidad en tu perfil de Shakers.', after: 'Hecho. Tu disponibilidad está guardada en Shakers.' },
|
|
1288
|
+
certifications: { before: 'Solo leo tus certificaciones de Shakers; no cambio nada.' },
|
|
1289
|
+
me: { before: 'Solo leo tu perfil de Shakers; no cambio nada.' },
|
|
1290
|
+
rate: { before: 'Solo leo tu tarifa de tu perfil de Shakers; no cambio nada.' },
|
|
1291
|
+
'rate:set': { before: 'Voy a cambiar tu tarifa en tu perfil de Shakers.', after: 'Hecho. Tu tarifa está guardada en Shakers.' },
|
|
1292
|
+
lang: { before: 'Solo leo tus idiomas de tu perfil de Shakers; no cambio nada.' },
|
|
1293
|
+
'lang:set': { before: 'Voy a cambiar tus idiomas en tu perfil de Shakers.', after: 'Hecho. Tus idiomas están guardados en Shakers.' },
|
|
1294
|
+
socials: { before: 'Solo leo tus redes de tu perfil de Shakers; no cambio nada.' },
|
|
1295
|
+
'socials:set': { before: 'Voy a cambiar tus redes en tu perfil de Shakers.', after: 'Hecho. Tus redes están guardadas en Shakers.' },
|
|
1296
|
+
experiences: { before: 'Solo leo tus experiencias de tu perfil de Shakers; no cambio nada.' },
|
|
1297
|
+
portfolios: { before: 'Solo leo tu portfolio de tu perfil de Shakers; no cambio nada.' },
|
|
1298
|
+
alma: { before: 'Voy a enviar tus mensajes a Alma, la asistente de Shakers. Si propone un cambio en tu perfil, te pregunto antes de hacerlo.' },
|
|
1299
|
+
register: { before: 'Voy a crear tu cuenta de Shakers: te pido aquí que aceptes los Términos y te abro una página de Shakers (shakersworks.com) con un código; tu contraseña solo se escribe allí. Cada paso que envíe datos te lo digo antes.' },
|
|
1300
|
+
onboarding: { before: 'Voy a hacer contigo la entrevista de onboarding: tus respuestas se envían a Shakers para conocer tu perfil. No leo nada de tu ordenador.', after: 'Hecho. Tu entrevista está guardada en Shakers.' },
|
|
1301
|
+
config: { before: 'Trabajo solo con la configuración del CLI en este ordenador (~/.config/shakers); no envío nada a Shakers.' },
|
|
1302
|
+
update: { before: 'Voy a comprobar si hay una versión nueva del CLI y, si la hay, a reemplazar sus archivos instalados en este ordenador. No toco tus proyectos ni tu sesión.' },
|
|
1303
|
+
logout: { before: 'Voy a cerrar tu sesión: aviso a Shakers y borro la sesión y el consentimiento guardados en este ordenador (~/.config/shakers). No cambio tu perfil.' },
|
|
1304
|
+
mcp: { before: 'Voy a añadir el servidor MCP de Shakers a la configuración de tus apps de IA en este ordenador (por ejemplo ~/.cursor/mcp.json o ~/.codex/config.toml). No envío nada a Shakers.', after: 'Hecho. Solo han cambiado los archivos de configuración que se listan arriba.' },
|
|
1305
|
+
skill: { before: 'Voy a escribir la skill del CLI de Shakers en las carpetas de skills de tus agentes en este ordenador (~/.claude/skills o ~/.codex/skills). No envío nada a Shakers.', after: 'Hecho. Solo han cambiado los archivos que se listan arriba.' },
|
|
1306
|
+
},
|
|
1307
|
+
},
|
|
1221
1308
|
// Branded mini-shell chrome.
|
|
1222
1309
|
login: {
|
|
1223
1310
|
intro: 'Inicia sesión con tu email y contraseña de Shakers.',
|
|
@@ -1231,26 +1318,12 @@ const catalogs = {
|
|
|
1231
1318
|
expiresAt: (iso) => `La sesión caduca: ${iso}. Cuando expire te lo diré y podrás volver a entrar con \`login\`.`,
|
|
1232
1319
|
loggedOut: 'Sesión cerrada. Vuelves a ver las sugerencias de mejora en tu informe.',
|
|
1233
1320
|
notLoggedIn: 'No había ninguna sesión iniciada. No hay nada que cerrar.',
|
|
1234
|
-
errorInvalidCredentials: 'Credenciales incorrectas: revisa tu email y contraseña e inténtalo otra vez.',
|
|
1235
|
-
errorNoEmailPassword: 'Esta cuenta existe pero no tiene contraseña de email: la registraste con Google o LinkedIn. Si fue con Google, usa `login --google`. Si fue con LinkedIn, entra desde la web para añadir una contraseña por ahora.',
|
|
1236
1321
|
errorUpstream: 'El servidor de identidad de Shakers no responde ahora mismo. No es tu contraseña; inténtalo de nuevo en un rato.',
|
|
1237
1322
|
errorUnreachable: 'No se pudo conectar con Shakers. Comprueba tu conexión y vuelve a ejecutar `login`.',
|
|
1238
1323
|
errorConfig: 'La dirección del servidor no es válida. Revisa la configuración del endpoint (`usage --show-endpoint`).',
|
|
1239
1324
|
errorNoEndpoint: 'No hay endpoint configurado. login usa la misma base que usage: define SHAKERS_CLI_INGEST_ENDPOINT o usa `usage --set-endpoint <url>`.',
|
|
1240
1325
|
errorPersist: 'El inicio de sesión funcionó, pero no se pudo guardar la sesión en disco. Revisa los permisos de ~/.config/shakers y vuelve a intentarlo.',
|
|
1241
1326
|
errorGeneric: 'No se pudo iniciar sesión. Inténtalo de nuevo.',
|
|
1242
|
-
// Login con Google por loopback (`login --google`).
|
|
1243
|
-
googleIntro: 'Inicia sesión con Google. Se abrirá tu navegador para autorizar; al terminar, vuelve aquí.',
|
|
1244
|
-
googleOpening: 'Abriendo el navegador para iniciar sesión con Google…',
|
|
1245
|
-
googlePasteUrl: 'Si el navegador no se abre solo, pega esta URL en él:',
|
|
1246
|
-
googleWaiting: 'Esperando a que completes el acceso en el navegador…',
|
|
1247
|
-
googleErrorConfigFailed: 'No se pudo obtener la configuración de login de Google desde Shakers. Comprueba tu conexión y el endpoint (`usage --show-endpoint`) e inténtalo de nuevo.',
|
|
1248
|
-
googleErrorConfigInvalid: 'La configuración de Google que devolvió Shakers está incompleta. Es un problema del servidor, no tuyo; inténtalo más tarde.',
|
|
1249
|
-
googleErrorPortInUse: 'El puerto local que usa el login de Google está ocupado por otro proceso. Ciérralo y vuelve a ejecutar `login --google`.',
|
|
1250
|
-
googleErrorTimeout: 'Se agotó el tiempo esperando a que completaras el acceso en el navegador. Vuelve a ejecutar `login --google` cuando estés listo.',
|
|
1251
|
-
googleErrorState: 'La respuesta del navegador no coincidió con lo esperado (posible interferencia). Por seguridad no se inició sesión; inténtalo de nuevo.',
|
|
1252
|
-
googleErrorDenied: 'Cancelaste el acceso en Google (o no se concedió). No se inició sesión.',
|
|
1253
|
-
googleErrorGeneric: 'No se pudo iniciar sesión con Google. Inténtalo de nuevo.',
|
|
1254
1327
|
// Device flow (RFC 8628) para TODO método (Google, LinkedIn, email): el Hub tiene la config; abres una URL y, si hace falta, escribes un código.
|
|
1255
1328
|
deviceIntro: (name) => `Inicia sesión con ${name}. Abre el enlace de abajo e introduce el código para autorizar; luego vuelve aquí.`,
|
|
1256
1329
|
// Email por device flow: se abre la web de Shakers; reutiliza tu sesión abierta o entra con tu email ahí. Nunca pide contraseña en la terminal.
|
|
@@ -1259,6 +1332,8 @@ const catalogs = {
|
|
|
1259
1332
|
deviceCodeLabel: (code) => `e introduce este código: ${code}`,
|
|
1260
1333
|
deviceWaiting: 'Esperando a que autorices en el navegador…',
|
|
1261
1334
|
deviceApproveHint: 'Abrimos tu navegador: apruébalo ahí para terminar (o entra con tu email si aún no has iniciado sesión). No hace falta contraseña.',
|
|
1335
|
+
deviceTrust: 'Qué va a pasar: se abre una página de Shakers en shakersworks.com. Comprueba que el código de esa página es el mismo que ves aquí y pulsa Aprobar. Tu contraseña solo se escribe en la web de Shakers, nunca en esta terminal. Si no has pedido tú este acceso, deniégalo.',
|
|
1336
|
+
deviceGranted: 'Qué puede hacer ahora el CLI: usar tu cuenta de Shakers desde este equipo para leer tu perfil y, solo cuando ejecutes un comando que lo haga, guardar cambios en él o enviar el análisis de uso de IA que apruebes. La sesión se guarda solo en este equipo (~/.config/shakers). Para cerrarla: `shakers logout`.',
|
|
1262
1337
|
deviceErrorExpired: 'La solicitud de acceso caducó antes de autorizarse. Vuelve a ejecutar `login` cuando estés listo.',
|
|
1263
1338
|
deviceErrorDenied: 'Se canceló el acceso (o no se concedió). No se inició sesión.',
|
|
1264
1339
|
deviceErrorGeneric: 'No se pudo iniciar sesión. Inténtalo de nuevo.',
|
|
@@ -1437,6 +1512,16 @@ const catalogs = {
|
|
|
1437
1512
|
agentDeclaredSuccess: (name) => `✓ "${name}" añadido a tu perfil.`,
|
|
1438
1513
|
agentDeclareFailed: (reason) => `✗ No se pudo añadir el agente a tu perfil: ${reason}`,
|
|
1439
1514
|
agentHubSessionExpired: 'Tu sesión de Shakers ha caducado mientras añadíamos el agente a tu perfil.',
|
|
1515
|
+
addAllDetectedEntry: (n) => `Añadir todos los agentes detectados que aún no tienes (${n})`,
|
|
1516
|
+
detectedAgentsHeading: 'Agentes detectados que aún no están en tu perfil:',
|
|
1517
|
+
detectedAgentsHint: 'Flechas ↑/↓ para moverte · espacio para marcar o desmarcar · a para todos · enter para añadir los marcados · esc para no añadir ninguno',
|
|
1518
|
+
detectedAgentsNeedsYes: (n) => `Hay ${n} agente(s) detectado(s) que aún no están en tu perfil. Sin terminal no los añado; para añadirlos todos: shakers add-agent --all --yes`,
|
|
1519
|
+
detectedAgentsCheckFailed: (reason) => `No se pudo comprobar qué agentes tienes ya en tu perfil: ${reason} No añado ninguno para no duplicarlos; inténtalo más tarde con shakers add-agent --all.`,
|
|
1520
|
+
detectedAgentsAllOnProfile: 'Todos los agentes detectados ya están en tu perfil.',
|
|
1521
|
+
detectedAgentsDeclaring: 'Añadiendo los agentes a tu perfil…',
|
|
1522
|
+
detectedAgentsHubSessionExpired: 'Tu sesión de Shakers ha caducado mientras añadíamos los agentes a tu perfil.',
|
|
1523
|
+
detectedAgentFailed: (name, reason) => `✗ No se pudo añadir "${name}": ${reason}`,
|
|
1524
|
+
detectedAgentsSummary: (added, total) => `${added} de ${total} agente(s) añadido(s) a tu perfil.`,
|
|
1440
1525
|
agentRelateNoPortfolios: 'Todavía no tienes experiencias en tu perfil, así que el agente se ha añadido sin relacionar. Puedes añadir una con "Añadir proyecto al portfolio" y relacionarlo más tarde.',
|
|
1441
1526
|
agentRelateAsk: (agentName) => `¿Quieres relacionar "${agentName}" con alguna de tus experiencias? (s/n):`,
|
|
1442
1527
|
agentRelateSelectHeading: (agentName) => `Relaciona "${agentName}" con una o varias experiencias:`,
|
|
@@ -1665,13 +1750,10 @@ const catalogs = {
|
|
|
1665
1750
|
askCv: 'Path to your CV PDF (optional, Enter to skip):',
|
|
1666
1751
|
askGithub: 'Your GitHub URL (optional, Enter to skip):',
|
|
1667
1752
|
askWebsite: 'Your personal website (optional, Enter to skip):',
|
|
1668
|
-
importStarted: 'Importing your profile in the background while we continue…',
|
|
1669
|
-
importError: 'Could not start your profile import.',
|
|
1670
1753
|
importUnavailable: 'We could not import your profile right now (service unavailable); we are continuing with your registration, you can retry the import later.',
|
|
1671
1754
|
importChecking: 'Importing your profile…',
|
|
1672
1755
|
importDone: 'Profile imported successfully.',
|
|
1673
1756
|
importFailed: 'We could not finish importing your profile. You can retry it later from your profile.',
|
|
1674
|
-
importStillRunning: 'Your profile is still importing in the background; it will be ready in a few minutes.',
|
|
1675
1757
|
professionalTitle: 'Your work situation',
|
|
1676
1758
|
askWorkSituation: "What's your current work situation? Choose one:",
|
|
1677
1759
|
workSituationLabels: {
|
|
@@ -1704,27 +1786,13 @@ const catalogs = {
|
|
|
1704
1786
|
professionalSaved: 'Work situation saved.',
|
|
1705
1787
|
chooseMethodHeading: 'How do you want to create your account?',
|
|
1706
1788
|
signupTitle: 'Create your Shakers account',
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
askPassword: 'Password (at least 8 characters):',
|
|
1711
|
-
askPasswordConfirm: 'Repeat the password:',
|
|
1712
|
-
passwordMismatch: 'The passwords do not match. Try again.',
|
|
1713
|
-
askFreelanceTypeSelect: 'How do you work? Choose one:',
|
|
1714
|
-
freelanceTypeLabels: {
|
|
1715
|
-
FREELANCE: 'Freelance',
|
|
1716
|
-
EMPLOYEE: 'Employed',
|
|
1717
|
-
AGENCY: 'Agency or company',
|
|
1718
|
-
POTENTIAL_FREELANCE: 'Considering freelancing',
|
|
1719
|
-
},
|
|
1720
|
-
invalidChoice: 'Invalid option.',
|
|
1721
|
-
askNewsletter: 'Do you want the newsletter? (y/n):',
|
|
1722
|
-
weakPassword: 'The password does not meet the requirements (at least 8 characters).',
|
|
1789
|
+
termsAsk: 'Do you accept, to create your account? [y/N]',
|
|
1790
|
+
termsDeclined: 'Without accepting the Terms and the Privacy Policy your account cannot be created. Nothing was created and nothing was sent to Shakers.',
|
|
1791
|
+
newsletterAsk: (label) => `Optional: ${label} [y/N]`,
|
|
1723
1792
|
signupError: 'Could not create the account.',
|
|
1724
1793
|
freelanceIntentRequired: 'Your freelance intent is required for that type.',
|
|
1725
|
-
accountExists: '
|
|
1726
|
-
accountReady: 'Account created. Signed in
|
|
1727
|
-
sessionError: 'The account was created but sign-in failed. Run `shakers login`.',
|
|
1794
|
+
accountExists: 'You already had a Shakers account: you are now signed in with it on this computer.',
|
|
1795
|
+
accountReady: 'Account created. Signed in only on this computer (~/.config/shakers); to end it: `shakers logout`.',
|
|
1728
1796
|
pricingTitle: 'Your per-project price',
|
|
1729
1797
|
pricingSaved: 'Price saved.',
|
|
1730
1798
|
askPricingFullAmount: (cur) => `Full-time project price in ${cur} (number, no thousands separators, e.g. 60000):`,
|
|
@@ -1799,7 +1867,6 @@ const catalogs = {
|
|
|
1799
1867
|
repeatNotFound: 'You have no onboarding yet. Run `shakers onboarding` first.',
|
|
1800
1868
|
repeatAuthError: 'Your session does not allow this action. Sign in again: shakers login',
|
|
1801
1869
|
repeatFailed: (reason) => `Could not reset the onboarding (${reason}). Try again.`,
|
|
1802
|
-
interviewAnswer: 'Your answer:',
|
|
1803
1870
|
questionHeading: (n) => `Question ${n}`,
|
|
1804
1871
|
interviewTurnError: 'Could not continue the interview.',
|
|
1805
1872
|
thinking: 'Alma is thinking…',
|
|
@@ -1856,7 +1923,7 @@ const catalogs = {
|
|
|
1856
1923
|
t2Met: (n) => `You have at least one persistent context file — instructions, config or rules — for some tool (you have ${n}).`,
|
|
1857
1924
|
t3Met: (n) => `You have at least one connected MCP server, giving the AI access to external data or tools (you have ${n}).`,
|
|
1858
1925
|
t4Met: (n) => `You've created your own assets — skills, commands or custom rules — beyond the default configuration (you have ${n}).`,
|
|
1859
|
-
t5Met: (hasAgentic, mcp, custom) => `You operate an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI or Amazon Q Developer) combined with MCP and your own assets (${mcp} MCP servers and ${custom} assets of your own).`,
|
|
1926
|
+
t5Met: (hasAgentic, mcp, custom) => `You operate an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI, Pi, OpenCode or Amazon Q Developer) combined with MCP and your own assets (${mcp} MCP servers and ${custom} assets of your own).`,
|
|
1860
1927
|
t6Met: (n) => `You have a team of at least 2 specialized agents defined (you have ${n}).`,
|
|
1861
1928
|
t7Met: (n) => `You have hook-based automation configured (you have ${n}).`,
|
|
1862
1929
|
t1Blocking: (n) => `To reach T1 (First tool) you need at least one detected AI tool — you have ${n} now.`,
|
|
@@ -1865,7 +1932,7 @@ const catalogs = {
|
|
|
1865
1932
|
t4Blocking: (n) => `To reach T4 (Own tooling) you need to create at least one asset of your own — skill, command or rule — you have ${n} now.`,
|
|
1866
1933
|
t5Blocking: (hasAgentic, mcp, custom) => {
|
|
1867
1934
|
const missing = [];
|
|
1868
|
-
if (!hasAgentic) missing.push('an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI or Amazon Q Developer)');
|
|
1935
|
+
if (!hasAgentic) missing.push('an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI, Pi, OpenCode or Amazon Q Developer)');
|
|
1869
1936
|
if (mcp < 1) missing.push('at least 1 MCP server');
|
|
1870
1937
|
if (custom < 1) missing.push('at least 1 asset of your own (skill, command or rule)');
|
|
1871
1938
|
return `To reach T5 (Agentic operator) you're missing: ${missing.join('; ')}.`;
|
|
@@ -2183,9 +2250,9 @@ const catalogs = {
|
|
|
2183
2250
|
},
|
|
2184
2251
|
frameworkIntroUsage:
|
|
2185
2252
|
'This measures your AI fluency across two axes: Setup (your tooling\'s maturity, T0–T7, deterministic) and Usage (how you use it, assessed via interview + code). It places you on the 3×3 map (Explorer → AI Native). Completing it positions your agentic profile for projects that value how you work with AI. By default it reads the AI usage across this whole machine and assumes it is yours (one machine = you).',
|
|
2186
|
-
scanningLabel: '
|
|
2253
|
+
scanningLabel: 'Reading the setup of your AI tools and your projects on this computer (nothing has left your computer yet)…',
|
|
2187
2254
|
// Loader for the per-selected-repo aggregation phase (git + sessions + steering/decisions + evidence + agent org chart).
|
|
2188
|
-
aggregatingLabel: '
|
|
2255
|
+
aggregatingLabel: 'Reading the git and AI-session history of the chosen repos to extract signals (nothing has left your computer yet)…',
|
|
2189
2256
|
reposScopePromptHeader: 'What do you want to evaluate?',
|
|
2190
2257
|
reposScopePromptHint: 'Arrows to move · enter to choose',
|
|
2191
2258
|
reposScopeOptionMachine: 'Whole machine (every repo with AI activity)',
|
|
@@ -2267,10 +2334,20 @@ const catalogs = {
|
|
|
2267
2334
|
persistIntro:
|
|
2268
2335
|
'This report has already been generated and shown on your machine, '
|
|
2269
2336
|
+ 'always. Saving it in Shakers is optional and revocable at any '
|
|
2270
|
-
+
|
|
2337
|
+
+ 'time (usage --consent-revoke). It sends your level/tier, '
|
|
2271
2338
|
+ 'structured signals derived across categories (tools, MCP, memory, '
|
|
2272
|
-
+ 'automations, agents, technologies)
|
|
2273
|
-
+ '
|
|
2339
|
+
+ 'automations, agents, technologies) and literal text: fragments of '
|
|
2340
|
+
+ 'your conversations with AI assistants (those in the analysed '
|
|
2341
|
+
+ 'repositories, or all of them on this machine if you analyse the '
|
|
2342
|
+
+ "whole machine), sample commands and your agents' definitions, "
|
|
2343
|
+
+ 'after removing anything that looks like a '
|
|
2344
|
+
+ 'secret. Before each upload you see what is sent. An AI model from '
|
|
2345
|
+
+ 'an external provider (OpenAI, Google or Anthropic) analyses it on '
|
|
2346
|
+
+ "Shakers' behalf to compute your evaluation and discards it: "
|
|
2347
|
+
+ 'only the result is kept (levels, scores, counts and the names of '
|
|
2348
|
+
+ 'your tools and agents). Do not use it on machines or '
|
|
2349
|
+
+ 'conversations holding data you are not allowed to share (client, '
|
|
2350
|
+
+ 'employer or third-party data). '
|
|
2274
2351
|
+ 'This same decision also authorizes, only if you accept, a '
|
|
2275
2352
|
+ 'third-party observability provider (Datadog) to capture the '
|
|
2276
2353
|
+ "content these optional AI calls send (sampled code, agent "
|
|
@@ -2302,6 +2379,9 @@ const catalogs = {
|
|
|
2302
2379
|
nonInteractiveWarning:
|
|
2303
2380
|
'Non-interactive input (no TTY) detected: if no answer arrives via stdin, consent will not be '
|
|
2304
2381
|
+ 'saved this run and you will be asked again next time.',
|
|
2382
|
+
nonInteractiveUnanswered:
|
|
2383
|
+
'No answer arrived, so your consent is still undecided and nothing was saved in or sent to Shakers. '
|
|
2384
|
+
+ 'Run `shakers ai-usage` in your own terminal to answer.',
|
|
2305
2385
|
status: {
|
|
2306
2386
|
heading: 'Consent status (saved in Shakers)',
|
|
2307
2387
|
decisionGranted: 'Decision: granted',
|
|
@@ -2470,6 +2550,42 @@ const catalogs = {
|
|
|
2470
2550
|
faqsHeading: 'FAQs',
|
|
2471
2551
|
done: 'Detail complete.',
|
|
2472
2552
|
},
|
|
2553
|
+
apply: {
|
|
2554
|
+
help:
|
|
2555
|
+
'apply — apply to a project/position with your message and your answers to its questions.\n\n'
|
|
2556
|
+
+ 'Usage:\n apply <number|id> [--lang es|en]\n\n'
|
|
2557
|
+
+ 'Requires an active session (shakers login) and an interactive terminal.\n',
|
|
2558
|
+
loginRequired: '"apply" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
|
|
2559
|
+
needsInteractive: 'Applying needs an interactive terminal: I ask for your message and your answers, and for your confirmation before sending. From an AI assistant, use the apply_to_project MCP tool.',
|
|
2560
|
+
idRequired: 'The project is missing. Usage: apply <number|id>.',
|
|
2561
|
+
refNoCache: 'There is no recent listing. Run shakers find-projects first and use the number it shows (or pass an id).',
|
|
2562
|
+
refOutOfRange: (count) => `That number is not in the last listing (it has ${count}). Run shakers find-projects again.`,
|
|
2563
|
+
loading: 'Loading the application questions…',
|
|
2564
|
+
fetchFailed: (reason) => `Could not get the questions (${reason}). Try again in a moment.`,
|
|
2565
|
+
notFound: 'That project/position was not found.',
|
|
2566
|
+
notOpen: 'This project does not take your application right now: you already applied, it is closed or it is not available to you.',
|
|
2567
|
+
untitled: 'Untitled',
|
|
2568
|
+
companyLine: (name) => `Company: ${name}`,
|
|
2569
|
+
mainMotivationFallback: "What's your main motivation to apply?",
|
|
2570
|
+
askMessage: (question) => `${question} (your message for the team; enter to leave it blank):`,
|
|
2571
|
+
askOpen: (question) => `${question} (enter to skip):`,
|
|
2572
|
+
choiceHint: 'Arrows ↑/↓ to move · enter to pick',
|
|
2573
|
+
skipChoice: 'Skip',
|
|
2574
|
+
summaryTitle: 'This is what will be sent',
|
|
2575
|
+
titleLine: (title) => `Project: ${title}`,
|
|
2576
|
+
messageLine: (message) => `Message: ${message}`,
|
|
2577
|
+
empty: '(empty)',
|
|
2578
|
+
answerLine: (question, answer) => `${question}: ${answer}`,
|
|
2579
|
+
sendNotice: (title) => `Your message and your answers for "${title}" are sent: the client will see your Shakers profile and a chat with the team opens. Your profile does not change.`,
|
|
2580
|
+
reviewNotice: 'On this project Shakers reviews your application before the client sees it.',
|
|
2581
|
+
confirm: 'Send the application? (y/n):',
|
|
2582
|
+
cancelled: 'Cancelled. Nothing was sent.',
|
|
2583
|
+
sending: 'Sending your application…',
|
|
2584
|
+
sent: 'Application sent. You can follow it with shakers applications.',
|
|
2585
|
+
sentPending: 'Application sent. Shakers reviews it before the client sees it; you can follow it with shakers applications.',
|
|
2586
|
+
alreadyApplied: (status) => (status ? `You already applied to this project (status: ${status}).` : 'You already applied to this project.'),
|
|
2587
|
+
failed: (reason) => `Could not send the application (${reason}). Try again in a moment.`,
|
|
2588
|
+
},
|
|
2473
2589
|
savedPositions: {
|
|
2474
2590
|
helpSave: 'save-project — bookmark a project/position.\n\nUsage:\n save-project <number|id> [--json]\n\nRequires an active session (shakers login).',
|
|
2475
2591
|
helpUnsave: 'unsave-project — remove a project/position from your saved list.\n\nUsage:\n unsave-project <number|id> [--json]\n\nRequires an active session (shakers login).',
|
|
@@ -2636,6 +2752,20 @@ const catalogs = {
|
|
|
2636
2752
|
noneFound: 'Found no supported AI app on this machine.',
|
|
2637
2753
|
failedAll: 'Could not connect Shakers to your AI apps. Re-run this installer to retry.',
|
|
2638
2754
|
},
|
|
2755
|
+
skillInstall: {
|
|
2756
|
+
title: 'Installing the shakers-cli skill for your AI agents',
|
|
2757
|
+
agents: { claudeCode: 'Claude Code', codex: 'Codex' },
|
|
2758
|
+
status: { installed: 'installed', failed: 'could not install' },
|
|
2759
|
+
found: (agents) => `Found: ${agents}.`,
|
|
2760
|
+
confirm: 'Install the skill so your agent knows how to use the Shakers CLI? [Y/n]',
|
|
2761
|
+
declined: 'Nothing touched. To install it later: shakers skill install',
|
|
2762
|
+
noTerminal: 'There is no terminal to ask you on, so nothing was touched.',
|
|
2763
|
+
yesHint: 'To install it without being asked (for example from an AI assistant): shakers skill install --yes',
|
|
2764
|
+
noneFound: 'Found neither Claude Code nor Codex on this machine; nothing touched.',
|
|
2765
|
+
done: (agents) => `Done. If ${agents} does not see the skill, start a new session.`,
|
|
2766
|
+
failedAll: 'Could not install the skill. Run shakers skill install again to retry.',
|
|
2767
|
+
help: 'skill install — install the shakers-cli skill, which teaches your AI agent (Claude Code, Codex) to use this CLI.\n\nUsage:\n shakers skill install ask on the terminal, then install for every agent found\n shakers skill install --yes install without asking (-y; for AI assistants and scripts)\n shakers skill install --json print the result as one JSON object\n\nWithout --yes and without a terminal, nothing is touched. It writes only ~/.claude/skills/shakers-cli/SKILL.md and <CODEX_HOME>/skills/shakers-cli/SKILL.md.',
|
|
2768
|
+
},
|
|
2639
2769
|
rate: {
|
|
2640
2770
|
help: 'rate — view or set your per-project rate.\n\nUsage:\n rate [--lang es|en] [--json] view your rate\n rate --set [--lang es|en] set it (interactive, with confirmation)\n\nRequires an active session (shakers login).',
|
|
2641
2771
|
loginRequired: '"rate" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
|
|
@@ -2856,6 +2986,48 @@ const catalogs = {
|
|
|
2856
2986
|
remediationCopiedLabel: 'Copied ✓',
|
|
2857
2987
|
},
|
|
2858
2988
|
},
|
|
2989
|
+
trust: {
|
|
2990
|
+
detectedAgents: 'If you confirm, I add the marked agents to your Shakers profile, only their name and description, and clients will see them on your profile. Nothing else is read or uploaded from this computer. You can remove them any time from your profile on the Shakers website.',
|
|
2991
|
+
uploadWarning: "Before you approve: up to 40 literal excerpts of your messages (corrections and decisions) and 20 commands, 200 characters max each, your agents' configuration and definitions, and activity counts would be sent. Anything that looks like a secret, an email or a path is removed, but the filter is approximate: do not approve it if there is data you are not allowed to share (client, employer or third-party data).",
|
|
2992
|
+
cli: {
|
|
2993
|
+
'ai-usage': { before: "I am going to analyse on this computer your AI tools, the history of your code projects and your conversations with AI coding assistants (Claude Code, Codex, Gemini, Cursor, Continue, Cline/Roo, Aider, Pi, OpenCode). Analysing a repo covers only that repo's conversations; choosing the whole machine, or signing up, covers every conversation on this computer. Before sending anything to Shakers I show you what would be sent and ask you. Do not use it on a computer or with conversations holding data you are not allowed to share (client, employer or third-party data).", after: 'Done. If you approved the upload, an AI model from an external provider (OpenAI, Google or Anthropic) analyses what was sent on behalf of Shakers to compute your evaluation and then it is discarded; only the result is kept (levels, scores, counts and the names of your tools and agents). If you did not approve it, nothing went to your profile. Human review: "Request human review" on the web or talent@shakersworks.com; to ask for deletion of what was sent, the same email. To stop sending from this computer: `shakers ai-usage --consent-revoke`.' },
|
|
2994
|
+
certify: { before: 'I am going to prepare the certification of your main role with Shakers: I explain each step and ask before sending anything.', after: 'Done. What was sent stays in your Shakers account.' },
|
|
2995
|
+
share: { before: 'I am going to create on this computer a card with your AI report to share. I send nothing.', after: 'Done. The card is on this computer; nothing was sent.' },
|
|
2996
|
+
report: { before: 'I am going to read your AI report (from Shakers or from your last analysis on this computer) and save it as a file on this computer. I do not change your profile.' },
|
|
2997
|
+
'add-skill': { before: 'I am going to read the skills from your last analysis on Shakers and add the ones you pick to your profile.', after: 'Done. Your Shakers profile has the skills you picked.' },
|
|
2998
|
+
'add-agent': { before: 'I am going to read the agents from your last analysis on Shakers and add the one you pick to your profile, with the description you approve, or every new one at once if you choose so.', after: 'Done. Your Shakers profile has the agents you picked.' },
|
|
2999
|
+
'add-project': { before: 'I am going to read this folder\'s name, the web address of its code and the dates of its first and last change, and ask you before sending them to your Shakers portfolio. I do not send your code.', after: 'Done. The project is in your Shakers portfolio.' },
|
|
3000
|
+
'add-role': { before: 'I am going to read the Shakers roles and add the one you pick to your profile.', after: 'Done. Your Shakers profile has the role you picked.' },
|
|
3001
|
+
'change-role': { before: 'I am going to read your Shakers roles and save the one you pick as your main role.', after: 'Done. Your main role is saved on Shakers.' },
|
|
3002
|
+
'find-projects': { before: 'I only read from Shakers the projects that fit you; I change nothing.' },
|
|
3003
|
+
'show-project': { before: 'I only read the project details from Shakers; I change nothing.' },
|
|
3004
|
+
apply: { before: 'I am going to read the questions of this project from Shakers and, if you confirm, send your message and your answers: the client will see your Shakers profile and a chat with the team opens. If the project asks for it, Shakers reviews your application before the client sees it. I do not change your profile.', after: 'Done. Your application is on Shakers; you can follow it with shakers applications.' },
|
|
3005
|
+
'save-project': { before: 'I am going to save this project to your saved projects on Shakers.', after: 'Done. The project is in your saved projects.' },
|
|
3006
|
+
'unsave-project': { before: 'I am going to remove this project from your saved projects on Shakers.', after: 'Done. The project is no longer in your saved projects.' },
|
|
3007
|
+
invitations: { before: 'I only read your Shakers invitations; I change nothing.' },
|
|
3008
|
+
applications: { before: 'I only read your Shakers applications; I change nothing.' },
|
|
3009
|
+
availability: { before: 'I only read your availability from your Shakers profile; I change nothing.' },
|
|
3010
|
+
'availability:set': { before: 'I am going to change your availability on your Shakers profile.', after: 'Done. Your availability is saved on Shakers.' },
|
|
3011
|
+
certifications: { before: 'I only read your Shakers certifications; I change nothing.' },
|
|
3012
|
+
me: { before: 'I only read your Shakers profile; I change nothing.' },
|
|
3013
|
+
rate: { before: 'I only read your rate from your Shakers profile; I change nothing.' },
|
|
3014
|
+
'rate:set': { before: 'I am going to change your rate on your Shakers profile.', after: 'Done. Your rate is saved on Shakers.' },
|
|
3015
|
+
lang: { before: 'I only read your languages from your Shakers profile; I change nothing.' },
|
|
3016
|
+
'lang:set': { before: 'I am going to change your languages on your Shakers profile.', after: 'Done. Your languages are saved on Shakers.' },
|
|
3017
|
+
socials: { before: 'I only read your social links from your Shakers profile; I change nothing.' },
|
|
3018
|
+
'socials:set': { before: 'I am going to change your social links on your Shakers profile.', after: 'Done. Your social links are saved on Shakers.' },
|
|
3019
|
+
experiences: { before: 'I only read your experiences from your Shakers profile; I change nothing.' },
|
|
3020
|
+
portfolios: { before: 'I only read your portfolio from your Shakers profile; I change nothing.' },
|
|
3021
|
+
alma: { before: 'I am going to send your messages to Alma, the Shakers assistant. If she proposes a change to your profile, I ask you before making it.' },
|
|
3022
|
+
register: { before: 'I am going to create your Shakers account: I ask you here to accept the Terms and open a Shakers page (shakersworks.com) with a code; your password is typed only there. I tell you before every step that sends data.' },
|
|
3023
|
+
onboarding: { before: 'I am going to run the onboarding interview with you: your answers are sent to Shakers to get to know your profile. I read nothing on your computer.', after: 'Done. Your interview is saved on Shakers.' },
|
|
3024
|
+
config: { before: 'I only work with the CLI configuration on this computer (~/.config/shakers); I send nothing to Shakers.' },
|
|
3025
|
+
update: { before: 'I am going to check for a new CLI version and, if there is one, replace its installed files on this computer. I do not touch your projects or your session.' },
|
|
3026
|
+
logout: { before: 'I am going to sign you out: I tell Shakers and delete the session and consent saved on this computer (~/.config/shakers). I do not change your profile.' },
|
|
3027
|
+
mcp: { before: 'I am going to add the Shakers MCP server to the configuration of your AI apps on this computer (for example ~/.cursor/mcp.json or ~/.codex/config.toml). I send nothing to Shakers.', after: 'Done. Only the configuration files listed above changed.' },
|
|
3028
|
+
skill: { before: 'I am going to write the Shakers CLI skill into your agents\' skill folders on this computer (~/.claude/skills or ~/.codex/skills). I send nothing to Shakers.', after: 'Done. Only the files listed above changed.' },
|
|
3029
|
+
},
|
|
3030
|
+
},
|
|
2859
3031
|
// Branded mini-shell chrome.
|
|
2860
3032
|
login: {
|
|
2861
3033
|
intro: 'Log in with your Shakers email and password.',
|
|
@@ -2869,26 +3041,12 @@ const catalogs = {
|
|
|
2869
3041
|
expiresAt: (iso) => `The session expires: ${iso}. When it does I will tell you, and you can log in again with \`login\`.`,
|
|
2870
3042
|
loggedOut: 'Logged out. Your report shows the improvement suggestions again.',
|
|
2871
3043
|
notLoggedIn: 'No session was active. Nothing to log out of.',
|
|
2872
|
-
errorInvalidCredentials: 'Wrong credentials: check your email and password and try again.',
|
|
2873
|
-
errorNoEmailPassword: 'This account exists but has no email password: you registered with Google or LinkedIn. If it was Google, use `login --google`. If it was LinkedIn, sign in on the web to add a password for now.',
|
|
2874
3044
|
errorUpstream: "Shakers' identity server is not responding right now. It is not your password; try again in a while.",
|
|
2875
3045
|
errorUnreachable: 'Could not reach Shakers. Check your connection and run `login` again.',
|
|
2876
3046
|
errorConfig: 'The server address is invalid. Check the endpoint configuration (`usage --show-endpoint`).',
|
|
2877
3047
|
errorNoEndpoint: 'No endpoint configured. login uses the same base as usage: set SHAKERS_CLI_INGEST_ENDPOINT or use `usage --set-endpoint <url>`.',
|
|
2878
3048
|
errorPersist: 'Login succeeded, but the session could not be saved to disk. Check the permissions of ~/.config/shakers and try again.',
|
|
2879
3049
|
errorGeneric: 'Could not log in. Try again.',
|
|
2880
|
-
// Google login by loopback (`login --google`).
|
|
2881
|
-
googleIntro: 'Log in with Google. Your browser will open to authorize; when you are done, come back here.',
|
|
2882
|
-
googleOpening: 'Opening your browser to log in with Google…',
|
|
2883
|
-
googlePasteUrl: 'If your browser does not open on its own, paste this URL into it:',
|
|
2884
|
-
googleWaiting: 'Waiting for you to finish signing in in the browser…',
|
|
2885
|
-
googleErrorConfigFailed: "Could not fetch the Google login configuration from Shakers. Check your connection and the endpoint (`usage --show-endpoint`) and try again.",
|
|
2886
|
-
googleErrorConfigInvalid: 'The Google configuration Shakers returned is incomplete. This is a server-side problem, not yours; try again later.',
|
|
2887
|
-
googleErrorPortInUse: 'The local port the Google login uses is busy with another process. Close it and run `login --google` again.',
|
|
2888
|
-
googleErrorTimeout: 'Timed out waiting for you to finish signing in in the browser. Run `login --google` again when you are ready.',
|
|
2889
|
-
googleErrorState: 'The browser response did not match what was expected (possible interference). For safety no session was started; try again.',
|
|
2890
|
-
googleErrorDenied: 'You cancelled access in Google (or it was not granted). No session was started.',
|
|
2891
|
-
googleErrorGeneric: 'Could not log in with Google. Try again.',
|
|
2892
3050
|
// Device flow (RFC 8628) for EVERY method (Google, LinkedIn, email): the Hub owns the config; you open a URL and, if needed, type a code.
|
|
2893
3051
|
deviceIntro: (name) => `Sign in with ${name}. Open the link below and enter the code to authorize; then come back here.`,
|
|
2894
3052
|
// Email via device flow: the Shakers web opens; reuse your open session or sign in with your email there. It never asks for a password in the terminal.
|
|
@@ -2897,6 +3055,8 @@ const catalogs = {
|
|
|
2897
3055
|
deviceCodeLabel: (code) => `and enter this code: ${code}`,
|
|
2898
3056
|
deviceWaiting: 'Waiting for you to authorize in the browser…',
|
|
2899
3057
|
deviceApproveHint: 'We opened your browser: approve there to finish (or sign in with your email if you are not signed in yet). No password needed.',
|
|
3058
|
+
deviceTrust: 'What happens next: a Shakers page opens on shakersworks.com. Check that the code on that page matches the one shown here and click Approve. Your password is typed only on the Shakers website, never in this terminal. If you did not ask for this access, deny it.',
|
|
3059
|
+
deviceGranted: 'What the CLI can do now: use your Shakers account from this computer to read your profile and, only when you run a command that does so, save changes to it or send the AI-usage analysis you approve. The session is stored only on this computer (~/.config/shakers). To end it: `shakers logout`.',
|
|
2900
3060
|
deviceErrorExpired: 'The sign-in request expired before it was authorized. Run `login` again when you are ready.',
|
|
2901
3061
|
deviceErrorDenied: 'The sign-in was cancelled or not granted. No session was started.',
|
|
2902
3062
|
deviceErrorGeneric: 'Could not sign in. Try again.',
|
|
@@ -3079,6 +3239,16 @@ const catalogs = {
|
|
|
3079
3239
|
agentDeclaredSuccess: (name) => `✓ "${name}" added to your profile.`,
|
|
3080
3240
|
agentDeclareFailed: (reason) => `✗ Could not add the agent to your profile: ${reason}`,
|
|
3081
3241
|
agentHubSessionExpired: 'Your Shakers session expired while we were adding the agent to your profile.',
|
|
3242
|
+
addAllDetectedEntry: (n) => `Add every detected agent you do not have yet (${n})`,
|
|
3243
|
+
detectedAgentsHeading: 'Detected agents that are not on your profile yet:',
|
|
3244
|
+
detectedAgentsHint: 'Arrows ↑/↓ to move · space to mark or unmark · a for all · enter to add the marked ones · esc to add none',
|
|
3245
|
+
detectedAgentsNeedsYes: (n) => `${n} detected agent(s) are not on your profile yet. Without a terminal I do not add them; to add them all: shakers add-agent --all --yes`,
|
|
3246
|
+
detectedAgentsCheckFailed: (reason) => `Could not check which agents are already on your profile: ${reason} I add none so they are not duplicated; try again later with shakers add-agent --all.`,
|
|
3247
|
+
detectedAgentsAllOnProfile: 'Every detected agent is already on your profile.',
|
|
3248
|
+
detectedAgentsDeclaring: 'Adding the agents to your profile…',
|
|
3249
|
+
detectedAgentsHubSessionExpired: 'Your Shakers session expired while we were adding the agents to your profile.',
|
|
3250
|
+
detectedAgentFailed: (name, reason) => `✗ Could not add "${name}": ${reason}`,
|
|
3251
|
+
detectedAgentsSummary: (added, total) => `${added} of ${total} agent(s) added to your profile.`,
|
|
3082
3252
|
// AFTER the agent is declared, offer to relate it to the experiences/projects the talent already declared (portfolioId only).
|
|
3083
3253
|
agentRelateNoPortfolios: "You don't have any experiences in your profile yet, so the agent was added without a relation. Add one with \"Add project to portfolio\" and relate it later.",
|
|
3084
3254
|
agentRelateAsk: (agentName) => `Do you want to relate "${agentName}" to any of your experiences? (y/n):`,
|