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.
- package/README.md +37 -1
- package/bin/amalgm.js +8 -2
- package/lib/auth-store.js +223 -0
- package/lib/cli.js +1000 -0
- package/lib/paths.js +30 -0
- package/lib/supervisor.js +467 -0
- package/lib/tunnel-chat.js +328 -0
- package/lib/tunnel-events.js +499 -0
- package/package.json +29 -3
- package/runtime/README.md +4 -0
- package/runtime/lib/chatInput.js +306 -0
- package/runtime/lib/harnesses.js +988 -0
- package/runtime/lib/local/amalgmStore.js +128 -0
- package/runtime/lib/local/credentialResolver.js +425 -0
- package/runtime/lib/mcpApps/registry.js +619 -0
- package/runtime/package.json +5 -0
- package/runtime/scripts/amalgm-mcp/agents/rest.js +165 -0
- package/runtime/scripts/amalgm-mcp/agents/store.js +153 -0
- package/runtime/scripts/amalgm-mcp/agents/talk.js +1156 -0
- package/runtime/scripts/amalgm-mcp/agents/tools.js +210 -0
- package/runtime/scripts/amalgm-mcp/artifacts/advertise.js +132 -0
- package/runtime/scripts/amalgm-mcp/artifacts/rest.js +103 -0
- package/runtime/scripts/amalgm-mcp/artifacts/store.js +141 -0
- package/runtime/scripts/amalgm-mcp/artifacts/supervisor.js +402 -0
- package/runtime/scripts/amalgm-mcp/artifacts/tools.js +176 -0
- package/runtime/scripts/amalgm-mcp/browser/page.js +637 -0
- package/runtime/scripts/amalgm-mcp/browser/tools.js +688 -0
- package/runtime/scripts/amalgm-mcp/config.js +138 -0
- package/runtime/scripts/amalgm-mcp/credentials/rest.js +45 -0
- package/runtime/scripts/amalgm-mcp/deps.js +40 -0
- package/runtime/scripts/amalgm-mcp/email/inbound.js +215 -0
- package/runtime/scripts/amalgm-mcp/events/executor.js +179 -0
- package/runtime/scripts/amalgm-mcp/events/ingress.js +113 -0
- package/runtime/scripts/amalgm-mcp/events/matcher.js +125 -0
- package/runtime/scripts/amalgm-mcp/events/rest.js +200 -0
- package/runtime/scripts/amalgm-mcp/events/ring-buffer.js +19 -0
- package/runtime/scripts/amalgm-mcp/events/store.js +98 -0
- package/runtime/scripts/amalgm-mcp/events/tools.js +306 -0
- package/runtime/scripts/amalgm-mcp/events/webhook-url.js +28 -0
- package/runtime/scripts/amalgm-mcp/fs/rest.js +293 -0
- package/runtime/scripts/amalgm-mcp/index.js +100 -0
- package/runtime/scripts/amalgm-mcp/lib/chat-runner.js +167 -0
- package/runtime/scripts/amalgm-mcp/lib/email-md.js +288 -0
- package/runtime/scripts/amalgm-mcp/lib/mcp-resolver.js +63 -0
- package/runtime/scripts/amalgm-mcp/lib/prefs.js +393 -0
- package/runtime/scripts/amalgm-mcp/lib/storage.js +92 -0
- package/runtime/scripts/amalgm-mcp/lib/supabase.js +118 -0
- package/runtime/scripts/amalgm-mcp/lib/tool-result.js +177 -0
- package/runtime/scripts/amalgm-mcp/local/rest.js +80 -0
- package/runtime/scripts/amalgm-mcp/mcp-connections/rest.js +151 -0
- package/runtime/scripts/amalgm-mcp/notify/index.js +107 -0
- package/runtime/scripts/amalgm-mcp/server/http.js +335 -0
- package/runtime/scripts/amalgm-mcp/server/mcp.js +116 -0
- package/runtime/scripts/amalgm-mcp/slack/inbound.js +200 -0
- package/runtime/scripts/amalgm-mcp/tasks/executor.js +225 -0
- package/runtime/scripts/amalgm-mcp/tasks/rest.js +110 -0
- package/runtime/scripts/amalgm-mcp/tasks/schedule-normalization.js +85 -0
- package/runtime/scripts/amalgm-mcp/tasks/scheduler.js +105 -0
- package/runtime/scripts/amalgm-mcp/tasks/store.js +139 -0
- package/runtime/scripts/amalgm-mcp/tasks/tools.js +391 -0
- package/runtime/scripts/amalgm-mcp/user-api-keys/rest.js +105 -0
- package/runtime/scripts/amalgm-mcp/workspace/rest.js +389 -0
- package/runtime/scripts/chat-core/adapters/claude.js +163 -0
- package/runtime/scripts/chat-core/adapters/codex.js +313 -0
- package/runtime/scripts/chat-core/adapters/opencode.js +412 -0
- package/runtime/scripts/chat-core/auth.js +177 -0
- package/runtime/scripts/chat-core/contract.js +326 -0
- package/runtime/scripts/chat-core/credentials/store.js +212 -0
- package/runtime/scripts/chat-core/egress.js +87 -0
- package/runtime/scripts/chat-core/engine.js +195 -0
- package/runtime/scripts/chat-core/event-schema.js +231 -0
- package/runtime/scripts/chat-core/events.js +190 -0
- package/runtime/scripts/chat-core/index.js +11 -0
- package/runtime/scripts/chat-core/input.js +50 -0
- package/runtime/scripts/chat-core/normalizers/claude.js +450 -0
- package/runtime/scripts/chat-core/normalizers/codex.js +380 -0
- package/runtime/scripts/chat-core/normalizers/normalizer_spec.md +259 -0
- package/runtime/scripts/chat-core/normalizers/opencode.js +552 -0
- package/runtime/scripts/chat-core/normalizers/tool_contract.md +123 -0
- package/runtime/scripts/chat-core/normalizers/usage_contract.md +304 -0
- package/runtime/scripts/chat-core/parts.js +253 -0
- package/runtime/scripts/chat-core/recorder.js +65 -0
- package/runtime/scripts/chat-core/runtime.js +86 -0
- package/runtime/scripts/chat-core/server.js +163 -0
- package/runtime/scripts/chat-core/sse.js +196 -0
- package/runtime/scripts/chat-core/stores.js +100 -0
- package/runtime/scripts/chat-core/tool-display.js +149 -0
- package/runtime/scripts/chat-core/tool-shape.js +143 -0
- package/runtime/scripts/chat-core/tooling/mcp-bundle.js +161 -0
- package/runtime/scripts/chat-core/tooling/mcp-relay.js +97 -0
- package/runtime/scripts/chat-core/tooling/native-binaries.js +608 -0
- package/runtime/scripts/chat-core/tooling/system-prompt.js +20 -0
- package/runtime/scripts/chat-core/usage.js +343 -0
- package/runtime/scripts/chat-server/config.js +110 -0
- package/runtime/scripts/chat-server/db.js +529 -0
- package/runtime/scripts/chat-server/index.js +33 -0
- package/runtime/scripts/chat-server/model-catalog.js +327 -0
- package/runtime/scripts/chat-server.js +75 -0
- package/runtime/scripts/credential-adapter.js +129 -0
- package/runtime/scripts/fs-watcher.js +888 -0
- package/runtime/scripts/local-gateway.js +852 -0
- package/runtime/scripts/platform-context.txt +246 -0
- package/runtime/scripts/port-monitor.js +175 -0
- package/runtime/scripts/proxy-token-store.js +162 -0
- package/runtime/scripts/runtime-auth.js +163 -0
- package/runtime/scripts/test-claude-code-models.js +87 -0
- 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');
|