@rubytech/create-maxy-code 0.1.110 → 0.1.111

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 CHANGED
@@ -1284,31 +1284,45 @@ function setupDedicatedNeo4j() {
1284
1284
  shell("cp", ["-r", "/etc/neo4j", confDir], { sudo: true });
1285
1285
  }
1286
1286
  // Idempotent per-brand state — runs on every install.
1287
- // sed `s|^#?key=.*|key=value|` no-ops when the file already has the target
1288
- // value; mkdir -p, chown -R, and unit-write are idempotent by definition.
1289
- // NEO4J_HOME=${dataDir} makes server.directories.run resolve per-brand to
1290
- // ${dataDir}/run, so the launcher's pre-flight does not collide with the
1291
- // system unit's /var/lib/neo4j/run/neo4j.pid (root cause). Plugins
1292
- // and import are sed-overridden because the apt base conf pins them to
1293
- // absolute /var/lib/neo4j/plugins and /var/lib/neo4j/import (shared).
1294
- console.log(" [privileged] sed -i");
1295
- shell("sed", ["-i", `s/^#\\?server\\.bolt\\.listen_address=.*/server.bolt.listen_address=:${NEO4J_PORT}/`, `${confDir}/neo4j.conf`], { sudo: true });
1296
- console.log(" [privileged] sed -i");
1297
- shell("sed", ["-i", `s/^#\\?server\\.http\\.listen_address=.*/server.http.listen_address=:${httpPort}/`, `${confDir}/neo4j.conf`], { sudo: true });
1298
- console.log(" [privileged] sed -i");
1299
- shell("sed", ["-i", `s|^#\\?server\\.directories\\.data=.*|server.directories.data=${dataDir}/data|`, `${confDir}/neo4j.conf`], { sudo: true });
1300
- console.log(" [privileged] sed -i");
1301
- shell("sed", ["-i", `s|^#\\?server\\.directories\\.logs=.*|server.directories.logs=${logDir}|`, `${confDir}/neo4j.conf`], { sudo: true });
1302
- console.log(" [privileged] sed -i");
1303
- shell("sed", ["-i", `s|^#\\?server\\.directories\\.plugins=.*|server.directories.plugins=${dataDir}/plugins|`, `${confDir}/neo4j.conf`], { sudo: true });
1304
- console.log(" [privileged] sed -i");
1305
- shell("sed", ["-i", `s|^#\\?server\\.directories\\.import=.*|server.directories.import=${dataDir}/import|`, `${confDir}/neo4j.conf`], { sudo: true });
1306
- // Verify config was updated — sed silently no-ops if the key format changed
1307
- const confContent = spawnSync("grep", [`server.bolt.listen_address=:${NEO4J_PORT}`, `${confDir}/neo4j.conf`], { stdio: "pipe" });
1308
- if (confContent.status !== 0) {
1309
- console.error(` WARNING: neo4j.conf may not have been updated correctly bolt port ${NEO4J_PORT} not found in config`);
1310
- logFile(` WARNING: sed verification failed bolt port ${NEO4J_PORT} not found in ${confDir}/neo4j.conf`);
1311
- }
1287
+ // Older Neo4j 5.x templates ship a SECOND commented occurrence of these
1288
+ // keys in the "Other Neo4j system properties" section. An in-place
1289
+ // `sed s|^#?key=.*|key=value|` matches both and writes duplicate active
1290
+ // lines; the 5.26.26 parser turns that into a fatal startup error.
1291
+ // Delete-all-then-append guarantees exactly one active line per key
1292
+ // regardless of how many commented occurrences the template ships.
1293
+ const confPath = `${confDir}/neo4j.conf`;
1294
+ const confKeys = [
1295
+ ["server.bolt.listen_address", `:${NEO4J_PORT}`],
1296
+ ["server.http.listen_address", `:${httpPort}`],
1297
+ ["server.directories.data", `${dataDir}/data`],
1298
+ ["server.directories.logs", logDir],
1299
+ ["server.directories.plugins", `${dataDir}/plugins`],
1300
+ ["server.directories.import", `${dataDir}/import`],
1301
+ ];
1302
+ for (const [key, value] of confKeys) {
1303
+ const keyRe = key.replace(/\./g, "\\.");
1304
+ console.log(" [privileged] sed -i (delete)");
1305
+ shell("sed", ["-i", `/^#\\?${keyRe}=/d`, confPath], { sudo: true });
1306
+ console.log(" [privileged] echo >>");
1307
+ shell("sh", ["-c", `echo '${key}=${value}' >> ${confPath}`], { sudo: true });
1308
+ }
1309
+ // Verify exactly one active line per key. Any n>1 aborts the install
1310
+ // BEFORE the systemd unit is written. n==0 means the append failed.
1311
+ const activeCounts = [];
1312
+ for (const [key] of confKeys) {
1313
+ const r = spawnSync("sudo", ["grep", "-c", `^${key}=`, confPath], { stdio: "pipe" });
1314
+ const n = parseInt((r.stdout?.toString() ?? "0").trim(), 10) || 0;
1315
+ activeCounts.push(`${key}:${n}`);
1316
+ if (n !== 1) {
1317
+ const msg = `[neo4j-conf] FATAL ${key} active_count=${n}`;
1318
+ console.error(` ${msg}`);
1319
+ logFile(` ${msg}`);
1320
+ throw new Error(msg);
1321
+ }
1322
+ }
1323
+ const summary = `[neo4j-conf] keys_active=${activeCounts.join(",")}`;
1324
+ console.log(` ${summary}`);
1325
+ logFile(` ${summary}`);
1312
1326
  console.log(" [privileged] mkdir -p");
