@askexenow/exe-os 0.8.59 → 0.8.60
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/bin/cli.js +46 -11
- package/dist/bin/exe-boot.js +46 -11
- package/dist/bin/exe-cloud.js +35 -3
- package/dist/bin/exe-dispatch.js +13 -10
- package/dist/bin/exe-gateway.js +46 -11
- package/dist/bin/exe-new-employee.js +44 -3
- package/dist/bin/git-sweep.js +13 -10
- package/dist/bin/scan-tasks.js +13 -10
- package/dist/bin/setup.js +35 -3
- package/dist/bin/update.js +35 -3
- package/dist/gateway/index.js +13 -10
- package/dist/hooks/bug-report-worker.js +13 -10
- package/dist/hooks/commit-complete.js +13 -10
- package/dist/hooks/ingest-worker.js +55 -11
- package/dist/hooks/pre-compact.js +13 -10
- package/dist/hooks/prompt-ingest-worker.js +44 -3
- package/dist/hooks/prompt-submit.js +8 -5
- package/dist/hooks/response-ingest-worker.js +44 -3
- package/dist/hooks/summary-worker.js +35 -3
- package/dist/index.js +13 -10
- package/dist/lib/exe-daemon.js +13 -10
- package/dist/lib/license.js +35 -3
- package/dist/lib/messaging.js +8 -5
- package/dist/lib/tasks.js +13 -10
- package/dist/lib/tmux-routing.js +13 -10
- package/dist/mcp/server.js +46 -11
- package/dist/mcp/tools/create-task.js +13 -10
- package/dist/mcp/tools/send-message.js +8 -5
- package/dist/runtime/index.js +13 -10
- package/dist/tui/App.js +46 -11
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -4864,6 +4864,32 @@ function readCachedToken() {
|
|
|
4864
4864
|
return null;
|
|
4865
4865
|
}
|
|
4866
4866
|
}
|
|
4867
|
+
function getRawCachedPlan() {
|
|
4868
|
+
try {
|
|
4869
|
+
const token = readCachedToken();
|
|
4870
|
+
if (!token) return null;
|
|
4871
|
+
const parts = token.split(".");
|
|
4872
|
+
if (parts.length !== 3) return null;
|
|
4873
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
4874
|
+
const plan = payload.plan ?? "free";
|
|
4875
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
4876
|
+
process.stderr.write(
|
|
4877
|
+
`[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
|
|
4878
|
+
`
|
|
4879
|
+
);
|
|
4880
|
+
return {
|
|
4881
|
+
valid: true,
|
|
4882
|
+
plan,
|
|
4883
|
+
email: payload.sub ?? "",
|
|
4884
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
|
|
4885
|
+
deviceLimit: limits.devices,
|
|
4886
|
+
employeeLimit: limits.employees,
|
|
4887
|
+
memoryLimit: limits.memories
|
|
4888
|
+
};
|
|
4889
|
+
} catch {
|
|
4890
|
+
return null;
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4867
4893
|
function cacheResponse(token) {
|
|
4868
4894
|
try {
|
|
4869
4895
|
writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
@@ -4884,6 +4910,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
4884
4910
|
if (data.error === "device_limit_exceeded") {
|
|
4885
4911
|
const cached2 = await getCachedLicense();
|
|
4886
4912
|
if (cached2) return cached2;
|
|
4913
|
+
const raw2 = getRawCachedPlan();
|
|
4914
|
+
if (raw2) return { ...raw2, valid: false };
|
|
4887
4915
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
4888
4916
|
}
|
|
4889
4917
|
if (data.token) {
|
|
@@ -4904,10 +4932,14 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
4904
4932
|
}
|
|
4905
4933
|
const cached = await getCachedLicense();
|
|
4906
4934
|
if (cached) return cached;
|
|
4935
|
+
const raw = getRawCachedPlan();
|
|
4936
|
+
if (raw) return raw;
|
|
4907
4937
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
4908
4938
|
} catch {
|
|
4909
4939
|
const cached = await getCachedLicense();
|
|
4910
4940
|
if (cached) return cached;
|
|
4941
|
+
const rawFallback = getRawCachedPlan();
|
|
4942
|
+
if (rawFallback) return rawFallback;
|
|
4911
4943
|
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
4912
4944
|
}
|
|
4913
4945
|
}
|
|
@@ -5096,8 +5128,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
5096
5128
|
-----END PUBLIC KEY-----`;
|
|
5097
5129
|
LICENSE_JWT_ALG = "ES256";
|
|
5098
5130
|
PLAN_LIMITS = {
|
|
5099
|
-
free: { devices: 1, employees: 1, memories:
|
|
5100
|
-
pro: { devices: 2, employees: 5, memories:
|
|
5131
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
5132
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
5101
5133
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
5102
5134
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
5103
5135
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -5109,7 +5141,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
5109
5141
|
expiresAt: null,
|
|
5110
5142
|
deviceLimit: 1,
|
|
5111
5143
|
employeeLimit: 1,
|
|
5112
|
-
memoryLimit:
|
|
5144
|
+
memoryLimit: 5e4
|
|
5113
5145
|
};
|
|
5114
5146
|
CACHE_MAX_AGE_MS = 36e5;
|
|
5115
5147
|
_revalTimer = null;
|
|
@@ -15004,18 +15036,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
|
|
|
15004
15036
|
function getMySession() {
|
|
15005
15037
|
return getTransport().getMySession();
|
|
15006
15038
|
}
|
|
15039
|
+
function isRootSession(name) {
|
|
15040
|
+
return name.length > 0 && !name.includes("-");
|
|
15041
|
+
}
|
|
15007
15042
|
function employeeSessionName(employee, exeSession, instance) {
|
|
15008
|
-
if (
|
|
15043
|
+
if (!isRootSession(exeSession)) {
|
|
15009
15044
|
const root = extractRootExe(exeSession);
|
|
15010
15045
|
if (root) {
|
|
15011
15046
|
process.stderr.write(
|
|
15012
|
-
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root
|
|
15047
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root session, using "${root}" instead
|
|
15013
15048
|
`
|
|
15014
15049
|
);
|
|
15015
15050
|
exeSession = root;
|
|
15016
15051
|
} else {
|
|
15017
15052
|
throw new Error(
|
|
15018
|
-
`Invalid exeSession "${exeSession}" \u2014
|
|
15053
|
+
`Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
15019
15054
|
);
|
|
15020
15055
|
}
|
|
15021
15056
|
}
|
|
@@ -15023,7 +15058,7 @@ function employeeSessionName(employee, exeSession, instance) {
|
|
|
15023
15058
|
const name = `${employee}${suffix}-${exeSession}`;
|
|
15024
15059
|
if (!VALID_SESSION_NAME.test(name)) {
|
|
15025
15060
|
throw new Error(
|
|
15026
|
-
`Invalid session name "${name}" \u2014 must match {agent}-
|
|
15061
|
+
`Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
|
|
15027
15062
|
);
|
|
15028
15063
|
}
|
|
15029
15064
|
return name;
|
|
@@ -15266,11 +15301,11 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
15266
15301
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
15267
15302
|
};
|
|
15268
15303
|
}
|
|
15269
|
-
if (
|
|
15304
|
+
if (!isRootSession(exeSession)) {
|
|
15270
15305
|
const root = extractRootExe(exeSession);
|
|
15271
15306
|
if (root) {
|
|
15272
15307
|
process.stderr.write(
|
|
15273
|
-
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root
|
|
15308
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root session). Auto-correcting to "${root}".
|
|
15274
15309
|
`
|
|
15275
15310
|
);
|
|
15276
15311
|
exeSession = root;
|
|
@@ -15278,7 +15313,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
15278
15313
|
return {
|
|
15279
15314
|
status: "failed",
|
|
15280
15315
|
sessionName: "",
|
|
15281
|
-
error: `Invalid exeSession "${exeSession}" \u2014
|
|
15316
|
+
error: `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
15282
15317
|
};
|
|
15283
15318
|
}
|
|
15284
15319
|
}
|
|
@@ -15543,7 +15578,7 @@ var init_tmux_routing = __esm({
|
|
|
15543
15578
|
SPAWN_LOCK_DIR = path24.join(os9.homedir(), ".exe-os", "spawn-locks");
|
|
15544
15579
|
SESSION_CACHE = path24.join(os9.homedir(), ".exe-os", "session-cache");
|
|
15545
15580
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
15546
|
-
VALID_SESSION_NAME = /^[a-z]
|
|
15581
|
+
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
15547
15582
|
VERIFY_PANE_LINES = 200;
|
|
15548
15583
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
15549
15584
|
INTERCOM_LOG2 = path24.join(os9.homedir(), ".exe-os", "intercom.log");
|
package/dist/bin/exe-boot.js
CHANGED
|
@@ -2418,6 +2418,32 @@ function readCachedToken() {
|
|
|
2418
2418
|
return null;
|
|
2419
2419
|
}
|
|
2420
2420
|
}
|
|
2421
|
+
function getRawCachedPlan() {
|
|
2422
|
+
try {
|
|
2423
|
+
const token = readCachedToken();
|
|
2424
|
+
if (!token) return null;
|
|
2425
|
+
const parts = token.split(".");
|
|
2426
|
+
if (parts.length !== 3) return null;
|
|
2427
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
2428
|
+
const plan = payload.plan ?? "free";
|
|
2429
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
2430
|
+
process.stderr.write(
|
|
2431
|
+
`[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
|
|
2432
|
+
`
|
|
2433
|
+
);
|
|
2434
|
+
return {
|
|
2435
|
+
valid: true,
|
|
2436
|
+
plan,
|
|
2437
|
+
email: payload.sub ?? "",
|
|
2438
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
|
|
2439
|
+
deviceLimit: limits.devices,
|
|
2440
|
+
employeeLimit: limits.employees,
|
|
2441
|
+
memoryLimit: limits.memories
|
|
2442
|
+
};
|
|
2443
|
+
} catch {
|
|
2444
|
+
return null;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2421
2447
|
function cacheResponse(token) {
|
|
2422
2448
|
try {
|
|
2423
2449
|
writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
@@ -2438,6 +2464,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
2438
2464
|
if (data.error === "device_limit_exceeded") {
|
|
2439
2465
|
const cached2 = await getCachedLicense();
|
|
2440
2466
|
if (cached2) return cached2;
|
|
2467
|
+
const raw2 = getRawCachedPlan();
|
|
2468
|
+
if (raw2) return { ...raw2, valid: false };
|
|
2441
2469
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
2442
2470
|
}
|
|
2443
2471
|
if (data.token) {
|
|
@@ -2458,10 +2486,14 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
2458
2486
|
}
|
|
2459
2487
|
const cached = await getCachedLicense();
|
|
2460
2488
|
if (cached) return cached;
|
|
2489
|
+
const raw = getRawCachedPlan();
|
|
2490
|
+
if (raw) return raw;
|
|
2461
2491
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
2462
2492
|
} catch {
|
|
2463
2493
|
const cached = await getCachedLicense();
|
|
2464
2494
|
if (cached) return cached;
|
|
2495
|
+
const rawFallback = getRawCachedPlan();
|
|
2496
|
+
if (rawFallback) return rawFallback;
|
|
2465
2497
|
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
2466
2498
|
}
|
|
2467
2499
|
}
|
|
@@ -2650,8 +2682,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2650
2682
|
-----END PUBLIC KEY-----`;
|
|
2651
2683
|
LICENSE_JWT_ALG = "ES256";
|
|
2652
2684
|
PLAN_LIMITS = {
|
|
2653
|
-
free: { devices: 1, employees: 1, memories:
|
|
2654
|
-
pro: { devices: 2, employees: 5, memories:
|
|
2685
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
2686
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
2655
2687
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
2656
2688
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
2657
2689
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -2663,7 +2695,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2663
2695
|
expiresAt: null,
|
|
2664
2696
|
deviceLimit: 1,
|
|
2665
2697
|
employeeLimit: 1,
|
|
2666
|
-
memoryLimit:
|
|
2698
|
+
memoryLimit: 5e4
|
|
2667
2699
|
};
|
|
2668
2700
|
CACHE_MAX_AGE_MS = 36e5;
|
|
2669
2701
|
_revalTimer = null;
|
|
@@ -4786,18 +4818,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
|
|
|
4786
4818
|
function getMySession() {
|
|
4787
4819
|
return getTransport().getMySession();
|
|
4788
4820
|
}
|
|
4821
|
+
function isRootSession(name) {
|
|
4822
|
+
return name.length > 0 && !name.includes("-");
|
|
4823
|
+
}
|
|
4789
4824
|
function employeeSessionName(employee, exeSession, instance) {
|
|
4790
|
-
if (
|
|
4825
|
+
if (!isRootSession(exeSession)) {
|
|
4791
4826
|
const root = extractRootExe(exeSession);
|
|
4792
4827
|
if (root) {
|
|
4793
4828
|
process.stderr.write(
|
|
4794
|
-
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root
|
|
4829
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root session, using "${root}" instead
|
|
4795
4830
|
`
|
|
4796
4831
|
);
|
|
4797
4832
|
exeSession = root;
|
|
4798
4833
|
} else {
|
|
4799
4834
|
throw new Error(
|
|
4800
|
-
`Invalid exeSession "${exeSession}" \u2014
|
|
4835
|
+
`Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
4801
4836
|
);
|
|
4802
4837
|
}
|
|
4803
4838
|
}
|
|
@@ -4805,7 +4840,7 @@ function employeeSessionName(employee, exeSession, instance) {
|
|
|
4805
4840
|
const name = `${employee}${suffix}-${exeSession}`;
|
|
4806
4841
|
if (!VALID_SESSION_NAME.test(name)) {
|
|
4807
4842
|
throw new Error(
|
|
4808
|
-
`Invalid session name "${name}" \u2014 must match {agent}-
|
|
4843
|
+
`Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
|
|
4809
4844
|
);
|
|
4810
4845
|
}
|
|
4811
4846
|
return name;
|
|
@@ -5048,11 +5083,11 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5048
5083
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
5049
5084
|
};
|
|
5050
5085
|
}
|
|
5051
|
-
if (
|
|
5086
|
+
if (!isRootSession(exeSession)) {
|
|
5052
5087
|
const root = extractRootExe(exeSession);
|
|
5053
5088
|
if (root) {
|
|
5054
5089
|
process.stderr.write(
|
|
5055
|
-
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root
|
|
5090
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root session). Auto-correcting to "${root}".
|
|
5056
5091
|
`
|
|
5057
5092
|
);
|
|
5058
5093
|
exeSession = root;
|
|
@@ -5060,7 +5095,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5060
5095
|
return {
|
|
5061
5096
|
status: "failed",
|
|
5062
5097
|
sessionName: "",
|
|
5063
|
-
error: `Invalid exeSession "${exeSession}" \u2014
|
|
5098
|
+
error: `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
5064
5099
|
};
|
|
5065
5100
|
}
|
|
5066
5101
|
}
|
|
@@ -5325,7 +5360,7 @@ var init_tmux_routing = __esm({
|
|
|
5325
5360
|
SPAWN_LOCK_DIR = path15.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
5326
5361
|
SESSION_CACHE = path15.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5327
5362
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5328
|
-
VALID_SESSION_NAME = /^[a-z]
|
|
5363
|
+
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
5329
5364
|
VERIFY_PANE_LINES = 200;
|
|
5330
5365
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5331
5366
|
INTERCOM_LOG2 = path15.join(os6.homedir(), ".exe-os", "intercom.log");
|
package/dist/bin/exe-cloud.js
CHANGED
|
@@ -316,6 +316,32 @@ function readCachedToken() {
|
|
|
316
316
|
return null;
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
|
+
function getRawCachedPlan() {
|
|
320
|
+
try {
|
|
321
|
+
const token = readCachedToken();
|
|
322
|
+
if (!token) return null;
|
|
323
|
+
const parts = token.split(".");
|
|
324
|
+
if (parts.length !== 3) return null;
|
|
325
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
326
|
+
const plan = payload.plan ?? "free";
|
|
327
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
328
|
+
process.stderr.write(
|
|
329
|
+
`[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
|
|
330
|
+
`
|
|
331
|
+
);
|
|
332
|
+
return {
|
|
333
|
+
valid: true,
|
|
334
|
+
plan,
|
|
335
|
+
email: payload.sub ?? "",
|
|
336
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
|
|
337
|
+
deviceLimit: limits.devices,
|
|
338
|
+
employeeLimit: limits.employees,
|
|
339
|
+
memoryLimit: limits.memories
|
|
340
|
+
};
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
319
345
|
function cacheResponse(token) {
|
|
320
346
|
try {
|
|
321
347
|
writeFileSync(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
@@ -336,6 +362,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
336
362
|
if (data.error === "device_limit_exceeded") {
|
|
337
363
|
const cached2 = await getCachedLicense();
|
|
338
364
|
if (cached2) return cached2;
|
|
365
|
+
const raw2 = getRawCachedPlan();
|
|
366
|
+
if (raw2) return { ...raw2, valid: false };
|
|
339
367
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
340
368
|
}
|
|
341
369
|
if (data.token) {
|
|
@@ -356,10 +384,14 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
356
384
|
}
|
|
357
385
|
const cached = await getCachedLicense();
|
|
358
386
|
if (cached) return cached;
|
|
387
|
+
const raw = getRawCachedPlan();
|
|
388
|
+
if (raw) return raw;
|
|
359
389
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
360
390
|
} catch {
|
|
361
391
|
const cached = await getCachedLicense();
|
|
362
392
|
if (cached) return cached;
|
|
393
|
+
const rawFallback = getRawCachedPlan();
|
|
394
|
+
if (rawFallback) return rawFallback;
|
|
363
395
|
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
364
396
|
}
|
|
365
397
|
}
|
|
@@ -548,8 +580,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
548
580
|
-----END PUBLIC KEY-----`;
|
|
549
581
|
LICENSE_JWT_ALG = "ES256";
|
|
550
582
|
PLAN_LIMITS = {
|
|
551
|
-
free: { devices: 1, employees: 1, memories:
|
|
552
|
-
pro: { devices: 2, employees: 5, memories:
|
|
583
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
584
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
553
585
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
554
586
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
555
587
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -561,7 +593,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
561
593
|
expiresAt: null,
|
|
562
594
|
deviceLimit: 1,
|
|
563
595
|
employeeLimit: 1,
|
|
564
|
-
memoryLimit:
|
|
596
|
+
memoryLimit: 5e4
|
|
565
597
|
};
|
|
566
598
|
CACHE_MAX_AGE_MS = 36e5;
|
|
567
599
|
_revalTimer = null;
|
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -1460,8 +1460,8 @@ var init_license = __esm({
|
|
|
1460
1460
|
CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
|
|
1461
1461
|
DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
|
|
1462
1462
|
PLAN_LIMITS = {
|
|
1463
|
-
free: { devices: 1, employees: 1, memories:
|
|
1464
|
-
pro: { devices: 2, employees: 5, memories:
|
|
1463
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
1464
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
1465
1465
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
1466
1466
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
1467
1467
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -3464,18 +3464,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
|
|
|
3464
3464
|
function getMySession() {
|
|
3465
3465
|
return getTransport().getMySession();
|
|
3466
3466
|
}
|
|
3467
|
+
function isRootSession(name) {
|
|
3468
|
+
return name.length > 0 && !name.includes("-");
|
|
3469
|
+
}
|
|
3467
3470
|
function employeeSessionName(employee, exeSession2, instance) {
|
|
3468
|
-
if (
|
|
3471
|
+
if (!isRootSession(exeSession2)) {
|
|
3469
3472
|
const root = extractRootExe(exeSession2);
|
|
3470
3473
|
if (root) {
|
|
3471
3474
|
process.stderr.write(
|
|
3472
|
-
`[tmux-routing] WARN: exeSession="${exeSession2}" is not a root
|
|
3475
|
+
`[tmux-routing] WARN: exeSession="${exeSession2}" is not a root session, using "${root}" instead
|
|
3473
3476
|
`
|
|
3474
3477
|
);
|
|
3475
3478
|
exeSession2 = root;
|
|
3476
3479
|
} else {
|
|
3477
3480
|
throw new Error(
|
|
3478
|
-
`Invalid exeSession "${exeSession2}" \u2014
|
|
3481
|
+
`Invalid exeSession "${exeSession2}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
3479
3482
|
);
|
|
3480
3483
|
}
|
|
3481
3484
|
}
|
|
@@ -3483,7 +3486,7 @@ function employeeSessionName(employee, exeSession2, instance) {
|
|
|
3483
3486
|
const name = `${employee}${suffix}-${exeSession2}`;
|
|
3484
3487
|
if (!VALID_SESSION_NAME.test(name)) {
|
|
3485
3488
|
throw new Error(
|
|
3486
|
-
`Invalid session name "${name}" \u2014 must match {agent}-
|
|
3489
|
+
`Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
|
|
3487
3490
|
);
|
|
3488
3491
|
}
|
|
3489
3492
|
return name;
|
|
@@ -3726,11 +3729,11 @@ function ensureEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
3726
3729
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName2}')`
|
|
3727
3730
|
};
|
|
3728
3731
|
}
|
|
3729
|
-
if (
|
|
3732
|
+
if (!isRootSession(exeSession2)) {
|
|
3730
3733
|
const root = extractRootExe(exeSession2);
|
|
3731
3734
|
if (root) {
|
|
3732
3735
|
process.stderr.write(
|
|
3733
|
-
`[ensureEmployee] WARN: caller passed exeSession="${exeSession2}" (not a root
|
|
3736
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession2}" (not a root session). Auto-correcting to "${root}".
|
|
3734
3737
|
`
|
|
3735
3738
|
);
|
|
3736
3739
|
exeSession2 = root;
|
|
@@ -3738,7 +3741,7 @@ function ensureEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
3738
3741
|
return {
|
|
3739
3742
|
status: "failed",
|
|
3740
3743
|
sessionName: "",
|
|
3741
|
-
error: `Invalid exeSession "${exeSession2}" \u2014
|
|
3744
|
+
error: `Invalid exeSession "${exeSession2}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
3742
3745
|
};
|
|
3743
3746
|
}
|
|
3744
3747
|
}
|
|
@@ -4003,7 +4006,7 @@ var init_tmux_routing = __esm({
|
|
|
4003
4006
|
SPAWN_LOCK_DIR = path13.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
4004
4007
|
SESSION_CACHE = path13.join(os5.homedir(), ".exe-os", "session-cache");
|
|
4005
4008
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4006
|
-
VALID_SESSION_NAME = /^[a-z]
|
|
4009
|
+
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4007
4010
|
VERIFY_PANE_LINES = 200;
|
|
4008
4011
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4009
4012
|
INTERCOM_LOG2 = path13.join(os5.homedir(), ".exe-os", "intercom.log");
|
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -3123,6 +3123,32 @@ function readCachedToken() {
|
|
|
3123
3123
|
return null;
|
|
3124
3124
|
}
|
|
3125
3125
|
}
|
|
3126
|
+
function getRawCachedPlan() {
|
|
3127
|
+
try {
|
|
3128
|
+
const token = readCachedToken();
|
|
3129
|
+
if (!token) return null;
|
|
3130
|
+
const parts = token.split(".");
|
|
3131
|
+
if (parts.length !== 3) return null;
|
|
3132
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
3133
|
+
const plan = payload.plan ?? "free";
|
|
3134
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
3135
|
+
process.stderr.write(
|
|
3136
|
+
`[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
|
|
3137
|
+
`
|
|
3138
|
+
);
|
|
3139
|
+
return {
|
|
3140
|
+
valid: true,
|
|
3141
|
+
plan,
|
|
3142
|
+
email: payload.sub ?? "",
|
|
3143
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
|
|
3144
|
+
deviceLimit: limits.devices,
|
|
3145
|
+
employeeLimit: limits.employees,
|
|
3146
|
+
memoryLimit: limits.memories
|
|
3147
|
+
};
|
|
3148
|
+
} catch {
|
|
3149
|
+
return null;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3126
3152
|
function cacheResponse(token) {
|
|
3127
3153
|
try {
|
|
3128
3154
|
writeFileSync(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
@@ -3143,6 +3169,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
3143
3169
|
if (data.error === "device_limit_exceeded") {
|
|
3144
3170
|
const cached2 = await getCachedLicense();
|
|
3145
3171
|
if (cached2) return cached2;
|
|
3172
|
+
const raw2 = getRawCachedPlan();
|
|
3173
|
+
if (raw2) return { ...raw2, valid: false };
|
|
3146
3174
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
3147
3175
|
}
|
|
3148
3176
|
if (data.token) {
|
|
@@ -3163,10 +3191,14 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
3163
3191
|
}
|
|
3164
3192
|
const cached = await getCachedLicense();
|
|
3165
3193
|
if (cached) return cached;
|
|
3194
|
+
const raw = getRawCachedPlan();
|
|
3195
|
+
if (raw) return raw;
|
|
3166
3196
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
3167
3197
|
} catch {
|
|
3168
3198
|
const cached = await getCachedLicense();
|
|
3169
3199
|
if (cached) return cached;
|
|
3200
|
+
const rawFallback = getRawCachedPlan();
|
|
3201
|
+
if (rawFallback) return rawFallback;
|
|
3170
3202
|
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
3171
3203
|
}
|
|
3172
3204
|
}
|
|
@@ -3355,8 +3387,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
3355
3387
|
-----END PUBLIC KEY-----`;
|
|
3356
3388
|
LICENSE_JWT_ALG = "ES256";
|
|
3357
3389
|
PLAN_LIMITS = {
|
|
3358
|
-
free: { devices: 1, employees: 1, memories:
|
|
3359
|
-
pro: { devices: 2, employees: 5, memories:
|
|
3390
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
3391
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
3360
3392
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
3361
3393
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
3362
3394
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -3368,7 +3400,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
3368
3400
|
expiresAt: null,
|
|
3369
3401
|
deviceLimit: 1,
|
|
3370
3402
|
employeeLimit: 1,
|
|
3371
|
-
memoryLimit:
|
|
3403
|
+
memoryLimit: 5e4
|
|
3372
3404
|
};
|
|
3373
3405
|
CACHE_MAX_AGE_MS = 36e5;
|
|
3374
3406
|
_revalTimer = null;
|
|
@@ -6942,18 +6974,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
|
|
|
6942
6974
|
function getMySession() {
|
|
6943
6975
|
return getTransport().getMySession();
|
|
6944
6976
|
}
|
|
6977
|
+
function isRootSession(name) {
|
|
6978
|
+
return name.length > 0 && !name.includes("-");
|
|
6979
|
+
}
|
|
6945
6980
|
function employeeSessionName(employee, exeSession, instance) {
|
|
6946
|
-
if (
|
|
6981
|
+
if (!isRootSession(exeSession)) {
|
|
6947
6982
|
const root = extractRootExe(exeSession);
|
|
6948
6983
|
if (root) {
|
|
6949
6984
|
process.stderr.write(
|
|
6950
|
-
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root
|
|
6985
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root session, using "${root}" instead
|
|
6951
6986
|
`
|
|
6952
6987
|
);
|
|
6953
6988
|
exeSession = root;
|
|
6954
6989
|
} else {
|
|
6955
6990
|
throw new Error(
|
|
6956
|
-
`Invalid exeSession "${exeSession}" \u2014
|
|
6991
|
+
`Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
6957
6992
|
);
|
|
6958
6993
|
}
|
|
6959
6994
|
}
|
|
@@ -6961,7 +6996,7 @@ function employeeSessionName(employee, exeSession, instance) {
|
|
|
6961
6996
|
const name = `${employee}${suffix}-${exeSession}`;
|
|
6962
6997
|
if (!VALID_SESSION_NAME.test(name)) {
|
|
6963
6998
|
throw new Error(
|
|
6964
|
-
`Invalid session name "${name}" \u2014 must match {agent}-
|
|
6999
|
+
`Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
|
|
6965
7000
|
);
|
|
6966
7001
|
}
|
|
6967
7002
|
return name;
|
|
@@ -7204,11 +7239,11 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7204
7239
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
7205
7240
|
};
|
|
7206
7241
|
}
|
|
7207
|
-
if (
|
|
7242
|
+
if (!isRootSession(exeSession)) {
|
|
7208
7243
|
const root = extractRootExe(exeSession);
|
|
7209
7244
|
if (root) {
|
|
7210
7245
|
process.stderr.write(
|
|
7211
|
-
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root
|
|
7246
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root session). Auto-correcting to "${root}".
|
|
7212
7247
|
`
|
|
7213
7248
|
);
|
|
7214
7249
|
exeSession = root;
|
|
@@ -7216,7 +7251,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7216
7251
|
return {
|
|
7217
7252
|
status: "failed",
|
|
7218
7253
|
sessionName: "",
|
|
7219
|
-
error: `Invalid exeSession "${exeSession}" \u2014
|
|
7254
|
+
error: `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
|
|
7220
7255
|
};
|
|
7221
7256
|
}
|
|
7222
7257
|
}
|
|
@@ -7481,7 +7516,7 @@ var init_tmux_routing = __esm({
|
|
|
7481
7516
|
SPAWN_LOCK_DIR = path17.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
7482
7517
|
SESSION_CACHE = path17.join(os7.homedir(), ".exe-os", "session-cache");
|
|
7483
7518
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
7484
|
-
VALID_SESSION_NAME = /^[a-z]
|
|
7519
|
+
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
7485
7520
|
VERIFY_PANE_LINES = 200;
|
|
7486
7521
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
7487
7522
|
INTERCOM_LOG2 = path17.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
@@ -1370,8 +1370,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
1370
1370
|
-----END PUBLIC KEY-----`;
|
|
1371
1371
|
var LICENSE_JWT_ALG = "ES256";
|
|
1372
1372
|
var PLAN_LIMITS = {
|
|
1373
|
-
free: { devices: 1, employees: 1, memories:
|
|
1374
|
-
pro: { devices: 2, employees: 5, memories:
|
|
1373
|
+
free: { devices: 1, employees: 1, memories: 5e4 },
|
|
1374
|
+
pro: { devices: 2, employees: 5, memories: 25e4 },
|
|
1375
1375
|
team: { devices: 10, employees: 20, memories: 1e6 },
|
|
1376
1376
|
agency: { devices: 50, employees: 100, memories: 1e7 },
|
|
1377
1377
|
enterprise: { devices: -1, employees: -1, memories: -1 }
|
|
@@ -1383,7 +1383,7 @@ var FREE_LICENSE = {
|
|
|
1383
1383
|
expiresAt: null,
|
|
1384
1384
|
deviceLimit: 1,
|
|
1385
1385
|
employeeLimit: 1,
|
|
1386
|
-
memoryLimit:
|
|
1386
|
+
memoryLimit: 5e4
|
|
1387
1387
|
};
|
|
1388
1388
|
function loadDeviceId() {
|
|
1389
1389
|
const deviceJsonPath = path3.join(EXE_AI_DIR, "device.json");
|
|
@@ -1450,6 +1450,41 @@ async function getCachedLicense() {
|
|
|
1450
1450
|
return null;
|
|
1451
1451
|
}
|
|
1452
1452
|
}
|
|
1453
|
+
function readCachedToken() {
|
|
1454
|
+
try {
|
|
1455
|
+
if (!existsSync3(CACHE_PATH)) return null;
|
|
1456
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
1457
|
+
return typeof raw.token === "string" ? raw.token : null;
|
|
1458
|
+
} catch {
|
|
1459
|
+
return null;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
function getRawCachedPlan() {
|
|
1463
|
+
try {
|
|
1464
|
+
const token = readCachedToken();
|
|
1465
|
+
if (!token) return null;
|
|
1466
|
+
const parts = token.split(".");
|
|
1467
|
+
if (parts.length !== 3) return null;
|
|
1468
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
1469
|
+
const plan = payload.plan ?? "free";
|
|
1470
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
1471
|
+
process.stderr.write(
|
|
1472
|
+
`[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
|
|
1473
|
+
`
|
|
1474
|
+
);
|
|
1475
|
+
return {
|
|
1476
|
+
valid: true,
|
|
1477
|
+
plan,
|
|
1478
|
+
email: payload.sub ?? "",
|
|
1479
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
|
|
1480
|
+
deviceLimit: limits.devices,
|
|
1481
|
+
employeeLimit: limits.employees,
|
|
1482
|
+
memoryLimit: limits.memories
|
|
1483
|
+
};
|
|
1484
|
+
} catch {
|
|
1485
|
+
return null;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1453
1488
|
function cacheResponse(token) {
|
|
1454
1489
|
try {
|
|
1455
1490
|
writeFileSync(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
@@ -1470,6 +1505,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1470
1505
|
if (data.error === "device_limit_exceeded") {
|
|
1471
1506
|
const cached2 = await getCachedLicense();
|
|
1472
1507
|
if (cached2) return cached2;
|
|
1508
|
+
const raw2 = getRawCachedPlan();
|
|
1509
|
+
if (raw2) return { ...raw2, valid: false };
|
|
1473
1510
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
1474
1511
|
}
|
|
1475
1512
|
if (data.token) {
|
|
@@ -1490,10 +1527,14 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1490
1527
|
}
|
|
1491
1528
|
const cached = await getCachedLicense();
|
|
1492
1529
|
if (cached) return cached;
|
|
1530
|
+
const raw = getRawCachedPlan();
|
|
1531
|
+
if (raw) return raw;
|
|
1493
1532
|
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
1494
1533
|
} catch {
|
|
1495
1534
|
const cached = await getCachedLicense();
|
|
1496
1535
|
if (cached) return cached;
|
|
1536
|
+
const rawFallback = getRawCachedPlan();
|
|
1537
|
+
if (rawFallback) return rawFallback;
|
|
1497
1538
|
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
1498
1539
|
}
|
|
1499
1540
|
}
|