shakers-cli-beta 0.8.0-beta.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 (218) hide show
  1. package/LICENSE +59 -0
  2. package/README.md +1175 -0
  3. package/bin/add-agent.js +88 -0
  4. package/bin/add-project.js +88 -0
  5. package/bin/add-role.js +61 -0
  6. package/bin/add-skill.js +88 -0
  7. package/bin/ai-usage.js +81 -0
  8. package/bin/alma.js +99 -0
  9. package/bin/applications.js +69 -0
  10. package/bin/availability.js +70 -0
  11. package/bin/certifications.js +69 -0
  12. package/bin/certify.js +73 -0
  13. package/bin/change-role.js +61 -0
  14. package/bin/config.js +120 -0
  15. package/bin/experiences.js +69 -0
  16. package/bin/find-projects.js +89 -0
  17. package/bin/invitations.js +69 -0
  18. package/bin/lang.js +70 -0
  19. package/bin/login.js +283 -0
  20. package/bin/mcp.js +98 -0
  21. package/bin/me.js +69 -0
  22. package/bin/onboarding.js +134 -0
  23. package/bin/portfolios.js +69 -0
  24. package/bin/rate.js +70 -0
  25. package/bin/register.js +325 -0
  26. package/bin/report-html.js +134 -0
  27. package/bin/save.js +77 -0
  28. package/bin/shakers.js +344 -0
  29. package/bin/share.js +72 -0
  30. package/bin/show-project.js +72 -0
  31. package/bin/socials.js +70 -0
  32. package/bin/superadmin.js +351 -0
  33. package/package.json +40 -0
  34. package/src/agent-category.js +13 -0
  35. package/src/agent-evaluation.js +177 -0
  36. package/src/agent-org-chart.js +355 -0
  37. package/src/agent-synthesis.js +132 -0
  38. package/src/agent-usage.js +118 -0
  39. package/src/agents-client.js +165 -0
  40. package/src/ai-fluency-cell.js +72 -0
  41. package/src/ai-profile-client.js +45 -0
  42. package/src/ai-profile-preview.js +154 -0
  43. package/src/ai.js +66 -0
  44. package/src/alma-client.js +123 -0
  45. package/src/alma-flow.js +32 -0
  46. package/src/alma-repo-context.js +47 -0
  47. package/src/alma-shell.js +161 -0
  48. package/src/ansi.js +62 -0
  49. package/src/applications-client.js +79 -0
  50. package/src/applications-flow.js +58 -0
  51. package/src/auth-client.js +144 -0
  52. package/src/auth-device-client.js +118 -0
  53. package/src/auth-method-picker.js +44 -0
  54. package/src/auth-methods.js +35 -0
  55. package/src/auth-session-store.js +214 -0
  56. package/src/authorship.js +203 -0
  57. package/src/automations-detector.js +170 -0
  58. package/src/availability-client.js +92 -0
  59. package/src/availability-flow.js +105 -0
  60. package/src/backend-request.js +170 -0
  61. package/src/blind-approval-extract.js +48 -0
  62. package/src/brand-ansi.js +14 -0
  63. package/src/brand-svg.js +9 -0
  64. package/src/browser-tools-detector.js +21 -0
  65. package/src/build-next-level.js +56 -0
  66. package/src/certifications-client.js +89 -0
  67. package/src/certifications-flow.js +75 -0
  68. package/src/certify-dimension-client.js +217 -0
  69. package/src/certify-dimension-flow.js +193 -0
  70. package/src/certify-disclaimer.js +51 -0
  71. package/src/certify-remediation-prompt.js +23 -0
  72. package/src/cli-args.js +83 -0
  73. package/src/config-dir.js +120 -0
  74. package/src/config.js +778 -0
  75. package/src/consent-flow.js +115 -0
  76. package/src/consent-skip.js +27 -0
  77. package/src/decisions-extract.js +43 -0
  78. package/src/detect-repos.js +145 -0
  79. package/src/detected-tools.js +15 -0
  80. package/src/detection-evidence.js +105 -0
  81. package/src/detection-noise.js +132 -0
  82. package/src/detectors.js +221 -0
  83. package/src/device-auth-store.js +100 -0
  84. package/src/device-login.js +118 -0
  85. package/src/email-verification.js +152 -0
  86. package/src/env-paths.js +16 -0
  87. package/src/find-projects-cache.js +89 -0
  88. package/src/find-projects-client.js +138 -0
  89. package/src/find-projects-flow.js +164 -0
  90. package/src/git-activity.js +123 -0
  91. package/src/graph-certs.js +58 -0
  92. package/src/graph-generator.js +230 -0
  93. package/src/graph-scan.js +239 -0
  94. package/src/i18n.js +3264 -0
  95. package/src/inter-fonts.js +6 -0
  96. package/src/interactive-select.js +183 -0
  97. package/src/interview-client.js +226 -0
  98. package/src/interview-transcript.js +56 -0
  99. package/src/inventory-client.js +90 -0
  100. package/src/invitations-client.js +66 -0
  101. package/src/invitations-flow.js +50 -0
  102. package/src/lang-client.js +147 -0
  103. package/src/lang-codes.js +14 -0
  104. package/src/lang-flow.js +85 -0
  105. package/src/legal-notice.js +53 -0
  106. package/src/locale.js +51 -0
  107. package/src/markdown-ansi.js +50 -0
  108. package/src/maturity.js +111 -0
  109. package/src/mcp-ai-usage-result-tool.js +109 -0
  110. package/src/mcp-ai-usage-tool.js +333 -0
  111. package/src/mcp-alma-tools.js +91 -0
  112. package/src/mcp-applications-tools.js +42 -0
  113. package/src/mcp-ask-tools.js +50 -0
  114. package/src/mcp-auth-form.js +282 -0
  115. package/src/mcp-availability-tools.js +43 -0
  116. package/src/mcp-certifications-tools.js +42 -0
  117. package/src/mcp-certify-dimension-tools.js +58 -0
  118. package/src/mcp-detector.js +223 -0
  119. package/src/mcp-device-login-tools.js +173 -0
  120. package/src/mcp-find-projects-tools.js +67 -0
  121. package/src/mcp-install.js +245 -0
  122. package/src/mcp-invitations-tools.js +42 -0
  123. package/src/mcp-lang-tools.js +39 -0
  124. package/src/mcp-onboarding-tools.js +388 -0
  125. package/src/mcp-portfolios-tools.js +46 -0
  126. package/src/mcp-profile-tools.js +46 -0
  127. package/src/mcp-rate-tools.js +42 -0
  128. package/src/mcp-register-tools.js +517 -0
  129. package/src/mcp-report-tools.js +101 -0
  130. package/src/mcp-role-tools.js +112 -0
  131. package/src/mcp-saved-positions-tools.js +55 -0
  132. package/src/mcp-server.js +170 -0
  133. package/src/mcp-show-project-tools.js +50 -0
  134. package/src/mcp-socials-tools.js +39 -0
  135. package/src/memory-structure-detector.js +108 -0
  136. package/src/model-call-record.js +198 -0
  137. package/src/onboarding-availability.js +26 -0
  138. package/src/onboarding-client.js +364 -0
  139. package/src/onboarding-flow.js +1078 -0
  140. package/src/onboarding-livekit-client.js +102 -0
  141. package/src/onboarding-status-client.js +42 -0
  142. package/src/open-file.js +32 -0
  143. package/src/osc-link.js +16 -0
  144. package/src/portfolio-client.js +164 -0
  145. package/src/portfolio-git-info.js +61 -0
  146. package/src/portfolios-client.js +85 -0
  147. package/src/portfolios-flow.js +79 -0
  148. package/src/profile-client.js +125 -0
  149. package/src/profile-flow.js +115 -0
  150. package/src/profile-switch.js +46 -0
  151. package/src/prompt-select.js +29 -0
  152. package/src/rate-client.js +82 -0
  153. package/src/rate-flow.js +137 -0
  154. package/src/render-ai-fluency.js +266 -0
  155. package/src/render-certification.js +177 -0
  156. package/src/render-html.js +140 -0
  157. package/src/render-report-text.js +27 -0
  158. package/src/render-sheet.js +261 -0
  159. package/src/render-terminal.js +109 -0
  160. package/src/render-usage-report-text.js +155 -0
  161. package/src/repo-context.js +215 -0
  162. package/src/report-gating.js +49 -0
  163. package/src/report-store.js +226 -0
  164. package/src/report-theme.js +177 -0
  165. package/src/report-view-client.js +50 -0
  166. package/src/reveal-output.js +29 -0
  167. package/src/roadmap-content.js +453 -0
  168. package/src/roadmap-personalization.js +132 -0
  169. package/src/roadmap-prompt.js +154 -0
  170. package/src/roles-client.js +114 -0
  171. package/src/roles-flow.js +192 -0
  172. package/src/sanitize-network-text.js +36 -0
  173. package/src/saved-positions-client.js +71 -0
  174. package/src/saved-positions-flow.js +50 -0
  175. package/src/scan-exclusions.js +50 -0
  176. package/src/scanner.js +612 -0
  177. package/src/scope-signals.js +148 -0
  178. package/src/secret-prompt.js +72 -0
  179. package/src/session-gate.js +30 -0
  180. package/src/session-refresh.js +51 -0
  181. package/src/session-scan.js +336 -0
  182. package/src/session-signals.js +36 -0
  183. package/src/shakers-wordmark.js +17 -0
  184. package/src/share-card.js +362 -0
  185. package/src/share-certification.js +111 -0
  186. package/src/share-consent-state.js +157 -0
  187. package/src/share-payload.js +300 -0
  188. package/src/share.js +184 -0
  189. package/src/show-project-client.js +58 -0
  190. package/src/show-project-flow.js +119 -0
  191. package/src/signup-client.js +91 -0
  192. package/src/skills-client.js +102 -0
  193. package/src/socials-client.js +91 -0
  194. package/src/socials-flow.js +83 -0
  195. package/src/specificity-extract.js +41 -0
  196. package/src/start-add-agents.js +306 -0
  197. package/src/start-add-portfolio.js +388 -0
  198. package/src/start-add-skills.js +260 -0
  199. package/src/stdin-ask.js +129 -0
  200. package/src/steering-extract.js +43 -0
  201. package/src/strip-internal-comments.js +45 -0
  202. package/src/tech-detector.js +295 -0
  203. package/src/templates/report-sheet.html +572 -0
  204. package/src/terminal-agents.js +199 -0
  205. package/src/terminal-format.js +85 -0
  206. package/src/terminal-progress.js +106 -0
  207. package/src/terminal-sections.js +219 -0
  208. package/src/tier-analysis.js +126 -0
  209. package/src/tier-engine.js +114 -0
  210. package/src/tier-projection.js +117 -0
  211. package/src/transcript-turns.js +49 -0
  212. package/src/translations-client.js +84 -0
  213. package/src/typewriter.js +154 -0
  214. package/src/usage-model-calls.js +119 -0
  215. package/src/usage-oneshot-commands.js +180 -0
  216. package/src/usage-repo-scope.js +162 -0
  217. package/src/usage-run-steps.js +338 -0
  218. package/src/work-streams.js +74 -0
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { detectReportLang, getCatalog } = require('../src/i18n');
5
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
6
+ const { createStdinAsk } = require('../src/stdin-ask');
7
+ const { run: runLogin } = require('./login');
8
+ const { runAddAgents } = require('../src/start-add-agents');
9
+
10
+ const VALID_LANGS = new Set(['es', 'en']);
11
+
12
+ const COPY = {
13
+ es: {
14
+ help: 'add-agent — añade a tu perfil de Talento un agente de tu inventario descubierto. Uso: add-agent [--lang es|en] [--accept-disclaimer]',
15
+ gate: '"add-agent" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
16
+ missingAccept: 'Modo no interactivo: falta --accept-disclaimer.\n add-agent es un flujo interactivo (elegir agente, editar campos) y su borrado por IA envía datos.\n Reejecuta con --accept-disclaimer, aportando las respuestas por stdin.',
17
+ },
18
+ en: {
19
+ help: 'add-agent — add an agent from your discovered inventory to your Talent profile. Usage: add-agent [--lang es|en] [--accept-disclaimer]',
20
+ gate: '"add-agent" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
21
+ missingAccept: 'Non-interactive mode: --accept-disclaimer is missing.\n add-agent is an interactive flow (pick an agent, edit fields) and its AI draft sends data.\n Re-run with --accept-disclaimer, feeding the answers over stdin.',
22
+ },
23
+ };
24
+
25
+ function parseArgs(argv) {
26
+ const o = { root: null, lang: null, help: false, acceptDisclaimer: false };
27
+ for (let i = 0; i < argv.length; i++) {
28
+ const a = argv[i];
29
+ if (a === '--root') o.root = argv[++i];
30
+ else if (a.startsWith('--root=')) o.root = a.slice(7);
31
+ else if (a === '--lang') o.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
32
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = VALID_LANGS.has(v) ? v : null; }
33
+ else if (a === '--accept-disclaimer') o.acceptDisclaimer = true;
34
+ else if (a === '--help' || a === '-h') o.help = true;
35
+ }
36
+ return o;
37
+ }
38
+
39
+ async function run(
40
+ argv = process.argv.slice(2),
41
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, session: injectedSession = null } = {},
42
+ ) {
43
+ const o = parseArgs(argv);
44
+ const lang = o.lang || detectReportLang();
45
+ const catalog = getCatalog(lang);
46
+ const c = COPY[lang] || COPY.en;
47
+
48
+ if (o.help) {
49
+ process.stdout.write(`\n ${c.help}\n\n`);
50
+ return;
51
+ }
52
+
53
+ const session = injectedSession || loadAuthSession();
54
+ if (sessionStatus(session) !== 'active') {
55
+ process.stderr.write(`\n ${c.gate}\n\n`);
56
+ process.exitCode = 1;
57
+ return;
58
+ }
59
+
60
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
61
+
62
+ if (!stdinIsTTY && !o.acceptDisclaimer) {
63
+ process.stderr.write(`\n ${c.missingAccept}\n\n`);
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ const ask = injectedAsk || createStdinAsk();
69
+ try {
70
+ await runAddAgents({
71
+ ask,
72
+ catalog,
73
+ root: o.root || process.cwd(),
74
+ session,
75
+ stdinIsTTY,
76
+ preAccepted: o.acceptDisclaimer,
77
+ deps: { runLogin },
78
+ });
79
+ } finally {
80
+ if (!injectedAsk) ask.close();
81
+ }
82
+ }
83
+
84
+ module.exports = { run, parseArgs };
85
+
86
+ if (require.main === module) {
87
+ run();
88
+ }
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { detectReportLang, getCatalog } = require('../src/i18n');
5
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
6
+ const { createStdinAsk } = require('../src/stdin-ask');
7
+ const { run: runLogin } = require('./login');
8
+ const { runAddPortfolio } = require('../src/start-add-portfolio');
9
+
10
+ const VALID_LANGS = new Set(['es', 'en']);
11
+
12
+ const COPY = {
13
+ es: {
14
+ help: 'add-project — añade este proyecto a tu portfolio de Talento. Uso: add-project [--root <dir>] [--lang es|en] [--accept-disclaimer]',
15
+ gate: '"add-project" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
16
+ missingAccept: 'Modo no interactivo: falta --accept-disclaimer.\n add-project es un flujo interactivo (título, tipo, descripción, skills) y su borrador por IA envía datos.\n Reejecuta con --accept-disclaimer, aportando las respuestas por stdin.',
17
+ },
18
+ en: {
19
+ help: 'add-project — add this project to your Talent portfolio. Usage: add-project [--root <dir>] [--lang es|en] [--accept-disclaimer]',
20
+ gate: '"add-project" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
21
+ missingAccept: 'Non-interactive mode: --accept-disclaimer is missing.\n add-project is an interactive flow (title, type, description, skills) and its AI draft sends data.\n Re-run with --accept-disclaimer, feeding the answers over stdin.',
22
+ },
23
+ };
24
+
25
+ function parseArgs(argv) {
26
+ const o = { root: null, lang: null, help: false, acceptDisclaimer: false };
27
+ for (let i = 0; i < argv.length; i++) {
28
+ const a = argv[i];
29
+ if (a === '--root') o.root = argv[++i];
30
+ else if (a.startsWith('--root=')) o.root = a.slice(7);
31
+ else if (a === '--lang') o.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
32
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = VALID_LANGS.has(v) ? v : null; }
33
+ else if (a === '--accept-disclaimer') o.acceptDisclaimer = true;
34
+ else if (a === '--help' || a === '-h') o.help = true;
35
+ }
36
+ return o;
37
+ }
38
+
39
+ async function run(
40
+ argv = process.argv.slice(2),
41
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, session: injectedSession = null } = {},
42
+ ) {
43
+ const o = parseArgs(argv);
44
+ const lang = o.lang || detectReportLang();
45
+ const catalog = getCatalog(lang);
46
+ const c = COPY[lang] || COPY.en;
47
+
48
+ if (o.help) {
49
+ process.stdout.write(`\n ${c.help}\n\n`);
50
+ return;
51
+ }
52
+
53
+ const session = injectedSession || loadAuthSession();
54
+ if (sessionStatus(session) !== 'active') {
55
+ process.stderr.write(`\n ${c.gate}\n\n`);
56
+ process.exitCode = 1;
57
+ return;
58
+ }
59
+
60
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
61
+
62
+ if (!stdinIsTTY && !o.acceptDisclaimer) {
63
+ process.stderr.write(`\n ${c.missingAccept}\n\n`);
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ const ask = injectedAsk || createStdinAsk();
69
+ try {
70
+ await runAddPortfolio({
71
+ ask,
72
+ catalog,
73
+ root: o.root || process.cwd(),
74
+ session,
75
+ stdinIsTTY,
76
+ preAccepted: o.acceptDisclaimer,
77
+ deps: { runLogin },
78
+ });
79
+ } finally {
80
+ if (!injectedAsk) ask.close();
81
+ }
82
+ }
83
+
84
+ module.exports = { run, parseArgs };
85
+
86
+ if (require.main === module) {
87
+ run();
88
+ }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `add-role` — add a role (GROWTH cluster) to the talent's profile (src/roles-flow.js).
5
+
6
+ const { detectReportLang, getCatalog } = require('../src/i18n');
7
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
8
+ const { createStdinAsk } = require('../src/stdin-ask');
9
+ const { makeIo } = require('./register');
10
+ const { runAddRole, makeRolesDeps } = require('../src/roles-flow');
11
+
12
+ function parseArgs(argv = []) {
13
+ const o = { lang: null, help: false };
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const a = argv[i];
16
+ if (a === '--help' || a === '-h') o.help = true;
17
+ else if (a === '--lang') { const v = argv[++i]; o.lang = v === 'es' || v === 'en' ? v : null; }
18
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = v === 'es' || v === 'en' ? v : null; }
19
+ }
20
+ return o;
21
+ }
22
+
23
+ async function run(
24
+ argv = process.argv.slice(2),
25
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, deps = null, session: injectedSession = null, out = null } = {},
26
+ ) {
27
+ const opts = parseArgs(argv);
28
+ const lang = opts.lang || detectReportLang();
29
+ const catalog = getCatalog(lang);
30
+ const r = catalog.roles;
31
+ const write = out || ((s) => process.stdout.write(s));
32
+
33
+ if (opts.help) {
34
+ write(r.addHelp + '\n');
35
+ return;
36
+ }
37
+
38
+ const session = injectedSession || loadAuthSession();
39
+ if (sessionStatus(session) !== 'active') {
40
+ process.stderr.write(`\n ${r.loginRequired}\n\n`);
41
+ process.exitCode = 1;
42
+ return;
43
+ }
44
+
45
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
46
+ const ask = injectedAsk || createStdinAsk();
47
+ try {
48
+ const io = makeIo({ ask, lang, out: write, stdinIsTTY });
49
+ const result = await runAddRole({ io, session, catalog, deps: deps || makeRolesDeps() });
50
+ if (result && result.ok === false) process.exitCode = 1;
51
+ return result;
52
+ } finally {
53
+ if (!injectedAsk) ask.close();
54
+ }
55
+ }
56
+
57
+ module.exports = { run, parseArgs };
58
+
59
+ if (require.main === module) {
60
+ run();
61
+ }
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { detectReportLang, getCatalog } = require('../src/i18n');
5
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
6
+ const { createStdinAsk } = require('../src/stdin-ask');
7
+ const { run: runLogin } = require('./login');
8
+ const { runAddSkills } = require('../src/start-add-skills');
9
+
10
+ const VALID_LANGS = new Set(['es', 'en']);
11
+
12
+ const COPY = {
13
+ es: {
14
+ help: 'add-skill — añade a tu perfil de Talento Skills de tu inventario descubierto. Uso: add-skill [--lang es|en] [--accept-disclaimer]',
15
+ gate: '"add-skill" requiere una sesión activa.\n Falta: iniciar sesión. Ejecuta primero: shakers login',
16
+ missingAccept: 'Modo no interactivo: falta --accept-disclaimer.\n add-skill es un flujo interactivo (elegir Skills de tu inventario descubierto) y su declaración envía datos.\n Reejecuta con --accept-disclaimer, aportando las respuestas por stdin.',
17
+ },
18
+ en: {
19
+ help: 'add-skill — add Skills from your discovered inventory to your Talent profile. Usage: add-skill [--lang es|en] [--accept-disclaimer]',
20
+ gate: '"add-skill" requires an active session.\n Missing: sign-in. Run `shakers login` first.',
21
+ missingAccept: 'Non-interactive mode: --accept-disclaimer is missing.\n add-skill is an interactive flow (pick Skills from your discovered inventory) and its declaration sends data.\n Re-run with --accept-disclaimer, feeding the answers over stdin.',
22
+ },
23
+ };
24
+
25
+ function parseArgs(argv) {
26
+ const o = { root: null, lang: null, help: false, acceptDisclaimer: false };
27
+ for (let i = 0; i < argv.length; i++) {
28
+ const a = argv[i];
29
+ if (a === '--root') o.root = argv[++i];
30
+ else if (a.startsWith('--root=')) o.root = a.slice(7);
31
+ else if (a === '--lang') o.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
32
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = VALID_LANGS.has(v) ? v : null; }
33
+ else if (a === '--accept-disclaimer') o.acceptDisclaimer = true;
34
+ else if (a === '--help' || a === '-h') o.help = true;
35
+ }
36
+ return o;
37
+ }
38
+
39
+ async function run(
40
+ argv = process.argv.slice(2),
41
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, session: injectedSession = null } = {},
42
+ ) {
43
+ const o = parseArgs(argv);
44
+ const lang = o.lang || detectReportLang();
45
+ const catalog = getCatalog(lang);
46
+ const c = COPY[lang] || COPY.en;
47
+
48
+ if (o.help) {
49
+ process.stdout.write(`\n ${c.help}\n\n`);
50
+ return;
51
+ }
52
+
53
+ const session = injectedSession || loadAuthSession();
54
+ if (sessionStatus(session) !== 'active') {
55
+ process.stderr.write(`\n ${c.gate}\n\n`);
56
+ process.exitCode = 1;
57
+ return;
58
+ }
59
+
60
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
61
+
62
+ if (!stdinIsTTY && !o.acceptDisclaimer) {
63
+ process.stderr.write(`\n ${c.missingAccept}\n\n`);
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ const ask = injectedAsk || createStdinAsk();
69
+ try {
70
+ await runAddSkills({
71
+ ask,
72
+ catalog,
73
+ root: o.root || process.cwd(),
74
+ session,
75
+ stdinIsTTY,
76
+ preAccepted: o.acceptDisclaimer,
77
+ deps: { runLogin },
78
+ });
79
+ } finally {
80
+ if (!injectedAsk) ask.close();
81
+ }
82
+ }
83
+
84
+ module.exports = { run, parseArgs };
85
+
86
+ if (require.main === module) {
87
+ run();
88
+ }
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { classify } = require('../src/maturity');
5
+ const { detectReportLang, getCatalog } = require('../src/i18n');
6
+ const { parseArgs } = require('../src/cli-args');
7
+ const { loadConsentState } = require('../src/share');
8
+ const { handleOneShotCommand } = require('../src/usage-oneshot-commands');
9
+ const {
10
+ resolveRepoScope,
11
+ machineWideToplevels,
12
+ promptScope,
13
+ } = require('../src/usage-repo-scope');
14
+ const {
15
+ performScan,
16
+ prepareIdentityAndUsage,
17
+ resolveAiConsent,
18
+ runAggregation,
19
+ runModelCalls,
20
+ renderAndFinalize,
21
+ } = require('../src/usage-run-steps');
22
+
23
+ // `run(argv, { ask })`: shared by the dispatcher and register flow; an injected
24
+ // `ask` is caller-owned. `bypassThrottle` (options, not argv) stays register-only.
25
+ async function run(argv = process.argv.slice(2), { ask: injectedAsk = null, bypassThrottle = false, inRegistration = false } = {}) {
26
+ const opts = parseArgs(argv);
27
+
28
+ // Resolve language first so even --help is localized.
29
+ const lang = opts.lang || detectReportLang();
30
+ const catalog = getCatalog(lang);
31
+
32
+ if (opts.help) {
33
+ process.stdout.write(catalog.cli.help);
34
+ return;
35
+ }
36
+
37
+ // One-shot commands (consent/endpoint config): act immediately, do NOT scan.
38
+ if (await handleOneShotCommand({ opts, catalog, injectedAsk })) return;
39
+
40
+ // 1. Local scan + classify (always computed and shown, ADR-011/013).
41
+ const { report, root, rootDir } = performScan({ opts, catalog });
42
+
43
+ // 2. Identity gate + local agent-usage signal. Roadmap only for anonymous runs
44
+ // (gate.showRoadmap = !loggedIn) AND never during register/onboarding.
45
+ const { gate: identityGate } = prepareIdentityAndUsage({ report, catalog });
46
+ const gate = (inRegistration && identityGate.showRoadmap)
47
+ ? { ...identityGate, showRoadmap: false }
48
+ : identityGate;
49
+
50
+ // 3. Consent gate before any AI/egress call (ADR-051); a decline still renders.
51
+ const aiConsentGranted = await resolveAiConsent({ opts, catalog, gate, injectedAsk });
52
+
53
+ // 4. Repo scoping (exclude client work).
54
+ const scope = await resolveRepoScope({ opts, cwd: rootDir, injectedAsk, catalog });
55
+ const consentEmail = (loadConsentState() || {}).email || null;
56
+ const agentRoots = scope.toplevels;
57
+
58
+ // 5. Aggregate scoped signals + rebuild scan/org-chart over the selection, re-classify.
59
+ runAggregation({ report, scope, consentEmail, agentRoots, root, catalog });
60
+ const maturity = classify(report);
61
+ const hasAgents = Array.isArray(report.agents) && report.agents.length > 0;
62
+ report.analyzedRepos =
63
+ scope.mode === 'all'
64
+ ? null
65
+ : scope.toplevels.map((tl) => tl.split(/[/\\]/).pop() || tl);
66
+
67
+ // 6. The three ephemeral model calls, serialized and gated by consent (ADR-051).
68
+ await runModelCalls({
69
+ report, maturity, aiConsentGranted, opts, gate, hasAgents, agentRoots, rootDir, lang, catalog,
70
+ });
71
+
72
+ // 7. Render (or emit --json), persist, optional --build-next-level, auto-share.
73
+ await renderAndFinalize({ report, maturity, lang, opts, root, gate, catalog, bypassThrottle });
74
+ }
75
+
76
+ module.exports = { run, resolveRepoScope, machineWideToplevels, promptScope };
77
+
78
+ // Auto-run only when executed directly, not when require()'d by the dispatcher.
79
+ if (require.main === module) {
80
+ run();
81
+ }
package/bin/alma.js ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { detectReportLang, getCatalog } = require('../src/i18n');
5
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
6
+ const { createStdinAsk } = require('../src/stdin-ask');
7
+ const { promptSelect } = require('../src/prompt-select');
8
+ const { makeIo } = require('./register');
9
+ const { runAlmaShell } = require('../src/alma-shell');
10
+ const { makeAlmaDeps } = require('../src/alma-flow');
11
+ const { run: runLogin } = require('./login');
12
+
13
+ function parseArgs(argv = []) {
14
+ const o = { lang: null, help: false };
15
+ for (let i = 0; i < argv.length; i++) {
16
+ const x = argv[i];
17
+ if (x === '--help' || x === '-h') o.help = true;
18
+ else if (x === '--lang') { const v = argv[++i]; o.lang = v === 'es' || v === 'en' ? v : null; }
19
+ else if (x.startsWith('--lang=')) { const v = x.slice(7); o.lang = v === 'es' || v === 'en' ? v : null; }
20
+ }
21
+ return o;
22
+ }
23
+
24
+ async function ensureSession({ lang, catalog, ask, stdinIsTTY, out }) {
25
+ let session = loadAuthSession();
26
+ if (sessionStatus(session) === 'active') return session;
27
+ if (!stdinIsTTY) return null;
28
+
29
+ const r = catalog.cli.accountReminder;
30
+ const choice = await promptSelect({
31
+ ask,
32
+ stdinIsTTY,
33
+ out: (line) => out(` ${line}\n`),
34
+ header: r.question,
35
+ hint: r.hint,
36
+ items: [{ id: 'yes', label: r.yes }, { id: 'no', label: r.no }],
37
+ labelFor: (it) => it.label,
38
+ });
39
+ if (!choice || choice.id !== 'yes') return null;
40
+
41
+ await runLogin(['--lang', lang]);
42
+ session = loadAuthSession();
43
+ return sessionStatus(session) === 'active' ? session : null;
44
+ }
45
+
46
+ async function run(
47
+ argv = process.argv.slice(2),
48
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, deps = null, session: injectedSession = null, out = null } = {},
49
+ ) {
50
+ const opts = parseArgs(argv);
51
+ const lang = opts.lang || detectReportLang();
52
+ const catalog = getCatalog(lang);
53
+ const a = catalog.alma;
54
+ const write = out || ((s) => process.stdout.write(s));
55
+ const d = deps || makeAlmaDeps();
56
+
57
+ if (opts.help) {
58
+ write(a.help + '\n');
59
+ return;
60
+ }
61
+
62
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
63
+ if (!stdinIsTTY && !injectedSession) {
64
+ process.stderr.write(`\n ${a.needTty}\n\n`);
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+
69
+ const ask = injectedAsk || createStdinAsk();
70
+ try {
71
+ const session = injectedSession
72
+ || (await ensureSession({ lang, catalog, ask, stdinIsTTY, out: write }));
73
+ if (!session) {
74
+ process.stderr.write(`\n ${a.loginRequired}\n\n`);
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+ const io = makeIo({ ask, lang, out: write, stdinIsTTY });
79
+ return await runAlmaShell({
80
+ io,
81
+ ask,
82
+ stdinIsTTY,
83
+ streamIsTTY: !!process.stdout.isTTY,
84
+ env: process.env,
85
+ rawOut: write,
86
+ session,
87
+ catalog,
88
+ deps: d,
89
+ });
90
+ } finally {
91
+ if (!injectedAsk) ask.close();
92
+ }
93
+ }
94
+
95
+ module.exports = { run, parseArgs };
96
+
97
+ if (require.main === module) {
98
+ run();
99
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `applications` — the positions the talent applied to (src/applications-flow.js).
5
+
6
+ const { detectReportLang, getCatalog } = require('../src/i18n');
7
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
8
+ const { createStdinAsk } = require('../src/stdin-ask');
9
+ const { makeIo } = require('./register');
10
+ const { makeRevealSink } = require('../src/reveal-output');
11
+ const { runApplications, makeApplicationsDeps } = require('../src/applications-flow');
12
+
13
+ function parseApplicationsArgs(argv = []) {
14
+ const o = { lang: null, help: false, json: false };
15
+ for (let i = 0; i < argv.length; i++) {
16
+ const a = argv[i];
17
+ if (a === '--help' || a === '-h') o.help = true;
18
+ else if (a === '--lang') { const v = argv[++i]; o.lang = v === 'es' || v === 'en' ? v : null; }
19
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = v === 'es' || v === 'en' ? v : null; }
20
+ else if (a === '--json') o.json = true;
21
+ }
22
+ return o;
23
+ }
24
+
25
+ async function run(
26
+ argv = process.argv.slice(2),
27
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, deps = null, session: injectedSession = null, out = null } = {},
28
+ ) {
29
+ const opts = parseApplicationsArgs(argv);
30
+ const lang = opts.lang || detectReportLang();
31
+ const catalog = getCatalog(lang);
32
+ const fp = catalog.applications;
33
+ const write = out || ((s) => process.stdout.write(s));
34
+
35
+ if (opts.help) {
36
+ write(fp.help + '\n');
37
+ return;
38
+ }
39
+
40
+ const session = injectedSession || loadAuthSession();
41
+ if (sessionStatus(session) !== 'active') {
42
+ process.stderr.write(`\n ${fp.loginRequired}\n\n`);
43
+ process.exitCode = 1;
44
+ return;
45
+ }
46
+
47
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
48
+ const ask = injectedAsk || createStdinAsk();
49
+ const sink = makeRevealSink({ json: opts.json, interactive: false, out, env: process.env });
50
+ try {
51
+ const io = makeIo({ ask, lang, out: sink.write, stdinIsTTY });
52
+ const result = await runApplications({
53
+ io, rawOut: sink.write, session, catalog,
54
+ opts: { json: opts.json },
55
+ deps: deps || makeApplicationsDeps(),
56
+ });
57
+ await sink.finish();
58
+ if (result && result.ok === false) process.exitCode = 1;
59
+ return result;
60
+ } finally {
61
+ if (!injectedAsk) ask.close();
62
+ }
63
+ }
64
+
65
+ module.exports = { run, parseApplicationsArgs };
66
+
67
+ if (require.main === module) {
68
+ run();
69
+ }
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `availability` — view or set the talent's availability (src/availability-flow.js).
5
+
6
+ const { detectReportLang, getCatalog } = require('../src/i18n');
7
+ const { loadAuthSession, sessionStatus } = require('../src/auth-session-store');
8
+ const { createStdinAsk } = require('../src/stdin-ask');
9
+ const { makeIo } = require('./register');
10
+ const { makeRevealSink } = require('../src/reveal-output');
11
+ const { runAvailability, makeAvailabilityDeps } = require('../src/availability-flow');
12
+
13
+ function parseAvailabilityArgs(argv = []) {
14
+ const o = { lang: null, help: false, json: false, set: false };
15
+ for (let i = 0; i < argv.length; i++) {
16
+ const a = argv[i];
17
+ if (a === '--help' || a === '-h') o.help = true;
18
+ else if (a === '--lang') { const v = argv[++i]; o.lang = v === 'es' || v === 'en' ? v : null; }
19
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = v === 'es' || v === 'en' ? v : null; }
20
+ else if (a === '--json') o.json = true;
21
+ else if (a === '--set') o.set = true;
22
+ }
23
+ return o;
24
+ }
25
+
26
+ async function run(
27
+ argv = process.argv.slice(2),
28
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, deps = null, session: injectedSession = null, out = null } = {},
29
+ ) {
30
+ const opts = parseAvailabilityArgs(argv);
31
+ const lang = opts.lang || detectReportLang();
32
+ const catalog = getCatalog(lang);
33
+ const fp = catalog.availability;
34
+ const write = out || ((s) => process.stdout.write(s));
35
+
36
+ if (opts.help) {
37
+ write(fp.help + '\n');
38
+ return;
39
+ }
40
+
41
+ const session = injectedSession || loadAuthSession();
42
+ if (sessionStatus(session) !== 'active') {
43
+ process.stderr.write(`\n ${fp.loginRequired}\n\n`);
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+
48
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
49
+ const ask = injectedAsk || createStdinAsk();
50
+ const sink = makeRevealSink({ json: opts.json, interactive: !!opts.set, out, env: process.env });
51
+ try {
52
+ const io = makeIo({ ask, lang, out: sink.write, stdinIsTTY });
53
+ const result = await runAvailability({
54
+ io, rawOut: sink.write, ask, session, catalog,
55
+ opts: { json: opts.json, set: opts.set, stdinIsTTY },
56
+ deps: deps || makeAvailabilityDeps(),
57
+ });
58
+ await sink.finish();
59
+ if (result && result.ok === false) process.exitCode = 1;
60
+ return result;
61
+ } finally {
62
+ if (!injectedAsk) ask.close();
63
+ }
64
+ }
65
+
66
+ module.exports = { run, parseAvailabilityArgs };
67
+
68
+ if (require.main === module) {
69
+ run();
70
+ }