1313
1327
  shell("mkdir", ["-p", `${dataDir}/data`, `${dataDir}/plugins`, `${dataDir}/import`, logDir], { sudo: true });
1314
1328
  console.log(" [privileged] chown -R");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.110",
3
+ "version": "0.1.111",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -1071,9 +1071,12 @@ FOR (n:Task) ON (n.createdBySession);
1071
1071
 
1072
1072
  // ----------------------------------------------------------
1073
1073
  // CloudflareTunnel / CloudflareHostname — graph audit of
1074
- // the tunnel-login deterministic flow. Written by the
1075
- // /api/admin/cloudflare/setup endpoint after setup-tunnel.sh exits 0,
1076
- // linked via (Task {kind:'cloudflare-tunnel-login'})-[:PRODUCED]->.
1074
+ // the tunnel-login flow. Historically written by the
1075
+ // /api/admin/cloudflare/setup endpoint after setup-tunnel.sh exits 0;
1076
+ // after Task 288 (PTY-native cloudflared) both the endpoint and the
1077
+ // wrapper script are gone. The constraints below remain so legacy
1078
+ // projections stay queryable, but no current writer emits these nodes.
1079
+ // Linked via (Task {kind:'cloudflare-tunnel-login'})-[:PRODUCED]->.
1077
1080
  // CloudflareHostname carries the routed FQDN; CloudflareTunnel
1078
1081
  // carries the connector identity. Source of truth remains the on-disk
1079
1082
  // cert.pem + tunnel.state + config.yml — these nodes are the graph
@@ -505,20 +505,20 @@ sudo cloudflared service uninstall
505
505
  If `admin.<yourdomain>` is rendering the public-agent UI, the tunnel is fine but the platform UI is treating the admin hostname as public. The platform UI classifies a host as public when either:
506
506
 
507
507
  - the hostname starts with `public.`, or
