@askexenow/exe-os 0.9.113 → 0.9.115
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/agentic-ontology-backfill.js +36 -12
- package/dist/bin/agentic-reflection-backfill.js +36 -12
- package/dist/bin/agentic-semantic-label.js +36 -12
- package/dist/bin/backfill-conversations.js +36 -12
- package/dist/bin/backfill-responses.js +36 -12
- package/dist/bin/backfill-vectors.js +36 -12
- package/dist/bin/bulk-sync-postgres.js +36 -12
- package/dist/bin/cleanup-stale-review-tasks.js +470 -113
- package/dist/bin/cli.js +413 -62
- package/dist/bin/exe-agent.js +27 -0
- package/dist/bin/exe-assign.js +36 -12
- package/dist/bin/exe-boot.js +246 -54
- package/dist/bin/exe-call.js +8 -0
- package/dist/bin/exe-cloud.js +47 -12
- package/dist/bin/exe-dispatch.js +348 -53
- package/dist/bin/exe-doctor.js +51 -13
- package/dist/bin/exe-export-behaviors.js +37 -12
- package/dist/bin/exe-forget.js +36 -12
- package/dist/bin/exe-gateway.js +348 -53
- package/dist/bin/exe-heartbeat.js +471 -113
- package/dist/bin/exe-kill.js +36 -12
- package/dist/bin/exe-launch-agent.js +117 -18
- package/dist/bin/exe-new-employee.js +9 -1
- package/dist/bin/exe-pending-messages.js +452 -95
- package/dist/bin/exe-pending-notifications.js +452 -95
- package/dist/bin/exe-pending-reviews.js +452 -95
- package/dist/bin/exe-rename.js +36 -12
- package/dist/bin/exe-review.js +36 -12
- package/dist/bin/exe-search.js +37 -12
- package/dist/bin/exe-session-cleanup.js +348 -53
- package/dist/bin/exe-settings.js +12 -0
- package/dist/bin/exe-start-codex.js +46 -13
- package/dist/bin/exe-start-opencode.js +46 -13
- package/dist/bin/exe-status.js +460 -114
- package/dist/bin/exe-support.js +12 -0
- package/dist/bin/exe-team.js +36 -12
- package/dist/bin/git-sweep.js +348 -53
- package/dist/bin/graph-backfill.js +36 -12
- package/dist/bin/graph-export.js +36 -12
- package/dist/bin/install.js +9 -1
- package/dist/bin/intercom-check.js +255 -53
- package/dist/bin/scan-tasks.js +348 -53
- package/dist/bin/setup.js +74 -12
- package/dist/bin/shard-migrate.js +36 -12
- package/dist/gateway/index.js +348 -53
- package/dist/hooks/bug-report-worker.js +348 -53
- package/dist/hooks/codex-stop-task-finalizer.js +308 -37
- package/dist/hooks/commit-complete.js +348 -53
- package/dist/hooks/error-recall.js +37 -12
- package/dist/hooks/ingest.js +363 -54
- package/dist/hooks/instructions-loaded.js +36 -12
- package/dist/hooks/notification.js +36 -12
- package/dist/hooks/post-compact.js +426 -72
- package/dist/hooks/post-tool-combined.js +501 -146
- package/dist/hooks/pre-compact.js +348 -53
- package/dist/hooks/pre-tool-use.js +92 -13
- package/dist/hooks/prompt-submit.js +348 -53
- package/dist/hooks/session-end.js +158 -53
- package/dist/hooks/session-start.js +66 -13
- package/dist/hooks/stop.js +420 -72
- package/dist/hooks/subagent-stop.js +419 -72
- package/dist/hooks/summary-worker.js +442 -121
- package/dist/index.js +375 -53
- package/dist/lib/agent-config.js +8 -0
- package/dist/lib/cloud-sync.js +35 -12
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +9 -1
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employees.js +8 -0
- package/dist/lib/exe-daemon.js +524 -60
- package/dist/lib/hybrid-search.js +37 -12
- package/dist/lib/keychain.js +25 -13
- package/dist/lib/messaging.js +395 -74
- package/dist/lib/schedules.js +36 -12
- package/dist/lib/skill-learning.js +21 -0
- package/dist/lib/store.js +36 -12
- package/dist/lib/tasks.js +324 -41
- package/dist/lib/tmux-routing.js +324 -41
- package/dist/mcp/server.js +374 -54
- package/dist/mcp/tools/create-task.js +324 -41
- package/dist/mcp/tools/list-tasks.js +406 -57
- package/dist/mcp/tools/send-message.js +395 -74
- package/dist/mcp/tools/update-task.js +324 -41
- package/dist/runtime/index.js +375 -53
- package/dist/tui/App.js +377 -55
- package/package.json +1 -1
package/dist/bin/exe-agent.js
CHANGED
|
@@ -1861,6 +1861,33 @@ var DANGEROUS_PATTERNS = [
|
|
|
1861
1861
|
regex: /\bkill\s+-9\b/,
|
|
1862
1862
|
severity: "warning",
|
|
1863
1863
|
reason: "Force kill signal"
|
|
1864
|
+
},
|
|
1865
|
+
// MCP bypass — agents must use MCP tools, never access the DB directly.
|
|
1866
|
+
// These patterns catch attempts to work around a disconnected MCP server.
|
|
1867
|
+
{
|
|
1868
|
+
regex: /\bsqlite3\b.*\bmemories\.db\b/,
|
|
1869
|
+
severity: "critical",
|
|
1870
|
+
reason: "Direct SQLite access bypasses MCP contract boundary \u2014 use MCP tools"
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
regex: /\bsqlite3\b.*\.exe-os\b/,
|
|
1874
|
+
severity: "critical",
|
|
1875
|
+
reason: "Direct SQLite access to exe-os database \u2014 use MCP tools"
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
regex: /\bnode\s+-e\b.*\b(better-sqlite3|libsql|sqlite3)\b/,
|
|
1879
|
+
severity: "critical",
|
|
1880
|
+
reason: "Inline Node.js script accessing SQLite directly \u2014 use MCP tools"
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
regex: /\brequire\s*\(\s*['"].*memories\.db['"]\s*\)/,
|
|
1884
|
+
severity: "critical",
|
|
1885
|
+
reason: "Direct require of memories database \u2014 use MCP tools"
|
|
1886
|
+
},
|
|
1887
|
+
{
|
|
1888
|
+
regex: /\bcat\b.*\bmemories\.db\b/,
|
|
1889
|
+
severity: "warning",
|
|
1890
|
+
reason: "Reading raw database file \u2014 encrypted data, use MCP tools instead"
|
|
1864
1891
|
}
|
|
1865
1892
|
];
|
|
1866
1893
|
function checkDangerousPatterns(command) {
|
package/dist/bin/exe-assign.js
CHANGED
|
@@ -129,6 +129,17 @@ function normalizeOrchestration(raw) {
|
|
|
129
129
|
const userOrg = raw.orchestration ?? {};
|
|
130
130
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
131
131
|
}
|
|
132
|
+
function normalizeCloudEndpoint(raw) {
|
|
133
|
+
const cloud = raw.cloud;
|
|
134
|
+
if (!cloud?.endpoint) return;
|
|
135
|
+
const ep = String(cloud.endpoint);
|
|
136
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
137
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
138
|
+
process.stderr.write(
|
|
139
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
132
143
|
async function loadConfig() {
|
|
133
144
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
134
145
|
await ensurePrivateDir(dir);
|
|
@@ -154,6 +165,7 @@ async function loadConfig() {
|
|
|
154
165
|
normalizeSessionLifecycle(migratedCfg);
|
|
155
166
|
normalizeAutoUpdate(migratedCfg);
|
|
156
167
|
normalizeOrchestration(migratedCfg);
|
|
168
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
157
169
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
158
170
|
if (config.dbPath.startsWith("~")) {
|
|
159
171
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4681,7 +4693,7 @@ init_memory();
|
|
|
4681
4693
|
init_database();
|
|
4682
4694
|
|
|
4683
4695
|
// src/lib/keychain.ts
|
|
4684
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4696
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4685
4697
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4686
4698
|
import { execSync as execSync3 } from "child_process";
|
|
4687
4699
|
import path6 from "path";
|
|
@@ -4720,12 +4732,14 @@ function linuxSecretAvailable() {
|
|
|
4720
4732
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4721
4733
|
if (process.platform !== "linux") return false;
|
|
4722
4734
|
try {
|
|
4723
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4724
4735
|
const st = statSync3(keyPath);
|
|
4725
4736
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4737
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4726
4738
|
if (uid === 0) return true;
|
|
4727
4739
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4728
|
-
|
|
4740
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4741
|
+
if (!linuxSecretAvailable()) return true;
|
|
4742
|
+
return false;
|
|
4729
4743
|
} catch {
|
|
4730
4744
|
return false;
|
|
4731
4745
|
}
|
|
@@ -4876,15 +4890,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4876
4890
|
await mkdir3(dir, { recursive: true });
|
|
4877
4891
|
const keyPath = getKeyPath();
|
|
4878
4892
|
const machineKey = deriveMachineKey();
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4893
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4894
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4895
|
+
const tmpPath = keyPath + ".tmp";
|
|
4896
|
+
try {
|
|
4897
|
+
if (existsSync7(keyPath)) {
|
|
4898
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4899
|
+
});
|
|
4900
|
+
}
|
|
4901
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4902
|
+
await chmod2(tmpPath, 384);
|
|
4903
|
+
await rename(tmpPath, keyPath);
|
|
4904
|
+
} catch (err) {
|
|
4905
|
+
try {
|
|
4906
|
+
await unlink(tmpPath);
|
|
4907
|
+
} catch {
|
|
4908
|
+
}
|
|
4909
|
+
throw err;
|
|
4884
4910
|
}
|
|
4885
|
-
|
|
4886
|
-
await chmod2(keyPath, 384);
|
|
4887
|
-
return "plaintext";
|
|
4911
|
+
return result;
|
|
4888
4912
|
}
|
|
4889
4913
|
async function getMasterKey() {
|
|
4890
4914
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4951,7 +4975,7 @@ async function getMasterKey() {
|
|
|
4951
4975
|
b64Value = content;
|
|
4952
4976
|
}
|
|
4953
4977
|
const key = Buffer.from(b64Value, "base64");
|
|
4954
|
-
if (
|
|
4978
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4955
4979
|
return key;
|
|
4956
4980
|
}
|
|
4957
4981
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
package/dist/bin/exe-boot.js
CHANGED
|
@@ -155,6 +155,17 @@ function normalizeOrchestration(raw) {
|
|
|
155
155
|
const userOrg = raw.orchestration ?? {};
|
|
156
156
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
157
157
|
}
|
|
158
|
+
function normalizeCloudEndpoint(raw) {
|
|
159
|
+
const cloud = raw.cloud;
|
|
160
|
+
if (!cloud?.endpoint) return;
|
|
161
|
+
const ep = String(cloud.endpoint);
|
|
162
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
163
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
164
|
+
process.stderr.write(
|
|
165
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
158
169
|
async function loadConfig() {
|
|
159
170
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
160
171
|
await ensurePrivateDir(dir);
|
|
@@ -180,6 +191,7 @@ async function loadConfig() {
|
|
|
180
191
|
normalizeSessionLifecycle(migratedCfg);
|
|
181
192
|
normalizeAutoUpdate(migratedCfg);
|
|
182
193
|
normalizeOrchestration(migratedCfg);
|
|
194
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
183
195
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
184
196
|
if (config.dbPath.startsWith("~")) {
|
|
185
197
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -208,6 +220,7 @@ function loadConfigSync() {
|
|
|
208
220
|
normalizeSessionLifecycle(migratedCfg);
|
|
209
221
|
normalizeAutoUpdate(migratedCfg);
|
|
210
222
|
normalizeOrchestration(migratedCfg);
|
|
223
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
211
224
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
212
225
|
if (config.dbPath.startsWith("~")) {
|
|
213
226
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -368,6 +381,7 @@ __export(agent_config_exports, {
|
|
|
368
381
|
clearAgentRuntime: () => clearAgentRuntime,
|
|
369
382
|
getAgentRuntime: () => getAgentRuntime,
|
|
370
383
|
loadAgentConfig: () => loadAgentConfig,
|
|
384
|
+
normalizeCcModelName: () => normalizeCcModelName,
|
|
371
385
|
saveAgentConfig: () => saveAgentConfig,
|
|
372
386
|
setAgentMcps: () => setAgentMcps,
|
|
373
387
|
setAgentRuntime: () => setAgentRuntime
|
|
@@ -396,6 +410,13 @@ function getAgentRuntime(agentId) {
|
|
|
396
410
|
if (orgDefault) return orgDefault;
|
|
397
411
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
398
412
|
}
|
|
413
|
+
function normalizeCcModelName(model) {
|
|
414
|
+
let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
415
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
416
|
+
ccModel += "[1m]";
|
|
417
|
+
}
|
|
418
|
+
return ccModel;
|
|
419
|
+
}
|
|
399
420
|
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
400
421
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
401
422
|
if (!knownModels) {
|
|
@@ -4060,7 +4081,7 @@ __export(keychain_exports, {
|
|
|
4060
4081
|
importMnemonic: () => importMnemonic,
|
|
4061
4082
|
setMasterKey: () => setMasterKey
|
|
4062
4083
|
});
|
|
4063
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4084
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4064
4085
|
import { existsSync as existsSync8, statSync as statSync3 } from "fs";
|
|
4065
4086
|
import { execSync as execSync3 } from "child_process";
|
|
4066
4087
|
import path7 from "path";
|
|
@@ -4095,12 +4116,14 @@ function linuxSecretAvailable() {
|
|
|
4095
4116
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4096
4117
|
if (process.platform !== "linux") return false;
|
|
4097
4118
|
try {
|
|
4098
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4099
4119
|
const st = statSync3(keyPath);
|
|
4100
4120
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4121
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4101
4122
|
if (uid === 0) return true;
|
|
4102
4123
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4103
|
-
|
|
4124
|
+
if (exeOsDir && path7.resolve(keyPath).startsWith(path7.resolve(exeOsDir) + path7.sep)) return true;
|
|
4125
|
+
if (!linuxSecretAvailable()) return true;
|
|
4126
|
+
return false;
|
|
4104
4127
|
} catch {
|
|
4105
4128
|
return false;
|
|
4106
4129
|
}
|
|
@@ -4250,15 +4273,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4250
4273
|
await mkdir3(dir, { recursive: true });
|
|
4251
4274
|
const keyPath = getKeyPath();
|
|
4252
4275
|
const machineKey = deriveMachineKey();
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4276
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4277
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4278
|
+
const tmpPath = keyPath + ".tmp";
|
|
4279
|
+
try {
|
|
4280
|
+
if (existsSync8(keyPath)) {
|
|
4281
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4282
|
+
});
|
|
4283
|
+
}
|
|
4284
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4285
|
+
await chmod2(tmpPath, 384);
|
|
4286
|
+
await rename(tmpPath, keyPath);
|
|
4287
|
+
} catch (err) {
|
|
4288
|
+
try {
|
|
4289
|
+
await unlink(tmpPath);
|
|
4290
|
+
} catch {
|
|
4291
|
+
}
|
|
4292
|
+
throw err;
|
|
4258
4293
|
}
|
|
4259
|
-
|
|
4260
|
-
await chmod2(keyPath, 384);
|
|
4261
|
-
return "plaintext";
|
|
4294
|
+
return result;
|
|
4262
4295
|
}
|
|
4263
4296
|
async function getMasterKey() {
|
|
4264
4297
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4325,7 +4358,7 @@ async function getMasterKey() {
|
|
|
4325
4358
|
b64Value = content;
|
|
4326
4359
|
}
|
|
4327
4360
|
const key = Buffer.from(b64Value, "base64");
|
|
4328
|
-
if (
|
|
4361
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4329
4362
|
return key;
|
|
4330
4363
|
}
|
|
4331
4364
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -5512,6 +5545,7 @@ var init_provider_table = __esm({
|
|
|
5512
5545
|
// src/lib/intercom-queue.ts
|
|
5513
5546
|
var intercom_queue_exports = {};
|
|
5514
5547
|
__export(intercom_queue_exports, {
|
|
5548
|
+
_resetDrainGuard: () => _resetDrainGuard,
|
|
5515
5549
|
clearQueueForAgent: () => clearQueueForAgent,
|
|
5516
5550
|
drainForSession: () => drainForSession,
|
|
5517
5551
|
drainQueue: () => drainQueue,
|
|
@@ -5557,38 +5591,47 @@ function queueIntercom(targetSession, reason) {
|
|
|
5557
5591
|
writeQueue(queue);
|
|
5558
5592
|
}
|
|
5559
5593
|
function drainQueue(isSessionBusy2, sendKeys) {
|
|
5594
|
+
if (_draining) {
|
|
5595
|
+
logQueue("SKIP_DRAIN \u2014 previous drain still running (possible tmux hang)");
|
|
5596
|
+
return { drained: 0, failed: 0 };
|
|
5597
|
+
}
|
|
5560
5598
|
const queue = readQueue();
|
|
5561
5599
|
if (queue.length === 0) return { drained: 0, failed: 0 };
|
|
5600
|
+
_draining = true;
|
|
5562
5601
|
const remaining = [];
|
|
5563
5602
|
let drained = 0;
|
|
5564
5603
|
let failed = 0;
|
|
5565
|
-
|
|
5566
|
-
const
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5604
|
+
try {
|
|
5605
|
+
for (const item of queue) {
|
|
5606
|
+
const age = Date.now() - new Date(item.queuedAt).getTime();
|
|
5607
|
+
if (age > TTL_MS) {
|
|
5608
|
+
logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
|
|
5609
|
+
failed++;
|
|
5610
|
+
continue;
|
|
5611
|
+
}
|
|
5612
|
+
try {
|
|
5613
|
+
if (!isSessionBusy2(item.targetSession)) {
|
|
5614
|
+
const success = sendKeys(item.targetSession);
|
|
5615
|
+
if (success) {
|
|
5616
|
+
logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
|
|
5617
|
+
drained++;
|
|
5618
|
+
continue;
|
|
5619
|
+
}
|
|
5579
5620
|
}
|
|
5621
|
+
} catch {
|
|
5580
5622
|
}
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5623
|
+
item.attempts++;
|
|
5624
|
+
if (item.attempts >= MAX_RETRIES2) {
|
|
5625
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
|
|
5626
|
+
failed++;
|
|
5627
|
+
continue;
|
|
5628
|
+
}
|
|
5629
|
+
remaining.push(item);
|
|
5588
5630
|
}
|
|
5589
|
-
remaining
|
|
5631
|
+
writeQueue(remaining);
|
|
5632
|
+
} finally {
|
|
5633
|
+
_draining = false;
|
|
5590
5634
|
}
|
|
5591
|
-
writeQueue(remaining);
|
|
5592
5635
|
return { drained, failed };
|
|
5593
5636
|
}
|
|
5594
5637
|
function drainForSession(targetSession, sendKeys) {
|
|
@@ -5613,6 +5656,9 @@ function clearQueueForAgent(agentName) {
|
|
|
5613
5656
|
logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
|
|
5614
5657
|
}
|
|
5615
5658
|
}
|
|
5659
|
+
function _resetDrainGuard() {
|
|
5660
|
+
_draining = false;
|
|
5661
|
+
}
|
|
5616
5662
|
function logQueue(msg) {
|
|
5617
5663
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
|
|
5618
5664
|
`;
|
|
@@ -5624,13 +5670,14 @@ function logQueue(msg) {
|
|
|
5624
5670
|
} catch {
|
|
5625
5671
|
}
|
|
5626
5672
|
}
|
|
5627
|
-
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
5673
|
+
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, _draining, INTERCOM_LOG;
|
|
5628
5674
|
var init_intercom_queue = __esm({
|
|
5629
5675
|
"src/lib/intercom-queue.ts"() {
|
|
5630
5676
|
"use strict";
|
|
5631
5677
|
QUEUE_PATH = path10.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
5632
5678
|
MAX_RETRIES2 = 5;
|
|
5633
5679
|
TTL_MS = 60 * 60 * 1e3;
|
|
5680
|
+
_draining = false;
|
|
5634
5681
|
INTERCOM_LOG = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
5635
5682
|
}
|
|
5636
5683
|
});
|
|
@@ -6245,6 +6292,17 @@ var init_agent_symlinks = __esm({
|
|
|
6245
6292
|
});
|
|
6246
6293
|
|
|
6247
6294
|
// src/lib/notifications.ts
|
|
6295
|
+
var notifications_exports = {};
|
|
6296
|
+
__export(notifications_exports, {
|
|
6297
|
+
cleanupOldNotifications: () => cleanupOldNotifications,
|
|
6298
|
+
formatNotifications: () => formatNotifications,
|
|
6299
|
+
markAsRead: () => markAsRead,
|
|
6300
|
+
markAsReadByTaskFile: () => markAsReadByTaskFile,
|
|
6301
|
+
markDoneTaskNotificationsAsRead: () => markDoneTaskNotificationsAsRead,
|
|
6302
|
+
migrateJsonNotifications: () => migrateJsonNotifications,
|
|
6303
|
+
readUnreadNotifications: () => readUnreadNotifications,
|
|
6304
|
+
writeNotification: () => writeNotification
|
|
6305
|
+
});
|
|
6248
6306
|
import crypto2 from "crypto";
|
|
6249
6307
|
import path14 from "path";
|
|
6250
6308
|
import os10 from "os";
|
|
@@ -6374,6 +6432,29 @@ async function markDoneTaskNotificationsAsRead(sessionScope) {
|
|
|
6374
6432
|
return 0;
|
|
6375
6433
|
}
|
|
6376
6434
|
}
|
|
6435
|
+
function formatNotifications(notifications) {
|
|
6436
|
+
if (notifications.length === 0) return "";
|
|
6437
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
6438
|
+
for (const n of notifications) {
|
|
6439
|
+
const key = `${n.agentId}|${n.agentRole}`;
|
|
6440
|
+
if (!grouped.has(key)) grouped.set(key, []);
|
|
6441
|
+
grouped.get(key).push(n);
|
|
6442
|
+
}
|
|
6443
|
+
const lines = [];
|
|
6444
|
+
lines.push(`## Notifications (${notifications.length} unread)
|
|
6445
|
+
`);
|
|
6446
|
+
for (const [key, items] of grouped) {
|
|
6447
|
+
const [agentId, agentRole] = key.split("|");
|
|
6448
|
+
lines.push(`**${agentId}** (${agentRole}):`);
|
|
6449
|
+
for (const item of items) {
|
|
6450
|
+
const ago = formatTimeAgo(item.timestamp);
|
|
6451
|
+
const icon = eventIcon(item.event);
|
|
6452
|
+
lines.push(`- ${icon} ${item.summary} (${item.project}) \u2014 ${ago}`);
|
|
6453
|
+
}
|
|
6454
|
+
lines.push("");
|
|
6455
|
+
}
|
|
6456
|
+
return lines.join("\n");
|
|
6457
|
+
}
|
|
6377
6458
|
async function migrateJsonNotifications() {
|
|
6378
6459
|
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path14.join(os10.homedir(), ".exe-os");
|
|
6379
6460
|
const notifDir = path14.join(base, "notifications");
|
|
@@ -6419,6 +6500,34 @@ async function migrateJsonNotifications() {
|
|
|
6419
6500
|
}
|
|
6420
6501
|
return migrated;
|
|
6421
6502
|
}
|
|
6503
|
+
function eventIcon(event) {
|
|
6504
|
+
switch (event) {
|
|
6505
|
+
case "task_complete":
|
|
6506
|
+
return "Completed:";
|
|
6507
|
+
case "task_needs_fix":
|
|
6508
|
+
return "Needs fix:";
|
|
6509
|
+
case "session_summary":
|
|
6510
|
+
return "Session:";
|
|
6511
|
+
case "error_spike":
|
|
6512
|
+
return "Errors:";
|
|
6513
|
+
case "orphan_task":
|
|
6514
|
+
return "Orphan:";
|
|
6515
|
+
case "subtasks_complete":
|
|
6516
|
+
return "Subtasks done:";
|
|
6517
|
+
case "capacity_relaunch":
|
|
6518
|
+
return "Relaunched:";
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
function formatTimeAgo(timestamp) {
|
|
6522
|
+
const diffMs = Date.now() - new Date(timestamp).getTime();
|
|
6523
|
+
const mins = Math.floor(diffMs / 6e4);
|
|
6524
|
+
if (mins < 1) return "just now";
|
|
6525
|
+
if (mins < 60) return `${mins}m ago`;
|
|
6526
|
+
const hours = Math.floor(mins / 60);
|
|
6527
|
+
if (hours < 24) return `${hours}h ago`;
|
|
6528
|
+
const days = Math.floor(hours / 24);
|
|
6529
|
+
return `${days}d ago`;
|
|
6530
|
+
}
|
|
6422
6531
|
var CLEANUP_DAYS;
|
|
6423
6532
|
var init_notifications = __esm({
|
|
6424
6533
|
"src/lib/notifications.ts"() {
|
|
@@ -7495,7 +7604,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
7495
7604
|
taskFile
|
|
7496
7605
|
});
|
|
7497
7606
|
const originalPriority = String(row.priority).toLowerCase();
|
|
7498
|
-
const
|
|
7607
|
+
const resultLower = result?.toLowerCase() ?? "";
|
|
7608
|
+
const hasTestEvidence = (
|
|
7609
|
+
// Vitest/Jest output patterns (hard to fake without actually running tests)
|
|
7610
|
+
/\d+\s+pass(ed|ing)/.test(resultLower) || /test files?\s+\d+\s+passed/.test(resultLower) || /tests?\s+\d+\s+passed/.test(resultLower)
|
|
7611
|
+
);
|
|
7612
|
+
const hasNoFailures = !/fail(ed|ure|ing)|error/i.test(resultLower);
|
|
7613
|
+
const autoApprove = originalPriority === "p2" && hasTestEvidence && hasNoFailures;
|
|
7499
7614
|
if (!autoApprove) {
|
|
7500
7615
|
try {
|
|
7501
7616
|
const key = getSessionKey();
|
|
@@ -7503,6 +7618,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
7503
7618
|
if (exeSession) {
|
|
7504
7619
|
sendIntercom(exeSession);
|
|
7505
7620
|
}
|
|
7621
|
+
if (reviewer && reviewer !== coordinatorName && reviewer !== exeSession) {
|
|
7622
|
+
const { employeeSessionName: employeeSessionName2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
7623
|
+
if (exeSession) {
|
|
7624
|
+
const reviewerSession = employeeSessionName2(reviewer, exeSession);
|
|
7625
|
+
sendIntercom(reviewerSession);
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7506
7628
|
} catch {
|
|
7507
7629
|
}
|
|
7508
7630
|
}
|
|
@@ -8278,6 +8400,20 @@ async function updateTask(input) {
|
|
|
8278
8400
|
notifyTaskDone();
|
|
8279
8401
|
}
|
|
8280
8402
|
await markTaskNotificationsRead(taskFile);
|
|
8403
|
+
if (input.status === "needs_review" && !isCoordinator) {
|
|
8404
|
+
try {
|
|
8405
|
+
const { writeNotification: writeNotification2 } = await Promise.resolve().then(() => (init_notifications(), notifications_exports));
|
|
8406
|
+
await writeNotification2({
|
|
8407
|
+
agentId: String(row.assigned_to),
|
|
8408
|
+
agentRole: String(row.assigned_to),
|
|
8409
|
+
event: "task_complete",
|
|
8410
|
+
project: String(row.project_name),
|
|
8411
|
+
summary: `"${String(row.title)}" is ready for review`,
|
|
8412
|
+
taskFile
|
|
8413
|
+
});
|
|
8414
|
+
} catch {
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8281
8417
|
if (input.status === "done" || input.status === "closed") {
|
|
8282
8418
|
try {
|
|
8283
8419
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
@@ -8710,18 +8846,31 @@ function acquireSpawnLock2(sessionName) {
|
|
|
8710
8846
|
mkdirSync9(SPAWN_LOCK_DIR, { recursive: true });
|
|
8711
8847
|
}
|
|
8712
8848
|
const lockFile = spawnLockPath(sessionName);
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8849
|
+
const lockData = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
|
|
8850
|
+
const { openSync: openSync4, closeSync: closeSync4, writeSync } = __require("fs");
|
|
8851
|
+
const { constants: constants2 } = __require("fs");
|
|
8852
|
+
try {
|
|
8853
|
+
const fd = openSync4(lockFile, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL, 420);
|
|
8854
|
+
writeSync(fd, lockData);
|
|
8855
|
+
closeSync4(fd);
|
|
8856
|
+
return true;
|
|
8857
|
+
} catch (err) {
|
|
8858
|
+
if (err?.code !== "EEXIST") {
|
|
8859
|
+
return true;
|
|
8721
8860
|
}
|
|
8722
8861
|
}
|
|
8723
|
-
|
|
8724
|
-
|
|
8862
|
+
try {
|
|
8863
|
+
const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
|
|
8864
|
+
const age = Date.now() - lock.timestamp;
|
|
8865
|
+
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
8866
|
+
return false;
|
|
8867
|
+
}
|
|
8868
|
+
writeFileSync8(lockFile, lockData);
|
|
8869
|
+
return true;
|
|
8870
|
+
} catch {
|
|
8871
|
+
writeFileSync8(lockFile, lockData);
|
|
8872
|
+
return true;
|
|
8873
|
+
}
|
|
8725
8874
|
}
|
|
8726
8875
|
function releaseSpawnLock2(sessionName) {
|
|
8727
8876
|
try {
|
|
@@ -8800,6 +8949,21 @@ function parseParentExe(sessionName, agentId) {
|
|
|
8800
8949
|
function extractRootExe(name) {
|
|
8801
8950
|
if (!name) return null;
|
|
8802
8951
|
if (!name.includes("-")) return name;
|
|
8952
|
+
try {
|
|
8953
|
+
const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
|
|
8954
|
+
if (roster.length > 0) {
|
|
8955
|
+
const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
|
|
8956
|
+
for (const agentName of sortedNames) {
|
|
8957
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8958
|
+
const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
|
|
8959
|
+
const match = name.match(regex);
|
|
8960
|
+
if (match) {
|
|
8961
|
+
return extractRootExe(match[1]);
|
|
8962
|
+
}
|
|
8963
|
+
}
|
|
8964
|
+
}
|
|
8965
|
+
} catch {
|
|
8966
|
+
}
|
|
8803
8967
|
const parts = name.split("-").filter(Boolean);
|
|
8804
8968
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8805
8969
|
}
|
|
@@ -8818,6 +8982,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
8818
8982
|
function getParentExe(sessionKey) {
|
|
8819
8983
|
try {
|
|
8820
8984
|
const data = JSON.parse(readFileSync12(path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
8985
|
+
if (data.registeredAt) {
|
|
8986
|
+
const age = Date.now() - new Date(data.registeredAt).getTime();
|
|
8987
|
+
if (age > PARENT_EXE_CACHE_TTL_MS) return null;
|
|
8988
|
+
}
|
|
8821
8989
|
return data.parentExe || null;
|
|
8822
8990
|
} catch {
|
|
8823
8991
|
return null;
|
|
@@ -9366,7 +9534,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9366
9534
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
9367
9535
|
} catch {
|
|
9368
9536
|
}
|
|
9369
|
-
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName}`;
|
|
9537
|
+
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName} EXE_SESSION_START_ISO=${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
9370
9538
|
if (ccProvider !== DEFAULT_PROVIDER) {
|
|
9371
9539
|
const cfg = PROVIDER_TABLE[ccProvider];
|
|
9372
9540
|
if (cfg?.apiKeyEnv) {
|
|
@@ -9401,10 +9569,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9401
9569
|
}
|
|
9402
9570
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
9403
9571
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
ccModel += "[1m]";
|
|
9407
|
-
}
|
|
9572
|
+
const { normalizeCcModelName: normalizeCcModelName2 } = (init_agent_config(), __toCommonJS(agent_config_exports));
|
|
9573
|
+
const ccModel = normalizeCcModelName2(agentRtConfig.model);
|
|
9408
9574
|
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
9409
9575
|
}
|
|
9410
9576
|
}
|
|
@@ -9505,7 +9671,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9505
9671
|
releaseSpawnLock2(sessionName);
|
|
9506
9672
|
return { sessionName };
|
|
9507
9673
|
}
|
|
9508
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, CODEX_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
9674
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, PARENT_EXE_CACHE_TTL_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, CODEX_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
9509
9675
|
var init_tmux_routing = __esm({
|
|
9510
9676
|
"src/lib/tmux-routing.ts"() {
|
|
9511
9677
|
"use strict";
|
|
@@ -9525,6 +9691,7 @@ var init_tmux_routing = __esm({
|
|
|
9525
9691
|
SESSION_CACHE = path20.join(os12.homedir(), ".exe-os", "session-cache");
|
|
9526
9692
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
9527
9693
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
9694
|
+
PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
9528
9695
|
VERIFY_PANE_LINES = 200;
|
|
9529
9696
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
9530
9697
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
@@ -9608,7 +9775,21 @@ function tryAcquireWorkerSlot() {
|
|
|
9608
9775
|
for (const f of files) {
|
|
9609
9776
|
if (!f.endsWith(".pid")) continue;
|
|
9610
9777
|
if (f.startsWith("res-")) {
|
|
9611
|
-
|
|
9778
|
+
const resParts = f.replace(".pid", "").split("-");
|
|
9779
|
+
const resPid = parseInt(resParts[1] ?? "", 10);
|
|
9780
|
+
if (!isNaN(resPid) && resPid > 0) {
|
|
9781
|
+
try {
|
|
9782
|
+
process.kill(resPid, 0);
|
|
9783
|
+
alive++;
|
|
9784
|
+
} catch {
|
|
9785
|
+
try {
|
|
9786
|
+
unlinkSync9(path22.join(WORKER_PID_DIR, f));
|
|
9787
|
+
} catch {
|
|
9788
|
+
}
|
|
9789
|
+
}
|
|
9790
|
+
} else {
|
|
9791
|
+
alive++;
|
|
9792
|
+
}
|
|
9612
9793
|
continue;
|
|
9613
9794
|
}
|
|
9614
9795
|
const dashIdx = f.lastIndexOf("-");
|
|
@@ -10151,6 +10332,7 @@ __export(cloud_sync_exports, {
|
|
|
10151
10332
|
markCloudReuploadRequired: () => markCloudReuploadRequired,
|
|
10152
10333
|
mergeConfig: () => mergeConfig,
|
|
10153
10334
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
10335
|
+
migrateEndpoint: () => migrateEndpoint,
|
|
10154
10336
|
pushToPostgres: () => pushToPostgres,
|
|
10155
10337
|
recordRosterDeletion: () => recordRosterDeletion
|
|
10156
10338
|
});
|
|
@@ -10321,6 +10503,15 @@ async function fetchWithRetry(url, init) {
|
|
|
10321
10503
|
}
|
|
10322
10504
|
throw lastError;
|
|
10323
10505
|
}
|
|
10506
|
+
function migrateEndpoint(endpoint) {
|
|
10507
|
+
if (endpoint === "https://askexe.com/cloud" || endpoint === "https://askexe.com/cloud/") {
|
|
10508
|
+
process.stderr.write(
|
|
10509
|
+
"[cloud-sync] Auto-migrating endpoint from askexe.com/cloud to cloud.askexe.com (bypasses Cloudflare WAF for datacenter IPs)\n"
|
|
10510
|
+
);
|
|
10511
|
+
return "https://cloud.askexe.com";
|
|
10512
|
+
}
|
|
10513
|
+
return endpoint;
|
|
10514
|
+
}
|
|
10324
10515
|
function assertSecureEndpoint(endpoint) {
|
|
10325
10516
|
if (endpoint.startsWith("https://")) return;
|
|
10326
10517
|
if (endpoint.startsWith("http://")) {
|
|
@@ -10458,6 +10649,7 @@ async function markCloudReuploadRequired(client = getClient()) {
|
|
|
10458
10649
|
await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
|
|
10459
10650
|
}
|
|
10460
10651
|
async function cloudSync(config) {
|
|
10652
|
+
config = { ...config, endpoint: migrateEndpoint(config.endpoint) };
|
|
10461
10653
|
if (!isSyncCryptoInitialized()) {
|
|
10462
10654
|
try {
|
|
10463
10655
|
const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
|
package/dist/bin/exe-call.js
CHANGED
|
@@ -1263,6 +1263,7 @@ __export(agent_config_exports, {
|
|
|
1263
1263
|
clearAgentRuntime: () => clearAgentRuntime,
|
|
1264
1264
|
getAgentRuntime: () => getAgentRuntime,
|
|
1265
1265
|
loadAgentConfig: () => loadAgentConfig,
|
|
1266
|
+
normalizeCcModelName: () => normalizeCcModelName,
|
|
1266
1267
|
saveAgentConfig: () => saveAgentConfig,
|
|
1267
1268
|
setAgentMcps: () => setAgentMcps,
|
|
1268
1269
|
setAgentRuntime: () => setAgentRuntime
|
|
@@ -1291,6 +1292,13 @@ function getAgentRuntime(agentId) {
|
|
|
1291
1292
|
if (orgDefault) return orgDefault;
|
|
1292
1293
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
1293
1294
|
}
|
|
1295
|
+
function normalizeCcModelName(model) {
|
|
1296
|
+
let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
1297
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
1298
|
+
ccModel += "[1m]";
|
|
1299
|
+
}
|
|
1300
|
+
return ccModel;
|
|
1301
|
+
}
|
|
1294
1302
|
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
1295
1303
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
1296
1304
|
if (!knownModels) {
|