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,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` — dimension certification interview over LiveKit (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,120 @@
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']);
19
+
20
+ const COPY = {
21
+ es: {
22
+ help: 'config — lee/escribe la configuracion NO sensible del CLI (bases de hub/certs, perfil). Uso: shakers config <list|get [clave]|set clave valor>\n Claves: certsBase, hubBase, ingestEndpoint, profileUrl, profile.\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
+ saved: (k, v) => `guardado ${k} = ${v}`,
28
+ resolvedHeading: 'Resueltos (env > config.json > default local):',
29
+ },
30
+ en: {
31
+ help: 'config — read/write the CLI NON-sensitive configuration (hub/certs bases, profile). Usage: shakers config <list|get [key]|set key value>\n Keys: certsBase, hubBase, ingestEndpoint, profileUrl, profile.\n Secrets (tokens/credentials) are NEVER stored here: get them via `shakers login` or the environment.',
32
+ unknownKey: (k) => `unknown key: ${k}. Valid keys: ${[...SETTABLE].join(', ')}.`,
33
+ needValue: 'set needs <key> <value>.',
34
+ badEndpoint: (k, r) => `invalid value for ${k} (${r}). Must be a loopback http URL or https.`,
35
+ badProfile: 'profile must be "external" or "talent".',
36
+ saved: (k, v) => `saved ${k} = ${v}`,
37
+ resolvedHeading: 'Resolved (env > config.json > local default):',
38
+ },
39
+ };
40
+
41
+ function parseArgs(argv) {
42
+ const o = { lang: null, help: false, rest: [] };
43
+ for (let i = 0; i < argv.length; i++) {
44
+ const a = argv[i];
45
+ if (a === '--lang') o.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
46
+ else if (a.startsWith('--lang=')) { const v = a.slice(7); o.lang = VALID_LANGS.has(v) ? v : null; }
47
+ else if (a === '--help' || a === '-h') o.help = true;
48
+ else o.rest.push(a);
49
+ }
50
+ return o;
51
+ }
52
+
53
+ function resolvedView(env) {
54
+ return {
55
+ certsBase: getCertsBase(env),
56
+ hubBase: getHubBase(env),
57
+ ingestEndpoint: getIngestEndpoint(env),
58
+ profileUrl: getTalentProfileUrl(env),
59
+ };
60
+ }
61
+
62
+ async function run(argv = process.argv.slice(2), { env = process.env, out = null } = {}) {
63
+ const o = parseArgs(argv);
64
+ const lang = o.lang || detectReportLang();
65
+ const c = COPY[lang] || COPY.en;
66
+ const write = out || ((s) => process.stdout.write(s));
67
+ const line = (s) => write(` ${s}\n`);
68
+
69
+ if (o.help || o.rest.length === 0) {
70
+ write(`\n ${c.help}\n\n`);
71
+ return;
72
+ }
73
+
74
+ const [sub, key, ...valueParts] = o.rest;
75
+
76
+ if (sub === 'list') {
77
+ const config = loadConfigFile(env);
78
+ for (const k of SETTABLE) {
79
+ if (config[k] !== undefined) line(`${k} = ${config[k]}`);
80
+ }
81
+ line(c.resolvedHeading);
82
+ const r = resolvedView(env);
83
+ for (const k of Object.keys(r)) line(` ${k} = ${r[k] === null ? '(unset)' : r[k]}`);
84
+ return;
85
+ }
86
+
87
+ if (sub === 'get') {
88
+ if (!key) { line(c.needValue); process.exitCode = 1; return; }
89
+ if (!SETTABLE.has(key)) { line(c.unknownKey(key)); process.exitCode = 1; return; }
90
+ const config = loadConfigFile(env);
91
+ line(config[key] !== undefined ? String(config[key]) : '(unset)');
92
+ return;
93
+ }
94
+
95
+ if (sub === 'set') {
96
+ const value = valueParts.join(' ').trim();
97
+ if (!key || !value) { line(c.needValue); process.exitCode = 1; return; }
98
+ if (!SETTABLE.has(key)) { line(c.unknownKey(key)); process.exitCode = 1; return; }
99
+ if (key === 'profile') {
100
+ if (!PROFILE_VALUES.has(value)) { line(c.badProfile); process.exitCode = 1; return; }
101
+ } else if (key !== 'profileUrl') {
102
+ const v = validateEndpoint(value);
103
+ if (!v.ok) { line(c.badEndpoint(key, v.reason)); process.exitCode = 1; return; }
104
+ }
105
+ const config = loadConfigFile(env);
106
+ config[key] = value;
107
+ try { saveConfigFile(config, env); } catch { line('could not write config.json'); process.exitCode = 1; return; }
108
+ line(c.saved(key, value));
109
+ return;
110
+ }
111
+
112
+ write(`\n ${c.help}\n\n`);
113
+ process.exitCode = 1;
114
+ }
115
+
116
+ module.exports = { run, parseArgs, SETTABLE, ENDPOINT_KEYS };
117
+
118
+ if (require.main === module) {
119
+ run();
120
+ }
@@ -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
+ }