openryoko 2026.4.28 → 2026.4.30

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 (141) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/cli/create.js +10 -10
  3. package/dist/src/cli/create.js.map +1 -1
  4. package/dist/src/cli/list.js +2 -2
  5. package/dist/src/cli/list.js.map +1 -1
  6. package/dist/src/cli/migrate.js +18 -18
  7. package/dist/src/cli/migrate.js.map +1 -1
  8. package/dist/src/cli/nuke.js +15 -15
  9. package/dist/src/cli/nuke.js.map +1 -1
  10. package/dist/src/cli/setup.js +22 -22
  11. package/dist/src/cli/setup.js.map +1 -1
  12. package/dist/src/cli/skills.js +17 -17
  13. package/dist/src/cli/skills.js.map +1 -1
  14. package/dist/src/connectors/slack/__tests__/conversation-tracker.test.d.ts +2 -0
  15. package/dist/src/connectors/slack/__tests__/conversation-tracker.test.d.ts.map +1 -0
  16. package/dist/src/connectors/slack/__tests__/conversation-tracker.test.js +132 -0
  17. package/dist/src/connectors/slack/__tests__/conversation-tracker.test.js.map +1 -0
  18. package/dist/src/connectors/slack/__tests__/dm-equivalent.test.d.ts +2 -0
  19. package/dist/src/connectors/slack/__tests__/dm-equivalent.test.d.ts.map +1 -0
  20. package/dist/src/connectors/slack/__tests__/dm-equivalent.test.js +72 -0
  21. package/dist/src/connectors/slack/__tests__/dm-equivalent.test.js.map +1 -0
  22. package/dist/src/connectors/slack/conversation-tracker.d.ts +64 -0
  23. package/dist/src/connectors/slack/conversation-tracker.d.ts.map +1 -0
  24. package/dist/src/connectors/slack/conversation-tracker.js +151 -0
  25. package/dist/src/connectors/slack/conversation-tracker.js.map +1 -0
  26. package/dist/src/connectors/slack/dm-equivalent.d.ts +44 -0
  27. package/dist/src/connectors/slack/dm-equivalent.d.ts.map +1 -0
  28. package/dist/src/connectors/slack/dm-equivalent.js +69 -0
  29. package/dist/src/connectors/slack/dm-equivalent.js.map +1 -0
  30. package/dist/src/connectors/slack/index.d.ts +1 -2
  31. package/dist/src/connectors/slack/index.d.ts.map +1 -1
  32. package/dist/src/connectors/slack/index.js +48 -20
  33. package/dist/src/connectors/slack/index.js.map +1 -1
  34. package/dist/src/connectors/slack/triage.d.ts.map +1 -1
  35. package/dist/src/connectors/slack/triage.js +5 -1
  36. package/dist/src/connectors/slack/triage.js.map +1 -1
  37. package/dist/src/gateway/server.js +1 -1
  38. package/dist/src/gateway/server.js.map +1 -1
  39. package/dist/src/shared/config.js +1 -1
  40. package/dist/src/shared/config.js.map +1 -1
  41. package/dist/src/shared/types.d.ts +5 -4
  42. package/dist/src/shared/types.d.ts.map +1 -1
  43. package/dist/web/404.html +1 -1
  44. package/dist/web/__next.__PAGE__.txt +2 -2
  45. package/dist/web/__next._full.txt +3 -3
  46. package/dist/web/__next._head.txt +1 -1
  47. package/dist/web/__next._index.txt +2 -2
  48. package/dist/web/__next._tree.txt +2 -2
  49. package/dist/web/_next/static/chunks/05uy~i7wsbsn3.js +1 -0
  50. package/dist/web/_next/static/chunks/0bj62gv2pext..css +1 -0
  51. package/dist/web/_next/static/chunks/{16b0jvgccyt2i.js → 0ma0h4_2c8y9y.js} +1 -1
  52. package/dist/web/_next/static/chunks/{0wzpea61sn2-k.js → 0v51a3blij~j6.js} +1 -1
  53. package/dist/web/_next/static/chunks/{12h4dws.tz7yb.js → 0wv0qjh9tuqx~.js} +1 -1
  54. package/dist/web/_next/static/chunks/{0398g9fy2i2l..js → 0y3uv64m1qh.k.js} +1 -1
  55. package/dist/web/_next/static/chunks/{07t-qdutaizlf.js → 1621s_jgljr1_.js} +1 -1
  56. package/dist/web/_next/static/chunks/{0_pxvi.u4tzw1.js → 1645~4k0qcst0.js} +1 -1
  57. package/dist/web/_next/static/chunks/{0ihbb7~gq42g~.js → 16zc7-yv7supr.js} +1 -1
  58. package/dist/web/_not-found/__next._full.txt +2 -2
  59. package/dist/web/_not-found/__next._head.txt +1 -1
  60. package/dist/web/_not-found/__next._index.txt +2 -2
  61. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +1 -1
  62. package/dist/web/_not-found/__next._not-found.txt +1 -1
  63. package/dist/web/_not-found/__next._tree.txt +2 -2
  64. package/dist/web/_not-found.html +1 -1
  65. package/dist/web/_not-found.txt +2 -2
  66. package/dist/web/chat/__next._full.txt +3 -3
  67. package/dist/web/chat/__next._head.txt +1 -1
  68. package/dist/web/chat/__next._index.txt +2 -2
  69. package/dist/web/chat/__next._tree.txt +2 -2
  70. package/dist/web/chat/__next.chat.__PAGE__.txt +2 -2
  71. package/dist/web/chat/__next.chat.txt +1 -1
  72. package/dist/web/chat.html +1 -1
  73. package/dist/web/chat.txt +3 -3
  74. package/dist/web/cron/__next._full.txt +3 -3
  75. package/dist/web/cron/__next._head.txt +1 -1
  76. package/dist/web/cron/__next._index.txt +2 -2
  77. package/dist/web/cron/__next._tree.txt +2 -2
  78. package/dist/web/cron/__next.cron.__PAGE__.txt +2 -2
  79. package/dist/web/cron/__next.cron.txt +1 -1
  80. package/dist/web/cron.html +1 -1
  81. package/dist/web/cron.txt +3 -3
  82. package/dist/web/dev/logs/next-development.log +5 -0
  83. package/dist/web/index.html +1 -1
  84. package/dist/web/index.txt +3 -3
  85. package/dist/web/kanban/__next._full.txt +3 -3
  86. package/dist/web/kanban/__next._head.txt +1 -1
  87. package/dist/web/kanban/__next._index.txt +2 -2
  88. package/dist/web/kanban/__next._tree.txt +2 -2
  89. package/dist/web/kanban/__next.kanban.__PAGE__.txt +2 -2
  90. package/dist/web/kanban/__next.kanban.txt +1 -1
  91. package/dist/web/kanban.html +1 -1
  92. package/dist/web/kanban.txt +3 -3
  93. package/dist/web/logs/__next._full.txt +3 -3
  94. package/dist/web/logs/__next._head.txt +1 -1
  95. package/dist/web/logs/__next._index.txt +2 -2
  96. package/dist/web/logs/__next._tree.txt +2 -2
  97. package/dist/web/logs/__next.logs.__PAGE__.txt +2 -2
  98. package/dist/web/logs/__next.logs.txt +1 -1
  99. package/dist/web/logs.html +2 -2
  100. package/dist/web/logs.txt +3 -3
  101. package/dist/web/org/__next._full.txt +3 -3
  102. package/dist/web/org/__next._head.txt +1 -1
  103. package/dist/web/org/__next._index.txt +2 -2
  104. package/dist/web/org/__next._tree.txt +2 -2
  105. package/dist/web/org/__next.org.__PAGE__.txt +2 -2
  106. package/dist/web/org/__next.org.txt +1 -1
  107. package/dist/web/org.html +1 -1
  108. package/dist/web/org.txt +3 -3
  109. package/dist/web/sessions/__next._full.txt +2 -2
  110. package/dist/web/sessions/__next._head.txt +1 -1
  111. package/dist/web/sessions/__next._index.txt +2 -2
  112. package/dist/web/sessions/__next._tree.txt +2 -2
  113. package/dist/web/sessions/__next.sessions.__PAGE__.txt +1 -1
  114. package/dist/web/sessions/__next.sessions.txt +1 -1
  115. package/dist/web/sessions.html +1 -1
  116. package/dist/web/sessions.txt +2 -2
  117. package/dist/web/settings/__next._full.txt +3 -3
  118. package/dist/web/settings/__next._head.txt +1 -1
  119. package/dist/web/settings/__next._index.txt +2 -2
  120. package/dist/web/settings/__next._tree.txt +2 -2
  121. package/dist/web/settings/__next.settings.__PAGE__.txt +2 -2
  122. package/dist/web/settings/__next.settings.txt +1 -1
  123. package/dist/web/settings.html +1 -1
  124. package/dist/web/settings.txt +3 -3
  125. package/dist/web/skills/__next._full.txt +3 -3
  126. package/dist/web/skills/__next._head.txt +1 -1
  127. package/dist/web/skills/__next._index.txt +2 -2
  128. package/dist/web/skills/__next._tree.txt +2 -2
  129. package/dist/web/skills/__next.skills.__PAGE__.txt +2 -2
  130. package/dist/web/skills/__next.skills.txt +1 -1
  131. package/dist/web/skills.html +1 -1
  132. package/dist/web/skills.txt +3 -3
  133. package/package.json +1 -1
  134. package/template/config.default.yaml +1 -1
  135. package/template/migrations/0.3.0/files/CLAUDE.md +3 -0
  136. package/template/migrations/0.3.0/files/config.default.yaml +1 -1
  137. package/dist/web/_next/static/chunks/068ifilpihtkg.js +0 -1
  138. package/dist/web/_next/static/chunks/0mlo32yrc7ziu.css +0 -1
  139. /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_buildManifest.js +0 -0
  140. /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_clientMiddlewareManifest.js +0 -0
  141. /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_ssgManifest.js +0 -0
