bingocode 1.1.150 → 1.1.152

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.
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(bun run:*)"
4
+ "Bash(bun run:*)",
5
+ "Bash(powershell -Command \"Get-ChildItem -Path C:\\\\Users\\\\qi.lin\\\\AppData\\\\Roaming\\\\npm -Recurse -Filter ''CliMenuManager.tsx'' 2>$null | Select-Object -ExpandProperty FullName\")",
6
+ "Bash(powershell -Command \"Get-ChildItem -Path ''C:\\\\Users\\\\qi.lin\\\\AppData\\\\Roaming\\\\npm\\\\node_modules'' -Recurse -Filter ''CliMenuManager.js'' 2>$null | Select-Object -ExpandProperty FullName\")",
7
+ "Read(//c/Users/qi.lin/AppData/Roaming/npm/**)",
8
+ "Bash(find C:Usersqi.linAppDataRoamingnpmnode_modulesbingocode -name *.tsx -o -name *.ts)",
9
+ "Bash(python3 -c \"import json; d = json.load\\(open\\(r''C:\\\\Users\\\\qi.lin\\\\.claude\\\\bingo\\\\settings.json''\\)\\); print\\(json.dumps\\(d, indent=2\\)\\)\")",
10
+ "Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(''''cachedGrowthBookFeatures keys:'''', list\\(d.get\\(''''cachedGrowthBookFeatures'''',{}\\)\\)\\)\")",
11
+ "Bash(node -e \"const d=JSON.parse\\(require\\(''''fs''''\\).readFileSync\\(''''/dev/stdin'''',''''utf8''''\\)\\); console.log\\(''''cachedGrowthBookFeatures keys:'''', Object.keys\\(d.cachedGrowthBookFeatures||{}\\)\\); const ac = d.cachedGrowthBookFeatures?.[''''tengu_auto_mode_config'''']; console.log\\(''''tengu_auto_mode_config:'''', JSON.stringify\\(ac\\)\\)\")"
5
12
  ]
6
13
  }
