@rubytech/create-maxy-code 0.1.460 → 0.1.461
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__/cron-heartbeat-registration.test.js +57 -28
- package/dist/__tests__/launchd-plist.test.js +26 -0
- package/dist/cron-registration.js +30 -8
- package/dist/index.js +50 -9
- package/dist/launchd-plist.js +1 -1
- package/dist/uninstall.js +9 -3
- package/package.json +1 -1
- package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +96 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/auth-route.test.ts +54 -40
- package/payload/platform/plugins/cloudflare/mcp/__tests__/passcode.test.ts +169 -39
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +207 -0
- package/payload/platform/plugins/cloudflare/mcp/package.json +1 -1
- package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +21 -19
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.mjs +193 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/auth.ts +18 -12
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/schema.sql +14 -5
- package/payload/platform/plugins/voice-mirror/PLUGIN.md +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +98 -9
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js +54 -21
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +110 -0
- package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +6 -3
- package/payload/platform/scripts/__tests__/logs-rotate.test.sh +256 -0
- package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +79 -0
- package/payload/platform/scripts/logs-rotate.sh +204 -0
- package/payload/platform/scripts/resume-tunnel.sh +27 -0
- 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 +41 -5
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.d.ts +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +22 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts +2 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.js +12 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +122 -9
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-census.js +214 -29
- package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
- 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 +2 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- 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 +13 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js +4 -2
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +150 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +333 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.js +55 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.js.map +1 -0
- package/payload/server/server.js +55 -35
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.ts +0 -73
package/payload/server/server.js
CHANGED
|
@@ -6780,7 +6780,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6780
6780
|
spawnedAt: /* @__PURE__ */ new Date()
|
|
6781
6781
|
});
|
|
6782
6782
|
const replyP = deps.awaitReply(session_key, webchatTurnTimeoutMs());
|
|
6783
|
-
await deps.handleInbound({
|
|
6783
|
+
const { spawn: spawn4 } = await deps.handleInbound({
|
|
6784
6784
|
role: "public",
|
|
6785
6785
|
accountId: account.accountId,
|
|
6786
6786
|
key: session_key,
|
|
@@ -6793,6 +6793,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6793
6793
|
name: publicTitle
|
|
6794
6794
|
}
|
|
6795
6795
|
});
|
|
6796
|
+
if (spawn4) await spawn4;
|
|
6796
6797
|
const reply = await replyP;
|
|
6797
6798
|
if ("timeout" in reply) {
|
|
6798
6799
|
controller.enqueue(
|
|
@@ -11881,7 +11882,7 @@ ${note}` : note;
|
|
|
11881
11882
|
console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=empty-text`);
|
|
11882
11883
|
return c.json({ error: "text required" }, 400);
|
|
11883
11884
|
}
|
|
11884
|
-
console.log(`[webchat:inbound] op=send-
|
|
11885
|
+
console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
11885
11886
|
}
|
|
11886
11887
|
let deliveredIntId = null;
|
|
11887
11888
|
if (deliverySessionId !== void 0 && await managerActivity(deliverySessionId) === "busy") {
|
|
@@ -11893,11 +11894,8 @@ ${note}` : note;
|
|
|
11893
11894
|
deliveredIntId = outcome.intId;
|
|
11894
11895
|
}
|
|
11895
11896
|
const adminUserId = requesterUserId ?? void 0;
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
} else {
|
|
11899
|
-
await deps.handleInbound({ role: "admin", accountId: bootstrapAccountId, key: deliveryKey, text, adminUserId });
|
|
11900
|
-
}
|
|
11897
|
+
const inboundStartedAt = Date.now();
|
|
11898
|
+
const inbound = deliverySessionId !== void 0 ? await deps.handleInbound({ role: "admin", accountId: deliveryAccountId, key: deliveryKey, text, sessionId: deliverySessionId, adminUserId }) : await deps.handleInbound({ role: "admin", accountId: bootstrapAccountId, key: deliveryKey, text, adminUserId });
|
|
11901
11899
|
if (deliveredIntId !== null) {
|
|
11902
11900
|
console.log(`[webchat-interrupt] op=delivered intId=${deliveredIntId} sessionId=${deliverySessionId.slice(0, 8)}`);
|
|
11903
11901
|
}
|
|
@@ -11914,7 +11912,9 @@ ${note}` : note;
|
|
|
11914
11912
|
}
|
|
11915
11913
|
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
11916
11914
|
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
11917
|
-
console.error(
|
|
11915
|
+
console.error(
|
|
11916
|
+
`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"} acceptMs=${Date.now() - inboundStartedAt} spawn=${inbound.spawn !== null ? "triggered" : "none"}`
|
|
11917
|
+
);
|
|
11918
11918
|
const turnTimer = setTimeout(() => {
|
|
11919
11919
|
const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
11920
11920
|
const grew = now !== null && (baseline === null || now > baseline);
|
|
@@ -24727,7 +24727,9 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24727
24727
|
this.recovering = false;
|
|
24728
24728
|
}
|
|
24729
24729
|
}
|
|
24730
|
-
/** Handle one inbound webchat message (browser POST → here).
|
|
24730
|
+
/** Handle one inbound webchat message (browser POST → here). Resolves when
|
|
24731
|
+
* the hub holds the message; the cold-start spawn is returned as a handle
|
|
24732
|
+
* (Task 1715 — see WebchatInboundResult). */
|
|
24731
24733
|
async handleInbound(input) {
|
|
24732
24734
|
const bytes = Buffer.byteLength(input.text, "utf8");
|
|
24733
24735
|
const hadSubscriber = this.hub.hasSubscriber(input.key);
|
|
@@ -24761,38 +24763,56 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24761
24763
|
}
|
|
24762
24764
|
const existing = this.publicSessions.get(input.key);
|
|
24763
24765
|
if (existing) existing.lastActivityAt = Date.now();
|
|
24766
|
+
let spawn4 = null;
|
|
24764
24767
|
if (!hadSubscriber && !this.spawning.has(input.key)) {
|
|
24765
24768
|
this.spawning.add(input.key);
|
|
24766
24769
|
console.error(`[webchat:inbound] op=spawn-trigger key=${input.key} role=${input.role}`);
|
|
24767
|
-
|
|
24768
|
-
|
|
24770
|
+
spawn4 = this.runSpawn(input);
|
|
24771
|
+
spawn4.catch(() => {
|
|
24772
|
+
});
|
|
24773
|
+
}
|
|
24774
|
+
return { spawn: spawn4 };
|
|
24775
|
+
}
|
|
24776
|
+
/** Task 1715 — the cold-start spawn, run off the accept's path. Rejects on a
|
|
24777
|
+
* failed spawn so the public caller's SSE still errors; logs op=spawn-failed
|
|
24778
|
+
* first, because on the admin path the 200 has already been returned and this
|
|
24779
|
+
* line is the only attribution the failure gets. */
|
|
24780
|
+
async runSpawn(input) {
|
|
24781
|
+
const startedAt = Date.now();
|
|
24782
|
+
try {
|
|
24783
|
+
const spawned = await this.deps.ensureChannelSession({
|
|
24784
|
+
accountId: input.accountId,
|
|
24785
|
+
key: input.key,
|
|
24786
|
+
role: input.role,
|
|
24787
|
+
gatewayUrl: this.deps.gatewayUrl,
|
|
24788
|
+
serverPath: this.deps.serverPath,
|
|
24789
|
+
// Task 800 — only present on a session-targeted launch, so the
|
|
24790
|
+
// default-path call shape stays byte-identical.
|
|
24791
|
+
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
|
|
24792
|
+
// The authenticated admin's userId on an admin bootstrap inbound; the
|
|
24793
|
+
// default-path call shape stays byte-identical when absent.
|
|
24794
|
+
...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {},
|
|
24795
|
+
// Task 756 — public spawn params on a role:'public' inbound.
|
|
24796
|
+
...input.public !== void 0 ? { public: input.public } : {}
|
|
24797
|
+
});
|
|
24798
|
+
if (input.role === "public" && input.public && spawned && "sessionId" in spawned) {
|
|
24799
|
+
this.publicSessions.set(input.key, {
|
|
24800
|
+
sessionId: spawned.sessionId,
|
|
24769
24801
|
accountId: input.accountId,
|
|
24770
|
-
|
|
24771
|
-
|
|
24772
|
-
|
|
24773
|
-
|
|
24774
|
-
// Task 800 — only present on a session-targeted launch, so the
|
|
24775
|
-
// default-path call shape stays byte-identical.
|
|
24776
|
-
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
|
|
24777
|
-
// The authenticated admin's userId on an admin bootstrap inbound; the
|
|
24778
|
-
// default-path call shape stays byte-identical when absent.
|
|
24779
|
-
...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {},
|
|
24780
|
-
// Task 756 — public spawn params on a role:'public' inbound.
|
|
24781
|
-
...input.public !== void 0 ? { public: input.public } : {}
|
|
24802
|
+
agentSlug: input.public.agentSlug,
|
|
24803
|
+
sliceToken: input.public.sliceToken,
|
|
24804
|
+
personId: input.public.personId,
|
|
24805
|
+
lastActivityAt: Date.now()
|
|
24782
24806
|
});
|
|
24783
|
-
if (input.role === "public" && input.public && spawned && "sessionId" in spawned) {
|
|
24784
|
-
this.publicSessions.set(input.key, {
|
|
24785
|
-
sessionId: spawned.sessionId,
|
|
24786
|
-
accountId: input.accountId,
|
|
24787
|
-
agentSlug: input.public.agentSlug,
|
|
24788
|
-
sliceToken: input.public.sliceToken,
|
|
24789
|
-
personId: input.public.personId,
|
|
24790
|
-
lastActivityAt: Date.now()
|
|
24791
|
-
});
|
|
24792
|
-
}
|
|
24793
|
-
} finally {
|
|
24794
|
-
this.spawning.delete(input.key);
|
|
24795
24807
|
}
|
|
24808
|
+
} catch (err) {
|
|
24809
|
+
const reason = (err instanceof Error ? err.message : String(err)).replace(/\s+/g, " ");
|
|
24810
|
+
console.error(
|
|
24811
|
+
`[webchat:inbound] op=spawn-failed key=${keyDisplay(input.key)} role=${input.role} ms=${Date.now() - startedAt} reason=${reason}`
|
|
24812
|
+
);
|
|
24813
|
+
throw err;
|
|
24814
|
+
} finally {
|
|
24815
|
+
this.spawning.delete(input.key);
|
|
24796
24816
|
}
|
|
24797
24817
|
}
|
|
24798
24818
|
};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// Passcode hashing for the data portal. PBKDF2-SHA256 via Web Crypto, which
|
|
2
|
-
// exists identically in the Workers runtime and in Node's webcrypto, so these
|
|
3
|
-
// functions are tested against real crypto rather than a fake.
|
|
4
|
-
//
|
|
5
|
-
// constantTimeEqual is hand-rolled deliberately: crypto.subtle.timingSafeEqual
|
|
6
|
-
// is a Cloudflare extension with no Node equivalent, so depending on it would
|
|
7
|
-
// make the comparison untestable here.
|
|
8
|
-
|
|
9
|
-
export const PBKDF2_ITERATIONS = 600_000
|
|
10
|
-
|
|
11
|
-
export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
12
|
-
// Length is not secret; an early return on it leaks nothing a caller cannot
|
|
13
|
-
// already see. The byte loop below never short-circuits.
|
|
14
|
-
if (a.length !== b.length) return false
|
|
15
|
-
let diff = 0
|
|
16
|
-
for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]
|
|
17
|
-
return diff === 0
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function randomSaltHex(bytes: Uint8Array): string {
|
|
21
|
-
return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Returns Uint8Array<ArrayBuffer>, not the bare Uint8Array: the bare form
|
|
25
|
-
// widens to ArrayBufferLike, which Web Crypto will not accept as a BufferSource
|
|
26
|
-
// because a SharedArrayBuffer could back it.
|
|
27
|
-
function hexToBytes(hex: string): Uint8Array<ArrayBuffer> | null {
|
|
28
|
-
if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(hex)) return null
|
|
29
|
-
const out = new Uint8Array(hex.length / 2)
|
|
30
|
-
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)
|
|
31
|
-
return out
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function hashPasscode(
|
|
35
|
-
passcode: string,
|
|
36
|
-
saltHex: string,
|
|
37
|
-
iterations: number,
|
|
38
|
-
): Promise<string> {
|
|
39
|
-
const salt = hexToBytes(saltHex)
|
|
40
|
-
if (!salt) throw new Error('salt must be hex')
|
|
41
|
-
const key = await crypto.subtle.importKey(
|
|
42
|
-
'raw',
|
|
43
|
-
new TextEncoder().encode(passcode),
|
|
44
|
-
'PBKDF2',
|
|
45
|
-
false,
|
|
46
|
-
['deriveBits'],
|
|
47
|
-
)
|
|
48
|
-
const bits = await crypto.subtle.deriveBits(
|
|
49
|
-
{ name: 'PBKDF2', salt, iterations, hash: 'SHA-256' },
|
|
50
|
-
key,
|
|
51
|
-
256,
|
|
52
|
-
)
|
|
53
|
-
return randomSaltHex(new Uint8Array(bits))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export async function verifyPasscode(
|
|
57
|
-
passcode: string,
|
|
58
|
-
saltHex: string,
|
|
59
|
-
expectedHashHex: string,
|
|
60
|
-
iterations: number,
|
|
61
|
-
): Promise<boolean> {
|
|
62
|
-
const expected = hexToBytes(expectedHashHex)
|
|
63
|
-
if (!expected) return false
|
|
64
|
-
let actualHex: string
|
|
65
|
-
try {
|
|
66
|
-
actualHex = await hashPasscode(passcode, saltHex, iterations)
|
|
67
|
-
} catch {
|
|
68
|
-
return false
|
|
69
|
-
}
|
|
70
|
-
const actual = hexToBytes(actualHex)
|
|
71
|
-
if (!actual) return false
|
|
72
|
-
return constantTimeEqual(actual, expected)
|
|
73
|
-
}
|