@@ -130,7 +130,7 @@ export function skillsFind(query) {
130
130
  process.exitCode = result.status ?? 1;
131
131
  }
132
132
  export function skillsAdd(pkg) {
133
- console.log(`\nInstalling skill: ${pkg}\n`);
133
+ console.log(`\nスキルをインストール中: ${pkg}\n`);
134
134
  // Snapshot before
135
135
  const before = snapshotDirs();
136
136
  // Run npx skills add
@@ -139,7 +139,7 @@ export function skillsAdd(pkg) {
139
139
  shell: true,
140
140
  });
141
141
  if (result.status !== 0) {
142
- console.error(`\n${RED}Failed to install skill.${RESET}`);
142
+ console.error(`\n${RED}スキルのインストールに失敗しました。${RESET}`);
143
143
  process.exitCode = 1;
144
144
  return;
145
145
  }
@@ -153,10 +153,10 @@ export function skillsAdd(pkg) {
153
153
  if (existing) {
154
154
  copySkillToInstance(existing.name, existing.dir);
155
155
  upsertManifest(existing.name, pkg);
156
- console.log(`\n${GREEN}Skill "${existing.name}" added to ${SKILLS_DIR}${RESET}`);
156
+ console.log(`\n${GREEN}スキル "${existing.name}" を ${SKILLS_DIR} に追加しました${RESET}`);
157
157
  }
158
158
  else {
159
- console.log(`\n${YELLOW}Skill installed globally but could not locate the directory.${RESET}`);
159
+ console.log(`\n${YELLOW}グローバルにはインストール済みですが、ディレクトリの特定に失敗しました。${RESET}`);
160
160
  }
161
161
  return;
162
162
  }
