jobarbiter 0.3.7 → 0.3.9

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.
@@ -435,9 +435,11 @@ async function runToolDetectionStep(prompt, config) {
435
435
  console.log(` communication clarity, iteration patterns, tool fluency\n`);
436
436
  console.log(` This is what makes your profile ${c.bold("verified")} and ${c.bold("valuable")}.`);
437
437
  console.log(` Your observer regularly records and reports your proven AI proficiency.\n`);
438
- console.log(` ${c.bold("Privacy:")} ${c.highlight("No code, prompts, or content leave your machine.")}`);
439
- console.log(` Only derived proficiency signals (scores, patterns, dimensions)`);
440
- console.log(` are submitted never raw session data.\n`);
438
+ console.log(` ${c.bold("Privacy:")} Analysis runs ${c.highlight("locally by your own AI agent.")}`);
439
+ console.log(` Your agent reads your sessions to evaluate proficiency, but`);
440
+ console.log(` ${c.bold("only derived scores and signals are submitted to JobArbiter.")}`);
441
+ console.log(` Raw session data — prompts, responses, code — never leaves`);
442
+ console.log(` your machine and is never stored on our servers.\n`);
441
443
  console.log(c.dim(` Data stored locally: ~/.config/jobarbiter/observer/observations.json`));
442
444
  console.log(c.dim(` Review anytime: jobarbiter observe review\n`));
443
445
  const observerNames = needsObserver.map((t) => t.name).join(", ");
@@ -457,7 +459,13 @@ async function runToolDetectionStep(prompt, config) {
457
459
  }
458
460
  if (result.installed.length > 0) {
459
461
  console.log(`\n ${sym.check} ${c.success(`${result.installed.length} observer${result.installed.length > 1 ? "s" : ""} installed!`)}`);
460
- console.log(c.dim(` Your proficiency profile will start building automatically.\n`));
462
+ console.log(`\n ${c.bold("What happens now?")}`);
463
+ console.log(` Observers activate each time you use your AI tools.`);
464
+ console.log(` Just work normally — every session builds your profile.\n`);
465
+ console.log(` ${sym.arrow} ${c.highlight("Your next AI session will begin your proficiency analysis.")}`);
466
+ console.log(` Your own AI agent performs the analysis locally — evaluating`);
467
+ console.log(` how you work, not just how much. Only derived scores are`);
468
+ console.log(` submitted to JobArbiter. Raw session data never leaves your machine.\n`);
461
469
  }
462
470
  }
