breakroom 2.1.5 → 2.1.6
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.
- package/bin/setup.js +108 -29
- package/package.json +1 -1
package/bin/setup.js
CHANGED
|
@@ -47,7 +47,7 @@ const banner = () => {
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
const CANDIDATE_FILES = [
|
|
50
|
-
// Project-level agent/IDE configs
|
|
50
|
+
// Project-level agent/IDE configs (cwd)
|
|
51
51
|
['.env'],
|
|
52
52
|
['.env.local'],
|
|
53
53
|
['.cursor', 'mcp.json'],
|
|
@@ -81,24 +81,49 @@ const CANDIDATE_FILES = [
|
|
|
81
81
|
['CLAUDE.md'],
|
|
82
82
|
['.continuerc.json'],
|
|
83
83
|
['.aider.conf.yml'],
|
|
84
|
-
|
|
85
|
-
['
|
|
86
|
-
|
|
87
|
-
[
|
|
88
|
-
[
|
|
89
|
-
[
|
|
90
|
-
[
|
|
91
|
-
[
|
|
92
|
-
[
|
|
93
|
-
[
|
|
94
|
-
[
|
|
95
|
-
[
|
|
96
|
-
[
|
|
97
|
-
[
|
|
98
|
-
[
|
|
99
|
-
[
|
|
100
|
-
[
|
|
101
|
-
[
|
|
84
|
+
// User-level agent/IDE configs (~/ = home dir)
|
|
85
|
+
['~', '.env'],
|
|
86
|
+
['~', '.env.local'],
|
|
87
|
+
['~', '.cursor', 'mcp.json'],
|
|
88
|
+
['~', '.cursor', 'settings.json'],
|
|
89
|
+
['~', '.vscode', 'settings.json'],
|
|
90
|
+
['~', '.vscode', 'mcp.json'],
|
|
91
|
+
['~', '.windsurf', 'settings.json'],
|
|
92
|
+
['~', '.trae', 'settings.json'],
|
|
93
|
+
['~', '.trae', 'mcp.json'],
|
|
94
|
+
['~', '.codex', 'config.json'],
|
|
95
|
+
['~', '.codex', 'setup.json'],
|
|
96
|
+
['~', '.opencode.json'],
|
|
97
|
+
['~', '.opencode.jsonc'],
|
|
98
|
+
['~', '.openclaw', 'config.yaml'],
|
|
99
|
+
['~', '.openclaw', 'config.yml'],
|
|
100
|
+
['~', '.cline', 'cline.json'],
|
|
101
|
+
['~', '.cline', 'settings.json'],
|
|
102
|
+
['~', '.clinerules'],
|
|
103
|
+
['~', '.cody.json'],
|
|
104
|
+
['~', '.tabby', 'config.json'],
|
|
105
|
+
['~', '.amazonq', 'config.json'],
|
|
106
|
+
['~', '.supermaven', 'config.json'],
|
|
107
|
+
['~', '.augment', 'config.json'],
|
|
108
|
+
['~', '.hermes', 'config.yaml'],
|
|
109
|
+
['~', 'litellm.yaml'],
|
|
110
|
+
['~', 'litellm.yml'],
|
|
111
|
+
['~', 'CLAUDE.md'],
|
|
112
|
+
['~', '.continuerc.json'],
|
|
113
|
+
['~', '.aider.conf.yml'],
|
|
114
|
+
['~', '.cursorrules'],
|
|
115
|
+
['~', '.windsurfrules'],
|
|
116
|
+
['~', '.github', 'copilot-instructions.md'],
|
|
117
|
+
['~', '.claude', 'settings.json'],
|
|
118
|
+
['~', '.continue', 'config.json'],
|
|
119
|
+
['~', '.goose', 'config.yaml'],
|
|
120
|
+
['~', '.codex', 'config.json'],
|
|
121
|
+
['~', '.config', 'opencode.json'],
|
|
122
|
+
['~', '.config', 'opencode.jsonc'],
|
|
123
|
+
['~', '.config', 'breakroom', 'config.yaml'],
|
|
124
|
+
['~', '.config', 'openclaw', 'config.yaml'],
|
|
125
|
+
['~', '.config', 'trae', 'config.json'],
|
|
126
|
+
['~', '.config', 'codex', 'config.json'],
|
|
102
127
|
];
|
|
103
128
|
|
|
104
129
|
function candidateFiles() {
|
|
@@ -690,6 +715,16 @@ async function actionRotate() {
|
|
|
690
715
|
console.log();
|
|
691
716
|
}
|
|
692
717
|
|
|
718
|
+
function extractLicenseKey(configured) {
|
|
719
|
+
for (const c of configured) {
|
|
720
|
+
for (const l of c.proxyLines) {
|
|
721
|
+
const m = l.match(/\/breakroom\/([^\/]+)\/v1/);
|
|
722
|
+
if (m) return decodeURIComponent(m[1]);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return '';
|
|
726
|
+
}
|
|
727
|
+
|
|
693
728
|
async function actionTestIntervention() {
|
|
694
729
|
console.log();
|
|
695
730
|
|
|
@@ -699,15 +734,7 @@ async function actionTestIntervention() {
|
|
|
699
734
|
return;
|
|
700
735
|
}
|
|
701
736
|
|
|
702
|
-
|
|
703
|
-
let licenseKey = '';
|
|
704
|
-
for (const c of configured) {
|
|
705
|
-
for (const l of c.proxyLines) {
|
|
706
|
-
const m = l.match(/\/breakroom\/([^\/]+)\/v1/);
|
|
707
|
-
if (m) { licenseKey = decodeURIComponent(m[1]); break; }
|
|
708
|
-
}
|
|
709
|
-
if (licenseKey) break;
|
|
710
|
-
}
|
|
737
|
+
const licenseKey = extractLicenseKey(configured);
|
|
711
738
|
if (!licenseKey) {
|
|
712
739
|
console.log('Could not extract license key from config.\n');
|
|
713
740
|
return;
|
|
@@ -751,6 +778,54 @@ async function actionTestIntervention() {
|
|
|
751
778
|
}
|
|
752
779
|
}
|
|
753
780
|
|
|
781
|
+
async function actionAnalytics() {
|
|
782
|
+
console.log();
|
|
783
|
+
|
|
784
|
+
const configured = scanExistingConfig();
|
|
785
|
+
if (!configured.length) {
|
|
786
|
+
console.log('No Break Room proxy configured. Use option 1 first.\n');
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const licenseKey = extractLicenseKey(configured);
|
|
791
|
+
if (!licenseKey) {
|
|
792
|
+
console.log('Could not extract license key from config.\n');
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
console.log('Fetching intervention analytics...\n');
|
|
797
|
+
|
|
798
|
+
try {
|
|
799
|
+
const resp = await requestJson(`${API_ORIGIN}/breakroom/${encodeURIComponent(licenseKey)}/v1/analytics`);
|
|
800
|
+
if (resp.status !== 200 || !resp.json.ok) {
|
|
801
|
+
console.log(`\x1b[31mFailed: ${resp.json?.error || 'Unknown'}\x1b[0m\n`);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const a = resp.json.analytics;
|
|
806
|
+
console.log(` Total calls analyzed: ${a.total_calls}`);
|
|
807
|
+
console.log(` Interventions fired: \x1b[33m${a.total_interventions}\x1b[0m`);
|
|
808
|
+
console.log(` Total tokens saved: ${a.tokens_saved.toLocaleString()}`);
|
|
809
|
+
console.log(` Total cost saved: \x1b[32m$${a.cost_saved.toFixed(2)}\x1b[0m`);
|
|
810
|
+
|
|
811
|
+
const providers = Object.keys(a.by_provider);
|
|
812
|
+
if (providers.length) {
|
|
813
|
+
console.log(`\n By provider:\n`);
|
|
814
|
+
for (const p of providers) {
|
|
815
|
+
const d = a.by_provider[p];
|
|
816
|
+
console.log(` ${p}:`);
|
|
817
|
+
console.log(` Calls: ${d.calls}`);
|
|
818
|
+
console.log(` Interventions: ${d.interventions}`);
|
|
819
|
+
console.log(` Tokens saved: ${d.tokens_saved.toLocaleString()}`);
|
|
820
|
+
console.log(` Cost saved: \x1b[32m$${d.cost_saved.toFixed(2)}\x1b[0m`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
console.log();
|
|
824
|
+
} catch (err) {
|
|
825
|
+
console.log(`\x1b[31mError: ${err.message}\x1b[0m\n`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
754
829
|
// --- Menu ---
|
|
755
830
|
|
|
756
831
|
function showMenu() {
|
|
@@ -765,6 +840,7 @@ function showMenu() {
|
|
|
765
840
|
console.log(' 7) Recover lost license');
|
|
766
841
|
console.log(' 8) Scan for IDE/config/Docker files');
|
|
767
842
|
console.log(' 9) Rotate license key (2FA)');
|
|
843
|
+
console.log(' b) View analytics');
|
|
768
844
|
console.log(' 0) Exit\n');
|
|
769
845
|
}
|
|
770
846
|
|
|
@@ -808,6 +884,9 @@ async function main() {
|
|
|
808
884
|
case '9':
|
|
809
885
|
await actionRotate();
|
|
810
886
|
break;
|
|
887
|
+
case 'b':
|
|
888
|
+
await actionAnalytics();
|
|
889
|
+
break;
|
|
811
890
|
case '0':
|
|
812
891
|
console.log('\nGoodbye.\n');
|
|
813
892
|
return;
|
|
@@ -818,7 +897,7 @@ async function main() {
|
|
|
818
897
|
console.error(`\n\x1b[31mError:\x1b[0m ${err.message}\n`);
|
|
819
898
|
}
|
|
820
899
|
|
|
821
|
-
if (
|
|
900
|
+
if (!['0', 'a', 'b'].includes(choice) && choice !== '__EOF__') {
|
|
822
901
|
if (await ask('Press Enter to return to the menu...') === '__EOF__') break;
|
|
823
902
|
}
|
|
824
903
|
}
|