@@ -164,22 +164,22 @@ export function skillsAdd(pkg) {
164
164
  const installed = newDirs[0];
165
165
  copySkillToInstance(installed.name, path.join(installed.dir, installed.name));
166
166
  upsertManifest(installed.name, pkg);
167
- console.log(`\n${GREEN}Skill "${installed.name}" added to ${SKILLS_DIR}${RESET}`);
167
+ console.log(`\n${GREEN}スキル "${installed.name}" を ${SKILLS_DIR} に追加しました${RESET}`);
168
168
  }
169
169
  export function skillsRemove(name) {
170
170
  const skillDir = path.join(SKILLS_DIR, name);
171
171
  if (!fs.existsSync(skillDir)) {
172
- console.error(`${RED}Skill "${name}" not found in ${SKILLS_DIR}${RESET}`);
172
+ console.error(`${RED}スキル "${name}" は ${SKILLS_DIR} に見つかりません${RESET}`);
173
173
  process.exitCode = 1;
174
174
  return;
175
175
  }
176
176
  fs.rmSync(skillDir, { recursive: true, force: true });
177
177
  removeFromManifest(name);
178
- console.log(`${GREEN}Skill "${name}" removed.${RESET}`);
178
+ console.log(`${GREEN}スキル "${name}" を削除しました。${RESET}`);
179
179
  }
