vexp-cli 2.0.13 → 2.0.15
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/dist/autostart.js +24 -4
- package/dist/license.js +23 -6
- package/package.json +6 -6
package/dist/autostart.js
CHANGED
|
@@ -251,12 +251,17 @@ function installWindowsStartup() {
|
|
|
251
251
|
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
252
252
|
const logPath = path.join(homedir(), ".vexp", "autostart.log");
|
|
253
253
|
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
// Two-context escaping: cmd.exe and VBScript both quote-double, but the
|
|
255
|
+
// contexts nest. Build the cmd string first, then wrap it as a VBScript
|
|
256
|
+
// string literal. /d /s /c forces legacy single-strip quote semantics so
|
|
257
|
+
// the outer `cmd ... "<inner>"` survives intact.
|
|
258
|
+
const quoteCmdArg = (a) => `"${a.replace(/"/g, '""')}"`;
|
|
259
|
+
const vbString = (s) => `"${s.replace(/"/g, '""')}"`;
|
|
260
|
+
const cmdParts = [launcher.bin, ...launcher.args].map(quoteCmdArg).join(" ");
|
|
261
|
+
const command = `%ComSpec% /d /s /c "${cmdParts} >> ${quoteCmdArg(logPath)} 2>&1"`;
|
|
257
262
|
const script = `' vexp autostart — launches \`vexp serve\` hidden at login.\n` +
|
|
258
263
|
`Set sh = CreateObject("WScript.Shell")\n` +
|
|
259
|
-
`sh.Run
|
|
264
|
+
`sh.Run ${vbString(command)}, 0, False\n`;
|
|
260
265
|
fs.writeFileSync(p, script);
|
|
261
266
|
return { installed: true, mechanism: "windows-startup", path: p };
|
|
262
267
|
}
|
|
@@ -318,6 +323,21 @@ export function uninstallAutostart() {
|
|
|
318
323
|
export function installAutostartIfNeeded() {
|
|
319
324
|
if (process.env.VEXP_NO_AUTOSTART_INSTALL === "1")
|
|
320
325
|
return;
|
|
326
|
+
// 2.0.12 shipped a broken Windows VBS template; rewrite any existing
|
|
327
|
+
// file matching that signature regardless of marker state, so upgraded
|
|
328
|
+
// users get fixed without manual autostart uninstall/install.
|
|
329
|
+
if (process.platform === "win32") {
|
|
330
|
+
try {
|
|
331
|
+
const p = windowsStartupPath();
|
|
332
|
+
if (fs.existsSync(p)) {
|
|
333
|
+
const existing = fs.readFileSync(p, "utf-8");
|
|
334
|
+
if (/sh\.Run\s+"cmd \/c "\s*&/.test(existing)) {
|
|
335
|
+
installWindowsStartup();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch { /* non-fatal */ }
|
|
340
|
+
}
|
|
321
341
|
const marker = installMarkerPath();
|
|
322
342
|
if (fs.existsSync(marker))
|
|
323
343
|
return;
|
package/dist/license.js
CHANGED
|
@@ -143,13 +143,21 @@ function clearDeviceBlocked() {
|
|
|
143
143
|
* exactly as before. This MUST never throw.
|
|
144
144
|
*/
|
|
145
145
|
export async function tryOnlineRefresh(longJwt) {
|
|
146
|
-
// Rate limit: at most one network call per REFRESH_BACKOFF_MS
|
|
147
|
-
const last = readLastCheck();
|
|
148
|
-
if (Date.now() - last < REFRESH_BACKOFF_MS)
|
|
149
|
-
return;
|
|
150
146
|
// Global kill switch for users who want to stay fully offline
|
|
151
147
|
if (process.env.VEXP_OFFLINE === "1")
|
|
152
148
|
return;
|
|
149
|
+
// Rate limit: at most one network call per REFRESH_BACKOFF_MS,
|
|
150
|
+
// UNLESS the long JWT is within the last 7 days of validity.
|
|
151
|
+
// That window is where expiry is imminent — bypass backoff so any
|
|
152
|
+
// CLI invocation in the danger zone attempts a refresh.
|
|
153
|
+
const last = readLastCheck();
|
|
154
|
+
const longClaims = verifyAndDecode(longJwt);
|
|
155
|
+
const nearExpiryMs = 7 * 24 * 60 * 60 * 1000;
|
|
156
|
+
const nearExpiry = longClaims
|
|
157
|
+
? longClaims.exp * 1000 - Date.now() < nearExpiryMs
|
|
158
|
+
: false;
|
|
159
|
+
if (!nearExpiry && Date.now() - last < REFRESH_BACKOFF_MS)
|
|
160
|
+
return;
|
|
153
161
|
const controller = new AbortController();
|
|
154
162
|
const timer = setTimeout(() => controller.abort(), VALIDATE_TIMEOUT_MS);
|
|
155
163
|
try {
|
|
@@ -309,7 +317,8 @@ export function readLicenseLimits() {
|
|
|
309
317
|
if (!longJwt)
|
|
310
318
|
return FREE_LIMITS;
|
|
311
319
|
const longClaims = verifyAndDecode(longJwt);
|
|
312
|
-
|
|
320
|
+
// Signature-invalid long JWT is fatal — nothing the server can do.
|
|
321
|
+
if (!longClaims) {
|
|
313
322
|
return FREE_LIMITS;
|
|
314
323
|
}
|
|
315
324
|
// Device cap enforcement: if this machine is over-cap, the server told
|
|
@@ -319,7 +328,9 @@ export function readLicenseLimits() {
|
|
|
319
328
|
return FREE_LIMITS;
|
|
320
329
|
}
|
|
321
330
|
// Fire-and-forget opportunistic refresh. Never awaited — we do not block
|
|
322
|
-
// CLI startup on the network.
|
|
331
|
+
// CLI startup on the network. We send the long JWT *even if it's already
|
|
332
|
+
// past `exp`*, because the server (Fix 3) accepts expired JWTs and
|
|
333
|
+
// re-issues freshTokens as long as the Stripe subscription (`pe`) holds.
|
|
323
334
|
void tryOnlineRefresh(longJwt);
|
|
324
335
|
// Prefer a still-valid freshToken within the grace window
|
|
325
336
|
const fresh = loadFreshToken();
|
|
@@ -332,5 +343,11 @@ export function readLicenseLimits() {
|
|
|
332
343
|
// grace window → server is unreachable for too long. Fall back to the
|
|
333
344
|
// long JWT (keeps working as today, no downgrade to free).
|
|
334
345
|
}
|
|
346
|
+
// No usable fresh token. If the long JWT itself has expired, we have
|
|
347
|
+
// nothing left to authenticate with → free tier. (The refresh fired
|
|
348
|
+
// above will populate fresh.jwt asynchronously for the next call.)
|
|
349
|
+
if (longClaims.exp * 1000 < Date.now()) {
|
|
350
|
+
return FREE_LIMITS;
|
|
351
|
+
}
|
|
335
352
|
return claimsToLimits(longClaims);
|
|
336
353
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vexp-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"description": "Vexp — Context Engine for AI Coding Agents. Pre-indexes your codebase into a dependency graph and delivers ranked context to any MCP-compatible agent. 58% lower cost per task, 90% fewer tool calls (SWE-bench Verified). Works with Claude Code, Cursor, Copilot, Windsurf, Codex, Cline, Aider, and 12+ agents. Local-first. Your code never leaves your machine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -99,10 +99,10 @@
|
|
|
99
99
|
"node": ">=20.0.0"
|
|
100
100
|
},
|
|
101
101
|
"optionalDependencies": {
|
|
102
|
-
"@vexp/core-linux-x64": "2.0.
|
|
103
|
-
"@vexp/core-linux-arm64": "2.0.
|
|
104
|
-
"@vexp/core-darwin-x64": "2.0.
|
|
105
|
-
"@vexp/core-darwin-arm64": "2.0.
|
|
106
|
-
"@vexp/core-win32-x64": "2.0.
|
|
102
|
+
"@vexp/core-linux-x64": "2.0.15",
|
|
103
|
+
"@vexp/core-linux-arm64": "2.0.15",
|
|
104
|
+
"@vexp/core-darwin-x64": "2.0.15",
|
|
105
|
+
"@vexp/core-darwin-arm64": "2.0.15",
|
|
106
|
+
"@vexp/core-win32-x64": "2.0.15"
|
|
107
107
|
}
|
|
108
108
|
}
|