shakers-cli 0.16.0 → 0.18.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 +21 -6
- package/bin/ai-usage.js +31 -12
- package/bin/command-audit-worker.js +19 -0
- package/bin/login.js +4 -8
- package/bin/mcp.js +32 -21
- package/bin/register.js +12 -30
- package/bin/shakers-cli.js +15 -10
- package/package.json +1 -1
- package/src/account-marker.js +40 -0
- package/src/account-trace.js +23 -0
- package/src/agents-client.js +1 -0
- package/src/ai-usage-review.js +103 -0
- package/src/auth-client.js +7 -107
- package/src/auth-session-store.js +12 -11
- package/src/backend-request.js +3 -24
- package/src/cli-skill.js +77 -0
- package/src/command-audit.js +47 -4
- package/src/config.js +2 -16
- package/src/consent-flow.js +9 -3
- package/src/detect-repos.js +4 -8
- 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 +186 -102
- package/src/mcp-ai-usage-result-tool.js +38 -14
- package/src/mcp-ai-usage-tool.js +317 -172
- 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 +292 -53
- package/src/mcp-instructions.js +43 -17
- package/src/mcp-onboarding-tools.js +1 -3
- package/src/mcp-prompts.js +8 -6
- package/src/mcp-register-tools.js +25 -14
- package/src/mcp-role-tools.js +59 -18
- 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 +250 -133
- package/src/onboarding-flow.js +72 -146
- package/src/onboarding-funnel.js +46 -6
- package/src/opencode-sessions.js +92 -0
- package/src/profile-agents.js +26 -0
- package/src/render-report-text.js +1 -1
- package/src/report-gating.js +4 -2
- package/src/report-store.js +7 -2
- package/src/roles-flow.js +8 -5
- 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-consent-state.js +2 -2
- 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 +545 -58
- package/src/skill-install.js +102 -0
- package/src/stdin-ask.js +13 -1
- package/src/tier-engine.js +14 -2
- package/src/trust-narration.js +32 -0
- package/src/usage-run-steps.js +68 -6
- package/src/usage-scan.js +11 -8
- package/src/brand-svg.js +0 -9
- package/src/inter-fonts.js +0 -6
- package/src/mcp-auth-form.js +0 -480
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('; ')}.`;
|
|
@@ -450,7 +432,7 @@ const catalogs = {
|
|
|
450
432
|
// Shown only when the 4 prose gaps below were actually replaced by a validated, project-adapted response — never on fallback to the curated content.
|
|
451
433
|
roadmapPersonalizedNotice: 'Contenido adaptado a tu proyecto.',
|
|
452
434
|
// Los dos avisos que faltaban, hermanos del `agentsEvalMissing` que añadió la 106.
|
|
453
|
-
roadmapNotPersonalizedNotice: 'Este roadmap es el genérico de tu tier: esta vez no se ha podido adaptar a tu proyecto. Vuelve a ejecutar `usage` para intentarlo otra vez.',
|
|
435
|
+
roadmapNotPersonalizedNotice: 'Este roadmap es el genérico de tu tier: esta vez no se ha podido adaptar a tu proyecto. Vuelve a ejecutar `usage --roadmap` para intentarlo otra vez.',
|
|
454
436
|
// El antes y el después del roadmap.
|
|
455
437
|
roadmapNowLabel: 'De dónde partes',
|
|
456
438
|
roadmapProjectionLabel: 'Dónde te deja esta ruta',
|
|
@@ -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)',
|
|
@@ -558,6 +540,7 @@ const catalogs = {
|
|
|
558
540
|
// Roadmap personalization: reuses the
|
|
559
541
|
// same spinner mechanism as synthesizingLabel above.
|
|
560
542
|
personalizingRoadmapLabel: 'Personalizando roadmap…',
|
|
543
|
+
roadmapNotForAccounts: 'El roadmap no está disponible para cuentas de Shakers: tu nivel sale de certificarte.',
|
|
561
544
|
// Agent definition-quality evaluation (ephemeral LLM call).
|
|
562
545
|
evaluatingAgentsLabel: 'Evaluando la calidad de tus agentes…',
|
|
563
546
|
// "Construir el siguiente nivel ahora": now a SECONDARY, opt-in alternative — the copyable implementation prompt (below) is the PRIMARY "how do I implement this" path.
|
|
@@ -575,7 +558,7 @@ const catalogs = {
|
|
|
575
558
|
+ ' --repo Evalúa solo el repo actual\n'
|
|
576
559
|
+ ' --scope machine|repo Igual que --machine / --repo (salta el selector)\n'
|
|
577
560
|
+ ' --all-repos Alias de --machine\n'
|
|
578
|
-
+ ' --roadmap Muestra los pasos para subir tu nivel de uso de IA (
|
|
561
|
+
+ ' --roadmap Muestra los pasos para subir tu nivel de uso de IA (solo sin cuenta de Shakers)\n'
|
|
579
562
|
+ ' --build-next-level Genera el starter del siguiente tier (alternativa secundaria)\n'
|
|
580
563
|
+ ' --force Junto a --build-next-level, sobrescribe un fichero existente\n'
|
|
581
564
|
+ ' --lang es|en Fuerza el idioma (informe + prompt) en vez de detectarlo del sistema\n'
|
|
@@ -620,10 +603,20 @@ const catalogs = {
|
|
|
620
603
|
persistIntro:
|
|
621
604
|
'Este informe se ha generado y mostrado en tu equipo, siempre. '
|
|
622
605
|
+ 'Guardarlo en Shakers es opcional y revocable en cualquier momento '
|
|
623
|
-
+ '(usage --consent-revoke)
|
|
606
|
+
+ '(usage --consent-revoke). Se envían tu nivel/tier, señales '
|
|
624
607
|
+ 'estructuradas derivadas (herramientas, MCP, memoria, '
|
|
625
|
-
+ 'automatizaciones, agentes, tecnologías)
|
|
626
|
-
+ '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). '
|
|
627
620
|
+ 'Esta misma decisión también autoriza, solo si aceptas, que un '
|
|
628
621
|
+ 'proveedor externo de observabilidad (Datadog) capture el contenido '
|
|
629
622
|
+ 'que envían las llamadas de IA opcionales de este CLI (código '
|
|
@@ -647,7 +640,7 @@ const catalogs = {
|
|
|
647
640
|
// Esta pregunta se pide ahora ANTES de cualquier llamada de IA/egress (agent-synthesis, agent-evaluation, personalización de roadmap), no después.
|
|
648
641
|
noReportWithoutConsent: 'Sin tu consentimiento, este informe no incluirá síntesis, evaluación ni roadmap generados por IA esta vez (el resto del informe se muestra igual). Vuelve a ejecutar `usage` y acepta para incluirlos, o usa --consent-reset si quieres que se te pregunte de nuevo.',
|
|
649
642
|
deniedSaved: 'Entendido, no se guardará nada. Puedes cambiar de opinión más adelante volviendo a ejecutar el comando.',
|
|
650
|
-
grantedSaved: (email) => `Gracias.
|
|
643
|
+
grantedSaved: (email) => `Gracias. Antes de subir nada a Shakers te enseñaré lo que se enviaría y solo lo subiré si lo apruebas (correo: ${email}, máx. 1 vez por hora).`,
|
|
651
644
|
// Un talento logueado NUNCA ve el prompt de email (su cuenta ya prueba su identidad).
|
|
652
645
|
noSessionEmail: 'No hay un correo asociado a tu sesión todavía, así que no se puede guardar el informe esta vez. Se te preguntará de nuevo la próxima ejecución.',
|
|
653
646
|
skipAlreadyDecided: (decision, path) =>
|
|
@@ -656,6 +649,9 @@ const catalogs = {
|
|
|
656
649
|
nonInteractiveWarning:
|
|
657
650
|
'Entrada no interactiva (no-TTY) detectada: si no llega ninguna respuesta por stdin, '
|
|
658
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.',
|
|
659
655
|
status: {
|
|
660
656
|
heading: 'Estado del consentimiento (guardado en Shakers)',
|
|
661
657
|
decisionGranted: 'Decisión: concedido (granted)',
|
|
@@ -972,12 +968,13 @@ const catalogs = {
|
|
|
972
968
|
},
|
|
973
969
|
mcpInstall: {
|
|
974
970
|
title: 'Conectando el MCP de Shakers',
|
|
975
|
-
clients: { claudeDesktop: 'Claude Desktop', claudeCode: 'Claude Code', cursor: 'Cursor', geminiCli: 'Gemini CLI', codex: 'Codex
|
|
971
|
+
clients: { claudeDesktop: 'Claude Desktop', claudeCode: 'Claude Code', cursor: 'Cursor', geminiCli: 'Gemini CLI', codex: 'Codex / ChatGPT', vscode: 'VS Code', windsurf: 'Windsurf' },
|
|
976
972
|
status: {
|
|
977
973
|
configured: 'conectado',
|
|
978
974
|
unchanged: 'ya estaba conectado',
|
|
979
975
|
'not-found': 'no instalado en esta máquina',
|
|
980
|
-
'invalid-
|
|
976
|
+
'invalid-config': 'no puedo editar su configuración con seguridad; no la he tocado',
|
|
977
|
+
manual: 'ejecuta este comando en tu terminal:',
|
|
981
978
|
failed: 'no se pudo conectar',
|
|
982
979
|
},
|
|
983
980
|
removedLegacy: 'Sustituye a la entrada antigua "shakers-ai-usage".',
|
|
@@ -985,10 +982,27 @@ const catalogs = {
|
|
|
985
982
|
confirm: '¿Conecto Shakers a ellas para que puedas usarlo desde tu IA? [S/n]',
|
|
986
983
|
declined: 'No he tocado nada. Para conectarlo más tarde, vuelve a ejecutar el instalador.',
|
|
987
984
|
noTerminal: 'No hay una terminal donde preguntarte, así que no he tocado nada. Vuelve a ejecutar el instalador en tu terminal para conectarlo.',
|
|
988
|
-
restart:
|
|
985
|
+
restart: (apps) => `Reinicia ${apps} (o recarga sus servidores MCP) para que aparezcan las herramientas de Shakers.`,
|
|
986
|
+
alreadyConnected: 'Shakers ya estaba conectado. Si no ves sus herramientas, reinicia la app o recarga sus servidores MCP.',
|
|
987
|
+
yesHint: 'Para conectarlas sin preguntar (por ejemplo, desde un asistente de IA): shakers mcp install --yes',
|
|
988
|
+
help: 'mcp install — conecta Shakers a las apps de IA de esta máquina (Claude Desktop, Claude Code, Cursor, Gemini CLI, Codex / ChatGPT, VS Code, Windsurf).\n\nUso:\n shakers mcp install pregunta en la terminal y conecta las apps encontradas\n shakers mcp install --yes conecta sin preguntar (-y; para asistentes de IA y scripts)\n shakers mcp install --json imprime el resultado como un único objeto JSON\n\nSin --yes y sin terminal no toca nada. SHAKERS_MCP_INSTALL=1 equivale a --yes.\nAl terminar, reinicia las apps que indique (o recarga sus servidores MCP) para que aparezcan las herramientas de Shakers.',
|
|
989
989
|
noneFound: 'No he encontrado ninguna app de IA compatible en esta máquina.',
|
|
990
990
|
failedAll: 'No he podido conectar Shakers a tus apps de IA. Vuelve a ejecutar el instalador para reintentarlo.',
|
|
991
991
|
},
|
|
992
|
+
skillInstall: {
|
|
993
|
+
title: 'Instalando la skill shakers-cli para tus agentes de IA',
|
|
994
|
+
agents: { claudeCode: 'Claude Code', codex: 'Codex' },
|
|
995
|
+
status: { installed: 'instalada', failed: 'no se pudo instalar' },
|
|
996
|
+
found: (agents) => `He encontrado: ${agents}.`,
|
|
997
|
+
confirm: '¿Instalo la skill para que tu agente sepa usar el CLI de Shakers? [S/n]',
|
|
998
|
+
declined: 'No he tocado nada. Para instalarla más tarde: shakers skill install',
|
|
999
|
+
noTerminal: 'No hay una terminal donde preguntarte, así que no he tocado nada.',
|
|
1000
|
+
yesHint: 'Para instalarla sin preguntar (por ejemplo, desde un asistente de IA): shakers skill install --yes',
|
|
1001
|
+
noneFound: 'No he encontrado Claude Code ni Codex en esta máquina; no he tocado nada.',
|
|
1002
|
+
done: (agents) => `Listo. Si ${agents} no ve la skill, abre una sesión nueva.`,
|
|
1003
|
+
failedAll: 'No he podido instalar la skill. Vuelve a ejecutar shakers skill install para reintentarlo.',
|
|
1004
|
+
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.',
|
|
1005
|
+
},
|
|
992
1006
|
rate: {
|
|
993
1007
|
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).',
|
|
994
1008
|
loginRequired: '"rate" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
|
|
@@ -1213,6 +1227,46 @@ const catalogs = {
|
|
|
1213
1227
|
remediationCopiedLabel: 'Copiado ✓',
|
|
1214
1228
|
},
|
|
1215
1229
|
},
|
|
1230
|
+
trust: {
|
|
1231
|
+
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).',
|
|
1232
|
+
cli: {
|
|
1233
|
+
'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`.' },
|
|
1234
|
+
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.' },
|
|
1235
|
+
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.' },
|
|
1236
|
+
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.' },
|
|
1237
|
+
'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.' },
|
|
1238
|
+
'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.', after: 'Hecho. Tu perfil de Shakers tiene el agente que elegiste.' },
|
|
1239
|
+
'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.' },
|
|
1240
|
+
'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.' },
|
|
1241
|
+
'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.' },
|
|
1242
|
+
'find-projects': { before: 'Solo leo de Shakers los proyectos que encajan contigo; no cambio nada.' },
|
|
1243
|
+
'show-project': { before: 'Solo leo de Shakers el detalle del proyecto; no cambio nada.' },
|
|
1244
|
+
'save-project': { before: 'Voy a guardar este proyecto en tus proyectos guardados de Shakers.', after: 'Hecho. El proyecto está en tus guardados.' },
|
|
1245
|
+
'unsave-project': { before: 'Voy a quitar este proyecto de tus proyectos guardados de Shakers.', after: 'Hecho. El proyecto ya no está en tus guardados.' },
|
|
1246
|
+
invitations: { before: 'Solo leo tus invitaciones de Shakers; no cambio nada.' },
|
|
1247
|
+
applications: { before: 'Solo leo tus candidaturas de Shakers; no cambio nada.' },
|
|
1248
|
+
availability: { before: 'Solo leo tu disponibilidad de tu perfil de Shakers; no cambio nada.' },
|
|
1249
|
+
'availability:set': { before: 'Voy a cambiar tu disponibilidad en tu perfil de Shakers.', after: 'Hecho. Tu disponibilidad está guardada en Shakers.' },
|
|
1250
|
+
certifications: { before: 'Solo leo tus certificaciones de Shakers; no cambio nada.' },
|
|
1251
|
+
me: { before: 'Solo leo tu perfil de Shakers; no cambio nada.' },
|
|
1252
|
+
rate: { before: 'Solo leo tu tarifa de tu perfil de Shakers; no cambio nada.' },
|
|
1253
|
+
'rate:set': { before: 'Voy a cambiar tu tarifa en tu perfil de Shakers.', after: 'Hecho. Tu tarifa está guardada en Shakers.' },
|
|
1254
|
+
lang: { before: 'Solo leo tus idiomas de tu perfil de Shakers; no cambio nada.' },
|
|
1255
|
+
'lang:set': { before: 'Voy a cambiar tus idiomas en tu perfil de Shakers.', after: 'Hecho. Tus idiomas están guardados en Shakers.' },
|
|
1256
|
+
socials: { before: 'Solo leo tus redes de tu perfil de Shakers; no cambio nada.' },
|
|
1257
|
+
'socials:set': { before: 'Voy a cambiar tus redes en tu perfil de Shakers.', after: 'Hecho. Tus redes están guardadas en Shakers.' },
|
|
1258
|
+
experiences: { before: 'Solo leo tus experiencias de tu perfil de Shakers; no cambio nada.' },
|
|
1259
|
+
portfolios: { before: 'Solo leo tu portfolio de tu perfil de Shakers; no cambio nada.' },
|
|
1260
|
+
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.' },
|
|
1261
|
+
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.' },
|
|
1262
|
+
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.' },
|
|
1263
|
+
config: { before: 'Trabajo solo con la configuración del CLI en este ordenador (~/.config/shakers); no envío nada a Shakers.' },
|
|
1264
|
+
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.' },
|
|
1265
|
+
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.' },
|
|
1266
|
+
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.' },
|
|
1267
|
+
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.' },
|
|
1268
|
+
},
|
|
1269
|
+
},
|
|
1216
1270
|
// Branded mini-shell chrome.
|
|
1217
1271
|
login: {
|
|
1218
1272
|
intro: 'Inicia sesión con tu email y contraseña de Shakers.',
|
|
@@ -1224,28 +1278,14 @@ const catalogs = {
|
|
|
1224
1278
|
needInput: 'Se necesitan email y contraseña para iniciar sesión.',
|
|
1225
1279
|
success: 'Sesión iniciada. Tu informe ya no incluye el roadmap ni las sugerencias de mejora: tu nivel sale de certificarte.',
|
|
1226
1280
|
expiresAt: (iso) => `La sesión caduca: ${iso}. Cuando expire te lo diré y podrás volver a entrar con \`login\`.`,
|
|
1227
|
-
loggedOut: 'Sesión cerrada. Vuelves a ver
|
|
1281
|
+
loggedOut: 'Sesión cerrada. Vuelves a ver las sugerencias de mejora en tu informe.',
|
|
1228
1282
|
notLoggedIn: 'No había ninguna sesión iniciada. No hay nada que cerrar.',
|
|
1229
|
-
errorInvalidCredentials: 'Credenciales incorrectas: revisa tu email y contraseña e inténtalo otra vez.',
|
|
1230
|
-
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.',
|
|
1231
1283
|
errorUpstream: 'El servidor de identidad de Shakers no responde ahora mismo. No es tu contraseña; inténtalo de nuevo en un rato.',
|
|
1232
1284
|
errorUnreachable: 'No se pudo conectar con Shakers. Comprueba tu conexión y vuelve a ejecutar `login`.',
|
|
1233
1285
|
errorConfig: 'La dirección del servidor no es válida. Revisa la configuración del endpoint (`usage --show-endpoint`).',
|
|
1234
1286
|
errorNoEndpoint: 'No hay endpoint configurado. login usa la misma base que usage: define SHAKERS_CLI_INGEST_ENDPOINT o usa `usage --set-endpoint <url>`.',
|
|
1235
1287
|
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.',
|
|
1236
1288
|
errorGeneric: 'No se pudo iniciar sesión. Inténtalo de nuevo.',
|
|
1237
|
-
// Login con Google por loopback (`login --google`).
|
|
1238
|
-
googleIntro: 'Inicia sesión con Google. Se abrirá tu navegador para autorizar; al terminar, vuelve aquí.',
|
|
1239
|
-
googleOpening: 'Abriendo el navegador para iniciar sesión con Google…',
|
|
1240
|
-
googlePasteUrl: 'Si el navegador no se abre solo, pega esta URL en él:',
|
|
1241
|
-
googleWaiting: 'Esperando a que completes el acceso en el navegador…',
|
|
1242
|
-
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.',
|
|
1243
|
-
googleErrorConfigInvalid: 'La configuración de Google que devolvió Shakers está incompleta. Es un problema del servidor, no tuyo; inténtalo más tarde.',
|
|
1244
|
-
googleErrorPortInUse: 'El puerto local que usa el login de Google está ocupado por otro proceso. Ciérralo y vuelve a ejecutar `login --google`.',
|
|
1245
|
-
googleErrorTimeout: 'Se agotó el tiempo esperando a que completaras el acceso en el navegador. Vuelve a ejecutar `login --google` cuando estés listo.',
|
|
1246
|
-
googleErrorState: 'La respuesta del navegador no coincidió con lo esperado (posible interferencia). Por seguridad no se inició sesión; inténtalo de nuevo.',
|
|
1247
|
-
googleErrorDenied: 'Cancelaste el acceso en Google (o no se concedió). No se inició sesión.',
|
|
1248
|
-
googleErrorGeneric: 'No se pudo iniciar sesión con Google. Inténtalo de nuevo.',
|
|
1249
1289
|
// 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.
|
|
1250
1290
|
deviceIntro: (name) => `Inicia sesión con ${name}. Abre el enlace de abajo e introduce el código para autorizar; luego vuelve aquí.`,
|
|
1251
1291
|
// 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.
|
|
@@ -1254,6 +1294,8 @@ const catalogs = {
|
|
|
1254
1294
|
deviceCodeLabel: (code) => `e introduce este código: ${code}`,
|
|
1255
1295
|
deviceWaiting: 'Esperando a que autorices en el navegador…',
|
|
1256
1296
|
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.',
|
|
1297
|
+
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.',
|
|
1298
|
+
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`.',
|
|
1257
1299
|
deviceErrorExpired: 'La solicitud de acceso caducó antes de autorizarse. Vuelve a ejecutar `login` cuando estés listo.',
|
|
1258
1300
|
deviceErrorDenied: 'Se canceló el acceso (o no se concedió). No se inició sesión.',
|
|
1259
1301
|
deviceErrorGeneric: 'No se pudo iniciar sesión. Inténtalo de nuevo.',
|
|
@@ -1660,13 +1702,10 @@ const catalogs = {
|
|
|
1660
1702
|
askCv: 'Path to your CV PDF (optional, Enter to skip):',
|
|
1661
1703
|
askGithub: 'Your GitHub URL (optional, Enter to skip):',
|
|
1662
1704
|
askWebsite: 'Your personal website (optional, Enter to skip):',
|
|
1663
|
-
importStarted: 'Importing your profile in the background while we continue…',
|
|
1664
|
-
importError: 'Could not start your profile import.',
|
|
1665
1705
|
importUnavailable: 'We could not import your profile right now (service unavailable); we are continuing with your registration, you can retry the import later.',
|
|
1666
1706
|
importChecking: 'Importing your profile…',
|
|
1667
1707
|
importDone: 'Profile imported successfully.',
|
|
1668
1708
|
importFailed: 'We could not finish importing your profile. You can retry it later from your profile.',
|
|
1669
|
-
importStillRunning: 'Your profile is still importing in the background; it will be ready in a few minutes.',
|
|
1670
1709
|
professionalTitle: 'Your work situation',
|
|
1671
1710
|
askWorkSituation: "What's your current work situation? Choose one:",
|
|
1672
1711
|
workSituationLabels: {
|
|
@@ -1699,27 +1738,13 @@ const catalogs = {
|
|
|
1699
1738
|
professionalSaved: 'Work situation saved.',
|
|
1700
1739
|
chooseMethodHeading: 'How do you want to create your account?',
|
|
1701
1740
|
signupTitle: 'Create your Shakers account',
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
askPassword: 'Password (at least 8 characters):',
|
|
1706
|
-
askPasswordConfirm: 'Repeat the password:',
|
|
1707
|
-
passwordMismatch: 'The passwords do not match. Try again.',
|
|
1708
|
-
askFreelanceTypeSelect: 'How do you work? Choose one:',
|
|
1709
|
-
freelanceTypeLabels: {
|
|
1710
|
-
FREELANCE: 'Freelance',
|
|
1711
|
-
EMPLOYEE: 'Employed',
|
|
1712
|
-
AGENCY: 'Agency or company',
|
|
1713
|
-
POTENTIAL_FREELANCE: 'Considering freelancing',
|
|
1714
|
-
},
|
|
1715
|
-
invalidChoice: 'Invalid option.',
|
|
1716
|
-
askNewsletter: 'Do you want the newsletter? (y/n):',
|
|
1717
|
-
weakPassword: 'The password does not meet the requirements (at least 8 characters).',
|
|
1741
|
+
termsAsk: 'Do you accept, to create your account? [y/N]',
|
|
1742
|
+
termsDeclined: 'Without accepting the Terms and the Privacy Policy your account cannot be created. Nothing was created and nothing was sent to Shakers.',
|
|
1743
|
+
newsletterAsk: (label) => `Optional: ${label} [y/N]`,
|
|
1718
1744
|
signupError: 'Could not create the account.',
|
|
1719
1745
|
freelanceIntentRequired: 'Your freelance intent is required for that type.',
|
|
1720
|
-
accountExists: '
|
|
1721
|
-
accountReady: 'Account created. Signed in
|
|
1722
|
-
sessionError: 'The account was created but sign-in failed. Run `shakers login`.',
|
|
1746
|
+
accountExists: 'You already had a Shakers account: you are now signed in with it on this computer.',
|
|
1747
|
+
accountReady: 'Account created. Signed in only on this computer (~/.config/shakers); to end it: `shakers logout`.',
|
|
1723
1748
|
pricingTitle: 'Your per-project price',
|
|
1724
1749
|
pricingSaved: 'Price saved.',
|
|
1725
1750
|
askPricingFullAmount: (cur) => `Full-time project price in ${cur} (number, no thousands separators, e.g. 60000):`,
|
|
@@ -1794,7 +1819,6 @@ const catalogs = {
|
|
|
1794
1819
|
repeatNotFound: 'You have no onboarding yet. Run `shakers onboarding` first.',
|
|
1795
1820
|
repeatAuthError: 'Your session does not allow this action. Sign in again: shakers login',
|
|
1796
1821
|
repeatFailed: (reason) => `Could not reset the onboarding (${reason}). Try again.`,
|
|
1797
|
-
interviewAnswer: 'Your answer:',
|
|
1798
1822
|
questionHeading: (n) => `Question ${n}`,
|
|
1799
1823
|
interviewTurnError: 'Could not continue the interview.',
|
|
1800
1824
|
thinking: 'Alma is thinking…',
|
|
@@ -1851,7 +1875,7 @@ const catalogs = {
|
|
|
1851
1875
|
t2Met: (n) => `You have at least one persistent context file — instructions, config or rules — for some tool (you have ${n}).`,
|
|
1852
1876
|
t3Met: (n) => `You have at least one connected MCP server, giving the AI access to external data or tools (you have ${n}).`,
|
|
1853
1877
|
t4Met: (n) => `You've created your own assets — skills, commands or custom rules — beyond the default configuration (you have ${n}).`,
|
|
1854
|
-
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).`,
|
|
1878
|
+
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).`,
|
|
1855
1879
|
t6Met: (n) => `You have a team of at least 2 specialized agents defined (you have ${n}).`,
|
|
1856
1880
|
t7Met: (n) => `You have hook-based automation configured (you have ${n}).`,
|
|
1857
1881
|
t1Blocking: (n) => `To reach T1 (First tool) you need at least one detected AI tool — you have ${n} now.`,
|
|
@@ -1860,7 +1884,7 @@ const catalogs = {
|
|
|
1860
1884
|
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.`,
|
|
1861
1885
|
t5Blocking: (hasAgentic, mcp, custom) => {
|
|
1862
1886
|
const missing = [];
|
|
1863
|
-
if (!hasAgentic) missing.push('an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI or Amazon Q Developer)');
|
|
1887
|
+
if (!hasAgentic) missing.push('an agentic CLI (Claude Code, Aider, Gemini CLI, Codex CLI, Pi, OpenCode or Amazon Q Developer)');
|
|
1864
1888
|
if (mcp < 1) missing.push('at least 1 MCP server');
|
|
1865
1889
|
if (custom < 1) missing.push('at least 1 asset of your own (skill, command or rule)');
|
|
1866
1890
|
return `To reach T5 (Agentic operator) you're missing: ${missing.join('; ')}.`;
|
|
@@ -2094,7 +2118,7 @@ const catalogs = {
|
|
|
2094
2118
|
roadmapPersonalizedNotice: 'Content adapted to your project.',
|
|
2095
2119
|
// See the Spanish catalog for why these say what was lost
|
|
2096
2120
|
// rather than what went wrong, and when they are allowed to show.
|
|
2097
|
-
roadmapNotPersonalizedNotice: 'This roadmap is the generic one for your tier: it could not be adapted to your project this run. Run `usage` again to retry.',
|
|
2121
|
+
roadmapNotPersonalizedNotice: 'This roadmap is the generic one for your tier: it could not be adapted to your project this run. Run `usage --roadmap` again to retry.',
|
|
2098
2122
|
// See the Spanish catalog for why the tag sits next to the
|
|
2099
2123
|
// heading instead of in a footnote.
|
|
2100
2124
|
roadmapNowLabel: 'Where you start from',
|
|
@@ -2178,9 +2202,9 @@ const catalogs = {
|
|
|
2178
2202
|
},
|
|
2179
2203
|
frameworkIntroUsage:
|
|
2180
2204
|
'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).',
|
|
2181
|
-
scanningLabel: '
|
|
2205
|
+
scanningLabel: 'Reading the setup of your AI tools and your projects on this computer (nothing has left your computer yet)…',
|
|
2182
2206
|
// Loader for the per-selected-repo aggregation phase (git + sessions + steering/decisions + evidence + agent org chart).
|
|
2183
|
-
aggregatingLabel: '
|
|
2207
|
+
aggregatingLabel: 'Reading the git and AI-session history of the chosen repos to extract signals (nothing has left your computer yet)…',
|
|
2184
2208
|
reposScopePromptHeader: 'What do you want to evaluate?',
|
|
2185
2209
|
reposScopePromptHint: 'Arrows to move · enter to choose',
|
|
2186
2210
|
reposScopeOptionMachine: 'Whole machine (every repo with AI activity)',
|
|
@@ -2198,6 +2222,7 @@ const catalogs = {
|
|
|
2198
2222
|
reposScopeAll: 'Evaluating all AI usage on this machine.',
|
|
2199
2223
|
synthesizingLabel: 'Synthesizing agents with AI…',
|
|
2200
2224
|
personalizingRoadmapLabel: 'Personalizing roadmap…',
|
|
2225
|
+
roadmapNotForAccounts: 'The roadmap is not available for Shakers accounts: your level comes from certifying.',
|
|
2201
2226
|
// Agent definition-quality evaluation (ephemeral LLM call).
|
|
2202
2227
|
evaluatingAgentsLabel: 'Evaluating your agents’ quality…',
|
|
2203
2228
|
buildNextLevelHint: 'Alternatively, run `usage --build-next-level` to generate the starter file directly in your project.',
|
|
@@ -2214,7 +2239,7 @@ const catalogs = {
|
|
|
2214
2239
|
+ ' --repo Evaluate the current repo only\n'
|
|
2215
2240
|
+ ' --scope machine|repo Same as --machine / --repo (skips the picker)\n'
|
|
2216
2241
|
+ ' --all-repos Alias of --machine\n'
|
|
2217
|
-
+ ' --roadmap Show the steps to raise your AI-usage level (
|
|
2242
|
+
+ ' --roadmap Show the steps to raise your AI-usage level (only without a Shakers account)\n'
|
|
2218
2243
|
+ ' --build-next-level Generate the next tier starter (secondary alternative)\n'
|
|
2219
2244
|
+ ' --force With --build-next-level, overwrite an existing file\n'
|
|
2220
2245
|
+ ' --lang es|en Force the language (report + prompt) instead of OS detection\n'
|
|
@@ -2261,10 +2286,20 @@ const catalogs = {
|
|
|
2261
2286
|
persistIntro:
|
|
2262
2287
|
'This report has already been generated and shown on your machine, '
|
|
2263
2288
|
+ 'always. Saving it in Shakers is optional and revocable at any '
|
|
2264
|
-
+
|
|
2289
|
+
+ 'time (usage --consent-revoke). It sends your level/tier, '
|
|
2265
2290
|
+ 'structured signals derived across categories (tools, MCP, memory, '
|
|
2266
|
-
+ 'automations, agents, technologies)
|
|
2267
|
-
+ '
|
|
2291
|
+
+ 'automations, agents, technologies) and literal text: fragments of '
|
|
2292
|
+
+ 'your conversations with AI assistants (those in the analysed '
|
|
2293
|
+
+ 'repositories, or all of them on this machine if you analyse the '
|
|
2294
|
+
+ "whole machine), sample commands and your agents' definitions, "
|
|
2295
|
+
+ 'after removing anything that looks like a '
|
|
2296
|
+
+ 'secret. Before each upload you see what is sent. An AI model from '
|
|
2297
|
+
+ 'an external provider (OpenAI, Google or Anthropic) analyses it on '
|
|
2298
|
+
+ "Shakers' behalf to compute your evaluation and discards it: "
|
|
2299
|
+
+ 'only the result is kept (levels, scores, counts and the names of '
|
|
2300
|
+
+ 'your tools and agents). Do not use it on machines or '
|
|
2301
|
+
+ 'conversations holding data you are not allowed to share (client, '
|
|
2302
|
+
+ 'employer or third-party data). '
|
|
2268
2303
|
+ 'This same decision also authorizes, only if you accept, a '
|
|
2269
2304
|
+ 'third-party observability provider (Datadog) to capture the '
|
|
2270
2305
|
+ "content these optional AI calls send (sampled code, agent "
|
|
@@ -2287,7 +2322,7 @@ const catalogs = {
|
|
|
2287
2322
|
// This question is now asked BEFORE any AI/egress call (agent-synthesis, agent-evaluation, roadmap personalization), not after.
|
|
2288
2323
|
noReportWithoutConsent: 'Without your consent, this report will not include AI-generated synthesis, evaluation, or roadmap this time (the rest of the report is shown as usual). Run `usage` again and accept to include them, or use --consent-reset if you want to be asked again.',
|
|
2289
2324
|
deniedSaved: 'Understood, nothing will be saved. You can change your mind later by running the command again.',
|
|
2290
|
-
grantedSaved: (email) => `Thanks.
|
|
2325
|
+
grantedSaved: (email) => `Thanks. Before anything is uploaded to Shakers I will show you what would be sent, and I will upload it only if you approve it (email: ${email}, at most once an hour).`,
|
|
2291
2326
|
// A logged-in Talent is NEVER asked for an email (their account already proves identity).
|
|
2292
2327
|
noSessionEmail: "There's no email on file for your session yet, so this report can't be saved this time. You'll be asked again next run.",
|
|
2293
2328
|
skipAlreadyDecided: (decision, path) =>
|
|
@@ -2296,6 +2331,9 @@ const catalogs = {
|
|
|
2296
2331
|
nonInteractiveWarning:
|
|
2297
2332
|
'Non-interactive input (no TTY) detected: if no answer arrives via stdin, consent will not be '
|
|
2298
2333
|
+ 'saved this run and you will be asked again next time.',
|
|
2334
|
+
nonInteractiveUnanswered:
|
|
2335
|
+
'No answer arrived, so your consent is still undecided and nothing was saved in or sent to Shakers. '
|
|
2336
|
+
+ 'Run `shakers ai-usage` in your own terminal to answer.',
|
|
2299
2337
|
status: {
|
|
2300
2338
|
heading: 'Consent status (saved in Shakers)',
|
|
2301
2339
|
decisionGranted: 'Decision: granted',
|
|
@@ -2609,12 +2647,13 @@ const catalogs = {
|
|
|
2609
2647
|
},
|
|
2610
2648
|
mcpInstall: {
|
|
2611
2649
|
title: 'Connecting the Shakers MCP',
|
|
2612
|
-
clients: { claudeDesktop: 'Claude Desktop', claudeCode: 'Claude Code', cursor: 'Cursor', geminiCli: 'Gemini CLI', codex: 'Codex
|
|
2650
|
+
clients: { claudeDesktop: 'Claude Desktop', claudeCode: 'Claude Code', cursor: 'Cursor', geminiCli: 'Gemini CLI', codex: 'Codex / ChatGPT', vscode: 'VS Code', windsurf: 'Windsurf' },
|
|
2613
2651
|
status: {
|
|
2614
2652
|
configured: 'connected',
|
|
2615
2653
|
unchanged: 'already connected',
|
|
2616
2654
|
'not-found': 'not installed on this machine',
|
|
2617
|
-
'invalid-
|
|
2655
|
+
'invalid-config': 'its config cannot be edited safely; left untouched',
|
|
2656
|
+
manual: 'run this command in your terminal:',
|
|
2618
2657
|
failed: 'could not connect',
|
|
2619
2658
|
},
|
|
2620
2659
|
removedLegacy: 'Replaces the old "shakers-ai-usage" entry.',
|
|
@@ -2622,10 +2661,27 @@ const catalogs = {
|
|
|
2622
2661
|
confirm: 'Connect Shakers to them so you can use it from your AI? [Y/n]',
|
|
2623
2662
|
declined: 'Nothing touched. To connect it later, run the installer again.',
|
|
2624
2663
|
noTerminal: 'There is no terminal to ask you on, so nothing was touched. Run the installer again in your terminal to connect it.',
|
|
2625
|
-
restart:
|
|
2664
|
+
restart: (apps) => `Restart ${apps} (or reload their MCP servers) so the Shakers tools appear.`,
|
|
2665
|
+
alreadyConnected: 'Shakers was already connected. If its tools do not appear, restart the app or reload its MCP servers.',
|
|
2666
|
+
yesHint: 'To connect them without being asked (for example from an AI assistant): shakers mcp install --yes',
|
|
2667
|
+
help: 'mcp install — connect Shakers to the AI apps on this machine (Claude Desktop, Claude Code, Cursor, Gemini CLI, Codex / ChatGPT, VS Code, Windsurf).\n\nUsage:\n shakers mcp install ask on the terminal, then connect every app found\n shakers mcp install --yes connect without asking (-y; for AI assistants and scripts)\n shakers mcp install --json print the result as one JSON object\n\nWithout --yes and without a terminal, nothing is touched. SHAKERS_MCP_INSTALL=1 works like --yes.\nWhen it finishes, restart the apps it names (or reload their MCP servers) so the Shakers tools appear.',
|
|
2626
2668
|
noneFound: 'Found no supported AI app on this machine.',
|
|
2627
2669
|
failedAll: 'Could not connect Shakers to your AI apps. Re-run this installer to retry.',
|
|
2628
2670
|
},
|
|
2671
|
+
skillInstall: {
|
|
2672
|
+
title: 'Installing the shakers-cli skill for your AI agents',
|
|
2673
|
+
agents: { claudeCode: 'Claude Code', codex: 'Codex' },
|
|
2674
|
+
status: { installed: 'installed', failed: 'could not install' },
|
|
2675
|
+
found: (agents) => `Found: ${agents}.`,
|
|
2676
|
+
confirm: 'Install the skill so your agent knows how to use the Shakers CLI? [Y/n]',
|
|
2677
|
+
declined: 'Nothing touched. To install it later: shakers skill install',
|
|
2678
|
+
noTerminal: 'There is no terminal to ask you on, so nothing was touched.',
|
|
2679
|
+
yesHint: 'To install it without being asked (for example from an AI assistant): shakers skill install --yes',
|
|
2680
|
+
noneFound: 'Found neither Claude Code nor Codex on this machine; nothing touched.',
|
|
2681
|
+
done: (agents) => `Done. If ${agents} does not see the skill, start a new session.`,
|
|
2682
|
+
failedAll: 'Could not install the skill. Run shakers skill install again to retry.',
|
|
2683
|
+
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.',
|
|
2684
|
+
},
|
|
2629
2685
|
rate: {
|
|
2630
2686
|
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).',
|
|
2631
2687
|
loginRequired: '"rate" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
|
|
@@ -2846,6 +2902,46 @@ const catalogs = {
|
|
|
2846
2902
|
remediationCopiedLabel: 'Copied ✓',
|
|
2847
2903
|
},
|
|
2848
2904
|
},
|
|
2905
|
+
trust: {
|
|
2906
|
+
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).",
|
|
2907
|
+
cli: {
|
|
2908
|
+
'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`.' },
|
|
2909
|
+
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.' },
|
|
2910
|
+
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.' },
|
|
2911
|
+
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.' },
|
|
2912
|
+
'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.' },
|
|
2913
|
+
'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.', after: 'Done. Your Shakers profile has the agent you picked.' },
|
|
2914
|
+
'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.' },
|
|
2915
|
+
'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.' },
|
|
2916
|
+
'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.' },
|
|
2917
|
+
'find-projects': { before: 'I only read from Shakers the projects that fit you; I change nothing.' },
|
|
2918
|
+
'show-project': { before: 'I only read the project details from Shakers; I change nothing.' },
|
|
2919
|
+
'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.' },
|
|
2920
|
+
'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.' },
|
|
2921
|
+
invitations: { before: 'I only read your Shakers invitations; I change nothing.' },
|
|
2922
|
+
applications: { before: 'I only read your Shakers applications; I change nothing.' },
|
|
2923
|
+
availability: { before: 'I only read your availability from your Shakers profile; I change nothing.' },
|
|
2924
|
+
'availability:set': { before: 'I am going to change your availability on your Shakers profile.', after: 'Done. Your availability is saved on Shakers.' },
|
|
2925
|
+
certifications: { before: 'I only read your Shakers certifications; I change nothing.' },
|
|
2926
|
+
me: { before: 'I only read your Shakers profile; I change nothing.' },
|
|
2927
|
+
rate: { before: 'I only read your rate from your Shakers profile; I change nothing.' },
|
|
2928
|
+
'rate:set': { before: 'I am going to change your rate on your Shakers profile.', after: 'Done. Your rate is saved on Shakers.' },
|
|
2929
|
+
lang: { before: 'I only read your languages from your Shakers profile; I change nothing.' },
|
|
2930
|
+
'lang:set': { before: 'I am going to change your languages on your Shakers profile.', after: 'Done. Your languages are saved on Shakers.' },
|
|
2931
|
+
socials: { before: 'I only read your social links from your Shakers profile; I change nothing.' },
|
|
2932
|
+
'socials:set': { before: 'I am going to change your social links on your Shakers profile.', after: 'Done. Your social links are saved on Shakers.' },
|
|
2933
|
+
experiences: { before: 'I only read your experiences from your Shakers profile; I change nothing.' },
|
|
2934
|
+
portfolios: { before: 'I only read your portfolio from your Shakers profile; I change nothing.' },
|
|
2935
|
+
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.' },
|
|
2936
|
+
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.' },
|
|
2937
|
+
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.' },
|
|
2938
|
+
config: { before: 'I only work with the CLI configuration on this computer (~/.config/shakers); I send nothing to Shakers.' },
|
|
2939
|
+
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.' },
|
|
2940
|
+
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.' },
|
|
2941
|
+
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.' },
|
|
2942
|
+
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.' },
|
|
2943
|
+
},
|
|
2944
|
+
},
|
|
2849
2945
|
// Branded mini-shell chrome.
|
|
2850
2946
|
login: {
|
|
2851
2947
|
intro: 'Log in with your Shakers email and password.',
|
|
@@ -2857,28 +2953,14 @@ const catalogs = {
|
|
|
2857
2953
|
needInput: 'Email and password are required to log in.',
|
|
2858
2954
|
success: 'Logged in. Your report no longer includes the roadmap or the improvement suggestions: your level comes from certifying.',
|
|
2859
2955
|
expiresAt: (iso) => `The session expires: ${iso}. When it does I will tell you, and you can log in again with \`login\`.`,
|
|
2860
|
-
loggedOut: 'Logged out.
|
|
2956
|
+
loggedOut: 'Logged out. Your report shows the improvement suggestions again.',
|
|
2861
2957
|
notLoggedIn: 'No session was active. Nothing to log out of.',
|
|
2862
|
-
errorInvalidCredentials: 'Wrong credentials: check your email and password and try again.',
|
|
2863
|
-
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.',
|
|
2864
2958
|
errorUpstream: "Shakers' identity server is not responding right now. It is not your password; try again in a while.",
|
|
2865
2959
|
errorUnreachable: 'Could not reach Shakers. Check your connection and run `login` again.',
|
|
2866
2960
|
errorConfig: 'The server address is invalid. Check the endpoint configuration (`usage --show-endpoint`).',
|
|
2867
2961
|
errorNoEndpoint: 'No endpoint configured. login uses the same base as usage: set SHAKERS_CLI_INGEST_ENDPOINT or use `usage --set-endpoint <url>`.',
|
|
2868
2962
|
errorPersist: 'Login succeeded, but the session could not be saved to disk. Check the permissions of ~/.config/shakers and try again.',
|
|
2869
2963
|
errorGeneric: 'Could not log in. Try again.',
|
|
2870
|
-
// Google login by loopback (`login --google`).
|
|
2871
|
-
googleIntro: 'Log in with Google. Your browser will open to authorize; when you are done, come back here.',
|
|
2872
|
-
googleOpening: 'Opening your browser to log in with Google…',
|
|
2873
|
-
googlePasteUrl: 'If your browser does not open on its own, paste this URL into it:',
|
|
2874
|
-
googleWaiting: 'Waiting for you to finish signing in in the browser…',
|
|
2875
|
-
googleErrorConfigFailed: "Could not fetch the Google login configuration from Shakers. Check your connection and the endpoint (`usage --show-endpoint`) and try again.",
|
|
2876
|
-
googleErrorConfigInvalid: 'The Google configuration Shakers returned is incomplete. This is a server-side problem, not yours; try again later.',
|
|
2877
|
-
googleErrorPortInUse: 'The local port the Google login uses is busy with another process. Close it and run `login --google` again.',
|
|
2878
|
-
googleErrorTimeout: 'Timed out waiting for you to finish signing in in the browser. Run `login --google` again when you are ready.',
|
|
2879
|
-
googleErrorState: 'The browser response did not match what was expected (possible interference). For safety no session was started; try again.',
|
|
2880
|
-
googleErrorDenied: 'You cancelled access in Google (or it was not granted). No session was started.',
|
|
2881
|
-
googleErrorGeneric: 'Could not log in with Google. Try again.',
|
|
2882
2964
|
// 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.
|
|
2883
2965
|
deviceIntro: (name) => `Sign in with ${name}. Open the link below and enter the code to authorize; then come back here.`,
|
|
2884
2966
|
// 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.
|
|
@@ -2887,6 +2969,8 @@ const catalogs = {
|
|
|
2887
2969
|
deviceCodeLabel: (code) => `and enter this code: ${code}`,
|
|
2888
2970
|
deviceWaiting: 'Waiting for you to authorize in the browser…',
|
|
2889
2971
|
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.',
|
|
2972
|
+
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.',
|
|
2973
|
+
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`.',
|
|
2890
2974
|
deviceErrorExpired: 'The sign-in request expired before it was authorized. Run `login` again when you are ready.',
|
|
2891
2975
|
deviceErrorDenied: 'The sign-in was cancelled or not granted. No session was started.',
|
|
2892
2976
|
deviceErrorGeneric: 'Could not sign in. Try again.',
|