@rubytech/create-maxy-code 0.1.372 → 0.1.374
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/__tests__/cgroup-memory-controller-install-flow.test.js +41 -0
- package/dist/__tests__/cgroup-memory-controller.test.js +32 -0
- package/dist/cgroup-memory-controller.js +33 -0
- package/dist/index.js +54 -0
- package/package.json +1 -1
- package/payload/platform/lib/models/dist/index.d.ts +1 -1
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +2 -2
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +2 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +2 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/scripts/rss-sampler.sh +18 -2
- 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 +14 -7
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +19 -0
- 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 +42 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +24 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts +75 -4
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js +138 -15
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js.map +1 -1
- package/payload/platform/templates/specialists/agents/data-manager.md +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/premium-plugins/writer-craft/agents/writer-craft--manuscript-reviewer.md +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-Cv3mxJVn.js → AdminLoginScreens-CGTA9noi.js} +1 -1
- package/payload/server/public/assets/AdminShell-CNwb23_A.js +1 -0
- package/payload/server/public/assets/{Checkbox-DlXtucB_.js → Checkbox-BagcrE4Q.js} +1 -1
- package/payload/server/public/assets/{OperatorConversations-ka_b3K3l.css → OperatorConversations-BX9t3jgm.css} +1 -1
- package/payload/server/public/assets/{admin-VOx7YvPT.js → admin-CodAEpgQ.js} +1 -1
- package/payload/server/public/assets/{browser-DUrqC4lq.js → browser-CRTlI7ck.js} +1 -1
- package/payload/server/public/assets/{calendar-1QEs24eI.js → calendar-BBEivUAw.js} +1 -1
- package/payload/server/public/assets/chat-r1qKuzHk.js +1 -0
- package/payload/server/public/assets/{data-Dx1lRmMH.js → data-BkY0bFYS.js} +1 -1
- package/payload/server/public/assets/{graph-CJURDOED.js → graph-HoHcI7qv.js} +1 -1
- package/payload/server/public/assets/{graph-labels-C-tGPoLE.js → graph-labels-BJfK0tbH.js} +1 -1
- package/payload/server/public/assets/{operator-B3_Odno9.js → operator-5wtImBoF.js} +1 -1
- package/payload/server/public/assets/{page-Caf6BQNK.js → page-CzTgPTp3.js} +1 -1
- package/payload/server/public/assets/{public-DGWDk4tx.js → public-CUopv7Ro.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-DeTygixt.js → rotate-ccw-DttFB1nY.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +4 -4
- package/payload/server/public/chat.html +6 -6
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +7 -7
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +3 -3
- package/payload/server/public/assets/AdminShell-CR0AdnAx.js +0 -1
- package/payload/server/public/assets/chat-BYua7UiL.js +0 -1
- /package/payload/server/public/assets/{OperatorConversations-tDWA0PWN.js → OperatorConversations-CivR0bnD.js} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Static-grep contract for configureCgroupMemoryController()'s placement in
|
|
2
|
+
// the install flow — same precedent as watchdog-deferred-arming.test.ts for
|
|
3
|
+
// an installer side-effecting step that shells out with sudo and can't be
|
|
4
|
+
// safely executed in a unit test. The pure decision rule itself is covered
|
|
5
|
+
// by cgroup-memory-controller.test.ts.
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { dirname, resolve } from "node:path";
|
|
11
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const INDEX_TS = resolve(here, "../../src/index.ts");
|
|
13
|
+
const SRC = readFileSync(INDEX_TS, "utf-8");
|
|
14
|
+
function fnBody(name) {
|
|
15
|
+
const start = SRC.indexOf(`function ${name}`);
|
|
16
|
+
assert.ok(start >= 0, `could not locate ${name} in index.ts`);
|
|
17
|
+
const nextFn = SRC.indexOf("\nfunction ", start + 1);
|
|
18
|
+
assert.ok(nextFn > start, `could not bound ${name} body`);
|
|
19
|
+
return SRC.slice(start, nextFn);
|
|
20
|
+
}
|
|
21
|
+
test("configureCgroupMemoryController is called inside installService()'s Linux branch", () => {
|
|
22
|
+
const installServiceStart = SRC.indexOf("function installService(");
|
|
23
|
+
assert.ok(installServiceStart >= 0, "installService() not found");
|
|
24
|
+
const darwinReturn = SRC.indexOf("installServiceDarwin();\n return;", installServiceStart);
|
|
25
|
+
assert.ok(darwinReturn > installServiceStart, "expected the darwin early-return inside installService()");
|
|
26
|
+
const callSite = SRC.indexOf("configureCgroupMemoryController();", darwinReturn);
|
|
27
|
+
assert.ok(callSite > darwinReturn, "configureCgroupMemoryController() must be called after the darwin early-return (Linux-only)");
|
|
28
|
+
});
|
|
29
|
+
test("configureCgroupMemoryController never throws on a patch failure (non-fatal, matches the sysctl.d precedent)", () => {
|
|
30
|
+
const body = fnBody("configureCgroupMemoryController");
|
|
31
|
+
assert.ok(body.includes("try {"), "expected a try/catch around the sudo cp — a read-only /boot must not abort install");
|
|
32
|
+
assert.ok(body.includes("catch"), "expected a catch branch");
|
|
33
|
+
});
|
|
34
|
+
test("configureCgroupMemoryController always logs a resolved op=cgroup-memory-status line", () => {
|
|
35
|
+
const body = fnBody("configureCgroupMemoryController");
|
|
36
|
+
const occurrences = body.match(/op=cgroup-memory-status/g) ?? [];
|
|
37
|
+
assert.ok(occurrences.length >= 4, `expected at least 4 branches to log op=cgroup-memory-status, found ${occurrences.length}`);
|
|
38
|
+
});
|
|
39
|
+
test("configureCgroupMemoryController imports the pure decision rule from cgroup-memory-controller.js", () => {
|
|
40
|
+
assert.ok(SRC.includes('from "./cgroup-memory-controller.js"'), "index.ts must import memoryControllerMissing/cmdlineAlreadyPatched/patchCmdline rather than re-implementing the parsing");
|
|
41
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Pure decision rule for Task 1297: does this host's kernel have the memory
|
|
2
|
+
// cgroup controller enabled, and if not, does its boot cmdline already carry
|
|
3
|
+
// the fix. The wrapper in index.ts owns the fs reads and the sudo cp; this
|
|
4
|
+
// suite exercises only the pure functions — inputs in, decision out.
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { CGROUP_MEMORY_CMDLINE_FLAGS, memoryControllerMissing, cmdlineAlreadyPatched, patchCmdline, } from "../cgroup-memory-controller.js";
|
|
8
|
+
test("memoryControllerMissing: false when memory is in the controller list", () => {
|
|
9
|
+
assert.equal(memoryControllerMissing("cpuset cpu io memory pids\n"), false);
|
|
10
|
+
});
|
|
11
|
+
test("memoryControllerMissing: true when memory is absent (the Pi default)", () => {
|
|
12
|
+
assert.equal(memoryControllerMissing("cpuset cpu io pids\n"), true);
|
|
13
|
+
});
|
|
14
|
+
test("memoryControllerMissing: true on an empty controller list", () => {
|
|
15
|
+
assert.equal(memoryControllerMissing(""), true);
|
|
16
|
+
});
|
|
17
|
+
test("cmdlineAlreadyPatched: true when the flags are present", () => {
|
|
18
|
+
const cmdline = "console=tty1 root=PARTUUID=abc rootwait cgroup_enable=memory cgroup_memory=1\n";
|
|
19
|
+
assert.equal(cmdlineAlreadyPatched(cmdline), true);
|
|
20
|
+
});
|
|
21
|
+
test("cmdlineAlreadyPatched: false on an unpatched line", () => {
|
|
22
|
+
const cmdline = "console=serial0,115200 console=tty1 root=PARTUUID=e9d78c4e-02 rootwait quiet splash\n";
|
|
23
|
+
assert.equal(cmdlineAlreadyPatched(cmdline), false);
|
|
24
|
+
});
|
|
25
|
+
test("patchCmdline: appends the flags with a single trailing newline", () => {
|
|
26
|
+
const cmdline = "console=tty1 root=PARTUUID=abc rootwait\n";
|
|
27
|
+
assert.equal(patchCmdline(cmdline), `console=tty1 root=PARTUUID=abc rootwait ${CGROUP_MEMORY_CMDLINE_FLAGS}\n`);
|
|
28
|
+
});
|
|
29
|
+
test("patchCmdline: works when the source has no trailing newline", () => {
|
|
30
|
+
const cmdline = "console=tty1 root=PARTUUID=abc rootwait";
|
|
31
|
+
assert.equal(patchCmdline(cmdline), `console=tty1 root=PARTUUID=abc rootwait ${CGROUP_MEMORY_CMDLINE_FLAGS}\n`);
|
|
32
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Pure logic for Task 1297: the Pi kernel ships with the memory cgroup
|
|
2
|
+
// controller disabled by default (/sys/fs/cgroup/cgroup.controllers has no
|
|
3
|
+
// `memory`), which makes every MemoryHigh=/MemoryMax= this platform
|
|
4
|
+
// configures (Task 1176, Task 1222) a silent no-op — confirmed fleet-wide
|
|
5
|
+
// across all 5 Pis via live inspection. The wrapper in index.ts owns the fs
|
|
6
|
+
// reads, locating the boot cmdline file, and the sudo cp. This module owns
|
|
7
|
+
// only the decision + the patched-content computation — inputs in, decision
|
|
8
|
+
// out. No reboot logic here or in the wrapper; a boot-param change only takes
|
|
9
|
+
// effect on the operator's next reboot.
|
|
10
|
+
export const CGROUP_MEMORY_CMDLINE_FLAGS = "cgroup_enable=memory cgroup_memory=1";
|
|
11
|
+
/** True when the cgroup-v2 root controller list (the raw content of
|
|
12
|
+
* /sys/fs/cgroup/cgroup.controllers) lacks `memory`. Inline rather than
|
|
13
|
+
* imported from platform/services/claude-session-manager because the
|
|
14
|
+
* installer is its own npm package and doesn't bundle platform services.
|
|
15
|
+
* Mirrors (negated) memoryControllerInList() in
|
|
16
|
+
* platform/services/claude-session-manager/src/rc-daemon.ts; future
|
|
17
|
+
* divergence between the two should be caught by the test suite. */
|
|
18
|
+
export function memoryControllerMissing(controllers) {
|
|
19
|
+
return !controllers.split(/\s+/).filter(Boolean).includes("memory");
|
|
20
|
+
}
|
|
21
|
+
/** True when the boot cmdline file already carries the enable flags —
|
|
22
|
+
* patching again would duplicate them. */
|
|
23
|
+
export function cmdlineAlreadyPatched(cmdline) {
|
|
24
|
+
return cmdline.includes("cgroup_enable=memory");
|
|
25
|
+
}
|
|
26
|
+
/** Append the enable flags to the single-line boot cmdline file. Callers
|
|
27
|
+
* must gate on cmdlineAlreadyPatched() first — this always appends, so
|
|
28
|
+
* calling it twice on the same content would duplicate the flags. Trims
|
|
29
|
+
* any trailing whitespace before appending, then restores exactly one
|
|
30
|
+
* trailing newline (cmdline.txt convention: one line, trailing newline). */
|
|
31
|
+
export function patchCmdline(cmdline) {
|
|
32
|
+
return `${cmdline.replace(/\s+$/, "")} ${CGROUP_MEMORY_CMDLINE_FLAGS}\n`;
|
|
33
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { installAllBrewPackages } from "./brew-install.js";
|
|
|
19
19
|
import { parseSwVers, isSupportedMacosVersion } from "./macos-version.js";
|
|
20
20
|
import { decideChromiumAction, isSnapConfinedPath } from "./snap-chromium.js";
|
|
21
21
|
import { classifyPortHolder } from "./preflight-port-classifier.js";
|
|
22
|
+
import { memoryControllerMissing, cmdlineAlreadyPatched, patchCmdline } from "./cgroup-memory-controller.js";
|
|
22
23
|
import { parsePluginList, computeInstallActions, parseExternalPlugins, findUnregisteredResyncs, } from "./lib/plugin-install.js";
|
|
23
24
|
import { findPremiumMcpDirs } from "./lib/premium-mcp-discover.js";
|
|
24
25
|
import { pickBindDecision, mergeSmbConf, formatSambaMarker, SAMBA_ENABLE_UNITS, } from "./samba-provision.js";
|
|
@@ -3243,6 +3244,56 @@ function installServiceDarwin() {
|
|
|
3243
3244
|
console.log(` Server may still be starting. Check http://localhost:${PORT} in a moment.`);
|
|
3244
3245
|
}
|
|
3245
3246
|
}
|
|
3247
|
+
/** Task 1297 — the Pi kernel ships with the memory cgroup controller
|
|
3248
|
+
* disabled by default (/sys/fs/cgroup/cgroup.controllers has no `memory`),
|
|
3249
|
+
* which makes every MemoryHigh=/MemoryMax= this platform configures (Task
|
|
3250
|
+
* 1176, Task 1222) a silent no-op — confirmed fleet-wide, not theorized.
|
|
3251
|
+
* Patches the boot cmdline so the NEXT reboot activates it; never triggers
|
|
3252
|
+
* the reboot itself. Non-fatal: a read-only /boot partition, an absent
|
|
3253
|
+
* cmdline file (x86 hosts don't have one and don't need this), or a host
|
|
3254
|
+
* where the controller is already enabled (laptop, hart) all resolve to a
|
|
3255
|
+
* logged status line and a clean return — matching the sysctl.d QUIC
|
|
3256
|
+
* drop-in step's failure handling immediately below this function's call
|
|
3257
|
+
* site. */
|
|
3258
|
+
function configureCgroupMemoryController() {
|
|
3259
|
+
let controllers;
|
|
3260
|
+
try {
|
|
3261
|
+
controllers = readFileSync("/sys/fs/cgroup/cgroup.controllers", "utf-8");
|
|
3262
|
+
}
|
|
3263
|
+
catch {
|
|
3264
|
+
logFile("[install] op=cgroup-memory-status enabled=unknown patched=unknown reason=no-cgroup-v2-root");
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
if (!memoryControllerMissing(controllers)) {
|
|
3268
|
+
logFile("[install] op=cgroup-memory-status enabled=true patched=false");
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
const cmdlinePath = existsSync("/boot/firmware/cmdline.txt")
|
|
3272
|
+
? "/boot/firmware/cmdline.txt"
|
|
3273
|
+
: existsSync("/boot/cmdline.txt")
|
|
3274
|
+
? "/boot/cmdline.txt"
|
|
3275
|
+
: null;
|
|
3276
|
+
if (!cmdlinePath) {
|
|
3277
|
+
logFile("[install] op=cgroup-memory-status enabled=false patched=false reason=no-cmdline-file");
|
|
3278
|
+
return;
|
|
3279
|
+
}
|
|
3280
|
+
const cmdline = readFileSync(cmdlinePath, "utf-8");
|
|
3281
|
+
if (cmdlineAlreadyPatched(cmdline)) {
|
|
3282
|
+
logFile("[install] op=cgroup-memory-status enabled=false patched=true");
|
|
3283
|
+
return;
|
|
3284
|
+
}
|
|
3285
|
+
try {
|
|
3286
|
+
const tmpPath = "/tmp/cmdline.txt.maxy-cgroup-patch";
|
|
3287
|
+
writeFileSync(tmpPath, patchCmdline(cmdline));
|
|
3288
|
+
console.log(" [privileged] cp");
|
|
3289
|
+
shell("cp", [tmpPath, cmdlinePath], { sudo: true });
|
|
3290
|
+
spawnSync("rm", ["-f", tmpPath]);
|
|
3291
|
+
logFile("[install] op=cgroup-memory-status enabled=false patched=true");
|
|
3292
|
+
}
|
|
3293
|
+
catch {
|
|
3294
|
+
logFile("[install] op=cgroup-memory-status enabled=false patched=false reason=patch-failed");
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3246
3297
|
function installService() {
|
|
3247
3298
|
log("11", TOTAL, `Starting ${BRAND.productName}...`);
|
|
3248
3299
|
// Linux falls through to the systemd-user body below; darwin renders +
|
|
@@ -3265,6 +3316,9 @@ function installService() {
|
|
|
3265
3316
|
spawnSync("sudo", ["sysctl", "--system"], { stdio: "ignore", timeout: 10_000 });
|
|
3266
3317
|
}
|
|
3267
3318
|
catch { /* non-critical — values applied on next reboot */ }
|
|
3319
|
+
// Task 1297 — activate the fleet-wide memory ceiling (Task 1176/1222) by
|
|
3320
|
+
// enabling the kernel controller it has silently depended on since it shipped.
|
|
3321
|
+
configureCgroupMemoryController();
|
|
3268
3322
|
const serviceDir = resolve(process.env.HOME ?? "/root", ".config/systemd/user");
|
|
3269
3323
|
mkdirSync(serviceDir, { recursive: true });
|
|
3270
3324
|
// Create systemd user service
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
2
|
-
export declare const SONNET_MODEL = "claude-sonnet-
|
|
2
|
+
export declare const SONNET_MODEL = "claude-sonnet-5";
|
|
3
3
|
export declare const HAIKU_MODEL = "claude-haiku-4-5";
|
|
4
4
|
export declare const MODEL_CONTEXT_WINDOW: Record<string, number>;
|
|
5
5
|
/** Look up context window size; defaults to 200k for unknown models. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAC9C,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIvD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;qEAEqE;AACrE,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAItD,CAAC;AAEF;+DAC+D;AAC/D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;mCAGmC;AACnC,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA4C,CAAC;AAC5F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;qCAKqC;AACrC,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;wDAIwD;AACxD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnD;AAaD,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,0EAA2E,CAAC;AACzG,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE;AAED,sDAAsD;AACtD,eAAO,MAAM,aAAa,6CAA8C,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AACzD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE;AASD;kFACkF;AAClF,eAAO,MAAM,sBAAsB,qFAA4C,CAAC;AAChF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;oEACoE;AACpE,eAAO,MAAM,qBAAqB,4DAA6C,CAAC;AAChF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;yCAKyC;AACzC,eAAO,MAAM,yBAAyB,oDAAqC,CAAC;AAC5E,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/E,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,qBAAqB,CAErF"}
|
|
@@ -16,7 +16,7 @@ exports.isNewSessionEffortLevel = isNewSessionEffortLevel;
|
|
|
16
16
|
// context-extension suffix, valid in settings.json "model" and agent
|
|
17
17
|
// frontmatter); Sonnet/Haiku stay on the standard 200k window.
|
|
18
18
|
exports.OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
19
|
-
exports.SONNET_MODEL = "claude-sonnet-
|
|
19
|
+
exports.SONNET_MODEL = "claude-sonnet-5";
|
|
20
20
|
exports.HAIKU_MODEL = "claude-haiku-4-5";
|
|
21
21
|
exports.MODEL_CONTEXT_WINDOW = {
|
|
22
22
|
[exports.OPUS_MODEL]: 1_000_000,
|
|
@@ -32,7 +32,7 @@ function contextWindow(model) {
|
|
|
32
32
|
* with its raw id as the label (the composer's append-fallback). */
|
|
33
33
|
exports.MODEL_DISPLAY_NAMES = {
|
|
34
34
|
[exports.OPUS_MODEL]: "Opus 4.8 (1M context)",
|
|
35
|
-
[exports.SONNET_MODEL]: "Sonnet
|
|
35
|
+
[exports.SONNET_MODEL]: "Sonnet 5",
|
|
36
36
|
[exports.HAIKU_MODEL]: "Haiku 4.5",
|
|
37
37
|
};
|
|
38
38
|
/** The dropdown label for a model id: friendly name when canonical, else the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,iEAAiE;AACjE,6CAA6C;;;AAgB7C,sCAEC;AAaD,4CAEC;AAOD,8CAEC;AAQD,kCAEC;AAOD,4CAEC;AAgBD,4CAEC;AAKD,sCAEC;AA2BD,0DAEC;AAjHD,iEAAiE;AACjE,qEAAqE;AACrE,+DAA+D;AAClD,QAAA,UAAU,GAAG,qBAAqB,CAAC;AACnC,QAAA,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// context-extension suffix, valid in settings.json "model" and agent
|
|
7
7
|
// frontmatter); Sonnet/Haiku stay on the standard 200k window.
|
|
8
8
|
export const OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
9
|
-
export const SONNET_MODEL = "claude-sonnet-
|
|
9
|
+
export const SONNET_MODEL = "claude-sonnet-5";
|
|
10
10
|
export const HAIKU_MODEL = "claude-haiku-4-5";
|
|
11
11
|
|
|
12
12
|
export const MODEL_CONTEXT_WINDOW: Record<string, number> = {
|
|
@@ -25,7 +25,7 @@ export function contextWindow(model: string): number {
|
|
|
25
25
|
* with its raw id as the label (the composer's append-fallback). */
|
|
26
26
|
export const MODEL_DISPLAY_NAMES: Record<string, string> = {
|
|
27
27
|
[OPUS_MODEL]: "Opus 4.8 (1M context)",
|
|
28
|
-
[SONNET_MODEL]: "Sonnet
|
|
28
|
+
[SONNET_MODEL]: "Sonnet 5",
|
|
29
29
|
[HAIKU_MODEL]: "Haiku 4.5",
|
|
30
30
|
};
|
|
31
31
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:e15d80a5ac347f9eb8167ecdc10e2ce092db72ca3d6dfa5d0d8ac85d6676ec2a
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -2535,7 +2535,7 @@ either is a regression.
|
|
|
2535
2535
|
| `/session-rc-spawn` | POST `{ sessionId?, name? }`. Fire-and-forget `claude --remote-control [name] [--session-id <sid>]`. Present `sessionId` resumes; absent starts a fresh session (also used by the sidebar's "New session" button — it no longer opens claude.ai/code directly). Proxies to the manager's `/rc-spawn`, which waits up to **60 s** (raised from 12 s) for the spawned PTY to bind and returns `{ spawnedPid, sessionId, bridgeSessionId, slug, outcome, reason }`. For a webchat-bound spawn (every admin-gated host's "New session", returning a same-origin `/chat?session=<id>` target — `resolveRcSpawnOutcome` → `sameOrigin:true`) the Sidebar navigates the **current** tab via `window.location.assign`, replacing the dashboard in place (back returns to it); only a claude.ai/code slug (`sameOrigin:false`, the bare-admin resume bridge, never a new-session outcome) navigates a separately-opened tab. On `timeout` or `spawn-failed` it shows an error modal (reason + sessionId) and **never** opens a bare claude.ai/code tab. The new process registers itself as its own Remote Control entry in claude.ai/code. | `POST /` |
|
|
2536
2536
|
| `/claude-sessions` | **Spawn surface only**. `POST /` is the Sidebar new-session-with-prompt path, cookie-auth only (the recorder loopback caller was removed; LinkedIn ingest moved to `/rc-spawn`). The former UI-facing handlers (SSE row feed, list, resume, stop, rename, archive, delete, `/:id/meta`, `/:id/input`, `/:id/log`) were removed — the maxy dashboard no longer manages or displays sessions. | `POST /` |
|
|
2537
2537
|
|
|
2538
|
-
**Admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot; the reasoning-effort lever is `account.json.effort` → `settings.json "effortLevel"` (accepted values `low|medium|high|xhigh`; any other value, e.g. legacy `"auto"`, leaves the key unset so claude's own default governs), written by the same read-merge-write at boot. A third inception lever, permission mode, is added: `account.json.adminPermissionMode` → `settings.json "permissions.defaultMode"` (the 5 composer-writable modes `default|acceptEdits|plan|auto|bypassPermissions`; `dontAsk` is out of scope). Unlike model/effort (top-level keys), this lever **deep-merges** the nested `permissions.defaultMode`, owning only that key and preserving sibling `permissions` keys (allow/deny/…) — what the binary and the spawn lifeline actually read. **For admin sessions, permission mode is fixed (Bypass) and not operator-chosen, while model and effort ARE operator-chosen at launch** via the composer's `+` new-session popover — a radio model list (Opus / Sonnet / Haiku) plus a 5-stop Faster→Smarter effort slider (Low / Medium / High / Extra / Max, where `max` applies via the `--effort` argv rather than `settings.json`); the popover description lives in `.docs/admin-webchat-native-channel.md`. Absent a pick (and on every resume), the daemon-pinned defaults govern: the `/chat` composer *footer* carries no live re-seat pickers — `rc-daemon.ts` pins settings.json `model`/`effortLevel`/`permissions.defaultMode` to `claude-opus-4-8[1m]` / `medium` / `bypassPermissions` regardless of `account.json` (read by the rc-spawn webchat path), and `pty-spawner.ts` forces the claude.ai/code PTY `--permission-mode` to `bypassPermissions` for `role=admin`. Public sessions are fixed to `claude-sonnet-
|
|
2538
|
+
**Admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot; the reasoning-effort lever is `account.json.effort` → `settings.json "effortLevel"` (accepted values `low|medium|high|xhigh`; any other value, e.g. legacy `"auto"`, leaves the key unset so claude's own default governs), written by the same read-merge-write at boot. A third inception lever, permission mode, is added: `account.json.adminPermissionMode` → `settings.json "permissions.defaultMode"` (the 5 composer-writable modes `default|acceptEdits|plan|auto|bypassPermissions`; `dontAsk` is out of scope). Unlike model/effort (top-level keys), this lever **deep-merges** the nested `permissions.defaultMode`, owning only that key and preserving sibling `permissions` keys (allow/deny/…) — what the binary and the spawn lifeline actually read. **For admin sessions, permission mode is fixed (Bypass) and not operator-chosen, while model and effort ARE operator-chosen at launch** via the composer's `+` new-session popover — a radio model list (Opus / Sonnet / Haiku) plus a 5-stop Faster→Smarter effort slider (Low / Medium / High / Extra / Max, where `max` applies via the `--effort` argv rather than `settings.json`); the popover description lives in `.docs/admin-webchat-native-channel.md`. Absent a pick (and on every resume), the daemon-pinned defaults govern: the `/chat` composer *footer* carries no live re-seat pickers — `rc-daemon.ts` pins settings.json `model`/`effortLevel`/`permissions.defaultMode` to `claude-opus-4-8[1m]` / `medium` / `bypassPermissions` regardless of `account.json` (read by the rc-spawn webchat path), and `pty-spawner.ts` forces the claude.ai/code PTY `--permission-mode` to `bypassPermissions` for `role=admin`. Public sessions are fixed to `claude-sonnet-5` (the `/public-spawn` chokepoint + `buildPublicWebchatSpawnRequest`), keeping `dontAsk`. The composer footer instead renders a **read-only** params row (mode · model · effort labels) plus a context-window usage figure (`pct% · ~used/~window`), all sourced from the session pointer; the full path is in `.docs/admin-webchat-native-channel.md`. The composer cannot re-seat a session, so the "no transcript" 400 on a brand-new chat is unreachable; the `/api/admin/session-reseat` + `/api/webchat/settings` routes and the dashboard re-seat form stay as off-composer surfaces. When the live session runs in `default` ("Ask permissions") mode, a tool the agent attempts that needs approval surfaces an Allow/Deny card in the composer (tool, description, argument preview); a click sends the verdict over Claude Code's channel permission relay and the tool runs or is refused — webchat is the only interactive ask surface (WhatsApp stays text-only; Telegram has no agent channel). Beyond the composer, the maxy admin UI keeps a single "New session" link (`https://claude.ai/code`, opens in a new tab) and no separate session list, viewer, controls, or model/mode picker. The daemon supervisor lives at [`platform/services/claude-session-manager/src/rc-daemon.ts`](../../../services/claude-session-manager/src/rc-daemon.ts). The `/session-defaults` route and `SpawnPreference` node were deleted with the picker. `/new-session-failure`, `/new-session-submit`, and `/claude-capabilities` are now orphaned (consumed only by the deleted NewSessionModal) — see [`.tasks/501`](../../../.tasks/) for their removal.
|
|
2539
2539
|
|
|
2540
2540
|
**Row title resolution.** Both the sidebar (`/sidebar-sessions`) and the manager's own row payload resolve a row's title in the same order: operator rename → Claude Code `ai-title` → first non-CLI user message → 8-char sessionId prefix. The operator-rename tier is the on-disk `<accountDir>/session-titles.json` (the manager's `UserTitleStore`), keyed by the CC sessionId — the sidebar reads that same file, so a write to the store lights up both surfaces with one write.
|
|
2541
2541
|
|
|
@@ -94,7 +94,7 @@ When the user asks to change output style, thinking view, effort, context mode,
|
|
|
94
94
|
|
|
95
95
|
| Setting | Field | Values |
|
|
96
96
|
|---------|-------|--------|
|
|
97
|
-
| Admin model | `adminModel` | Any Anthropic model ID (e.g. `"claude-sonnet-
|
|
97
|
+
| Admin model | `adminModel` | Any Anthropic model ID (e.g. `"claude-sonnet-5"`) |
|
|
98
98
|
| Public model | `publicModel` | Any Anthropic model ID (e.g. `"claude-haiku-4-5"`) |
|
|
99
99
|
| Output style | `outputStyle` | `"default"` \| `"explanatory"` |
|
|
100
100
|
| Thinking view | `thinkingView` | `"default"` \| `"expanded"` \| `"collapsed"` |
|
|
@@ -82,7 +82,7 @@ Present as a `select` field within the agent configuration `form` during creatio
|
|
|
82
82
|
| Model | ID | Suitability | Cost |
|
|
83
83
|
|-------|-----|------------|------|
|
|
84
84
|
| Haiku | `claude-haiku-4-5` | Fast, cost-effective. FAQ, routing, high-volume. | Low |
|
|
85
|
-
| Sonnet | `claude-sonnet-
|
|
85
|
+
| Sonnet | `claude-sonnet-5` | Balanced. Nuanced conversation, qualification, support. | Standard |
|
|
86
86
|
| Opus | `claude-opus-4-8[1m]` | Maximum intelligence. Complex sales, consultative selling. | Premium |
|
|
87
87
|
|
|
88
88
|
## SOUL.md Scope Enforcement
|
|
@@ -161,7 +161,7 @@ After creation, no template metadata persists in the agent's files. The resultin
|
|
|
161
161
|
- `knowledgeKeywords` (`text`): label "Knowledge keywords (max 5, comma-separated)", placeholder with examples relevant to the agent's role
|
|
162
162
|
- `model` (`select`): label "Model", options with descriptions:
|
|
163
163
|
- `claude-haiku-4-5` — "Haiku — Fast, cost-effective. FAQ, routing, high-volume."
|
|
164
|
-
- `claude-sonnet-
|
|
164
|
+
- `claude-sonnet-5` — "Sonnet — Balanced. Nuanced conversation, qualification, support."
|
|
165
165
|
- `claude-opus-4-8[1m]` — "Opus — Maximum intelligence. Complex sales, consultative selling."
|
|
166
166
|
- `showAgentName` (`select`): label "Chat header title", options: `false` — "Business name (default)", `true` — "Agent display name", `"none"` — "None (logo only)"
|
|
167
167
|
The `model` field should have a `defaultValue` of `"claude-haiku-4-5"`.
|
|
@@ -61,7 +61,7 @@ either is a regression.
|
|
|
61
61
|
| `/session-rc-spawn` | POST `{ sessionId?, name? }`. Fire-and-forget `claude --remote-control [name] [--session-id <sid>]`. Present `sessionId` resumes; absent starts a fresh session (also used by the sidebar's "New session" button — it no longer opens claude.ai/code directly). Proxies to the manager's `/rc-spawn`, which waits up to **60 s** (raised from 12 s) for the spawned PTY to bind and returns `{ spawnedPid, sessionId, bridgeSessionId, slug, outcome, reason }`. For a webchat-bound spawn (every admin-gated host's "New session", returning a same-origin `/chat?session=<id>` target — `resolveRcSpawnOutcome` → `sameOrigin:true`) the Sidebar navigates the **current** tab via `window.location.assign`, replacing the dashboard in place (back returns to it); only a claude.ai/code slug (`sameOrigin:false`, the bare-admin resume bridge, never a new-session outcome) navigates a separately-opened tab. On `timeout` or `spawn-failed` it shows an error modal (reason + sessionId) and **never** opens a bare claude.ai/code tab. The new process registers itself as its own Remote Control entry in claude.ai/code. | `POST /` |
|
|
62
62
|
| `/claude-sessions` | **Spawn surface only**. `POST /` is the Sidebar new-session-with-prompt path, cookie-auth only (the recorder loopback caller was removed; LinkedIn ingest moved to `/rc-spawn`). The former UI-facing handlers (SSE row feed, list, resume, stop, rename, archive, delete, `/:id/meta`, `/:id/input`, `/:id/log`) were removed — the maxy dashboard no longer manages or displays sessions. | `POST /` |
|
|
63
63
|
|
|
64
|
-
**Admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot; the reasoning-effort lever is `account.json.effort` → `settings.json "effortLevel"` (accepted values `low|medium|high|xhigh`; any other value, e.g. legacy `"auto"`, leaves the key unset so claude's own default governs), written by the same read-merge-write at boot. A third inception lever, permission mode, is added: `account.json.adminPermissionMode` → `settings.json "permissions.defaultMode"` (the 5 composer-writable modes `default|acceptEdits|plan|auto|bypassPermissions`; `dontAsk` is out of scope). Unlike model/effort (top-level keys), this lever **deep-merges** the nested `permissions.defaultMode`, owning only that key and preserving sibling `permissions` keys (allow/deny/…) — what the binary and the spawn lifeline actually read. **For admin sessions, permission mode is fixed (Bypass) and not operator-chosen, while model and effort ARE operator-chosen at launch** via the composer's `+` new-session popover — a radio model list (Opus / Sonnet / Haiku) plus a 5-stop Faster→Smarter effort slider (Low / Medium / High / Extra / Max, where `max` applies via the `--effort` argv rather than `settings.json`); the popover description lives in `.docs/admin-webchat-native-channel.md`. Absent a pick (and on every resume), the daemon-pinned defaults govern: the `/chat` composer *footer* carries no live re-seat pickers — `rc-daemon.ts` pins settings.json `model`/`effortLevel`/`permissions.defaultMode` to `claude-opus-4-8[1m]` / `medium` / `bypassPermissions` regardless of `account.json` (read by the rc-spawn webchat path), and `pty-spawner.ts` forces the claude.ai/code PTY `--permission-mode` to `bypassPermissions` for `role=admin`. Public sessions are fixed to `claude-sonnet-
|
|
64
|
+
**Admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot; the reasoning-effort lever is `account.json.effort` → `settings.json "effortLevel"` (accepted values `low|medium|high|xhigh`; any other value, e.g. legacy `"auto"`, leaves the key unset so claude's own default governs), written by the same read-merge-write at boot. A third inception lever, permission mode, is added: `account.json.adminPermissionMode` → `settings.json "permissions.defaultMode"` (the 5 composer-writable modes `default|acceptEdits|plan|auto|bypassPermissions`; `dontAsk` is out of scope). Unlike model/effort (top-level keys), this lever **deep-merges** the nested `permissions.defaultMode`, owning only that key and preserving sibling `permissions` keys (allow/deny/…) — what the binary and the spawn lifeline actually read. **For admin sessions, permission mode is fixed (Bypass) and not operator-chosen, while model and effort ARE operator-chosen at launch** via the composer's `+` new-session popover — a radio model list (Opus / Sonnet / Haiku) plus a 5-stop Faster→Smarter effort slider (Low / Medium / High / Extra / Max, where `max` applies via the `--effort` argv rather than `settings.json`); the popover description lives in `.docs/admin-webchat-native-channel.md`. Absent a pick (and on every resume), the daemon-pinned defaults govern: the `/chat` composer *footer* carries no live re-seat pickers — `rc-daemon.ts` pins settings.json `model`/`effortLevel`/`permissions.defaultMode` to `claude-opus-4-8[1m]` / `medium` / `bypassPermissions` regardless of `account.json` (read by the rc-spawn webchat path), and `pty-spawner.ts` forces the claude.ai/code PTY `--permission-mode` to `bypassPermissions` for `role=admin`. Public sessions are fixed to `claude-sonnet-5` (the `/public-spawn` chokepoint + `buildPublicWebchatSpawnRequest`), keeping `dontAsk`. The composer footer instead renders a **read-only** params row (mode · model · effort labels) plus a context-window usage figure (`pct% · ~used/~window`), all sourced from the session pointer; the full path is in `.docs/admin-webchat-native-channel.md`. The composer cannot re-seat a session, so the "no transcript" 400 on a brand-new chat is unreachable; the `/api/admin/session-reseat` + `/api/webchat/settings` routes and the dashboard re-seat form stay as off-composer surfaces. When the live session runs in `default` ("Ask permissions") mode, a tool the agent attempts that needs approval surfaces an Allow/Deny card in the composer (tool, description, argument preview); a click sends the verdict over Claude Code's channel permission relay and the tool runs or is refused — webchat is the only interactive ask surface (WhatsApp stays text-only; Telegram has no agent channel). Beyond the composer, the maxy admin UI keeps a single "New session" link (`https://claude.ai/code`, opens in a new tab) and no separate session list, viewer, controls, or model/mode picker. The daemon supervisor lives at [`platform/services/claude-session-manager/src/rc-daemon.ts`](../../../services/claude-session-manager/src/rc-daemon.ts). The `/session-defaults` route and `SpawnPreference` node were deleted with the picker. `/new-session-failure`, `/new-session-submit`, and `/claude-capabilities` are now orphaned (consumed only by the deleted NewSessionModal) — see [`.tasks/501`](../../../.tasks/) for their removal.
|
|
65
65
|
|
|
66
66
|
**Row title resolution.** Both the sidebar (`/sidebar-sessions`) and the manager's own row payload resolve a row's title in the same order: operator rename → Claude Code `ai-title` → first non-CLI user message → 8-char sessionId prefix. The operator-rename tier is the on-disk `<accountDir>/session-titles.json` (the manager's `UserTitleStore`), keyed by the CC sessionId — the sidebar reads that same file, so a write to the store lights up both surfaces with one write.
|
|
67
67
|
|
|
@@ -56,14 +56,30 @@ while true; do
|
|
|
56
56
|
# interface, not CLI prose); skip the line on any host where systemctl is
|
|
57
57
|
# absent, the slice is unknown, or MemoryHigh is unset/infinity.
|
|
58
58
|
if command -v systemctl >/dev/null 2>&1; then
|
|
59
|
-
slice_props=$(systemctl --user show claude-ptys.slice -p MemoryCurrent -p MemoryHigh 2>/dev/null || true)
|
|
59
|
+
slice_props=$(systemctl --user show claude-ptys.slice -p MemoryCurrent -p MemoryHigh -p ControlGroup 2>/dev/null || true)
|
|
60
60
|
slice_current=$(printf '%s\n' "$slice_props" | sed -n 's/^MemoryCurrent=//p')
|
|
61
61
|
slice_high=$(printf '%s\n' "$slice_props" | sed -n 's/^MemoryHigh=//p')
|
|
62
|
+
slice_cgroup=$(printf '%s\n' "$slice_props" | sed -n 's/^ControlGroup=//p')
|
|
62
63
|
if [[ "$slice_current" =~ ^[0-9]+$ && "$slice_high" =~ ^[0-9]+$ && "$slice_high" -gt 0 ]]; then
|
|
63
64
|
slice_current_mb=$(( slice_current / 1048576 ))
|
|
64
65
|
slice_high_mb=$(( slice_high / 1048576 ))
|
|
65
66
|
slice_ratio=$(( slice_current * 100 / slice_high ))
|
|
66
|
-
|
|
67
|
+
# Task 1297 — memory.events `high` is the cgroup's own count of times
|
|
68
|
+
# this slice crossed MemoryHigh (a throttle event). The concern this
|
|
69
|
+
# answers: a MemoryHigh throttle could itself slow the brand server
|
|
70
|
+
# enough to miss its systemd watchdog heartbeat — this makes that
|
|
71
|
+
# correlation checkable from logs instead of guessed.
|
|
72
|
+
high_events=0
|
|
73
|
+
if [[ -n "$slice_cgroup" && -r "/sys/fs/cgroup${slice_cgroup}/memory.events" ]]; then
|
|
74
|
+
high_events=$(sed -n 's/^high //p' "/sys/fs/cgroup${slice_cgroup}/memory.events" 2>/dev/null || echo 0)
|
|
75
|
+
[[ "$high_events" =~ ^[0-9]+$ ]] || high_events=0
|
|
76
|
+
fi
|
|
77
|
+
echo "[rss] op=slice-pressure slice=claude-ptys current=${slice_current_mb} high=${slice_high_mb} ratio=${slice_ratio} highEvents=${high_events}" >> "$LOG_PATH"
|
|
78
|
+
# Task 1297 — the exact standing-sampler line the task names: real
|
|
79
|
+
# cgroup-accounted cohort total (not the claude.exe-only pgrep sum used
|
|
80
|
+
# by the plain per-cycle line above) against the real ceiling, so
|
|
81
|
+
# sizing can be tuned from evidence instead of guessed.
|
|
82
|
+
echo "[realagent-mem-census] rss_total=${slice_current} ceiling=${slice_high} sessions_live=${claude_count}" >> "$LOG_PATH"
|
|
67
83
|
fi
|
|
68
84
|
fi
|
|
69
85
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAe3B,OAAO,EAkBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAe3B,OAAO,EAkBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AA4BzB,OAAO,KAAK,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAA;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAgFlE,eAAO,MAAM,kBAAkB,QAA2B,CAAA;AAS1D,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAIlD,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC7E;;qEAEiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;IAC9B;kFAC8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,cAAc,EAAE,cAAc,CAAA;IAC9B;;;6BAGyB;IACzB,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC;;;sCAGkC;IAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C;;gFAE4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAsFD;;;;;;mEAMmE;AACnE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAiC9D;AAMD;;;;;;iBAMiB;AACjB,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAmCvF;AAID;;;;;;yBAMyB;AACzB,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAiCzD;AAkCD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpG;AAgBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAUD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAMvE;AAMD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,MAAM,CAER;AAkCD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe5F;AAwJD;;;kEAGkE;AAClE,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG;IAC3B,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACpD;;;+CAG2C;IAC3C,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAChD,CAAA;AA8CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAgoFpD"}
|
|
@@ -44,7 +44,7 @@ import { createRcChildLog } from './rc-child-log.js';
|
|
|
44
44
|
// --append-system-prompt for channel-bound admin sessions.
|
|
45
45
|
import { extractVoiceSection } from './system-prompt.js';
|
|
46
46
|
import { readJsonlSession } from './jsonl-enumerator.js';
|
|
47
|
-
import { claudeStateRoot, projectSlugForCwd, jsonlPathForSessionId, sidecarPathForSessionId, permissionModeLogPathForSessionId, findExistingJsonlForSessionId, detectRemoteControlSlug, classifyBindBlocker, } from './jsonl-path.js';
|
|
47
|
+
import { claudeStateRoot, projectSlugForCwd, jsonlPathForSessionId, sidecarPathForSessionId, permissionModeLogPathForSessionId, findExistingJsonlForSessionId, slugForExistingJsonl, jsonlPathForSlug, sidecarPathForSlug, detectRemoteControlSlug, classifyBindBlocker, } from './jsonl-path.js';
|
|
48
48
|
import { basename, dirname, join } from 'node:path';
|
|
49
49
|
import { validateUserTitle } from './user-title-store.js';
|
|
50
50
|
import { credentialsPathForConfigDir, snapshotAuthForFailureReason } from './auth-snapshot.js';
|
|
@@ -933,7 +933,7 @@ export function buildHttpApp(deps) {
|
|
|
933
933
|
const specialist = typeof body.specialist === 'string' && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist)
|
|
934
934
|
? body.specialist
|
|
935
935
|
: undefined;
|
|
936
|
-
// Task 956 — public sessions are pinned to Sonnet
|
|
936
|
+
// Task 956 — public sessions are pinned to Sonnet 5 (operator decision:
|
|
937
937
|
// admin-only Bypass/Opus; public stays Sonnet + fail-closed dontAsk). The
|
|
938
938
|
// role==='public' force is the chokepoint covering every public spawn
|
|
939
939
|
// (webchat + WhatsApp); other roles keep their body-supplied model.
|
|
@@ -1669,17 +1669,24 @@ export function buildHttpApp(deps) {
|
|
|
1669
1669
|
}
|
|
1670
1670
|
// Task 260 — purge from BOTH locations: a row may have its JSONL
|
|
1671
1671
|
// at the top level (live or just-ended) or under archive/ (archived).
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1672
|
+
// Task 1298 — resolve the slug that actually holds the JSONL first;
|
|
1673
|
+
// the list (sidebar-sessions.ts) walks every slug, so delete must too.
|
|
1674
|
+
// Fall back to spawnCwd's slug only when nothing is found anywhere —
|
|
1675
|
+
// hasTop/hasArchived will both be false regardless, so the fallback
|
|
1676
|
+
// only affects which (nonexistent) paths appear in the 404 case.
|
|
1677
|
+
const resolvedSlug = slugForExistingJsonl(deps.claudeConfigDir, sessionId) ?? projectSlugForCwd(deps.spawnCwd);
|
|
1678
|
+
const topJsonl = jsonlPathForSlug(deps.claudeConfigDir, resolvedSlug, sessionId);
|
|
1679
|
+
const archivedJsonl = jsonlPathForSlug(deps.claudeConfigDir, resolvedSlug, sessionId, { archived: true });
|
|
1680
|
+
const topSidecar = sidecarPathForSlug(deps.claudeConfigDir, resolvedSlug, sessionId);
|
|
1681
|
+
const archivedSidecar = sidecarPathForSlug(deps.claudeConfigDir, resolvedSlug, sessionId, { archived: true });
|
|
1676
1682
|
const hasTop = existsSync(topJsonl);
|
|
1677
1683
|
const hasArchived = existsSync(archivedJsonl);
|
|
1678
1684
|
if (!row || (!hasTop && !hasArchived)) {
|
|
1685
|
+
deps.logger(`delete-not-found sessionId=${sessionId.slice(0, 8)} reason=not-found-anywhere`);
|
|
1679
1686
|
timed(deps.logger, 'DELETE', `/${id}`, 404, Date.now() - start);
|
|
1680
1687
|
return c.json({ error: 'session-not-found' }, 404);
|
|
1681
1688
|
}
|
|
1682
|
-
const subdir = join(claudeStateRoot(), 'projects',
|
|
1689
|
+
const subdir = join(claudeStateRoot(), 'projects', resolvedSlug, sessionId);
|
|
1683
1690
|
let bytes = 0;
|
|
1684
1691
|
try {
|
|
1685
1692
|
bytes = hasTop ? statSync(topJsonl).size : hasArchived ? statSync(archivedJsonl).size : 0;
|