@atomicmail/agent-skill-openclaw 0.3.24
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/LICENSE +21 -0
- package/README.md +182 -0
- package/SKILL.md +206 -0
- package/esm/_dnt.polyfills.d.ts +101 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +127 -0
- package/esm/lib/agent/auth/agent-auth-http.d.ts +26 -0
- package/esm/lib/agent/auth/agent-auth-http.d.ts.map +1 -0
- package/esm/lib/agent/auth/agent-auth-http.js +85 -0
- package/esm/lib/agent/auth/agent-jwt.d.ts +12 -0
- package/esm/lib/agent/auth/agent-jwt.d.ts.map +1 -0
- package/esm/lib/agent/auth/agent-jwt.js +27 -0
- package/esm/lib/agent/auth/agent-pow.d.ts +5 -0
- package/esm/lib/agent/auth/agent-pow.d.ts.map +1 -0
- package/esm/lib/agent/auth/agent-pow.js +49 -0
- package/esm/lib/agent/jmap/agent-help-content.d.ts +2 -0
- package/esm/lib/agent/jmap/agent-help-content.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-help-content.js +2 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-limits.d.ts +27 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-limits.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-limits.js +166 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-upload.d.ts +24 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-upload.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap-blob-upload.js +104 -0
- package/esm/lib/agent/jmap/agent-jmap-email-charset.d.ts +8 -0
- package/esm/lib/agent/jmap/agent-jmap-email-charset.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap-email-charset.js +61 -0
- package/esm/lib/agent/jmap/agent-jmap-run.d.ts +52 -0
- package/esm/lib/agent/jmap/agent-jmap-run.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap-run.js +260 -0
- package/esm/lib/agent/jmap/agent-jmap-verify.d.ts +9 -0
- package/esm/lib/agent/jmap/agent-jmap-verify.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap-verify.js +50 -0
- package/esm/lib/agent/jmap/agent-jmap.d.ts +89 -0
- package/esm/lib/agent/jmap/agent-jmap.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-jmap.js +373 -0
- package/esm/lib/agent/jmap/agent-vars.d.ts +30 -0
- package/esm/lib/agent/jmap/agent-vars.d.ts.map +1 -0
- package/esm/lib/agent/jmap/agent-vars.js +96 -0
- package/esm/lib/agent/jmap/help-content/auth.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/auth.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/auth.js +33 -0
- package/esm/lib/agent/jmap/help-content/cron.d.ts +6 -0
- package/esm/lib/agent/jmap/help-content/cron.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/cron.js +159 -0
- package/esm/lib/agent/jmap/help-content/index.d.ts +6 -0
- package/esm/lib/agent/jmap/help-content/index.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/index.js +61 -0
- package/esm/lib/agent/jmap/help-content/installation.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/installation.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/installation.js +47 -0
- package/esm/lib/agent/jmap/help-content/jmap-cheatsheet.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/jmap-cheatsheet.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/jmap-cheatsheet.js +230 -0
- package/esm/lib/agent/jmap/help-content/multi-account.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/multi-account.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/multi-account.js +49 -0
- package/esm/lib/agent/jmap/help-content/overview.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/overview.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/overview.js +49 -0
- package/esm/lib/agent/jmap/help-content/presets.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/presets.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/presets.js +51 -0
- package/esm/lib/agent/jmap/help-content/tools.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/tools.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/tools.js +49 -0
- package/esm/lib/agent/jmap/help-content/troubleshooting.d.ts +2 -0
- package/esm/lib/agent/jmap/help-content/troubleshooting.d.ts.map +1 -0
- package/esm/lib/agent/jmap/help-content/troubleshooting.js +65 -0
- package/esm/lib/agent/session/agent-credentials-store.d.ts +45 -0
- package/esm/lib/agent/session/agent-credentials-store.d.ts.map +1 -0
- package/esm/lib/agent/session/agent-credentials-store.js +121 -0
- package/esm/lib/agent/session/agent-resolve-config.d.ts +29 -0
- package/esm/lib/agent/session/agent-resolve-config.d.ts.map +1 -0
- package/esm/lib/agent/session/agent-resolve-config.js +71 -0
- package/esm/lib/agent/session/agent-session-for-dir.d.ts +8 -0
- package/esm/lib/agent/session/agent-session-for-dir.d.ts.map +1 -0
- package/esm/lib/agent/session/agent-session-for-dir.js +33 -0
- package/esm/lib/agent/session/agent-session.d.ts +89 -0
- package/esm/lib/agent/session/agent-session.d.ts.map +1 -0
- package/esm/lib/agent/session/agent-session.js +320 -0
- package/esm/lib/agent/session/inbox-id-to-mailbox-email.d.ts +6 -0
- package/esm/lib/agent/session/inbox-id-to-mailbox-email.d.ts.map +1 -0
- package/esm/lib/agent/session/inbox-id-to-mailbox-email.js +21 -0
- package/esm/lib/core/consts.d.ts +17 -0
- package/esm/lib/core/consts.d.ts.map +1 -0
- package/esm/lib/core/consts.js +28 -0
- package/esm/lib/core/jmap-hints.d.ts +3 -0
- package/esm/lib/core/jmap-hints.d.ts.map +1 -0
- package/esm/lib/core/jmap-hints.js +6 -0
- package/esm/lib/core/messages.d.ts +6 -0
- package/esm/lib/core/messages.d.ts.map +1 -0
- package/esm/lib/core/messages.js +19 -0
- package/esm/lib/core/read-npm-package-readme.d.ts +6 -0
- package/esm/lib/core/read-npm-package-readme.d.ts.map +1 -0
- package/esm/lib/core/read-npm-package-readme.js +81 -0
- package/esm/lib/core/shared-assets.d.ts +6 -0
- package/esm/lib/core/shared-assets.d.ts.map +1 -0
- package/esm/lib/core/shared-assets.js +46 -0
- package/esm/lib/core/types.d.ts +2 -0
- package/esm/lib/core/types.d.ts.map +1 -0
- package/esm/lib/core/types.js +2 -0
- package/esm/lib/core/utils.d.ts +12 -0
- package/esm/lib/core/utils.d.ts.map +1 -0
- package/esm/lib/core/utils.js +29 -0
- package/esm/lib/integrations/create-agent-session.d.ts +25 -0
- package/esm/lib/integrations/create-agent-session.d.ts.map +1 -0
- package/esm/lib/integrations/create-agent-session.js +36 -0
- package/esm/lib/integrations/key-value-credential-store.d.ts +21 -0
- package/esm/lib/integrations/key-value-credential-store.d.ts.map +1 -0
- package/esm/lib/integrations/key-value-credential-store.js +71 -0
- package/esm/lib/integrations/n8n-credential-store.d.ts +18 -0
- package/esm/lib/integrations/n8n-credential-store.d.ts.map +1 -0
- package/esm/lib/integrations/n8n-credential-store.js +62 -0
- package/esm/lib/mod.d.ts +23 -0
- package/esm/lib/mod.d.ts.map +1 -0
- package/esm/lib/mod.js +22 -0
- package/esm/lib/network/auth-client.d.ts +57 -0
- package/esm/lib/network/auth-client.d.ts.map +1 -0
- package/esm/lib/network/auth-client.js +210 -0
- package/esm/package.json +3 -0
- package/esm/skill/cli.d.ts +3 -0
- package/esm/skill/cli.d.ts.map +1 -0
- package/esm/skill/cli.js +321 -0
- package/package.json +45 -0
- package/presets/list_inbox.json +46 -0
- package/presets/reply.json +97 -0
- package/presets/send_mail.json +70 -0
- package/presets/send_mail_attachment.json +92 -0
- package/presets/send_mail_blob_attachment.json +74 -0
- package/shared/consts.json +11 -0
- package/shared/fixtures/pow_vectors.json +32 -0
- package/shared/help/fragments/inbox_cron_agent_prompt.md +1 -0
- package/shared/help/fragments/post_register_cron_reminder.md +5 -0
- package/shared/help/readme_stub.md +3 -0
- package/shared/help/topics/auth.md +8 -0
- package/shared/help/topics/cron.md +217 -0
- package/shared/help/topics/installation.md +35 -0
- package/shared/help/topics/jmap_cheatsheet.md +19 -0
- package/shared/help/topics/multi_account.md +9 -0
- package/shared/help/topics/overview.md +27 -0
- package/shared/help/topics/presets.md +12 -0
- package/shared/help/topics/tools.md +16 -0
- package/shared/help/topics/troubleshooting.md +6 -0
- package/shared/manifest.json +31 -0
- package/shared/messages/errors.json +68 -0
- package/shared/messages/hints.json +8 -0
- package/shared/presets/list_inbox.json +46 -0
- package/shared/presets/reply.json +97 -0
- package/shared/presets/send_mail.json +70 -0
- package/shared/presets/send_mail_attachment.json +92 -0
- package/shared/presets/send_mail_blob_attachment.json +74 -0
- package/shared/skill/SKILL.template.md +202 -0
- package/shared/skill/manifest.json +89 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type CredentialStore, type SkillFiles } from "./agent-credentials-store.js";
|
|
2
|
+
import type { JmapBlobUploadLimits } from "../jmap/agent-jmap-blob-limits.js";
|
|
3
|
+
export interface AgentSessionConfig {
|
|
4
|
+
authUrl: string;
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
scryptSalt: string;
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
inboxId?: string;
|
|
9
|
+
credentialDir: string;
|
|
10
|
+
files?: SkillFiles;
|
|
11
|
+
store?: CredentialStore;
|
|
12
|
+
}
|
|
13
|
+
export interface RegisterResult {
|
|
14
|
+
inbox: string;
|
|
15
|
+
accountId: string;
|
|
16
|
+
/** Present only on first-time signup (not idempotent replay). */
|
|
17
|
+
apiKey?: string;
|
|
18
|
+
idempotent?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface RegisterOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Allows replacing credentials in the current credential directory when the
|
|
23
|
+
* requested username differs from the stored inbox local-part.
|
|
24
|
+
*/
|
|
25
|
+
forced?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Local-part of an inbox email, or the whole string if no @. */
|
|
28
|
+
export declare function inboxLocalPart(inboxId: string): string;
|
|
29
|
+
export declare class AgentSession {
|
|
30
|
+
private readonly authUrl;
|
|
31
|
+
readonly apiUrl: string;
|
|
32
|
+
private readonly scryptSalt;
|
|
33
|
+
private apiKey;
|
|
34
|
+
private inboxId;
|
|
35
|
+
readonly credentialDir: string;
|
|
36
|
+
readonly files: SkillFiles | undefined;
|
|
37
|
+
private readonly store;
|
|
38
|
+
private sessionJWT;
|
|
39
|
+
private capabilityJWT;
|
|
40
|
+
private cachedMailAccountId;
|
|
41
|
+
private cachedUploadUrl;
|
|
42
|
+
private cachedDownloadUrl;
|
|
43
|
+
/** RFC 8620 Session `apiUrl` (POST target); from `/.well-known/jmap`. */
|
|
44
|
+
private cachedJmapPostUrl;
|
|
45
|
+
/** Last successful GET /.well-known/jmap JSON (for RFC 9404 blob limits). */
|
|
46
|
+
private cachedJmapSession;
|
|
47
|
+
constructor(cfg: AgentSessionConfig);
|
|
48
|
+
static create(cfg: AgentSessionConfig): Promise<AgentSession>;
|
|
49
|
+
get hasApiKey(): boolean;
|
|
50
|
+
get currentInboxId(): string | undefined;
|
|
51
|
+
get currentUploadUrl(): string | undefined;
|
|
52
|
+
get currentDownloadUrl(): string | undefined;
|
|
53
|
+
private loadFromStore;
|
|
54
|
+
private currentCredentialArtifacts;
|
|
55
|
+
/**
|
|
56
|
+
* Primary JMAP mail accountId from GET /.well-known/jmap (cached).
|
|
57
|
+
*/
|
|
58
|
+
getPrimaryMailAccountId(): Promise<string>;
|
|
59
|
+
invalidateJmapSessionCache(): void;
|
|
60
|
+
private refreshJmapSessionData;
|
|
61
|
+
/**
|
|
62
|
+
* Full URL for JMAP `POST` batches (RFC 8620 Session `apiUrl` from
|
|
63
|
+
* `GET /.well-known/jmap`).
|
|
64
|
+
*/
|
|
65
|
+
getJmapPostUrl(): Promise<string>;
|
|
66
|
+
getBlobUploadLimitsForAccount(accountId: string): Promise<JmapBlobUploadLimits | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Register or return existing inbox when username matches (idempotent).
|
|
69
|
+
* Different username requires explicit force to replace credentials and
|
|
70
|
+
* create a new inbox.
|
|
71
|
+
*/
|
|
72
|
+
register(username: string, options?: RegisterOptions): Promise<RegisterResult>;
|
|
73
|
+
getCapabilityToken(): Promise<string>;
|
|
74
|
+
private ensureSession;
|
|
75
|
+
destroy(): void;
|
|
76
|
+
}
|
|
77
|
+
export interface PersistLoginWithApiKeyInput {
|
|
78
|
+
authUrl: string;
|
|
79
|
+
apiUrl: string;
|
|
80
|
+
scryptSalt: string;
|
|
81
|
+
apiKey: string;
|
|
82
|
+
files: SkillFiles;
|
|
83
|
+
onPowProgress?: (nonce: bigint) => void;
|
|
84
|
+
}
|
|
85
|
+
/** PoW login with an existing API key; writes credentials + JWT files. */
|
|
86
|
+
export declare function persistLoginWithApiKey(input: PersistLoginWithApiKeyInput): Promise<{
|
|
87
|
+
inboxId: string;
|
|
88
|
+
}>;
|
|
89
|
+
//# sourceMappingURL=agent-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/session/agent-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,UAAU,EAGhB,MAAM,8BAA8B,CAAC;AAOtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAa9E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IAExC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,yEAAyE;IACzE,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,6EAA6E;IAC7E,OAAO,CAAC,iBAAiB,CAAsC;gBAEnD,GAAG,EAAE,kBAAkB;WActB,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAMnE,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED,IAAI,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED,IAAI,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAE3C;YAEa,aAAa;IAa3B,OAAO,CAAC,0BAA0B;IA2BlC;;OAEG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBhD,0BAA0B,IAAI,IAAI;YAQpB,sBAAsB;IAWpC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAWjC,6BAA6B,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAUvC;;;;OAIG;IACG,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC;IAgGpB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;YA4B7B,aAAa;IA6B3B,OAAO,IAAI,IAAI;CAGhB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,0EAA0E;AAC1E,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA6B9B"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// Stateful PoW + capability JWT + optional cached JMAP session (accountId).
|
|
2
|
+
import { FilesystemCredentialStore, writeCredentials, writeJwtFile, } from "./agent-credentials-store.js";
|
|
3
|
+
import { CAPABILITY_SAFETY_MARGIN_MS, decodeJwtPayload, isJwtExpired, SESSION_SAFETY_MARGIN_MS, } from "../auth/agent-jwt.js";
|
|
4
|
+
import { extractBlobEndpoints, extractBlobUploadLimits, extractJmapApiUrl, extractPrimaryMailAccountId, fetchJmapWellKnown, } from "../jmap/agent-jmap-run.js";
|
|
5
|
+
import { fetchCapability, performPoWAndSession, } from "../auth/agent-auth-http.js";
|
|
6
|
+
function normalizeUsername(u) {
|
|
7
|
+
return u.trim().toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
/** Local-part of an inbox email, or the whole string if no @. */
|
|
10
|
+
export function inboxLocalPart(inboxId) {
|
|
11
|
+
const i = inboxId.indexOf("@");
|
|
12
|
+
return i === -1
|
|
13
|
+
? normalizeUsername(inboxId)
|
|
14
|
+
: normalizeUsername(inboxId.slice(0, i));
|
|
15
|
+
}
|
|
16
|
+
export class AgentSession {
|
|
17
|
+
authUrl;
|
|
18
|
+
apiUrl;
|
|
19
|
+
scryptSalt;
|
|
20
|
+
apiKey;
|
|
21
|
+
inboxId;
|
|
22
|
+
credentialDir;
|
|
23
|
+
files;
|
|
24
|
+
store;
|
|
25
|
+
sessionJWT;
|
|
26
|
+
capabilityJWT;
|
|
27
|
+
cachedMailAccountId;
|
|
28
|
+
cachedUploadUrl;
|
|
29
|
+
cachedDownloadUrl;
|
|
30
|
+
/** RFC 8620 Session `apiUrl` (POST target); from `/.well-known/jmap`. */
|
|
31
|
+
cachedJmapPostUrl;
|
|
32
|
+
/** Last successful GET /.well-known/jmap JSON (for RFC 9404 blob limits). */
|
|
33
|
+
cachedJmapSession;
|
|
34
|
+
constructor(cfg) {
|
|
35
|
+
this.authUrl = cfg.authUrl.replace(/\/+$/, "");
|
|
36
|
+
this.apiUrl = cfg.apiUrl.replace(/\/+$/, "");
|
|
37
|
+
this.scryptSalt = cfg.scryptSalt;
|
|
38
|
+
this.apiKey = cfg.apiKey;
|
|
39
|
+
this.inboxId = cfg.inboxId;
|
|
40
|
+
this.credentialDir = cfg.credentialDir;
|
|
41
|
+
this.store = cfg.store ??
|
|
42
|
+
(cfg.files ? new FilesystemCredentialStore(cfg.files) : (() => {
|
|
43
|
+
throw new Error("AgentSessionConfig requires either store or files.");
|
|
44
|
+
})());
|
|
45
|
+
this.files = cfg.files;
|
|
46
|
+
}
|
|
47
|
+
static async create(cfg) {
|
|
48
|
+
const session = new AgentSession(cfg);
|
|
49
|
+
await session.loadFromStore();
|
|
50
|
+
return session;
|
|
51
|
+
}
|
|
52
|
+
get hasApiKey() {
|
|
53
|
+
return this.apiKey !== undefined && this.apiKey.length > 0;
|
|
54
|
+
}
|
|
55
|
+
get currentInboxId() {
|
|
56
|
+
return this.inboxId;
|
|
57
|
+
}
|
|
58
|
+
get currentUploadUrl() {
|
|
59
|
+
return this.cachedUploadUrl;
|
|
60
|
+
}
|
|
61
|
+
get currentDownloadUrl() {
|
|
62
|
+
return this.cachedDownloadUrl;
|
|
63
|
+
}
|
|
64
|
+
async loadFromStore() {
|
|
65
|
+
const loaded = await this.store.load();
|
|
66
|
+
this.sessionJWT = loaded.sessionJwt;
|
|
67
|
+
this.capabilityJWT = loaded.capabilityJwt;
|
|
68
|
+
const disk = loaded.credentials;
|
|
69
|
+
if (disk) {
|
|
70
|
+
this.apiKey = this.apiKey ?? disk.apiKey;
|
|
71
|
+
this.inboxId = this.inboxId ?? disk.inboxId;
|
|
72
|
+
this.cachedUploadUrl = disk.uploadUrl;
|
|
73
|
+
this.cachedDownloadUrl = disk.downloadUrl;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
currentCredentialArtifacts() {
|
|
77
|
+
const artifacts = {};
|
|
78
|
+
if (this.apiKey &&
|
|
79
|
+
this.inboxId &&
|
|
80
|
+
this.cachedUploadUrl &&
|
|
81
|
+
this.cachedDownloadUrl) {
|
|
82
|
+
artifacts.credentials = {
|
|
83
|
+
apiKey: this.apiKey,
|
|
84
|
+
inboxId: this.inboxId,
|
|
85
|
+
authUrl: this.authUrl,
|
|
86
|
+
apiUrl: this.apiUrl,
|
|
87
|
+
scryptSalt: this.scryptSalt,
|
|
88
|
+
uploadUrl: this.cachedUploadUrl,
|
|
89
|
+
downloadUrl: this.cachedDownloadUrl,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (this.sessionJWT !== undefined) {
|
|
93
|
+
artifacts.sessionJwt = this.sessionJWT;
|
|
94
|
+
}
|
|
95
|
+
if (this.capabilityJWT !== undefined) {
|
|
96
|
+
artifacts.capabilityJwt = this.capabilityJWT;
|
|
97
|
+
}
|
|
98
|
+
return artifacts;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Primary JMAP mail accountId from GET /.well-known/jmap (cached).
|
|
102
|
+
*/
|
|
103
|
+
async getPrimaryMailAccountId() {
|
|
104
|
+
if (this.cachedMailAccountId &&
|
|
105
|
+
this.cachedUploadUrl &&
|
|
106
|
+
this.cachedDownloadUrl &&
|
|
107
|
+
this.cachedJmapPostUrl &&
|
|
108
|
+
this.cachedJmapSession) {
|
|
109
|
+
return this.cachedMailAccountId;
|
|
110
|
+
}
|
|
111
|
+
await this.refreshJmapSessionData();
|
|
112
|
+
if (!this.cachedMailAccountId) {
|
|
113
|
+
throw new Error("JMAP session missing primary mail account id.");
|
|
114
|
+
}
|
|
115
|
+
return this.cachedMailAccountId;
|
|
116
|
+
}
|
|
117
|
+
invalidateJmapSessionCache() {
|
|
118
|
+
this.cachedMailAccountId = undefined;
|
|
119
|
+
this.cachedUploadUrl = undefined;
|
|
120
|
+
this.cachedDownloadUrl = undefined;
|
|
121
|
+
this.cachedJmapPostUrl = undefined;
|
|
122
|
+
this.cachedJmapSession = undefined;
|
|
123
|
+
}
|
|
124
|
+
async refreshJmapSessionData() {
|
|
125
|
+
const cap = await this.getCapabilityToken();
|
|
126
|
+
const session = await fetchJmapWellKnown(this.apiUrl, cap);
|
|
127
|
+
this.cachedJmapSession = session;
|
|
128
|
+
this.cachedMailAccountId = extractPrimaryMailAccountId(session);
|
|
129
|
+
const blobs = extractBlobEndpoints(session);
|
|
130
|
+
this.cachedUploadUrl = blobs.uploadUrl;
|
|
131
|
+
this.cachedDownloadUrl = blobs.downloadUrl;
|
|
132
|
+
this.cachedJmapPostUrl = extractJmapApiUrl(session);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Full URL for JMAP `POST` batches (RFC 8620 Session `apiUrl` from
|
|
136
|
+
* `GET /.well-known/jmap`).
|
|
137
|
+
*/
|
|
138
|
+
async getJmapPostUrl() {
|
|
139
|
+
if (this.cachedJmapPostUrl && this.cachedJmapSession) {
|
|
140
|
+
return this.cachedJmapPostUrl;
|
|
141
|
+
}
|
|
142
|
+
await this.refreshJmapSessionData();
|
|
143
|
+
if (!this.cachedJmapPostUrl) {
|
|
144
|
+
throw new Error("JMAP session missing apiUrl.");
|
|
145
|
+
}
|
|
146
|
+
return this.cachedJmapPostUrl;
|
|
147
|
+
}
|
|
148
|
+
async getBlobUploadLimitsForAccount(accountId) {
|
|
149
|
+
if (!this.cachedJmapSession) {
|
|
150
|
+
await this.refreshJmapSessionData();
|
|
151
|
+
}
|
|
152
|
+
if (!this.cachedJmapSession) {
|
|
153
|
+
throw new Error("JMAP session cache missing after refresh.");
|
|
154
|
+
}
|
|
155
|
+
return extractBlobUploadLimits(this.cachedJmapSession, accountId);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Register or return existing inbox when username matches (idempotent).
|
|
159
|
+
* Different username requires explicit force to replace credentials and
|
|
160
|
+
* create a new inbox.
|
|
161
|
+
*/
|
|
162
|
+
async register(username, options = {}) {
|
|
163
|
+
const want = normalizeUsername(username);
|
|
164
|
+
if (want.length < 5 || want.length > 21) {
|
|
165
|
+
throw new Error("Username must be 5–21 characters.");
|
|
166
|
+
}
|
|
167
|
+
if (this.hasApiKey && !this.inboxId) {
|
|
168
|
+
throw new Error("Cannot register: an API key is configured but inboxId is unknown. " +
|
|
169
|
+
"Fix credentials.json or unset ATOMIC_MAIL_API_KEY before registering.");
|
|
170
|
+
}
|
|
171
|
+
if (this.hasApiKey && this.inboxId) {
|
|
172
|
+
const have = inboxLocalPart(this.inboxId);
|
|
173
|
+
if (have === want) {
|
|
174
|
+
const accountId = await this.getPrimaryMailAccountId();
|
|
175
|
+
return {
|
|
176
|
+
inbox: this.inboxId,
|
|
177
|
+
accountId,
|
|
178
|
+
idempotent: true,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (options.forced !== true) {
|
|
182
|
+
throw new Error("Register refused because credentials already belong to " +
|
|
183
|
+
`"${this.inboxId}" and requested username is "${want}". ` +
|
|
184
|
+
"Alternatively, use a separate credential directory " +
|
|
185
|
+
"(credentials_dir in MCP / --credentials-dir in AgentSkill) to " +
|
|
186
|
+
"register another account without replacing the current one. " +
|
|
187
|
+
"If you want to replace credentials in this directory, first " +
|
|
188
|
+
"back it up and remember where you copied it, otherwise you may " +
|
|
189
|
+
"lose access to your old account. Then retry with forced=true " +
|
|
190
|
+
"(MCP) or --forced (AgentSkill).");
|
|
191
|
+
}
|
|
192
|
+
await this.store.clear();
|
|
193
|
+
this.apiKey = undefined;
|
|
194
|
+
this.inboxId = undefined;
|
|
195
|
+
this.sessionJWT = undefined;
|
|
196
|
+
this.capabilityJWT = undefined;
|
|
197
|
+
this.cachedMailAccountId = undefined;
|
|
198
|
+
this.cachedUploadUrl = undefined;
|
|
199
|
+
this.cachedDownloadUrl = undefined;
|
|
200
|
+
this.cachedJmapPostUrl = undefined;
|
|
201
|
+
this.cachedJmapSession = undefined;
|
|
202
|
+
}
|
|
203
|
+
const result = await performPoWAndSession({
|
|
204
|
+
authUrl: this.authUrl,
|
|
205
|
+
scryptSalt: this.scryptSalt,
|
|
206
|
+
username,
|
|
207
|
+
});
|
|
208
|
+
if (!result.apiKey) {
|
|
209
|
+
throw new Error("Signup did not return an apiKey — this indicates a server bug.");
|
|
210
|
+
}
|
|
211
|
+
this.apiKey = result.apiKey;
|
|
212
|
+
this.sessionJWT = result.sessionJWT;
|
|
213
|
+
await this.store.save({ sessionJwt: this.sessionJWT });
|
|
214
|
+
const capability = await fetchCapability(this.authUrl, this.sessionJWT);
|
|
215
|
+
this.capabilityJWT = capability;
|
|
216
|
+
await this.store.save({ capabilityJwt: capability });
|
|
217
|
+
const claims = decodeJwtPayload(capability);
|
|
218
|
+
if (typeof claims.inboxId !== "string" || claims.inboxId.length === 0) {
|
|
219
|
+
throw new Error("Capability JWT missing inboxId claim after signup.");
|
|
220
|
+
}
|
|
221
|
+
this.inboxId = claims.inboxId;
|
|
222
|
+
this.cachedMailAccountId = undefined;
|
|
223
|
+
this.cachedUploadUrl = undefined;
|
|
224
|
+
this.cachedDownloadUrl = undefined;
|
|
225
|
+
this.cachedJmapPostUrl = undefined;
|
|
226
|
+
this.cachedJmapSession = undefined;
|
|
227
|
+
const accountId = await this.getPrimaryMailAccountId();
|
|
228
|
+
if (!this.cachedUploadUrl || !this.cachedDownloadUrl ||
|
|
229
|
+
!this.cachedJmapPostUrl) {
|
|
230
|
+
throw new Error("JMAP session did not provide uploadUrl, downloadUrl, or apiUrl.");
|
|
231
|
+
}
|
|
232
|
+
await this.store.save(this.currentCredentialArtifacts());
|
|
233
|
+
return {
|
|
234
|
+
inbox: this.inboxId,
|
|
235
|
+
accountId,
|
|
236
|
+
apiKey: this.apiKey,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async getCapabilityToken() {
|
|
240
|
+
if (this.capabilityJWT &&
|
|
241
|
+
!isJwtExpired(this.capabilityJWT, CAPABILITY_SAFETY_MARGIN_MS)) {
|
|
242
|
+
return this.capabilityJWT;
|
|
243
|
+
}
|
|
244
|
+
await this.ensureSession();
|
|
245
|
+
if (!this.sessionJWT) {
|
|
246
|
+
throw new Error("Internal: ensureSession() left sessionJWT unset.");
|
|
247
|
+
}
|
|
248
|
+
const cap = await fetchCapability(this.authUrl, this.sessionJWT);
|
|
249
|
+
this.capabilityJWT = cap;
|
|
250
|
+
await this.store.save({ capabilityJwt: cap });
|
|
251
|
+
try {
|
|
252
|
+
const claims = decodeJwtPayload(cap);
|
|
253
|
+
if (typeof claims.inboxId === "string" && claims.inboxId.length > 0) {
|
|
254
|
+
this.inboxId = claims.inboxId;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// non-fatal
|
|
259
|
+
}
|
|
260
|
+
return cap;
|
|
261
|
+
}
|
|
262
|
+
async ensureSession() {
|
|
263
|
+
if (this.sessionJWT &&
|
|
264
|
+
!isJwtExpired(this.sessionJWT, SESSION_SAFETY_MARGIN_MS)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (!this.apiKey) {
|
|
268
|
+
throw new Error("No API key configured and no valid session on disk. Run register " +
|
|
269
|
+
"first, set ATOMIC_MAIL_API_KEY, or place credentials.json in the " +
|
|
270
|
+
"credential directory.");
|
|
271
|
+
}
|
|
272
|
+
const result = await performPoWAndSession({
|
|
273
|
+
authUrl: this.authUrl,
|
|
274
|
+
scryptSalt: this.scryptSalt,
|
|
275
|
+
apiKey: this.apiKey,
|
|
276
|
+
});
|
|
277
|
+
this.sessionJWT = result.sessionJWT;
|
|
278
|
+
this.capabilityJWT = undefined;
|
|
279
|
+
this.cachedMailAccountId = undefined;
|
|
280
|
+
this.cachedUploadUrl = undefined;
|
|
281
|
+
this.cachedDownloadUrl = undefined;
|
|
282
|
+
this.cachedJmapPostUrl = undefined;
|
|
283
|
+
this.cachedJmapSession = undefined;
|
|
284
|
+
await this.store.save({ sessionJwt: this.sessionJWT });
|
|
285
|
+
}
|
|
286
|
+
destroy() {
|
|
287
|
+
// reserved
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** PoW login with an existing API key; writes credentials + JWT files. */
|
|
291
|
+
export async function persistLoginWithApiKey(input) {
|
|
292
|
+
const authUrl = input.authUrl.replace(/\/+$/, "");
|
|
293
|
+
const apiUrl = input.apiUrl.replace(/\/+$/, "");
|
|
294
|
+
const session = await performPoWAndSession({
|
|
295
|
+
authUrl,
|
|
296
|
+
scryptSalt: input.scryptSalt,
|
|
297
|
+
apiKey: input.apiKey,
|
|
298
|
+
onPowProgress: input.onPowProgress,
|
|
299
|
+
});
|
|
300
|
+
const capabilityJWT = await fetchCapability(authUrl, session.sessionJWT);
|
|
301
|
+
const claims = decodeJwtPayload(capabilityJWT);
|
|
302
|
+
const inboxId = claims.inboxId;
|
|
303
|
+
if (typeof inboxId !== "string" || inboxId.length === 0) {
|
|
304
|
+
throw new Error("Capability JWT did not contain an inboxId claim.");
|
|
305
|
+
}
|
|
306
|
+
const jmapSession = await fetchJmapWellKnown(apiUrl, capabilityJWT);
|
|
307
|
+
const blobs = extractBlobEndpoints(jmapSession);
|
|
308
|
+
await writeCredentials(input.files.credentialsFile, {
|
|
309
|
+
apiKey: input.apiKey,
|
|
310
|
+
inboxId,
|
|
311
|
+
authUrl,
|
|
312
|
+
apiUrl,
|
|
313
|
+
scryptSalt: input.scryptSalt,
|
|
314
|
+
uploadUrl: blobs.uploadUrl,
|
|
315
|
+
downloadUrl: blobs.downloadUrl,
|
|
316
|
+
});
|
|
317
|
+
await writeJwtFile(input.files.sessionFile, session.sessionJWT);
|
|
318
|
+
await writeJwtFile(input.files.capabilityFile, capabilityJWT);
|
|
319
|
+
return { inboxId };
|
|
320
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Optional inbox domain override for `$INBOX` normalization. */
|
|
2
|
+
export type InboxEmailEnv = {
|
|
3
|
+
ATOMIC_MAIL_INBOX_DOMAIN?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function inboxIdToMailboxEmail(inboxId: string, env?: InboxEmailEnv): string;
|
|
6
|
+
//# sourceMappingURL=inbox-id-to-mailbox-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-id-to-mailbox-email.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/session/inbox-id-to-mailbox-email.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG;IAAE,wBAAwB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAYlE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,aAAa,GAClB,MAAM,CAWR"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes stored `inboxId` into an RFC5322 mailbox address for `$INBOX`
|
|
3
|
+
* substitution (`From`, submission `envelope`, etc.).
|
|
4
|
+
*
|
|
5
|
+
* Credentials may store only the local-part (`alice`); production mailboxes
|
|
6
|
+
* live at `alice@atomicmail.ai`. Pass `ATOMIC_MAIL_INBOX_DOMAIN` via `env`
|
|
7
|
+
* when not using the default domain.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_INBOX_DOMAIN = "atomicmail.ai";
|
|
10
|
+
export function inboxIdToMailboxEmail(inboxId, env) {
|
|
11
|
+
const trimmed = inboxId.trim();
|
|
12
|
+
if (trimmed.length === 0)
|
|
13
|
+
return inboxId;
|
|
14
|
+
if (trimmed.includes("@"))
|
|
15
|
+
return trimmed;
|
|
16
|
+
const raw = env?.ATOMIC_MAIL_INBOX_DOMAIN?.trim();
|
|
17
|
+
const domain = raw && raw.length > 0
|
|
18
|
+
? raw.replace(/^@+/, "")
|
|
19
|
+
: DEFAULT_INBOX_DOMAIN;
|
|
20
|
+
return `${trimmed}@${domain}`;
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed proof-of-work scrypt salt. The auth-service passes this string (UTF-8
|
|
3
|
+
* bytes of the hex text, not decoded binary) to `scrypt` as the `salt`
|
|
4
|
+
* argument; all PoW clients must use the same value.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_POW_SCRYPT_SALT_HEX: string;
|
|
7
|
+
/** Production auth-service base URL when unset in env and credentials.json. */
|
|
8
|
+
export declare const DEFAULT_AUTH_URL: string;
|
|
9
|
+
/** Production JMAP / API base URL when unset in env and credentials.json. */
|
|
10
|
+
export declare const DEFAULT_API_URL: string;
|
|
11
|
+
export declare const ONE_SEC_MS: number;
|
|
12
|
+
export declare const ONE_MIN_MS: number;
|
|
13
|
+
export declare const ONE_HOUR_MS: number;
|
|
14
|
+
export declare const ONE_DAY_MS: number;
|
|
15
|
+
export declare const ONE_MONTH_MS: number;
|
|
16
|
+
export declare const ONE_YEAR_MS: number;
|
|
17
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../../src/lib/core/consts.ts"],"names":[],"mappings":"AA2BA;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,QACG,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,QAAiC,CAAC;AAE/D,6EAA6E;AAC7E,eAAO,MAAM,eAAe,QAAgC,CAAC;AAE7D,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,WAAW,QAA4B,CAAC;AACrD,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,YAAY,QAA6B,CAAC;AACvD,eAAO,MAAM,WAAW,QAA4B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { tryReadSharedJson } from "./shared-assets.js";
|
|
2
|
+
const SHARED_CONSTS = tryReadSharedJson("consts.json") ?? {
|
|
3
|
+
DEFAULT_POW_SCRYPT_SALT_HEX: "0b980734412c292d6549110276b604ab1dea4883bd460d77d1b984adf8bca083",
|
|
4
|
+
DEFAULT_AUTH_URL: "https://auth.atomicmail.ai",
|
|
5
|
+
DEFAULT_API_URL: "https://api.atomicmail.ai",
|
|
6
|
+
ONE_SEC_MS: 1000,
|
|
7
|
+
ONE_MIN_MS: 1000 * 60,
|
|
8
|
+
ONE_HOUR_MS: 1000 * 60 * 60,
|
|
9
|
+
ONE_DAY_MS: 1000 * 60 * 60 * 24,
|
|
10
|
+
ONE_MONTH_MS: 1000 * 60 * 60 * 24 * 30,
|
|
11
|
+
ONE_YEAR_MS: 1000 * 60 * 60 * 24 * 365,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Fixed proof-of-work scrypt salt. The auth-service passes this string (UTF-8
|
|
15
|
+
* bytes of the hex text, not decoded binary) to `scrypt` as the `salt`
|
|
16
|
+
* argument; all PoW clients must use the same value.
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_POW_SCRYPT_SALT_HEX = SHARED_CONSTS.DEFAULT_POW_SCRYPT_SALT_HEX;
|
|
19
|
+
/** Production auth-service base URL when unset in env and credentials.json. */
|
|
20
|
+
export const DEFAULT_AUTH_URL = SHARED_CONSTS.DEFAULT_AUTH_URL;
|
|
21
|
+
/** Production JMAP / API base URL when unset in env and credentials.json. */
|
|
22
|
+
export const DEFAULT_API_URL = SHARED_CONSTS.DEFAULT_API_URL;
|
|
23
|
+
export const ONE_SEC_MS = SHARED_CONSTS.ONE_SEC_MS;
|
|
24
|
+
export const ONE_MIN_MS = SHARED_CONSTS.ONE_MIN_MS;
|
|
25
|
+
export const ONE_HOUR_MS = SHARED_CONSTS.ONE_HOUR_MS;
|
|
26
|
+
export const ONE_DAY_MS = SHARED_CONSTS.ONE_DAY_MS;
|
|
27
|
+
export const ONE_MONTH_MS = SHARED_CONSTS.ONE_MONTH_MS;
|
|
28
|
+
export const ONE_YEAR_MS = SHARED_CONSTS.ONE_YEAR_MS;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Static JMAP success hints (no shared/ filesystem reads). */
|
|
2
|
+
export declare const JMAP_NEXT_HINTS: readonly ["Use jmap_request with Mailbox/get or Email/query to work with mail data.", "Use presets with $VAR placeholders — $ACCOUNT_ID, $INBOX, and $INBOX_MAILBOX_ID come from the session; pass others via vars / --vars.", "Call help for the JMAP cheatsheet and troubleshooting."];
|
|
3
|
+
//# sourceMappingURL=jmap-hints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jmap-hints.d.ts","sourceRoot":"","sources":["../../../src/lib/core/jmap-hints.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,eAAO,MAAM,eAAe,0RAIlB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Static JMAP success hints (no shared/ filesystem reads). */
|
|
2
|
+
export const JMAP_NEXT_HINTS = [
|
|
3
|
+
"Use jmap_request with Mailbox/get or Email/query to work with mail data.",
|
|
4
|
+
"Use presets with $VAR placeholders — $ACCOUNT_ID, $INBOX, and $INBOX_MAILBOX_ID come from the session; pass others via vars / --vars.",
|
|
5
|
+
"Call help for the JMAP cheatsheet and troubleshooting.",
|
|
6
|
+
];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type SharedErrorMap = Record<string, string>;
|
|
2
|
+
declare const SHARED_ERRORS: SharedErrorMap;
|
|
3
|
+
export declare function sharedError(key: keyof typeof SHARED_ERRORS): string;
|
|
4
|
+
export declare function sharedErrorTemplate(key: keyof typeof SHARED_ERRORS, values: Record<string, string | number>): string;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/lib/core/messages.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE7C,QAAA,MAAM,aAAa,gBAShB,CAAC;AAEJ,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,OAAO,aAAa,GAAG,MAAM,CAEnE;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,OAAO,aAAa,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACtC,MAAM,CAMR"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { tryReadSharedJson } from "./shared-assets.js";
|
|
2
|
+
const SHARED_ERRORS = tryReadSharedJson("messages/errors.json") ??
|
|
3
|
+
{
|
|
4
|
+
mcp_ops_mutually_exclusive: "ops and ops_file are mutually exclusive — provide one.",
|
|
5
|
+
mcp_ops_required: "Provide either ops or ops_file.",
|
|
6
|
+
cli_ops_mutually_exclusive: "--ops and --ops-file are mutually exclusive.",
|
|
7
|
+
cli_ops_required: "Provide --ops or --ops-file.",
|
|
8
|
+
cli_dry_run_with_attachment: "--dry-run cannot be combined with --attachment.",
|
|
9
|
+
};
|
|
10
|
+
export function sharedError(key) {
|
|
11
|
+
return SHARED_ERRORS[key];
|
|
12
|
+
}
|
|
13
|
+
export function sharedErrorTemplate(key, values) {
|
|
14
|
+
let out = SHARED_ERRORS[key];
|
|
15
|
+
for (const [k, v] of Object.entries(values)) {
|
|
16
|
+
out = out.replaceAll(`{${k}}`, String(v));
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads README.md from the npm package root (next to package.json).
|
|
3
|
+
* Intended for published @atomicmail/mcp and @atomicmail/agent-skill layouts.
|
|
4
|
+
*/
|
|
5
|
+
export declare function readNpmPackageReadme(): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=read-npm-package-readme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-npm-package-readme.d.ts","sourceRoot":"","sources":["../../../src/lib/core/read-npm-package-readme.ts"],"names":[],"mappings":"AAiCA;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CA+C5D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Locate and read README.md from an installed @atomicmail/* npm package.
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const MAX_DEPTH = 16;
|
|
6
|
+
const ATOMICMAIL_NPM_NAMES = new Set([
|
|
7
|
+
"@atomicmail/mcp",
|
|
8
|
+
"@atomicmail/mcp-github",
|
|
9
|
+
"@atomicmail/mcp-gh-pages",
|
|
10
|
+
"@atomicmail/mcp-modelcontextprotocol",
|
|
11
|
+
"@atomicmail/mcp-clawhub",
|
|
12
|
+
"@atomic-mail/mcp",
|
|
13
|
+
"@atomic-mail/mcp-github",
|
|
14
|
+
"@atomic-mail/mcp-gh-pages",
|
|
15
|
+
"@atomic-mail/mcp-modelcontextprotocol",
|
|
16
|
+
"@atomic-mail/mcp-clawhub",
|
|
17
|
+
"@atomicmail/agent-skill",
|
|
18
|
+
"@atomicmail/agent-skill-github",
|
|
19
|
+
"@atomicmail/agent-skill-gh-pages",
|
|
20
|
+
"@atomic-mail/agent-skill",
|
|
21
|
+
"@atomic-mail/agent-skill-github",
|
|
22
|
+
"@atomic-mail/agent-skill-gh-pages",
|
|
23
|
+
]);
|
|
24
|
+
function isEnoent(err) {
|
|
25
|
+
if (!(err instanceof Error))
|
|
26
|
+
return false;
|
|
27
|
+
const code = err.code;
|
|
28
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reads README.md from the npm package root (next to package.json).
|
|
32
|
+
* Intended for published @atomicmail/mcp and @atomicmail/agent-skill layouts.
|
|
33
|
+
*/
|
|
34
|
+
export async function readNpmPackageReadme() {
|
|
35
|
+
const moduleDir = dirname(fileURLToPath(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url));
|
|
36
|
+
let currentDir = moduleDir;
|
|
37
|
+
for (let i = 0; i < MAX_DEPTH; i++) {
|
|
38
|
+
const pkgPath = resolve(currentDir, "package.json");
|
|
39
|
+
const readmePath = resolve(currentDir, "README.md");
|
|
40
|
+
let pkgRaw;
|
|
41
|
+
try {
|
|
42
|
+
pkgRaw = await readFile(pkgPath, "utf-8");
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (!isEnoent(err))
|
|
46
|
+
throw err;
|
|
47
|
+
const parent = resolve(currentDir, "..");
|
|
48
|
+
if (parent === currentDir)
|
|
49
|
+
break;
|
|
50
|
+
currentDir = parent;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
let name;
|
|
54
|
+
try {
|
|
55
|
+
name = JSON.parse(pkgRaw).name;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
name = undefined;
|
|
59
|
+
}
|
|
60
|
+
if (!name || !ATOMICMAIL_NPM_NAMES.has(name)) {
|
|
61
|
+
const parent = resolve(currentDir, "..");
|
|
62
|
+
if (parent === currentDir)
|
|
63
|
+
break;
|
|
64
|
+
currentDir = parent;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return await readFile(readmePath, "utf-8");
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (!isEnoent(err))
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
const parent = resolve(currentDir, "..");
|
|
75
|
+
if (parent === currentDir)
|
|
76
|
+
break;
|
|
77
|
+
currentDir = parent;
|
|
78
|
+
}
|
|
79
|
+
throw new Error("Could not find Atomic Mail package README.md — use a published npm install " +
|
|
80
|
+
"(@atomicmail/mcp* channel package) for --topic readme.");
|
|
81
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function getSharedRootPath(): string;
|
|
2
|
+
export declare function readSharedText(relativePath: string): string;
|
|
3
|
+
export declare function readSharedJson<T>(relativePath: string): T;
|
|
4
|
+
export declare function tryReadSharedText(relativePath: string): string | undefined;
|
|
5
|
+
export declare function tryReadSharedJson<T>(relativePath: string): T | undefined;
|
|
6
|
+
//# sourceMappingURL=shared-assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-assets.d.ts","sourceRoot":"","sources":["../../../src/lib/core/shared-assets.ts"],"names":[],"mappings":"AAwBA,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAC9B,YAAY,EAAE,MAAM,GACnB,CAAC,CAEH;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM1E;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAMxE"}
|