negotium 0.2.2 → 0.2.4
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/agent-helpers.js +3117 -2915
- package/dist/agent-helpers.js.map +38 -37
- package/dist/background-bash.js.map +1 -1
- package/dist/browser-runtime.js +137 -21
- package/dist/browser-runtime.js.map +10 -9
- package/dist/{chunk-kc5kmr95.js → chunk-1s9ryz8g.js} +1195 -21
- package/dist/chunk-1s9ryz8g.js.map +35 -0
- package/dist/hosted-agent.js +60 -48
- package/dist/hosted-agent.js.map +10 -10
- package/dist/main.js +3038 -3357
- package/dist/main.js.map +35 -35
- package/dist/mcp-factories.js +6227 -6021
- package/dist/mcp-factories.js.map +40 -39
- package/dist/prompts.js.map +1 -1
- package/dist/query-runtime.js +22 -2
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +169 -213
- package/dist/registry.js.map +8 -9
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/codex-app-server.ts +136 -0
- package/dist/runtime/src/agents/codex-native-multi-agent.ts +1 -1
- package/dist/runtime/src/agents/codex-provider.ts +21 -11
- package/dist/runtime/src/agents/codex-registry.ts +9 -17
- package/dist/runtime/src/agents/contracts.ts +2 -0
- package/dist/runtime/src/agents/execution-host.ts +6 -0
- package/dist/runtime/src/agents/fork.ts +24 -18
- package/dist/runtime/src/agents/idle-archiver.ts +7 -2
- package/dist/runtime/src/agents/index.ts +2 -1
- package/dist/runtime/src/agents/maestro-registry.ts +26 -7
- package/dist/runtime/src/agents/memory-archive-policy.ts +20 -0
- package/dist/runtime/src/agents/rollout/codex.ts +6 -5
- package/dist/runtime/src/agents/rollout/shared.ts +3 -5
- package/dist/runtime/src/mcp/factories/session-comm.ts +12 -0
- package/dist/runtime/src/mcp/session-comm/default-host.ts +16 -0
- package/dist/runtime/src/mcp/session-comm/server.ts +25 -0
- package/dist/runtime/src/platform/config.ts +4 -1
- package/dist/runtime/src/platform/playwright/manager.ts +57 -1
- package/dist/runtime/src/platform/playwright/profile-management.ts +33 -0
- package/dist/runtime/src/platform/playwright/public-runtime.ts +5 -0
- package/dist/runtime/src/platform/playwright/vault-broker.ts +9 -10
- package/dist/runtime/src/storage/browser-profiles.ts +35 -10
- package/dist/runtime/src/storage/storage-host.ts +31 -5
- package/dist/runtime/src/storage/vault.ts +30 -2
- package/dist/runtime/src/topics/derive.ts +38 -2
- package/dist/runtime/src/topics/lifecycle.ts +12 -2
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +22 -2
- package/dist/runtime-helpers.js.map +4 -4
- package/dist/storage.js +22 -2
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/agents/codex-app-server.d.ts +13 -0
- package/dist/types/packages/core/src/agents/codex-native-multi-agent.d.ts +1 -0
- package/dist/types/packages/core/src/agents/contracts.d.ts +2 -0
- package/dist/types/packages/core/src/agents/execution-host.d.ts +2 -0
- package/dist/types/packages/core/src/agents/fork.d.ts +8 -7
- package/dist/types/packages/core/src/agents/memory-archive-policy.d.ts +10 -0
- package/dist/types/packages/core/src/agents/rollout/codex.d.ts +4 -2
- package/dist/types/packages/core/src/mcp/factories/session-comm.d.ts +1 -0
- package/dist/types/packages/core/src/platform/playwright/manager.d.ts +15 -0
- package/dist/types/packages/core/src/platform/playwright/profile-management.d.ts +8 -0
- package/dist/types/packages/core/src/platform/playwright/public-runtime.d.ts +2 -1
- package/dist/types/packages/core/src/storage/browser-profiles.d.ts +3 -1
- package/dist/types/packages/core/src/storage/storage-host.d.ts +1 -0
- package/dist/types/packages/core/src/storage/vault.d.ts +8 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +19 -3
- package/dist/vault.js.map +4 -4
- package/package.json +2 -2
- package/dist/chunk-kc5kmr95.js.map +0 -19
- package/dist/runtime/src/migration/single-user.ts +0 -805
|
@@ -67,16 +67,42 @@ function defaultSessionsDatabasePath(): string {
|
|
|
67
67
|
return envPath("SESSIONS_DB_PATH", join(resolveStorageDataDir(), "sessions.db"));
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const SQLITE_INIT_RETRY_MS = 25;
|
|
71
|
+
const SQLITE_INIT_TIMEOUT_MS = 5_000;
|
|
72
|
+
const SQLITE_INIT_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
73
|
+
|
|
74
|
+
function isSqliteBusy(error: unknown): boolean {
|
|
75
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
+
return /database is (?:locked|busy)|SQLITE_(?:BUSY|LOCKED)/i.test(message);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function execWithBusyRetry(
|
|
80
|
+
database: InternalStorageDatabase,
|
|
81
|
+
sql: string,
|
|
82
|
+
timeoutMs = SQLITE_INIT_TIMEOUT_MS,
|
|
83
|
+
): void {
|
|
84
|
+
const deadline = Date.now() + timeoutMs;
|
|
85
|
+
while (true) {
|
|
86
|
+
try {
|
|
87
|
+
database.exec(sql);
|
|
88
|
+
return;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (!isSqliteBusy(error) || Date.now() >= deadline) throw error;
|
|
91
|
+
Atomics.wait(SQLITE_INIT_SLEEP, 0, 0, Math.min(SQLITE_INIT_RETRY_MS, deadline - Date.now()));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function initializeDatabase(database: InternalStorageDatabase): void {
|
|
71
97
|
// busy_timeout FIRST. Switching to WAL needs a brief exclusive lock, so when
|
|
72
98
|
// two processes open the same database at the same moment — the node daemon
|
|
73
99
|
// and an adapter, or two MCP servers — one of them hits SQLITE_BUSY. With the
|
|
74
100
|
// timeout configured afterwards there was no retry budget in effect for the
|
|
75
|
-
// statement that needed it most
|
|
76
|
-
//
|
|
77
|
-
//
|
|
101
|
+
// statement that needed it most. Older Bun releases can still surface
|
|
102
|
+
// SQLITE_BUSY immediately for journal_mode, so keep a bounded host-level
|
|
103
|
+
// retry around that one exclusive transition as well.
|
|
78
104
|
database.exec("PRAGMA busy_timeout = 5000");
|
|
79
|
-
database
|
|
105
|
+
execWithBusyRetry(database, "PRAGMA journal_mode = WAL");
|
|
80
106
|
database.exec("PRAGMA foreign_keys = ON");
|
|
81
107
|
database.exec("PRAGMA wal_autocheckpoint = 1000");
|
|
82
108
|
try {
|
|
@@ -143,6 +143,33 @@ export function vaultListWithValues(userId: string): VaultEntryWithValue[] {
|
|
|
143
143
|
}));
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Return only rows that can still be authenticated with the active master key.
|
|
148
|
+
*
|
|
149
|
+
* This is intentionally limited to redaction indexes: one damaged credential
|
|
150
|
+
* must not disable unrelated tools, while direct access to that credential
|
|
151
|
+
* continues to fail closed through vaultGetValue().
|
|
152
|
+
*/
|
|
153
|
+
export function vaultListDecryptableValues(userId: string): VaultEntryWithValue[] {
|
|
154
|
+
const rows = activeVaultDatabase()
|
|
155
|
+
.prepare("SELECT key, description, value FROM vault WHERE user_id = ? ORDER BY key")
|
|
156
|
+
.all(userId) as VaultEntryWithValue[];
|
|
157
|
+
const entries: VaultEntryWithValue[] = [];
|
|
158
|
+
for (const row of rows) {
|
|
159
|
+
try {
|
|
160
|
+
entries.push({
|
|
161
|
+
key: row.key,
|
|
162
|
+
description: row.description,
|
|
163
|
+
value: decryptRow(userId, row.key, row.value),
|
|
164
|
+
});
|
|
165
|
+
} catch {
|
|
166
|
+
// A value that cannot be authenticated cannot be exposed by substitution,
|
|
167
|
+
// so there is no plaintext form available to add to the redaction index.
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return entries;
|
|
171
|
+
}
|
|
172
|
+
|
|
146
173
|
export function vaultSet(userId: string, key: string, value: string, description = ""): void {
|
|
147
174
|
const normalizedKey = normalizeVaultKey(key);
|
|
148
175
|
activeVaultDatabase()
|
|
@@ -203,10 +230,11 @@ export interface VaultSubstitutionResult {
|
|
|
203
230
|
|
|
204
231
|
/** Replace {{KEY}} placeholders and report which credentials were consumed. */
|
|
205
232
|
export function vaultSubstituteDetailed(userId: string, text: string): VaultSubstitutionResult {
|
|
206
|
-
const entries = new Map
|
|
233
|
+
const entries = new Map<string, string | undefined>();
|
|
207
234
|
const usedKeys = new Set<string>();
|
|
208
235
|
const substituted = text.replace(/\{\{([^}]+)\}\}/g, (match, rawKey: string) => {
|
|
209
236
|
const key = normalizeVaultKey(rawKey);
|
|
237
|
+
if (!entries.has(key)) entries.set(key, vaultGetValue(userId, key));
|
|
210
238
|
const value = entries.get(key);
|
|
211
239
|
if (value === undefined) return match;
|
|
212
240
|
usedKeys.add(key);
|
|
@@ -248,7 +276,7 @@ function encodedSecretForms(value: string): string[] {
|
|
|
248
276
|
|
|
249
277
|
/** Scrub raw and common encoded forms before tool output reaches a model. */
|
|
250
278
|
export function redactVaultSecrets(userId: string, text: string): string {
|
|
251
|
-
const candidates =
|
|
279
|
+
const candidates = vaultListDecryptableValues(userId)
|
|
252
280
|
.flatMap((entry) => encodedSecretForms(entry.value).map((form) => ({ form, key: entry.key })))
|
|
253
281
|
.sort((a, b) => b.form.length - a.form.length || a.key.localeCompare(b.key));
|
|
254
282
|
if (candidates.length === 0) return text;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
11
11
|
import { mkdirSync, rmSync, unlinkSync } from "node:fs";
|
|
12
|
-
import { cleanupAgentFork, type ForkHandle } from "#agents/fork";
|
|
12
|
+
import { cleanupAgentFork, type ForkHandle, forkAgentSession } from "#agents/fork";
|
|
13
13
|
import { resolveCompactionExecution, resolveModelForAgent } from "#agents/model-catalog";
|
|
14
14
|
import { getRegistry, getRegistryOperations } from "#agents/registry";
|
|
15
15
|
import { WsHub } from "#bus";
|
|
@@ -26,6 +26,7 @@ import { getApiTopicConfig, setApiTopicConfig } from "#storage/api-topic-config"
|
|
|
26
26
|
import {
|
|
27
27
|
findTopicTitleConflict,
|
|
28
28
|
getTopic,
|
|
29
|
+
getTopicSessionId,
|
|
29
30
|
inferTopicKind,
|
|
30
31
|
isTopicVisible,
|
|
31
32
|
listTopics,
|
|
@@ -312,6 +313,11 @@ async function createDerivedTopicImpl(
|
|
|
312
313
|
(subagent?.agent ? undefined : sourceConfig?.model) ??
|
|
313
314
|
derived.defaultModel;
|
|
314
315
|
const rolloutModel = resolveModelForAgent(agent, requestedRolloutModel, registry);
|
|
316
|
+
const sourceRolloutModel = resolveModelForAgent(
|
|
317
|
+
agent,
|
|
318
|
+
sourceConfig?.model ?? topic.defaultModel,
|
|
319
|
+
registry,
|
|
320
|
+
);
|
|
315
321
|
const requestedRolloutEffort = subagent?.agent
|
|
316
322
|
? registry.defaultEffort
|
|
317
323
|
: (sourceConfig?.effort ?? derived.defaultEffort);
|
|
@@ -323,7 +329,37 @@ async function createDerivedTopicImpl(
|
|
|
323
329
|
|
|
324
330
|
if (copyHistory) {
|
|
325
331
|
if (!forkSnapshot) throw new Error("fork snapshot was not captured");
|
|
326
|
-
const
|
|
332
|
+
const parentSessionId = getTopicSessionId(sourceTopicId);
|
|
333
|
+
const cachePreservingNativeFork =
|
|
334
|
+
(agent === "codex" || agent === "maestro") && sourceRolloutModel === rolloutModel;
|
|
335
|
+
if (cachePreservingNativeFork && parentSessionId) {
|
|
336
|
+
try {
|
|
337
|
+
rollbackHandle = await forkAgentSession({
|
|
338
|
+
agent,
|
|
339
|
+
parentSessionId,
|
|
340
|
+
cwd,
|
|
341
|
+
userId,
|
|
342
|
+
topicName: topic.title,
|
|
343
|
+
title,
|
|
344
|
+
model: rolloutModel,
|
|
345
|
+
...(rolloutEffort ? { effort: rolloutEffort } : {}),
|
|
346
|
+
});
|
|
347
|
+
sessionId = rollbackHandle.forkId;
|
|
348
|
+
logger.info(
|
|
349
|
+
{ sourceTopicId, derivedTopicId: derived.id, parentSessionId, sessionId },
|
|
350
|
+
"createDerivedTopic: native provider fork materialized",
|
|
351
|
+
);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
logger.warn(
|
|
354
|
+
{ err: error, sourceTopicId, derivedTopicId: derived.id, parentSessionId },
|
|
355
|
+
"createDerivedTopic: native provider fork failed; using snapshot fallback",
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Successful native forks retain the exact provider prefix. Once that
|
|
360
|
+
// path is unavailable, cache continuity is already lost; keep a small
|
|
361
|
+
// snapshot verbatim and compact only an oversized fallback.
|
|
362
|
+
const compactionRequired = !sessionId && shouldCompactForkEntries(forkSnapshot.entries);
|
|
327
363
|
if (compactionRequired) {
|
|
328
364
|
try {
|
|
329
365
|
compactedForkEntries = await createCompactedRolloutEntries(
|
|
@@ -9,7 +9,10 @@ import { rmSync } from "node:fs";
|
|
|
9
9
|
import { runArchiverTurn } from "#agents/archiver";
|
|
10
10
|
import { cancelIdleArchiveForTopic } from "#agents/idle-archiver";
|
|
11
11
|
import { cancelSubagentWatchForDeletedTopic } from "#agents/mcp-tools/spawn-subagent";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
MIN_MEMORY_ARCHIVE_EXCHANGES,
|
|
14
|
+
meetsMemoryArchiveExchangeThreshold,
|
|
15
|
+
} from "#agents/memory-archive-policy";
|
|
13
16
|
import { type PurgeSessionRef, purgeTopicLogs } from "#agents/topic-cleanup";
|
|
14
17
|
import { WsHub } from "#bus";
|
|
15
18
|
import { killBgBash } from "#platform/background-bash/manager";
|
|
@@ -238,7 +241,14 @@ async function deleteTopicCascadeImpl(
|
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
243
|
|
|
241
|
-
if (
|
|
244
|
+
if (
|
|
245
|
+
archived &&
|
|
246
|
+
meetsMemoryArchiveExchangeThreshold(
|
|
247
|
+
archived.exchangeCount,
|
|
248
|
+
MIN_MEMORY_ARCHIVE_EXCHANGES,
|
|
249
|
+
topic,
|
|
250
|
+
)
|
|
251
|
+
) {
|
|
242
252
|
try {
|
|
243
253
|
const memoryTopic = getTopicMemoryOrigin(topicId) ?? topic;
|
|
244
254
|
runArchiverTurn({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const NEGOTIUM_VERSION = "0.2.
|
|
1
|
+
export const NEGOTIUM_VERSION = "0.2.4";
|
package/dist/runtime-helpers.js
CHANGED
|
@@ -695,9 +695,29 @@ function defaultDataDir() {
|
|
|
695
695
|
function defaultSessionsDatabasePath() {
|
|
696
696
|
return envPath("SESSIONS_DB_PATH", join2(resolveStorageDataDir(), "sessions.db"));
|
|
697
697
|
}
|
|
698
|
+
var SQLITE_INIT_RETRY_MS = 25;
|
|
699
|
+
var SQLITE_INIT_TIMEOUT_MS = 5000;
|
|
700
|
+
var SQLITE_INIT_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
701
|
+
function isSqliteBusy(error) {
|
|
702
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
703
|
+
return /database is (?:locked|busy)|SQLITE_(?:BUSY|LOCKED)/i.test(message);
|
|
704
|
+
}
|
|
705
|
+
function execWithBusyRetry(database, sql, timeoutMs = SQLITE_INIT_TIMEOUT_MS) {
|
|
706
|
+
const deadline = Date.now() + timeoutMs;
|
|
707
|
+
while (true) {
|
|
708
|
+
try {
|
|
709
|
+
database.exec(sql);
|
|
710
|
+
return;
|
|
711
|
+
} catch (error) {
|
|
712
|
+
if (!isSqliteBusy(error) || Date.now() >= deadline)
|
|
713
|
+
throw error;
|
|
714
|
+
Atomics.wait(SQLITE_INIT_SLEEP, 0, 0, Math.min(SQLITE_INIT_RETRY_MS, deadline - Date.now()));
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
698
718
|
function initializeDatabase(database) {
|
|
699
719
|
database.exec("PRAGMA busy_timeout = 5000");
|
|
700
|
-
database
|
|
720
|
+
execWithBusyRetry(database, "PRAGMA journal_mode = WAL");
|
|
701
721
|
database.exec("PRAGMA foreign_keys = ON");
|
|
702
722
|
database.exec("PRAGMA wal_autocheckpoint = 1000");
|
|
703
723
|
try {
|
|
@@ -1114,4 +1134,4 @@ export {
|
|
|
1114
1134
|
CLAUDE_EFFORT_VALUES
|
|
1115
1135
|
};
|
|
1116
1136
|
|
|
1117
|
-
//# debugId=
|
|
1137
|
+
//# debugId=16168DE340D196C364756E2164756E21
|