@rubytech/create-maxy-code 0.1.445 → 0.1.446

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.
Files changed (24) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/mcp/dist/index.js +13 -3
  3. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  4. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +8 -0
  5. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
  6. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +20 -3
  7. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
  8. package/payload/platform/plugins/outlook/PLUGIN.md +1 -1
  9. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +23 -0
  10. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -1
  11. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js +34 -1
  12. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js.map +1 -1
  13. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +26 -0
  14. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -1
  15. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +20 -3
  16. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -1
  17. package/payload/platform/plugins/outlook/mcp/dist/index.js +2 -2
  18. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  19. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +7 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -1
  21. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +4 -1
  22. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -1
  23. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +9 -3
  24. package/payload/server/server.js +16 -9
@@ -29,15 +29,21 @@ The client ID ships with the brand, so there is no app to register and no Azure
29
29
 
30
30
  Connect a mailbox via the device-code flow. The operator never needs the box's browser and never screen-shares.
31
31
 
32
- 1. Call **`outlook-account-register`**. It returns immediately with `{ status: "pending", userCode, verificationUri, verificationUriComplete, expiresInSec, intervalSec }`. Relay the `userCode` and `verificationUri` to the operator in your reply.
32
+ 1. Call **`outlook-account-register`**. It returns immediately with `{ status: "pending", userCode, verificationUri, verificationUriComplete, expiresInSec, intervalSec }`. Relay the `userCode` and `verificationUri` to the operator in your reply so the sign-in can begin.
33
33
  2. The operator opens `verificationUri` (`microsoft.com/devicelogin`) on any device (their phone or laptop), enters the `userCode`, signs in with the Microsoft account they want to connect, and consents to the requested scopes (`offline_access`, `User.Read`, `Mail.ReadWrite`, `Mail.Send`, `Calendars.ReadWrite`, `Contacts.Read`). `Mail.Send` enables sending and `Calendars.ReadWrite` enables calendar control; a mailbox last consented on an older read-only scope set must re-register before send or any calendar write succeeds.
34
- 3. Call **`outlook-account-register-poll`** once per check. While it returns `{ status: "pending" }`, wait `intervalSec` seconds and call it again. It returns `{ status: "registered", graphUserId, scopes, tokenExpSec }` once consent completes, `{ status: "expired" }` if the code timed out (restart at step 1), or `{ status: "denied" }` if the operator declined.
34
+ 3. **Poll immediately, and keep polling to a terminal outcome.** As soon as the code is issued in step 1, start calling **`outlook-account-register-poll`** on the returned `intervalSec` cadence, and keep calling it until it returns a terminal status. Do not wait for the operator to say the sign-in is finished. The flow is poll-driven: Microsoft's confirmation page authenticates the code at Microsoft and pushes nothing back to this plugin, so only this poll harvests the token. `{ status: "pending" }` means keep polling. `{ status: "registered", graphUserId, scopes, tokenExpSec }` is the sole completion signal (consent finished, tokens persisted); after it, confirm the mailbox is addressable with `outlook-mailbox-list` (a `status:ok` entry) or `outlook-mailbox-info`. `{ status: "expired" }` means the code lapsed unharvested, so restart at step 1. `{ status: "denied" }` means the operator declined.
35
+
36
+ **An operator "done" means poll, not verify.** A message like "done", "he confirmed", or "she signed in" maps to *poll now, and keep polling* on the `intervalSec` cadence. It never maps to a read-only `outlook-mailbox-info` check. A read-only check is a valid way to confirm a mailbox that is *already* `registered`; it never completes an in-flight sign-in, and running it in place of the poll lets the live code lapse unharvested.
37
+
38
+ **Never end the flow with a live pending code.** Once `outlook-account-register` has issued a code, drive it to a terminal status (`registered`, `expired`, or `denied`) before the flow ends. A pending code left hanging is not only an unfinished sign-in: the leftover pending entry makes the next `outlook-account-register` return `register-in-progress` instead of starting a fresh code.
35
39
 
36
40
  Subsequent tool calls use the persisted refresh token to mint access tokens transparently. Re-register is only needed if the refresh token expires (90 days) or the user revokes consent.
37
41
 
38
42
  If the brand ships no vendor app yet, `outlook-account-register` reports that the client ID is not configured. There is no per-install workaround; the brand's vendor app has to exist first.
