@askexenow/exe-os 0.8.85 → 0.8.87
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/cleanup-stale-review-tasks.js +57 -19
- package/dist/bin/cli.js +510 -340
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +3 -3
- package/dist/bin/exe-boot.js +344 -346
- package/dist/bin/exe-dispatch.js +375 -250
- package/dist/bin/exe-forget.js +5 -1
- package/dist/bin/exe-gateway.js +260 -135
- package/dist/bin/exe-healthcheck.js +133 -1
- package/dist/bin/exe-heartbeat.js +72 -31
- package/dist/bin/exe-link.js +25 -2
- package/dist/bin/exe-new-employee.js +22 -0
- package/dist/bin/exe-pending-messages.js +55 -17
- package/dist/bin/exe-pending-reviews.js +57 -19
- package/dist/bin/exe-search.js +6 -2
- package/dist/bin/exe-session-cleanup.js +260 -135
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +57 -19
- package/dist/bin/git-sweep.js +391 -266
- package/dist/bin/install.js +22 -0
- package/dist/bin/scan-tasks.js +394 -269
- package/dist/bin/setup.js +50 -5
- package/dist/gateway/index.js +257 -132
- package/dist/hooks/bug-report-worker.js +242 -117
- package/dist/hooks/commit-complete.js +389 -264
- package/dist/hooks/error-recall.js +6 -2
- package/dist/hooks/ingest-worker.js +314 -193
- package/dist/hooks/post-compact.js +84 -46
- package/dist/hooks/pre-compact.js +272 -147
- package/dist/hooks/pre-tool-use.js +104 -66
- package/dist/hooks/prompt-submit.js +126 -66
- package/dist/hooks/session-end.js +277 -152
- package/dist/hooks/session-start.js +70 -28
- package/dist/hooks/stop.js +90 -52
- package/dist/hooks/subagent-stop.js +84 -46
- package/dist/hooks/summary-worker.js +175 -114
- package/dist/index.js +296 -171
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +25 -2
- package/dist/lib/exe-daemon.js +338 -213
- package/dist/lib/hybrid-search.js +7 -2
- package/dist/lib/messaging.js +95 -39
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/tasks.js +242 -117
- package/dist/lib/tmux-routing.js +314 -189
- package/dist/mcp/server.js +573 -274
- package/dist/mcp/tools/create-task.js +260 -135
- package/dist/mcp/tools/list-tasks.js +68 -30
- package/dist/mcp/tools/send-message.js +100 -44
- package/dist/mcp/tools/update-task.js +123 -67
- package/dist/runtime/index.js +276 -151
- package/dist/tui/App.js +479 -354
- package/package.json +1 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -2219,18 +2219,69 @@ var init_provider_table = __esm({
|
|
|
2219
2219
|
}
|
|
2220
2220
|
});
|
|
2221
2221
|
|
|
2222
|
-
// src/lib/
|
|
2223
|
-
|
|
2222
|
+
// src/lib/runtime-table.ts
|
|
2223
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
2224
|
+
var init_runtime_table = __esm({
|
|
2225
|
+
"src/lib/runtime-table.ts"() {
|
|
2226
|
+
"use strict";
|
|
2227
|
+
RUNTIME_TABLE = {
|
|
2228
|
+
codex: {
|
|
2229
|
+
binary: "codex",
|
|
2230
|
+
launchMode: "exec",
|
|
2231
|
+
autoApproveFlag: "--full-auto",
|
|
2232
|
+
inlineFlag: "--no-alt-screen",
|
|
2233
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
2234
|
+
defaultModel: "gpt-5.4"
|
|
2235
|
+
}
|
|
2236
|
+
};
|
|
2237
|
+
DEFAULT_RUNTIME = "claude";
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
|
|
2241
|
+
// src/lib/agent-config.ts
|
|
2242
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
2224
2243
|
import path7 from "path";
|
|
2244
|
+
function loadAgentConfig() {
|
|
2245
|
+
if (!existsSync7(AGENT_CONFIG_PATH)) return {};
|
|
2246
|
+
try {
|
|
2247
|
+
return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
|
|
2248
|
+
} catch {
|
|
2249
|
+
return {};
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
function getAgentRuntime(agentId) {
|
|
2253
|
+
const config = loadAgentConfig();
|
|
2254
|
+
const entry = config[agentId];
|
|
2255
|
+
if (entry) return entry;
|
|
2256
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
2257
|
+
}
|
|
2258
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
2259
|
+
var init_agent_config = __esm({
|
|
2260
|
+
"src/lib/agent-config.ts"() {
|
|
2261
|
+
"use strict";
|
|
2262
|
+
init_config();
|
|
2263
|
+
init_runtime_table();
|
|
2264
|
+
AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
|
|
2265
|
+
DEFAULT_MODELS = {
|
|
2266
|
+
claude: "claude-opus-4",
|
|
2267
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
2268
|
+
opencode: "minimax-m2.7"
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
|
|
2273
|
+
// src/lib/intercom-queue.ts
|
|
2274
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
2275
|
+
import path8 from "path";
|
|
2225
2276
|
import os6 from "os";
|
|
2226
2277
|
function ensureDir() {
|
|
2227
|
-
const dir =
|
|
2228
|
-
if (!
|
|
2278
|
+
const dir = path8.dirname(QUEUE_PATH);
|
|
2279
|
+
if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
|
|
2229
2280
|
}
|
|
2230
2281
|
function readQueue() {
|
|
2231
2282
|
try {
|
|
2232
|
-
if (!
|
|
2233
|
-
return JSON.parse(
|
|
2283
|
+
if (!existsSync8(QUEUE_PATH)) return [];
|
|
2284
|
+
return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
|
|
2234
2285
|
} catch {
|
|
2235
2286
|
return [];
|
|
2236
2287
|
}
|
|
@@ -2238,7 +2289,7 @@ function readQueue() {
|
|
|
2238
2289
|
function writeQueue(queue) {
|
|
2239
2290
|
ensureDir();
|
|
2240
2291
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
2241
|
-
|
|
2292
|
+
writeFileSync4(tmp, JSON.stringify(queue, null, 2));
|
|
2242
2293
|
renameSync3(tmp, QUEUE_PATH);
|
|
2243
2294
|
}
|
|
2244
2295
|
function queueIntercom(targetSession, reason) {
|
|
@@ -2262,25 +2313,25 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2262
2313
|
var init_intercom_queue = __esm({
|
|
2263
2314
|
"src/lib/intercom-queue.ts"() {
|
|
2264
2315
|
"use strict";
|
|
2265
|
-
QUEUE_PATH =
|
|
2316
|
+
QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
2266
2317
|
TTL_MS = 60 * 60 * 1e3;
|
|
2267
|
-
INTERCOM_LOG =
|
|
2318
|
+
INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2268
2319
|
}
|
|
2269
2320
|
});
|
|
2270
2321
|
|
|
2271
2322
|
// src/lib/license.ts
|
|
2272
|
-
import { readFileSync as
|
|
2323
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
2273
2324
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2274
|
-
import
|
|
2325
|
+
import path9 from "path";
|
|
2275
2326
|
import { jwtVerify, importSPKI } from "jose";
|
|
2276
2327
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
2277
2328
|
var init_license = __esm({
|
|
2278
2329
|
"src/lib/license.ts"() {
|
|
2279
2330
|
"use strict";
|
|
2280
2331
|
init_config();
|
|
2281
|
-
LICENSE_PATH =
|
|
2282
|
-
CACHE_PATH =
|
|
2283
|
-
DEVICE_ID_PATH =
|
|
2332
|
+
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
2333
|
+
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
2334
|
+
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
2284
2335
|
PLAN_LIMITS = {
|
|
2285
2336
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
2286
2337
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -2292,12 +2343,12 @@ var init_license = __esm({
|
|
|
2292
2343
|
});
|
|
2293
2344
|
|
|
2294
2345
|
// src/lib/plan-limits.ts
|
|
2295
|
-
import { readFileSync as
|
|
2296
|
-
import
|
|
2346
|
+
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
2347
|
+
import path10 from "path";
|
|
2297
2348
|
function getLicenseSync() {
|
|
2298
2349
|
try {
|
|
2299
|
-
if (!
|
|
2300
|
-
const raw = JSON.parse(
|
|
2350
|
+
if (!existsSync10(CACHE_PATH2)) return freeLicense();
|
|
2351
|
+
const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
|
|
2301
2352
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2302
2353
|
const parts = raw.token.split(".");
|
|
2303
2354
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2335,8 +2386,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2335
2386
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
2336
2387
|
let count = 0;
|
|
2337
2388
|
try {
|
|
2338
|
-
if (
|
|
2339
|
-
const raw =
|
|
2389
|
+
if (existsSync10(filePath)) {
|
|
2390
|
+
const raw = readFileSync8(filePath, "utf8");
|
|
2340
2391
|
const employees = JSON.parse(raw);
|
|
2341
2392
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2342
2393
|
}
|
|
@@ -2365,7 +2416,7 @@ var init_plan_limits = __esm({
|
|
|
2365
2416
|
this.name = "PlanLimitError";
|
|
2366
2417
|
}
|
|
2367
2418
|
};
|
|
2368
|
-
CACHE_PATH2 =
|
|
2419
|
+
CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2369
2420
|
}
|
|
2370
2421
|
});
|
|
2371
2422
|
|
|
@@ -2713,13 +2764,13 @@ __export(tmux_routing_exports, {
|
|
|
2713
2764
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
2714
2765
|
});
|
|
2715
2766
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
2716
|
-
import { readFileSync as
|
|
2717
|
-
import
|
|
2767
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2768
|
+
import path11 from "path";
|
|
2718
2769
|
import os7 from "os";
|
|
2719
2770
|
import { fileURLToPath } from "url";
|
|
2720
2771
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
2721
2772
|
function spawnLockPath(sessionName) {
|
|
2722
|
-
return
|
|
2773
|
+
return path11.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
2723
2774
|
}
|
|
2724
2775
|
function isProcessAlive(pid) {
|
|
2725
2776
|
try {
|
|
@@ -2730,13 +2781,13 @@ function isProcessAlive(pid) {
|
|
|
2730
2781
|
}
|
|
2731
2782
|
}
|
|
2732
2783
|
function acquireSpawnLock(sessionName) {
|
|
2733
|
-
if (!
|
|
2734
|
-
|
|
2784
|
+
if (!existsSync11(SPAWN_LOCK_DIR)) {
|
|
2785
|
+
mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
|
|
2735
2786
|
}
|
|
2736
2787
|
const lockFile = spawnLockPath(sessionName);
|
|
2737
|
-
if (
|
|
2788
|
+
if (existsSync11(lockFile)) {
|
|
2738
2789
|
try {
|
|
2739
|
-
const lock = JSON.parse(
|
|
2790
|
+
const lock = JSON.parse(readFileSync9(lockFile, "utf8"));
|
|
2740
2791
|
const age = Date.now() - lock.timestamp;
|
|
2741
2792
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
2742
2793
|
return false;
|
|
@@ -2744,7 +2795,7 @@ function acquireSpawnLock(sessionName) {
|
|
|
2744
2795
|
} catch {
|
|
2745
2796
|
}
|
|
2746
2797
|
}
|
|
2747
|
-
|
|
2798
|
+
writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
2748
2799
|
return true;
|
|
2749
2800
|
}
|
|
2750
2801
|
function releaseSpawnLock(sessionName) {
|
|
@@ -2756,13 +2807,13 @@ function releaseSpawnLock(sessionName) {
|
|
|
2756
2807
|
function resolveBehaviorsExporterScript() {
|
|
2757
2808
|
try {
|
|
2758
2809
|
const thisFile = fileURLToPath(import.meta.url);
|
|
2759
|
-
const scriptPath =
|
|
2760
|
-
|
|
2810
|
+
const scriptPath = path11.join(
|
|
2811
|
+
path11.dirname(thisFile),
|
|
2761
2812
|
"..",
|
|
2762
2813
|
"bin",
|
|
2763
2814
|
"exe-export-behaviors.js"
|
|
2764
2815
|
);
|
|
2765
|
-
return
|
|
2816
|
+
return existsSync11(scriptPath) ? scriptPath : null;
|
|
2766
2817
|
} catch {
|
|
2767
2818
|
return null;
|
|
2768
2819
|
}
|
|
@@ -2828,12 +2879,12 @@ function extractRootExe(name) {
|
|
|
2828
2879
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
2829
2880
|
}
|
|
2830
2881
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
2831
|
-
if (!
|
|
2832
|
-
|
|
2882
|
+
if (!existsSync11(SESSION_CACHE)) {
|
|
2883
|
+
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
2833
2884
|
}
|
|
2834
2885
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
2835
|
-
const filePath =
|
|
2836
|
-
|
|
2886
|
+
const filePath = path11.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
2887
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
2837
2888
|
parentExe: rootExe,
|
|
2838
2889
|
dispatchedBy: dispatchedBy || rootExe,
|
|
2839
2890
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2841,7 +2892,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
2841
2892
|
}
|
|
2842
2893
|
function getParentExe(sessionKey) {
|
|
2843
2894
|
try {
|
|
2844
|
-
const data = JSON.parse(
|
|
2895
|
+
const data = JSON.parse(readFileSync9(path11.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2845
2896
|
return data.parentExe || null;
|
|
2846
2897
|
} catch {
|
|
2847
2898
|
return null;
|
|
@@ -2849,8 +2900,8 @@ function getParentExe(sessionKey) {
|
|
|
2849
2900
|
}
|
|
2850
2901
|
function getDispatchedBy(sessionKey) {
|
|
2851
2902
|
try {
|
|
2852
|
-
const data = JSON.parse(
|
|
2853
|
-
|
|
2903
|
+
const data = JSON.parse(readFileSync9(
|
|
2904
|
+
path11.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
2854
2905
|
"utf8"
|
|
2855
2906
|
));
|
|
2856
2907
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -2911,32 +2962,50 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
2911
2962
|
}
|
|
2912
2963
|
function readDebounceState() {
|
|
2913
2964
|
try {
|
|
2914
|
-
if (!
|
|
2915
|
-
|
|
2965
|
+
if (!existsSync11(DEBOUNCE_FILE)) return {};
|
|
2966
|
+
const raw = JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
|
|
2967
|
+
const state = {};
|
|
2968
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
2969
|
+
if (typeof val === "number") {
|
|
2970
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
2971
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
2972
|
+
state[key] = val;
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
return state;
|
|
2916
2976
|
} catch {
|
|
2917
2977
|
return {};
|
|
2918
2978
|
}
|
|
2919
2979
|
}
|
|
2920
2980
|
function writeDebounceState(state) {
|
|
2921
2981
|
try {
|
|
2922
|
-
if (!
|
|
2923
|
-
|
|
2982
|
+
if (!existsSync11(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
2983
|
+
writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
|
|
2924
2984
|
} catch {
|
|
2925
2985
|
}
|
|
2926
2986
|
}
|
|
2927
2987
|
function isDebounced(targetSession) {
|
|
2928
2988
|
const state = readDebounceState();
|
|
2929
|
-
const
|
|
2930
|
-
|
|
2989
|
+
const entry = state[targetSession];
|
|
2990
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
2991
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
2992
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
2993
|
+
state[targetSession].pending++;
|
|
2994
|
+
writeDebounceState(state);
|
|
2995
|
+
return true;
|
|
2996
|
+
}
|
|
2997
|
+
return false;
|
|
2931
2998
|
}
|
|
2932
2999
|
function recordDebounce(targetSession) {
|
|
2933
3000
|
const state = readDebounceState();
|
|
2934
|
-
state[targetSession]
|
|
3001
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
3002
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
2935
3003
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
2936
3004
|
for (const key of Object.keys(state)) {
|
|
2937
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
3005
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
2938
3006
|
}
|
|
2939
3007
|
writeDebounceState(state);
|
|
3008
|
+
return batched;
|
|
2940
3009
|
}
|
|
2941
3010
|
function logIntercom(msg) {
|
|
2942
3011
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -2981,7 +3050,7 @@ function sendIntercom(targetSession) {
|
|
|
2981
3050
|
return "skipped_exe";
|
|
2982
3051
|
}
|
|
2983
3052
|
if (isDebounced(targetSession)) {
|
|
2984
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
3053
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
2985
3054
|
return "debounced";
|
|
2986
3055
|
}
|
|
2987
3056
|
try {
|
|
@@ -2993,14 +3062,14 @@ function sendIntercom(targetSession) {
|
|
|
2993
3062
|
const sessionState = getSessionState(targetSession);
|
|
2994
3063
|
if (sessionState === "no_claude") {
|
|
2995
3064
|
queueIntercom(targetSession, "claude not running in session");
|
|
2996
|
-
recordDebounce(targetSession);
|
|
2997
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
3065
|
+
const batched2 = recordDebounce(targetSession);
|
|
3066
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
2998
3067
|
return "queued";
|
|
2999
3068
|
}
|
|
3000
3069
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
3001
3070
|
queueIntercom(targetSession, "session busy at send time");
|
|
3002
|
-
recordDebounce(targetSession);
|
|
3003
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
3071
|
+
const batched2 = recordDebounce(targetSession);
|
|
3072
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
3004
3073
|
return "queued";
|
|
3005
3074
|
}
|
|
3006
3075
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -3008,8 +3077,8 @@ function sendIntercom(targetSession) {
|
|
|
3008
3077
|
transport.sendKeys(targetSession, "q");
|
|
3009
3078
|
}
|
|
3010
3079
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
3011
|
-
recordDebounce(targetSession);
|
|
3012
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
3080
|
+
const batched = recordDebounce(targetSession);
|
|
3081
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
3013
3082
|
return "delivered";
|
|
3014
3083
|
} catch {
|
|
3015
3084
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -3111,26 +3180,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3111
3180
|
const transport = getTransport();
|
|
3112
3181
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3113
3182
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3114
|
-
const logDir =
|
|
3115
|
-
const logFile =
|
|
3116
|
-
if (!
|
|
3117
|
-
|
|
3183
|
+
const logDir = path11.join(os7.homedir(), ".exe-os", "session-logs");
|
|
3184
|
+
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3185
|
+
if (!existsSync11(logDir)) {
|
|
3186
|
+
mkdirSync6(logDir, { recursive: true });
|
|
3118
3187
|
}
|
|
3119
3188
|
transport.kill(sessionName);
|
|
3120
3189
|
let cleanupSuffix = "";
|
|
3121
3190
|
try {
|
|
3122
3191
|
const thisFile = fileURLToPath(import.meta.url);
|
|
3123
|
-
const cleanupScript =
|
|
3124
|
-
if (
|
|
3192
|
+
const cleanupScript = path11.join(path11.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
3193
|
+
if (existsSync11(cleanupScript)) {
|
|
3125
3194
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
3126
3195
|
}
|
|
3127
3196
|
} catch {
|
|
3128
3197
|
}
|
|
3129
3198
|
try {
|
|
3130
|
-
const claudeJsonPath =
|
|
3199
|
+
const claudeJsonPath = path11.join(os7.homedir(), ".claude.json");
|
|
3131
3200
|
let claudeJson = {};
|
|
3132
3201
|
try {
|
|
3133
|
-
claudeJson = JSON.parse(
|
|
3202
|
+
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
3134
3203
|
} catch {
|
|
3135
3204
|
}
|
|
3136
3205
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -3138,17 +3207,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3138
3207
|
const trustDir = opts?.cwd ?? projectDir;
|
|
3139
3208
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
3140
3209
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
3141
|
-
|
|
3210
|
+
writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
3142
3211
|
} catch {
|
|
3143
3212
|
}
|
|
3144
3213
|
try {
|
|
3145
|
-
const settingsDir =
|
|
3214
|
+
const settingsDir = path11.join(os7.homedir(), ".claude", "projects");
|
|
3146
3215
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3147
|
-
const projSettingsDir =
|
|
3148
|
-
const settingsPath =
|
|
3216
|
+
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
3217
|
+
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
3149
3218
|
let settings = {};
|
|
3150
3219
|
try {
|
|
3151
|
-
settings = JSON.parse(
|
|
3220
|
+
settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
|
|
3152
3221
|
} catch {
|
|
3153
3222
|
}
|
|
3154
3223
|
const perms = settings.permissions ?? {};
|
|
@@ -3176,20 +3245,23 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3176
3245
|
if (changed) {
|
|
3177
3246
|
perms.allow = allow;
|
|
3178
3247
|
settings.permissions = perms;
|
|
3179
|
-
|
|
3180
|
-
|
|
3248
|
+
mkdirSync6(projSettingsDir, { recursive: true });
|
|
3249
|
+
writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
3181
3250
|
}
|
|
3182
3251
|
} catch {
|
|
3183
3252
|
}
|
|
3184
3253
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
3185
3254
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
3186
|
-
const
|
|
3255
|
+
const agentRtConfig = getAgentRuntime(employeeName);
|
|
3256
|
+
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
3257
|
+
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
3258
|
+
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
3187
3259
|
const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
|
|
3188
3260
|
let identityFlag = "";
|
|
3189
3261
|
let behaviorsFlag = "";
|
|
3190
3262
|
let legacyFallbackWarned = false;
|
|
3191
3263
|
if (!useExeAgent && !useBinSymlink) {
|
|
3192
|
-
const identityPath =
|
|
3264
|
+
const identityPath = path11.join(
|
|
3193
3265
|
os7.homedir(),
|
|
3194
3266
|
".exe-os",
|
|
3195
3267
|
"identity",
|
|
@@ -3199,13 +3271,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3199
3271
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
3200
3272
|
if (hasAgentFlag) {
|
|
3201
3273
|
identityFlag = ` --agent ${employeeName}`;
|
|
3202
|
-
} else if (
|
|
3274
|
+
} else if (existsSync11(identityPath)) {
|
|
3203
3275
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
3204
3276
|
legacyFallbackWarned = true;
|
|
3205
3277
|
}
|
|
3206
3278
|
const behaviorsFile = exportBehaviorsSync(
|
|
3207
3279
|
employeeName,
|
|
3208
|
-
|
|
3280
|
+
path11.basename(spawnCwd),
|
|
3209
3281
|
sessionName
|
|
3210
3282
|
);
|
|
3211
3283
|
if (behaviorsFile) {
|
|
@@ -3220,16 +3292,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3220
3292
|
}
|
|
3221
3293
|
let sessionContextFlag = "";
|
|
3222
3294
|
try {
|
|
3223
|
-
const ctxDir =
|
|
3224
|
-
|
|
3225
|
-
const ctxFile =
|
|
3295
|
+
const ctxDir = path11.join(os7.homedir(), ".exe-os", "session-cache");
|
|
3296
|
+
mkdirSync6(ctxDir, { recursive: true });
|
|
3297
|
+
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3226
3298
|
const ctxContent = [
|
|
3227
3299
|
`## Session Context`,
|
|
3228
3300
|
`You are running in tmux session: ${sessionName}.`,
|
|
3229
3301
|
`Your parent coordinator session is ${exeSession}.`,
|
|
3230
3302
|
`Your employees (if any) use the -${exeSession} suffix.`
|
|
3231
3303
|
].join("\n");
|
|
3232
|
-
|
|
3304
|
+
writeFileSync6(ctxFile, ctxContent);
|
|
3233
3305
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
3234
3306
|
} catch {
|
|
3235
3307
|
}
|
|
@@ -3243,9 +3315,48 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3243
3315
|
}
|
|
3244
3316
|
}
|
|
3245
3317
|
}
|
|
3318
|
+
if (useCodex) {
|
|
3319
|
+
const codexCfg = RUNTIME_TABLE.codex;
|
|
3320
|
+
if (codexCfg?.apiKeyEnv) {
|
|
3321
|
+
const keyVal = process.env[codexCfg.apiKeyEnv];
|
|
3322
|
+
if (keyVal) {
|
|
3323
|
+
envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
|
|
3327
|
+
}
|
|
3328
|
+
if (useOpencode) {
|
|
3329
|
+
const ocCfg = PROVIDER_TABLE.opencode;
|
|
3330
|
+
if (ocCfg?.apiKeyEnv) {
|
|
3331
|
+
const keyVal = process.env[ocCfg.apiKeyEnv];
|
|
3332
|
+
if (keyVal) {
|
|
3333
|
+
envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
3337
|
+
}
|
|
3338
|
+
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
3339
|
+
const defaultClaudeModel = DEFAULT_MODELS.claude;
|
|
3340
|
+
if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
|
|
3341
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3246
3344
|
let spawnCommand;
|
|
3247
3345
|
if (useExeAgent) {
|
|
3248
3346
|
spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
|
|
3347
|
+
} else if (useCodex) {
|
|
3348
|
+
process.stderr.write(
|
|
3349
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
|
|
3350
|
+
`
|
|
3351
|
+
);
|
|
3352
|
+
spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
|
|
3353
|
+
} else if (useOpencode) {
|
|
3354
|
+
const binName = `${employeeName}-opencode`;
|
|
3355
|
+
process.stderr.write(
|
|
3356
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
|
|
3357
|
+
`
|
|
3358
|
+
);
|
|
3359
|
+
spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
|
|
3249
3360
|
} else if (useBinSymlink) {
|
|
3250
3361
|
const binName = `${employeeName}-${ccProvider}`;
|
|
3251
3362
|
process.stderr.write(
|
|
@@ -3267,11 +3378,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3267
3378
|
transport.pipeLog(sessionName, logFile);
|
|
3268
3379
|
try {
|
|
3269
3380
|
const mySession = getMySession();
|
|
3270
|
-
const dispatchInfo =
|
|
3271
|
-
|
|
3381
|
+
const dispatchInfo = path11.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
3382
|
+
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
3272
3383
|
dispatchedBy: mySession,
|
|
3273
3384
|
rootExe: exeSession,
|
|
3274
|
-
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
|
|
3385
|
+
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
3386
|
+
runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
|
|
3387
|
+
model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
|
|
3275
3388
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3276
3389
|
}));
|
|
3277
3390
|
} catch {
|
|
@@ -3289,6 +3402,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3289
3402
|
booted = true;
|
|
3290
3403
|
break;
|
|
3291
3404
|
}
|
|
3405
|
+
} else if (useCodex) {
|
|
3406
|
+
if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
|
|
3407
|
+
booted = true;
|
|
3408
|
+
break;
|
|
3409
|
+
}
|
|
3292
3410
|
} else {
|
|
3293
3411
|
if (pane.includes("Claude Code") || pane.includes("\u276F")) {
|
|
3294
3412
|
booted = true;
|
|
@@ -3300,9 +3418,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3300
3418
|
}
|
|
3301
3419
|
if (!booted) {
|
|
3302
3420
|
releaseSpawnLock(sessionName);
|
|
3303
|
-
|
|
3421
|
+
const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
|
|
3422
|
+
return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
|
|
3304
3423
|
}
|
|
3305
|
-
if (!useExeAgent) {
|
|
3424
|
+
if (!useExeAgent && !useCodex) {
|
|
3306
3425
|
try {
|
|
3307
3426
|
transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
|
|
3308
3427
|
} catch {
|
|
@@ -3329,17 +3448,19 @@ var init_tmux_routing = __esm({
|
|
|
3329
3448
|
init_cc_agent_support();
|
|
3330
3449
|
init_mcp_prefix();
|
|
3331
3450
|
init_provider_table();
|
|
3451
|
+
init_agent_config();
|
|
3452
|
+
init_runtime_table();
|
|
3332
3453
|
init_intercom_queue();
|
|
3333
3454
|
init_plan_limits();
|
|
3334
3455
|
init_employees();
|
|
3335
|
-
SPAWN_LOCK_DIR =
|
|
3336
|
-
SESSION_CACHE =
|
|
3456
|
+
SPAWN_LOCK_DIR = path11.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
3457
|
+
SESSION_CACHE = path11.join(os7.homedir(), ".exe-os", "session-cache");
|
|
3337
3458
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3338
3459
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
3339
3460
|
VERIFY_PANE_LINES = 200;
|
|
3340
3461
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3341
|
-
INTERCOM_LOG2 =
|
|
3342
|
-
DEBOUNCE_FILE =
|
|
3462
|
+
INTERCOM_LOG2 = path11.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
3463
|
+
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3343
3464
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3344
3465
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
3345
3466
|
}
|
|
@@ -3371,11 +3492,11 @@ var init_task_scope = __esm({
|
|
|
3371
3492
|
|
|
3372
3493
|
// src/lib/tasks-crud.ts
|
|
3373
3494
|
import crypto3 from "crypto";
|
|
3374
|
-
import
|
|
3495
|
+
import path12 from "path";
|
|
3375
3496
|
import os8 from "os";
|
|
3376
3497
|
import { execSync as execSync5 } from "child_process";
|
|
3377
3498
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
3378
|
-
import { existsSync as
|
|
3499
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
3379
3500
|
async function writeCheckpoint(input) {
|
|
3380
3501
|
const client = getClient();
|
|
3381
3502
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -3550,8 +3671,8 @@ ${laneWarning}` : laneWarning;
|
|
|
3550
3671
|
}
|
|
3551
3672
|
if (input.baseDir) {
|
|
3552
3673
|
try {
|
|
3553
|
-
await mkdir4(
|
|
3554
|
-
await mkdir4(
|
|
3674
|
+
await mkdir4(path12.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
3675
|
+
await mkdir4(path12.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
3555
3676
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
3556
3677
|
await ensureGitignoreExe(input.baseDir);
|
|
3557
3678
|
} catch {
|
|
@@ -3587,10 +3708,10 @@ ${laneWarning}` : laneWarning;
|
|
|
3587
3708
|
});
|
|
3588
3709
|
if (input.baseDir) {
|
|
3589
3710
|
try {
|
|
3590
|
-
const EXE_OS_DIR =
|
|
3591
|
-
const mdPath =
|
|
3592
|
-
const mdDir =
|
|
3593
|
-
if (!
|
|
3711
|
+
const EXE_OS_DIR = path12.join(os8.homedir(), ".exe-os");
|
|
3712
|
+
const mdPath = path12.join(EXE_OS_DIR, taskFile);
|
|
3713
|
+
const mdDir = path12.dirname(mdPath);
|
|
3714
|
+
if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
|
|
3594
3715
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
3595
3716
|
const mdContent = `# ${input.title}
|
|
3596
3717
|
|
|
@@ -3615,7 +3736,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
|
|
|
3615
3736
|
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
3616
3737
|
`;
|
|
3617
3738
|
await writeFile4(mdPath, mdContent, "utf-8");
|
|
3618
|
-
} catch {
|
|
3739
|
+
} catch (err) {
|
|
3740
|
+
process.stderr.write(
|
|
3741
|
+
`[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
|
|
3742
|
+
`
|
|
3743
|
+
);
|
|
3619
3744
|
}
|
|
3620
3745
|
}
|
|
3621
3746
|
return {
|
|
@@ -3875,9 +4000,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
3875
4000
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
3876
4001
|
}
|
|
3877
4002
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
3878
|
-
const archPath =
|
|
4003
|
+
const archPath = path12.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
3879
4004
|
try {
|
|
3880
|
-
if (
|
|
4005
|
+
if (existsSync12(archPath)) return;
|
|
3881
4006
|
const template = [
|
|
3882
4007
|
`# ${projectName} \u2014 System Architecture`,
|
|
3883
4008
|
"",
|
|
@@ -3910,10 +4035,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
3910
4035
|
}
|
|
3911
4036
|
}
|
|
3912
4037
|
async function ensureGitignoreExe(baseDir) {
|
|
3913
|
-
const gitignorePath =
|
|
4038
|
+
const gitignorePath = path12.join(baseDir, ".gitignore");
|
|
3914
4039
|
try {
|
|
3915
|
-
if (
|
|
3916
|
-
const content =
|
|
4040
|
+
if (existsSync12(gitignorePath)) {
|
|
4041
|
+
const content = readFileSync10(gitignorePath, "utf-8");
|
|
3917
4042
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
3918
4043
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
3919
4044
|
} else {
|
|
@@ -3944,8 +4069,8 @@ var init_tasks_crud = __esm({
|
|
|
3944
4069
|
});
|
|
3945
4070
|
|
|
3946
4071
|
// src/lib/tasks-review.ts
|
|
3947
|
-
import
|
|
3948
|
-
import { existsSync as
|
|
4072
|
+
import path13 from "path";
|
|
4073
|
+
import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
3949
4074
|
async function countPendingReviews(sessionScope) {
|
|
3950
4075
|
const client = getClient();
|
|
3951
4076
|
if (sessionScope) {
|
|
@@ -4126,11 +4251,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
4126
4251
|
);
|
|
4127
4252
|
}
|
|
4128
4253
|
try {
|
|
4129
|
-
const cacheDir =
|
|
4130
|
-
if (
|
|
4254
|
+
const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
|
|
4255
|
+
if (existsSync13(cacheDir)) {
|
|
4131
4256
|
for (const f of readdirSync3(cacheDir)) {
|
|
4132
4257
|
if (f.startsWith("review-notified-")) {
|
|
4133
|
-
unlinkSync4(
|
|
4258
|
+
unlinkSync4(path13.join(cacheDir, f));
|
|
4134
4259
|
}
|
|
4135
4260
|
}
|
|
4136
4261
|
}
|
|
@@ -4151,7 +4276,7 @@ var init_tasks_review = __esm({
|
|
|
4151
4276
|
});
|
|
4152
4277
|
|
|
4153
4278
|
// src/lib/tasks-chain.ts
|
|
4154
|
-
import
|
|
4279
|
+
import path14 from "path";
|
|
4155
4280
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
4156
4281
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
4157
4282
|
const client = getClient();
|
|
@@ -4168,7 +4293,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
4168
4293
|
});
|
|
4169
4294
|
for (const ur of unblockedRows.rows) {
|
|
4170
4295
|
try {
|
|
4171
|
-
const ubFile =
|
|
4296
|
+
const ubFile = path14.join(baseDir, String(ur.task_file));
|
|
4172
4297
|
let ubContent = await readFile4(ubFile, "utf-8");
|
|
4173
4298
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
4174
4299
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -4237,7 +4362,7 @@ var init_tasks_chain = __esm({
|
|
|
4237
4362
|
|
|
4238
4363
|
// src/lib/project-name.ts
|
|
4239
4364
|
import { execSync as execSync6 } from "child_process";
|
|
4240
|
-
import
|
|
4365
|
+
import path15 from "path";
|
|
4241
4366
|
function getProjectName(cwd) {
|
|
4242
4367
|
const dir = cwd ?? process.cwd();
|
|
4243
4368
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -4250,7 +4375,7 @@ function getProjectName(cwd) {
|
|
|
4250
4375
|
timeout: 2e3,
|
|
4251
4376
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4252
4377
|
}).trim();
|
|
4253
|
-
repoRoot =
|
|
4378
|
+
repoRoot = path15.dirname(gitCommonDir);
|
|
4254
4379
|
} catch {
|
|
4255
4380
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
4256
4381
|
cwd: dir,
|
|
@@ -4259,11 +4384,11 @@ function getProjectName(cwd) {
|
|
|
4259
4384
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4260
4385
|
}).trim();
|
|
4261
4386
|
}
|
|
4262
|
-
_cached2 =
|
|
4387
|
+
_cached2 = path15.basename(repoRoot);
|
|
4263
4388
|
_cachedCwd = dir;
|
|
4264
4389
|
return _cached2;
|
|
4265
4390
|
} catch {
|
|
4266
|
-
_cached2 =
|
|
4391
|
+
_cached2 = path15.basename(dir);
|
|
4267
4392
|
_cachedCwd = dir;
|
|
4268
4393
|
return _cached2;
|
|
4269
4394
|
}
|
|
@@ -4736,8 +4861,8 @@ __export(tasks_exports, {
|
|
|
4736
4861
|
updateTaskStatus: () => updateTaskStatus,
|
|
4737
4862
|
writeCheckpoint: () => writeCheckpoint
|
|
4738
4863
|
});
|
|
4739
|
-
import
|
|
4740
|
-
import { writeFileSync as
|
|
4864
|
+
import path16 from "path";
|
|
4865
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
4741
4866
|
async function createTask(input) {
|
|
4742
4867
|
const result = await createTaskCore(input);
|
|
4743
4868
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -4756,11 +4881,11 @@ async function updateTask(input) {
|
|
|
4756
4881
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
4757
4882
|
try {
|
|
4758
4883
|
const agent = String(row.assigned_to);
|
|
4759
|
-
const cacheDir =
|
|
4760
|
-
const cachePath =
|
|
4884
|
+
const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
|
|
4885
|
+
const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
|
|
4761
4886
|
if (input.status === "in_progress") {
|
|
4762
|
-
|
|
4763
|
-
|
|
4887
|
+
mkdirSync7(cacheDir, { recursive: true });
|
|
4888
|
+
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
4764
4889
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
4765
4890
|
try {
|
|
4766
4891
|
unlinkSync5(cachePath);
|