negotium 0.2.18 → 0.2.20
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 +367 -313
- package/dist/agent-helpers.js.map +18 -18
- package/dist/background-bash.js +3 -2
- package/dist/background-bash.js.map +3 -3
- package/dist/browser-runtime.js +60 -36
- package/dist/browser-runtime.js.map +6 -6
- package/dist/{chunk-fc58cqry.js → chunk-g2kqfdwm.js} +154 -24
- package/dist/{chunk-fc58cqry.js.map → chunk-g2kqfdwm.js.map} +7 -6
- package/dist/hosted-agent.js +183 -53
- package/dist/hosted-agent.js.map +8 -7
- package/dist/main.js +1395 -626
- package/dist/main.js.map +27 -26
- package/dist/mcp-factories.js +1204 -624
- package/dist/mcp-factories.js.map +21 -20
- package/dist/prompts.js +3 -2
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +47 -26
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/archiver.ts +4 -3
- package/dist/runtime/src/application/switch-topic-access-mode.ts +81 -8
- package/dist/runtime/src/bus.ts +19 -2
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +13 -14
- package/dist/runtime/src/mcp/session-comm/runtime.ts +16 -0
- package/dist/runtime/src/mcp/wiki-search-index.ts +359 -0
- package/dist/runtime/src/mcp/wiki-server.ts +559 -98
- package/dist/runtime/src/platform/config.ts +13 -1
- package/dist/runtime/src/platform/mcp-config.ts +1 -1
- package/dist/runtime/src/prompts/agents/wiki-archiver.md +62 -47
- package/dist/runtime/src/runtime/ask-callbacks.ts +19 -11
- package/dist/runtime/src/runtime/background-sessions.ts +9 -7
- package/dist/runtime/src/runtime/visual-store.ts +31 -23
- package/dist/runtime/src/storage/api-topics.ts +26 -0
- package/dist/runtime/src/storage/browser-profiles.ts +16 -8
- package/dist/runtime/src/storage/runtime-events.ts +30 -20
- package/dist/runtime/src/storage/runtime-gateway-submissions.ts +24 -16
- package/dist/runtime/src/storage/runtime-turn-requests.ts +9 -1
- package/dist/runtime/src/storage/self-schedules.ts +32 -24
- package/dist/runtime/src/storage/storage-host.ts +105 -43
- package/dist/runtime/src/storage/vault.ts +12 -3
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +47 -26
- package/dist/runtime-helpers.js.map +4 -4
- package/dist/storage.js +76 -41
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/agents/archiver.d.ts +1 -1
- package/dist/types/packages/core/src/mcp/wiki-search-index.d.ts +59 -0
- package/dist/types/packages/core/src/storage/api-topics.d.ts +15 -0
- package/dist/types/packages/core/src/storage/storage-host.d.ts +10 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +140 -10
- package/dist/vault.js.map +6 -5
- package/package.json +1 -1
|
@@ -73,7 +73,7 @@ export interface ArchiverRuntime {
|
|
|
73
73
|
export declare function createArchiverRuntime(host: ArchiverHost): ArchiverRuntime;
|
|
74
74
|
/**
|
|
75
75
|
* Locate the summary the archiver turn just wrote. The wiki MCP's
|
|
76
|
-
* `
|
|
76
|
+
* `wiki_write(kind="summary")` writes `summaries/<date>-<title>[~N].md`.
|
|
77
77
|
*/
|
|
78
78
|
export declare function findSummaryFile(storage: ArchiverStorageHost, topicTitle: string, date: string, sinceMs: number, topicId?: string): string | null;
|
|
79
79
|
export declare function runArchiverTurn(params: RunArchiverTurnParams): boolean;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type IndexedWikiKind = "article" | "summary";
|
|
2
|
+
export interface WikiSearchIndexSource {
|
|
3
|
+
kind: IndexedWikiKind;
|
|
4
|
+
key: string;
|
|
5
|
+
path: string;
|
|
6
|
+
mtimeMs: number;
|
|
7
|
+
size: number;
|
|
8
|
+
}
|
|
9
|
+
export interface PreparedWikiSearchDocument {
|
|
10
|
+
title: string;
|
|
11
|
+
text: string;
|
|
12
|
+
tokens: string[];
|
|
13
|
+
date?: string;
|
|
14
|
+
family?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface WikiSearchIndexDocument extends PreparedWikiSearchDocument {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: IndexedWikiKind;
|
|
19
|
+
key: string;
|
|
20
|
+
path: string;
|
|
21
|
+
}
|
|
22
|
+
export interface WikiSearchIndexMetadata {
|
|
23
|
+
id: string;
|
|
24
|
+
kind: IndexedWikiKind;
|
|
25
|
+
key: string;
|
|
26
|
+
title: string;
|
|
27
|
+
date?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface WikiSummaryTemporalQuery {
|
|
30
|
+
year?: string;
|
|
31
|
+
month?: string;
|
|
32
|
+
direction: "latest" | "oldest";
|
|
33
|
+
limit: number;
|
|
34
|
+
}
|
|
35
|
+
export interface WikiSearchIndexSyncResult {
|
|
36
|
+
added: number;
|
|
37
|
+
updated: number;
|
|
38
|
+
removed: number;
|
|
39
|
+
}
|
|
40
|
+
export declare class WikiSearchIndex {
|
|
41
|
+
#private;
|
|
42
|
+
readonly path: string;
|
|
43
|
+
constructor(path: string);
|
|
44
|
+
close(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Record one document that was just written.
|
|
47
|
+
*
|
|
48
|
+
* The write path already holds the document text, so the index is maintained
|
|
49
|
+
* incrementally and never needs to scan the content directories. `sync` stays
|
|
50
|
+
* for the explicit backfill of documents that predate the write tool.
|
|
51
|
+
*/
|
|
52
|
+
upsert(source: WikiSearchIndexSource, document: PreparedWikiSearchDocument): void;
|
|
53
|
+
sync(sources: WikiSearchIndexSource[], prepare: (source: WikiSearchIndexSource, text: string) => PreparedWikiSearchDocument): WikiSearchIndexSyncResult;
|
|
54
|
+
metadata(kinds: IndexedWikiKind[]): WikiSearchIndexMetadata[];
|
|
55
|
+
summaryMetadataByDate(query: WikiSummaryTemporalQuery): WikiSearchIndexMetadata[];
|
|
56
|
+
matchingDocumentIds(kinds: IndexedWikiKind[], terms: string[]): Set<string>;
|
|
57
|
+
documents(ids: Set<string>): WikiSearchIndexDocument[];
|
|
58
|
+
}
|
|
59
|
+
export declare function resetCorruptWikiSearchIndex(path: string): void;
|
|
@@ -63,6 +63,21 @@ export declare function normalizeTopicState(input: {
|
|
|
63
63
|
agent?: AgentKind;
|
|
64
64
|
};
|
|
65
65
|
export declare function upsertTopic(t: TopicDto): void;
|
|
66
|
+
/**
|
|
67
|
+
* Apply one access mode to a set of topics as a single all-or-nothing write.
|
|
68
|
+
*
|
|
69
|
+
* A partial write is not a cosmetic glitch here: a public parent left with
|
|
70
|
+
* private subagent children (or the reverse) is exactly the half-exposed state
|
|
71
|
+
* the access-mode cascade exists to prevent, so every row commits or none do.
|
|
72
|
+
*
|
|
73
|
+
* Deliberately a narrow UPDATE instead of a loop over {@link upsertTopic}.
|
|
74
|
+
* That helper opens its own transaction, and the node:sqlite shim in
|
|
75
|
+
* `sqlite.ts` emulates transactions with bare BEGIN/COMMIT rather than
|
|
76
|
+
* savepoints — nesting one inside an outer transaction would fail outright.
|
|
77
|
+
* It also rewrites participants and browser-profile ownership, none of which
|
|
78
|
+
* an access-mode change should touch.
|
|
79
|
+
*/
|
|
80
|
+
export declare function setTopicAccessModes(topicIds: readonly string[], accessMode: TopicAccessMode): void;
|
|
66
81
|
export declare function listTopics(): TopicDto[];
|
|
67
82
|
export declare function getTopic(id: string): TopicDto | null;
|
|
68
83
|
/** Return the private manager room owned by a user, excluding the retired shared General row. */
|
|
@@ -5,6 +5,16 @@ type InternalStorageDatabase = InstanceType<typeof Database>;
|
|
|
5
5
|
type StorageSchemaInitializer = (database: InternalStorageDatabase) => void;
|
|
6
6
|
export declare function initializeDatabase(database: InternalStorageDatabase): void;
|
|
7
7
|
export declare function resolveStorageDatabase(): InternalStorageDatabase;
|
|
8
|
+
/**
|
|
9
|
+
* The host-injected connection, or null when Negotium owns its own store.
|
|
10
|
+
*
|
|
11
|
+
* Unlike {@link resolveStorageDatabase} this never opens anything. Callers that
|
|
12
|
+
* manage their own short-lived connections need to know whether a host store
|
|
13
|
+
* exists *before* deciding to open one by path: opening it anyway is how an
|
|
14
|
+
* embedded Negotium ends up writing half its state into the host's database and
|
|
15
|
+
* the other half into `~/.negotium`, with nothing reporting an error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function configuredStorageDatabase(): InternalStorageDatabase | null;
|
|
8
18
|
export declare function resolveStorageDataDir(): string;
|
|
9
19
|
export declare function resolveStorageLogDir(): string;
|
|
10
20
|
export declare function resolveStorageSessionAsksDir(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const NEGOTIUM_VERSION = "0.2.
|
|
1
|
+
export declare const NEGOTIUM_VERSION = "0.2.20";
|
package/dist/vault.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
4
|
// ../../packages/core/src/storage/vault.ts
|
|
5
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
6
|
-
import { join as
|
|
5
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
6
|
+
import { join as join3 } from "path";
|
|
7
7
|
|
|
8
8
|
// ../../packages/core/src/platform/config.ts
|
|
9
9
|
import { execFileSync } from "child_process";
|
|
@@ -125,11 +125,12 @@ function versionAtLeast(actualVersion, minimumVersion) {
|
|
|
125
125
|
}
|
|
126
126
|
return true;
|
|
127
127
|
}
|
|
128
|
+
var BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000;
|
|
128
129
|
function browserRsMeetsMinimumVersion(candidate) {
|
|
129
130
|
try {
|
|
130
131
|
const output = execFileSync(candidate, ["--version"], {
|
|
131
132
|
encoding: "utf8",
|
|
132
|
-
timeout:
|
|
133
|
+
timeout: BROWSER_RS_VERSION_PROBE_TIMEOUT_MS,
|
|
133
134
|
stdio: ["ignore", "pipe", "ignore"]
|
|
134
135
|
}).trim();
|
|
135
136
|
const match = output.match(/^browser-rs (\d+)\.(\d+)\.(\d+)$/);
|
|
@@ -340,6 +341,134 @@ if (isBun) {
|
|
|
340
341
|
Database = NodeDatabase;
|
|
341
342
|
}
|
|
342
343
|
|
|
344
|
+
// ../../packages/core/src/storage/storage-host.ts
|
|
345
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
346
|
+
import { homedir as homedir2 } from "os";
|
|
347
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
348
|
+
var STORAGE_HOST_STATE = Symbol.for("negotium.storage-host.state.v1");
|
|
349
|
+
function storageState() {
|
|
350
|
+
const holder = globalThis;
|
|
351
|
+
const existing = holder[STORAGE_HOST_STATE];
|
|
352
|
+
if (existing)
|
|
353
|
+
return existing;
|
|
354
|
+
const created = {
|
|
355
|
+
configuredHost: {},
|
|
356
|
+
fallbackDatabase: null,
|
|
357
|
+
fallbackDatabasePath: null,
|
|
358
|
+
frames: [],
|
|
359
|
+
schemaInitializers: [],
|
|
360
|
+
initializedSchemas: new WeakMap,
|
|
361
|
+
initializingDatabases: new WeakSet
|
|
362
|
+
};
|
|
363
|
+
Object.defineProperty(holder, STORAGE_HOST_STATE, {
|
|
364
|
+
value: created,
|
|
365
|
+
enumerable: false,
|
|
366
|
+
writable: false,
|
|
367
|
+
configurable: false
|
|
368
|
+
});
|
|
369
|
+
return created;
|
|
370
|
+
}
|
|
371
|
+
function envPath(name, fallback) {
|
|
372
|
+
const value = process.env[name]?.trim();
|
|
373
|
+
return resolve2(value || fallback);
|
|
374
|
+
}
|
|
375
|
+
function defaultStateDir() {
|
|
376
|
+
return envPath("NEGOTIUM_STATE_DIR", join2(homedir2(), ".negotium"));
|
|
377
|
+
}
|
|
378
|
+
function defaultDataDir() {
|
|
379
|
+
return envPath("NEGOTIUM_DATA_DIR", join2(defaultStateDir(), "data"));
|
|
380
|
+
}
|
|
381
|
+
function defaultSessionsDatabasePath() {
|
|
382
|
+
return envPath("SESSIONS_DB_PATH", join2(resolveStorageDataDir(), "sessions.db"));
|
|
383
|
+
}
|
|
384
|
+
var SQLITE_INIT_RETRY_MS = 25;
|
|
385
|
+
var SQLITE_INIT_TIMEOUT_MS = 5000;
|
|
386
|
+
var SQLITE_INIT_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
387
|
+
function isSqliteBusy(error) {
|
|
388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
389
|
+
return /database is (?:locked|busy)|SQLITE_(?:BUSY|LOCKED)/i.test(message);
|
|
390
|
+
}
|
|
391
|
+
function execWithBusyRetry(database, sql, timeoutMs = SQLITE_INIT_TIMEOUT_MS) {
|
|
392
|
+
const deadline = Date.now() + timeoutMs;
|
|
393
|
+
while (true) {
|
|
394
|
+
try {
|
|
395
|
+
database.exec(sql);
|
|
396
|
+
return;
|
|
397
|
+
} catch (error) {
|
|
398
|
+
if (!isSqliteBusy(error) || Date.now() >= deadline)
|
|
399
|
+
throw error;
|
|
400
|
+
Atomics.wait(SQLITE_INIT_SLEEP, 0, 0, Math.min(SQLITE_INIT_RETRY_MS, deadline - Date.now()));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function initializeDatabase(database) {
|
|
405
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
406
|
+
execWithBusyRetry(database, "PRAGMA journal_mode = WAL");
|
|
407
|
+
database.exec("PRAGMA foreign_keys = ON");
|
|
408
|
+
database.exec("PRAGMA wal_autocheckpoint = 1000");
|
|
409
|
+
try {
|
|
410
|
+
database.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
411
|
+
} catch {}
|
|
412
|
+
}
|
|
413
|
+
function defaultDatabase() {
|
|
414
|
+
const path = defaultSessionsDatabasePath();
|
|
415
|
+
const state = storageState();
|
|
416
|
+
if (state.fallbackDatabase && state.fallbackDatabasePath === path)
|
|
417
|
+
return state.fallbackDatabase;
|
|
418
|
+
if (state.fallbackDatabase)
|
|
419
|
+
state.fallbackDatabase.close();
|
|
420
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
421
|
+
state.fallbackDatabase = new Database(path, { create: true });
|
|
422
|
+
state.fallbackDatabasePath = path;
|
|
423
|
+
initializeDatabase(state.fallbackDatabase);
|
|
424
|
+
return state.fallbackDatabase;
|
|
425
|
+
}
|
|
426
|
+
function resolveStorageDatabase() {
|
|
427
|
+
return storageState().configuredHost.database ?? defaultDatabase();
|
|
428
|
+
}
|
|
429
|
+
function resolveStorageDataDir() {
|
|
430
|
+
return storageState().configuredHost.dataDir ?? defaultDataDir();
|
|
431
|
+
}
|
|
432
|
+
function ensureStorageSchemas(database = resolveStorageDatabase()) {
|
|
433
|
+
const state = storageState();
|
|
434
|
+
if (state.initializingDatabases.has(database))
|
|
435
|
+
return;
|
|
436
|
+
let initialized = state.initializedSchemas.get(database);
|
|
437
|
+
if (!initialized) {
|
|
438
|
+
initialized = new Set;
|
|
439
|
+
state.initializedSchemas.set(database, initialized);
|
|
440
|
+
}
|
|
441
|
+
state.initializingDatabases.add(database);
|
|
442
|
+
try {
|
|
443
|
+
for (const entry of state.schemaInitializers) {
|
|
444
|
+
if (initialized.has(entry.initialize))
|
|
445
|
+
continue;
|
|
446
|
+
initialized.add(entry.initialize);
|
|
447
|
+
try {
|
|
448
|
+
entry.initialize(database);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
initialized.delete(entry.initialize);
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} finally {
|
|
455
|
+
state.initializingDatabases.delete(database);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
var internalStorageDatabase = new Proxy({}, {
|
|
459
|
+
get(_target, property) {
|
|
460
|
+
const database = resolveStorageDatabase();
|
|
461
|
+
ensureStorageSchemas(database);
|
|
462
|
+
const value = Reflect.get(database, property, database);
|
|
463
|
+
return typeof value === "function" ? value.bind(database) : value;
|
|
464
|
+
},
|
|
465
|
+
set(_target, property, value) {
|
|
466
|
+
const database = resolveStorageDatabase();
|
|
467
|
+
ensureStorageSchemas(database);
|
|
468
|
+
return Reflect.set(database, property, value, database);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
343
472
|
// ../../packages/core/src/storage/vault-crypto-core.ts
|
|
344
473
|
import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes2 } from "crypto";
|
|
345
474
|
var ENVELOPE_PREFIX = "otium-vault:v1:";
|
|
@@ -429,17 +558,18 @@ function initializeVaultDatabase(database) {
|
|
|
429
558
|
}
|
|
430
559
|
}
|
|
431
560
|
function openVaultDatabase(dataDir) {
|
|
432
|
-
const vaultDir =
|
|
433
|
-
const path =
|
|
434
|
-
|
|
561
|
+
const vaultDir = join3(dataDir, "vault");
|
|
562
|
+
const path = join3(vaultDir, "vault.db");
|
|
563
|
+
mkdirSync3(vaultDir, { recursive: true, mode: 448 });
|
|
435
564
|
const database = new Database(path, { create: true });
|
|
436
565
|
chmodSync2(path, 384);
|
|
437
566
|
initializeVaultDatabase(database);
|
|
438
567
|
return database;
|
|
439
568
|
}
|
|
440
569
|
function activeVaultDatabase() {
|
|
441
|
-
if (!vaultDb)
|
|
442
|
-
vaultDb = openVaultDatabase(
|
|
570
|
+
if (!vaultDb) {
|
|
571
|
+
vaultDb = openVaultDatabase(resolveStorageDataDir());
|
|
572
|
+
}
|
|
443
573
|
return vaultDb;
|
|
444
574
|
}
|
|
445
575
|
function configureVaultStorage(options) {
|
|
@@ -448,7 +578,7 @@ function configureVaultStorage(options) {
|
|
|
448
578
|
}
|
|
449
579
|
const previousDb = vaultDb;
|
|
450
580
|
const previousMasterKey = vaultMasterKey;
|
|
451
|
-
const configuredDb = options.database ?? openVaultDatabase(options.dataDir ??
|
|
581
|
+
const configuredDb = options.database ?? openVaultDatabase(options.dataDir ?? resolveStorageDataDir());
|
|
452
582
|
if (options.database)
|
|
453
583
|
initializeVaultDatabase(configuredDb);
|
|
454
584
|
vaultDb = configuredDb;
|
|
@@ -626,4 +756,4 @@ export {
|
|
|
626
756
|
VAULT_DESCRIPTION_MAX_LENGTH
|
|
627
757
|
};
|
|
628
758
|
|
|
629
|
-
//# debugId=
|
|
759
|
+
//# debugId=E210ECA559CC5E1164756E2164756E21
|