paperclip-plugin-mattermost 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -84,7 +84,7 @@ PAPERCLIP_REF=<commit> node build.mjs # build for another Paperclip version
84
84
  Bump `version` in `package.json` and `src/manifest.ts`, commit, then tag and push:
85
85
 
86
86
  ```bash
87
- git tag -a v0.16.0 -m v0.16.0 && git push origin main v0.16.0
87
+ git tag -a v0.16.1 -m v0.16.1 && git push origin main v0.16.1
88
88
  ```
89
89
 
90
90
  GitHub Actions builds, tests and publishes to npm through npm trusted publishing, so no npm token is involved.
package/dist/manifest.js CHANGED
@@ -82,7 +82,7 @@ var route = (routeKey, method, path) => ({ routeKey, method, path, auth: "agent"
82
82
  var manifest = {
83
83
  id: "mattermost-bridge",
84
84
  apiVersion: 1,
85
- version: "0.16.0",
85
+ version: "0.16.1",
86
86
  displayName: "Mattermost",
87
87
  description: "Every agent becomes its own Mattermost bot. DM an agent or mention it in a channel and it answers in the thread, showing its steps as it works; follow-ups continue the conversation. Paperclip approvals arrive with Approve / Reject buttons.",
88
88
  author: "Haseeb Azhar",
package/dist/worker.js CHANGED
@@ -45032,7 +45032,9 @@ var Actions = class {
45032
45032
  this.d = deps;
45033
45033
  }
45034
45034
  /** One route call. `params` are the route's path parameters, `input` its query or body. */
45035
- async handle(agentId, routeKey, params, input2) {
45035
+ runId = null;
45036
+ async handle(agentId, routeKey, params, input2, runId = null) {
45037
+ this.runId = runId;
45036
45038
  const bot = this.d.bot(agentId);
45037
45039
  if (!bot) return bad(409, "You have no Mattermost bot in this company yet (your agent may be switched off in the plugin's settings).");
45038
45040
  try {
@@ -45184,7 +45186,7 @@ var Actions = class {
45184
45186
  const text2 = str3(input2.text);
45185
45187
  if (!text2) return bad(400, "text is empty");
45186
45188
  const ch = await this.channel(bot, str3(input2.channel));
45187
- const threadId = str3(input2.threadId);
45189
+ const threadId = str3(input2.threadId) || await this.d.taskThread?.(agentId, this.runId, ch.id).catch(() => null) || "";
45188
45190
  const waiting = await this.gate(agentId, canPost(text2), "post", `post in ~${ch.name}: "${text2.slice(0, 200)}"`, { channelId: ch.id, threadId, text: text2 });
45189
45191
  if (waiting) return waiting;
45190
45192
  return ok(await this.doPost(bot, ch.id, threadId, text2));
@@ -45207,7 +45209,8 @@ var Actions = class {
45207
45209
  const verdict = canDm(await this.d.canTalk(user2.id, agentId));
45208
45210
  if (!verdict.ok) return bad(403, `Not allowed: ${verdict.why}.`);
45209
45211
  const channel2 = await bot.request("POST", "/channels/direct", [bot.botUserId, user2.id]);
45210
- return ok(await this.doPost(bot, channel2.id, "", text2));
45212
+ const threadId = str3(input2.threadId) || await this.d.taskThread?.(agentId, this.runId, channel2.id).catch(() => null) || "";
45213
+ return ok(await this.doPost(bot, channel2.id, threadId, text2));
45211
45214
  }
45212
45215
  // ---- channels ----------------------------------------------------------------------
45213
45216
  async created() {
@@ -46272,7 +46275,7 @@ var route = (routeKey, method, path3) => ({ routeKey, method, path: path3, auth:
46272
46275
  var manifest = {
46273
46276
  id: "mattermost-bridge",
46274
46277
  apiVersion: 1,
46275
- version: "0.16.0",
46278
+ version: "0.16.1",
46276
46279
  displayName: "Mattermost",
46277
46280
  description: "Every agent becomes its own Mattermost bot. DM an agent or mention it in a channel and it answers in the thread, showing its steps as it works; follow-ups continue the conversation. Paperclip approvals arrive with Approve / Reject buttons.",
46278
46281
  author: "Haseeb Azhar",
@@ -46598,6 +46601,14 @@ var Tenant = class {
46598
46601
  agents: () => roster.all().map((m) => ({ agentId: m.agentId, agentName: m.agentName, username: m.username, botUserId: m.botUserId })),
46599
46602
  canTalk: async (userId, agentId) => !canTalk || canTalk(userId, agentId),
46600
46603
  origin: (agentId) => bridge.activeThread(agentId),
46604
+ // The task this run works on (its execution or checkout run), and the thread it was asked for in.
46605
+ taskThread: async (agentId, runId, channelId) => {
46606
+ if (!runId) return null;
46607
+ const issues = await ctx.issues.list({ companyId, assigneeAgentId: agentId, limit: 200 });
46608
+ const issue2 = issues.find((i) => i.executionRunId === runId || i.checkoutRunId === runId);
46609
+ const at = issue2 ? await store.get(`issuethread:${issue2.id}`) : null;
46610
+ return at && at.channelId === channelId ? at.rootId : null;
46611
+ },
46601
46612
  task: async (taskId) => await ctx.issues.get(taskId, companyId),
46602
46613
  askApproval: async (req) => {
46603
46614
  if (!paperclipUrl || !approvers.size) throw Object.assign(new Error("this needs a person's approval, and nobody can approve from Mattermost yet (the plugin needs its Paperclip public URL and approvers set)"), { status: 403 });
@@ -46668,9 +46679,9 @@ var Tenant = class {
46668
46679
  return null;
46669
46680
  }
46670
46681
  /** An agent's call to one of the plugin's `/mm/...` routes. */
46671
- async api(agentId, routeKey, params, input2) {
46682
+ async api(agentId, routeKey, params, input2, runId = null) {
46672
46683
  if (!this.actions) return { status: 503, body: { error: `Mattermost is not connected for this company (${this.status})` } };
46673
- return this.actions.handle(agentId, routeKey, params, input2);
46684
+ return this.actions.handle(agentId, routeKey, params, input2, runId);
46674
46685
  }
46675
46686
  /** The Agent computer plugin: an agent wants a person at its computer. Posted where the agent is working. */
46676
46687
  async computerNeedsPerson(p) {
@@ -46826,6 +46837,14 @@ var plugin = definePlugin({
46826
46837
  ctx.events.on("plugin.agent-computer.needs-person", (e) => quietly("could not post a computer help request", async () => {
46827
46838
  await tenants.get(e.companyId)?.computerNeedsPerson(e.payload ?? {});
46828
46839
  }));
46840
+ ctx.events.on("issue.created", (e) => quietly("could not link a task to its thread", async () => {
46841
+ const tenant = tenants.get(e.companyId);
46842
+ if (!tenant?.bridge || !e.entityId) return;
46843
+ const issue2 = await ctx.issues.get(e.entityId, e.companyId);
46844
+ const by = issue2?.createdByAgentId;
46845
+ const at = by ? tenant.bridge.activeThread(by) : null;
46846
+ if (at) await tenant.store().set(`issuethread:${e.entityId}`, at);
46847
+ }));
46829
46848
  ctx.events.on("approval.decided", (e) => quietly("could not update approval", async () => {
46830
46849
  if (e.entityId) await tenants.get(e.companyId)?.approvals?.decided(e.entityId);
46831
46850
  }));
@@ -46865,7 +46884,7 @@ var plugin = definePlugin({
46865
46884
  const messages = tenant.bridge ? await tenant.bridge.takeInbox(agentId) : [];
46866
46885
  return { status: 200, body: { messages, note: messages.length ? "Written to you while you were working. Act on them now: they are not sent to you again." : "Nothing new." } };
46867
46886
  }
46868
- const res = await tenant.api(agentId, input2.routeKey, input2.params, { ...query, ...body });
46887
+ const res = await tenant.api(agentId, input2.routeKey, input2.params, { ...query, ...body }, input2.actor.runId ?? null);
46869
46888
  if (tenant.bridge?.hasInbox(agentId) && res.body && typeof res.body === "object" && !Array.isArray(res.body)) {
46870
46889
  res.body = { ...res.body, newMessages: await tenant.bridge.takeInbox(agentId) };
46871
46890
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-plugin-mattermost",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Paperclip agents in Mattermost: a bot per agent, live progress, files, approval and decision buttons, and per-person access, for each Paperclip company.",
5
5
  "type": "module",
6
6
  "license": "MIT",