amalgm 0.1.145 → 0.1.146

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/lib/service.js CHANGED
@@ -248,7 +248,7 @@ function runningInContainer() {
248
248
  if (fs.existsSync('/.dockerenv') || fs.existsSync('/run/.containerenv')) return true;
249
249
  try {
250
250
  const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
251
- return /docker|kubepods|containerd|libpod|lxc|daytona|e2b/i.test(cgroup);
251
+ return /docker|kubepods|containerd|libpod|lxc|e2b/i.test(cgroup);
252
252
  } catch {
253
253
  return false;
254
254
  }
package/lib/supervisor.js CHANGED
@@ -86,6 +86,11 @@ const CHILD_HEALTH_POLICY = {
86
86
  maxFailures: 3,
87
87
  };
88
88
 
89
+ const CHAT_SERVER_HEALTH_POLICY = {
90
+ timeoutMs: 15000,
91
+ maxFailures: 6,
92
+ };
93
+
89
94
  const AUTO_UPDATE_POLICY = {
90
95
  checkIntervalMs: 15 * 60_000,
91
96
  initialDelayMs: 60_000,
@@ -289,19 +294,30 @@ function baseRuntimeEnv(record, ports, options = {}) {
289
294
 
290
295
  function serviceSpecs(record, ports, options = {}) {
291
296
  const env = baseRuntimeEnv(record, ports, options);
292
- return runtimeLaunchServices().map((service) => ({
293
- name: service.name,
294
- command: process.execPath,
295
- args: [runtimeEntry(service.script), RUNTIME_INSTANCE_ARG],
296
- env: service.name === 'port-monitor' ? { ...env, PORT: process.env.PORT || '0' } : env,
297
- port: ports[service.portKey],
298
- healthPath: '/healthz',
299
- expectedRuntimeInstanceId: AMALGM_RUNTIME_INSTANCE_ID,
300
- expectedService: service.name,
301
- healthHeaders: env.AMALGM_RUNTIME_TOKEN
302
- ? { 'x-amalgm-runtime-token': env.AMALGM_RUNTIME_TOKEN }
303
- : {},
304
- }));
297
+ return runtimeLaunchServices().map((service) => {
298
+ const healthPolicy = healthPolicyForService(service.name);
299
+ return {
300
+ name: service.name,
301
+ command: process.execPath,
302
+ args: [runtimeEntry(service.script), RUNTIME_INSTANCE_ARG],
303
+ env: service.name === 'port-monitor' ? { ...env, PORT: process.env.PORT || '0' } : env,
304
+ port: ports[service.portKey],
305
+ healthPath: '/healthz',
306
+ expectedRuntimeInstanceId: AMALGM_RUNTIME_INSTANCE_ID,
307
+ expectedService: service.name,
308
+ healthPolicy,
309
+ healthHeaders: env.AMALGM_RUNTIME_TOKEN
310
+ ? { 'x-amalgm-runtime-token': env.AMALGM_RUNTIME_TOKEN }
311
+ : {},
312
+ };
313
+ });
314
+ }
315
+
316
+ function healthPolicyForService(serviceName) {
317
+ return {
318
+ ...CHILD_HEALTH_POLICY,
319
+ ...(serviceName === 'chat-server' ? CHAT_SERVER_HEALTH_POLICY : {}),
320
+ };
305
321
  }
306
322
 
307
323
  function isPortFree(port, host = '127.0.0.1') {
@@ -983,6 +999,7 @@ function checkServiceHealth(spec, timeoutMs = CHILD_HEALTH_POLICY.timeoutMs) {
983
999
 
984
1000
  function createManagedProcess(spec, options) {
985
1001
  const { stream } = openServiceLog(spec.name);
1002
+ const healthPolicy = { ...CHILD_HEALTH_POLICY, ...(spec.healthPolicy || {}) };
986
1003
  let child = null;
987
1004
  let stopped = false;
988
1005
  let restartTimer = null;
@@ -1026,12 +1043,12 @@ function createManagedProcess(spec, options) {
1026
1043
  };
1027
1044
 
1028
1045
  const scheduleHealthCheck = () => {
1029
- const delayMs = state === 'running' ? CHILD_HEALTH_POLICY.intervalMs : 500;
1046
+ const delayMs = state === 'running' ? healthPolicy.intervalMs : 500;
1030
1047
  clearHealthTimer();
1031
1048
  if (stopped) return;
1032
1049
  healthTimer = setTimeout(async () => {
1033
1050
  if (stopped || !child) return;
1034
- const ok = await checkServiceHealth(spec);
1051
+ const ok = await checkServiceHealth(spec, healthPolicy.timeoutMs);
1035
1052
  if (stopped || !child) return;
1036
1053
  if (ok) {
1037
1054
  healthFailures = 0;
@@ -1040,7 +1057,7 @@ function createManagedProcess(spec, options) {
1040
1057
  settleReady();
1041
1058
  }
1042
1059
  } else {
1043
- if (Date.now() - startedAt < CHILD_HEALTH_POLICY.graceMs) {
1060
+ if (Date.now() - startedAt < healthPolicy.graceMs) {
1044
1061
  scheduleHealthCheck();
1045
1062
  return;
1046
1063
  }
@@ -1048,10 +1065,10 @@ function createManagedProcess(spec, options) {
1048
1065
  writePrefixed(
1049
1066
  stream,
1050
1067
  spec.name,
1051
- `health check failed (${healthFailures}/${CHILD_HEALTH_POLICY.maxFailures})\n`,
1068
+ `health check failed (${healthFailures}/${healthPolicy.maxFailures})\n`,
1052
1069
  options.foreground ? process.stderr : null,
1053
1070
  );
1054
- if (healthFailures >= CHILD_HEALTH_POLICY.maxFailures) {
1071
+ if (healthFailures >= healthPolicy.maxFailures) {
1055
1072
  setState('restarting', { reason: 'health_check_failed' });
1056
1073
  try {
1057
1074
  child.kill('SIGTERM');
@@ -1105,7 +1122,7 @@ function createManagedProcess(spec, options) {
1105
1122
  if (readyTimer) clearTimeout(readyTimer);
1106
1123
  readyTimer = setTimeout(() => {
1107
1124
  settleReady(new Error(`${spec.name} did not become healthy on port ${spec.port}`));
1108
- }, CHILD_HEALTH_POLICY.graceMs + (CHILD_HEALTH_POLICY.intervalMs * CHILD_HEALTH_POLICY.maxFailures));
1125
+ }, healthPolicy.graceMs + ((healthPolicy.intervalMs + healthPolicy.timeoutMs) * healthPolicy.maxFailures));
1109
1126
  }
1110
1127
  child = spawn(spec.command, spec.args, {
1111
1128
  cwd: RUNTIME_DIR,
@@ -1333,6 +1350,7 @@ async function startSupervisor(options = {}) {
1333
1350
  module.exports = {
1334
1351
  startSupervisor,
1335
1352
  _test: {
1353
+ healthPolicyForService,
1336
1354
  liveDeclaredRuntimePorts,
1337
1355
  runtimeStateFilesUnder,
1338
1356
  runtimeStateSearchRoots,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalgm",
3
- "version": "0.1.145",
3
+ "version": "0.1.146",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -719,12 +719,9 @@ function envForBuild(
719
719
  ...baseEnv,
720
720
  DESKTOP_RELEASE_LANE: request.lane,
721
721
  DESKTOP_RELEASE_CHANNEL: request.lane === 'preview' ? 'preview' : 'latest',
722
- AMALGM_DESKTOP_THIN: desktopThinRuntimeBuildEnabled(baseEnv) ? '1' : '0',
723
- AMALGM_DESKTOP_RENDERER_DELIVERY: desktopRendererDelivery(baseEnv),
724
- AMALGM_DESKTOP_RUNTIME_DELIVERY: desktopRuntimeDelivery(baseEnv),
725
- ...(desktopRendererDelivery(baseEnv) === 'bundled-next' ? {
726
- NEXT_IMAGE_UNOPTIMIZED: '1',
727
- } : {}),
722
+ AMALGM_DESKTOP_RENDERER_DELIVERY: 'bundled-next',
723
+ AMALGM_DESKTOP_RUNTIME_DELIVERY: 'npm',
724
+ NEXT_IMAGE_UNOPTIMIZED: '1',
728
725
  AMALGM_RUNTIME_LABEL: request.lane === 'preview' ? 'preview' : 'main',
729
726
  AMALGM_BRANCH: request.lane,
730
727
  ELECTRON_VERSION: version,
@@ -770,33 +767,6 @@ function envForBuild(
770
767
  return env;
771
768
  }
772
769
 
773
- function desktopThinRuntimeBuildEnabled(env = process.env) {
774
- const raw = cleanString(env.AMALGM_DESKTOP_THIN || env.DESKTOP_THIN_BUILD).toLowerCase();
775
- if (!raw) return true;
776
- if (['1', 'true', 'yes', 'on'].includes(raw)) return true;
777
- if (['0', 'false', 'no', 'off'].includes(raw)) return false;
778
- throw new Error(`Unsupported AMALGM_DESKTOP_THIN value: ${raw}`);
779
- }
780
-
781
- function desktopRendererDelivery(env = process.env) {
782
- const raw = cleanString(
783
- env.AMALGM_DESKTOP_RENDERER_DELIVERY
784
- || env.AMALGM_DESKTOP_UI_DELIVERY
785
- || (cleanString(env.AMALGM_DESKTOP_UI_MODE).toLowerCase() === 'local' ? 'bundled-next' : ''),
786
- ).toLowerCase();
787
- if (!raw) return desktopThinRuntimeBuildEnabled(env) ? 'hosted' : 'bundled-next';
788
- if (['hosted', 'remote', 'web'].includes(raw)) return 'hosted';
789
- if (['bundled-next', 'bundled', 'local', 'next', 'local-next'].includes(raw)) return 'bundled-next';
790
- throw new Error(`Unsupported AMALGM_DESKTOP_RENDERER_DELIVERY value: ${raw}`);
791
- }
792
-
793
- function desktopRuntimeDelivery(env = process.env) {
794
- const raw = cleanString(env.AMALGM_DESKTOP_RUNTIME_DELIVERY).toLowerCase();
795
- if (!raw) return desktopThinRuntimeBuildEnabled(env) ? 'npm' : 'bundled-with-npm-handoff';
796
- if (['npm', 'managed-npm'].includes(raw)) return 'npm';
797
- if (['bundled-with-npm-handoff', 'bundled', 'local', 'embedded'].includes(raw)) return 'bundled-with-npm-handoff';
798
- throw new Error(`Unsupported AMALGM_DESKTOP_RUNTIME_DELIVERY value: ${raw}`);
799
- }
800
770
 
801
771
  function appOriginForLane(lane, env = process.env) {
802
772
  if (lane === 'preview') {
@@ -1802,29 +1772,15 @@ function publishDesktopRelease(request, options = {}) {
1802
1772
  run('git', ['push', 'origin', `refs/tags/v${version}`, '--force'], { cwd: engineDir });
1803
1773
  run('npm', ['version', '--no-git-tag-version', '--allow-same-version', version], { cwd: engineDir, env: releaseEnv });
1804
1774
  run('npm', ['run', 'compile'], { cwd: engineDir, env: releaseEnv });
1805
- const rendererDelivery = desktopRendererDelivery(releaseEnv);
1806
- const runtimeDelivery = desktopRuntimeDelivery(releaseEnv);
1807
- const hostedRenderer = rendererDelivery === 'hosted';
1808
- const npmRuntime = runtimeDelivery === 'npm';
1809
- let appOrigin = appOriginForLane(request.lane, releaseEnv);
1810
- if (hostedRenderer) {
1811
- console.log('Building hosted-UI desktop shell; skipping bundled Next.js renderer payload.');
1812
- } else {
1813
- copyUiIntoEngine(uiDir, engineDir);
1814
- appOrigin = writeBundledWebEnv(engineDir, request.lane, releaseEnv);
1815
- run('npm', ['run', 'build:next'], {
1816
- cwd: engineDir,
1817
- env: {
1818
- ...releaseEnv,
1819
- NEXT_IMAGE_UNOPTIMIZED: '1',
1820
- },
1821
- });
1822
- }
1823
- if (npmRuntime) {
1824
- console.log('Building desktop shell with managed npm runtime; skipping bundled engine runtime payload.');
1825
- } else {
1826
- run('npm', ['run', 'npm:sync'], { cwd: engineDir, env: releaseEnv });
1827
- }
1775
+ copyUiIntoEngine(uiDir, engineDir);
1776
+ const appOrigin = writeBundledWebEnv(engineDir, request.lane, releaseEnv);
1777
+ run('npm', ['run', 'build:next'], {
1778
+ cwd: engineDir,
1779
+ env: {
1780
+ ...releaseEnv,
1781
+ NEXT_IMAGE_UNOPTIMIZED: '1',
1782
+ },
1783
+ });
1828
1784
  if (request.lane === 'preview') run('npm', ['run', 'assets:preview-icon'], { cwd: engineDir, env: releaseEnv });
1829
1785
 
1830
1786
  const buildEnv = envForBuild(releaseEnv, request, sourcePackageVersion, version, refs, shas, appOrigin, releaseRepository, publishTarget);
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  // GENERATED tokens/chrome — serialized from lib/rendering/tokens.ts and
19
- // chromeTokens.ts by scripts/amalgm-mcp/generate-email-render-assets.mts.
19
+ // chromeTokens.ts by scripts/email-render/generate-email-render-assets.mts.
20
20
  // No hand-mirrored values here: change the canonical file and regenerate.
21
21
  const RENDER_ASSETS = require('./generated/email-render.json');
22
22
  const TOKENS = RENDER_ASSETS.tokens;
@@ -21,7 +21,7 @@ const embeds = require('./email-embeds');
21
21
  const { buildEmailRenderContext, normalizeEmailLink } = require('./email-deeplinks');
22
22
 
23
23
  // GENERATED from lib/rendering/tokens.ts by
24
- // scripts/amalgm-mcp/generate-email-render-assets.mts — the deterministic
24
+ // scripts/email-render/generate-email-render-assets.mts — the deterministic
25
25
  // adapter. There is no hand-mirrored token copy anymore; change tokens.ts
26
26
  // (or Citation.tsx for the templates below) and regenerate.
27
27
  const RENDER_ASSETS = require('./generated/email-render.json');
@@ -1,5 +1,5 @@
1
1
  {
2
- "//": "GENERATED by scripts/amalgm-mcp/generate-email-render-assets.mts — do not edit.",
2
+ "//": "GENERATED by scripts/email-render/generate-email-render-assets.mts — do not edit.",
3
3
  "version": 1,
4
4
  "tokens": {
5
5
  "font": {
@@ -246,40 +246,13 @@ test('desktop release runner uses electron-builder compatible signing identity n
246
246
  assert.equal(env.AMALGM_DESKTOP_RELEASE_UPLOAD_URL, 'https://amalgm-desktop-releases.fly.dev/');
247
247
  assert.equal(env.AMALGM_DESKTOP_RELEASE_FLY_APP, 'amalgm-desktop-releases');
248
248
  assert.equal(env.AMALGM_DESKTOP_RELEASE_FLY_ROOT, '/data');
249
- assert.equal(env.AMALGM_DESKTOP_THIN, '1');
250
249
  assert.equal(env.AMALGM_DESKTOP_NOTARIZE, 'off');
251
250
  });
252
251
 
253
- test('desktop release runner preserves explicit bundled desktop builds', () => {
252
+ test('desktop release runner always builds bundled UI with npm runtime', () => {
254
253
  const env = envForBuild(
255
254
  {
256
255
  GH_TOKEN: 'token',
257
- AMALGM_DESKTOP_THIN: '0',
258
- NEXT_PUBLIC_SUPABASE_URL: 'https://example.supabase.co',
259
- NEXT_PUBLIC_SUPABASE_ANON_KEY: 'anon-key',
260
- },
261
- { lane: 'main', delivery: 'delivery-id' },
262
- '0.1.124',
263
- '0.1.124000001',
264
- { engineRef: 'engine', uiRef: 'ui' },
265
- { engineSha: 'engine-sha', uiSha: 'ui-sha' },
266
- 'https://amalgm.ai',
267
- );
268
-
269
- assert.equal(env.AMALGM_DESKTOP_THIN, '0');
270
- assert.equal(env.AMALGM_DESKTOP_RENDERER_DELIVERY, 'bundled-next');
271
- assert.equal(env.AMALGM_DESKTOP_RUNTIME_DELIVERY, 'bundled-with-npm-handoff');
272
- assert.equal(env.NEXT_IMAGE_UNOPTIMIZED, '1');
273
- assert.equal(env.NEXT_PUBLIC_SUPABASE_URL, 'https://example.supabase.co');
274
- assert.equal(env.NEXT_PUBLIC_SUPABASE_ANON_KEY, 'anon-key');
275
- });
276
-
277
- test('desktop release runner supports bundled UI with npm runtime', () => {
278
- const env = envForBuild(
279
- {
280
- GH_TOKEN: 'token',
281
- AMALGM_DESKTOP_RENDERER_DELIVERY: 'bundled-next',
282
- AMALGM_DESKTOP_RUNTIME_DELIVERY: 'npm',
283
256
  NEXT_PUBLIC_SUPABASE_URL: 'https://example.supabase.co',
284
257
  NEXT_PUBLIC_SUPABASE_ANON_KEY: 'anon-key',
285
258
  },
@@ -8,7 +8,7 @@
8
8
  * email-render-goldens/. The full notification shell is covered once.
9
9
  *
10
10
  * When output changes on purpose (tokens, chrome, templates, renderer):
11
- * UPDATE_GOLDENS=1 node --test scripts/amalgm-mcp/tests/email-render.test.js
11
+ * UPDATE_GOLDENS=1 node --test scripts/email-render/tests/email-render.test.js
12
12
  * then review the golden diff like any code change.
13
13
  */
14
14
 
@@ -91,7 +91,6 @@ function applyRuntimeCors(req, res, options = {}) {
91
91
  'Last-Event-ID',
92
92
  'Mcp-Session-Id',
93
93
  'X-Amalgm-Session-Id',
94
- 'X-Daytona-Preview-Token',
95
94
  RUNTIME_TOKEN_HEADER,
96
95
  ].join(', '),
97
96
  );