@askexenow/exe-os 0.9.295 → 0.9.296
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/deploy/compose/cloudflared/config.yml.example +14 -9
- package/deploy/compose/docker-compose.yml +86 -8
- package/deploy/compose/sso-edge/default.conf.template +87 -0
- package/deploy/compose/sso-edge/entrypoint.sh +23 -0
- package/deploy/compose/sso-edge/sso-redirect.conf +63 -0
- package/deploy/stack-manifests/v0.9.json +1 -1
- package/dist/active-agent-AFX2FODG.js +28 -0
- package/dist/active-agent-E2IJA7YX.js +27 -0
- package/dist/agentic-ontology-A2YUZK5O.js +25 -0
- package/dist/assets/com.askexe.exed.plist +4 -1
- package/dist/backfill-metadata-OC7EOD5U.js +600 -0
- package/dist/behaviors-H5ZOVHDH.js +46 -0
- package/dist/bin/agentic-ontology-backfill.js +5 -5
- package/dist/bin/agentic-reflection-backfill.js +6 -6
- package/dist/bin/agentic-semantic-label.js +5 -5
- package/dist/bin/backfill-conversations.js +6 -6
- package/dist/bin/backfill-responses.js +6 -6
- package/dist/bin/backfill-vectors.js +8 -8
- package/dist/bin/bulk-sync-postgres.js +7 -7
- package/dist/bin/cc-doctor.js +4 -4
- package/dist/bin/cleanup-stale-review-tasks.js +11 -11
- package/dist/bin/cli.js +16 -16
- package/dist/bin/deferred-daemon-restart.js +1 -1
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +8 -8
- package/dist/bin/exe-boot.js +21 -18
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +7 -7
- package/dist/bin/exe-dispatch.js +11 -11
- package/dist/bin/exe-doctor.js +3 -2
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +7 -7
- package/dist/bin/exe-healthcheck.js +6 -4
- package/dist/bin/exe-heartbeat.js +11 -11
- package/dist/bin/exe-kill.js +14 -14
- package/dist/bin/exe-launch-agent.js +18 -18
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +12 -12
- package/dist/bin/exe-pending-notifications.js +11 -11
- package/dist/bin/exe-pending-reviews.js +11 -11
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +13 -13
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +16 -16
- package/dist/bin/exe-settings.js +39 -9
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +12 -12
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/git-sweep.js +12 -12
- package/dist/bin/graph-backfill.js +4 -4
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/import-history.js +7 -7
- package/dist/bin/install-launchd.js +13 -6
- package/dist/bin/install.js +26 -14
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/scan-tasks.js +11 -11
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/bin/stack-update.js +2 -2
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/capability-cards-4USI7CUW.js +89 -0
- package/dist/capacity-monitor-WLCBTEYR.js +51 -0
- package/dist/catchup-brief-ZR3NX6LZ.js +175 -0
- package/dist/chunk-22TVSRQQ.js +226 -0
- package/dist/chunk-2E43UXRH.js +395 -0
- package/dist/chunk-2PIGT6UJ.js +460 -0
- package/dist/chunk-3XTMW2MZ.js +535 -0
- package/dist/chunk-465PQFTH.js +262 -0
- package/dist/chunk-5CCXU2AW.js +129 -0
- package/dist/chunk-5D6MPWR7.js +1094 -0
- package/dist/chunk-5Q4MR6SL.js +123 -0
- package/dist/chunk-6327RBWR.js +345 -0
- package/dist/chunk-6MZZREZY.js +199 -0
- package/dist/chunk-7DI2Q4O5.js +1186 -0
- package/dist/chunk-7PW5VNIY.js +122 -0
- package/dist/chunk-7T7Y56HW.js +43 -0
- package/dist/chunk-7UHCWCLT.js +128 -0
- package/dist/chunk-A2ZUMF6L.js +1350 -0
- package/dist/chunk-AKV44JEH.js +185 -0
- package/dist/chunk-ANHWGX5N.js +735 -0
- package/dist/chunk-BQ3P4TKD.js +97 -0
- package/dist/chunk-BUZMT3KZ.js +604 -0
- package/dist/chunk-C2SBESBO.js +210 -0
- package/dist/chunk-CLSXZUZW.js +51 -0
- package/dist/chunk-CONHLVAR.js +1079 -0
- package/dist/chunk-D3WTZPFX.js +456 -0
- package/dist/chunk-DE6SOIYL.js +197 -0
- package/dist/chunk-EIVNMA3Q.js +284 -0
- package/dist/chunk-EJIF4FNT.js +12 -0
- package/dist/chunk-FDFOW564.js +171 -0
- package/dist/chunk-GZUBJ5EC.js +127 -0
- package/dist/chunk-HGZITN22.js +105 -0
- package/dist/chunk-HSRKDU6X.js +362 -0
- package/dist/chunk-IIEN2PHV.js +85 -0
- package/dist/chunk-JQ56VLMM.js +567 -0
- package/dist/chunk-JVHHXRFY.js +280 -0
- package/dist/chunk-JXCXGZ3S.js +55 -0
- package/dist/chunk-K5ZO532Q.js +4388 -0
- package/dist/chunk-K6CAAMXF.js +97 -0
- package/dist/chunk-KA26YTNU.js +81 -0
- package/dist/chunk-KMUW5C3R.js +381 -0
- package/dist/chunk-KOO3J5PV.js +20 -0
- package/dist/chunk-LSV7OFIH.js +290 -0
- package/dist/chunk-LSVFDVNY.js +1158 -0
- package/dist/chunk-LXDQTW32.js +230 -0
- package/dist/chunk-MEP7OUVZ.js +181 -0
- package/dist/chunk-MN2B2LKS.js +240 -0
- package/dist/chunk-N2EAYPYQ.js +1352 -0
- package/dist/chunk-N7I2A667.js +70 -0
- package/dist/chunk-NLZHVIOP.js +630 -0
- package/dist/chunk-NUH5TRZL.js +227 -0
- package/dist/chunk-OAHEIH3G.js +167 -0
- package/dist/chunk-OBHRQGCK.js +58 -0
- package/dist/chunk-ODFA7B2V.js +54 -0
- package/dist/chunk-OSNUP45F.js +731 -0
- package/dist/chunk-OTPRHBTO.js +33 -0
- package/dist/chunk-P6MUA4QU.js +157 -0
- package/dist/chunk-PGIOFKSK.js +2093 -0
- package/dist/chunk-PSE7VHWK.js +50 -0
- package/dist/chunk-QIFUVZFW.js +331 -0
- package/dist/chunk-RDPXKTVK.js +221 -0
- package/dist/chunk-RKYTYJGB.js +76 -0
- package/dist/chunk-RXLR6EFM.js +348 -0
- package/dist/chunk-SDB67PQJ.js +159 -0
- package/dist/chunk-SF2T7MP3.js +402 -0
- package/dist/chunk-SLU3FRFQ.js +2133 -0
- package/dist/chunk-SNDZJ5IV.js +214 -0
- package/dist/chunk-STEEAABW.js +448 -0
- package/dist/chunk-TUTWNHIQ.js +244 -0
- package/dist/chunk-UDP35QBR.js +30 -0
- package/dist/chunk-UKFHNJBI.js +85 -0
- package/dist/chunk-VC2DTK2X.js +382 -0
- package/dist/chunk-VRRAE5JX.js +836 -0
- package/dist/chunk-VVJTBQPR.js +38 -0
- package/dist/chunk-W3EQ362K.js +581 -0
- package/dist/chunk-WHIXIFHC.js +2242 -0
- package/dist/chunk-WRNGJJNR.js +377 -0
- package/dist/chunk-WUKHLCBE.js +3313 -0
- package/dist/chunk-WVPLHGDG.js +150 -0
- package/dist/chunk-XJZBSTL5.js +204 -0
- package/dist/chunk-Y3PMNUM5.js +304 -0
- package/dist/chunk-YHVS4QOV.js +14597 -0
- package/dist/chunk-YJ2OYAOC.js +668 -0
- package/dist/chunk-YYAD2GXX.js +128 -0
- package/dist/chunk-ZQML7EWE.js +333 -0
- package/dist/co-activation-XJLH46OX.js +74 -0
- package/dist/co-occurrence-GNN2X526.js +95 -0
- package/dist/code-context-index-OCPRLFG5.js +30 -0
- package/dist/core-memory-J4W2IYOF.js +110 -0
- package/dist/crdt-sync-QCBTSHIH.js +33 -0
- package/dist/crm-webhook-EM442VUW.js +10 -0
- package/dist/cto-delegation-gate-MLJMVHBK.js +280 -0
- package/dist/daemon-orchestration-2VNLZVTW.js +139 -0
- package/dist/db-backup-VUGFTPJ4.js +43 -0
- package/dist/doc-graph-extractor-PNRSFPSS.js +133 -0
- package/dist/dreaming-SK5VEQRF.js +34 -0
- package/dist/entity-boost-TQWWJUC2.js +375 -0
- package/dist/exe-drift-N34UPO7S.js +70 -0
- package/dist/exe-export-KACBKGVV.js +77 -0
- package/dist/exe-import-GXGDWACG.js +80 -0
- package/dist/exe-key-XPDOZBWW.js +673 -0
- package/dist/exe-snapshot-32GQKGQ5.js +338 -0
- package/dist/fast-db-init-F3TDD5VV.js +7 -0
- package/dist/gateway/index.js +8 -8
- package/dist/git-staleness-J45WNYRF.js +112 -0
- package/dist/git-task-sweep-BTGVQPFB.js +42 -0
- package/dist/global-procedures-6JCQWU4D.js +22 -0
- package/dist/graph-auto-extract-3ZQNXTPC.js +183 -0
- package/dist/hooks/bug-report-worker.js +13 -13
- package/dist/hooks/codex-stop-task-finalizer.js +13 -13
- package/dist/hooks/commit-complete.js +13 -13
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest-worker.js +3 -3
- package/dist/hooks/ingest.js +6 -6
- package/dist/hooks/instructions-loaded.js +4 -4
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +4 -4
- package/dist/hooks/post-compact.js +12 -12
- package/dist/hooks/post-tool-combined.js +6 -6
- package/dist/hooks/pre-compact.js +16 -16
- package/dist/hooks/pre-tool-use.js +16 -16
- package/dist/hooks/prompt-submit.js +24 -24
- package/dist/hooks/session-end.js +21 -21
- package/dist/hooks/session-start.js +12 -12
- package/dist/hooks/stop.js +19 -19
- package/dist/hooks/subagent-stop.js +12 -12
- package/dist/hooks/summary-worker.js +19 -19
- package/dist/index.js +19 -19
- package/dist/installer-5VPFY7SB.js +298 -0
- package/dist/installer-OENFPMA2.js +344 -0
- package/dist/installer-OIX4QOG5.js +40 -0
- package/dist/lib/cloud-sync.js +7 -7
- package/dist/lib/consolidation.js +6 -5
- package/dist/lib/database.js +2 -2
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +2 -2
- package/dist/lib/embed-worker.js +1 -0
- package/dist/lib/embedder.js +7 -3
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +160 -79
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +11 -11
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +5 -5
- package/dist/lib/session-registry.js +4 -4
- package/dist/lib/skill-learning.js +6 -6
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +12 -12
- package/dist/lib/tmux-routing.js +12 -10
- package/dist/lib/tmux-transport.js +1 -1
- package/dist/lib/token-spend.js +3 -3
- package/dist/lib/transport.js +2 -2
- package/dist/mcp/register-tools.js +62 -61
- package/dist/mcp/server.js +63 -62
- package/dist/mcp/tools/complete-reminder.js +4 -4
- package/dist/mcp/tools/create-reminder.js +4 -4
- package/dist/mcp/tools/create-task.js +14 -14
- package/dist/mcp/tools/deactivate-behavior.js +7 -7
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +14 -14
- package/dist/mcp/tools/send-message.js +13 -13
- package/dist/mcp/tools/update-task.js +13 -13
- package/dist/mcp-http-config-PQTOLCTP.js +29 -0
- package/dist/memory-cards-4RVDZIY2.js +180 -0
- package/dist/memory-graph-extractor-L6YC7G4M.js +22 -0
- package/dist/memory-poisoning-defense-4YVJYH4G.js +224 -0
- package/dist/memory-queue-client-MVAUOZNJ.js +16 -0
- package/dist/memory-reflection-SHHDQNOH.js +244 -0
- package/dist/message-queue-client-DCKZT6X2.js +92 -0
- package/dist/notifications-JFR3G42W.js +47 -0
- package/dist/orchestration-events-MGCGPTDN.js +27 -0
- package/dist/orchestrator-DAFL2YZB.js +35 -0
- package/dist/pipeline-router-WWSZVPCH.js +15 -0
- package/dist/plan-limits-C7XCSDZC.js +28 -0
- package/dist/project-boot-N3NTBVLE.js +299 -0
- package/dist/projection-worker-MTPAPCWX.js +1084 -0
- package/dist/prospective-memory-BTIVUJSB.js +232 -0
- package/dist/reranker-UA6WVESJ.js +19 -0
- package/dist/retrieval-health-7XNZJEBF.js +12 -0
- package/dist/review-polling-4ALGMXC3.js +126 -0
- package/dist/runtime/index.js +13 -13
- package/dist/self-query-router-MROFQLQB.js +192 -0
- package/dist/session-events-CK44XOU4.js +38 -0
- package/dist/session-kill-telemetry-MT6ITDOG.js +31 -0
- package/dist/session-scope-3XDBWV65.js +88 -0
- package/dist/setup-wizard-X6DOD7MC.js +12 -0
- package/dist/skill-refinement-G2CCY3GM.js +159 -0
- package/dist/stack-update-JF7F56AS.js +84 -0
- package/dist/steward-gate-YF2CYXE7.js +15 -0
- package/dist/task-enforcement-YN6HK7NE.js +506 -0
- package/dist/task-scope-CVK6ISCZ.js +37 -0
- package/dist/tasks-crud-NTNET4JE.js +79 -0
- package/dist/tasks-notify-4LJVFPCV.js +40 -0
- package/dist/tasks-review-3V4WOIRG.js +49 -0
- package/dist/telemetry-upload-5PNUKGTM.js +741 -0
- package/dist/token-budget-E46G7ZAQ.js +86 -0
- package/dist/tool-capability-index-JDSMKJER.js +10 -0
- package/dist/tool-telemetry-J3NLS3LJ.js +17 -0
- package/dist/tui/App.js +18 -18
- package/dist/tui-data-6DOMUUCM.js +260 -0
- package/dist/wiki-acl-5UK37LKF.js +111 -0
- package/dist/worker-gate-FM7AEC7G.js +21 -0
- package/dist/workflow-engine-2EDUHUIY.js +28 -0
- package/dist/worktree-7YKKJIYR.js +28 -0
- package/dist/worktree-sweep-C3ELFGDN.js +21 -0
- package/package.json +1 -1
- package/release-notes.json +23 -23
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listReminders
|
|
3
|
+
} from "./chunk-MEP7OUVZ.js";
|
|
4
|
+
|
|
5
|
+
// src/mcp/tools/list-reminders.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
function registerListReminders(server) {
|
|
8
|
+
server.registerTool(
|
|
9
|
+
"list_reminders",
|
|
10
|
+
{
|
|
11
|
+
title: "List Reminders",
|
|
12
|
+
description: "List active reminders. Pass include_completed=true to see all.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
include_completed: z.boolean().optional().default(false).describe("Include completed reminders")
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
async ({ include_completed }) => {
|
|
18
|
+
const reminders = await listReminders(include_completed);
|
|
19
|
+
if (reminders.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: "No active reminders." }]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const lines = reminders.map((r) => {
|
|
25
|
+
const due = r.dueDate ? ` (due: ${r.dueDate})` : "";
|
|
26
|
+
const done = r.completedAt ? " [DONE]" : "";
|
|
27
|
+
return `\u2022 ${r.text}${due}${done} [id: ${r.id.slice(0, 8)}]`;
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
registerListReminders
|
|
38
|
+
};
|
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureDaemonToken,
|
|
3
|
+
readDaemonToken
|
|
4
|
+
} from "./chunk-QOZQ2MYZ.js";
|
|
5
|
+
import {
|
|
6
|
+
computeDaemonHeapCapMb
|
|
7
|
+
} from "./chunk-7T7Y56HW.js";
|
|
8
|
+
import {
|
|
9
|
+
requestRestart
|
|
10
|
+
} from "./chunk-7L2EV3XX.js";
|
|
11
|
+
import {
|
|
12
|
+
EXE_AI_DIR
|
|
13
|
+
} from "./chunk-R36FAN53.js";
|
|
14
|
+
|
|
15
|
+
// src/lib/exe-daemon-client.ts
|
|
16
|
+
import net from "net";
|
|
17
|
+
import os from "os";
|
|
18
|
+
import { spawn, execSync } from "child_process";
|
|
19
|
+
import { randomUUID } from "crypto";
|
|
20
|
+
import { existsSync, unlinkSync, readFileSync, openSync, closeSync, statSync, writeSync } from "fs";
|
|
21
|
+
import path from "path";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
var SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path.join(EXE_AI_DIR, "exed.sock");
|
|
24
|
+
var PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path.join(EXE_AI_DIR, "exed.pid");
|
|
25
|
+
var SPAWN_LOCK_PATH = path.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
26
|
+
var SPAWN_LOCK_STALE_MS = 3e4;
|
|
27
|
+
var CONNECT_TIMEOUT_MS = 15e3;
|
|
28
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
29
|
+
var DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
30
|
+
function isBootFast() {
|
|
31
|
+
return process.env.EXE_BOOT_FAST === "1";
|
|
32
|
+
}
|
|
33
|
+
var _socket = null;
|
|
34
|
+
var _connected = false;
|
|
35
|
+
var _autoReconnecting = false;
|
|
36
|
+
var _buffer = "";
|
|
37
|
+
var _requestCount = 0;
|
|
38
|
+
var _consecutiveFailures = 0;
|
|
39
|
+
var _lastAliveSocketWarningAt = 0;
|
|
40
|
+
var _missingSocketRecoveryAttemptedAt = 0;
|
|
41
|
+
var _connectFailedAt = 0;
|
|
42
|
+
var CONNECT_FAILFAST_COOLDOWN_MS = 1e4;
|
|
43
|
+
var HEALTH_CHECK_INTERVAL = 100;
|
|
44
|
+
var MAX_RETRIES_BEFORE_RESTART = 3;
|
|
45
|
+
var RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
|
|
46
|
+
var ALIVE_SOCKET_WARNING_INTERVAL_MS = 6e4;
|
|
47
|
+
var MISSING_SOCKET_RECOVERY_INTERVAL_MS = 6e4;
|
|
48
|
+
var _pending = /* @__PURE__ */ new Map();
|
|
49
|
+
var MAX_BUFFER = 1e7;
|
|
50
|
+
function handleData(chunk) {
|
|
51
|
+
_buffer += chunk.toString();
|
|
52
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
53
|
+
_buffer = "";
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
let newlineIdx;
|
|
57
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
58
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
59
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
60
|
+
if (!line) continue;
|
|
61
|
+
try {
|
|
62
|
+
const response = JSON.parse(line);
|
|
63
|
+
const id = response.id;
|
|
64
|
+
if (!id) continue;
|
|
65
|
+
const entry = _pending.get(id);
|
|
66
|
+
if (entry) {
|
|
67
|
+
clearTimeout(entry.timer);
|
|
68
|
+
_pending.delete(id);
|
|
69
|
+
entry.resolve(response);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
var _zombieCache = null;
|
|
76
|
+
function isZombie(pid) {
|
|
77
|
+
if (_zombieCache && _zombieCache.pid === pid && Date.now() - _zombieCache.ts < 2e3) {
|
|
78
|
+
return _zombieCache.result;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const state = execSync(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
82
|
+
const result = state.startsWith("Z");
|
|
83
|
+
_zombieCache = { pid, result, ts: Date.now() };
|
|
84
|
+
return result;
|
|
85
|
+
} catch {
|
|
86
|
+
_zombieCache = { pid, result: false, ts: Date.now() };
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function cleanupStaleFiles() {
|
|
91
|
+
if (existsSync(PID_PATH)) {
|
|
92
|
+
try {
|
|
93
|
+
const pid = parseInt(readFileSync(PID_PATH, "utf8").trim(), 10);
|
|
94
|
+
if (pid > 0) {
|
|
95
|
+
try {
|
|
96
|
+
process.kill(pid, 0);
|
|
97
|
+
if (!isZombie(pid)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
101
|
+
`);
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
unlinkSync(PID_PATH);
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
unlinkSync(SOCKET_PATH);
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function isDaemonPidAlive() {
|
|
118
|
+
if (!existsSync(PID_PATH)) return false;
|
|
119
|
+
try {
|
|
120
|
+
const pid = parseInt(readFileSync(PID_PATH, "utf8").trim(), 10);
|
|
121
|
+
if (!(pid > 0)) return false;
|
|
122
|
+
process.kill(pid, 0);
|
|
123
|
+
return !isZombie(pid);
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function readDaemonPid() {
|
|
129
|
+
if (!existsSync(PID_PATH)) return null;
|
|
130
|
+
try {
|
|
131
|
+
const pid = parseInt(readFileSync(PID_PATH, "utf8").trim(), 10);
|
|
132
|
+
return pid > 0 ? pid : null;
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function warnAliveSocketUnresponsive(message) {
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
if (now - _lastAliveSocketWarningAt < ALIVE_SOCKET_WARNING_INTERVAL_MS) return;
|
|
140
|
+
_lastAliveSocketWarningAt = now;
|
|
141
|
+
process.stderr.write(`${message}
|
|
142
|
+
`);
|
|
143
|
+
}
|
|
144
|
+
function shouldRecoverMissingSocket() {
|
|
145
|
+
if (existsSync(SOCKET_PATH)) return false;
|
|
146
|
+
if (!isDaemonPidAlive()) return false;
|
|
147
|
+
const now = Date.now();
|
|
148
|
+
if (now - _missingSocketRecoveryAttemptedAt < MISSING_SOCKET_RECOVERY_INTERVAL_MS) return false;
|
|
149
|
+
_missingSocketRecoveryAttemptedAt = now;
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
function findPackageRoot() {
|
|
153
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
154
|
+
const { root } = path.parse(dir);
|
|
155
|
+
while (dir !== root) {
|
|
156
|
+
if (existsSync(path.join(dir, "package.json"))) return dir;
|
|
157
|
+
dir = path.dirname(dir);
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
function spawnDaemon() {
|
|
162
|
+
try {
|
|
163
|
+
const result = execSync("launchctl list com.askexe.exed 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
|
|
164
|
+
if (result.includes("com.askexe.exed")) {
|
|
165
|
+
process.stderr.write("[exed-client] Daemon not responding \u2014 launchd will restart it. Waiting...\n");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
process.stderr.write("[exed-client] No launchd supervisor \u2014 spawning daemon directly (dev mode)\n");
|
|
171
|
+
const totalGB = os.totalmem() / (1024 * 1024 * 1024);
|
|
172
|
+
if (totalGB <= 8) {
|
|
173
|
+
process.stderr.write(`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 daemon disabled.
|
|
174
|
+
`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const pkgRoot = findPackageRoot();
|
|
178
|
+
if (!pkgRoot) {
|
|
179
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const daemonPath = path.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
183
|
+
if (!existsSync(daemonPath)) {
|
|
184
|
+
process.stderr.write(`[exed-client] WARN: daemon not found at ${daemonPath}
|
|
185
|
+
`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
189
|
+
const logPath = path.join(path.dirname(SOCKET_PATH), "exed.log");
|
|
190
|
+
let stderrFd = "ignore";
|
|
191
|
+
try {
|
|
192
|
+
stderrFd = openSync(logPath, "a");
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
const heapCapMB = computeDaemonHeapCapMb(totalGB);
|
|
196
|
+
const child = spawn(process.execPath, [`--max-old-space-size=${heapCapMB}`, "--expose-gc", daemonPath], {
|
|
197
|
+
detached: true,
|
|
198
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
199
|
+
env: {
|
|
200
|
+
...process.env,
|
|
201
|
+
TMUX: void 0,
|
|
202
|
+
TMUX_PANE: void 0,
|
|
203
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
204
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
205
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
child.unref();
|
|
209
|
+
if (typeof stderrFd === "number") try {
|
|
210
|
+
closeSync(stderrFd);
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function acquireSpawnLock() {
|
|
215
|
+
try {
|
|
216
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
217
|
+
writeSync(fd, String(process.pid));
|
|
218
|
+
closeSync(fd);
|
|
219
|
+
return true;
|
|
220
|
+
} catch {
|
|
221
|
+
try {
|
|
222
|
+
const lockContent = readFileSync(SPAWN_LOCK_PATH, "utf8").trim();
|
|
223
|
+
const lockPid = parseInt(lockContent, 10);
|
|
224
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
225
|
+
const isStale = Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS;
|
|
226
|
+
let holderDead = false;
|
|
227
|
+
if (lockPid > 0) {
|
|
228
|
+
try {
|
|
229
|
+
process.kill(lockPid, 0);
|
|
230
|
+
} catch {
|
|
231
|
+
holderDead = true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (isStale || holderDead) {
|
|
235
|
+
try {
|
|
236
|
+
unlinkSync(SPAWN_LOCK_PATH);
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
241
|
+
writeSync(fd, String(process.pid));
|
|
242
|
+
closeSync(fd);
|
|
243
|
+
return true;
|
|
244
|
+
} catch {
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function releaseSpawnLock() {
|
|
253
|
+
try {
|
|
254
|
+
unlinkSync(SPAWN_LOCK_PATH);
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function connectToSocket() {
|
|
259
|
+
return new Promise((resolve) => {
|
|
260
|
+
if (_socket && _connected) {
|
|
261
|
+
resolve(true);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
265
|
+
const connectTimeout = setTimeout(() => {
|
|
266
|
+
socket.destroy();
|
|
267
|
+
resolve(false);
|
|
268
|
+
}, 2e3);
|
|
269
|
+
socket.on("connect", () => {
|
|
270
|
+
clearTimeout(connectTimeout);
|
|
271
|
+
_socket = socket;
|
|
272
|
+
_connected = true;
|
|
273
|
+
_buffer = "";
|
|
274
|
+
socket.on("data", handleData);
|
|
275
|
+
socket.on("close", () => {
|
|
276
|
+
_connected = false;
|
|
277
|
+
_socket = null;
|
|
278
|
+
for (const [id, entry] of _pending) {
|
|
279
|
+
clearTimeout(entry.timer);
|
|
280
|
+
_pending.delete(id);
|
|
281
|
+
entry.resolve({ error: "Connection closed" });
|
|
282
|
+
}
|
|
283
|
+
if (!_autoReconnecting && !isBootFast()) {
|
|
284
|
+
_autoReconnecting = true;
|
|
285
|
+
const maxRetries = 20;
|
|
286
|
+
let attempt = 0;
|
|
287
|
+
const daemonDead = !isDaemonPidAlive();
|
|
288
|
+
if (daemonDead) {
|
|
289
|
+
process.stderr.write("[daemon-client] Daemon PID dead \u2014 fast-path respawn (skipping jitter)\n");
|
|
290
|
+
try {
|
|
291
|
+
cleanupStaleFiles();
|
|
292
|
+
if (acquireSpawnLock()) {
|
|
293
|
+
try {
|
|
294
|
+
spawnDaemon();
|
|
295
|
+
} finally {
|
|
296
|
+
releaseSpawnLock();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const jitter = daemonDead ? () => 500 + Math.random() * 500 : () => 2e3 + Math.random() * 2e3;
|
|
303
|
+
const initialDelay = daemonDead ? 200 : Math.random() * 2e3;
|
|
304
|
+
setTimeout(() => {
|
|
305
|
+
const retryTimer = setInterval(async () => {
|
|
306
|
+
attempt++;
|
|
307
|
+
if (attempt > maxRetries) {
|
|
308
|
+
clearInterval(retryTimer);
|
|
309
|
+
_autoReconnecting = false;
|
|
310
|
+
process.stderr.write(`[daemon-client] Auto-reconnect failed after ${maxRetries} attempts
|
|
311
|
+
`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const ok = await connectToSocket();
|
|
315
|
+
if (ok) {
|
|
316
|
+
clearInterval(retryTimer);
|
|
317
|
+
_autoReconnecting = false;
|
|
318
|
+
if (attempt > 1) process.stderr.write(`[daemon-client] Auto-reconnected to daemon (attempt ${attempt})
|
|
319
|
+
`);
|
|
320
|
+
}
|
|
321
|
+
}, jitter());
|
|
322
|
+
}, initialDelay);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
socket.on("error", () => {
|
|
326
|
+
_connected = false;
|
|
327
|
+
_socket = null;
|
|
328
|
+
});
|
|
329
|
+
resolve(true);
|
|
330
|
+
});
|
|
331
|
+
socket.on("error", () => {
|
|
332
|
+
clearTimeout(connectTimeout);
|
|
333
|
+
resolve(false);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
async function connectEmbedDaemon() {
|
|
338
|
+
if (process.env.EXE_DISABLE_DAEMON_AUTOSTART === "1" || process.env.VITEST) {
|
|
339
|
+
return connectToSocket();
|
|
340
|
+
}
|
|
341
|
+
if (_socket && _connected) return true;
|
|
342
|
+
if (await connectToSocket()) {
|
|
343
|
+
_connectFailedAt = 0;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
if (isBootFast()) {
|
|
347
|
+
_connectFailedAt = Date.now();
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
if (_connectFailedAt > 0 && Date.now() - _connectFailedAt < CONNECT_FAILFAST_COOLDOWN_MS) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
if (shouldRecoverMissingSocket()) {
|
|
354
|
+
const pid = readDaemonPid();
|
|
355
|
+
process.stderr.write(
|
|
356
|
+
`[exed-client] Daemon socket missing while PID ${pid ?? "unknown"} is alive \u2014 requesting supervised recovery
|
|
357
|
+
`
|
|
358
|
+
);
|
|
359
|
+
killAndRespawnDaemon("daemon socket missing while PID alive", { forceMissingSocket: true });
|
|
360
|
+
}
|
|
361
|
+
if (isDaemonPidAlive()) {
|
|
362
|
+
warnAliveSocketUnresponsive("[exed-client] Daemon PID alive but socket unresponsive \u2014 waiting for recovery (not spawning duplicate)");
|
|
363
|
+
} else if (acquireSpawnLock()) {
|
|
364
|
+
try {
|
|
365
|
+
cleanupStaleFiles();
|
|
366
|
+
spawnDaemon();
|
|
367
|
+
} finally {
|
|
368
|
+
releaseSpawnLock();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const start = Date.now();
|
|
372
|
+
let delay = 100;
|
|
373
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
374
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
375
|
+
if (await connectToSocket()) {
|
|
376
|
+
_connectFailedAt = 0;
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
delay = Math.min(delay * 2, 3e3);
|
|
380
|
+
}
|
|
381
|
+
_connectFailedAt = Date.now();
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
function sendRequest(texts, priority) {
|
|
385
|
+
return sendDaemonRequest({ texts, priority });
|
|
386
|
+
}
|
|
387
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
388
|
+
return new Promise(async (resolve) => {
|
|
389
|
+
if ((!_socket || !_connected) && _autoReconnecting) {
|
|
390
|
+
const waitStart = Date.now();
|
|
391
|
+
while (!_connected && Date.now() - waitStart < 15e3) {
|
|
392
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (!_socket || !_connected) {
|
|
396
|
+
resolve({ error: "Not connected" });
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const id = randomUUID();
|
|
400
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
401
|
+
const timer = setTimeout(() => {
|
|
402
|
+
_pending.delete(id);
|
|
403
|
+
resolve({ error: "Request timeout" });
|
|
404
|
+
}, timeoutMs);
|
|
405
|
+
_pending.set(id, { resolve, timer });
|
|
406
|
+
try {
|
|
407
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
408
|
+
} catch {
|
|
409
|
+
clearTimeout(timer);
|
|
410
|
+
_pending.delete(id);
|
|
411
|
+
resolve({ error: "Write failed" });
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
async function pingDaemon() {
|
|
416
|
+
if ((!_socket || !_connected) && !await connectEmbedDaemon()) return null;
|
|
417
|
+
const response = await sendDaemonRequest({ type: "health" }, 5e3);
|
|
418
|
+
if (response.health) {
|
|
419
|
+
return response.health;
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
function canClientRequestDaemonRestart() {
|
|
424
|
+
return process.env.EXE_DAEMON_CLIENT_CAN_RESTART === "1";
|
|
425
|
+
}
|
|
426
|
+
function killAndRespawnDaemon(reason, opts) {
|
|
427
|
+
if (!opts?.forceMissingSocket && !canClientRequestDaemonRestart()) {
|
|
428
|
+
process.stderr.write(
|
|
429
|
+
`[exed-client] Restart suppressed (${reason ?? "consecutive failures"}) \u2014 client-side daemon restarts are disabled; degrading gracefully.
|
|
430
|
+
`
|
|
431
|
+
);
|
|
432
|
+
if (_socket) {
|
|
433
|
+
_socket.destroy();
|
|
434
|
+
_socket = null;
|
|
435
|
+
}
|
|
436
|
+
_connected = false;
|
|
437
|
+
_buffer = "";
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
const result = requestRestart(reason ?? "consecutive failures", opts);
|
|
441
|
+
if (_socket) {
|
|
442
|
+
_socket.destroy();
|
|
443
|
+
_socket = null;
|
|
444
|
+
}
|
|
445
|
+
_connected = false;
|
|
446
|
+
_buffer = "";
|
|
447
|
+
if (!result.ok) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
if (!isDaemonPidAlive()) {
|
|
451
|
+
spawnDaemon();
|
|
452
|
+
} else {
|
|
453
|
+
process.stderr.write("[exed-client] Daemon PID alive after kill \u2014 launchd will restart when it exits\n");
|
|
454
|
+
}
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
async function retryThenRestart(doRequest, label) {
|
|
458
|
+
const result = await doRequest();
|
|
459
|
+
if (!result.error) {
|
|
460
|
+
_consecutiveFailures = 0;
|
|
461
|
+
return result;
|
|
462
|
+
}
|
|
463
|
+
if (result.error.includes("Model not loaded") || result.error.includes("embeddings unavailable")) {
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
_consecutiveFailures++;
|
|
467
|
+
for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
|
|
468
|
+
const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
|
|
469
|
+
process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
|
|
470
|
+
`);
|
|
471
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
472
|
+
if (!_connected) {
|
|
473
|
+
if (!await connectToSocket()) continue;
|
|
474
|
+
}
|
|
475
|
+
const retry = await doRequest();
|
|
476
|
+
if (!retry.error) {
|
|
477
|
+
_consecutiveFailures = 0;
|
|
478
|
+
return retry;
|
|
479
|
+
}
|
|
480
|
+
_consecutiveFailures++;
|
|
481
|
+
}
|
|
482
|
+
const isEmbed = label.toLowerCase().includes("embed");
|
|
483
|
+
process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 handling daemon failure
|
|
484
|
+
`);
|
|
485
|
+
const restartRequested = killAndRespawnDaemon(`${label}: ${_consecutiveFailures} consecutive failures`, { isEmbedRelated: isEmbed });
|
|
486
|
+
if (!restartRequested) {
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
const start = Date.now();
|
|
490
|
+
let delay = 200;
|
|
491
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
492
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
493
|
+
if (await connectToSocket()) break;
|
|
494
|
+
delay = Math.min(delay * 2, 3e3);
|
|
495
|
+
}
|
|
496
|
+
if (!_connected) return { error: "Daemon restart failed" };
|
|
497
|
+
const final = await doRequest();
|
|
498
|
+
if (!final.error) _consecutiveFailures = 0;
|
|
499
|
+
return final;
|
|
500
|
+
}
|
|
501
|
+
async function embedViaClient(text, priority = "high") {
|
|
502
|
+
const _oomPath = path.join(os.homedir(), ".exe-os", "embedding-oom-marker");
|
|
503
|
+
if (existsSync(_oomPath)) return null;
|
|
504
|
+
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
505
|
+
_requestCount++;
|
|
506
|
+
if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
|
|
507
|
+
const health = await pingDaemon();
|
|
508
|
+
if (!health) {
|
|
509
|
+
process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 handling daemon failure
|
|
510
|
+
`);
|
|
511
|
+
const restartRequested = killAndRespawnDaemon(`Embed health check failed at request ${_requestCount}`, { isEmbedRelated: true });
|
|
512
|
+
if (!restartRequested) return null;
|
|
513
|
+
const start = Date.now();
|
|
514
|
+
let d = 200;
|
|
515
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
516
|
+
await new Promise((r) => setTimeout(r, d));
|
|
517
|
+
if (await connectToSocket()) break;
|
|
518
|
+
d = Math.min(d * 2, 3e3);
|
|
519
|
+
}
|
|
520
|
+
if (!_connected) return null;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const result = await retryThenRestart(
|
|
524
|
+
() => sendRequest([text], priority),
|
|
525
|
+
"Embed"
|
|
526
|
+
);
|
|
527
|
+
return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
|
|
528
|
+
}
|
|
529
|
+
async function embedBatchViaClient(texts, priority = "high") {
|
|
530
|
+
const _oomPath2 = path.join(os.homedir(), ".exe-os", "embedding-oom-marker");
|
|
531
|
+
if (existsSync(_oomPath2)) return null;
|
|
532
|
+
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
533
|
+
_requestCount++;
|
|
534
|
+
const result = await retryThenRestart(
|
|
535
|
+
() => sendRequest(texts, priority),
|
|
536
|
+
"Batch embed"
|
|
537
|
+
);
|
|
538
|
+
return !result.error && result.vectors ? result.vectors : null;
|
|
539
|
+
}
|
|
540
|
+
function disconnectClient() {
|
|
541
|
+
if (_socket) {
|
|
542
|
+
_socket.destroy();
|
|
543
|
+
_socket = null;
|
|
544
|
+
}
|
|
545
|
+
_connected = false;
|
|
546
|
+
_buffer = "";
|
|
547
|
+
for (const [id, entry] of _pending) {
|
|
548
|
+
clearTimeout(entry.timer);
|
|
549
|
+
_pending.delete(id);
|
|
550
|
+
entry.resolve({ error: "Client disconnected" });
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function isClientConnected() {
|
|
554
|
+
return _connected;
|
|
555
|
+
}
|
|
556
|
+
function isDaemonAutoReconnecting() {
|
|
557
|
+
return _autoReconnecting;
|
|
558
|
+
}
|
|
559
|
+
function sendIngestRequest(payload) {
|
|
560
|
+
if (!_socket || !_connected) return false;
|
|
561
|
+
try {
|
|
562
|
+
const id = randomUUID();
|
|
563
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
564
|
+
_socket.write(JSON.stringify({ id, token, type: "ingest", ...payload }) + "\n");
|
|
565
|
+
return true;
|
|
566
|
+
} catch {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export {
|
|
572
|
+
connectEmbedDaemon,
|
|
573
|
+
sendDaemonRequest,
|
|
574
|
+
pingDaemon,
|
|
575
|
+
embedViaClient,
|
|
576
|
+
embedBatchViaClient,
|
|
577
|
+
disconnectClient,
|
|
578
|
+
isClientConnected,
|
|
579
|
+
isDaemonAutoReconnecting,
|
|
580
|
+
sendIngestRequest
|
|
581
|
+
};
|