@askexenow/exe-os 0.9.203 → 0.9.205
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/init-db.sql +162 -0
- package/deploy/stack-manifests/v0.9.json +45 -1
- package/dist/{active-agent-EFWC3HGP.js → active-agent-4RUP4VYK.js} +2 -2
- package/dist/{active-agent-NXX5Z3LX.js → active-agent-VEML3XMS.js} +2 -2
- package/dist/{agentic-ontology-JS6DPKQB.js → agentic-ontology-FNJAKZF5.js} +1 -1
- package/dist/{backfill-metadata-PTACRLYK.js → backfill-metadata-BT4RLVMZ.js} +3 -3
- package/dist/{behaviors-WDIKLZA3.js → behaviors-LCPNHP5Q.js} +2 -2
- package/dist/bin/agentic-ontology-backfill.js +4 -4
- package/dist/bin/agentic-reflection-backfill.js +5 -5
- package/dist/bin/agentic-semantic-label.js +4 -4
- package/dist/bin/backfill-conversations.js +3 -3
- package/dist/bin/backfill-responses.js +3 -3
- package/dist/bin/backfill-vectors.js +4 -4
- package/dist/bin/bulk-sync-postgres.js +5 -5
- package/dist/bin/cleanup-stale-review-tasks.js +8 -8
- package/dist/bin/cli.js +12 -12
- package/dist/bin/exe-agent-config.js +1 -1
- package/dist/bin/exe-agent.js +3 -3
- package/dist/bin/exe-assign.js +4 -4
- package/dist/bin/exe-boot.js +15 -15
- package/dist/bin/exe-call.js +3 -3
- package/dist/bin/exe-cloud.js +3 -3
- package/dist/bin/exe-dispatch.js +8 -8
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +6 -6
- package/dist/bin/exe-forget.js +5 -5
- package/dist/bin/exe-gateway.js +5 -5
- package/dist/bin/exe-heartbeat.js +8 -8
- package/dist/bin/exe-kill.js +11 -11
- package/dist/bin/exe-launch-agent.js +9 -9
- package/dist/bin/exe-new-employee.js +5 -5
- package/dist/bin/exe-pending-messages.js +9 -9
- package/dist/bin/exe-pending-notifications.js +8 -8
- package/dist/bin/exe-pending-reviews.js +8 -8
- package/dist/bin/exe-rename.js +3 -3
- package/dist/bin/exe-review.js +10 -10
- package/dist/bin/exe-search.js +4 -4
- package/dist/bin/exe-session-cleanup.js +13 -13
- package/dist/bin/exe-settings.js +3 -3
- package/dist/bin/exe-start-codex.js +10 -10
- package/dist/bin/exe-start-opencode.js +7 -7
- package/dist/bin/exe-status.js +9 -9
- package/dist/bin/exe-team.js +2 -2
- package/dist/bin/git-sweep.js +8 -8
- package/dist/bin/graph-backfill.js +3 -3
- package/dist/bin/graph-export.js +4 -4
- package/dist/bin/import-history.js +4 -4
- package/dist/bin/install.js +5 -5
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/orchestration-metrics.js +4 -3
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/scan-tasks.js +8 -8
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +3 -3
- package/dist/{capacity-monitor-TGSIL7W4.js → capacity-monitor-EPHJTSKF.js} +9 -9
- package/dist/{catchup-brief-ABL4NSAE.js → catchup-brief-HVITENL5.js} +10 -10
- package/dist/{chunk-25K6KNZ5.js → chunk-22GPB6FO.js} +58 -6
- package/dist/chunk-2THPPZF2.js +81 -0
- package/dist/{chunk-K3O4MWMS.js → chunk-3MHKTBHZ.js} +1 -0
- package/dist/{chunk-UY6RQK5F.js → chunk-3N4ZEPZI.js} +1 -1
- package/dist/{chunk-SN6Z3CBF.js → chunk-3PDZQICZ.js} +1 -1
- package/dist/{chunk-CGM6BIK3.js → chunk-3S3ERUUH.js} +1 -1
- package/dist/{chunk-5EW4GKGZ.js → chunk-434A3L6O.js} +1 -1
- package/dist/{chunk-BQ4U2SYC.js → chunk-4FNJPA5O.js} +1 -1
- package/dist/{chunk-O5RJH6GU.js → chunk-4RJD3GXL.js} +1 -1
- package/dist/{chunk-3K2BCD5Y.js → chunk-5HTEMMOJ.js} +21 -4
- package/dist/{chunk-SZDSQ3AW.js → chunk-6JORPKMR.js} +3 -3
- package/dist/{chunk-DAFEIA2M.js → chunk-6MOFCQFH.js} +124 -65
- package/dist/{chunk-K62M5FIM.js → chunk-6VVSXO3M.js} +4 -4
- package/dist/{chunk-SPMVTZ7Z.js → chunk-723DSUG3.js} +3 -3
- package/dist/{chunk-5POKNLFV.js → chunk-7DTEJAIC.js} +2 -2
- package/dist/{chunk-E66FQ7IN.js → chunk-7HIWJLXK.js} +1 -1
- package/dist/{chunk-IGRQE5Y5.js → chunk-BGLXECHT.js} +2 -2
- package/dist/{chunk-BYHFW5CT.js → chunk-COOX4FXM.js} +1 -1
- package/dist/{chunk-GZLGB72W.js → chunk-CXBLK3ZA.js} +1 -1
- package/dist/{chunk-MJNI3S5H.js → chunk-EDQ4GH2D.js} +2 -2
- package/dist/{chunk-GPK2WJXA.js → chunk-EF57I73W.js} +1 -1
- package/dist/{chunk-HXYL4QX6.js → chunk-EUMLEWXO.js} +2 -2
- package/dist/{chunk-RJCZY4BY.js → chunk-FMKD6N33.js} +86 -10
- package/dist/{chunk-RN6XYY7U.js → chunk-FYJCMGTD.js} +71 -0
- package/dist/{chunk-USQF2GGF.js → chunk-H7U7FPQF.js} +82 -6
- package/dist/{chunk-FMI7SCZJ.js → chunk-HLYNKMAG.js} +1 -1
- package/dist/{chunk-BGOQFJ2H.js → chunk-HMGIQNME.js} +3 -3
- package/dist/chunk-IR4L6K5L.js +147 -0
- package/dist/chunk-ITYWLFYC.js +609 -0
- package/dist/{chunk-FFECDA24.js → chunk-JUB74GFQ.js} +2 -2
- package/dist/{chunk-D4B6SVEC.js → chunk-MKOW4EXB.js} +1 -1
- package/dist/{chunk-XWM23YJO.js → chunk-MQX47XMP.js} +2 -2
- package/dist/{chunk-IXFE5R6T.js → chunk-MZ2BL3JP.js} +2 -2
- package/dist/{chunk-WGMHQVGX.js → chunk-O2JGR7EU.js} +83 -6
- package/dist/{chunk-BV3L2S54.js → chunk-P2ZIM765.js} +1 -1
- package/dist/{chunk-DEGQESR7.js → chunk-PHCK4KQW.js} +3 -3
- package/dist/{chunk-Y2W54BET.js → chunk-PXDR3UTB.js} +8 -8
- package/dist/{chunk-ETHQJXO3.js → chunk-PYLNOBNW.js} +1 -1
- package/dist/{chunk-HXNTQP4B.js → chunk-RN6DEMC7.js} +1 -1
- package/dist/{chunk-3WMXVABU.js → chunk-S4AXKNPT.js} +1 -1
- package/dist/{chunk-X2BTDYHZ.js → chunk-SEAFDIKF.js} +13 -1
- package/dist/{chunk-QLKRYO7O.js → chunk-TCBUBBTL.js} +8 -8
- package/dist/{chunk-ZQMOF6E7.js → chunk-THFFC43M.js} +1 -1
- package/dist/{chunk-XXHDXAZV.js → chunk-VG3VVFF5.js} +1 -1
- package/dist/{chunk-P4JQGT4Q.js → chunk-VH6WU3GK.js} +2 -2
- package/dist/{chunk-AH6MV6CC.js → chunk-W4BFBCZA.js} +3 -3
- package/dist/{chunk-PVVA5SY5.js → chunk-XSOKVFQ6.js} +14 -3
- package/dist/{chunk-JUTI2DXY.js → chunk-YCL4RHFY.js} +1 -1
- package/dist/{chunk-UXD5KOND.js → chunk-YGUWCJN2.js} +2 -2
- package/dist/{chunk-AUPGTF7I.js → chunk-YOXXZAOR.js} +2 -2
- package/dist/{chunk-GPNUPCTZ.js → chunk-YXHY5F34.js} +2 -2
- package/dist/{chunk-6FJ2TJYB.js → chunk-ZDK3M72Z.js} +1 -1
- package/dist/{chunk-6H6Q4MJC.js → chunk-ZIBSTUGU.js} +1 -1
- package/dist/{chunk-LIHR5DQF.js → chunk-ZXZJLVGD.js} +1 -1
- package/dist/{co-occurrence-A2SJL5AH.js → co-occurrence-TJRQ5V7W.js} +1 -1
- package/dist/{crdt-sync-SGAW6DJQ.js → crdt-sync-RI7XPXTI.js} +1 -1
- package/dist/{crm-webhook-FBENY6FW.js → crm-webhook-AVG4F2NB.js} +2 -2
- package/dist/{cto-delegation-gate-A53RLTJZ.js → cto-delegation-gate-ZTNJLSPO.js} +7 -7
- package/dist/{daemon-orchestration-3U3XXFG7.js → daemon-orchestration-AKICH7C5.js} +10 -10
- package/dist/{exe-drift-3OUOHWAI.js → exe-drift-BPVS4MOJ.js} +2 -2
- package/dist/{exe-export-AFXTJ63F.js → exe-export-LL4CXNLT.js} +4 -4
- package/dist/{exe-import-QRZBTBBG.js → exe-import-JNKAAJ5T.js} +4 -4
- package/dist/{exe-key-BXN7WPOX.js → exe-key-C5UQ77AT.js} +1 -1
- package/dist/{fast-db-init-YVJD4JT2.js → fast-db-init-UNK4BEEO.js} +1 -1
- package/dist/gateway/index.js +6 -6
- package/dist/{git-staleness-DBFCOX65.js → git-staleness-WTJFIPHH.js} +1 -1
- package/dist/{git-task-sweep-O5CH3MKA.js → git-task-sweep-PT3RIE6W.js} +8 -8
- package/dist/{global-procedures-SL2TTCED.js → global-procedures-ZPN7KZH5.js} +2 -2
- package/dist/{graph-auto-extract-JGNJ3BB7.js → graph-auto-extract-4M4J42NA.js} +1 -1
- package/dist/hooks/bug-report-worker.js +9 -9
- package/dist/hooks/codex-stop-task-finalizer.js +9 -9
- package/dist/hooks/commit-complete.js +10 -10
- package/dist/hooks/error-recall.js +5 -5
- package/dist/hooks/exe-heartbeat-hook.js +2 -2
- package/dist/hooks/ingest.js +5 -5
- package/dist/hooks/instructions-loaded.js +3 -3
- package/dist/hooks/manifest.json +19 -19
- package/dist/hooks/notification.js +3 -3
- package/dist/hooks/post-compact.js +9 -9
- package/dist/hooks/post-tool-combined.js +4 -4
- package/dist/hooks/pre-compact.js +10 -10
- package/dist/hooks/pre-tool-use.js +13 -13
- package/dist/hooks/prompt-submit.js +29 -18
- package/dist/hooks/session-end.js +13 -13
- package/dist/hooks/session-start.js +30 -7
- package/dist/hooks/stop.js +13 -13
- package/dist/hooks/subagent-stop.js +9 -9
- package/dist/hooks/summary-worker.js +13 -13
- package/dist/index.js +15 -15
- package/dist/{installer-TAPAEWRV.js → installer-3DE2IDUZ.js} +4 -4
- package/dist/{installer-5FI6CX62.js → installer-IYELX3KG.js} +4 -4
- package/dist/{installer-HNOVAUW6.js → installer-SCWIMZT7.js} +4 -4
- package/dist/lib/cloud-sync.js +3 -3
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +1 -1
- package/dist/lib/db.js +1 -1
- package/dist/lib/employee-templates.js +3 -3
- package/dist/lib/employees.js +1 -1
- package/dist/lib/exe-daemon.js +102 -27
- package/dist/lib/hybrid-search.js +4 -4
- package/dist/lib/identity.js +1 -1
- package/dist/lib/messaging.js +8 -8
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +4 -4
- package/dist/lib/session-registry.js +9 -1
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/store.js +3 -3
- package/dist/lib/task-router.js +2 -2
- package/dist/lib/tasks.js +8 -8
- package/dist/lib/tmux-routing.js +7 -7
- package/dist/lib/token-spend.js +2 -2
- package/dist/mcp/register-tools.js +46 -46
- package/dist/mcp/server.js +47 -47
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +10 -10
- package/dist/mcp/tools/deactivate-behavior.js +4 -4
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +10 -10
- package/dist/mcp/tools/send-message.js +10 -10
- package/dist/mcp/tools/update-task.js +9 -9
- package/dist/{mcp-http-config-6UAI2FAV.js → mcp-http-config-EWIT2DEN.js} +2 -2
- package/dist/{memory-cards-PVPUQ7MX.js → memory-cards-W4VTTFYM.js} +1 -1
- package/dist/{memory-graph-extractor-RP7ZXDTE.js → memory-graph-extractor-A3HRDXY6.js} +2 -2
- package/dist/{memory-poisoning-defense-DDBUHHGB.js → memory-poisoning-defense-MH6QBXVT.js} +1 -1
- package/dist/{memory-reflection-HLR26FXG.js → memory-reflection-RUCTWMQ5.js} +1 -1
- package/dist/{notifications-GHNYYITD.js → notifications-6GRSVIP6.js} +7 -7
- package/dist/{orchestration-events-2SVPXMK2.js → orchestration-events-MSJVUR4T.js} +6 -2
- package/dist/{orchestrator-3BDZ6OUC.js → orchestrator-QQKU4VM2.js} +9 -9
- package/dist/{plan-limits-QBNFIU45.js → plan-limits-NKUSDF3I.js} +2 -2
- package/dist/{projection-worker-B7HHFYEG.js → projection-worker-UEG6I5DV.js} +1 -1
- package/dist/{reranker-B3BOGR3A.js → reranker-JTDM3MV2.js} +1 -1
- package/dist/{review-polling-RUXU45AK.js → review-polling-MWBVXHG3.js} +8 -8
- package/dist/runtime/index.js +10 -10
- package/dist/{session-events-ICZPUGJN.js → session-events-FRB3UYJG.js} +8 -8
- package/dist/{session-kill-telemetry-OGFLFTYX.js → session-kill-telemetry-GPZUHBCT.js} +2 -2
- package/dist/{session-scope-UJI35BLD.js → session-scope-7BZTNB2X.js} +7 -7
- package/dist/{setup-wizard-M6ZZ2VNM.js → setup-wizard-2INM4CSL.js} +1 -1
- package/dist/{skill-refinement-WZL35CMY.js → skill-refinement-7C7X42Z5.js} +1 -1
- package/dist/{task-enforcement-AYHKGR45.js → task-enforcement-VB5P45ZM.js} +7 -7
- package/dist/{task-scope-EYAOY6YX.js → task-scope-ULC62J6G.js} +7 -7
- package/dist/{tasks-crud-K3UGPCPT.js → tasks-crud-IBSTM6ID.js} +9 -7
- package/dist/{tasks-review-J6LTVVO5.js → tasks-review-P4MCKBDT.js} +7 -7
- package/dist/telemetry-upload-Y3CPHI7M.js +214 -0
- package/dist/{token-budget-XU2QZEWX.js → token-budget-CO74EBTY.js} +1 -1
- package/dist/{tool-telemetry-OE57ERK7.js → tool-telemetry-5PX7A6TX.js} +3 -1
- package/dist/tui/App.js +15 -15
- package/dist/{tui-data-32OEC3DH.js → tui-data-YAT6A36V.js} +7 -7
- package/dist/{worker-gate-UIGQCEUE.js → worker-gate-27O2WEYU.js} +1 -1
- package/dist/{workflow-engine-IY7KO7DU.js → workflow-engine-4T36KCTQ.js} +2 -2
- package/dist/{worktree-VIXR2Z4J.js → worktree-QTCOX6RV.js} +7 -1
- package/package.json +1 -1
- package/release-notes.json +95 -95
- package/dist/chunk-64WZEXXA.js +0 -64
- package/dist/chunk-L63IOJ5N.js +0 -69
- package/dist/chunk-ZGQH3V2F.js +0 -254
- /package/dist/{chunk-3GFR2TX6.js → chunk-AF7A5IQ5.js} +0 -0
- /package/dist/{chunk-7SY5JOLR.js → chunk-ATKMIQXP.js} +0 -0
- /package/dist/{chunk-KCWIOR55.js → chunk-GONOOIFL.js} +0 -0
- /package/dist/{chunk-QQN7MHQG.js → chunk-ONCFSN5C.js} +0 -0
- /package/dist/{chunk-Q3MRTJLA.js → chunk-WVNWAV36.js} +0 -0
- /package/dist/{chunk-RH5NYRQH.js → chunk-XJQASQPO.js} +0 -0
- /package/dist/{chunk-LJA6RQ3L.js → chunk-YKCH4T4T.js} +0 -0
- /package/dist/{core-memory-VZ4YJVMA.js → core-memory-3QGHBERR.js} +0 -0
- /package/dist/{wiki-acl-NUUPHYWC.js → wiki-acl-WCBKBLGQ.js} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
vectorToBlob
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TCBUBBTL.js";
|
|
4
4
|
import {
|
|
5
5
|
extractKeywords,
|
|
6
6
|
keywordsToString
|
|
7
7
|
} from "./chunk-CHCA3ZM2.js";
|
|
8
8
|
import {
|
|
9
9
|
isCoordinatorName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3MHKTBHZ.js";
|
|
11
11
|
|
|
12
12
|
// src/lib/consolidation.ts
|
|
13
13
|
import { randomUUID } from "crypto";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureWorktree
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FYJCMGTD.js";
|
|
4
4
|
import {
|
|
5
5
|
queueIntercom
|
|
6
6
|
} from "./chunk-QI4IXJN7.js";
|
|
7
7
|
import {
|
|
8
8
|
registerSession
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-IR4L6K5L.js";
|
|
10
10
|
import {
|
|
11
11
|
getTransport
|
|
12
12
|
} from "./chunk-5YDHBZCO.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-GZIAQYGI.js";
|
|
16
16
|
import {
|
|
17
17
|
recordOrchestrationEventBestEffort
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-ITYWLFYC.js";
|
|
19
19
|
import {
|
|
20
20
|
DEFAULT_PROVIDER,
|
|
21
21
|
PROVIDER_TABLE,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
import {
|
|
34
34
|
PlanLimitError,
|
|
35
35
|
assertEmployeeLimitSync
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-3PDZQICZ.js";
|
|
37
37
|
import {
|
|
38
38
|
getSessionKey
|
|
39
39
|
} from "./chunk-CVYC6DUW.js";
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
} from "./chunk-MP2AFCGL.js";
|
|
49
49
|
import {
|
|
50
50
|
ensureAgentSymlink
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-RN6DEMC7.js";
|
|
52
52
|
import {
|
|
53
53
|
expandDualPrefixTools
|
|
54
54
|
} from "./chunk-HYZV25LY.js";
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
isCoordinatorName,
|
|
61
61
|
loadEmployees,
|
|
62
62
|
loadEmployeesSync
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-3MHKTBHZ.js";
|
|
64
64
|
import {
|
|
65
65
|
loadDeviceId
|
|
66
66
|
} from "./chunk-72DJ42IE.js";
|
|
@@ -374,7 +374,7 @@ async function createTaskCore(input) {
|
|
|
374
374
|
if (isCoordinatorSession) {
|
|
375
375
|
earlySessionScope = resolved;
|
|
376
376
|
} else {
|
|
377
|
-
const { getSessionProject } = await import("./session-scope-
|
|
377
|
+
const { getSessionProject } = await import("./session-scope-7BZTNB2X.js");
|
|
378
378
|
const sessionProject = getSessionProject(resolved);
|
|
379
379
|
if (sessionProject && sessionProject !== input.projectName) {
|
|
380
380
|
scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
|
|
@@ -823,7 +823,7 @@ async function updateTaskStatus(input) {
|
|
|
823
823
|
} catch {
|
|
824
824
|
}
|
|
825
825
|
try {
|
|
826
|
-
const { writeNotification: writeNotification2 } = await import("./notifications-
|
|
826
|
+
const { writeNotification: writeNotification2 } = await import("./notifications-6GRSVIP6.js");
|
|
827
827
|
await writeNotification2({
|
|
828
828
|
agentId: reviewer,
|
|
829
829
|
agentRole: isCoordinatorName(reviewer) ? "COO" : "manager",
|
|
@@ -1146,13 +1146,36 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
1146
1146
|
projectName: eventProjectName
|
|
1147
1147
|
});
|
|
1148
1148
|
}
|
|
1149
|
+
if (input.status === "closed" && previousStatus === "needs_review") {
|
|
1150
|
+
recordOrchestrationEventBestEffort({
|
|
1151
|
+
eventType: "review.approved",
|
|
1152
|
+
source: "tasks-crud.updateTaskStatus",
|
|
1153
|
+
taskId,
|
|
1154
|
+
agentId: eventAgentId,
|
|
1155
|
+
reviewer: row.reviewer ? String(row.reviewer) : null,
|
|
1156
|
+
sessionScope: eventSessionScope,
|
|
1157
|
+
projectName: eventProjectName
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
if (previousStatus === "needs_review" && (input.status === "open" || input.status === "in_progress")) {
|
|
1161
|
+
recordOrchestrationEventBestEffort({
|
|
1162
|
+
eventType: "review.rejected",
|
|
1163
|
+
source: "tasks-crud.updateTaskStatus",
|
|
1164
|
+
taskId,
|
|
1165
|
+
agentId: eventAgentId,
|
|
1166
|
+
reviewer: row.reviewer ? String(row.reviewer) : null,
|
|
1167
|
+
sessionScope: eventSessionScope,
|
|
1168
|
+
projectName: eventProjectName,
|
|
1169
|
+
result: input.status
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1149
1172
|
try {
|
|
1150
1173
|
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
1151
1174
|
} catch {
|
|
1152
1175
|
}
|
|
1153
1176
|
if (input.status === "done" || input.status === "needs_review") {
|
|
1154
1177
|
try {
|
|
1155
|
-
const { incrementSkillSuccess } = await import("./skill-refinement-
|
|
1178
|
+
const { incrementSkillSuccess } = await import("./skill-refinement-7C7X42Z5.js");
|
|
1156
1179
|
await incrementSkillSuccess(
|
|
1157
1180
|
String(row.assigned_to),
|
|
1158
1181
|
row.project_name ? String(row.project_name) : null
|
|
@@ -1272,6 +1295,15 @@ async function cleanOrphanedTaskFiles() {
|
|
|
1272
1295
|
if (ageMs > 24 * 60 * 60 * 1e3) {
|
|
1273
1296
|
await unlink(fullPath);
|
|
1274
1297
|
cleaned++;
|
|
1298
|
+
recordOrchestrationEventBestEffort({
|
|
1299
|
+
eventType: "task_file.orphan_cleaned",
|
|
1300
|
+
source: "tasks-crud.cleanOrphanedTaskFiles",
|
|
1301
|
+
severity: "warn",
|
|
1302
|
+
payload: {
|
|
1303
|
+
ageHours: Math.round(ageMs / 36e5),
|
|
1304
|
+
type: "task_file_missing_db"
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1275
1307
|
process.stderr.write(`[task-cleanup] Removed orphan task file: ${relativePath}
|
|
1276
1308
|
`);
|
|
1277
1309
|
}
|
|
@@ -1285,6 +1317,39 @@ async function cleanOrphanedTaskFiles() {
|
|
|
1285
1317
|
await walkDir(EXE_TASKS_DIR);
|
|
1286
1318
|
return cleaned;
|
|
1287
1319
|
}
|
|
1320
|
+
async function checkTaskFileConsistency() {
|
|
1321
|
+
const client = getClient();
|
|
1322
|
+
let mismatches = 0;
|
|
1323
|
+
try {
|
|
1324
|
+
const result = await client.execute({
|
|
1325
|
+
sql: `SELECT id, title, task_file, status, assigned_to, session_scope, project_name
|
|
1326
|
+
FROM tasks
|
|
1327
|
+
WHERE status IN ('open', 'in_progress', 'needs_review', 'blocked')
|
|
1328
|
+
AND task_file IS NOT NULL AND task_file != ''`,
|
|
1329
|
+
args: []
|
|
1330
|
+
});
|
|
1331
|
+
for (const row of result.rows) {
|
|
1332
|
+
const taskFile = String(row.task_file ?? "");
|
|
1333
|
+
if (!taskFile) continue;
|
|
1334
|
+
const fullPath = taskFile.startsWith("/") ? taskFile : path2.join(os2.homedir(), ".exe-os", taskFile);
|
|
1335
|
+
if (!existsSync2(fullPath)) {
|
|
1336
|
+
mismatches++;
|
|
1337
|
+
recordOrchestrationEventBestEffort({
|
|
1338
|
+
eventType: "consistency.mismatch",
|
|
1339
|
+
source: "tasks-crud.checkTaskFileConsistency",
|
|
1340
|
+
severity: "warn",
|
|
1341
|
+
taskId: String(row.id),
|
|
1342
|
+
agentId: row.assigned_to ? String(row.assigned_to) : null,
|
|
1343
|
+
sessionScope: row.session_scope ? String(row.session_scope) : null,
|
|
1344
|
+
projectName: row.project_name ? String(row.project_name) : null,
|
|
1345
|
+
payload: { taskFile, status: String(row.status), type: "db_row_missing_file" }
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
} catch {
|
|
1350
|
+
}
|
|
1351
|
+
return mismatches;
|
|
1352
|
+
}
|
|
1288
1353
|
|
|
1289
1354
|
// src/lib/notifications.ts
|
|
1290
1355
|
import crypto2 from "crypto";
|
|
@@ -2239,7 +2304,7 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
2239
2304
|
reason: `capture-pane failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2240
2305
|
};
|
|
2241
2306
|
}
|
|
2242
|
-
const { isAtCapacity } = await import("./capacity-monitor-
|
|
2307
|
+
const { isAtCapacity } = await import("./capacity-monitor-EPHJTSKF.js");
|
|
2243
2308
|
if (!isAtCapacity(pane)) {
|
|
2244
2309
|
return {
|
|
2245
2310
|
atCapacity: false,
|
|
@@ -2576,6 +2641,16 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2576
2641
|
};
|
|
2577
2642
|
}
|
|
2578
2643
|
effectiveInstance = free === 0 ? void 0 : free;
|
|
2644
|
+
if (free !== null) {
|
|
2645
|
+
recordOrchestrationEventBestEffort({
|
|
2646
|
+
eventType: "worker.instance.selected",
|
|
2647
|
+
source: "tmux-routing.ensureEmployee",
|
|
2648
|
+
agentId: employeeName,
|
|
2649
|
+
sessionScope: exeSession,
|
|
2650
|
+
instanceId: String(free),
|
|
2651
|
+
payload: { maxInstances: opts.maxAutoInstances ?? 10 }
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2579
2654
|
}
|
|
2580
2655
|
const sessionName = employeeSessionName(employeeName, exeSession, effectiveInstance);
|
|
2581
2656
|
if (isEmployeeAlive(sessionName)) {
|
|
@@ -3023,6 +3098,7 @@ export {
|
|
|
3023
3098
|
ensureArchitectureDoc,
|
|
3024
3099
|
ensureGitignoreExe,
|
|
3025
3100
|
cleanOrphanedTaskFiles,
|
|
3101
|
+
checkTaskFileConsistency,
|
|
3026
3102
|
formatAge,
|
|
3027
3103
|
isStale,
|
|
3028
3104
|
countPendingReviews,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
recordOrchestrationEventBestEffort
|
|
3
|
+
} from "./chunk-ITYWLFYC.js";
|
|
4
|
+
|
|
1
5
|
// src/lib/worktree.ts
|
|
2
6
|
import { execSync } from "child_process";
|
|
3
7
|
import { existsSync, readFileSync, appendFileSync, mkdirSync, realpathSync } from "fs";
|
|
@@ -48,6 +52,13 @@ function ensureWorktree(projectDir, employeeName, instance) {
|
|
|
48
52
|
const wtPath = worktreePath(repoRoot, employeeName, instance);
|
|
49
53
|
const branch = worktreeBranch(employeeName, instance);
|
|
50
54
|
if (existsSync(path.join(wtPath, ".git"))) {
|
|
55
|
+
recordOrchestrationEventBestEffort({
|
|
56
|
+
eventType: "worktree.reused",
|
|
57
|
+
source: "worktree.ensureWorktree",
|
|
58
|
+
agentId: employeeName,
|
|
59
|
+
instanceId: instance != null ? String(instance) : null,
|
|
60
|
+
payload: { branch }
|
|
61
|
+
});
|
|
51
62
|
return wtPath;
|
|
52
63
|
}
|
|
53
64
|
const worktreesDir = path.join(repoRoot, ".worktrees");
|
|
@@ -79,8 +90,24 @@ function ensureWorktree(projectDir, employeeName, instance) {
|
|
|
79
90
|
stdio: ["pipe", "pipe", "pipe"]
|
|
80
91
|
});
|
|
81
92
|
}
|
|
93
|
+
recordOrchestrationEventBestEffort({
|
|
94
|
+
eventType: "worktree.created",
|
|
95
|
+
source: "worktree.ensureWorktree",
|
|
96
|
+
agentId: employeeName,
|
|
97
|
+
instanceId: instance != null ? String(instance) : null,
|
|
98
|
+
payload: { branch, reusedBranch: branchExists }
|
|
99
|
+
});
|
|
82
100
|
return wtPath;
|
|
83
101
|
} catch (err) {
|
|
102
|
+
recordOrchestrationEventBestEffort({
|
|
103
|
+
eventType: "worktree.failed",
|
|
104
|
+
source: "worktree.ensureWorktree",
|
|
105
|
+
severity: "warn",
|
|
106
|
+
agentId: employeeName,
|
|
107
|
+
instanceId: instance != null ? String(instance) : null,
|
|
108
|
+
errorCode: err instanceof Error ? err.name : "worktree_create_failed",
|
|
109
|
+
payload: { branch }
|
|
110
|
+
});
|
|
84
111
|
process.stderr.write(
|
|
85
112
|
`[worktree] Failed to create worktree for ${employeeName}: ${err instanceof Error ? err.message : String(err)}
|
|
86
113
|
`
|
|
@@ -107,16 +134,44 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
107
134
|
const wtPath = worktreePath(repoRoot, employeeName, instance);
|
|
108
135
|
const branch = worktreeBranch(employeeName, instance);
|
|
109
136
|
if (!existsSync(wtPath)) {
|
|
137
|
+
recordOrchestrationEventBestEffort({
|
|
138
|
+
eventType: "worktree.skipped",
|
|
139
|
+
source: "worktree.cleanupWorktree",
|
|
140
|
+
agentId: employeeName,
|
|
141
|
+
instanceId: instance != null ? String(instance) : null,
|
|
142
|
+
payload: { reason: "worktree does not exist", branch }
|
|
143
|
+
});
|
|
110
144
|
return { cleaned: false, reason: "worktree does not exist" };
|
|
111
145
|
}
|
|
112
146
|
if (isWorktreeDirty(wtPath)) {
|
|
147
|
+
recordOrchestrationEventBestEffort({
|
|
148
|
+
eventType: "worktree.skipped",
|
|
149
|
+
source: "worktree.cleanupWorktree",
|
|
150
|
+
agentId: employeeName,
|
|
151
|
+
instanceId: instance != null ? String(instance) : null,
|
|
152
|
+
payload: { reason: "worktree has uncommitted changes", branch }
|
|
153
|
+
});
|
|
113
154
|
return { cleaned: false, reason: "worktree has uncommitted changes" };
|
|
114
155
|
}
|
|
115
156
|
const mainBranch = detectMainBranch(repoRoot);
|
|
116
157
|
if (!mainBranch) {
|
|
158
|
+
recordOrchestrationEventBestEffort({
|
|
159
|
+
eventType: "worktree.skipped",
|
|
160
|
+
source: "worktree.cleanupWorktree",
|
|
161
|
+
agentId: employeeName,
|
|
162
|
+
instanceId: instance != null ? String(instance) : null,
|
|
163
|
+
payload: { reason: "could not determine main branch", branch }
|
|
164
|
+
});
|
|
117
165
|
return { cleaned: false, reason: "could not determine main branch" };
|
|
118
166
|
}
|
|
119
167
|
if (!isBranchMerged(repoRoot, branch, mainBranch)) {
|
|
168
|
+
recordOrchestrationEventBestEffort({
|
|
169
|
+
eventType: "worktree.skipped",
|
|
170
|
+
source: "worktree.cleanupWorktree",
|
|
171
|
+
agentId: employeeName,
|
|
172
|
+
instanceId: instance != null ? String(instance) : null,
|
|
173
|
+
payload: { reason: "branch not merged", branch, mainBranch }
|
|
174
|
+
});
|
|
120
175
|
return { cleaned: false, reason: `branch ${branch} not merged into ${mainBranch}` };
|
|
121
176
|
}
|
|
122
177
|
try {
|
|
@@ -127,6 +182,15 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
127
182
|
stdio: ["pipe", "pipe", "pipe"]
|
|
128
183
|
});
|
|
129
184
|
} catch (err) {
|
|
185
|
+
recordOrchestrationEventBestEffort({
|
|
186
|
+
eventType: "worktree.failed",
|
|
187
|
+
source: "worktree.cleanupWorktree",
|
|
188
|
+
severity: "warn",
|
|
189
|
+
agentId: employeeName,
|
|
190
|
+
instanceId: instance != null ? String(instance) : null,
|
|
191
|
+
errorCode: err instanceof Error ? err.name : "worktree_remove_failed",
|
|
192
|
+
payload: { branch, mainBranch }
|
|
193
|
+
});
|
|
130
194
|
return {
|
|
131
195
|
cleaned: false,
|
|
132
196
|
reason: `git worktree remove failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -141,6 +205,13 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
141
205
|
});
|
|
142
206
|
} catch {
|
|
143
207
|
}
|
|
208
|
+
recordOrchestrationEventBestEffort({
|
|
209
|
+
eventType: "worktree.pruned",
|
|
210
|
+
source: "worktree.cleanupWorktree",
|
|
211
|
+
agentId: employeeName,
|
|
212
|
+
instanceId: instance != null ? String(instance) : null,
|
|
213
|
+
payload: { branch, mainBranch }
|
|
214
|
+
});
|
|
144
215
|
return { cleaned: true, reason: `worktree and branch ${branch} removed (merged into ${mainBranch})` };
|
|
145
216
|
}
|
|
146
217
|
function branchExistsLocally(repoRoot, branch) {
|
|
@@ -3,30 +3,44 @@ import {
|
|
|
3
3
|
} from "./chunk-MLXJ5EZG.js";
|
|
4
4
|
import {
|
|
5
5
|
createTask
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-O2JGR7EU.js";
|
|
7
7
|
import {
|
|
8
8
|
getActiveAgent
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3N4ZEPZI.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureEmployee,
|
|
12
12
|
logTaskDispatch,
|
|
13
13
|
resolveExeSession
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FMKD6N33.js";
|
|
15
|
+
import {
|
|
16
|
+
recordOrchestrationEventBestEffort
|
|
17
|
+
} from "./chunk-ITYWLFYC.js";
|
|
18
|
+
import {
|
|
19
|
+
getAgentRuntime
|
|
20
|
+
} from "./chunk-6RX2XEET.js";
|
|
15
21
|
import {
|
|
16
22
|
getLicenseSync
|
|
17
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-3PDZQICZ.js";
|
|
18
24
|
import {
|
|
19
25
|
getAgentContext
|
|
20
26
|
} from "./chunk-GJV3WDWM.js";
|
|
21
27
|
import {
|
|
22
28
|
isCoordinatorName
|
|
23
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3MHKTBHZ.js";
|
|
24
30
|
|
|
25
31
|
// src/mcp/tools/create-task.ts
|
|
26
32
|
import { z } from "zod";
|
|
27
33
|
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
28
34
|
import { join } from "path";
|
|
29
35
|
import { homedir } from "os";
|
|
36
|
+
function resolveDispatchRuntime(agentId, override) {
|
|
37
|
+
if (override) return override;
|
|
38
|
+
try {
|
|
39
|
+
return getAgentRuntime(agentId).runtime ?? null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
30
44
|
async function resolveProjectDir(projectName, callerSession) {
|
|
31
45
|
const home = homedir();
|
|
32
46
|
if (callerSession) {
|
|
@@ -197,19 +211,39 @@ function registerCreateTask(server) {
|
|
|
197
211
|
session_scope: sessionScope,
|
|
198
212
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
199
213
|
}), "utf-8");
|
|
214
|
+
const { recordOrchestrationEventBestEffort: recordOE } = await import("./orchestration-events-MSJVUR4T.js");
|
|
215
|
+
recordOE({
|
|
216
|
+
eventType: "signal.created",
|
|
217
|
+
source: "create-task.mcp",
|
|
218
|
+
taskId: task.id,
|
|
219
|
+
agentId: assigned_to,
|
|
220
|
+
sessionScope,
|
|
221
|
+
payload: { priority }
|
|
222
|
+
});
|
|
200
223
|
} catch {
|
|
201
224
|
}
|
|
202
225
|
let dispatchStatus = "";
|
|
203
226
|
if (task.status !== "blocked" && !process.env.VITEST) {
|
|
204
227
|
try {
|
|
205
228
|
const exeSession = callerRoot || resolveExeSession();
|
|
229
|
+
const dispatchRuntime = resolveDispatchRuntime(assigned_to, spawn_runtime ?? null);
|
|
230
|
+
recordOrchestrationEventBestEffort({
|
|
231
|
+
eventType: "dispatch.attempted",
|
|
232
|
+
source: "create-task.mcp",
|
|
233
|
+
taskId: task.id,
|
|
234
|
+
agentId: assigned_to,
|
|
235
|
+
sessionScope: task.sessionScope || callerRoot || exeSession || null,
|
|
236
|
+
projectName: project_name,
|
|
237
|
+
runtime: dispatchRuntime,
|
|
238
|
+
payload: { priority }
|
|
239
|
+
});
|
|
206
240
|
if (exeSession) {
|
|
207
241
|
const { shouldAutoInstance } = await import("./lib/employees.js");
|
|
208
242
|
const autoOpts = shouldAutoInstance(assigned_to);
|
|
209
243
|
let projectConflictOpts = {};
|
|
210
244
|
try {
|
|
211
245
|
const { getClient } = await import("./lib/database.js");
|
|
212
|
-
const { sessionScopeFilter } = await import("./task-scope-
|
|
246
|
+
const { sessionScopeFilter } = await import("./task-scope-ULC62J6G.js");
|
|
213
247
|
const client = getClient();
|
|
214
248
|
const scope = sessionScopeFilter();
|
|
215
249
|
const existing = await client.execute({
|
|
@@ -243,6 +277,10 @@ function registerCreateTask(server) {
|
|
|
243
277
|
dispatchStatus = `
|
|
244
278
|
Dispatched: intercom sent to ${result.sessionName}`;
|
|
245
279
|
break;
|
|
280
|
+
case "intercom_unprocessed":
|
|
281
|
+
dispatchStatus = `
|
|
282
|
+
Dispatched: intercom delivered to ${result.sessionName}`;
|
|
283
|
+
break;
|
|
246
284
|
case "spawned":
|
|
247
285
|
dispatchStatus = `
|
|
248
286
|
Dispatched: spawned ${result.sessionName}`;
|
|
@@ -252,6 +290,20 @@ Dispatched: spawned ${result.sessionName}`;
|
|
|
252
290
|
Dispatch failed: ${result.error ?? "unknown"}`;
|
|
253
291
|
break;
|
|
254
292
|
}
|
|
293
|
+
recordOrchestrationEventBestEffort({
|
|
294
|
+
eventType: result.status === "failed" ? "dispatch.failed" : "dispatch.completed",
|
|
295
|
+
source: "create-task.mcp",
|
|
296
|
+
severity: result.status === "failed" ? "warn" : "info",
|
|
297
|
+
taskId: task.id,
|
|
298
|
+
agentId: assigned_to,
|
|
299
|
+
sessionScope: task.sessionScope || callerRoot || exeSession,
|
|
300
|
+
projectName: project_name,
|
|
301
|
+
tmuxSession: result.sessionName || null,
|
|
302
|
+
runtime: dispatchRuntime,
|
|
303
|
+
result: result.status,
|
|
304
|
+
errorCode: result.status === "failed" ? "ensure_employee_failed" : null,
|
|
305
|
+
payload: { priority, error: result.error ?? null }
|
|
306
|
+
});
|
|
255
307
|
try {
|
|
256
308
|
const { sendIntercom: si } = await import("./lib/tmux-routing.js");
|
|
257
309
|
const { listTmuxSessions } = await import("./lib/tmux-status.js");
|
|
@@ -287,8 +339,32 @@ Dispatch failed: ${result.error ?? "unknown"}`;
|
|
|
287
339
|
sessionName: result.sessionName,
|
|
288
340
|
error: result.error
|
|
289
341
|
});
|
|
342
|
+
} else {
|
|
343
|
+
recordOrchestrationEventBestEffort({
|
|
344
|
+
eventType: "dispatch.failed",
|
|
345
|
+
source: "create-task.mcp",
|
|
346
|
+
severity: "warn",
|
|
347
|
+
taskId: task.id,
|
|
348
|
+
agentId: assigned_to,
|
|
349
|
+
sessionScope: task.sessionScope || callerRoot || null,
|
|
350
|
+
projectName: project_name,
|
|
351
|
+
runtime: dispatchRuntime,
|
|
352
|
+
errorCode: "no_exe_session",
|
|
353
|
+
payload: { priority }
|
|
354
|
+
});
|
|
290
355
|
}
|
|
291
356
|
} catch (dispatchErr) {
|
|
357
|
+
recordOrchestrationEventBestEffort({
|
|
358
|
+
eventType: "dispatch.failed",
|
|
359
|
+
source: "create-task.mcp",
|
|
360
|
+
severity: "warn",
|
|
361
|
+
taskId: task.id,
|
|
362
|
+
agentId: assigned_to,
|
|
363
|
+
sessionScope: task.sessionScope || callerRoot || null,
|
|
364
|
+
projectName: project_name,
|
|
365
|
+
runtime: resolveDispatchRuntime(assigned_to, spawn_runtime ?? null),
|
|
366
|
+
errorCode: "exception"
|
|
367
|
+
});
|
|
292
368
|
process.stderr.write(`[create-task] dispatch error for ${assigned_to}: ${dispatchErr instanceof Error ? dispatchErr.message : String(dispatchErr)}
|
|
293
369
|
${dispatchErr instanceof Error ? dispatchErr.stack : ""}
|
|
294
370
|
`);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fastDbInit
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2THPPZF2.js";
|
|
4
4
|
import {
|
|
5
5
|
sessionScopeFilter
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FMKD6N33.js";
|
|
7
7
|
import {
|
|
8
8
|
formatStatusAll,
|
|
9
9
|
formatStatusDeep,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getClient,
|
|
15
15
|
isCoordinatorRole,
|
|
16
16
|
loadEmployees
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3MHKTBHZ.js";
|
|
18
18
|
import {
|
|
19
19
|
isMainModule
|
|
20
20
|
} from "./chunk-6Y4B3QF6.js";
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
recordOrchestrationEventBestEffort
|
|
3
|
+
} from "./chunk-ITYWLFYC.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/session-registry.ts
|
|
6
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import os from "os";
|
|
10
|
+
var REGISTRY_PATH = path.join(os.homedir(), ".exe-os", "session-registry.json");
|
|
11
|
+
function registerSession(entry) {
|
|
12
|
+
const dir = path.dirname(REGISTRY_PATH);
|
|
13
|
+
if (!existsSync(dir)) {
|
|
14
|
+
mkdirSync(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
const sessions = listSessions();
|
|
17
|
+
const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
|
|
18
|
+
if (idx >= 0) {
|
|
19
|
+
sessions[idx] = entry;
|
|
20
|
+
} else {
|
|
21
|
+
sessions.push(entry);
|
|
22
|
+
}
|
|
23
|
+
writeFileSync(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
24
|
+
recordOrchestrationEventBestEffort({
|
|
25
|
+
eventType: "registry.registered",
|
|
26
|
+
source: "session-registry.registerSession",
|
|
27
|
+
agentId: entry.agentId,
|
|
28
|
+
sessionScope: entry.parentExe,
|
|
29
|
+
tmuxSession: entry.windowName,
|
|
30
|
+
payload: { hasProjectDir: Boolean(entry.projectDir) }
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function refreshSessionProject(windowName, projectDir) {
|
|
34
|
+
const sessions = listSessions();
|
|
35
|
+
const entry = sessions.find((s) => s.windowName === windowName);
|
|
36
|
+
if (!entry || entry.projectDir === projectDir) return;
|
|
37
|
+
entry.projectDir = projectDir;
|
|
38
|
+
try {
|
|
39
|
+
writeFileSync(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function listSessions() {
|
|
44
|
+
try {
|
|
45
|
+
const raw = readFileSync(REGISTRY_PATH, "utf8");
|
|
46
|
+
return JSON.parse(raw);
|
|
47
|
+
} catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function pruneStaleSessions() {
|
|
52
|
+
const sessions = listSessions();
|
|
53
|
+
if (sessions.length === 0) return 0;
|
|
54
|
+
let liveSessions = [];
|
|
55
|
+
try {
|
|
56
|
+
liveSessions = execSync("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
57
|
+
encoding: "utf8"
|
|
58
|
+
}).trim().split("\n").filter(Boolean);
|
|
59
|
+
} catch {
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
const liveSet = new Set(liveSessions);
|
|
63
|
+
const alive = sessions.filter((s) => liveSet.has(s.windowName));
|
|
64
|
+
const staleSessions = sessions.filter((s) => !liveSet.has(s.windowName));
|
|
65
|
+
if (staleSessions.length > 0) {
|
|
66
|
+
recordOrchestrationEventBestEffort({
|
|
67
|
+
eventType: "registry.missing_tmux",
|
|
68
|
+
source: "session-registry.pruneStaleSessions",
|
|
69
|
+
severity: "warn",
|
|
70
|
+
attempt: staleSessions.length,
|
|
71
|
+
payload: {
|
|
72
|
+
count: staleSessions.length,
|
|
73
|
+
examples: staleSessions.slice(0, 5).map((s) => s.windowName)
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const pruned = sessions.length - alive.length;
|
|
78
|
+
if (pruned > 0) {
|
|
79
|
+
writeFileSync(REGISTRY_PATH, JSON.stringify(alive, null, 2));
|
|
80
|
+
}
|
|
81
|
+
return pruned;
|
|
82
|
+
}
|
|
83
|
+
function checkSessionRegistryConsistency(liveSessionsOverride) {
|
|
84
|
+
const sessions = listSessions();
|
|
85
|
+
const result = { missingTmux: 0, missingRegistry: 0 };
|
|
86
|
+
let liveSessions = liveSessionsOverride;
|
|
87
|
+
if (!liveSessions) {
|
|
88
|
+
try {
|
|
89
|
+
liveSessions = execSync("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
90
|
+
encoding: "utf8"
|
|
91
|
+
}).trim().split("\n").filter(Boolean);
|
|
92
|
+
} catch {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const liveSet = new Set(liveSessions);
|
|
97
|
+
const registeredSet = new Set(sessions.map((s) => s.windowName));
|
|
98
|
+
const missingTmuxExamples = [];
|
|
99
|
+
const missingRegistryExamples = [];
|
|
100
|
+
for (const entry of sessions) {
|
|
101
|
+
if (liveSet.has(entry.windowName)) continue;
|
|
102
|
+
result.missingTmux++;
|
|
103
|
+
if (missingTmuxExamples.length < 5) missingTmuxExamples.push(entry.windowName);
|
|
104
|
+
}
|
|
105
|
+
for (const live of liveSessions) {
|
|
106
|
+
if (registeredSet.has(live)) continue;
|
|
107
|
+
if (!looksLikeExeOsSession(live)) continue;
|
|
108
|
+
result.missingRegistry++;
|
|
109
|
+
if (missingRegistryExamples.length < 5) missingRegistryExamples.push(live);
|
|
110
|
+
}
|
|
111
|
+
if (result.missingTmux > 0) {
|
|
112
|
+
recordOrchestrationEventBestEffort({
|
|
113
|
+
eventType: "registry.missing_tmux",
|
|
114
|
+
source: "session-registry.checkSessionRegistryConsistency",
|
|
115
|
+
severity: "warn",
|
|
116
|
+
attempt: result.missingTmux,
|
|
117
|
+
payload: {
|
|
118
|
+
count: result.missingTmux,
|
|
119
|
+
examples: missingTmuxExamples
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (result.missingRegistry > 0) {
|
|
124
|
+
recordOrchestrationEventBestEffort({
|
|
125
|
+
eventType: "registry.missing_entry",
|
|
126
|
+
source: "session-registry.checkSessionRegistryConsistency",
|
|
127
|
+
severity: "warn",
|
|
128
|
+
attempt: result.missingRegistry,
|
|
129
|
+
payload: {
|
|
130
|
+
count: result.missingRegistry,
|
|
131
|
+
examples: missingRegistryExamples
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
function looksLikeExeOsSession(sessionName) {
|
|
138
|
+
return /^exe\d*$/.test(sessionName) || /-exe\d*$/.test(sessionName);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
registerSession,
|
|
143
|
+
refreshSessionProject,
|
|
144
|
+
listSessions,
|
|
145
|
+
pruneStaleSessions,
|
|
146
|
+
checkSessionRegistryConsistency
|
|
147
|
+
};
|