@rubytech/create-maxy-code 0.1.573 → 0.1.574
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/package.json +1 -1
- package/payload/platform/lib/admins-write/__tests__/index.test.ts +97 -0
- package/payload/platform/lib/admins-write/dist/index.d.ts +12 -0
- package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admins-write/dist/index.js +27 -5
- package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
- package/payload/platform/lib/admins-write/src/index.ts +35 -5
- package/payload/platform/lib/admins-write/vitest.config.ts +14 -0
- package/payload/platform/lib/dispatch-read/dist/session.d.ts.map +1 -1
- package/payload/platform/lib/dispatch-read/dist/session.js +19 -4
- package/payload/platform/lib/dispatch-read/dist/session.js.map +1 -1
- package/payload/platform/lib/dispatch-read/src/__tests__/session.test.ts +91 -0
- package/payload/platform/lib/dispatch-read/src/session.ts +25 -6
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +8 -3
- package/payload/platform/plugins/admin/hooks/__tests__/html-structure-gate.test.sh +264 -0
- package/payload/platform/plugins/admin/hooks/__tests__/quote-render-pdf-conformance.test.sh +122 -24
- package/payload/platform/plugins/admin/hooks/__tests__/specialist-dispatch-gate.test.sh +158 -0
- package/payload/platform/plugins/admin/hooks/html-structure-gate.sh +165 -0
- package/payload/platform/plugins/admin/hooks/quote-render-pdf-conformance.sh +111 -19
- package/payload/platform/plugins/admin/hooks/specialist-dispatch-gate.sh +159 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.d.ts +27 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.js +29 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.d.ts +11 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.js +20 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +133 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +32 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +157 -46
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +8 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +71 -31
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +38 -13
- package/payload/platform/plugins/docs/references/internals.md +6 -0
- package/payload/platform/plugins/docs/references/outlook-guide.md +31 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
- package/payload/platform/plugins/outlook/PLUGIN.md +3 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.js +177 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.js +130 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.js +162 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.js +168 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.d.ts +64 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.js +110 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.d.ts +119 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.js +0 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.d.ts +8 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.js +247 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js +10 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +21 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts +16 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +5 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +4 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +2 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +24 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +2 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js +29 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.js +21 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.d.ts +13 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.js +10 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +54 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.d.ts +32 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.js +144 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.d.ts +44 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.js +185 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.js +125 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.d.ts +42 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.js +254 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.d.ts +92 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.js +227 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.js.map +1 -0
- package/payload/platform/templates/account-settings.json +8 -4
- package/payload/server/server.js +465 -361
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { DraftLedgerEntry } from "./draft-ledger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Classification for one ledger draft, and the pruning rule for the file.
|
|
4
|
+
*
|
|
5
|
+
* Pure and injectable: the Graph read happens in scripts/draft-reconcile.ts and
|
|
6
|
+
* arrives here as a `DraftState`, so every verdict is testable without a live
|
|
7
|
+
* mailbox (Task 2530).
|
|
8
|
+
*/
|
|
9
|
+
export type DraftVerdict = "still-draft" | "sent-by-maxy" | "sent-not-by-maxy" | "deleted" | "unreadable";
|
|
10
|
+
export type DraftState = {
|
|
11
|
+
kind: "read";
|
|
12
|
+
isDraft: boolean;
|
|
13
|
+
parentFolderId: string | null;
|
|
14
|
+
sentDateTime: string | null;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "not-found";
|
|
17
|
+
} | {
|
|
18
|
+
kind: "error";
|
|
19
|
+
statusCode: number;
|
|
20
|
+
code: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Hard age cap. Terminal rows are pruned as soon as they are classified; this
|
|
24
|
+
* bounds the file even if a draft never reaches a terminal verdict.
|
|
25
|
+
*
|
|
26
|
+
* 90 days, not the email ledger's 48 hours (`sent-ledger.ts:28`). That file's
|
|
27
|
+
* window is a 24h sweep, so 48h leaves margin. A draft awaiting the operator's
|
|
28
|
+
* review legitimately sits for days, and a short prune would drop exactly the
|
|
29
|
+
* rows that carry the point.
|
|
30
|
+
*/
|
|
31
|
+
export declare const RETENTION_CAP_MS: number;
|
|
32
|
+
/**
|
|
33
|
+
* The ids this plugin actually sent.
|
|
34
|
+
*
|
|
35
|
+
* An empty id is excluded. mail-send's `sendMail` route has no draft id when
|
|
36
|
+
* Graph returns none and writes "", and a created row's id is never "" — but
|
|
37
|
+
* letting "" into the set would make a naive membership test match nothing
|
|
38
|
+
* useful while looking like it worked.
|
|
39
|
+
*/
|
|
40
|
+
export declare function sentDraftIds(rows: DraftLedgerEntry[]): Set<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Created rows with no matching sent row.
|
|
43
|
+
*
|
|
44
|
+
* A sent row with no created row is normal, not an error: mail-send's
|
|
45
|
+
* attachment route and mail-reply both mint their own draft and send it in one
|
|
46
|
+
* call, so they never write a `created` row.
|
|
47
|
+
*/
|
|
48
|
+
export declare function openDrafts(rows: DraftLedgerEntry[]): DraftLedgerEntry[];
|
|
49
|
+
/**
|
|
50
|
+
* `parentFolderId` is the discriminator, not `isDraft`.
|
|
51
|
+
*
|
|
52
|
+
* Two states both mean the draft is no longer an open draft in that folder, and
|
|
53
|
+
* only one of them sets `isDraft: false`. On 2026-08-07 the Ecolec Drafts
|
|
54
|
+
* listing returned zero items while the same draft id still fetched and still
|
|
55
|
+
* returned `from: null` eleven seconds later — a draft object outside the
|
|
56
|
+
* Drafts folder. Keying on `isDraft` alone calls that healthy.
|
|
57
|
+
*
|
|
58
|
+
* A null `draftsFolderId` is `unreadable`, never a verdict: with nothing to
|
|
59
|
+
* compare against, reporting a healthy draft as sent by someone else is the one
|
|
60
|
+
* mistake this check must not make.
|
|
61
|
+
*/
|
|
62
|
+
export declare function classifyDraft(state: DraftState, draftsFolderId: string | null): DraftVerdict;
|
|
63
|
+
/**
|
|
64
|
+
* A verdict that will not change, so its rows can be dropped.
|
|
65
|
+
*
|
|
66
|
+
* `unreadable` is deliberately not terminal — a transient 503 must not retire a
|
|
67
|
+
* draft — and neither is `still-draft`, which is the state the reconcile exists
|
|
68
|
+
* to keep watching.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isTerminal(verdict: DraftVerdict): boolean;
|
|
71
|
+
/** One Sent Items row, as much of it as the match needs. */
|
|
72
|
+
export interface SentItemsRow {
|
|
73
|
+
id?: unknown;
|
|
74
|
+
subject?: unknown;
|
|
75
|
+
conversationId?: unknown;
|
|
76
|
+
toRecipients?: Array<{
|
|
77
|
+
emailAddress?: {
|
|
78
|
+
address?: string;
|
|
79
|
+
};
|
|
80
|
+
}>;
|
|
81
|
+
sentDateTime?: unknown;
|
|
82
|
+
}
|
|
83
|
+
export interface SentCopy {
|
|
84
|
+
id: string;
|
|
85
|
+
to: string;
|
|
86
|
+
at: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Find the copy that actually went out, among a page of Sent Items.
|
|
90
|
+
*
|
|
91
|
+
* Matched by conversationId when the draft carries one, else by subject. The
|
|
92
|
+
* 2026-08-07 Leaders draft was standalone with `conversationId: null`, so a
|
|
93
|
+
* conversationId-only match would have found nothing and the operator would
|
|
94
|
+
* still not know who received it.
|
|
95
|
+
*
|
|
96
|
+
* A row with neither key matches nothing rather than matching the newest item:
|
|
97
|
+
* naming the wrong recipient is worse than naming none.
|
|
98
|
+
*/
|
|
99
|
+
export declare function matchSentCopy(rows: SentItemsRow[], draft: DraftLedgerEntry): SentCopy | null;
|
|
100
|
+
/** Graph's message projection, narrowed to the three fields a verdict needs. */
|
|
101
|
+
export declare function mapDraftState(json: {
|
|
102
|
+
isDraft?: boolean;
|
|
103
|
+
parentFolderId?: string | null;
|
|
104
|
+
sentDateTime?: string | null;
|
|
105
|
+
} | null): DraftState;
|
|
106
|
+
/**
|
|
107
|
+
* The prune key: account AND draft, never the draft id alone.
|
|
108
|
+
*
|
|
109
|
+
* Graph ids are long enough that a collision across two accounts is unlikely,
|
|
110
|
+
* but account scope is a property that has to hold exactly — a shared key would
|
|
111
|
+
* let one account's terminal verdict delete another account's open row.
|
|
112
|
+
*/
|
|
113
|
+
export declare function ledgerKey(accountId: string, draftId: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* Drop every row for a draft that reached a terminal verdict, and every row past
|
|
116
|
+
* the hard cap. Called once per run from the reconcile's single process.
|
|
117
|
+
*/
|
|
118
|
+
export declare function pruneRows(rows: DraftLedgerEntry[], terminalKeys: Set<string>, nowMs: number): DraftLedgerEntry[];
|
|
119
|
+
//# sourceMappingURL=draft-reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-reconcile.d.ts","sourceRoot":"","sources":["../../src/lib/draft-reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GACpB,aAAa,GACb,cAAc,GACd,kBAAkB,GAClB,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9F;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAIlE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAGvE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAM5F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAEzD;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,YAAY,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IAC9D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,gBAAgB,GAAG,QAAQ,GAAG,IAAI,CAgB5F;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,IAAI,GAAG,UAAU,CAOpB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,gBAAgB,EAAE,EACxB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,KAAK,EAAE,MAAM,GACZ,gBAAgB,EAAE,CASpB"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-reconcile.js","sourceRoot":"","sources":["../../src/lib/draft-reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface VendorApp {
|
|
2
|
+
clientId: string;
|
|
3
|
+
tenantId: string;
|
|
4
|
+
}
|
|
5
|
+
/** The brand's Outlook app, read from disk because the heartbeat's env has none. */
|
|
6
|
+
export declare function readVendorApp(platformRoot: string): VendorApp | null;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=draft-reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-reconcile.d.ts","sourceRoot":"","sources":["../../src/scripts/draft-reconcile.ts"],"names":[],"mappings":"AA+CA,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAcpE"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standing reconciliation of every draft this plugin created, one pass over
|
|
3
|
+
* every local account.
|
|
4
|
+
*
|
|
5
|
+
* Spawned by the scheduling heartbeat on an hourly throttle rather than
|
|
6
|
+
* imported by it: the scheduling plugin builds with its own rootDir and does
|
|
7
|
+
* not carry the Graph client, so the Graph work stays on this side of the
|
|
8
|
+
* boundary — the rule Task 1822 set for the email sent-copy sweep.
|
|
9
|
+
*
|
|
10
|
+
* It has to be a standing check rather than another action log. The failure it
|
|
11
|
+
* exists for emits no event: nobody calls a tool when an external mail client
|
|
12
|
+
* sends a draft, so there is nothing to hang a log line on, and re-running the
|
|
13
|
+
* code will not surface it. On 2026-08-07 a Maxy-created draft left the Drafts
|
|
14
|
+
* folder at 12:26:47Z and the platform recorded nothing at all.
|
|
15
|
+
*
|
|
16
|
+
* The heartbeat's cron line carries only PLATFORM_ROOT, NEO4J_URI and
|
|
17
|
+
* MAXY_UI_INTERNAL_PORT — no OUTLOOK_CLIENT_ID — so the vendor app is read from
|
|
18
|
+
* platform/config/brand.json here, the same source and the same reason as
|
|
19
|
+
* scheduling's connector-freebusy.ts:83.
|
|
20
|
+
*
|
|
21
|
+
* Exit code is 0 whenever the reconcile ran, including when it found a
|
|
22
|
+
* sent-not-by-maxy: a finding is a result, not a failure of the check. Non-zero
|
|
23
|
+
* means it could not run, which is what keeps "failing" and "did not run"
|
|
24
|
+
* distinguishable.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
27
|
+
import { resolve } from "node:path";
|
|
28
|
+
import { enumerateValidAccountIds } from "../../../../../lib/account-enumeration/dist/index.js";
|
|
29
|
+
import { MailboxRegistry } from "../auth/mailbox-registry.js";
|
|
30
|
+
import { callGraph, classifyGraphError } from "../lib/graph-client.js";
|
|
31
|
+
import { log } from "../lib/log.js";
|
|
32
|
+
import { readDraftLedger, writeDraftLedger } from "../lib/draft-ledger.js";
|
|
33
|
+
import { openDrafts, sentDraftIds, classifyDraft, pruneRows, isTerminal, ledgerKey, mapDraftState, matchSentCopy, } from "../lib/draft-reconcile.js";
|
|
34
|
+
/** The brand's Outlook app, read from disk because the heartbeat's env has none. */
|
|
35
|
+
export function readVendorApp(platformRoot) {
|
|
36
|
+
const path = resolve(platformRoot, "config", "brand.json");
|
|
37
|
+
try {
|
|
38
|
+
const brand = JSON.parse(readFileSync(path, "utf-8"));
|
|
39
|
+
const clientId = typeof brand.outlookClientId === "string" ? brand.outlookClientId : "";
|
|
40
|
+
if (!clientId)
|
|
41
|
+
return null;
|
|
42
|
+
const tenantId = typeof brand.outlookTenantId === "string" && brand.outlookTenantId
|
|
43
|
+
? brand.outlookTenantId
|
|
44
|
+
: "common";
|
|
45
|
+
return { clientId, tenantId };
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The Drafts folder's opaque id.
|
|
53
|
+
*
|
|
54
|
+
* `parentFolderId` on a message is an opaque id, never the well-known `drafts`
|
|
55
|
+
* token, so it can only be compared against a resolved one. Null on failure,
|
|
56
|
+
* which classifyDraft turns into `unreadable` rather than a verdict.
|
|
57
|
+
*/
|
|
58
|
+
async function resolveDraftsFolderId(config) {
|
|
59
|
+
try {
|
|
60
|
+
const json = await callGraph(config, (client) => client.api("/me/mailFolders/drafts").select("id").get(), { tool: "draft-reconcile" });
|
|
61
|
+
return json?.id ?? null;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function readDraftState(config, draftId) {
|
|
68
|
+
try {
|
|
69
|
+
const json = await callGraph(config, (client) => client
|
|
70
|
+
.api(`/me/messages/${encodeURIComponent(draftId)}`)
|
|
71
|
+
.select("isDraft,parentFolderId,sentDateTime,lastModifiedDateTime")
|
|
72
|
+
.get(), { tool: "draft-reconcile", target: draftId });
|
|
73
|
+
return mapDraftState(json);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const cls = classifyGraphError(err);
|
|
77
|
+
if (cls.statusCode === 404)
|
|
78
|
+
return { kind: "not-found" };
|
|
79
|
+
// Two of the rate-limit classes carry no `code` field at all, so it is read
|
|
80
|
+
// off the union rather than assumed present.
|
|
81
|
+
const code = "code" in cls ? cls.code : cls.kind;
|
|
82
|
+
return { kind: "error", statusCode: cls.statusCode, code };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The newest Sent Items, fetched at most once per mailbox per run.
|
|
87
|
+
*
|
|
88
|
+
* Several drafts in one mailbox can come back sent-not-by-maxy together, and
|
|
89
|
+
* they all match against the same page — refetching it per draft would be N
|
|
90
|
+
* identical Graph calls. A failed fetch caches the empty page too, so one
|
|
91
|
+
* outage does not become N retries inside a single run.
|
|
92
|
+
*/
|
|
93
|
+
async function sentItemsPage(config) {
|
|
94
|
+
try {
|
|
95
|
+
const page = await callGraph(config, (client) => client
|
|
96
|
+
.api("/me/mailFolders/sentitems/messages")
|
|
97
|
+
.select("id,subject,conversationId,toRecipients,sentDateTime")
|
|
98
|
+
.top(25)
|
|
99
|
+
.orderby("sentDateTime desc")
|
|
100
|
+
.get(), { tool: "draft-reconcile" });
|
|
101
|
+
return page?.value ?? [];
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function emptyCounts() {
|
|
108
|
+
return {
|
|
109
|
+
"still-draft": 0,
|
|
110
|
+
"sent-by-maxy": 0,
|
|
111
|
+
"sent-not-by-maxy": 0,
|
|
112
|
+
deleted: 0,
|
|
113
|
+
unreadable: 0,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async function reconcileAccount(accountId, accountsDir, vendor, rows, nowMs, terminal) {
|
|
117
|
+
const mine = rows.filter((r) => r.accountId === accountId);
|
|
118
|
+
if (mine.length === 0)
|
|
119
|
+
return;
|
|
120
|
+
const counts = emptyCounts();
|
|
121
|
+
const alreadySent = sentDraftIds(mine);
|
|
122
|
+
// A created row whose id also carries a sent row is answered by the ledger
|
|
123
|
+
// alone. No Graph call: the ledger already knows, and asking would spend a
|
|
124
|
+
// request to learn nothing.
|
|
125
|
+
for (const r of mine) {
|
|
126
|
+
if (r.event === "created" && alreadySent.has(r.draftId)) {
|
|
127
|
+
counts["sent-by-maxy"]++;
|
|
128
|
+
terminal.add(ledgerKey(accountId, r.draftId));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const registry = new MailboxRegistry(accountId, accountsDir);
|
|
132
|
+
const byMailbox = new Map();
|
|
133
|
+
for (const r of openDrafts(mine)) {
|
|
134
|
+
const list = byMailbox.get(r.mailbox) ?? [];
|
|
135
|
+
list.push(r);
|
|
136
|
+
byMailbox.set(r.mailbox, list);
|
|
137
|
+
}
|
|
138
|
+
for (const [mailbox, drafts] of byMailbox) {
|
|
139
|
+
const resolved = registry.resolve(mailbox || undefined);
|
|
140
|
+
if (resolved.kind !== "ok") {
|
|
141
|
+
// Not terminal: a mailbox that is momentarily unresolvable must not
|
|
142
|
+
// retire a draft that is still sitting there.
|
|
143
|
+
for (const r of drafts) {
|
|
144
|
+
counts.unreadable++;
|
|
145
|
+
log({
|
|
146
|
+
event: "draft-reconcile",
|
|
147
|
+
account: accountId,
|
|
148
|
+
mailbox,
|
|
149
|
+
draftId: r.draftId,
|
|
150
|
+
outcome: "unreadable",
|
|
151
|
+
createdTs: r.at,
|
|
152
|
+
reason: `mailbox-${resolved.kind}`,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const config = {
|
|
158
|
+
clientId: vendor.clientId,
|
|
159
|
+
tenantId: vendor.tenantId,
|
|
160
|
+
accountId,
|
|
161
|
+
tokenStore: resolved.store,
|
|
162
|
+
mailboxPathPrefix: resolved.pathPrefix,
|
|
163
|
+
mailboxAddress: resolved.delegatedAddress ?? resolved.descriptor.mail ?? null,
|
|
164
|
+
};
|
|
165
|
+
const draftsFolderId = await resolveDraftsFolderId(config);
|
|
166
|
+
let sentPage = null;
|
|
167
|
+
for (const r of drafts) {
|
|
168
|
+
const state = await readDraftState(config, r.draftId);
|
|
169
|
+
const outcome = classifyDraft(state, draftsFolderId);
|
|
170
|
+
counts[outcome]++;
|
|
171
|
+
if (isTerminal(outcome))
|
|
172
|
+
terminal.add(ledgerKey(accountId, r.draftId));
|
|
173
|
+
const createdMs = Date.parse(r.at);
|
|
174
|
+
const fields = {
|
|
175
|
+
event: "draft-reconcile",
|
|
176
|
+
account: accountId,
|
|
177
|
+
mailbox,
|
|
178
|
+
draftId: r.draftId,
|
|
179
|
+
outcome,
|
|
180
|
+
createdTs: r.at,
|
|
181
|
+
sentDateTime: state.kind === "read" ? state.sentDateTime : null,
|
|
182
|
+
parentFolderId: state.kind === "read" ? state.parentFolderId : null,
|
|
183
|
+
ageMs: Number.isFinite(createdMs) ? nowMs - createdMs : null,
|
|
184
|
+
};
|
|
185
|
+
if (state.kind === "error") {
|
|
186
|
+
fields.status = state.statusCode;
|
|
187
|
+
fields.code = state.code;
|
|
188
|
+
}
|
|
189
|
+
if (outcome === "sent-not-by-maxy") {
|
|
190
|
+
if (sentPage === null)
|
|
191
|
+
sentPage = await sentItemsPage(config);
|
|
192
|
+
const copy = matchSentCopy(sentPage, r);
|
|
193
|
+
fields.sentCopyId = copy?.id ?? "none";
|
|
194
|
+
fields.sentCopyTo = copy?.to ?? "none";
|
|
195
|
+
fields.sentCopyAt = copy?.at ?? "none";
|
|
196
|
+
}
|
|
197
|
+
log(fields);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Emitted on every pass including an all-zero one: an absent census line is
|
|
201
|
+
// the signal that the reconcile stopped running, and that only works if a
|
|
202
|
+
// quiet pass still speaks.
|
|
203
|
+
log({
|
|
204
|
+
event: "draft-reconcile-census",
|
|
205
|
+
account: accountId,
|
|
206
|
+
total: mine.filter((r) => r.event === "created").length,
|
|
207
|
+
stillDraft: counts["still-draft"],
|
|
208
|
+
sentByMaxy: counts["sent-by-maxy"],
|
|
209
|
+
sentNotByMaxy: counts["sent-not-by-maxy"],
|
|
210
|
+
deleted: counts.deleted,
|
|
211
|
+
unreadable: counts.unreadable,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
async function main() {
|
|
215
|
+
const platformRoot = process.env.PLATFORM_ROOT;
|
|
216
|
+
if (!platformRoot)
|
|
217
|
+
throw new Error("PLATFORM_ROOT is not set");
|
|
218
|
+
const vendor = readVendorApp(platformRoot);
|
|
219
|
+
if (!vendor) {
|
|
220
|
+
// A brand that ships no Outlook vendor app has nothing to reconcile. A
|
|
221
|
+
// distinct outcome from "did not run", and it has to say so.
|
|
222
|
+
log({ event: "draft-reconcile-skipped", reason: "no-vendor-app" });
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const accountsDir = resolve(platformRoot, "..", "data/accounts");
|
|
226
|
+
const accountIds = existsSync(accountsDir) ? enumerateValidAccountIds(accountsDir) : [];
|
|
227
|
+
const rows = readDraftLedger();
|
|
228
|
+
const terminal = new Set();
|
|
229
|
+
const nowMs = Date.now();
|
|
230
|
+
for (const accountId of accountIds) {
|
|
231
|
+
await reconcileAccount(accountId, accountsDir, vendor, rows, nowMs, terminal);
|
|
232
|
+
}
|
|
233
|
+
const kept = pruneRows(rows, terminal, nowMs);
|
|
234
|
+
if (kept.length !== rows.length)
|
|
235
|
+
writeDraftLedger(kept);
|
|
236
|
+
log({
|
|
237
|
+
event: "draft-reconcile-pruned",
|
|
238
|
+
accounts: accountIds.length,
|
|
239
|
+
removed: rows.length - kept.length,
|
|
240
|
+
kept: kept.length,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
main().catch((err) => {
|
|
244
|
+
log({ event: "draft-reconcile-failed", error: err.message });
|
|
245
|
+
process.exit(1);
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=draft-reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-reconcile.js","sourceRoot":"","sources":["../../src/scripts/draft-reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-send.d.ts","sourceRoot":"","sources":["../../src/tools/draft-send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"draft-send.d.ts","sourceRoot":"","sources":["../../src/tools/draft-send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CA6B1B"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { postGraph } from "../lib/graph-client.js";
|
|
2
2
|
import { log } from "../lib/log.js";
|
|
3
|
+
import { appendDraftLedger } from "../lib/draft-ledger.js";
|
|
3
4
|
/**
|
|
4
5
|
* Send an existing draft via Graph `POST /me/messages/{id}/send` (empty body).
|
|
5
6
|
* Graph consumes the draft and returns 202. Success is asserted on the 202
|
|
@@ -16,6 +17,15 @@ export async function runDraftSend(config, args) {
|
|
|
16
17
|
try {
|
|
17
18
|
const { status } = await postGraph(config, `/me/messages/${encodeURIComponent(draftId)}/send`, undefined, { tool: "draft-send" });
|
|
18
19
|
log({ event: "draft-sent", account, id: draftId, status });
|
|
20
|
+
appendDraftLedger({
|
|
21
|
+
at: new Date().toISOString(),
|
|
22
|
+
accountId: account,
|
|
23
|
+
mailbox: config.mailboxAddress ?? "",
|
|
24
|
+
draftId,
|
|
25
|
+
event: "sent",
|
|
26
|
+
tool: "draft-send",
|
|
27
|
+
route: "draft-send",
|
|
28
|
+
});
|
|
19
29
|
return { status: "sent", draftId, httpStatus: status };
|
|
20
30
|
}
|
|
21
31
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-send.js","sourceRoot":"","sources":["../../src/tools/draft-send.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"draft-send.js","sourceRoot":"","sources":["../../src/tools/draft-send.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAY3D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAyB,EACzB,IAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,GAAG,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAChC,MAAM,EACN,gBAAgB,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAClD,SAAS,EACT,EAAE,IAAI,EAAE,YAAY,EAAE,CACvB,CAAC;QACF,GAAG,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3D,iBAAiB,CAAC;YAChB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE;YACpC,OAAO;YACP,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,YAAY;SACpB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IACzD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACzF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAMpE;;;;;;GAMG;AACH,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IACtE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;qFACiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB;;;yDAGqD;IACrD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;4DAKwD;IACxD,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAmDjG"}
|
|
@@ -2,6 +2,7 @@ import { postGraph } from "../lib/graph-client.js";
|
|
|
2
2
|
import { buildMessage } from "../lib/message.js";
|
|
3
3
|
import { attachFilesToDraft, resolveAttachmentsOrRefuse } from "../lib/attach.js";
|
|
4
4
|
import { log } from "../lib/log.js";
|
|
5
|
+
import { appendDraftLedger } from "../lib/draft-ledger.js";
|
|
5
6
|
import { addrs, applyCcBccToDraft } from "../lib/recipients.js";
|
|
6
7
|
/**
|
|
7
8
|
* Create a draft via Graph, attach any files to it, and return an id naming a
|
|
@@ -54,6 +55,26 @@ export async function runDraft(config, input) {
|
|
|
54
55
|
const { draftId, conversationId, to } = threaded
|
|
55
56
|
? await createThreadedDraft(config, input)
|
|
56
57
|
: await createStandaloneDraft(config, input);
|
|
58
|
+
// Written the moment the draft exists, BEFORE the attach. An attach that
|
|
59
|
+
// fails Graph-side rethrows but leaves the draft in Drafts (see the orphan
|
|
60
|
+
// note above), and a row written after the attach would miss exactly that
|
|
61
|
+
// draft — the reconcile would never watch the one case that already goes
|
|
62
|
+
// wrong (Task 2530).
|
|
63
|
+
//
|
|
64
|
+
// `subject` is undefined on the threaded path — Graph sets it there — and
|
|
65
|
+
// that is correct: a threaded draft carries a conversationId, which is the
|
|
66
|
+
// stronger Sent Items match key. A standalone draft has no conversationId
|
|
67
|
+
// and always has a subject.
|
|
68
|
+
appendDraftLedger({
|
|
69
|
+
at: new Date().toISOString(),
|
|
70
|
+
accountId: account,
|
|
71
|
+
mailbox: config.mailboxAddress ?? "",
|
|
72
|
+
draftId,
|
|
73
|
+
event: "created",
|
|
74
|
+
tool: "draft",
|
|
75
|
+
subject: input.subject,
|
|
76
|
+
conversationId,
|
|
77
|
+
});
|
|
57
78
|
await attachFilesToDraft(config, draftId, files, "draft");
|
|
58
79
|
log({
|
|
59
80
|
event: "draft-created",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,22 @@ export interface FetchBodyResult {
|
|
|
10
10
|
conversationId: string | null;
|
|
11
11
|
isRead: boolean;
|
|
12
12
|
hasAttachments: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Graph's own view of whether this is still an unsent draft, and which folder
|
|
15
|
+
* it is actually in. Both are needed to answer "is my draft still a draft":
|
|
16
|
+
* an item can be `isDraft: true` and no longer sit in the Drafts folder, and a
|
|
17
|
+
* fetch by id still succeeds in that state — on 2026-08-07 the Ecolec Drafts
|
|
18
|
+
* listing returned zero items while this same call returned `from: null`
|
|
19
|
+
* eleven seconds later (Task 2530). `parentFolderId` is the discriminator;
|
|
20
|
+
* `isDraft` alone calls that healthy.
|
|
21
|
+
*
|
|
22
|
+
* `sentDateTime` is `0001-01-01T00:00:00Z` on anything never sent, and null
|
|
23
|
+
* only when Graph omitted the field.
|
|
24
|
+
*/
|
|
25
|
+
isDraft: boolean;
|
|
26
|
+
parentFolderId: string | null;
|
|
27
|
+
sentDateTime: string | null;
|
|
28
|
+
lastModifiedDateTime: string | null;
|
|
13
29
|
contentType: "html" | "text";
|
|
14
30
|
body: string;
|
|
15
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-fetch-body.d.ts","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;
|
|
1
|
+
{"version":3,"file":"mail-fetch-body.d.ts","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAsBD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,GACnE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAKlD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,eAAe,CAAC,CAyC1B"}
|
|
@@ -2,7 +2,7 @@ import { callGraph } from "../lib/graph-client.js";
|
|
|
2
2
|
import { htmlToText } from "../lib/html-to-text.js";
|
|
3
3
|
import { log } from "../lib/log.js";
|
|
4
4
|
import { addrs } from "../lib/recipients.js";
|
|
5
|
-
const SELECT = "id,subject,from,toRecipients,ccRecipients,receivedDateTime,conversationId,isRead,hasAttachments,body";
|
|
5
|
+
const SELECT = "id,subject,from,toRecipients,ccRecipients,receivedDateTime,conversationId,isRead,hasAttachments,isDraft,parentFolderId,sentDateTime,lastModifiedDateTime,body";
|
|
6
6
|
/**
|
|
7
7
|
* Map Graph's `from.emailAddress` to the archive's { from, fromName } pair.
|
|
8
8
|
* Exported so the mapping is unit-testable without a live Graph call.
|
|
@@ -46,6 +46,10 @@ export async function runMailFetchBody(config, args) {
|
|
|
46
46
|
conversationId: msg.conversationId ?? null,
|
|
47
47
|
isRead: msg.isRead ?? false,
|
|
48
48
|
hasAttachments: msg.hasAttachments ?? false,
|
|
49
|
+
isDraft: msg.isDraft ?? false,
|
|
50
|
+
parentFolderId: msg.parentFolderId ?? null,
|
|
51
|
+
sentDateTime: msg.sentDateTime ?? null,
|
|
52
|
+
lastModifiedDateTime: msg.lastModifiedDateTime ?? null,
|
|
49
53
|
contentType,
|
|
50
54
|
body,
|
|
51
55
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-fetch-body.js","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,KAAK,EAAqB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-fetch-body.js","sourceRoot":"","sources":["../../src/tools/mail-fetch-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,KAAK,EAAqB,MAAM,sBAAsB,CAAC;AAkDhE,MAAM,MAAM,GACV,+JAA+J,CAAC;AAElK;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,IAAoE;IAEpE,OAAO;QACL,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,IAAI,IAAI;QACzC,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,IAAI,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAyB,EACzB,IAA2B;IAE3B,MAAM,IAAI,GAAG,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,SAAS,CACzB,MAAM,EACN,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAe,EAC7E,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAC1C,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAChE,MAAM,WAAW,GAAoB,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1E,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAE5D,GAAG,CAAC;QACF,KAAK,EAAE,iBAAiB;QACxB,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,EAAE,EAAE,IAAI,CAAC,SAAS;QAClB,KAAK,EAAE,IAAI,CAAC,MAAM;QAClB,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI;QAC5B,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QAC3B,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QAC3B,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;QACtC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;QAC1C,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK;QAC3B,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,KAAK;QAC3C,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK;QAC7B,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;QAC1C,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,IAAI;QACtC,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,IAAI;QACtD,WAAW;QACX,IAAI;KACL,CAAC;AACJ,CAAC"}
|
|
@@ -41,6 +41,10 @@ export interface MailListItem {
|
|
|
41
41
|
* outlook-mail-attachment to list/download them. Inline-only images can read
|
|
42
42
|
* false, matching Graph. */
|
|
43
43
|
hasAttachments: boolean;
|
|
44
|
+
/** Graph `isDraft`. Carried on every folder's listing, not just Drafts, so a
|
|
45
|
+
* caller comparing a Drafts listing against a message it fetched by id is
|
|
46
|
+
* reading the same field on both sides (Task 2530). */
|
|
47
|
+
isDraft: boolean;
|
|
44
48
|
}
|
|
45
49
|
export interface MailListResult {
|
|
46
50
|
items: MailListItem[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail-list.d.ts","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIhE,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IAMb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAUjF;AAsBD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB;;iCAE6B;IAC7B,cAAc,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"mail-list.d.ts","sourceRoot":"","sources":["../../src/tools/mail-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIhE,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IAMb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAUjF;AAsBD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB;;iCAE6B;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB;;4DAEwD;IACxD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kFAAkF;IAClF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AA8BD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CA+DzB"}
|
|
@@ -43,7 +43,7 @@ const WELL_KNOWN_ALIASES = {
|
|
|
43
43
|
archive: "archive",
|
|
44
44
|
outbox: "outbox",
|
|
45
45
|
};
|
|
46
|
-
const FIELDS = "id,subject,from,receivedDateTime,bodyPreview,isRead,hasAttachments";
|
|
46
|
+
const FIELDS = "id,subject,from,receivedDateTime,bodyPreview,isRead,hasAttachments,isDraft";
|
|
47
47
|
function toGraphDate(input, field) {
|
|
48
48
|
const d = new Date(input);
|
|
49
49
|
if (!Number.isFinite(d.getTime())) {
|
|
@@ -128,6 +128,7 @@ function shapeMessage(msg) {
|
|
|
128
128
|
bodyPreview: (msg.bodyPreview ?? "").slice(0, 1024),
|
|
129
129
|
isRead: msg.isRead ?? false,
|
|
130
130
|
hasAttachments: msg.hasAttachments ?? false,
|
|
131
|
+
isDraft: msg.isDraft ?? false,
|
|
131
132
|
};
|
|
132
133
|
}
|
|
133
134
|
function clampTop(input, fallback) {
|