@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.
Files changed (63) hide show
  1. package/dist/__tests__/cron-heartbeat-registration.test.js +57 -28
  2. package/dist/__tests__/launchd-plist.test.js +26 -0
  3. package/dist/cron-registration.js +30 -8
  4. package/dist/index.js +50 -9
  5. package/dist/launchd-plist.js +1 -1
  6. package/dist/uninstall.js +9 -3
  7. package/package.json +1 -1
  8. package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +96 -0
  9. package/payload/platform/plugins/cloudflare/mcp/__tests__/auth-route.test.ts +54 -40
  10. package/payload/platform/plugins/cloudflare/mcp/__tests__/passcode.test.ts +169 -39
  11. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +207 -0
  12. package/payload/platform/plugins/cloudflare/mcp/package.json +1 -1
  13. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +21 -19
  14. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.mjs +193 -0
  15. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/auth.ts +18 -12
  16. package/payload/platform/plugins/cloudflare/skills/data-portal/template/schema.sql +14 -5
  17. package/payload/platform/plugins/voice-mirror/PLUGIN.md +1 -1
  18. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
  19. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +98 -9
  20. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
  21. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
  22. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js +54 -21
  23. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
  24. package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +110 -0
  25. package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +6 -3
  26. package/payload/platform/scripts/__tests__/logs-rotate.test.sh +256 -0
  27. package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +79 -0
  28. package/payload/platform/scripts/logs-rotate.sh +204 -0
  29. package/payload/platform/scripts/resume-tunnel.sh +27 -0
  30. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  31. package/payload/platform/services/claude-session-manager/dist/http-server.js +41 -5
  32. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/index.d.ts +1 -0
  34. package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/index.js +22 -0
  36. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts +2 -0
  38. package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts.map +1 -0
  39. package/payload/platform/services/claude-session-manager/dist/install-start-counter.js +12 -0
  40. package/payload/platform/services/claude-session-manager/dist/install-start-counter.js.map +1 -0
  41. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +122 -9
  42. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
  43. package/payload/platform/services/claude-session-manager/dist/pty-census.js +214 -29
  44. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
  45. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  46. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +2 -1
  47. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  48. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  49. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +13 -1
  50. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  51. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.d.ts.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js +4 -2
  53. package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js.map +1 -1
  54. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +150 -0
  55. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -0
  56. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +333 -0
  57. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -0
  58. package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts +10 -0
  59. package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts.map +1 -0
  60. package/payload/platform/services/claude-session-manager/dist/start-counter.js +55 -0
  61. package/payload/platform/services/claude-session-manager/dist/start-counter.js.map +1 -0
  62. package/payload/server/server.js +55 -35
  63. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.ts +0 -73
@@ -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-accepted kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
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
- if (deliverySessionId !== void 0) {
11897
- await deps.handleInbound({ role: "admin", accountId: deliveryAccountId, key: deliveryKey, text, sessionId: deliverySessionId, adminUserId });
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(`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
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
- try {
24768
- const spawned = await this.deps.ensureChannelSession({
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
- key: input.key,
24771
- role: input.role,
24772
- gatewayUrl: this.deps.gatewayUrl,
24773
- serverPath: this.deps.serverPath,
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
- }