@ours.network/codex 1.1.0 → 1.2.0-nightly.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.
@@ -2979,7 +2979,7 @@ var require_compile = __commonJS({
2979
2979
  const schOrFunc = root.refs[ref];
2980
2980
  if (schOrFunc)
2981
2981
  return schOrFunc;
2982
- let _sch = resolve.call(this, root, ref);
2982
+ let _sch = resolve2.call(this, root, ref);
2983
2983
  if (_sch === void 0) {
2984
2984
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
2985
2985
  const { schemaId } = this.opts;
@@ -3006,7 +3006,7 @@ var require_compile = __commonJS({
3006
3006
  function sameSchemaEnv(s1, s2) {
3007
3007
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3008
3008
  }
3009
- function resolve(root, ref) {
3009
+ function resolve2(root, ref) {
3010
3010
  let sch;
3011
3011
  while (typeof (sch = this.refs[ref]) == "string")
3012
3012
  ref = sch;
@@ -3831,7 +3831,7 @@ var require_fast_uri = __commonJS({
3831
3831
  }
3832
3832
  return uri;
3833
3833
  }
3834
- function resolve(baseURI, relativeURI, options) {
3834
+ function resolve2(baseURI, relativeURI, options) {
3835
3835
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3836
3836
  const {
3837
3837
  parsed: baseParsed,
@@ -3857,7 +3857,7 @@ var require_fast_uri = __commonJS({
3857
3857
  const resolvedHost = resolved.host;
3858
3858
  const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
3859
3859
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
3860
- const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
3860
+ const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
3861
3861
  if (resolved.error && !encodedASCIIHost) {
3862
3862
  throw new Error(resolved.error);
3863
3863
  }
@@ -4193,7 +4193,7 @@ var require_fast_uri = __commonJS({
4193
4193
  var fastUri = {
4194
4194
  SCHEMES,
4195
4195
  normalize,
4196
- resolve,
4196
+ resolve: resolve2,
4197
4197
  resolveComponent,
4198
4198
  equal,
4199
4199
  serialize,
@@ -19274,7 +19274,7 @@ var Protocol = class {
19274
19274
  return;
19275
19275
  }
19276
19276
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
19277
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
19277
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
19278
19278
  options?.signal?.throwIfAborted();
19279
19279
  }
19280
19280
  } catch (error2) {
@@ -19291,7 +19291,7 @@ var Protocol = class {
19291
19291
  */
19292
19292
  request(request, resultSchema, options) {
19293
19293
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
19294
- return new Promise((resolve, reject) => {
19294
+ return new Promise((resolve2, reject) => {
19295
19295
  const earlyReject = (error2) => {
19296
19296
  reject(error2);
19297
19297
  };
@@ -19369,7 +19369,7 @@ var Protocol = class {
19369
19369
  if (!parseResult.success) {
19370
19370
  reject(parseResult.error);
19371
19371
  } else {
19372
- resolve(parseResult.data);
19372
+ resolve2(parseResult.data);
19373
19373
  }
19374
19374
  } catch (error2) {
19375
19375
  reject(error2);
@@ -19630,12 +19630,12 @@ var Protocol = class {
19630
19630
  }
19631
19631
  } catch {
19632
19632
  }
19633
- return new Promise((resolve, reject) => {
19633
+ return new Promise((resolve2, reject) => {
19634
19634
  if (signal.aborted) {
19635
19635
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
19636
19636
  return;
19637
19637
  }
19638
- const timeoutId = setTimeout(resolve, interval);
19638
+ const timeoutId = setTimeout(resolve2, interval);
19639
19639
  signal.addEventListener("abort", () => {
19640
19640
  clearTimeout(timeoutId);
19641
19641
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -20735,7 +20735,7 @@ var McpServer = class {
20735
20735
  let task = createTaskResult.task;
20736
20736
  const pollInterval = task.pollInterval ?? 5e3;
20737
20737
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
20738
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
20738
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
20739
20739
  const updatedTask = await extra.taskStore.getTask(taskId);
20740
20740
  if (!updatedTask) {
20741
20741
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -21384,12 +21384,12 @@ var StdioServerTransport = class {
21384
21384
  this.onclose?.();
21385
21385
  }
21386
21386
  send(message) {
21387
- return new Promise((resolve) => {
21387
+ return new Promise((resolve2) => {
21388
21388
  const json = serializeMessage(message);
21389
21389
  if (this._stdout.write(json)) {
21390
- resolve();
21390
+ resolve2();
21391
21391
  } else {
21392
- this._stdout.once("drain", resolve);
21392
+ this._stdout.once("drain", resolve2);
21393
21393
  }
21394
21394
  });
21395
21395
  }
@@ -21398,6 +21398,125 @@ var StdioServerTransport = class {
21398
21398
  // src/monitor-mcp.mjs
21399
21399
  import { spawn } from "node:child_process";
21400
21400
  import { createRequire } from "node:module";
21401
+ import { fileURLToPath } from "node:url";
21402
+
21403
+ // ../core/src/host-profile.ts
21404
+ import { existsSync, lstatSync, readFileSync } from "node:fs";
21405
+ import { homedir } from "node:os";
21406
+ import { resolve } from "node:path";
21407
+ var PROFILE_KEYS = ["endpoint", "expectedInstanceId", "credentialPath"];
21408
+ var LEGACY_SELECTION_KEYS = ["port", "stateDir", "apiToken", "apiVisibility"];
21409
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
21410
+ var CONFLICTING_ENV = ["OURS_API_TOKEN", "OURS_PORT", "OURS_STATE_DIR", "OURS_DAEMON_ID"];
21411
+ function profileError(reason) {
21412
+ return new Error(`Invalid external host profile: ${reason}`);
21413
+ }
21414
+ function validateHostProfile(value) {
21415
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
21416
+ throw profileError("expected a complete host profile object.");
21417
+ }
21418
+ const record2 = value;
21419
+ const present = PROFILE_KEYS.filter((key) => Object.hasOwn(record2, key));
21420
+ if (present.length !== PROFILE_KEYS.length) {
21421
+ throw profileError("expected a complete host profile tuple: endpoint, expectedInstanceId, credentialPath.");
21422
+ }
21423
+ const mixed = LEGACY_SELECTION_KEYS.filter((key) => Object.hasOwn(record2, key));
21424
+ if (mixed.length) throw profileError(`legacy selection keys cannot be mixed with a host profile (${mixed.join(", ")}).`);
21425
+ const endpoint = record2.endpoint;
21426
+ const expectedInstanceId = record2.expectedInstanceId;
21427
+ const credentialPath = record2.credentialPath;
21428
+ if (typeof endpoint !== "string" || endpoint.trim() !== endpoint || endpoint === "") {
21429
+ throw profileError("endpoint must be a non-empty HTTP origin.");
21430
+ }
21431
+ if (typeof expectedInstanceId !== "string" || !UUID.test(expectedInstanceId)) {
21432
+ throw profileError("expectedInstanceId must be a lowercase UUID.");
21433
+ }
21434
+ if (typeof credentialPath !== "string" || credentialPath === "" || !credentialPath.startsWith("/") || resolve(credentialPath) !== credentialPath) {
21435
+ throw profileError("credentialPath must be a normalized absolute path.");
21436
+ }
21437
+ let url;
21438
+ try {
21439
+ url = new URL(endpoint);
21440
+ } catch {
21441
+ throw profileError("endpoint must be an HTTP origin.");
21442
+ }
21443
+ if (url.protocol !== "http:" || url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
21444
+ throw profileError("endpoint must be an HTTP origin without credentials, path, query, or fragment.");
21445
+ }
21446
+ return { endpoint: url.origin, expectedInstanceId, credentialPath };
21447
+ }
21448
+ function readProfileObject(configPath) {
21449
+ let text;
21450
+ try {
21451
+ text = readFileSync(configPath, "utf8");
21452
+ } catch {
21453
+ throw new Error(`Cannot read host profile ${JSON.stringify(configPath)}.`);
21454
+ }
21455
+ let value;
21456
+ try {
21457
+ value = JSON.parse(text);
21458
+ } catch {
21459
+ throw profileError(`config ${JSON.stringify(configPath)} is not valid JSON.`);
21460
+ }
21461
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw profileError(`config ${JSON.stringify(configPath)} must be an object.`);
21462
+ return value;
21463
+ }
21464
+ function assertPrivateRegularFile(configPath) {
21465
+ let stat;
21466
+ try {
21467
+ stat = lstatSync(configPath);
21468
+ } catch {
21469
+ throw new Error(`Cannot read host profile ${JSON.stringify(configPath)}.`);
21470
+ }
21471
+ if (!stat.isFile()) throw profileError(`config ${JSON.stringify(configPath)} must be a regular file.`);
21472
+ const currentUid = process.getuid?.();
21473
+ if (currentUid === void 0 || stat.uid !== currentUid) throw profileError(`config ${JSON.stringify(configPath)} must be owned by the current user.`);
21474
+ if ((stat.mode & 63) !== 0) throw profileError(`config ${JSON.stringify(configPath)} must have private permissions.`);
21475
+ }
21476
+ function readHostProfile(configPath) {
21477
+ const record2 = readProfileObject(configPath);
21478
+ const found = PROFILE_KEYS.filter((key) => Object.hasOwn(record2, key));
21479
+ if (found.length === 0) return null;
21480
+ assertPrivateRegularFile(configPath);
21481
+ return validateHostProfile(record2);
21482
+ }
21483
+ function nonempty(env, key) {
21484
+ return (env[key] ?? "").trim() !== "";
21485
+ }
21486
+ function hostProfileSelectionFromEnv(env = process.env) {
21487
+ const explicit = (env.OURS_CONFIG ?? "").trim();
21488
+ const managedPath = resolve(env.HOME || homedir(), ".ours-client", "profile.json");
21489
+ let configPath = explicit;
21490
+ if (!configPath) {
21491
+ try {
21492
+ lstatSync(managedPath);
21493
+ configPath = managedPath;
21494
+ } catch (error2) {
21495
+ if (error2.code !== "ENOENT") {
21496
+ throw new Error(`Cannot read host profile ${JSON.stringify(managedPath)}.`);
21497
+ }
21498
+ configPath = resolve(homedir(), ".ours", "config.json");
21499
+ if (!existsSync(configPath)) return null;
21500
+ }
21501
+ }
21502
+ const profile = readHostProfile(configPath);
21503
+ if (profile === null) {
21504
+ if (resolve(configPath) === managedPath) throw profileError("managed client config must contain a complete host profile tuple.");
21505
+ return null;
21506
+ }
21507
+ const conflicting = CONFLICTING_ENV.filter((key) => nonempty(env, key));
21508
+ if (conflicting.length) throw profileError(`${conflicting.join(", ")} conflicts with host-profile mode.`);
21509
+ return { profile, configPath };
21510
+ }
21511
+ function hostProfileFromEnv(env = process.env) {
21512
+ return hostProfileSelectionFromEnv(env)?.profile ?? null;
21513
+ }
21514
+
21515
+ // ../core/src/host-client/files.ts
21516
+ import { buildIdentityFile, writeIdentityFile } from "@ours.network/sdk/connector";
21517
+
21518
+ // ../core/src/native-session.ts
21519
+ import { attachOursClient } from "@ours.network/sdk";
21401
21520
 
21402
21521
  // src/control-server.mjs
21403
21522
  import { createServer, createConnection } from "node:net";
@@ -21411,7 +21530,7 @@ function encodeControlResponse(value) {
21411
21530
 
21412
21531
  // src/control-server.mjs
21413
21532
  function sendControlCommand(socketPath, capability, message, timeoutMs = 2e3) {
21414
- return new Promise((resolve, reject) => {
21533
+ return new Promise((resolve2, reject) => {
21415
21534
  const socket = createConnection(socketPath);
21416
21535
  let buffer = "";
21417
21536
  const timer = setTimeout(() => {
@@ -21432,7 +21551,7 @@ function sendControlCommand(socketPath, capability, message, timeoutMs = 2e3) {
21432
21551
  try {
21433
21552
  const response = JSON.parse(buffer);
21434
21553
  if (!response.ok) reject(new Error(response.error || "monitor control failed"));
21435
- else resolve(response);
21554
+ else resolve2(response);
21436
21555
  } catch (error2) {
21437
21556
  reject(error2);
21438
21557
  }
@@ -21442,10 +21561,20 @@ function sendControlCommand(socketPath, capability, message, timeoutMs = 2e3) {
21442
21561
 
21443
21562
  // src/monitor-mcp.mjs
21444
21563
  var require2 = createRequire(import.meta.url);
21564
+ var networkWatchPath = fileURLToPath(new URL("../bin/network-watch.mjs", import.meta.url));
21445
21565
  var monitorToolNames = ["arm_monitor", "foreground_monitor", "disarm_monitor", "monitor_status"];
21446
21566
  var content = (text, isError = false) => ({ content: [{ type: "text", text }], ...isError ? { isError: true } : {} });
21447
21567
  var foregroundOffer = (identity) => `IMPORTANT: Before offering the fallback, tell the user exactly: "This standard \`codex\` session only supports a blocking foreground monitor. For background monitoring, restart the session with \`ours-codex\` instead; it adds the App Server integration needed for session-scoped background wake." A blocking foreground monitor is available here, but while it waits this Codex session cannot accept another prompt (press Escape to stop it). Ask the user: "Do you want to arm the foreground blocking monitor here?" Only after an explicit yes, call get_messages once to drain existing unread mail, then call foreground_monitor({ identity: ${JSON.stringify(identity)} }).`;
21448
- function foregroundWatchProcess(identity) {
21568
+ function foregroundWatchProcess(identity, nativeSessionId, env = process.env) {
21569
+ if (hostProfileFromEnv(env)) {
21570
+ if (typeof nativeSessionId !== "string" || !nativeSessionId.trim()) {
21571
+ throw new Error("Native session metadata is required for host-profile monitoring.");
21572
+ }
21573
+ return {
21574
+ command: process.execPath,
21575
+ args: [networkWatchPath, identity, nativeSessionId]
21576
+ };
21577
+ }
21449
21578
  try {
21450
21579
  const cliPath = require2.resolve("@ours.network/mcp/dist/cli.js");
21451
21580
  return { command: process.execPath, args: [cliPath, "watch", identity] };
@@ -21468,23 +21597,24 @@ async function handleMonitorCommand(command, args = {}, { env = process.env, sen
21468
21597
  if (command === "disarm") return { text: "Live ours monitor disarmed." };
21469
21598
  return { text: state.armedIdentity ? `Live ours monitor is armed for "${state.armedIdentity}"${state.turnActive ? "; a turn is active" : ""}.` : `Live ours monitor is available but not armed${state.boundIdentity ? `; current binding is "${state.boundIdentity}"` : "; bind an identity first"}.` };
21470
21599
  }
21471
- function waitForForegroundMail(identity, {
21600
+ function waitForForegroundMail(identity, nativeSessionId, {
21472
21601
  env = process.env,
21473
21602
  spawnImpl = spawn,
21474
21603
  signal,
21475
21604
  commandFor = foregroundWatchProcess
21476
21605
  } = {}) {
21477
21606
  if (typeof identity !== "string" || !identity.trim()) return Promise.reject(new Error("identity is required"));
21478
- return new Promise((resolve, reject) => {
21479
- const invocation = commandFor(identity);
21607
+ return new Promise((resolve2, reject) => {
21608
+ const invocation = commandFor(identity, nativeSessionId, env);
21480
21609
  const child = spawnImpl(invocation.command, invocation.args, {
21481
- env,
21482
- stdio: ["ignore", "pipe", "pipe"]
21610
+ env: invocation.env ?? env,
21611
+ stdio: [invocation.stdin ?? "ignore", "pipe", "pipe"]
21483
21612
  });
21484
21613
  let stdout = "";
21485
21614
  let stderr = "";
21486
21615
  let settled = false;
21487
21616
  const stop = () => {
21617
+ if (invocation.stdin === "pipe") child.stdin?.end();
21488
21618
  if (!child.killed) child.kill("SIGTERM");
21489
21619
  };
21490
21620
  const finish = (fn, value) => {
@@ -21506,7 +21636,7 @@ function waitForForegroundMail(identity, {
21506
21636
  const newline = stdout.indexOf("\n");
21507
21637
  if (newline === -1) return;
21508
21638
  const event = stdout.slice(0, newline).trim();
21509
- if (event) finish(resolve, event);
21639
+ if (event) finish(resolve2, event);
21510
21640
  });
21511
21641
  child.once("exit", (code, childSignal) => {
21512
21642
  if (settled) return;
@@ -21530,7 +21660,7 @@ function createMonitorMcpServer(deps = {}) {
21530
21660
  identity: external_exports.string().min(1).describe("The already-bound ours identity to monitor.")
21531
21661
  }, async ({ identity }, extra) => {
21532
21662
  try {
21533
- const event = await waitForForegroundMail(identity, { ...deps, signal: extra?.signal });
21663
+ const event = await waitForForegroundMail(identity, extra?._meta?.threadId, { ...deps, signal: extra?.signal });
21534
21664
  return content(`Foreground ours monitor received a body-free arrival event: ${event}
21535
21665
  Call get_messages now. After handling the mail, call foreground_monitor again without asking if monitoring should remain armed.`);
21536
21666
  } catch (error2) {