gsd-pi 2.18.0 → 2.20.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/README.md +5 -1
- package/dist/cli.js +3 -3
- package/dist/onboarding.d.ts +3 -1
- package/dist/onboarding.js +77 -3
- package/dist/remote-questions-config.d.ts +1 -1
- package/dist/resources/extensions/google-search/index.ts +164 -47
- package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/dist/resources/extensions/gsd/auto.ts +690 -39
- package/dist/resources/extensions/gsd/captures.ts +384 -0
- package/dist/resources/extensions/gsd/commands.ts +654 -36
- package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/dist/resources/extensions/gsd/context-budget.ts +243 -0
- package/dist/resources/extensions/gsd/context-store.ts +195 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/dist/resources/extensions/gsd/db-writer.ts +341 -0
- package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/dist/resources/extensions/gsd/doctor.ts +283 -2
- package/dist/resources/extensions/gsd/export.ts +81 -2
- package/dist/resources/extensions/gsd/files.ts +39 -9
- package/dist/resources/extensions/gsd/git-service.ts +6 -0
- package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
- package/dist/resources/extensions/gsd/history.ts +0 -1
- package/dist/resources/extensions/gsd/index.ts +277 -1
- package/dist/resources/extensions/gsd/md-importer.ts +526 -0
- package/dist/resources/extensions/gsd/metrics.ts +84 -0
- package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/dist/resources/extensions/gsd/model-router.ts +256 -0
- package/dist/resources/extensions/gsd/notifications.ts +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/dist/resources/extensions/gsd/preferences.ts +198 -150
- package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/dist/resources/extensions/gsd/prompts/system.md +2 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/dist/resources/extensions/gsd/quick.ts +156 -0
- package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/dist/resources/extensions/gsd/skill-health.ts +417 -0
- package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/dist/resources/extensions/gsd/state.ts +30 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
- package/dist/resources/extensions/gsd/types.ts +29 -0
- package/dist/resources/extensions/gsd/undo.ts +0 -1
- package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/dist/resources/extensions/remote-questions/config.ts +4 -2
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/dist/resources/extensions/remote-questions/format.ts +166 -14
- package/dist/resources/extensions/remote-questions/manager.ts +14 -4
- package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/dist/resources/extensions/remote-questions/types.ts +2 -1
- package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/dist/resources/extensions/voice/index.ts +4 -3
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
- package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +43 -11
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -0
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +5 -0
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
- package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
- package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
- package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
- package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
- package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
- package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
- package/src/resources/extensions/google-search/index.ts +164 -47
- package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/src/resources/extensions/gsd/auto.ts +690 -39
- package/src/resources/extensions/gsd/captures.ts +384 -0
- package/src/resources/extensions/gsd/commands.ts +654 -36
- package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/src/resources/extensions/gsd/context-budget.ts +243 -0
- package/src/resources/extensions/gsd/context-store.ts +195 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/src/resources/extensions/gsd/db-writer.ts +341 -0
- package/src/resources/extensions/gsd/debug-logger.ts +178 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/src/resources/extensions/gsd/doctor.ts +283 -2
- package/src/resources/extensions/gsd/export.ts +81 -2
- package/src/resources/extensions/gsd/files.ts +39 -9
- package/src/resources/extensions/gsd/git-service.ts +6 -0
- package/src/resources/extensions/gsd/gsd-db.ts +752 -0
- package/src/resources/extensions/gsd/guided-flow.ts +26 -1
- package/src/resources/extensions/gsd/history.ts +0 -1
- package/src/resources/extensions/gsd/index.ts +277 -1
- package/src/resources/extensions/gsd/md-importer.ts +526 -0
- package/src/resources/extensions/gsd/metrics.ts +84 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/src/resources/extensions/gsd/model-router.ts +256 -0
- package/src/resources/extensions/gsd/notifications.ts +0 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/src/resources/extensions/gsd/preferences.ts +198 -150
- package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/src/resources/extensions/gsd/prompts/system.md +2 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/src/resources/extensions/gsd/quick.ts +156 -0
- package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/src/resources/extensions/gsd/skill-health.ts +417 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/src/resources/extensions/gsd/state.ts +30 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/src/resources/extensions/gsd/triage-ui.ts +175 -0
- package/src/resources/extensions/gsd/types.ts +29 -0
- package/src/resources/extensions/gsd/undo.ts +0 -1
- package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/src/resources/extensions/gsd/worktree-command.ts +18 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/src/resources/extensions/remote-questions/config.ts +4 -2
- package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/src/resources/extensions/remote-questions/format.ts +166 -14
- package/src/resources/extensions/remote-questions/manager.ts +14 -4
- package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/src/resources/extensions/remote-questions/types.ts +2 -1
- package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/src/resources/extensions/voice/index.ts +4 -3
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ChannelAdapter, RemotePrompt, RemoteDispatchResult, RemoteAnswer, RemotePromptRef } from "./types.js";
|
|
6
|
-
import { formatForSlack, parseSlackReply } from "./format.js";
|
|
6
|
+
import { formatForSlack, parseSlackReply, parseSlackReactionResponse, SLACK_NUMBER_REACTION_NAMES } from "./format.js";
|
|
7
7
|
|
|
8
8
|
const SLACK_API = "https://slack.com/api";
|
|
9
9
|
const PER_REQUEST_TIMEOUT_MS = 15_000;
|
|
10
|
+
const SLACK_ACK_REACTION = "white_check_mark";
|
|
10
11
|
|
|
11
12
|
export class SlackAdapter implements ChannelAdapter {
|
|
12
13
|
readonly name = "slack" as const;
|
|
@@ -36,6 +37,17 @@ export class SlackAdapter implements ChannelAdapter {
|
|
|
36
37
|
|
|
37
38
|
const ts = String(res.ts);
|
|
38
39
|
const channel = String(res.channel);
|
|
40
|
+
if (prompt.questions.length === 1) {
|
|
41
|
+
const reactionNames = SLACK_NUMBER_REACTION_NAMES.slice(0, prompt.questions[0].options.length);
|
|
42
|
+
for (const name of reactionNames) {
|
|
43
|
+
try {
|
|
44
|
+
await this.slackApi("reactions.add", { channel, timestamp: ts, name });
|
|
45
|
+
} catch {
|
|
46
|
+
// Best-effort only
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
return {
|
|
40
52
|
ref: {
|
|
41
53
|
id: prompt.id,
|
|
@@ -51,6 +63,11 @@ export class SlackAdapter implements ChannelAdapter {
|
|
|
51
63
|
async pollAnswer(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null> {
|
|
52
64
|
if (!this.botUserId) await this.validate();
|
|
53
65
|
|
|
66
|
+
if (prompt.questions.length === 1) {
|
|
67
|
+
const reactionAnswer = await this.checkReactions(prompt, ref);
|
|
68
|
+
if (reactionAnswer) return reactionAnswer;
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
const res = await this.slackApi("conversations.replies", {
|
|
55
72
|
channel: ref.channelId,
|
|
56
73
|
ts: ref.threadTs!,
|
|
@@ -66,9 +83,48 @@ export class SlackAdapter implements ChannelAdapter {
|
|
|
66
83
|
return parseSlackReply(String(userReplies[0].text), prompt.questions);
|
|
67
84
|
}
|
|
68
85
|
|
|
86
|
+
async acknowledgeAnswer(ref: RemotePromptRef): Promise<void> {
|
|
87
|
+
try {
|
|
88
|
+
await this.slackApi("reactions.add", {
|
|
89
|
+
channel: ref.channelId,
|
|
90
|
+
timestamp: ref.messageId,
|
|
91
|
+
name: SLACK_ACK_REACTION,
|
|
92
|
+
});
|
|
93
|
+
} catch {
|
|
94
|
+
// Best-effort only
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private async checkReactions(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null> {
|
|
99
|
+
const res = await this.slackApi("reactions.get", {
|
|
100
|
+
channel: ref.channelId,
|
|
101
|
+
timestamp: ref.messageId,
|
|
102
|
+
full: "true",
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (!res.ok) return null;
|
|
106
|
+
|
|
107
|
+
const message = (res.message ?? {}) as {
|
|
108
|
+
reactions?: Array<{ name?: string; count?: number; users?: string[] }>;
|
|
109
|
+
};
|
|
110
|
+
const reactions = Array.isArray(message.reactions) ? message.reactions : [];
|
|
111
|
+
const picked = reactions
|
|
112
|
+
.filter((reaction) => reaction.name && SLACK_NUMBER_REACTION_NAMES.includes(reaction.name))
|
|
113
|
+
.filter((reaction) => {
|
|
114
|
+
const count = Number(reaction.count ?? 0);
|
|
115
|
+
const users = Array.isArray(reaction.users) ? reaction.users.map(String) : [];
|
|
116
|
+
const botIncluded = this.botUserId ? users.includes(this.botUserId) : false;
|
|
117
|
+
return count > (botIncluded ? 1 : 0);
|
|
118
|
+
})
|
|
119
|
+
.map((reaction) => String(reaction.name));
|
|
120
|
+
|
|
121
|
+
if (picked.length === 0) return null;
|
|
122
|
+
return parseSlackReactionResponse(picked, prompt.questions);
|
|
123
|
+
}
|
|
124
|
+
|
|
69
125
|
private async slackApi(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
70
126
|
const url = `${SLACK_API}/${method}`;
|
|
71
|
-
const isGet = method === "conversations.replies" || method === "auth.test";
|
|
127
|
+
const isGet = method === "conversations.replies" || method === "auth.test" || method === "reactions.get";
|
|
72
128
|
|
|
73
129
|
let response: Response;
|
|
74
130
|
if (isGet) {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote Questions — Telegram adapter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ChannelAdapter, RemotePrompt, RemoteDispatchResult, RemoteAnswer, RemotePromptRef } from "./types.js";
|
|
6
|
+
import { formatForTelegram, parseTelegramResponse } from "./format.js";
|
|
7
|
+
|
|
8
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
9
|
+
const PER_REQUEST_TIMEOUT_MS = 15_000;
|
|
10
|
+
|
|
11
|
+
export class TelegramAdapter implements ChannelAdapter {
|
|
12
|
+
readonly name = "telegram" as const;
|
|
13
|
+
private botUserId: number | null = null;
|
|
14
|
+
private lastUpdateId = 0;
|
|
15
|
+
private lastSentText = "";
|
|
16
|
+
private readonly token: string;
|
|
17
|
+
private readonly chatId: string;
|
|
18
|
+
|
|
19
|
+
constructor(token: string, chatId: string) {
|
|
20
|
+
this.token = token;
|
|
21
|
+
this.chatId = chatId;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async validate(): Promise<void> {
|
|
25
|
+
const res = await this.telegramApi("getMe");
|
|
26
|
+
if (!res.ok || !res.result?.id) throw new Error("Telegram auth failed: invalid bot token");
|
|
27
|
+
this.botUserId = res.result.id;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async sendPrompt(prompt: RemotePrompt): Promise<RemoteDispatchResult> {
|
|
31
|
+
const payload = formatForTelegram(prompt);
|
|
32
|
+
this.lastSentText = payload.text;
|
|
33
|
+
|
|
34
|
+
const params: Record<string, unknown> = {
|
|
35
|
+
chat_id: this.chatId,
|
|
36
|
+
text: payload.text,
|
|
37
|
+
parse_mode: payload.parse_mode,
|
|
38
|
+
};
|
|
39
|
+
if (payload.reply_markup) {
|
|
40
|
+
params.reply_markup = payload.reply_markup;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const res = await this.telegramApi("sendMessage", params);
|
|
44
|
+
if (!res.ok || !res.result?.message_id) {
|
|
45
|
+
throw new Error(`Telegram sendMessage failed: ${JSON.stringify(res)}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const messageId = String(res.result.message_id);
|
|
49
|
+
const messageUrl = this.buildMessageUrl(this.chatId, messageId);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
ref: {
|
|
53
|
+
id: prompt.id,
|
|
54
|
+
channel: "telegram",
|
|
55
|
+
messageId,
|
|
56
|
+
channelId: this.chatId,
|
|
57
|
+
threadUrl: messageUrl,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async pollAnswer(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null> {
|
|
63
|
+
if (!this.botUserId) await this.validate();
|
|
64
|
+
|
|
65
|
+
const res = await this.telegramApi("getUpdates", {
|
|
66
|
+
offset: this.lastUpdateId + 1,
|
|
67
|
+
timeout: 0,
|
|
68
|
+
allowed_updates: ["message", "callback_query"],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (!res.ok || !Array.isArray(res.result)) return null;
|
|
72
|
+
|
|
73
|
+
for (const update of res.result) {
|
|
74
|
+
// Advance offset for all updates to prevent reprocessing
|
|
75
|
+
if (update.update_id > this.lastUpdateId) {
|
|
76
|
+
this.lastUpdateId = update.update_id;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Handle callback_query (inline keyboard button press)
|
|
80
|
+
if (update.callback_query) {
|
|
81
|
+
const cq = update.callback_query;
|
|
82
|
+
const msg = cq.message;
|
|
83
|
+
if (
|
|
84
|
+
msg &&
|
|
85
|
+
String(msg.chat?.id) === ref.channelId &&
|
|
86
|
+
String(msg.message_id) === ref.messageId &&
|
|
87
|
+
cq.from?.id !== this.botUserId
|
|
88
|
+
) {
|
|
89
|
+
// Dismiss the loading spinner on the button
|
|
90
|
+
try {
|
|
91
|
+
await this.telegramApi("answerCallbackQuery", { callback_query_id: cq.id });
|
|
92
|
+
} catch { /* best-effort */ }
|
|
93
|
+
|
|
94
|
+
return parseTelegramResponse(cq.data ?? null, null, prompt.questions, prompt.id);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle text reply (reply_to_message)
|
|
99
|
+
if (update.message) {
|
|
100
|
+
const msg = update.message;
|
|
101
|
+
if (
|
|
102
|
+
String(msg.chat?.id) === ref.channelId &&
|
|
103
|
+
msg.reply_to_message &&
|
|
104
|
+
String(msg.reply_to_message.message_id) === ref.messageId &&
|
|
105
|
+
msg.from?.id !== this.botUserId &&
|
|
106
|
+
msg.text
|
|
107
|
+
) {
|
|
108
|
+
return parseTelegramResponse(null, msg.text, prompt.questions, prompt.id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Acknowledge receipt by editing the original message to append a checkmark.
|
|
118
|
+
* Best-effort — failures are silently ignored.
|
|
119
|
+
*/
|
|
120
|
+
async acknowledgeAnswer(ref: RemotePromptRef): Promise<void> {
|
|
121
|
+
try {
|
|
122
|
+
await this.telegramApi("editMessageText", {
|
|
123
|
+
chat_id: ref.channelId,
|
|
124
|
+
message_id: parseInt(ref.messageId, 10),
|
|
125
|
+
text: this.lastSentText + "\n\n✅ Answered",
|
|
126
|
+
parse_mode: "HTML",
|
|
127
|
+
});
|
|
128
|
+
} catch {
|
|
129
|
+
// Best-effort — don't let acknowledgement failures affect the flow
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private buildMessageUrl(chatId: string, messageId: string): string | undefined {
|
|
134
|
+
// Supergroups have chat IDs starting with -100
|
|
135
|
+
if (chatId.startsWith("-100")) {
|
|
136
|
+
return `https://t.me/c/${chatId.slice(4)}/${messageId}`;
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private async telegramApi(method: string, params?: Record<string, unknown>): Promise<any> {
|
|
142
|
+
const url = `${TELEGRAM_API}/bot${this.token}/${method}`;
|
|
143
|
+
const init: RequestInit = {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: { "Content-Type": "application/json" },
|
|
146
|
+
signal: AbortSignal.timeout(PER_REQUEST_TIMEOUT_MS),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (params) {
|
|
150
|
+
init.body = JSON.stringify(params);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const response = await fetch(url, init);
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
const text = await response.text().catch(() => "");
|
|
156
|
+
const safeText = text.length > 200 ? text.slice(0, 200) + "…" : text;
|
|
157
|
+
throw new Error(`Telegram API HTTP ${response.status}: ${safeText}`);
|
|
158
|
+
}
|
|
159
|
+
return response.json();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Remote Questions — shared types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export type RemoteChannel = "slack" | "discord";
|
|
5
|
+
export type RemoteChannel = "slack" | "discord" | "telegram";
|
|
6
6
|
|
|
7
7
|
export interface RemoteQuestionOption {
|
|
8
8
|
label: string;
|
|
@@ -72,4 +72,5 @@ export interface ChannelAdapter {
|
|
|
72
72
|
validate(): Promise<void>;
|
|
73
73
|
sendPrompt(prompt: RemotePrompt): Promise<RemoteDispatchResult>;
|
|
74
74
|
pollAnswer(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null>;
|
|
75
|
+
acknowledgeAnswer?(ref: RemotePromptRef): Promise<void>;
|
|
75
76
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* per-rule JS RegExp iteration when the native module is not loaded.
|
|
11
11
|
*/
|
|
12
12
|
import picomatch from "picomatch";
|
|
13
|
+
import { debugTime, debugCount, debugPeak } from "../gsd/debug-logger.js";
|
|
13
14
|
|
|
14
15
|
// ── Native TTSR engine (optional) ─────────────────────────────────────
|
|
15
16
|
let nativeTtsr: {
|
|
@@ -98,6 +99,12 @@ const DEFAULT_SETTINGS: Required<TtsrSettings> = {
|
|
|
98
99
|
/** Cap per-stream buffer at 512KB to prevent unbounded memory growth. */
|
|
99
100
|
const MAX_BUFFER_BYTES = 512 * 1024;
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Minimum interval (ms) between JS-fallback regex checks on the same buffer.
|
|
104
|
+
* Prevents CPU spinning when deltas arrive faster than regex evaluation (#468).
|
|
105
|
+
*/
|
|
106
|
+
const JS_FALLBACK_CHECK_INTERVAL_MS = 50;
|
|
107
|
+
|
|
101
108
|
const DEFAULT_SCOPE: TtsrScope = {
|
|
102
109
|
allowText: true,
|
|
103
110
|
allowThinking: false,
|
|
@@ -110,6 +117,8 @@ export class TtsrManager {
|
|
|
110
117
|
readonly #rules = new Map<string, TtsrEntry>();
|
|
111
118
|
readonly #injectionRecords = new Map<string, InjectionRecord>();
|
|
112
119
|
readonly #buffers = new Map<string, string>();
|
|
120
|
+
/** Tracks last JS-fallback check time per buffer key to throttle CPU (#468). */
|
|
121
|
+
readonly #lastJsCheckAt = new Map<string, number>();
|
|
113
122
|
#messageCount = 0;
|
|
114
123
|
#nativeHandle: number | null = null;
|
|
115
124
|
#nativeDirty = false;
|
|
@@ -333,6 +342,7 @@ export class TtsrManager {
|
|
|
333
342
|
* remain in JS as they are lightweight and context-dependent.
|
|
334
343
|
*/
|
|
335
344
|
checkDelta(delta: string, context: TtsrMatchContext): Rule[] {
|
|
345
|
+
const stopTimer = debugTime("ttsr-check");
|
|
336
346
|
const bufferKey = this.#bufferKey(context);
|
|
337
347
|
let nextBuffer = `${this.#buffers.get(bufferKey) ?? ""}${delta}`;
|
|
338
348
|
// Cap buffer size — keep the tail so patterns still match recent output
|
|
@@ -340,6 +350,7 @@ export class TtsrManager {
|
|
|
340
350
|
nextBuffer = nextBuffer.slice(-MAX_BUFFER_BYTES);
|
|
341
351
|
}
|
|
342
352
|
this.#buffers.set(bufferKey, nextBuffer);
|
|
353
|
+
debugPeak("ttsrPeakBuffer", nextBuffer.length);
|
|
343
354
|
|
|
344
355
|
// Lazily compile native engine if rules changed.
|
|
345
356
|
if (this.#nativeDirty) this.#compileNative();
|
|
@@ -357,10 +368,22 @@ export class TtsrManager {
|
|
|
357
368
|
if (!this.#matchesGlobalPaths(entry, context)) continue;
|
|
358
369
|
matches.push(entry.rule);
|
|
359
370
|
}
|
|
371
|
+
debugCount("ttsrChecks");
|
|
372
|
+
stopTimer({ bufferSize: nextBuffer.length, native: true, rulesChecked: this.#rules.size, matched: matches.map(m => m.name) });
|
|
360
373
|
return matches;
|
|
361
374
|
}
|
|
362
375
|
|
|
363
376
|
// ── JS fallback: per-rule regex iteration ─────────────────────────
|
|
377
|
+
// Throttle JS regex checks to prevent CPU spinning on fast token
|
|
378
|
+
// streams — regex on a growing buffer is O(rules × buffer_size) (#468).
|
|
379
|
+
const now = Date.now();
|
|
380
|
+
const lastCheck = this.#lastJsCheckAt.get(bufferKey) ?? 0;
|
|
381
|
+
if (now - lastCheck < JS_FALLBACK_CHECK_INTERVAL_MS) {
|
|
382
|
+
stopTimer({ bufferSize: nextBuffer.length, throttled: true });
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
this.#lastJsCheckAt.set(bufferKey, now);
|
|
386
|
+
|
|
364
387
|
const matches: Rule[] = [];
|
|
365
388
|
for (const [name, entry] of this.#rules) {
|
|
366
389
|
if (!this.#canTrigger(name)) continue;
|
|
@@ -369,6 +392,8 @@ export class TtsrManager {
|
|
|
369
392
|
if (!this.#matchesCondition(entry, nextBuffer)) continue;
|
|
370
393
|
matches.push(entry.rule);
|
|
371
394
|
}
|
|
395
|
+
debugCount("ttsrChecks");
|
|
396
|
+
stopTimer({ bufferSize: nextBuffer.length, native: false, rulesChecked: this.#rules.size, matched: matches.map(m => m.name) });
|
|
372
397
|
return matches;
|
|
373
398
|
}
|
|
374
399
|
|
|
@@ -406,6 +431,7 @@ export class TtsrManager {
|
|
|
406
431
|
/** Reset stream buffers (called on new turn). */
|
|
407
432
|
resetBuffer(): void {
|
|
408
433
|
this.#buffers.clear();
|
|
434
|
+
this.#lastJsCheckAt.clear();
|
|
409
435
|
}
|
|
410
436
|
|
|
411
437
|
/** Check if any TTSR rules are registered. */
|
|
@@ -7,9 +7,10 @@ import * as fs from "node:fs";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import * as readline from "node:readline";
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
const __extensionDir = import.meta.dirname!;
|
|
11
|
+
const SWIFT_SRC = path.join(__extensionDir, "speech-recognizer.swift");
|
|
12
|
+
const RECOGNIZER_BIN = path.join(__extensionDir, "speech-recognizer");
|
|
13
|
+
const PYTHON_SCRIPT = path.join(__extensionDir, "speech-recognizer.py");
|
|
13
14
|
|
|
14
15
|
const IS_DARWIN = process.platform === "darwin";
|
|
15
16
|
const IS_LINUX = process.platform === "linux";
|