negotium 0.19.0 → 0.19.1

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.
@@ -3099,6 +3099,13 @@ function parseJsonlText(raw) {
3099
3099
  return raw.trim().split(`
3100
3100
  `).filter(Boolean).map((line) => JSON.parse(line));
3101
3101
  }
3102
+ function readJsonFile(filePath) {
3103
+ try {
3104
+ return JSON.parse(readFileSync2(filePath, "utf-8"));
3105
+ } catch {
3106
+ return null;
3107
+ }
3108
+ }
3102
3109
  function lockStaleMs() {
3103
3110
  const raw = Number.parseInt(process.env.NEGOTIUM_JSONL_LOCK_STALE_MS ?? "", 10);
3104
3111
  return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LOCK_STALE_MS;
@@ -3962,7 +3969,7 @@ var init_codex = __esm(async () => {
3962
3969
  });
3963
3970
 
3964
3971
  // ../../packages/core/src/version.ts
3965
- var NEGOTIUM_VERSION = "0.19.0";
3972
+ var NEGOTIUM_VERSION = "0.19.1";
3966
3973
 
3967
3974
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3968
3975
  import { spawn as spawn2 } from "child_process";
@@ -14952,15 +14959,84 @@ var init_derive = __esm(async () => {
14952
14959
  };
14953
14960
  });
14954
14961
 
14962
+ // ../../packages/core/src/query/state.ts
14963
+ import { mkdirSync as mkdirSync15, renameSync as renameSync7, unlinkSync as unlinkSync14, writeFileSync as writeFileSync13 } from "fs";
14964
+ import { basename as basename4, join as join24 } from "path";
14965
+ function createQueryStateStore(options) {
14966
+ const sanitize = options.sanitizeTopicId ?? sanitizeId;
14967
+ const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
14968
+ const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
14969
+ const legacyQueryStateFile = (userId, topicName) => {
14970
+ if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
14971
+ return null;
14972
+ }
14973
+ return join24(queryStateDirPath(userId), `${topicName}.json`);
14974
+ };
14975
+ return {
14976
+ write(userId, topicId, topicName, task) {
14977
+ const dir = queryStateDirPath(userId);
14978
+ mkdirSync15(dir, { recursive: true });
14979
+ const state = { topicId, topicName, since: new Date().toISOString() };
14980
+ if (task)
14981
+ state.task = [...task.replace(/\n+/g, " ").trim()].slice(0, 100).join("");
14982
+ const target = queryStateFile(userId, topicId);
14983
+ const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
14984
+ writeFileSync13(tmp, JSON.stringify(state));
14985
+ renameSync7(tmp, target);
14986
+ },
14987
+ clear(userId, topicId, legacyTopicName) {
14988
+ const paths = [
14989
+ queryStateFile(userId, topicId),
14990
+ legacyQueryStateFile(userId, legacyTopicName)
14991
+ ].filter((path) => Boolean(path));
14992
+ for (const path of new Set(paths)) {
14993
+ try {
14994
+ unlinkSync14(path);
14995
+ } catch (error) {
14996
+ if (error?.code !== "ENOENT") {
14997
+ options.logger?.warn({ err: error, userId, topicId, path }, "Failed to clear query state file");
14998
+ }
14999
+ }
15000
+ }
15001
+ },
15002
+ hasActive(userId, topicId) {
15003
+ const state = readJsonFile(queryStateFile(userId, topicId));
15004
+ if (!state)
15005
+ return false;
15006
+ const sinceMs = new Date(state.since).getTime();
15007
+ return Date.now() - sinceMs <= ACTIVE_QUERY_STALE_MS;
15008
+ }
15009
+ };
15010
+ }
15011
+ function writeQueryState(userId, topicId, topicName, task) {
15012
+ defaultQueryStateStore.write(userId, topicId, topicName, task);
15013
+ }
15014
+ function clearQueryState(userId, topicId, legacyTopicName) {
15015
+ defaultQueryStateStore.clear(userId, topicId, legacyTopicName);
15016
+ }
15017
+ function hasActiveQuery(userId, topicId) {
15018
+ return defaultQueryStateStore.hasActive(userId, topicId);
15019
+ }
15020
+ var defaultQueryStateStore;
15021
+ var init_state = __esm(() => {
15022
+ init_config();
15023
+ init_jsonl();
15024
+ init_logger();
15025
+ defaultQueryStateStore = createQueryStateStore({
15026
+ usersLogDir: USERS_LOG_DIR,
15027
+ logger
15028
+ });
15029
+ });
15030
+
14955
15031
  // ../../packages/core/src/query/session-inbox-path.ts