463
471
  else {
@@ -497,10 +505,11 @@ async function runConnectAIAccountsStep(prompt) {
497
505
  console.log(` ${sym.bullet} Model preferences ${c.dim("(which models you reach for)")}`);
498
506
  console.log(` ${sym.bullet} Session frequency and consistency over time`);
499
507
  console.log(` ${sym.bullet} API spend patterns ${c.dim("(demonstrates serious usage)")}\n`);
500
- console.log(` ${c.bold("What we NEVER access:")}`);
501
- console.log(` ${sym.bullet} Your conversation content`);
502
- console.log(` ${sym.bullet} Prompts or responses`);
503
- console.log(` ${sym.bullet} Any proprietary or sensitive data\n`);
508
+ console.log(` ${c.bold("How your data stays safe:")}`);
509
+ console.log(` ${sym.bullet} Analysis runs ${c.bold("locally on your machine")} by your own AI agent`);
510
+ console.log(` ${sym.bullet} Only derived proficiency scores leave your machine — never raw`);
511
+ console.log(` session data, prompts, responses, or conversation content`);
512
+ console.log(` ${sym.bullet} ${c.bold("Nothing is stored on JobArbiter's servers")} except your scores\n`);
504
513
  // Check for already connected providers
505
514
  const existingProviders = loadProviderKeys();
506
515
  if (existingProviders.length > 0) {
@@ -516,27 +525,31 @@ async function runConnectAIAccountsStep(prompt) {
516
525
  console.log(` ${c.bold("Available connections:")}\n`);
517
526
  console.log(` ${c.highlight("1.")} Anthropic API key — Pull Claude usage stats`);
518
527
  console.log(` ${c.highlight("2.")} OpenAI API key — Pull GPT/ChatGPT usage stats`);
519
- console.log(` ${c.highlight("3.")} Skip for now\n`);
528
+ console.log(` ${c.highlight("3.")} Google AI API key — Pull Gemini usage stats`);
529
+ console.log(` ${c.highlight("4.")} Skip for now\n`);
520
530
  console.log(c.dim(` You can connect accounts later with 'jobarbiter tokens connect'\n`));
521
- const choice = await prompt.question(` Your choice ${c.dim("[1/2/3]")}: `);
522
- if (choice === "3" || choice.toLowerCase() === "skip" || choice === "") {
531
+ const choice = await prompt.question(` Your choice ${c.dim("[1/2/3/4]")}: `);
532
+ if (choice === "4" || choice.toLowerCase() === "skip" || choice === "") {
523
533
  console.log(`\n${c.dim(" Skipped — you can connect providers later with 'jobarbiter tokens connect'")}\n`);
524
534
  continueConnecting = false;
525
535
  }
526
536
  else if (choice === "1") {
527
537
  await connectProvider(prompt, "anthropic", "Anthropic");
528
- // Ask if they want to connect another
529
538
  continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
530
539
  console.log();
531
540
  }
532
541
  else if (choice === "2") {
533
542
  await connectProvider(prompt, "openai", "OpenAI");
534
- // Ask if they want to connect another
543
+ continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
544
+ console.log();
545
+ }
546
+ else if (choice === "3") {
547
+ await connectProvider(prompt, "google", "Google AI");
535
548
  continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
536
549
  console.log();
537
550
  }
538
551
  else {
539
- console.log(c.error(" Please enter 1, 2, or 3"));
552
+ console.log(c.error(" Please enter 1, 2, 3, or 4"));
540
553
  }
541
554
  }
542
555
  }
@@ -567,7 +580,11 @@ async function connectProvider(prompt, providerId, providerName) {
567
580
  }
568
581
  function showWorkerCompletion(state) {
569
582
  console.log(`${sym.done} ${c.bold("Step 7/7 — You're In!")}\n`);
570
- console.log(`Your profile is live. Here's what happens next:\n`);
583
+ console.log(`Your profile is live. Here's how it builds:\n`);
584
+ console.log(` 💡 ${c.bold("Your next AI session will begin your proficiency analysis.")}`);
585
+ console.log(` Just use your tools normally. Your own AI agent analyzes each`);
586
+ console.log(` session locally — evaluating how you work with AI, not just`);
587
+ console.log(` how much. Only proficiency scores are sent to JobArbiter.\n`);
571
588
  console.log(` 📊 Your proficiency profile builds automatically from:`);
572
589
  console.log(` ${c.bold("How you use AI (qualitative):")}`);
573
590
  console.log(` ${sym.bullet} Orchestration complexity ${c.dim("— single prompts vs multi-agent pipelines")}`);
@@ -35,6 +35,10 @@ export declare function validateAnthropicKey(apiKey: string): Promise<Validation
35
35
  * Returns validation result with usage summary if available.
36
36
  */
37
37
  export declare function validateOpenAIKey(apiKey: string): Promise<ValidationResult>;
38
+ /**
39
+ * Validate a Google AI API key by making a test API call.
40
+ */
41
+ export declare function validateGoogleKey(apiKey: string): Promise<ValidationResult>;
38
42
  /**
39
43
  * Get list of supported providers.
40
44
  */
@@ -133,6 +133,30 @@ export async function validateOpenAIKey(apiKey) {
133
133
  return { valid: false, error: "Unknown error" };
134
134
  }
135
135
  }
136
+ /**
137
+ * Validate a Google AI API key by making a test API call.
138
+ */
139
+ export async function validateGoogleKey(apiKey) {
140
+ try {
141
+ const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`, { method: "GET" });
142
+ if (response.status === 400 || response.status === 401 || response.status === 403) {
143
+ return { valid: false, error: "Invalid API key" };
144
+ }
145
+ if (!response.ok) {
146
+ return { valid: false, error: `API error: ${response.status}` };
147
+ }
148
+ return {
149
+ valid: true,
150
+ summary: "API key validated",
151
+ };
152
+ }
153
+ catch (err) {
154
+ if (err instanceof Error) {
155
+ return { valid: false, error: `Connection error: ${err.message}` };
156
+ }
157
+ return { valid: false, error: "Unknown error" };
158
+ }
159
+ }
136
160
  /**
137
161
  * Get list of supported providers.
138
162
  */
@@ -140,6 +164,7 @@ export function getSupportedProviders() {
140
164
  return [
141
165
  { id: "anthropic", name: "Anthropic" },
142
166
  { id: "openai", name: "OpenAI" },
167
+ { id: "google", name: "Google AI" },
143
168
  ];
144
169
  }
145
170
  /**
@@ -151,6 +176,8 @@ export async function validateProviderKey(provider, apiKey) {
151
176
  return validateAnthropicKey(apiKey);
152
177
  case "openai":
153
178
  return validateOpenAIKey(apiKey);
179
+ case "google":
180
+ return validateGoogleKey(apiKey);
154
181
  default:
155
182
  return { valid: false, error: `Unknown provider: ${provider}` };
156
183
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jobarbiter",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "CLI for JobArbiter — the first AI Proficiency Marketplace",
5
5
  "type": "module",
6
6
  "bin": {
@@ -529,9 +529,11 @@ async function runToolDetectionStep(
529
529
  console.log(` communication clarity, iteration patterns, tool fluency\n`);
530
530
  console.log(` This is what makes your profile ${c.bold("verified")} and ${c.bold("valuable")}.`);
531
531
  console.log(` Your observer regularly records and reports your proven AI proficiency.\n`);
532
- console.log(` ${c.bold("Privacy:")} ${c.highlight("No code, prompts, or content leave your machine.")}`);
533
- console.log(` Only derived proficiency signals (scores, patterns, dimensions)`);
534
- console.log(` are submitted never raw session data.\n`);
532
+ console.log(` ${c.bold("Privacy:")} Analysis runs ${c.highlight("locally by your own AI agent.")}`);
533
+ console.log(` Your agent reads your sessions to evaluate proficiency, but`);
534
+ console.log(` ${c.bold("only derived scores and signals are submitted to JobArbiter.")}`);
535
+ console.log(` Raw session data — prompts, responses, code — never leaves`);
536
+ console.log(` your machine and is never stored on our servers.\n`);
535
537
  console.log(c.dim(` Data stored locally: ~/.config/jobarbiter/observer/observations.json`));
536
538
  console.log(c.dim(` Review anytime: jobarbiter observe review\n`));
537
539
 
@@ -557,7 +559,13 @@ async function runToolDetectionStep(
557
559
 
558
560
  if (result.installed.length > 0) {
559
561
  console.log(`\n ${sym.check} ${c.success(`${result.installed.length} observer${result.installed.length > 1 ? "s" : ""} installed!`)}`);
560
- console.log(c.dim(` Your proficiency profile will start building automatically.\n`));
562
+ console.log(`\n ${c.bold("What happens now?")}`);
563
+ console.log(` Observers activate each time you use your AI tools.`);
564
+ console.log(` Just work normally — every session builds your profile.\n`);
565
+ console.log(` ${sym.arrow} ${c.highlight("Your next AI session will begin your proficiency analysis.")}`);
566
+ console.log(` Your own AI agent performs the analysis locally — evaluating`);
567
+ console.log(` how you work, not just how much. Only derived scores are`);
568
+ console.log(` submitted to JobArbiter. Raw session data never leaves your machine.\n`);
561
569
  }
562
570
  } else {
563
571
  console.log(c.dim("\n Skipped — you can install observers later with 'jobarbiter observe install'.\n"));
@@ -601,10 +609,11 @@ async function runConnectAIAccountsStep(prompt: Prompt): Promise<void> {
601
609
  console.log(` ${sym.bullet} Session frequency and consistency over time`);
602
610
  console.log(` ${sym.bullet} API spend patterns ${c.dim("(demonstrates serious usage)")}\n`);
603
611
 
604
- console.log(` ${c.bold("What we NEVER access:")}`);
605
- console.log(` ${sym.bullet} Your conversation content`);
606
- console.log(` ${sym.bullet} Prompts or responses`);
607
- console.log(` ${sym.bullet} Any proprietary or sensitive data\n`);
612
+ console.log(` ${c.bold("How your data stays safe:")}`);
613
+ console.log(` ${sym.bullet} Analysis runs ${c.bold("locally on your machine")} by your own AI agent`);
614
+ console.log(` ${sym.bullet} Only derived proficiency scores leave your machine — never raw`);
615
+ console.log(` session data, prompts, responses, or conversation content`);
616
+ console.log(` ${sym.bullet} ${c.bold("Nothing is stored on JobArbiter's servers")} except your scores\n`);
608
617
 
609
618
  // Check for already connected providers
610
619
  const existingProviders = loadProviderKeys();
@@ -623,26 +632,29 @@ async function runConnectAIAccountsStep(prompt: Prompt): Promise<void> {
623
632
  console.log(` ${c.bold("Available connections:")}\n`);
624
633
  console.log(` ${c.highlight("1.")} Anthropic API key — Pull Claude usage stats`);
625
634
  console.log(` ${c.highlight("2.")} OpenAI API key — Pull GPT/ChatGPT usage stats`);
626
- console.log(` ${c.highlight("3.")} Skip for now\n`);
635
+ console.log(` ${c.highlight("3.")} Google AI API key — Pull Gemini usage stats`);
636
+ console.log(` ${c.highlight("4.")} Skip for now\n`);
627
637
  console.log(c.dim(` You can connect accounts later with 'jobarbiter tokens connect'\n`));
628
638
 
629
- const choice = await prompt.question(` Your choice ${c.dim("[1/2/3]")}: `);
639
+ const choice = await prompt.question(` Your choice ${c.dim("[1/2/3/4]")}: `);
630
640
 
631
- if (choice === "3" || choice.toLowerCase() === "skip" || choice === "") {
641
+ if (choice === "4" || choice.toLowerCase() === "skip" || choice === "") {
632
642
  console.log(`\n${c.dim(" Skipped — you can connect providers later with 'jobarbiter tokens connect'")}\n`);
633
643
  continueConnecting = false;
634
644
  } else if (choice === "1") {
635
645
  await connectProvider(prompt, "anthropic", "Anthropic");
636
- // Ask if they want to connect another
637
646
  continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
638
647
  console.log();
639
648
  } else if (choice === "2") {
640
649
  await connectProvider(prompt, "openai", "OpenAI");
641
- // Ask if they want to connect another
650
+ continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
651
+ console.log();
652
+ } else if (choice === "3") {
653
+ await connectProvider(prompt, "google", "Google AI");
642
654
  continueConnecting = await prompt.confirm(`\n Connect another provider?`, false);
643
655
  console.log();
644
656
  } else {
645
- console.log(c.error(" Please enter 1, 2, or 3"));
657
+ console.log(c.error(" Please enter 1, 2, 3, or 4"));
646
658
  }
647
659
  }
648
660
  }
@@ -679,7 +691,11 @@ async function connectProvider(prompt: Prompt, providerId: string, providerName:
679
691
 
680
692
  function showWorkerCompletion(state: OnboardState): void {
681
693
  console.log(`${sym.done} ${c.bold("Step 7/7 — You're In!")}\n`);
682
- console.log(`Your profile is live. Here's what happens next:\n`);
694
+ console.log(`Your profile is live. Here's how it builds:\n`);
695
+ console.log(` 💡 ${c.bold("Your next AI session will begin your proficiency analysis.")}`);
696
+ console.log(` Just use your tools normally. Your own AI agent analyzes each`);
697
+ console.log(` session locally — evaluating how you work with AI, not just`);
698
+ console.log(` how much. Only proficiency scores are sent to JobArbiter.\n`);
683
699
 
684
700
  console.log(` 📊 Your proficiency profile builds automatically from:`);
685
701
  console.log(` ${c.bold("How you use AI (qualitative):")}`);
@@ -180,6 +180,36 @@ export async function validateOpenAIKey(apiKey: string): Promise<ValidationResul
180
180
  }
181
181
  }
182
182
 
183
+ /**
184
+ * Validate a Google AI API key by making a test API call.
185
+ */
186
+ export async function validateGoogleKey(apiKey: string): Promise<ValidationResult> {
187
+ try {
188
+ const response = await fetch(
189
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,
190
+ { method: "GET" },
191
+ );
192
+
193
+ if (response.status === 400 || response.status === 401 || response.status === 403) {
194
+ return { valid: false, error: "Invalid API key" };
195
+ }
196
+
197
+ if (!response.ok) {
198
+ return { valid: false, error: `API error: ${response.status}` };
199
+ }
200
+
201
+ return {
202
+ valid: true,
203
+ summary: "API key validated",
204
+ };
205
+ } catch (err) {
206
+ if (err instanceof Error) {
207
+ return { valid: false, error: `Connection error: ${err.message}` };
208
+ }
209
+ return { valid: false, error: "Unknown error" };
210
+ }
211
+ }
212
+
183
213
  /**
184
214
  * Get list of supported providers.
185
215
  */
@@ -187,6 +217,7 @@ export function getSupportedProviders(): Array<{ id: string; name: string }> {
187
217
  return [
188
218
  { id: "anthropic", name: "Anthropic" },
189
219
  { id: "openai", name: "OpenAI" },
220
+ { id: "google", name: "Google AI" },
190
221
  ];
191
222
  }
192
223
 
@@ -199,6 +230,8 @@ export async function validateProviderKey(provider: string, apiKey: string): Pro
199
230
  return validateAnthropicKey(apiKey);
200
231
  case "openai":
201
232
  return validateOpenAIKey(apiKey);
233
+ case "google":
234
+ return validateGoogleKey(apiKey);
202
235
  default:
203
236
  return { valid: false, error: `Unknown provider: ${provider}` };
204
237
  }