@rubytech/create-maxy-code 0.1.90 → 0.1.91
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
|
@@ -3128,6 +3128,37 @@ WantedBy=multi-user.target
|
|
|
3128
3128
|
spawnSync("sudo", ["loginctl", "enable-linger", currentUser], { stdio: "inherit" });
|
|
3129
3129
|
}
|
|
3130
3130
|
catch { /* not critical */ }
|
|
3131
|
+
// Task 249: persist the systemd journal so per-unit lifecycle events
|
|
3132
|
+
// (watchdog timeouts, SIGTERM/SIGKILL transitions, restart reasons) survive
|
|
3133
|
+
// reboots and are queryable via `journalctl --user -u <brand>.service`.
|
|
3134
|
+
//
|
|
3135
|
+
// Bookworm-canonical mechanism: journald uses persistent storage when
|
|
3136
|
+
// `/var/log/journal/<machine-id>/` exists. No user-level
|
|
3137
|
+
// systemd-journald.service exists by default on Debian; the system instance
|
|
3138
|
+
// stores user-unit events in the same tree, filtered at read time. We only
|
|
3139
|
+
// restart journald when we just created the directory — if the path already
|
|
3140
|
+
// existed, persistence was already active and restarting would needlessly
|
|
3141
|
+
// churn the system journal during the install.
|
|
3142
|
+
try {
|
|
3143
|
+
const machineId = readFileSync("/etc/machine-id", "utf-8").trim();
|
|
3144
|
+
if (machineId) {
|
|
3145
|
+
const journalPath = `/var/log/journal/${machineId}`;
|
|
3146
|
+
const alreadyPersistent = existsSync(journalPath);
|
|
3147
|
+
if (!alreadyPersistent) {
|
|
3148
|
+
console.log(" [privileged] mkdir /var/log/journal");
|
|
3149
|
+
shell("mkdir", ["-p", journalPath], { sudo: true });
|
|
3150
|
+
console.log(" [privileged] systemctl restart systemd-journald");
|
|
3151
|
+
spawnSync("sudo", ["systemctl", "restart", "systemd-journald"], { stdio: "inherit", timeout: 15_000 });
|
|
3152
|
+
logFile(` journald persistence: enabled (created ${journalPath} + restarted journald)`);
|
|
3153
|
+
}
|
|
3154
|
+
else {
|
|
3155
|
+
logFile(` journald persistence: already active (${journalPath} present)`);
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
catch (err) {
|
|
3160
|
+
console.error(` WARNING: failed to enable journald persistence: ${err instanceof Error ? err.message : String(err)}`);
|
|
3161
|
+
}
|
|
3131
3162
|
// Reload and (re)start.
|
|
3132
3163
|
//
|
|
3133
3164
|
// ordering: on upgrades, the old main brand service still holds
|
package/dist/port-resolution.js
CHANGED
|
@@ -97,7 +97,7 @@ ExecStartPre=-/bin/bash ${o.installDir}/platform/scripts/resume-tunnel.sh
|
|
|
97
97
|
ExecStart=/usr/bin/node --require ./server-init.cjs server.js
|
|
98
98
|
Restart=on-failure
|
|
99
99
|
RestartSec=5
|
|
100
|
-
WatchdogSec=
|
|
100
|
+
WatchdogSec=120
|
|
101
101
|
TimeoutStartSec=60
|
|
102
102
|
TimeoutStopSec=10
|
|
103
103
|
Environment=NODE_ENV=production
|
package/package.json
CHANGED
|
@@ -48,7 +48,7 @@ Optional:
|
|
|
48
48
|
|
|
49
49
|
- `force` — one of `brand`, `property`, `all`, or absent. When set, the named upstream step runs even if its output already exists.
|
|
50
50
|
- `output_root` — defaults to the **caller's current working directory** (`./`). The orchestrator creates `<output_root>/<brand_slug>/` for the brand pack and nests properties at `<brand_slug>/properties/<property_slug>-<id>/`. To place the workspace elsewhere — e.g. alongside an existing brand pack from a prior run — pass `output_root` explicitly (absolute path, or relative to CWD). The orchestrator never infers location from an existing brand pack; if you already have one and want this run to reuse it, point `brand_source` at its directory path (see Routing rule 1) AND pass `output_root` to its parent so the new property nests under the same workspace.
|
|
51
|
-
- `register` — one of `premium`, `branded`, or absent. **Premium** keeps the template's super-premium tokens verbatim (only the agent's logo and contact details change); the brand pack's DESIGN.md palette/type are deliberately *not* applied. **Branded** re-skins the template with the brand's tokens. Absent
|
|
51
|
+
- `register` — one of `premium`, `branded`, or absent. **Premium** keeps the template's super-premium tokens verbatim (only the agent's logo and contact details change); the brand pack's DESIGN.md palette/type are deliberately *not* applied. **Branded** re-skins the template with the brand's tokens. **Absent → branded.** Resolve the register only AFTER brand-design has run, so DESIGN.md presence is a guaranteed state (brand-design is step 1 of this same pipeline; gating "branded" on a pre-existing DESIGN.md made the branch structurally unreachable on first runs and silently fell through to premium). Premium is **opt-in only** — the operator must say "premium" or "super-premium" in the request, otherwise branded. The orchestrator passes the resolved register through to `property-brochure`. See `property-brochure → Default visual scheme — and when to override it` for the full contract.
|
|
52
52
|
|
|
53
53
|
If only one input is supplied, **decline and ask for the other** — the orchestrator's reason for being is having both. Route a single-input request to the appropriate sub-skill directly.
|
|
54
54
|
|
|
@@ -17,6 +17,7 @@ const { spawnSync } = require('node:child_process')
|
|
|
17
17
|
const { existsSync, readFileSync, writeFileSync } = require('node:fs')
|
|
18
18
|
const os = require('node:os')
|
|
19
19
|
const path = require('node:path')
|
|
20
|
+
const { monitorEventLoopDelay } = require('node:perf_hooks')
|
|
20
21
|
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
// 0. Start counter — Task 173
|
|
@@ -124,10 +125,41 @@ if (NOTIFY_SOCKET) {
|
|
|
124
125
|
console.error('[server-init] sd_notify READY=1 sent')
|
|
125
126
|
})
|
|
126
127
|
|
|
127
|
-
//
|
|
128
|
-
|
|
128
|
+
// Task 249: WATCHDOG_USEC is injected by systemd when Type=notify +
|
|
129
|
+
// WatchdogSec= is configured (microseconds, integer). Reading it at runtime
|
|
130
|
+
// means a future unit-file bump (e.g. 120 → 180) propagates without code
|
|
131
|
+
// changes. Ping every 15s regardless of deadline: trivially satisfies
|
|
132
|
+
// systemd's "≤ half-deadline" requirement for any deadline ≥ 30s, and
|
|
133
|
+
// gives the near-miss check 15s observation windows so a long block is
|
|
134
|
+
// surfaced within 15s of unblocking.
|
|
135
|
+
const WATCHDOG_USEC = Number.parseInt(process.env.WATCHDOG_USEC ?? '', 10)
|
|
136
|
+
const watchdogDeadlineMs = Number.isFinite(WATCHDOG_USEC) && WATCHDOG_USEC > 0
|
|
137
|
+
? Math.floor(WATCHDOG_USEC / 1000)
|
|
138
|
+
: null
|
|
139
|
+
|
|
140
|
+
// monitorEventLoopDelay records every libuv tick's lag; a sync block of N
|
|
141
|
+
// seconds shows up as histogram.max ≈ N*1000 ms in the cycle where the
|
|
142
|
+
// block ends. When max crosses 50% of the deadline we emit one line so
|
|
143
|
+
// `grep '[server-init] watchdog ping miss' server.log` answers "did we
|
|
144
|
+
// approach the deadline, and how close" without needing systemd state or
|
|
145
|
+
// journald. Histogram is reset every cycle so max reflects this window.
|
|
146
|
+
// Only enabled when the deadline is known — no point recording samples no
|
|
147
|
+
// one reads.
|
|
148
|
+
const loopHist = watchdogDeadlineMs !== null ? monitorEventLoopDelay({ resolution: 50 }) : null
|
|
149
|
+
if (loopHist) loopHist.enable()
|
|
150
|
+
|
|
151
|
+
const watchdogInterval = setInterval(() => {
|
|
152
|
+
sdNotify('WATCHDOG=1')
|
|
153
|
+
if (loopHist && watchdogDeadlineMs !== null) {
|
|
154
|
+
const maxMs = loopHist.max / 1_000_000
|
|
155
|
+
loopHist.reset()
|
|
156
|
+
if (maxMs >= watchdogDeadlineMs / 2) {
|
|
157
|
+
console.error(`[server-init] watchdog ping miss lag-ms=${Math.round(maxMs)} deadline-ms=${watchdogDeadlineMs}`)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}, 15_000)
|
|
129
161
|
watchdogInterval.unref() // don't keep the process alive for this
|
|
130
|
-
console.error(
|
|
162
|
+
console.error(`[server-init] watchdog enabled (ping-interval-ms=15000 deadline-ms=${watchdogDeadlineMs ?? 'unset'})`)
|
|
131
163
|
} else {
|
|
132
164
|
console.error('[server-init] no NOTIFY_SOCKET, watchdog disabled')
|
|
133
165
|
}
|
package/payload/server/server.js
CHANGED
|
@@ -601,6 +601,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
601
601
|
import { readFileSync as readFileSync20, existsSync as existsSync22, watchFile } from "fs";
|
|
602
602
|
import { resolve as resolve23, join as join13, basename as basename5 } from "path";
|
|
603
603
|
import { homedir as homedir4 } from "os";
|
|
604
|
+
import { monitorEventLoopDelay } from "perf_hooks";
|
|
604
605
|
|
|
605
606
|
// app/lib/agent-slug-pattern.ts
|
|
606
607
|
var AGENT_SLUG_PATTERN = /^\/([a-z][a-z0-9-]{2,49})$/;
|
|
@@ -14085,6 +14086,21 @@ var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
|
14085
14086
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14086
14087
|
var httpServer = serve({ fetch: app37.fetch, port, hostname });
|
|
14087
14088
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14089
|
+
{
|
|
14090
|
+
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
14091
|
+
loopHist.enable();
|
|
14092
|
+
const LOG_THRESHOLD_MS = 1e3;
|
|
14093
|
+
const WINDOW_MS2 = 3e4;
|
|
14094
|
+
const lagTimer = setInterval(() => {
|
|
14095
|
+
const maxMs = loopHist.max / 1e6;
|
|
14096
|
+
const p99Ms = loopHist.percentile(99) / 1e6;
|
|
14097
|
+
loopHist.reset();
|
|
14098
|
+
if (maxMs >= LOG_THRESHOLD_MS) {
|
|
14099
|
+
console.error(`[event-loop] lag p99=${Math.round(p99Ms)} max=${Math.round(maxMs)} window=${WINDOW_MS2 / 1e3}s`);
|
|
14100
|
+
}
|
|
14101
|
+
}, WINDOW_MS2);
|
|
14102
|
+
lagTimer.unref();
|
|
14103
|
+
}
|
|
14088
14104
|
console.log("[boot] auth-mode summary: oauth=8 api-key=1 (api-key consumer: invokePublicAgent only)");
|
|
14089
14105
|
var SUBAPP_MANIFEST = [
|
|
14090
14106
|
{ prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
|