amalgm 0.0.0 → 0.0.1

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 (107) hide show
  1. package/README.md +37 -1
  2. package/bin/amalgm.js +8 -2
  3. package/lib/auth-store.js +223 -0
  4. package/lib/cli.js +1000 -0
  5. package/lib/paths.js +30 -0
  6. package/lib/supervisor.js +467 -0
  7. package/lib/tunnel-chat.js +328 -0
  8. package/lib/tunnel-events.js +499 -0
  9. package/package.json +29 -3
  10. package/runtime/README.md +4 -0
  11. package/runtime/lib/chatInput.js +306 -0
  12. package/runtime/lib/harnesses.js +988 -0
  13. package/runtime/lib/local/amalgmStore.js +128 -0
  14. package/runtime/lib/local/credentialResolver.js +425 -0
  15. package/runtime/lib/mcpApps/registry.js +619 -0
  16. package/runtime/package.json +5 -0
  17. package/runtime/scripts/amalgm-mcp/agents/rest.js +165 -0
  18. package/runtime/scripts/amalgm-mcp/agents/store.js +153 -0
  19. package/runtime/scripts/amalgm-mcp/agents/talk.js +1156 -0
  20. package/runtime/scripts/amalgm-mcp/agents/tools.js +210 -0
  21. package/runtime/scripts/amalgm-mcp/artifacts/advertise.js +132 -0
  22. package/runtime/scripts/amalgm-mcp/artifacts/rest.js +103 -0
  23. package/runtime/scripts/amalgm-mcp/artifacts/store.js +141 -0
  24. package/runtime/scripts/amalgm-mcp/artifacts/supervisor.js +402 -0
  25. package/runtime/scripts/amalgm-mcp/artifacts/tools.js +176 -0
  26. package/runtime/scripts/amalgm-mcp/browser/page.js +637 -0
  27. package/runtime/scripts/amalgm-mcp/browser/tools.js +688 -0
  28. package/runtime/scripts/amalgm-mcp/config.js +138 -0
  29. package/runtime/scripts/amalgm-mcp/credentials/rest.js +45 -0
  30. package/runtime/scripts/amalgm-mcp/deps.js +40 -0
  31. package/runtime/scripts/amalgm-mcp/email/inbound.js +215 -0
  32. package/runtime/scripts/amalgm-mcp/events/executor.js +179 -0
  33. package/runtime/scripts/amalgm-mcp/events/ingress.js +113 -0
  34. package/runtime/scripts/amalgm-mcp/events/matcher.js +125 -0
  35. package/runtime/scripts/amalgm-mcp/events/rest.js +200 -0
  36. package/runtime/scripts/amalgm-mcp/events/ring-buffer.js +19 -0
  37. package/runtime/scripts/amalgm-mcp/events/store.js +98 -0
  38. package/runtime/scripts/amalgm-mcp/events/tools.js +306 -0
  39. package/runtime/scripts/amalgm-mcp/events/webhook-url.js +28 -0
  40. package/runtime/scripts/amalgm-mcp/fs/rest.js +293 -0
  41. package/runtime/scripts/amalgm-mcp/index.js +100 -0
  42. package/runtime/scripts/amalgm-mcp/lib/chat-runner.js +167 -0
  43. package/runtime/scripts/amalgm-mcp/lib/email-md.js +288 -0
  44. package/runtime/scripts/amalgm-mcp/lib/mcp-resolver.js +63 -0
  45. package/runtime/scripts/amalgm-mcp/lib/prefs.js +393 -0
  46. package/runtime/scripts/amalgm-mcp/lib/storage.js +92 -0
  47. package/runtime/scripts/amalgm-mcp/lib/supabase.js +118 -0
  48. package/runtime/scripts/amalgm-mcp/lib/tool-result.js +177 -0
  49. package/runtime/scripts/amalgm-mcp/local/rest.js +80 -0
  50. package/runtime/scripts/amalgm-mcp/mcp-connections/rest.js +151 -0
  51. package/runtime/scripts/amalgm-mcp/notify/index.js +107 -0
  52. package/runtime/scripts/amalgm-mcp/server/http.js +335 -0
  53. package/runtime/scripts/amalgm-mcp/server/mcp.js +116 -0
  54. package/runtime/scripts/amalgm-mcp/slack/inbound.js +200 -0
  55. package/runtime/scripts/amalgm-mcp/tasks/executor.js +225 -0
  56. package/runtime/scripts/amalgm-mcp/tasks/rest.js +110 -0
  57. package/runtime/scripts/amalgm-mcp/tasks/schedule-normalization.js +85 -0
  58. package/runtime/scripts/amalgm-mcp/tasks/scheduler.js +105 -0
  59. package/runtime/scripts/amalgm-mcp/tasks/store.js +139 -0
  60. package/runtime/scripts/amalgm-mcp/tasks/tools.js +391 -0
  61. package/runtime/scripts/amalgm-mcp/user-api-keys/rest.js +105 -0
  62. package/runtime/scripts/amalgm-mcp/workspace/rest.js +389 -0
  63. package/runtime/scripts/chat-core/adapters/claude.js +163 -0
  64. package/runtime/scripts/chat-core/adapters/codex.js +313 -0
  65. package/runtime/scripts/chat-core/adapters/opencode.js +412 -0
  66. package/runtime/scripts/chat-core/auth.js +177 -0
  67. package/runtime/scripts/chat-core/contract.js +326 -0
  68. package/runtime/scripts/chat-core/credentials/store.js +212 -0
  69. package/runtime/scripts/chat-core/egress.js +87 -0
  70. package/runtime/scripts/chat-core/engine.js +195 -0
  71. package/runtime/scripts/chat-core/event-schema.js +231 -0
  72. package/runtime/scripts/chat-core/events.js +190 -0
  73. package/runtime/scripts/chat-core/index.js +11 -0
  74. package/runtime/scripts/chat-core/input.js +50 -0
  75. package/runtime/scripts/chat-core/normalizers/claude.js +450 -0
  76. package/runtime/scripts/chat-core/normalizers/codex.js +380 -0
  77. package/runtime/scripts/chat-core/normalizers/normalizer_spec.md +259 -0
  78. package/runtime/scripts/chat-core/normalizers/opencode.js +552 -0
  79. package/runtime/scripts/chat-core/normalizers/tool_contract.md +123 -0
  80. package/runtime/scripts/chat-core/normalizers/usage_contract.md +304 -0
  81. package/runtime/scripts/chat-core/parts.js +253 -0
  82. package/runtime/scripts/chat-core/recorder.js +65 -0
  83. package/runtime/scripts/chat-core/runtime.js +86 -0
  84. package/runtime/scripts/chat-core/server.js +163 -0
  85. package/runtime/scripts/chat-core/sse.js +196 -0
  86. package/runtime/scripts/chat-core/stores.js +100 -0
  87. package/runtime/scripts/chat-core/tool-display.js +149 -0
  88. package/runtime/scripts/chat-core/tool-shape.js +143 -0
  89. package/runtime/scripts/chat-core/tooling/mcp-bundle.js +161 -0
  90. package/runtime/scripts/chat-core/tooling/mcp-relay.js +97 -0
  91. package/runtime/scripts/chat-core/tooling/native-binaries.js +608 -0
  92. package/runtime/scripts/chat-core/tooling/system-prompt.js +20 -0
  93. package/runtime/scripts/chat-core/usage.js +343 -0
  94. package/runtime/scripts/chat-server/config.js +110 -0
  95. package/runtime/scripts/chat-server/db.js +529 -0
  96. package/runtime/scripts/chat-server/index.js +33 -0
  97. package/runtime/scripts/chat-server/model-catalog.js +327 -0
  98. package/runtime/scripts/chat-server.js +75 -0
  99. package/runtime/scripts/credential-adapter.js +129 -0
  100. package/runtime/scripts/fs-watcher.js +888 -0
  101. package/runtime/scripts/local-gateway.js +852 -0
  102. package/runtime/scripts/platform-context.txt +246 -0
  103. package/runtime/scripts/port-monitor.js +175 -0
  104. package/runtime/scripts/proxy-token-store.js +162 -0
  105. package/runtime/scripts/runtime-auth.js +163 -0
  106. package/runtime/scripts/test-claude-code-models.js +87 -0
  107. package/runtime/tsconfig.json +15 -0
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+
5
+ const RUNTIME_TOKEN_HEADER = 'x-amalgm-runtime-token';
6
+
7
+ function getRuntimeToken() {
8
+ return String(process.env.AMALGM_RUNTIME_TOKEN || '').trim();
9
+ }
10
+
11
+ function runtimeAuthRequired() {
12
+ if (process.env.AMALGM_RUNTIME_AUTH === 'disabled') return false;
13
+ return Boolean(
14
+ getRuntimeToken()
15
+ || process.env.AMALGM_RUNTIME_SOURCE === 'npm'
16
+ || process.env.AMALGM_LOCAL_MODE === 'true',
17
+ );
18
+ }
19
+
20
+ function safeEqual(a, b) {
21
+ const left = Buffer.from(String(a || ''));
22
+ const right = Buffer.from(String(b || ''));
23
+ return left.length === right.length && crypto.timingSafeEqual(left, right);
24
+ }
25
+
26
+ function headerValue(req, name) {
27
+ const raw = req?.headers?.[name.toLowerCase()];
28
+ if (Array.isArray(raw)) return raw[0] || '';
29
+ return typeof raw === 'string' ? raw : '';
30
+ }
31
+
32
+ function tokenFromProtocol(req) {
33
+ const raw = headerValue(req, 'sec-websocket-protocol');
34
+ for (const part of raw.split(',').map((value) => value.trim()).filter(Boolean)) {
35
+ if (part.startsWith('amalgm-runtime-token.')) {
36
+ return part.slice('amalgm-runtime-token.'.length);
37
+ }
38
+ }
39
+ return '';
40
+ }
41
+
42
+ function tokenFromRequest(req) {
43
+ const headerToken = headerValue(req, RUNTIME_TOKEN_HEADER);
44
+ if (headerToken) return headerToken;
45
+
46
+ const auth = headerValue(req, 'authorization');
47
+ const match = auth.match(/^Bearer\s+(.+)$/i);
48
+ if (match) return match[1].trim();
49
+
50
+ const protocolToken = tokenFromProtocol(req);
51
+ if (protocolToken) return protocolToken;
52
+
53
+ return '';
54
+ }
55
+
56
+ function isAuthorizedRuntimeRequest(req) {
57
+ if (!runtimeAuthRequired()) return true;
58
+ const expected = getRuntimeToken();
59
+ if (!expected) return false;
60
+ return safeEqual(tokenFromRequest(req), expected);
61
+ }
62
+
63
+ function isLoopbackOrigin(origin) {
64
+ if (!origin) return true;
65
+ try {
66
+ const url = new URL(origin);
67
+ return (
68
+ (url.protocol === 'http:' || url.protocol === 'https:')
69
+ && ['localhost', '127.0.0.1', '[::1]', '::1'].includes(url.hostname)
70
+ );
71
+ } catch {
72
+ return false;
73
+ }
74
+ }
75
+
76
+ function applyRuntimeCors(req, res, options = {}) {
77
+ const origin = headerValue(req, 'origin');
78
+ if (origin && isLoopbackOrigin(origin)) {
79
+ res.setHeader('Access-Control-Allow-Origin', origin);
80
+ res.setHeader('Vary', 'Origin');
81
+ }
82
+
83
+ res.setHeader('Access-Control-Allow-Methods', options.methods || 'GET, POST, DELETE, OPTIONS');
84
+ res.setHeader(
85
+ 'Access-Control-Allow-Headers',
86
+ options.headers || [
87
+ 'Content-Type',
88
+ 'Authorization',
89
+ 'Accept',
90
+ 'Cache-Control',
91
+ 'Last-Event-ID',
92
+ 'Mcp-Session-Id',
93
+ 'X-Amalgm-Session-Id',
94
+ 'X-Daytona-Preview-Token',
95
+ RUNTIME_TOKEN_HEADER,
96
+ ].join(', '),
97
+ );
98
+ if (options.exposeHeaders) {
99
+ res.setHeader('Access-Control-Expose-Headers', options.exposeHeaders);
100
+ }
101
+ }
102
+
103
+ function pathnameFor(req) {
104
+ try {
105
+ return new URL(req.url || '/', 'http://127.0.0.1').pathname;
106
+ } catch {
107
+ return '/';
108
+ }
109
+ }
110
+
111
+ function isHealthPath(req) {
112
+ const pathname = pathnameFor(req);
113
+ return pathname === '/healthz' || pathname === '/';
114
+ }
115
+
116
+ function rejectUnauthorized(res) {
117
+ res.writeHead(401, {
118
+ 'Content-Type': 'application/json',
119
+ 'Cache-Control': 'no-store',
120
+ });
121
+ res.end(JSON.stringify({ error: 'Missing or invalid Amalgm runtime token' }));
122
+ }
123
+
124
+ function authorizeRuntimeHttp(req, res, options = {}) {
125
+ applyRuntimeCors(req, res, options);
126
+
127
+ if (req.method === 'OPTIONS') {
128
+ if (isLoopbackOrigin(headerValue(req, 'origin'))) {
129
+ res.writeHead(204);
130
+ } else {
131
+ res.writeHead(403);
132
+ }
133
+ res.end();
134
+ return false;
135
+ }
136
+
137
+ const pathname = pathnameFor(req);
138
+ const exemptPrefixes = options.exemptPrefixes || [];
139
+ const exempt = isHealthPath(req) || exemptPrefixes.some((prefix) => pathname.startsWith(prefix));
140
+ if (exempt || isAuthorizedRuntimeRequest(req)) return true;
141
+
142
+ rejectUnauthorized(res);
143
+ return false;
144
+ }
145
+
146
+ function runtimeAuthHeaders(headers = {}) {
147
+ const token = getRuntimeToken();
148
+ if (!token) return headers;
149
+ return {
150
+ ...headers,
151
+ [RUNTIME_TOKEN_HEADER]: token,
152
+ };
153
+ }
154
+
155
+ module.exports = {
156
+ RUNTIME_TOKEN_HEADER,
157
+ applyRuntimeCors,
158
+ authorizeRuntimeHttp,
159
+ getRuntimeToken,
160
+ isAuthorizedRuntimeRequest,
161
+ runtimeAuthHeaders,
162
+ runtimeAuthRequired,
163
+ };
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ const assert = require('node:assert/strict');
4
+
5
+ const {
6
+ canonicalModel,
7
+ cliModelFor,
8
+ createContract,
9
+ } = require('./chat-core/contract');
10
+ const {
11
+ getHarnessModels,
12
+ resolveHarnessModel,
13
+ } = require('../lib/harnesses');
14
+ const {
15
+ resolveModelSelection,
16
+ } = require('./amalgm-mcp/lib/prefs');
17
+
18
+ const OPUS_1M = 'anthropic/claude-opus-4.7-1m';
19
+
20
+ assert.deepEqual(
21
+ getHarnessModels('claude_code').map((model) => ({
22
+ id: model.id,
23
+ name: model.name,
24
+ cliModel: model.cliModel,
25
+ })),
26
+ [
27
+ { id: 'anthropic/claude-haiku-4.5', name: 'Haiku 4.5', cliModel: 'haiku' },
28
+ { id: 'anthropic/claude-sonnet-4.6', name: 'Sonnet 4.6', cliModel: 'sonnet' },
29
+ { id: 'anthropic/claude-opus-4.7', name: 'Opus 4.7', cliModel: 'opus' },
30
+ { id: OPUS_1M, name: 'Opus 4.7 1M', cliModel: 'opus[1m]' },
31
+ ],
32
+ );
33
+
34
+ assert.equal(canonicalModel('haiku', 'claude_code'), 'anthropic/claude-haiku-4.5');
35
+ assert.equal(canonicalModel('sonnet', 'claude_code'), 'anthropic/claude-sonnet-4.6');
36
+ assert.equal(canonicalModel('opus', 'claude_code'), 'anthropic/claude-opus-4.7');
37
+ assert.equal(canonicalModel('opus1m', 'claude_code'), OPUS_1M);
38
+ assert.equal(canonicalModel('opus[1m]', 'claude_code'), OPUS_1M);
39
+ assert.equal(canonicalModel('claude-code-opus-46', 'claude_code'), 'anthropic/claude-opus-4.7');
40
+ assert.equal(canonicalModel('claude-code-opus-4.6', 'claude_code'), 'anthropic/claude-opus-4.7');
41
+ assert.equal(canonicalModel('claude-opus-4-6', 'claude_code'), 'anthropic/claude-opus-4.7');
42
+ assert.equal(canonicalModel('anthropic/claude-opus-4-6', 'claude_code'), 'anthropic/claude-opus-4.7');
43
+ assert.equal(canonicalModel('anthropic/claude-opus-4.5', 'claude_code'), 'anthropic/claude-opus-4.7');
44
+ assert.equal(canonicalModel('claude-code-sonnet-45', 'claude_code'), 'anthropic/claude-sonnet-4.6');
45
+ assert.equal(canonicalModel('claude-code-sonnet-4.5', 'claude_code'), 'anthropic/claude-sonnet-4.6');
46
+ assert.equal(canonicalModel('claude-sonnet-4-5', 'claude_code'), 'anthropic/claude-sonnet-4.6');
47
+ assert.equal(canonicalModel('anthropic/claude-sonnet-4-5', 'claude_code'), 'anthropic/claude-sonnet-4.6');
48
+ assert.equal(canonicalModel('claude-code-haiku-4.5', 'claude_code'), 'anthropic/claude-haiku-4.5');
49
+
50
+ assert.equal(cliModelFor({ harness: 'claude_code', modelId: 'anthropic/claude-haiku-4.5' }), 'haiku');
51
+ assert.equal(cliModelFor({ harness: 'claude_code', modelId: 'anthropic/claude-sonnet-4.6' }), 'sonnet');
52
+ assert.equal(cliModelFor({ harness: 'claude_code', modelId: 'anthropic/claude-opus-4.7' }), 'opus');
53
+ assert.equal(cliModelFor({ harness: 'claude_code', modelId: OPUS_1M }), 'opus[1m]');
54
+ assert.equal(cliModelFor({ harness: 'claude_code', modelId: 'anthropic/claude-opus-4.7', cliModel: 'opus1m' }), 'opus[1m]');
55
+
56
+ for (const [modelId, cliModel] of [
57
+ ['anthropic/claude-haiku-4.5', 'haiku'],
58
+ ['anthropic/claude-sonnet-4.6', 'sonnet'],
59
+ ['anthropic/claude-opus-4.7', 'opus'],
60
+ [OPUS_1M, 'opus[1m]'],
61
+ ]) {
62
+ const contract = createContract({
63
+ codeSessionId: `session-${cliModel}`,
64
+ assistantMessageId: `assistant-${cliModel}`,
65
+ userId: 'user',
66
+ agentId: 'claude',
67
+ authMethod: 'provider_auth',
68
+ modelId,
69
+ cwd: process.cwd(),
70
+ });
71
+ assert.equal(contract.harness, 'claude_code');
72
+ assert.equal(contract.modelId, modelId);
73
+ assert.equal(contract.cliModel, cliModel);
74
+ }
75
+
76
+ assert.deepEqual(resolveHarnessModel('claude_code', 'opus1m'), {
77
+ modelId: OPUS_1M,
78
+ cliModel: 'opus[1m]',
79
+ reasoningEffort: undefined,
80
+ });
81
+ assert.deepEqual(resolveModelSelection('claude_code', 'opus1m'), {
82
+ modelId: OPUS_1M,
83
+ cliModel: 'opus[1m]',
84
+ reasoningEffort: null,
85
+ });
86
+
87
+ console.log('Claude Code engine model mapping OK');
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "Node",
6
+ "esModuleInterop": true,
7
+ "skipLibCheck": true,
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": [
11
+ "./*"
12
+ ]
13
+ }
14
+ }
15
+ }