amalgm 0.1.124 → 0.1.125

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalgm",
3
- "version": "0.1.124",
3
+ "version": "0.1.125",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -0,0 +1,482 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+
5
+ const DESKTOP_RELEASE_AUTOMATION_ID = 'internal-amalgm-desktop-release';
6
+ const DESKTOP_RELEASE_TRIGGER_ID = 'internal-amalgm-desktop-release-github-push';
7
+ const DESKTOP_RELEASE_WORKFLOW_ID = 'internal-amalgm-desktop-release-workflow';
8
+ const NPM_RELEASE_WORKFLOW_ID = 'internal-amalgm-npm-release-workflow';
9
+
10
+ function desktopReleaseRunnerPath() {
11
+ return path.resolve(__dirname, '../events/desktop-release-runner.js');
12
+ }
13
+
14
+ function npmReleaseRunnerPath() {
15
+ return path.resolve(__dirname, '../events/npm-release-runner.js');
16
+ }
17
+
18
+ function shellQuote(value) {
19
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
20
+ }
21
+
22
+ function desktopReleaseWorkflow(runnerPath = desktopReleaseRunnerPath()) {
23
+ const escapedRunnerCommand = JSON.stringify(`node ${shellQuote(runnerPath)}`);
24
+ const escapedRunnerDir = JSON.stringify(path.dirname(runnerPath));
25
+ return `export default workflow({
26
+ trigger: event("github.push"),
27
+
28
+ allowlist: {
29
+ localCompute: true,
30
+ secrets: [
31
+ "GH_TOKEN",
32
+ "GITHUB_TOKEN",
33
+ "NEXT_PUBLIC_SUPABASE_URL",
34
+ "NEXT_PUBLIC_SUPABASE_ANON_KEY",
35
+ "NEXT_PUBLIC_SITE_URL",
36
+ "NEXT_PUBLIC_PREVIEW_SITE_URL",
37
+ "AMALGM_DESKTOP_MAIN_APP_ORIGIN",
38
+ "AMALGM_DESKTOP_PREVIEW_APP_ORIGIN",
39
+ "AMALGM_DESKTOP_RELEASE_CHECKOUT_ROOT",
40
+ "AMALGM_DESKTOP_RELEASE_ENV_FILE",
41
+ "AMALGM_DESKTOP_RELEASE_ENGINE_REPO_PATH",
42
+ "AMALGM_DESKTOP_RELEASE_NODE_BIN",
43
+ "AMALGM_DESKTOP_RELEASE_PATH_PREFIX",
44
+ "AMALGM_DESKTOP_RELEASE_PYTHON",
45
+ "AMALGM_DESKTOP_RELEASE_PROVIDER",
46
+ "AMALGM_DESKTOP_RELEASE_REPOSITORY",
47
+ "AMALGM_DESKTOP_RELEASE_REPO_FULL_NAME",
48
+ "AMALGM_DESKTOP_RELEASE_FLY_APP",
49
+ "AMALGM_DESKTOP_RELEASE_FLY_ROOT",
50
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_TOKEN",
51
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_METHOD",
52
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_URL",
53
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_CHUNK_BYTES",
54
+ "AMALGM_DESKTOP_LEGACY_BRIDGE_ENABLED",
55
+ "AMALGM_DESKTOP_LEGACY_BRIDGE_REPOSITORY",
56
+ "AMALGM_DESKTOP_LEGACY_BRIDGE_REPO_FULL_NAME",
57
+ "AMALGM_DESKTOP_LEGACY_BRIDGE_OWNER",
58
+ "AMALGM_DESKTOP_LEGACY_BRIDGE_REPO",
59
+ "AMALGM_DESKTOP_UPDATE_PROVIDER",
60
+ "AMALGM_DESKTOP_UPDATE_BASE_URL",
61
+ "AMALGM_DESKTOP_UPDATE_URL",
62
+ "AMALGM_DESKTOP_UPDATE_OWNER",
63
+ "AMALGM_DESKTOP_UPDATE_REPO",
64
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_ATTEMPTS",
65
+ "AMALGM_DESKTOP_RELEASE_UPLOAD_LIMIT_RATE",
66
+ "AMALGM_DESKTOP_RELEASE_UI_REPO_PATH",
67
+ "AMALGM_ENGINE_REPO_URL",
68
+ "AMALGM_UI_REPO_URL",
69
+ "FLY_ACCESS_TOKEN",
70
+ "CSC_LINK",
71
+ "CSC_KEY_PASSWORD",
72
+ "CSC_NAME",
73
+ "AMALGM_DESKTOP_NOTARIZE",
74
+ "APPLE_API_KEY",
75
+ "APPLE_API_KEY_ID",
76
+ "APPLE_API_ISSUER",
77
+ "APPLE_ID",
78
+ "APPLE_APP_SPECIFIC_PASSWORD",
79
+ "APPLE_TEAM_ID",
80
+ "APPLE_KEYCHAIN",
81
+ "APPLE_KEYCHAIN_PROFILE"
82
+ ],
83
+ actions: ["notifications.notify_user"]
84
+ },
85
+
86
+ limits: {
87
+ maxConcurrentRuns: 1,
88
+ queueLimit: 10,
89
+ cellTimeoutMs: 7200000,
90
+ codeTimeoutMs: 15000
91
+ },
92
+
93
+ cells: [
94
+ code("filter_push", async ({ payload, headers, stop }) => {
95
+ const repository = String(payload?.repository?.full_name || "").trim()
96
+ const ref = String(payload?.ref || "").trim()
97
+ const branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref
98
+ const after = String(payload?.after || "").trim()
99
+ const allowedRepositories = ["amalgm-inc/amalgm-engine", "amalgm-inc/amalgm-ui"]
100
+ const allowedBranches = ["main", "preview"]
101
+ const commits = Array.isArray(payload?.commits) ? payload.commits : []
102
+ const messages = [
103
+ payload?.head_commit?.message,
104
+ ...commits.map((commit) => commit?.message)
105
+ ].map((message) => String(message || ""))
106
+
107
+ if (!allowedRepositories.includes(repository)) stop()
108
+ if (!allowedBranches.includes(branch)) stop()
109
+ if (!/^[a-f0-9]{40}$/i.test(after) || /^0{40}$/.test(after)) stop()
110
+ if (messages.some((message) => /\\[(skip desktop|skip ci|ci skip)\\]/i.test(message))) stop()
111
+
112
+ return {
113
+ repository,
114
+ ref,
115
+ branch,
116
+ after,
117
+ delivery: String(headers?.["x-github-delivery"] || "")
118
+ }
119
+ }),
120
+
121
+ cli("publish_desktop_release", {
122
+ cwd: ${escapedRunnerDir},
123
+ command: ${escapedRunnerCommand},
124
+ env: ({ cells, secrets }) => ({
125
+ GH_TOKEN: secrets.GH_TOKEN || secrets.GITHUB_TOKEN || "",
126
+ GITHUB_TOKEN: secrets.GITHUB_TOKEN || secrets.GH_TOKEN || "",
127
+ NEXT_PUBLIC_SUPABASE_URL: secrets.NEXT_PUBLIC_SUPABASE_URL || "",
128
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY || "",
129
+ NEXT_PUBLIC_SITE_URL: secrets.NEXT_PUBLIC_SITE_URL || "",
130
+ NEXT_PUBLIC_PREVIEW_SITE_URL: secrets.NEXT_PUBLIC_PREVIEW_SITE_URL || "",
131
+ AMALGM_DESKTOP_MAIN_APP_ORIGIN: secrets.AMALGM_DESKTOP_MAIN_APP_ORIGIN || "",
132
+ AMALGM_DESKTOP_PREVIEW_APP_ORIGIN: secrets.AMALGM_DESKTOP_PREVIEW_APP_ORIGIN || "",
133
+ AMALGM_DESKTOP_RELEASE_CHECKOUT_ROOT: secrets.AMALGM_DESKTOP_RELEASE_CHECKOUT_ROOT || "",
134
+ AMALGM_DESKTOP_RELEASE_ENV_FILE: secrets.AMALGM_DESKTOP_RELEASE_ENV_FILE || "",
135
+ AMALGM_DESKTOP_RELEASE_ENGINE_REPO_PATH: secrets.AMALGM_DESKTOP_RELEASE_ENGINE_REPO_PATH || "",
136
+ AMALGM_DESKTOP_RELEASE_NODE_BIN: secrets.AMALGM_DESKTOP_RELEASE_NODE_BIN || "",
137
+ AMALGM_DESKTOP_RELEASE_PATH_PREFIX: secrets.AMALGM_DESKTOP_RELEASE_PATH_PREFIX || "",
138
+ AMALGM_DESKTOP_RELEASE_PYTHON: secrets.AMALGM_DESKTOP_RELEASE_PYTHON || "",
139
+ AMALGM_DESKTOP_RELEASE_PROVIDER: secrets.AMALGM_DESKTOP_RELEASE_PROVIDER || "",
140
+ AMALGM_DESKTOP_RELEASE_REPOSITORY: secrets.AMALGM_DESKTOP_RELEASE_REPOSITORY || secrets.AMALGM_DESKTOP_RELEASE_REPO_FULL_NAME || "",
141
+ AMALGM_DESKTOP_RELEASE_REPO_FULL_NAME: secrets.AMALGM_DESKTOP_RELEASE_REPO_FULL_NAME || secrets.AMALGM_DESKTOP_RELEASE_REPOSITORY || "",
142
+ AMALGM_DESKTOP_RELEASE_FLY_APP: secrets.AMALGM_DESKTOP_RELEASE_FLY_APP || "",
143
+ AMALGM_DESKTOP_RELEASE_FLY_ROOT: secrets.AMALGM_DESKTOP_RELEASE_FLY_ROOT || "",
144
+ AMALGM_DESKTOP_RELEASE_UPLOAD_TOKEN: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_TOKEN || "",
145
+ AMALGM_DESKTOP_RELEASE_UPLOAD_METHOD: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_METHOD || "",
146
+ AMALGM_DESKTOP_RELEASE_UPLOAD_URL: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_URL || "",
147
+ AMALGM_DESKTOP_RELEASE_UPLOAD_CHUNK_BYTES: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_CHUNK_BYTES || "",
148
+ AMALGM_DESKTOP_LEGACY_BRIDGE_ENABLED: secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_ENABLED || "",
149
+ AMALGM_DESKTOP_LEGACY_BRIDGE_REPOSITORY: secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_REPOSITORY || secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_REPO_FULL_NAME || "",
150
+ AMALGM_DESKTOP_LEGACY_BRIDGE_REPO_FULL_NAME: secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_REPO_FULL_NAME || secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_REPOSITORY || "",
151
+ AMALGM_DESKTOP_LEGACY_BRIDGE_OWNER: secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_OWNER || "",
152
+ AMALGM_DESKTOP_LEGACY_BRIDGE_REPO: secrets.AMALGM_DESKTOP_LEGACY_BRIDGE_REPO || "",
153
+ AMALGM_DESKTOP_UPDATE_PROVIDER: secrets.AMALGM_DESKTOP_UPDATE_PROVIDER || secrets.AMALGM_DESKTOP_RELEASE_PROVIDER || "",
154
+ AMALGM_DESKTOP_UPDATE_BASE_URL: secrets.AMALGM_DESKTOP_UPDATE_BASE_URL || "",
155
+ AMALGM_DESKTOP_UPDATE_URL: secrets.AMALGM_DESKTOP_UPDATE_URL || "",
156
+ AMALGM_DESKTOP_UPDATE_OWNER: secrets.AMALGM_DESKTOP_UPDATE_OWNER || "",
157
+ AMALGM_DESKTOP_UPDATE_REPO: secrets.AMALGM_DESKTOP_UPDATE_REPO || "",
158
+ AMALGM_DESKTOP_RELEASE_UPLOAD_ATTEMPTS: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_ATTEMPTS || "",
159
+ AMALGM_DESKTOP_RELEASE_UPLOAD_LIMIT_RATE: secrets.AMALGM_DESKTOP_RELEASE_UPLOAD_LIMIT_RATE || "",
160
+ AMALGM_DESKTOP_RELEASE_UI_REPO_PATH: secrets.AMALGM_DESKTOP_RELEASE_UI_REPO_PATH || "",
161
+ AMALGM_ENGINE_REPO_URL: secrets.AMALGM_ENGINE_REPO_URL || "",
162
+ AMALGM_UI_REPO_URL: secrets.AMALGM_UI_REPO_URL || "",
163
+ FLY_ACCESS_TOKEN: secrets.FLY_ACCESS_TOKEN || "",
164
+ ...(String(secrets.CSC_LINK || "").trim() ? { CSC_LINK: secrets.CSC_LINK } : {}),
165
+ ...(String(secrets.CSC_KEY_PASSWORD || "").trim() ? { CSC_KEY_PASSWORD: secrets.CSC_KEY_PASSWORD } : {}),
166
+ ...(String(secrets.CSC_NAME || "").trim() ? { CSC_NAME: secrets.CSC_NAME } : {}),
167
+ AMALGM_DESKTOP_NOTARIZE: secrets.AMALGM_DESKTOP_NOTARIZE || "",
168
+ APPLE_API_KEY: secrets.APPLE_API_KEY || "",
169
+ APPLE_API_KEY_ID: secrets.APPLE_API_KEY_ID || "",
170
+ APPLE_API_ISSUER: secrets.APPLE_API_ISSUER || "",
171
+ APPLE_ID: secrets.APPLE_ID || "",
172
+ APPLE_APP_SPECIFIC_PASSWORD: secrets.APPLE_APP_SPECIFIC_PASSWORD || "",
173
+ APPLE_TEAM_ID: secrets.APPLE_TEAM_ID || "",
174
+ APPLE_KEYCHAIN: secrets.APPLE_KEYCHAIN || "",
175
+ APPLE_KEYCHAIN_PROFILE: secrets.APPLE_KEYCHAIN_PROFILE || "",
176
+ AMALGM_DESKTOP_RELEASE_SOURCE_REPO: cells.filter_push.output.repository,
177
+ AMALGM_DESKTOP_RELEASE_REF: cells.filter_push.output.ref,
178
+ AMALGM_DESKTOP_RELEASE_BRANCH: cells.filter_push.output.branch,
179
+ AMALGM_DESKTOP_RELEASE_AFTER: cells.filter_push.output.after,
180
+ AMALGM_DESKTOP_RELEASE_DELIVERY: cells.filter_push.output.delivery
181
+ }),
182
+ timeoutMs: 7200000
183
+ }),
184
+
185
+ tool("notify_success", "notifications.notify_user", {
186
+ subject: "amalgm desktop release complete",
187
+ level: "success",
188
+ message: ({ cells }) => {
189
+ const output = cells.publish_desktop_release.output || {}
190
+ const stdout = String(output.stdout || "").trim()
191
+ const jsonStart = stdout.lastIndexOf("\\n{")
192
+ const jsonText = jsonStart >= 0 ? stdout.slice(jsonStart + 1) : stdout
193
+ let result = null
194
+ try { result = JSON.parse(jsonText) } catch {}
195
+ if (!result || result.skipped) {
196
+ return [
197
+ "Desktop release automation finished.",
198
+ "",
199
+ result?.reason || "No release metadata was emitted.",
200
+ "",
201
+ "~~~",
202
+ stdout || "No stdout captured.",
203
+ "~~~"
204
+ ].join("\\n")
205
+ }
206
+ return [
207
+ "Desktop release published.",
208
+ "",
209
+ "Tag: " + result.tag,
210
+ "Lane: " + result.lane,
211
+ "Provider: " + (result.releaseProvider || "unknown"),
212
+ "Engine: " + result.shas.engineSha,
213
+ "UI: " + result.shas.uiSha,
214
+ "",
215
+ result.releaseUrl
216
+ ].join("\\n")
217
+ }
218
+ })
219
+ ]
220
+ })`;
221
+ }
222
+
223
+ function npmReleaseWorkflow(runnerPath = npmReleaseRunnerPath()) {
224
+ const escapedRunnerCommand = JSON.stringify(`node ${shellQuote(runnerPath)}`);
225
+ const escapedRunnerDir = JSON.stringify(path.dirname(runnerPath));
226
+ return `export default workflow({
227
+ trigger: event("github.push"),
228
+
229
+ allowlist: {
230
+ localCompute: true,
231
+ secrets: [
232
+ "GH_TOKEN",
233
+ "GITHUB_TOKEN",
234
+ "NODE_AUTH_TOKEN",
235
+ "NPM_TOKEN",
236
+ "AMALGM_NPM_RELEASE_CHECKOUT_ROOT",
237
+ "AMALGM_NPM_RELEASE_ENV_FILE",
238
+ "AMALGM_NPM_RELEASE_ENGINE_REPO_PATH",
239
+ "AMALGM_NPM_RELEASE_NODE_BIN",
240
+ "AMALGM_NPM_RELEASE_PATH_PREFIX",
241
+ "AMALGM_NPM_RELEASE_PYTHON",
242
+ "AMALGM_NPM_RELEASE_NPM_CACHE",
243
+ "AMALGM_ENGINE_REPO_URL"
244
+ ],
245
+ actions: ["notifications.notify_user"]
246
+ },
247
+
248
+ limits: {
249
+ maxConcurrentRuns: 1,
250
+ queueLimit: 10,
251
+ cellTimeoutMs: 1800000,
252
+ codeTimeoutMs: 15000
253
+ },
254
+
255
+ cells: [
256
+ code("filter_push", async ({ payload, headers, stop }) => {
257
+ const repository = String(payload?.repository?.full_name || "").trim()
258
+ const ref = String(payload?.ref || "").trim()
259
+ const branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref
260
+ const after = String(payload?.after || "").trim()
261
+ const commits = Array.isArray(payload?.commits) ? payload.commits : []
262
+ const messages = [
263
+ payload?.head_commit?.message,
264
+ ...commits.map((commit) => commit?.message)
265
+ ].map((message) => String(message || ""))
266
+
267
+ if (repository !== "amalgm-inc/amalgm-engine") stop()
268
+ if (!["main", "preview"].includes(branch)) stop()
269
+ if (!/^[a-f0-9]{40}$/i.test(after) || /^0{40}$/.test(after)) stop()
270
+ if (messages.some((message) => /\\[(skip npm|skip runtime|skip ci|ci skip)\\]/i.test(message))) stop()
271
+
272
+ return {
273
+ repository,
274
+ ref,
275
+ branch,
276
+ after,
277
+ delivery: String(headers?.["x-github-delivery"] || "")
278
+ }
279
+ }),
280
+
281
+ cli("publish_npm_release", {
282
+ cwd: ${escapedRunnerDir},
283
+ command: ${escapedRunnerCommand},
284
+ env: ({ cells, secrets }) => ({
285
+ GH_TOKEN: secrets.GH_TOKEN || secrets.GITHUB_TOKEN || "",
286
+ GITHUB_TOKEN: secrets.GITHUB_TOKEN || secrets.GH_TOKEN || "",
287
+ NODE_AUTH_TOKEN: secrets.NODE_AUTH_TOKEN || secrets.NPM_TOKEN || "",
288
+ NPM_TOKEN: secrets.NPM_TOKEN || secrets.NODE_AUTH_TOKEN || "",
289
+ AMALGM_NPM_RELEASE_CHECKOUT_ROOT: secrets.AMALGM_NPM_RELEASE_CHECKOUT_ROOT || "",
290
+ AMALGM_NPM_RELEASE_ENV_FILE: secrets.AMALGM_NPM_RELEASE_ENV_FILE || "",
291
+ AMALGM_NPM_RELEASE_ENGINE_REPO_PATH: secrets.AMALGM_NPM_RELEASE_ENGINE_REPO_PATH || "",
292
+ AMALGM_NPM_RELEASE_NODE_BIN: secrets.AMALGM_NPM_RELEASE_NODE_BIN || "",
293
+ AMALGM_NPM_RELEASE_PATH_PREFIX: secrets.AMALGM_NPM_RELEASE_PATH_PREFIX || "",
294
+ AMALGM_NPM_RELEASE_PYTHON: secrets.AMALGM_NPM_RELEASE_PYTHON || "",
295
+ AMALGM_NPM_RELEASE_NPM_CACHE: secrets.AMALGM_NPM_RELEASE_NPM_CACHE || "",
296
+ AMALGM_ENGINE_REPO_URL: secrets.AMALGM_ENGINE_REPO_URL || "",
297
+ AMALGM_NPM_RELEASE_SOURCE_REPO: cells.filter_push.output.repository,
298
+ AMALGM_NPM_RELEASE_REF: cells.filter_push.output.ref,
299
+ AMALGM_NPM_RELEASE_BRANCH: cells.filter_push.output.branch,
300
+ AMALGM_NPM_RELEASE_AFTER: cells.filter_push.output.after,
301
+ AMALGM_NPM_RELEASE_DELIVERY: cells.filter_push.output.delivery
302
+ }),
303
+ timeoutMs: 1800000
304
+ }),
305
+
306
+ tool("notify_success", "notifications.notify_user", {
307
+ subject: "amalgm npm release complete",
308
+ level: "success",
309
+ message: ({ cells }) => {
310
+ const output = cells.publish_npm_release.output || {}
311
+ const stdout = String(output.stdout || "").trim()
312
+ const jsonStart = stdout.lastIndexOf("\\n{")
313
+ const jsonText = jsonStart >= 0 ? stdout.slice(jsonStart + 1) : stdout
314
+ let result = null
315
+ try { result = JSON.parse(jsonText) } catch {}
316
+ if (!result || result.skipped) {
317
+ return [
318
+ "npm release automation finished.",
319
+ "",
320
+ result?.reason || "No release metadata was emitted.",
321
+ "",
322
+ "~~~",
323
+ stdout || "No stdout captured.",
324
+ "~~~"
325
+ ].join("\\n")
326
+ }
327
+ return [
328
+ "npm release published.",
329
+ "",
330
+ "Version: " + result.version,
331
+ "Lane: " + result.lane,
332
+ "Tags: " + (Array.isArray(result.distTags) ? result.distTags.join(", ") : ""),
333
+ "Published: " + String(result.published),
334
+ "Already existed: " + String(result.alreadyExists)
335
+ ].join("\\n")
336
+ }
337
+ })
338
+ ]
339
+ })`;
340
+ }
341
+
342
+ function desktopReleaseAutomationSeed() {
343
+ return {
344
+ id: DESKTOP_RELEASE_AUTOMATION_ID,
345
+ name: 'Run Amalgm release automation',
346
+ description: 'Internal workflow: publish npm runtime packages and signed macOS desktop releases from GitHub push webhooks.',
347
+ enabled: true,
348
+ internal: true,
349
+ triggers: [{
350
+ id: DESKTOP_RELEASE_TRIGGER_ID,
351
+ kind: 'event',
352
+ name: 'GitHub push',
353
+ description: 'GitHub push webhook for amalgm-engine and amalgm-ui release branches.',
354
+ source: 'github',
355
+ event: 'push',
356
+ sourceUrl: 'https://github.com/amalgm-inc',
357
+ enabled: true,
358
+ }],
359
+ workflows: [{
360
+ id: DESKTOP_RELEASE_WORKFLOW_ID,
361
+ name: 'Build signed macOS desktop release',
362
+ description: 'Runs the local desktop release publisher on this Mac.',
363
+ enabled: true,
364
+ internal: true,
365
+ workflowText: desktopReleaseWorkflow(),
366
+ allowlist: {
367
+ localCompute: true,
368
+ secrets: [
369
+ 'GH_TOKEN',
370
+ 'GITHUB_TOKEN',
371
+ 'NEXT_PUBLIC_SUPABASE_URL',
372
+ 'NEXT_PUBLIC_SUPABASE_ANON_KEY',
373
+ 'NEXT_PUBLIC_SITE_URL',
374
+ 'NEXT_PUBLIC_PREVIEW_SITE_URL',
375
+ 'AMALGM_DESKTOP_MAIN_APP_ORIGIN',
376
+ 'AMALGM_DESKTOP_PREVIEW_APP_ORIGIN',
377
+ 'AMALGM_DESKTOP_RELEASE_CHECKOUT_ROOT',
378
+ 'AMALGM_DESKTOP_RELEASE_ENV_FILE',
379
+ 'AMALGM_DESKTOP_RELEASE_ENGINE_REPO_PATH',
380
+ 'AMALGM_DESKTOP_RELEASE_NODE_BIN',
381
+ 'AMALGM_DESKTOP_RELEASE_PATH_PREFIX',
382
+ 'AMALGM_DESKTOP_RELEASE_PYTHON',
383
+ 'AMALGM_DESKTOP_RELEASE_PROVIDER',
384
+ 'AMALGM_DESKTOP_RELEASE_REPOSITORY',
385
+ 'AMALGM_DESKTOP_RELEASE_REPO_FULL_NAME',
386
+ 'AMALGM_DESKTOP_RELEASE_FLY_APP',
387
+ 'AMALGM_DESKTOP_RELEASE_FLY_ROOT',
388
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_TOKEN',
389
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_METHOD',
390
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_URL',
391
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_CHUNK_BYTES',
392
+ 'AMALGM_DESKTOP_LEGACY_BRIDGE_ENABLED',
393
+ 'AMALGM_DESKTOP_LEGACY_BRIDGE_REPOSITORY',
394
+ 'AMALGM_DESKTOP_LEGACY_BRIDGE_REPO_FULL_NAME',
395
+ 'AMALGM_DESKTOP_LEGACY_BRIDGE_OWNER',
396
+ 'AMALGM_DESKTOP_LEGACY_BRIDGE_REPO',
397
+ 'AMALGM_DESKTOP_UPDATE_PROVIDER',
398
+ 'AMALGM_DESKTOP_UPDATE_BASE_URL',
399
+ 'AMALGM_DESKTOP_UPDATE_URL',
400
+ 'AMALGM_DESKTOP_UPDATE_OWNER',
401
+ 'AMALGM_DESKTOP_UPDATE_REPO',
402
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_ATTEMPTS',
403
+ 'AMALGM_DESKTOP_RELEASE_UPLOAD_LIMIT_RATE',
404
+ 'AMALGM_DESKTOP_RELEASE_UI_REPO_PATH',
405
+ 'AMALGM_ENGINE_REPO_URL',
406
+ 'AMALGM_UI_REPO_URL',
407
+ 'FLY_ACCESS_TOKEN',
408
+ 'CSC_LINK',
409
+ 'CSC_KEY_PASSWORD',
410
+ 'CSC_NAME',
411
+ 'AMALGM_DESKTOP_NOTARIZE',
412
+ 'APPLE_API_KEY',
413
+ 'APPLE_API_KEY_ID',
414
+ 'APPLE_API_ISSUER',
415
+ 'APPLE_ID',
416
+ 'APPLE_APP_SPECIFIC_PASSWORD',
417
+ 'APPLE_TEAM_ID',
418
+ 'APPLE_KEYCHAIN',
419
+ 'APPLE_KEYCHAIN_PROFILE',
420
+ ],
421
+ actions: ['notifications.notify_user'],
422
+ },
423
+ limits: {
424
+ maxConcurrentRuns: 1,
425
+ queueLimit: 10,
426
+ cellTimeoutMs: 7200000,
427
+ codeTimeoutMs: 15000,
428
+ },
429
+ }, {
430
+ id: NPM_RELEASE_WORKFLOW_ID,
431
+ name: 'Publish npm runtime release',
432
+ description: 'Publishes amalgm@canary from preview and stable amalgm tags from main.',
433
+ enabled: true,
434
+ internal: true,
435
+ workflowText: npmReleaseWorkflow(),
436
+ allowlist: {
437
+ localCompute: true,
438
+ secrets: [
439
+ 'GH_TOKEN',
440
+ 'GITHUB_TOKEN',
441
+ 'NODE_AUTH_TOKEN',
442
+ 'NPM_TOKEN',
443
+ 'AMALGM_NPM_RELEASE_CHECKOUT_ROOT',
444
+ 'AMALGM_NPM_RELEASE_ENV_FILE',
445
+ 'AMALGM_NPM_RELEASE_ENGINE_REPO_PATH',
446
+ 'AMALGM_NPM_RELEASE_NODE_BIN',
447
+ 'AMALGM_NPM_RELEASE_PATH_PREFIX',
448
+ 'AMALGM_NPM_RELEASE_PYTHON',
449
+ 'AMALGM_NPM_RELEASE_NPM_CACHE',
450
+ 'AMALGM_ENGINE_REPO_URL',
451
+ ],
452
+ actions: ['notifications.notify_user'],
453
+ },
454
+ limits: {
455
+ maxConcurrentRuns: 1,
456
+ queueLimit: 10,
457
+ cellTimeoutMs: 1800000,
458
+ codeTimeoutMs: 15000,
459
+ },
460
+ }],
461
+ };
462
+ }
463
+
464
+ function internalAutomationSeeds() {
465
+ if (['1', 'true', 'yes', 'on'].includes(String(process.env.AMALGM_DISABLE_INTERNAL_DESKTOP_RELEASE_AUTOMATION || '').trim().toLowerCase())) {
466
+ return [];
467
+ }
468
+ return [desktopReleaseAutomationSeed()];
469
+ }
470
+
471
+ module.exports = {
472
+ DESKTOP_RELEASE_AUTOMATION_ID,
473
+ DESKTOP_RELEASE_TRIGGER_ID,
474
+ DESKTOP_RELEASE_WORKFLOW_ID,
475
+ NPM_RELEASE_WORKFLOW_ID,
476
+ desktopReleaseAutomationSeed,
477
+ desktopReleaseRunnerPath,
478
+ desktopReleaseWorkflow,
479
+ internalAutomationSeeds,
480
+ npmReleaseRunnerPath,
481
+ npmReleaseWorkflow,
482
+ };
@@ -11,8 +11,10 @@ const { getWebhookUrl } = require('../events/webhook-url');
11
11
  const { canonicalProjectPath } = require('../../lib/project-paths');
