@codeforbreakfast/commy-mcp 0.16.0 → 0.18.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 +152 -51
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -6657,7 +6657,7 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
6657
6657
|
});
|
|
6658
6658
|
|
|
6659
6659
|
// packages/mcp/server.ts
|
|
6660
|
-
import { basename as basename2, join as
|
|
6660
|
+
import { basename as basename2, join as join10 } from "node:path";
|
|
6661
6661
|
// node_modules/.bun/effect@3.21.4/node_modules/effect/dist/esm/Array.js
|
|
6662
6662
|
var exports_Array = {};
|
|
6663
6663
|
__export(exports_Array, {
|
|
@@ -56816,6 +56816,7 @@ var envConfigError = (issues) => new EnvConfigError({
|
|
|
56816
56816
|
});
|
|
56817
56817
|
var SessionIdSchema = exports_Schema.UUID.pipe(exports_Schema.brand("SessionId"));
|
|
56818
56818
|
var parseSessionId = exports_Schema.decodeUnknownOption(SessionIdSchema);
|
|
56819
|
+
var readBootSessionId = exports_Effect.orElseSucceed(exports_Effect.map(exports_Config.option(exports_Config.string("CLAUDE_CODE_SESSION_ID")), exports_Option.flatMap(parseSessionId)), () => exports_Option.none());
|
|
56819
56820
|
var BOT_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
56820
56821
|
var parseBotName = (raw3) => {
|
|
56821
56822
|
if (raw3.length === 0 || raw3.length > 40)
|
|
@@ -56895,7 +56896,8 @@ var envConfig = exports_Config.all({
|
|
|
56895
56896
|
botApiKey: optionalApiKey("COMMY_BOT_API_KEY"),
|
|
56896
56897
|
subscribe: optionalUserConfig("COMMY_SUBSCRIBE"),
|
|
56897
56898
|
project: optionalNonEmpty("COMMY_PROJECT"),
|
|
56898
|
-
catchupWindowSeconds: optionalNonNegativeInt("COMMY_CATCHUP_WINDOW_SECONDS")
|
|
56899
|
+
catchupWindowSeconds: optionalNonNegativeInt("COMMY_CATCHUP_WINDOW_SECONDS"),
|
|
56900
|
+
downloadDir: optionalNonEmpty("COMMY_DOWNLOAD_DIR")
|
|
56899
56901
|
}).pipe(exports_Config.mapOrFail((raw3) => {
|
|
56900
56902
|
if (exports_Option.isSome(raw3.botApiKey) && exports_Option.isNone(raw3.botName)) {
|
|
56901
56903
|
return exports_Either.left(exports_ConfigError.InvalidData(["COMMY_BOT_API_KEY"], "COMMY_BOT_API_KEY requires COMMY_BOT_NAME — the key identifies which provisioned persona to attach to"));
|
|
@@ -56915,6 +56917,10 @@ var envConfig = exports_Config.all({
|
|
|
56915
56917
|
...exports_Option.match(raw3.catchupWindowSeconds, {
|
|
56916
56918
|
onNone: () => ({}),
|
|
56917
56919
|
onSome: (catchupWindowSeconds) => ({ catchupWindowSeconds })
|
|
56920
|
+
}),
|
|
56921
|
+
...exports_Option.match(raw3.downloadDir, {
|
|
56922
|
+
onNone: () => ({}),
|
|
56923
|
+
onSome: (downloadDir) => ({ downloadDir })
|
|
56918
56924
|
})
|
|
56919
56925
|
});
|
|
56920
56926
|
}));
|
|
@@ -57163,6 +57169,35 @@ var createEnsureBound = (deps) => exports_Effect.map(exports_Ref.make({ kind: "i
|
|
|
57163
57169
|
return ensureBound;
|
|
57164
57170
|
});
|
|
57165
57171
|
|
|
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
|
+
|
|
57166
57201
|
// packages/mcp/event-pump.ts
|
|
57167
57202
|
var originatorId = (event) => exports_Match.value(event).pipe(exports_Match.discriminatorsExhaustive("kind")({
|
|
57168
57203
|
"message-posted": (message) => message.message.sender.id,
|
|
@@ -57218,9 +57253,11 @@ var startEventPump = (deps) => exports_Effect.gen(function* () {
|
|
|
57218
57253
|
deps.rememberIdentity(identity6);
|
|
57219
57254
|
}
|
|
57220
57255
|
const mentionAdvance = deps.onMention !== undefined && event.kind === "mention-received" ? deps.onMention(event.message.ts) : exports_Effect.void;
|
|
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);
|
|
57221
57258
|
if (recordMessageDelivery(event, seenDelivered) === "duplicate")
|
|
57222
|
-
return
|
|
57223
|
-
return
|
|
57259
|
+
return advance;
|
|
57260
|
+
return advance.pipe(exports_Effect.zipRight(renderEvent(event, botIdentityId)), exports_Effect.flatMap((payload) => exports_Effect.tryPromise({
|
|
57224
57261
|
try: () => deps.notifier(payload),
|
|
57225
57262
|
catch: (cause3) => new DispatchFailure({ cause: cause3 })
|
|
57226
57263
|
})));
|
|
@@ -58730,7 +58767,7 @@ class Server extends Protocol {
|
|
|
58730
58767
|
}
|
|
58731
58768
|
|
|
58732
58769
|
// packages/mcp/mcp-server.ts
|
|
58733
|
-
var PLUGIN_VERSION = "0.
|
|
58770
|
+
var PLUGIN_VERSION = "0.18.0";
|
|
58734
58771
|
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.
|
|
58735
58772
|
|
|
58736
58773
|
**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.
|
|
@@ -58741,7 +58778,7 @@ var COMMY_INSTRUCTIONS = `**Substrate.** commy is the inter-agent channel: agent
|
|
|
58741
58778
|
|
|
58742
58779
|
**Links.** Every ref the substrate hands you carries a ready-to-click \`permalink\` — on \`post\` results, \`read_channel\`/\`read_thread\` messages (message \`permalink\` plus \`channel.permalink\` and \`thread.permalink\`), \`list_channels\` (channel \`permalink\`), and inbound \`<channel source="commy">\` frames (\`permalink\` / \`channel_permalink\` / \`thread_permalink\` meta, \`target_permalink\` on reaction frames). **Whenever you show a human a message, channel, or topic reference, render it as that clickable permalink — never a bare name or numeric id.** A human can click a permalink straight to the message; a bare \`#channel > topic\` or message number makes them hunt. When you hold only a message id (e.g. one cited elsewhere, with no permalink to hand), \`message_link(message_id, channel_name?, thread?)\` returns its \`{permalink}\`.
|
|
58743
58780
|
|
|
58744
|
-
**Tools.** \`post\` (channel; optionally thread or reply), \`react\`/\`unreact\` (emoji on a message), \`subscribe\`/\`unsubscribe\` (live target), \`read_channel\`/\`read_thread\` (history within a range), \`list_channels\` (enumerate channels in the realm), \`message_link\` (canonical permalink for a message id), \`resolve\` (identity by name), \`current_identity\` (passive — never acquires), \`download_file\` (fetch a \`/user_uploads/...\` attachment to a temp file — use Read on the returned path to view images), \`upload_file\` (upload a local file by absolute path; returns a \`reference\` string to embed in a \`post\` body).
|
|
58781
|
+
**Tools.** \`post\` (channel; optionally thread or reply), \`react\`/\`unreact\` (emoji on a message), \`subscribe\`/\`unsubscribe\` (live target), \`read_channel\`/\`read_thread\` (history within a range), \`list_channels\` (enumerate channels in the realm), \`message_link\` (canonical permalink for a message id), \`resolve\` (identity by name), \`current_identity\` (passive — never acquires), \`download_file\` (fetch a \`/user_uploads/...\` attachment to a temp file — rooted under the operator-set \`COMMY_DOWNLOAD_DIR\` when configured so it lands somewhere you can Read, else \`$TMPDIR\`; use Read on the returned path to view images), \`upload_file\` (upload a local file by absolute path; returns a \`reference\` string to embed in a \`post\` body).
|
|
58745
58782
|
|
|
58746
58783
|
**session_id.** Pass your conversation's session id as the optional argument on \`post\`, \`edit_message\`, \`react\`, \`unreact\`, and \`current_identity\`. **Must be a UUID** (e.g. \`crypto.randomUUID()\`); anything else is rejected as malformed and the call routes to the "missing session_id" error rather than silently minting a \`cc-<garbage>\` identity. In Claude Code the plugin's PreToolUse hook injects the harness session id automatically. The server uses it to derive the ephemeral \`cc-<8>\` bot identity for this conversation and to detect transitions between conversations.`;
|
|
58747
58784
|
var buildMcpServer = () => new Server({ name: "commy", version: PLUGIN_VERSION }, {
|
|
@@ -58793,6 +58830,8 @@ var mentionsMatches = (intents, mentions, botIdentityId) => {
|
|
|
58793
58830
|
var createNarrowSet = () => {
|
|
58794
58831
|
let intents = exports_HashSet.empty();
|
|
58795
58832
|
let seenTopics = exports_HashSet.empty();
|
|
58833
|
+
const pending3 = [];
|
|
58834
|
+
let recording = false;
|
|
58796
58835
|
const newTopicsMatches = (ref) => exports_Option.match(threadKey(ref), {
|
|
58797
58836
|
onNone: () => false,
|
|
58798
58837
|
onSome: (tk) => {
|
|
@@ -58807,15 +58846,30 @@ var createNarrowSet = () => {
|
|
|
58807
58846
|
const messagePostedMatches = (ref) => refMatches(ref, intents) || newTopicsMatches(ref);
|
|
58808
58847
|
return {
|
|
58809
58848
|
add: (intent) => {
|
|
58810
|
-
|
|
58849
|
+
const key = intentKey(intent);
|
|
58850
|
+
intents = exports_HashSet.add(intents, key);
|
|
58851
|
+
if (recording)
|
|
58852
|
+
pending3.push({ op: "add", key });
|
|
58811
58853
|
},
|
|
58812
58854
|
remove: (intent) => {
|
|
58813
|
-
|
|
58855
|
+
const key = intentKey(intent);
|
|
58856
|
+
intents = exports_HashSet.remove(intents, key);
|
|
58857
|
+
if (recording)
|
|
58858
|
+
pending3.push({ op: "remove", key });
|
|
58814
58859
|
},
|
|
58815
58860
|
size: () => exports_HashSet.size(intents),
|
|
58816
58861
|
intents: () => exports_Array.fromIterable(intents).map(keyToIntent),
|
|
58817
|
-
|
|
58818
|
-
|
|
58862
|
+
beginBuffering: () => {
|
|
58863
|
+
recording = true;
|
|
58864
|
+
},
|
|
58865
|
+
load: (base) => {
|
|
58866
|
+
const seeded = exports_Option.match(base, {
|
|
58867
|
+
onNone: () => intents,
|
|
58868
|
+
onSome: (next4) => exports_HashSet.fromIterable(next4.map(intentKey))
|
|
58869
|
+
});
|
|
58870
|
+
intents = pending3.reduce((acc, delta) => delta.op === "add" ? exports_HashSet.add(acc, delta.key) : exports_HashSet.remove(acc, delta.key), seeded);
|
|
58871
|
+
pending3.length = 0;
|
|
58872
|
+
recording = false;
|
|
58819
58873
|
},
|
|
58820
58874
|
matches: (event, botIdentityId) => exports_Match.value(event).pipe(exports_Match.discriminatorsExhaustive("kind")({
|
|
58821
58875
|
"message-posted": (e) => messagePostedMatches(e.message.ref) || mentionsMatches(intents, e.message.mentions, botIdentityId),
|
|
@@ -58830,24 +58884,28 @@ var createNarrowSet = () => {
|
|
|
58830
58884
|
var DEFAULT_TIMEOUT_MS = 5000;
|
|
58831
58885
|
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));
|
|
58832
58886
|
|
|
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
|
+
|
|
58833
58892
|
// packages/mcp/subscription-restore.ts
|
|
58834
|
-
var applyRestored = (deps, intents) => exports_Effect.sync(() => deps.narrowSet.
|
|
58893
|
+
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)), {
|
|
58835
58894
|
discard: true
|
|
58836
58895
|
})));
|
|
58837
|
-
var seedDefaultsIfFresh = (deps,
|
|
58896
|
+
var seedDefaultsIfFresh = (deps, project3) => deps.subscriptionStore.read().pipe(exports_Effect.flatMap(exports_Option.match({
|
|
58838
58897
|
onNone: () => deps.registerDefaults(project3),
|
|
58839
58898
|
onSome: () => exports_Effect.void
|
|
58840
58899
|
})));
|
|
58841
|
-
var restoreSubscriptions = (deps
|
|
58842
|
-
onNone: () => exports_Effect.
|
|
58900
|
+
var restoreSubscriptions = (deps) => deps.subscriptionStore.read().pipe(exports_Effect.flatMap(exports_Option.match({
|
|
58901
|
+
onNone: () => exports_Effect.sync(() => deps.narrowSet.load(exports_Option.none())),
|
|
58843
58902
|
onSome: (intents) => applyRestored(deps, intents)
|
|
58844
58903
|
})));
|
|
58845
|
-
var
|
|
58846
|
-
var persistSubscriptions = (store, narrowSet, sessionId) => store.write(sessionId, narrowSet.intents());
|
|
58904
|
+
var persistSubscriptions = (store, narrowSet) => store.write(narrowSet.intents());
|
|
58847
58905
|
|
|
58848
58906
|
// packages/mcp/subscription-store.ts
|
|
58849
|
-
import { homedir as
|
|
58850
|
-
import { join as
|
|
58907
|
+
import { homedir as homedir3 } from "node:os";
|
|
58908
|
+
import { join as join9 } from "node:path";
|
|
58851
58909
|
class SubscriptionStoreTag extends exports_Context.Tag("SubscriptionStore")() {
|
|
58852
58910
|
}
|
|
58853
58911
|
var SubscribeIntentSchema = exports_Schema.Union(exports_Schema.Struct({ kind: exports_Schema.Literal("mentions") }), exports_Schema.Struct({ kind: exports_Schema.Literal("channel"), channelName: ChannelNameSchema }), exports_Schema.Struct({
|
|
@@ -58857,24 +58915,33 @@ var SubscribeIntentSchema = exports_Schema.Union(exports_Schema.Struct({ kind: e
|
|
|
58857
58915
|
}), exports_Schema.Struct({ kind: exports_Schema.Literal("new-topics-in-channel"), channelName: ChannelNameSchema }));
|
|
58858
58916
|
var SubscriptionsFileSchema = exports_Schema.parseJson(exports_Schema.Array(SubscribeIntentSchema));
|
|
58859
58917
|
var decodeSubscriptionsFile = exports_Schema.decodeUnknown(SubscriptionsFileSchema);
|
|
58860
|
-
var
|
|
58918
|
+
var FILENAME_SAFE3 = /[^a-zA-Z0-9._-]/g;
|
|
58861
58919
|
var subscriptionFilename = (id3) => {
|
|
58862
|
-
const safe = id3.replace(
|
|
58920
|
+
const safe = id3.replace(FILENAME_SAFE3, "_");
|
|
58863
58921
|
return `${safe}.json`;
|
|
58864
58922
|
};
|
|
58865
|
-
var
|
|
58866
|
-
var readSubscriptions = (fs, path) => fs.readFileString(path).pipe(exports_Effect.flatMap(decodeSubscriptionsFile), exports_Effect.map((intents) => exports_Option.some(intents)), exports_Effect.catchIf(
|
|
58923
|
+
var isNotFound3 = (error2) => error2._tag === "SystemError" && error2.reason === "NotFound";
|
|
58924
|
+
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())));
|
|
58867
58925
|
var createFileSubscriptionStore = (deps) => {
|
|
58868
|
-
const { dir, fs } = deps;
|
|
58869
|
-
const pathFor = (id3) =>
|
|
58870
|
-
const read3 = (id3) => readSubscriptions(fs, pathFor(id3));
|
|
58871
|
-
const write4 = (
|
|
58872
|
-
|
|
58873
|
-
|
|
58874
|
-
|
|
58875
|
-
|
|
58876
|
-
|
|
58877
|
-
|
|
58926
|
+
const { dir, fs, cursorDir, session } = deps;
|
|
58927
|
+
const pathFor = (id3) => join9(dir, subscriptionFilename(id3));
|
|
58928
|
+
const read3 = () => exports_Effect.flatMap(exports_Deferred.await(session), (id3) => readSubscriptions(fs, pathFor(id3)));
|
|
58929
|
+
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
|
+
const advanceCursor = (target, ts) => exports_Effect.flatMap(exports_Deferred.poll(session), exports_Option.match({
|
|
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 };
|
|
58935
|
+
};
|
|
58936
|
+
var STATE_SEGMENT3 = "commy";
|
|
58937
|
+
var stateBaseConfig3 = exports_Config.nonEmptyString("XDG_STATE_HOME").pipe(exports_Config.withDefault(join9(homedir3(), ".local", "state")));
|
|
58938
|
+
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 }))));
|
|
58878
58945
|
|
|
58879
58946
|
// packages/mcp/tools.ts
|
|
58880
58947
|
var emptyObjectSchema = {
|
|
@@ -59048,11 +59115,17 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59048
59115
|
description: "Calling session's working directory. In Claude Code, the PreToolUse hook injects this from the harness cwd; non-CC MCP clients may supply their own. Drives the project component of ephemeral cc-<project>-<8> names — without this the minted name falls back to bare cc-<8> (or the operator-forced COMMY_PROJECT slug)."
|
|
59049
59116
|
};
|
|
59050
59117
|
const readSessionId = (args2) => exports_Option.getOrUndefined(parseSessionId(args2["session_id"]));
|
|
59118
|
+
const feedSession = (sessionId) => sessionId === undefined || deps.feedSessionId === undefined ? exports_Effect.void : deps.feedSessionId(sessionId);
|
|
59051
59119
|
const readCwd = (args2) => {
|
|
59052
59120
|
const raw3 = args2["cwd"];
|
|
59053
59121
|
return exports_Predicate.isString(raw3) ? raw3 : undefined;
|
|
59054
59122
|
};
|
|
59055
59123
|
const projectForArgs = (args2) => projectForCwd(readCwd(args2));
|
|
59124
|
+
const ensureBoundForArgs = (args2) => exports_Effect.gen(function* () {
|
|
59125
|
+
const sessionId = readSessionId(args2);
|
|
59126
|
+
yield* feedSession(sessionId);
|
|
59127
|
+
return yield* identityCache.ensureBoundFor(sessionId, yield* projectForArgs(args2));
|
|
59128
|
+
});
|
|
59056
59129
|
const stickyThreadEngagement = async (channel, threadName3) => {
|
|
59057
59130
|
if (exports_Option.isNone(threadName3))
|
|
59058
59131
|
return;
|
|
@@ -59074,8 +59147,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59074
59147
|
additionalProperties: false
|
|
59075
59148
|
},
|
|
59076
59149
|
handler: async (args2) => {
|
|
59077
|
-
const
|
|
59078
|
-
const ensureBound = await runEdge(exports_Effect.flatMap(projectForArgs(args2), (project3) => identityCache.ensureBoundFor(sessionId, project3)));
|
|
59150
|
+
const ensureBound = await runEdge(ensureBoundForArgs(args2));
|
|
59079
59151
|
const current2 = ensureBound.current();
|
|
59080
59152
|
if (current2 === undefined) {
|
|
59081
59153
|
return { state: "unbound", identity: null };
|
|
@@ -59181,7 +59253,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59181
59253
|
additionalProperties: false
|
|
59182
59254
|
},
|
|
59183
59255
|
handler: async (args2) => {
|
|
59184
|
-
await runEdge(
|
|
59256
|
+
await runEdge(ensureBoundForArgs(args2).pipe(exports_Effect.flatMap((ensureBound) => ensureBound())));
|
|
59185
59257
|
const ref = await runEdge(exports_Effect.gen(function* () {
|
|
59186
59258
|
const { channel_name, body, thread, mentions, reply_to } = yield* exports_Schema.decodeUnknown(PostArgs)(args2);
|
|
59187
59259
|
const channel = yield* decodeChannelName(channel_name);
|
|
@@ -59235,7 +59307,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59235
59307
|
additionalProperties: false
|
|
59236
59308
|
},
|
|
59237
59309
|
handler: async (args2) => {
|
|
59238
|
-
await runEdge(
|
|
59310
|
+
await runEdge(ensureBoundForArgs(args2).pipe(exports_Effect.flatMap((ensureBound) => ensureBound())));
|
|
59239
59311
|
const ref = await runEdge(exports_Effect.gen(function* () {
|
|
59240
59312
|
const { message_id, body, channel_name } = yield* exports_Schema.decodeUnknown(EditMessageArgs)(args2);
|
|
59241
59313
|
const target = yield* reconstructMessageRef(cache, message_id, channel_name);
|
|
@@ -59269,7 +59341,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59269
59341
|
additionalProperties: false
|
|
59270
59342
|
},
|
|
59271
59343
|
handler: async (args2) => {
|
|
59272
|
-
await runEdge(
|
|
59344
|
+
await runEdge(ensureBoundForArgs(args2).pipe(exports_Effect.flatMap((ensureBound) => ensureBound())));
|
|
59273
59345
|
const { ref, threadName: threadName3 } = await runEdge(exports_Effect.gen(function* () {
|
|
59274
59346
|
const { message_id, emoji: emoji2, channel_name, thread } = yield* exports_Schema.decodeUnknown(ReactArgs)(args2);
|
|
59275
59347
|
const target = yield* reconstructMessageRef(cache, message_id, channel_name);
|
|
@@ -59300,7 +59372,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59300
59372
|
additionalProperties: false
|
|
59301
59373
|
},
|
|
59302
59374
|
handler: async (args2) => {
|
|
59303
|
-
await runEdge(
|
|
59375
|
+
await runEdge(ensureBoundForArgs(args2).pipe(exports_Effect.flatMap((ensureBound) => ensureBound())));
|
|
59304
59376
|
await runEdge(exports_Effect.gen(function* () {
|
|
59305
59377
|
const { message_id, emoji: emoji2, channel_name } = yield* exports_Schema.decodeUnknown(ReactArgs)(args2);
|
|
59306
59378
|
const ref = yield* reconstructMessageRef(cache, message_id, channel_name);
|
|
@@ -59330,13 +59402,14 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59330
59402
|
const { target: raw3 } = yield* exports_Schema.decodeUnknown(SubscribeArgs)(args2);
|
|
59331
59403
|
const intent = yield* parseSubscribeTarget(raw3);
|
|
59332
59404
|
const sessionId = readSessionId(args2);
|
|
59405
|
+
yield* feedSession(sessionId);
|
|
59333
59406
|
if (sessionId !== undefined && deps.ensureSessionSubscriptions !== undefined) {
|
|
59334
59407
|
yield* deps.ensureSessionSubscriptions(sessionId, yield* projectForArgs(args2));
|
|
59335
59408
|
}
|
|
59336
59409
|
narrowSet.add(intent);
|
|
59337
59410
|
yield* adapter4.inbox.subscribe(intentToTarget(intent));
|
|
59338
|
-
if (
|
|
59339
|
-
yield* deps.persistSessionSubscriptions
|
|
59411
|
+
if (deps.persistSessionSubscriptions !== undefined) {
|
|
59412
|
+
yield* deps.persistSessionSubscriptions;
|
|
59340
59413
|
}
|
|
59341
59414
|
}));
|
|
59342
59415
|
return {};
|
|
@@ -59363,13 +59436,14 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59363
59436
|
const { target: raw3 } = yield* exports_Schema.decodeUnknown(SubscribeArgs)(args2);
|
|
59364
59437
|
const intent = yield* parseSubscribeTarget(raw3);
|
|
59365
59438
|
const sessionId = readSessionId(args2);
|
|
59439
|
+
yield* feedSession(sessionId);
|
|
59366
59440
|
if (sessionId !== undefined && deps.ensureSessionSubscriptions !== undefined) {
|
|
59367
59441
|
yield* deps.ensureSessionSubscriptions(sessionId, yield* projectForArgs(args2));
|
|
59368
59442
|
}
|
|
59369
59443
|
narrowSet.remove(intent);
|
|
59370
59444
|
yield* adapter4.inbox.unsubscribe(intentToTarget(intent));
|
|
59371
|
-
if (
|
|
59372
|
-
yield* deps.persistSessionSubscriptions
|
|
59445
|
+
if (deps.persistSessionSubscriptions !== undefined) {
|
|
59446
|
+
yield* deps.persistSessionSubscriptions;
|
|
59373
59447
|
}
|
|
59374
59448
|
}));
|
|
59375
59449
|
return {};
|
|
@@ -59533,7 +59607,7 @@ var buildToolDefs = (deps, cache) => {
|
|
|
59533
59607
|
const download = deps.downloadFile;
|
|
59534
59608
|
optionalTools.push({
|
|
59535
59609
|
name: "download_file",
|
|
59536
|
-
description: "Download a Zulip user upload by its /user_uploads/... path (visible in message bodies). Writes the file
|
|
59610
|
+
description: "Download a Zulip user upload by its /user_uploads/... path (visible in message bodies). Writes the file into a fresh temp directory and returns {file_path, content_type, size}. The temp directory is created under the operator-set COMMY_DOWNLOAD_DIR when configured (so the file lands in a directory you can Read), otherwise under $TMPDIR. Use the Read tool on the returned file_path to view images.",
|
|
59537
59611
|
inputSchema: {
|
|
59538
59612
|
type: "object",
|
|
59539
59613
|
properties: {
|
|
@@ -59669,7 +59743,22 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59669
59743
|
const adapter4 = yield* SubstrateAdapter;
|
|
59670
59744
|
const cursorStore = yield* CursorStoreTag;
|
|
59671
59745
|
const subscriptionStore = yield* SubscriptionStoreTag;
|
|
59746
|
+
const sessionIdDeferred = yield* SessionId;
|
|
59747
|
+
yield* exports_Effect.flatMap(readBootSessionId, exports_Option.match({
|
|
59748
|
+
onNone: () => exports_Effect.void,
|
|
59749
|
+
onSome: (sessionId) => exports_Deferred.succeed(sessionIdDeferred, sessionId).pipe(exports_Effect.asVoid)
|
|
59750
|
+
}));
|
|
59751
|
+
const feedSessionId = (sessionId) => exports_Deferred.succeed(sessionIdDeferred, sessionId).pipe(exports_Effect.asVoid);
|
|
59672
59752
|
const fs = yield* exports_FileSystem.FileSystem;
|
|
59753
|
+
if (parsed.downloadDir !== undefined) {
|
|
59754
|
+
const base = parsed.downloadDir;
|
|
59755
|
+
const baseStat = yield* fs.stat(base).pipe(exports_Effect.option);
|
|
59756
|
+
if (exports_Option.isNone(baseStat) || baseStat.value.type !== "Directory") {
|
|
59757
|
+
return yield* envConfigError([
|
|
59758
|
+
`COMMY_DOWNLOAD_DIR is set to ${base} but is not an existing directory`
|
|
59759
|
+
]);
|
|
59760
|
+
}
|
|
59761
|
+
}
|
|
59673
59762
|
const loggerLayer = params.loggerLayer ?? stderrLoggerLayer;
|
|
59674
59763
|
const commandExecutor = yield* exports_CommandExecutor.CommandExecutor;
|
|
59675
59764
|
const readGitContext2 = params.readGitContext ?? ((cwd) => readGitContext(cwd).pipe(exports_Effect.provideService(exports_CommandExecutor.CommandExecutor, commandExecutor)));
|
|
@@ -59694,12 +59783,14 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59694
59783
|
const mcp = buildMcpServer();
|
|
59695
59784
|
const notifier = params.notifier ?? channelNotifier(mcp);
|
|
59696
59785
|
const registerType2Defaults = parsed.botName === undefined ? createType2DefaultsOnAcquire(narrowSet, adapter4.inbox) : undefined;
|
|
59697
|
-
const
|
|
59786
|
+
const restoreOnResume = parsed.botName !== undefined ? exports_Effect.void : restoreSubscriptions({ subscriptionStore, narrowSet, inbox: adapter4.inbox }).pipe(exports_Effect.catchAll((err) => exports_Effect.logError(`commy plugin: subscription restore failed: ${exports_Predicate.isError(err) ? err.message : String(err)}`)), exports_Effect.provide(loggerLayer));
|
|
59698
59787
|
const seedDefaults = (project3) => registerType2Defaults !== undefined ? registerType2Defaults(project3) : exports_Effect.void;
|
|
59699
|
-
const
|
|
59700
|
-
const
|
|
59701
|
-
const
|
|
59702
|
-
|
|
59788
|
+
const seedIfFresh = (sessionId, project3) => parsed.botName !== undefined ? exports_Effect.void : seedDefaultsIfFresh({ subscriptionStore, registerDefaults: seedDefaults }, project3).pipe(exports_Effect.catchAll((err) => exports_Effect.logError(`commy plugin: subscription seed check failed for ${sessionId}: ${exports_Predicate.isError(err) ? err.message : String(err)}`).pipe(exports_Effect.zipRight(seedDefaults(project3)))), exports_Effect.provide(loggerLayer));
|
|
59789
|
+
const ensureSessionSubscriptions = (sessionId, project3) => seedIfFresh(sessionId, project3);
|
|
59790
|
+
const persistSessionSubscriptions = parsed.botName !== undefined ? exports_Effect.void : exports_Deferred.poll(sessionIdDeferred).pipe(exports_Effect.flatMap(exports_Option.match({
|
|
59791
|
+
onNone: () => exports_Effect.void,
|
|
59792
|
+
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
|
+
})));
|
|
59703
59794
|
const ephemeralOnAcquire = parsed.botName === undefined ? (acquired, project3, sessionId) => ensureSessionSubscriptions(sessionId, project3).pipe(exports_Effect.zipRight(catchUpMentions({
|
|
59704
59795
|
cursorStore,
|
|
59705
59796
|
inbox: adapter4.inbox,
|
|
@@ -59723,6 +59814,9 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59723
59814
|
yield* exports_Effect.addFinalizer(() => identityCache.boundIdentityIds().size > 0 ? raceReleaseAgainstTimeout(adapter4.identity.release({ persistent: releasePersistent }), RELEASE_TIMEOUT_MS) : exports_Effect.void);
|
|
59724
59815
|
const runsIdleSweep = parsed.botName === undefined;
|
|
59725
59816
|
const subscribedIntents = yield* subscribeFromEnv(adapter4.inbox, narrowSet, parsed);
|
|
59817
|
+
if (parsed.botName === undefined) {
|
|
59818
|
+
narrowSet.beginBuffering();
|
|
59819
|
+
}
|
|
59726
59820
|
const toolsCache = registerTools(mcp, {
|
|
59727
59821
|
adapter: adapter4,
|
|
59728
59822
|
identityCache,
|
|
@@ -59730,10 +59824,11 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59730
59824
|
projectForCwd,
|
|
59731
59825
|
ensureSessionSubscriptions,
|
|
59732
59826
|
persistSessionSubscriptions,
|
|
59827
|
+
feedSessionId,
|
|
59733
59828
|
downloadFile: (urlPath) => exports_Effect.gen(function* () {
|
|
59734
59829
|
const result = yield* adapter4.downloadFile(urlPath);
|
|
59735
|
-
const dir = yield* fs.makeTempDirectory({ prefix: "commy-dl-" });
|
|
59736
|
-
const filePath =
|
|
59830
|
+
const dir = yield* fs.makeTempDirectory(parsed.downloadDir === undefined ? { prefix: "commy-dl-" } : { directory: parsed.downloadDir, prefix: "commy-dl-" });
|
|
59831
|
+
const filePath = join10(dir, basename2(urlPath));
|
|
59737
59832
|
yield* fs.writeFile(filePath, result.data);
|
|
59738
59833
|
return { filePath, contentType: result.contentType, size: result.data.byteLength };
|
|
59739
59834
|
}),
|
|
@@ -59786,15 +59881,21 @@ var makeProgram = (params = {}) => exports_Effect.scoped(exports_Effect.gen(func
|
|
|
59786
59881
|
if (id3 === undefined)
|
|
59787
59882
|
return exports_Effect.void;
|
|
59788
59883
|
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));
|
|
59789
59889
|
}
|
|
59790
59890
|
});
|
|
59791
59891
|
yield* exports_Effect.addFinalizer(() => pump.cancel);
|
|
59792
59892
|
if (runsIdleSweep) {
|
|
59793
59893
|
yield* forkIdleSweep(identityCache, EPHEMERAL_IDLE_SWEEP_INTERVAL_MS);
|
|
59794
59894
|
}
|
|
59895
|
+
yield* exports_Effect.forkScoped(restoreOnResume);
|
|
59795
59896
|
yield* exports_Effect.raceFirst(pump.done, params.shutdownSignal ?? exports_Effect.never);
|
|
59796
59897
|
}));
|
|
59797
|
-
var AppLayer = exports_Layer.mergeAll(ZulipAdapterLive, FileCursorStoreLive, FileSubscriptionStoreLive, stderrLoggerLayer);
|
|
59898
|
+
var AppLayer = exports_Layer.mergeAll(ZulipAdapterLive, FileCursorStoreLive, exports_Layer.provideMerge(FileSubscriptionStoreLive, SessionIdLive), stderrLoggerLayer);
|
|
59798
59899
|
var PlatformLive = exports_Layer.mergeAll(exports_Layer.setConfigProvider(exports_ConfigProvider.fromEnv()), exports_FetchHttpClient.layer, exports_NodeContext.layer);
|
|
59799
59900
|
var MainLive = exports_Layer.provideMerge(AppLayer, PlatformLive);
|
|
59800
59901
|
var clientDisconnect = (stdin3) => exports_Effect.async((resume2) => {
|