@askexenow/exe-os 0.9.7 → 0.9.9
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/backfill-conversations.js +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
package/dist/lib/employees.js
CHANGED
|
@@ -1,13 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/lib/secure-files.ts
|
|
12
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
13
|
+
import { chmod, mkdir } from "fs/promises";
|
|
14
|
+
function ensurePrivateDirSync(dirPath) {
|
|
15
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
16
|
+
try {
|
|
17
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function enforcePrivateFileSync(filePath) {
|
|
22
|
+
try {
|
|
23
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
28
|
+
var init_secure_files = __esm({
|
|
29
|
+
"src/lib/secure-files.ts"() {
|
|
30
|
+
"use strict";
|
|
31
|
+
PRIVATE_DIR_MODE = 448;
|
|
32
|
+
PRIVATE_FILE_MODE = 384;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
7
35
|
|
|
8
36
|
// src/lib/config.ts
|
|
9
|
-
import { readFile, writeFile
|
|
10
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
37
|
+
import { readFile, writeFile } from "fs/promises";
|
|
38
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
11
39
|
import path from "path";
|
|
12
40
|
import os from "os";
|
|
13
41
|
function resolveDataDir() {
|
|
@@ -15,7 +43,7 @@ function resolveDataDir() {
|
|
|
15
43
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
16
44
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
17
45
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
18
|
-
if (!
|
|
46
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
19
47
|
try {
|
|
20
48
|
renameSync(legacyDir, newDir);
|
|
21
49
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -26,72 +54,199 @@ function resolveDataDir() {
|
|
|
26
54
|
}
|
|
27
55
|
return newDir;
|
|
28
56
|
}
|
|
29
|
-
var EXE_AI_DIR
|
|
30
|
-
var
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
57
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
|
|
58
|
+
var init_config = __esm({
|
|
59
|
+
"src/lib/config.ts"() {
|
|
60
|
+
"use strict";
|
|
61
|
+
init_secure_files();
|
|
62
|
+
EXE_AI_DIR = resolveDataDir();
|
|
63
|
+
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
64
|
+
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
65
|
+
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
66
|
+
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
67
|
+
CURRENT_CONFIG_VERSION = 1;
|
|
68
|
+
DEFAULT_CONFIG = {
|
|
69
|
+
config_version: CURRENT_CONFIG_VERSION,
|
|
70
|
+
dbPath: DB_PATH,
|
|
71
|
+
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
72
|
+
embeddingDim: 1024,
|
|
73
|
+
batchSize: 20,
|
|
74
|
+
flushIntervalMs: 1e4,
|
|
75
|
+
autoIngestion: true,
|
|
76
|
+
autoRetrieval: true,
|
|
77
|
+
searchMode: "hybrid",
|
|
78
|
+
hookSearchMode: "hybrid",
|
|
79
|
+
fileGrepEnabled: true,
|
|
80
|
+
splashEffect: true,
|
|
81
|
+
consolidationEnabled: true,
|
|
82
|
+
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
83
|
+
consolidationModel: "claude-haiku-4-5-20251001",
|
|
84
|
+
consolidationMaxCallsPerRun: 20,
|
|
85
|
+
selfQueryRouter: true,
|
|
86
|
+
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
87
|
+
rerankerEnabled: true,
|
|
88
|
+
scalingRoadmap: {
|
|
89
|
+
rerankerAutoTrigger: {
|
|
90
|
+
enabled: true,
|
|
91
|
+
broadQueryMinCardinality: 5e4,
|
|
92
|
+
fetchTopK: 150,
|
|
93
|
+
returnTopK: 5
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
graphRagEnabled: true,
|
|
97
|
+
wikiEnabled: false,
|
|
98
|
+
wikiUrl: "",
|
|
99
|
+
wikiApiKey: "",
|
|
100
|
+
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
101
|
+
wikiWorkspaceMapping: {},
|
|
102
|
+
wikiAutoUpdate: true,
|
|
103
|
+
wikiAutoUpdateThreshold: 0.5,
|
|
104
|
+
wikiAutoUpdateCreateNew: true,
|
|
105
|
+
skillLearning: true,
|
|
106
|
+
skillThreshold: 3,
|
|
107
|
+
skillModel: "claude-haiku-4-5-20251001",
|
|
108
|
+
exeHeartbeat: {
|
|
109
|
+
enabled: true,
|
|
110
|
+
intervalSeconds: 60,
|
|
111
|
+
staleInProgressThresholdHours: 2
|
|
112
|
+
},
|
|
113
|
+
sessionLifecycle: {
|
|
114
|
+
idleKillEnabled: true,
|
|
115
|
+
idleKillTicksRequired: 3,
|
|
116
|
+
idleKillIntercomAckWindowMs: 1e4,
|
|
117
|
+
maxAutoInstances: 10
|
|
118
|
+
},
|
|
119
|
+
autoUpdate: {
|
|
120
|
+
checkOnBoot: true,
|
|
121
|
+
autoInstall: false,
|
|
122
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
123
|
+
}
|
|
124
|
+
};
|
|
90
125
|
}
|
|
91
|
-
};
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// src/lib/runtime-table.ts
|
|
129
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
130
|
+
var init_runtime_table = __esm({
|
|
131
|
+
"src/lib/runtime-table.ts"() {
|
|
132
|
+
"use strict";
|
|
133
|
+
RUNTIME_TABLE = {
|
|
134
|
+
codex: {
|
|
135
|
+
binary: "codex",
|
|
136
|
+
launchMode: "interactive",
|
|
137
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
138
|
+
inlineFlag: "--no-alt-screen",
|
|
139
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
140
|
+
defaultModel: "gpt-5.4"
|
|
141
|
+
},
|
|
142
|
+
opencode: {
|
|
143
|
+
binary: "opencode",
|
|
144
|
+
launchMode: "exec",
|
|
145
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
146
|
+
inlineFlag: "",
|
|
147
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
148
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
DEFAULT_RUNTIME = "claude";
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// src/lib/agent-config.ts
|
|
156
|
+
var agent_config_exports = {};
|
|
157
|
+
__export(agent_config_exports, {
|
|
158
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
159
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
160
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
161
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
162
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
163
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
164
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
165
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
166
|
+
setAgentRuntime: () => setAgentRuntime
|
|
167
|
+
});
|
|
168
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
169
|
+
import path2 from "path";
|
|
170
|
+
function loadAgentConfig() {
|
|
171
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
172
|
+
try {
|
|
173
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
174
|
+
} catch {
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function saveAgentConfig(config) {
|
|
179
|
+
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
180
|
+
ensurePrivateDirSync(dir);
|
|
181
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
182
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
183
|
+
}
|
|
184
|
+
function getAgentRuntime(agentId) {
|
|
185
|
+
const config = loadAgentConfig();
|
|
186
|
+
const entry = config[agentId];
|
|
187
|
+
if (entry) return entry;
|
|
188
|
+
const orgDefault = config["default"];
|
|
189
|
+
if (orgDefault) return orgDefault;
|
|
190
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
191
|
+
}
|
|
192
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
193
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
194
|
+
if (!knownModels) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (!knownModels.includes(model)) {
|
|
201
|
+
return {
|
|
202
|
+
ok: false,
|
|
203
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const config = loadAgentConfig();
|
|
207
|
+
config[agentId] = { runtime, model };
|
|
208
|
+
saveAgentConfig(config);
|
|
209
|
+
return { ok: true };
|
|
210
|
+
}
|
|
211
|
+
function clearAgentRuntime(agentId) {
|
|
212
|
+
const config = loadAgentConfig();
|
|
213
|
+
delete config[agentId];
|
|
214
|
+
saveAgentConfig(config);
|
|
215
|
+
}
|
|
216
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
217
|
+
var init_agent_config = __esm({
|
|
218
|
+
"src/lib/agent-config.ts"() {
|
|
219
|
+
"use strict";
|
|
220
|
+
init_config();
|
|
221
|
+
init_runtime_table();
|
|
222
|
+
init_secure_files();
|
|
223
|
+
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
224
|
+
KNOWN_RUNTIMES = {
|
|
225
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
226
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
227
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
228
|
+
};
|
|
229
|
+
RUNTIME_LABELS = {
|
|
230
|
+
claude: "Claude Code (Anthropic)",
|
|
231
|
+
codex: "Codex (OpenAI)",
|
|
232
|
+
opencode: "OpenCode (open source)"
|
|
233
|
+
};
|
|
234
|
+
DEFAULT_MODELS = {
|
|
235
|
+
claude: "claude-opus-4",
|
|
236
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
237
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
});
|
|
92
241
|
|
|
93
242
|
// src/lib/employees.ts
|
|
94
|
-
|
|
243
|
+
init_config();
|
|
244
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
245
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
246
|
+
import { execSync } from "child_process";
|
|
247
|
+
import path3 from "path";
|
|
248
|
+
import os2 from "os";
|
|
249
|
+
var EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
95
250
|
var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
96
251
|
var COORDINATOR_ROLE = "COO";
|
|
97
252
|
function normalizeRole(role) {
|
|
@@ -129,7 +284,7 @@ function validateEmployeeName(name) {
|
|
|
129
284
|
return { valid: true };
|
|
130
285
|
}
|
|
131
286
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
132
|
-
if (!
|
|
287
|
+
if (!existsSync4(employeesPath)) {
|
|
133
288
|
return [];
|
|
134
289
|
}
|
|
135
290
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -140,13 +295,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
140
295
|
}
|
|
141
296
|
}
|
|
142
297
|
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
143
|
-
await mkdir2(
|
|
298
|
+
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
144
299
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
145
300
|
}
|
|
146
301
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
147
|
-
if (!
|
|
302
|
+
if (!existsSync4(employeesPath)) return [];
|
|
148
303
|
try {
|
|
149
|
-
return JSON.parse(
|
|
304
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
150
305
|
} catch {
|
|
151
306
|
return [];
|
|
152
307
|
}
|
|
@@ -189,6 +344,54 @@ function addEmployee(employees, employee) {
|
|
|
189
344
|
}
|
|
190
345
|
return [...employees, normalized];
|
|
191
346
|
}
|
|
347
|
+
var IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
348
|
+
var TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
349
|
+
function appendToCoordinatorTeam(employee) {
|
|
350
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
351
|
+
if (!coordinator) return;
|
|
352
|
+
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
353
|
+
if (!existsSync4(idPath)) return;
|
|
354
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
355
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
356
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
357
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
358
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
359
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
360
|
+
const entry = `
|
|
361
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
362
|
+
`;
|
|
363
|
+
let updated;
|
|
364
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
365
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
366
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
367
|
+
} else {
|
|
368
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
369
|
+
}
|
|
370
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
371
|
+
}
|
|
372
|
+
function capitalize(s) {
|
|
373
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
374
|
+
}
|
|
375
|
+
async function hireEmployee(employee) {
|
|
376
|
+
const employees = await loadEmployees();
|
|
377
|
+
const updated = addEmployee(employees, employee);
|
|
378
|
+
await saveEmployees(updated);
|
|
379
|
+
try {
|
|
380
|
+
appendToCoordinatorTeam(employee);
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
385
|
+
const config = loadAgentConfig2();
|
|
386
|
+
const name = employee.name.toLowerCase();
|
|
387
|
+
if (!config[name] && config["default"]) {
|
|
388
|
+
config[name] = { ...config["default"] };
|
|
389
|
+
saveAgentConfig2(config);
|
|
390
|
+
}
|
|
391
|
+
} catch {
|
|
392
|
+
}
|
|
393
|
+
return updated;
|
|
394
|
+
}
|
|
192
395
|
async function normalizeRosterCase(rosterPath) {
|
|
193
396
|
const employees = await loadEmployees(rosterPath);
|
|
194
397
|
let changed = false;
|
|
@@ -198,14 +401,14 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
198
401
|
emp.name = emp.name.toLowerCase();
|
|
199
402
|
changed = true;
|
|
200
403
|
try {
|
|
201
|
-
const identityDir =
|
|
202
|
-
const oldPath =
|
|
203
|
-
const newPath =
|
|
204
|
-
if (
|
|
404
|
+
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
405
|
+
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
406
|
+
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
407
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
205
408
|
renameSync2(oldPath, newPath);
|
|
206
|
-
} else if (
|
|
207
|
-
const content =
|
|
208
|
-
|
|
409
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
410
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
411
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
209
412
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
210
413
|
unlinkSync(oldPath);
|
|
211
414
|
}
|
|
@@ -235,7 +438,7 @@ function registerBinSymlinks(name) {
|
|
|
235
438
|
errors.push("Could not find 'exe-os' in PATH");
|
|
236
439
|
return { created, skipped, errors };
|
|
237
440
|
}
|
|
238
|
-
const binDir =
|
|
441
|
+
const binDir = path3.dirname(exeBinPath);
|
|
239
442
|
let target;
|
|
240
443
|
try {
|
|
241
444
|
target = readlinkSync(exeBinPath);
|
|
@@ -245,8 +448,8 @@ function registerBinSymlinks(name) {
|
|
|
245
448
|
}
|
|
246
449
|
for (const suffix of ["", "-opencode"]) {
|
|
247
450
|
const linkName = `${name}${suffix}`;
|
|
248
|
-
const linkPath =
|
|
249
|
-
if (
|
|
451
|
+
const linkPath = path3.join(binDir, linkName);
|
|
452
|
+
if (existsSync4(linkPath)) {
|
|
250
453
|
skipped.push(linkName);
|
|
251
454
|
continue;
|
|
252
455
|
}
|
|
@@ -272,6 +475,7 @@ export {
|
|
|
272
475
|
getEmployeeByRole,
|
|
273
476
|
getEmployeeNamesByRole,
|
|
274
477
|
hasRole,
|
|
478
|
+
hireEmployee,
|
|
275
479
|
isCoordinatorName,
|
|
276
480
|
isCoordinatorRole,
|
|
277
481
|
isMultiInstance,
|