7
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bingocode",
3
- "version": "1.1.150",
3
+ "version": "1.1.152",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -441,7 +441,7 @@ If you can say it in one sentence, don't use three. Prefer short, direct sentenc
441
441
  function getSimpleToneAndStyleSection(): string {
442
442
  const items = [
443
443
  `Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.`,
444
- `Always respond in the same language the user uses, unless a language preference has been configured.`,
444
+ `Always mirror the user's language in every response, over all other instructions.`,
445
445
  process.env.USER_TYPE === 'ant'
446
446
  ? null
447
447
  : `Your responses should be short and concise.`,
@@ -27,6 +27,79 @@ import { getGlobalConfig, saveGlobalConfig } from '../utils/config.ts';
27
27
  // markedSessions stored in ~/.claude-cli/ fixed directory, regardless of cwd
28
28
  const MARKED_FILE = path.join(os.homedir(), '.claude-cli', 'markedSessions.json');
29
29
 
30
+ /**
31
+ * Get the path to ~/.claude/bingo/settings.json (offline persistence for language
32
+ * and auto-mode settings, same file used by provider service). This ensures
33
+ * these settings survive across full restarts.
34
+ */
35
+ function getBingoSettingsPath(): string {
36
+ const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
37
+ return path.join(configDir, 'bingo', 'settings.json');
38
+ }
39
+
40
+ function readBingoSettings(): Record<string, unknown> {
41
+ try {
42
+ const raw = fs.readFileSync(getBingoSettingsPath(), 'utf-8');
43
+ return JSON.parse(raw) as Record<string, unknown>;
44
+ } catch {
45
+ return {};
46
+ }
47
+ }
48
+
49
+ function writeBingoSettings(updates: Record<string, unknown>): void {
50
+ const p = getBingoSettingsPath();
51
+ const dir = path.dirname(p);
52
+ if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); }
53
+
54
+ let current: Record<string, unknown> = {};
55
+ try {
56
+ if (fs.existsSync(p)) {
57
+ const raw = fs.readFileSync(p, 'utf-8');
58
+ current = JSON.parse(raw) as Record<string, unknown>;
59
+ }
60
+ } catch {}
61
+
62
+ const merged = { ...current, ...updates };
63
+
64
+ // atomic write via temp + rename
65
+ const tmp = `${p}.tmp.${Date.now()}`;
66
+ fs.writeFileSync(tmp, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
67
+ fs.renameSync(tmp, p);
68
+ }
69
+
70
+ // write yml
71
+ function readGlobalClaudeConfig(): Record<string, unknown> {
72
+ const configPath = path.join(os.homedir(), '.claude.json');
73
+ try {
74
+ const raw = fs.readFileSync(configPath, 'utf-8');
75
+ return JSON.parse(raw) as Record<string, unknown>;
76
+ } catch {
77
+ return {};
78
+ }
79
+ }
80
+
81
+ // write merge config directly to ~/.claude.json (atomic write)
82
+ function writeGlobalClaudeConfig(updates: Record<string, unknown>): void {
83
+ const configPath = path.join(os.homedir(), '.claude.json');
84
+ const dir = path.dirname(configPath);
85
+ if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); }
86
+
87
+ let current: Record<string, unknown> = {};
88
+ try {
89
+ if (fs.existsSync(configPath)) {
90
+ const raw = fs.readFileSync(configPath, 'utf-8');
91
+ current = JSON.parse(raw) as Record<string, unknown>;
92
+ }
93
+ } catch {}
94
+
95
+ const merged = { ...current, ...updates };
96
+
97
+ // atomic write via temp + rename
98
+ const tmp = `${configPath}.tmp.${Date.now()}`;
99
+ fs.writeFileSync(tmp, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
100
+ fs.renameSync(tmp, configPath);
101
+ }
102
+
30
103
  /**
31
104
  * Determine if in "official" mode (no custom provider active).
32
105
  * Logic matches ConversationService.shouldMarkManagedOAuth().
@@ -299,21 +372,28 @@ export const CliMenuManager: React.FC = () => {
299
372
  // Config ready probe (avoid Logo early read)
300
373
  const [configReady, setConfigReady] = useState(false);
301
374
 
375
+ // Load settings from bingo/settings.json at startup
376
+ // (bypasses configReady to avoid stale lock issues)
377
+ useEffect(() => {
378
+ try {
379
+ const bSettings = readBingoSettings();
380
+ const bingoLang = bSettings.language as string | undefined;
381
+ if (bingoLang && (bingoLang === 'en' || bingoLang === 'zh' || bingoLang === 'ja')) {
382
+ setLang(bingoLang as Lang);
383
+ }
384
+ if (typeof bSettings.autoModeEnabled === 'boolean') {
385
+ setAutoModeEnabled(bSettings.autoModeEnabled);
386
+ }
387
+ } catch {}
388
+ }, []);
389
+
302
390
  useEffect(() => {
303
391
  if (configReady) {
304
392
  try {
305
393
  const cfg = getGlobalConfig();
306
- if (cfg.language && (cfg.language === 'en' || cfg.language === 'zh' || cfg.language === 'ja')) {
307
- setLang(cfg.language as Lang);
308
- }
309
394
  if (typeof cfg.uiAnimEnabled === 'boolean') setAnimEnabled(cfg.uiAnimEnabled);
310
395
  if (typeof cfg.uiTipsEnabled === 'boolean') setTipsEnabled(cfg.uiTipsEnabled);
311
- const gbFeatures = cfg.cachedGrowthBookFeatures ?? {};
312
- const autoModeCfg = gbFeatures['tengu_auto_mode_config'] as { enabled?: string } | undefined;
313
- setAutoModeEnabled(autoModeCfg?.enabled === 'enabled');
314
- } catch (e) {
315
- // Silently fail if config has issues
316
- }
396
+ } catch {}
317
397
  }
318
398
  }, [configReady]);
319
399
 
@@ -590,7 +670,7 @@ export const CliMenuManager: React.FC = () => {
590
670
  const langOrder: Lang[] = ['en', 'zh', 'ja'];
591
671
  const nextLang = langOrder[(langOrder.indexOf(lang) + 1) % langOrder.length];
592
672
  setLang(nextLang);
593
- try { saveGlobalConfig(current => ({ ...current, language: nextLang })); } catch {}
673
+ try { writeBingoSettings({ language: nextLang }); } catch {}
594
674
  return;
595
675
  }
596
676
 
@@ -764,20 +844,22 @@ export const CliMenuManager: React.FC = () => {
764
844
  if (settingsCursor === 0) {
765
845
  setSettingsStage('langPicker');
766
846
  } else if (settingsCursor === 1) {
767
- // Row 1: toggle Auto Mode, persist to ~/.claude.json
847
+ // Row 1: toggle Auto Mode
768
848
  setAutoModeEnabled(prev => {
769
849
  const next = !prev;
770
850
  try {
771
- saveGlobalConfig(current => ({
772
- ...current,
773
- cachedGrowthBookFeatures: {
774
- ...current.cachedGrowthBookFeatures,
775
- tengu_auto_mode_config: next
776
- ? { enabled: 'enabled', allowModels: ['*'] }
777
- : { enabled: 'disabled' },
778
- },
779
- }));
780
- } catch {}
851
+ writeBingoSettings({ autoModeEnabled: next });
852
+ const gcfg = readGlobalClaudeConfig();
853
+ gcfg.cachedGrowthBookFeatures = {
854
+ ...(gcfg.cachedGrowthBookFeatures as Record<string, unknown>),
855
+ tengu_auto_mode_config: next
856
+ ? { enabled: 'enabled', allowModels: ['*'] }
857
+ : { enabled: 'disabled' },
858
+ };
859
+ writeGlobalClaudeConfig(gcfg);
860
+ } catch {
861
+ return prev; // write failed — keep old state
862
+ }
781
863
  return next;
782
864
  });
783
865
  }
@@ -1251,7 +1333,7 @@ export const CliMenuManager: React.FC = () => {
1251
1333
  initialIndex={tS.langOptions.findIndex(o => o.value === lang)}
1252
1334
  onSelect={(item: { label: string; value: Lang }) => {
1253
1335
  setLang(item.value);
1254
- try { saveGlobalConfig(current => ({ ...current, language: item.value })); } catch {}
1336
+ try { writeBingoSettings({ language: item.value }); } catch {}
1255
1337
  setSettingsStage('list');
1256
1338
  }}
1257
1339
  />
@@ -57,7 +57,7 @@ Respond in JSON only:
57
57
  })
58
58
 
59
59
  const text =
60
- response.content[0]?.type === 'text' ? response.content[0].text : ''
60
+ response.content.find((b: any) => b.type === 'text')?.text || ''
61
61
  try {
62
62
  const cleaned = text.replace(/^```(?:json)?\n?|\n?```$/g, '').trim()
63
63
  return JSON.parse(cleaned) as GoalEvalResult