shakers-cli 0.17.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 +15 -5
- package/bin/command-audit-worker.js +19 -0
- package/bin/login.js +4 -8
- package/bin/mcp.js +29 -19
- package/bin/register.js +10 -29
- package/bin/shakers-cli.js +14 -9
- package/package.json +1 -1
- package/src/agents-client.js +1 -0
- package/src/ai-usage-review.js +5 -3
- 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 +47 -4
- package/src/config.js +0 -16
- package/src/consent-flow.js +7 -2
- 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 +162 -88
- package/src/mcp-ai-usage-result-tool.js +6 -4
- package/src/mcp-ai-usage-tool.js +72 -46
- 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 +1 -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 +380 -68
- package/src/skill-install.js +102 -0
- package/src/tier-engine.js +14 -2
- package/src/trust-narration.js +32 -0
- package/src/usage-run-steps.js +12 -3
- 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)',
|
|
@@ -994,6 +989,20 @@ const catalogs = {
|
|
|
994
989
|
noneFound: 'No he encontrado ninguna app de IA compatible en esta máquina.',
|
|
995
990
|
failedAll: 'No he podido conectar Shakers a tus apps de IA. Vuelve a ejecutar el instalador para reintentarlo.',
|
|
996
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
|
+
},
|
|
997
1006
|
rate: {
|
|
998
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).',
|
|
999
1008
|
loginRequired: '"rate" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
|
|
@@ -1218,6 +1227,46 @@ const catalogs = {
|
|
|
1218
1227
|
remediationCopiedLabel: 'Copiado ✓',
|
|
1219
1228
|
},
|
|
1220
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
|
+
},
|
|
1221
1270
|
// Branded mini-shell chrome.
|
|
1222
1271
|
login: {
|
|
1223
1272
|
intro: 'Inicia sesión con tu email y contraseña de Shakers.',
|
|
@@ -1231,26 +1280,12 @@ const catalogs = {
|
|
|
1231
1280
|
expiresAt: (iso) => `La sesión caduca: ${iso}. Cuando expire te lo diré y podrás volver a entrar con \`login\`.`,
|
|
1232
1281
|
loggedOut: 'Sesión cerrada. Vuelves a ver las sugerencias de mejora en tu informe.',
|
|
1233
1282
|
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
1283
|
errorUpstream: 'El servidor de identidad de Shakers no responde ahora mismo. No es tu contraseña; inténtalo de nuevo en un rato.',
|
|
1237
1284
|
errorUnreachable: 'No se pudo conectar con Shakers. Comprueba tu conexión y vuelve a ejecutar `login`.',
|
|
1238
1285
|
errorConfig: 'La dirección del servidor no es válida. Revisa la configuración del endpoint (`usage --show-endpoint`).',
|
|
1239
1286
|
errorNoEndpoint: 'No hay endpoint configurado. login usa la misma base que usage: define SHAKERS_CLI_INGEST_ENDPOINT o usa `usage --set-endpoint <url>`.',
|
|
1240
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.',
|
|
1241
1288
|
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
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.
|
|
1255
1290
|
deviceIntro: (name) => `Inicia sesión con ${name}. Abre el enlace de abajo e introduce el código para autorizar; luego vuelve aquí.`,
|
|
1256
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.
|
|
@@ -1259,6 +1294,8 @@ const catalogs = {
|
|
|
1259
1294
|
deviceCodeLabel: (code) => `e introduce este código: ${code}`,
|
|
1260
1295
|
deviceWaiting: 'Esperando a que autorices en el navegador…',
|
|
1261
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`.',
|
|
1262
1299
|
deviceErrorExpired: 'La solicitud de acceso caducó antes de autorizarse. Vuelve a ejecutar `login` cuando estés listo.',
|
|
1263
1300
|
deviceErrorDenied: 'Se canceló el acceso (o no se concedió). No se inició sesión.',
|
|
1264
1301
|
deviceErrorGeneric: 'No se pudo iniciar sesión. Inténtalo de nuevo.',
|
|
@@ -1665,13 +1702,10 @@ const catalogs = {
|
|
|
1665
1702
|
askCv: 'Path to your CV PDF (optional, Enter to skip):',
|
|
1666
1703
|
askGithub: 'Your GitHub URL (optional, Enter to skip):',
|
|
1667
1704
|
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
1705
|
importUnavailable: 'We could not import your profile right now (service unavailable); we are continuing with your registration, you can retry the import later.',
|
|
1671
1706
|
importChecking: 'Importing your profile…',
|
|
1672
1707
|
importDone: 'Profile imported successfully.',
|
|
1673
1708
|
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
1709
|
professionalTitle: 'Your work situation',
|
|
1676
1710
|
askWorkSituation: "What's your current work situation? Choose one:",
|
|
1677
1711
|
workSituationLabels: {
|
|
@@ -1704,27 +1738,13 @@ const catalogs = {
|
|
|
1704
1738
|
professionalSaved: 'Work situation saved.',
|
|
1705
1739
|
chooseMethodHeading: 'How do you want to create your account?',
|
|
1706
1740
|
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).',
|
|
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]`,
|
|
1723
1744
|
signupError: 'Could not create the account.',
|
|
1724
1745
|
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`.',
|
|
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`.',
|
|
1728
1748
|
pricingTitle: 'Your per-project price',
|
|
1729
1749
|
pricingSaved: 'Price saved.',
|
|
1730
1750
|
askPricingFullAmount: (cur) => `Full-time project price in ${cur} (number, no thousands separators, e.g. 60000):`,
|
|
@@ -1799,7 +1819,6 @@ const catalogs = {
|
|
|
1799
1819
|
repeatNotFound: 'You have no onboarding yet. Run `shakers onboarding` first.',
|
|
1800
1820
|
repeatAuthError: 'Your session does not allow this action. Sign in again: shakers login',
|
|
1801
1821
|
repeatFailed: (reason) => `Could not reset the onboarding (${reason}). Try again.`,
|
|
1802
|
-
interviewAnswer: 'Your answer:',
|
|
1803
1822
|
questionHeading: (n) => `Question ${n}`,
|
|
1804
1823
|
interviewTurnError: 'Could not continue the interview.',
|
|
1805
1824
|
thinking: 'Alma is thinking…',
|
|
@@ -1856,7 +1875,7 @@ const catalogs = {
|
|
|
1856
1875
|
t2Met: (n) => `You have at least one persistent context file — instructions, config or rules — for some tool (you have ${n}).`,
|
|
1857
1876
|
t3Met: (n) => `You have at least one connected MCP server, giving the AI access to external data or tools (you have ${n}).`,
|
|
1858
1877
|
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).`,
|
|
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).`,
|
|
1860
1879
|
t6Met: (n) => `You have a team of at least 2 specialized agents defined (you have ${n}).`,
|
|
1861
1880
|
t7Met: (n) => `You have hook-based automation configured (you have ${n}).`,
|
|
1862
1881
|
t1Blocking: (n) => `To reach T1 (First tool) you need at least one detected AI tool — you have ${n} now.`,
|
|
@@ -1865,7 +1884,7 @@ const catalogs = {
|
|
|
1865
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.`,
|
|
1866
1885
|
t5Blocking: (hasAgentic, mcp, custom) => {
|
|
1867
1886
|
const missing = [];
|
|
1868
|
-
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)');
|
|
1869
1888
|
if (mcp < 1) missing.push('at least 1 MCP server');
|
|
1870
1889
|
if (custom < 1) missing.push('at least 1 asset of your own (skill, command or rule)');
|
|
1871
1890
|
return `To reach T5 (Agentic operator) you're missing: ${missing.join('; ')}.`;
|
|
@@ -2183,9 +2202,9 @@ const catalogs = {
|
|
|
2183
2202
|
},
|
|
2184
2203
|
frameworkIntroUsage:
|
|
2185
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).',
|
|
2186
|
-
scanningLabel: '
|
|
2205
|
+
scanningLabel: 'Reading the setup of your AI tools and your projects on this computer (nothing has left your computer yet)…',
|
|
2187
2206
|
// Loader for the per-selected-repo aggregation phase (git + sessions + steering/decisions + evidence + agent org chart).
|
|
2188
|
-
aggregatingLabel: '
|
|
2207
|
+
aggregatingLabel: 'Reading the git and AI-session history of the chosen repos to extract signals (nothing has left your computer yet)…',
|
|
2189
2208
|
reposScopePromptHeader: 'What do you want to evaluate?',
|
|
2190
2209
|
reposScopePromptHint: 'Arrows to move · enter to choose',
|
|
2191
2210
|
reposScopeOptionMachine: 'Whole machine (every repo with AI activity)',
|
|
@@ -2267,10 +2286,20 @@ const catalogs = {
|
|
|
2267
2286
|
persistIntro:
|
|
2268
2287
|
'This report has already been generated and shown on your machine, '
|
|
2269
2288
|
+ 'always. Saving it in Shakers is optional and revocable at any '
|
|
2270
|
-
+
|
|
2289
|
+
+ 'time (usage --consent-revoke). It sends your level/tier, '
|
|
2271
2290
|
+ 'structured signals derived across categories (tools, MCP, memory, '
|
|
2272
|
-
+ 'automations, agents, technologies)
|
|
2273
|
-
+ '
|
|
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). '
|
|
2274
2303
|
+ 'This same decision also authorizes, only if you accept, a '
|
|
2275
2304
|
+ 'third-party observability provider (Datadog) to capture the '
|
|
2276
2305
|
+ "content these optional AI calls send (sampled code, agent "
|
|
@@ -2302,6 +2331,9 @@ const catalogs = {
|
|
|
2302
2331
|
nonInteractiveWarning:
|
|
2303
2332
|
'Non-interactive input (no TTY) detected: if no answer arrives via stdin, consent will not be '
|
|
2304
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.',
|
|
2305
2337
|
status: {
|
|
2306
2338
|
heading: 'Consent status (saved in Shakers)',
|
|
2307
2339
|
decisionGranted: 'Decision: granted',
|
|
@@ -2636,6 +2668,20 @@ const catalogs = {
|
|
|
2636
2668
|
noneFound: 'Found no supported AI app on this machine.',
|
|
2637
2669
|
failedAll: 'Could not connect Shakers to your AI apps. Re-run this installer to retry.',
|
|
2638
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
|
+
},
|
|
2639
2685
|
rate: {
|
|
2640
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).',
|
|
2641
2687
|
loginRequired: '"rate" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
|
|
@@ -2856,6 +2902,46 @@ const catalogs = {
|
|
|
2856
2902
|
remediationCopiedLabel: 'Copied ✓',
|
|
2857
2903
|
},
|
|
2858
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
|
+
},
|
|
2859
2945
|
// Branded mini-shell chrome.
|
|
2860
2946
|
login: {
|
|
2861
2947
|
intro: 'Log in with your Shakers email and password.',
|
|
@@ -2869,26 +2955,12 @@ const catalogs = {
|
|
|
2869
2955
|
expiresAt: (iso) => `The session expires: ${iso}. When it does I will tell you, and you can log in again with \`login\`.`,
|
|
2870
2956
|
loggedOut: 'Logged out. Your report shows the improvement suggestions again.',
|
|
2871
2957
|
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
2958
|
errorUpstream: "Shakers' identity server is not responding right now. It is not your password; try again in a while.",
|
|
2875
2959
|
errorUnreachable: 'Could not reach Shakers. Check your connection and run `login` again.',
|
|
2876
2960
|
errorConfig: 'The server address is invalid. Check the endpoint configuration (`usage --show-endpoint`).',
|
|
2877
2961
|
errorNoEndpoint: 'No endpoint configured. login uses the same base as usage: set SHAKERS_CLI_INGEST_ENDPOINT or use `usage --set-endpoint <url>`.',
|
|
2878
2962
|
errorPersist: 'Login succeeded, but the session could not be saved to disk. Check the permissions of ~/.config/shakers and try again.',
|
|
2879
2963
|
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
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.
|
|
2893
2965
|
deviceIntro: (name) => `Sign in with ${name}. Open the link below and enter the code to authorize; then come back here.`,
|
|
2894
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.
|
|
@@ -2897,6 +2969,8 @@ const catalogs = {
|
|
|
2897
2969
|
deviceCodeLabel: (code) => `and enter this code: ${code}`,
|
|
2898
2970
|
deviceWaiting: 'Waiting for you to authorize in the browser…',
|
|
2899
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`.',
|
|
2900
2974
|
deviceErrorExpired: 'The sign-in request expired before it was authorized. Run `login` again when you are ready.',
|
|
2901
2975
|
deviceErrorDenied: 'The sign-in was cancelled or not granted. No session was started.',
|
|
2902
2976
|
deviceErrorGeneric: 'Could not sign in. Try again.',
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
const FLOOR_METHOD = 'floor';
|
|
4
4
|
const FLOOR_CODE = 'other-1';
|
|
5
5
|
const POLL_INTERVAL_MS = 5000;
|
|
6
|
-
|
|
6
|
+
// With the last inventory request (its own timeout) this answers within ~45 s, under Claude Desktop's ~60 s cut.
|
|
7
|
+
const POLL_CAP_MS = 30000;
|
|
7
8
|
const INVENTORY_TIMEOUT_MS = 15000;
|
|
8
9
|
|
|
9
10
|
const RESULT_INPUT_SCHEMA = { type: 'object', properties: {} };
|
|
@@ -75,7 +76,8 @@ function makeAiUsageResultTool(deps = {}) {
|
|
|
75
76
|
lang = () => require('./signup-language').signupLanguage(require('./i18n').detectFlowLang()),
|
|
76
77
|
} = deps;
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
// `explained` comes only from the sign-up, whose review already explained the axes and how to disagree.
|
|
80
|
+
async function handler(args = {}) {
|
|
79
81
|
const session = loadAuthSession();
|
|
80
82
|
if (sessionStatus(session) !== 'active') {
|
|
81
83
|
throw new Error('no active Shakers session — sign in with social_signin_start (or run `shakers login`) first.');
|
|
@@ -109,7 +111,7 @@ function makeAiUsageResultTool(deps = {}) {
|
|
|
109
111
|
return {
|
|
110
112
|
...result,
|
|
111
113
|
aiProfile,
|
|
112
|
-
relayVerbatim: resultText(lang(), profileReady ? aiProfile.preview : null),
|
|
114
|
+
relayVerbatim: resultText(lang(), profileReady ? aiProfile.preview : null, { explained: args.explained === true }),
|
|
113
115
|
message: `${RESULT_MESSAGE} ${result.status === 'ready' ? READY_MESSAGE : PENDING_MESSAGE}${profileReady ? '' : ` ${PROFILE_PENDING_MESSAGE}`}`,
|
|
114
116
|
};
|
|
115
117
|
}
|
|
@@ -119,7 +121,7 @@ function makeAiUsageResultTool(deps = {}) {
|
|
|
119
121
|
title: 'Results of your AI analysis',
|
|
120
122
|
description: 'Fetches from Shakers the result of the AI analysis you approved, what it means, and the description of each AI agent found. It reads nothing on this computer.',
|
|
121
123
|
guidance:
|
|
122
|
-
"Retrieve the result after an approved upload: relayVerbatim is the 'My work with AI' result with its levels and explanation in plain words, and how to ask for a human review; print it word for word. It also returns the enriched Shakers classification for the talent's agents. Shakers classifies agents and writes their descriptions server-side (no client LLM), so this reads the result: per agent { name, tools, model, category, role, level, code, whatItDoes }. Session-keyed, no arguments. Server-side classification can take a few minutes, so this does a bounded internal poll (~
|
|
124
|
+
"Retrieve the result after an approved upload: relayVerbatim is the 'My work with AI' result with its levels and explanation in plain words, and how to ask for a human review; print it word for word. It also returns the enriched Shakers classification for the talent's agents. Shakers classifies agents and writes their descriptions server-side (no client LLM), so this reads the result: per agent { name, tools, model, category, role, level, code, whatItDoes }. Session-keyed, no arguments. Server-side classification can take a few minutes, so this does a bounded internal poll (~30 s, never a long-held call): returns { status: 'ready', agents } once every agent has been classified, or { status: 'pending', agents } while Shakers is still processing (call it again to keep waiting — 'pending' is normal progress, not an error). Present agents to the talent by NAME and category/role only; the `code` field is an internal handle for add_agent, never show it. Requires an active session.",
|
|
123
125
|
inputSchema: RESULT_INPUT_SCHEMA,
|
|
124
126
|
handler,
|
|
125
127
|
};
|