@askexenow/exe-os 0.8.60 → 0.8.61

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.
@@ -17,15 +17,15 @@ var __export = (target, all) => {
17
17
 
18
18
  // src/lib/config.ts
19
19
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
20
- import { readFileSync, existsSync, renameSync } from "fs";
21
- import path from "path";
20
+ import { readFileSync as readFileSync2, existsSync as existsSync2, renameSync } from "fs";
21
+ import path2 from "path";
22
22
  import os from "os";
23
23
  function resolveDataDir() {
24
24
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
25
25
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
26
- const newDir = path.join(os.homedir(), ".exe-os");
27
- const legacyDir = path.join(os.homedir(), ".exe-mem");
28
- if (!existsSync(newDir) && existsSync(legacyDir)) {
26
+ const newDir = path2.join(os.homedir(), ".exe-os");
27
+ const legacyDir = path2.join(os.homedir(), ".exe-mem");
28
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
29
29
  try {
30
30
  renameSync(legacyDir, newDir);
31
31
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -41,10 +41,10 @@ var init_config = __esm({
41
41
  "src/lib/config.ts"() {
42
42
  "use strict";
43
43
  EXE_AI_DIR = resolveDataDir();
44
- DB_PATH = path.join(EXE_AI_DIR, "memories.db");
45
- MODELS_DIR = path.join(EXE_AI_DIR, "models");
46
- CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
47
- LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
44
+ DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
45
+ MODELS_DIR = path2.join(EXE_AI_DIR, "models");
46
+ CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
47
+ LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
48
48
  CURRENT_CONFIG_VERSION = 1;
49
49
  DEFAULT_CONFIG = {
50
50
  config_version: CURRENT_CONFIG_VERSION,
@@ -112,6 +112,97 @@ var init_config = __esm({
112
112
  }
113
113
  });
114
114
 
115
+ // src/lib/employees.ts
116
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
117
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
118
+ import { execSync } from "child_process";
119
+ import path3 from "path";
120
+ function validateEmployeeName(name) {
121
+ if (!name) {
122
+ return { valid: false, error: "Name is required" };
123
+ }
124
+ if (name.length > 32) {
125
+ return { valid: false, error: "Name must be 32 characters or fewer" };
126
+ }
127
+ if (!/^[a-z][a-z0-9]*$/.test(name)) {
128
+ return {
129
+ valid: false,
130
+ error: "Name must start with a letter and contain only lowercase alphanumeric characters"
131
+ };
132
+ }
133
+ return { valid: true };
134
+ }
135
+ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
136
+ if (!existsSync3(employeesPath)) {
137
+ return [];
138
+ }
139
+ const raw = await readFile2(employeesPath, "utf-8");
140
+ try {
141
+ return JSON.parse(raw);
142
+ } catch {
143
+ return [];
144
+ }
145
+ }
146
+ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
147
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
148
+ await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
149
+ }
150
+ function addEmployee(employees, employee) {
151
+ const normalized = { ...employee, name: employee.name.toLowerCase() };
152
+ if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
153
+ throw new Error(`Employee '${normalized.name}' already exists`);
154
+ }
155
+ return [...employees, normalized];
156
+ }
157
+ function findExeBin() {
158
+ try {
159
+ return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
160
+ } catch {
161
+ return null;
162
+ }
163
+ }
164
+ function registerBinSymlinks(name) {
165
+ const created = [];
166
+ const skipped = [];
167
+ const errors = [];
168
+ const exeBinPath = findExeBin();
169
+ if (!exeBinPath) {
170
+ errors.push("Could not find 'exe-os' in PATH");
171
+ return { created, skipped, errors };
172
+ }
173
+ const binDir = path3.dirname(exeBinPath);
174
+ let target;
175
+ try {
176
+ target = readlinkSync(exeBinPath);
177
+ } catch {
178
+ errors.push("Could not read 'exe' symlink");
179
+ return { created, skipped, errors };
180
+ }
181
+ for (const suffix of ["", "-opencode"]) {
182
+ const linkName = `${name}${suffix}`;
183
+ const linkPath = path3.join(binDir, linkName);
184
+ if (existsSync3(linkPath)) {
185
+ skipped.push(linkName);
186
+ continue;
187
+ }
188
+ try {
189
+ symlinkSync(target, linkPath);
190
+ created.push(linkName);
191
+ } catch (err) {
192
+ errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
193
+ }
194
+ }
195
+ return { created, skipped, errors };
196
+ }
197
+ var EMPLOYEES_PATH;
198
+ var init_employees = __esm({
199
+ "src/lib/employees.ts"() {
200
+ "use strict";
201
+ init_config();
202
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
203
+ }
204
+ });
205
+
115
206
  // src/lib/db-retry.ts
116
207
  var init_db_retry = __esm({
117
208
  "src/lib/db-retry.ts"() {
@@ -675,17 +766,17 @@ __export(identity_exports, {
675
766
  listIdentities: () => listIdentities,
676
767
  updateIdentity: () => updateIdentity
677
768
  });
678
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
679
- import { readdirSync } from "fs";
680
- import path5 from "path";
769
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
770
+ import { readdirSync as readdirSync2 } from "fs";
771
+ import path6 from "path";
681
772
  import { createHash } from "crypto";
682
773
  function ensureDir() {
683
- if (!existsSync5(IDENTITY_DIR)) {
684
- mkdirSync2(IDENTITY_DIR, { recursive: true });
774
+ if (!existsSync6(IDENTITY_DIR)) {
775
+ mkdirSync3(IDENTITY_DIR, { recursive: true });
685
776
  }
686
777
  }
687
778
  function identityPath(agentId) {
688
- return path5.join(IDENTITY_DIR, `${agentId}.md`);
779
+ return path6.join(IDENTITY_DIR, `${agentId}.md`);
689
780
  }
690
781
  function parseFrontmatter(raw) {
691
782
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -726,8 +817,8 @@ function contentHash(content) {
726
817
  }
727
818
  function getIdentity(agentId) {
728
819
  const filePath = identityPath(agentId);
729
- if (!existsSync5(filePath)) return null;
730
- const raw = readFileSync5(filePath, "utf-8");
820
+ if (!existsSync6(filePath)) return null;
821
+ const raw = readFileSync6(filePath, "utf-8");
731
822
  const { frontmatter, body } = parseFrontmatter(raw);
732
823
  return {
733
824
  agentId,
@@ -741,7 +832,7 @@ async function updateIdentity(agentId, content, updatedBy) {
741
832
  ensureDir();
742
833
  const filePath = identityPath(agentId);
743
834
  const hash = contentHash(content);
744
- writeFileSync2(filePath, content, "utf-8");
835
+ writeFileSync3(filePath, content, "utf-8");
745
836
  try {
746
837
  const client = getClient();
747
838
  await client.execute({
@@ -758,7 +849,7 @@ async function updateIdentity(agentId, content, updatedBy) {
758
849
  }
759
850
  function listIdentities() {
760
851
  ensureDir();
761
- const files = readdirSync(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
852
+ const files = readdirSync2(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
762
853
  const results = [];
763
854
  for (const file of files) {
764
855
  const agentId = file.replace(".md", "");
@@ -797,99 +888,746 @@ var init_identity = __esm({
797
888
  "use strict";
798
889
  init_config();
799
890
  init_database();
800
- IDENTITY_DIR = path5.join(EXE_AI_DIR, "identity");
891
+ IDENTITY_DIR = path6.join(EXE_AI_DIR, "identity");
801
892
  }
802
893
  });
803
894
 
804
- // src/bin/exe-new-employee.ts
805
- import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
806
- import path6 from "path";
807
-
808
- // src/lib/employees.ts
809
- init_config();
810
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
811
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
812
- import { execSync } from "child_process";
813
- import path2 from "path";
814
- var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
815
- function validateEmployeeName(name) {
816
- if (!name) {
817
- return { valid: false, error: "Name is required" };
818
- }
819
- if (name.length > 32) {
820
- return { valid: false, error: "Name must be 32 characters or fewer" };
895
+ // src/lib/agent-symlinks.ts
896
+ import os2 from "os";
897
+ import path7 from "path";
898
+ import {
899
+ existsSync as existsSync7,
900
+ lstatSync,
901
+ mkdirSync as mkdirSync4,
902
+ readlinkSync as readlinkSync2,
903
+ symlinkSync as symlinkSync2
904
+ } from "fs";
905
+ function claudeAgentsDir(homeDir) {
906
+ return path7.join(homeDir, ".claude", "agents");
907
+ }
908
+ function identitySourcePath(homeDir, agentId) {
909
+ return path7.join(homeDir, ".exe-os", "identity", `${agentId}.md`);
910
+ }
911
+ function claudeAgentLinkPath(homeDir, agentId) {
912
+ return path7.join(claudeAgentsDir(homeDir), `${agentId}.md`);
913
+ }
914
+ function ensureAgentSymlink(agentId, homeDir = os2.homedir()) {
915
+ const target = identitySourcePath(homeDir, agentId);
916
+ const link = claudeAgentLinkPath(homeDir, agentId);
917
+ mkdirSync4(claudeAgentsDir(homeDir), { recursive: true });
918
+ if (existsSync7(link)) {
919
+ let stat;
920
+ try {
921
+ stat = lstatSync(link);
922
+ } catch {
923
+ return { agentId, action: "conflict", target, link, conflict: "stat_failed" };
924
+ }
925
+ if (!stat.isSymbolicLink()) {
926
+ return { agentId, action: "conflict", target, link, conflict: "regular_file" };
927
+ }
928
+ let currentTarget;
929
+ try {
930
+ currentTarget = readlinkSync2(link);
931
+ } catch {
932
+ return { agentId, action: "conflict", target, link, conflict: "readlink_failed" };
933
+ }
934
+ if (currentTarget === target) {
935
+ return { agentId, action: "already_correct", target, link };
936
+ }
937
+ return { agentId, action: "conflict", target, link, conflict: `points_to:${currentTarget}` };
821
938
  }
822
- if (!/^[a-z][a-z0-9]*$/.test(name)) {
939
+ try {
940
+ symlinkSync2(target, link);
941
+ } catch (err) {
823
942
  return {
824
- valid: false,
825
- error: "Name must start with a letter and contain only lowercase alphanumeric characters"
943
+ agentId,
944
+ action: "conflict",
945
+ target,
946
+ link,
947
+ conflict: err instanceof Error ? err.message : String(err)
826
948
  };
827
949
  }
828
- return { valid: true };
950
+ return { agentId, action: "created", target, link };
829
951
  }
830
- async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
831
- if (!existsSync2(employeesPath)) {
832
- return [];
952
+ async function ensureAllAgentSymlinks(homeDir = os2.homedir()) {
953
+ const employees = await loadEmployees();
954
+ return employees.map((emp) => ensureAgentSymlink(emp.name, homeDir));
955
+ }
956
+ var init_agent_symlinks = __esm({
957
+ "src/lib/agent-symlinks.ts"() {
958
+ "use strict";
959
+ init_employees();
833
960
  }
834
- const raw = await readFile2(employeesPath, "utf-8");
961
+ });
962
+
963
+ // src/lib/mcp-prefix.ts
964
+ function expandDualPrefixTools(shortNames) {
965
+ const out = [];
966
+ for (const name of shortNames) {
967
+ for (const prefix of MCP_TOOL_PREFIXES) {
968
+ out.push(prefix + name);
969
+ }
970
+ }
971
+ return out;
972
+ }
973
+ var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
974
+ var init_mcp_prefix = __esm({
975
+ "src/lib/mcp-prefix.ts"() {
976
+ "use strict";
977
+ MCP_PRIMARY_KEY = "exe-os";
978
+ MCP_LEGACY_KEY = "exe-mem";
979
+ MCP_TOOL_PREFIXES = [
980
+ `mcp__${MCP_PRIMARY_KEY}__`,
981
+ `mcp__${MCP_LEGACY_KEY}__`
982
+ ];
983
+ }
984
+ });
985
+
986
+ // src/adapters/claude/installer.ts
987
+ var installer_exports = {};
988
+ __export(installer_exports, {
989
+ copySlashCommands: () => copySlashCommands,
990
+ mergeHooks: () => mergeHooks,
991
+ registerMcpServer: () => registerMcpServer,
992
+ resolvePackageRoot: () => resolvePackageRoot,
993
+ runInstaller: () => runInstaller,
994
+ setupTmux: () => setupTmux
995
+ });
996
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
997
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync5 } from "fs";
998
+ import path8 from "path";
999
+ import os3 from "os";
1000
+ import { execSync as execSync2 } from "child_process";
1001
+ import { fileURLToPath as fileURLToPath2 } from "url";
1002
+ function resolvePackageRoot() {
1003
+ const thisFile = fileURLToPath2(import.meta.url);
1004
+ let dir = path8.dirname(thisFile);
1005
+ const root = path8.parse(dir).root;
1006
+ while (dir !== root) {
1007
+ const pkgPath = path8.join(dir, "package.json");
1008
+ if (existsSync8(pkgPath)) {
1009
+ try {
1010
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
1011
+ if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
1012
+ } catch {
1013
+ }
1014
+ }
1015
+ dir = path8.dirname(dir);
1016
+ }
1017
+ return path8.resolve(path8.dirname(thisFile), "..", "..", "..");
1018
+ }
1019
+ async function copySlashCommands(packageRoot, homeDir = os3.homedir()) {
1020
+ let copied = 0;
1021
+ let skipped = 0;
1022
+ const skillsBase = path8.join(homeDir, ".claude", "skills");
1023
+ const exeDir = path8.join(packageRoot, "src", "commands", "exe");
1024
+ if (existsSync8(exeDir)) {
1025
+ const entries = await readdir(exeDir);
1026
+ const mdFiles = entries.filter((f) => f.endsWith(".md"));
1027
+ for (const file of mdFiles) {
1028
+ const name = file.replace(".md", "");
1029
+ const destDir = path8.join(skillsBase, `exe-${name}`);
1030
+ await mkdir3(destDir, { recursive: true });
1031
+ const srcPath = path8.join(exeDir, file);
1032
+ const destPath = path8.join(destDir, "SKILL.md");
1033
+ const result = await copyAsSkill(srcPath, destPath, `exe-${name}`);
1034
+ if (result) copied++;
1035
+ else skipped++;
1036
+ }
1037
+ }
1038
+ const topLevelSrc = path8.join(packageRoot, "src", "commands", "exe.md");
1039
+ if (existsSync8(topLevelSrc)) {
1040
+ const destDir = path8.join(skillsBase, "exe");
1041
+ await mkdir3(destDir, { recursive: true });
1042
+ const destPath = path8.join(destDir, "SKILL.md");
1043
+ const result = await copyAsSkill(topLevelSrc, destPath, "exe");
1044
+ if (result) copied++;
1045
+ else skipped++;
1046
+ }
1047
+ return { copied, skipped };
1048
+ }
1049
+ async function copyAsSkill(srcPath, destPath, skillName) {
1050
+ let content = await readFile3(srcPath, "utf-8");
1051
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
1052
+ if (fmMatch?.[1]) {
1053
+ const fm = fmMatch[1];
1054
+ if (fm.includes("name:")) {
1055
+ content = content.replace(
1056
+ /^(---\n[\s\S]*?)name:\s*[^\n]+/,
1057
+ `$1name: ${skillName}`
1058
+ );
1059
+ } else {
1060
+ content = content.replace(/^---\n/, `---
1061
+ name: ${skillName}
1062
+ `);
1063
+ }
1064
+ }
1065
+ if (existsSync8(destPath)) {
1066
+ const existing = await readFile3(destPath, "utf-8");
1067
+ if (existing === content) return false;
1068
+ }
1069
+ await writeFile3(destPath, content);
1070
+ return true;
1071
+ }
1072
+ async function registerMcpServer(packageRoot, homeDir = os3.homedir()) {
1073
+ const claudeJsonPath = path8.join(homeDir, ".claude.json");
1074
+ let claudeJson = {};
1075
+ if (existsSync8(claudeJsonPath)) {
1076
+ try {
1077
+ claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
1078
+ } catch {
1079
+ claudeJson = {};
1080
+ }
1081
+ }
1082
+ if (!claudeJson.mcpServers) {
1083
+ claudeJson.mcpServers = {};
1084
+ }
1085
+ const newEntry = {
1086
+ type: "stdio",
1087
+ command: "node",
1088
+ args: [path8.join(packageRoot, "dist", "mcp", "server.js")],
1089
+ env: {}
1090
+ };
1091
+ const legacy = claudeJson.mcpServers[MCP_LEGACY_KEY];
1092
+ const current = claudeJson.mcpServers[MCP_PRIMARY_KEY];
1093
+ const currentMatches = current && JSON.stringify(current) === JSON.stringify(newEntry);
1094
+ if (currentMatches && !legacy) {
1095
+ return false;
1096
+ }
1097
+ claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
1098
+ if (legacy) {
1099
+ delete claudeJson.mcpServers[MCP_LEGACY_KEY];
1100
+ }
1101
+ await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
1102
+ return true;
1103
+ }
1104
+ async function mergeHooks(packageRoot, homeDir = os3.homedir()) {
1105
+ const settingsPath = path8.join(homeDir, ".claude", "settings.json");
1106
+ let settings = {};
1107
+ if (existsSync8(settingsPath)) {
1108
+ try {
1109
+ settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
1110
+ } catch {
1111
+ settings = {};
1112
+ }
1113
+ }
1114
+ if (!settings.hooks) {
1115
+ settings.hooks = {};
1116
+ }
1117
+ if (settings.hooks && typeof settings.hooks !== "object") {
1118
+ console.warn("[exe-os] Unexpected hooks schema in settings.json \u2014 skipping hook installation");
1119
+ return { added: 0, skipped: 0 };
1120
+ }
1121
+ const hooksToRegister = [
1122
+ {
1123
+ event: "PostToolUse",
1124
+ group: {
1125
+ matcher: "Bash|Edit|Write|Read|Glob|Grep|Agent|mcp__.*",
1126
+ hooks: [
1127
+ {
1128
+ type: "command",
1129
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "ingest.js")}"`
1130
+ },
1131
+ {
1132
+ type: "command",
1133
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "error-recall.js")}"`
1134
+ }
1135
+ ]
1136
+ },
1137
+ marker: "dist/hooks/ingest.js"
1138
+ },
1139
+ {
1140
+ event: "SessionStart",
1141
+ group: {
1142
+ hooks: [
1143
+ {
1144
+ type: "command",
1145
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "session-start.js")}"`,
1146
+ timeout: 1e4
1147
+ }
1148
+ ]
1149
+ },
1150
+ marker: "dist/hooks/session-start.js"
1151
+ },
1152
+ {
1153
+ event: "UserPromptSubmit",
1154
+ group: {
1155
+ hooks: [
1156
+ {
1157
+ type: "command",
1158
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"`
1159
+ }
1160
+ ]
1161
+ },
1162
+ marker: "dist/hooks/prompt-submit.js"
1163
+ },
1164
+ {
1165
+ event: "UserPromptSubmit",
1166
+ group: {
1167
+ hooks: [
1168
+ {
1169
+ type: "command",
1170
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"`,
1171
+ timeout: 5e3
1172
+ }
1173
+ ]
1174
+ },
1175
+ marker: "dist/hooks/exe-heartbeat-hook.js"
1176
+ },
1177
+ {
1178
+ event: "Stop",
1179
+ group: {
1180
+ hooks: [
1181
+ {
1182
+ type: "command",
1183
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "stop.js")}"`
1184
+ }
1185
+ ]
1186
+ },
1187
+ marker: "dist/hooks/stop.js"
1188
+ },
1189
+ {
1190
+ event: "PreToolUse",
1191
+ group: {
1192
+ matcher: "Write|Edit|Read|Bash",
1193
+ hooks: [
1194
+ {
1195
+ type: "command",
1196
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"`
1197
+ }
1198
+ ]
1199
+ },
1200
+ marker: "dist/hooks/pre-tool-use.js"
1201
+ },
1202
+ {
1203
+ event: "SubagentStop",
1204
+ group: {
1205
+ hooks: [
1206
+ {
1207
+ type: "command",
1208
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"`
1209
+ }
1210
+ ]
1211
+ },
1212
+ marker: "dist/hooks/subagent-stop.js"
1213
+ },
1214
+ {
1215
+ event: "PreCompact",
1216
+ group: {
1217
+ hooks: [
1218
+ {
1219
+ type: "command",
1220
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "pre-compact.js")}"`,
1221
+ timeout: 1e4
1222
+ }
1223
+ ]
1224
+ },
1225
+ marker: "dist/hooks/pre-compact.js"
1226
+ },
1227
+ {
1228
+ event: "SessionEnd",
1229
+ group: {
1230
+ hooks: [
1231
+ {
1232
+ type: "command",
1233
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "session-end.js")}"`
1234
+ }
1235
+ ]
1236
+ },
1237
+ marker: "dist/hooks/session-end.js"
1238
+ },
1239
+ {
1240
+ event: "Notification",
1241
+ group: {
1242
+ hooks: [
1243
+ {
1244
+ type: "command",
1245
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "notification.js")}"`
1246
+ }
1247
+ ]
1248
+ },
1249
+ marker: "dist/hooks/notification.js"
1250
+ },
1251
+ {
1252
+ event: "PostCompact",
1253
+ group: {
1254
+ hooks: [
1255
+ {
1256
+ type: "command",
1257
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "post-compact.js")}"`,
1258
+ timeout: 1e4
1259
+ }
1260
+ ]
1261
+ },
1262
+ marker: "dist/hooks/post-compact.js"
1263
+ },
1264
+ {
1265
+ event: "InstructionsLoaded",
1266
+ group: {
1267
+ hooks: [
1268
+ {
1269
+ type: "command",
1270
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"`
1271
+ }
1272
+ ]
1273
+ },
1274
+ marker: "dist/hooks/instructions-loaded.js"
1275
+ }
1276
+ ];
1277
+ let added = 0;
1278
+ let skipped = 0;
1279
+ for (const { event, group, marker } of hooksToRegister) {
1280
+ if (!settings.hooks[event]) {
1281
+ settings.hooks[event] = [];
1282
+ }
1283
+ if (!Array.isArray(settings.hooks[event])) {
1284
+ console.warn(`[exe-os] Hook event "${event}" has unexpected structure \u2014 skipping`);
1285
+ skipped++;
1286
+ continue;
1287
+ }
1288
+ const existing = settings.hooks[event];
1289
+ const correctCommand = group.hooks[0]?.command ?? "";
1290
+ const alreadyCorrect = existing.some(
1291
+ (g) => g.hooks.some((h) => h.command === correctCommand)
1292
+ );
1293
+ if (alreadyCorrect) {
1294
+ skipped++;
1295
+ } else {
1296
+ settings.hooks[event] = existing.filter(
1297
+ (g) => !g.hooks.some((h) => h.command.includes(marker))
1298
+ );
1299
+ settings.hooks[event].push(group);
1300
+ added++;
1301
+ }
1302
+ }
1303
+ const perms = settings.permissions;
1304
+ if (!perms) {
1305
+ settings.permissions = {};
1306
+ }
1307
+ const permissions = settings.permissions;
1308
+ if (!Array.isArray(permissions.allow)) {
1309
+ permissions.allow = [];
1310
+ }
1311
+ const toolNames = [
1312
+ // Core memory
1313
+ "store_memory",
1314
+ "recall_my_memory",
1315
+ "commit_to_long_term_memory",
1316
+ "consolidate_memories",
1317
+ "ask_team_memory",
1318
+ "get_session_context",
1319
+ // Tasks
1320
+ "create_task",
1321
+ "list_tasks",
1322
+ "get_task",
1323
+ "update_task",
1324
+ "close_task",
1325
+ "checkpoint_task",
1326
+ // Behaviors
1327
+ "store_behavior",
1328
+ "deactivate_behavior",
1329
+ "list_behaviors",
1330
+ // Identity
1331
+ "get_identity",
1332
+ "update_identity",
1333
+ // Messaging
1334
+ "send_message",
1335
+ "acknowledge_messages",
1336
+ "send_whatsapp",
1337
+ "query_conversations",
1338
+ // Reminders + triggers
1339
+ "create_reminder",
1340
+ "complete_reminder",
1341
+ "list_reminders",
1342
+ "create_trigger",
1343
+ "list_triggers",
1344
+ // GraphRAG
1345
+ "query_relationships",
1346
+ "merge_entities",
1347
+ // Documents + wiki
1348
+ "ingest_document",
1349
+ "list_documents",
1350
+ "purge_document",
1351
+ "rerank_documents",
1352
+ "set_document_importance",
1353
+ "create_wiki_page",
1354
+ "update_wiki_page",
1355
+ "get_wiki_page",
1356
+ "list_wiki_pages",
1357
+ // System
1358
+ "load_skill",
1359
+ "apply_starter_pack",
1360
+ "resume_employee",
1361
+ "deploy_client"
1362
+ ];
1363
+ const allowList = permissions.allow;
1364
+ for (const tool of expandDualPrefixTools(toolNames)) {
1365
+ if (!allowList.includes(tool)) {
1366
+ allowList.push(tool);
1367
+ }
1368
+ }
1369
+ await mkdir3(path8.dirname(settingsPath), { recursive: true });
1370
+ await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1371
+ return { added, skipped };
1372
+ }
1373
+ async function injectOrchestrationRules(homeDir) {
1374
+ const claudeDir = path8.join(homeDir, ".claude");
1375
+ const claudeMdPath = path8.join(claudeDir, "CLAUDE.md");
1376
+ await mkdir3(claudeDir, { recursive: true });
1377
+ let existing = "";
835
1378
  try {
836
- return JSON.parse(raw);
1379
+ existing = await readFile3(claudeMdPath, "utf-8");
837
1380
  } catch {
838
- return [];
839
1381
  }
1382
+ const startIdx = existing.indexOf(EXE_SECTION_START);
1383
+ const endIdx = existing.indexOf(EXE_SECTION_END);
1384
+ if (startIdx !== -1 && endIdx !== -1) {
1385
+ const currentSection = existing.slice(startIdx, endIdx + EXE_SECTION_END.length);
1386
+ if (currentSection === ORCHESTRATION_RULES) {
1387
+ return "unchanged";
1388
+ }
1389
+ const updated = existing.slice(0, startIdx) + ORCHESTRATION_RULES + existing.slice(endIdx + EXE_SECTION_END.length);
1390
+ await writeFile3(claudeMdPath, updated, "utf-8");
1391
+ return "updated";
1392
+ }
1393
+ const separator = existing.length > 0 && !existing.endsWith("\n\n") ? "\n\n" : "";
1394
+ await writeFile3(claudeMdPath, existing + separator + ORCHESTRATION_RULES + "\n", "utf-8");
1395
+ return "injected";
840
1396
  }
841
- async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
842
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
843
- await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
844
- }
845
- function addEmployee(employees, employee) {
846
- const normalized = { ...employee, name: employee.name.toLowerCase() };
847
- if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
848
- throw new Error(`Employee '${normalized.name}' already exists`);
1397
+ async function runInstaller(homeDir) {
1398
+ const packageRoot = resolvePackageRoot();
1399
+ process.stderr.write(`exe-os installer v1.3.0
1400
+ `);
1401
+ process.stderr.write(`Package root: ${packageRoot}
1402
+
1403
+ `);
1404
+ const cmdResult = await copySlashCommands(packageRoot, homeDir);
1405
+ process.stderr.write(
1406
+ `Slash commands: ${cmdResult.copied} copied, ${cmdResult.skipped} unchanged
1407
+ `
1408
+ );
1409
+ const mcpChanged = await registerMcpServer(packageRoot, homeDir);
1410
+ process.stderr.write(
1411
+ `MCP server: ${mcpChanged ? "registered" : "already registered"}
1412
+ `
1413
+ );
1414
+ const hookResult = await mergeHooks(packageRoot, homeDir);
1415
+ process.stderr.write(
1416
+ `Hooks: ${hookResult.added} added, ${hookResult.skipped} unchanged
1417
+ `
1418
+ );
1419
+ const resolvedHome = homeDir ?? os3.homedir();
1420
+ const exeWorkspace = path8.join(resolvedHome, "exe");
1421
+ if (!existsSync8(exeWorkspace)) {
1422
+ try {
1423
+ await mkdir3(path8.join(exeWorkspace, "content"), { recursive: true });
1424
+ await mkdir3(path8.join(exeWorkspace, "operations"), { recursive: true });
1425
+ await mkdir3(path8.join(exeWorkspace, "output"), { recursive: true });
1426
+ process.stderr.write(
1427
+ `Created ~/exe/ \u2014 your automation workspace for non-code projects
1428
+ `
1429
+ );
1430
+ } catch {
1431
+ }
849
1432
  }
850
- return [...employees, normalized];
1433
+ const claudeMdResult = await injectOrchestrationRules(resolvedHome);
1434
+ process.stderr.write(
1435
+ `CLAUDE.md orchestration: ${claudeMdResult}
1436
+ `
1437
+ );
1438
+ const symlinkResults = await ensureAllAgentSymlinks(resolvedHome);
1439
+ process.stderr.write(
1440
+ `Agent symlinks: ${summarizeSymlinkResults(symlinkResults)}
1441
+ `
1442
+ );
1443
+ process.stderr.write(`
1444
+ exe-os installed successfully.
1445
+ `);
851
1446
  }
852
- function findExeBin() {
1447
+ function setupTmux(home) {
1448
+ const homeDir = home ?? os3.homedir();
1449
+ const exeDir = path8.join(homeDir, ".exe-os");
1450
+ const exeTmuxConf = path8.join(exeDir, "tmux.conf");
1451
+ const userTmuxConf = path8.join(homeDir, ".tmux.conf");
1452
+ const backupPath = path8.join(homeDir, ".tmux.conf.backup");
1453
+ const sourceLine = "source-file ~/.exe-os/tmux.conf";
1454
+ const pkgRoot = resolvePackageRoot();
1455
+ const assetPath = path8.join(pkgRoot, "dist", "assets", "tmux.conf");
1456
+ if (!existsSync8(assetPath)) {
1457
+ process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
1458
+ `);
1459
+ return;
1460
+ }
1461
+ mkdirSync5(exeDir, { recursive: true });
1462
+ copyFileSync(assetPath, exeTmuxConf);
1463
+ if (existsSync8(userTmuxConf)) {
1464
+ const existing = readFileSync7(userTmuxConf, "utf8");
1465
+ if (!existing.includes(sourceLine)) {
1466
+ if (!existsSync8(backupPath)) {
1467
+ copyFileSync(userTmuxConf, backupPath);
1468
+ process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
1469
+ `);
1470
+ }
1471
+ writeFileSync4(userTmuxConf, `${sourceLine}
1472
+ ${existing}`);
1473
+ }
1474
+ } else {
1475
+ writeFileSync4(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1476
+ ${sourceLine}
1477
+ `);
1478
+ }
853
1479
  try {
854
- return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
1480
+ execSync2(`tmux source-file ${exeTmuxConf} 2>/dev/null`);
855
1481
  } catch {
856
- return null;
857
1482
  }
1483
+ process.stderr.write("exe-os: tmux config installed\n");
858
1484
  }
859
- function registerBinSymlinks(name) {
860
- const created = [];
861
- const skipped = [];
862
- const errors = [];
863
- const exeBinPath = findExeBin();
864
- if (!exeBinPath) {
865
- errors.push("Could not find 'exe-os' in PATH");
866
- return { created, skipped, errors };
1485
+ function summarizeSymlinkResults(results) {
1486
+ if (results.length === 0) return "no employees in roster";
1487
+ const created = results.filter((r) => r.action === "created").length;
1488
+ const already = results.filter((r) => r.action === "already_correct").length;
1489
+ const conflicts = results.filter((r) => r.action === "conflict");
1490
+ let summary = `${created} created, ${already} already linked`;
1491
+ if (conflicts.length > 0) {
1492
+ const details = conflicts.map((r) => `${r.agentId} (${r.conflict ?? "unknown"})`).join(", ");
1493
+ summary += `, ${conflicts.length} conflict(s): ${details}`;
867
1494
  }
868
- const binDir = path2.dirname(exeBinPath);
869
- let target;
1495
+ return summary;
1496
+ }
1497
+ var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
1498
+ var init_installer = __esm({
1499
+ "src/adapters/claude/installer.ts"() {
1500
+ "use strict";
1501
+ init_agent_symlinks();
1502
+ init_mcp_prefix();
1503
+ EXE_SECTION_START = "<!-- exe-os:orchestration-start -->";
1504
+ EXE_SECTION_END = "<!-- exe-os:orchestration-end -->";
1505
+ ORCHESTRATION_RULES = `${EXE_SECTION_START}
1506
+ ## exe-os Multi-Agent Orchestration (auto-managed \u2014 do not edit)
1507
+
1508
+ These rules are injected by exe-os and override default behavior for multi-agent coordination.
1509
+
1510
+ - **Session routing is deterministic.** When working in exeN (e.g. exe1), ALL employee sessions use the same number: yoshi-exe1, tom-exe1, mari-exe1. NEVER reference, consider, or dispatch to employee sessions from other project numbers. This is not a choice \u2014 it is a hard constraint.
1511
+ - **Always use create_task to assign work.** Never use messages, tmux send-keys, or ad-hoc instructions as a substitute for tasks.
1512
+ - **Never modify another agent's in-progress task.** Create a new task instead. Modifying active tasks causes race conditions.
1513
+ - **Chain of command:** founder \u2192 exe \u2192 yoshi \u2192 engineers. Exe does not assign directly to tom or other engineers below yoshi.
1514
+ - **Verify dispatch.** After every create_task, confirm the employee received and started the task via tmux capture-pane.
1515
+ ${EXE_SECTION_END}`;
1516
+ }
1517
+ });
1518
+
1519
+ // src/bin/exe-new-employee.ts
1520
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
1521
+ import path9 from "path";
1522
+
1523
+ // src/lib/session-wrappers.ts
1524
+ import {
1525
+ existsSync,
1526
+ readFileSync,
1527
+ writeFileSync,
1528
+ mkdirSync,
1529
+ chmodSync,
1530
+ readdirSync,
1531
+ unlinkSync
1532
+ } from "fs";
1533
+ import path from "path";
1534
+ import { homedir } from "os";
1535
+ var MAX_N = 9;
1536
+ function generateSessionWrappers(packageRoot, homeDir) {
1537
+ const home = homeDir ?? homedir();
1538
+ const binDir = path.join(home, ".exe-os", "bin");
1539
+ const rosterPath = path.join(home, ".exe-os", "exe-employees.json");
1540
+ mkdirSync(binDir, { recursive: true });
1541
+ const exeStartDst = path.join(binDir, "exe-start");
1542
+ const candidates = [
1543
+ path.join(packageRoot, "dist", "bin", "exe-start.sh"),
1544
+ path.join(packageRoot, "src", "bin", "exe-start.sh")
1545
+ ];
1546
+ for (const src of candidates) {
1547
+ if (existsSync(src)) {
1548
+ writeFileSync(exeStartDst, readFileSync(src));
1549
+ chmodSync(exeStartDst, 493);
1550
+ break;
1551
+ }
1552
+ }
1553
+ let employees = [];
870
1554
  try {
871
- target = readlinkSync(exeBinPath);
1555
+ employees = JSON.parse(readFileSync(rosterPath, "utf8"));
872
1556
  } catch {
873
- errors.push("Could not read 'exe' symlink");
874
- return { created, skipped, errors };
1557
+ return { created: 0, pathConfigured: false };
875
1558
  }
876
- for (const suffix of ["", "-opencode"]) {
877
- const linkName = `${name}${suffix}`;
878
- const linkPath = path2.join(binDir, linkName);
879
- if (existsSync2(linkPath)) {
880
- skipped.push(linkName);
881
- continue;
1559
+ if (employees.length === 0) {
1560
+ return { created: 0, pathConfigured: false };
1561
+ }
1562
+ try {
1563
+ for (const f of readdirSync(binDir)) {
1564
+ if (f === "exe-start") continue;
1565
+ const fPath = path.join(binDir, f);
1566
+ try {
1567
+ const content = readFileSync(fPath, "utf8");
1568
+ if (content.includes("exe-start")) {
1569
+ unlinkSync(fPath);
1570
+ }
1571
+ } catch {
1572
+ }
1573
+ }
1574
+ } catch {
1575
+ }
1576
+ let created = 0;
1577
+ const wrapperContent = `#!/bin/bash
1578
+ exec "${exeStartDst}" "$0" "$@"
1579
+ `;
1580
+ for (const emp of employees) {
1581
+ for (let n = 1; n <= MAX_N; n++) {
1582
+ const wrapperPath = path.join(binDir, `${emp.name}${n}`);
1583
+ writeFileSync(wrapperPath, wrapperContent);
1584
+ chmodSync(wrapperPath, 493);
1585
+ created++;
882
1586
  }
1587
+ }
1588
+ const pathConfigured = ensurePath(home, binDir);
1589
+ return { created, pathConfigured };
1590
+ }
1591
+ function ensurePath(home, binDir) {
1592
+ if (process.env.PATH?.split(":").includes(binDir)) {
1593
+ return false;
1594
+ }
1595
+ const exportLine = `
1596
+ # exe-os session commands
1597
+ export PATH="${binDir}:$PATH"
1598
+ `;
1599
+ const shell = process.env.SHELL ?? "/bin/bash";
1600
+ const profilePaths = [];
1601
+ if (shell.includes("zsh")) {
1602
+ profilePaths.push(path.join(home, ".zshrc"));
1603
+ } else if (shell.includes("bash")) {
1604
+ profilePaths.push(path.join(home, ".bashrc"));
1605
+ profilePaths.push(path.join(home, ".bash_profile"));
1606
+ } else {
1607
+ profilePaths.push(path.join(home, ".profile"));
1608
+ }
1609
+ for (const profilePath of profilePaths) {
883
1610
  try {
884
- symlinkSync(target, linkPath);
885
- created.push(linkName);
886
- } catch (err) {
887
- errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
1611
+ let content = "";
1612
+ try {
1613
+ content = readFileSync(profilePath, "utf8");
1614
+ } catch {
1615
+ }
1616
+ if (content.includes(".exe-os/bin")) {
1617
+ return false;
1618
+ }
1619
+ writeFileSync(profilePath, content + exportLine);
1620
+ return true;
1621
+ } catch {
1622
+ continue;
888
1623
  }
889
1624
  }
890
- return { created, skipped, errors };
1625
+ return false;
891
1626
  }
892
1627
 
1628
+ // src/bin/exe-new-employee.ts
1629
+ init_employees();
1630
+
893
1631
  // src/lib/global-procedures.ts
894
1632
  init_database();
895
1633
  import { randomUUID } from "crypto";
@@ -1342,18 +2080,19 @@ function isMainModule(importMetaUrl) {
1342
2080
 
1343
2081
  // src/lib/plan-limits.ts
1344
2082
  init_database();
1345
- import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
1346
- import path4 from "path";
2083
+ init_employees();
2084
+ import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2085
+ import path5 from "path";
1347
2086
 
1348
2087
  // src/lib/license.ts
1349
2088
  init_config();
1350
- import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
2089
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
1351
2090
  import { randomUUID as randomUUID2 } from "crypto";
1352
- import path3 from "path";
2091
+ import path4 from "path";
1353
2092
  import { jwtVerify, importSPKI } from "jose";
1354
- var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
1355
- var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
1356
- var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
2093
+ var LICENSE_PATH = path4.join(EXE_AI_DIR, "license.key");
2094
+ var CACHE_PATH = path4.join(EXE_AI_DIR, "license-cache.json");
2095
+ var DEVICE_ID_PATH = path4.join(EXE_AI_DIR, "device-id");
1357
2096
  var API_BASE = "https://askexe.com/cloud";
1358
2097
  var RETRY_DELAY_MS = 500;
1359
2098
  async function fetchRetry(url, init) {
@@ -1386,37 +2125,37 @@ var FREE_LICENSE = {
1386
2125
  memoryLimit: 5e4
1387
2126
  };
1388
2127
  function loadDeviceId() {
1389
- const deviceJsonPath = path3.join(EXE_AI_DIR, "device.json");
2128
+ const deviceJsonPath = path4.join(EXE_AI_DIR, "device.json");
1390
2129
  try {
1391
- if (existsSync3(deviceJsonPath)) {
1392
- const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
2130
+ if (existsSync4(deviceJsonPath)) {
2131
+ const data = JSON.parse(readFileSync4(deviceJsonPath, "utf8"));
1393
2132
  if (data.deviceId) return data.deviceId;
1394
2133
  }
1395
2134
  } catch {
1396
2135
  }
1397
2136
  try {
1398
- if (existsSync3(DEVICE_ID_PATH)) {
1399
- const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
2137
+ if (existsSync4(DEVICE_ID_PATH)) {
2138
+ const id2 = readFileSync4(DEVICE_ID_PATH, "utf8").trim();
1400
2139
  if (id2) return id2;
1401
2140
  }
1402
2141
  } catch {
1403
2142
  }
1404
2143
  const id = randomUUID2();
1405
- mkdirSync(EXE_AI_DIR, { recursive: true });
1406
- writeFileSync(DEVICE_ID_PATH, id, "utf8");
2144
+ mkdirSync2(EXE_AI_DIR, { recursive: true });
2145
+ writeFileSync2(DEVICE_ID_PATH, id, "utf8");
1407
2146
  return id;
1408
2147
  }
1409
2148
  function loadLicense() {
1410
2149
  try {
1411
- if (!existsSync3(LICENSE_PATH)) return null;
1412
- return readFileSync3(LICENSE_PATH, "utf8").trim();
2150
+ if (!existsSync4(LICENSE_PATH)) return null;
2151
+ return readFileSync4(LICENSE_PATH, "utf8").trim();
1413
2152
  } catch {
1414
2153
  return null;
1415
2154
  }
1416
2155
  }
1417
2156
  function saveLicense(apiKey) {
1418
- mkdirSync(EXE_AI_DIR, { recursive: true });
1419
- writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2157
+ mkdirSync2(EXE_AI_DIR, { recursive: true });
2158
+ writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
1420
2159
  }
1421
2160
  async function verifyLicenseJwt(token) {
1422
2161
  try {
@@ -1442,8 +2181,8 @@ async function verifyLicenseJwt(token) {
1442
2181
  }
1443
2182
  async function getCachedLicense() {
1444
2183
  try {
1445
- if (!existsSync3(CACHE_PATH)) return null;
1446
- const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
2184
+ if (!existsSync4(CACHE_PATH)) return null;
2185
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
1447
2186
  if (!raw.token || typeof raw.token !== "string") return null;
1448
2187
  return await verifyLicenseJwt(raw.token);
1449
2188
  } catch {
@@ -1452,8 +2191,8 @@ async function getCachedLicense() {
1452
2191
  }
1453
2192
  function readCachedToken() {
1454
2193
  try {
1455
- if (!existsSync3(CACHE_PATH)) return null;
1456
- const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
2194
+ if (!existsSync4(CACHE_PATH)) return null;
2195
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
1457
2196
  return typeof raw.token === "string" ? raw.token : null;
1458
2197
  } catch {
1459
2198
  return null;
@@ -1487,7 +2226,7 @@ function getRawCachedPlan() {
1487
2226
  }
1488
2227
  function cacheResponse(token) {
1489
2228
  try {
1490
- writeFileSync(CACHE_PATH, JSON.stringify({ token }), "utf8");
2229
+ writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
1491
2230
  } catch {
1492
2231
  }
1493
2232
  }
@@ -1552,9 +2291,9 @@ async function checkLicense() {
1552
2291
  let key = loadLicense();
1553
2292
  if (!key) {
1554
2293
  try {
1555
- const configPath = path3.join(EXE_AI_DIR, "config.json");
1556
- if (existsSync3(configPath)) {
1557
- const raw = JSON.parse(readFileSync3(configPath, "utf8"));
2294
+ const configPath = path4.join(EXE_AI_DIR, "config.json");
2295
+ if (existsSync4(configPath)) {
2296
+ const raw = JSON.parse(readFileSync4(configPath, "utf8"));
1558
2297
  const cloud = raw.cloud;
1559
2298
  if (cloud?.apiKey) {
1560
2299
  key = cloud.apiKey;
@@ -1579,7 +2318,7 @@ var PlanLimitError = class extends Error {
1579
2318
  this.name = "PlanLimitError";
1580
2319
  }
1581
2320
  };
1582
- var CACHE_PATH2 = path4.join(EXE_AI_DIR, "license-cache.json");
2321
+ var CACHE_PATH2 = path5.join(EXE_AI_DIR, "license-cache.json");
1583
2322
  async function assertEmployeeLimit(license, rosterPath) {
1584
2323
  const lic = license ?? await checkLicense();
1585
2324
  if (lic.employeeLimit < 0) return;
@@ -1675,7 +2414,7 @@ async function main() {
1675
2414
  const identityTemplate = templateKey ? getIdentityTemplate(templateKey) : null;
1676
2415
  if (identityTemplate) {
1677
2416
  const idPath = identityPath2(name);
1678
- const dir = path6.dirname(idPath);
2417
+ const dir = path9.dirname(idPath);
1679
2418
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
1680
2419
  const content = identityTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`);
1681
2420
  fs.writeFileSync(idPath, content, "utf-8");
@@ -1683,9 +2422,9 @@ async function main() {
1683
2422
  }
1684
2423
  } catch {
1685
2424
  }
1686
- const taskDir = path6.join(process.cwd(), "exe", name);
1687
- if (!existsSync6(taskDir)) {
1688
- mkdirSync3(taskDir, { recursive: true });
2425
+ const taskDir = path9.join(process.cwd(), "exe", name);
2426
+ if (!existsSync9(taskDir)) {
2427
+ mkdirSync6(taskDir, { recursive: true });
1689
2428
  }
1690
2429
  const bins = registerBinSymlinks(newEmployee.name);
1691
2430
  if (bins.created.length > 0) {
@@ -1694,6 +2433,15 @@ async function main() {
1694
2433
  if (bins.errors.length > 0) {
1695
2434
  console.error(`Warning: some launchers failed: ${bins.errors.join("; ")}`);
1696
2435
  }
2436
+ try {
2437
+ const { resolvePackageRoot: resolvePackageRoot2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
2438
+ const pkgRoot = resolvePackageRoot2();
2439
+ const wrapResult = generateSessionWrappers(pkgRoot);
2440
+ if (wrapResult.created > 0) {
2441
+ console.log(`Session wrappers: ${wrapResult.created} generated (${newEmployee.name}1-9 added)`);
2442
+ }
2443
+ } catch {
2444
+ }
1697
2445
  console.log(`Created employee: ${newEmployee.name} (${newEmployee.role})`);
1698
2446
  }
1699
2447
  if (isMainModule(import.meta.url)) {