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.
- package/dist/package.json +1 -1
- package/dist/src/cli/create.js +10 -10
- package/dist/src/cli/create.js.map +1 -1
- package/dist/src/cli/list.js +2 -2
- package/dist/src/cli/list.js.map +1 -1
- package/dist/src/cli/migrate.js +18 -18
- package/dist/src/cli/migrate.js.map +1 -1
- package/dist/src/cli/nuke.js +15 -15
- package/dist/src/cli/nuke.js.map +1 -1
- package/dist/src/cli/setup.js +22 -22
- package/dist/src/cli/setup.js.map +1 -1
- package/dist/src/cli/skills.js +17 -17
- package/dist/src/cli/skills.js.map +1 -1
- package/dist/src/connectors/slack/__tests__/conversation-tracker.test.d.ts +2 -0
- package/dist/src/connectors/slack/__tests__/conversation-tracker.test.d.ts.map +1 -0
- package/dist/src/connectors/slack/__tests__/conversation-tracker.test.js +132 -0
- package/dist/src/connectors/slack/__tests__/conversation-tracker.test.js.map +1 -0
- package/dist/src/connectors/slack/__tests__/dm-equivalent.test.d.ts +2 -0
- package/dist/src/connectors/slack/__tests__/dm-equivalent.test.d.ts.map +1 -0
- package/dist/src/connectors/slack/__tests__/dm-equivalent.test.js +72 -0
- package/dist/src/connectors/slack/__tests__/dm-equivalent.test.js.map +1 -0
- package/dist/src/connectors/slack/conversation-tracker.d.ts +64 -0
- package/dist/src/connectors/slack/conversation-tracker.d.ts.map +1 -0
- package/dist/src/connectors/slack/conversation-tracker.js +151 -0
- package/dist/src/connectors/slack/conversation-tracker.js.map +1 -0
- package/dist/src/connectors/slack/dm-equivalent.d.ts +44 -0
- package/dist/src/connectors/slack/dm-equivalent.d.ts.map +1 -0
- package/dist/src/connectors/slack/dm-equivalent.js +69 -0
- package/dist/src/connectors/slack/dm-equivalent.js.map +1 -0
- package/dist/src/connectors/slack/index.d.ts +1 -2
- package/dist/src/connectors/slack/index.d.ts.map +1 -1
- package/dist/src/connectors/slack/index.js +48 -20
- package/dist/src/connectors/slack/index.js.map +1 -1
- package/dist/src/connectors/slack/triage.d.ts.map +1 -1
- package/dist/src/connectors/slack/triage.js +5 -1
- package/dist/src/connectors/slack/triage.js.map +1 -1
- package/dist/src/gateway/server.js +1 -1
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/shared/config.js +1 -1
- package/dist/src/shared/config.js.map +1 -1
- package/dist/src/shared/types.d.ts +5 -4
- package/dist/src/shared/types.d.ts.map +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +2 -2
- package/dist/web/__next._full.txt +3 -3
- package/dist/web/__next._head.txt +1 -1
- package/dist/web/__next._index.txt +2 -2
- package/dist/web/__next._tree.txt +2 -2
- package/dist/web/_next/static/chunks/05uy~i7wsbsn3.js +1 -0
- package/dist/web/_next/static/chunks/0bj62gv2pext..css +1 -0
- package/dist/web/_next/static/chunks/{16b0jvgccyt2i.js → 0ma0h4_2c8y9y.js} +1 -1
- package/dist/web/_next/static/chunks/{0wzpea61sn2-k.js → 0v51a3blij~j6.js} +1 -1
- package/dist/web/_next/static/chunks/{12h4dws.tz7yb.js → 0wv0qjh9tuqx~.js} +1 -1
- package/dist/web/_next/static/chunks/{0398g9fy2i2l..js → 0y3uv64m1qh.k.js} +1 -1
- package/dist/web/_next/static/chunks/{07t-qdutaizlf.js → 1621s_jgljr1_.js} +1 -1
- package/dist/web/_next/static/chunks/{0_pxvi.u4tzw1.js → 1645~4k0qcst0.js} +1 -1
- package/dist/web/_next/static/chunks/{0ihbb7~gq42g~.js → 16zc7-yv7supr.js} +1 -1
- package/dist/web/_not-found/__next._full.txt +2 -2
- package/dist/web/_not-found/__next._head.txt +1 -1
- package/dist/web/_not-found/__next._index.txt +2 -2
- package/dist/web/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/web/_not-found/__next._not-found.txt +1 -1
- package/dist/web/_not-found/__next._tree.txt +2 -2
- package/dist/web/_not-found.html +1 -1
- package/dist/web/_not-found.txt +2 -2
- package/dist/web/chat/__next._full.txt +3 -3
- package/dist/web/chat/__next._head.txt +1 -1
- package/dist/web/chat/__next._index.txt +2 -2
- package/dist/web/chat/__next._tree.txt +2 -2
- package/dist/web/chat/__next.chat.__PAGE__.txt +2 -2
- package/dist/web/chat/__next.chat.txt +1 -1
- package/dist/web/chat.html +1 -1
- package/dist/web/chat.txt +3 -3
- package/dist/web/cron/__next._full.txt +3 -3
- package/dist/web/cron/__next._head.txt +1 -1
- package/dist/web/cron/__next._index.txt +2 -2
- package/dist/web/cron/__next._tree.txt +2 -2
- package/dist/web/cron/__next.cron.__PAGE__.txt +2 -2
- package/dist/web/cron/__next.cron.txt +1 -1
- package/dist/web/cron.html +1 -1
- package/dist/web/cron.txt +3 -3
- package/dist/web/dev/logs/next-development.log +5 -0
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +3 -3
- package/dist/web/kanban/__next._full.txt +3 -3
- package/dist/web/kanban/__next._head.txt +1 -1
- package/dist/web/kanban/__next._index.txt +2 -2
- package/dist/web/kanban/__next._tree.txt +2 -2
- package/dist/web/kanban/__next.kanban.__PAGE__.txt +2 -2
- package/dist/web/kanban/__next.kanban.txt +1 -1
- package/dist/web/kanban.html +1 -1
- package/dist/web/kanban.txt +3 -3
- package/dist/web/logs/__next._full.txt +3 -3
- package/dist/web/logs/__next._head.txt +1 -1
- package/dist/web/logs/__next._index.txt +2 -2
- package/dist/web/logs/__next._tree.txt +2 -2
- package/dist/web/logs/__next.logs.__PAGE__.txt +2 -2
- package/dist/web/logs/__next.logs.txt +1 -1
- package/dist/web/logs.html +2 -2
- package/dist/web/logs.txt +3 -3
- package/dist/web/org/__next._full.txt +3 -3
- package/dist/web/org/__next._head.txt +1 -1
- package/dist/web/org/__next._index.txt +2 -2
- package/dist/web/org/__next._tree.txt +2 -2
- package/dist/web/org/__next.org.__PAGE__.txt +2 -2
- package/dist/web/org/__next.org.txt +1 -1
- package/dist/web/org.html +1 -1
- package/dist/web/org.txt +3 -3
- package/dist/web/sessions/__next._full.txt +2 -2
- package/dist/web/sessions/__next._head.txt +1 -1
- package/dist/web/sessions/__next._index.txt +2 -2
- package/dist/web/sessions/__next._tree.txt +2 -2
- package/dist/web/sessions/__next.sessions.__PAGE__.txt +1 -1
- package/dist/web/sessions/__next.sessions.txt +1 -1
- package/dist/web/sessions.html +1 -1
- package/dist/web/sessions.txt +2 -2
- package/dist/web/settings/__next._full.txt +3 -3
- package/dist/web/settings/__next._head.txt +1 -1
- package/dist/web/settings/__next._index.txt +2 -2
- package/dist/web/settings/__next._tree.txt +2 -2
- package/dist/web/settings/__next.settings.__PAGE__.txt +2 -2
- package/dist/web/settings/__next.settings.txt +1 -1
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +3 -3
- package/dist/web/skills/__next._full.txt +3 -3
- package/dist/web/skills/__next._head.txt +1 -1
- package/dist/web/skills/__next._index.txt +2 -2
- package/dist/web/skills/__next._tree.txt +2 -2
- package/dist/web/skills/__next.skills.__PAGE__.txt +2 -2
- package/dist/web/skills/__next.skills.txt +1 -1
- package/dist/web/skills.html +1 -1
- package/dist/web/skills.txt +3 -3
- package/package.json +1 -1
- package/template/config.default.yaml +1 -1
- package/template/migrations/0.3.0/files/CLAUDE.md +3 -0
- package/template/migrations/0.3.0/files/config.default.yaml +1 -1
- package/dist/web/_next/static/chunks/068ifilpihtkg.js +0 -1
- package/dist/web/_next/static/chunks/0mlo32yrc7ziu.css +0 -1
- /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{iB5cSG_ItwMbyPzZc7Com → VBjMXtz9-pIo9izqNT-iu}/_ssgManifest.js +0 -0
package/dist/src/cli/skills.js
CHANGED
|
@@ -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(`\
|
|
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}
|
|
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}
|
|
156
|
+
console.log(`\n${GREEN}スキル "${existing.name}" を ${SKILLS_DIR} に追加しました${RESET}`);
|
|
157
157
|
}
|
|
158
158
|
else {
|
|
159
|
-
console.log(`\n${YELLOW}
|
|
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}
|
|
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}
|
|
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}
|
|
178
|
+
console.log(`${GREEN}スキル "${name}" を削除しました。${RESET}`);
|
|
179
179
|
}
|
|
180
180
|
export function skillsList() {
|
|
181
181
|
if (!fs.existsSync(SKILLS_DIR)) {
|
|
182
|
-
console.log("
|
|
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("
|
|
190
|
+
console.log("インストール済みスキルがありません。");
|
|
191
191
|
return;
|
|
192
192
|
}
|
|
193
|
-
console.log(`\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("
|
|
215
|
+
console.log("更新対象のスキルがマニフェストにありません。");
|
|
216
216
|
return;
|
|
217
217
|
}
|
|
218
|
-
console.log(`\
|
|
218
|
+
console.log(`\n${manifest.length} 件のスキルを更新中...\n`);
|
|
219
219
|
for (const entry of manifest) {
|
|
220
|
-
console.log(`
|
|
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}
|
|
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}
|
|
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("
|
|
249
|
+
console.log("復元対象のスキルがマニフェストにありません。");
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
|
-
console.log(`\
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|