shakers-cli 0.15.0 → 0.17.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.
Files changed (132) hide show
  1. package/README.md +56 -1203
  2. package/bin/ai-usage.js +32 -58
  3. package/bin/login.js +10 -10
  4. package/bin/mcp.js +17 -12
  5. package/bin/mcpb.js +1 -1
  6. package/bin/onboarding.js +3 -2
  7. package/bin/register.js +19 -5
  8. package/bin/report-html.js +2 -2
  9. package/bin/shakers-cli.js +352 -0
  10. package/bin/shakers.js +20 -344
  11. package/bin/share.js +1 -1
  12. package/bin/superadmin.js +5 -5
  13. package/bin/version.js +3 -0
  14. package/package.json +12 -3
  15. package/src/account-marker.js +40 -0
  16. package/src/account-trace.js +23 -0
  17. package/src/agent-category.js +1 -1
  18. package/src/agent-evaluation.js +3 -3
  19. package/src/agent-org-chart.js +5 -5
  20. package/src/agent-synthesis.js +3 -3
  21. package/src/agent-usage.js +1 -1
  22. package/src/agents-client.js +4 -4
  23. package/src/ai-usage-review.js +101 -0
  24. package/src/ai.js +1 -1
  25. package/src/ansi.js +1 -1
  26. package/src/auth-client.js +18 -4
  27. package/src/auth-method-picker.js +1 -1
  28. package/src/auth-methods.js +1 -1
  29. package/src/auth-session-store.js +18 -8
  30. package/src/authorship-mismatch.js +1 -1
  31. package/src/authorship.js +2 -2
  32. package/src/automations-detector.js +1 -1
  33. package/src/backend-request.js +5 -3
  34. package/src/brand-ansi.js +1 -1
  35. package/src/browser-tools-detector.js +1 -1
  36. package/src/certify-disclaimer.js +1 -1
  37. package/src/certify-remediation-prompt.js +1 -1
  38. package/src/cli-args.js +2 -2
  39. package/src/command-audit.js +8 -5
  40. package/src/config-dir.js +1 -1
  41. package/src/config.js +114 -48
  42. package/src/consent-flow.js +7 -6
  43. package/src/consent-skip.js +1 -1
  44. package/src/detection-evidence.js +2 -2
  45. package/src/detection-noise.js +1 -1
  46. package/src/detectors.js +1 -1
  47. package/src/device-login.js +12 -1
  48. package/src/email-verification.js +3 -3
  49. package/src/env-paths.js +1 -1
  50. package/src/find-projects-client.js +12 -0
  51. package/src/find-projects-flow.js +1 -13
  52. package/src/git-activity.js +1 -1
  53. package/src/graph-certs.js +3 -3
  54. package/src/graph-scan.js +9 -9
  55. package/src/i18n.js +148 -138
  56. package/src/interactive-select.js +1 -1
  57. package/src/interview-client.js +6 -1
  58. package/src/interview-transcript.js +1 -1
  59. package/src/legal-notice.js +1 -1
  60. package/src/maturity.js +6 -6
  61. package/src/mcp-ai-usage-result-tool.js +34 -12
  62. package/src/mcp-ai-usage-tool.js +282 -163
  63. package/src/mcp-auth-form.js +7 -3
  64. package/src/mcp-detector.js +3 -3
  65. package/src/mcp-device-login-tools.js +2 -1
  66. package/src/mcp-find-projects-tools.js +1 -2
  67. package/src/mcp-install.js +279 -44
  68. package/src/mcp-instructions.js +1 -1
  69. package/src/mcp-onboarding-tools.js +4 -4
  70. package/src/mcp-prompts.js +4 -4
  71. package/src/mcp-register-tools.js +1 -0
  72. package/src/mcp-role-tools.js +24 -1
  73. package/src/mcp-server.js +5 -1
  74. package/src/mcp-signup-client.js +2 -2
  75. package/src/mcp-signup-tools.js +39 -9
  76. package/src/memory-structure-detector.js +1 -1
  77. package/src/model-call-record.js +2 -2
  78. package/src/onboarding-flow.js +63 -42
  79. package/src/onboarding-funnel.js +153 -20
  80. package/src/open-file.js +1 -1
  81. package/src/osc-link.js +1 -1
  82. package/src/portfolio-client.js +11 -1
  83. package/src/portfolio-git-info.js +1 -1
  84. package/src/profile-flow.js +1 -1
  85. package/src/profile-switch.js +5 -12
  86. package/src/render-certification.js +10 -10
  87. package/src/render-html.js +6 -6
  88. package/src/render-report-text.js +1 -1
  89. package/src/render-sheet.js +10 -10
  90. package/src/render-terminal.js +6 -6
  91. package/src/repo-scope.js +132 -0
  92. package/src/report-gating.js +5 -3
  93. package/src/report-store.js +13 -8
  94. package/src/roadmap-content.js +5 -5
  95. package/src/roadmap-personalization.js +3 -3
  96. package/src/roadmap-prompt.js +2 -2
  97. package/src/roles-flow.js +8 -5
  98. package/src/scan-exclusions.js +1 -1
  99. package/src/scanner.js +14 -14
  100. package/src/secret-prompt.js +1 -1
  101. package/src/session-gate.js +1 -1
  102. package/src/session-refresh.js +33 -3
  103. package/src/session-scan.js +1 -1
  104. package/src/shakers-wordmark.js +1 -1
  105. package/src/share-card.js +2 -2
  106. package/src/share-certification.js +4 -4
  107. package/src/share-consent-state.js +9 -9
  108. package/src/share-payload.js +7 -7
  109. package/src/share.js +7 -7
  110. package/src/signup-client.js +1 -1
  111. package/src/signup-copy.js +177 -2
  112. package/src/skills-client.js +1 -1
  113. package/src/start-add-agents.js +2 -2
  114. package/src/start-add-portfolio.js +3 -13
  115. package/src/start-add-skills.js +2 -2
  116. package/src/stdin-ask.js +16 -4
  117. package/src/strip-internal-comments.js +1 -1
  118. package/src/tech-detector.js +2 -2
  119. package/src/templates/report-sheet.html +11 -13
  120. package/src/terminal-agents.js +8 -8
  121. package/src/terminal-format.js +3 -3
  122. package/src/terminal-sections.js +11 -11
  123. package/src/tier-engine.js +3 -3
  124. package/src/tier-projection.js +2 -2
  125. package/src/transcript-turns.js +1 -1
  126. package/src/typewriter.js +1 -1
  127. package/src/usage-model-calls.js +6 -6
  128. package/src/usage-oneshot-commands.js +5 -5
  129. package/src/usage-repo-scope.js +11 -129
  130. package/src/usage-run-steps.js +82 -181
  131. package/src/usage-scan.js +235 -0
  132. package/src/work-streams.js +1 -1
