@bike4mind/cli 0.9.3 → 0.10.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.
- package/README.md +13 -3
- package/bin/bike4mind-cli.mjs +44 -1
- package/dist/{BubblewrapRuntime-CUD3bsgG.mjs → BubblewrapRuntime-CkL9-gnG.mjs} +1 -1
- package/dist/{ConfigStore-BauEpjvT.mjs → ConfigStore-aeJGqjKm.mjs} +116 -15
- package/dist/ProxyManager-ByuAHFMq.mjs +3 -0
- package/dist/{SandboxOrchestrator-C4oDqltp.mjs → SandboxOrchestrator-BS6gALNq.mjs} +1 -1
- package/dist/{SandboxOrchestrator-B4GcZdBc.mjs → SandboxOrchestrator-BoINxbX4.mjs} +1 -1
- package/dist/{SandboxRuntimeAdapter-DXa3nFOw.mjs → SandboxRuntimeAdapter-CKelGICD.mjs} +1 -1
- package/dist/{SandboxRuntimeAdapter-D1RUReNL.mjs → SandboxRuntimeAdapter-ChGlxSGQ.mjs} +2 -2
- package/dist/{SeatbeltRuntime-CTElMR9Q.mjs → SeatbeltRuntime-Qqt19cAN.mjs} +1 -1
- package/dist/{bashExecute-pYljpfPn-BZXHMQEl.mjs → bashExecute-B1N1lMOS-TZVDbcQ4.mjs} +1 -1
- package/dist/commands/apiCommand.mjs +45 -0
- package/dist/commands/doctorCommand.mjs +2 -2
- package/dist/commands/headlessCommand.mjs +6 -6
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +2 -2
- package/dist/{createFile-C1JoeuYh-metInFKd.mjs → createFile-DPv180yF-BnWFIxey.mjs} +2 -2
- package/dist/{deleteFile-BTberNGj-CW922hRM.mjs → deleteFile-BdjUwUQF-B3XOJmg3.mjs} +2 -2
- package/dist/{globFiles-Bez8QCbS-DZb6McbJ.mjs → globFiles-DjfDGaUK-CNR8pMRC.mjs} +2 -2
- package/dist/{grepSearch-BxucZWO8-lPRv6R6F.mjs → grepSearch-DJs-cubo-Bm0Y8oS3.mjs} +2 -2
- package/dist/index.mjs +258 -39
- package/dist/{pathValidation-CIytuhr3-Dt5dntLx.mjs → pathValidation-D8tjkQXE-1HwvsuYT.mjs} +1 -1
- package/dist/store-DgzCTRkN.mjs +3 -0
- package/dist/{tools-CpWE3Qif.mjs → tools-RdGu37Lw.mjs} +11217 -10240
- package/dist/types-CqscS34o.mjs +3 -0
- package/dist/{updateChecker-DhWcEKAu.mjs → updateChecker-CP_jeER9.mjs} +1 -1
- package/dist/utils-BGtSXfce.mjs +3 -0
- package/dist/utils-PpNti-tY.mjs +146 -0
- package/package.json +31 -31
- package/dist/ProxyManager-DIAAw902.mjs +0 -3
- package/dist/store-5PXzE9DM.mjs +0 -3
- package/dist/types-DK3P88Px.mjs +0 -3
- /package/dist/{ImageStore-BFp_d12J.mjs → ImageStore-BVmEG1xc.mjs} +0 -0
- /package/dist/{ProxyManager-BsCoxpns.mjs → ProxyManager-CV94yZUW.mjs} +0 -0
- /package/dist/{StderrViolationParser-BFP4bo7I.mjs → StderrViolationParser-CS43a-TP.mjs} +0 -0
- /package/dist/{ViolationLogStore-Dp6HF0nz.mjs → ViolationLogStore-B-plqJfn.mjs} +0 -0
- /package/dist/{ripgrepCheck-DIu4apVE.mjs → ripgrepCheck-BmkyTK2i.mjs} +0 -0
- /package/dist/{store-BonrwrMi.mjs → store-DV5s-qni.mjs} +0 -0
- /package/dist/{terminalSetup-DxloCowq.mjs → terminalSetup-BbJt04ZG.mjs} +0 -0
- /package/dist/{treeSitterEngine-Cw2LbVZT.mjs → treeSitterEngine-BRbQ9b7I.mjs} +0 -0
- /package/dist/{types-DBEjF9YS.mjs → types-LyRNHOiS.mjs} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { timingSafeEqual } from "crypto";
|
|
3
|
+
import speakeasy from "speakeasy";
|
|
4
|
+
import QRCode from "qrcode";
|
|
5
|
+
//#region ../../b4m-core/auth/dist/mfaService/utils.mjs
|
|
6
|
+
const originalEmitWarning = process.emitWarning;
|
|
7
|
+
process.emitWarning = (warning, name) => {
|
|
8
|
+
if (name === "DeprecationWarning" && warning?.toString().includes("Buffer")) return;
|
|
9
|
+
return originalEmitWarning.call(process, warning, name);
|
|
10
|
+
};
|
|
11
|
+
process.emitWarning = originalEmitWarning;
|
|
12
|
+
/**
|
|
13
|
+
* Generate TOTP setup data including secret and QR code
|
|
14
|
+
* Using the same implementation as polaris
|
|
15
|
+
*/
|
|
16
|
+
async function generateTOTPSetup(userEmail, appName = "Bike4Mind") {
|
|
17
|
+
const secret = speakeasy.generateSecret({ name: `${appName} (${userEmail})` });
|
|
18
|
+
const qrCodeUrl = await QRCode.toDataURL(secret.otpauth_url);
|
|
19
|
+
return {
|
|
20
|
+
secret: secret.base32,
|
|
21
|
+
qrCodeUrl,
|
|
22
|
+
manualEntryKey: secret.base32
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Verify a TOTP token against a secret
|
|
27
|
+
* Using industry-standard window to handle minor clock drift
|
|
28
|
+
*/
|
|
29
|
+
function verifyTOTPToken(secret, token, window = 1) {
|
|
30
|
+
return speakeasy.totp.verify({
|
|
31
|
+
secret,
|
|
32
|
+
encoding: "base32",
|
|
33
|
+
token,
|
|
34
|
+
window
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate cryptographically secure backup codes for MFA
|
|
39
|
+
* Using speakeasy's secure random generation to be consistent with TOTP secrets
|
|
40
|
+
*/
|
|
41
|
+
function generateBackupCodes(count = 10) {
|
|
42
|
+
return Array.from({ length: count }, () => {
|
|
43
|
+
return speakeasy.generateSecret({ length: 20 }).base32.substring(0, 10).toUpperCase();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Verify a backup code against the user's backup codes
|
|
48
|
+
*/
|
|
49
|
+
function verifyBackupCode(userBackupCodes, providedCode) {
|
|
50
|
+
if (!userBackupCodes || !providedCode) return { isValid: false };
|
|
51
|
+
const cleanProvidedCode = providedCode.trim().toUpperCase();
|
|
52
|
+
const providedBuf = Buffer.from(cleanProvidedCode, "utf8");
|
|
53
|
+
let matchIdx = -1;
|
|
54
|
+
for (let i = 0; i < userBackupCodes.length; i++) {
|
|
55
|
+
const storedBuf = Buffer.from(userBackupCodes[i].trim().toUpperCase(), "utf8");
|
|
56
|
+
if (storedBuf.length === providedBuf.length && timingSafeEqual(storedBuf, providedBuf)) {
|
|
57
|
+
matchIdx = i;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (matchIdx !== -1) return {
|
|
62
|
+
isValid: true,
|
|
63
|
+
usedBackupCode: userBackupCodes[matchIdx]
|
|
64
|
+
};
|
|
65
|
+
return { isValid: false };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a user requires MFA based on enforcement settings
|
|
69
|
+
* In lumina5, when MFA is enforced, it applies to ALL users (unlike polaris)
|
|
70
|
+
*/
|
|
71
|
+
function userRequiresMFA(user, enforceMFASetting) {
|
|
72
|
+
return enforceMFASetting;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if a user has MFA configured
|
|
76
|
+
*/
|
|
77
|
+
function userHasMFAConfigured(user) {
|
|
78
|
+
return !!(user.mfa && user.mfa.totpEnabled && user.mfa.totpSecret);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Server-side attempt tracking to prevent bypass via refresh/cancel
|
|
82
|
+
* Constants for lockout policy
|
|
83
|
+
*/
|
|
84
|
+
const MAX_FAILED_ATTEMPTS = 3;
|
|
85
|
+
const LOCKOUT_DURATION_MS = 900 * 1e3;
|
|
86
|
+
const ATTEMPT_RESET_WINDOW_MS = 3600 * 1e3;
|
|
87
|
+
/**
|
|
88
|
+
* Check if user is currently locked out from MFA attempts
|
|
89
|
+
*/
|
|
90
|
+
function isUserLockedOut(user) {
|
|
91
|
+
if (!user.mfa?.lockedUntil) return false;
|
|
92
|
+
return /* @__PURE__ */ new Date() < new Date(user.mfa.lockedUntil);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get remaining lockout time in minutes
|
|
96
|
+
*/
|
|
97
|
+
function getLockoutTimeRemaining(user) {
|
|
98
|
+
if (!user.mfa?.lockedUntil) return 0;
|
|
99
|
+
const remaining = new Date(user.mfa.lockedUntil).getTime() - Date.now();
|
|
100
|
+
return Math.max(0, Math.ceil(remaining / (60 * 1e3)));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reset failed attempts if enough time has passed since last failure
|
|
104
|
+
*/
|
|
105
|
+
function shouldResetFailedAttempts(user) {
|
|
106
|
+
if (!user.mfa?.lastFailedAttempt) return false;
|
|
107
|
+
return Date.now() - new Date(user.mfa.lastFailedAttempt).getTime() > ATTEMPT_RESET_WINDOW_MS;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Record a failed MFA attempt and return updated MFA object
|
|
111
|
+
*/
|
|
112
|
+
function recordFailedAttempt(user) {
|
|
113
|
+
const newAttempts = (shouldResetFailedAttempts(user) ? 0 : user.mfa?.failedAttempts || 0) + 1;
|
|
114
|
+
const now = /* @__PURE__ */ new Date();
|
|
115
|
+
const updatedMFA = { ...user.mfa };
|
|
116
|
+
updatedMFA.failedAttempts = newAttempts;
|
|
117
|
+
updatedMFA.lastFailedAttempt = now;
|
|
118
|
+
if (newAttempts >= MAX_FAILED_ATTEMPTS) updatedMFA.lockedUntil = new Date(Date.now() + LOCKOUT_DURATION_MS);
|
|
119
|
+
return updatedMFA;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear failed attempts on successful verification
|
|
123
|
+
*/
|
|
124
|
+
function clearFailedAttempts(user) {
|
|
125
|
+
if (!user.mfa) return null;
|
|
126
|
+
const updatedMFA = { ...user.mfa };
|
|
127
|
+
updatedMFA.failedAttempts = 0;
|
|
128
|
+
updatedMFA.lastFailedAttempt = void 0;
|
|
129
|
+
updatedMFA.lockedUntil = void 0;
|
|
130
|
+
return updatedMFA;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Check if a user is eligible to set up MFA
|
|
134
|
+
*/
|
|
135
|
+
function userEligibleForMFA(user) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if a user can disable MFA based on enforcement settings
|
|
140
|
+
* In lumina5, when MFA is enforced, NO user can disable it
|
|
141
|
+
*/
|
|
142
|
+
function userCanDisableMFA(user, enforceMFASetting) {
|
|
143
|
+
return !enforceMFASetting;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { isUserLockedOut as a, userCanDisableMFA as c, userRequiresMFA as d, verifyBackupCode as f, getLockoutTimeRemaining as i, userEligibleForMFA as l, generateBackupCodes as n, recordFailedAttempt as o, verifyTOTPToken as p, generateTOTPSetup as r, shouldResetFailedAttempts as s, clearFailedAttempts as t, userHasMFAConfigured as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -34,29 +34,29 @@
|
|
|
34
34
|
"node": ">=24.0.0"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@anthropic-ai/sdk": "^0.
|
|
38
|
-
"@aws-sdk/client-apigatewaymanagementapi": "^3.
|
|
39
|
-
"@aws-sdk/client-bedrock-runtime": "^3.
|
|
40
|
-
"@aws-sdk/client-cloudwatch": "^3.
|
|
41
|
-
"@aws-sdk/client-lambda": "^3.
|
|
42
|
-
"@aws-sdk/client-s3": "^3.
|
|
43
|
-
"@aws-sdk/client-sqs": "^3.
|
|
44
|
-
"@aws-sdk/client-transcribe": "^3.
|
|
45
|
-
"@aws-sdk/credential-provider-node": "^3.972.
|
|
46
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
37
|
+
"@anthropic-ai/sdk": "^0.97.1",
|
|
38
|
+
"@aws-sdk/client-apigatewaymanagementapi": "^3.1050.0",
|
|
39
|
+
"@aws-sdk/client-bedrock-runtime": "^3.1050.0",
|
|
40
|
+
"@aws-sdk/client-cloudwatch": "^3.1050.0",
|
|
41
|
+
"@aws-sdk/client-lambda": "^3.1050.0",
|
|
42
|
+
"@aws-sdk/client-s3": "^3.1050.0",
|
|
43
|
+
"@aws-sdk/client-sqs": "^3.1050.0",
|
|
44
|
+
"@aws-sdk/client-transcribe": "^3.1050.0",
|
|
45
|
+
"@aws-sdk/credential-provider-node": "^3.972.43",
|
|
46
|
+
"@aws-sdk/s3-request-presigner": "^3.1050.0",
|
|
47
47
|
"@casl/ability": "^6.8.1",
|
|
48
48
|
"@google/genai": "^1.46.0",
|
|
49
|
-
"@joplin/turndown-plugin-gfm": "^1.0.
|
|
49
|
+
"@joplin/turndown-plugin-gfm": "^1.0.67",
|
|
50
50
|
"@mendable/firecrawl-js": "^1.29.3",
|
|
51
|
-
"@modelcontextprotocol/sdk": "1.
|
|
51
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
52
52
|
"@octokit/rest": "^22.0.1",
|
|
53
53
|
"@opensearch-project/opensearch": "2.11.0",
|
|
54
|
-
"@smithy/node-http-handler": "^4.
|
|
54
|
+
"@smithy/node-http-handler": "^4.7.3",
|
|
55
55
|
"async-mutex": "^0.5.0",
|
|
56
56
|
"axios": "1.16.1",
|
|
57
57
|
"bcryptjs": "^3.0.2",
|
|
58
|
-
"better-sqlite3": "^12.
|
|
59
|
-
"cheerio": "1.
|
|
58
|
+
"better-sqlite3": "^12.10.0",
|
|
59
|
+
"cheerio": "1.2.0",
|
|
60
60
|
"chess.js": "^1.0.0-beta.8",
|
|
61
61
|
"cli-highlight": "^2.1.11",
|
|
62
62
|
"csv-parse": "^6.2.1",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"glob": "^13.0.6",
|
|
73
73
|
"gray-matter": "^4.0.3",
|
|
74
74
|
"ignore": "^7.0.5",
|
|
75
|
-
"ink": "^7.0.
|
|
75
|
+
"ink": "^7.0.3",
|
|
76
76
|
"ink-select-input": "^6.2.0",
|
|
77
77
|
"ink-spinner": "^5.0.0",
|
|
78
78
|
"ink-text-input": "^6.0.0",
|
|
@@ -85,11 +85,11 @@
|
|
|
85
85
|
"mongoose": "^8.8.3",
|
|
86
86
|
"ollama": "^0.6.3",
|
|
87
87
|
"open": "^11.0.0",
|
|
88
|
-
"openai": "^6.
|
|
88
|
+
"openai": "^6.38.0",
|
|
89
89
|
"p-limit": "^7.3.0",
|
|
90
90
|
"picomatch": "^4.0.3",
|
|
91
91
|
"qrcode": "^1.5.4",
|
|
92
|
-
"react": "^19.2.
|
|
92
|
+
"react": "^19.2.6",
|
|
93
93
|
"sharp": "^0.34.5",
|
|
94
94
|
"speakeasy": "^2.0.0",
|
|
95
95
|
"tiktoken": "^1.0.22",
|
|
@@ -100,11 +100,11 @@
|
|
|
100
100
|
"uuid": "^13.0.0",
|
|
101
101
|
"voyageai": "^0.0.4",
|
|
102
102
|
"web-tree-sitter": "0.25.10",
|
|
103
|
-
"ws": "^8.20.
|
|
103
|
+
"ws": "^8.20.1",
|
|
104
104
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
105
105
|
"yargs": "^18.0.0",
|
|
106
106
|
"yauzl": "^3.3.0",
|
|
107
|
-
"zod": "^4.3
|
|
107
|
+
"zod": "^4.4.3",
|
|
108
108
|
"zod-validation-error": "^5.0.0",
|
|
109
109
|
"zustand": "^5.0.13"
|
|
110
110
|
},
|
|
@@ -113,22 +113,22 @@
|
|
|
113
113
|
"@types/jsonwebtoken": "^9.0.4",
|
|
114
114
|
"@types/node": "^24.0.0",
|
|
115
115
|
"@types/picomatch": "^4.0.3",
|
|
116
|
-
"@types/react": "^19.2.
|
|
116
|
+
"@types/react": "^19.2.15",
|
|
117
117
|
"@types/ws": "^8.18.1",
|
|
118
118
|
"@types/yargs": "^17.0.35",
|
|
119
119
|
"ink-testing-library": "^4.0.0",
|
|
120
|
-
"tsdown": "^0.
|
|
121
|
-
"tsx": "^4.
|
|
120
|
+
"tsdown": "^0.22.0",
|
|
121
|
+
"tsx": "^4.22.3",
|
|
122
122
|
"typescript": "^5.9.3",
|
|
123
|
-
"vitest": "^4.1.
|
|
124
|
-
"@bike4mind/agents": "0.
|
|
125
|
-
"@bike4mind/common": "2.
|
|
126
|
-
"@bike4mind/mcp": "1.37.
|
|
127
|
-
"@bike4mind/services": "2.
|
|
128
|
-
"@bike4mind/utils": "2.
|
|
123
|
+
"vitest": "^4.1.7",
|
|
124
|
+
"@bike4mind/agents": "0.11.3",
|
|
125
|
+
"@bike4mind/common": "2.103.0",
|
|
126
|
+
"@bike4mind/mcp": "1.37.17",
|
|
127
|
+
"@bike4mind/services": "2.90.3",
|
|
128
|
+
"@bike4mind/utils": "2.23.5"
|
|
129
129
|
},
|
|
130
130
|
"optionalDependencies": {
|
|
131
|
-
"@vscode/ripgrep": "^1.
|
|
131
|
+
"@vscode/ripgrep": "^1.18.0"
|
|
132
132
|
},
|
|
133
133
|
"scripts": {
|
|
134
134
|
"dev": "tsx src/index.tsx",
|
package/dist/store-5PXzE9DM.mjs
DELETED
package/dist/types-DK3P88Px.mjs
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|