shakers-cli 0.0.0-stage → 0.14.1

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 (237) hide show
  1. package/LICENSE +59 -0
  2. package/README.md +1233 -2
  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 +99 -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 +124 -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 +216 -0
  20. package/bin/mcp.js +124 -0
  21. package/bin/mcpb.js +5 -0
  22. package/bin/me.js +69 -0
  23. package/bin/onboarding.js +134 -0
  24. package/bin/portfolios.js +69 -0
  25. package/bin/rate.js +70 -0
  26. package/bin/register.js +337 -0
  27. package/bin/report-html.js +134 -0
  28. package/bin/save.js +77 -0
  29. package/bin/shakers.js +363 -0
  30. package/bin/share.js +72 -0
  31. package/bin/show-project.js +72 -0
  32. package/bin/socials.js +70 -0
  33. package/bin/superadmin.js +351 -0
  34. package/bin/update-check-worker.js +70 -0
  35. package/bin/update.js +111 -0
  36. package/package.json +40 -4
  37. package/src/agent-category.js +13 -0
  38. package/src/agent-evaluation.js +177 -0
  39. package/src/agent-org-chart.js +355 -0
  40. package/src/agent-synthesis.js +132 -0
  41. package/src/agent-usage.js +118 -0
  42. package/src/agents-client.js +165 -0
  43. package/src/ai-fluency-cell.js +72 -0
  44. package/src/ai-profile-client.js +45 -0
  45. package/src/ai-profile-preview.js +154 -0
  46. package/src/ai.js +66 -0
  47. package/src/alma-client.js +123 -0
  48. package/src/alma-flow.js +32 -0
  49. package/src/alma-repo-context.js +47 -0
  50. package/src/alma-shell.js +161 -0
  51. package/src/ansi.js +62 -0
  52. package/src/applications-client.js +79 -0
  53. package/src/applications-flow.js +58 -0
  54. package/src/auth-client.js +144 -0
  55. package/src/auth-device-client.js +118 -0
  56. package/src/auth-method-picker.js +44 -0
  57. package/src/auth-methods.js +35 -0
  58. package/src/auth-session-store.js +215 -0
  59. package/src/authorship-mismatch.js +62 -0
  60. package/src/authorship.js +204 -0
  61. package/src/automations-detector.js +170 -0
  62. package/src/availability-client.js +93 -0
  63. package/src/availability-flow.js +124 -0
  64. package/src/backend-request.js +191 -0
  65. package/src/blind-approval-extract.js +48 -0
  66. package/src/brand-ansi.js +14 -0
  67. package/src/brand-svg.js +9 -0
  68. package/src/browser-tools-detector.js +21 -0
  69. package/src/build-next-level.js +56 -0
  70. package/src/certifications-client.js +89 -0
  71. package/src/certifications-flow.js +75 -0
  72. package/src/certify-dimension-client.js +163 -0
  73. package/src/certify-dimension-flow.js +135 -0
  74. package/src/certify-disclaimer.js +51 -0
  75. package/src/certify-remediation-prompt.js +23 -0
  76. package/src/cli-args.js +83 -0
  77. package/src/command-audit.js +105 -0
  78. package/src/config-dir.js +120 -0
  79. package/src/config.js +877 -0
  80. package/src/consent-flow.js +115 -0
  81. package/src/consent-skip.js +27 -0
  82. package/src/cv-file.js +62 -0
  83. package/src/cv-text.js +92 -0
  84. package/src/decisions-extract.js +43 -0
  85. package/src/detect-repos.js +145 -0
  86. package/src/detected-tools.js +15 -0
  87. package/src/detection-evidence.js +105 -0
  88. package/src/detection-noise.js +132 -0
  89. package/src/detectors.js +221 -0
  90. package/src/device-auth-store.js +100 -0
  91. package/src/device-login.js +120 -0
  92. package/src/email-verification.js +152 -0
  93. package/src/env-paths.js +30 -0
  94. package/src/find-projects-cache.js +89 -0
  95. package/src/find-projects-client.js +148 -0
  96. package/src/find-projects-flow.js +164 -0
  97. package/src/git-activity.js +124 -0
  98. package/src/git-log-prefetch.js +53 -0
  99. package/src/graph-certs.js +58 -0
  100. package/src/graph-generator.js +230 -0
  101. package/src/graph-scan.js +239 -0
  102. package/src/i18n.js +3341 -0
  103. package/src/inter-fonts.js +6 -0
  104. package/src/interactive-select.js +183 -0
  105. package/src/interview-client.js +226 -0
  106. package/src/interview-transcript.js +56 -0
  107. package/src/inventory-client.js +90 -0
  108. package/src/invitations-client.js +66 -0
  109. package/src/invitations-flow.js +50 -0
  110. package/src/lang-client.js +147 -0
  111. package/src/lang-codes.js +14 -0
  112. package/src/lang-flow.js +85 -0
  113. package/src/legal-notice.js +53 -0
  114. package/src/locale.js +72 -0
  115. package/src/markdown-ansi.js +50 -0
  116. package/src/maturity.js +111 -0
  117. package/src/mcp-ai-usage-result-tool.js +111 -0
  118. package/src/mcp-ai-usage-tool.js +401 -0
  119. package/src/mcp-alma-tools.js +95 -0
  120. package/src/mcp-applications-tools.js +44 -0
  121. package/src/mcp-auth-form.js +480 -0
  122. package/src/mcp-availability-tools.js +45 -0
  123. package/src/mcp-certifications-tools.js +44 -0
  124. package/src/mcp-certify-dimension-tools.js +66 -0
  125. package/src/mcp-choice.js +95 -0
  126. package/src/mcp-detector.js +223 -0
  127. package/src/mcp-device-login-tools.js +177 -0
  128. package/src/mcp-find-projects-tools.js +69 -0
  129. package/src/mcp-install.js +275 -0
  130. package/src/mcp-instructions.js +27 -0
  131. package/src/mcp-invitations-tools.js +44 -0
  132. package/src/mcp-lang-tools.js +41 -0
  133. package/src/mcp-onboarding-tools.js +379 -0
  134. package/src/mcp-portfolios-tools.js +50 -0
  135. package/src/mcp-profile-tools.js +48 -0
  136. package/src/mcp-prompts.js +73 -0
  137. package/src/mcp-rate-tools.js +44 -0
  138. package/src/mcp-register-tools.js +441 -0
  139. package/src/mcp-report-tools.js +105 -0
  140. package/src/mcp-role-tools.js +372 -0
  141. package/src/mcp-saved-positions-tools.js +59 -0
  142. package/src/mcp-server.js +290 -0
  143. package/src/mcp-show-project-tools.js +52 -0
  144. package/src/mcp-signup-client.js +118 -0
  145. package/src/mcp-signup-tools.js +1171 -0
  146. package/src/mcp-socials-tools.js +41 -0
  147. package/src/memory-structure-detector.js +108 -0
  148. package/src/model-call-record.js +198 -0
  149. package/src/onboarding-availability.js +26 -0
  150. package/src/onboarding-client.js +374 -0
  151. package/src/onboarding-flow.js +1162 -0
  152. package/src/onboarding-funnel.js +272 -0
  153. package/src/onboarding-livekit-client.js +102 -0
  154. package/src/onboarding-status-client.js +57 -0
  155. package/src/open-file.js +32 -0
  156. package/src/osc-link.js +16 -0
  157. package/src/portfolio-client.js +164 -0
  158. package/src/portfolio-git-info.js +61 -0
  159. package/src/portfolios-client.js +85 -0
  160. package/src/portfolios-flow.js +79 -0
  161. package/src/profile-client.js +133 -0
  162. package/src/profile-flow.js +115 -0
  163. package/src/profile-switch.js +46 -0
  164. package/src/prompt-select.js +66 -0
  165. package/src/rate-client.js +81 -0
  166. package/src/rate-flow.js +137 -0
  167. package/src/register-context.js +145 -0
  168. package/src/render-ai-fluency.js +266 -0
  169. package/src/render-certification.js +177 -0
  170. package/src/render-html.js +140 -0
  171. package/src/render-report-text.js +27 -0
  172. package/src/render-sheet.js +261 -0
  173. package/src/render-terminal.js +109 -0
  174. package/src/render-usage-report-text.js +155 -0
  175. package/src/repo-context.js +215 -0
  176. package/src/report-gating.js +49 -0
  177. package/src/report-store.js +226 -0
  178. package/src/report-theme.js +177 -0
  179. package/src/report-view-client.js +50 -0
  180. package/src/reveal-output.js +29 -0
  181. package/src/roadmap-content.js +453 -0
  182. package/src/roadmap-personalization.js +132 -0
  183. package/src/roadmap-prompt.js +154 -0
  184. package/src/roles-client.js +112 -0
  185. package/src/roles-flow.js +192 -0
  186. package/src/sanitize-network-text.js +36 -0
  187. package/src/saved-positions-client.js +71 -0
  188. package/src/saved-positions-flow.js +50 -0
  189. package/src/scan-exclusions.js +50 -0
  190. package/src/scanner.js +624 -0
  191. package/src/scope-signals.js +148 -0
  192. package/src/secret-prompt.js +72 -0
  193. package/src/session-gate.js +30 -0
  194. package/src/session-normalizers.js +174 -0
  195. package/src/session-refresh.js +51 -0
  196. package/src/session-scan.js +475 -0
  197. package/src/session-signals.js +36 -0
  198. package/src/shakers-wordmark.js +17 -0
  199. package/src/share-card.js +362 -0
  200. package/src/share-certification.js +111 -0
  201. package/src/share-consent-state.js +157 -0
  202. package/src/share-payload.js +300 -0
  203. package/src/share.js +185 -0
  204. package/src/show-project-client.js +58 -0
  205. package/src/show-project-flow.js +119 -0
  206. package/src/signup-client.js +103 -0
  207. package/src/signup-copy.js +450 -0
  208. package/src/signup-language.js +21 -0
  209. package/src/skills-client.js +102 -0
  210. package/src/socials-client.js +91 -0
  211. package/src/socials-flow.js +83 -0
  212. package/src/specificity-extract.js +41 -0
  213. package/src/start-add-agents.js +306 -0
  214. package/src/start-add-portfolio.js +388 -0
  215. package/src/start-add-skills.js +260 -0
  216. package/src/stdin-ask.js +129 -0
  217. package/src/steering-extract.js +43 -0
  218. package/src/strip-internal-comments.js +45 -0
  219. package/src/tech-detector.js +295 -0
  220. package/src/templates/report-sheet.html +572 -0
  221. package/src/terminal-agents.js +207 -0
  222. package/src/terminal-format.js +85 -0
  223. package/src/terminal-progress.js +106 -0
  224. package/src/terminal-sections.js +219 -0
  225. package/src/tier-analysis.js +126 -0
  226. package/src/tier-engine.js +114 -0
  227. package/src/tier-projection.js +117 -0
  228. package/src/transcript-turns.js +49 -0
  229. package/src/translations-client.js +84 -0
  230. package/src/typewriter.js +154 -0
  231. package/src/update-flow.js +223 -0
  232. package/src/update-notifier.js +113 -0
  233. package/src/usage-model-calls.js +119 -0
  234. package/src/usage-oneshot-commands.js +180 -0
  235. package/src/usage-repo-scope.js +162 -0
  236. package/src/usage-run-steps.js +354 -0
  237. package/src/work-streams.js +79 -0
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `certifications` — the talent's dimension certifications (src/certifications-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 { runCertifications, makeCertificationsDeps } = require('../src/certifications-flow');
12
+
13
+ function parseCertificationsArgs(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 = parseCertificationsArgs(argv);
30
+ const lang = opts.lang || detectReportLang();
31
+ const catalog = getCatalog(lang);
32
+ const fp = catalog.certifications;
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 runCertifications({
53
+ io, rawOut: sink.write, session, catalog,
54
+ opts: { json: opts.json },
55
+ deps: deps || makeCertificationsDeps(),
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, parseCertificationsArgs };
66
+
67
+ if (require.main === module) {
68
+ run();
69
+ }
package/bin/certify.js ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `certify` — discover + pick a dimension, then hand over the web link (src/certify-dimension-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 { runCertifyDimension, makeCertifyDimensionDeps } = require('../src/certify-dimension-flow');
11
+
12
+ function parseCertifyArgs(argv = []) {
13
+ const o = { lang: null, help: false, dimension: null, acceptDisclaimer: 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
+ else if (a === '--dimension') o.dimension = argv[++i] != null ? argv[i] : null;
20
+ else if (a.startsWith('--dimension=')) o.dimension = a.slice('--dimension='.length);
21
+ else if (a === '--accept-disclaimer') o.acceptDisclaimer = 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, input = undefined, output = undefined } = {},
29
+ ) {
30
+ const opts = parseCertifyArgs(argv);
31
+ const lang = opts.lang || detectReportLang();
32
+ const catalog = getCatalog(lang);
33
+ const cd = catalog.certifyDimension;
34
+ const write = out || ((s) => process.stdout.write(s));
35
+
36
+ if (opts.help) {
37
+ write(cd.help + '\n');
38
+ return;
39
+ }
40
+
41
+ const session = injectedSession || loadAuthSession();
42
+ if (sessionStatus(session) !== 'active') {
43
+ process.stderr.write(`\n ${cd.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
+ try {
51
+ const io = makeIo({ ask, lang, out: write, acceptDisclaimer: opts.acceptDisclaimer, stdinIsTTY });
52
+ const result = await runCertifyDimension({
53
+ io,
54
+ ask,
55
+ stdinIsTTY,
56
+ session,
57
+ lang,
58
+ catalog,
59
+ opts: { dimension: opts.dimension, input, output },
60
+ deps: deps || makeCertifyDimensionDeps(),
61
+ });
62
+ if (result && result.ok === false) process.exitCode = 1;
63
+ return result;
64
+ } finally {
65
+ if (!injectedAsk) ask.close();
66
+ }
67
+ }
68
+
69
+ module.exports = { run, parseCertifyArgs };
70
+
71
+ if (require.main === module) {
72
+ run();
73
+ }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `change-role` — set the MAIN role to one the talent already holds (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 { runChangeMainRole, 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.changeHelp + '\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 runChangeMainRole({ 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
+ }
package/bin/config.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { detectReportLang } = require('../src/i18n');
5
+ const {
6
+ loadConfigFile,
7
+ saveConfigFile,
8
+ validateEndpoint,
9
+ getCertsBase,
10
+ getHubBase,
11
+ getTalentProfileUrl,
12
+ getIngestEndpoint,
13
+ } = require('../src/config');
14
+
15
+ const VALID_LANGS = new Set(['es', 'en']);
16
+ const ENDPOINT_KEYS = new Set(['certsBase', 'hubBase', 'ingestEndpoint', 'profileUrl']);
17
+ const PROFILE_VALUES = new Set(['external', 'talent']);
18
+ const SETTABLE = new Set([...ENDPOINT_KEYS, 'profile', 'lang']);
19
+
20
+ const COPY = {
21
+ es: {
22
+ help: 'config — lee/escribe la configuracion NO sensible del CLI (bases de hub/certs, perfil, idioma). Uso: shakers config <list|get [clave]|set clave valor>\n Claves: certsBase, hubBase, ingestEndpoint, profileUrl, profile, lang.\n Los secretos (tokens/credenciales) NUNCA se guardan aqui: se obtienen con `shakers login` o por entorno.',
23
+ unknownKey: (k) => `clave desconocida: ${k}. Claves validas: ${[...SETTABLE].join(', ')}.`,
24
+ needValue: 'set necesita <clave> <valor>.',
25
+ badEndpoint: (k, r) => `valor invalido para ${k} (${r}). Debe ser una URL http de loopback o https.`,
26
+ badProfile: 'profile debe ser "external" o "talent".',
27
+ badLang: 'lang debe ser "es" o "en".',
28
+ saved: (k, v) => `guardado ${k} = ${v}`,
29
+ resolvedHeading: 'Resueltos (env > config.json > default local):',
30
+ },
31
+ en: {
32
+ help: 'config — read/write the CLI NON-sensitive configuration (hub/certs bases, profile, language). Usage: shakers config <list|get [key]|set key value>\n Keys: certsBase, hubBase, ingestEndpoint, profileUrl, profile, lang.\n Secrets (tokens/credentials) are NEVER stored here: get them via `shakers login` or the environment.',
33
+ unknownKey: (k) => `unknown key: ${k}. Valid keys: ${[...SETTABLE].join(', ')}.`,
34
+ needValue: 'set needs <key> <value>.',
35
+ badEndpoint: (k, r) => `invalid value for ${k} (${r}). Must be a loopback http URL or https.`,
36
+ badProfile: 'profile must be "external" or "talent".',
37
+ badLang: 'lang must be "es" or "en".',
38
+ saved: (k, v) => `saved ${k} = ${v}`,
39
+ resolvedHeading: 'Resolved (env > config.json > local default):',
40
+ },
41
+ };
42
+
43
+ function parseArgs(argv) {
44
+ const o = { lang: null, help: false, rest: [] };
45
+ for (let i = 0; i < argv.length; i++) {
46
+ const a = argv[i];
47
+ if (a === '--lang') o.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
48
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = VALID_LANGS.has(v) ? v : null; }
49
+ else if (a === '--help' || a === '-h') o.help = true;
50
+ else o.rest.push(a);
51
+ }
52
+ return o;
53
+ }
54
+
55
+ function resolvedView(env) {
56
+ return {
57
+ certsBase: getCertsBase(env),
58
+ hubBase: getHubBase(env),
59
+ ingestEndpoint: getIngestEndpoint(env),
60
+ profileUrl: getTalentProfileUrl(env),
61
+ };
62
+ }
63
+
64
+ async function run(argv = process.argv.slice(2), { env = process.env, out = null } = {}) {
65
+ const o = parseArgs(argv);
66
+ const lang = o.lang || detectReportLang();
67
+ const c = COPY[lang] || COPY.en;
68
+ const write = out || ((s) => process.stdout.write(s));
69
+ const line = (s) => write(` ${s}\n`);
70
+
71
+ if (o.help || o.rest.length === 0) {
72
+ write(`\n ${c.help}\n\n`);
73
+ return;
74
+ }
75
+
76
+ const [sub, key, ...valueParts] = o.rest;
77
+
78
+ if (sub === 'list') {
79
+ const config = loadConfigFile(env);
80
+ for (const k of SETTABLE) {
81
+ if (config[k] !== undefined) line(`${k} = ${config[k]}`);
82
+ }
83
+ line(c.resolvedHeading);
84
+ const r = resolvedView(env);
85
+ for (const k of Object.keys(r)) line(` ${k} = ${r[k] === null ? '(unset)' : r[k]}`);
86
+ return;
87
+ }
88
+
89
+ if (sub === 'get') {
90
+ if (!key) { line(c.needValue); process.exitCode = 1; return; }
91
+ if (!SETTABLE.has(key)) { line(c.unknownKey(key)); process.exitCode = 1; return; }
92
+ const config = loadConfigFile(env);
93
+ line(config[key] !== undefined ? String(config[key]) : '(unset)');
94
+ return;
95
+ }
96
+
97
+ if (sub === 'set') {
98
+ const value = valueParts.join(' ').trim();
99
+ if (!key || !value) { line(c.needValue); process.exitCode = 1; return; }
100
+ if (!SETTABLE.has(key)) { line(c.unknownKey(key)); process.exitCode = 1; return; }
101
+ if (key === 'profile') {
102
+ if (!PROFILE_VALUES.has(value)) { line(c.badProfile); process.exitCode = 1; return; }
103
+ } else if (key === 'lang') {
104
+ if (!VALID_LANGS.has(value)) { line(c.badLang); process.exitCode = 1; return; }
105
+ } else if (key !== 'profileUrl') {
106
+ const v = validateEndpoint(value);
107
+ if (!v.ok) { line(c.badEndpoint(key, v.reason)); process.exitCode = 1; return; }
108
+ }
109
+ const config = loadConfigFile(env);
110
+ config[key] = value;
111
+ try { saveConfigFile(config, env); } catch { line('could not write config.json'); process.exitCode = 1; return; }
112
+ line(c.saved(key, value));
113
+ return;
114
+ }
115
+
116
+ write(`\n ${c.help}\n\n`);
117
+ process.exitCode = 1;
118
+ }
119
+
120
+ module.exports = { run, parseArgs, SETTABLE, ENDPOINT_KEYS };
121
+
122
+ if (require.main === module) {
123
+ run();
124
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `experiences` — the talent's work experiences (portfolios type=EXPERIENCE).
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 { runPortfolioList, makePortfoliosDeps } = require('../src/portfolios-flow');
12
+
13
+ function parseArgs(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 = parseArgs(argv);
30
+ const lang = opts.lang || detectReportLang();
31
+ const catalog = getCatalog(lang);
32
+ const fp = catalog.experiences;
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, out, env: process.env });
50
+ try {
51
+ const io = makeIo({ ask, lang, out: sink.write, stdinIsTTY });
52
+ const result = await runPortfolioList({
53
+ io, rawOut: sink.write, lang, session, catalog, kind: 'experiences',
54
+ opts: { json: opts.json },
55
+ deps: deps || makePortfoliosDeps(),
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, parseArgs };
66
+
67
+ if (require.main === module) {
68
+ run();
69
+ }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `find-projects` — list the Positions/Projects available to the talent (src/find-projects-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 { runFindProjects, makeFindProjectsDeps } = require('../src/find-projects-flow');
11
+ const { makeRevealSink } = require('../src/reveal-output');
12
+
13
+ function toInt(v) {
14
+ const n = Number.parseInt(v, 10);
15
+ return Number.isInteger(n) ? n : null;
16
+ }
17
+
18
+ function parseFindProjectsArgs(argv = []) {
19
+ const o = { lang: null, help: false, tab: null, json: false, limit: null, page: null, attendance: null, country: null, recommended: false };
20
+ for (let i = 0; i < argv.length; i++) {
21
+ const a = argv[i];
22
+ if (a === '--help' || a === '-h') o.help = true;
23
+ else if (a === '--lang') { const v = argv[++i]; o.lang = v === 'es' || v === 'en' ? v : null; }
24
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = v === 'es' || v === 'en' ? v : null; }
25
+ else if (a === '--tab') o.tab = argv[++i] != null ? argv[i] : null;
26
+ else if (a.startsWith('--tab=')) o.tab = a.slice('--tab='.length);
27
+ else if (a === '--limit') o.limit = toInt(argv[++i]);
28
+ else if (a.startsWith('--limit=')) o.limit = toInt(a.slice('--limit='.length));
29
+ else if (a === '--page') o.page = toInt(argv[++i]);
30
+ else if (a.startsWith('--page=')) o.page = toInt(a.slice('--page='.length));
31
+ else if (a === '--attendance') o.attendance = argv[++i] != null ? argv[i] : null;
32
+ else if (a.startsWith('--attendance=')) o.attendance = a.slice('--attendance='.length);
33
+ else if (a === '--country') o.country = argv[++i] != null ? argv[i] : null;
34
+ else if (a.startsWith('--country=')) o.country = a.slice('--country='.length);
35
+ else if (a === '--recommended') o.recommended = true;
36
+ else if (a === '--json') o.json = true;
37
+ }
38
+ return o;
39
+ }
40
+
41
+ async function run(
42
+ argv = process.argv.slice(2),
43
+ { ask: injectedAsk = null, stdinIsTTY: ttyOverride = undefined, deps = null, session: injectedSession = null, out = null } = {},
44
+ ) {
45
+ const opts = parseFindProjectsArgs(argv);
46
+ const lang = opts.lang || detectReportLang();
47
+ const catalog = getCatalog(lang);
48
+ const fp = catalog.findProjects;
49
+ const write = out || ((s) => process.stdout.write(s));
50
+
51
+ if (opts.help) {
52
+ write(fp.help + '\n');
53
+ return;
54
+ }
55
+
56
+ const session = injectedSession || loadAuthSession();
57
+ if (sessionStatus(session) !== 'active') {
58
+ process.stderr.write(`\n ${fp.loginRequired}\n\n`);
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+
63
+ const stdinIsTTY = ttyOverride !== undefined ? ttyOverride : !!process.stdin.isTTY;
64
+ const ask = injectedAsk || createStdinAsk();
65
+ const sink = makeRevealSink({ json: opts.json, out, env: process.env });
66
+ try {
67
+ const io = makeIo({ ask, lang, out: sink.write, stdinIsTTY });
68
+ const result = await runFindProjects({
69
+ io,
70
+ rawOut: sink.write,
71
+ session,
72
+ lang,
73
+ catalog,
74
+ opts: { tab: opts.tab, json: opts.json, limit: opts.limit, page: opts.page, attendance: opts.attendance, country: opts.country, recommended: opts.recommended },
75
+ deps: deps || makeFindProjectsDeps(),
76
+ });
77
+ await sink.finish();
78
+ if (result && result.ok === false) process.exitCode = 1;
79
+ return result;
80
+ } finally {
81
+ if (!injectedAsk) ask.close();
82
+ }
83
+ }
84
+
85
+ module.exports = { run, parseFindProjectsArgs };
86
+
87
+ if (require.main === module) {
88
+ run();
89
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `invitations` — the talent's unread position invitations (src/invitations-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 { runInvitations, makeInvitationsDeps } = require('../src/invitations-flow');
12
+
13
+ function parseInvitationsArgs(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 = parseInvitationsArgs(argv);
30
+ const lang = opts.lang || detectReportLang();
31
+ const catalog = getCatalog(lang);
32
+ const fp = catalog.invitations;
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 runInvitations({
53
+ io, rawOut: sink.write, session, catalog,
54
+ opts: { json: opts.json },
55
+ deps: deps || makeInvitationsDeps(),
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, parseInvitationsArgs };
66
+
67
+ if (require.main === module) {
68
+ run();
69
+ }
package/bin/lang.js ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // `lang` — view or set the talent's languages (src/lang-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 { runLang, makeLangDeps } = require('../src/lang-flow');
12
+
13
+ function parseLangArgs(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 = parseLangArgs(argv);
31
+ const lang = opts.lang || detectReportLang();
32
+ const catalog = getCatalog(lang);
33
+ const fp = catalog.lang;
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 runLang({
54
+ io, rawOut: sink.write, ask, session, catalog,
55
+ opts: { json: opts.json, set: opts.set, stdinIsTTY },
56
+ deps: deps || makeLangDeps(),
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, parseLangArgs };
67
+
68
+ if (require.main === module) {
69
+ run();
70
+ }