180
180
  export function skillsList() {
181
181
  if (!fs.existsSync(SKILLS_DIR)) {
182
- console.log("No skills installed.");
182
+ console.log("インストール済みスキルがありません。");
183
183
  return;
184
184
  }
185
185
  const manifest = readManifest();
@@ -187,10 +187,10 @@ export function skillsList() {
187
187
  const entries = fs.readdirSync(SKILLS_DIR, { withFileTypes: true });
188
188
  const skillDirs = entries.filter((e) => e.isDirectory());
189
189
  if (skillDirs.length === 0) {
190
- console.log("No skills installed.");
190
+ console.log("インストール済みスキルがありません。");
191
191
  return;
192
192
  }
193
- console.log(`\n Skills in ${DIM}${SKILLS_DIR}${RESET}\n`);
193
+ console.log(`\n ${DIM}${SKILLS_DIR}${RESET} のスキル\n`);
194
194
  for (const dir of skillDirs) {
195
195
  const meta = manifestMap.get(dir.name);
196
196
  const source = meta ? `${DIM}(${meta.source})${RESET}` : `${DIM}(local)${RESET}`;
@@ -212,19 +212,19 @@ export function skillsList() {
212
212
  export function skillsUpdate() {
213
213
  const manifest = readManifest();
214
214
  if (manifest.length === 0) {
215
- console.log("No skills in manifest to update.");
215
+ console.log("更新対象のスキルがマニフェストにありません。");
216
216
  return;
217
217
  }
218
- console.log(`\nUpdating ${manifest.length} skill(s)...\n`);
218
+ console.log(`\n${manifest.length} 件のスキルを更新中...\n`);
219
219
  for (const entry of manifest) {
220
- console.log(` Updating ${entry.name} from ${entry.source}...`);
220
+ console.log(` ${entry.name} を ${entry.source} から更新中...`);
221
221
  const before = snapshotDirs();
222
222
  const result = spawnSync("npx", ["skills", "add", entry.source, "-g", "-y"], {
223
223
  stdio: "pipe",
224
224
  shell: true,
225
225
  });
226
226
  if (result.status !== 0) {
227
- console.log(` ${RED}Failed to update ${entry.name}${RESET}`);
227
+ console.log(` ${RED}${entry.name} の更新に失敗${RESET}`);
228
228
  continue;
229
229
  }
230
230
  const after = snapshotDirs();
@@ -239,17 +239,17 @@ export function skillsUpdate() {
239
239
  }
240
240
  }
241
241
  upsertManifest(entry.name, entry.source);
242
- console.log(` ${GREEN}Updated ${entry.name}${RESET}`);
242
+ console.log(` ${GREEN}${entry.name} を更新しました${RESET}`);
243
243
  }
244
244
  console.log("");
245
245
  }
246
246
  export function skillsRestore() {
247
247
  const manifest = readManifest();
248
248
  if (manifest.length === 0) {
249
- console.log("No skills in manifest to restore.");
249
+ console.log("復元対象のスキルがマニフェストにありません。");
250
250
  return;
251
251
  }
252
- console.log(`\nRestoring ${manifest.length} skill(s)...\n`);
252
+ console.log(`\n${manifest.length} 件のスキルを復元中...\n`);
253
253
  for (const entry of manifest) {
254
254
  const destDir = path.join(SKILLS_DIR, entry.name);
255
255
  if (fs.existsSync(destDir)) {
@@ -1 +1 @@
1
- {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/cli/skills.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/cli/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=conversation-tracker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-tracker.test.d.ts","sourceRoot":"","sources":["../../../../../src/connectors/slack/__tests__/conversation-tracker.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,132 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { ConversationTracker } from "../conversation-tracker.js";
3
+ describe("ConversationTracker.keyFor", () => {
4
+ it("returns a thread key when thread_ts != ts", () => {
5
+ expect(ConversationTracker.keyFor({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" })).toBe("C1:thread:T1");
6
+ });
7
+ it("returns a user key when thread_ts is undefined", () => {
8
+ expect(ConversationTracker.keyFor({ channel: "C1", ts: "T1", userId: "U1" })).toBe("C1:user:U1");
9
+ });
10
+ it("returns a user key when thread_ts equals ts (thread root, no replies)", () => {
11
+ expect(ConversationTracker.keyFor({ channel: "C1", threadTs: "T1", ts: "T1", userId: "U1" })).toBe("C1:user:U1");
12
+ });
13
+ it("returns null when channel is missing", () => {
14
+ expect(ConversationTracker.keyFor({ channel: "", ts: "T1", userId: "U1" })).toBeNull();
15
+ });
16
+ it("returns null when userId is missing", () => {
17
+ expect(ConversationTracker.keyFor({ channel: "C1", ts: "T1", userId: "" })).toBeNull();
18
+ });
19
+ });
20
+ describe("ConversationTracker — DM-equivalent gating", () => {
21
+ it("starts non-DM-equivalent (bot has not engaged)", () => {
22
+ const t = new ConversationTracker();
23
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
24
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T1", userId: "U1" })).toBe(false);
25
+ });
26
+ it("becomes DM-equivalent after bot engages with single human", () => {
27
+ const t = new ConversationTracker();
28
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
29
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
30
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T2", userId: "U1" })).toBe(true);
31
+ });
32
+ it("breaks DM-equivalence when a third party speaks in the same thread", () => {
33
+ const t = new ConversationTracker();
34
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" });
35
+ t.recordBotEngaged({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" });
36
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T3", userId: "U1" })).toBe(true);
37
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T4", userId: "U2" });
38
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T5", userId: "U1" })).toBe(false);
39
+ });
40
+ it("does not break user-key DM-equivalence when another user posts elsewhere in the channel", () => {
41
+ const t = new ConversationTracker();
42
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
43
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
44
+ t.recordHumanMessage({ channel: "C1", ts: "T2", userId: "U2" });
45
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T3", userId: "U1" })).toBe(true);
46
+ });
47
+ it("permanence: DM-equivalence survives many follow-ups without TTL", () => {
48
+ const t = new ConversationTracker();
49
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
50
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
51
+ for (let i = 0; i < 100; i += 1) {
52
+ t.recordHumanMessage({ channel: "C1", ts: `T${i}`, userId: "U1" });
53
+ }
54
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T999", userId: "U1" })).toBe(true);
55
+ });
56
+ });
57
+ describe("ConversationTracker — thread/channel-user bridging", () => {
58
+ it("does NOT prime the future thread key from receipt-time engagement (outbound is responsible)", () => {
59
+ const t = new ConversationTracker();
60
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
61
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
62
+ // Thread key has not been touched yet — the user follow-up in thread
63
+ // should fall through to triage until the outbound path marks the
64
+ // thread (which the connector does at replyMessage time).
65
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" })).toBe(false);
66
+ });
67
+ it("full flow: user top-level → bot replies in thread (outbound marks thread) → user follow-up in thread is DM-equivalent", () => {
68
+ const t = new ConversationTracker();
69
+ // 1. User posts top-level
70
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
71
+ // 2. Bot decides to engage at receipt time — marks user-key engaged
72
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
73
+ // 3. Bot calls replyMessage → outbound marks the thread anchor
74
+ t.recordBotInitiatedThread("C1", "T1");
75
+ // 4. User follows up in the thread
76
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" });
77
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T3", userId: "U1" })).toBe(true);
78
+ });
79
+ it("user-key still active after bot replied via thread (mixed top-level + thread follow-ups)", () => {
80
+ const t = new ConversationTracker();
81
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
82
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
83
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T99", userId: "U1" })).toBe(true);
84
+ });
85
+ });
86
+ describe("ConversationTracker — bot-initiated threads", () => {
87
+ it("treats first human reply in a bot-initiated thread as DM-equivalent", () => {
88
+ const t = new ConversationTracker();
89
+ t.recordBotInitiatedThread("C1", "T1");
90
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" });
91
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T3", userId: "U1" })).toBe(true);
92
+ });
93
+ it("reverts to triage in bot-initiated thread when a second human joins", () => {
94
+ const t = new ConversationTracker();
95
+ t.recordBotInitiatedThread("C1", "T1");
96
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T2", userId: "U1" });
97
+ t.recordHumanMessage({ channel: "C1", threadTs: "T1", ts: "T3", userId: "U2" });
98
+ expect(t.isDmEquivalent({ channel: "C1", threadTs: "T1", ts: "T4", userId: "U1" })).toBe(false);
99
+ });
100
+ });
101
+ describe("ConversationTracker — eviction policy", () => {
102
+ it("never evicts an engaged conversation when pruning under cap pressure", () => {
103
+ const t = new ConversationTracker();
104
+ // Engage one conversation early — this is the entry we must NOT lose.
105
+ t.recordHumanMessage({ channel: "C-engaged", ts: "T1", userId: "U1" });
106
+ t.recordBotEngaged({ channel: "C-engaged", ts: "T1", userId: "U1" });
107
+ // Flood with 6000 distinct non-engaged (channel, user) pairs to push
108
+ // the tracker past the prune threshold.
109
+ for (let i = 0; i < 6000; i += 1) {
110
+ t.recordHumanMessage({ channel: `C-noise-${i}`, ts: `T${i}`, userId: `U-noise-${i}` });
111
+ }
112
+ // The engaged conversation must still be DM-equivalent.
113
+ expect(t.isDmEquivalent({ channel: "C-engaged", ts: "T-late", userId: "U1" })).toBe(true);
114
+ });
115
+ });
116
+ describe("ConversationTracker — robustness", () => {
117
+ it("tolerates missing fields in keyFor inputs", () => {
118
+ const t = new ConversationTracker();
119
+ t.recordHumanMessage({ channel: "", ts: "T1", userId: "U1" });
120
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "" });
121
+ expect(t.size()).toBe(0);
122
+ });
123
+ it("invalidate clears a specific key", () => {
124
+ const t = new ConversationTracker();
125
+ t.recordHumanMessage({ channel: "C1", ts: "T1", userId: "U1" });
126
+ t.recordBotEngaged({ channel: "C1", ts: "T1", userId: "U1" });
127
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T2", userId: "U1" })).toBe(true);
128
+ t.invalidate("C1:user:U1");
129
+ expect(t.isDmEquivalent({ channel: "C1", ts: "T3", userId: "U1" })).toBe(false);
130
+ });
131
+ });
132
+ //# sourceMappingURL=conversation-tracker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-tracker.test.js","sourceRoot":"","sources":["../../../../../src/connectors/slack/__tests__/conversation-tracker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dm-equivalent.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dm-equivalent.test.d.ts","sourceRoot":"","sources":["../../../../../src/connectors/slack/__tests__/dm-equivalent.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { DmEquivalentDetector } from "../dm-equivalent.js";
3
+ function makeClient(responses) {
4
+ let i = 0;
5
+ const info = vi.fn().mockImplementation(async (_args) => {
6
+ const next = responses[i++] ?? responses[responses.length - 1];
7
+ if (next instanceof Error)
8
+ throw next;
9
+ return { ok: true, channel: next };
10
+ });
11
+ return { info };
12
+ }
13
+ describe("DmEquivalentDetector", () => {
14
+ it("returns true when the channel has exactly 2 members", async () => {
15
+ const client = makeClient([{ num_members: 2 }]);
16
+ const det = new DmEquivalentDetector(client);
17
+ expect(await det.isTwoMember("C123")).toBe(true);
18
+ });
19
+ it("returns false when the channel has more than 2 members", async () => {
20
+ const client = makeClient([{ num_members: 5 }]);
21
+ const det = new DmEquivalentDetector(client);
22
+ expect(await det.isTwoMember("C123")).toBe(false);
23
+ });
24
+ it("returns null on Slack API failure (caller should treat as 'unknown')", async () => {
25
+ const client = makeClient([new Error("not_in_channel")]);
26
+ const det = new DmEquivalentDetector(client);
27
+ expect(await det.isTwoMember("C123")).toBeNull();
28
+ });
29
+ it("returns null when num_members is missing from the response", async () => {
30
+ const client = makeClient([{}]);
31
+ const det = new DmEquivalentDetector(client);
32
+ expect(await det.isTwoMember("C123")).toBeNull();
33
+ });
34
+ it("caches results across calls within the TTL window", async () => {
35
+ const client = makeClient([{ num_members: 2 }]);
36
+ const det = new DmEquivalentDetector(client, 60_000);
37
+ await det.isTwoMember("C123");
38
+ await det.isTwoMember("C123");
39
+ await det.isTwoMember("C123");
40
+ expect(client.info).toHaveBeenCalledTimes(1);
41
+ });
42
+ it("re-fetches once the TTL expires", async () => {
43
+ const client = makeClient([{ num_members: 2 }, { num_members: 5 }]);
44
+ const det = new DmEquivalentDetector(client, 1_000);
45
+ const start = 1_000_000_000;
46
+ expect(await det.isTwoMember("C123", start)).toBe(true);
47
+ expect(await det.isTwoMember("C123", start + 1_500)).toBe(false);
48
+ expect(client.info).toHaveBeenCalledTimes(2);
49
+ });
50
+ it("does not cache failures (so transient errors recover on the next message)", async () => {
51
+ const client = makeClient([new Error("rate_limited"), { num_members: 2 }]);
52
+ const det = new DmEquivalentDetector(client);
53
+ expect(await det.isTwoMember("C123")).toBeNull();
54
+ expect(await det.isTwoMember("C123")).toBe(true);
55
+ expect(client.info).toHaveBeenCalledTimes(2);
56
+ });
57
+ it("invalidate() drops the cached entry", async () => {
58
+ const client = makeClient([{ num_members: 2 }, { num_members: 3 }]);
59
+ const det = new DmEquivalentDetector(client);
60
+ expect(await det.isTwoMember("C123")).toBe(true);
61
+ det.invalidate("C123");
62
+ expect(await det.isTwoMember("C123")).toBe(false);
63
+ expect(client.info).toHaveBeenCalledTimes(2);
64
+ });
65
+ it("returns null for empty channel id without calling the API", async () => {
66
+ const client = makeClient([{ num_members: 2 }]);
67
+ const det = new DmEquivalentDetector(client);
68
+ expect(await det.isTwoMember("")).toBeNull();
69
+ expect(client.info).not.toHaveBeenCalled();
70
+ });
71
+ });
72
+ //# sourceMappingURL=dm-equivalent.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dm-equivalent.test.js","sourceRoot":"","sources":["../../../../../src/connectors/slack/__tests__/dm-equivalent.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ export interface ConversationKeyInput {
2
+ channel: string;
3
+ threadTs?: string;
4
+ ts?: string;
5
+ userId: string;
6
+ }
7
+ export declare class ConversationTracker {
8
+ private readonly entries;
9
+ /**
10
+ * Compute the conversation key for a Slack message. Returns `null` if
11
+ * required fields (channel + userId) are missing.
12
+ */
13
+ static keyFor(input: ConversationKeyInput): string | null;
14
+ /**
15
+ * Record a human speaker for the conversation key implied by the given
16
+ * message. Adds the user to the `humanSpeakers` set; multiple distinct
17
+ * users in the same key invalidates DM-equivalence.
18
+ */
19
+ recordHumanMessage(input: ConversationKeyInput): void;
20
+ /**
21
+ * Mark the conversation as having received bot engagement (a reply, a
22
+ * reaction, or any other deliberate response) for the *current* key —
23
+ * the user-key for top-level messages, the thread-key for thread
24
+ * replies. Once set, this flag is permanent for the key.
25
+ *
26
+ * Thread keys for bot-created threads are not primed here. The outbound
27
+ * paths (`recordBotInitiatedThread` from `replyMessage` / `sendMessage`)
28
+ * mark them when a thread actually materializes, which avoids retaining
29
+ * a permanent entry for every top-level message that never gets a reply.
30
+ */
31
+ recordBotEngaged(input: ConversationKeyInput): void;
32
+ /**
33
+ * Mark a key as bot-engaged without a specific user attribution. Used
34
+ * when the bot initiates a top-level message of its own — the new
35
+ * message becomes a thread root, and any future replies in that thread
36
+ * are implicitly bot-addressed.
37
+ */
38
+ recordBotInitiatedThread(channel: string, threadTs: string): void;
39
+ /**
40
+ * Should this incoming message skip triage?
41
+ * Returns true when bot has engaged AND exactly one human has spoken in
42
+ * this conversation.
43
+ */
44
+ isDmEquivalent(input: ConversationKeyInput): boolean;
45
+ /** For tests / debugging. */
46
+ size(): number;
47
+ /** Remove a key (e.g. on member_left_channel). */
48
+ invalidate(key: string): void;
49
+ private addSpeaker;
50
+ private markEngaged;
51
+ private touch;
52
+ /**
53
+ * Evict the oldest *non-engaged* entry. Engaged entries are protected
54
+ * because their state ("bot has replied here") is durable conversational
55
+ * context that must survive past 5,000-conversation traffic — losing it
56
+ * would silently re-introduce the silent-drop bug for the evicted user.
57
+ *
58
+ * If every entry is engaged, we accept unbounded growth rather than
59
+ * sacrifice correctness. In practice the engaged set is bounded by the
60
+ * number of (operator × channel) pairs in the workspace.
61
+ */
62
+ private evictOldestNonEngaged;
63
+ }
64
+ //# sourceMappingURL=conversation-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-tracker.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/conversation-tracker.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AASD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAEhE;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI;IAQzD;;;;OAIG;IACH,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAMrD;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAOnD;;;;;OAKG;IACH,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQjE;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO;IAQpD,6BAA6B;IAC7B,IAAI,IAAI,MAAM;IAId,kDAAkD;IAClD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,KAAK;IAOb;;;;;;;;;OASG;IACH,OAAO,CAAC,qBAAqB;CAS9B"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Tracks Slack conversations to decide whether incoming messages should
3
+ * skip the air-reading triage gate.
4
+ *
5
+ * A conversation is "DM-equivalent" — implicitly addressed to the bot —
6
+ * once the bot has engaged with it AND only one human has spoken. The
7
+ * decision is permanent until a third human joins, at which point we
8
+ * fall back to normal triage.
9
+ *
10
+ * Conversation keys:
11
+ * - Threaded message (`thread_ts && thread_ts !== ts`):
12
+ * `${channel}:thread:${thread_ts}`
13
+ * - Top-level message (no `thread_ts` or `thread_ts === ts`):
14
+ * `${channel}:user:${user_id}`
15
+ *
16
+ * The thread keying handles the obvious case ("this thread is just me and
17
+ * the bot"). The user keying handles operators who don't reply in threads
18
+ * — once the bot has answered them once in a channel, follow-up top-level
19
+ * messages from the same user skip triage.
20
+ */
21
+ import { logger } from "../../shared/logger.js";
22
+ const PRUNE_AT_SIZE = 5000;
23
+ export class ConversationTracker {
24
+ entries = new Map();
25
+ /**
26
+ * Compute the conversation key for a Slack message. Returns `null` if
27
+ * required fields (channel + userId) are missing.
28
+ */
29
+ static keyFor(input) {
30
+ if (!input.channel || !input.userId)
31
+ return null;
32
+ if (input.threadTs && input.threadTs !== input.ts) {
33
+ return `${input.channel}:thread:${input.threadTs}`;
34
+ }
35
+ return `${input.channel}:user:${input.userId}`;
36
+ }
37
+ /**
38
+ * Record a human speaker for the conversation key implied by the given
39
+ * message. Adds the user to the `humanSpeakers` set; multiple distinct
40
+ * users in the same key invalidates DM-equivalence.
41
+ */
42
+ recordHumanMessage(input) {
43
+ const key = ConversationTracker.keyFor(input);
44
+ if (!key)
45
+ return;
46
+ this.addSpeaker(key, input.userId);
47
+ }
48
+ /**
49
+ * Mark the conversation as having received bot engagement (a reply, a
50
+ * reaction, or any other deliberate response) for the *current* key —
51
+ * the user-key for top-level messages, the thread-key for thread
52
+ * replies. Once set, this flag is permanent for the key.
53
+ *
54
+ * Thread keys for bot-created threads are not primed here. The outbound
55
+ * paths (`recordBotInitiatedThread` from `replyMessage` / `sendMessage`)
56
+ * mark them when a thread actually materializes, which avoids retaining
57
+ * a permanent entry for every top-level message that never gets a reply.
58
+ */
59
+ recordBotEngaged(input) {
60
+ if (!input.userId)
61
+ return;
62
+ const primary = ConversationTracker.keyFor(input);
63
+ if (!primary)
64
+ return;
65
+ this.markEngaged(primary, input.userId);
66
+ }
67
+ /**
68
+ * Mark a key as bot-engaged without a specific user attribution. Used
69
+ * when the bot initiates a top-level message of its own — the new
70
+ * message becomes a thread root, and any future replies in that thread
71
+ * are implicitly bot-addressed.
72
+ */
73
+ recordBotInitiatedThread(channel, threadTs) {
74
+ if (!channel || !threadTs)
75
+ return;
76
+ const key = `${channel}:thread:${threadTs}`;
77
+ const state = this.entries.get(key) ?? { humanSpeakers: new Set(), botEngaged: false };
78
+ state.botEngaged = true;
79
+ this.touch(key, state);
80
+ }
81
+ /**
82
+ * Should this incoming message skip triage?
83
+ * Returns true when bot has engaged AND exactly one human has spoken in
84
+ * this conversation.
85
+ */
86
+ isDmEquivalent(input) {
87
+ const key = ConversationTracker.keyFor(input);
88
+ if (!key)
89
+ return false;
90
+ const state = this.entries.get(key);
91
+ if (!state)
92
+ return false;
93
+ return state.botEngaged && state.humanSpeakers.size === 1;
94
+ }
95
+ /** For tests / debugging. */
96
+ size() {
97
+ return this.entries.size;
98
+ }
99
+ /** Remove a key (e.g. on member_left_channel). */
100
+ invalidate(key) {
101
+ this.entries.delete(key);
102
+ }
103
+ addSpeaker(key, userId) {
104
+ const existing = this.entries.get(key);
105
+ if (existing) {
106
+ if (!existing.humanSpeakers.has(userId)) {
107
+ existing.humanSpeakers.add(userId);
108
+ if (existing.humanSpeakers.size === 2 && existing.botEngaged) {
109
+ logger.debug(`[slack] conversation ${key} no longer DM-equivalent (third party joined)`);
110
+ }
111
+ }
112
+ return;
113
+ }
114
+ const state = { humanSpeakers: new Set([userId]), botEngaged: false };
115
+ this.touch(key, state);
116
+ }
117
+ markEngaged(key, userId) {
118
+ const state = this.entries.get(key) ?? { humanSpeakers: new Set(), botEngaged: false };
119
+ state.botEngaged = true;
120
+ if (userId)
121
+ state.humanSpeakers.add(userId);
122
+ this.touch(key, state);
123
+ }
124
+ touch(key, state) {
125
+ this.entries.set(key, state);
126
+ if (this.entries.size > PRUNE_AT_SIZE) {
127
+ this.evictOldestNonEngaged(key);
128
+ }
129
+ }
130
+ /**
131
+ * Evict the oldest *non-engaged* entry. Engaged entries are protected
132
+ * because their state ("bot has replied here") is durable conversational
133
+ * context that must survive past 5,000-conversation traffic — losing it
134
+ * would silently re-introduce the silent-drop bug for the evicted user.
135
+ *
136
+ * If every entry is engaged, we accept unbounded growth rather than
137
+ * sacrifice correctness. In practice the engaged set is bounded by the
138
+ * number of (operator × channel) pairs in the workspace.
139
+ */
140
+ evictOldestNonEngaged(skipKey) {
141
+ for (const [key, state] of this.entries) {
142
+ if (key === skipKey)
143
+ continue;
144
+ if (!state.botEngaged) {
145
+ this.entries.delete(key);
146
+ return;
147
+ }
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=conversation-tracker.js.map