508
- - the hostname appears in `${CFG_DIR}/alias-domains.json`.
508
+ - the hostname appears in `${HOME}/.${BRAND}/alias-domains.json` (note: brand root, **not** `${CFG_DIR}` — `alias-domains.json` lives one level above `cloudflared/`, because that's where the platform UI watches).
509
509
 
510
510
  Pre-Task-548 sessions populated this file via the now-deleted `tunnel-add-hostname` MCP tool, which wrote every routed hostname — including `admin.*` — into the alias set. The pollution persists across installs.
511
511
 
512
512
  **Diagnose:**
513
513
 
514
514
  ```
515
- cat "${CFG_DIR}/alias-domains.json"
515
+ cat "${HOME}/.${BRAND}/alias-domains.json"
516
516
  ```
517
517
 
518
518
  If `admin.<yourdomain>` appears in the array, remove it:
519
519
 
520
520
  ```
521
- jq --arg H "admin.<yourdomain>" 'map(select(. != $H))' "${CFG_DIR}/alias-domains.json" > /tmp/alias.json && mv /tmp/alias.json "${CFG_DIR}/alias-domains.json"
521
+ jq --arg H "admin.<yourdomain>" 'map(select(. != $H))' "${HOME}/.${BRAND}/alias-domains.json" > /tmp/alias.json && mv /tmp/alias.json "${HOME}/.${BRAND}/alias-domains.json"
522
522
  ```
523
523
 
524
524
  Replace `<yourdomain>` with your actual domain. The platform UI watches the file — no restart required; the next request to the admin hostname routes to the admin surface.
@@ -86,16 +86,18 @@ When the operator is unsure which records are stray, have them list the zone's C
86
86
 
87
87
  ### Remove a rogue entry from `alias-domains.json`
88
88
 
89
- `alias-domains.json` controls which hostnames the platform UI classifies as public (serving the public agent) rather than admin. A prior setup flow may have written an `admin.*` hostname into this file by mistake. Remove it manually:
89
+ `alias-domains.json` controls which hostnames the platform UI classifies as public (serving the public agent) rather than admin. It lives at `${HOME}/.${BRAND}/alias-domains.json` the brand root, **not** `${CFG_DIR}` (which is `${HOME}/.${BRAND}/cloudflared`). The platform UI watches the brand root; writing to `${CFG_DIR}/alias-domains.json` is invisible to the watcher.
90
+
91
+ A prior setup flow may have written an `admin.*` hostname into this file by mistake. Remove it manually:
90
92
 
91
93
  ```
92
- cat "${CFG_DIR}/alias-domains.json"
94
+ cat "${HOME}/.${BRAND}/alias-domains.json"
93
95
  ```
94
96
 
95
97
  If `admin.<yourdomain>` is listed, strip it:
96
98
 
97
99
  ```
98
- jq --arg H "admin.<yourdomain>" 'map(select(. != $H))' "${CFG_DIR}/alias-domains.json" > /tmp/alias.json && mv /tmp/alias.json "${CFG_DIR}/alias-domains.json"
100
+ jq --arg H "admin.<yourdomain>" 'map(select(. != $H))' "${HOME}/.${BRAND}/alias-domains.json" > /tmp/alias.json && mv /tmp/alias.json "${HOME}/.${BRAND}/alias-domains.json"
99
101
  ```
100
102
 
101
103
  Replace `<yourdomain>` with the actual domain. The platform UI watches the file and reloads without a restart.
@@ -23,7 +23,7 @@ These three rules win when anything else in this prompt conflicts with them.
23
23
  Each domain has a small set of tools and, where it exists, a skill that drives the multi-step flow. Match the brief to the domain, load the skill if one is named, and run the tools the skill prescribes.
24
24
 
25
25
  - **WhatsApp setup or config:** load `skill-load skillName=connect-whatsapp` for QR pairing and admin-phone setup; load `skill-load skillName=manage-whatsapp-config` for DM/group policies and admin-phone management. The skills carry the per-phase flow.
26
- - **Cloudflare tunnel:** load `skill-load skillName=setup-tunnel`. The skill names the four sanctioned surfaces (`setup-tunnel.sh`, `reset-tunnel.sh`, `manual-setup.md`, `dashboard-guide.md`) and the inputs to collect.
26
+ - **Cloudflare tunnel:** load `skill-load skillName=setup-tunnel`. The skill drives `cloudflared` directly via Bash following `references/manual-setup.md`, `references/reset-guide.md`, and `references/dashboard-guide.md`. There is no shell-script wrapper; PTY stdout is the only surface.
27
27
  - **Every other domain** (scheduling, Telegram, email, Outlook, contacts, browser, platform admin) runs through the tool descriptions injected into your system prompt. The rules below apply across these domains regardless of which tool is invoked.
28
28
 
29
29
  ## Cross-domain rules