shakers-cli-beta 0.8.0-beta.3 → 0.8.0-beta.4

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/bin/mcp.js CHANGED
@@ -53,10 +53,26 @@ const HELP = `\n shakers mcp — local MCP server (stdio)\n\n`
53
53
  + ` list_certifications, get_profile, get_rate, get_languages,\n`
54
54
  + ` list_socials, list_experiences, list_portfolios, ask.\n\n`;
55
55
 
56
+ // The register and onboarding flows span several tools. Clients that load tool
57
+ // schemas on demand only see the tool the model picked first, so the flow lives
58
+ // here, where the client keeps it in context.
59
+ const SERVER_INSTRUCTIONS = [
60
+ 'Shakers talent tools. When the talent asks to register or sign up on Shakers, the goal is that they type almost nothing: you fill the registration from what you know and they confirm.',
61
+ 'Register flow — load and use these tools in this order:',
62
+ '1. suggest_register_context: timezone, git name/email, GitHub login and CV file candidates on this machine.',
63
+ '2. If a CV candidate is clearly theirs (nameMatch) propose it; if only a generic one like cv.pdf exists, ask whether it is theirs and whether you may read it and send it with the registration. With permission call read_cv and use its text.',
64
+ '3. Pre-fill EVERY register field you can infer from your memory of the talent, the chat, that context and the CV, pricing and motivation included (an estimate, labelled as such). Then call register_preview with that payload.',
65
+ '4. Show ONE short summary saying where each value comes from, ask only for what you have no basis for, offer unknown optional fields in a single closing line, and let them confirm or correct once.',
66
+ '5. Only then call register with the confirmed payload.',
67
+ 'Do not open with a questionnaire of empty fields: propose first, ask second.',
68
+ 'Onboarding interview (onboarding_interview_start / onboarding_interview_turn): follow the ANSWER MODE described in onboarding_interview_start.',
69
+ ].join('\n');
70
+
56
71
  function buildServer() {
57
72
  return createMcpServer({
58
73
  tools: [makeAiUsageTool(), makeAiUsageResultTool(), ...makeOnboardingTools(), ...makeRoleTools(), ...makeDeviceLoginTools(), ...makeRegisterTools({ lang: detectFlowLang() }), ...makeReportTools(), ...makeCertifyDimensionTools(), ...makeFindProjectsTools(), ...makeShowProjectTools(), ...makeSavedPositionsTools(), ...makeInvitationsTools(), ...makeApplicationsTools(), ...makeAvailabilityTools(), ...makeCertificationsTools(), ...makeProfileTools(), ...makeRateTools(), ...makeLangTools(), ...makeSocialsTools(), ...makePortfolioTools(), ...makeAskTools(), ...makeAlmaTools()],
59
74
  serverInfo: { name: 'Shakers', version: VERSION || '0.0.0' },
75
+ instructions: SERVER_INSTRUCTIONS,
60
76
  // Long-lived server: refresh the email session's hub JWT from the stored
61
77
  // cookie before each tool call so a stale (~15-min) JWT never reaches a tool.
62
78
  beforeCall: () => ensureFreshSession(process.env),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shakers-cli-beta",
3
- "version": "0.8.0-beta.3",
3
+ "version": "0.8.0-beta.4",
4
4
  "description": "Shakers AI usage & skills evaluator: a local-first CLI (`shakers` binary) plus a local MCP server. Commands: ai-usage (scan + classify your AI-tool setup, T0-T7), certify (certify Skills from your code), share (branded LinkedIn card).",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -96,7 +96,7 @@ function buildSchemas(lang) {
96
96
  // collection guide with friendly labels inline for every choice field.
97
97
  function buildRegisterDescription(lang) {
98
98
  const L = getCatalog(lang).onboarding;
99
- return "The talent registers THEMSELVES on Shakers (self-service; no prior session needed). Your job is to relay the non-secret profile details the talent gives you in the chat as arguments. Credentials never touch the chat or any tool argument: the tool opens a sign-up window on the talent's own machine (127.0.0.1) where they either Continue with Google (no password at all) or type an email and password directly into that local window.\n\nSAVE THE TALENT TYPING: first call suggest_register_context (timezone, local git identity, GitHub login, CV files) and PROPOSE those values for them to confirm; then call register_preview with the partial payload to get a review (what would be written, what is still missing) and show the talent a short summary to confirm or correct BEFORE calling register. Pre-fill EVERY field you can reasonably infer from what you know about the talent (your memory of past conversations, the chat, context) — including `pricing` and `workSituation.changeMotivators`. PRICING: whenever you know anything about their role, seniority, stack or location, ALWAYS propose a concrete per-project amount yourself (full-time and/or part-time, in their currency), labelled as your estimate — do not hand the question back to the talent; only ask for it when you know nothing at all about their work. MOTIVATORS: pick the one that best matches what they have told you. What you know about the person outranks suggest_register_context: if the git identity does not match the person you know, ignore it. For each inferred value briefly say where it comes from. Ask ONLY for what you genuinely have no basis for. Use suggest_register_context's githubUrl and cvCandidates to propose profile.githubUrl and profile.cvPath (cvCandidates often include OTHER people's CVs, e.g. candidates they downloaded: propose a CV ONLY if its file name matches the talent's name — nameMatch:true or a name you know — and never one named after someone else; if none matches but there is a generic:true one like cv.pdf, ASK the talent whether it is theirs and whether you may read it and send it with the registration; otherwise ask for the path). Once the talent confirms a CV and allows it, ALWAYS call read_cv BEFORE register_preview and use its text to pre-fill or correct the other fields (languages and levels, experience, location); if the CV adds or changes any value, show the talent just those changes and get their OK before calling register; pass paths exactly as given, the short ~/ form is fine. For optional fields you have no basis for (phone, website, newsletter), do not ask one by one: add a single closing line offering them (e.g. '¿Quieres añadir teléfono o web?'). The goal is that the talent only has to answer 'sí' or correct a value. Never write without the talent's confirmation of the summary. All of this is self-declared profile data.\n\nCOLLECT THE DETAILS IN A FEW GROUPED BATCHES, not one field at a time, and for every CHOICE field PRESENT THE VALID OPTIONS so the talent just picks one. For every choice field SHOW THE TALENT THE FRIENDLY LABEL, never the raw code (e.g. show 'Nativo', not 'NATIVE'), and pass the code as the value. Suggested batches:\n1. Identity — name, lastName, email (optional: preferredLanguage, newsletterConsent).\n2. Profile — `profile.linkedinUrl` (required source; optional GitHub/website/CV path).\n3. Work — freelanceType (offer: "
99
+ return "The talent registers THEMSELVES on Shakers (self-service; no prior session needed). Your job is to relay the non-secret profile details the talent gives you in the chat as arguments. Credentials never touch the chat or any tool argument: the tool opens a sign-up window on the talent's own machine (127.0.0.1) where they either Continue with Google (no password at all) or type an email and password directly into that local window.\n\nSAVE THE TALENT TYPING: first call suggest_register_context (timezone, local git identity, GitHub login, CV files) and PROPOSE those values for them to confirm; then call register_preview with the partial payload to get a review (what would be written, what is still missing) and show the talent a short summary to confirm or correct BEFORE calling register. Pre-fill EVERY field you can reasonably infer from what you know about the talent (your memory of past conversations, the chat, context) — including `pricing` and `workSituation.changeMotivators`. PRICING: whenever you know anything about their role, seniority, stack or location, ALWAYS propose a concrete per-project amount yourself (full-time and/or part-time, in their currency), labelled as your estimate — do not hand the question back to the talent; only ask for it when you know nothing at all about their work. MOTIVATORS: pick the one that best matches what they have told you. What you know about the person outranks suggest_register_context: if the git identity does not match the person you know, ignore it. For each inferred value briefly say where it comes from. Ask ONLY for what you genuinely have no basis for. Use suggest_register_context's githubUrl and cvCandidates to propose profile.githubUrl and profile.cvPath (cvCandidates often include OTHER people's CVs, e.g. candidates they downloaded: propose a CV ONLY if its file name matches the talent's name — nameMatch:true or a name you know — and never one named after someone else; if none matches but there is a generic:true one like cv.pdf, ASK the talent whether it is theirs and whether you may read it and send it with the registration; otherwise ask for the path). Once the talent confirms a CV and allows it, ALWAYS call read_cv BEFORE register_preview and use its text to pre-fill or correct the other fields (languages and levels, experience, location); if the CV adds or changes any value, show the talent just those changes and get their OK before calling register; pass paths exactly as given, the short ~/ form is fine. For optional fields you have no basis for (phone, website, newsletter), do not ask one by one: add a single closing line offering them (e.g. '¿Quieres añadir teléfono o web?'). The goal is that the talent only has to answer 'sí' or correct a value. Never write without the talent's confirmation of the summary. All of this is self-declared profile data.\n\nFor whatever you still have to ASK (only what you could not infer), ask in ONE grouped message, not one field at a time, and for every CHOICE field PRESENT THE VALID OPTIONS so the talent just picks one. For every choice field SHOW THE TALENT THE FRIENDLY LABEL, never the raw code (e.g. show 'Nativo', not 'NATIVE'), and pass the code as the value. Fields, grouped:\n1. Identity — name, lastName, email (optional: preferredLanguage, newsletterConsent).\n2. Profile — `profile.linkedinUrl` (required source; optional GitHub/website/CV path).\n3. Work — freelanceType (offer: "
100
100
  + labelledOptions(FREELANCE_TYPES, L.freelanceTypeLabels)
101
101
  + ") and `workSituation` (offer situation: "
102
102
  + labelledOptions(WORK_SITUATIONS, L.workSituationLabels)
package/src/mcp-server.js CHANGED
@@ -27,7 +27,7 @@ function errorResponse(id, code, message, data) {
27
27
  return { jsonrpc: JSONRPC, id: id === undefined ? null : id, error };
28
28
  }
29
29
 
30
- function createMcpServer({ tools = [], serverInfo = {}, protocolVersion, beforeCall = null } = {}) {
30
+ function createMcpServer({ tools = [], serverInfo = {}, protocolVersion, beforeCall = null, instructions = null } = {}) {
31
31
  const registry = new Map();
32
32
  for (const t of tools) {
33
33
  if (!t || !t.name || typeof t.handler !== 'function') {
@@ -117,6 +117,9 @@ function createMcpServer({ tools = [], serverInfo = {}, protocolVersion, beforeC
117
117
  name: serverInfo.name || 'shakers-mcp',
118
118
  version: serverInfo.version || '0.0.0',
119
119
  },
120
+ // Server-level guidance the client keeps in the model's context even
121
+ // when it loads tool schemas lazily (Claude Code defers MCP tools).
122
+ ...(typeof instructions === 'string' && instructions ? { instructions } : {}),
120
123
  });
121
124
  }
122
125
  case 'ping':