@rubytech/create-realagent-code 0.1.30 → 0.1.32
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/dist/index.js +37 -39
- package/package.json +1 -1
- package/payload/platform/lib/graph-trash/dist/index.d.ts +1 -1
- package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js +1 -2
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +1 -2
- package/payload/platform/lib/persistent-components/dist/index.d.ts +11 -12
- package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/persistent-components/dist/index.js +11 -12
- package/payload/platform/lib/persistent-components/dist/index.js.map +1 -1
- package/payload/platform/lib/persistent-components/src/index.ts +11 -12
- package/payload/platform/neo4j/schema.cypher +10 -19
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -7
- package/payload/platform/plugins/admin/mcp/dist/index.js +15 -582
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/access-manager/references/operations.md +7 -7
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +2 -2
- package/payload/platform/plugins/anthropic/skills/get-api-key/SKILL.md +2 -4
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +0 -47
- package/payload/platform/plugins/docs/references/cloudflare.md +0 -1
- package/payload/platform/plugins/docs/references/deployment.md +9 -18
- package/payload/platform/plugins/docs/references/internals.md +4 -4
- package/payload/platform/plugins/docs/references/platform.md +5 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +11 -7
- package/payload/platform/plugins/email/references/email-reference.md +3 -7
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +2 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +2 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +5 -5
- package/payload/platform/plugins/teaching/PLUGIN.md +2 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +1 -1
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -8
- package/payload/platform/plugins/writer-craft/PLUGIN.md +2 -1
- package/payload/platform/scripts/component-knowledgedoc-backfill.ts +1 -1
- package/payload/platform/scripts/seed-neo4j.sh +9 -38
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +45 -44
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +30 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +175 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +4 -2
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +15 -22
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +13 -14
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +28 -13
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +1 -25
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +3 -54
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
- package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
- package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -2
- package/payload/premium-plugins/teaching/PLUGIN.md +2 -1
- package/payload/premium-plugins/writer-craft/PLUGIN.md +2 -1
- package/payload/server/{chunk-NL7QLVAD.js → chunk-KVGTWNKQ.js} +1 -70
- package/payload/server/{chunk-2MRZBQMH.js → chunk-RZQMYJVY.js} +1 -1
- package/payload/server/{chunk-YPZFYTYP.js → chunk-ZGJ6CUU2.js} +1 -1
- package/payload/server/{cloudflare-task-tracker-QVOGHKWV.js → cloudflare-task-tracker-4PKOLE4H.js} +2 -2
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/{Checkbox-YIF0payo.js → Checkbox-C6zXApx_.js} +1 -1
- package/payload/server/public/assets/admin-Cuu1QdAA.js +216 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Bz8mlxZZ.js → architectureDiagram-Q4EWVU46-BYXgFii5.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DwV8Z8-i.js → blockDiagram-DXYQGD6D-GIQ0eO13.js} +1 -1
- package/payload/server/public/assets/{brand-Bm671owU.js → brand-B-bNrpwc.js} +1 -1
- package/payload/server/public/assets/{brand-DqiRNMlu.css → brand-DdhkC994.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DiUTejMp.js → c4Diagram-AHTNJAMY-BmyWfG-l.js} +1 -1
- package/payload/server/public/assets/channel-C76knBRO.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-4mHZpBXe.js → chunk-336JU56O-DcWl0MQo.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-Cbv0vrN9.js → chunk-426QAEUC-BIW6kq6y.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BvLhId_2.js → chunk-4TB4RGXK-CdoHpV4X.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-bBafOTkw.js → chunk-5FUZZQ4R-bn_a4sfU.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-B0NqBKVy.js → chunk-5PVQY5BW-C_Rq8j_M.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CFd4SqI6.js → chunk-EDXVE4YY-CWQvoVKV.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-ajf2sb6c.js → chunk-ENJZ2VHE-DBHn1kSk.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-pWg6bug7.js → chunk-ICPOFSXX-SW2Qx11O.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-OjEd-17c.js → chunk-OYMX7WX6-BvIG7tVW.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-DbEFSPoh.js → chunk-U2HBQHQK-BiBUb0cF.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-COdNwrBb.js → chunk-X2U36JSP-Y0MKZCCh.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CHMWuY9B.js → chunk-YZCP3GAM-DKPh06GH.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-B-uDLQOB.js → chunk-ZZ45TVLE-C2WNo-fK.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Bohexn7P.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DVsmsAu7.js +1 -0
- package/payload/server/public/assets/clone-DUrXF4sO.js +1 -0
- package/payload/server/public/assets/{dagre-bhIG_KnW.js → dagre-CrK8E9ee.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-CMEzmhIL.js → dagre-KV5264BT-_o6uXcH8.js} +1 -1
- package/payload/server/public/assets/data-j1WNhF8t.js +1 -0
- package/payload/server/public/assets/{device-url-actions-AcOyLSeF.js → device-url-actions-BcHerWqJ.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-6RIoQhIL.js → diagram-5BDNPKRD-FFP9DKhc.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BSp36TVv.js → diagram-G4DWMVQ6-DpwD1jBP.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-D54fo52D.js → diagram-MMDJMWI5-C3K5agdK.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CWL8z-Pq.js → diagram-TYMM5635-CbeDipbC.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-AnnHBo3z.js → erDiagram-SMLLAGMA-XBIFndNy.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-laWmBl5o.js → flowDiagram-DWJPFMVM-BvEgySyn.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B94ko8ie.js → ganttDiagram-T4ZO3ILL-D7gIRKJf.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DxzL1fxZ.js → gitGraphDiagram-UUTBAWPF-vJu_hcri.js} +1 -1
- package/payload/server/public/assets/graph-C_f_9L_7.js +1 -0
- package/payload/server/public/assets/graph-labels-BSQJHlgf.js +1 -0
- package/payload/server/public/assets/{graphlib-CY-zIElM.js → graphlib-Dp0mN6JW.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-BMTajIIr.js → infoDiagram-42DDH7IO-g4Dlc5Cr.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B_QauE5O.js → ishikawaDiagram-UXIWVN3A-D_45LXOe.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DmlqSIih.js → journeyDiagram-VCZTEJTY-CggbHl6N.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-ZGDQT7xB.js → kanban-definition-6JOO6SKY-CysAe-Ab.js} +1 -1
- package/payload/server/public/assets/{line-D13opgep.js → line-BAxq_DSY.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-C650Sual.js → mermaid-parser.core-DbFuvkjL.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BqnQoXTp.js → mermaid.core-CehvJn5b.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BS_8y-tY.js → mindmap-definition-QFDTVHPH-DbPbBJ9h.js} +1 -1
- package/payload/server/public/assets/page-B0BPrSE3.js +1 -0
- package/payload/server/public/assets/{page-qSH972X0.js → page-Co7KCRV8.js} +2 -2
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-B5OmNvBO.js → pieDiagram-DEJITSTG-cagLL9ng.js} +1 -1
- package/payload/server/public/assets/{public-DDsYgotk.js → public-B6TEcDLx.js} +5 -5
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DTYITdNo.js → quadrantDiagram-34T5L4WZ-Keaa1jDh.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CRZWxH06.js → requirementDiagram-MS252O5E-BcYRyn5z.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DazRENhe.js → sankeyDiagram-XADWPNL6--fKoG9NR.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BcHTxmPy.js → sequenceDiagram-FGHM5R23-lKG36-Di.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DYU7nbqg.js → stateDiagram-FHFEXIEX-BuVsrlig.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DSt88_xL.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BKGmqkST.js → timeline-definition-GMOUNBTQ-D6X6uq17.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BXvLPmX7.js → vennDiagram-DHZGUBPP-BgvcfRVf.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BCclUa3Z.js → wardleyDiagram-NUSXRM2D-Cpd1xsrt.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-C-Xp-Eoc.js → xychartDiagram-5P7HB3ND-CDF5ZVFv.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +142 -278
- package/payload/platform/plugins/admin/hooks/onboarding-skill-drift.sh +0 -102
- package/payload/platform/plugins/admin/references/contextual-ui.md +0 -109
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +0 -240
- package/payload/platform/scripts/__tests__/admin-persist-audit.test.ts +0 -182
- package/payload/server/public/assets/admin-CDvF5de6.js +0 -216
- package/payload/server/public/assets/channel-PtVtoBEL.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-RVH_SEhY.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Cm3rAb93.js +0 -1
- package/payload/server/public/assets/clone-BjY0Wzht.js +0 -1
- package/payload/server/public/assets/data-K_kS__sL.js +0 -1
- package/payload/server/public/assets/graph-DeEigyO_.js +0 -1
- package/payload/server/public/assets/graph-labels-C7I5QvNv.js +0 -1
- package/payload/server/public/assets/page-B_rpjIRr.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BgljVtlp.js +0 -1
|
@@ -8,9 +8,8 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
8
8
|
import { resolve, join } from "node:path";
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
10
|
import { appendFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { writeKey, validateKey,
|
|
11
|
+
import { writeKey, validateKey, keyFilePath } from "../../../../lib/anthropic-key/dist/index.js";
|
|
12
12
|
import { writeAdminEntry, removeAdminFromAccount } from "../../../../lib/admins-write/dist/index.js";
|
|
13
|
-
import { isPersistentComponent } from "../../../../lib/persistent-components/dist/index.js";
|
|
14
13
|
import { deviceUrlBlock } from "../../../../lib/device-url/dist/index.js";
|
|
15
14
|
import { substituteBrandPlaceholders } from "../../../../lib/brand-templating/dist/index.js";
|
|
16
15
|
import { resolveEntitlement } from "../../../../lib/entitlement/dist/index.js";
|
|
@@ -19,7 +18,6 @@ import { createConnection } from "node:net";
|
|
|
19
18
|
import { homedir, hostname as osHostname } from "node:os";
|
|
20
19
|
import QRCode from "qrcode";
|
|
21
20
|
import { getSession, closeDriver } from "./lib/neo4j.js";
|
|
22
|
-
import { getOnboardingState, completeOnboardingStep } from "./lib/onboarding.js";
|
|
23
21
|
import { findSkillOwners, computePluginReadHint, loadSkill, parseRequiredInputs } from "./skill-resolution.js";
|
|
24
22
|
import { resolvePublicHostname } from "./lib/public-hostname.js";
|
|
25
23
|
const server = new McpServer({
|
|
@@ -486,70 +484,6 @@ eagerTool(server, "brand-settings", "Read the brand/styling configuration (name,
|
|
|
486
484
|
};
|
|
487
485
|
}
|
|
488
486
|
});
|
|
489
|
-
/* ── Plugin selector options (deterministic) ────────────────────── */
|
|
490
|
-
const PLUGIN_DISPLAY = {
|
|
491
|
-
admin: { value: "admin", label: "admin", description: "Platform management — system status, account settings, logs, session control." },
|
|
492
|
-
memory: { value: "memory", label: "memory", description: "Graph memory — search, write, reindex, and ingest knowledge." },
|
|
493
|
-
docs: { value: "docs", label: "maxy-guide", description: "User guide and platform documentation — loaded on demand." },
|
|
494
|
-
cloudflare: { value: "cloudflare", label: "cloudflare", description: "Cloudflare Tunnel — expose your assistant publicly via a custom domain." },
|
|
495
|
-
anthropic: { value: "anthropic", label: "anthropic", description: "Claude connection — API key acquisition and configuration." },
|
|
496
|
-
scheduling: { value: "scheduling", label: "scheduling", description: "Calendar and scheduling — events, appointments, recurring triggers." },
|
|
497
|
-
email: { value: "email", label: "email", description: "Agent email account — setup, read, send, search." },
|
|
498
|
-
contacts: { value: "contacts", label: "contacts", description: "CRM contact management — create, lookup, update, list." },
|
|
499
|
-
tasks: { value: "tasks", label: "tasks", description: "Graph-backed task lifecycle — create, update, list, relate, complete." },
|
|
500
|
-
workflows: { value: "workflows", label: "workflows", description: "Persistent named workflows — reusable instruction sets." },
|
|
501
|
-
projects: { value: "projects", label: "projects", description: "Structured project execution — phased sprints, investigations, reviews, retrospectives." },
|
|
502
|
-
"business-assistant": { value: "business-assistant", label: "business-assistant", description: "Customer enquiries, scheduling, quoting, invoicing, daily briefings. Enhances: personal-assistant" },
|
|
503
|
-
sales: { value: "sales", label: "sales", description: "Buying signal detection, closing techniques, objection handling. Enhances: personal-assistant" },
|
|
504
|
-
"deep-research": { value: "deep-research", label: "deep-research", description: "Structured multi-source research — query decomposition, source evaluation, citation formatting. Enhances: research-assistant" },
|
|
505
|
-
telegram: { value: "telegram", label: "telegram", description: "Telegram bot setup — BotFather, admin and public channels. Enhances: personal-assistant" },
|
|
506
|
-
whatsapp: { value: "whatsapp", label: "whatsapp", description: "WhatsApp messaging, pairing, and conversation browsing. Enhances: personal-assistant" },
|
|
507
|
-
waitlist: { value: "waitlist", label: "waitlist", description: "Waitlist lifecycle — extract sign-ups, review, schedule automation." },
|
|
508
|
-
replicate: { value: "replicate", label: "replicate", description: "Image generation — photorealistic, design, and fast draft images via Replicate. Enhances: content-producer, research-assistant" },
|
|
509
|
-
};
|
|
510
|
-
server.tool("onboarding-plugin-options", "Return the fully-assembled multi-select options array for onboarding Step 1. Classification (core/recommended/available) is derived from brand.json — the agent renders the result directly via render-component without further transformation.", {}, async () => {
|
|
511
|
-
try {
|
|
512
|
-
const brandPath = resolve(PLATFORM_ROOT, "config", "brand.json");
|
|
513
|
-
if (!existsSync(brandPath)) {
|
|
514
|
-
return { content: [{ type: "text", text: "No brand.json found at " + brandPath + " — platform not properly installed." }], isError: true };
|
|
515
|
-
}
|
|
516
|
-
const brand = JSON.parse(readFileSync(brandPath, "utf-8"));
|
|
517
|
-
const plugins = brand?.plugins;
|
|
518
|
-
if (!plugins)
|
|
519
|
-
return { content: [{ type: "text", text: "brand.json has no plugins configuration." }], isError: true };
|
|
520
|
-
const coreSet = new Set(plugins.core ?? []);
|
|
521
|
-
const defaultSet = new Set(plugins.defaultEnabled ?? []);
|
|
522
|
-
const availableSet = new Set(plugins.available ?? []);
|
|
523
|
-
const options = [];
|
|
524
|
-
for (const name of plugins.core ?? []) {
|
|
525
|
-
const meta = PLUGIN_DISPLAY[name] ?? { value: name, label: name, description: "" };
|
|
526
|
-
options.push({ ...meta, badge: "Core", group: "Core — always active", locked: true, defaultSelected: true });
|
|
527
|
-
}
|
|
528
|
-
for (const name of plugins.defaultEnabled ?? []) {
|
|
529
|
-
if (coreSet.has(name))
|
|
530
|
-
continue;
|
|
531
|
-
const meta = PLUGIN_DISPLAY[name] ?? { value: name, label: name, description: "" };
|
|
532
|
-
options.push({ ...meta, badge: "Recommended", group: "Maxy", defaultSelected: true });
|
|
533
|
-
}
|
|
534
|
-
for (const name of plugins.available ?? []) {
|
|
535
|
-
if (coreSet.has(name) || defaultSet.has(name))
|
|
536
|
-
continue;
|
|
537
|
-
const meta = PLUGIN_DISPLAY[name] ?? { value: name, label: name, description: "" };
|
|
538
|
-
options.push({ ...meta, group: "Maxy" });
|
|
539
|
-
}
|
|
540
|
-
// Task 976: signal that the onboarding skill will append three Anthropic
|
|
541
|
-
// vertical entries from the claude-for-financial-services and
|
|
542
|
-
// knowledge-work-plugins marketplaces. The count is fixed because the
|
|
543
|
-
// skill prose always appends the same three (kyc-screener,
|
|
544
|
-
// meeting-prep-agent, pdf-viewer). Absence of this line post-install
|
|
545
|
-
// = the group was not surfaced (release blocker per task spec).
|
|
546
|
-
console.error(`[plugin-onboarding] group=anthropic-verticals presented=3`);
|
|
547
|
-
return { content: [{ type: "text", text: JSON.stringify(options, null, 2) }] };
|
|
548
|
-
}
|
|
549
|
-
catch (err) {
|
|
550
|
-
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
487
|
eagerTool(server, "account-manage", "Read the account configuration (tier, domains, settings).", {}, async () => {
|
|
554
488
|
try {
|
|
555
489
|
const config = await readAccountConfig();
|
|
@@ -1769,50 +1703,15 @@ eagerTool(server, "skill-load", "Load a plugin skill's SKILL.md body by skill na
|
|
|
1769
1703
|
};
|
|
1770
1704
|
}
|
|
1771
1705
|
});
|
|
1772
|
-
// Task
|
|
1773
|
-
//
|
|
1774
|
-
//
|
|
1775
|
-
//
|
|
1776
|
-
//
|
|
1777
|
-
//
|
|
1778
|
-
//
|
|
1779
|
-
//
|
|
1780
|
-
//
|
|
1781
|
-
// in the admin server process (stream-parser path) because the SDK delivers
|
|
1782
|
-
// `tool_use.input` to the UI in the assistant message but the MCP handler's
|
|
1783
|
-
// return reaches only the agent — there is no path back to persistMessage
|
|
1784
|
-
// from here. This handler emits a one-line observability marker per
|
|
1785
|
-
// persistence-eligible call so operators can grep for the commitment, and
|
|
1786
|
-
// returns richer JSON so the doctrine grep
|
|
1787
|
-
// `render-component.*"rendered"` resolves to a persistence-aware handler
|
|
1788
|
-
// rather than a bare stub.
|
|
1789
|
-
eagerTool(server, "render-component", "Render a pre-built UI component inline in the conversation. " +
|
|
1790
|
-
"Call this instead of describing a UI — the component handles input collection. " +
|
|
1791
|
-
"Wait for the user's response before continuing.", {
|
|
1792
|
-
name: z.string().describe("Component name from the UI suite (e.g. single-select, confirm, info-card, form, progress)"),
|
|
1793
|
-
data: z.record(z.string(), z.unknown()),
|
|
1794
|
-
}, async ({ name, data }) => {
|
|
1795
|
-
if (isPersistentComponent(name)) {
|
|
1796
|
-
// Persistence-eligible: log the commitment so the live + audit grep
|
|
1797
|
-
// (`[render-component-persist]`) can correlate the MCP call against
|
|
1798
|
-
// the downstream :KnowledgeDocument MERGE. Byte counts come from
|
|
1799
|
-
// data.html (preferred) or data.content; both being absent is a
|
|
1800
|
-
// legitimate render of an empty editor and the projection is skipped
|
|
1801
|
-
// server-side.
|
|
1802
|
-
const html = typeof data?.html === "string" ? data.html : "";
|
|
1803
|
-
const content = typeof data?.content === "string" ? data.content : "";
|
|
1804
|
-
const bytes = html.length > 0 ? html.length : content.length;
|
|
1805
|
-
const mimeType = html.length > 0 ? "text/html" : (content.length > 0 ? "text/markdown" : "");
|
|
1806
|
-
console.error(`[render-component-persist] componentName=${name} bytes=${bytes} mimeType=${mimeType || "none"}`);
|
|
1807
|
-
return {
|
|
1808
|
-
content: [{
|
|
1809
|
-
type: "text",
|
|
1810
|
-
text: JSON.stringify({ rendered: true, name, persistent: true, bytes, mimeType }),
|
|
1811
|
-
}],
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
return { content: [{ type: "text", text: "rendered" }] };
|
|
1815
|
-
});
|
|
1706
|
+
// Task 066 — the inline UI-component tool is gone from the admin surface
|
|
1707
|
+
// on native Claude Code. The PTY runtime has no host bridge for the UI
|
|
1708
|
+
// primitives the legacy tool wrapped; calling it logged a "rendered"
|
|
1709
|
+
// sentinel that read like a successful render to the agent while the
|
|
1710
|
+
// chat surface saw nothing. Admin flows now use plain markdown for
|
|
1711
|
+
// reviewable artefacts (`skills/file-presentation/SKILL.md`) and
|
|
1712
|
+
// `file-attach` for downloadable artefacts. The :Component / :KnowledgeDocument
|
|
1713
|
+
// persistence pipeline is preserved for historical conversations that
|
|
1714
|
+
// already carry the rows; no new conversations write to it.
|
|
1816
1715
|
eagerTool(server, "session-reset", "Reset the current session. Compacts conversation history to memory, clears the visible conversation, " +
|
|
1817
1716
|
"and starts a fresh session with a new greeting. Call when the user asks to start a new session, " +
|
|
1818
1717
|
"clear the conversation, or start fresh.", {}, async () => ({ content: [{ type: "text", text: "reset" }] }));
|
|
@@ -1887,473 +1786,6 @@ eagerTool(server, "api-key-verify", "Verify the stored Anthropic API key works b
|
|
|
1887
1786
|
};
|
|
1888
1787
|
});
|
|
1889
1788
|
// ===================================================================
|
|
1890
|
-
// Anthropic setup — deterministic state machine
|
|
1891
|
-
// ===================================================================
|
|
1892
|
-
/*
|
|
1893
|
-
* anthropic-setup state machine (action-relay pattern)
|
|
1894
|
-
*
|
|
1895
|
-
* Call 1: anthropic-setup({})
|
|
1896
|
-
* ├─ no public endpoint → { status: "not_needed" } ← Phase 0 gate
|
|
1897
|
-
* ├─ key stored + valid? → { status: "complete" }
|
|
1898
|
-
* ├─ key stored + billing → { status: "awaiting_credits" }
|
|
1899
|
-
* ├─ key stored + error → { status: "error" }
|
|
1900
|
-
* └─ no key → { status: "awaiting_signin", action }
|
|
1901
|
-
*
|
|
1902
|
-
* Call 2: anthropic-setup({ consoleResult: "..." })
|
|
1903
|
-
* ├─ no_session → { status: "awaiting_signin", action }
|
|
1904
|
-
* ├─ no_org → { status: "error" }
|
|
1905
|
-
* ├─ no_credits → { status: "awaiting_credits", action }
|
|
1906
|
-
* ├─ success → writeKey → validateKey → { status: "complete" }
|
|
1907
|
-
* └─ *_failed → { status: "error" }
|
|
1908
|
-
*/
|
|
1909
|
-
const CONSOLE_BASE = "https://platform.claude.com";
|
|
1910
|
-
/**
|
|
1911
|
-
* JavaScript expression for browser_evaluate that runs the complete
|
|
1912
|
-
* Console API pipeline in one call: check session → find API org →
|
|
1913
|
-
* check credits → create key. Returns a structured JSON result.
|
|
1914
|
-
*/
|
|
1915
|
-
function consoleEvaluateExpression(keyName) {
|
|
1916
|
-
return `async () => {
|
|
1917
|
-
try {
|
|
1918
|
-
const orgsRes = await fetch("/api/organizations", { credentials: "include" });
|
|
1919
|
-
if (orgsRes.status === 401 || orgsRes.status === 403) {
|
|
1920
|
-
return JSON.stringify({ status: "no_session" });
|
|
1921
|
-
}
|
|
1922
|
-
if (!orgsRes.ok) {
|
|
1923
|
-
return JSON.stringify({ status: "fetch_error", error: "organizations: " + orgsRes.status });
|
|
1924
|
-
}
|
|
1925
|
-
const orgs = await orgsRes.json();
|
|
1926
|
-
const apiOrg = orgs.find(o => o.capabilities && o.capabilities.includes("api"));
|
|
1927
|
-
if (!apiOrg) {
|
|
1928
|
-
return JSON.stringify({ status: "no_org" });
|
|
1929
|
-
}
|
|
1930
|
-
const creditsRes = await fetch("/api/organizations/" + apiOrg.uuid + "/prepaid/credits", { credentials: "include" });
|
|
1931
|
-
if (!creditsRes.ok) {
|
|
1932
|
-
return JSON.stringify({ status: "fetch_error", error: "credits: " + creditsRes.status });
|
|
1933
|
-
}
|
|
1934
|
-
const credits = await creditsRes.json();
|
|
1935
|
-
if (typeof credits.amount === "number" && credits.amount <= 0) {
|
|
1936
|
-
return JSON.stringify({ status: "no_credits", orgId: apiOrg.uuid, orgName: apiOrg.name, creditUrl: "${CONSOLE_BASE}/settings/billing" });
|
|
1937
|
-
}
|
|
1938
|
-
const createRes = await fetch("/api/console/organizations/" + apiOrg.uuid + "/workspaces/default/api_keys", {
|
|
1939
|
-
method: "POST",
|
|
1940
|
-
credentials: "include",
|
|
1941
|
-
headers: { "content-type": "application/json" },
|
|
1942
|
-
body: JSON.stringify({ name: ${JSON.stringify(keyName)} })
|
|
1943
|
-
});
|
|
1944
|
-
if (!createRes.ok) {
|
|
1945
|
-
return JSON.stringify({ status: "create_failed", error: "key creation: " + createRes.status });
|
|
1946
|
-
}
|
|
1947
|
-
const keyData = await createRes.json();
|
|
1948
|
-
if (!keyData.raw_key) {
|
|
1949
|
-
return JSON.stringify({ status: "create_failed", error: "no raw_key in response" });
|
|
1950
|
-
}
|
|
1951
|
-
return JSON.stringify({
|
|
1952
|
-
status: "success",
|
|
1953
|
-
key: keyData.raw_key,
|
|
1954
|
-
keyId: keyData.id,
|
|
1955
|
-
keyHint: keyData.partial_key_hint,
|
|
1956
|
-
orgName: apiOrg.name,
|
|
1957
|
-
credits: credits.amount
|
|
1958
|
-
});
|
|
1959
|
-
} catch (err) {
|
|
1960
|
-
return JSON.stringify({ status: "fetch_error", error: String(err) });
|
|
1961
|
-
}
|
|
1962
|
-
}`;
|
|
1963
|
-
}
|
|
1964
|
-
function anthropicResult(r) {
|
|
1965
|
-
return {
|
|
1966
|
-
content: [{ type: "text", text: JSON.stringify(r, null, 2) }],
|
|
1967
|
-
...(r.status === "error" ? { isError: true } : {}),
|
|
1968
|
-
};
|
|
1969
|
-
}
|
|
1970
|
-
/**
|
|
1971
|
-
* Check whether a public-facing hostname is configured. The Anthropic API key
|
|
1972
|
-
* powers the public agent only — admin runs on Claude OAuth — so without a
|
|
1973
|
-
* public endpoint there is nothing for the key to power.
|
|
1974
|
-
*
|
|
1975
|
-
* Mirrors the runtime `isPublicHost(host)` predicate in
|
|
1976
|
-
* `platform/ui/server/index.ts`: a host is public iff it starts with `public.`
|
|
1977
|
-
* OR is listed in `~/{configDir}/alias-domains.json`. Step 7's form submit
|
|
1978
|
-
* handler at `platform/ui/server/routes/admin/cloudflare.ts` writes secondary
|
|
1979
|
-
* hostnames (apex + custom public labels) to `alias-domains.json` and skips
|
|
1980
|
-
* `public.*` because the prefix itself is the signal — so the two predicates
|
|
1981
|
-
* together cover every shape the form can produce.
|
|
1982
|
-
*
|
|
1983
|
-
* Returns true if any configured hostname satisfies either predicate.
|
|
1984
|
-
*/
|
|
1985
|
-
function hasPublicEndpointConfigured() {
|
|
1986
|
-
const aliasPath = join(CONFIG_DIR, "alias-domains.json");
|
|
1987
|
-
if (existsSync(aliasPath)) {
|
|
1988
|
-
try {
|
|
1989
|
-
const parsed = JSON.parse(readFileSync(aliasPath, "utf-8"));
|
|
1990
|
-
if (Array.isArray(parsed)) {
|
|
1991
|
-
const entries = parsed.filter((h) => typeof h === "string" && h.length > 0);
|
|
1992
|
-
if (entries.length > 0) {
|
|
1993
|
-
return { has: true, reason: `alias-domains.json: ${entries.join(", ")}` };
|
|
1994
|
-
}
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
catch {
|
|
1998
|
-
// Malformed file — treat as empty; matches the server-side reader's tolerance.
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
const cfConfigPath = join(CONFIG_DIR, "cloudflared", "config.yml");
|
|
2002
|
-
if (existsSync(cfConfigPath)) {
|
|
2003
|
-
try {
|
|
2004
|
-
const yaml = readFileSync(cfConfigPath, "utf-8");
|
|
2005
|
-
const hostnames = [...yaml.matchAll(/^\s*-\s*hostname:\s*(\S+)/gm)].map((m) => m[1]);
|
|
2006
|
-
const publicPrefixed = hostnames.find((h) => h.startsWith("public."));
|
|
2007
|
-
if (publicPrefixed) {
|
|
2008
|
-
return { has: true, reason: `cloudflared/config.yml ingress: ${publicPrefixed}` };
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
catch {
|
|
2012
|
-
// Unreadable — treat as no public host.
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
return {
|
|
2016
|
-
has: false,
|
|
2017
|
-
reason: "no entries in alias-domains.json and no public.* hostname in cloudflared/config.yml",
|
|
2018
|
-
};
|
|
2019
|
-
}
|
|
2020
|
-
eagerTool(server, "anthropic-setup", "Deterministic state machine for Anthropic API key acquisition. " +
|
|
2021
|
-
"Checks current state, advances as far as possible, and returns a structured JSON result. " +
|
|
2022
|
-
"On first call (no consoleResult): first verifies a public-facing endpoint is configured " +
|
|
2023
|
-
"(the key only powers the public agent); if not, returns status 'not_needed'. Otherwise " +
|
|
2024
|
-
"checks if a valid key is already stored. If not, returns status 'awaiting_signin' with " +
|
|
2025
|
-
"a browser_evaluate action — the agent must open the browser to platform.claude.com, run " +
|
|
2026
|
-
"the action's function via browser_evaluate, and pass the string result back as " +
|
|
2027
|
-
"consoleResult on the next call. " +
|
|
2028
|
-
"On second call (with consoleResult): parses the Console API result, stores the key, " +
|
|
2029
|
-
"verifies it, and returns status 'complete'. " +
|
|
2030
|
-
"Statuses: complete (key stored and verified), not_needed (no public endpoint configured — " +
|
|
2031
|
-
"skip the step), awaiting_signin (user must sign in to Console), awaiting_credits (signed in " +
|
|
2032
|
-
"but no credits — user must add credits), error (fatal — relay message).", {
|
|
2033
|
-
consoleResult: z.string().optional().describe("JSON string result from running the browser_evaluate action returned by a prior call. " +
|
|
2034
|
-
"Omit on the first call."),
|
|
2035
|
-
}, async ({ consoleResult }) => {
|
|
2036
|
-
const log = (msg) => console.error(`[anthropic-setup] ${msg}`);
|
|
2037
|
-
// ── Phase 0: gate on public endpoint existence ─────────────
|
|
2038
|
-
// The API key only powers the public-facing agent. If no public hostname
|
|
2039
|
-
// is configured (operator skipped step 7, or completed it without a
|
|
2040
|
-
// public/apex hostname) the key has no consumer — short-circuit before
|
|
2041
|
-
// any Console interaction so we never create keys the operator cannot use.
|
|
2042
|
-
if (!consoleResult) {
|
|
2043
|
-
const publicCheck = hasPublicEndpointConfigured();
|
|
2044
|
-
if (!publicCheck.has) {
|
|
2045
|
-
log(`gate: no public endpoint (${publicCheck.reason}) — returning not_needed`);
|
|
2046
|
-
return anthropicResult({
|
|
2047
|
-
status: "not_needed",
|
|
2048
|
-
message: "No public-facing endpoint is configured, so an Anthropic API key is not needed. " +
|
|
2049
|
-
"The key powers the public agent only — admin runs on your Claude OAuth session. " +
|
|
2050
|
-
"When you set up a public hostname via Cloudflare (or apex domain), come back and " +
|
|
2051
|
-
"ask to set up the API key then.",
|
|
2052
|
-
});
|
|
2053
|
-
}
|
|
2054
|
-
log(`gate: public endpoint present (${publicCheck.reason})`);
|
|
2055
|
-
}
|
|
2056
|
-
// ── Phase 1: check stored key ──────────────────────────────
|
|
2057
|
-
if (!consoleResult) {
|
|
2058
|
-
log("checking stored key");
|
|
2059
|
-
if (hasKey()) {
|
|
2060
|
-
const verification = await validateKey();
|
|
2061
|
-
log(`stored key verification: ${verification.status}`);
|
|
2062
|
-
switch (verification.status) {
|
|
2063
|
-
case "valid":
|
|
2064
|
-
log("key valid, returning complete");
|
|
2065
|
-
return anthropicResult({
|
|
2066
|
-
status: "complete",
|
|
2067
|
-
message: `API key is stored and working. Key file: ${keyFilePath()}.`,
|
|
2068
|
-
});
|
|
2069
|
-
case "billing":
|
|
2070
|
-
log("key valid but billing issue");
|
|
2071
|
-
return anthropicResult({
|
|
2072
|
-
status: "awaiting_credits",
|
|
2073
|
-
message: "API key is stored and valid, but your account has insufficient credits. " +
|
|
2074
|
-
`Add credits at ${CONSOLE_BASE}/settings/billing, then call this tool again.`,
|
|
2075
|
-
data: { url: `${CONSOLE_BASE}/settings/billing` },
|
|
2076
|
-
});
|
|
2077
|
-
case "auth_error":
|
|
2078
|
-
// Deterministic transition: the state machine knows the key file
|
|
2079
|
-
// path and the only recovery is to delete and restart sign-in.
|
|
2080
|
-
// Auto-reset here so the agent never has to rediscover the path
|
|
2081
|
-
// via filesystem probes.
|
|
2082
|
-
log(`auth_error → auto-resetting: deleting revoked key at ${keyFilePath()}`);
|
|
2083
|
-
try {
|
|
2084
|
-
deleteKey();
|
|
2085
|
-
}
|
|
2086
|
-
catch (err) {
|
|
2087
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2088
|
-
log(`auto-reset failed: ${msg}`);
|
|
2089
|
-
return anthropicResult({
|
|
2090
|
-
status: "error",
|
|
2091
|
-
message: `The stored API key was rejected and auto-reset failed: ${msg}. ` +
|
|
2092
|
-
`Manual intervention needed — remove ${keyFilePath()} and call this tool again.`,
|
|
2093
|
-
});
|
|
2094
|
-
}
|
|
2095
|
-
// Fall through to the awaiting_signin path below.
|
|
2096
|
-
break;
|
|
2097
|
-
case "missing":
|
|
2098
|
-
// hasKey() returned true but readKey() returned null — shouldn't happen
|
|
2099
|
-
log("hasKey true but validate returned missing — proceeding to setup");
|
|
2100
|
-
break;
|
|
2101
|
-
case "error":
|
|
2102
|
-
log(`verification failed: ${verification.message}`);
|
|
2103
|
-
return anthropicResult({
|
|
2104
|
-
status: "error",
|
|
2105
|
-
message: `Could not verify the stored key: ${verification.message}. ` +
|
|
2106
|
-
"This may be a network issue or Anthropic outage. Try again later.",
|
|
2107
|
-
});
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
else {
|
|
2111
|
-
log("no key stored");
|
|
2112
|
-
}
|
|
2113
|
-
// No valid key — return action for Console API calls
|
|
2114
|
-
const expression = consoleEvaluateExpression(BRAND_NAME);
|
|
2115
|
-
log("returning awaiting_signin with browser_evaluate action");
|
|
2116
|
-
return anthropicResult({
|
|
2117
|
-
status: "awaiting_signin",
|
|
2118
|
-
message: "No valid API key stored. Open the browser to the Anthropic Console " +
|
|
2119
|
-
`(${CONSOLE_BASE}) and sign in. This is a separate service from Claude — ` +
|
|
2120
|
-
"you may need to sign in again even if you used the same credentials earlier. " +
|
|
2121
|
-
"Once signed in, run the browser_evaluate action below, then call this tool " +
|
|
2122
|
-
"again with the result as consoleResult.",
|
|
2123
|
-
data: {
|
|
2124
|
-
url: CONSOLE_BASE,
|
|
2125
|
-
action: {
|
|
2126
|
-
tool: "browser_evaluate",
|
|
2127
|
-
params: { function: expression },
|
|
2128
|
-
},
|
|
2129
|
-
},
|
|
2130
|
-
});
|
|
2131
|
-
}
|
|
2132
|
-
// ── Phase 2: process Console API result ────────────────────
|
|
2133
|
-
log("processing consoleResult");
|
|
2134
|
-
let parsed;
|
|
2135
|
-
try {
|
|
2136
|
-
parsed = JSON.parse(consoleResult);
|
|
2137
|
-
}
|
|
2138
|
-
catch {
|
|
2139
|
-
log(`consoleResult parse failed: ${consoleResult.slice(0, 200)}`);
|
|
2140
|
-
return anthropicResult({
|
|
2141
|
-
status: "error",
|
|
2142
|
-
message: "Failed to parse the browser result. The Console session may have " +
|
|
2143
|
-
"been lost or the browser encountered an error. Please try again — " +
|
|
2144
|
-
"open the browser to platform.claude.com, sign in, and re-run the action.",
|
|
2145
|
-
});
|
|
2146
|
-
}
|
|
2147
|
-
log(`console result status: ${parsed.status}`);
|
|
2148
|
-
switch (parsed.status) {
|
|
2149
|
-
case "no_session": {
|
|
2150
|
-
log("no Console session — user needs to sign in");
|
|
2151
|
-
const expression = consoleEvaluateExpression(BRAND_NAME);
|
|
2152
|
-
return anthropicResult({
|
|
2153
|
-
status: "awaiting_signin",
|
|
2154
|
-
message: "Not signed in to the Anthropic Console. Please sign in at " +
|
|
2155
|
-
`${CONSOLE_BASE} and then run the browser_evaluate action below.`,
|
|
2156
|
-
data: {
|
|
2157
|
-
url: CONSOLE_BASE,
|
|
2158
|
-
action: {
|
|
2159
|
-
tool: "browser_evaluate",
|
|
2160
|
-
params: { function: expression },
|
|
2161
|
-
},
|
|
2162
|
-
},
|
|
2163
|
-
});
|
|
2164
|
-
}
|
|
2165
|
-
case "no_org":
|
|
2166
|
-
log("no API organization found");
|
|
2167
|
-
return anthropicResult({
|
|
2168
|
-
status: "error",
|
|
2169
|
-
message: "No API organization found in your Anthropic account. " +
|
|
2170
|
-
"You may be signed in to a Claude consumer account instead of the API Console. " +
|
|
2171
|
-
`Sign in at ${CONSOLE_BASE} with an account that has API access.`,
|
|
2172
|
-
});
|
|
2173
|
-
case "no_credits": {
|
|
2174
|
-
log(`no credits — org: ${parsed.orgName ?? "unknown"}`);
|
|
2175
|
-
const expression = consoleEvaluateExpression(BRAND_NAME);
|
|
2176
|
-
return anthropicResult({
|
|
2177
|
-
status: "awaiting_credits",
|
|
2178
|
-
message: `Your API organization (${parsed.orgName ?? "unknown"}) has no credits. ` +
|
|
2179
|
-
`Add credits at ${parsed.creditUrl ?? CONSOLE_BASE + "/settings/billing"}, ` +
|
|
2180
|
-
"then run the browser_evaluate action below.",
|
|
2181
|
-
data: {
|
|
2182
|
-
url: parsed.creditUrl ?? `${CONSOLE_BASE}/settings/billing`,
|
|
2183
|
-
action: {
|
|
2184
|
-
tool: "browser_evaluate",
|
|
2185
|
-
params: { function: expression },
|
|
2186
|
-
},
|
|
2187
|
-
},
|
|
2188
|
-
});
|
|
2189
|
-
}
|
|
2190
|
-
case "create_failed":
|
|
2191
|
-
log(`key creation failed: ${parsed.error ?? "unknown"}`);
|
|
2192
|
-
return anthropicResult({
|
|
2193
|
-
status: "error",
|
|
2194
|
-
message: `Failed to create API key: ${parsed.error ?? "unknown error"}. ` +
|
|
2195
|
-
"This may be a permissions issue or a temporary Console error. Try again.",
|
|
2196
|
-
});
|
|
2197
|
-
case "fetch_error":
|
|
2198
|
-
log(`fetch error: ${parsed.error ?? "unknown"}`);
|
|
2199
|
-
return anthropicResult({
|
|
2200
|
-
status: "error",
|
|
2201
|
-
message: `Console API error: ${parsed.error ?? "unknown"}. ` +
|
|
2202
|
-
"The Console may be temporarily unavailable. Try again.",
|
|
2203
|
-
});
|
|
2204
|
-
case "success": {
|
|
2205
|
-
if (!parsed.key) {
|
|
2206
|
-
log("success status but no key in result");
|
|
2207
|
-
return anthropicResult({
|
|
2208
|
-
status: "error",
|
|
2209
|
-
message: "Key creation succeeded but the key was not returned. " +
|
|
2210
|
-
"This is unexpected. Please try again.",
|
|
2211
|
-
});
|
|
2212
|
-
}
|
|
2213
|
-
log(`key created: ${parsed.keyId ?? "unknown"} (hint: ${parsed.keyHint ?? "n/a"}) — org: ${parsed.orgName ?? "unknown"}`);
|
|
2214
|
-
// Store the key — persist AFTER confirmation (sprint learning: Task 201)
|
|
2215
|
-
try {
|
|
2216
|
-
writeKey(parsed.key);
|
|
2217
|
-
log("key stored");
|
|
2218
|
-
}
|
|
2219
|
-
catch (err) {
|
|
2220
|
-
log(`key storage failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2221
|
-
return anthropicResult({
|
|
2222
|
-
status: "error",
|
|
2223
|
-
message: `Key was created in the Console but could not be stored locally: ` +
|
|
2224
|
-
`${err instanceof Error ? err.message : String(err)}`,
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
// Verify the stored key
|
|
2228
|
-
const verification = await validateKey();
|
|
2229
|
-
log(`post-store verification: ${verification.status}`);
|
|
2230
|
-
switch (verification.status) {
|
|
2231
|
-
case "valid":
|
|
2232
|
-
log("key stored and verified");
|
|
2233
|
-
return anthropicResult({
|
|
2234
|
-
status: "complete",
|
|
2235
|
-
message: `API key created, stored at ${keyFilePath()}, and verified. ` +
|
|
2236
|
-
`Organization: ${parsed.orgName ?? "unknown"}. ` +
|
|
2237
|
-
`Credits: $${((parsed.credits ?? 0) / 100).toFixed(2)}.`,
|
|
2238
|
-
});
|
|
2239
|
-
case "billing":
|
|
2240
|
-
log("key stored but billing issue on verification");
|
|
2241
|
-
return anthropicResult({
|
|
2242
|
-
status: "awaiting_credits",
|
|
2243
|
-
message: "API key created and stored, but your account has insufficient credits. " +
|
|
2244
|
-
`Add credits at ${CONSOLE_BASE}/settings/billing, then verify the key with api-key-verify.`,
|
|
2245
|
-
data: { url: `${CONSOLE_BASE}/settings/billing` },
|
|
2246
|
-
});
|
|
2247
|
-
default:
|
|
2248
|
-
log(`unexpected verification status after store: ${verification.status} — ${verification.message}`);
|
|
2249
|
-
return anthropicResult({
|
|
2250
|
-
status: "error",
|
|
2251
|
-
message: `Key was stored but verification returned: ${verification.status}. ` +
|
|
2252
|
-
`${verification.message}. Try running api-key-verify manually.`,
|
|
2253
|
-
});
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
default:
|
|
2257
|
-
log(`unknown console result status: ${parsed.status}`);
|
|
2258
|
-
return anthropicResult({
|
|
2259
|
-
status: "error",
|
|
2260
|
-
message: `Unexpected result from Console: status "${parsed.status}". ` +
|
|
2261
|
-
"Please try again.",
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
});
|
|
2265
|
-
// ===================================================================
|
|
2266
|
-
// Onboarding tools
|
|
2267
|
-
// ===================================================================
|
|
2268
|
-
server.tool("onboarding-get", "Read the current onboarding state from the graph. Returns which setup steps " +
|
|
2269
|
-
"have been completed and their timestamps. On first call for an account, " +
|
|
2270
|
-
"migrates any existing onboardingStep from account.json to the graph and " +
|
|
2271
|
-
"removes it from the file. If Neo4j is unreachable, returns an error — " +
|
|
2272
|
-
"the agent should skip onboarding for this session and retry next time.", {}, async () => {
|
|
2273
|
-
try {
|
|
2274
|
-
const state = await getOnboardingState(getSession, ACCOUNT_ID, getAccountDir());
|
|
2275
|
-
return {
|
|
2276
|
-
content: [{
|
|
2277
|
-
type: "text",
|
|
2278
|
-
text: JSON.stringify(state, null, 2),
|
|
2279
|
-
}],
|
|
2280
|
-
};
|
|
2281
|
-
}
|
|
2282
|
-
catch (err) {
|
|
2283
|
-
return {
|
|
2284
|
-
content: [{
|
|
2285
|
-
type: "text",
|
|
2286
|
-
text: `Failed to read onboarding state: ${err instanceof Error ? err.message : String(err)}`,
|
|
2287
|
-
}],
|
|
2288
|
-
isError: true,
|
|
2289
|
-
};
|
|
2290
|
-
}
|
|
2291
|
-
});
|
|
2292
|
-
server.tool("onboarding-complete-step", "Mark an onboarding step as completed. Sets a completion timestamp on the step " +
|
|
2293
|
-
"and updates currentStep to the highest completed step. Idempotent — completing " +
|
|
2294
|
-
"an already-completed step preserves its original timestamp. Step must be 1–9. " +
|
|
2295
|
-
"When step is 1, optionally pass acceptedAnthropicVerticals + declinedAnthropicVerticals " +
|
|
2296
|
-
"(both required together) to emit the paired counter for the [plugin-onboarding] " +
|
|
2297
|
-
"group=anthropic-verticals prefix; the skill derives both arrays from the closed set " +
|
|
2298
|
-
"{kyc-screener, meeting-prep-agent, pdf-viewer} and the user's submission.", {
|
|
2299
|
-
step: z.number().int().min(1).max(9).describe("The onboarding step number (1–9) to mark as completed"),
|
|
2300
|
-
acceptedAnthropicVerticals: z.array(z.string()).optional().describe("Step 1 only: plugin slugs the user accepted from the Anthropic verticals group. Pass together with declinedAnthropicVerticals."),
|
|
2301
|
-
declinedAnthropicVerticals: z.array(z.string()).optional().describe("Step 1 only: plugin slugs the user declined from the Anthropic verticals group. Pass together with acceptedAnthropicVerticals."),
|
|
2302
|
-
}, async ({ step, acceptedAnthropicVerticals, declinedAnthropicVerticals }) => {
|
|
2303
|
-
try {
|
|
2304
|
-
const state = await completeOnboardingStep(getSession, ACCOUNT_ID, step);
|
|
2305
|
-
// Task 977: closed set lives in skill prose, not server validation — a fourth vertical updates the skill.
|
|
2306
|
-
if (step === 1 && acceptedAnthropicVerticals !== undefined && declinedAnthropicVerticals !== undefined) {
|
|
2307
|
-
console.error(`[plugin-onboarding] group=anthropic-verticals accepted=${acceptedAnthropicVerticals.length} declined=${declinedAnthropicVerticals.length}`);
|
|
2308
|
-
}
|
|
2309
|
-
return {
|
|
2310
|
-
content: [{
|
|
2311
|
-
type: "text",
|
|
2312
|
-
text: JSON.stringify(state, null, 2),
|
|
2313
|
-
}],
|
|
2314
|
-
};
|
|
2315
|
-
}
|
|
2316
|
-
catch (err) {
|
|
2317
|
-
return {
|
|
2318
|
-
content: [{
|
|
2319
|
-
type: "text",
|
|
2320
|
-
text: `Failed to complete onboarding step: ${err instanceof Error ? err.message : String(err)}`,
|
|
2321
|
-
}],
|
|
2322
|
-
isError: true,
|
|
2323
|
-
};
|
|
2324
|
-
}
|
|
2325
|
-
});
|
|
2326
|
-
// Task 704: pin the operator's persona (personal/business-owner) at step 9
|
|
2327
|
-
// BEFORE any graph write happens. The agent calls this immediately on the
|
|
2328
|
-
// user's single-select submission. The tool's job is twofold:
|
|
2329
|
-
// 1. Emit a deterministic [onboarding-step9-mode] log line for the
|
|
2330
|
-
// diagnostic-grep path on the Pi (matches [onboarding-step-complete]
|
|
2331
|
-
// format — same accountId-prefix slicing, same surrounding code).
|
|
2332
|
-
// 2. Return the next-action prose so the agent's branching is anchored to
|
|
2333
|
-
// the tool surface, not free-text inference.
|
|
2334
|
-
// No persistence — the graph state (LocalBusiness exists vs Person with
|
|
2335
|
-
// role=admin-personal exists) remains the source of truth for gate
|
|
2336
|
-
// satisfaction. Re-calling this tool with a different mode on the same
|
|
2337
|
-
// session is allowed; the most recent log line wins for diagnostic purposes.
|
|
2338
|
-
server.tool("onboarding-step9-mode", "Step 9 onboarding fork: record the operator's persona (personal or " +
|
|
2339
|
-
"business-owner) before any graph write. Logs the choice for diagnostic " +
|
|
2340
|
-
"grep and returns the deterministic next-action prose for the agent.", {
|
|
2341
|
-
mode: z
|
|
2342
|
-
.enum(["personal", "business-owner"])
|
|
2343
|
-
.describe("The operator's persona: 'personal' for an individual using Maxy for personal operations (including someone with an employer that is NOT being registered here), or 'business-owner' for someone setting up Maxy as the operations agent for their own company."),
|
|
2344
|
-
}, async ({ mode }) => {
|
|
2345
|
-
console.log(`[onboarding-step9-mode] accountId=${ACCOUNT_ID.slice(0, 8)}… mode=${mode}`);
|
|
2346
|
-
const nextAction = mode === "business-owner"
|
|
2347
|
-
? "Invoke the `business-profile` skill to create AdminUser + LocalBusiness and capture the business identity. Mark step 9 complete only after both nodes exist in the graph."
|
|
2348
|
-
: "Ask the user for their email (one sentence). Use their name from `admin-identity` in the system prompt; split into givenName + familyName. Call `memory-write` to create the AdminUser node, then call `memory-write` to create a Person node with `role: \"admin-personal\"`, the givenName, familyName, email, and an OWNS edge from the AdminUser. Then call `onboarding-complete-step` with step 9. Do not invoke the `business-profile` skill — personal mode does not register a LocalBusiness.";
|
|
2349
|
-
return {
|
|
2350
|
-
content: [{
|
|
2351
|
-
type: "text",
|
|
2352
|
-
text: JSON.stringify({ mode, nextAction }, null, 2),
|
|
2353
|
-
}],
|
|
2354
|
-
};
|
|
2355
|
-
});
|
|
2356
|
-
// ===================================================================
|
|
2357
1789
|
// Utility tools
|
|
2358
1790
|
// ===================================================================
|
|
2359
1791
|
eagerTool(server, "qr-generate", "Generate a QR code from text or a URL. Returns the QR code as a data URI (PNG) or saves to a file path.", {
|
|
@@ -2984,10 +2416,11 @@ server.tool("premium-deliver", "Deliver a purchased premium plugin. Copies plugi
|
|
|
2984
2416
|
// file-attach — copy a generated file into the attachment store for download
|
|
2985
2417
|
// ---------------------------------------------------------------------------
|
|
2986
2418
|
eagerTool(server, "file-attach", "Attach a file from the account directory for delivery to the user. " +
|
|
2987
|
-
"Copies the file into the attachment store and returns metadata
|
|
2988
|
-
"
|
|
2989
|
-
"
|
|
2990
|
-
"
|
|
2419
|
+
"Copies the file into the attachment store and returns metadata the chat " +
|
|
2420
|
+
"surface uses to present the download. The file must be within the account " +
|
|
2421
|
+
"directory tree. The returned metadata is the operator-visible record of the " +
|
|
2422
|
+
"attachment; quote it back to the user in plain text so they have the filename " +
|
|
2423
|
+
"and size on screen.", {
|
|
2991
2424
|
filePath: z.string().describe("Absolute path to the file to attach"),
|
|
2992
2425
|
}, async ({ filePath }) => {
|
|
2993
2426
|
const TAG = "[file-attach]";
|