@askexenow/exe-os 0.8.83 → 0.8.86
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/backfill-conversations.js +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +154 -21
- package/dist/bin/cli.js +14678 -12676
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +100 -91
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1420 -485
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +572 -271
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +102 -3
- package/dist/bin/exe-gateway.js +796 -292
- package/dist/bin/exe-healthcheck.js +134 -1
- package/dist/bin/exe-heartbeat.js +172 -36
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +927 -82
- package/dist/bin/exe-new-employee.js +60 -8
- package/dist/bin/exe-pending-messages.js +151 -19
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +155 -22
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +995 -228
- package/dist/bin/exe-session-cleanup.js +4930 -1664
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +154 -21
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +1180 -363
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +60 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +1185 -367
- package/dist/bin/setup.js +914 -270
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +792 -285
- package/dist/hooks/bug-report-worker.js +445 -135
- package/dist/hooks/commit-complete.js +1178 -361
- package/dist/hooks/error-recall.js +994 -228
- package/dist/hooks/ingest-worker.js +1799 -1234
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +757 -109
- package/dist/hooks/pre-compact.js +1061 -244
- package/dist/hooks/pre-tool-use.js +787 -130
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +1121 -299
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +4063 -397
- package/dist/hooks/session-start.js +1071 -254
- package/dist/hooks/stop.js +768 -120
- package/dist/hooks/subagent-stop.js +757 -109
- package/dist/hooks/summary-worker.js +1706 -1011
- package/dist/index.js +1821 -1098
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +932 -88
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +2733 -1575
- package/dist/lib/hybrid-search.js +995 -228
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +103 -40
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +348 -134
- package/dist/lib/tmux-routing.js +422 -208
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5742 -696
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +375 -152
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +99 -31
- package/dist/mcp/tools/send-message.js +108 -45
- package/dist/mcp/tools/update-task.js +162 -77
- package/dist/runtime/index.js +1075 -258
- package/dist/tui/App.js +1333 -506
- package/package.json +6 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
package/dist/lib/identity.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { createHash } from "crypto";
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __esm = (fn, res) => function __init() {
|
|
3
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
|
+
};
|
|
6
5
|
|
|
7
6
|
// src/lib/config.ts
|
|
8
7
|
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
@@ -25,74 +24,88 @@ function resolveDataDir() {
|
|
|
25
24
|
}
|
|
26
25
|
return newDir;
|
|
27
26
|
}
|
|
28
|
-
var EXE_AI_DIR
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
27
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
|
|
28
|
+
var init_config = __esm({
|
|
29
|
+
"src/lib/config.ts"() {
|
|
30
|
+
"use strict";
|
|
31
|
+
EXE_AI_DIR = resolveDataDir();
|
|
32
|
+
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
33
|
+
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
34
|
+
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
35
|
+
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
36
|
+
CURRENT_CONFIG_VERSION = 1;
|
|
37
|
+
DEFAULT_CONFIG = {
|
|
38
|
+
config_version: CURRENT_CONFIG_VERSION,
|
|
39
|
+
dbPath: DB_PATH,
|
|
40
|
+
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
41
|
+
embeddingDim: 1024,
|
|
42
|
+
batchSize: 20,
|
|
43
|
+
flushIntervalMs: 1e4,
|
|
44
|
+
autoIngestion: true,
|
|
45
|
+
autoRetrieval: true,
|
|
46
|
+
searchMode: "hybrid",
|
|
47
|
+
hookSearchMode: "hybrid",
|
|
48
|
+
fileGrepEnabled: true,
|
|
49
|
+
splashEffect: true,
|
|
50
|
+
consolidationEnabled: true,
|
|
51
|
+
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
52
|
+
consolidationModel: "claude-haiku-4-5-20251001",
|
|
53
|
+
consolidationMaxCallsPerRun: 20,
|
|
54
|
+
selfQueryRouter: true,
|
|
55
|
+
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
56
|
+
rerankerEnabled: true,
|
|
57
|
+
scalingRoadmap: {
|
|
58
|
+
rerankerAutoTrigger: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
broadQueryMinCardinality: 5e4,
|
|
61
|
+
fetchTopK: 150,
|
|
62
|
+
returnTopK: 5
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
graphRagEnabled: true,
|
|
66
|
+
wikiEnabled: false,
|
|
67
|
+
wikiUrl: "",
|
|
68
|
+
wikiApiKey: "",
|
|
69
|
+
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
70
|
+
wikiWorkspaceMapping: {},
|
|
71
|
+
wikiAutoUpdate: true,
|
|
72
|
+
wikiAutoUpdateThreshold: 0.5,
|
|
73
|
+
wikiAutoUpdateCreateNew: true,
|
|
74
|
+
skillLearning: true,
|
|
75
|
+
skillThreshold: 3,
|
|
76
|
+
skillModel: "claude-haiku-4-5-20251001",
|
|
77
|
+
exeHeartbeat: {
|
|
78
|
+
enabled: true,
|
|
79
|
+
intervalSeconds: 60,
|
|
80
|
+
staleInProgressThresholdHours: 2
|
|
81
|
+
},
|
|
82
|
+
sessionLifecycle: {
|
|
83
|
+
idleKillEnabled: true,
|
|
84
|
+
idleKillTicksRequired: 3,
|
|
85
|
+
idleKillIntercomAckWindowMs: 1e4,
|
|
86
|
+
maxAutoInstances: 10
|
|
87
|
+
},
|
|
88
|
+
autoUpdate: {
|
|
89
|
+
checkOnBoot: true,
|
|
90
|
+
autoInstall: false,
|
|
91
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
92
|
+
}
|
|
93
|
+
};
|
|
89
94
|
}
|
|
90
|
-
};
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/lib/identity.ts
|
|
98
|
+
init_config();
|
|
99
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
100
|
+
import { readdirSync } from "fs";
|
|
101
|
+
import path3 from "path";
|
|
102
|
+
import { createHash } from "crypto";
|
|
91
103
|
|
|
92
104
|
// src/lib/database.ts
|
|
93
105
|
import { createClient } from "@libsql/client";
|
|
94
106
|
|
|
95
107
|
// src/lib/employees.ts
|
|
108
|
+
init_config();
|
|
96
109
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
97
110
|
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
98
111
|
import { execSync } from "child_process";
|
|
@@ -102,10 +115,17 @@ var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
|
102
115
|
|
|
103
116
|
// src/lib/database.ts
|
|
104
117
|
var _resilientClient = null;
|
|
118
|
+
var _daemonClient = null;
|
|
105
119
|
function getClient() {
|
|
106
120
|
if (!_resilientClient) {
|
|
107
121
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
108
122
|
}
|
|
123
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
124
|
+
return _resilientClient;
|
|
125
|
+
}
|
|
126
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
127
|
+
return _daemonClient;
|
|
128
|
+
}
|
|
109
129
|
return _resilientClient;
|
|
110
130
|
}
|
|
111
131
|
|
package/dist/lib/keychain.js
CHANGED
|
@@ -31,12 +31,20 @@ async function getMasterKey() {
|
|
|
31
31
|
}
|
|
32
32
|
const keyPath = getKeyPath();
|
|
33
33
|
if (!existsSync(keyPath)) {
|
|
34
|
+
process.stderr.write(
|
|
35
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
36
|
+
`
|
|
37
|
+
);
|
|
34
38
|
return null;
|
|
35
39
|
}
|
|
36
40
|
try {
|
|
37
41
|
const content = await readFile(keyPath, "utf-8");
|
|
38
42
|
return Buffer.from(content.trim(), "base64");
|
|
39
|
-
} catch {
|
|
43
|
+
} catch (err) {
|
|
44
|
+
process.stderr.write(
|
|
45
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
46
|
+
`
|
|
47
|
+
);
|
|
40
48
|
return null;
|
|
41
49
|
}
|
|
42
50
|
}
|
package/dist/lib/messaging.js
CHANGED
|
@@ -160,15 +160,22 @@ function getClient() {
|
|
|
160
160
|
if (!_resilientClient) {
|
|
161
161
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
162
162
|
}
|
|
163
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
164
|
+
return _resilientClient;
|
|
165
|
+
}
|
|
166
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
167
|
+
return _daemonClient;
|
|
168
|
+
}
|
|
163
169
|
return _resilientClient;
|
|
164
170
|
}
|
|
165
|
-
var _resilientClient;
|
|
171
|
+
var _resilientClient, _daemonClient;
|
|
166
172
|
var init_database = __esm({
|
|
167
173
|
"src/lib/database.ts"() {
|
|
168
174
|
"use strict";
|
|
169
175
|
init_db_retry();
|
|
170
176
|
init_employees();
|
|
171
177
|
_resilientClient = null;
|
|
178
|
+
_daemonClient = null;
|
|
172
179
|
}
|
|
173
180
|
});
|
|
174
181
|
|
|
@@ -354,18 +361,54 @@ var init_provider_table = __esm({
|
|
|
354
361
|
}
|
|
355
362
|
});
|
|
356
363
|
|
|
357
|
-
// src/lib/
|
|
358
|
-
|
|
364
|
+
// src/lib/runtime-table.ts
|
|
365
|
+
var RUNTIME_TABLE;
|
|
366
|
+
var init_runtime_table = __esm({
|
|
367
|
+
"src/lib/runtime-table.ts"() {
|
|
368
|
+
"use strict";
|
|
369
|
+
RUNTIME_TABLE = {
|
|
370
|
+
codex: {
|
|
371
|
+
binary: "codex",
|
|
372
|
+
launchMode: "exec",
|
|
373
|
+
autoApproveFlag: "--full-auto",
|
|
374
|
+
inlineFlag: "--no-alt-screen",
|
|
375
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
376
|
+
defaultModel: "gpt-5.4"
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// src/lib/agent-config.ts
|
|
383
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
|
|
359
384
|
import path4 from "path";
|
|
385
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
386
|
+
var init_agent_config = __esm({
|
|
387
|
+
"src/lib/agent-config.ts"() {
|
|
388
|
+
"use strict";
|
|
389
|
+
init_config();
|
|
390
|
+
init_runtime_table();
|
|
391
|
+
AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
|
|
392
|
+
DEFAULT_MODELS = {
|
|
393
|
+
claude: "claude-opus-4",
|
|
394
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
395
|
+
opencode: "minimax-m2.7"
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// src/lib/intercom-queue.ts
|
|
401
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
402
|
+
import path5 from "path";
|
|
360
403
|
import os4 from "os";
|
|
361
404
|
function ensureDir() {
|
|
362
|
-
const dir =
|
|
363
|
-
if (!
|
|
405
|
+
const dir = path5.dirname(QUEUE_PATH);
|
|
406
|
+
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
364
407
|
}
|
|
365
408
|
function readQueue() {
|
|
366
409
|
try {
|
|
367
|
-
if (!
|
|
368
|
-
return JSON.parse(
|
|
410
|
+
if (!existsSync4(QUEUE_PATH)) return [];
|
|
411
|
+
return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
|
|
369
412
|
} catch {
|
|
370
413
|
return [];
|
|
371
414
|
}
|
|
@@ -373,7 +416,7 @@ function readQueue() {
|
|
|
373
416
|
function writeQueue(queue) {
|
|
374
417
|
ensureDir();
|
|
375
418
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
376
|
-
|
|
419
|
+
writeFileSync3(tmp, JSON.stringify(queue, null, 2));
|
|
377
420
|
renameSync3(tmp, QUEUE_PATH);
|
|
378
421
|
}
|
|
379
422
|
function queueIntercom(targetSession, reason) {
|
|
@@ -397,31 +440,31 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
397
440
|
var init_intercom_queue = __esm({
|
|
398
441
|
"src/lib/intercom-queue.ts"() {
|
|
399
442
|
"use strict";
|
|
400
|
-
QUEUE_PATH =
|
|
443
|
+
QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
401
444
|
TTL_MS = 60 * 60 * 1e3;
|
|
402
|
-
INTERCOM_LOG =
|
|
445
|
+
INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
403
446
|
}
|
|
404
447
|
});
|
|
405
448
|
|
|
406
449
|
// src/lib/license.ts
|
|
407
|
-
import { readFileSync as
|
|
450
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
408
451
|
import { randomUUID } from "crypto";
|
|
409
|
-
import
|
|
452
|
+
import path6 from "path";
|
|
410
453
|
import { jwtVerify, importSPKI } from "jose";
|
|
411
454
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
412
455
|
var init_license = __esm({
|
|
413
456
|
"src/lib/license.ts"() {
|
|
414
457
|
"use strict";
|
|
415
458
|
init_config();
|
|
416
|
-
LICENSE_PATH =
|
|
417
|
-
CACHE_PATH =
|
|
418
|
-
DEVICE_ID_PATH =
|
|
459
|
+
LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
460
|
+
CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
461
|
+
DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
419
462
|
}
|
|
420
463
|
});
|
|
421
464
|
|
|
422
465
|
// src/lib/plan-limits.ts
|
|
423
|
-
import { readFileSync as
|
|
424
|
-
import
|
|
466
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
467
|
+
import path7 from "path";
|
|
425
468
|
var CACHE_PATH2;
|
|
426
469
|
var init_plan_limits = __esm({
|
|
427
470
|
"src/lib/plan-limits.ts"() {
|
|
@@ -430,13 +473,13 @@ var init_plan_limits = __esm({
|
|
|
430
473
|
init_employees();
|
|
431
474
|
init_license();
|
|
432
475
|
init_config();
|
|
433
|
-
CACHE_PATH2 =
|
|
476
|
+
CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
434
477
|
}
|
|
435
478
|
});
|
|
436
479
|
|
|
437
480
|
// src/lib/tmux-routing.ts
|
|
438
|
-
import { readFileSync as
|
|
439
|
-
import
|
|
481
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
|
|
482
|
+
import path8 from "path";
|
|
440
483
|
import os5 from "os";
|
|
441
484
|
import { fileURLToPath } from "url";
|
|
442
485
|
function getMySession() {
|
|
@@ -477,7 +520,7 @@ function extractRootExe(name) {
|
|
|
477
520
|
}
|
|
478
521
|
function getParentExe(sessionKey) {
|
|
479
522
|
try {
|
|
480
|
-
const data = JSON.parse(
|
|
523
|
+
const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
481
524
|
return data.parentExe || null;
|
|
482
525
|
} catch {
|
|
483
526
|
return null;
|
|
@@ -501,32 +544,50 @@ function isEmployeeAlive(sessionName) {
|
|
|
501
544
|
}
|
|
502
545
|
function readDebounceState() {
|
|
503
546
|
try {
|
|
504
|
-
if (!
|
|
505
|
-
|
|
547
|
+
if (!existsSync7(DEBOUNCE_FILE)) return {};
|
|
548
|
+
const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
|
|
549
|
+
const state = {};
|
|
550
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
551
|
+
if (typeof val === "number") {
|
|
552
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
553
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
554
|
+
state[key] = val;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return state;
|
|
506
558
|
} catch {
|
|
507
559
|
return {};
|
|
508
560
|
}
|
|
509
561
|
}
|
|
510
562
|
function writeDebounceState(state) {
|
|
511
563
|
try {
|
|
512
|
-
if (!
|
|
513
|
-
|
|
564
|
+
if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
|
|
565
|
+
writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
|
|
514
566
|
} catch {
|
|
515
567
|
}
|
|
516
568
|
}
|
|
517
569
|
function isDebounced(targetSession) {
|
|
518
570
|
const state = readDebounceState();
|
|
519
|
-
const
|
|
520
|
-
|
|
571
|
+
const entry = state[targetSession];
|
|
572
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
573
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
574
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
575
|
+
state[targetSession].pending++;
|
|
576
|
+
writeDebounceState(state);
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
521
580
|
}
|
|
522
581
|
function recordDebounce(targetSession) {
|
|
523
582
|
const state = readDebounceState();
|
|
524
|
-
state[targetSession]
|
|
583
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
584
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
525
585
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
526
586
|
for (const key of Object.keys(state)) {
|
|
527
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
587
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
528
588
|
}
|
|
529
589
|
writeDebounceState(state);
|
|
590
|
+
return batched;
|
|
530
591
|
}
|
|
531
592
|
function logIntercom(msg) {
|
|
532
593
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -567,7 +628,7 @@ function sendIntercom(targetSession) {
|
|
|
567
628
|
return "skipped_exe";
|
|
568
629
|
}
|
|
569
630
|
if (isDebounced(targetSession)) {
|
|
570
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
631
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
571
632
|
return "debounced";
|
|
572
633
|
}
|
|
573
634
|
try {
|
|
@@ -579,14 +640,14 @@ function sendIntercom(targetSession) {
|
|
|
579
640
|
const sessionState = getSessionState(targetSession);
|
|
580
641
|
if (sessionState === "no_claude") {
|
|
581
642
|
queueIntercom(targetSession, "claude not running in session");
|
|
582
|
-
recordDebounce(targetSession);
|
|
583
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
643
|
+
const batched2 = recordDebounce(targetSession);
|
|
644
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
584
645
|
return "queued";
|
|
585
646
|
}
|
|
586
647
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
587
648
|
queueIntercom(targetSession, "session busy at send time");
|
|
588
|
-
recordDebounce(targetSession);
|
|
589
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
649
|
+
const batched2 = recordDebounce(targetSession);
|
|
650
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
590
651
|
return "queued";
|
|
591
652
|
}
|
|
592
653
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -594,8 +655,8 @@ function sendIntercom(targetSession) {
|
|
|
594
655
|
transport.sendKeys(targetSession, "q");
|
|
595
656
|
}
|
|
596
657
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
597
|
-
recordDebounce(targetSession);
|
|
598
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
658
|
+
const batched = recordDebounce(targetSession);
|
|
659
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
599
660
|
return "delivered";
|
|
600
661
|
} catch {
|
|
601
662
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -612,15 +673,17 @@ var init_tmux_routing = __esm({
|
|
|
612
673
|
init_cc_agent_support();
|
|
613
674
|
init_mcp_prefix();
|
|
614
675
|
init_provider_table();
|
|
676
|
+
init_agent_config();
|
|
677
|
+
init_runtime_table();
|
|
615
678
|
init_intercom_queue();
|
|
616
679
|
init_plan_limits();
|
|
617
680
|
init_employees();
|
|
618
|
-
SPAWN_LOCK_DIR =
|
|
619
|
-
SESSION_CACHE =
|
|
681
|
+
SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
682
|
+
SESSION_CACHE = path8.join(os5.homedir(), ".exe-os", "session-cache");
|
|
620
683
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
621
684
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
622
|
-
INTERCOM_LOG2 =
|
|
623
|
-
DEBOUNCE_FILE =
|
|
685
|
+
INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
686
|
+
DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
|
|
624
687
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
625
688
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
626
689
|
}
|