@askexenow/exe-os 0.9.93 → 0.9.95
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/docker-compose.yml +1 -0
- package/dist/bin/agentic-ontology-backfill.js +65 -8
- package/dist/bin/agentic-reflection-backfill.js +54 -3
- package/dist/bin/agentic-semantic-label.js +54 -3
- package/dist/bin/backfill-conversations.js +69 -9
- package/dist/bin/backfill-responses.js +69 -9
- package/dist/bin/backfill-vectors.js +54 -3
- package/dist/bin/bulk-sync-postgres.js +66 -8
- package/dist/bin/cleanup-stale-review-tasks.js +121 -13
- package/dist/bin/cli.js +1561 -466
- package/dist/bin/customer-readiness.js +61 -0
- package/dist/bin/exe-agent.js +17 -3
- package/dist/bin/exe-assign.js +75 -9
- package/dist/bin/exe-boot.js +114 -12
- package/dist/bin/exe-call.js +17 -3
- package/dist/bin/exe-cloud.js +76 -10
- package/dist/bin/exe-dispatch.js +136 -18
- package/dist/bin/exe-doctor.js +75 -9
- package/dist/bin/exe-export-behaviors.js +75 -9
- package/dist/bin/exe-forget.js +94 -9
- package/dist/bin/exe-gateway.js +135 -18
- package/dist/bin/exe-heartbeat.js +121 -13
- package/dist/bin/exe-kill.js +75 -9
- package/dist/bin/exe-launch-agent.js +75 -9
- package/dist/bin/exe-new-employee.js +18 -4
- package/dist/bin/exe-pending-messages.js +121 -13
- package/dist/bin/exe-pending-notifications.js +121 -13
- package/dist/bin/exe-pending-reviews.js +121 -13
- package/dist/bin/exe-rename.js +75 -9
- package/dist/bin/exe-review.js +75 -9
- package/dist/bin/exe-search.js +100 -9
- package/dist/bin/exe-session-cleanup.js +136 -18
- package/dist/bin/exe-settings.js +1 -0
- package/dist/bin/exe-start-codex.js +65 -8
- package/dist/bin/exe-start-opencode.js +65 -8
- package/dist/bin/exe-status.js +121 -13
- package/dist/bin/exe-support.js +1 -0
- package/dist/bin/exe-team.js +75 -9
- package/dist/bin/git-sweep.js +136 -18
- package/dist/bin/graph-backfill.js +65 -8
- package/dist/bin/graph-export.js +75 -9
- package/dist/bin/intercom-check.js +136 -18
- package/dist/bin/scan-tasks.js +136 -18
- package/dist/bin/setup.js +55 -4
- package/dist/bin/shard-migrate.js +65 -8
- package/dist/bin/stack-update.js +5 -6
- package/dist/bin/update.js +1 -1
- package/dist/gateway/index.js +136 -18
- package/dist/hooks/bug-report-worker.js +136 -18
- package/dist/hooks/codex-stop-task-finalizer.js +126 -14
- package/dist/hooks/commit-complete.js +136 -18
- package/dist/hooks/error-recall.js +100 -9
- package/dist/hooks/ingest.js +75 -9
- package/dist/hooks/instructions-loaded.js +75 -9
- package/dist/hooks/notification.js +75 -9
- package/dist/hooks/post-compact.js +313 -50
- package/dist/hooks/post-tool-combined.js +436 -13
- package/dist/hooks/pre-compact.js +136 -18
- package/dist/hooks/pre-tool-use.js +121 -13
- package/dist/hooks/prompt-submit.js +194 -19
- package/dist/hooks/session-end.js +136 -18
- package/dist/hooks/session-start.js +146 -13
- package/dist/hooks/stop.js +121 -13
- package/dist/hooks/subagent-stop.js +121 -13
- package/dist/hooks/summary-worker.js +99 -7
- package/dist/index.js +136 -18
- package/dist/lib/cloud-sync.js +38 -0
- package/dist/lib/consolidation.js +3 -1
- package/dist/lib/database.js +37 -0
- package/dist/lib/db.js +37 -0
- package/dist/lib/device-registry.js +37 -0
- package/dist/lib/employee-templates.js +17 -3
- package/dist/lib/exe-daemon.js +916 -42
- package/dist/lib/hybrid-search.js +100 -9
- package/dist/lib/license.js +1 -1
- package/dist/lib/messaging.js +43 -4
- package/dist/lib/schedules.js +54 -3
- package/dist/lib/store.js +75 -9
- package/dist/lib/tasks.js +61 -9
- package/dist/lib/tmux-routing.js +61 -9
- package/dist/mcp/server.js +878 -42
- package/dist/mcp/tools/create-task.js +70 -12
- package/dist/mcp/tools/list-tasks.js +49 -5
- package/dist/mcp/tools/send-message.js +43 -4
- package/dist/mcp/tools/update-task.js +61 -9
- package/dist/runtime/index.js +136 -18
- package/dist/tui/App.js +135 -18
- package/package.json +1 -1
|
@@ -1201,7 +1201,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
|
|
|
1201
1201
|
import os6 from "os";
|
|
1202
1202
|
import path7 from "path";
|
|
1203
1203
|
import { jwtVerify, importSPKI } from "jose";
|
|
1204
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
1204
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, PLAN_LIMITS;
|
|
1205
1205
|
var init_license = __esm({
|
|
1206
1206
|
"src/lib/license.ts"() {
|
|
1207
1207
|
"use strict";
|
|
@@ -1209,6 +1209,7 @@ var init_license = __esm({
|
|
|
1209
1209
|
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
1210
1210
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
1211
1211
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1212
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
|
|
1212
1213
|
PLAN_LIMITS = {
|
|
1213
1214
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
1214
1215
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -2215,9 +2216,13 @@ function getDispatchedBy(sessionKey) {
|
|
|
2215
2216
|
}
|
|
2216
2217
|
}
|
|
2217
2218
|
function resolveExeSession() {
|
|
2219
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
2220
|
+
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
2221
|
+
}
|
|
2218
2222
|
const mySession = getMySession();
|
|
2219
2223
|
if (!mySession) return null;
|
|
2220
2224
|
const fromSessionName = extractRootExe(mySession);
|
|
2225
|
+
let candidate = null;
|
|
2221
2226
|
try {
|
|
2222
2227
|
const key = getSessionKey();
|
|
2223
2228
|
const parentExe = getParentExe(key);
|
|
@@ -2228,13 +2233,47 @@ function resolveExeSession() {
|
|
|
2228
2233
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
2229
2234
|
`
|
|
2230
2235
|
);
|
|
2231
|
-
|
|
2236
|
+
candidate = fromSessionName;
|
|
2237
|
+
} else {
|
|
2238
|
+
candidate = fromCache;
|
|
2232
2239
|
}
|
|
2233
|
-
return fromCache;
|
|
2234
2240
|
}
|
|
2235
2241
|
} catch {
|
|
2236
2242
|
}
|
|
2237
|
-
|
|
2243
|
+
if (!candidate) {
|
|
2244
|
+
candidate = fromSessionName ?? mySession;
|
|
2245
|
+
}
|
|
2246
|
+
if (candidate && isRootSession(candidate)) {
|
|
2247
|
+
try {
|
|
2248
|
+
const transport = getTransport();
|
|
2249
|
+
const liveSessions = transport.listSessions();
|
|
2250
|
+
if (!liveSessions.includes(candidate)) {
|
|
2251
|
+
const liveRoots = liveSessions.filter((s) => isRootSession(s));
|
|
2252
|
+
if (liveRoots.length === 1) {
|
|
2253
|
+
process.stderr.write(
|
|
2254
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
|
|
2255
|
+
`
|
|
2256
|
+
);
|
|
2257
|
+
return liveRoots[0];
|
|
2258
|
+
} else if (liveRoots.length > 1) {
|
|
2259
|
+
const base = candidate.replace(/\d+$/, "");
|
|
2260
|
+
const match = liveRoots.find((s) => s.startsWith(base));
|
|
2261
|
+
const chosen = match ?? liveRoots[0];
|
|
2262
|
+
process.stderr.write(
|
|
2263
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
|
|
2264
|
+
`
|
|
2265
|
+
);
|
|
2266
|
+
return chosen;
|
|
2267
|
+
}
|
|
2268
|
+
process.stderr.write(
|
|
2269
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
|
|
2270
|
+
`
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
} catch {
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
return candidate;
|
|
2238
2277
|
}
|
|
2239
2278
|
function isEmployeeAlive(sessionName) {
|
|
2240
2279
|
return getTransport().isAlive(sessionName);
|
|
@@ -2636,7 +2675,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2636
2675
|
}
|
|
2637
2676
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
2638
2677
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
2639
|
-
const
|
|
2678
|
+
const baseRtConfig = getAgentRuntime(employeeName);
|
|
2679
|
+
const agentRtConfig = {
|
|
2680
|
+
...baseRtConfig,
|
|
2681
|
+
...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
|
|
2682
|
+
...opts?.modelOverride ? { model: opts.modelOverride } : {}
|
|
2683
|
+
};
|
|
2640
2684
|
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
2641
2685
|
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
2642
2686
|
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
@@ -3274,8 +3318,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3274
3318
|
const complexity = input.complexity ?? "standard";
|
|
3275
3319
|
const sessionScope = earlySessionScope;
|
|
3276
3320
|
await client.execute({
|
|
3277
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
3278
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3321
|
+
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, spawn_runtime, spawn_model, created_at, updated_at)
|
|
3322
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3279
3323
|
args: [
|
|
3280
3324
|
id,
|
|
3281
3325
|
input.title,
|
|
@@ -3295,6 +3339,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3295
3339
|
0,
|
|
3296
3340
|
null,
|
|
3297
3341
|
sessionScope,
|
|
3342
|
+
input.spawnRuntime ?? null,
|
|
3343
|
+
input.spawnModel ?? null,
|
|
3298
3344
|
now,
|
|
3299
3345
|
now
|
|
3300
3346
|
]
|
|
@@ -3351,7 +3397,9 @@ ${input.context}
|
|
|
3351
3397
|
budgetTokens: input.budgetTokens ?? null,
|
|
3352
3398
|
budgetFallbackModel: input.budgetFallbackModel ?? null,
|
|
3353
3399
|
tokensUsed: 0,
|
|
3354
|
-
tokensWarnedAt: null
|
|
3400
|
+
tokensWarnedAt: null,
|
|
3401
|
+
spawnRuntime: input.spawnRuntime ?? null,
|
|
3402
|
+
spawnModel: input.spawnModel ?? null
|
|
3355
3403
|
};
|
|
3356
3404
|
}
|
|
3357
3405
|
async function listTasks(input) {
|
|
@@ -3401,7 +3449,9 @@ async function listTasks(input) {
|
|
|
3401
3449
|
budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
|
|
3402
3450
|
budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
|
|
3403
3451
|
tokensUsed: Number(r.tokens_used ?? 0),
|
|
3404
|
-
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
3452
|
+
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
|
|
3453
|
+
spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
|
|
3454
|
+
spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
|
|
3405
3455
|
}));
|
|
3406
3456
|
}
|
|
3407
3457
|
function isTmuxSessionAlive(identifier) {
|
|
@@ -4868,6 +4918,8 @@ async function updateTask(input) {
|
|
|
4868
4918
|
budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
|
|
4869
4919
|
tokensUsed: Number(row.tokens_used ?? 0),
|
|
4870
4920
|
tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
|
|
4921
|
+
spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
|
|
4922
|
+
spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
|
|
4871
4923
|
nextTask
|
|
4872
4924
|
};
|
|
4873
4925
|
}
|
|
@@ -5721,10 +5773,12 @@ function registerCreateTask(server) {
|
|
|
5721
5773
|
parent_task_id: z.string().optional().describe("Parent task ID or slug. Links this task as a subtask."),
|
|
5722
5774
|
reviewer: z.string().optional().describe("Who should review this task when done. Defaults to assigner."),
|
|
5723
5775
|
budget_tokens: z.number().optional().describe("Max tokens allowed for this task (null = unlimited)"),
|
|
5724
|
-
budget_fallback_model: z.string().optional().describe("Model to route to when budget is exhausted")
|
|
5776
|
+
budget_fallback_model: z.string().optional().describe("Model to route to when budget is exhausted"),
|
|
5777
|
+
spawn_runtime: z.string().optional().describe("Override runtime for spawned session (e.g., 'claude', 'codex', 'opencode')"),
|
|
5778
|
+
spawn_model: z.string().optional().describe("Override model for spawned session (e.g., 'claude-sonnet-4.6', 'claude-haiku-4.5')")
|
|
5725
5779
|
}
|
|
5726
5780
|
},
|
|
5727
|
-
async ({ title, assigned_to, project_name, priority, complexity, context, blocked_by, parent_task_id, reviewer, budget_tokens, budget_fallback_model }) => {
|
|
5781
|
+
async ({ title, assigned_to, project_name, priority, complexity, context, blocked_by, parent_task_id, reviewer, budget_tokens, budget_fallback_model, spawn_runtime, spawn_model }) => {
|
|
5728
5782
|
if (!isCoordinatorName(assigned_to)) {
|
|
5729
5783
|
const license = getLicenseSync();
|
|
5730
5784
|
if (license.plan === "free") {
|
|
@@ -5752,6 +5806,8 @@ function registerCreateTask(server) {
|
|
|
5752
5806
|
reviewer,
|
|
5753
5807
|
budgetTokens: budget_tokens,
|
|
5754
5808
|
budgetFallbackModel: budget_fallback_model,
|
|
5809
|
+
spawnRuntime: spawn_runtime,
|
|
5810
|
+
spawnModel: spawn_model,
|
|
5755
5811
|
// Skip internal dispatch — we handle it below with autoInstance
|
|
5756
5812
|
// support. Without this, createTask fires dispatchTaskToEmployee
|
|
5757
5813
|
// (no autoInstance) in parallel, racing with our ensureEmployee
|
|
@@ -5789,7 +5845,9 @@ function registerCreateTask(server) {
|
|
|
5789
5845
|
const cfg = loadConfigSync2();
|
|
5790
5846
|
const result = ensureEmployee(assigned_to, exeSession, process.cwd(), {
|
|
5791
5847
|
autoInstance: useAutoInstance,
|
|
5792
|
-
maxAutoInstances: useAutoInstance ? cfg.sessionLifecycle.maxAutoInstances : void 0
|
|
5848
|
+
maxAutoInstances: useAutoInstance ? cfg.sessionLifecycle.maxAutoInstances : void 0,
|
|
5849
|
+
runtimeOverride: spawn_runtime ?? void 0,
|
|
5850
|
+
modelOverride: spawn_model ?? void 0
|
|
5793
5851
|
});
|
|
5794
5852
|
switch (result.status) {
|
|
5795
5853
|
case "intercom_sent":
|
|
@@ -527,7 +527,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
|
|
|
527
527
|
import os6 from "os";
|
|
528
528
|
import path7 from "path";
|
|
529
529
|
import { jwtVerify, importSPKI } from "jose";
|
|
530
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
530
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE;
|
|
531
531
|
var init_license = __esm({
|
|
532
532
|
"src/lib/license.ts"() {
|
|
533
533
|
"use strict";
|
|
@@ -535,6 +535,7 @@ var init_license = __esm({
|
|
|
535
535
|
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
536
536
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
537
537
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
538
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
|
|
538
539
|
}
|
|
539
540
|
});
|
|
540
541
|
|
|
@@ -578,6 +579,9 @@ import { fileURLToPath } from "url";
|
|
|
578
579
|
function getMySession() {
|
|
579
580
|
return getTransport().getMySession();
|
|
580
581
|
}
|
|
582
|
+
function isRootSession(name) {
|
|
583
|
+
return name.length > 0 && !name.includes("-");
|
|
584
|
+
}
|
|
581
585
|
function extractRootExe(name) {
|
|
582
586
|
if (!name) return null;
|
|
583
587
|
if (!name.includes("-")) return name;
|
|
@@ -593,9 +597,13 @@ function getParentExe(sessionKey) {
|
|
|
593
597
|
}
|
|
594
598
|
}
|
|
595
599
|
function resolveExeSession() {
|
|
600
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
601
|
+
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
602
|
+
}
|
|
596
603
|
const mySession = getMySession();
|
|
597
604
|
if (!mySession) return null;
|
|
598
605
|
const fromSessionName = extractRootExe(mySession);
|
|
606
|
+
let candidate = null;
|
|
599
607
|
try {
|
|
600
608
|
const key = getSessionKey();
|
|
601
609
|
const parentExe = getParentExe(key);
|
|
@@ -606,13 +614,47 @@ function resolveExeSession() {
|
|
|
606
614
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
607
615
|
`
|
|
608
616
|
);
|
|
609
|
-
|
|
617
|
+
candidate = fromSessionName;
|
|
618
|
+
} else {
|
|
619
|
+
candidate = fromCache;
|
|
610
620
|
}
|
|
611
|
-
return fromCache;
|
|
612
621
|
}
|
|
613
622
|
} catch {
|
|
614
623
|
}
|
|
615
|
-
|
|
624
|
+
if (!candidate) {
|
|
625
|
+
candidate = fromSessionName ?? mySession;
|
|
626
|
+
}
|
|
627
|
+
if (candidate && isRootSession(candidate)) {
|
|
628
|
+
try {
|
|
629
|
+
const transport = getTransport();
|
|
630
|
+
const liveSessions = transport.listSessions();
|
|
631
|
+
if (!liveSessions.includes(candidate)) {
|
|
632
|
+
const liveRoots = liveSessions.filter((s) => isRootSession(s));
|
|
633
|
+
if (liveRoots.length === 1) {
|
|
634
|
+
process.stderr.write(
|
|
635
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
|
|
636
|
+
`
|
|
637
|
+
);
|
|
638
|
+
return liveRoots[0];
|
|
639
|
+
} else if (liveRoots.length > 1) {
|
|
640
|
+
const base = candidate.replace(/\d+$/, "");
|
|
641
|
+
const match = liveRoots.find((s) => s.startsWith(base));
|
|
642
|
+
const chosen = match ?? liveRoots[0];
|
|
643
|
+
process.stderr.write(
|
|
644
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
|
|
645
|
+
`
|
|
646
|
+
);
|
|
647
|
+
return chosen;
|
|
648
|
+
}
|
|
649
|
+
process.stderr.write(
|
|
650
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
|
|
651
|
+
`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
} catch {
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return candidate;
|
|
616
658
|
}
|
|
617
659
|
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
618
660
|
var init_tmux_routing = __esm({
|
|
@@ -801,7 +843,9 @@ async function listTasks(input) {
|
|
|
801
843
|
budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
|
|
802
844
|
budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
|
|
803
845
|
tokensUsed: Number(r.tokens_used ?? 0),
|
|
804
|
-
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
846
|
+
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
|
|
847
|
+
spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
|
|
848
|
+
spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
|
|
805
849
|
}));
|
|
806
850
|
}
|
|
807
851
|
var LANE_KEYWORDS, KEYWORD_INDEX;
|
|
@@ -590,7 +590,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
|
|
|
590
590
|
import os6 from "os";
|
|
591
591
|
import path7 from "path";
|
|
592
592
|
import { jwtVerify, importSPKI } from "jose";
|
|
593
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
593
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE;
|
|
594
594
|
var init_license = __esm({
|
|
595
595
|
"src/lib/license.ts"() {
|
|
596
596
|
"use strict";
|
|
@@ -598,6 +598,7 @@ var init_license = __esm({
|
|
|
598
598
|
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
599
599
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
600
600
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
601
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
|
|
601
602
|
}
|
|
602
603
|
});
|
|
603
604
|
|
|
@@ -683,9 +684,13 @@ function getParentExe(sessionKey) {
|
|
|
683
684
|
}
|
|
684
685
|
}
|
|
685
686
|
function resolveExeSession() {
|
|
687
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
688
|
+
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
689
|
+
}
|
|
686
690
|
const mySession = getMySession();
|
|
687
691
|
if (!mySession) return null;
|
|
688
692
|
const fromSessionName = extractRootExe(mySession);
|
|
693
|
+
let candidate = null;
|
|
689
694
|
try {
|
|
690
695
|
const key = getSessionKey();
|
|
691
696
|
const parentExe = getParentExe(key);
|
|
@@ -696,13 +701,47 @@ function resolveExeSession() {
|
|
|
696
701
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
697
702
|
`
|
|
698
703
|
);
|
|
699
|
-
|
|
704
|
+
candidate = fromSessionName;
|
|
705
|
+
} else {
|
|
706
|
+
candidate = fromCache;
|
|
700
707
|
}
|
|
701
|
-
return fromCache;
|
|
702
708
|
}
|
|
703
709
|
} catch {
|
|
704
710
|
}
|
|
705
|
-
|
|
711
|
+
if (!candidate) {
|
|
712
|
+
candidate = fromSessionName ?? mySession;
|
|
713
|
+
}
|
|
714
|
+
if (candidate && isRootSession(candidate)) {
|
|
715
|
+
try {
|
|
716
|
+
const transport = getTransport();
|
|
717
|
+
const liveSessions = transport.listSessions();
|
|
718
|
+
if (!liveSessions.includes(candidate)) {
|
|
719
|
+
const liveRoots = liveSessions.filter((s) => isRootSession(s));
|
|
720
|
+
if (liveRoots.length === 1) {
|
|
721
|
+
process.stderr.write(
|
|
722
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
|
|
723
|
+
`
|
|
724
|
+
);
|
|
725
|
+
return liveRoots[0];
|
|
726
|
+
} else if (liveRoots.length > 1) {
|
|
727
|
+
const base = candidate.replace(/\d+$/, "");
|
|
728
|
+
const match = liveRoots.find((s) => s.startsWith(base));
|
|
729
|
+
const chosen = match ?? liveRoots[0];
|
|
730
|
+
process.stderr.write(
|
|
731
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
|
|
732
|
+
`
|
|
733
|
+
);
|
|
734
|
+
return chosen;
|
|
735
|
+
}
|
|
736
|
+
process.stderr.write(
|
|
737
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
|
|
738
|
+
`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
} catch {
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return candidate;
|
|
706
745
|
}
|
|
707
746
|
function isEmployeeAlive(sessionName) {
|
|
708
747
|
return getTransport().isAlive(sessionName);
|
|
@@ -964,7 +964,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
|
|
|
964
964
|
import os6 from "os";
|
|
965
965
|
import path7 from "path";
|
|
966
966
|
import { jwtVerify, importSPKI } from "jose";
|
|
967
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
967
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, PLAN_LIMITS;
|
|
968
968
|
var init_license = __esm({
|
|
969
969
|
"src/lib/license.ts"() {
|
|
970
970
|
"use strict";
|
|
@@ -972,6 +972,7 @@ var init_license = __esm({
|
|
|
972
972
|
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
973
973
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
974
974
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
975
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
|
|
975
976
|
PLAN_LIMITS = {
|
|
976
977
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
977
978
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -1978,9 +1979,13 @@ function getDispatchedBy(sessionKey) {
|
|
|
1978
1979
|
}
|
|
1979
1980
|
}
|
|
1980
1981
|
function resolveExeSession() {
|
|
1982
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
1983
|
+
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
1984
|
+
}
|
|
1981
1985
|
const mySession = getMySession();
|
|
1982
1986
|
if (!mySession) return null;
|
|
1983
1987
|
const fromSessionName = extractRootExe(mySession);
|
|
1988
|
+
let candidate = null;
|
|
1984
1989
|
try {
|
|
1985
1990
|
const key = getSessionKey();
|
|
1986
1991
|
const parentExe = getParentExe(key);
|
|
@@ -1991,13 +1996,47 @@ function resolveExeSession() {
|
|
|
1991
1996
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
1992
1997
|
`
|
|
1993
1998
|
);
|
|
1994
|
-
|
|
1999
|
+
candidate = fromSessionName;
|
|
2000
|
+
} else {
|
|
2001
|
+
candidate = fromCache;
|
|
1995
2002
|
}
|
|
1996
|
-
return fromCache;
|
|
1997
2003
|
}
|
|
1998
2004
|
} catch {
|
|
1999
2005
|
}
|
|
2000
|
-
|
|
2006
|
+
if (!candidate) {
|
|
2007
|
+
candidate = fromSessionName ?? mySession;
|
|
2008
|
+
}
|
|
2009
|
+
if (candidate && isRootSession(candidate)) {
|
|
2010
|
+
try {
|
|
2011
|
+
const transport = getTransport();
|
|
2012
|
+
const liveSessions = transport.listSessions();
|
|
2013
|
+
if (!liveSessions.includes(candidate)) {
|
|
2014
|
+
const liveRoots = liveSessions.filter((s) => isRootSession(s));
|
|
2015
|
+
if (liveRoots.length === 1) {
|
|
2016
|
+
process.stderr.write(
|
|
2017
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
|
|
2018
|
+
`
|
|
2019
|
+
);
|
|
2020
|
+
return liveRoots[0];
|
|
2021
|
+
} else if (liveRoots.length > 1) {
|
|
2022
|
+
const base = candidate.replace(/\d+$/, "");
|
|
2023
|
+
const match = liveRoots.find((s) => s.startsWith(base));
|
|
2024
|
+
const chosen = match ?? liveRoots[0];
|
|
2025
|
+
process.stderr.write(
|
|
2026
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
|
|
2027
|
+
`
|
|
2028
|
+
);
|
|
2029
|
+
return chosen;
|
|
2030
|
+
}
|
|
2031
|
+
process.stderr.write(
|
|
2032
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
|
|
2033
|
+
`
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
} catch {
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
return candidate;
|
|
2001
2040
|
}
|
|
2002
2041
|
function isEmployeeAlive(sessionName) {
|
|
2003
2042
|
return getTransport().isAlive(sessionName);
|
|
@@ -2399,7 +2438,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2399
2438
|
}
|
|
2400
2439
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
2401
2440
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
2402
|
-
const
|
|
2441
|
+
const baseRtConfig = getAgentRuntime(employeeName);
|
|
2442
|
+
const agentRtConfig = {
|
|
2443
|
+
...baseRtConfig,
|
|
2444
|
+
...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
|
|
2445
|
+
...opts?.modelOverride ? { model: opts.modelOverride } : {}
|
|
2446
|
+
};
|
|
2403
2447
|
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
2404
2448
|
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
2405
2449
|
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
@@ -3037,8 +3081,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3037
3081
|
const complexity = input.complexity ?? "standard";
|
|
3038
3082
|
const sessionScope = earlySessionScope;
|
|
3039
3083
|
await client.execute({
|
|
3040
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
3041
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3084
|
+
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, spawn_runtime, spawn_model, created_at, updated_at)
|
|
3085
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3042
3086
|
args: [
|
|
3043
3087
|
id,
|
|
3044
3088
|
input.title,
|
|
@@ -3058,6 +3102,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3058
3102
|
0,
|
|
3059
3103
|
null,
|
|
3060
3104
|
sessionScope,
|
|
3105
|
+
input.spawnRuntime ?? null,
|
|
3106
|
+
input.spawnModel ?? null,
|
|
3061
3107
|
now,
|
|
3062
3108
|
now
|
|
3063
3109
|
]
|
|
@@ -3114,7 +3160,9 @@ ${input.context}
|
|
|
3114
3160
|
budgetTokens: input.budgetTokens ?? null,
|
|
3115
3161
|
budgetFallbackModel: input.budgetFallbackModel ?? null,
|
|
3116
3162
|
tokensUsed: 0,
|
|
3117
|
-
tokensWarnedAt: null
|
|
3163
|
+
tokensWarnedAt: null,
|
|
3164
|
+
spawnRuntime: input.spawnRuntime ?? null,
|
|
3165
|
+
spawnModel: input.spawnModel ?? null
|
|
3118
3166
|
};
|
|
3119
3167
|
}
|
|
3120
3168
|
async function listTasks(input) {
|
|
@@ -3164,7 +3212,9 @@ async function listTasks(input) {
|
|
|
3164
3212
|
budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
|
|
3165
3213
|
budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
|
|
3166
3214
|
tokensUsed: Number(r.tokens_used ?? 0),
|
|
3167
|
-
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
3215
|
+
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
|
|
3216
|
+
spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
|
|
3217
|
+
spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
|
|
3168
3218
|
}));
|
|
3169
3219
|
}
|
|
3170
3220
|
function isTmuxSessionAlive(identifier) {
|
|
@@ -4631,6 +4681,8 @@ async function updateTask(input) {
|
|
|
4631
4681
|
budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
|
|
4632
4682
|
tokensUsed: Number(row.tokens_used ?? 0),
|
|
4633
4683
|
tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
|
|
4684
|
+
spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
|
|
4685
|
+
spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
|
|
4634
4686
|
nextTask
|
|
4635
4687
|
};
|
|
4636
4688
|
}
|