negotium 0.1.24 → 0.1.26
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/README.md +5 -2
- package/dist/agent-helpers.js +64 -8
- package/dist/agent-helpers.js.map +9 -9
- package/dist/background-bash.js.map +1 -1
- package/dist/chunk-7azk83mw.js.map +1 -1
- package/dist/cron.js +161 -50
- package/dist/cron.js.map +20 -19
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +5 -5
- package/dist/main.js +321 -130
- package/dist/main.js.map +23 -22
- package/dist/mcp-factories.js.map +1 -1
- package/dist/prompts.js +22 -2
- package/dist/prompts.js.map +4 -4
- package/dist/registry.js +8 -3
- package/dist/registry.js.map +3 -3
- package/dist/runtime/src/agents/api-topic-agent-switch.ts +8 -2
- package/dist/runtime/src/agents/auth-check.ts +33 -3
- package/dist/runtime/src/agents/idle-archiver.ts +20 -1
- package/dist/runtime/src/agents/maestro-provider.ts +2 -1
- package/dist/runtime/src/agents/maestro-registry.ts +11 -6
- package/dist/runtime/src/agents/mcp-tools/spawn-subagent.ts +16 -10
- package/dist/runtime/src/agents/model-catalog.ts +47 -5
- package/dist/runtime/src/agents/public-helpers.ts +2 -0
- package/dist/runtime/src/agents/self-config-core.ts +17 -5
- package/dist/runtime/src/agents/topic-agent-switch.ts +4 -2
- package/dist/runtime/src/application/switch-topic-model.ts +3 -0
- package/dist/runtime/src/index.ts +1 -1
- package/dist/runtime/src/platform/playwright/headed-launch.ts +61 -0
- package/dist/runtime/src/platform/playwright/manager.ts +39 -9
- package/dist/runtime/src/runtime/errors.ts +2 -2
- package/dist/runtime/src/topics/derive.ts +7 -3
- package/dist/runtime/src/topics/session.ts +45 -1
- package/dist/runtime/src/types.ts +1 -1
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js.map +1 -1
- package/dist/storage.js.map +1 -1
- package/dist/types/packages/core/src/agents/auth-check.d.ts +2 -0
- package/dist/types/packages/core/src/agents/idle-archiver.d.ts +4 -0
- package/dist/types/packages/core/src/agents/maestro-provider.d.ts +2 -1
- package/dist/types/packages/core/src/agents/maestro-registry.d.ts +3 -5
- package/dist/types/packages/core/src/agents/model-catalog.d.ts +5 -1
- package/dist/types/packages/core/src/agents/public-helpers.d.ts +2 -1
- package/dist/types/packages/core/src/types.d.ts +1 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +2 -2
package/dist/cron.js
CHANGED
|
@@ -1716,14 +1716,19 @@ import {
|
|
|
1716
1716
|
setConversationReader,
|
|
1717
1717
|
maestroRegistry as upstreamMaestroRegistry
|
|
1718
1718
|
} from "maestro-agent-sdk";
|
|
1719
|
-
var maestroRegistry;
|
|
1719
|
+
var DISABLED_MODEL_ALIASES, upstream, maestroRegistry;
|
|
1720
1720
|
var init_maestro_registry = __esm(async () => {
|
|
1721
1721
|
init_maestro_bootstrap_env();
|
|
1722
1722
|
await init_conversations();
|
|
1723
|
+
DISABLED_MODEL_ALIASES = new Set(["deepseek", "deepseek-flash", "deepseek-v4-flash"]);
|
|
1724
|
+
upstream = upstreamMaestroRegistry;
|
|
1723
1725
|
setConversationReader(readConversation);
|
|
1724
1726
|
maestroRegistry = {
|
|
1725
|
-
...
|
|
1726
|
-
defaultModel: "deepseek-pro"
|
|
1727
|
+
...upstream,
|
|
1728
|
+
defaultModel: "deepseek-pro",
|
|
1729
|
+
validateModel(model) {
|
|
1730
|
+
return !DISABLED_MODEL_ALIASES.has(model) && upstream.validateModel(model);
|
|
1731
|
+
}
|
|
1727
1732
|
};
|
|
1728
1733
|
});
|
|
1729
1734
|
|
|
@@ -3463,7 +3468,7 @@ var init_claude_provider = __esm(async () => {
|
|
|
3463
3468
|
});
|
|
3464
3469
|
|
|
3465
3470
|
// ../../packages/core/src/version.ts
|
|
3466
|
-
var NEGOTIUM_VERSION = "0.1.
|
|
3471
|
+
var NEGOTIUM_VERSION = "0.1.26";
|
|
3467
3472
|
|
|
3468
3473
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
3469
3474
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -5445,19 +5450,25 @@ var init_ask_user = __esm(async () => {
|
|
|
5445
5450
|
});
|
|
5446
5451
|
|
|
5447
5452
|
// ../../packages/core/src/agents/model-catalog.ts
|
|
5453
|
+
function canonicalModelId(value) {
|
|
5454
|
+
const trimmed = value.trim();
|
|
5455
|
+
return SELECTABLE_MODEL_ALIASES[trimmed.toLowerCase()] ?? trimmed;
|
|
5456
|
+
}
|
|
5448
5457
|
function formatSelectableModel(candidate) {
|
|
5449
5458
|
const tier = `${candidate.intelligenceTier[0].toUpperCase()}${candidate.intelligenceTier.slice(1)}`;
|
|
5450
5459
|
return `${candidate.agent} / \`${candidate.model}\` [${tier}-level]: ${candidate.routingSummary}`;
|
|
5451
5460
|
}
|
|
5452
5461
|
function selectableModel(value) {
|
|
5453
|
-
const
|
|
5454
|
-
return SELECTABLE_MODELS.find((candidate) => candidate.model ===
|
|
5462
|
+
const canonical = canonicalModelId(value).toLowerCase();
|
|
5463
|
+
return SELECTABLE_MODELS.find((candidate) => candidate.model === canonical);
|
|
5455
5464
|
}
|
|
5456
5465
|
function modelOwner(model) {
|
|
5457
5466
|
if (model.startsWith("claude-"))
|
|
5458
5467
|
return "claude";
|
|
5459
5468
|
if (model.startsWith("deepseek-"))
|
|
5460
5469
|
return "maestro";
|
|
5470
|
+
if (model.startsWith("kimi-"))
|
|
5471
|
+
return "maestro";
|
|
5461
5472
|
if (model.startsWith("gpt-"))
|
|
5462
5473
|
return "codex";
|
|
5463
5474
|
return MODEL_OWNER[model];
|
|
@@ -5466,12 +5477,13 @@ function resolveModelForAgent(agent, requested, registry) {
|
|
|
5466
5477
|
const defaultModel = resolveDefaultModel(agent, registry.defaultModel);
|
|
5467
5478
|
if (!requested)
|
|
5468
5479
|
return defaultModel;
|
|
5469
|
-
const
|
|
5480
|
+
const candidate = canonicalModelId(requested);
|
|
5481
|
+
const owner = modelOwner(candidate);
|
|
5470
5482
|
if (owner && owner !== agent)
|
|
5471
5483
|
return defaultModel;
|
|
5472
|
-
return registry.validateModel(
|
|
5484
|
+
return registry.validateModel(candidate) ? candidate : defaultModel;
|
|
5473
5485
|
}
|
|
5474
|
-
var MODEL_OWNER, MODEL_COST_RESEARCHED_AT = "2026-07-19", MODEL_COST_ROUTING_SUMMARY = "Cost basis (2026-07-19): Codex Pro 20x and Claude Max 20x are each $200/month;
|
|
5486
|
+
var MODEL_OWNER, MODEL_COST_RESEARCHED_AT = "2026-07-19", MODEL_COST_ROUTING_SUMMARY = "Cost basis (2026-07-19): Codex Pro 20x and Claude Max 20x are each $200/month; Maestro models are pay-per-token. DeepSeek Pro is cheapest, Kimi K2.7 Code is the coding route, and Kimi K3 is the frontier route.", CODEX_PRO_20X_COST = "ChatGPT Pro 20x subscription: $200/month", CODEX_COMMUNITY_WEEKLY = "Community plan-level observation: roughly 2\u20134B raw/cached tokens per week; fresh-input equivalent is much lower and unstable (low confidence)", CLAUDE_MAX_20X_COST = "Claude Max 20x subscription: $200/month", CLAUDE_COMMUNITY_SESSION = "Community observations vary from roughly 220\u2013250K locally displayed tokens per 5-hour session to billions of cache-heavy raw tokens per week; calibrated reports value a full weekly allowance around $680\u2013$1,900 at API rates. Recent heavy-model reports reach the weekly cap after about 4\u20135 full sessions (low confidence; not a token cap)", SELECTABLE_MODELS, SELECTABLE_MODEL_ALIASES, FALLBACK_ORDER, AGENT_DISPLAY_NAME;
|
|
5475
5487
|
var init_model_catalog = __esm(() => {
|
|
5476
5488
|
init_config();
|
|
5477
5489
|
MODEL_OWNER = {
|
|
@@ -5485,7 +5497,12 @@ var init_model_catalog = __esm(() => {
|
|
|
5485
5497
|
"gpt-5.5": "codex",
|
|
5486
5498
|
deepseek: "maestro",
|
|
5487
5499
|
"deepseek-pro": "maestro",
|
|
5488
|
-
"deepseek-flash": "maestro"
|
|
5500
|
+
"deepseek-flash": "maestro",
|
|
5501
|
+
kimi: "maestro",
|
|
5502
|
+
"kimi-pro": "maestro",
|
|
5503
|
+
"kimi-k3": "maestro",
|
|
5504
|
+
"kimi-code": "maestro",
|
|
5505
|
+
"kimi-k2.7-code": "maestro"
|
|
5489
5506
|
};
|
|
5490
5507
|
SELECTABLE_MODELS = [
|
|
5491
5508
|
{
|
|
@@ -5548,6 +5565,26 @@ var init_model_catalog = __esm(() => {
|
|
|
5548
5565
|
marginalTokenCost: "Claude API/extra usage introductory rate: $2/M input, $2.50/M cache write, $0.20/M cache read, $10/M output through 2026-08-31; then $3/M input and $15/M output",
|
|
5549
5566
|
estimatedUsage: `${CLAUDE_COMMUNITY_SESSION}; Sonnet also has a separate weekly allowance and normally provides the highest Claude throughput. No stable weekly token cap is published.`
|
|
5550
5567
|
},
|
|
5568
|
+
{
|
|
5569
|
+
model: "kimi-k3",
|
|
5570
|
+
agent: "maestro",
|
|
5571
|
+
description: "Frontier Kimi route for long-horizon coding and knowledge work.",
|
|
5572
|
+
intelligenceTier: "fable",
|
|
5573
|
+
routingSummary: "frontier general/coding route; 1M context; highest Maestro API cost",
|
|
5574
|
+
accessCost: "Moonshot AI pay-as-you-go API; no monthly subscription required",
|
|
5575
|
+
marginalTokenCost: "Kimi API: $3/M cache-miss input, $0.30/M cached input, $15/M output",
|
|
5576
|
+
estimatedUsage: "No subscription token cap; pay per token. Supports a 1M-token context window."
|
|
5577
|
+
},
|
|
5578
|
+
{
|
|
5579
|
+
model: "kimi-k2.7-code",
|
|
5580
|
+
agent: "maestro",
|
|
5581
|
+
description: "Coding-specialized Kimi route for repository-scale, long-horizon work.",
|
|
5582
|
+
intelligenceTier: "opus",
|
|
5583
|
+
routingSummary: "coding-specialized route; 256K context; cheaper than Kimi K3",
|
|
5584
|
+
accessCost: "Moonshot AI pay-as-you-go API; no monthly subscription required",
|
|
5585
|
+
marginalTokenCost: "Kimi API: $0.95/M cache-miss input, $0.19/M cached input, $4/M output",
|
|
5586
|
+
estimatedUsage: "No subscription token cap; pay per token. Always uses thinking and supports a 256K context window."
|
|
5587
|
+
},
|
|
5551
5588
|
{
|
|
5552
5589
|
model: "deepseek-pro",
|
|
5553
5590
|
agent: "maestro",
|
|
@@ -5559,6 +5596,11 @@ var init_model_catalog = __esm(() => {
|
|
|
5559
5596
|
estimatedUsage: "No subscription token cap; pay per token. Official account concurrency limit is 500 requests."
|
|
5560
5597
|
}
|
|
5561
5598
|
];
|
|
5599
|
+
SELECTABLE_MODEL_ALIASES = {
|
|
5600
|
+
kimi: "kimi-k3",
|
|
5601
|
+
"kimi-pro": "kimi-k3",
|
|
5602
|
+
"kimi-code": "kimi-k2.7-code"
|
|
5603
|
+
};
|
|
5562
5604
|
FALLBACK_ORDER = {
|
|
5563
5605
|
claude: [
|
|
5564
5606
|
{ agent: "maestro", model: "deepseek-pro" },
|
|
@@ -5748,6 +5790,38 @@ var init_self_schedules = __esm(async () => {
|
|
|
5748
5790
|
`);
|
|
5749
5791
|
});
|
|
5750
5792
|
|
|
5793
|
+
// ../../packages/core/src/platform/playwright/headed-launch.ts
|
|
5794
|
+
import { accessSync, constants } from "fs";
|
|
5795
|
+
import { delimiter, isAbsolute, resolve as resolve5 } from "path";
|
|
5796
|
+
function findExecutableOnPath(command, environment = process.env) {
|
|
5797
|
+
const candidates = isAbsolute(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve5(directory, command));
|
|
5798
|
+
for (const candidate of candidates) {
|
|
5799
|
+
try {
|
|
5800
|
+
accessSync(candidate, constants.X_OK);
|
|
5801
|
+
return candidate;
|
|
5802
|
+
} catch {}
|
|
5803
|
+
}
|
|
5804
|
+
return null;
|
|
5805
|
+
}
|
|
5806
|
+
function resolveHeadedPlaywrightSpawn(command, args, options = {}) {
|
|
5807
|
+
const platform2 = options.platform ?? process.platform;
|
|
5808
|
+
const environment = options.environment ?? process.env;
|
|
5809
|
+
const hasDisplay = Boolean(environment.DISPLAY?.trim() || environment.WAYLAND_DISPLAY?.trim());
|
|
5810
|
+
if (platform2 !== "linux" || hasDisplay) {
|
|
5811
|
+
return { command, args: [...args], virtualDisplay: false };
|
|
5812
|
+
}
|
|
5813
|
+
const xvfbRun = (options.findExecutable ?? findExecutableOnPath)("xvfb-run", environment);
|
|
5814
|
+
if (!xvfbRun) {
|
|
5815
|
+
throw new Error("Headed Playwright on Linux requires DISPLAY/WAYLAND_DISPLAY or xvfb-run; install Xvfb and ensure xvfb-run is on PATH");
|
|
5816
|
+
}
|
|
5817
|
+
return {
|
|
5818
|
+
command: xvfbRun,
|
|
5819
|
+
args: ["-a", "-s", "-screen 0 1440x1000x24", command, ...args],
|
|
5820
|
+
virtualDisplay: true
|
|
5821
|
+
};
|
|
5822
|
+
}
|
|
5823
|
+
var init_headed_launch = () => {};
|
|
5824
|
+
|
|
5751
5825
|
// ../../packages/core/src/storage/browser-profiles.ts
|
|
5752
5826
|
function normalizeBrowserProfileName(name) {
|
|
5753
5827
|
const value = name.trim().toLowerCase();
|
|
@@ -5852,7 +5926,7 @@ import {
|
|
|
5852
5926
|
unlinkSync as unlinkSync9,
|
|
5853
5927
|
writeFileSync as writeFileSync7
|
|
5854
5928
|
} from "fs";
|
|
5855
|
-
import { dirname as dirname8, join as join13, resolve as
|
|
5929
|
+
import { dirname as dirname8, join as join13, resolve as resolve6 } from "path";
|
|
5856
5930
|
function makeInstanceKey(userId, topic) {
|
|
5857
5931
|
if (!topic)
|
|
5858
5932
|
return makeBrowserProfileInstanceKey(userId, "default");
|
|
@@ -5870,7 +5944,7 @@ function migrateLegacyTopicProfile(ownerId, topic) {
|
|
|
5870
5944
|
const current2 = getTopicBrowserProfile(topic);
|
|
5871
5945
|
if (current2 !== "default" || !hasBrowserProfileTopic(topic))
|
|
5872
5946
|
return current2;
|
|
5873
|
-
const legacyDir =
|
|
5947
|
+
const legacyDir = resolve6(BROWSER_PROFILES_DIR, sanitizeTopicName(topic));
|
|
5874
5948
|
if (!existsSync13(legacyDir))
|
|
5875
5949
|
return current2;
|
|
5876
5950
|
const profile = legacyBrowserProfileName(topic);
|
|
@@ -6049,11 +6123,11 @@ async function killPlaywrightOnPort(port, expectedUserDataDir) {
|
|
|
6049
6123
|
}
|
|
6050
6124
|
function browserProcessMatchesExpectedProfile(cmdline, expectedUserDataDir) {
|
|
6051
6125
|
const actualUserDataDir = extractUserDataDirArg(cmdline);
|
|
6052
|
-
return actualUserDataDir !== null &&
|
|
6126
|
+
return actualUserDataDir !== null && resolve6(actualUserDataDir) === resolve6(expectedUserDataDir);
|
|
6053
6127
|
}
|
|
6054
6128
|
function killBrowserProcsForUserDataDir(userDataDir) {
|
|
6055
|
-
const target =
|
|
6056
|
-
if (!target.startsWith(
|
|
6129
|
+
const target = resolve6(userDataDir);
|
|
6130
|
+
if (!target.startsWith(resolve6(BROWSER_PROFILES_DIR)))
|
|
6057
6131
|
return;
|
|
6058
6132
|
let pids;
|
|
6059
6133
|
try {
|
|
@@ -6073,7 +6147,7 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
6073
6147
|
stdio: "pipe"
|
|
6074
6148
|
}).toString().trim();
|
|
6075
6149
|
const argDir = extractUserDataDirArg(cmdline);
|
|
6076
|
-
if (!argDir ||
|
|
6150
|
+
if (!argDir || resolve6(argDir) !== target)
|
|
6077
6151
|
continue;
|
|
6078
6152
|
killProcessTreeChildren(pidNum);
|
|
6079
6153
|
process.kill(pidNum, "SIGKILL");
|
|
@@ -6084,13 +6158,13 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
6084
6158
|
}
|
|
6085
6159
|
}
|
|
6086
6160
|
function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid) {
|
|
6087
|
-
const root =
|
|
6088
|
-
const live = new Set([...liveUserDataDirs].map((d) =>
|
|
6161
|
+
const root = resolve6(profileRoot);
|
|
6162
|
+
const live = new Set([...liveUserDataDirs].map((d) => resolve6(d)));
|
|
6089
6163
|
const out = [];
|
|
6090
6164
|
for (const { pid, userDataDir } of procs) {
|
|
6091
6165
|
if (pid === selfPid || !userDataDir)
|
|
6092
6166
|
continue;
|
|
6093
|
-
const dir =
|
|
6167
|
+
const dir = resolve6(userDataDir);
|
|
6094
6168
|
if (!dir.startsWith(root))
|
|
6095
6169
|
continue;
|
|
6096
6170
|
if (live.has(dir))
|
|
@@ -6106,7 +6180,7 @@ function reapOrphanBrowsers() {
|
|
|
6106
6180
|
const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
|
|
6107
6181
|
if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
|
|
6108
6182
|
return;
|
|
6109
|
-
const profileRoot =
|
|
6183
|
+
const profileRoot = resolve6(BROWSER_PROFILES_DIR);
|
|
6110
6184
|
let pids;
|
|
6111
6185
|
try {
|
|
6112
6186
|
pids = execFileSync4("pgrep", ["-f", "--", profileRoot], { stdio: "pipe" }).toString().trim();
|
|
@@ -6159,7 +6233,7 @@ function cleanSingletonFiles(userDataDir) {
|
|
|
6159
6233
|
for (const f of files) {
|
|
6160
6234
|
if (f.startsWith("Singleton")) {
|
|
6161
6235
|
try {
|
|
6162
|
-
unlinkSync9(
|
|
6236
|
+
unlinkSync9(resolve6(userDataDir, f));
|
|
6163
6237
|
logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
|
|
6164
6238
|
} catch (e) {
|
|
6165
6239
|
logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
|
|
@@ -6195,7 +6269,7 @@ function ownerDirectory(ownerId) {
|
|
|
6195
6269
|
return `${sanitizeTopicName(ownerId).slice(0, 24)}_${digest}`;
|
|
6196
6270
|
}
|
|
6197
6271
|
function resolveProfileDir(ownerId, profile) {
|
|
6198
|
-
return
|
|
6272
|
+
return resolve6(BROWSER_PROFILES_DIR, "profiles", ownerDirectory(ownerId), profile);
|
|
6199
6273
|
}
|
|
6200
6274
|
function resolveUserDataDir(instanceKey) {
|
|
6201
6275
|
const { ownerId, profile } = parseInstanceKey(instanceKey);
|
|
@@ -6253,11 +6327,25 @@ async function spawnPlaywright(instanceKey, userId, reservedPort, browserBin = P
|
|
|
6253
6327
|
}
|
|
6254
6328
|
const command = browserBin.endsWith(".mjs") ? process.execPath : browserBin;
|
|
6255
6329
|
const args = browserBin.endsWith(".mjs") ? [browserBin, ...mcpArgs] : mcpArgs;
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6330
|
+
let spawnSpec;
|
|
6331
|
+
try {
|
|
6332
|
+
spawnSpec = resolveHeadedPlaywrightSpawn(command, args, { environment: childEnv });
|
|
6333
|
+
} catch (err) {
|
|
6334
|
+
releasePort(port);
|
|
6335
|
+
throw err;
|
|
6336
|
+
}
|
|
6337
|
+
let proc;
|
|
6338
|
+
try {
|
|
6339
|
+
proc = spawn4(spawnSpec.command, spawnSpec.args, {
|
|
6340
|
+
stdio: "ignore",
|
|
6341
|
+
detached: false,
|
|
6342
|
+
env: childEnv
|
|
6343
|
+
});
|
|
6344
|
+
} catch (err) {
|
|
6345
|
+
releasePort(port);
|
|
6346
|
+
throw err;
|
|
6347
|
+
}
|
|
6348
|
+
const spawnError = waitForChildProcessSpawnError(proc);
|
|
6261
6349
|
const reapCrashedBrowser = () => {
|
|
6262
6350
|
const userDataDir2 = resolveUserDataDir(instanceKey);
|
|
6263
6351
|
killBrowserProcsForUserDataDir(userDataDir2);
|
|
@@ -6290,7 +6378,10 @@ async function spawnPlaywright(instanceKey, userId, reservedPort, browserBin = P
|
|
|
6290
6378
|
lastUsedAt: now,
|
|
6291
6379
|
capability
|
|
6292
6380
|
});
|
|
6293
|
-
const ready = await
|
|
6381
|
+
const ready = await Promise.race([
|
|
6382
|
+
(async () => await waitForServer(port, 1e4) && await supportsOwnerCleanup(port, capability))(),
|
|
6383
|
+
spawnError
|
|
6384
|
+
]);
|
|
6294
6385
|
if (!ready) {
|
|
6295
6386
|
const exitCode = proc.exitCode;
|
|
6296
6387
|
killInstance(instanceKey);
|
|
@@ -6301,7 +6392,7 @@ async function spawnPlaywright(instanceKey, userId, reservedPort, browserBin = P
|
|
|
6301
6392
|
throw new Error(`Playwright MCP failed health check after spawn on port ${port}` + (exitCode === null ? "" : ` (exitCode=${exitCode})`));
|
|
6302
6393
|
}
|
|
6303
6394
|
writePortFile(instanceKey, port);
|
|
6304
|
-
logger.info({ instanceKey, port, pid: proc.pid, ready }, "Playwright MCP started");
|
|
6395
|
+
logger.info({ instanceKey, port, pid: proc.pid, ready, virtualDisplay: spawnSpec.virtualDisplay }, "Playwright MCP started");
|
|
6305
6396
|
return port;
|
|
6306
6397
|
}
|
|
6307
6398
|
async function supportsOwnerCleanup(port, capability) {
|
|
@@ -6369,10 +6460,16 @@ async function waitForServer(port, timeoutMs) {
|
|
|
6369
6460
|
logger.warn({ port, timeoutMs }, "Playwright MCP not ready before timeout");
|
|
6370
6461
|
return false;
|
|
6371
6462
|
}
|
|
6463
|
+
function waitForChildProcessSpawnError(proc) {
|
|
6464
|
+
return new Promise((_resolve, reject) => {
|
|
6465
|
+
proc.once("error", reject);
|
|
6466
|
+
});
|
|
6467
|
+
}
|
|
6372
6468
|
var BASE_PORT, MAX_PORT, MAX_IDLE_MS, instances, usedPorts, spawning, pinnedInstances, _onPlaywrightExit = null;
|
|
6373
6469
|
var init_manager2 = __esm(async () => {
|
|
6374
6470
|
init_config();
|
|
6375
6471
|
init_logger();
|
|
6472
|
+
init_headed_launch();
|
|
6376
6473
|
await init_browser_profiles();
|
|
6377
6474
|
await init_runtime_process_leases();
|
|
6378
6475
|
BASE_PORT = PLAYWRIGHT_BASE_PORT;
|
|
@@ -6997,9 +7094,9 @@ var init_runtime_turn_requests = __esm(async () => {
|
|
|
6997
7094
|
|
|
6998
7095
|
// ../../packages/core/src/prompts/builders.ts
|
|
6999
7096
|
import { readFileSync as readFileSync10 } from "fs";
|
|
7000
|
-
import { resolve as
|
|
7097
|
+
import { resolve as resolve7 } from "path";
|
|
7001
7098
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
7002
|
-
const raw = readFileSync10(
|
|
7099
|
+
const raw = readFileSync10(resolve7(dir, filename), "utf-8");
|
|
7003
7100
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
7004
7101
|
}
|
|
7005
7102
|
function replaceVars(template, vars) {
|
|
@@ -7042,7 +7139,7 @@ function visualDesignGuide() {
|
|
|
7042
7139
|
return _visualDesignGuide;
|
|
7043
7140
|
}
|
|
7044
7141
|
function loadAgentPrompt(filename) {
|
|
7045
|
-
const raw = readFileSync10(
|
|
7142
|
+
const raw = readFileSync10(resolve7(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
7046
7143
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
7047
7144
|
if (!match)
|
|
7048
7145
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -7242,8 +7339,8 @@ var init_builders = __esm(() => {
|
|
|
7242
7339
|
init_model_catalog();
|
|
7243
7340
|
init_config();
|
|
7244
7341
|
init_logger();
|
|
7245
|
-
PROMPTS_DIR =
|
|
7246
|
-
SESSIONS_DIR =
|
|
7342
|
+
PROMPTS_DIR = resolve7(PROJECT_ROOT, "src/prompts");
|
|
7343
|
+
SESSIONS_DIR = resolve7(PROMPTS_DIR, "sessions");
|
|
7247
7344
|
});
|
|
7248
7345
|
|
|
7249
7346
|
// ../../packages/core/src/storage/api-topic-brief.ts
|
|
@@ -7934,7 +8031,17 @@ function archiveActiveTopicForMemory(topicId, userId, options) {
|
|
|
7934
8031
|
archivePath: job.archivePath,
|
|
7935
8032
|
messageCount: job.messageCount,
|
|
7936
8033
|
mode: "active-topic",
|
|
7937
|
-
onSettled: (success) =>
|
|
8034
|
+
onSettled: (success) => {
|
|
8035
|
+
let settled = false;
|
|
8036
|
+
try {
|
|
8037
|
+
(options.settleArchiveJob ?? settleTopicArchiveJob)(topicId, job.archivePath, success);
|
|
8038
|
+
settled = true;
|
|
8039
|
+
} catch (err) {
|
|
8040
|
+
logger.warn({ err, topicId, archive: job.archivePath }, "topic-memory-archiver: failed to settle archive job");
|
|
8041
|
+
} finally {
|
|
8042
|
+
options.onSettled?.(settled && success);
|
|
8043
|
+
}
|
|
8044
|
+
}
|
|
7938
8045
|
});
|
|
7939
8046
|
if (!launched) {
|
|
7940
8047
|
settleTopicArchiveJob(topicId, job.archivePath, false);
|
|
@@ -8556,7 +8663,7 @@ function authRecoveryHint(agent) {
|
|
|
8556
8663
|
case "codex":
|
|
8557
8664
|
return "Please log in again with `codex login` (~/.codex/auth.json)";
|
|
8558
8665
|
case "maestro":
|
|
8559
|
-
return "Please check the DEEPSEEK_API_KEY environment variable";
|
|
8666
|
+
return "Please check the DEEPSEEK_API_KEY or MOONSHOT_API_KEY environment variable";
|
|
8560
8667
|
}
|
|
8561
8668
|
}
|
|
8562
8669
|
function classifyAgentError(err, agent) {
|
|
@@ -8572,7 +8679,7 @@ function classifyAgentError(err, agent) {
|
|
|
8572
8679
|
return status === 529 ? `${name} server is overloaded. Please try again in a moment. (529)` : `${name} server error occurred. Please try again in a moment. (500)`;
|
|
8573
8680
|
}
|
|
8574
8681
|
const s = stringifyError(err);
|
|
8575
|
-
if (/401|authentication.error|invalid.*api.key|not logged|ANTHROPIC_API_KEY|DEEPSEEK_API_KEY/i.test(s)) {
|
|
8682
|
+
if (/401|authentication.error|invalid.*api.key|not logged|ANTHROPIC_API_KEY|DEEPSEEK_API_KEY|MOONSHOT_API_KEY/i.test(s)) {
|
|
8576
8683
|
return `${name} authentication expired. ${hint}. (401)`;
|
|
8577
8684
|
}
|
|
8578
8685
|
if (/429|rate.limit/i.test(s))
|
|
@@ -8594,12 +8701,12 @@ var init_errors = __esm(() => {
|
|
|
8594
8701
|
|
|
8595
8702
|
// ../../packages/core/src/runtime/event-heartbeat.ts
|
|
8596
8703
|
function nextOrHeartbeat(pending, intervalMs) {
|
|
8597
|
-
return new Promise((
|
|
8598
|
-
const timer = setTimeout(() =>
|
|
8704
|
+
return new Promise((resolve8, reject) => {
|
|
8705
|
+
const timer = setTimeout(() => resolve8({ kind: "heartbeat" }), intervalMs);
|
|
8599
8706
|
timer.unref?.();
|
|
8600
8707
|
pending.then((result) => {
|
|
8601
8708
|
clearTimeout(timer);
|
|
8602
|
-
|
|
8709
|
+
resolve8({ kind: "event", result });
|
|
8603
8710
|
}, (error) => {
|
|
8604
8711
|
clearTimeout(timer);
|
|
8605
8712
|
reject(error);
|
|
@@ -9026,7 +9133,7 @@ var init_visual_html = __esm(() => {
|
|
|
9026
9133
|
|
|
9027
9134
|
// ../../packages/core/src/runtime/visuals.ts
|
|
9028
9135
|
import { realpathSync as realpathSync2 } from "fs";
|
|
9029
|
-
import { isAbsolute, resolve as
|
|
9136
|
+
import { isAbsolute as isAbsolute2, resolve as resolve8 } from "path";
|
|
9030
9137
|
function activeVisualHtmlForPrompt(html) {
|
|
9031
9138
|
if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
|
|
9032
9139
|
return { html, omittedChars: 0 };
|
|
@@ -9077,8 +9184,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
|
|
|
9077
9184
|
return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
|
|
9078
9185
|
}
|
|
9079
9186
|
function isPathInside(baseDir, filePath) {
|
|
9080
|
-
const base =
|
|
9081
|
-
const normalized =
|
|
9187
|
+
const base = resolve8(baseDir);
|
|
9188
|
+
const normalized = resolve8(filePath);
|
|
9082
9189
|
try {
|
|
9083
9190
|
const realBase = realpathSync2(base);
|
|
9084
9191
|
const real = realpathSync2(normalized);
|
|
@@ -9140,7 +9247,7 @@ function resolveVisualMediaInput(topicId, input) {
|
|
|
9140
9247
|
}
|
|
9141
9248
|
const rawPath = input.file_path.trim();
|
|
9142
9249
|
const cwd = workspaceCwdFor(topicId);
|
|
9143
|
-
const candidate =
|
|
9250
|
+
const candidate = isAbsolute2(rawPath) ? rawPath : resolve8(cwd, rawPath);
|
|
9144
9251
|
if (!isPathInside(cwd, candidate)) {
|
|
9145
9252
|
return { error: "file_path must be inside the topic workspace" };
|
|
9146
9253
|
}
|
|
@@ -9836,6 +9943,7 @@ __export(exports_turn_runner, {
|
|
|
9836
9943
|
composeAttachmentPrompt: () => composeAttachmentPrompt,
|
|
9837
9944
|
classifyAgentError: () => classifyAgentError,
|
|
9838
9945
|
channelTranscriptSpeaker: () => channelTranscriptSpeaker,
|
|
9946
|
+
canonicalModelId: () => canonicalModelId,
|
|
9839
9947
|
buildVideoHtml: () => buildVideoHtml,
|
|
9840
9948
|
buildMermaidHtml: () => buildMermaidHtml,
|
|
9841
9949
|
buildMentionOnlyChannelPrompt: () => buildMentionOnlyChannelPrompt,
|
|
@@ -9853,7 +9961,7 @@ __export(exports_turn_runner, {
|
|
|
9853
9961
|
});
|
|
9854
9962
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
9855
9963
|
import { mkdirSync as mkdirSync16, realpathSync as realpathSync3, statSync as statSync6 } from "fs";
|
|
9856
|
-
import { isAbsolute as
|
|
9964
|
+
import { isAbsolute as isAbsolute3, resolve as resolve9 } from "path";
|
|
9857
9965
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
9858
9966
|
if (isManager)
|
|
9859
9967
|
return configuredMcp;
|
|
@@ -10197,7 +10305,7 @@ async function streamAgentEvents(topicId, topicTitle, queryId, events, control,
|
|
|
10197
10305
|
case "file":
|
|
10198
10306
|
if (!silent && peerBridge) {
|
|
10199
10307
|
const cwd = workspaceCwdFor(topicId);
|
|
10200
|
-
const path =
|
|
10308
|
+
const path = isAbsolute3(event.path) ? event.path : resolve9(cwd, event.path);
|
|
10201
10309
|
if (!isPathInside(cwd, path)) {
|
|
10202
10310
|
logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
|
|
10203
10311
|
break;
|
|
@@ -11796,6 +11904,7 @@ await init_api_topics();
|
|
|
11796
11904
|
await init_conversations();
|
|
11797
11905
|
|
|
11798
11906
|
// ../../packages/core/src/agents/self-config-core.ts
|
|
11907
|
+
init_auth_check();
|
|
11799
11908
|
init_model_catalog();
|
|
11800
11909
|
await init_registry();
|
|
11801
11910
|
await init_bus();
|
|
@@ -11918,6 +12027,7 @@ await init_bus();
|
|
|
11918
12027
|
await init_api_topic_config();
|
|
11919
12028
|
await init_api_topics();
|
|
11920
12029
|
// ../../packages/core/src/application/switch-topic-model.ts
|
|
12030
|
+
init_auth_check();
|
|
11921
12031
|
init_model_catalog();
|
|
11922
12032
|
await init_registry();
|
|
11923
12033
|
await init_bus();
|
|
@@ -11967,6 +12077,7 @@ await init_runtime_leases();
|
|
|
11967
12077
|
await init_runtime_topic_state();
|
|
11968
12078
|
await init_runtime_turn_requests();
|
|
11969
12079
|
await init_personal_general();
|
|
12080
|
+
var RESET_MEMORY_ARCHIVE_WAIT_MS = 5 * 60 * 1000;
|
|
11970
12081
|
// ../../packages/core/src/application/vault-command.ts
|
|
11971
12082
|
await init_vault();
|
|
11972
12083
|
var VAULT_COMMAND_HELP = [
|
|
@@ -12474,8 +12585,8 @@ function computeNextCronRun(expression, after = new Date, timezone) {
|
|
|
12474
12585
|
// ../../packages/module-cron/src/scripts.ts
|
|
12475
12586
|
import { spawn as spawn5 } from "child_process";
|
|
12476
12587
|
import { existsSync as existsSync16, mkdirSync as mkdirSync19, readdirSync as readdirSync6 } from "fs";
|
|
12477
|
-
import { resolve as
|
|
12478
|
-
var CRON_JOBS_DIR =
|
|
12588
|
+
import { resolve as resolve10, sep } from "path";
|
|
12589
|
+
var CRON_JOBS_DIR = resolve10(process.env.NEGOTIUM_CRON_JOBS_DIR?.trim() || resolve10(WORKSPACE_DIR, "cron", "jobs"));
|
|
12479
12590
|
var DEFAULT_SCRIPT_TIMEOUT_MS = 10 * 60000;
|
|
12480
12591
|
var DEFAULT_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
12481
12592
|
var KILL_GRACE_MS = 2500;
|
|
@@ -12498,7 +12609,7 @@ function resolveCronScriptPath(script) {
|
|
|
12498
12609
|
const valid = validateCronScriptName(script);
|
|
12499
12610
|
if (!valid.ok)
|
|
12500
12611
|
throw new Error(valid.error);
|
|
12501
|
-
const path =
|
|
12612
|
+
const path = resolve10(CRON_JOBS_DIR, script);
|
|
12502
12613
|
if (!path.startsWith(`${CRON_JOBS_DIR}${sep}`))
|
|
12503
12614
|
throw new Error("script path escaped jobs directory");
|
|
12504
12615
|
return path;
|
|
@@ -13956,4 +14067,4 @@ export {
|
|
|
13956
14067
|
CRON_CONTEXT_RETAIN_TURNS
|
|
13957
14068
|
};
|
|
13958
14069
|
|
|
13959
|
-
//# debugId=
|
|
14070
|
+
//# debugId=8A97E8B383252AFE64756E2164756E21
|