@codeforbreakfast/commy-mcp 0.19.0 → 0.20.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +75 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeforbreakfast/commy-mcp",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "commy MCP server — the inter-agent communication substrate, runnable on node via npx.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/server.js CHANGED
@@ -3048,13 +3048,14 @@ var require_data = __commonJS((exports, module) => {
3048
3048
  };
3049
3049
  });
3050
3050
 
3051
- // node_modules/.bun/fast-uri@4.0.0/node_modules/fast-uri/lib/utils.js
3051
+ // node_modules/.bun/fast-uri@4.1.0/node_modules/fast-uri/lib/utils.js
3052
3052
  var require_utils = __commonJS((exports, module) => {
3053
3053
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
3054
3054
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
3055
3055
  var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
3056
3056
  var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
3057
3057
  var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
3058
+ var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/?]$/iu);
3058
3059
  function stringArrayToHexStripped(input) {
3059
3060
  let acc = "";
3060
3061
  let code = 0;
@@ -3198,7 +3199,7 @@ var require_utils = __commonJS((exports, module) => {
3198
3199
  continue;
3199
3200
  }
3200
3201
  } else if (input[0] === "/") {
3201
- if (input[1] === "." || input[1] === "/") {
3202
+ if (input[1] === ".") {
3202
3203
  output.push("/");
3203
3204
  break;
3204
3205
  }
@@ -3340,6 +3341,47 @@ var require_utils = __commonJS((exports, module) => {
3340
3341
  }
3341
3342
  return output;
3342
3343
  }
3344
+ function normalizeQueryFragmentEncoding(input) {
3345
+ let output = "";
3346
+ for (let i = 0;i < input.length; i++) {
3347
+ const ch = input[i];
3348
+ if (ch === "%" && i + 2 < input.length) {
3349
+ const hex = input.slice(i + 1, i + 3);
3350
+ if (isHexPair(hex)) {
3351
+ const normalizedHex = hex.toUpperCase();
3352
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3353
+ if (isUnreserved(decoded)) {
3354
+ output += decoded;
3355
+ } else {
3356
+ output += "%" + normalizedHex;
3357
+ }
3358
+ i += 2;
3359
+ continue;
3360
+ }
3361
+ }
3362
+ if (isQueryFragmentCharacter(ch)) {
3363
+ output += ch;
3364
+ } else {
3365
+ const code = input.charCodeAt(i);
3366
+ if (code < 128) {
3367
+ output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
3368
+ } else if (code < 55296 || code > 57343) {
3369
+ output += percentEncodeNonAscii(code);
3370
+ } else if (code <= 56319 && i + 1 < input.length) {
3371
+ const low = input.charCodeAt(i + 1);
3372
+ if (low >= 56320 && low <= 57343) {
3373
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
3374
+ i++;
3375
+ } else {
3376
+ output += percentEncodeNonAscii(65533);
3377
+ }
3378
+ } else {
3379
+ output += percentEncodeNonAscii(65533);
3380
+ }
3381
+ }
3382
+ }
3383
+ return output;
3384
+ }
3343
3385
  function escapePreservingEscapes(input) {
3344
3386
  let output = "";
3345
3387
  for (let i = 0;i < input.length; i++) {
@@ -3401,6 +3443,7 @@ var require_utils = __commonJS((exports, module) => {
3401
3443
  reescapeHostDelimiters,
3402
3444
  normalizePercentEncoding,
3403
3445
  normalizePathEncoding,
3446
+ normalizeQueryFragmentEncoding,
3404
3447
  escapePreservingEscapes,
3405
3448
  removeDotSegments,
3406
3449
  isIPv4,
@@ -3410,7 +3453,7 @@ var require_utils = __commonJS((exports, module) => {
3410
3453
  };
3411
3454
  });
3412
3455
 
3413
- // node_modules/.bun/fast-uri@4.0.0/node_modules/fast-uri/lib/schemes.js
3456
+ // node_modules/.bun/fast-uri@4.1.0/node_modules/fast-uri/lib/schemes.js
3414
3457
  var require_schemes = __commonJS((exports, module) => {
3415
3458
  var { isUUID } = require_utils();
3416
3459
  var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
@@ -3584,9 +3627,9 @@ var require_schemes = __commonJS((exports, module) => {
3584
3627
  };
3585
3628
  });
3586
3629
 
3587
- // node_modules/.bun/fast-uri@4.0.0/node_modules/fast-uri/index.js
3630
+ // node_modules/.bun/fast-uri@4.1.0/node_modules/fast-uri/index.js
3588
3631
  var require_fast_uri = __commonJS((exports, module) => {
3589
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3632
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, normalizeQueryFragmentEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3590
3633
  var { SCHEMES, getSchemeHandler } = require_schemes();
3591
3634
  function normalize3(uri, options5) {
3592
3635
  if (typeof uri === "string") {
@@ -3755,7 +3798,7 @@ var require_fast_uri = __commonJS((exports, module) => {
3755
3798
  }
3756
3799
  const matches = uri.match(URI_PARSE);
3757
3800
  if (matches) {
3758
- parsed.scheme = matches[1];
3801
+ parsed.scheme = matches[1] === undefined ? undefined : matches[1].toLowerCase();
3759
3802
  parsed.userinfo = matches[3];
3760
3803
  parsed.host = matches[4];
3761
3804
  parsed.port = parseInt(matches[5], 10);
@@ -3796,7 +3839,7 @@ var require_fast_uri = __commonJS((exports, module) => {
3796
3839
  if (!options5.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
3797
3840
  if (parsed.host && (options5.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
3798
3841
  try {
3799
- parsed.host = URL.domainToASCII(parsed.host.toLowerCase());
3842
+ parsed.host = new URL("http://" + parsed.host).hostname;
3800
3843
  } catch (e) {
3801
3844
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
3802
3845
  }
@@ -3814,12 +3857,11 @@ var require_fast_uri = __commonJS((exports, module) => {
3814
3857
  if (parsed.path) {
3815
3858
  parsed.path = normalizePathEncoding(parsed.path);
3816
3859
  }
3860
+ if (parsed.query) {
3861
+ parsed.query = normalizeQueryFragmentEncoding(parsed.query);
3862
+ }
3817
3863
  if (parsed.fragment) {
3818
- try {
3819
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3820
- } catch {
3821
- parsed.error = parsed.error || "URI malformed";
3822
- }
3864
+ parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
3823
3865
  }
3824
3866
  }
3825
3867
  if (schemeHandler && schemeHandler.parse) {
@@ -47676,6 +47718,7 @@ var markReplayed = (events) => events.map((ev) => {
47676
47718
  return ev;
47677
47719
  });
47678
47720
  var defaultRetrySchedule = exports_Schedule.exponential(exports_Duration.seconds(1)).pipe(exports_Schedule.either(exports_Schedule.spaced(exports_Duration.seconds(30))));
47721
+ var RESUME_VERDICT_FALLBACK = exports_Duration.seconds(60);
47679
47722
  var skipWithLog = (line) => exports_Effect.logInfo(line).pipe(exports_Effect.as([]));
47680
47723
  var processSingleEvent = (evt, directory, config2) => {
47681
47724
  if (evt.type === "message") {
@@ -47707,7 +47750,7 @@ var processSingleEvent = (evt, directory, config2) => {
47707
47750
  }
47708
47751
  return exports_Effect.succeed([]);
47709
47752
  };
47710
- var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function* () {
47753
+ var inboxEvents = (config2) => exports_Stream.unwrapScoped(exports_Effect.gen(function* () {
47711
47754
  const watermark = config2.watermarkStore ?? (yield* createWatermarkStore());
47712
47755
  const breadcrumb = yield* exports_Ref.make({
47713
47756
  consecutiveFailures: 0,
@@ -47720,6 +47763,9 @@ var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function
47720
47763
  return exports_Effect.void;
47721
47764
  return exports_Ref.getAndSet(resumeReported, true).pipe(exports_Effect.flatMap((already) => already ? exports_Effect.void : onResumeOutcome(queueReplayed)));
47722
47765
  };
47766
+ if (config2.onResumeOutcome !== undefined) {
47767
+ yield* exports_Effect.forkScoped(exports_Effect.sleep(RESUME_VERDICT_FALLBACK).pipe(exports_Effect.zipRight(reportResume(false))));
47768
+ }
47723
47769
  const recordTransientFailure = (cause3) => exports_Ref.modify(breadcrumb, (s) => {
47724
47770
  const consecutiveFailures = s.consecutiveFailures + 1;
47725
47771
  return [consecutiveFailures, { consecutiveFailures, needsBreadcrumb: true }];
@@ -47954,6 +48000,7 @@ var sanitiseShortName = (name) => {
47954
48000
  const collapsed = name.toLowerCase().replace(SHORT_NAME_PATTERN, "-");
47955
48001
  return collapsed.replace(/^-+|-+$/g, "") || "bot";
47956
48002
  };
48003
+ var ACQUIRE_MINT_TIMEOUT = exports_Duration.seconds(30);
47957
48004
  var userSchema = exports_Schema.Struct({
47958
48005
  user_id: exports_Schema.Int,
47959
48006
  email: exports_Schema.String,
@@ -48226,7 +48273,7 @@ var zulipAdapter = (config2) => exports_Effect.gen(function* () {
48226
48273
  }
48227
48274
  return exports_Effect.die(new Error(`zulipAdapter: already bound to ${existing.acquiredName} — release() before acquiring ${name}`));
48228
48275
  },
48229
- onNone: () => provideMintedFor(name).pipe(exports_Effect.flatMap((minted) => exports_Effect.gen(function* () {
48276
+ onNone: () => provideMintedFor(name).pipe(exports_Effect.timeout(ACQUIRE_MINT_TIMEOUT), exports_Effect.flatMap((minted) => exports_Effect.gen(function* () {
48230
48277
  const innerHttp = yield* makeZulipHttp(buildHttpConfig(config2.realmUrl, minted.email, minted.apiKey, config2.hostHeader)).pipe(exports_Effect.provideService(exports_HttpClient.HttpClient, httpClient));
48231
48278
  const http = wrapBotHttp(innerHttp, recipientDirectory, minted.userId);
48232
48279
  const ident = {
@@ -48360,15 +48407,25 @@ var zulipAdapter = (config2) => exports_Effect.gen(function* () {
48360
48407
  })))
48361
48408
  })))), exports_Effect.mapError((cause3) => cause3 instanceof PublisherError ? cause3 : new PublisherError({ operation, cause: cause3 })));
48362
48409
  };
48410
+ const addressThread = (channel, thread) => {
48411
+ const resolvedTopic = applyResolvedPrefix(thread, true);
48412
+ return findNewestInTopic(channel, thread).pipe(exports_Effect.flatMap(exports_Option.match({
48413
+ onSome: () => exports_Effect.succeed({ topic: thread, resolved: false }),
48414
+ onNone: () => findNewestInTopic(channel, resolvedTopic).pipe(exports_Effect.map(exports_Option.match({
48415
+ onSome: () => ({ topic: resolvedTopic, resolved: true }),
48416
+ onNone: () => ({ topic: thread, resolved: false })
48417
+ })))
48418
+ })));
48419
+ };
48363
48420
  const publisher = {
48364
48421
  post: (channel, body, opts) => {
48365
48422
  const thread = opts?.thread;
48366
- return boundHttp().pipe(exports_Effect.flatMap((http) => resolvePublishChannel(channel).pipe(exports_Effect.flatMap((effective) => http.post("/messages", sentMessageSchema, {
48423
+ return boundHttp().pipe(exports_Effect.flatMap((http) => resolvePublishChannel(channel).pipe(exports_Effect.flatMap((effective) => (thread === undefined ? exports_Effect.succeed({ topic: "(no topic)", resolved: false }) : addressThread(effective.name, thread)).pipe(exports_Effect.flatMap((addressed) => http.post("/messages", sentMessageSchema, {
48367
48424
  type: "channel",
48368
48425
  to: effective.name,
48369
48426
  content: body,
48370
- topic: thread ?? "(no topic)"
48371
- }).pipe(exports_Effect.flatMap((sent) => decodeMessageId(String(sent.id)).pipe(exports_Effect.map((id3) => decorateMessageRef(id3, effective, thread === undefined ? undefined : { name: thread, resolved: false })))))))), exports_Effect.mapError((cause3) => cause3 instanceof UnknownChannel ? cause3 : new PublisherError({ operation: "post", cause: cause3 })));
48427
+ topic: addressed.topic
48428
+ }).pipe(exports_Effect.flatMap((sent) => decodeMessageId(String(sent.id)).pipe(exports_Effect.map((id3) => decorateMessageRef(id3, effective, thread === undefined ? undefined : { name: thread, resolved: addressed.resolved })))))))))), exports_Effect.mapError((cause3) => cause3 instanceof UnknownChannel ? cause3 : new PublisherError({ operation: "post", cause: cause3 })));
48372
48429
  },
48373
48430
  edit: (message, body) => boundHttp().pipe(exports_Effect.flatMap((http) => http.patch(`/messages/${encodeURIComponent(message.id)}`, successSchema2, {
48374
48431
  content: body
@@ -58849,7 +58906,7 @@ class Server extends Protocol {
58849
58906
  }
58850
58907
 
58851
58908
  // packages/mcp/mcp-server.ts
58852
- var PLUGIN_VERSION = "0.19.0";
58909
+ var PLUGIN_VERSION = "0.20.0";
58853
58910
  var COMMY_INSTRUCTIONS = `**Substrate.** commy is the inter-agent channel: agents and humans coordinate here. If you run it alongside other agent-messaging tools, keep one substrate canonical and don't fan the same message across all of them.
58854
58911
 
58855
58912
  **Channels.** Each project has one channel: \`#<project-slug>\` where the slug is resolved per session as \`COMMY_PROJECT\` env > git remote \`origin\` basename > git root basename. Sessions launched outside a git repo (e.g. \`/tmp\`, \`$HOME\`) have no project channel and should post to \`#general\` instead. Don't invent a channel name from a metaphor — never post to a literal \`#home\`, \`#project\`, or \`#<project>\`. Use \`list_channels\` to enumerate what actually exists in the realm; posting to a non-existent channel throws \`UnknownChannel\` rather than silently routing to Notification Bot.