pi-ui-extend 1.0.42 → 1.0.45
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 +41 -12
- package/dist/app/app.d.ts +10 -0
- package/dist/app/app.js +132 -8
- package/dist/app/cli/install.js +2 -2
- package/dist/app/commands/command-controller.d.ts +4 -0
- package/dist/app/commands/command-controller.js +11 -0
- package/dist/app/commands/command-git-actions.d.ts +25 -0
- package/dist/app/commands/command-git-actions.js +381 -0
- package/dist/app/commands/command-host.d.ts +3 -0
- package/dist/app/commands/command-host.js +5 -2
- package/dist/app/commands/command-model-actions.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +51 -34
- package/dist/app/commands/command-navigation-actions.d.ts +1 -0
- package/dist/app/commands/command-navigation-actions.js +16 -3
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +14 -0
- package/dist/app/commands/reload-context-inventory.js +12 -1
- package/dist/app/input/autocomplete-controller.js +61 -34
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/input/input-controller.d.ts +2 -1
- package/dist/app/input/input-controller.js +7 -2
- package/dist/app/input/prompt-enhancer-controller.js +53 -35
- package/dist/app/input/voice-controller.d.ts +41 -45
- package/dist/app/input/voice-controller.js +351 -419
- package/dist/app/model/model-usage-controller.js +17 -7
- package/dist/app/model/model-usage-status.d.ts +4 -1
- package/dist/app/model/model-usage-status.js +270 -46
- package/dist/app/popup/menu-items-controller.d.ts +13 -3
- package/dist/app/popup/menu-items-controller.js +37 -21
- package/dist/app/popup/popup-action-controller.d.ts +12 -2
- package/dist/app/popup/popup-action-controller.js +77 -24
- package/dist/app/popup/popup-menu-controller.d.ts +36 -14
- package/dist/app/popup/popup-menu-controller.js +239 -69
- package/dist/app/rendering/dcp-stats.d.ts +9 -4
- package/dist/app/rendering/dcp-stats.js +40 -425
- package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
- package/dist/app/rendering/popup-menu-renderer.js +42 -37
- package/dist/app/rendering/render-controller.js +23 -2
- package/dist/app/rendering/status-line-renderer.d.ts +5 -0
- package/dist/app/rendering/status-line-renderer.js +41 -5
- package/dist/app/rendering/tab-line-renderer.js +26 -20
- package/dist/app/runtime.d.ts +12 -1
- package/dist/app/runtime.js +120 -12
- package/dist/app/screen/mouse-controller.d.ts +2 -0
- package/dist/app/screen/mouse-controller.js +17 -7
- package/dist/app/screen/status-controller.d.ts +4 -0
- package/dist/app/screen/status-controller.js +5 -0
- package/dist/app/session/lazy-session-manager.js +34 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +10 -1
- package/dist/app/session/session-history.d.ts +1 -0
- package/dist/app/session/session-history.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
- package/dist/app/session/session-lifecycle-controller.js +10 -1
- package/dist/app/session/tabs-controller.d.ts +25 -1
- package/dist/app/session/tabs-controller.js +442 -153
- package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
- package/dist/app/subagents/subagents-widget-controller.js +6 -0
- package/dist/app/types.d.ts +11 -1
- package/dist/app/workspace/workspace-actions-controller.js +10 -2
- package/dist/app/workspace/workspace-undo.d.ts +1 -0
- package/dist/app/workspace/workspace-undo.js +1 -0
- package/dist/bundled-extensions/question/index.js +9 -1
- package/dist/bundled-extensions/question/remote.d.ts +4 -0
- package/dist/bundled-extensions/question/remote.js +33 -0
- package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
- package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
- package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
- package/dist/bundled-extensions/telegram-connector/config.js +87 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
- package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
- package/dist/bundled-extensions/telegram-connector/index.js +195 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
- package/dist/bundled-extensions/terminal-bell/index.js +0 -76
- package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
- package/dist/bundled-extensions/workspace-undo/index.js +191 -0
- package/dist/config.d.ts +21 -2
- package/dist/config.js +159 -32
- package/dist/default-pix-config.js +20 -10
- package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
- package/dist/schemas/pi-tools-suite-schema.js +11 -5
- package/dist/schemas/pix-schema.d.ts +12 -2
- package/dist/schemas/pix-schema.js +37 -9
- package/dist/schemas/tasks-schema.js +1 -1
- package/docs/concurrency.md +3 -1
- package/docs/desktop-mvp.md +10 -5
- package/docs/desktop-task-manager.md +81 -28
- package/docs/release.md +30 -6
- package/external/pi-tools-suite/README.md +165 -39
- package/external/pi-tools-suite/docs/session-recovery.md +7 -0
- package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
- package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
- package/external/pi-tools-suite/package.json +6 -1
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
- package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
- package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
- package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
- package/external/pi-tools-suite/src/config.ts +14 -0
- package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
- package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
- package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
- package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
- package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
- package/external/pi-tools-suite/src/dcp/config.ts +58 -4
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
- package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
- package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
- package/external/pi-tools-suite/src/dcp/index.ts +338 -66
- package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
- package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
- package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
- package/external/pi-tools-suite/src/dcp/state.ts +9 -0
- package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
- package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
- package/external/pi-tools-suite/src/lib/project.ts +36 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
- package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
- package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
- package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
- package/external/pi-tools-suite/src/todo/index.ts +21 -0
- package/external/pi-tools-suite/src/todo/todo.ts +19 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
- package/package.json +7 -8
- package/schemas/pi-tools-suite.json +44 -12
- package/schemas/pix.json +109 -15
- package/schemas/tasks.json +1 -2
- package/skills/simplify/SKILL.md +33 -5
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
- package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
- package/skills/playwright-cli/SKILL.md +0 -420
- package/skills/playwright-cli/references/element-attributes.md +0 -23
- package/skills/playwright-cli/references/playwright-tests.md +0 -50
- package/skills/playwright-cli/references/request-mocking.md +0 -87
- package/skills/playwright-cli/references/running-code.md +0 -241
- package/skills/playwright-cli/references/session-management.md +0 -273
- package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
- package/skills/playwright-cli/references/storage-state.md +0 -290
- package/skills/playwright-cli/references/test-generation.md +0 -142
- package/skills/playwright-cli/references/tracing.md +0 -154
- package/skills/playwright-cli/references/video-recording.md +0 -147
- package/skills/spec-wiki/SKILL.md +0 -55
- package/skills/spec-wiki/evals/evals.json +0 -132
- package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
- package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
- package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
- package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
- package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
- package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
- package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
- package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
- package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
- package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
- package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
- package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
- package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
- package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
- package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
- package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
- package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
- package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
- package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
- package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
- package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
- package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
- package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
- package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
- package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
- package/skills/spec-wiki/evals/trigger-evals.json +0 -94
- package/skills/spec-wiki/references/bootstrap.md +0 -100
- package/skills/spec-wiki/references/focused-spec.md +0 -117
- package/skills/spec-wiki/references/index-schema.md +0 -330
- package/skills/spec-wiki/references/maintenance.md +0 -134
- package/skills/spec-wiki/references/query.md +0 -74
- package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
|
@@ -22,6 +22,8 @@ export class AppSubagentsWidgetController {
|
|
|
22
22
|
this.host = host;
|
|
23
23
|
}
|
|
24
24
|
get widgetState() {
|
|
25
|
+
if (!this.host.hasActiveRuntime())
|
|
26
|
+
return undefined;
|
|
25
27
|
return this.state;
|
|
26
28
|
}
|
|
27
29
|
startPolling() {
|
|
@@ -51,6 +53,8 @@ export class AppSubagentsWidgetController {
|
|
|
51
53
|
return;
|
|
52
54
|
if (!isSubagentRunRenderDetails(details))
|
|
53
55
|
return;
|
|
56
|
+
if (!this.host.hasActiveRuntime())
|
|
57
|
+
return;
|
|
54
58
|
const runDir = resolveSubagentRunDir(this.host.cwd, details.runDir);
|
|
55
59
|
const normalizedDetails = { ...details, runDir };
|
|
56
60
|
if (normalizedDetails.tasks)
|
|
@@ -372,6 +376,8 @@ export class AppSubagentsWidgetController {
|
|
|
372
376
|
return activeSubagentStates(this.state?.agents ?? []).length > 0;
|
|
373
377
|
}
|
|
374
378
|
eventMatchesCurrentSession(eventSessionFile) {
|
|
379
|
+
if (!this.host.hasActiveRuntime())
|
|
380
|
+
return false;
|
|
375
381
|
if (!eventSessionFile)
|
|
376
382
|
return true;
|
|
377
383
|
const sessionFile = this.host.sessionFile();
|
package/dist/app/types.d.ts
CHANGED
|
@@ -235,6 +235,8 @@ export type RenderedLine = {
|
|
|
235
235
|
index: number;
|
|
236
236
|
} | {
|
|
237
237
|
kind: "popup-menu-close";
|
|
238
|
+
} | {
|
|
239
|
+
kind: "model-visibility-clear";
|
|
238
240
|
} | {
|
|
239
241
|
kind: "todo-panel";
|
|
240
242
|
} | {
|
|
@@ -346,6 +348,7 @@ export type SessionTab = {
|
|
|
346
348
|
id: string;
|
|
347
349
|
title: string;
|
|
348
350
|
titlePlaceholder?: "loading" | "new";
|
|
351
|
+
draft?: boolean;
|
|
349
352
|
isFork?: boolean;
|
|
350
353
|
status: SessionTabStatus;
|
|
351
354
|
activity?: SessionActivity;
|
|
@@ -542,6 +545,7 @@ export type ModelMenuValue = {
|
|
|
542
545
|
model: SessionModel;
|
|
543
546
|
ref: string;
|
|
544
547
|
current: boolean;
|
|
548
|
+
visible?: boolean;
|
|
545
549
|
};
|
|
546
550
|
export type ScopedSessionModel = {
|
|
547
551
|
model: SessionModel;
|
|
@@ -551,6 +555,12 @@ export type ThinkingMenuValue = {
|
|
|
551
555
|
level: ThinkingLevel;
|
|
552
556
|
current: boolean;
|
|
553
557
|
};
|
|
558
|
+
export type ModelThinkingMenuState = {
|
|
559
|
+
thinkingLevel: ThinkingLevel;
|
|
560
|
+
availableThinkingLevels: readonly ThinkingLevel[];
|
|
561
|
+
source: "model" | "thinking";
|
|
562
|
+
visibilityMode: boolean;
|
|
563
|
+
};
|
|
554
564
|
export type UserMessageMenuValue = "copy" | "fork" | "fork-new-tab" | "undo";
|
|
555
565
|
export type UserMessageJumpMenuValue = {
|
|
556
566
|
entryId?: string;
|
|
@@ -567,7 +577,7 @@ export type ResumeMenuValue = {
|
|
|
567
577
|
session: SessionInfo;
|
|
568
578
|
};
|
|
569
579
|
export type ActivePopupMenu = "slash" | "model" | "thinking" | "resume" | "user-message" | "user-message-jump" | "queue-message" | "sdk-menu";
|
|
570
|
-
export type PopupMenuPlacement = "default" | "under-tabs";
|
|
580
|
+
export type PopupMenuPlacement = "default" | "under-tabs" | "draft-surface";
|
|
571
581
|
export type StatusThinkingTarget = {
|
|
572
582
|
row: number;
|
|
573
583
|
startColumn: number;
|
|
@@ -2,7 +2,7 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { copyTextToClipboard } from "../screen/clipboard.js";
|
|
3
3
|
import { isRecord } from "../guards.js";
|
|
4
4
|
import { createId } from "../id.js";
|
|
5
|
-
import { loadWorkspaceUndoIndex, prepareWorkspaceMutation, revertWorkspaceMutations, saveWorkspaceUndoIndex, workspaceMutationFromToolExecution, workspaceUndoIndexKey, } from "./workspace-undo.js";
|
|
5
|
+
import { loadWorkspaceUndoIndex, prepareWorkspaceMutation, revertWorkspaceMutations, saveWorkspaceUndoIndex, workspaceMutationFromToolExecution, WORKSPACE_MUTATION_ENTRY_TYPE, workspaceUndoIndexKey, } from "./workspace-undo.js";
|
|
6
6
|
export class AppWorkspaceActionsController {
|
|
7
7
|
host;
|
|
8
8
|
workspaceUndoIndex = loadWorkspaceUndoIndex(getAgentDir());
|
|
@@ -23,8 +23,16 @@ export class AppWorkspaceActionsController {
|
|
|
23
23
|
return;
|
|
24
24
|
entry.workspaceMutations = [...(entry.workspaceMutations ?? []), mutation];
|
|
25
25
|
const sessionEntryId = this.resolveUserSessionEntryId(entry);
|
|
26
|
-
if (sessionEntryId)
|
|
26
|
+
if (sessionEntryId) {
|
|
27
27
|
this.persistWorkspaceMutations(sessionEntryId, entry.workspaceMutations);
|
|
28
|
+
// Also persist each new mutation in the session branch so Desktop and
|
|
29
|
+
// future renderers can perform the same message-scoped undo without
|
|
30
|
+
// relying on this process-wide compatibility index.
|
|
31
|
+
this.host.runtime()?.session.sessionManager.appendCustomEntry?.(WORKSPACE_MUTATION_ENTRY_TYPE, {
|
|
32
|
+
userEntryId: sessionEntryId,
|
|
33
|
+
mutation,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
28
36
|
this.host.touchEntry(entry);
|
|
29
37
|
}
|
|
30
38
|
scheduleUserSessionEntryMetadataSync() {
|
|
@@ -36,6 +36,7 @@ export type WorkspaceRevertResult = {
|
|
|
36
36
|
ok: false;
|
|
37
37
|
error: string;
|
|
38
38
|
};
|
|
39
|
+
export declare const WORKSPACE_MUTATION_ENTRY_TYPE = "pix-workspace-mutation";
|
|
39
40
|
export declare function workspaceUndoIndexKey(_sessionFile: string | undefined, _sessionId: string, entryId: string): string;
|
|
40
41
|
export declare function loadWorkspaceUndoIndex(agentDir: string): WorkspaceUndoIndex;
|
|
41
42
|
export declare function saveWorkspaceUndoIndex(agentDir: string, index: WorkspaceUndoIndex): void;
|
|
@@ -3,6 +3,7 @@ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { runProcess } from "../process.js";
|
|
5
5
|
const UNDO_INDEX_VERSION = 1;
|
|
6
|
+
export const WORKSPACE_MUTATION_ENTRY_TYPE = "pix-workspace-mutation";
|
|
6
7
|
export function workspaceUndoIndexKey(_sessionFile, _sessionId, entryId) {
|
|
7
8
|
return entryId;
|
|
8
9
|
}
|
|
@@ -3,6 +3,7 @@ import { questionParameters, normalizeQuestionInput } from "./contract.js";
|
|
|
3
3
|
import { renderQuestionCall, renderQuestionResult } from "./render.js";
|
|
4
4
|
import { createCanceledQuestionResult, createQuestionToolResult, createSuccessfulQuestionResult } from "./result.js";
|
|
5
5
|
import { runDesktopQuestionnaire, shouldUseDesktopQuestionBridge } from "./desktop.js";
|
|
6
|
+
import { runRemoteQuestionnaire } from "./remote.js";
|
|
6
7
|
import { runQuestionnaire } from "./tui.js";
|
|
7
8
|
export default function questionExtension(pi) {
|
|
8
9
|
pi.registerTool({
|
|
@@ -14,8 +15,15 @@ export default function questionExtension(pi) {
|
|
|
14
15
|
renderResult(result, _options, theme, context) {
|
|
15
16
|
return renderQuestionResult(result, theme, context.args);
|
|
16
17
|
},
|
|
17
|
-
async execute(_toolCallId, params,
|
|
18
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
18
19
|
const questions = normalizeQuestionInput(params);
|
|
20
|
+
const sessionId = ctx.sessionManager?.getSessionId();
|
|
21
|
+
const remoteSelections = sessionId ? await runRemoteQuestionnaire(sessionId, questions, signal) : undefined;
|
|
22
|
+
if (remoteSelections !== undefined) {
|
|
23
|
+
if (remoteSelections === null)
|
|
24
|
+
return createQuestionToolResult(createCanceledQuestionResult("user_canceled"), questions);
|
|
25
|
+
return createQuestionToolResult(createSuccessfulQuestionResult(questions, remoteSelections), questions);
|
|
26
|
+
}
|
|
19
27
|
if (!ctx.hasUI)
|
|
20
28
|
return createQuestionToolResult(createCanceledQuestionResult("ui_unavailable", questions), questions);
|
|
21
29
|
const selections = shouldUseDesktopQuestionBridge(ctx)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { NormalizedQuestion, QuestionSelection } from "./types.js";
|
|
2
|
+
export type RemoteQuestionHandler = (questions: NormalizedQuestion[], signal?: AbortSignal) => Promise<QuestionSelection[] | null | undefined>;
|
|
3
|
+
export declare function registerRemoteQuestionHandler(sessionId: string, handler: RemoteQuestionHandler): () => void;
|
|
4
|
+
export declare function runRemoteQuestionnaire(sessionId: string, questions: NormalizedQuestion[], signal?: AbortSignal): Promise<QuestionSelection[] | null | undefined>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const REGISTRY_KEY = Symbol.for("pix.question.remote-registry.v1");
|
|
2
|
+
export function registerRemoteQuestionHandler(sessionId, handler) {
|
|
3
|
+
const registry = remoteQuestionRegistry();
|
|
4
|
+
registry.set(sessionId, handler);
|
|
5
|
+
let active = true;
|
|
6
|
+
return () => {
|
|
7
|
+
if (!active)
|
|
8
|
+
return;
|
|
9
|
+
active = false;
|
|
10
|
+
if (registry.get(sessionId) === handler)
|
|
11
|
+
registry.delete(sessionId);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function runRemoteQuestionnaire(sessionId, questions, signal) {
|
|
15
|
+
const handler = remoteQuestionRegistry().get(sessionId);
|
|
16
|
+
if (!handler)
|
|
17
|
+
return undefined;
|
|
18
|
+
try {
|
|
19
|
+
return await handler(questions, signal);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
if (signal?.aborted)
|
|
23
|
+
return null;
|
|
24
|
+
// Remote integrations are optional. If Telegram/networking fails before an
|
|
25
|
+
// answer is obtained, fall back to the normal local question UI.
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function remoteQuestionRegistry() {
|
|
30
|
+
const root = globalThis;
|
|
31
|
+
root[REGISTRY_KEY] ??= new Map();
|
|
32
|
+
return root[REGISTRY_KEY];
|
|
33
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type TelegramBotClientOptions = {
|
|
2
|
+
sendTimeoutMs?: number;
|
|
3
|
+
pollRequestTimeoutMs?: number;
|
|
4
|
+
};
|
|
5
|
+
export type TelegramIncomingMessage = {
|
|
6
|
+
messageId: number;
|
|
7
|
+
chatId: string;
|
|
8
|
+
text: string;
|
|
9
|
+
replyToMessageId?: number;
|
|
10
|
+
};
|
|
11
|
+
type TelegramUpdate = {
|
|
12
|
+
update_id?: unknown;
|
|
13
|
+
message?: {
|
|
14
|
+
message_id?: unknown;
|
|
15
|
+
chat?: {
|
|
16
|
+
id?: unknown;
|
|
17
|
+
};
|
|
18
|
+
text?: unknown;
|
|
19
|
+
reply_to_message?: {
|
|
20
|
+
message_id?: unknown;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type TelegramFetch = typeof fetch;
|
|
25
|
+
export declare class TelegramBotClient {
|
|
26
|
+
private readonly botToken;
|
|
27
|
+
private readonly chatId;
|
|
28
|
+
private readonly fetchFn;
|
|
29
|
+
private readonly options;
|
|
30
|
+
private running;
|
|
31
|
+
private abortController;
|
|
32
|
+
private nextOffset;
|
|
33
|
+
constructor(botToken: string, chatId: string, fetchFn?: TelegramFetch, options?: TelegramBotClientOptions);
|
|
34
|
+
start(onMessage: (message: TelegramIncomingMessage) => void | Promise<void>, onError?: (error: Error) => void): void;
|
|
35
|
+
stop(): void;
|
|
36
|
+
sendMessage(text: string, signal?: AbortSignal): Promise<number>;
|
|
37
|
+
private pollLoop;
|
|
38
|
+
private sanitizeError;
|
|
39
|
+
private call;
|
|
40
|
+
}
|
|
41
|
+
export declare function normalizeIncomingMessage(update: TelegramUpdate): TelegramIncomingMessage | undefined;
|
|
42
|
+
export declare function trimTelegramText(text: string): string;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const TELEGRAM_API_BASE = "https://api.telegram.org";
|
|
2
|
+
const MAX_TELEGRAM_TEXT = 4000;
|
|
3
|
+
const POLL_TIMEOUT_SECONDS = 25;
|
|
4
|
+
const DEFAULT_SEND_TIMEOUT_MS = 10_000;
|
|
5
|
+
const DEFAULT_POLL_REQUEST_TIMEOUT_MS = (POLL_TIMEOUT_SECONDS + 10) * 1000;
|
|
6
|
+
export class TelegramBotClient {
|
|
7
|
+
botToken;
|
|
8
|
+
chatId;
|
|
9
|
+
fetchFn;
|
|
10
|
+
options;
|
|
11
|
+
running = false;
|
|
12
|
+
abortController;
|
|
13
|
+
nextOffset;
|
|
14
|
+
constructor(botToken, chatId, fetchFn = fetch, options = {}) {
|
|
15
|
+
this.botToken = botToken;
|
|
16
|
+
this.chatId = chatId;
|
|
17
|
+
this.fetchFn = fetchFn;
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
start(onMessage, onError = () => { }) {
|
|
21
|
+
if (this.running)
|
|
22
|
+
return;
|
|
23
|
+
this.running = true;
|
|
24
|
+
this.abortController = new AbortController();
|
|
25
|
+
void this.pollLoop(onMessage, onError, this.abortController.signal);
|
|
26
|
+
}
|
|
27
|
+
stop() {
|
|
28
|
+
this.running = false;
|
|
29
|
+
this.abortController?.abort();
|
|
30
|
+
this.abortController = undefined;
|
|
31
|
+
}
|
|
32
|
+
async sendMessage(text, signal) {
|
|
33
|
+
try {
|
|
34
|
+
const body = await this.call("sendMessage", {
|
|
35
|
+
chat_id: this.chatId,
|
|
36
|
+
text: trimTelegramText(text),
|
|
37
|
+
disable_web_page_preview: true,
|
|
38
|
+
}, signal);
|
|
39
|
+
if (!body || typeof body.message_id !== "number")
|
|
40
|
+
throw new Error("Telegram sendMessage returned no message id");
|
|
41
|
+
return body.message_id;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw this.sanitizeError(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async pollLoop(onMessage, onError, signal) {
|
|
48
|
+
let failures = 0;
|
|
49
|
+
let baselineReady = false;
|
|
50
|
+
while (this.running && !signal.aborted) {
|
|
51
|
+
try {
|
|
52
|
+
if (!baselineReady) {
|
|
53
|
+
const pending = await this.call("getUpdates", {
|
|
54
|
+
offset: -1,
|
|
55
|
+
limit: 1,
|
|
56
|
+
timeout: 0,
|
|
57
|
+
allowed_updates: ["message"],
|
|
58
|
+
}, signal);
|
|
59
|
+
const latestUpdateId = pending
|
|
60
|
+
?.map((update) => update.update_id)
|
|
61
|
+
.filter((updateId) => typeof updateId === "number")
|
|
62
|
+
.at(-1);
|
|
63
|
+
if (latestUpdateId !== undefined)
|
|
64
|
+
this.nextOffset = latestUpdateId + 1;
|
|
65
|
+
baselineReady = true;
|
|
66
|
+
failures = 0;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const updates = await this.call("getUpdates", {
|
|
70
|
+
...(this.nextOffset === undefined ? {} : { offset: this.nextOffset }),
|
|
71
|
+
timeout: POLL_TIMEOUT_SECONDS,
|
|
72
|
+
allowed_updates: ["message"],
|
|
73
|
+
}, signal);
|
|
74
|
+
failures = 0;
|
|
75
|
+
for (const update of updates ?? []) {
|
|
76
|
+
if (typeof update.update_id === "number")
|
|
77
|
+
this.nextOffset = update.update_id + 1;
|
|
78
|
+
const message = normalizeIncomingMessage(update);
|
|
79
|
+
if (!message || message.chatId !== this.chatId)
|
|
80
|
+
continue;
|
|
81
|
+
await onMessage(message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (signal.aborted || !this.running)
|
|
86
|
+
return;
|
|
87
|
+
failures += 1;
|
|
88
|
+
onError(this.sanitizeError(error));
|
|
89
|
+
await sleep(Math.min(30_000, 500 * 2 ** Math.min(failures - 1, 6)), signal);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
sanitizeError(error) {
|
|
94
|
+
const message = asError(error).message.replaceAll(this.botToken, "[redacted]");
|
|
95
|
+
return new Error(message);
|
|
96
|
+
}
|
|
97
|
+
async call(method, payload, signal) {
|
|
98
|
+
const requestSignal = combineAbortSignals([
|
|
99
|
+
signal,
|
|
100
|
+
this.abortController?.signal,
|
|
101
|
+
], method === "getUpdates"
|
|
102
|
+
? this.options.pollRequestTimeoutMs ?? DEFAULT_POLL_REQUEST_TIMEOUT_MS
|
|
103
|
+
: this.options.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS);
|
|
104
|
+
const response = await this.fetchFn(`${TELEGRAM_API_BASE}/bot${this.botToken}/${method}`, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: { "Content-Type": "application/json" },
|
|
107
|
+
body: JSON.stringify(payload),
|
|
108
|
+
signal: requestSignal,
|
|
109
|
+
});
|
|
110
|
+
let parsed;
|
|
111
|
+
try {
|
|
112
|
+
parsed = await response.json();
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Fall through to the sanitized HTTP error below.
|
|
116
|
+
}
|
|
117
|
+
if (!response.ok || parsed?.ok !== true) {
|
|
118
|
+
const description = typeof parsed?.description === "string" ? `: ${parsed.description}` : "";
|
|
119
|
+
throw new Error(`Telegram ${method} failed (${response.status})${description}`);
|
|
120
|
+
}
|
|
121
|
+
return parsed.result;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function combineAbortSignals(signals, timeoutMs) {
|
|
125
|
+
const active = signals.filter((signal) => signal !== undefined);
|
|
126
|
+
active.push(AbortSignal.timeout(Math.max(1, timeoutMs)));
|
|
127
|
+
return active.length === 1 ? active[0] : AbortSignal.any(active);
|
|
128
|
+
}
|
|
129
|
+
export function normalizeIncomingMessage(update) {
|
|
130
|
+
const message = update.message;
|
|
131
|
+
if (!message || typeof message.message_id !== "number" || typeof message.text !== "string")
|
|
132
|
+
return undefined;
|
|
133
|
+
const rawChatId = message.chat?.id;
|
|
134
|
+
if (typeof rawChatId !== "number" && typeof rawChatId !== "string")
|
|
135
|
+
return undefined;
|
|
136
|
+
const text = message.text.trim();
|
|
137
|
+
if (!text)
|
|
138
|
+
return undefined;
|
|
139
|
+
const rawReplyId = message.reply_to_message?.message_id;
|
|
140
|
+
return {
|
|
141
|
+
messageId: message.message_id,
|
|
142
|
+
chatId: String(rawChatId),
|
|
143
|
+
text,
|
|
144
|
+
...(typeof rawReplyId === "number" ? { replyToMessageId: rawReplyId } : {}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function trimTelegramText(text) {
|
|
148
|
+
if (text.length <= MAX_TELEGRAM_TEXT)
|
|
149
|
+
return text;
|
|
150
|
+
return `${text.slice(0, MAX_TELEGRAM_TEXT - 2)}…`;
|
|
151
|
+
}
|
|
152
|
+
function asError(error) {
|
|
153
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
154
|
+
}
|
|
155
|
+
async function sleep(ms, signal) {
|
|
156
|
+
if (signal.aborted)
|
|
157
|
+
return;
|
|
158
|
+
await new Promise((resolve) => {
|
|
159
|
+
const timer = setTimeout(resolve, ms);
|
|
160
|
+
timer.unref?.();
|
|
161
|
+
signal.addEventListener("abort", () => {
|
|
162
|
+
clearTimeout(timer);
|
|
163
|
+
resolve();
|
|
164
|
+
}, { once: true });
|
|
165
|
+
});
|
|
166
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type TelegramConnectorConfig = {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
botToken?: string;
|
|
4
|
+
chatId?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function getTelegramConnectorConfigPath(homeDir?: string): string;
|
|
7
|
+
export declare function readTelegramConnectorConfig(configPath?: string): TelegramConnectorConfig;
|
|
8
|
+
export declare function resolveTelegramConnectorConfig(configPath?: string, environment?: NodeJS.ProcessEnv): TelegramConnectorConfig;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { parse as parseJsonc } from "jsonc-parser";
|
|
5
|
+
const CONFIG_KEY = "telegramConnector";
|
|
6
|
+
const ENV_ENABLED = "PIX_TELEGRAM_CONNECTOR";
|
|
7
|
+
const ENV_BOT_TOKEN = "PIX_TELEGRAM_BOT_TOKEN";
|
|
8
|
+
const ENV_CHAT_ID = "PIX_TELEGRAM_CHAT_ID";
|
|
9
|
+
export function getTelegramConnectorConfigPath(homeDir = homedir()) {
|
|
10
|
+
return join(homeDir, ".config", "pi", "pi-tools-suite.jsonc");
|
|
11
|
+
}
|
|
12
|
+
export function readTelegramConnectorConfig(configPath = getTelegramConnectorConfigPath()) {
|
|
13
|
+
return readTelegramConnectorConfigState(configPath).config;
|
|
14
|
+
}
|
|
15
|
+
function readTelegramConnectorConfigState(configPath) {
|
|
16
|
+
if (!existsSync(configPath))
|
|
17
|
+
return { config: { enabled: false }, explicitlyDisabled: false };
|
|
18
|
+
try {
|
|
19
|
+
const parsed = parseJsonc(readFileSync(configPath, "utf-8"));
|
|
20
|
+
if (!isRecord(parsed))
|
|
21
|
+
return { config: { enabled: false }, explicitlyDisabled: false };
|
|
22
|
+
const raw = parsed[CONFIG_KEY];
|
|
23
|
+
if (!isRecord(raw))
|
|
24
|
+
return { config: { enabled: false }, explicitlyDisabled: false };
|
|
25
|
+
const botToken = nonEmptyString(raw.botToken);
|
|
26
|
+
const chatId = normalizeChatId(raw.chatId);
|
|
27
|
+
const explicitlyDisabled = raw.enabled === false;
|
|
28
|
+
return {
|
|
29
|
+
config: {
|
|
30
|
+
enabled: !explicitlyDisabled && Boolean(botToken && chatId),
|
|
31
|
+
...(botToken ? { botToken } : {}),
|
|
32
|
+
...(chatId ? { chatId } : {}),
|
|
33
|
+
},
|
|
34
|
+
explicitlyDisabled,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { config: { enabled: false }, explicitlyDisabled: false };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function resolveTelegramConnectorConfig(configPath = getTelegramConnectorConfigPath(), environment = process.env) {
|
|
42
|
+
const { config: fromConfig, explicitlyDisabled } = readTelegramConnectorConfigState(configPath);
|
|
43
|
+
const envBotToken = nonEmptyString(environment[ENV_BOT_TOKEN]);
|
|
44
|
+
const envChatId = normalizeChatId(environment[ENV_CHAT_ID]);
|
|
45
|
+
const botToken = envBotToken ?? fromConfig.botToken;
|
|
46
|
+
const chatId = envChatId ?? fromConfig.chatId;
|
|
47
|
+
const envEnabled = parseBooleanEnv(environment[ENV_ENABLED]);
|
|
48
|
+
const enabled = envEnabled === false
|
|
49
|
+
? false
|
|
50
|
+
: envEnabled === true
|
|
51
|
+
? Boolean(botToken && chatId)
|
|
52
|
+
: explicitlyDisabled
|
|
53
|
+
? false
|
|
54
|
+
: Boolean(botToken && chatId);
|
|
55
|
+
return {
|
|
56
|
+
enabled,
|
|
57
|
+
...(botToken ? { botToken } : {}),
|
|
58
|
+
...(chatId ? { chatId } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function normalizeChatId(value) {
|
|
62
|
+
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
63
|
+
return String(value);
|
|
64
|
+
if (typeof value !== "string")
|
|
65
|
+
return undefined;
|
|
66
|
+
const trimmed = value.trim();
|
|
67
|
+
return /^-?\d+$/.test(trimmed) ? trimmed : undefined;
|
|
68
|
+
}
|
|
69
|
+
function nonEmptyString(value) {
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
return undefined;
|
|
72
|
+
const trimmed = value.trim();
|
|
73
|
+
return trimmed || undefined;
|
|
74
|
+
}
|
|
75
|
+
function parseBooleanEnv(value) {
|
|
76
|
+
if (value === undefined || value.trim() === "")
|
|
77
|
+
return undefined;
|
|
78
|
+
const normalized = value.trim().toLowerCase();
|
|
79
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
80
|
+
return true;
|
|
81
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
82
|
+
return false;
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
function isRecord(value) {
|
|
86
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
87
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { NormalizedQuestion, QuestionSelection } from "../question/types.js";
|
|
2
|
+
import { TelegramBotClient, type TelegramIncomingMessage } from "./bot.js";
|
|
3
|
+
import type { TelegramConnectorConfig } from "./config.js";
|
|
4
|
+
export type TelegramCompletionKind = "complete" | "error";
|
|
5
|
+
export type TelegramSessionEndpoint = {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
cwd: string;
|
|
8
|
+
getTitle(): string;
|
|
9
|
+
isIdle(): boolean;
|
|
10
|
+
sendUserMessage(text: string): void;
|
|
11
|
+
dispatchNewSession(requestId: string): void;
|
|
12
|
+
};
|
|
13
|
+
type BotLike = Pick<TelegramBotClient, "start" | "stop" | "sendMessage">;
|
|
14
|
+
type BotFactory = (botToken: string, chatId: string) => BotLike;
|
|
15
|
+
export declare class TelegramConnectorCoordinator {
|
|
16
|
+
private readonly createBot;
|
|
17
|
+
private readonly reportError;
|
|
18
|
+
private readonly sessions;
|
|
19
|
+
private readonly completionRoutes;
|
|
20
|
+
private readonly pendingQuestions;
|
|
21
|
+
private readonly newSessionRequests;
|
|
22
|
+
private readonly newSessionSources;
|
|
23
|
+
private bot;
|
|
24
|
+
private botKey;
|
|
25
|
+
private focusSessionId;
|
|
26
|
+
private stopTimer;
|
|
27
|
+
constructor(createBot?: BotFactory, reportError?: (message: string) => void);
|
|
28
|
+
attachSession(endpoint: TelegramSessionEndpoint, config: TelegramConnectorConfig): void;
|
|
29
|
+
detachSession(sessionId: string, endpoint?: TelegramSessionEndpoint): void;
|
|
30
|
+
notifyCompletion(sessionId: string, kind: TelegramCompletionKind, summary?: string): Promise<void>;
|
|
31
|
+
askQuestions(sessionId: string, questions: NormalizedQuestion[], signal?: AbortSignal): Promise<QuestionSelection[] | null | undefined>;
|
|
32
|
+
createNewSessionRequest(sourceSessionId: string, task: string): string | undefined;
|
|
33
|
+
consumeNewSessionRequest(requestId: string, sourceSessionId: string): string | undefined;
|
|
34
|
+
finishNewSessionRequest(sourceSessionId: string): void;
|
|
35
|
+
announceNewSession(sessionId: string): Promise<void>;
|
|
36
|
+
sendStatus(): Promise<void>;
|
|
37
|
+
sendHelp(): Promise<void>;
|
|
38
|
+
sendNotice(text: string): Promise<void>;
|
|
39
|
+
handleIncoming(message: TelegramIncomingMessage): Promise<void>;
|
|
40
|
+
stop(): void;
|
|
41
|
+
private ensureBot;
|
|
42
|
+
private waitForQuestionReply;
|
|
43
|
+
private resolvePendingQuestion;
|
|
44
|
+
private cancelPendingQuestion;
|
|
45
|
+
private rememberCompletionRoute;
|
|
46
|
+
private hasPendingQuestionFor;
|
|
47
|
+
private pruneExpiredNewSessionRequests;
|
|
48
|
+
private scheduleStop;
|
|
49
|
+
private clearStopTimer;
|
|
50
|
+
}
|
|
51
|
+
type ParsedTelegramCommand = {
|
|
52
|
+
kind: "new";
|
|
53
|
+
task: string;
|
|
54
|
+
} | {
|
|
55
|
+
kind: "help";
|
|
56
|
+
} | {
|
|
57
|
+
kind: "status";
|
|
58
|
+
} | {
|
|
59
|
+
kind: "message";
|
|
60
|
+
text: string;
|
|
61
|
+
};
|
|
62
|
+
export declare function parseTelegramCommand(text: string): ParsedTelegramCommand;
|
|
63
|
+
export declare function parseQuestionAnswer(question: NormalizedQuestion, answer: string): QuestionSelection | undefined;
|
|
64
|
+
export declare function getTelegramConnectorCoordinator(): TelegramConnectorCoordinator;
|
|
65
|
+
export declare function resetTelegramConnectorCoordinatorForTests(): void;
|
|
66
|
+
export {};
|