@brain0pia/pi-notify 0.1.0 → 0.2.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 +22 -1
- package/package.json +1 -1
- package/src/config.ts +79 -5
- package/src/controller.ts +22 -5
- package/src/format.ts +34 -5
- package/src/index.ts +76 -2
- package/src/types.ts +3 -0
package/README.md
CHANGED
|
@@ -25,6 +25,27 @@ Create `~/.pi/notify.json`:
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Optional: add a session URL template. If present, `SESSION_ID` is replaced with the current Pi session id and the resolved link is included in each Telegram notification.
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"botToken": "123456:ABCDEF...",
|
|
33
|
+
"chatId": "123456789",
|
|
34
|
+
"sessionUrlTemplate": "https://session-viewer.example/#SESSION_ID"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You can also manage that field from Pi with the slash command:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
/pi-notify-url https://session-viewer.example/#SESSION_ID
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Useful variants:
|
|
45
|
+
|
|
46
|
+
- `/pi-notify-url` — show the current template
|
|
47
|
+
- `/pi-notify-url off` — clear the template
|
|
48
|
+
|
|
28
49
|
## Behavior
|
|
29
50
|
|
|
30
51
|
After every `agent_end` event the extension:
|
|
@@ -35,7 +56,7 @@ After every `agent_end` event the extension:
|
|
|
35
56
|
4. Cancels on any other key.
|
|
36
57
|
5. Sends automatically when the countdown reaches zero.
|
|
37
58
|
|
|
38
|
-
The Telegram payload includes metadata (`project`, `cwd`, `timestamp`, `model`) plus the full assistant output. Short outputs are sent as a MarkdownV2 message with a plain-text fallback on parse errors. Long outputs are sent as a short header message plus a `.md` attachment containing the full response.
|
|
59
|
+
The Telegram payload includes metadata (`project`, `cwd`, `timestamp`, `model`) plus the full assistant output. If `sessionUrlTemplate` is configured, the notification also includes an `Open session` link built from the current session id. Short outputs are sent as a MarkdownV2 message with a plain-text fallback on parse errors. Long outputs are sent as a short header message plus a `.md` attachment containing the full response.
|
|
39
60
|
|
|
40
61
|
## Development
|
|
41
62
|
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
@@ -6,20 +6,93 @@ import type { ConfigLoadResult } from "./types.js";
|
|
|
6
6
|
|
|
7
7
|
export const NOTIFY_CONFIG_PATH = path.join(homedir(), ".pi", "notify.json");
|
|
8
8
|
|
|
9
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function normalizeSessionUrlTemplate(value: unknown): string | undefined {
|
|
14
|
+
if (typeof value !== "string") {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveSessionUrl(template: string | undefined, sessionId: string): string | undefined {
|
|
23
|
+
const normalizedTemplate = normalizeSessionUrlTemplate(template);
|
|
24
|
+
const normalizedSessionId = sessionId.trim();
|
|
25
|
+
if (!normalizedTemplate || !normalizedSessionId) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return normalizedTemplate.replaceAll("SESSION_ID", normalizedSessionId);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function readNotifyConfigRecord(configPath = NOTIFY_CONFIG_PATH): Promise<Record<string, unknown>> {
|
|
33
|
+
let raw: string;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
raw = await readFile(configPath, "utf8");
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let parsed: unknown;
|
|
46
|
+
try {
|
|
47
|
+
parsed = JSON.parse(raw);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
throw new Error(`pi-notify: invalid JSON in ${configPath}: ${message}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!isRecord(parsed)) {
|
|
54
|
+
throw new Error(`pi-notify: expected an object in ${configPath}.`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { ...parsed };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function getNotifySessionUrlTemplate(configPath = NOTIFY_CONFIG_PATH): Promise<string | undefined> {
|
|
61
|
+
const record = await readNotifyConfigRecord(configPath);
|
|
62
|
+
return normalizeSessionUrlTemplate(record.sessionUrlTemplate);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function setNotifySessionUrlTemplate(
|
|
66
|
+
template: string | undefined,
|
|
67
|
+
configPath = NOTIFY_CONFIG_PATH,
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
const record = await readNotifyConfigRecord(configPath);
|
|
70
|
+
const normalizedTemplate = normalizeSessionUrlTemplate(template);
|
|
71
|
+
|
|
72
|
+
if (normalizedTemplate) {
|
|
73
|
+
record.sessionUrlTemplate = normalizedTemplate;
|
|
74
|
+
} else {
|
|
75
|
+
delete record.sessionUrlTemplate;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await mkdir(path.dirname(configPath), { recursive: true });
|
|
79
|
+
await writeFile(configPath, `${JSON.stringify(record, null, 2)}\n`, "utf8");
|
|
80
|
+
}
|
|
81
|
+
|
|
9
82
|
export function validateNotifyConfig(value: unknown, configPath = NOTIFY_CONFIG_PATH): ConfigLoadResult {
|
|
10
|
-
if (!
|
|
83
|
+
if (!isRecord(value)) {
|
|
11
84
|
return { ok: false, reason: `pi-notify: expected an object in ${configPath}.` };
|
|
12
85
|
}
|
|
13
86
|
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const chatIdValue = record.chatId;
|
|
87
|
+
const botToken = typeof value.botToken === "string" ? value.botToken.trim() : "";
|
|
88
|
+
const chatIdValue = value.chatId;
|
|
17
89
|
const chatId =
|
|
18
90
|
typeof chatIdValue === "string"
|
|
19
91
|
? chatIdValue.trim()
|
|
20
92
|
: typeof chatIdValue === "number" && Number.isFinite(chatIdValue)
|
|
21
93
|
? String(chatIdValue)
|
|
22
94
|
: "";
|
|
95
|
+
const sessionUrlTemplate = normalizeSessionUrlTemplate(value.sessionUrlTemplate);
|
|
23
96
|
|
|
24
97
|
if (!botToken) {
|
|
25
98
|
return { ok: false, reason: `pi-notify: missing \"botToken\" in ${configPath}.` };
|
|
@@ -38,6 +111,7 @@ export function validateNotifyConfig(value: unknown, configPath = NOTIFY_CONFIG_
|
|
|
38
111
|
config: {
|
|
39
112
|
botToken,
|
|
40
113
|
chatId,
|
|
114
|
+
...(sessionUrlTemplate ? { sessionUrlTemplate } : {}),
|
|
41
115
|
},
|
|
42
116
|
};
|
|
43
117
|
}
|
package/src/controller.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
|
|
5
|
-
import { loadNotifyConfig } from "./config.js";
|
|
5
|
+
import { loadNotifyConfig, resolveSessionUrl } from "./config.js";
|
|
6
6
|
import { showCountdownOverlay, type CountdownOverlayOptions } from "./countdown.js";
|
|
7
7
|
import { sendTelegramNotification } from "./telegram.js";
|
|
8
8
|
import type { ConfigLoadResult, CountdownDecision, NotificationPayload, NotifyConfig } from "./types.js";
|
|
@@ -60,7 +60,7 @@ export function extractAssistantText(messages: readonly AgentMessageLike[]): str
|
|
|
60
60
|
|
|
61
61
|
export function createNotificationPayload(
|
|
62
62
|
messages: readonly AgentMessageLike[],
|
|
63
|
-
ctx: Pick<ExtensionContext, "cwd" | "model">,
|
|
63
|
+
ctx: Pick<ExtensionContext, "cwd" | "model" | "sessionManager">,
|
|
64
64
|
now: Date,
|
|
65
65
|
): NotificationPayload | null {
|
|
66
66
|
const assistantText = extractAssistantText(messages);
|
|
@@ -77,12 +77,28 @@ export function createNotificationPayload(
|
|
|
77
77
|
project: basename.length > 0 ? basename : cwd,
|
|
78
78
|
cwd,
|
|
79
79
|
timestamp: now.toISOString(),
|
|
80
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
80
81
|
model,
|
|
81
82
|
},
|
|
82
83
|
assistantText,
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
export function applySessionUrlTemplate(payload: NotificationPayload, config: NotifyConfig): NotificationPayload {
|
|
88
|
+
const sessionUrl = resolveSessionUrl(config.sessionUrlTemplate, payload.metadata.sessionId);
|
|
89
|
+
if (!sessionUrl) {
|
|
90
|
+
return payload;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
...payload,
|
|
95
|
+
metadata: {
|
|
96
|
+
...payload.metadata,
|
|
97
|
+
sessionUrl,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
function describeError(error: unknown): string {
|
|
87
103
|
return error instanceof Error ? error.message : String(error);
|
|
88
104
|
}
|
|
@@ -122,11 +138,12 @@ export class PiNotifyController {
|
|
|
122
138
|
return;
|
|
123
139
|
}
|
|
124
140
|
|
|
141
|
+
const payloadWithSessionUrl = applySessionUrlTemplate(payload, configResult.config);
|
|
125
142
|
this.lastConfigWarning = null;
|
|
126
143
|
const job = this.startNewJob();
|
|
127
144
|
|
|
128
145
|
if (!ctx.hasUI) {
|
|
129
|
-
this.scheduleBackgroundSend(job, ctx, configResult.config,
|
|
146
|
+
this.scheduleBackgroundSend(job, ctx, configResult.config, payloadWithSessionUrl);
|
|
130
147
|
return;
|
|
131
148
|
}
|
|
132
149
|
|
|
@@ -144,7 +161,7 @@ export class PiNotifyController {
|
|
|
144
161
|
|
|
145
162
|
this.finishJob(job.id);
|
|
146
163
|
if (decision === "send" || decision === "timeout") {
|
|
147
|
-
await this.deliver(configResult.config,
|
|
164
|
+
await this.deliver(configResult.config, payloadWithSessionUrl, ctx);
|
|
148
165
|
}
|
|
149
166
|
} catch (error) {
|
|
150
167
|
if (!this.isActive(job.id)) {
|
|
@@ -152,7 +169,7 @@ export class PiNotifyController {
|
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
this.notify(ctx, `pi-notify: overlay unavailable, sending automatically in ${Math.ceil(this.delayMs / 1000)}s.`, "warning");
|
|
155
|
-
this.scheduleBackgroundSend(job, ctx, configResult.config,
|
|
172
|
+
this.scheduleBackgroundSend(job, ctx, configResult.config, payloadWithSessionUrl);
|
|
156
173
|
const description = describeError(error);
|
|
157
174
|
if (description) {
|
|
158
175
|
this.notify(ctx, `pi-notify: overlay error: ${description}`, "warning");
|
package/src/format.ts
CHANGED
|
@@ -10,7 +10,7 @@ function normalizeAssistantText(text: string): string {
|
|
|
10
10
|
return normalized.length > 0 ? normalized : EMPTY_ASSISTANT_MESSAGE;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function
|
|
13
|
+
function baseMetadataLines(metadata: NotificationMetadata): string[] {
|
|
14
14
|
return [
|
|
15
15
|
`Project: ${metadata.project}`,
|
|
16
16
|
`CWD: ${metadata.cwd}`,
|
|
@@ -19,6 +19,33 @@ function metadataLines(metadata: NotificationMetadata): string[] {
|
|
|
19
19
|
];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function plainMetadataLines(metadata: NotificationMetadata): string[] {
|
|
23
|
+
return [
|
|
24
|
+
...baseMetadataLines(metadata),
|
|
25
|
+
...(metadata.sessionUrl ? [`Session: ${metadata.sessionUrl}`] : []),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function escapeMarkdownV2LinkUrl(url: string): string {
|
|
30
|
+
return url.replace(/\\/g, "\\\\").replace(/\)/g, "\\)");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function markdownSessionLine(metadata: NotificationMetadata): string | undefined {
|
|
34
|
+
if (!metadata.sessionUrl) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return `Session: [Open session](${escapeMarkdownV2LinkUrl(metadata.sessionUrl)})`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function markdownMetadataLines(metadata: NotificationMetadata): string[] {
|
|
42
|
+
const sessionLine = markdownSessionLine(metadata);
|
|
43
|
+
return [
|
|
44
|
+
...baseMetadataLines(metadata).map((line) => escapeMarkdownV2(line)),
|
|
45
|
+
...(sessionLine ? [sessionLine] : []),
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
export function escapeMarkdownV2(text: string): string {
|
|
23
50
|
return text.replace(MARKDOWN_V2_SPECIALS, (char) => `\\${char}`);
|
|
24
51
|
}
|
|
@@ -26,7 +53,7 @@ export function escapeMarkdownV2(text: string): string {
|
|
|
26
53
|
export function buildPlainTextMessage(payload: NotificationPayload): string {
|
|
27
54
|
return [
|
|
28
55
|
"Pi finished",
|
|
29
|
-
...
|
|
56
|
+
...plainMetadataLines(payload.metadata),
|
|
30
57
|
"",
|
|
31
58
|
normalizeAssistantText(payload.assistantText),
|
|
32
59
|
].join("\n");
|
|
@@ -36,7 +63,7 @@ export function buildMarkdownMessage(payload: NotificationPayload): string {
|
|
|
36
63
|
const assistantText = escapeMarkdownV2(normalizeAssistantText(payload.assistantText));
|
|
37
64
|
const metadata = [
|
|
38
65
|
"*Pi finished*",
|
|
39
|
-
...
|
|
66
|
+
...markdownMetadataLines(payload.metadata),
|
|
40
67
|
"",
|
|
41
68
|
assistantText,
|
|
42
69
|
];
|
|
@@ -47,7 +74,7 @@ export function buildMarkdownMessage(payload: NotificationPayload): string {
|
|
|
47
74
|
export function buildLongOutputPlainTextNotice(payload: NotificationPayload): string {
|
|
48
75
|
return [
|
|
49
76
|
"Pi finished",
|
|
50
|
-
...
|
|
77
|
+
...plainMetadataLines(payload.metadata),
|
|
51
78
|
"",
|
|
52
79
|
"Full output attached as pi-notify-output.md",
|
|
53
80
|
].join("\n");
|
|
@@ -56,7 +83,7 @@ export function buildLongOutputPlainTextNotice(payload: NotificationPayload): st
|
|
|
56
83
|
export function buildLongOutputMarkdownNotice(payload: NotificationPayload): string {
|
|
57
84
|
return [
|
|
58
85
|
"*Pi finished*",
|
|
59
|
-
...
|
|
86
|
+
...markdownMetadataLines(payload.metadata),
|
|
60
87
|
"",
|
|
61
88
|
escapeMarkdownV2("Full output attached as pi-notify-output.md"),
|
|
62
89
|
].join("\n");
|
|
@@ -69,6 +96,7 @@ export function buildAttachmentFilename(metadata: NotificationMetadata): string
|
|
|
69
96
|
|
|
70
97
|
export function buildAttachmentMarkdown(payload: NotificationPayload): string {
|
|
71
98
|
const modelLine = payload.metadata.model ? `- Model: ${payload.metadata.model}` : undefined;
|
|
99
|
+
const sessionLine = payload.metadata.sessionUrl ? `- Session: ${payload.metadata.sessionUrl}` : undefined;
|
|
72
100
|
|
|
73
101
|
return [
|
|
74
102
|
"# Pi finished",
|
|
@@ -77,6 +105,7 @@ export function buildAttachmentMarkdown(payload: NotificationPayload): string {
|
|
|
77
105
|
`- CWD: ${payload.metadata.cwd}`,
|
|
78
106
|
`- Time: ${payload.metadata.timestamp}`,
|
|
79
107
|
...(modelLine ? [modelLine] : []),
|
|
108
|
+
...(sessionLine ? [sessionLine] : []),
|
|
80
109
|
"",
|
|
81
110
|
"## Assistant output",
|
|
82
111
|
"",
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,84 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
getNotifySessionUrlTemplate,
|
|
5
|
+
NOTIFY_CONFIG_PATH,
|
|
6
|
+
setNotifySessionUrlTemplate,
|
|
7
|
+
} from "./config.js";
|
|
3
8
|
import { PiNotifyController } from "./controller.js";
|
|
4
9
|
|
|
5
|
-
export
|
|
10
|
+
export interface RegisterPiNotifyOptions {
|
|
11
|
+
configPath?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CLEAR_URL_TEMPLATE_ARGS = new Set(["clear", "disable", "disabled", "none", "off"]);
|
|
15
|
+
|
|
16
|
+
function describeError(error: unknown): string {
|
|
17
|
+
return error instanceof Error ? error.message : String(error);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function notify(ctx: Pick<ExtensionCommandContext, "hasUI" | "ui">, message: string, type: "info" | "warning" | "error"): void {
|
|
21
|
+
if (ctx.hasUI) {
|
|
22
|
+
ctx.ui.notify(message, type);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function handlePiNotifyUrlCommand(
|
|
27
|
+
args: string,
|
|
28
|
+
ctx: ExtensionCommandContext,
|
|
29
|
+
configPath = NOTIFY_CONFIG_PATH,
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
const trimmedArgs = args.trim();
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (!trimmedArgs) {
|
|
35
|
+
const currentTemplate = await getNotifySessionUrlTemplate(configPath);
|
|
36
|
+
if (currentTemplate) {
|
|
37
|
+
notify(ctx, `pi-notify: current session URL template is ${currentTemplate}`, "info");
|
|
38
|
+
} else {
|
|
39
|
+
notify(ctx, "pi-notify: session URL template is not set.", "info");
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (CLEAR_URL_TEMPLATE_ARGS.has(trimmedArgs.toLowerCase())) {
|
|
45
|
+
await setNotifySessionUrlTemplate(undefined, configPath);
|
|
46
|
+
notify(ctx, `pi-notify: cleared session URL template in ${configPath}.`, "info");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!trimmedArgs.includes("SESSION_ID")) {
|
|
51
|
+
notify(
|
|
52
|
+
ctx,
|
|
53
|
+
"pi-notify: URL template must include SESSION_ID. Example: /pi-notify-url https://archi.example/#SESSION_ID",
|
|
54
|
+
"warning",
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await setNotifySessionUrlTemplate(trimmedArgs, configPath);
|
|
60
|
+
notify(ctx, `pi-notify: saved session URL template to ${configPath}.`, "info");
|
|
61
|
+
} catch (error) {
|
|
62
|
+
notify(ctx, `pi-notify: failed to update session URL template: ${describeError(error)}`, "warning");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default function registerPiNotify(pi: ExtensionAPI, options: RegisterPiNotifyOptions = {}): void {
|
|
67
|
+
const configPath = options.configPath ?? NOTIFY_CONFIG_PATH;
|
|
6
68
|
const controller = new PiNotifyController();
|
|
7
69
|
|
|
70
|
+
pi.registerCommand("pi-notify-url", {
|
|
71
|
+
description: "Set or clear the session URL template used in Telegram notifications",
|
|
72
|
+
getArgumentCompletions: (prefix) => {
|
|
73
|
+
const suggestions = ["off", "clear"];
|
|
74
|
+
const filtered = suggestions.filter((value) => value.startsWith(prefix));
|
|
75
|
+
return filtered.length > 0 ? filtered.map((value) => ({ value, label: value })) : null;
|
|
76
|
+
},
|
|
77
|
+
handler: async (args, ctx) => {
|
|
78
|
+
await handlePiNotifyUrlCommand(args, ctx, configPath);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
8
82
|
pi.on("agent_end", async (event, ctx) => {
|
|
9
83
|
await controller.handleAgentEnd(event.messages, ctx);
|
|
10
84
|
});
|
package/src/types.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export interface NotifyConfig {
|
|
2
2
|
botToken: string;
|
|
3
3
|
chatId: string;
|
|
4
|
+
sessionUrlTemplate?: string;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
export interface NotificationMetadata {
|
|
7
8
|
project: string;
|
|
8
9
|
cwd: string;
|
|
9
10
|
timestamp: string;
|
|
11
|
+
sessionId: string;
|
|
10
12
|
model?: string;
|
|
13
|
+
sessionUrl?: string;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export interface NotificationPayload {
|