sealnet-mcp 0.2.1 → 0.2.3

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/cli.cjs CHANGED
@@ -2914,7 +2914,6 @@ var upload_default = {
2914
2914
  HEDGE_MIN_INFLIGHT_MS: 3e3,
2915
2915
  HEDGE_LAG_FACTOR: 3,
2916
2916
  HEDGE_POLL_MS: 1e3,
2917
- HEDGE_MAX_CONCURRENT: 1,
2918
2917
  LIVENESS_SILENCE_MS: 3e4,
2919
2918
  RETRY_BACKOFF_MS: [1e3, 3e3, 7e3, 15e3, 3e4],
2920
2919
  RETRY_JITTER_RATIO: 0.2,
@@ -4209,7 +4208,6 @@ var DEFAULT_TRANSPORT_POLICY = {
4209
4208
  hedgeMinInflightMs: upload_default.upload.HEDGE_MIN_INFLIGHT_MS,
4210
4209
  hedgeLagFactor: upload_default.upload.HEDGE_LAG_FACTOR,
4211
4210
  hedgePollMs: upload_default.upload.HEDGE_POLL_MS,
4212
- hedgeMaxConcurrent: upload_default.upload.HEDGE_MAX_CONCURRENT,
4213
4211
  livenessSilenceMs: upload_default.upload.LIVENESS_SILENCE_MS,
4214
4212
  verifyPollBackoffMs: upload_default.upload.VERIFY_POLL_BACKOFF_MS,
4215
4213
  verifyFallbackWaitMs: upload_default.upload.VERIFY_FALLBACK_WAIT_MS,
@@ -4531,7 +4529,6 @@ async function multipartUploadStream(options) {
4531
4529
  let lastRoundRate = null;
4532
4530
  let roomWaiters = [];
4533
4531
  const fullPartPace = [];
4534
- let hedgesInFlight = 0;
4535
4532
  const partsInFlight = /* @__PURE__ */ new Set();
4536
4533
  let lastSocketActivityAt = performance.now();
4537
4534
  let socketActivityObservable = false;
@@ -4576,10 +4573,10 @@ async function multipartUploadStream(options) {
4576
4573
  roundBytes = 0;
4577
4574
  roundDeliveries = 0;
4578
4575
  }
4579
- function hedgeDue(item, lastLaunchAt, ownDuplicates) {
4576
+ function hedgeDue(item, lastLaunchAt) {
4580
4577
  const inFlightMs = performance.now() - lastLaunchAt;
4581
4578
  if (inFlightMs < policy.hedgeMinInflightMs) return false;
4582
- const flowsNow = runningParts.size + hedgesInFlight - ownDuplicates;
4579
+ const flowsNow = runningParts.size;
4583
4580
  const peers = fullPartPace.filter((p) => p.flows >= flowsNow).map((p) => p.rate);
4584
4581
  if (peers.length === 0) return false;
4585
4582
  peers.sort((a, b) => a - b);
@@ -4701,135 +4698,80 @@ async function multipartUploadStream(options) {
4701
4698
  }
4702
4699
  async function hedgedPut(item, presignedUrl) {
4703
4700
  const t0 = performance.now();
4704
- let controllers = [];
4705
- const detachFns = [];
4706
4701
  let hedgeTicker = null;
4707
4702
  let hedgeCount = 0;
4708
- let liveHedges = 0;
4709
- let currentHedge = null;
4710
4703
  let lastLaunchAt = t0;
4711
- let generation = 0;
4712
- const unsentByCopy = /* @__PURE__ */ new Map();
4713
- let reconnect = () => {
4714
- };
4715
- const launchCopy = async (isHedge) => {
4716
- const ctl = new AbortController();
4717
- controllers.push(ctl);
4718
- if (isHedge) currentHedge = ctl;
4719
- unsentByCopy.set(ctl, true);
4720
- lastSocketActivityAt = performance.now();
4721
- if (runSignal) {
4722
- if (runSignal.aborted) {
4723
- ctl.abort();
4724
- } else {
4725
- const onAbort = () => ctl.abort();
4726
- runSignal.addEventListener("abort", onAbort, { once: true });
4727
- detachFns.push(() => runSignal.removeEventListener("abort", onAbort));
4728
- }
4729
- }
4730
- try {
4731
- const outcome = await transportPut(
4732
- item.ciphertext,
4733
- item.contentMd5,
4734
- item.partNumber,
4735
- presignedUrl,
4736
- ctl.signal,
4737
- {
4738
- onSocketActivity: (loaded, total) => {
4739
- lastSocketActivityAt = performance.now();
4740
- unsentByCopy.set(ctl, loaded < total);
4741
- },
4742
- onDeadline: () => reconnect("copy deadline")
4743
- }
4744
- );
4745
- return validatePutOutcome(item.partNumber, outcome);
4746
- } finally {
4747
- unsentByCopy.delete(ctl);
4748
- }
4704
+ let current = null;
4705
+ let replace = () => {
4749
4706
  };
4750
4707
  const inFlight = {
4751
- reconnect: (why) => reconnect(why),
4752
- hasUnsentBytes: () => [...unsentByCopy.values()].some(Boolean)
4708
+ reconnect: (why) => replace(why, false),
4709
+ hasUnsentBytes: () => current?.unsent ?? false
4753
4710
  };
4754
4711
  partsInFlight.add(inFlight);
4755
4712
  try {
4756
4713
  const etag = await new Promise((resolve5, reject) => {
4757
- let pending = 0;
4758
4714
  let settled = false;
4759
- const run = (label) => {
4760
- const born = generation;
4761
- pending++;
4762
- launchCopy(label === "hedge").then((confirmedEtag) => {
4763
- if (settled) return;
4764
- settled = true;
4765
- if (label === "hedge") log3.debug(`hedge won part=${item.partNumber}`);
4766
- resolve5(confirmedEtag);
4767
- }).catch((err2) => {
4768
- if (settled || born !== generation) return;
4769
- pending--;
4770
- const failure = toUploadError(err2, `Failed to upload part ${item.partNumber}`);
4771
- if (label === "hedge") {
4772
- liveHedges--;
4773
- hedgesInFlight--;
4774
- currentHedge = null;
4775
- if (failure.code !== "ABORTED") hedgeCount--;
4776
- }
4777
- if (failure.code === "ABORTED" && signal?.aborted) {
4778
- settled = true;
4779
- reject(failure);
4780
- return;
4781
- }
4782
- if (pending === 0) {
4783
- if (hedgeTicker !== null) {
4784
- clearInterval(hedgeTicker);
4785
- hedgeTicker = null;
4715
+ const settle = (outcome) => {
4716
+ if (settled) return;
4717
+ settled = true;
4718
+ outcome();
4719
+ };
4720
+ const launch = () => {
4721
+ const ctl = new AbortController();
4722
+ const onUploadEnd = () => ctl.abort();
4723
+ if (runSignal?.aborted) ctl.abort();
4724
+ else runSignal?.addEventListener("abort", onUploadEnd, { once: true });
4725
+ const copy = { ctl, unsent: true, ended: Promise.resolve() };
4726
+ current = copy;
4727
+ lastLaunchAt = performance.now();
4728
+ lastSocketActivityAt = lastLaunchAt;
4729
+ copy.ended = transportPut(item.ciphertext, item.contentMd5, item.partNumber, presignedUrl, ctl.signal, {
4730
+ onSocketActivity: (loaded, total) => {
4731
+ lastSocketActivityAt = performance.now();
4732
+ copy.unsent = loaded < total;
4733
+ },
4734
+ onDeadline: () => replace("copy deadline", false)
4735
+ }).then(
4736
+ (outcome) => {
4737
+ if (current !== copy) return;
4738
+ try {
4739
+ const confirmed = validatePutOutcome(item.partNumber, outcome);
4740
+ settle(() => resolve5(confirmed));
4741
+ } catch (err2) {
4742
+ settle(() => reject(err2));
4786
4743
  }
4787
- settled = true;
4788
- reject(failure);
4744
+ },
4745
+ (err2) => {
4746
+ if (current === copy) settle(() => reject(toUploadError(err2, `Failed to upload part ${item.partNumber}`)));
4789
4747
  }
4748
+ ).finally(() => {
4749
+ copy.unsent = false;
4750
+ runSignal?.removeEventListener("abort", onUploadEnd);
4790
4751
  });
4791
4752
  };
4792
- reconnect = (why) => {
4793
- if (settled || signal?.aborted) return;
4794
- generation++;
4795
- pending = 0;
4796
- hedgesInFlight -= liveHedges;
4797
- liveHedges = 0;
4798
- hedgeCount = 0;
4799
- currentHedge = null;
4800
- const stale = controllers;
4801
- controllers = [];
4802
- for (const ctl of stale) ctl.abort();
4803
- lastLaunchAt = performance.now();
4804
- log3.debug(`reconnect part=${item.partNumber} (${why})`);
4805
- run("primary");
4753
+ replace = (why, spendsTicket) => {
4754
+ const old = current;
4755
+ if (settled || old === null || signal?.aborted) return;
4756
+ current = null;
4757
+ hedgeCount = spendsTicket ? hedgeCount + 1 : 0;
4758
+ log3.debug(`${spendsTicket ? "replace" : "reconnect"} part=${item.partNumber} (${why})`);
4759
+ old.ctl.abort();
4760
+ void old.ended.then(() => {
4761
+ if (settled) return;
4762
+ if (runSignal?.aborted) {
4763
+ settle(() => reject(new UploadError("Upload aborted", "ABORTED", void 0, item.partNumber)));
4764
+ } else {
4765
+ launch();
4766
+ }
4767
+ });
4806
4768
  };
4807
- run("primary");
4769
+ launch();
4808
4770
  hedgeTicker = setInterval(() => {
4809
- if (settled || signal?.aborted) {
4810
- if (hedgeTicker !== null) {
4811
- clearInterval(hedgeTicker);
4812
- hedgeTicker = null;
4813
- }
4814
- return;
4815
- }
4771
+ if (settled || signal?.aborted || current === null) return;
4816
4772
  if (hedgeCount >= HEDGE_MAX_PER_PART) return;
4817
- if (!hedgeDue(item, lastLaunchAt, liveHedges)) return;
4818
- if (hedgesInFlight >= policy.hedgeMaxConcurrent) {
4819
- if (currentHedge !== null) {
4820
- currentHedge.abort();
4821
- currentHedge = null;
4822
- }
4823
- return;
4824
- }
4825
- hedgeCount++;
4826
- liveHedges++;
4827
- hedgesInFlight++;
4828
- lastLaunchAt = performance.now();
4829
- log3.debug(
4830
- `hedge launched part=${item.partNumber} copy=${hedgeCount + 1} after ${Math.round(performance.now() - t0)}ms`
4831
- );
4832
- run("hedge");
4773
+ if (!hedgeDue(item, lastLaunchAt)) return;
4774
+ replace(`slower than its peers after ${Math.round(performance.now() - t0)}ms`, true);
4833
4775
  }, policy.hedgePollMs);
4834
4776
  });
4835
4777
  const tPut = performance.now();
@@ -4840,17 +4782,15 @@ async function multipartUploadStream(options) {
4840
4782
  clock.delivered();
4841
4783
  lastSocketActivityAt = tPut;
4842
4784
  log3.debug(
4843
- `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` hedged\xD7${hedgeCount}` : ""}`
4785
+ `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` replaced\xD7${hedgeCount}` : ""}`
4844
4786
  );
4845
4787
  report("uploading");
4846
4788
  } finally {
4847
4789
  partsInFlight.delete(inFlight);
4848
- reconnect = () => {
4790
+ replace = () => {
4849
4791
  };
4850
4792
  if (hedgeTicker !== null) clearInterval(hedgeTicker);
4851
- hedgesInFlight -= liveHedges;
4852
- for (const ctl of controllers) ctl.abort();
4853
- for (const detach of detachFns) detach();
4793
+ current?.ctl.abort();
4854
4794
  }
4855
4795
  }
4856
4796
  const controlFetch = (url, init3, timeoutMs) => policyFetch(url, init3, timeoutMs, runSignal);
@@ -4955,6 +4895,10 @@ async function multipartUploadStream(options) {
4955
4895
  item.round = round;
4956
4896
  item.flowsAtStart = runningParts.size;
4957
4897
  let url = presignedUrlCache.get(item.partNumber);
4898
+ if (!url && presignPrefetchInFlight) {
4899
+ await presignPrefetchInFlight;
4900
+ url = presignedUrlCache.get(item.partNumber);
4901
+ }
4958
4902
  presignedUrlCache.delete(item.partNumber);
4959
4903
  schedulePresignPrefetch(item.partNumber + 1);
4960
4904
  await retrying(
@@ -11398,6 +11342,10 @@ var seal_mcp_v1_default = {
11398
11342
  server_info: "name `sealnet-mcp` (the npm package and its binary); version = `package.json::version`, injected at build time (tsup `define`), never a source literal. The state directory, the keychain service and the handoff directory keep the name `seal-mcp`: they are where existing state lives.",
11399
11343
  progress: "When a `tools/call` carries `_meta.progressToken`, `seal_share` and `seal_open mode=file` send `notifications/progress` with `progress` = ciphertext bytes done (upload: confirmed by storage) and `total` = ciphertext bytes in all; at most one per second, `progress` strictly increasing, the last one at `progress = total`."
11400
11344
  },
11345
+ server_instructions: {
11346
+ text: "SEAL moves files and secrets between people and agents without their content entering this conversation. When someone wants a file, folder or secret sent to them, to another machine or to another agent, call seal_share with its path and do not open, print or Read it first. When you need an API key, password, file or folder from the user, or they offer or ask how to give you one, call seal_request right away instead of explaining other ways or asking them to paste or upload it. Open a SEAL link someone gave you with seal_open (mode=file for secrets and large files).",
11347
+ note: "The `instructions` of the `initialize` result (SPEC-AGENTS \xA78.1). Hosts that defer MCP tools behind a tool search (Claude Code) show the model only tool names until it searches, but put these instructions into the system prompt: this is the one text a model reads before it decides to look for a tool, or reads the file it was asked to send."
11348
+ },
11401
11349
  tools: {
11402
11350
  seal_share: {
11403
11351
  title: "Share a file via SEAL",
@@ -13989,7 +13937,7 @@ function proFileGetOutputToWire(out) {
13989
13937
  }
13990
13938
 
13991
13939
  // src/server.ts
13992
- var SERVER_VERSION = "0.2.1";
13940
+ var SERVER_VERSION = "0.2.3";
13993
13941
  var toolMeta = (name) => {
13994
13942
  const { title, description, annotations } = seal_mcp_v1_default.tools[name];
13995
13943
  return { title, description, annotations };
@@ -14057,7 +14005,7 @@ async function createServer(options) {
14057
14005
  };
14058
14006
  const mcp = new import_mcp.McpServer(
14059
14007
  { name: "sealnet-mcp", version: SERVER_VERSION },
14060
- { capabilities: { tools: {} } }
14008
+ { capabilities: { tools: {} }, instructions: seal_mcp_v1_default.server_instructions.text }
14061
14009
  );
14062
14010
  const disableClipboard = process.env.SEAL_MCP_DISABLE_CLIPBOARD === "1";
14063
14011
  mcp.registerTool(
package/dist/cli.js CHANGED
@@ -2886,7 +2886,6 @@ var upload_default = {
2886
2886
  HEDGE_MIN_INFLIGHT_MS: 3e3,
2887
2887
  HEDGE_LAG_FACTOR: 3,
2888
2888
  HEDGE_POLL_MS: 1e3,
2889
- HEDGE_MAX_CONCURRENT: 1,
2890
2889
  LIVENESS_SILENCE_MS: 3e4,
2891
2890
  RETRY_BACKOFF_MS: [1e3, 3e3, 7e3, 15e3, 3e4],
2892
2891
  RETRY_JITTER_RATIO: 0.2,
@@ -4181,7 +4180,6 @@ var DEFAULT_TRANSPORT_POLICY = {
4181
4180
  hedgeMinInflightMs: upload_default.upload.HEDGE_MIN_INFLIGHT_MS,
4182
4181
  hedgeLagFactor: upload_default.upload.HEDGE_LAG_FACTOR,
4183
4182
  hedgePollMs: upload_default.upload.HEDGE_POLL_MS,
4184
- hedgeMaxConcurrent: upload_default.upload.HEDGE_MAX_CONCURRENT,
4185
4183
  livenessSilenceMs: upload_default.upload.LIVENESS_SILENCE_MS,
4186
4184
  verifyPollBackoffMs: upload_default.upload.VERIFY_POLL_BACKOFF_MS,
4187
4185
  verifyFallbackWaitMs: upload_default.upload.VERIFY_FALLBACK_WAIT_MS,
@@ -4503,7 +4501,6 @@ async function multipartUploadStream(options) {
4503
4501
  let lastRoundRate = null;
4504
4502
  let roomWaiters = [];
4505
4503
  const fullPartPace = [];
4506
- let hedgesInFlight = 0;
4507
4504
  const partsInFlight = /* @__PURE__ */ new Set();
4508
4505
  let lastSocketActivityAt = performance.now();
4509
4506
  let socketActivityObservable = false;
@@ -4548,10 +4545,10 @@ async function multipartUploadStream(options) {
4548
4545
  roundBytes = 0;
4549
4546
  roundDeliveries = 0;
4550
4547
  }
4551
- function hedgeDue(item, lastLaunchAt, ownDuplicates) {
4548
+ function hedgeDue(item, lastLaunchAt) {
4552
4549
  const inFlightMs = performance.now() - lastLaunchAt;
4553
4550
  if (inFlightMs < policy.hedgeMinInflightMs) return false;
4554
- const flowsNow = runningParts.size + hedgesInFlight - ownDuplicates;
4551
+ const flowsNow = runningParts.size;
4555
4552
  const peers = fullPartPace.filter((p) => p.flows >= flowsNow).map((p) => p.rate);
4556
4553
  if (peers.length === 0) return false;
4557
4554
  peers.sort((a, b) => a - b);
@@ -4673,135 +4670,80 @@ async function multipartUploadStream(options) {
4673
4670
  }
4674
4671
  async function hedgedPut(item, presignedUrl) {
4675
4672
  const t0 = performance.now();
4676
- let controllers = [];
4677
- const detachFns = [];
4678
4673
  let hedgeTicker = null;
4679
4674
  let hedgeCount = 0;
4680
- let liveHedges = 0;
4681
- let currentHedge = null;
4682
4675
  let lastLaunchAt = t0;
4683
- let generation = 0;
4684
- const unsentByCopy = /* @__PURE__ */ new Map();
4685
- let reconnect = () => {
4686
- };
4687
- const launchCopy = async (isHedge) => {
4688
- const ctl = new AbortController();
4689
- controllers.push(ctl);
4690
- if (isHedge) currentHedge = ctl;
4691
- unsentByCopy.set(ctl, true);
4692
- lastSocketActivityAt = performance.now();
4693
- if (runSignal) {
4694
- if (runSignal.aborted) {
4695
- ctl.abort();
4696
- } else {
4697
- const onAbort = () => ctl.abort();
4698
- runSignal.addEventListener("abort", onAbort, { once: true });
4699
- detachFns.push(() => runSignal.removeEventListener("abort", onAbort));
4700
- }
4701
- }
4702
- try {
4703
- const outcome = await transportPut(
4704
- item.ciphertext,
4705
- item.contentMd5,
4706
- item.partNumber,
4707
- presignedUrl,
4708
- ctl.signal,
4709
- {
4710
- onSocketActivity: (loaded, total) => {
4711
- lastSocketActivityAt = performance.now();
4712
- unsentByCopy.set(ctl, loaded < total);
4713
- },
4714
- onDeadline: () => reconnect("copy deadline")
4715
- }
4716
- );
4717
- return validatePutOutcome(item.partNumber, outcome);
4718
- } finally {
4719
- unsentByCopy.delete(ctl);
4720
- }
4676
+ let current = null;
4677
+ let replace = () => {
4721
4678
  };
4722
4679
  const inFlight = {
4723
- reconnect: (why) => reconnect(why),
4724
- hasUnsentBytes: () => [...unsentByCopy.values()].some(Boolean)
4680
+ reconnect: (why) => replace(why, false),
4681
+ hasUnsentBytes: () => current?.unsent ?? false
4725
4682
  };
4726
4683
  partsInFlight.add(inFlight);
4727
4684
  try {
4728
4685
  const etag = await new Promise((resolve5, reject) => {
4729
- let pending = 0;
4730
4686
  let settled = false;
4731
- const run = (label) => {
4732
- const born = generation;
4733
- pending++;
4734
- launchCopy(label === "hedge").then((confirmedEtag) => {
4735
- if (settled) return;
4736
- settled = true;
4737
- if (label === "hedge") log3.debug(`hedge won part=${item.partNumber}`);
4738
- resolve5(confirmedEtag);
4739
- }).catch((err2) => {
4740
- if (settled || born !== generation) return;
4741
- pending--;
4742
- const failure = toUploadError(err2, `Failed to upload part ${item.partNumber}`);
4743
- if (label === "hedge") {
4744
- liveHedges--;
4745
- hedgesInFlight--;
4746
- currentHedge = null;
4747
- if (failure.code !== "ABORTED") hedgeCount--;
4748
- }
4749
- if (failure.code === "ABORTED" && signal?.aborted) {
4750
- settled = true;
4751
- reject(failure);
4752
- return;
4753
- }
4754
- if (pending === 0) {
4755
- if (hedgeTicker !== null) {
4756
- clearInterval(hedgeTicker);
4757
- hedgeTicker = null;
4687
+ const settle = (outcome) => {
4688
+ if (settled) return;
4689
+ settled = true;
4690
+ outcome();
4691
+ };
4692
+ const launch = () => {
4693
+ const ctl = new AbortController();
4694
+ const onUploadEnd = () => ctl.abort();
4695
+ if (runSignal?.aborted) ctl.abort();
4696
+ else runSignal?.addEventListener("abort", onUploadEnd, { once: true });
4697
+ const copy = { ctl, unsent: true, ended: Promise.resolve() };
4698
+ current = copy;
4699
+ lastLaunchAt = performance.now();
4700
+ lastSocketActivityAt = lastLaunchAt;
4701
+ copy.ended = transportPut(item.ciphertext, item.contentMd5, item.partNumber, presignedUrl, ctl.signal, {
4702
+ onSocketActivity: (loaded, total) => {
4703
+ lastSocketActivityAt = performance.now();
4704
+ copy.unsent = loaded < total;
4705
+ },
4706
+ onDeadline: () => replace("copy deadline", false)
4707
+ }).then(
4708
+ (outcome) => {
4709
+ if (current !== copy) return;
4710
+ try {
4711
+ const confirmed = validatePutOutcome(item.partNumber, outcome);
4712
+ settle(() => resolve5(confirmed));
4713
+ } catch (err2) {
4714
+ settle(() => reject(err2));
4758
4715
  }
4759
- settled = true;
4760
- reject(failure);
4716
+ },
4717
+ (err2) => {
4718
+ if (current === copy) settle(() => reject(toUploadError(err2, `Failed to upload part ${item.partNumber}`)));
4761
4719
  }
4720
+ ).finally(() => {
4721
+ copy.unsent = false;
4722
+ runSignal?.removeEventListener("abort", onUploadEnd);
4762
4723
  });
4763
4724
  };
4764
- reconnect = (why) => {
4765
- if (settled || signal?.aborted) return;
4766
- generation++;
4767
- pending = 0;
4768
- hedgesInFlight -= liveHedges;
4769
- liveHedges = 0;
4770
- hedgeCount = 0;
4771
- currentHedge = null;
4772
- const stale = controllers;
4773
- controllers = [];
4774
- for (const ctl of stale) ctl.abort();
4775
- lastLaunchAt = performance.now();
4776
- log3.debug(`reconnect part=${item.partNumber} (${why})`);
4777
- run("primary");
4725
+ replace = (why, spendsTicket) => {
4726
+ const old = current;
4727
+ if (settled || old === null || signal?.aborted) return;
4728
+ current = null;
4729
+ hedgeCount = spendsTicket ? hedgeCount + 1 : 0;
4730
+ log3.debug(`${spendsTicket ? "replace" : "reconnect"} part=${item.partNumber} (${why})`);
4731
+ old.ctl.abort();
4732
+ void old.ended.then(() => {
4733
+ if (settled) return;
4734
+ if (runSignal?.aborted) {
4735
+ settle(() => reject(new UploadError("Upload aborted", "ABORTED", void 0, item.partNumber)));
4736
+ } else {
4737
+ launch();
4738
+ }
4739
+ });
4778
4740
  };
4779
- run("primary");
4741
+ launch();
4780
4742
  hedgeTicker = setInterval(() => {
4781
- if (settled || signal?.aborted) {
4782
- if (hedgeTicker !== null) {
4783
- clearInterval(hedgeTicker);
4784
- hedgeTicker = null;
4785
- }
4786
- return;
4787
- }
4743
+ if (settled || signal?.aborted || current === null) return;
4788
4744
  if (hedgeCount >= HEDGE_MAX_PER_PART) return;
4789
- if (!hedgeDue(item, lastLaunchAt, liveHedges)) return;
4790
- if (hedgesInFlight >= policy.hedgeMaxConcurrent) {
4791
- if (currentHedge !== null) {
4792
- currentHedge.abort();
4793
- currentHedge = null;
4794
- }
4795
- return;
4796
- }
4797
- hedgeCount++;
4798
- liveHedges++;
4799
- hedgesInFlight++;
4800
- lastLaunchAt = performance.now();
4801
- log3.debug(
4802
- `hedge launched part=${item.partNumber} copy=${hedgeCount + 1} after ${Math.round(performance.now() - t0)}ms`
4803
- );
4804
- run("hedge");
4745
+ if (!hedgeDue(item, lastLaunchAt)) return;
4746
+ replace(`slower than its peers after ${Math.round(performance.now() - t0)}ms`, true);
4805
4747
  }, policy.hedgePollMs);
4806
4748
  });
4807
4749
  const tPut = performance.now();
@@ -4812,17 +4754,15 @@ async function multipartUploadStream(options) {
4812
4754
  clock.delivered();
4813
4755
  lastSocketActivityAt = tPut;
4814
4756
  log3.debug(
4815
- `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` hedged\xD7${hedgeCount}` : ""}`
4757
+ `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` replaced\xD7${hedgeCount}` : ""}`
4816
4758
  );
4817
4759
  report("uploading");
4818
4760
  } finally {
4819
4761
  partsInFlight.delete(inFlight);
4820
- reconnect = () => {
4762
+ replace = () => {
4821
4763
  };
4822
4764
  if (hedgeTicker !== null) clearInterval(hedgeTicker);
4823
- hedgesInFlight -= liveHedges;
4824
- for (const ctl of controllers) ctl.abort();
4825
- for (const detach of detachFns) detach();
4765
+ current?.ctl.abort();
4826
4766
  }
4827
4767
  }
4828
4768
  const controlFetch = (url, init3, timeoutMs) => policyFetch(url, init3, timeoutMs, runSignal);
@@ -4927,6 +4867,10 @@ async function multipartUploadStream(options) {
4927
4867
  item.round = round;
4928
4868
  item.flowsAtStart = runningParts.size;
4929
4869
  let url = presignedUrlCache.get(item.partNumber);
4870
+ if (!url && presignPrefetchInFlight) {
4871
+ await presignPrefetchInFlight;
4872
+ url = presignedUrlCache.get(item.partNumber);
4873
+ }
4930
4874
  presignedUrlCache.delete(item.partNumber);
4931
4875
  schedulePresignPrefetch(item.partNumber + 1);
4932
4876
  await retrying(
@@ -11370,6 +11314,10 @@ var seal_mcp_v1_default = {
11370
11314
  server_info: "name `sealnet-mcp` (the npm package and its binary); version = `package.json::version`, injected at build time (tsup `define`), never a source literal. The state directory, the keychain service and the handoff directory keep the name `seal-mcp`: they are where existing state lives.",
11371
11315
  progress: "When a `tools/call` carries `_meta.progressToken`, `seal_share` and `seal_open mode=file` send `notifications/progress` with `progress` = ciphertext bytes done (upload: confirmed by storage) and `total` = ciphertext bytes in all; at most one per second, `progress` strictly increasing, the last one at `progress = total`."
11372
11316
  },
11317
+ server_instructions: {
11318
+ text: "SEAL moves files and secrets between people and agents without their content entering this conversation. When someone wants a file, folder or secret sent to them, to another machine or to another agent, call seal_share with its path and do not open, print or Read it first. When you need an API key, password, file or folder from the user, or they offer or ask how to give you one, call seal_request right away instead of explaining other ways or asking them to paste or upload it. Open a SEAL link someone gave you with seal_open (mode=file for secrets and large files).",
11319
+ note: "The `instructions` of the `initialize` result (SPEC-AGENTS \xA78.1). Hosts that defer MCP tools behind a tool search (Claude Code) show the model only tool names until it searches, but put these instructions into the system prompt: this is the one text a model reads before it decides to look for a tool, or reads the file it was asked to send."
11320
+ },
11373
11321
  tools: {
11374
11322
  seal_share: {
11375
11323
  title: "Share a file via SEAL",
@@ -13961,7 +13909,7 @@ function proFileGetOutputToWire(out) {
13961
13909
  }
13962
13910
 
13963
13911
  // src/server.ts
13964
- var SERVER_VERSION = "0.2.1";
13912
+ var SERVER_VERSION = "0.2.3";
13965
13913
  var toolMeta = (name) => {
13966
13914
  const { title, description, annotations } = seal_mcp_v1_default.tools[name];
13967
13915
  return { title, description, annotations };
@@ -14029,7 +13977,7 @@ async function createServer(options) {
14029
13977
  };
14030
13978
  const mcp = new McpServer(
14031
13979
  { name: "sealnet-mcp", version: SERVER_VERSION },
14032
- { capabilities: { tools: {} } }
13980
+ { capabilities: { tools: {} }, instructions: seal_mcp_v1_default.server_instructions.text }
14033
13981
  );
14034
13982
  const disableClipboard = process.env.SEAL_MCP_DISABLE_CLIPBOARD === "1";
14035
13983
  mcp.registerTool(
package/dist/index.cjs CHANGED
@@ -4137,6 +4137,10 @@ var seal_mcp_v1_default = {
4137
4137
  server_info: "name `sealnet-mcp` (the npm package and its binary); version = `package.json::version`, injected at build time (tsup `define`), never a source literal. The state directory, the keychain service and the handoff directory keep the name `seal-mcp`: they are where existing state lives.",
4138
4138
  progress: "When a `tools/call` carries `_meta.progressToken`, `seal_share` and `seal_open mode=file` send `notifications/progress` with `progress` = ciphertext bytes done (upload: confirmed by storage) and `total` = ciphertext bytes in all; at most one per second, `progress` strictly increasing, the last one at `progress = total`."
4139
4139
  },
4140
+ server_instructions: {
4141
+ text: "SEAL moves files and secrets between people and agents without their content entering this conversation. When someone wants a file, folder or secret sent to them, to another machine or to another agent, call seal_share with its path and do not open, print or Read it first. When you need an API key, password, file or folder from the user, or they offer or ask how to give you one, call seal_request right away instead of explaining other ways or asking them to paste or upload it. Open a SEAL link someone gave you with seal_open (mode=file for secrets and large files).",
4142
+ note: "The `instructions` of the `initialize` result (SPEC-AGENTS \xA78.1). Hosts that defer MCP tools behind a tool search (Claude Code) show the model only tool names until it searches, but put these instructions into the system prompt: this is the one text a model reads before it decides to look for a tool, or reads the file it was asked to send."
4143
+ },
4140
4144
  tools: {
4141
4145
  seal_share: {
4142
4146
  title: "Share a file via SEAL",
@@ -7579,7 +7583,6 @@ var upload_default = {
7579
7583
  HEDGE_MIN_INFLIGHT_MS: 3e3,
7580
7584
  HEDGE_LAG_FACTOR: 3,
7581
7585
  HEDGE_POLL_MS: 1e3,
7582
- HEDGE_MAX_CONCURRENT: 1,
7583
7586
  LIVENESS_SILENCE_MS: 3e4,
7584
7587
  RETRY_BACKOFF_MS: [1e3, 3e3, 7e3, 15e3, 3e4],
7585
7588
  RETRY_JITTER_RATIO: 0.2,
@@ -8874,7 +8877,6 @@ var DEFAULT_TRANSPORT_POLICY = {
8874
8877
  hedgeMinInflightMs: upload_default.upload.HEDGE_MIN_INFLIGHT_MS,
8875
8878
  hedgeLagFactor: upload_default.upload.HEDGE_LAG_FACTOR,
8876
8879
  hedgePollMs: upload_default.upload.HEDGE_POLL_MS,
8877
- hedgeMaxConcurrent: upload_default.upload.HEDGE_MAX_CONCURRENT,
8878
8880
  livenessSilenceMs: upload_default.upload.LIVENESS_SILENCE_MS,
8879
8881
  verifyPollBackoffMs: upload_default.upload.VERIFY_POLL_BACKOFF_MS,
8880
8882
  verifyFallbackWaitMs: upload_default.upload.VERIFY_FALLBACK_WAIT_MS,
@@ -9196,7 +9198,6 @@ async function multipartUploadStream(options) {
9196
9198
  let lastRoundRate = null;
9197
9199
  let roomWaiters = [];
9198
9200
  const fullPartPace = [];
9199
- let hedgesInFlight = 0;
9200
9201
  const partsInFlight = /* @__PURE__ */ new Set();
9201
9202
  let lastSocketActivityAt = performance.now();
9202
9203
  let socketActivityObservable = false;
@@ -9241,10 +9242,10 @@ async function multipartUploadStream(options) {
9241
9242
  roundBytes = 0;
9242
9243
  roundDeliveries = 0;
9243
9244
  }
9244
- function hedgeDue(item, lastLaunchAt, ownDuplicates) {
9245
+ function hedgeDue(item, lastLaunchAt) {
9245
9246
  const inFlightMs = performance.now() - lastLaunchAt;
9246
9247
  if (inFlightMs < policy.hedgeMinInflightMs) return false;
9247
- const flowsNow = runningParts.size + hedgesInFlight - ownDuplicates;
9248
+ const flowsNow = runningParts.size;
9248
9249
  const peers = fullPartPace.filter((p) => p.flows >= flowsNow).map((p) => p.rate);
9249
9250
  if (peers.length === 0) return false;
9250
9251
  peers.sort((a, b) => a - b);
@@ -9366,135 +9367,80 @@ async function multipartUploadStream(options) {
9366
9367
  }
9367
9368
  async function hedgedPut(item, presignedUrl) {
9368
9369
  const t0 = performance.now();
9369
- let controllers = [];
9370
- const detachFns = [];
9371
9370
  let hedgeTicker = null;
9372
9371
  let hedgeCount = 0;
9373
- let liveHedges = 0;
9374
- let currentHedge = null;
9375
9372
  let lastLaunchAt = t0;
9376
- let generation = 0;
9377
- const unsentByCopy = /* @__PURE__ */ new Map();
9378
- let reconnect = () => {
9379
- };
9380
- const launchCopy = async (isHedge) => {
9381
- const ctl = new AbortController();
9382
- controllers.push(ctl);
9383
- if (isHedge) currentHedge = ctl;
9384
- unsentByCopy.set(ctl, true);
9385
- lastSocketActivityAt = performance.now();
9386
- if (runSignal) {
9387
- if (runSignal.aborted) {
9388
- ctl.abort();
9389
- } else {
9390
- const onAbort = () => ctl.abort();
9391
- runSignal.addEventListener("abort", onAbort, { once: true });
9392
- detachFns.push(() => runSignal.removeEventListener("abort", onAbort));
9393
- }
9394
- }
9395
- try {
9396
- const outcome = await transportPut(
9397
- item.ciphertext,
9398
- item.contentMd5,
9399
- item.partNumber,
9400
- presignedUrl,
9401
- ctl.signal,
9402
- {
9403
- onSocketActivity: (loaded, total) => {
9404
- lastSocketActivityAt = performance.now();
9405
- unsentByCopy.set(ctl, loaded < total);
9406
- },
9407
- onDeadline: () => reconnect("copy deadline")
9408
- }
9409
- );
9410
- return validatePutOutcome(item.partNumber, outcome);
9411
- } finally {
9412
- unsentByCopy.delete(ctl);
9413
- }
9373
+ let current = null;
9374
+ let replace = () => {
9414
9375
  };
9415
9376
  const inFlight = {
9416
- reconnect: (why) => reconnect(why),
9417
- hasUnsentBytes: () => [...unsentByCopy.values()].some(Boolean)
9377
+ reconnect: (why) => replace(why, false),
9378
+ hasUnsentBytes: () => current?.unsent ?? false
9418
9379
  };
9419
9380
  partsInFlight.add(inFlight);
9420
9381
  try {
9421
9382
  const etag = await new Promise((resolve5, reject) => {
9422
- let pending = 0;
9423
9383
  let settled = false;
9424
- const run = (label) => {
9425
- const born = generation;
9426
- pending++;
9427
- launchCopy(label === "hedge").then((confirmedEtag) => {
9428
- if (settled) return;
9429
- settled = true;
9430
- if (label === "hedge") log3.debug(`hedge won part=${item.partNumber}`);
9431
- resolve5(confirmedEtag);
9432
- }).catch((err2) => {
9433
- if (settled || born !== generation) return;
9434
- pending--;
9435
- const failure = toUploadError(err2, `Failed to upload part ${item.partNumber}`);
9436
- if (label === "hedge") {
9437
- liveHedges--;
9438
- hedgesInFlight--;
9439
- currentHedge = null;
9440
- if (failure.code !== "ABORTED") hedgeCount--;
9441
- }
9442
- if (failure.code === "ABORTED" && signal?.aborted) {
9443
- settled = true;
9444
- reject(failure);
9445
- return;
9446
- }
9447
- if (pending === 0) {
9448
- if (hedgeTicker !== null) {
9449
- clearInterval(hedgeTicker);
9450
- hedgeTicker = null;
9384
+ const settle = (outcome) => {
9385
+ if (settled) return;
9386
+ settled = true;
9387
+ outcome();
9388
+ };
9389
+ const launch = () => {
9390
+ const ctl = new AbortController();
9391
+ const onUploadEnd = () => ctl.abort();
9392
+ if (runSignal?.aborted) ctl.abort();
9393
+ else runSignal?.addEventListener("abort", onUploadEnd, { once: true });
9394
+ const copy = { ctl, unsent: true, ended: Promise.resolve() };
9395
+ current = copy;
9396
+ lastLaunchAt = performance.now();
9397
+ lastSocketActivityAt = lastLaunchAt;
9398
+ copy.ended = transportPut(item.ciphertext, item.contentMd5, item.partNumber, presignedUrl, ctl.signal, {
9399
+ onSocketActivity: (loaded, total) => {
9400
+ lastSocketActivityAt = performance.now();
9401
+ copy.unsent = loaded < total;
9402
+ },
9403
+ onDeadline: () => replace("copy deadline", false)
9404
+ }).then(
9405
+ (outcome) => {
9406
+ if (current !== copy) return;
9407
+ try {
9408
+ const confirmed = validatePutOutcome(item.partNumber, outcome);
9409
+ settle(() => resolve5(confirmed));
9410
+ } catch (err2) {
9411
+ settle(() => reject(err2));
9451
9412
  }
9452
- settled = true;
9453
- reject(failure);
9413
+ },
9414
+ (err2) => {
9415
+ if (current === copy) settle(() => reject(toUploadError(err2, `Failed to upload part ${item.partNumber}`)));
9454
9416
  }
9417
+ ).finally(() => {
9418
+ copy.unsent = false;
9419
+ runSignal?.removeEventListener("abort", onUploadEnd);
9455
9420
  });
9456
9421
  };
9457
- reconnect = (why) => {
9458
- if (settled || signal?.aborted) return;
9459
- generation++;
9460
- pending = 0;
9461
- hedgesInFlight -= liveHedges;
9462
- liveHedges = 0;
9463
- hedgeCount = 0;
9464
- currentHedge = null;
9465
- const stale = controllers;
9466
- controllers = [];
9467
- for (const ctl of stale) ctl.abort();
9468
- lastLaunchAt = performance.now();
9469
- log3.debug(`reconnect part=${item.partNumber} (${why})`);
9470
- run("primary");
9422
+ replace = (why, spendsTicket) => {
9423
+ const old = current;
9424
+ if (settled || old === null || signal?.aborted) return;
9425
+ current = null;
9426
+ hedgeCount = spendsTicket ? hedgeCount + 1 : 0;
9427
+ log3.debug(`${spendsTicket ? "replace" : "reconnect"} part=${item.partNumber} (${why})`);
9428
+ old.ctl.abort();
9429
+ void old.ended.then(() => {
9430
+ if (settled) return;
9431
+ if (runSignal?.aborted) {
9432
+ settle(() => reject(new UploadError("Upload aborted", "ABORTED", void 0, item.partNumber)));
9433
+ } else {
9434
+ launch();
9435
+ }
9436
+ });
9471
9437
  };
9472
- run("primary");
9438
+ launch();
9473
9439
  hedgeTicker = setInterval(() => {
9474
- if (settled || signal?.aborted) {
9475
- if (hedgeTicker !== null) {
9476
- clearInterval(hedgeTicker);
9477
- hedgeTicker = null;
9478
- }
9479
- return;
9480
- }
9440
+ if (settled || signal?.aborted || current === null) return;
9481
9441
  if (hedgeCount >= HEDGE_MAX_PER_PART) return;
9482
- if (!hedgeDue(item, lastLaunchAt, liveHedges)) return;
9483
- if (hedgesInFlight >= policy.hedgeMaxConcurrent) {
9484
- if (currentHedge !== null) {
9485
- currentHedge.abort();
9486
- currentHedge = null;
9487
- }
9488
- return;
9489
- }
9490
- hedgeCount++;
9491
- liveHedges++;
9492
- hedgesInFlight++;
9493
- lastLaunchAt = performance.now();
9494
- log3.debug(
9495
- `hedge launched part=${item.partNumber} copy=${hedgeCount + 1} after ${Math.round(performance.now() - t0)}ms`
9496
- );
9497
- run("hedge");
9442
+ if (!hedgeDue(item, lastLaunchAt)) return;
9443
+ replace(`slower than its peers after ${Math.round(performance.now() - t0)}ms`, true);
9498
9444
  }, policy.hedgePollMs);
9499
9445
  });
9500
9446
  const tPut = performance.now();
@@ -9505,17 +9451,15 @@ async function multipartUploadStream(options) {
9505
9451
  clock.delivered();
9506
9452
  lastSocketActivityAt = tPut;
9507
9453
  log3.debug(
9508
- `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` hedged\xD7${hedgeCount}` : ""}`
9454
+ `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` replaced\xD7${hedgeCount}` : ""}`
9509
9455
  );
9510
9456
  report("uploading");
9511
9457
  } finally {
9512
9458
  partsInFlight.delete(inFlight);
9513
- reconnect = () => {
9459
+ replace = () => {
9514
9460
  };
9515
9461
  if (hedgeTicker !== null) clearInterval(hedgeTicker);
9516
- hedgesInFlight -= liveHedges;
9517
- for (const ctl of controllers) ctl.abort();
9518
- for (const detach of detachFns) detach();
9462
+ current?.ctl.abort();
9519
9463
  }
9520
9464
  }
9521
9465
  const controlFetch = (url, init3, timeoutMs) => policyFetch(url, init3, timeoutMs, runSignal);
@@ -9620,6 +9564,10 @@ async function multipartUploadStream(options) {
9620
9564
  item.round = round;
9621
9565
  item.flowsAtStart = runningParts.size;
9622
9566
  let url = presignedUrlCache.get(item.partNumber);
9567
+ if (!url && presignPrefetchInFlight) {
9568
+ await presignPrefetchInFlight;
9569
+ url = presignedUrlCache.get(item.partNumber);
9570
+ }
9623
9571
  presignedUrlCache.delete(item.partNumber);
9624
9572
  schedulePresignPrefetch(item.partNumber + 1);
9625
9573
  await retrying(
@@ -13844,7 +13792,7 @@ function proFileGetOutputToWire(out) {
13844
13792
  }
13845
13793
 
13846
13794
  // src/server.ts
13847
- var SERVER_VERSION = "0.2.1";
13795
+ var SERVER_VERSION = "0.2.3";
13848
13796
  var toolMeta = (name) => {
13849
13797
  const { title, description, annotations } = seal_mcp_v1_default.tools[name];
13850
13798
  return { title, description, annotations };
@@ -13912,7 +13860,7 @@ async function createServer(options) {
13912
13860
  };
13913
13861
  const mcp = new import_mcp.McpServer(
13914
13862
  { name: "sealnet-mcp", version: SERVER_VERSION },
13915
- { capabilities: { tools: {} } }
13863
+ { capabilities: { tools: {} }, instructions: seal_mcp_v1_default.server_instructions.text }
13916
13864
  );
13917
13865
  const disableClipboard = process.env.SEAL_MCP_DISABLE_CLIPBOARD === "1";
13918
13866
  mcp.registerTool(
package/dist/index.d.cts CHANGED
@@ -218,7 +218,8 @@ interface TransportPolicy {
218
218
  /**
219
219
  * Parallel part PUTs: where the pool starts, and how wide it may get.
220
220
  * Storage speaks HTTP/1.1 only, so every PUT is a connection of its own and
221
- * a browser gives a host six: `poolMax` + `hedgeMaxConcurrent` must fit.
221
+ * a browser gives a host six: `poolMax` must fit. A replacement takes the
222
+ * connection of the copy it replaces, never a second one (F-263).
222
223
  */
223
224
  poolStart: number;
224
225
  poolMax: number;
@@ -234,13 +235,11 @@ interface TransportPolicy {
234
235
  poolShrinkRatio: number;
235
236
  /** Encrypted parts that may wait for a slot (bounds memory). */
236
237
  partQueueLimit: number;
237
- /** Never duplicate a part before it has been in flight this long. */
238
+ /** Never replace a copy before it has been in flight this long. */
238
239
  hedgeMinInflightMs: number;
239
240
  /** A part is an outlier when it is this many times slower than its peers' median. */
240
241
  hedgeLagFactor: number;
241
242
  hedgePollMs: number;
242
- /** Duplicate copies in flight across the whole upload, at most. */
243
- hedgeMaxConcurrent: number;
244
243
  /**
245
244
  * No part delivered and no socket of ANY copy taking bytes for this long,
246
245
  * while some copy still has bytes to send ⇒ the connections are dead: every
package/dist/index.d.ts CHANGED
@@ -218,7 +218,8 @@ interface TransportPolicy {
218
218
  /**
219
219
  * Parallel part PUTs: where the pool starts, and how wide it may get.
220
220
  * Storage speaks HTTP/1.1 only, so every PUT is a connection of its own and
221
- * a browser gives a host six: `poolMax` + `hedgeMaxConcurrent` must fit.
221
+ * a browser gives a host six: `poolMax` must fit. A replacement takes the
222
+ * connection of the copy it replaces, never a second one (F-263).
222
223
  */
223
224
  poolStart: number;
224
225
  poolMax: number;
@@ -234,13 +235,11 @@ interface TransportPolicy {
234
235
  poolShrinkRatio: number;
235
236
  /** Encrypted parts that may wait for a slot (bounds memory). */
236
237
  partQueueLimit: number;
237
- /** Never duplicate a part before it has been in flight this long. */
238
+ /** Never replace a copy before it has been in flight this long. */
238
239
  hedgeMinInflightMs: number;
239
240
  /** A part is an outlier when it is this many times slower than its peers' median. */
240
241
  hedgeLagFactor: number;
241
242
  hedgePollMs: number;
242
- /** Duplicate copies in flight across the whole upload, at most. */
243
- hedgeMaxConcurrent: number;
244
243
  /**
245
244
  * No part delivered and no socket of ANY copy taking bytes for this long,
246
245
  * while some copy still has bytes to send ⇒ the connections are dead: every
package/dist/index.js CHANGED
@@ -4065,6 +4065,10 @@ var seal_mcp_v1_default = {
4065
4065
  server_info: "name `sealnet-mcp` (the npm package and its binary); version = `package.json::version`, injected at build time (tsup `define`), never a source literal. The state directory, the keychain service and the handoff directory keep the name `seal-mcp`: they are where existing state lives.",
4066
4066
  progress: "When a `tools/call` carries `_meta.progressToken`, `seal_share` and `seal_open mode=file` send `notifications/progress` with `progress` = ciphertext bytes done (upload: confirmed by storage) and `total` = ciphertext bytes in all; at most one per second, `progress` strictly increasing, the last one at `progress = total`."
4067
4067
  },
4068
+ server_instructions: {
4069
+ text: "SEAL moves files and secrets between people and agents without their content entering this conversation. When someone wants a file, folder or secret sent to them, to another machine or to another agent, call seal_share with its path and do not open, print or Read it first. When you need an API key, password, file or folder from the user, or they offer or ask how to give you one, call seal_request right away instead of explaining other ways or asking them to paste or upload it. Open a SEAL link someone gave you with seal_open (mode=file for secrets and large files).",
4070
+ note: "The `instructions` of the `initialize` result (SPEC-AGENTS \xA78.1). Hosts that defer MCP tools behind a tool search (Claude Code) show the model only tool names until it searches, but put these instructions into the system prompt: this is the one text a model reads before it decides to look for a tool, or reads the file it was asked to send."
4071
+ },
4068
4072
  tools: {
4069
4073
  seal_share: {
4070
4074
  title: "Share a file via SEAL",
@@ -7507,7 +7511,6 @@ var upload_default = {
7507
7511
  HEDGE_MIN_INFLIGHT_MS: 3e3,
7508
7512
  HEDGE_LAG_FACTOR: 3,
7509
7513
  HEDGE_POLL_MS: 1e3,
7510
- HEDGE_MAX_CONCURRENT: 1,
7511
7514
  LIVENESS_SILENCE_MS: 3e4,
7512
7515
  RETRY_BACKOFF_MS: [1e3, 3e3, 7e3, 15e3, 3e4],
7513
7516
  RETRY_JITTER_RATIO: 0.2,
@@ -8802,7 +8805,6 @@ var DEFAULT_TRANSPORT_POLICY = {
8802
8805
  hedgeMinInflightMs: upload_default.upload.HEDGE_MIN_INFLIGHT_MS,
8803
8806
  hedgeLagFactor: upload_default.upload.HEDGE_LAG_FACTOR,
8804
8807
  hedgePollMs: upload_default.upload.HEDGE_POLL_MS,
8805
- hedgeMaxConcurrent: upload_default.upload.HEDGE_MAX_CONCURRENT,
8806
8808
  livenessSilenceMs: upload_default.upload.LIVENESS_SILENCE_MS,
8807
8809
  verifyPollBackoffMs: upload_default.upload.VERIFY_POLL_BACKOFF_MS,
8808
8810
  verifyFallbackWaitMs: upload_default.upload.VERIFY_FALLBACK_WAIT_MS,
@@ -9124,7 +9126,6 @@ async function multipartUploadStream(options) {
9124
9126
  let lastRoundRate = null;
9125
9127
  let roomWaiters = [];
9126
9128
  const fullPartPace = [];
9127
- let hedgesInFlight = 0;
9128
9129
  const partsInFlight = /* @__PURE__ */ new Set();
9129
9130
  let lastSocketActivityAt = performance.now();
9130
9131
  let socketActivityObservable = false;
@@ -9169,10 +9170,10 @@ async function multipartUploadStream(options) {
9169
9170
  roundBytes = 0;
9170
9171
  roundDeliveries = 0;
9171
9172
  }
9172
- function hedgeDue(item, lastLaunchAt, ownDuplicates) {
9173
+ function hedgeDue(item, lastLaunchAt) {
9173
9174
  const inFlightMs = performance.now() - lastLaunchAt;
9174
9175
  if (inFlightMs < policy.hedgeMinInflightMs) return false;
9175
- const flowsNow = runningParts.size + hedgesInFlight - ownDuplicates;
9176
+ const flowsNow = runningParts.size;
9176
9177
  const peers = fullPartPace.filter((p) => p.flows >= flowsNow).map((p) => p.rate);
9177
9178
  if (peers.length === 0) return false;
9178
9179
  peers.sort((a, b) => a - b);
@@ -9294,135 +9295,80 @@ async function multipartUploadStream(options) {
9294
9295
  }
9295
9296
  async function hedgedPut(item, presignedUrl) {
9296
9297
  const t0 = performance.now();
9297
- let controllers = [];
9298
- const detachFns = [];
9299
9298
  let hedgeTicker = null;
9300
9299
  let hedgeCount = 0;
9301
- let liveHedges = 0;
9302
- let currentHedge = null;
9303
9300
  let lastLaunchAt = t0;
9304
- let generation = 0;
9305
- const unsentByCopy = /* @__PURE__ */ new Map();
9306
- let reconnect = () => {
9307
- };
9308
- const launchCopy = async (isHedge) => {
9309
- const ctl = new AbortController();
9310
- controllers.push(ctl);
9311
- if (isHedge) currentHedge = ctl;
9312
- unsentByCopy.set(ctl, true);
9313
- lastSocketActivityAt = performance.now();
9314
- if (runSignal) {
9315
- if (runSignal.aborted) {
9316
- ctl.abort();
9317
- } else {
9318
- const onAbort = () => ctl.abort();
9319
- runSignal.addEventListener("abort", onAbort, { once: true });
9320
- detachFns.push(() => runSignal.removeEventListener("abort", onAbort));
9321
- }
9322
- }
9323
- try {
9324
- const outcome = await transportPut(
9325
- item.ciphertext,
9326
- item.contentMd5,
9327
- item.partNumber,
9328
- presignedUrl,
9329
- ctl.signal,
9330
- {
9331
- onSocketActivity: (loaded, total) => {
9332
- lastSocketActivityAt = performance.now();
9333
- unsentByCopy.set(ctl, loaded < total);
9334
- },
9335
- onDeadline: () => reconnect("copy deadline")
9336
- }
9337
- );
9338
- return validatePutOutcome(item.partNumber, outcome);
9339
- } finally {
9340
- unsentByCopy.delete(ctl);
9341
- }
9301
+ let current = null;
9302
+ let replace = () => {
9342
9303
  };
9343
9304
  const inFlight = {
9344
- reconnect: (why) => reconnect(why),
9345
- hasUnsentBytes: () => [...unsentByCopy.values()].some(Boolean)
9305
+ reconnect: (why) => replace(why, false),
9306
+ hasUnsentBytes: () => current?.unsent ?? false
9346
9307
  };
9347
9308
  partsInFlight.add(inFlight);
9348
9309
  try {
9349
9310
  const etag = await new Promise((resolve5, reject) => {
9350
- let pending = 0;
9351
9311
  let settled = false;
9352
- const run = (label) => {
9353
- const born = generation;
9354
- pending++;
9355
- launchCopy(label === "hedge").then((confirmedEtag) => {
9356
- if (settled) return;
9357
- settled = true;
9358
- if (label === "hedge") log3.debug(`hedge won part=${item.partNumber}`);
9359
- resolve5(confirmedEtag);
9360
- }).catch((err2) => {
9361
- if (settled || born !== generation) return;
9362
- pending--;
9363
- const failure = toUploadError(err2, `Failed to upload part ${item.partNumber}`);
9364
- if (label === "hedge") {
9365
- liveHedges--;
9366
- hedgesInFlight--;
9367
- currentHedge = null;
9368
- if (failure.code !== "ABORTED") hedgeCount--;
9369
- }
9370
- if (failure.code === "ABORTED" && signal?.aborted) {
9371
- settled = true;
9372
- reject(failure);
9373
- return;
9374
- }
9375
- if (pending === 0) {
9376
- if (hedgeTicker !== null) {
9377
- clearInterval(hedgeTicker);
9378
- hedgeTicker = null;
9312
+ const settle = (outcome) => {
9313
+ if (settled) return;
9314
+ settled = true;
9315
+ outcome();
9316
+ };
9317
+ const launch = () => {
9318
+ const ctl = new AbortController();
9319
+ const onUploadEnd = () => ctl.abort();
9320
+ if (runSignal?.aborted) ctl.abort();
9321
+ else runSignal?.addEventListener("abort", onUploadEnd, { once: true });
9322
+ const copy = { ctl, unsent: true, ended: Promise.resolve() };
9323
+ current = copy;
9324
+ lastLaunchAt = performance.now();
9325
+ lastSocketActivityAt = lastLaunchAt;
9326
+ copy.ended = transportPut(item.ciphertext, item.contentMd5, item.partNumber, presignedUrl, ctl.signal, {
9327
+ onSocketActivity: (loaded, total) => {
9328
+ lastSocketActivityAt = performance.now();
9329
+ copy.unsent = loaded < total;
9330
+ },
9331
+ onDeadline: () => replace("copy deadline", false)
9332
+ }).then(
9333
+ (outcome) => {
9334
+ if (current !== copy) return;
9335
+ try {
9336
+ const confirmed = validatePutOutcome(item.partNumber, outcome);
9337
+ settle(() => resolve5(confirmed));
9338
+ } catch (err2) {
9339
+ settle(() => reject(err2));
9379
9340
  }
9380
- settled = true;
9381
- reject(failure);
9341
+ },
9342
+ (err2) => {
9343
+ if (current === copy) settle(() => reject(toUploadError(err2, `Failed to upload part ${item.partNumber}`)));
9382
9344
  }
9345
+ ).finally(() => {
9346
+ copy.unsent = false;
9347
+ runSignal?.removeEventListener("abort", onUploadEnd);
9383
9348
  });
9384
9349
  };
9385
- reconnect = (why) => {
9386
- if (settled || signal?.aborted) return;
9387
- generation++;
9388
- pending = 0;
9389
- hedgesInFlight -= liveHedges;
9390
- liveHedges = 0;
9391
- hedgeCount = 0;
9392
- currentHedge = null;
9393
- const stale = controllers;
9394
- controllers = [];
9395
- for (const ctl of stale) ctl.abort();
9396
- lastLaunchAt = performance.now();
9397
- log3.debug(`reconnect part=${item.partNumber} (${why})`);
9398
- run("primary");
9350
+ replace = (why, spendsTicket) => {
9351
+ const old = current;
9352
+ if (settled || old === null || signal?.aborted) return;
9353
+ current = null;
9354
+ hedgeCount = spendsTicket ? hedgeCount + 1 : 0;
9355
+ log3.debug(`${spendsTicket ? "replace" : "reconnect"} part=${item.partNumber} (${why})`);
9356
+ old.ctl.abort();
9357
+ void old.ended.then(() => {
9358
+ if (settled) return;
9359
+ if (runSignal?.aborted) {
9360
+ settle(() => reject(new UploadError("Upload aborted", "ABORTED", void 0, item.partNumber)));
9361
+ } else {
9362
+ launch();
9363
+ }
9364
+ });
9399
9365
  };
9400
- run("primary");
9366
+ launch();
9401
9367
  hedgeTicker = setInterval(() => {
9402
- if (settled || signal?.aborted) {
9403
- if (hedgeTicker !== null) {
9404
- clearInterval(hedgeTicker);
9405
- hedgeTicker = null;
9406
- }
9407
- return;
9408
- }
9368
+ if (settled || signal?.aborted || current === null) return;
9409
9369
  if (hedgeCount >= HEDGE_MAX_PER_PART) return;
9410
- if (!hedgeDue(item, lastLaunchAt, liveHedges)) return;
9411
- if (hedgesInFlight >= policy.hedgeMaxConcurrent) {
9412
- if (currentHedge !== null) {
9413
- currentHedge.abort();
9414
- currentHedge = null;
9415
- }
9416
- return;
9417
- }
9418
- hedgeCount++;
9419
- liveHedges++;
9420
- hedgesInFlight++;
9421
- lastLaunchAt = performance.now();
9422
- log3.debug(
9423
- `hedge launched part=${item.partNumber} copy=${hedgeCount + 1} after ${Math.round(performance.now() - t0)}ms`
9424
- );
9425
- run("hedge");
9370
+ if (!hedgeDue(item, lastLaunchAt)) return;
9371
+ replace(`slower than its peers after ${Math.round(performance.now() - t0)}ms`, true);
9426
9372
  }, policy.hedgePollMs);
9427
9373
  });
9428
9374
  const tPut = performance.now();
@@ -9433,17 +9379,15 @@ async function multipartUploadStream(options) {
9433
9379
  clock.delivered();
9434
9380
  lastSocketActivityAt = tPut;
9435
9381
  log3.debug(
9436
- `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` hedged\xD7${hedgeCount}` : ""}`
9382
+ `part=${item.partNumber}/${totalParts} put=${Math.round(tPut - t0)}ms size=${item.ciphertext.length}${hedgeCount > 0 ? ` replaced\xD7${hedgeCount}` : ""}`
9437
9383
  );
9438
9384
  report("uploading");
9439
9385
  } finally {
9440
9386
  partsInFlight.delete(inFlight);
9441
- reconnect = () => {
9387
+ replace = () => {
9442
9388
  };
9443
9389
  if (hedgeTicker !== null) clearInterval(hedgeTicker);
9444
- hedgesInFlight -= liveHedges;
9445
- for (const ctl of controllers) ctl.abort();
9446
- for (const detach of detachFns) detach();
9390
+ current?.ctl.abort();
9447
9391
  }
9448
9392
  }
9449
9393
  const controlFetch = (url, init3, timeoutMs) => policyFetch(url, init3, timeoutMs, runSignal);
@@ -9548,6 +9492,10 @@ async function multipartUploadStream(options) {
9548
9492
  item.round = round;
9549
9493
  item.flowsAtStart = runningParts.size;
9550
9494
  let url = presignedUrlCache.get(item.partNumber);
9495
+ if (!url && presignPrefetchInFlight) {
9496
+ await presignPrefetchInFlight;
9497
+ url = presignedUrlCache.get(item.partNumber);
9498
+ }
9551
9499
  presignedUrlCache.delete(item.partNumber);
9552
9500
  schedulePresignPrefetch(item.partNumber + 1);
9553
9501
  await retrying(
@@ -13772,7 +13720,7 @@ function proFileGetOutputToWire(out) {
13772
13720
  }
13773
13721
 
13774
13722
  // src/server.ts
13775
- var SERVER_VERSION = "0.2.1";
13723
+ var SERVER_VERSION = "0.2.3";
13776
13724
  var toolMeta = (name) => {
13777
13725
  const { title, description, annotations } = seal_mcp_v1_default.tools[name];
13778
13726
  return { title, description, annotations };
@@ -13840,7 +13788,7 @@ async function createServer(options) {
13840
13788
  };
13841
13789
  const mcp = new McpServer(
13842
13790
  { name: "sealnet-mcp", version: SERVER_VERSION },
13843
- { capabilities: { tools: {} } }
13791
+ { capabilities: { tools: {} }, instructions: seal_mcp_v1_default.server_instructions.text }
13844
13792
  );
13845
13793
  const disableClipboard = process.env.SEAL_MCP_DISABLE_CLIPBOARD === "1";
13846
13794
  mcp.registerTool(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sealnet-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "mcpName": "net.seal/mcp",
5
5
  "description": "Model Context Protocol server for SEAL — model never holds capability by default (handoff mode); explicit opt-in to forward mode with strict TTL/recipient policy.",
6
6
  "type": "module",