@askexenow/exe-os 0.8.39 → 0.8.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +58 -10
- package/dist/bin/exe-boot.js +75 -16
- package/dist/bin/exe-cloud.js +12 -2
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-gateway.js +48 -2
- package/dist/bin/exe-link.js +35 -11
- package/dist/bin/exe-pending-reviews.js +29 -0
- package/dist/bin/exe-search.js +3 -1
- package/dist/bin/exe-session-cleanup.js +32 -1
- package/dist/bin/exe-settings.js +2 -1
- package/dist/bin/git-sweep.js +1 -1
- package/dist/bin/setup.js +3 -1
- package/dist/gateway/index.js +48 -2
- package/dist/hooks/commit-complete.js +1 -1
- package/dist/hooks/error-recall.js +3 -1
- package/dist/hooks/ingest-worker.js +48 -2
- package/dist/hooks/prompt-ingest-worker.js +3 -1
- package/dist/hooks/prompt-submit.js +33 -2
- package/dist/hooks/response-ingest-worker.js +3 -1
- package/dist/hooks/session-start.js +3 -1
- package/dist/hooks/subagent-stop.js +4 -2
- package/dist/hooks/summary-worker.js +30 -15
- package/dist/index.js +48 -2
- package/dist/lib/cloud-sync.js +22 -9
- package/dist/lib/config.js +2 -0
- package/dist/lib/embedder.js +3 -1
- package/dist/lib/exe-daemon.js +49 -2
- package/dist/lib/hybrid-search.js +3 -1
- package/dist/lib/tasks.js +45 -1
- package/dist/lib/tmux-routing.js +45 -1
- package/dist/mcp/server.js +48 -2
- package/dist/mcp/tools/create-task.js +3 -1
- package/dist/mcp/tools/list-tasks.js +1 -1
- package/dist/mcp/tools/update-task.js +15 -0
- package/dist/runtime/index.js +45 -1
- package/dist/tui/App.js +58 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1274,6 +1274,7 @@ var config_exports = {};
|
|
|
1274
1274
|
__export(config_exports, {
|
|
1275
1275
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
1276
1276
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
1277
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
1277
1278
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
1278
1279
|
DB_PATH: () => DB_PATH,
|
|
1279
1280
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -1429,7 +1430,7 @@ async function loadConfigFrom(configPath) {
|
|
|
1429
1430
|
return { ...DEFAULT_CONFIG };
|
|
1430
1431
|
}
|
|
1431
1432
|
}
|
|
1432
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
1433
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
1433
1434
|
var init_config = __esm({
|
|
1434
1435
|
"src/lib/config.ts"() {
|
|
1435
1436
|
"use strict";
|
|
@@ -1437,6 +1438,7 @@ var init_config = __esm({
|
|
|
1437
1438
|
DB_PATH = path4.join(EXE_AI_DIR, "memories.db");
|
|
1438
1439
|
MODELS_DIR = path4.join(EXE_AI_DIR, "models");
|
|
1439
1440
|
CONFIG_PATH = path4.join(EXE_AI_DIR, "config.json");
|
|
1441
|
+
COO_AGENT_NAME = "exe";
|
|
1440
1442
|
LEGACY_LANCE_PATH = path4.join(EXE_AI_DIR, "local.lance");
|
|
1441
1443
|
CURRENT_CONFIG_VERSION = 1;
|
|
1442
1444
|
DEFAULT_CONFIG = {
|
|
@@ -1944,7 +1946,7 @@ async function listTasks(input) {
|
|
|
1944
1946
|
}
|
|
1945
1947
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1946
1948
|
const result = await client.execute({
|
|
1947
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
1949
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
1948
1950
|
args
|
|
1949
1951
|
});
|
|
1950
1952
|
return result.rows.map((r) => ({
|
|
@@ -2165,6 +2167,34 @@ async function listPendingReviews(limit) {
|
|
|
2165
2167
|
});
|
|
2166
2168
|
return result.rows;
|
|
2167
2169
|
}
|
|
2170
|
+
async function cleanupOrphanedReviews() {
|
|
2171
|
+
const client = getClient();
|
|
2172
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2173
|
+
const r1 = await client.execute({
|
|
2174
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
2175
|
+
WHERE status = 'needs_review'
|
|
2176
|
+
AND assigned_by = 'system'
|
|
2177
|
+
AND title LIKE 'Review:%'
|
|
2178
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
2179
|
+
args: [now]
|
|
2180
|
+
});
|
|
2181
|
+
const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
|
|
2182
|
+
const r2 = await client.execute({
|
|
2183
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
2184
|
+
WHERE status = 'needs_review'
|
|
2185
|
+
AND result IS NOT NULL
|
|
2186
|
+
AND updated_at < ?`,
|
|
2187
|
+
args: [now, staleThreshold]
|
|
2188
|
+
});
|
|
2189
|
+
const total = r1.rowsAffected + r2.rowsAffected;
|
|
2190
|
+
if (total > 0) {
|
|
2191
|
+
process.stderr.write(
|
|
2192
|
+
`[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
|
|
2193
|
+
`
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2196
|
+
return total;
|
|
2197
|
+
}
|
|
2168
2198
|
function getReviewChecklist(role, agent, taskSlug) {
|
|
2169
2199
|
const roleLower = role.toLowerCase();
|
|
2170
2200
|
if (roleLower.includes("engineer") || roleLower === "principal engineer") {
|
|
@@ -2906,6 +2936,7 @@ var init_skill_learning = __esm({
|
|
|
2906
2936
|
// src/lib/tasks.ts
|
|
2907
2937
|
var tasks_exports = {};
|
|
2908
2938
|
__export(tasks_exports, {
|
|
2939
|
+
cleanupOrphanedReviews: () => cleanupOrphanedReviews,
|
|
2909
2940
|
countNewPendingReviewsSince: () => countNewPendingReviewsSince,
|
|
2910
2941
|
countPendingReviews: () => countPendingReviews,
|
|
2911
2942
|
createTask: () => createTask,
|
|
@@ -2971,6 +3002,21 @@ async function updateTask(input) {
|
|
|
2971
3002
|
});
|
|
2972
3003
|
} catch {
|
|
2973
3004
|
}
|
|
3005
|
+
try {
|
|
3006
|
+
const client = getClient();
|
|
3007
|
+
const cascaded = await client.execute({
|
|
3008
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
3009
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
3010
|
+
args: [now, taskId]
|
|
3011
|
+
});
|
|
3012
|
+
if (cascaded.rowsAffected > 0) {
|
|
3013
|
+
process.stderr.write(
|
|
3014
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
3015
|
+
`
|
|
3016
|
+
);
|
|
3017
|
+
}
|
|
3018
|
+
} catch {
|
|
3019
|
+
}
|
|
2974
3020
|
}
|
|
2975
3021
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
2976
3022
|
if (isTerminal) {
|
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -6,7 +6,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
// src/lib/cloud-sync.ts
|
|
9
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
|
|
9
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync, openSync, closeSync } from "fs";
|
|
10
|
+
import crypto2 from "crypto";
|
|
10
11
|
import path5 from "path";
|
|
11
12
|
import { homedir } from "os";
|
|
12
13
|
|
|
@@ -436,17 +437,29 @@ var PUSH_BATCH_SIZE = 5e3;
|
|
|
436
437
|
var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
|
|
437
438
|
var LOCK_STALE_MS = 3e4;
|
|
438
439
|
async function withRosterLock(fn) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
440
|
+
try {
|
|
441
|
+
const fd = openSync(ROSTER_LOCK_PATH, "wx");
|
|
442
|
+
closeSync(fd);
|
|
443
|
+
writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
|
|
444
|
+
} catch (err) {
|
|
445
|
+
if (err.code === "EEXIST") {
|
|
446
|
+
try {
|
|
447
|
+
const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
448
|
+
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
449
|
+
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
450
|
+
}
|
|
451
|
+
unlinkSync(ROSTER_LOCK_PATH);
|
|
452
|
+
const fd = openSync(ROSTER_LOCK_PATH, "wx");
|
|
453
|
+
closeSync(fd);
|
|
454
|
+
writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
|
|
455
|
+
} catch (retryErr) {
|
|
456
|
+
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
443
457
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
444
458
|
}
|
|
445
|
-
}
|
|
446
|
-
|
|
459
|
+
} else {
|
|
460
|
+
throw err;
|
|
447
461
|
}
|
|
448
462
|
}
|
|
449
|
-
writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
|
|
450
463
|
try {
|
|
451
464
|
return await fn();
|
|
452
465
|
} finally {
|
|
@@ -769,7 +782,7 @@ function buildRosterBlob(paths) {
|
|
|
769
782
|
}
|
|
770
783
|
const deletedNames = consumeRosterDeletions();
|
|
771
784
|
const content = JSON.stringify({ roster, identities, config, deletedNames });
|
|
772
|
-
const hash =
|
|
785
|
+
const hash = crypto2.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
773
786
|
return { roster, identities, config, deletedNames, version: hash };
|
|
774
787
|
}
|
|
775
788
|
async function cloudPushRoster(config) {
|
package/dist/lib/config.js
CHANGED
|
@@ -23,6 +23,7 @@ var EXE_AI_DIR = resolveDataDir();
|
|
|
23
23
|
var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
24
24
|
var MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
25
25
|
var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
26
|
+
var COO_AGENT_NAME = "exe";
|
|
26
27
|
var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
27
28
|
var CURRENT_CONFIG_VERSION = 1;
|
|
28
29
|
var DEFAULT_CONFIG = {
|
|
@@ -225,6 +226,7 @@ async function loadConfigFrom(configPath) {
|
|
|
225
226
|
export {
|
|
226
227
|
CONFIG_MIGRATIONS,
|
|
227
228
|
CONFIG_PATH,
|
|
229
|
+
COO_AGENT_NAME,
|
|
228
230
|
CURRENT_CONFIG_VERSION,
|
|
229
231
|
DB_PATH,
|
|
230
232
|
EXE_AI_DIR,
|
package/dist/lib/embedder.js
CHANGED
|
@@ -13,6 +13,7 @@ var config_exports = {};
|
|
|
13
13
|
__export(config_exports, {
|
|
14
14
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
15
15
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
16
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
16
17
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
17
18
|
DB_PATH: () => DB_PATH,
|
|
18
19
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -168,7 +169,7 @@ async function loadConfigFrom(configPath) {
|
|
|
168
169
|
return { ...DEFAULT_CONFIG };
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
172
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
172
173
|
var init_config = __esm({
|
|
173
174
|
"src/lib/config.ts"() {
|
|
174
175
|
"use strict";
|
|
@@ -176,6 +177,7 @@ var init_config = __esm({
|
|
|
176
177
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
177
178
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
178
179
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
180
|
+
COO_AGENT_NAME = "exe";
|
|
179
181
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
180
182
|
CURRENT_CONFIG_VERSION = 1;
|
|
181
183
|
DEFAULT_CONFIG = {
|
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -30,6 +30,7 @@ var config_exports = {};
|
|
|
30
30
|
__export(config_exports, {
|
|
31
31
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
32
32
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
33
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
33
34
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
34
35
|
DB_PATH: () => DB_PATH,
|
|
35
36
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -185,7 +186,7 @@ async function loadConfigFrom(configPath) {
|
|
|
185
186
|
return { ...DEFAULT_CONFIG };
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
189
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
189
190
|
var init_config = __esm({
|
|
190
191
|
"src/lib/config.ts"() {
|
|
191
192
|
"use strict";
|
|
@@ -193,6 +194,7 @@ var init_config = __esm({
|
|
|
193
194
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
194
195
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
195
196
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
197
|
+
COO_AGENT_NAME = "exe";
|
|
196
198
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
197
199
|
CURRENT_CONFIG_VERSION = 1;
|
|
198
200
|
DEFAULT_CONFIG = {
|
|
@@ -2963,7 +2965,7 @@ async function listTasks(input) {
|
|
|
2963
2965
|
}
|
|
2964
2966
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2965
2967
|
const result = await client.execute({
|
|
2966
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
2968
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
2967
2969
|
args
|
|
2968
2970
|
});
|
|
2969
2971
|
return result.rows.map((r) => ({
|
|
@@ -3157,6 +3159,7 @@ var init_tasks_crud = __esm({
|
|
|
3157
3159
|
// src/lib/tasks-review.ts
|
|
3158
3160
|
var tasks_review_exports = {};
|
|
3159
3161
|
__export(tasks_review_exports, {
|
|
3162
|
+
cleanupOrphanedReviews: () => cleanupOrphanedReviews,
|
|
3160
3163
|
cleanupReviewFile: () => cleanupReviewFile,
|
|
3161
3164
|
countNewPendingReviewsSince: () => countNewPendingReviewsSince,
|
|
3162
3165
|
countPendingReviews: () => countPendingReviews,
|
|
@@ -3193,6 +3196,34 @@ async function listPendingReviews(limit) {
|
|
|
3193
3196
|
});
|
|
3194
3197
|
return result.rows;
|
|
3195
3198
|
}
|
|
3199
|
+
async function cleanupOrphanedReviews() {
|
|
3200
|
+
const client = getClient();
|
|
3201
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3202
|
+
const r1 = await client.execute({
|
|
3203
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
3204
|
+
WHERE status = 'needs_review'
|
|
3205
|
+
AND assigned_by = 'system'
|
|
3206
|
+
AND title LIKE 'Review:%'
|
|
3207
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
3208
|
+
args: [now]
|
|
3209
|
+
});
|
|
3210
|
+
const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
|
|
3211
|
+
const r2 = await client.execute({
|
|
3212
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
3213
|
+
WHERE status = 'needs_review'
|
|
3214
|
+
AND result IS NOT NULL
|
|
3215
|
+
AND updated_at < ?`,
|
|
3216
|
+
args: [now, staleThreshold]
|
|
3217
|
+
});
|
|
3218
|
+
const total = r1.rowsAffected + r2.rowsAffected;
|
|
3219
|
+
if (total > 0) {
|
|
3220
|
+
process.stderr.write(
|
|
3221
|
+
`[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
|
|
3222
|
+
`
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
return total;
|
|
3226
|
+
}
|
|
3196
3227
|
function getReviewChecklist(role, agent, taskSlug) {
|
|
3197
3228
|
const roleLower = role.toLowerCase();
|
|
3198
3229
|
if (roleLower.includes("engineer") || roleLower === "principal engineer") {
|
|
@@ -3962,6 +3993,7 @@ var init_skill_learning = __esm({
|
|
|
3962
3993
|
// src/lib/tasks.ts
|
|
3963
3994
|
var tasks_exports = {};
|
|
3964
3995
|
__export(tasks_exports, {
|
|
3996
|
+
cleanupOrphanedReviews: () => cleanupOrphanedReviews,
|
|
3965
3997
|
countNewPendingReviewsSince: () => countNewPendingReviewsSince,
|
|
3966
3998
|
countPendingReviews: () => countPendingReviews,
|
|
3967
3999
|
createTask: () => createTask,
|
|
@@ -4027,6 +4059,21 @@ async function updateTask(input) {
|
|
|
4027
4059
|
});
|
|
4028
4060
|
} catch {
|
|
4029
4061
|
}
|
|
4062
|
+
try {
|
|
4063
|
+
const client = getClient();
|
|
4064
|
+
const cascaded = await client.execute({
|
|
4065
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
4066
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
4067
|
+
args: [now, taskId]
|
|
4068
|
+
});
|
|
4069
|
+
if (cascaded.rowsAffected > 0) {
|
|
4070
|
+
process.stderr.write(
|
|
4071
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
4072
|
+
`
|
|
4073
|
+
);
|
|
4074
|
+
}
|
|
4075
|
+
} catch {
|
|
4076
|
+
}
|
|
4030
4077
|
}
|
|
4031
4078
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
4032
4079
|
if (isTerminal) {
|
|
@@ -968,6 +968,7 @@ var config_exports = {};
|
|
|
968
968
|
__export(config_exports, {
|
|
969
969
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
970
970
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
971
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
971
972
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
972
973
|
DB_PATH: () => DB_PATH,
|
|
973
974
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -1123,7 +1124,7 @@ async function loadConfigFrom(configPath) {
|
|
|
1123
1124
|
return { ...DEFAULT_CONFIG };
|
|
1124
1125
|
}
|
|
1125
1126
|
}
|
|
1126
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
1127
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
1127
1128
|
var init_config = __esm({
|
|
1128
1129
|
"src/lib/config.ts"() {
|
|
1129
1130
|
"use strict";
|
|
@@ -1131,6 +1132,7 @@ var init_config = __esm({
|
|
|
1131
1132
|
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
1132
1133
|
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
1133
1134
|
CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
|
|
1135
|
+
COO_AGENT_NAME = "exe";
|
|
1134
1136
|
LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
|
|
1135
1137
|
CURRENT_CONFIG_VERSION = 1;
|
|
1136
1138
|
DEFAULT_CONFIG = {
|
package/dist/lib/tasks.js
CHANGED
|
@@ -494,7 +494,7 @@ async function listTasks(input) {
|
|
|
494
494
|
}
|
|
495
495
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
496
496
|
const result = await client.execute({
|
|
497
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
497
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
498
498
|
args
|
|
499
499
|
});
|
|
500
500
|
return result.rows.map((r) => ({
|
|
@@ -1686,6 +1686,34 @@ async function listPendingReviews(limit) {
|
|
|
1686
1686
|
});
|
|
1687
1687
|
return result.rows;
|
|
1688
1688
|
}
|
|
1689
|
+
async function cleanupOrphanedReviews() {
|
|
1690
|
+
const client = getClient();
|
|
1691
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1692
|
+
const r1 = await client.execute({
|
|
1693
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1694
|
+
WHERE status = 'needs_review'
|
|
1695
|
+
AND assigned_by = 'system'
|
|
1696
|
+
AND title LIKE 'Review:%'
|
|
1697
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
1698
|
+
args: [now]
|
|
1699
|
+
});
|
|
1700
|
+
const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
|
|
1701
|
+
const r2 = await client.execute({
|
|
1702
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1703
|
+
WHERE status = 'needs_review'
|
|
1704
|
+
AND result IS NOT NULL
|
|
1705
|
+
AND updated_at < ?`,
|
|
1706
|
+
args: [now, staleThreshold]
|
|
1707
|
+
});
|
|
1708
|
+
const total = r1.rowsAffected + r2.rowsAffected;
|
|
1709
|
+
if (total > 0) {
|
|
1710
|
+
process.stderr.write(
|
|
1711
|
+
`[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
|
|
1712
|
+
`
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
return total;
|
|
1716
|
+
}
|
|
1689
1717
|
function getReviewChecklist(role, agent, taskSlug) {
|
|
1690
1718
|
const roleLower = role.toLowerCase();
|
|
1691
1719
|
if (roleLower.includes("engineer") || roleLower === "principal engineer") {
|
|
@@ -2411,6 +2439,21 @@ async function updateTask(input) {
|
|
|
2411
2439
|
});
|
|
2412
2440
|
} catch {
|
|
2413
2441
|
}
|
|
2442
|
+
try {
|
|
2443
|
+
const client = getClient();
|
|
2444
|
+
const cascaded = await client.execute({
|
|
2445
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
2446
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
2447
|
+
args: [now, taskId]
|
|
2448
|
+
});
|
|
2449
|
+
if (cascaded.rowsAffected > 0) {
|
|
2450
|
+
process.stderr.write(
|
|
2451
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
2452
|
+
`
|
|
2453
|
+
);
|
|
2454
|
+
}
|
|
2455
|
+
} catch {
|
|
2456
|
+
}
|
|
2414
2457
|
}
|
|
2415
2458
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
2416
2459
|
if (isTerminal) {
|
|
@@ -2500,6 +2543,7 @@ var init_tasks = __esm({
|
|
|
2500
2543
|
});
|
|
2501
2544
|
init_tasks();
|
|
2502
2545
|
export {
|
|
2546
|
+
cleanupOrphanedReviews,
|
|
2503
2547
|
countNewPendingReviewsSince,
|
|
2504
2548
|
countPendingReviews,
|
|
2505
2549
|
createTask,
|
package/dist/lib/tmux-routing.js
CHANGED
|
@@ -959,7 +959,7 @@ async function listTasks(input) {
|
|
|
959
959
|
}
|
|
960
960
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
961
961
|
const result = await client.execute({
|
|
962
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
962
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
963
963
|
args
|
|
964
964
|
});
|
|
965
965
|
return result.rows.map((r) => ({
|
|
@@ -1180,6 +1180,34 @@ async function listPendingReviews(limit) {
|
|
|
1180
1180
|
});
|
|
1181
1181
|
return result.rows;
|
|
1182
1182
|
}
|
|
1183
|
+
async function cleanupOrphanedReviews() {
|
|
1184
|
+
const client = getClient();
|
|
1185
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1186
|
+
const r1 = await client.execute({
|
|
1187
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1188
|
+
WHERE status = 'needs_review'
|
|
1189
|
+
AND assigned_by = 'system'
|
|
1190
|
+
AND title LIKE 'Review:%'
|
|
1191
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
1192
|
+
args: [now]
|
|
1193
|
+
});
|
|
1194
|
+
const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
|
|
1195
|
+
const r2 = await client.execute({
|
|
1196
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1197
|
+
WHERE status = 'needs_review'
|
|
1198
|
+
AND result IS NOT NULL
|
|
1199
|
+
AND updated_at < ?`,
|
|
1200
|
+
args: [now, staleThreshold]
|
|
1201
|
+
});
|
|
1202
|
+
const total = r1.rowsAffected + r2.rowsAffected;
|
|
1203
|
+
if (total > 0) {
|
|
1204
|
+
process.stderr.write(
|
|
1205
|
+
`[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
|
|
1206
|
+
`
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
return total;
|
|
1210
|
+
}
|
|
1183
1211
|
function getReviewChecklist(role, agent, taskSlug) {
|
|
1184
1212
|
const roleLower = role.toLowerCase();
|
|
1185
1213
|
if (roleLower.includes("engineer") || roleLower === "principal engineer") {
|
|
@@ -1859,6 +1887,7 @@ var init_skill_learning = __esm({
|
|
|
1859
1887
|
// src/lib/tasks.ts
|
|
1860
1888
|
var tasks_exports = {};
|
|
1861
1889
|
__export(tasks_exports, {
|
|
1890
|
+
cleanupOrphanedReviews: () => cleanupOrphanedReviews,
|
|
1862
1891
|
countNewPendingReviewsSince: () => countNewPendingReviewsSince,
|
|
1863
1892
|
countPendingReviews: () => countPendingReviews,
|
|
1864
1893
|
createTask: () => createTask,
|
|
@@ -1924,6 +1953,21 @@ async function updateTask(input) {
|
|
|
1924
1953
|
});
|
|
1925
1954
|
} catch {
|
|
1926
1955
|
}
|
|
1956
|
+
try {
|
|
1957
|
+
const client = getClient();
|
|
1958
|
+
const cascaded = await client.execute({
|
|
1959
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1960
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
1961
|
+
args: [now, taskId]
|
|
1962
|
+
});
|
|
1963
|
+
if (cascaded.rowsAffected > 0) {
|
|
1964
|
+
process.stderr.write(
|
|
1965
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
1966
|
+
`
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
} catch {
|
|
1970
|
+
}
|
|
1927
1971
|
}
|
|
1928
1972
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
1929
1973
|
if (isTerminal) {
|
package/dist/mcp/server.js
CHANGED
|
@@ -39,6 +39,7 @@ var config_exports = {};
|
|
|
39
39
|
__export(config_exports, {
|
|
40
40
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
41
41
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
42
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
42
43
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
43
44
|
DB_PATH: () => DB_PATH,
|
|
44
45
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -194,7 +195,7 @@ async function loadConfigFrom(configPath) {
|
|
|
194
195
|
return { ...DEFAULT_CONFIG };
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
198
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
198
199
|
var init_config = __esm({
|
|
199
200
|
"src/lib/config.ts"() {
|
|
200
201
|
"use strict";
|
|
@@ -202,6 +203,7 @@ var init_config = __esm({
|
|
|
202
203
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
203
204
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
204
205
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
206
|
+
COO_AGENT_NAME = "exe";
|
|
205
207
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
206
208
|
CURRENT_CONFIG_VERSION = 1;
|
|
207
209
|
DEFAULT_CONFIG = {
|
|
@@ -3870,7 +3872,7 @@ async function listTasks(input) {
|
|
|
3870
3872
|
}
|
|
3871
3873
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
3872
3874
|
const result = await client.execute({
|
|
3873
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
3875
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
3874
3876
|
args
|
|
3875
3877
|
});
|
|
3876
3878
|
return result.rows.map((r) => ({
|
|
@@ -4894,6 +4896,34 @@ async function listPendingReviews(limit) {
|
|
|
4894
4896
|
});
|
|
4895
4897
|
return result.rows;
|
|
4896
4898
|
}
|
|
4899
|
+
async function cleanupOrphanedReviews() {
|
|
4900
|
+
const client = getClient();
|
|
4901
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4902
|
+
const r1 = await client.execute({
|
|
4903
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
4904
|
+
WHERE status = 'needs_review'
|
|
4905
|
+
AND assigned_by = 'system'
|
|
4906
|
+
AND title LIKE 'Review:%'
|
|
4907
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
4908
|
+
args: [now]
|
|
4909
|
+
});
|
|
4910
|
+
const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
|
|
4911
|
+
const r2 = await client.execute({
|
|
4912
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
4913
|
+
WHERE status = 'needs_review'
|
|
4914
|
+
AND result IS NOT NULL
|
|
4915
|
+
AND updated_at < ?`,
|
|
4916
|
+
args: [now, staleThreshold]
|
|
4917
|
+
});
|
|
4918
|
+
const total = r1.rowsAffected + r2.rowsAffected;
|
|
4919
|
+
if (total > 0) {
|
|
4920
|
+
process.stderr.write(
|
|
4921
|
+
`[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
|
|
4922
|
+
`
|
|
4923
|
+
);
|
|
4924
|
+
}
|
|
4925
|
+
return total;
|
|
4926
|
+
}
|
|
4897
4927
|
function getReviewChecklist(role, agent, taskSlug) {
|
|
4898
4928
|
const roleLower = role.toLowerCase();
|
|
4899
4929
|
if (roleLower.includes("engineer") || roleLower === "principal engineer") {
|
|
@@ -5559,6 +5589,7 @@ var init_skill_learning = __esm({
|
|
|
5559
5589
|
// src/lib/tasks.ts
|
|
5560
5590
|
var tasks_exports = {};
|
|
5561
5591
|
__export(tasks_exports, {
|
|
5592
|
+
cleanupOrphanedReviews: () => cleanupOrphanedReviews,
|
|
5562
5593
|
countNewPendingReviewsSince: () => countNewPendingReviewsSince,
|
|
5563
5594
|
countPendingReviews: () => countPendingReviews,
|
|
5564
5595
|
createTask: () => createTask,
|
|
@@ -5624,6 +5655,21 @@ async function updateTask(input) {
|
|
|
5624
5655
|
});
|
|
5625
5656
|
} catch {
|
|
5626
5657
|
}
|
|
5658
|
+
try {
|
|
5659
|
+
const client = getClient();
|
|
5660
|
+
const cascaded = await client.execute({
|
|
5661
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
5662
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
5663
|
+
args: [now, taskId]
|
|
5664
|
+
});
|
|
5665
|
+
if (cascaded.rowsAffected > 0) {
|
|
5666
|
+
process.stderr.write(
|
|
5667
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
5668
|
+
`
|
|
5669
|
+
);
|
|
5670
|
+
}
|
|
5671
|
+
} catch {
|
|
5672
|
+
}
|
|
5627
5673
|
}
|
|
5628
5674
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
5629
5675
|
if (isTerminal) {
|
|
@@ -48,6 +48,7 @@ var config_exports = {};
|
|
|
48
48
|
__export(config_exports, {
|
|
49
49
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
50
50
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
51
|
+
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
51
52
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
52
53
|
DB_PATH: () => DB_PATH,
|
|
53
54
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -203,7 +204,7 @@ async function loadConfigFrom(configPath) {
|
|
|
203
204
|
return { ...DEFAULT_CONFIG };
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
207
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
207
208
|
var init_config = __esm({
|
|
208
209
|
"src/lib/config.ts"() {
|
|
209
210
|
"use strict";
|
|
@@ -211,6 +212,7 @@ var init_config = __esm({
|
|
|
211
212
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
212
213
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
213
214
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
215
|
+
COO_AGENT_NAME = "exe";
|
|
214
216
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
215
217
|
CURRENT_CONFIG_VERSION = 1;
|
|
216
218
|
DEFAULT_CONFIG = {
|
|
@@ -172,7 +172,7 @@ async function listTasks(input) {
|
|
|
172
172
|
}
|
|
173
173
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
174
174
|
const result = await client.execute({
|
|
175
|
-
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
|
|
175
|
+
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
176
176
|
args
|
|
177
177
|
});
|
|
178
178
|
return result.rows.map((r) => ({
|
|
@@ -1461,6 +1461,21 @@ async function updateTask(input) {
|
|
|
1461
1461
|
});
|
|
1462
1462
|
} catch {
|
|
1463
1463
|
}
|
|
1464
|
+
try {
|
|
1465
|
+
const client = getClient();
|
|
1466
|
+
const cascaded = await client.execute({
|
|
1467
|
+
sql: `UPDATE tasks SET status = 'done', updated_at = ?
|
|
1468
|
+
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
1469
|
+
args: [now, taskId]
|
|
1470
|
+
});
|
|
1471
|
+
if (cascaded.rowsAffected > 0) {
|
|
1472
|
+
process.stderr.write(
|
|
1473
|
+
`[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
|
|
1474
|
+
`
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
} catch {
|
|
1478
|
+
}
|
|
1464
1479
|
}
|
|
1465
1480
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
1466
1481
|
if (isTerminal) {
|