12
12
  const { validateCellReferences } = require('./cell-references');
13
13
  const { validateWorkflowToolActions } = require('./tool-actions');
14
+ const { internalAutomationSeeds } = require('./internal-workflows');
14
15
 
15
16
  const LEGACY_MIGRATION_KEY = 'automations_legacy_migrated_v1';
17
+ const INTERNAL_SEED_HASH_PREFIX = 'automations_internal_seed_hash:';
16
18
  const DEFAULT_RUN_LIMIT = 100;
17
19
  const TERMINAL_RUN_STATUSES = new Set(['completed', 'failed', 'stopped', 'rejected', 'interrupted', 'unmatched']);
18
20
  const DEFAULT_STALE_RUN_MS = Math.max(60_000, Number(process.env.AMALGM_AUTOMATION_RUN_STALE_MS) || 10 * 60_000);
@@ -1516,6 +1518,54 @@ function migrateLegacyAutomations(db) {
1516
1518
  setMetaValue(db, LEGACY_MIGRATION_KEY, nowIso());
1517
1519
  }
1518
1520
 
1521
+ function seedHash(seed) {
1522
+ return crypto.createHash('sha256').update(JSON.stringify(seed)).digest('hex');
1523
+ }
1524
+
1525
+ function seedForUpdate(seed, existing) {
1526
+ const workflowsById = new Map((existing.workflows || []).map((workflow) => [workflow.id, workflow]));
1527
+ const triggersById = new Map((existing.triggers || []).map((trigger) => [trigger.id, trigger]));
1528
+ return {
1529
+ ...seed,
1530
+ enabled: existing.enabled,
1531
+ workflows: (seed.workflows || []).map((workflow) => {
1532
+ const prior = workflowsById.get(workflow.id);
1533
+ return {
1534
+ ...workflow,
1535
+ enabled: prior?.enabled ?? workflow.enabled,
1536
+ };
1537
+ }),
1538
+ triggers: (seed.triggers || []).map((trigger) => {
1539
+ const prior = triggersById.get(trigger.id);
1540
+ return {
1541
+ ...trigger,
1542
+ enabled: prior?.enabled ?? trigger.enabled,
1543
+ webhookUrl: prior?.webhookUrl || trigger.webhookUrl,
1544
+ secret: prior?.secret || trigger.secret,
1545
+ };
1546
+ }),
1547
+ };
1548
+ }
1549
+
1550
+ function seedInternalAutomations(db) {
1551
+ for (const seed of internalAutomationSeeds()) {
1552
+ const hashKey = `${INTERNAL_SEED_HASH_PREFIX}${seed.id}`;
1553
+ const hash = seedHash(seed);
1554
+ const existing = readAutomationGraph(db).automations.find((automation) => automation.id === seed.id) || null;
1555
+
1556
+ if (!existing) {
1557
+ createAutomation(seed, { source: 'automations:internal-seed' });
1558
+ setMetaValue(db, hashKey, hash);
1559
+ continue;
1560
+ }
1561
+
1562
+ if (metaValue(db, hashKey) === hash) continue;
1563
+
1564
+ updateAutomation(seed.id, seedForUpdate(seed, existing), { source: 'automations:internal-seed' });
1565
+ setMetaValue(db, hashKey, hash);
1566
+ }
1567
+ }
1568
+
1519
1569
  let ensuring = false;
1520
1570
  let ensured = false;
1521
1571
 
@@ -1525,6 +1575,7 @@ function ensureAutomationsStore() {
1525
1575
  try {
1526
1576
  const db = openLocalDb();
1527
1577
  migrateLegacyAutomations(db);
1578
+ seedInternalAutomations(db);
1528
1579
  ensured = true;
1529
1580
  } finally {
1530
1581
  ensuring = false;