@codeforbreakfast/commy-mcp 0.18.0 → 0.19.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.
- package/package.json +1 -1
- package/server.js +171 -94
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -47638,9 +47638,11 @@ var reactionToInboundEvent = (reaction, directory, target) => exports_Effect.gen
|
|
|
47638
47638
|
by
|
|
47639
47639
|
};
|
|
47640
47640
|
});
|
|
47641
|
-
var
|
|
47641
|
+
var MAX_QUEUE_TIMEOUT_SECS = 604800;
|
|
47642
|
+
var registerQueue = (http, mode, idleTimeoutSecs) => {
|
|
47642
47643
|
const baseParams = { event_types: JSON.stringify(["message", "reaction"]) };
|
|
47643
|
-
const
|
|
47644
|
+
const modeParams = mode === "mentions" ? { ...baseParams, narrow: JSON.stringify([["is", "mentioned"]]) } : baseParams;
|
|
47645
|
+
const params = idleTimeoutSecs === undefined ? modeParams : { ...modeParams, idle_queue_timeout: idleTimeoutSecs };
|
|
47644
47646
|
return http.post("/register", registerResponseSchema, params).pipe(exports_Effect.map((res) => ({ queueId: res.queue_id, lastEventId: res.last_event_id })));
|
|
47645
47647
|
};
|
|
47646
47648
|
var populateCacheFromInboundEvents = (cache, events) => {
|
|
@@ -47711,6 +47713,13 @@ var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function
|
|
|
47711
47713
|
consecutiveFailures: 0,
|
|
47712
47714
|
needsBreadcrumb: false
|
|
47713
47715
|
});
|
|
47716
|
+
const resumeReported = yield* exports_Ref.make(false);
|
|
47717
|
+
const reportResume = (queueReplayed) => {
|
|
47718
|
+
const onResumeOutcome = config2.onResumeOutcome;
|
|
47719
|
+
if (onResumeOutcome === undefined)
|
|
47720
|
+
return exports_Effect.void;
|
|
47721
|
+
return exports_Ref.getAndSet(resumeReported, true).pipe(exports_Effect.flatMap((already) => already ? exports_Effect.void : onResumeOutcome(queueReplayed)));
|
|
47722
|
+
};
|
|
47714
47723
|
const recordTransientFailure = (cause3) => exports_Ref.modify(breadcrumb, (s) => {
|
|
47715
47724
|
const consecutiveFailures = s.consecutiveFailures + 1;
|
|
47716
47725
|
return [consecutiveFailures, { consecutiveFailures, needsBreadcrumb: true }];
|
|
@@ -47723,6 +47732,7 @@ var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function
|
|
|
47723
47732
|
}
|
|
47724
47733
|
})));
|
|
47725
47734
|
const handleBadQueue = exports_Effect.gen(function* () {
|
|
47735
|
+
yield* reportResume(false);
|
|
47726
47736
|
const since = yield* watermark.get();
|
|
47727
47737
|
if (config2.replay === undefined || exports_Option.isNone(since)) {
|
|
47728
47738
|
return [[], undefined];
|
|
@@ -47736,11 +47746,12 @@ var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function
|
|
|
47736
47746
|
return [markReplayed(gapEither.right), undefined];
|
|
47737
47747
|
});
|
|
47738
47748
|
const step4 = (queue) => exports_Effect.gen(function* () {
|
|
47739
|
-
const currentQueue = queue ?? (yield* registerQueue(config2.http, config2.mode));
|
|
47749
|
+
const currentQueue = queue ?? (yield* registerQueue(config2.http, config2.mode, config2.queueIdleTimeoutSecs).pipe(exports_Effect.tap((q) => config2.onQueueRegister?.(q) ?? exports_Effect.void)));
|
|
47740
47750
|
const res = yield* config2.http.get("/events", eventsResponseSchema, {
|
|
47741
47751
|
queue_id: currentQueue.queueId,
|
|
47742
47752
|
last_event_id: currentQueue.lastEventId
|
|
47743
47753
|
});
|
|
47754
|
+
yield* reportResume(true);
|
|
47744
47755
|
const directory = res.events.length > 0 ? yield* config2.resolveDirectory() : undefined;
|
|
47745
47756
|
let maxId = currentQueue.lastEventId;
|
|
47746
47757
|
const mapped = [];
|
|
@@ -47763,6 +47774,9 @@ var inboxEvents = (config2) => exports_Stream.unwrap(exports_Effect.gen(function
|
|
|
47763
47774
|
yield* watermark.advance(ev.message.ts);
|
|
47764
47775
|
}
|
|
47765
47776
|
}
|
|
47777
|
+
if (config2.onQueueAdvance !== undefined && maxId > currentQueue.lastEventId) {
|
|
47778
|
+
yield* config2.onQueueAdvance(maxId);
|
|
47779
|
+
}
|
|
47766
47780
|
return [mapped, { queueId: currentQueue.queueId, lastEventId: maxId }];
|
|
47767
47781
|
}).pipe(exports_Effect.catchTag("ZulipApiError", (e) => {
|
|
47768
47782
|
if (e.code === "BAD_EVENT_QUEUE_ID")
|
|
@@ -48406,7 +48420,7 @@ var zulipAdapter = (config2) => exports_Effect.gen(function* () {
|
|
|
48406
48420
|
if (exports_Option.exists(state.registration, (r) => r.mode === mode)) {
|
|
48407
48421
|
return exports_Effect.succeed([undefined, state]);
|
|
48408
48422
|
}
|
|
48409
|
-
return registerQueue(minterHttp, mode).pipe(exports_Effect.map((q) => [
|
|
48423
|
+
return registerQueue(minterHttp, mode, config2.queueIdleTimeoutSecs).pipe(exports_Effect.tap((q) => config2.onQueueRegister?.(q) ?? exports_Effect.void), exports_Effect.map((q) => [
|
|
48410
48424
|
undefined,
|
|
48411
48425
|
{ ...state, registration: exports_Option.some(exports_Data.struct({ queue: q, mode })) }
|
|
48412
48426
|
]));
|
|
@@ -48463,23 +48477,35 @@ var zulipAdapter = (config2) => exports_Effect.gen(function* () {
|
|
|
48463
48477
|
subscriptions: JSON.stringify([channel])
|
|
48464
48478
|
}).pipe(exports_Effect.asVoid)));
|
|
48465
48479
|
}).pipe(exports_Effect.mapError((cause3) => new InboxError({ operation: "unsubscribe", cause: cause3 }))),
|
|
48466
|
-
events: () => exports_Stream.unwrap(exports_Effect.all([
|
|
48467
|
-
|
|
48468
|
-
|
|
48469
|
-
|
|
48470
|
-
|
|
48471
|
-
|
|
48472
|
-
|
|
48473
|
-
|
|
48474
|
-
|
|
48475
|
-
|
|
48476
|
-
|
|
48477
|
-
|
|
48478
|
-
|
|
48479
|
-
|
|
48480
|
-
|
|
48481
|
-
|
|
48482
|
-
|
|
48480
|
+
events: () => exports_Stream.unwrap(exports_Effect.all([
|
|
48481
|
+
exports_SynchronizedRef.get(boundRef),
|
|
48482
|
+
exports_SynchronizedRef.get(inboxRef),
|
|
48483
|
+
config2.resumeQueue?.() ?? exports_Effect.succeedNone
|
|
48484
|
+
]).pipe(exports_Effect.flatMap(([current2, state, resumed]) => {
|
|
48485
|
+
const initialQueue = exports_Option.orElse(resumed, () => exports_Option.map(state.registration, (r) => r.queue));
|
|
48486
|
+
const reportAbsentResume = exports_Option.isNone(resumed) ? config2.onResumeOutcome?.(false) ?? exports_Effect.void : exports_Effect.void;
|
|
48487
|
+
return reportAbsentResume.pipe(exports_Effect.as(inboxEvents({
|
|
48488
|
+
http: minterHttp,
|
|
48489
|
+
permalinkBase: base,
|
|
48490
|
+
resolveDirectory: buildDirectoryLookup,
|
|
48491
|
+
mode: currentMode(state),
|
|
48492
|
+
messageRefCache,
|
|
48493
|
+
watermarkStore,
|
|
48494
|
+
...config2.queueIdleTimeoutSecs === undefined ? {} : { queueIdleTimeoutSecs: config2.queueIdleTimeoutSecs },
|
|
48495
|
+
...config2.onQueueRegister === undefined ? {} : { onQueueRegister: config2.onQueueRegister },
|
|
48496
|
+
...config2.onQueueAdvance === undefined ? {} : { onQueueAdvance: config2.onQueueAdvance },
|
|
48497
|
+
replay: (since) => inbox.replay(since),
|
|
48498
|
+
...exports_Option.match(current2, {
|
|
48499
|
+
onNone: () => ({}),
|
|
48500
|
+
onSome: (b) => ({ boundIdentity: b.identity })
|
|
48501
|
+
}),
|
|
48502
|
+
...exports_Option.match(initialQueue, {
|
|
48503
|
+
onNone: () => ({}),
|
|
48504
|
+
onSome: (q) => ({ initialQueue: q })
|
|
48505
|
+
}),
|
|
48506
|
+
...exports_Option.isSome(resumed) && config2.onResumeOutcome !== undefined ? { onResumeOutcome: config2.onResumeOutcome } : {}
|
|
48507
|
+
})));
|
|
48508
|
+
}))).pipe(exports_Stream.filterEffect(shouldDeliver)),
|
|
48483
48509
|
replay: (since) => {
|
|
48484
48510
|
const replayNarrow = JSON.stringify([{ negated: true, operator: "is", operand: "dm" }]);
|
|
48485
48511
|
return exports_Effect.all([
|
|
@@ -56742,6 +56768,70 @@ class StdioServerTransport {
|
|
|
56742
56768
|
}
|
|
56743
56769
|
}
|
|
56744
56770
|
|
|
56771
|
+
// packages/mcp/queue-state-hooks.ts
|
|
56772
|
+
var buildQueueStateHooks = (deps) => {
|
|
56773
|
+
const { store, session, idleTimeoutSecs, resumeOutcome } = deps;
|
|
56774
|
+
const withSession = (use) => exports_Deferred.poll(session).pipe(exports_Effect.flatMap(exports_Option.match({
|
|
56775
|
+
onNone: () => exports_Effect.void,
|
|
56776
|
+
onSome: (awaitId) => exports_Effect.flatMap(awaitId, use)
|
|
56777
|
+
})));
|
|
56778
|
+
return {
|
|
56779
|
+
queueIdleTimeoutSecs: idleTimeoutSecs,
|
|
56780
|
+
onQueueRegister: (queue) => withSession((id3) => exports_Deferred.poll(resumeOutcome).pipe(exports_Effect.flatMap(exports_Option.match({
|
|
56781
|
+
onSome: () => store.write(id3, queue),
|
|
56782
|
+
onNone: () => store.read(id3).pipe(exports_Effect.map(exports_Option.isNone), exports_Effect.catchAll(() => exports_Effect.succeed(true)), exports_Effect.flatMap((isFresh3) => isFresh3 ? store.write(id3, queue) : exports_Effect.void))
|
|
56783
|
+
})), exports_Effect.catchAllCause(() => exports_Effect.void))),
|
|
56784
|
+
onQueueAdvance: (lastEventId) => withSession((id3) => store.advance(id3, lastEventId).pipe(exports_Effect.catchAllCause(() => exports_Effect.void))),
|
|
56785
|
+
resumeQueue: () => exports_Deferred.poll(session).pipe(exports_Effect.flatMap(exports_Option.match({
|
|
56786
|
+
onNone: () => exports_Effect.succeedNone,
|
|
56787
|
+
onSome: (awaitId) => exports_Effect.flatMap(awaitId, (id3) => store.read(id3).pipe(exports_Effect.catchAllCause(() => exports_Effect.succeedNone)))
|
|
56788
|
+
}))),
|
|
56789
|
+
onResumeOutcome: (queueReplayed) => exports_Deferred.succeed(resumeOutcome, queueReplayed).pipe(exports_Effect.asVoid)
|
|
56790
|
+
};
|
|
56791
|
+
};
|
|
56792
|
+
|
|
56793
|
+
// packages/mcp/queue-state-store.ts
|
|
56794
|
+
import { homedir } from "node:os";
|
|
56795
|
+
import { join as join7 } from "node:path";
|
|
56796
|
+
class QueueStateStoreTag extends exports_Context.Tag("QueueStateStore")() {
|
|
56797
|
+
}
|
|
56798
|
+
var FILENAME_SAFE = /[^a-zA-Z0-9._-]/g;
|
|
56799
|
+
var stateFilename = (id3) => `${id3.replace(FILENAME_SAFE, "_")}.json`;
|
|
56800
|
+
var QueueStateFileSchema = exports_Schema.parseJson(exports_Schema.Struct({ queueId: exports_Schema.String, lastEventId: exports_Schema.Int }));
|
|
56801
|
+
var decodeQueueStateFile = exports_Schema.decodeUnknown(QueueStateFileSchema);
|
|
56802
|
+
var encodeQueueStateFile = exports_Schema.encode(QueueStateFileSchema);
|
|
56803
|
+
var isNotFound = (error2) => error2._tag === "SystemError" && error2.reason === "NotFound";
|
|
56804
|
+
var readState = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeQueueStateFile), exports_Effect.map(exports_Option.some), exports_Effect.catchIf(isNotFound, () => exports_Effect.succeed(exports_Option.none())));
|
|
56805
|
+
var createFileQueueStateStore = (deps) => {
|
|
56806
|
+
const { dir, fs } = deps;
|
|
56807
|
+
const pathFor = (id3) => join7(dir, stateFilename(id3));
|
|
56808
|
+
const persist = (path, state) => encodeQueueStateFile(state).pipe(exports_Effect.orDie, exports_Effect.flatMap((json4) => fs.makeDirectory(dir, { recursive: true }).pipe(exports_Effect.zipRight(fs.writeFileString(path, json4)))));
|
|
56809
|
+
const read3 = (id3) => readState(fs, pathFor(id3));
|
|
56810
|
+
const write4 = (id3, state) => persist(pathFor(id3), state);
|
|
56811
|
+
const advance = (id3, lastEventId) => {
|
|
56812
|
+
const path = pathFor(id3);
|
|
56813
|
+
return readState(fs, path).pipe(exports_Effect.catchTag("ParseError", () => exports_Effect.succeed(exports_Option.none())), exports_Effect.flatMap(exports_Option.match({
|
|
56814
|
+
onNone: () => exports_Effect.void,
|
|
56815
|
+
onSome: (prior) => lastEventId > prior.lastEventId ? persist(path, { queueId: prior.queueId, lastEventId }) : exports_Effect.void
|
|
56816
|
+
})));
|
|
56817
|
+
};
|
|
56818
|
+
return { read: read3, write: write4, advance };
|
|
56819
|
+
};
|
|
56820
|
+
var STATE_SEGMENT = "commy";
|
|
56821
|
+
var stateBaseConfig = exports_Config.nonEmptyString("XDG_STATE_HOME").pipe(exports_Config.withDefault(join7(homedir(), ".local", "state")));
|
|
56822
|
+
var queueStateDirConfig = stateBaseConfig.pipe(exports_Config.map((base) => join7(base, STATE_SEGMENT, "queue-state")));
|
|
56823
|
+
var FileQueueStateStoreLive = exports_Layer.effect(QueueStateStoreTag, exports_Effect.all([exports_FileSystem.FileSystem, exports_Effect.orDie(queueStateDirConfig)]).pipe(exports_Effect.map(([fs, dir]) => createFileQueueStateStore({ dir, fs }))));
|
|
56824
|
+
|
|
56825
|
+
// packages/mcp/resume-outcome.ts
|
|
56826
|
+
class ResumeOutcome extends exports_Context.Tag("commy/mcp/ResumeOutcome")() {
|
|
56827
|
+
}
|
|
56828
|
+
var ResumeOutcomeLive = exports_Layer.effect(ResumeOutcome, exports_Deferred.make());
|
|
56829
|
+
|
|
56830
|
+
// packages/mcp/session-id.ts
|
|
56831
|
+
class SessionId extends exports_Context.Tag("commy/mcp/SessionId")() {
|
|
56832
|
+
}
|
|
56833
|
+
var SessionIdLive = exports_Layer.effect(SessionId, exports_Deferred.make());
|
|
56834
|
+
|
|
56745
56835
|
// packages/mcp/subscribe-parser.ts
|
|
56746
56836
|
class SubscribeTokenError extends exports_Data.TaggedError("SubscribeTokenError") {
|
|
56747
56837
|
get message() {
|
|
@@ -56867,6 +56957,14 @@ var userConfigString = (key) => exports_Config.string(key).pipe(exports_Config.m
|
|
|
56867
56957
|
return exports_Either.right(value5);
|
|
56868
56958
|
}));
|
|
56869
56959
|
var optionalUserConfig = (key) => exports_Config.option(userConfigString(key));
|
|
56960
|
+
var QUEUE_IDLE_TIMEOUT_DEFAULT_SECS = 86400;
|
|
56961
|
+
var queueIdleTimeoutSecs = (key) => optionalUserConfig(key).pipe(exports_Config.mapOrFail((option7) => exports_Option.match(option7, {
|
|
56962
|
+
onNone: () => exports_Either.right(QUEUE_IDLE_TIMEOUT_DEFAULT_SECS),
|
|
56963
|
+
onSome: (raw3) => {
|
|
56964
|
+
const parsed = Number(raw3);
|
|
56965
|
+
return Number.isInteger(parsed) && parsed > 0 ? exports_Either.right(Math.min(parsed, MAX_QUEUE_TIMEOUT_SECS)) : exports_Either.left(exports_ConfigError.InvalidData([key], `${key} must be a positive integer — received: ${raw3}`));
|
|
56966
|
+
}
|
|
56967
|
+
})));
|
|
56870
56968
|
var optionalNonNegativeInt = (key) => optionalUserConfig(key).pipe(exports_Config.mapOrFail((option7) => exports_Option.match(option7, {
|
|
56871
56969
|
onNone: () => exports_Either.right(exports_Option.none()),
|
|
56872
56970
|
onSome: (raw3) => {
|
|
@@ -56897,6 +56995,7 @@ var envConfig = exports_Config.all({
|
|
|
56897
56995
|
subscribe: optionalUserConfig("COMMY_SUBSCRIBE"),
|
|
56898
56996
|
project: optionalNonEmpty("COMMY_PROJECT"),
|
|
56899
56997
|
catchupWindowSeconds: optionalNonNegativeInt("COMMY_CATCHUP_WINDOW_SECONDS"),
|
|
56998
|
+
queueIdleTimeoutSecs: queueIdleTimeoutSecs("COMMY_QUEUE_IDLE_TIMEOUT_SECS"),
|
|
56900
56999
|
downloadDir: optionalNonEmpty("COMMY_DOWNLOAD_DIR")
|
|
56901
57000
|
}).pipe(exports_Config.mapOrFail((raw3) => {
|
|
56902
57001
|
if (exports_Option.isSome(raw3.botApiKey) && exports_Option.isNone(raw3.botName)) {
|
|
@@ -56907,6 +57006,7 @@ var envConfig = exports_Config.all({
|
|
|
56907
57006
|
realmUrl: raw3.realmUrl,
|
|
56908
57007
|
minterEmail: raw3.minterEmail,
|
|
56909
57008
|
minterApiKey: raw3.minterApiKey,
|
|
57009
|
+
queueIdleTimeoutSecs: raw3.queueIdleTimeoutSecs,
|
|
56910
57010
|
...exports_Option.match(raw3.botName, { onNone: () => ({}), onSome: (botName) => ({ botName }) }),
|
|
56911
57011
|
...exports_Option.isSome(raw3.botName) && exports_Option.isSome(raw3.botApiKey) ? { attachIdentity: { name: raw3.botName.value, apiKey: raw3.botApiKey.value } } : {},
|
|
56912
57012
|
...exports_Option.match(raw3.subscribe, {
|
|
@@ -56980,11 +57080,24 @@ class SubstrateAdapter extends exports_Context.Tag("SubstrateAdapter")() {
|
|
|
56980
57080
|
var substrateAdapterLayer = (make78) => exports_Layer.scoped(SubstrateAdapter, exports_Effect.tap(make78, (adapter4) => exports_Effect.addFinalizer(() => exports_Effect.promise(() => adapter4.close()))));
|
|
56981
57081
|
var ZulipAdapterLive = substrateAdapterLayer(exports_Effect.gen(function* () {
|
|
56982
57082
|
const parsed = yield* parseEnv;
|
|
57083
|
+
const queueHooks = parsed.botName === undefined ? buildQueueStateHooks({
|
|
57084
|
+
store: yield* QueueStateStoreTag,
|
|
57085
|
+
session: yield* SessionId,
|
|
57086
|
+
idleTimeoutSecs: parsed.queueIdleTimeoutSecs,
|
|
57087
|
+
resumeOutcome: yield* ResumeOutcome
|
|
57088
|
+
}) : undefined;
|
|
56983
57089
|
return yield* zulipAdapter({
|
|
56984
57090
|
realmUrl: parsed.realmUrl,
|
|
56985
57091
|
minterEmail: parsed.minterEmail,
|
|
56986
57092
|
minterApiKey: parsed.minterApiKey,
|
|
56987
|
-
...parsed.attachIdentity === undefined ? {} : { attachIdentity: parsed.attachIdentity }
|
|
57093
|
+
...parsed.attachIdentity === undefined ? {} : { attachIdentity: parsed.attachIdentity },
|
|
57094
|
+
...queueHooks === undefined ? {} : {
|
|
57095
|
+
queueIdleTimeoutSecs: queueHooks.queueIdleTimeoutSecs,
|
|
57096
|
+
onQueueRegister: queueHooks.onQueueRegister,
|
|
57097
|
+
onQueueAdvance: queueHooks.onQueueAdvance,
|
|
57098
|
+
resumeQueue: queueHooks.resumeQueue,
|
|
57099
|
+
onResumeOutcome: queueHooks.onResumeOutcome
|
|
57100
|
+
}
|
|
56988
57101
|
});
|
|
56989
57102
|
}));
|
|
56990
57103
|
var subscribeFromEnv = (inbox, narrowSet, parsed) => {
|
|
@@ -57111,29 +57224,29 @@ var catchUpChannels = (deps) => exports_Effect.gen(function* () {
|
|
|
57111
57224
|
});
|
|
57112
57225
|
|
|
57113
57226
|
// packages/mcp/cursor-store.ts
|
|
57114
|
-
import { homedir } from "node:os";
|
|
57115
|
-
import { join as
|
|
57227
|
+
import { homedir as homedir2 } from "node:os";
|
|
57228
|
+
import { join as join8 } from "node:path";
|
|
57116
57229
|
class CursorStoreTag extends exports_Context.Tag("CursorStore")() {
|
|
57117
57230
|
}
|
|
57118
|
-
var
|
|
57231
|
+
var FILENAME_SAFE2 = /[^a-zA-Z0-9._-]/g;
|
|
57119
57232
|
var cursorFilename = (id3) => {
|
|
57120
|
-
const safe = id3.replace(
|
|
57233
|
+
const safe = id3.replace(FILENAME_SAFE2, "_");
|
|
57121
57234
|
return `${safe}.json`;
|
|
57122
57235
|
};
|
|
57123
57236
|
var CursorFileSchema = exports_Schema.parseJson(exports_Schema.Struct({ lastSeenTs: TimestampSchema }));
|
|
57124
57237
|
var decodeCursorFile = exports_Schema.decodeUnknown(CursorFileSchema);
|
|
57125
|
-
var
|
|
57126
|
-
var readCursor = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeCursorFile), exports_Effect.map((file3) => exports_Option.some(file3.lastSeenTs)), exports_Effect.catchIf(
|
|
57238
|
+
var isNotFound2 = (error2) => error2._tag === "SystemError" && error2.reason === "NotFound";
|
|
57239
|
+
var readCursor = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeCursorFile), exports_Effect.map((file3) => exports_Option.some(file3.lastSeenTs)), exports_Effect.catchIf(isNotFound2, () => exports_Effect.succeed(exports_Option.none())));
|
|
57127
57240
|
var createFileCursorStore = (deps) => {
|
|
57128
57241
|
const { dir, fs } = deps;
|
|
57129
|
-
const pathFor = (id3) =>
|
|
57242
|
+
const pathFor = (id3) => join8(dir, cursorFilename(id3));
|
|
57130
57243
|
const read3 = (id3) => readCursor(fs, pathFor(id3));
|
|
57131
57244
|
const write4 = (id3, ts) => readCursor(fs, pathFor(id3)).pipe(exports_Effect.catchTag("ParseError", () => exports_Effect.succeed(exports_Option.none())), exports_Effect.flatMap((prior) => exports_Option.isSome(prior) && prior.value >= ts ? exports_Effect.void : fs.makeDirectory(dir, { recursive: true }).pipe(exports_Effect.zipRight(fs.writeFileString(pathFor(id3), JSON.stringify({ lastSeenTs: ts }))))));
|
|
57132
57245
|
return { read: read3, write: write4 };
|
|
57133
57246
|
};
|
|
57134
|
-
var
|
|
57135
|
-
var
|
|
57136
|
-
var cursorDirConfig =
|
|
57247
|
+
var STATE_SEGMENT2 = "commy";
|
|
57248
|
+
var stateBaseConfig2 = exports_Config.nonEmptyString("XDG_STATE_HOME").pipe(exports_Config.withDefault(join8(homedir2(), ".local", "state")));
|
|
57249
|
+
var cursorDirConfig = stateBaseConfig2.pipe(exports_Config.map((base) => join8(base, STATE_SEGMENT2, "cursors")));
|
|
57137
57250
|
var FileCursorStoreLive = exports_Layer.effect(CursorStoreTag, exports_Effect.all([exports_FileSystem.FileSystem, exports_Effect.orDie(cursorDirConfig)]).pipe(exports_Effect.map(([fs, dir]) => createFileCursorStore({ dir, fs }))));
|
|
57138
57251
|
|
|
57139
57252
|
// packages/mcp/ensure-bound.ts
|
|
@@ -57169,35 +57282,6 @@ var createEnsureBound = (deps) => exports_Effect.map(exports_Ref.make({ kind: "i
|
|
|
57169
57282
|
return ensureBound;
|
|
57170
57283
|
});
|
|
57171
57284
|
|
|
57172
|
-
// packages/mcp/target-cursor.ts
|
|
57173
|
-
import { homedir as homedir2 } from "node:os";
|
|
57174
|
-
import { join as join8 } from "node:path";
|
|
57175
|
-
var deliveryTargetOf = (message) => exports_Data.struct({
|
|
57176
|
-
channel: message.ref.channel.name,
|
|
57177
|
-
thread: exports_Option.map(message.ref.thread, (observed) => observed.name)
|
|
57178
|
-
});
|
|
57179
|
-
var DeliveryTargetSchema = exports_Schema.Data(exports_Schema.Struct({
|
|
57180
|
-
channel: ChannelNameSchema,
|
|
57181
|
-
thread: exports_Schema.OptionFromNullOr(ThreadNameSchema)
|
|
57182
|
-
}));
|
|
57183
|
-
var TargetCursorsFileSchema = exports_Schema.parseJson(exports_Schema.HashMap({ key: DeliveryTargetSchema, value: TimestampSchema }));
|
|
57184
|
-
var decodeTargetCursorsFile = exports_Schema.decodeUnknown(TargetCursorsFileSchema);
|
|
57185
|
-
var encodeTargetCursorsFile = exports_Schema.encode(TargetCursorsFileSchema);
|
|
57186
|
-
var FILENAME_SAFE2 = /[^a-zA-Z0-9._-]/g;
|
|
57187
|
-
var cursorsFilename = (id3) => `${id3.replace(FILENAME_SAFE2, "_")}.json`;
|
|
57188
|
-
var isNotFound2 = (error2) => error2._tag === "SystemError" && error2.reason === "NotFound";
|
|
57189
|
-
var readCursors = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeTargetCursorsFile), exports_Effect.map(exports_Option.some), exports_Effect.catchIf(isNotFound2, () => exports_Effect.succeed(exports_Option.none())));
|
|
57190
|
-
var advanceTargetCursor = (fs, dir, id3, target, ts) => {
|
|
57191
|
-
const path = join8(dir, cursorsFilename(id3));
|
|
57192
|
-
return readCursors(fs, path).pipe(exports_Effect.catchTag("ParseError", () => exports_Effect.succeed(exports_Option.none())), exports_Effect.map(exports_Option.getOrElse(() => exports_HashMap.empty())), exports_Effect.flatMap((cursors) => {
|
|
57193
|
-
const prior = exports_HashMap.get(cursors, target);
|
|
57194
|
-
return exports_Option.isSome(prior) && prior.value >= ts ? exports_Effect.void : encodeTargetCursorsFile(exports_HashMap.set(cursors, target, ts)).pipe(exports_Effect.orDie, exports_Effect.flatMap((json4) => fs.makeDirectory(dir, { recursive: true }).pipe(exports_Effect.zipRight(fs.writeFileString(path, json4)))));
|
|
57195
|
-
}));
|
|
57196
|
-
};
|
|
57197
|
-
var STATE_SEGMENT2 = "commy";
|
|
57198
|
-
var stateBaseConfig2 = exports_Config.nonEmptyString("XDG_STATE_HOME").pipe(exports_Config.withDefault(join8(homedir2(), ".local", "state")));
|
|
57199
|
-
var targetCursorDirConfig = stateBaseConfig2.pipe(exports_Config.map((base) => join8(base, STATE_SEGMENT2, "target-cursors")));
|
|
57200
|
-
|
|
57201
57285
|
// packages/mcp/event-pump.ts
|
|
57202
57286
|
var originatorId = (event) => exports_Match.value(event).pipe(exports_Match.discriminatorsExhaustive("kind")({
|
|
57203
57287
|
"message-posted": (message) => message.message.sender.id,
|
|
@@ -57252,9 +57336,7 @@ var startEventPump = (deps) => exports_Effect.gen(function* () {
|
|
|
57252
57336
|
for (const identity6 of identitiesIn(event))
|
|
57253
57337
|
deps.rememberIdentity(identity6);
|
|
57254
57338
|
}
|
|
57255
|
-
const
|
|
57256
|
-
const deliveryAdvance = deps.onDelivery !== undefined && (event.kind === "message-posted" || event.kind === "mention-received") ? deps.onDelivery(deliveryTargetOf(event.message), event.message.ts) : exports_Effect.void;
|
|
57257
|
-
const advance = exports_Effect.zipRight(mentionAdvance, deliveryAdvance);
|
|
57339
|
+
const advance = deps.onMention !== undefined && event.kind === "mention-received" ? deps.onMention(event.message.ts) : exports_Effect.void;
|
|
57258
57340
|
if (recordMessageDelivery(event, seenDelivered) === "duplicate")
|
|
57259
57341
|
return advance;
|
|
57260
57342
|
return advance.pipe(exports_Effect.zipRight(renderEvent(event, botIdentityId)), exports_Effect.flatMap((payload) => exports_Effect.tryPromise({
|
|
@@ -58767,7 +58849,7 @@ class Server extends Protocol {
|
|
|
58767
58849
|
}
|
|
58768
58850
|
|
|
58769
58851
|
// packages/mcp/mcp-server.ts
|
|
58770
|
-
var PLUGIN_VERSION = "0.
|
|
58852
|
+
var PLUGIN_VERSION = "0.19.0";
|
|
58771
58853
|
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.
|
|
58772
58854
|
|
|
58773
58855
|
**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.
|
|
@@ -58884,11 +58966,6 @@ var createNarrowSet = () => {
|
|
|
58884
58966
|
var DEFAULT_TIMEOUT_MS = 5000;
|
|
58885
58967
|
var raceReleaseAgainstTimeout = (release, timeoutMs = DEFAULT_TIMEOUT_MS) => release.pipe(exports_Effect.tapDefect((cause3) => exports_Effect.logError(`release failed: ${exports_Cause.pretty(cause3)}`)), exports_Effect.catchAllDefect(() => exports_Effect.void), exports_Effect.timeoutOption(exports_Duration.millis(timeoutMs)), exports_Effect.flatMap((result) => exports_Option.isNone(result) ? exports_Effect.logError(`release timed out after ${timeoutMs}ms`) : exports_Effect.void));
|
|
58886
58968
|
|
|
58887
|
-
// packages/mcp/session-id.ts
|
|
58888
|
-
class SessionId extends exports_Context.Tag("commy/mcp/SessionId")() {
|
|
58889
|
-
}
|
|
58890
|
-
var SessionIdLive = exports_Layer.effect(SessionId, exports_Deferred.make());
|
|
58891
|
-
|
|
58892
58969
|
// packages/mcp/subscription-restore.ts
|
|
58893
58970
|
var applyRestored = (deps, intents) => exports_Effect.sync(() => deps.narrowSet.load(exports_Option.some(intents))).pipe(exports_Effect.zipRight(exports_Effect.forEach(intents, (intent) => deps.inbox.subscribe(intentToTarget(intent)), {
|
|
58894
58971
|
discard: true
|
|
@@ -58923,25 +59000,16 @@ var subscriptionFilename = (id3) => {
|
|
|
58923
59000
|
var isNotFound3 = (error2) => error2._tag === "SystemError" && error2.reason === "NotFound";
|
|
58924
59001
|
var readSubscriptions = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeSubscriptionsFile), exports_Effect.map((intents) => exports_Option.some(intents)), exports_Effect.catchIf(isNotFound3, () => exports_Effect.succeed(exports_Option.none())));
|
|
58925
59002
|
var createFileSubscriptionStore = (deps) => {
|
|
58926
|
-
const { dir, fs,
|
|
59003
|
+
const { dir, fs, session } = deps;
|
|
58927
59004
|
const pathFor = (id3) => join9(dir, subscriptionFilename(id3));
|
|
58928
59005
|
const read3 = () => exports_Effect.flatMap(exports_Deferred.await(session), (id3) => readSubscriptions(fs, pathFor(id3)));
|
|
58929
59006
|
const write4 = (intents) => exports_Effect.flatMap(exports_Deferred.await(session), (id3) => fs.makeDirectory(dir, { recursive: true }).pipe(exports_Effect.zipRight(fs.writeFileString(pathFor(id3), JSON.stringify(intents)))));
|
|
58930
|
-
|
|
58931
|
-
onNone: () => exports_Effect.void,
|
|
58932
|
-
onSome: (awaitId) => exports_Effect.flatMap(awaitId, (id3) => advanceTargetCursor(fs, cursorDir, id3, target, ts))
|
|
58933
|
-
}));
|
|
58934
|
-
return { read: read3, write: write4, advanceCursor };
|
|
59007
|
+
return { read: read3, write: write4 };
|
|
58935
59008
|
};
|
|
58936
59009
|
var STATE_SEGMENT3 = "commy";
|
|
58937
59010
|
var stateBaseConfig3 = exports_Config.nonEmptyString("XDG_STATE_HOME").pipe(exports_Config.withDefault(join9(homedir3(), ".local", "state")));
|
|
58938
59011
|
var subscriptionDirConfig = stateBaseConfig3.pipe(exports_Config.map((base) => join9(base, STATE_SEGMENT3, "subscriptions")));
|
|
58939
|
-
var FileSubscriptionStoreLive = exports_Layer.effect(SubscriptionStoreTag, exports_Effect.all([
|
|
58940
|
-
exports_FileSystem.FileSystem,
|
|
58941
|
-
exports_Effect.orDie(subscriptionDirConfig),
|
|
58942
|
-
exports_Effect.orDie(targetCursorDirConfig),
|
|
58943
|
-
SessionId
|
|
58944
|
-
]).pipe(exports_Effect.map(([fs, dir, cursorDir, session]) => createFileSubscriptionStore({ dir, fs, cursorDir, session }))));
|
|
59012
|
+
var FileSubscriptionStoreLive = exports_Layer.effect(SubscriptionStoreTag, exports_Effect.all([exports_FileSystem.FileSystem, exports_Effect.orDie(subscriptionDirConfig), SessionId]).pipe(exports_Effect.map(([fs, dir, session]) => createFileSubscriptionStore({ dir, fs, session }))));
|
|
58945
59013
|
|
|
58946
59014
|
// packages/mcp/tools.ts
|
|
58947
59015
|
var emptyObjectSchema = {
|
|
@@ -59744,6 +59812,7 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59744
59812
|
const cursorStore = yield* CursorStoreTag;
|
|
59745
59813
|
const subscriptionStore = yield* SubscriptionStoreTag;
|
|
59746
59814
|
const sessionIdDeferred = yield* SessionId;
|
|
59815
|
+
const resumeOutcome = yield* ResumeOutcome;
|
|
59747
59816
|
yield* exports_Effect.flatMap(readBootSessionId, exports_Option.match({
|
|
59748
59817
|
onNone: () => exports_Effect.void,
|
|
59749
59818
|
onSome: (sessionId) => exports_Deferred.succeed(sessionIdDeferred, sessionId).pipe(exports_Effect.asVoid)
|
|
@@ -59791,12 +59860,25 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59791
59860
|
onNone: () => exports_Effect.void,
|
|
59792
59861
|
onSome: () => persistSubscriptions(subscriptionStore, narrowSet).pipe(exports_Effect.catchAll((err) => exports_Effect.logError(`commy plugin: subscription persist failed: ${exports_Predicate.isError(err) ? err.message : String(err)}`)), exports_Effect.provide(loggerLayer))
|
|
59793
59862
|
})));
|
|
59794
|
-
const ephemeralOnAcquire = parsed.botName === undefined ? (acquired, project3, sessionId) => ensureSessionSubscriptions(sessionId, project3).pipe(exports_Effect.zipRight(
|
|
59795
|
-
|
|
59796
|
-
|
|
59797
|
-
identityId
|
|
59798
|
-
|
|
59799
|
-
|
|
59863
|
+
const ephemeralOnAcquire = parsed.botName === undefined ? (acquired, project3, sessionId) => ensureSessionSubscriptions(sessionId, project3).pipe(exports_Effect.zipRight(exports_Deferred.await(resumeOutcome)), exports_Effect.flatMap((queueReplayed) => {
|
|
59864
|
+
if (queueReplayed)
|
|
59865
|
+
return exports_Effect.void;
|
|
59866
|
+
const identityId = acquired.identity.id;
|
|
59867
|
+
const windowSeconds = parsed.catchupWindowSeconds ?? DEFAULT_CATCHUP_WINDOW_SECONDS;
|
|
59868
|
+
const catchUpIntents = narrowSet.intents();
|
|
59869
|
+
return catchUpMentions({
|
|
59870
|
+
cursorStore,
|
|
59871
|
+
inbox: adapter4.inbox,
|
|
59872
|
+
identityId,
|
|
59873
|
+
notifier
|
|
59874
|
+
}).pipe(exports_Effect.catchAllCause(logCatchUpFailure("ephemeral mentions")), exports_Effect.zipRight(windowSeconds > 0 && catchUpIntents.length > 0 ? catchUpChannels({
|
|
59875
|
+
intents: catchUpIntents,
|
|
59876
|
+
history: adapter4.history,
|
|
59877
|
+
notifier,
|
|
59878
|
+
botIdentityId: identityId,
|
|
59879
|
+
windowSeconds
|
|
59880
|
+
}).pipe(exports_Effect.catchAllCause(logCatchUpFailure("ephemeral channels"))) : exports_Effect.void));
|
|
59881
|
+
}), exports_Effect.provide(loggerLayer)) : undefined;
|
|
59800
59882
|
const identityCache = yield* buildIdentityCache(adapter4, parsed.botName, ephemeralOnAcquire);
|
|
59801
59883
|
let type1Intents = [];
|
|
59802
59884
|
if (parsed.botName !== undefined) {
|
|
@@ -59881,11 +59963,6 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59881
59963
|
if (id3 === undefined)
|
|
59882
59964
|
return exports_Effect.void;
|
|
59883
59965
|
return cursorStore.write(id3, ts).pipe(exports_Effect.catchAllCause(() => exports_Effect.void));
|
|
59884
|
-
},
|
|
59885
|
-
onDelivery: (target, ts) => {
|
|
59886
|
-
if (parsed.botName !== undefined)
|
|
59887
|
-
return exports_Effect.void;
|
|
59888
|
-
return subscriptionStore.advanceCursor(target, ts).pipe(exports_Effect.catchAllCause(() => exports_Effect.void));
|
|
59889
59966
|
}
|
|
59890
59967
|
});
|
|
59891
59968
|
yield* exports_Effect.addFinalizer(() => pump.cancel);
|
|
@@ -59895,7 +59972,7 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59895
59972
|
yield* exports_Effect.forkScoped(restoreOnResume);
|
|
59896
59973
|
yield* exports_Effect.raceFirst(pump.done, params.shutdownSignal ?? exports_Effect.never);
|
|
59897
59974
|
}));
|
|
59898
|
-
var AppLayer = exports_Layer.mergeAll(ZulipAdapterLive, FileCursorStoreLive, exports_Layer.provideMerge(
|
|
59975
|
+
var AppLayer = exports_Layer.mergeAll(ZulipAdapterLive, FileCursorStoreLive, FileSubscriptionStoreLive, stderrLoggerLayer).pipe(exports_Layer.provideMerge(FileQueueStateStoreLive), exports_Layer.provideMerge(SessionIdLive), exports_Layer.provideMerge(ResumeOutcomeLive));
|
|
59899
59976
|
var PlatformLive = exports_Layer.mergeAll(exports_Layer.setConfigProvider(exports_ConfigProvider.fromEnv()), exports_FetchHttpClient.layer, exports_NodeContext.layer);
|
|
59900
59977
|
var MainLive = exports_Layer.provideMerge(AppLayer, PlatformLive);
|
|
59901
59978
|
var clientDisconnect = (stdin3) => exports_Effect.async((resume2) => {
|