14956
- import { join as join24 } from "path";
15032
+ import { join as join25 } from "path";
14957
15033
  function sessionInboxPath(userId, topicId) {
14958
15034
  const key = Buffer.from(topicId, "utf8").toString("base64url");
14959
- return join24(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
15035
+ return join25(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
14960
15036
  }
14961
15037
  function scheduledSessionInboxPath(userId, topicId) {
14962
15038
  const key = Buffer.from(topicId, "utf8").toString("base64url");
14963
- return join24(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
15039
+ return join25(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
14964
15040
  }
14965
15041
  var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
14966
15042
  var init_session_inbox_path = __esm(() => {
@@ -14968,12 +15044,12 @@ var init_session_inbox_path = __esm(() => {
14968
15044
  });
14969
15045
 
14970
15046
  // ../../packages/core/src/storage/session-inbox-signal.ts
14971
- import { join as join25 } from "path";
15047
+ import { join as join26 } from "path";
14972
15048
  var SESSION_INBOX_WAKE_FILE, listeners;
14973
15049
  var init_session_inbox_signal = __esm(() => {
14974
15050
  init_config();
14975
15051
  init_logger();
14976
- SESSION_INBOX_WAKE_FILE = join25(SESSION_INBOX_DIR, ".wake");
15052
+ SESSION_INBOX_WAKE_FILE = join26(SESSION_INBOX_DIR, ".wake");
14977
15053
  listeners = new Set;
14978
15054
  });
14979
15055
 
@@ -15010,14 +15086,14 @@ var init_session_inbox = __esm(async () => {
15010
15086
  });
15011
15087
 
15012
15088
  // ../../packages/core/src/query/session-inbox-cleanup.ts
15013
- import { unlinkSync as unlinkSync14 } from "fs";
15014
- import { basename as basename4, join as join26 } from "path";
15089
+ import { unlinkSync as unlinkSync15 } from "fs";
15090
+ import { basename as basename5, join as join27 } from "path";
15015
15091
  function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
15016
15092
  const live = sessionInboxPath(userId, topicId);
15017
15093
  const scheduled = scheduledSessionInboxPath(userId, topicId);
15018
15094
  const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
15019
- if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename4(legacyTopicTitle) === legacyTopicTitle) {
15020
- const legacyBase = join26(SESSION_INBOX_DIR, userId, legacyTopicTitle);
15095
+ if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename5(legacyTopicTitle) === legacyTopicTitle) {
15096
+ const legacyBase = join27(SESSION_INBOX_DIR, userId, legacyTopicTitle);
15021
15097
  for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
15022
15098
  candidates.add(`${legacyBase}${suffix}`);
15023
15099
  }
@@ -15025,7 +15101,7 @@ function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
15025
15101
  let deleted = deleteSessionInboxForTopic(topicId);
15026
15102
  for (const path of candidates) {
15027
15103
  try {
15028
- unlinkSync14(path);
15104
+ unlinkSync15(path);
15029
15105
  deleted++;
15030
15106
  } catch (err2) {
15031
15107
  if (err2?.code !== "ENOENT") {
@@ -15042,64 +15118,6 @@ var init_session_inbox_cleanup = __esm(async () => {
15042
15118
  await init_session_inbox();
15043
15119
  });
15044
15120
 
15045
- // ../../packages/core/src/query/state.ts
15046
- import { mkdirSync as mkdirSync15, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync13 } from "fs";
15047
- import { basename as basename5, join as join27 } from "path";
15048
- function createQueryStateStore(options) {
15049
- const sanitize = options.sanitizeTopicId ?? sanitizeId;
15050
- const queryStateDirPath = (userId) => join27(options.usersLogDir, String(userId), "active-queries");
15051
- const queryStateFile = (userId, topicId) => join27(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
15052
- const legacyQueryStateFile = (userId, topicName) => {
15053
- if (!topicName || topicName === "." || topicName === ".." || basename5(topicName) !== topicName) {
15054
- return null;
15055
- }
15056
- return join27(queryStateDirPath(userId), `${topicName}.json`);
15057
- };
15058
- return {
15059
- write(userId, topicId, topicName, task) {
15060
- const dir = queryStateDirPath(userId);
15061
- mkdirSync15(dir, { recursive: true });
15062
- const state = { topicId, topicName, since: new Date().toISOString() };
15063
- if (task)
15064
- state.task = [...task.replace(/\n+/g, " ").trim()].slice(0, 100).join("");
15065
- const target = queryStateFile(userId, topicId);
15066
- const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
15067
- writeFileSync13(tmp, JSON.stringify(state));
15068
- renameSync7(tmp, target);
15069
- },
15070
- clear(userId, topicId, legacyTopicName) {
15071
- const paths = [
15072
- queryStateFile(userId, topicId),
15073
- legacyQueryStateFile(userId, legacyTopicName)
15074
- ].filter((path) => Boolean(path));
15075
- for (const path of new Set(paths)) {
15076
- try {
15077
- unlinkSync15(path);
15078
- } catch (error) {
15079
- if (error?.code !== "ENOENT") {
15080
- options.logger?.warn({ err: error, userId, topicId, path }, "Failed to clear query state file");
15081
- }
15082
- }
15083
- }
15084
- }
15085
- };
15086
- }
15087
- function writeQueryState(userId, topicId, topicName, task) {
15088
- defaultQueryStateStore.write(userId, topicId, topicName, task);
15089
- }
15090
- function clearQueryState(userId, topicId, legacyTopicName) {
15091
- defaultQueryStateStore.clear(userId, topicId, legacyTopicName);
15092
- }
15093
- var defaultQueryStateStore;
15094
- var init_state = __esm(() => {
15095
- init_config();
15096
- init_logger();
15097
- defaultQueryStateStore = createQueryStateStore({
15098
- usersLogDir: USERS_LOG_DIR,
15099
- logger
15100
- });
15101
- });
15102
-
15103
15121
  // ../../packages/core/src/mcp/session-comm/peer-forward.ts
15104
15122
  var exports_peer_forward = {};
15105
15123
  __export(exports_peer_forward, {
@@ -19201,6 +19219,12 @@ var init_turn_runner = __esm(async () => {
19201
19219
 
19202
19220
  // ../../packages/core/src/agents/mcp-tools/spawn-subagent.ts
19203
19221
  import { z as z4 } from "zod";
19222
+ function activeQueryUserId(topic) {
19223
+ return topic?.participants.find((participant) => hasActiveQuery(participant.userId, topic.id))?.userId;
19224
+ }
19225
+ function persistedWatchUserId(topic) {
19226
+ return activeQueryUserId(topic) ?? topic?.participants.find((participant) => participant.role === "owner")?.userId ?? topic?.participants[0]?.userId;
19227
+ }
19204
19228
  function createSubagentLifecycle(host) {
19205
19229
  const runtimeOwnerId = host.runtime.ownerId;
19206
19230
  const limits = Object.freeze({
@@ -19315,7 +19339,7 @@ function createSubagentLifecycle(host) {
19315
19339
  }
19316
19340
  function watchFromPersistedCard(message, card, queryId) {
19317
19341
  const child = host.storage.getTopic(card.subagentTopicId);
19318
- const userId = child?.participants.find((participant) => participant.role === "owner")?.userId ?? child?.participants[0]?.userId;
19342
+ const userId = persistedWatchUserId(child);
19319
19343
  if (!userId)
19320
19344
  return null;
19321
19345
  return {
@@ -19674,6 +19698,10 @@ ${card.task}${reportInstruction}`;
19674
19698
  if (watch?.running)
19675
19699
  return "running";
19676
19700
  const card = host.storage.listSubagentMessages().filter((message) => message.topicId === parentTopicId && message.subagentCard?.subagentTopicId === childTopicId).at(-1)?.subagentCard;
19701
+ if (!card || card.status === "failed") {
19702
+ if (activeQueryUserId(host.storage.getTopic(childTopicId)))
19703
+ return "running";
19704
+ }
19677
19705
  return card?.status ?? "unknown";
19678
19706
  }
19679
19707
  function listMemoryTopicNames(ctx) {
@@ -19897,6 +19925,7 @@ var MAX_TASK_CHARS = 8000, MAX_NAME_CHARS = 80, MAX_LIVE_CHILDREN_PER_PARENT = 5
19897
19925
  var init_spawn_subagent = __esm(async () => {
19898
19926
  init_common();
19899
19927
  init_logger();
19928
+ init_state();
19900
19929
  init_wiki_summary_names();
19901
19930
  init_types();
19902
19931
  await __promiseAll([
@@ -19993,7 +20022,9 @@ var init_spawn_subagent = __esm(async () => {
19993
20022
  if (getRuntimeUserTurnRequest(childTopicId))
19994
20023
  return true;
19995
20024
  const lease = getRuntimeTurnLease(childTopicId);
19996
- return Boolean(lease && processOwnerIsAlive(lease.ownerId));
20025
+ if (lease && processOwnerIsAlive(lease.ownerId))
20026
+ return true;
20027
+ return Boolean(activeQueryUserId(getTopic(childTopicId)));
19997
20028
  }
19998
20029
  },
19999
20030
  config: {
@@ -21130,4 +21161,4 @@ export {
21130
21161
  DEFAULT_SELF_CONFIG_PRODUCT
21131
21162
  };
21132
21163
 
21133
- //# debugId=BACEE10AB360A31A64756E2164756E21
21164
+ //# debugId=7A2CA1A98309099B64756E2164756E21