@askexenow/exe-os 0.8.55 → 0.8.56
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 +49 -1
- package/dist/bin/install.js +47 -3
- package/dist/bin/update.js +485 -0
- package/dist/hooks/summary-worker.js +662 -211
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
2
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
3
5
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
6
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
7
|
}) : x)(function(x) {
|
|
@@ -13,6 +15,15 @@ var __export = (target, all) => {
|
|
|
13
15
|
for (var name in all)
|
|
14
16
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
17
|
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
27
|
|
|
17
28
|
// src/types/memory.ts
|
|
18
29
|
var EMBEDDING_DIM;
|
|
@@ -1347,6 +1358,61 @@ var init_config = __esm({
|
|
|
1347
1358
|
}
|
|
1348
1359
|
});
|
|
1349
1360
|
|
|
1361
|
+
// src/lib/state-bus.ts
|
|
1362
|
+
var StateBus, orgBus;
|
|
1363
|
+
var init_state_bus = __esm({
|
|
1364
|
+
"src/lib/state-bus.ts"() {
|
|
1365
|
+
"use strict";
|
|
1366
|
+
StateBus = class {
|
|
1367
|
+
handlers = /* @__PURE__ */ new Map();
|
|
1368
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
1369
|
+
/** Emit an event to all subscribers */
|
|
1370
|
+
emit(event) {
|
|
1371
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
1372
|
+
if (typeHandlers) {
|
|
1373
|
+
for (const handler of typeHandlers) {
|
|
1374
|
+
try {
|
|
1375
|
+
handler(event);
|
|
1376
|
+
} catch {
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
for (const handler of this.globalHandlers) {
|
|
1381
|
+
try {
|
|
1382
|
+
handler(event);
|
|
1383
|
+
} catch {
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
/** Subscribe to a specific event type */
|
|
1388
|
+
on(type, handler) {
|
|
1389
|
+
if (!this.handlers.has(type)) {
|
|
1390
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
1391
|
+
}
|
|
1392
|
+
this.handlers.get(type).add(handler);
|
|
1393
|
+
}
|
|
1394
|
+
/** Subscribe to ALL events */
|
|
1395
|
+
onAny(handler) {
|
|
1396
|
+
this.globalHandlers.add(handler);
|
|
1397
|
+
}
|
|
1398
|
+
/** Unsubscribe from a specific event type */
|
|
1399
|
+
off(type, handler) {
|
|
1400
|
+
this.handlers.get(type)?.delete(handler);
|
|
1401
|
+
}
|
|
1402
|
+
/** Unsubscribe from ALL events */
|
|
1403
|
+
offAny(handler) {
|
|
1404
|
+
this.globalHandlers.delete(handler);
|
|
1405
|
+
}
|
|
1406
|
+
/** Remove all listeners */
|
|
1407
|
+
clear() {
|
|
1408
|
+
this.handlers.clear();
|
|
1409
|
+
this.globalHandlers.clear();
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
orgBus = new StateBus();
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1350
1416
|
// src/lib/shard-manager.ts
|
|
1351
1417
|
var shard_manager_exports = {};
|
|
1352
1418
|
__export(shard_manager_exports, {
|
|
@@ -1756,13 +1822,251 @@ ${p.content}`).join("\n\n");
|
|
|
1756
1822
|
}
|
|
1757
1823
|
});
|
|
1758
1824
|
|
|
1825
|
+
// src/lib/notifications.ts
|
|
1826
|
+
import crypto2 from "crypto";
|
|
1827
|
+
import path4 from "path";
|
|
1828
|
+
import os3 from "os";
|
|
1829
|
+
import {
|
|
1830
|
+
readFileSync as readFileSync2,
|
|
1831
|
+
readdirSync as readdirSync2,
|
|
1832
|
+
unlinkSync,
|
|
1833
|
+
existsSync as existsSync4,
|
|
1834
|
+
rmdirSync
|
|
1835
|
+
} from "fs";
|
|
1836
|
+
async function writeNotification(notification) {
|
|
1837
|
+
try {
|
|
1838
|
+
const client = getClient();
|
|
1839
|
+
const id = crypto2.randomUUID();
|
|
1840
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1841
|
+
await client.execute({
|
|
1842
|
+
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
1843
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
1844
|
+
args: [
|
|
1845
|
+
id,
|
|
1846
|
+
notification.agentId,
|
|
1847
|
+
notification.agentRole,
|
|
1848
|
+
notification.event,
|
|
1849
|
+
notification.project,
|
|
1850
|
+
notification.summary,
|
|
1851
|
+
notification.taskFile ?? null,
|
|
1852
|
+
now
|
|
1853
|
+
]
|
|
1854
|
+
});
|
|
1855
|
+
} catch (err) {
|
|
1856
|
+
process.stderr.write(`[notifications] WRITE FAILED: ${err instanceof Error ? err.message : String(err)}
|
|
1857
|
+
`);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
var init_notifications = __esm({
|
|
1861
|
+
"src/lib/notifications.ts"() {
|
|
1862
|
+
"use strict";
|
|
1863
|
+
init_database();
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
|
|
1867
|
+
// src/lib/session-registry.ts
|
|
1868
|
+
import path5 from "path";
|
|
1869
|
+
import os4 from "os";
|
|
1870
|
+
var REGISTRY_PATH;
|
|
1871
|
+
var init_session_registry = __esm({
|
|
1872
|
+
"src/lib/session-registry.ts"() {
|
|
1873
|
+
"use strict";
|
|
1874
|
+
REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
// src/lib/session-key.ts
|
|
1879
|
+
import { execSync } from "child_process";
|
|
1880
|
+
function getSessionKey() {
|
|
1881
|
+
if (_cached) return _cached;
|
|
1882
|
+
let pid = process.ppid;
|
|
1883
|
+
for (let i = 0; i < 10; i++) {
|
|
1884
|
+
try {
|
|
1885
|
+
const info = execSync(`ps -p ${pid} -o ppid=,comm=`, {
|
|
1886
|
+
encoding: "utf8",
|
|
1887
|
+
timeout: 2e3
|
|
1888
|
+
}).trim();
|
|
1889
|
+
const match = info.match(/^\s*(\d+)\s+(.+)$/);
|
|
1890
|
+
if (!match) break;
|
|
1891
|
+
const [, ppid, cmd] = match;
|
|
1892
|
+
if (cmd === "claude" || cmd.endsWith("/claude")) {
|
|
1893
|
+
_cached = String(pid);
|
|
1894
|
+
return _cached;
|
|
1895
|
+
}
|
|
1896
|
+
pid = parseInt(ppid, 10);
|
|
1897
|
+
if (pid <= 1) break;
|
|
1898
|
+
} catch {
|
|
1899
|
+
break;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
_cached = process.env.CLAUDE_CODE_SSE_PORT ?? String(process.ppid);
|
|
1903
|
+
return _cached;
|
|
1904
|
+
}
|
|
1905
|
+
var _cached;
|
|
1906
|
+
var init_session_key = __esm({
|
|
1907
|
+
"src/lib/session-key.ts"() {
|
|
1908
|
+
"use strict";
|
|
1909
|
+
_cached = null;
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
|
|
1913
|
+
// src/lib/tmux-transport.ts
|
|
1914
|
+
var tmux_transport_exports = {};
|
|
1915
|
+
__export(tmux_transport_exports, {
|
|
1916
|
+
TmuxTransport: () => TmuxTransport
|
|
1917
|
+
});
|
|
1918
|
+
import { execFileSync } from "child_process";
|
|
1919
|
+
var QUIET, TmuxTransport;
|
|
1920
|
+
var init_tmux_transport = __esm({
|
|
1921
|
+
"src/lib/tmux-transport.ts"() {
|
|
1922
|
+
"use strict";
|
|
1923
|
+
QUIET = {
|
|
1924
|
+
encoding: "utf8",
|
|
1925
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1926
|
+
};
|
|
1927
|
+
TmuxTransport = class {
|
|
1928
|
+
getMySession() {
|
|
1929
|
+
try {
|
|
1930
|
+
return execFileSync("tmux", ["display-message", "-p", "#{session_name}"], QUIET).trim() || null;
|
|
1931
|
+
} catch {
|
|
1932
|
+
return null;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
listSessions() {
|
|
1936
|
+
try {
|
|
1937
|
+
return execFileSync("tmux", ["list-sessions", "-F", "#{session_name}"], QUIET).trim().split("\n").filter(Boolean);
|
|
1938
|
+
} catch {
|
|
1939
|
+
return [];
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
isAlive(target) {
|
|
1943
|
+
try {
|
|
1944
|
+
const sessions = this.listSessions();
|
|
1945
|
+
if (!sessions.includes(target)) return false;
|
|
1946
|
+
const paneStatus = execFileSync(
|
|
1947
|
+
"tmux",
|
|
1948
|
+
["list-panes", "-t", target, "-F", "#{pane_dead}"],
|
|
1949
|
+
QUIET
|
|
1950
|
+
).trim();
|
|
1951
|
+
return paneStatus !== "1";
|
|
1952
|
+
} catch {
|
|
1953
|
+
return false;
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
sendKeys(target, keys) {
|
|
1957
|
+
execFileSync("tmux", ["send-keys", "-t", target, keys, "Enter"], QUIET);
|
|
1958
|
+
}
|
|
1959
|
+
capturePane(target, lines) {
|
|
1960
|
+
const args = ["capture-pane", "-t", target, "-p"];
|
|
1961
|
+
if (lines) args.push("-S", `-${lines}`);
|
|
1962
|
+
return execFileSync("tmux", args, { ...QUIET, timeout: 3e3 });
|
|
1963
|
+
}
|
|
1964
|
+
isPaneInCopyMode(target) {
|
|
1965
|
+
try {
|
|
1966
|
+
const result = execFileSync(
|
|
1967
|
+
"tmux",
|
|
1968
|
+
["display-message", "-p", "-t", target, "#{pane_in_mode}"],
|
|
1969
|
+
{ ...QUIET, timeout: 3e3 }
|
|
1970
|
+
).trim();
|
|
1971
|
+
return result === "1";
|
|
1972
|
+
} catch {
|
|
1973
|
+
return false;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
spawn(name, config) {
|
|
1977
|
+
try {
|
|
1978
|
+
const args = ["new-session", "-d", "-s", name];
|
|
1979
|
+
if (config.cwd) args.push("-c", config.cwd);
|
|
1980
|
+
args.push(config.command);
|
|
1981
|
+
execFileSync("tmux", args);
|
|
1982
|
+
return { sessionName: name };
|
|
1983
|
+
} catch (e) {
|
|
1984
|
+
return { sessionName: name, error: `spawn failed: ${e}` };
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
kill(target) {
|
|
1988
|
+
try {
|
|
1989
|
+
execFileSync("tmux", ["kill-session", "-t", target], QUIET);
|
|
1990
|
+
} catch {
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
pipeLog(target, logFile) {
|
|
1994
|
+
try {
|
|
1995
|
+
const safePath = logFile.replace(/'/g, "'\\''");
|
|
1996
|
+
execFileSync("tmux", ["pipe-pane", "-t", target, `cat >> '${safePath}'`], QUIET);
|
|
1997
|
+
} catch {
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
});
|
|
2003
|
+
|
|
2004
|
+
// src/lib/transport.ts
|
|
2005
|
+
function getTransport() {
|
|
2006
|
+
if (!_transport) {
|
|
2007
|
+
const { TmuxTransport: TmuxTransport2 } = (init_tmux_transport(), __toCommonJS(tmux_transport_exports));
|
|
2008
|
+
_transport = new TmuxTransport2();
|
|
2009
|
+
}
|
|
2010
|
+
return _transport;
|
|
2011
|
+
}
|
|
2012
|
+
var _transport;
|
|
2013
|
+
var init_transport = __esm({
|
|
2014
|
+
"src/lib/transport.ts"() {
|
|
2015
|
+
"use strict";
|
|
2016
|
+
_transport = null;
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
|
|
2020
|
+
// src/lib/cc-agent-support.ts
|
|
2021
|
+
import { execSync as execSync2 } from "child_process";
|
|
2022
|
+
var init_cc_agent_support = __esm({
|
|
2023
|
+
"src/lib/cc-agent-support.ts"() {
|
|
2024
|
+
"use strict";
|
|
2025
|
+
}
|
|
2026
|
+
});
|
|
2027
|
+
|
|
2028
|
+
// src/lib/mcp-prefix.ts
|
|
2029
|
+
var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
|
|
2030
|
+
var init_mcp_prefix = __esm({
|
|
2031
|
+
"src/lib/mcp-prefix.ts"() {
|
|
2032
|
+
"use strict";
|
|
2033
|
+
MCP_PRIMARY_KEY = "exe-os";
|
|
2034
|
+
MCP_LEGACY_KEY = "exe-mem";
|
|
2035
|
+
MCP_TOOL_PREFIXES = [
|
|
2036
|
+
`mcp__${MCP_PRIMARY_KEY}__`,
|
|
2037
|
+
`mcp__${MCP_LEGACY_KEY}__`
|
|
2038
|
+
];
|
|
2039
|
+
}
|
|
2040
|
+
});
|
|
2041
|
+
|
|
2042
|
+
// src/lib/provider-table.ts
|
|
2043
|
+
var init_provider_table = __esm({
|
|
2044
|
+
"src/lib/provider-table.ts"() {
|
|
2045
|
+
"use strict";
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
|
|
2049
|
+
// src/lib/intercom-queue.ts
|
|
2050
|
+
import { readFileSync as readFileSync3, writeFileSync, renameSync as renameSync2, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
2051
|
+
import path6 from "path";
|
|
2052
|
+
import os5 from "os";
|
|
2053
|
+
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
2054
|
+
var init_intercom_queue = __esm({
|
|
2055
|
+
"src/lib/intercom-queue.ts"() {
|
|
2056
|
+
"use strict";
|
|
2057
|
+
QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2058
|
+
TTL_MS = 60 * 60 * 1e3;
|
|
2059
|
+
INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
|
|
1759
2063
|
// src/lib/employees.ts
|
|
1760
2064
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
1761
|
-
import { existsSync as
|
|
1762
|
-
import { execSync } from "child_process";
|
|
1763
|
-
import
|
|
2065
|
+
import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
|
|
2066
|
+
import { execSync as execSync3 } from "child_process";
|
|
2067
|
+
import path7 from "path";
|
|
1764
2068
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
1765
|
-
if (!
|
|
2069
|
+
if (!existsSync6(employeesPath)) {
|
|
1766
2070
|
return [];
|
|
1767
2071
|
}
|
|
1768
2072
|
const raw = await readFile3(employeesPath, "utf-8");
|
|
@@ -1773,12 +2077,12 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
1773
2077
|
}
|
|
1774
2078
|
}
|
|
1775
2079
|
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
1776
|
-
await mkdir3(
|
|
2080
|
+
await mkdir3(path7.dirname(employeesPath), { recursive: true });
|
|
1777
2081
|
await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
1778
2082
|
}
|
|
1779
2083
|
function findExeBin() {
|
|
1780
2084
|
try {
|
|
1781
|
-
return
|
|
2085
|
+
return execSync3(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
1782
2086
|
} catch {
|
|
1783
2087
|
return null;
|
|
1784
2088
|
}
|
|
@@ -1792,7 +2096,7 @@ function registerBinSymlinks(name) {
|
|
|
1792
2096
|
errors.push("Could not find 'exe-os' in PATH");
|
|
1793
2097
|
return { created, skipped, errors };
|
|
1794
2098
|
}
|
|
1795
|
-
const binDir =
|
|
2099
|
+
const binDir = path7.dirname(exeBinPath);
|
|
1796
2100
|
let target;
|
|
1797
2101
|
try {
|
|
1798
2102
|
target = readlinkSync(exeBinPath);
|
|
@@ -1802,8 +2106,8 @@ function registerBinSymlinks(name) {
|
|
|
1802
2106
|
}
|
|
1803
2107
|
for (const suffix of ["", "-opencode"]) {
|
|
1804
2108
|
const linkName = `${name}${suffix}`;
|
|
1805
|
-
const linkPath =
|
|
1806
|
-
if (
|
|
2109
|
+
const linkPath = path7.join(binDir, linkName);
|
|
2110
|
+
if (existsSync6(linkPath)) {
|
|
1807
2111
|
skipped.push(linkName);
|
|
1808
2112
|
continue;
|
|
1809
2113
|
}
|
|
@@ -1821,14 +2125,30 @@ var init_employees = __esm({
|
|
|
1821
2125
|
"src/lib/employees.ts"() {
|
|
1822
2126
|
"use strict";
|
|
1823
2127
|
init_config();
|
|
1824
|
-
EMPLOYEES_PATH =
|
|
2128
|
+
EMPLOYEES_PATH = path7.join(EXE_AI_DIR, "exe-employees.json");
|
|
1825
2129
|
}
|
|
1826
2130
|
});
|
|
1827
2131
|
|
|
1828
2132
|
// src/lib/license.ts
|
|
1829
|
-
|
|
2133
|
+
var license_exports = {};
|
|
2134
|
+
__export(license_exports, {
|
|
2135
|
+
LICENSE_PUBLIC_KEY_PEM: () => LICENSE_PUBLIC_KEY_PEM,
|
|
2136
|
+
PLAN_LIMITS: () => PLAN_LIMITS,
|
|
2137
|
+
assertVpsLicense: () => assertVpsLicense,
|
|
2138
|
+
checkLicense: () => checkLicense,
|
|
2139
|
+
getCachedLicense: () => getCachedLicense,
|
|
2140
|
+
isFeatureAllowed: () => isFeatureAllowed,
|
|
2141
|
+
loadDeviceId: () => loadDeviceId,
|
|
2142
|
+
loadLicense: () => loadLicense,
|
|
2143
|
+
mirrorLicenseKey: () => mirrorLicenseKey,
|
|
2144
|
+
saveLicense: () => saveLicense,
|
|
2145
|
+
startLicenseRevalidation: () => startLicenseRevalidation,
|
|
2146
|
+
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
2147
|
+
validateLicense: () => validateLicense
|
|
2148
|
+
});
|
|
2149
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
1830
2150
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1831
|
-
import
|
|
2151
|
+
import path8 from "path";
|
|
1832
2152
|
import { jwtVerify, importSPKI } from "jose";
|
|
1833
2153
|
async function fetchRetry(url, init) {
|
|
1834
2154
|
try {
|
|
@@ -1839,37 +2159,37 @@ async function fetchRetry(url, init) {
|
|
|
1839
2159
|
}
|
|
1840
2160
|
}
|
|
1841
2161
|
function loadDeviceId() {
|
|
1842
|
-
const deviceJsonPath =
|
|
2162
|
+
const deviceJsonPath = path8.join(EXE_AI_DIR, "device.json");
|
|
1843
2163
|
try {
|
|
1844
|
-
if (
|
|
1845
|
-
const data = JSON.parse(
|
|
2164
|
+
if (existsSync7(deviceJsonPath)) {
|
|
2165
|
+
const data = JSON.parse(readFileSync5(deviceJsonPath, "utf8"));
|
|
1846
2166
|
if (data.deviceId) return data.deviceId;
|
|
1847
2167
|
}
|
|
1848
2168
|
} catch {
|
|
1849
2169
|
}
|
|
1850
2170
|
try {
|
|
1851
|
-
if (
|
|
1852
|
-
const id2 =
|
|
2171
|
+
if (existsSync7(DEVICE_ID_PATH)) {
|
|
2172
|
+
const id2 = readFileSync5(DEVICE_ID_PATH, "utf8").trim();
|
|
1853
2173
|
if (id2) return id2;
|
|
1854
2174
|
}
|
|
1855
2175
|
} catch {
|
|
1856
2176
|
}
|
|
1857
2177
|
const id = randomUUID2();
|
|
1858
|
-
|
|
1859
|
-
|
|
2178
|
+
mkdirSync3(EXE_AI_DIR, { recursive: true });
|
|
2179
|
+
writeFileSync2(DEVICE_ID_PATH, id, "utf8");
|
|
1860
2180
|
return id;
|
|
1861
2181
|
}
|
|
1862
2182
|
function loadLicense() {
|
|
1863
2183
|
try {
|
|
1864
|
-
if (!
|
|
1865
|
-
return
|
|
2184
|
+
if (!existsSync7(LICENSE_PATH)) return null;
|
|
2185
|
+
return readFileSync5(LICENSE_PATH, "utf8").trim();
|
|
1866
2186
|
} catch {
|
|
1867
2187
|
return null;
|
|
1868
2188
|
}
|
|
1869
2189
|
}
|
|
1870
2190
|
function saveLicense(apiKey) {
|
|
1871
|
-
|
|
1872
|
-
|
|
2191
|
+
mkdirSync3(EXE_AI_DIR, { recursive: true });
|
|
2192
|
+
writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
1873
2193
|
}
|
|
1874
2194
|
async function verifyLicenseJwt(token) {
|
|
1875
2195
|
try {
|
|
@@ -1895,17 +2215,26 @@ async function verifyLicenseJwt(token) {
|
|
|
1895
2215
|
}
|
|
1896
2216
|
async function getCachedLicense() {
|
|
1897
2217
|
try {
|
|
1898
|
-
if (!
|
|
1899
|
-
const raw = JSON.parse(
|
|
2218
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2219
|
+
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
1900
2220
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
1901
2221
|
return await verifyLicenseJwt(raw.token);
|
|
1902
2222
|
} catch {
|
|
1903
2223
|
return null;
|
|
1904
2224
|
}
|
|
1905
2225
|
}
|
|
2226
|
+
function readCachedToken() {
|
|
2227
|
+
try {
|
|
2228
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2229
|
+
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2230
|
+
return typeof raw.token === "string" ? raw.token : null;
|
|
2231
|
+
} catch {
|
|
2232
|
+
return null;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
1906
2235
|
function cacheResponse(token) {
|
|
1907
2236
|
try {
|
|
1908
|
-
|
|
2237
|
+
writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
1909
2238
|
} catch {
|
|
1910
2239
|
}
|
|
1911
2240
|
}
|
|
@@ -1963,9 +2292,9 @@ async function checkLicense() {
|
|
|
1963
2292
|
let key = loadLicense();
|
|
1964
2293
|
if (!key) {
|
|
1965
2294
|
try {
|
|
1966
|
-
const configPath =
|
|
1967
|
-
if (
|
|
1968
|
-
const raw = JSON.parse(
|
|
2295
|
+
const configPath = path8.join(EXE_AI_DIR, "config.json");
|
|
2296
|
+
if (existsSync7(configPath)) {
|
|
2297
|
+
const raw = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
1969
2298
|
const cloud = raw.cloud;
|
|
1970
2299
|
if (cloud?.apiKey) {
|
|
1971
2300
|
key = cloud.apiKey;
|
|
@@ -1991,14 +2320,142 @@ function isFeatureAllowed(license, feature) {
|
|
|
1991
2320
|
return license.plan === "team" || license.plan === "agency" || license.plan === "enterprise";
|
|
1992
2321
|
}
|
|
1993
2322
|
}
|
|
1994
|
-
|
|
2323
|
+
function mirrorLicenseKey(apiKey) {
|
|
2324
|
+
const trimmed = apiKey.trim();
|
|
2325
|
+
if (!trimmed) return;
|
|
2326
|
+
saveLicense(trimmed);
|
|
2327
|
+
}
|
|
2328
|
+
async function assertVpsLicense(opts) {
|
|
2329
|
+
const env = opts?.env ?? process.env;
|
|
2330
|
+
const inProduction = env.NODE_ENV === "production";
|
|
2331
|
+
if (!opts?.force && !inProduction) {
|
|
2332
|
+
return { ...FREE_LICENSE, plan: "free" };
|
|
2333
|
+
}
|
|
2334
|
+
const envKey = env.EXE_LICENSE_KEY?.trim();
|
|
2335
|
+
if (envKey) {
|
|
2336
|
+
saveLicense(envKey);
|
|
2337
|
+
}
|
|
2338
|
+
const apiKey = envKey ?? loadLicense();
|
|
2339
|
+
if (!apiKey) {
|
|
2340
|
+
throw new Error(
|
|
2341
|
+
"License required: set EXE_LICENSE_KEY env var with your exe_sk_* key. Purchase at https://askexe.com. This VPS image refuses to boot without a valid license."
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
const deviceId = loadDeviceId();
|
|
2345
|
+
let backendResponse = null;
|
|
2346
|
+
let explicitRejection = false;
|
|
2347
|
+
let transientFailure = false;
|
|
2348
|
+
try {
|
|
2349
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2350
|
+
method: "POST",
|
|
2351
|
+
headers: { "Content-Type": "application/json" },
|
|
2352
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
2353
|
+
signal: AbortSignal.timeout(1e4)
|
|
2354
|
+
});
|
|
2355
|
+
if (res.ok) {
|
|
2356
|
+
backendResponse = await res.json();
|
|
2357
|
+
if (!backendResponse.valid) explicitRejection = true;
|
|
2358
|
+
} else if (res.status === 401 || res.status === 403) {
|
|
2359
|
+
explicitRejection = true;
|
|
2360
|
+
} else {
|
|
2361
|
+
transientFailure = true;
|
|
2362
|
+
}
|
|
2363
|
+
} catch {
|
|
2364
|
+
transientFailure = true;
|
|
2365
|
+
}
|
|
2366
|
+
if (backendResponse?.valid) {
|
|
2367
|
+
if (backendResponse.token) {
|
|
2368
|
+
cacheResponse(backendResponse.token);
|
|
2369
|
+
const verified = await verifyLicenseJwt(backendResponse.token);
|
|
2370
|
+
if (verified) return verified;
|
|
2371
|
+
}
|
|
2372
|
+
const limits = PLAN_LIMITS[backendResponse.plan] ?? PLAN_LIMITS.free;
|
|
2373
|
+
return {
|
|
2374
|
+
valid: true,
|
|
2375
|
+
plan: backendResponse.plan,
|
|
2376
|
+
email: backendResponse.email,
|
|
2377
|
+
expiresAt: backendResponse.expiresAt,
|
|
2378
|
+
deviceLimit: limits.devices,
|
|
2379
|
+
employeeLimit: limits.employees,
|
|
2380
|
+
memoryLimit: limits.memories
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
if (explicitRejection) {
|
|
2384
|
+
throw new Error(
|
|
2385
|
+
`License invalid or expired. Renew at https://askexe.com, then restart. Backend rejected key ending in ...${apiKey.slice(-4)}.`
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
if (!transientFailure) {
|
|
2389
|
+
throw new Error(
|
|
2390
|
+
"License validation failed: unknown backend state. Restore network connectivity to https://askexe.com/cloud and retry."
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
2393
|
+
const fresh = await getCachedLicense();
|
|
2394
|
+
if (fresh && fresh.valid) return fresh;
|
|
2395
|
+
const graceDays = opts?.offlineGraceDays ?? 7;
|
|
2396
|
+
const graceMs = graceDays * 24 * 60 * 60 * 1e3;
|
|
2397
|
+
try {
|
|
2398
|
+
const token = readCachedToken();
|
|
2399
|
+
if (token) {
|
|
2400
|
+
const payloadB64 = token.split(".")[1];
|
|
2401
|
+
if (payloadB64) {
|
|
2402
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
2403
|
+
const expMs = (payload.exp ?? 0) * 1e3;
|
|
2404
|
+
if (Date.now() < expMs + graceMs) {
|
|
2405
|
+
const key = await importSPKI(LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG);
|
|
2406
|
+
const { payload: verified } = await jwtVerify(token, key, {
|
|
2407
|
+
algorithms: [LICENSE_JWT_ALG],
|
|
2408
|
+
clockTolerance: graceDays * 24 * 60 * 60
|
|
2409
|
+
});
|
|
2410
|
+
const plan = verified.plan ?? "free";
|
|
2411
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
2412
|
+
return {
|
|
2413
|
+
valid: true,
|
|
2414
|
+
plan,
|
|
2415
|
+
email: verified.sub ?? "",
|
|
2416
|
+
expiresAt: verified.exp ? new Date(verified.exp * 1e3).toISOString() : null,
|
|
2417
|
+
deviceLimit: limits.devices,
|
|
2418
|
+
employeeLimit: limits.employees,
|
|
2419
|
+
memoryLimit: limits.memories
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
} catch {
|
|
2425
|
+
}
|
|
2426
|
+
throw new Error(
|
|
2427
|
+
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
2431
|
+
if (_revalTimer) return;
|
|
2432
|
+
_revalTimer = setInterval(async () => {
|
|
2433
|
+
try {
|
|
2434
|
+
const license = await checkLicense();
|
|
2435
|
+
if (!license.valid) {
|
|
2436
|
+
process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
|
|
2437
|
+
}
|
|
2438
|
+
} catch {
|
|
2439
|
+
}
|
|
2440
|
+
}, intervalMs);
|
|
2441
|
+
if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
|
|
2442
|
+
_revalTimer.unref();
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
function stopLicenseRevalidation() {
|
|
2446
|
+
if (_revalTimer) {
|
|
2447
|
+
clearInterval(_revalTimer);
|
|
2448
|
+
_revalTimer = null;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
|
|
1995
2452
|
var init_license = __esm({
|
|
1996
2453
|
"src/lib/license.ts"() {
|
|
1997
2454
|
"use strict";
|
|
1998
2455
|
init_config();
|
|
1999
|
-
LICENSE_PATH =
|
|
2000
|
-
CACHE_PATH =
|
|
2001
|
-
DEVICE_ID_PATH =
|
|
2456
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
2457
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
2458
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
2002
2459
|
API_BASE = "https://askexe.com/cloud";
|
|
2003
2460
|
RETRY_DELAY_MS = 500;
|
|
2004
2461
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -2023,6 +2480,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2023
2480
|
memoryLimit: 5e3
|
|
2024
2481
|
};
|
|
2025
2482
|
CACHE_MAX_AGE_MS = 36e5;
|
|
2483
|
+
_revalTimer = null;
|
|
2026
2484
|
}
|
|
2027
2485
|
});
|
|
2028
2486
|
|
|
@@ -2037,12 +2495,12 @@ __export(plan_limits_exports, {
|
|
|
2037
2495
|
countActiveMemories: () => countActiveMemories,
|
|
2038
2496
|
getLicenseSync: () => getLicenseSync
|
|
2039
2497
|
});
|
|
2040
|
-
import { readFileSync as
|
|
2041
|
-
import
|
|
2498
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
|
|
2499
|
+
import path9 from "path";
|
|
2042
2500
|
function getLicenseSync() {
|
|
2043
2501
|
try {
|
|
2044
|
-
if (!
|
|
2045
|
-
const raw = JSON.parse(
|
|
2502
|
+
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
2503
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
|
|
2046
2504
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2047
2505
|
const parts = raw.token.split(".");
|
|
2048
2506
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2109,8 +2567,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2109
2567
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
2110
2568
|
let count = 0;
|
|
2111
2569
|
try {
|
|
2112
|
-
if (
|
|
2113
|
-
const raw =
|
|
2570
|
+
if (existsSync8(filePath)) {
|
|
2571
|
+
const raw = readFileSync6(filePath, "utf8");
|
|
2114
2572
|
const employees = JSON.parse(raw);
|
|
2115
2573
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2116
2574
|
}
|
|
@@ -2147,7 +2605,60 @@ var init_plan_limits = __esm({
|
|
|
2147
2605
|
this.name = "PlanLimitError";
|
|
2148
2606
|
}
|
|
2149
2607
|
};
|
|
2150
|
-
CACHE_PATH2 =
|
|
2608
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
|
|
2612
|
+
// src/lib/tmux-routing.ts
|
|
2613
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync9, appendFileSync } from "fs";
|
|
2614
|
+
import path10 from "path";
|
|
2615
|
+
import os6 from "os";
|
|
2616
|
+
import { fileURLToPath } from "url";
|
|
2617
|
+
function getMySession() {
|
|
2618
|
+
return getTransport().getMySession();
|
|
2619
|
+
}
|
|
2620
|
+
function extractRootExe(name) {
|
|
2621
|
+
const match = name.match(/(exe\d+)$/);
|
|
2622
|
+
return match?.[1] ?? null;
|
|
2623
|
+
}
|
|
2624
|
+
function getParentExe(sessionKey) {
|
|
2625
|
+
try {
|
|
2626
|
+
const data = JSON.parse(readFileSync7(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2627
|
+
return data.parentExe || null;
|
|
2628
|
+
} catch {
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
function resolveExeSession() {
|
|
2633
|
+
const mySession = getMySession();
|
|
2634
|
+
if (!mySession) return null;
|
|
2635
|
+
try {
|
|
2636
|
+
const key = getSessionKey();
|
|
2637
|
+
const parentExe = getParentExe(key);
|
|
2638
|
+
if (parentExe) {
|
|
2639
|
+
return extractRootExe(parentExe) ?? parentExe;
|
|
2640
|
+
}
|
|
2641
|
+
} catch {
|
|
2642
|
+
}
|
|
2643
|
+
return extractRootExe(mySession) ?? mySession;
|
|
2644
|
+
}
|
|
2645
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
2646
|
+
var init_tmux_routing = __esm({
|
|
2647
|
+
"src/lib/tmux-routing.ts"() {
|
|
2648
|
+
"use strict";
|
|
2649
|
+
init_session_registry();
|
|
2650
|
+
init_session_key();
|
|
2651
|
+
init_transport();
|
|
2652
|
+
init_cc_agent_support();
|
|
2653
|
+
init_mcp_prefix();
|
|
2654
|
+
init_provider_table();
|
|
2655
|
+
init_intercom_queue();
|
|
2656
|
+
init_plan_limits();
|
|
2657
|
+
SPAWN_LOCK_DIR = path10.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
2658
|
+
SESSION_CACHE = path10.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2659
|
+
INTERCOM_LOG2 = path10.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2660
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2661
|
+
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2151
2662
|
}
|
|
2152
2663
|
});
|
|
2153
2664
|
|
|
@@ -2155,9 +2666,9 @@ var init_plan_limits = __esm({
|
|
|
2155
2666
|
import net from "net";
|
|
2156
2667
|
import { spawn } from "child_process";
|
|
2157
2668
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2158
|
-
import { existsSync as
|
|
2159
|
-
import
|
|
2160
|
-
import { fileURLToPath } from "url";
|
|
2669
|
+
import { existsSync as existsSync10, unlinkSync as unlinkSync2, readFileSync as readFileSync8, openSync, closeSync, statSync } from "fs";
|
|
2670
|
+
import path11 from "path";
|
|
2671
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2161
2672
|
function handleData(chunk) {
|
|
2162
2673
|
_buffer += chunk.toString();
|
|
2163
2674
|
if (_buffer.length > MAX_BUFFER) {
|
|
@@ -2182,9 +2693,9 @@ function handleData(chunk) {
|
|
|
2182
2693
|
}
|
|
2183
2694
|
}
|
|
2184
2695
|
function cleanupStaleFiles() {
|
|
2185
|
-
if (
|
|
2696
|
+
if (existsSync10(PID_PATH)) {
|
|
2186
2697
|
try {
|
|
2187
|
-
const pid = parseInt(
|
|
2698
|
+
const pid = parseInt(readFileSync8(PID_PATH, "utf8").trim(), 10);
|
|
2188
2699
|
if (pid > 0) {
|
|
2189
2700
|
try {
|
|
2190
2701
|
process.kill(pid, 0);
|
|
@@ -2205,11 +2716,11 @@ function cleanupStaleFiles() {
|
|
|
2205
2716
|
}
|
|
2206
2717
|
}
|
|
2207
2718
|
function findPackageRoot() {
|
|
2208
|
-
let dir =
|
|
2209
|
-
const { root } =
|
|
2719
|
+
let dir = path11.dirname(fileURLToPath2(import.meta.url));
|
|
2720
|
+
const { root } = path11.parse(dir);
|
|
2210
2721
|
while (dir !== root) {
|
|
2211
|
-
if (
|
|
2212
|
-
dir =
|
|
2722
|
+
if (existsSync10(path11.join(dir, "package.json"))) return dir;
|
|
2723
|
+
dir = path11.dirname(dir);
|
|
2213
2724
|
}
|
|
2214
2725
|
return null;
|
|
2215
2726
|
}
|
|
@@ -2219,8 +2730,8 @@ function spawnDaemon() {
|
|
|
2219
2730
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
2220
2731
|
return;
|
|
2221
2732
|
}
|
|
2222
|
-
const daemonPath =
|
|
2223
|
-
if (!
|
|
2733
|
+
const daemonPath = path11.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
2734
|
+
if (!existsSync10(daemonPath)) {
|
|
2224
2735
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
2225
2736
|
`);
|
|
2226
2737
|
return;
|
|
@@ -2228,7 +2739,7 @@ function spawnDaemon() {
|
|
|
2228
2739
|
const resolvedPath = daemonPath;
|
|
2229
2740
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
2230
2741
|
`);
|
|
2231
|
-
const logPath =
|
|
2742
|
+
const logPath = path11.join(path11.dirname(SOCKET_PATH), "exed.log");
|
|
2232
2743
|
let stderrFd = "ignore";
|
|
2233
2744
|
try {
|
|
2234
2745
|
stderrFd = openSync(logPath, "a");
|
|
@@ -2390,9 +2901,9 @@ async function pingDaemon() {
|
|
|
2390
2901
|
}
|
|
2391
2902
|
function killAndRespawnDaemon() {
|
|
2392
2903
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
2393
|
-
if (
|
|
2904
|
+
if (existsSync10(PID_PATH)) {
|
|
2394
2905
|
try {
|
|
2395
|
-
const pid = parseInt(
|
|
2906
|
+
const pid = parseInt(readFileSync8(PID_PATH, "utf8").trim(), 10);
|
|
2396
2907
|
if (pid > 0) {
|
|
2397
2908
|
try {
|
|
2398
2909
|
process.kill(pid, "SIGKILL");
|
|
@@ -2476,9 +2987,9 @@ var init_exe_daemon_client = __esm({
|
|
|
2476
2987
|
"src/lib/exe-daemon-client.ts"() {
|
|
2477
2988
|
"use strict";
|
|
2478
2989
|
init_config();
|
|
2479
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
2480
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
2481
|
-
SPAWN_LOCK_PATH =
|
|
2990
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path11.join(EXE_AI_DIR, "exed.sock");
|
|
2991
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path11.join(EXE_AI_DIR, "exed.pid");
|
|
2992
|
+
SPAWN_LOCK_PATH = path11.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
2482
2993
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
2483
2994
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
2484
2995
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -2529,10 +3040,10 @@ async function disposeEmbedder() {
|
|
|
2529
3040
|
async function embedDirect(text) {
|
|
2530
3041
|
const llamaCpp = await import("node-llama-cpp");
|
|
2531
3042
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2532
|
-
const { existsSync:
|
|
2533
|
-
const
|
|
2534
|
-
const modelPath =
|
|
2535
|
-
if (!
|
|
3043
|
+
const { existsSync: existsSync13 } = await import("fs");
|
|
3044
|
+
const path15 = await import("path");
|
|
3045
|
+
const modelPath = path15.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
3046
|
+
if (!existsSync13(modelPath)) {
|
|
2536
3047
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2537
3048
|
}
|
|
2538
3049
|
const llama = await llamaCpp.getLlama();
|
|
@@ -2568,11 +3079,11 @@ __export(worker_gate_exports, {
|
|
|
2568
3079
|
registerWorkerPid: () => registerWorkerPid,
|
|
2569
3080
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
2570
3081
|
});
|
|
2571
|
-
import { readdirSync as readdirSync3, writeFileSync as
|
|
2572
|
-
import
|
|
3082
|
+
import { readdirSync as readdirSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, mkdirSync as mkdirSync5 } from "fs";
|
|
3083
|
+
import path12 from "path";
|
|
2573
3084
|
function tryAcquireWorkerSlot() {
|
|
2574
3085
|
try {
|
|
2575
|
-
|
|
3086
|
+
mkdirSync5(WORKER_PID_DIR, { recursive: true });
|
|
2576
3087
|
const files = readdirSync3(WORKER_PID_DIR);
|
|
2577
3088
|
let alive = 0;
|
|
2578
3089
|
for (const f of files) {
|
|
@@ -2585,7 +3096,7 @@ function tryAcquireWorkerSlot() {
|
|
|
2585
3096
|
alive++;
|
|
2586
3097
|
} catch {
|
|
2587
3098
|
try {
|
|
2588
|
-
unlinkSync3(
|
|
3099
|
+
unlinkSync3(path12.join(WORKER_PID_DIR, f));
|
|
2589
3100
|
} catch {
|
|
2590
3101
|
}
|
|
2591
3102
|
}
|
|
@@ -2597,14 +3108,14 @@ function tryAcquireWorkerSlot() {
|
|
|
2597
3108
|
}
|
|
2598
3109
|
function registerWorkerPid(pid) {
|
|
2599
3110
|
try {
|
|
2600
|
-
|
|
2601
|
-
|
|
3111
|
+
mkdirSync5(WORKER_PID_DIR, { recursive: true });
|
|
3112
|
+
writeFileSync4(path12.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
2602
3113
|
} catch {
|
|
2603
3114
|
}
|
|
2604
3115
|
}
|
|
2605
3116
|
function cleanupWorkerPid() {
|
|
2606
3117
|
try {
|
|
2607
|
-
unlinkSync3(
|
|
3118
|
+
unlinkSync3(path12.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
2608
3119
|
} catch {
|
|
2609
3120
|
}
|
|
2610
3121
|
}
|
|
@@ -2613,7 +3124,7 @@ var init_worker_gate = __esm({
|
|
|
2613
3124
|
"src/lib/worker-gate.ts"() {
|
|
2614
3125
|
"use strict";
|
|
2615
3126
|
init_config();
|
|
2616
|
-
WORKER_PID_DIR =
|
|
3127
|
+
WORKER_PID_DIR = path12.join(EXE_AI_DIR, "worker-pids");
|
|
2617
3128
|
MAX_CONCURRENT_WORKERS = 3;
|
|
2618
3129
|
}
|
|
2619
3130
|
});
|
|
@@ -2725,14 +3236,14 @@ __export(cloud_sync_exports, {
|
|
|
2725
3236
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
2726
3237
|
recordRosterDeletion: () => recordRosterDeletion
|
|
2727
3238
|
});
|
|
2728
|
-
import { readFileSync as
|
|
3239
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync11, readdirSync as readdirSync4, mkdirSync as mkdirSync6, appendFileSync as appendFileSync2, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
2729
3240
|
import crypto4 from "crypto";
|
|
2730
|
-
import
|
|
3241
|
+
import path13 from "path";
|
|
2731
3242
|
import { homedir } from "os";
|
|
2732
3243
|
function logError(msg) {
|
|
2733
3244
|
try {
|
|
2734
|
-
const logPath =
|
|
2735
|
-
|
|
3245
|
+
const logPath = path13.join(homedir(), ".exe-os", "workers.log");
|
|
3246
|
+
appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
2736
3247
|
`);
|
|
2737
3248
|
} catch {
|
|
2738
3249
|
}
|
|
@@ -2741,18 +3252,18 @@ async function withRosterLock(fn) {
|
|
|
2741
3252
|
try {
|
|
2742
3253
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
2743
3254
|
closeSync2(fd);
|
|
2744
|
-
|
|
3255
|
+
writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
|
|
2745
3256
|
} catch (err) {
|
|
2746
3257
|
if (err.code === "EEXIST") {
|
|
2747
3258
|
try {
|
|
2748
|
-
const ts = parseInt(
|
|
3259
|
+
const ts = parseInt(readFileSync9(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
2749
3260
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
2750
3261
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
2751
3262
|
}
|
|
2752
3263
|
unlinkSync4(ROSTER_LOCK_PATH);
|
|
2753
3264
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
2754
3265
|
closeSync2(fd);
|
|
2755
|
-
|
|
3266
|
+
writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
|
|
2756
3267
|
} catch (retryErr) {
|
|
2757
3268
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
2758
3269
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -3059,48 +3570,48 @@ async function cloudSync(config) {
|
|
|
3059
3570
|
function recordRosterDeletion(name) {
|
|
3060
3571
|
let deletions = [];
|
|
3061
3572
|
try {
|
|
3062
|
-
if (
|
|
3063
|
-
deletions = JSON.parse(
|
|
3573
|
+
if (existsSync11(ROSTER_DELETIONS_PATH)) {
|
|
3574
|
+
deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
3064
3575
|
}
|
|
3065
3576
|
} catch {
|
|
3066
3577
|
}
|
|
3067
3578
|
if (!deletions.includes(name)) deletions.push(name);
|
|
3068
|
-
|
|
3579
|
+
writeFileSync5(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
3069
3580
|
}
|
|
3070
3581
|
function consumeRosterDeletions() {
|
|
3071
3582
|
try {
|
|
3072
|
-
if (!
|
|
3073
|
-
const deletions = JSON.parse(
|
|
3074
|
-
|
|
3583
|
+
if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
|
|
3584
|
+
const deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
3585
|
+
writeFileSync5(ROSTER_DELETIONS_PATH, "[]");
|
|
3075
3586
|
return deletions;
|
|
3076
3587
|
} catch {
|
|
3077
3588
|
return [];
|
|
3078
3589
|
}
|
|
3079
3590
|
}
|
|
3080
3591
|
function buildRosterBlob(paths) {
|
|
3081
|
-
const rosterPath = paths?.rosterPath ??
|
|
3082
|
-
const identityDir = paths?.identityDir ??
|
|
3083
|
-
const configPath = paths?.configPath ??
|
|
3592
|
+
const rosterPath = paths?.rosterPath ?? path13.join(EXE_AI_DIR, "exe-employees.json");
|
|
3593
|
+
const identityDir = paths?.identityDir ?? path13.join(EXE_AI_DIR, "identity");
|
|
3594
|
+
const configPath = paths?.configPath ?? path13.join(EXE_AI_DIR, "config.json");
|
|
3084
3595
|
let roster = [];
|
|
3085
|
-
if (
|
|
3596
|
+
if (existsSync11(rosterPath)) {
|
|
3086
3597
|
try {
|
|
3087
|
-
roster = JSON.parse(
|
|
3598
|
+
roster = JSON.parse(readFileSync9(rosterPath, "utf-8"));
|
|
3088
3599
|
} catch {
|
|
3089
3600
|
}
|
|
3090
3601
|
}
|
|
3091
3602
|
const identities = {};
|
|
3092
|
-
if (
|
|
3603
|
+
if (existsSync11(identityDir)) {
|
|
3093
3604
|
for (const file of readdirSync4(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
3094
3605
|
try {
|
|
3095
|
-
identities[file] =
|
|
3606
|
+
identities[file] = readFileSync9(path13.join(identityDir, file), "utf-8");
|
|
3096
3607
|
} catch {
|
|
3097
3608
|
}
|
|
3098
3609
|
}
|
|
3099
3610
|
}
|
|
3100
3611
|
let config;
|
|
3101
|
-
if (
|
|
3612
|
+
if (existsSync11(configPath)) {
|
|
3102
3613
|
try {
|
|
3103
|
-
config = JSON.parse(
|
|
3614
|
+
config = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
3104
3615
|
} catch {
|
|
3105
3616
|
}
|
|
3106
3617
|
}
|
|
@@ -3176,23 +3687,23 @@ async function cloudPullRoster(config) {
|
|
|
3176
3687
|
}
|
|
3177
3688
|
}
|
|
3178
3689
|
function mergeConfig(remoteConfig, configPath) {
|
|
3179
|
-
const cfgPath = configPath ??
|
|
3690
|
+
const cfgPath = configPath ?? path13.join(EXE_AI_DIR, "config.json");
|
|
3180
3691
|
let local = {};
|
|
3181
|
-
if (
|
|
3692
|
+
if (existsSync11(cfgPath)) {
|
|
3182
3693
|
try {
|
|
3183
|
-
local = JSON.parse(
|
|
3694
|
+
local = JSON.parse(readFileSync9(cfgPath, "utf-8"));
|
|
3184
3695
|
} catch {
|
|
3185
3696
|
}
|
|
3186
3697
|
}
|
|
3187
3698
|
const merged = { ...remoteConfig, ...local };
|
|
3188
|
-
const dir =
|
|
3189
|
-
if (!
|
|
3190
|
-
|
|
3699
|
+
const dir = path13.dirname(cfgPath);
|
|
3700
|
+
if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
|
|
3701
|
+
writeFileSync5(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
3191
3702
|
}
|
|
3192
3703
|
async function mergeRosterFromRemote(remote, paths) {
|
|
3193
3704
|
return withRosterLock(async () => {
|
|
3194
3705
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
3195
|
-
const identityDir = paths?.identityDir ??
|
|
3706
|
+
const identityDir = paths?.identityDir ?? path13.join(EXE_AI_DIR, "identity");
|
|
3196
3707
|
const localEmployees = await loadEmployees(rosterPath);
|
|
3197
3708
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
3198
3709
|
let added = 0;
|
|
@@ -3202,10 +3713,10 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
3202
3713
|
localNames.add(remoteEmp.name);
|
|
3203
3714
|
added++;
|
|
3204
3715
|
if (remote.identities[`${remoteEmp.name}.md`]) {
|
|
3205
|
-
if (!
|
|
3206
|
-
const idPath =
|
|
3207
|
-
if (!
|
|
3208
|
-
|
|
3716
|
+
if (!existsSync11(identityDir)) mkdirSync6(identityDir, { recursive: true });
|
|
3717
|
+
const idPath = path13.join(identityDir, `${remoteEmp.name}.md`);
|
|
3718
|
+
if (!existsSync11(idPath)) {
|
|
3719
|
+
writeFileSync5(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
|
|
3209
3720
|
}
|
|
3210
3721
|
}
|
|
3211
3722
|
try {
|
|
@@ -3665,9 +4176,9 @@ var init_cloud_sync = __esm({
|
|
|
3665
4176
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
3666
4177
|
FETCH_TIMEOUT_MS = 3e4;
|
|
3667
4178
|
PUSH_BATCH_SIZE = 5e3;
|
|
3668
|
-
ROSTER_LOCK_PATH =
|
|
4179
|
+
ROSTER_LOCK_PATH = path13.join(EXE_AI_DIR, "roster-merge.lock");
|
|
3669
4180
|
LOCK_STALE_MS = 3e4;
|
|
3670
|
-
ROSTER_DELETIONS_PATH =
|
|
4181
|
+
ROSTER_DELETIONS_PATH = path13.join(EXE_AI_DIR, "roster-deletions.json");
|
|
3671
4182
|
}
|
|
3672
4183
|
});
|
|
3673
4184
|
|
|
@@ -3676,57 +4187,7 @@ init_memory();
|
|
|
3676
4187
|
init_database();
|
|
3677
4188
|
init_keychain();
|
|
3678
4189
|
init_config();
|
|
3679
|
-
|
|
3680
|
-
// src/lib/state-bus.ts
|
|
3681
|
-
var StateBus = class {
|
|
3682
|
-
handlers = /* @__PURE__ */ new Map();
|
|
3683
|
-
globalHandlers = /* @__PURE__ */ new Set();
|
|
3684
|
-
/** Emit an event to all subscribers */
|
|
3685
|
-
emit(event) {
|
|
3686
|
-
const typeHandlers = this.handlers.get(event.type);
|
|
3687
|
-
if (typeHandlers) {
|
|
3688
|
-
for (const handler of typeHandlers) {
|
|
3689
|
-
try {
|
|
3690
|
-
handler(event);
|
|
3691
|
-
} catch {
|
|
3692
|
-
}
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3695
|
-
for (const handler of this.globalHandlers) {
|
|
3696
|
-
try {
|
|
3697
|
-
handler(event);
|
|
3698
|
-
} catch {
|
|
3699
|
-
}
|
|
3700
|
-
}
|
|
3701
|
-
}
|
|
3702
|
-
/** Subscribe to a specific event type */
|
|
3703
|
-
on(type, handler) {
|
|
3704
|
-
if (!this.handlers.has(type)) {
|
|
3705
|
-
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
3706
|
-
}
|
|
3707
|
-
this.handlers.get(type).add(handler);
|
|
3708
|
-
}
|
|
3709
|
-
/** Subscribe to ALL events */
|
|
3710
|
-
onAny(handler) {
|
|
3711
|
-
this.globalHandlers.add(handler);
|
|
3712
|
-
}
|
|
3713
|
-
/** Unsubscribe from a specific event type */
|
|
3714
|
-
off(type, handler) {
|
|
3715
|
-
this.handlers.get(type)?.delete(handler);
|
|
3716
|
-
}
|
|
3717
|
-
/** Unsubscribe from ALL events */
|
|
3718
|
-
offAny(handler) {
|
|
3719
|
-
this.globalHandlers.delete(handler);
|
|
3720
|
-
}
|
|
3721
|
-
/** Remove all listeners */
|
|
3722
|
-
clear() {
|
|
3723
|
-
this.handlers.clear();
|
|
3724
|
-
this.globalHandlers.clear();
|
|
3725
|
-
}
|
|
3726
|
-
};
|
|
3727
|
-
var orgBus = new StateBus();
|
|
3728
|
-
|
|
3729
|
-
// src/lib/store.ts
|
|
4190
|
+
init_state_bus();
|
|
3730
4191
|
var INIT_MAX_RETRIES = 3;
|
|
3731
4192
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
3732
4193
|
function isBusyError2(err) {
|
|
@@ -4005,49 +4466,32 @@ function vectorToBlob(vector) {
|
|
|
4005
4466
|
|
|
4006
4467
|
// src/adapters/claude/hooks/summary-worker.ts
|
|
4007
4468
|
init_database();
|
|
4469
|
+
init_notifications();
|
|
4008
4470
|
import crypto5 from "crypto";
|
|
4471
|
+
import { execSync as execSync4 } from "child_process";
|
|
4472
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, openSync as openSync3, closeSync as closeSync3 } from "fs";
|
|
4473
|
+
import path14 from "path";
|
|
4009
4474
|
|
|
4010
|
-
// src/lib/
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
import path4 from "path";
|
|
4014
|
-
import os3 from "os";
|
|
4015
|
-
import {
|
|
4016
|
-
readFileSync as readFileSync2,
|
|
4017
|
-
readdirSync as readdirSync2,
|
|
4018
|
-
unlinkSync,
|
|
4019
|
-
existsSync as existsSync4,
|
|
4020
|
-
rmdirSync
|
|
4021
|
-
} from "fs";
|
|
4022
|
-
async function writeNotification(notification) {
|
|
4475
|
+
// src/lib/task-scope.ts
|
|
4476
|
+
init_tmux_routing();
|
|
4477
|
+
function getCurrentSessionScope() {
|
|
4023
4478
|
try {
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
await client.execute({
|
|
4028
|
-
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
4029
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
4030
|
-
args: [
|
|
4031
|
-
id,
|
|
4032
|
-
notification.agentId,
|
|
4033
|
-
notification.agentRole,
|
|
4034
|
-
notification.event,
|
|
4035
|
-
notification.project,
|
|
4036
|
-
notification.summary,
|
|
4037
|
-
notification.taskFile ?? null,
|
|
4038
|
-
now
|
|
4039
|
-
]
|
|
4040
|
-
});
|
|
4041
|
-
} catch (err) {
|
|
4042
|
-
process.stderr.write(`[notifications] WRITE FAILED: ${err instanceof Error ? err.message : String(err)}
|
|
4043
|
-
`);
|
|
4479
|
+
return resolveExeSession();
|
|
4480
|
+
} catch {
|
|
4481
|
+
return null;
|
|
4044
4482
|
}
|
|
4045
4483
|
}
|
|
4484
|
+
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
4485
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
4486
|
+
if (!scope) return { sql: "", args: [] };
|
|
4487
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
4488
|
+
return {
|
|
4489
|
+
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
4490
|
+
args: [scope]
|
|
4491
|
+
};
|
|
4492
|
+
}
|
|
4046
4493
|
|
|
4047
4494
|
// src/adapters/claude/hooks/summary-worker.ts
|
|
4048
|
-
import { execSync as execSync2 } from "child_process";
|
|
4049
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, openSync as openSync3, closeSync as closeSync3 } from "fs";
|
|
4050
|
-
import path11 from "path";
|
|
4051
4495
|
async function main() {
|
|
4052
4496
|
const agentId = process.env.AGENT_ID ?? "default";
|
|
4053
4497
|
const agentRole = process.env.AGENT_ROLE ?? "employee";
|
|
@@ -4171,20 +4615,20 @@ async function main() {
|
|
|
4171
4615
|
}
|
|
4172
4616
|
try {
|
|
4173
4617
|
const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4174
|
-
const flagPath =
|
|
4175
|
-
if (
|
|
4618
|
+
const flagPath = path14.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
|
|
4619
|
+
if (existsSync12(flagPath)) {
|
|
4176
4620
|
const { tryAcquireWorkerSlot: tryAcquireWorkerSlot2, registerWorkerPid: registerWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
4177
4621
|
if (!tryAcquireWorkerSlot2()) {
|
|
4178
4622
|
process.stderr.write("[summary-worker] Backfill needed but worker gate full \u2014 skipping\n");
|
|
4179
4623
|
} else {
|
|
4180
4624
|
const { spawn: spawn2 } = await import("child_process");
|
|
4181
|
-
const { fileURLToPath:
|
|
4182
|
-
const thisFile =
|
|
4183
|
-
const backfillPath =
|
|
4184
|
-
if (
|
|
4625
|
+
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
4626
|
+
const thisFile = fileURLToPath3(import.meta.url);
|
|
4627
|
+
const backfillPath = path14.resolve(path14.dirname(thisFile), "backfill-vectors.js");
|
|
4628
|
+
if (existsSync12(backfillPath)) {
|
|
4185
4629
|
const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4186
|
-
const bLogPath =
|
|
4187
|
-
|
|
4630
|
+
const bLogPath = path14.join(exeDir2, "workers.log");
|
|
4631
|
+
mkdirSync7(path14.dirname(bLogPath), { recursive: true });
|
|
4188
4632
|
const bLogFd = openSync3(bLogPath, "a");
|
|
4189
4633
|
const child = spawn2(process.execPath, [backfillPath], {
|
|
4190
4634
|
detached: true,
|
|
@@ -4210,26 +4654,33 @@ async function main() {
|
|
|
4210
4654
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4211
4655
|
const cfg = await loadConfig2();
|
|
4212
4656
|
if (cfg.cloud?.apiKey) {
|
|
4213
|
-
const {
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4657
|
+
const { checkLicense: checkLicense2, isFeatureAllowed: isFeatureAllowed2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
4658
|
+
const license = await checkLicense2();
|
|
4659
|
+
if (!isFeatureAllowed2(license, "cloud_sync")) {
|
|
4660
|
+
} else {
|
|
4661
|
+
const { initSyncCrypto: initSyncCrypto2, isSyncCryptoInitialized: isSyncCryptoInitialized2 } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
|
|
4662
|
+
if (!isSyncCryptoInitialized2()) {
|
|
4663
|
+
const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
|
|
4664
|
+
const mk = await getMasterKey2();
|
|
4665
|
+
if (mk) initSyncCrypto2(mk);
|
|
4666
|
+
}
|
|
4667
|
+
const { cloudSync: cloudSync2 } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
|
|
4668
|
+
await cloudSync2({ apiKey: cfg.cloud.apiKey, endpoint: cfg.cloud.endpoint });
|
|
4218
4669
|
}
|
|
4219
|
-
const { cloudSync: cloudSync2 } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
|
|
4220
|
-
await cloudSync2({ apiKey: cfg.cloud.apiKey, endpoint: cfg.cloud.endpoint });
|
|
4221
4670
|
}
|
|
4222
4671
|
} catch (err) {
|
|
4223
4672
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4224
|
-
|
|
4225
|
-
|
|
4673
|
+
if (!msg.includes("requires a paid plan")) {
|
|
4674
|
+
process.stderr.write(`[summary-worker] cloud sync failed: ${msg}
|
|
4226
4675
|
`);
|
|
4676
|
+
}
|
|
4227
4677
|
}
|
|
4228
4678
|
if (agentId !== "exe" && agentId !== "default") {
|
|
4229
4679
|
try {
|
|
4680
|
+
const swScope = sessionScopeFilter();
|
|
4230
4681
|
const inProgressResult = await client.execute({
|
|
4231
|
-
sql:
|
|
4232
|
-
args: [agentId]
|
|
4682
|
+
sql: `SELECT id, title, task_file FROM tasks WHERE assigned_to = ? AND status = 'in_progress'${swScope.sql}`,
|
|
4683
|
+
args: [agentId, ...swScope.args]
|
|
4233
4684
|
});
|
|
4234
4685
|
for (const taskRow of inProgressResult.rows) {
|
|
4235
4686
|
const taskFile = String(taskRow.task_file);
|
|
@@ -4237,7 +4688,7 @@ async function main() {
|
|
|
4237
4688
|
const taskTitle = String(taskRow.title);
|
|
4238
4689
|
let lastCommit = "";
|
|
4239
4690
|
try {
|
|
4240
|
-
lastCommit =
|
|
4691
|
+
lastCommit = execSync4("git log --oneline -1 --since='30 minutes ago'", {
|
|
4241
4692
|
encoding: "utf8",
|
|
4242
4693
|
timeout: 5e3
|
|
4243
4694
|
}).trim();
|