39
43
 
40
- **Re-connecting a mailbox that already granted access.** First-time registration works cleanly. But if the target Microsoft account has *already* consented to this brand's app on a prior registration, starting a fresh `outlook-account-register` for it dead-ends: after the operator enters the code, Microsoft's consent step redirects the browser to a `http://localhost` "this site can't be reached" page instead of completing. This is Microsoft's re-consent behaviour for a personal account (outlook.com, hotmail.com, live.com), not a fault in this plugin; our device-code request is unchanged, and the connected mailbox keeps working throughout. The block is the stale Microsoft-side grant, and there is no server-side tool to clear it because that grant lives in the end user's own Microsoft account. To re-connect, the operator first revokes this app at **https://account.microsoft.com/privacy/app-access** (find the brand's app, remove it), then re-runs `outlook-account-register`; the next sign-in is treated as new and completes. Relay this to the operator whenever a re-registration stalls at a localhost page.
44
+ **Re-connecting a mailbox that already granted access.** Re-registering an already-connected mailbox is normally just the poll flow above. The sign-in completes, and `outlook-account-register-poll` overwrites the stored record in place (same `graphUserId`, no duplicate, any previously-blank fields such as the email backfilled) with no revoke and no removal step. This is the case for work/school accounts (Microsoft 365) whose sign-in completes normally: they need only the poll.
45
+
46
+ The revoke path below is scoped to one specific, visible failure. It is not a general "revoke before re-registering" rule, and applying it that way sends the operator on an unnecessary detour. It applies **only when a re-registration visibly stalls at a `http://localhost` "this site can't be reached" page** after the operator enters the code. That stall is Microsoft's re-consent behaviour for a *personal* account (outlook.com, hotmail.com, live.com) that has already consented to this brand's app. It is not a fault in this plugin (our device-code request is unchanged, and the connected mailbox keeps working throughout), and there is no server-side tool to clear it because the stale grant lives in the end user's own Microsoft account. Only in that localhost-stall case: the operator revokes this app at **https://account.microsoft.com/privacy/app-access** (find the brand's app, remove it), then re-runs `outlook-account-register`; the next sign-in is treated as new and completes. If a re-registration does not stall at a localhost page, do not send the operator to revoke. Just poll to `registered`.
41
47
 
42
48
  **Microsoft mail does not use IMAP or app passwords.** Microsoft retired Basic auth for Exchange Online and app passwords stopped working. Never route a Microsoft mailbox through the `email` plugin's IMAP path, and never suggest an app password. The device-code flow above is the only supported connection.
43
49
 
@@ -12789,18 +12789,25 @@ function operatorRoleFor(config, userId) {
12789
12789
  return config.admins?.find((a) => a.userId === userId)?.role ?? "admin";
12790
12790
  }
12791
12791
  async function buildAccountOptionList(accounts, userId) {
12792
- const houseFirst = [
12793
- ...accounts.filter((a) => a.config.role === "house"),
12794
- ...accounts.filter((a) => a.config.role !== "house")
12795
- ];
12796
12792
  const houseAccount = accounts.find((a) => a.config.role === "house");
12797
12793
  console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
12798
- return Promise.all(
12799
- houseFirst.map(async (a) => {
12800
- const businessName = await fetchAccountName(a.accountId) || void 0;
12801
- return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
12802
- })
12794
+ const resolve36 = async (a) => {
12795
+ const businessName = await fetchAccountName(a.accountId) || void 0;
12796
+ return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
12797
+ };
12798
+ const houseOptions = await Promise.all(
12799
+ accounts.filter((a) => a.config.role === "house").map(resolve36)
12803
12800
  );
12801
+ const nonHouseOptions = await Promise.all(
12802
+ accounts.filter((a) => a.config.role !== "house").map(resolve36)
12803
+ );
12804
+ const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
12805
+ nonHouseOptions.sort((x, y) => {
12806
+ const byName = sortKey(x).localeCompare(sortKey(y));
12807
+ if (byName !== 0) return byName;
12808
+ return x.accountId.localeCompare(y.accountId);
12809
+ });
12810
+ return [...houseOptions, ...nonHouseOptions];
12804
12811
  }
12805
12812
  var app12 = new Hono();
12806
12813
  app12.get("/", async (c) => {