@@ -3,7 +3,7 @@
3
3
  const { palette, styleQuestion } = require('./ansi');
4
4
  const { BRAND_ANSI } = require('./brand-ansi');
5
5
 
6
- // Zero-dependency interactive multi-select (skill-code-certification, issue 011).
6
+ // Zero-dependency interactive multi-select.
7
7
 
8
8
  // COLOUR goes through the one gate (src/ansi.js).
9
9
  const ANSI = palette({
@@ -100,7 +100,7 @@ class InterviewClient {
100
100
 
101
101
  // The end of the interview is a protocol message, not a sentence: matching the
102
102
  // goodbye text never fired (certs sends no closingMessage), so the CLI kept
103
- // asking for answers until its turn-timeout (new-works, 2026-09-25).
103
+ // asking for answers until its turn-timeout.
104
104
  if (RoomEvent && RoomEvent.DataReceived && typeof room.on === 'function') {
105
105
  room.on(RoomEvent.DataReceived, (payload, _participant, _kind, topic) => {
106
106
  if (topic !== PROTOCOL_TOPIC) return;
@@ -216,8 +216,13 @@ class InterviewClient {
216
216
  }
217
217
  }
218
218
 
219
+ function createInterviewClient(opts) {
220
+ return new InterviewClient(opts);
221
+ }
222
+
219
223
  module.exports = {
220
224
  InterviewClient,
225
+ createInterviewClient,
221
226
  LiveKitNotInstalledError,
222
227
  loadLiveKitSdk,
223
228
  CHAT_TOPIC,
@@ -4,7 +4,7 @@
4
4
 
5
5
  // Upper case: certs validates the role against its AGENT/USER enum and 400s the
6
6
  // whole PATCH otherwise, so every terminal onboarding lost its transcript
7
- // ("no se pudo guardar la transcripcion (http-400)", new-works 2026-09-25).
7
+ // ("no se pudo guardar la transcripcion (http-400)").
8
8
  const ROLE_AGENT = 'AGENT';
9
9
  const ROLE_USER = 'USER';
10
10
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- // Shared PRESENTATION for the CLI's legal/consent disclosures (talents-ai-score).
3
+ // Shared PRESENTATION for the CLI's legal/consent disclosures.
4
4
 
5
5
  const { palette, colorEnabled } = require('./ansi');
6
6
  const { BRAND_ANSI } = require('./brand-ansi');
package/src/maturity.js CHANGED
@@ -12,7 +12,7 @@ const LEVELS = [
12
12
  { level: 4, key: 'orchestrator', name: 'Orquestador', emoji: '●' },
13
13
  ];
14
14
 
15
- // DECISION (talents-ai-score, signal expansion): the level definitions (LEVELS, HANDOFF §4) have NOT been touched.
15
+ // DECISION: the level definitions (LEVELS) have NOT been touched.
16
16
  function depthTotals(tools) {
17
17
  let instructions = 0; // project instructions/rules files
18
18
  let mcp = 0; // configured MCP servers
@@ -30,7 +30,7 @@ function depthTotals(tools) {
30
30
  return { instructions, mcp, custom, hooks };
31
31
  }
32
32
 
33
- // Score model 0-100 for the visual meter — RECALIBRATED (ADR-008, skill-code-certification).
33
+ // Score model 0-100 for the visual meter — RECALIBRATED.
34
34
  const SCORE_MODEL = [
35
35
  { key: 'breadth', weight: 12, full: 3 }, // number of AI tools detected
36
36
  { key: 'context', weight: 16, full: 2 }, // instructions + config files
@@ -61,7 +61,7 @@ function classify(report) {
61
61
  ? report.agentCounts.agents
62
62
  : 0;
63
63
 
64
- // Score scope reverted to PROJECT ∪ HOME (skill-code-certification / ADR-010, which reverts ADR-009).
64
+ // Score scope reverted to PROJECT ∪ HOME.
65
65
  const score = computeScore({
66
66
  breadth,
67
67
  context: d.instructions, // depthTotals already folds `config` into instructions
@@ -72,7 +72,7 @@ function classify(report) {
72
72
  multiAgent: agentCount,
73
73
  });
74
74
 
75
- // Band 0-4 derived from the tier engine (issue 019, single source of truth).
75
+ // Band 0-4 derived from the tier engine (single source of truth).
76
76
  const tierResult = computeTierResult(report);
77
77
  const level = tierResult.band;
78
78
  const meta = LEVELS[level];
@@ -87,11 +87,11 @@ function classify(report) {
87
87
  depth: d,
88
88
  hasAgentic,
89
89
  next: nextStep(level, { breadth, ...d, hasAgentic }),
90
- // Tier (T0-T7, issue 019): the fine-grained axis the band is derived from.
90
+ // Tier (T0-T7): the fine-grained axis the band is derived from.
91
91
  tier: tierResult.tier,
92
92
  tierKey: tierResult.tierKey,
93
93
  tierName: tierResult.tierName,
94
- // Setup Level (ADR-016): the 3-value rollup shown to the talent, derived
94
+ // Setup Level: the 3-value rollup shown to the talent, derived
95
95
  // from the tier. `{key, code, rank, emoji}`; label localized via i18n.
96
96
  setupLevel: tierResult.setupLevel,
97
97
  };
@@ -52,6 +52,8 @@ async function pollClassifiedInventory({
52
52
  }
53
53
  }
54
54
 
55
+ const RESULT_MESSAGE = 'Print relayVerbatim word for word: the result in "My work with AI", what it means and how to ask for a human review.';
56
+ const PROFILE_PENDING_MESSAGE = 'The profile result is not ready yet: call ai_usage_result again in a few minutes.';
55
57
  const READY_MESSAGE = 'Shakers finished classifying the agents.';
56
58
  const PENDING_MESSAGE = 'Shakers is still classifying the agents — this is normal, call ai_usage_result again shortly to keep waiting.';
57
59
 
@@ -65,6 +67,12 @@ function makeAiUsageResultTool(deps = {}) {
65
67
  now = () => Date.now(),
66
68
  intervalMs = POLL_INTERVAL_MS,
67
69
  capMs = POLL_CAP_MS,
70
+ resolveAiProfilePreview = require('./ai-profile-preview').resolveAiProfilePreview,
71
+ getAiProfileEndpoint = require('./config').getAiProfileEndpoint,
72
+ ensureFreshSession = require('./session-refresh').ensureFreshSession,
73
+ aiProfileWaitMs = 30000,
74
+ resultText = require('./ai-usage-review').resultText,
75
+ lang = () => require('./signup-language').signupLanguage(require('./i18n').detectFlowLang()),
68
76
  } = deps;
69
77
 
70
78
  async function handler() {
@@ -77,27 +85,41 @@ function makeAiUsageResultTool(deps = {}) {
77
85
  throw new Error('discovered-inventory endpoint is not configured (set SHAKERS_CLI_INGEST_ENDPOINT).');
78
86
  }
79
87
 
80
- const result = await pollClassifiedInventory({
81
- accessToken: session.accessToken,
82
- endpoint,
83
- requestDiscoveredInventory,
84
- sleep,
85
- now,
86
- intervalMs,
87
- capMs,
88
- });
88
+ const [result, aiProfile] = await Promise.all([
89
+ pollClassifiedInventory({
90
+ accessToken: session.accessToken,
91
+ endpoint,
92
+ requestDiscoveredInventory,
93
+ sleep,
94
+ now,
95
+ intervalMs,
96
+ capMs,
97
+ }),
98
+ resolveAiProfilePreview(
99
+ { session, endpoint: getAiProfileEndpoint(), timeoutMs: aiProfileWaitMs },
100
+ {
101
+ refreshToken: async () => {
102
+ const fresh = await ensureFreshSession(process.env);
103
+ return fresh ? { accessToken: fresh.accessToken, hubAccessToken: fresh.hubAccessToken } : null;
104
+ },
105
+ },
106
+ ).catch(() => ({ status: 'unavailable', preview: null })),
107
+ ]);
108
+ const profileReady = aiProfile.status === 'ready';
89
109
  return {
90
110
  ...result,
91
- message: result.status === 'ready' ? READY_MESSAGE : PENDING_MESSAGE,
111
+ aiProfile,
112
+ relayVerbatim: resultText(lang(), profileReady ? aiProfile.preview : null),
113
+ message: `${RESULT_MESSAGE} ${result.status === 'ready' ? READY_MESSAGE : PENDING_MESSAGE}${profileReady ? '' : ` ${PROFILE_PENDING_MESSAGE}`}`,
92
114
  };
93
115
  }
94
116
 
95
117
  return {
96
118
  name: 'ai_usage_result',
97
119
  title: 'Results of your AI analysis',
98
- description: 'Fetches from Shakers the description of each AI agent found in the analysis you approved. It reads nothing on this computer.',
120
+ 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.',
99
121
  guidance:
100
- "Retrieve the enriched Shakers classification for the talent's agents after ai_usage. 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 (~90s max, 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.",
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 (~90s max, 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.",
101
123
  inputSchema: RESULT_INPUT_SCHEMA,
102
124
  handler,
103
125
  };