@rubytech/create-maxy-code 0.1.455 → 0.1.456
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/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +24 -6
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +10 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +44 -4
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -2
- package/payload/platform/plugins/docs/references/outlook-guide.md +2 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-bootstrap.test.js +52 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-bootstrap.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +11 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +6 -2
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/has-attachments.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/has-attachments.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/has-attachments.test.js +66 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/has-attachments.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-attachment.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-attachment.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-attachment.test.js +195 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-attachment.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +19 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.d.ts +55 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.js +130 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-attachment.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts +1 -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 +2 -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-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/references/graph-surfaces.md +18 -3
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +2 -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/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-WC4WJR6X.js → chunk-F4D35LKL.js} +7 -3
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +1 -1
- package/payload/server/{userprofile-reconcile-GLGKDVQQ.js → userprofile-reconcile-QHVLY2AH.js} +12 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "admin",
|
|
3
|
-
"description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder \"Owner\" and seeding it onto the sub-account's owner AdminUser and owner Person, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder \"Owner\", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
|
|
3
|
+
"description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder \"Owner\" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder \"Owner\", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rubytech LLC"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: admin
|
|
3
3
|
surface: platform
|
|
4
|
-
description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder "Owner" and seeding it onto the sub-account's owner AdminUser and owner Person, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder "Owner", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
|
|
4
|
+
description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder "Owner" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder "Owner", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
|
|
5
5
|
tools:
|
|
6
6
|
- name: system-status
|
|
7
7
|
publicAllowlist: false
|
|
@@ -28,7 +28,7 @@ import { publishSite } from "./tools/publish-site.js";
|
|
|
28
28
|
import { resolveCapabilitiesHere } from "./tools/capabilities-here.js";
|
|
29
29
|
import { runCatalogueCensus } from "./lib/catalogue-census.js";
|
|
30
30
|
import { lifelineTool } from "../../../../lib/mcp-lifeline/dist/index.js";
|
|
31
|
-
import { listAccountsFromDir, isHouseAccount, archiveAccountDir, provisionClientAccount, findHouseAccount, getChannelRoutingAccountId, setChannelRoutingAccountId, seedAccountGraphRoot, isPlaceholderOwnerName, isBlankBusinessName, refuseClientAdminAdd, readHouseAdminUserIds, setManagingAdmin, findClientAccountsManagedBy, reassignManagingAdmin, ACCOUNT_NODE_COUNT_CYPHER, ACCOUNT_PURGE_CYPHER, classifyManagingAdmin, ownerNameStatus, readManagingAdminUserId, setOwnerName, } from "./tools/account-lifecycle.js";
|
|
31
|
+
import { listAccountsFromDir, isHouseAccount, archiveAccountDir, provisionClientAccount, findHouseAccount, getChannelRoutingAccountId, setChannelRoutingAccountId, seedAccountGraphRoot, isPlaceholderOwnerName, isBlankBusinessName, isValidTimeZone, refuseClientAdminAdd, readHouseAdminUserIds, setManagingAdmin, findClientAccountsManagedBy, reassignManagingAdmin, ACCOUNT_NODE_COUNT_CYPHER, ACCOUNT_PURGE_CYPHER, classifyManagingAdmin, ownerNameStatus, readManagingAdminUserId, setOwnerName, } from "./tools/account-lifecycle.js";
|
|
32
32
|
function refusalGuidance(kind) {
|
|
33
33
|
switch (kind) {
|
|
34
34
|
case "unsafe-slug":
|
|
@@ -3416,11 +3416,12 @@ eagerTool(server, "account_roster", "Canonical per-account identity roster for t
|
|
|
3416
3416
|
process.stderr.write(`${TAG} op=roster accounts=${accounts.length} nameless-owners=${namelessOwners} absent-mgr=${absentMgr} dangling-mgr=${danglingMgr}\n`);
|
|
3417
3417
|
return { content: [{ type: "text", text: accounts.length ? `Account roster:\n\n${lines.join("\n")}` : "No accounts found." }] };
|
|
3418
3418
|
});
|
|
3419
|
-
eagerTool(server, "account_create", "Provision a new CLIENT sub-account on this install (managed service). REQUIRES `businessName`, the real name of the client business itself,
|
|
3419
|
+
eagerTool(server, "account_create", "Provision a new CLIENT sub-account on this install (managed service). REQUIRES `businessName`, the real name of the client business itself, `ownerName`, the real name of the client business's owner, and `timezone`, the owner's IANA timezone (ask the operator for all three — never invent them or reuse the house operator's name/zone). OPTIONALLY takes `adminUserId`, the userId of the house team member who will manage this client (get the choices from admin-list; ask the operator, but omit it if the client is run by its owner rather than a house admin). Mints a UUID, scaffolds the account directory (agents, specialists, settings, account.json with role:\"client\", and managingAdminUserId when an admin is named), seeds default plugins, and seeds the account's graph root (a :LocalBusiness carrying businessName plus its owner :AdminUser, owner :Person carrying ownerName, and owner :UserProfile carrying the timezone) so you can populate it immediately and the sub-account picker shows the business name at once. Refuses if businessName is missing/blank, if ownerName is missing/blank/the placeholder \"Owner\", if timezone is missing or not a valid IANA zone, or if a supplied adminUserId is not a current house admin. When no managing admin is set, that account's passive-intake tasks route to the install's primary admin. Returns the new accountId. Operator-only; never creates the house sub-account (that is the install itself).", {
|
|
3420
3420
|
adminUserId: z.string().optional().describe("The userId of the house admin who will manage this client sub-account. Optional — omit it for a client run by its owner rather than a house admin (its passive-intake tasks then route to the install's primary admin). When supplied, it must be a current house admin (see admin-list) or creation is refused."),
|
|
3421
3421
|
businessName: z.string().describe("The real name of the client business itself. Written onto the new sub-account's :LocalBusiness so the sub-account picker/header shows it immediately. Required — creation is refused when missing or blank. Ask the operator for the client's real business name; never invent it."),
|
|
3422
3422
|
ownerName: z.string().describe("The real name of the client business's owner. Applied to both the owner AdminUser and owner Person for the new sub-account. Required — creation is refused when missing, blank, or the placeholder \"Owner\". Ask the operator; never reuse the house operator's name."),
|
|
3423
|
-
|
|
3423
|
+
timezone: z.string().describe("The client business owner's IANA timezone, e.g. \"Europe/London\" or \"America/New_York\". Written onto the owner :UserProfile so scheduling and locale time formatting use the owner's real zone from the start, not the server's. Required — creation is refused when missing or not a valid IANA zone. Ask the operator for the owner's location; never guess or reuse the house zone."),
|
|
3424
|
+
}, async ({ adminUserId, businessName, ownerName, timezone }) => {
|
|
3424
3425
|
if (!ACCOUNT_ID)
|
|
3425
3426
|
return refuseNoAccount("account_create");
|
|
3426
3427
|
// Task 1630 — a managing admin is optional. `adminUserId` omitted/blank ⇒ the
|
|
@@ -3445,6 +3446,20 @@ eagerTool(server, "account_create", "Provision a new CLIENT sub-account on this
|
|
|
3445
3446
|
process.stderr.write(`[account-create] op=refused reason=no-business-name\n`);
|
|
3446
3447
|
return { content: [{ type: "text", text: `account_create refused: give the client business's real name (businessName). It cannot be blank. Ask the operator what the client business is called.` }], isError: true };
|
|
3447
3448
|
}
|
|
3449
|
+
// Task 1685 — the owner's timezone is a hard precondition, refused before any
|
|
3450
|
+
// scaffold so a create with no zone leaves no partial account behind. It is
|
|
3451
|
+
// seeded onto the owner :UserProfile marked owner-set (seedAccountGraphRoot),
|
|
3452
|
+
// so scheduling reads the owner's real zone rather than the box's default.
|
|
3453
|
+
// Empty and non-IANA are distinct refusals so the operator knows which to fix.
|
|
3454
|
+
const timezoneInput = timezone.trim();
|
|
3455
|
+
if (timezoneInput === "") {
|
|
3456
|
+
process.stderr.write(`[account-create] op=refused reason=no-timezone\n`);
|
|
3457
|
+
return { content: [{ type: "text", text: `account_create refused: give the client owner's timezone (timezone), e.g. "Europe/London". Ask the operator where the owner is based; it sets their scheduling and time formatting.` }], isError: true };
|
|
3458
|
+
}
|
|
3459
|
+
if (!isValidTimeZone(timezoneInput)) {
|
|
3460
|
+
process.stderr.write(`[account-create] op=refused reason=bad-timezone\n`);
|
|
3461
|
+
return { content: [{ type: "text", text: `account_create refused: "${timezoneInput}" is not a valid IANA timezone. Use a zone name like "Europe/London" or "America/New_York" — ask the operator for the owner's location and map it to the IANA zone.` }], isError: true };
|
|
3462
|
+
}
|
|
3448
3463
|
if (managingAdminUserId && !readHouseAdminUserIds(ACCOUNTS_ROOT).includes(managingAdminUserId)) {
|
|
3449
3464
|
process.stderr.write(`[account-lifecycle] op=create-refused reason=unknown-admin adminUserId=${managingAdminUserId.slice(0, 8)}\n`);
|
|
3450
3465
|
return { content: [{ type: "text", text: `account_create refused: ${managingAdminUserId} is not a current house admin. Call admin-list for the valid managing-admin choices, or omit adminUserId to leave the client unmanaged.` }], isError: true };
|
|
@@ -3478,22 +3493,25 @@ eagerTool(server, "account_create", "Provision a new CLIENT sub-account on this
|
|
|
3478
3493
|
const seedSession = getSession();
|
|
3479
3494
|
let rootSeeded = false;
|
|
3480
3495
|
try {
|
|
3481
|
-
const { businessSeeded, adminSeeded } = await seedAccountGraphRoot({
|
|
3496
|
+
const { businessSeeded, adminSeeded, profileSeeded } = await seedAccountGraphRoot({
|
|
3482
3497
|
session: seedSession,
|
|
3483
3498
|
accountId: newId,
|
|
3484
3499
|
ownerUserId,
|
|
3485
3500
|
ownerName,
|
|
3486
3501
|
businessName,
|
|
3502
|
+
// Task 1685 — the validated IANA zone from the tool input (refused above
|
|
3503
|
+
// if blank/invalid). Seeded onto the owner :UserProfile as owner-set.
|
|
3504
|
+
timezone: timezoneInput,
|
|
3487
3505
|
createdAt: new Date().toISOString(),
|
|
3488
3506
|
});
|
|
3489
|
-
rootSeeded = businessSeeded && adminSeeded;
|
|
3507
|
+
rootSeeded = businessSeeded && adminSeeded && profileSeeded;
|
|
3490
3508
|
}
|
|
3491
3509
|
finally {
|
|
3492
3510
|
await seedSession.close();
|
|
3493
3511
|
}
|
|
3494
3512
|
process.stderr.write(`[account-lifecycle] op=create accountId=${newId} dir-exists=${dirExists} root-seeded=${rootSeeded} managingAdmin=${managingAdminUserId ? managingAdminUserId.slice(0, 8) : "-"}\n`);
|
|
3495
3513
|
if (!rootSeeded) {
|
|
3496
|
-
return { content: [{ type: "text", text: `account_create FAILED: graph root not seeded for ${newId} (business+admin read-back failed). The account directory was scaffolded but is rootless — run account_delete ${newId} and retry.` }], isError: true };
|
|
3514
|
+
return { content: [{ type: "text", text: `account_create FAILED: graph root not seeded for ${newId} (business+admin+profile read-back failed). The account directory was scaffolded but is rootless — run account_delete ${newId} and retry.` }], isError: true };
|
|
3497
3515
|
}
|
|
3498
3516
|
// Task 1500/1630 — persist the managing admin on the new sub-account when
|
|
3499
3517
|
// one was named. Skipped when adminUserId was omitted: the account is left
|