@rubytech/create-realagent 1.0.775 → 1.0.791
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 +30 -39
- package/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +79 -6
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +2 -0
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/scripts/wifi-provision-server/server.js +157 -59
- package/payload/platform/scripts/wifi-provision.sh +88 -8
- package/payload/server/chunk-FEEKJZOY.js +9841 -0
- package/payload/server/chunk-H5F4S42X.js +9850 -0
- package/payload/server/maxy-edge.js +80 -24
- package/payload/server/public/assets/{Checkbox-C_KxaLc-.js → Checkbox-DHsoNPeM.js} +1 -1
- package/payload/server/public/assets/admin-gOk3qrFw.js +352 -0
- package/payload/server/public/assets/data-bIkywng-.js +1 -0
- package/payload/server/public/assets/graph-CT4W30GR.js +1 -0
- package/payload/server/public/assets/jsx-runtime-lOmSwjvd.css +1 -0
- package/payload/server/public/assets/{page-CjTfZ3O6.js → page-Cs2i--Z2.js} +18 -18
- package/payload/server/public/assets/{page-DEWgk_nR.js → page-DU8F3OGU.js} +1 -1
- package/payload/server/public/assets/{public-CehiL-qZ.js → public-Bn-gEWOv.js} +1 -1
- package/payload/server/public/assets/{share-2-BG1VXt3z.js → share-2-0IDKUUq9.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-1Dvb-yHn.js → useVoiceRecorder-B1S_t3Hq.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 +68 -74
- package/payload/platform/scripts/embed-backfill.sh +0 -382
- package/payload/server/public/assets/admin-xbKPR6ZI.js +0 -352
- package/payload/server/public/assets/data-D23IzpJ2.js +0 -1
- package/payload/server/public/assets/graph-D2AS9zFS.js +0 -1
- package/payload/server/public/assets/jsx-runtime-BZtBxBng.css +0 -1
- /package/payload/server/public/assets/{jsx-runtime-DrneHL3t.js → jsx-runtime-Br2bU3EJ.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -430,6 +430,18 @@ function installSystemDeps() {
|
|
|
430
430
|
console.log(` Avahi host-name: ${HOSTNAME_FLAG} (updated avahi-daemon.conf)`);
|
|
431
431
|
}
|
|
432
432
|
catch { /* avahi-daemon.conf may not exist — non-critical */ }
|
|
433
|
+
// Restart avahi-daemon so the new hostname takes effect immediately
|
|
434
|
+
// and any stale "maxytest-2" auto-renamed records from a previous
|
|
435
|
+
// boot's hostname-conflict cycle are withdrawn. Without this,
|
|
436
|
+
// avahi-resolve -n <hostname>.local times out from the device itself
|
|
437
|
+
// because the daemon is still advertising the previous identity.
|
|
438
|
+
try {
|
|
439
|
+
console.log(" [privileged] systemctl restart avahi-daemon");
|
|
440
|
+
shell("systemctl", ["restart", "avahi-daemon"], { sudo: true });
|
|
441
|
+
}
|
|
442
|
+
catch (err) {
|
|
443
|
+
console.error(` WARNING: avahi-daemon restart failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
444
|
+
}
|
|
433
445
|
}
|
|
434
446
|
catch (err) {
|
|
435
447
|
console.error(` WARNING: Failed to set hostname to '${HOSTNAME_FLAG}': ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1346,6 +1358,19 @@ function buildPlatform() {
|
|
|
1346
1358
|
// server/package.json but NOT shipped as pre-built node_modules — npm pack silently
|
|
1347
1359
|
// strips files from nested node_modules (e.g. rxjs/package.json), breaking require().
|
|
1348
1360
|
// Install fresh on device to guarantee a complete dependency tree.
|
|
1361
|
+
//
|
|
1362
|
+
// On upgrade, wipe `node_modules` first so npm extracts a clean tree. Without
|
|
1363
|
+
// this, an interrupted previous install (network blip, operator cancellation,
|
|
1364
|
+
// power loss) can leave nested package.json files half-truncated — the most
|
|
1365
|
+
// common manifestation is `Error: Invalid package config .../rxjs/package.json`
|
|
1366
|
+
// at server startup, which loops the brand service indefinitely. The wipe
|
|
1367
|
+
// adds ~30 s to upgrades but eliminates a class of unrecoverable customer
|
|
1368
|
+
// states; reliability wins over speed for a one-shot install path.
|
|
1369
|
+
const serverNodeModules = join(INSTALL_DIR, "server", "node_modules");
|
|
1370
|
+
if (existsSync(serverNodeModules)) {
|
|
1371
|
+
console.log(" Wiping previous server/node_modules for a clean reinstall...");
|
|
1372
|
+
rmSync(serverNodeModules, { recursive: true, force: true });
|
|
1373
|
+
}
|
|
1349
1374
|
console.log(` Installing server dependencies (${join(INSTALL_DIR, "server")})...`);
|
|
1350
1375
|
shellRetry("npm", ["install", "--omit=dev", ...NPM_NET_FLAGS], { cwd: join(INSTALL_DIR, "server") }, 3, 15);
|
|
1351
1376
|
}
|
|
@@ -1541,11 +1566,11 @@ function setupVncViewer() {
|
|
|
1541
1566
|
}
|
|
1542
1567
|
function setupAccount() {
|
|
1543
1568
|
log("10", TOTAL, "Setting up...");
|
|
1544
|
-
//
|
|
1545
|
-
//
|
|
1546
|
-
//
|
|
1547
|
-
//
|
|
1548
|
-
//
|
|
1569
|
+
// Task 787 — seed-neo4j.sh hard-exits without NEO4J_URI. The installer
|
|
1570
|
+
// owns the brand-correct URI and password, so we derive them once.
|
|
1571
|
+
// Missing password file is a hard error: ensureNeo4jPassword() ran
|
|
1572
|
+
// upstream and would have thrown already if it couldn't reach the
|
|
1573
|
+
// brand's Neo4j.
|
|
1549
1574
|
const passwordFile = join(INSTALL_DIR, "platform/config/.neo4j-password");
|
|
1550
1575
|
if (!existsSync(passwordFile)) {
|
|
1551
1576
|
throw new Error(`Neo4j password file missing at ${passwordFile} — required by setup step.`);
|
|
@@ -1559,40 +1584,6 @@ function setupAccount() {
|
|
|
1559
1584
|
logFile(` [neo4j] passing NEO4J_URI=${neo4jUri} to seed`);
|
|
1560
1585
|
shell("bash", [seedScript], { cwd: INSTALL_DIR, env: neo4jEnv });
|
|
1561
1586
|
}
|
|
1562
|
-
// Task 748 — universal embedding coverage backfill. Run after seed so the
|
|
1563
|
-
// entity_search index is in place and any pre-Task-748 nodes (e.g. the
|
|
1564
|
-
// 5096 LinkedIn-imported Persons on existing Pis that bulk-import skipped
|
|
1565
|
-
// embedding for) get a vector populated. Idempotent — instant no-op when
|
|
1566
|
-
// nothing is pending, so re-running on every install is harmless.
|
|
1567
|
-
//
|
|
1568
|
-
// Failure-mode policy: WARN, do not abort. The fulltext index is already
|
|
1569
|
-
// applied above, so BM25 search works end-to-end without embeddings; the
|
|
1570
|
-
// only gap is vector ranking quality on legacy nodes. Aborting the
|
|
1571
|
-
// installer on an Ollama hiccup would block every install for a
|
|
1572
|
-
// strictly-degradable feature. The script's own loud-failure output
|
|
1573
|
-
// tells the operator how to re-run.
|
|
1574
|
-
const backfillScript = join(INSTALL_DIR, "platform/scripts/embed-backfill.sh");
|
|
1575
|
-
if (existsSync(backfillScript)) {
|
|
1576
|
-
const start = Date.now();
|
|
1577
|
-
logFile(`> bash ${backfillScript} (warn-not-abort)`);
|
|
1578
|
-
const result = spawnSync("bash", [backfillScript], {
|
|
1579
|
-
stdio: "inherit",
|
|
1580
|
-
timeout: 30 * 60_000,
|
|
1581
|
-
cwd: INSTALL_DIR,
|
|
1582
|
-
env: neo4jEnv,
|
|
1583
|
-
});
|
|
1584
|
-
const dur = ((Date.now() - start) / 1000).toFixed(1);
|
|
1585
|
-
if (result.status !== 0 || result.signal) {
|
|
1586
|
-
const reason = result.signal ? `signal=${result.signal}` : `exit=${result.status}`;
|
|
1587
|
-
logFile(` WARN: embed-backfill non-zero (${reason}) after ${dur}s`);
|
|
1588
|
-
console.warn(`\n WARNING: embed-backfill did not complete (${reason}) — BM25 search works,\n` +
|
|
1589
|
-
` but vector ranking on legacy nodes will be sparse until you re-run:\n` +
|
|
1590
|
-
` bash ${backfillScript}\n`);
|
|
1591
|
-
}
|
|
1592
|
-
else {
|
|
1593
|
-
logFile(` OK embed-backfill in ${dur}s`);
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
1587
|
}
|
|
1597
1588
|
// ---------------------------------------------------------------------------
|
|
1598
1589
|
// Tunnel script shortcuts
|
package/package.json
CHANGED
|
@@ -1557,6 +1557,7 @@ server.tool("api-key-verify", "Verify the stored Anthropic API key works by maki
|
|
|
1557
1557
|
* anthropic-setup state machine (action-relay pattern)
|
|
1558
1558
|
*
|
|
1559
1559
|
* Call 1: anthropic-setup({})
|
|
1560
|
+
* ├─ no public endpoint → { status: "not_needed" } ← Phase 0 gate
|
|
1560
1561
|
* ├─ key stored + valid? → { status: "complete" }
|
|
1561
1562
|
* ├─ key stored + billing → { status: "awaiting_credits" }
|
|
1562
1563
|
* ├─ key stored + error → { status: "error" }
|
|
@@ -1630,20 +1631,92 @@ function anthropicResult(r) {
|
|
|
1630
1631
|
...(r.status === "error" ? { isError: true } : {}),
|
|
1631
1632
|
};
|
|
1632
1633
|
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Check whether a public-facing hostname is configured. The Anthropic API key
|
|
1636
|
+
* powers the public agent only — admin runs on Claude OAuth — so without a
|
|
1637
|
+
* public endpoint there is nothing for the key to power.
|
|
1638
|
+
*
|
|
1639
|
+
* Mirrors the runtime `isPublicHost(host)` predicate in
|
|
1640
|
+
* `platform/ui/server/index.ts`: a host is public iff it starts with `public.`
|
|
1641
|
+
* OR is listed in `~/{configDir}/alias-domains.json`. Step 7's form submit
|
|
1642
|
+
* handler at `platform/ui/server/routes/admin/cloudflare.ts` writes secondary
|
|
1643
|
+
* hostnames (apex + custom public labels) to `alias-domains.json` and skips
|
|
1644
|
+
* `public.*` because the prefix itself is the signal — so the two predicates
|
|
1645
|
+
* together cover every shape the form can produce.
|
|
1646
|
+
*
|
|
1647
|
+
* Returns true if any configured hostname satisfies either predicate.
|
|
1648
|
+
*/
|
|
1649
|
+
function hasPublicEndpointConfigured() {
|
|
1650
|
+
const aliasPath = join(CONFIG_DIR, "alias-domains.json");
|
|
1651
|
+
if (existsSync(aliasPath)) {
|
|
1652
|
+
try {
|
|
1653
|
+
const parsed = JSON.parse(readFileSync(aliasPath, "utf-8"));
|
|
1654
|
+
if (Array.isArray(parsed)) {
|
|
1655
|
+
const entries = parsed.filter((h) => typeof h === "string" && h.length > 0);
|
|
1656
|
+
if (entries.length > 0) {
|
|
1657
|
+
return { has: true, reason: `alias-domains.json: ${entries.join(", ")}` };
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
catch {
|
|
1662
|
+
// Malformed file — treat as empty; matches the server-side reader's tolerance.
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
const cfConfigPath = join(CONFIG_DIR, "cloudflared", "config.yml");
|
|
1666
|
+
if (existsSync(cfConfigPath)) {
|
|
1667
|
+
try {
|
|
1668
|
+
const yaml = readFileSync(cfConfigPath, "utf-8");
|
|
1669
|
+
const hostnames = [...yaml.matchAll(/^\s*-\s*hostname:\s*(\S+)/gm)].map((m) => m[1]);
|
|
1670
|
+
const publicPrefixed = hostnames.find((h) => h.startsWith("public."));
|
|
1671
|
+
if (publicPrefixed) {
|
|
1672
|
+
return { has: true, reason: `cloudflared/config.yml ingress: ${publicPrefixed}` };
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
catch {
|
|
1676
|
+
// Unreadable — treat as no public host.
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
return {
|
|
1680
|
+
has: false,
|
|
1681
|
+
reason: "no entries in alias-domains.json and no public.* hostname in cloudflared/config.yml",
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1633
1684
|
server.tool("anthropic-setup", "Deterministic state machine for Anthropic API key acquisition. " +
|
|
1634
1685
|
"Checks current state, advances as far as possible, and returns a structured JSON result. " +
|
|
1635
|
-
"On first call (no consoleResult):
|
|
1636
|
-
"
|
|
1637
|
-
"
|
|
1638
|
-
"
|
|
1686
|
+
"On first call (no consoleResult): first verifies a public-facing endpoint is configured " +
|
|
1687
|
+
"(the key only powers the public agent); if not, returns status 'not_needed'. Otherwise " +
|
|
1688
|
+
"checks if a valid key is already stored. If not, returns status 'awaiting_signin' with " +
|
|
1689
|
+
"a browser_evaluate action — the agent must open the browser to platform.claude.com, run " +
|
|
1690
|
+
"the action's function via browser_evaluate, and pass the string result back as " +
|
|
1691
|
+
"consoleResult on the next call. " +
|
|
1639
1692
|
"On second call (with consoleResult): parses the Console API result, stores the key, " +
|
|
1640
1693
|
"verifies it, and returns status 'complete'. " +
|
|
1641
|
-
"Statuses: complete (key stored and verified),
|
|
1642
|
-
"
|
|
1694
|
+
"Statuses: complete (key stored and verified), not_needed (no public endpoint configured — " +
|
|
1695
|
+
"skip the step), awaiting_signin (user must sign in to Console), awaiting_credits (signed in " +
|
|
1696
|
+
"but no credits — user must add credits), error (fatal — relay message).", {
|
|
1643
1697
|
consoleResult: z.string().optional().describe("JSON string result from running the browser_evaluate action returned by a prior call. " +
|
|
1644
1698
|
"Omit on the first call."),
|
|
1645
1699
|
}, async ({ consoleResult }) => {
|
|
1646
1700
|
const log = (msg) => console.error(`[anthropic-setup] ${msg}`);
|
|
1701
|
+
// ── Phase 0: gate on public endpoint existence ─────────────
|
|
1702
|
+
// The API key only powers the public-facing agent. If no public hostname
|
|
1703
|
+
// is configured (operator skipped step 7, or completed it without a
|
|
1704
|
+
// public/apex hostname) the key has no consumer — short-circuit before
|
|
1705
|
+
// any Console interaction so we never create keys the operator cannot use.
|
|
1706
|
+
if (!consoleResult) {
|
|
1707
|
+
const publicCheck = hasPublicEndpointConfigured();
|
|
1708
|
+
if (!publicCheck.has) {
|
|
1709
|
+
log(`gate: no public endpoint (${publicCheck.reason}) — returning not_needed`);
|
|
1710
|
+
return anthropicResult({
|
|
1711
|
+
status: "not_needed",
|
|
1712
|
+
message: "No public-facing endpoint is configured, so an Anthropic API key is not needed. " +
|
|
1713
|
+
"The key powers the public agent only — admin runs on your Claude OAuth session. " +
|
|
1714
|
+
"When you set up a public hostname via Cloudflare (or apex domain), come back and " +
|
|
1715
|
+
"ask to set up the API key then.",
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
log(`gate: public endpoint present (${publicCheck.reason})`);
|
|
1719
|
+
}
|
|
1647
1720
|
// ── Phase 1: check stored key ──────────────────────────────
|
|
1648
1721
|
if (!consoleResult) {
|
|
1649
1722
|
log("checking stored key");
|