pi-protonmail 0.1.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/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/biome.json +25 -0
- package/package.json +63 -0
- package/src/constants.ts +1 -0
- package/src/hub.ts +559 -0
- package/src/index.ts +7 -0
- package/src/proton-bridge.ts +444 -0
- package/src/protonmail.ts +624 -0
- package/src/secret-refs.ts +81 -0
- package/src/types.ts +90 -0
- package/src/workspace.ts +96 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export interface ProtonBridgeConfig {
|
|
4
|
+
host: string;
|
|
5
|
+
imapPort: number;
|
|
6
|
+
smtpPort: number;
|
|
7
|
+
username?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
security: string;
|
|
10
|
+
defaultMailbox?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ProtonMailProfilePolicy {
|
|
14
|
+
default_mailbox?: string;
|
|
15
|
+
mailbox_filter?: string;
|
|
16
|
+
default_period?: string;
|
|
17
|
+
import_workspace_root?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ProtonMailWorkspaceConfig {
|
|
21
|
+
activeProfile?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ProtonMailWorkingProfile {
|
|
25
|
+
profile: string;
|
|
26
|
+
policy: ProtonMailProfilePolicy;
|
|
27
|
+
policyPath: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface BridgeStatusResult {
|
|
31
|
+
config: {
|
|
32
|
+
host: string;
|
|
33
|
+
imap_port: number;
|
|
34
|
+
smtp_port: number;
|
|
35
|
+
security: string;
|
|
36
|
+
default_mailbox?: string;
|
|
37
|
+
username_set: boolean;
|
|
38
|
+
password_set: boolean;
|
|
39
|
+
};
|
|
40
|
+
imap: { open: boolean; banner?: string; error?: string };
|
|
41
|
+
smtp: { open: boolean; banner?: string; error?: string };
|
|
42
|
+
login?: {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
mailbox_count?: number;
|
|
45
|
+
mailboxes?: Array<{ name: string }>;
|
|
46
|
+
error?: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface MailboxInfo {
|
|
51
|
+
name: string;
|
|
52
|
+
raw?: string;
|
|
53
|
+
flags?: string[];
|
|
54
|
+
delimiter?: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface MessageAttachmentInfo {
|
|
58
|
+
filename: string;
|
|
59
|
+
content_type?: string;
|
|
60
|
+
size?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface MessageInfo {
|
|
64
|
+
uid: string;
|
|
65
|
+
message_id?: string;
|
|
66
|
+
from?: string;
|
|
67
|
+
subject?: string;
|
|
68
|
+
date?: string;
|
|
69
|
+
attachments: MessageAttachmentInfo[];
|
|
70
|
+
attachment_count: number;
|
|
71
|
+
raw_size?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface MailboxListResult {
|
|
75
|
+
mailboxes: MailboxInfo[];
|
|
76
|
+
count: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface MessageListResult {
|
|
80
|
+
mailbox: string;
|
|
81
|
+
count: number;
|
|
82
|
+
messages: MessageInfo[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type CommandContext = Pick<ExtensionCommandContext, "cwd" | "hasUI" | "ui">;
|
|
86
|
+
|
|
87
|
+
export interface ToolContext {
|
|
88
|
+
cwd: string;
|
|
89
|
+
signal?: AbortSignal;
|
|
90
|
+
}
|
package/src/workspace.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { ProtonMailProfilePolicy, ProtonMailWorkspaceConfig } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
export function normalizeProtonMailProfile(profile?: string): string {
|
|
7
|
+
const normalized = (profile ?? "default")
|
|
8
|
+
.trim()
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
11
|
+
.replace(/(^-|-$)/g, "");
|
|
12
|
+
return normalized || "default";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function protonMailWorkspaceRoot(baseDir = ""): string {
|
|
16
|
+
return join(baseDir, ".pi", "protonmail");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function protonMailConfigPath(baseDir = ""): string {
|
|
20
|
+
return join(protonMailWorkspaceRoot(baseDir), "config.json");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function protonMailProfilesRoot(baseDir = ""): string {
|
|
24
|
+
return join(protonMailWorkspaceRoot(baseDir), "profiles");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function protonMailProfileDir(profile: string, baseDir = ""): string {
|
|
28
|
+
return join(protonMailProfilesRoot(baseDir), normalizeProtonMailProfile(profile));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function protonMailProfilePolicyPath(profile: string, baseDir = ""): string {
|
|
32
|
+
return join(protonMailProfileDir(profile, baseDir), "policy.json");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function readJsonObject<T>(path: string): Promise<T | undefined> {
|
|
36
|
+
try {
|
|
37
|
+
const text = await fs.readFile(path, "utf8");
|
|
38
|
+
return JSON.parse(text) as T;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if ((error as { code?: string }).code === "ENOENT") return undefined;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function writeJsonObject(path: string, value: unknown): Promise<string> {
|
|
46
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
47
|
+
await fs.writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
48
|
+
return path;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function readProtonMailWorkspaceConfig(
|
|
52
|
+
cwd: string,
|
|
53
|
+
): Promise<ProtonMailWorkspaceConfig> {
|
|
54
|
+
return (await readJsonObject<ProtonMailWorkspaceConfig>(protonMailConfigPath(cwd))) ?? {};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function writeProtonMailWorkspaceConfig(
|
|
58
|
+
cwd: string,
|
|
59
|
+
config: ProtonMailWorkspaceConfig,
|
|
60
|
+
): Promise<string> {
|
|
61
|
+
return writeJsonObject(protonMailConfigPath(cwd), config);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function listProtonMailProfiles(cwd: string): Promise<string[]> {
|
|
65
|
+
try {
|
|
66
|
+
const entries = await fs.readdir(protonMailProfilesRoot(cwd), { withFileTypes: true });
|
|
67
|
+
return entries
|
|
68
|
+
.filter((entry) => entry.isDirectory())
|
|
69
|
+
.map((entry) => entry.name)
|
|
70
|
+
.sort();
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if ((error as { code?: string }).code === "ENOENT") return [];
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function readProtonMailProfilePolicy(
|
|
78
|
+
cwd: string,
|
|
79
|
+
profile: string,
|
|
80
|
+
): Promise<ProtonMailProfilePolicy> {
|
|
81
|
+
return (
|
|
82
|
+
(await readJsonObject<ProtonMailProfilePolicy>(protonMailProfilePolicyPath(profile, cwd))) ?? {}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function writeProtonMailProfilePolicy(
|
|
87
|
+
cwd: string,
|
|
88
|
+
profile: string,
|
|
89
|
+
policy: ProtonMailProfilePolicy,
|
|
90
|
+
): Promise<string> {
|
|
91
|
+
return writeJsonObject(protonMailProfilePolicyPath(profile, cwd), policy);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function deleteProtonMailProfile(cwd: string, profile: string): Promise<void> {
|
|
95
|
+
await fs.rm(protonMailProfileDir(profile, cwd), { recursive: true, force: true });
|
|
96
|
+
}
|