alaska-ai 0.1.0
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 +56 -0
- package/dist/adapters/slack.d.ts +130 -0
- package/dist/adapters/slack.js +1484 -0
- package/dist/adapters/slack.js.map +1 -0
- package/dist/backends/claude.d.ts +78 -0
- package/dist/backends/claude.js +452 -0
- package/dist/backends/claude.js.map +1 -0
- package/dist/backends/codex.d.ts +53 -0
- package/dist/backends/codex.js +324 -0
- package/dist/backends/codex.js.map +1 -0
- package/dist/cli/init.d.ts +50 -0
- package/dist/cli/init.js +386 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/prompt.d.ts +31 -0
- package/dist/cli/prompt.js +145 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/start.d.ts +28 -0
- package/dist/cli/start.js +522 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/callbacks.d.ts +32 -0
- package/dist/mcp/callbacks.js +181 -0
- package/dist/mcp/callbacks.js.map +1 -0
- package/dist/mcp/config.d.ts +15 -0
- package/dist/mcp/config.js +22 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/entry.d.ts +13 -0
- package/dist/mcp/entry.js +119 -0
- package/dist/mcp/entry.js.map +1 -0
- package/dist/mcp/file-browser.d.ts +15 -0
- package/dist/mcp/file-browser.js +135 -0
- package/dist/mcp/file-browser.js.map +1 -0
- package/dist/mcp/ipc-server.d.ts +64 -0
- package/dist/mcp/ipc-server.js +380 -0
- package/dist/mcp/ipc-server.js.map +1 -0
- package/dist/mcp/preview-server.d.ts +33 -0
- package/dist/mcp/preview-server.js +254 -0
- package/dist/mcp/preview-server.js.map +1 -0
- package/dist/mcp/server.d.ts +51 -0
- package/dist/mcp/server.js +257 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tunnel.d.ts +17 -0
- package/dist/mcp/tunnel.js +154 -0
- package/dist/mcp/tunnel.js.map +1 -0
- package/dist/router.d.ts +113 -0
- package/dist/router.js +511 -0
- package/dist/router.js.map +1 -0
- package/dist/sandbox-policy.d.ts +6 -0
- package/dist/sandbox-policy.js +46 -0
- package/dist/sandbox-policy.js.map +1 -0
- package/dist/scheduler.d.ts +42 -0
- package/dist/scheduler.js +169 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/store.d.ts +95 -0
- package/dist/store.js +353 -0
- package/dist/store.js.map +1 -0
- package/dist/types/adapter.d.ts +50 -0
- package/dist/types/adapter.js +9 -0
- package/dist/types/adapter.js.map +1 -0
- package/dist/types/backend.d.ts +73 -0
- package/dist/types/backend.js +8 -0
- package/dist/types/backend.js.map +1 -0
- package/dist/types/events.d.ts +47 -0
- package/dist/types/events.js +9 -0
- package/dist/types/events.js.map +1 -0
- package/dist/utils.d.ts +59 -0
- package/dist/utils.js +272 -0
- package/dist/utils.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback handler glue layer.
|
|
3
|
+
*
|
|
4
|
+
* Implements IpcHandler by routing MCP tool calls to the correct adapter
|
|
5
|
+
* (for example, Slack), tunnel manager, and file browser.
|
|
6
|
+
*/
|
|
7
|
+
import type { IpcHandler } from './ipc-server.js';
|
|
8
|
+
import type { Adapter } from '../types/adapter.js';
|
|
9
|
+
import type { Store } from '../store.js';
|
|
10
|
+
export interface CallbackHandlerOptions {
|
|
11
|
+
adapters: Map<string, Adapter>;
|
|
12
|
+
store?: Store;
|
|
13
|
+
}
|
|
14
|
+
/** Clear the post_message flag for a thread. Call before starting a turn. */
|
|
15
|
+
export declare function clearPostMessageFlag(threadId: string): void;
|
|
16
|
+
/** Check if post_message was called for a thread during the current turn. */
|
|
17
|
+
export declare function wasPostMessageCalled(threadId: string): boolean;
|
|
18
|
+
/** Mark that post_message was called for a thread. Used by tests. */
|
|
19
|
+
export declare function markPostMessageCalled(threadId: string): void;
|
|
20
|
+
/** Clear the schedule-created flag for a thread. Call before starting a turn. */
|
|
21
|
+
export declare function clearScheduleFlag(threadId: string): void;
|
|
22
|
+
/** Check if schedule_session was called for a thread during the current turn. */
|
|
23
|
+
export declare function wasScheduleCreated(threadId: string): boolean;
|
|
24
|
+
/** Mark that schedule_session was called for a thread. */
|
|
25
|
+
export declare function markScheduleCreated(threadId: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Create an IPC handler that routes MCP tool calls to the appropriate
|
|
28
|
+
* adapter, tunnel manager, or file browser.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createCallbackHandler(options: CallbackHandlerOptions): IpcHandler;
|
|
31
|
+
/** Close all active file browsers. Called during shutdown. */
|
|
32
|
+
export declare function closeAllFileBrowsers(): Promise<void>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback handler glue layer.
|
|
3
|
+
*
|
|
4
|
+
* Implements IpcHandler by routing MCP tool calls to the correct adapter
|
|
5
|
+
* (for example, Slack), tunnel manager, and file browser.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { openTunnel } from './tunnel.js';
|
|
10
|
+
import { startFileBrowser } from './file-browser.js';
|
|
11
|
+
import { startPreviewServer } from './preview-server.js';
|
|
12
|
+
import { getUploadsDir } from '../utils.js';
|
|
13
|
+
import { computeNextRun } from '../scheduler.js';
|
|
14
|
+
/** Tracks active file browsers for cleanup. */
|
|
15
|
+
const activeFileBrowsers = [];
|
|
16
|
+
/**
|
|
17
|
+
* Tracks which threads had post_message called during the current turn.
|
|
18
|
+
* The adapter clears this before spawning a backend, and checks after
|
|
19
|
+
* the backend completes to decide whether to suppress assistant_text events.
|
|
20
|
+
*/
|
|
21
|
+
const threadsWithPostMessage = new Set();
|
|
22
|
+
/** Clear the post_message flag for a thread. Call before starting a turn. */
|
|
23
|
+
export function clearPostMessageFlag(threadId) {
|
|
24
|
+
threadsWithPostMessage.delete(threadId);
|
|
25
|
+
}
|
|
26
|
+
/** Check if post_message was called for a thread during the current turn. */
|
|
27
|
+
export function wasPostMessageCalled(threadId) {
|
|
28
|
+
return threadsWithPostMessage.has(threadId);
|
|
29
|
+
}
|
|
30
|
+
/** Mark that post_message was called for a thread. Used by tests. */
|
|
31
|
+
export function markPostMessageCalled(threadId) {
|
|
32
|
+
threadsWithPostMessage.add(threadId);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Tracks which threads had schedule_session called during the current turn.
|
|
36
|
+
* The adapter checks this after the backend completes to suppress assistant_text
|
|
37
|
+
* and swap the eyes emoji to a checkmark instead.
|
|
38
|
+
*/
|
|
39
|
+
const threadsWithScheduleCreated = new Set();
|
|
40
|
+
/** Clear the schedule-created flag for a thread. Call before starting a turn. */
|
|
41
|
+
export function clearScheduleFlag(threadId) {
|
|
42
|
+
threadsWithScheduleCreated.delete(threadId);
|
|
43
|
+
}
|
|
44
|
+
/** Check if schedule_session was called for a thread during the current turn. */
|
|
45
|
+
export function wasScheduleCreated(threadId) {
|
|
46
|
+
return threadsWithScheduleCreated.has(threadId);
|
|
47
|
+
}
|
|
48
|
+
/** Mark that schedule_session was called for a thread. */
|
|
49
|
+
export function markScheduleCreated(threadId) {
|
|
50
|
+
threadsWithScheduleCreated.add(threadId);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create an IPC handler that routes MCP tool calls to the appropriate
|
|
54
|
+
* adapter, tunnel manager, or file browser.
|
|
55
|
+
*/
|
|
56
|
+
export function createCallbackHandler(options) {
|
|
57
|
+
const { adapters, store } = options;
|
|
58
|
+
function getAdapter(platform) {
|
|
59
|
+
const adapter = adapters.get(platform);
|
|
60
|
+
if (!adapter) {
|
|
61
|
+
throw new Error(`No adapter registered for platform: ${platform}`);
|
|
62
|
+
}
|
|
63
|
+
return adapter;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
async uploadFile(channelId, threadId, filePath, platform) {
|
|
67
|
+
const adapter = getAdapter(platform);
|
|
68
|
+
await adapter.uploadFile(channelId, threadId, filePath);
|
|
69
|
+
},
|
|
70
|
+
async openTunnel(port, ttl) {
|
|
71
|
+
const tunnel = await openTunnel(port, ttl);
|
|
72
|
+
return tunnel.url;
|
|
73
|
+
},
|
|
74
|
+
async serveFileBrowser(directory) {
|
|
75
|
+
const browser = await startFileBrowser(directory);
|
|
76
|
+
activeFileBrowsers.push(browser);
|
|
77
|
+
// Tunnel the file browser so it's accessible externally
|
|
78
|
+
const tunnel = await openTunnel(browser.port, 3600); // 1 hour default TTL
|
|
79
|
+
return tunnel.url;
|
|
80
|
+
},
|
|
81
|
+
async previewServer(directory, command, ttl) {
|
|
82
|
+
const preview = await startPreviewServer(directory, command, ttl);
|
|
83
|
+
return { url: preview.url, port: preview.port };
|
|
84
|
+
},
|
|
85
|
+
async postMessage(channelId, threadId, text, platform) {
|
|
86
|
+
// If a schedule was just created for this thread, suppress the confirmation text
|
|
87
|
+
// (Claude may still call post_message despite being told not to)
|
|
88
|
+
if (threadsWithScheduleCreated.has(threadId)) {
|
|
89
|
+
console.log(`[callbacks] suppressed post_message for thread ${threadId} (schedule created)`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
threadsWithPostMessage.add(threadId);
|
|
93
|
+
const adapter = getAdapter(platform);
|
|
94
|
+
await adapter.sendMessage(channelId, threadId, text);
|
|
95
|
+
},
|
|
96
|
+
async askUserQuestion(channelId, threadId, questions, platform, requestId) {
|
|
97
|
+
const adapter = getAdapter(platform);
|
|
98
|
+
await adapter.postUserQuestion(channelId, threadId, questions, requestId, null);
|
|
99
|
+
},
|
|
100
|
+
async renderTodos(channelId, threadId, todos, platform) {
|
|
101
|
+
const adapter = getAdapter(platform);
|
|
102
|
+
await adapter.renderTodoList(channelId, threadId, todos);
|
|
103
|
+
},
|
|
104
|
+
async requestPermission(channelId, threadId, toolName, toolInput, platform, requestId) {
|
|
105
|
+
const adapter = getAdapter(platform);
|
|
106
|
+
await adapter.postPermissionPrompt(channelId, threadId, {
|
|
107
|
+
toolName,
|
|
108
|
+
toolInput,
|
|
109
|
+
requestId,
|
|
110
|
+
}, null);
|
|
111
|
+
},
|
|
112
|
+
async saveUploadedFile(uploadId, destination, projectDir) {
|
|
113
|
+
const uploadsDir = getUploadsDir();
|
|
114
|
+
if (!fs.existsSync(uploadsDir)) {
|
|
115
|
+
throw new Error('No uploads directory found');
|
|
116
|
+
}
|
|
117
|
+
// Find the staging file by uploadId prefix
|
|
118
|
+
const files = fs.readdirSync(uploadsDir);
|
|
119
|
+
const match = files.find((f) => f.startsWith(`${uploadId}-`));
|
|
120
|
+
if (!match) {
|
|
121
|
+
throw new Error(`No staged file found for upload_id: ${uploadId}`);
|
|
122
|
+
}
|
|
123
|
+
const sourcePath = path.join(uploadsDir, match);
|
|
124
|
+
// Validate destination is within the project directory
|
|
125
|
+
const resolvedDest = path.resolve(projectDir, destination);
|
|
126
|
+
const normalizedProject = path.resolve(projectDir);
|
|
127
|
+
if (!resolvedDest.startsWith(normalizedProject + path.sep) && resolvedDest !== normalizedProject) {
|
|
128
|
+
throw new Error(`Destination "${destination}" is outside the project directory`);
|
|
129
|
+
}
|
|
130
|
+
// Ensure parent directory exists and copy (not move, so model can save to multiple destinations)
|
|
131
|
+
fs.mkdirSync(path.dirname(resolvedDest), { recursive: true });
|
|
132
|
+
fs.copyFileSync(sourcePath, resolvedDest);
|
|
133
|
+
console.log(`[callbacks] saved uploaded file ${uploadId} to ${resolvedDest}`);
|
|
134
|
+
return resolvedDest;
|
|
135
|
+
},
|
|
136
|
+
async scheduleSession(channelId, threadId, prompt, originalRequest, cronExpression, scheduledAt, title) {
|
|
137
|
+
if (!store) {
|
|
138
|
+
throw new Error('Store not available for scheduling');
|
|
139
|
+
}
|
|
140
|
+
const project = await store.getProjectByChannelId(channelId);
|
|
141
|
+
if (!project) {
|
|
142
|
+
throw new Error(`No project connected to channel ${channelId}`);
|
|
143
|
+
}
|
|
144
|
+
// computeNextRun already returns UTC (cron-parser with tz option).
|
|
145
|
+
// For one-time scheduled_at: Claude provides local time without Z suffix.
|
|
146
|
+
// new Date() interprets strings without timezone indicator as local time,
|
|
147
|
+
// and toISOString() converts to UTC — exactly what the scheduler needs.
|
|
148
|
+
let nextRunAt;
|
|
149
|
+
if (cronExpression) {
|
|
150
|
+
nextRunAt = computeNextRun(cronExpression);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const parsed = new Date(scheduledAt);
|
|
154
|
+
if (isNaN(parsed.getTime())) {
|
|
155
|
+
throw new Error(`Invalid scheduled_at value: ${scheduledAt}`);
|
|
156
|
+
}
|
|
157
|
+
nextRunAt = parsed.toISOString();
|
|
158
|
+
}
|
|
159
|
+
const schedule = await store.createSchedule(project.id, channelId, prompt, originalRequest, { cronExpression, scheduledAt, nextRunAt, threadId, title });
|
|
160
|
+
console.log(`[callbacks] created schedule ${schedule.id} for channel ${channelId}`);
|
|
161
|
+
// Mark the thread so the adapter can suppress assistant_text and swap emoji
|
|
162
|
+
if (threadId) {
|
|
163
|
+
threadsWithScheduleCreated.add(threadId);
|
|
164
|
+
}
|
|
165
|
+
return { scheduleId: schedule.id };
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** Close all active file browsers. Called during shutdown. */
|
|
170
|
+
export async function closeAllFileBrowsers() {
|
|
171
|
+
for (const browser of activeFileBrowsers) {
|
|
172
|
+
try {
|
|
173
|
+
await browser.close();
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
console.error(`[callbacks] failed to close file browser: ${err.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
activeFileBrowsers.length = 0;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=callbacks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callbacks.js","sourceRoot":"","sources":["../../src/mcp/callbacks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpServerEntry } from '../types/backend.js';
|
|
2
|
+
export interface McpSessionContext {
|
|
3
|
+
channelId: string;
|
|
4
|
+
threadId: string;
|
|
5
|
+
projectDir: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Generate MCP server config for backend CLI invocations.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getMcpConfig(entryScriptPath: string, context: McpSessionContext & {
|
|
11
|
+
platform: string;
|
|
12
|
+
}, ipc: {
|
|
13
|
+
port: number;
|
|
14
|
+
secret: string;
|
|
15
|
+
}): McpServerEntry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate MCP server config for backend CLI invocations.
|
|
3
|
+
*/
|
|
4
|
+
export function getMcpConfig(entryScriptPath, context, ipc) {
|
|
5
|
+
return {
|
|
6
|
+
command: 'node',
|
|
7
|
+
args: [
|
|
8
|
+
entryScriptPath,
|
|
9
|
+
'--channel', context.channelId,
|
|
10
|
+
'--thread', context.threadId,
|
|
11
|
+
'--project-dir', context.projectDir,
|
|
12
|
+
'--platform', context.platform,
|
|
13
|
+
'--ipc-port', String(ipc.port),
|
|
14
|
+
'--ipc-secret', ipc.secret,
|
|
15
|
+
],
|
|
16
|
+
env: {
|
|
17
|
+
ALASKA_IPC_PORT: String(ipc.port),
|
|
18
|
+
ALASKA_IPC_SECRET: ipc.secret,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/mcp/config.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,eAAuB,EACvB,OAAiD,EACjD,GAAqC;IAErC,OAAO;QACL,OAAO,EAAE,MAAM;QACf,IAAI,EAAE;YACJ,eAAe;YACf,WAAW,EAAE,OAAO,CAAC,SAAS;YAC9B,UAAU,EAAE,OAAO,CAAC,QAAQ;YAC5B,eAAe,EAAE,OAAO,CAAC,UAAU;YACnC,YAAY,EAAE,OAAO,CAAC,QAAQ;YAC9B,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,cAAc,EAAE,GAAG,CAAC,MAAM;SAC3B;QACD,GAAG,EAAE;YACH,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YACjC,iBAAiB,EAAE,GAAG,CAAC,MAAM;SAC9B;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP entry point — spawned by the backend (Claude Code / Codex) as a
|
|
3
|
+
* grandchild process. Connects via stdio transport and uses fetch() to
|
|
4
|
+
* call back to the bridge's IPC server for side-effects.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node dist/mcp/entry.js --channel C123 --thread T456 --project-dir /path --platform slack
|
|
8
|
+
*
|
|
9
|
+
* Environment:
|
|
10
|
+
* ALASKA_IPC_PORT — port of the bridge's IPC server
|
|
11
|
+
* ALASKA_IPC_SECRET — auth secret for IPC requests
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP entry point — spawned by the backend (Claude Code / Codex) as a
|
|
3
|
+
* grandchild process. Connects via stdio transport and uses fetch() to
|
|
4
|
+
* call back to the bridge's IPC server for side-effects.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node dist/mcp/entry.js --channel C123 --thread T456 --project-dir /path --platform slack
|
|
8
|
+
*
|
|
9
|
+
* Environment:
|
|
10
|
+
* ALASKA_IPC_PORT — port of the bridge's IPC server
|
|
11
|
+
* ALASKA_IPC_SECRET — auth secret for IPC requests
|
|
12
|
+
*/
|
|
13
|
+
import { startMcpServer } from './server.js';
|
|
14
|
+
/** Parse --key value pairs from argv. */
|
|
15
|
+
function parseArgs(argv) {
|
|
16
|
+
const args = {};
|
|
17
|
+
for (let i = 0; i < argv.length; i++) {
|
|
18
|
+
if (argv[i].startsWith('--') && i + 1 < argv.length) {
|
|
19
|
+
args[argv[i].slice(2)] = argv[i + 1];
|
|
20
|
+
i++; // skip value
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return args;
|
|
24
|
+
}
|
|
25
|
+
/** POST JSON to the IPC server and return the parsed response. */
|
|
26
|
+
async function ipcPost(port, secret, path, body) {
|
|
27
|
+
const res = await fetch(`http://127.0.0.1:${port}${path}`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
'x-alaska-secret': secret,
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(body),
|
|
34
|
+
});
|
|
35
|
+
const json = await res.json();
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
throw new Error(`IPC ${path} failed (${res.status}): ${json.error ?? 'unknown'}`);
|
|
38
|
+
}
|
|
39
|
+
return json;
|
|
40
|
+
}
|
|
41
|
+
async function main() {
|
|
42
|
+
const args = parseArgs(process.argv.slice(2));
|
|
43
|
+
const channelId = args['channel'];
|
|
44
|
+
const threadId = args['thread'];
|
|
45
|
+
const projectDir = args['project-dir'];
|
|
46
|
+
const platform = args['platform'];
|
|
47
|
+
if (!channelId || !threadId || !projectDir || !platform) {
|
|
48
|
+
console.error('[mcp-entry] missing required args: --channel, --thread, --project-dir, --platform');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
// Read IPC config from args first (needed for Codex which doesn't pass env),
|
|
52
|
+
// fall back to environment variables (Claude Code passes them via env)
|
|
53
|
+
const ipcPort = parseInt(args['ipc-port'] ?? process.env.ALASKA_IPC_PORT ?? '', 10);
|
|
54
|
+
const ipcSecret = args['ipc-secret'] ?? process.env.ALASKA_IPC_SECRET ?? '';
|
|
55
|
+
if (!ipcPort || !ipcSecret) {
|
|
56
|
+
console.error('[mcp-entry] missing env: ALASKA_IPC_PORT, ALASKA_IPC_SECRET');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const context = { channelId, threadId, projectDir };
|
|
60
|
+
const callbacks = {
|
|
61
|
+
async uploadFile(filePath, chId, thId) {
|
|
62
|
+
await ipcPost(ipcPort, ipcSecret, '/upload-file', {
|
|
63
|
+
channelId: chId,
|
|
64
|
+
threadId: thId,
|
|
65
|
+
filePath,
|
|
66
|
+
platform,
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
async openTunnel(port, ttl) {
|
|
70
|
+
const result = await ipcPost(ipcPort, ipcSecret, '/open-tunnel', { port, ttl });
|
|
71
|
+
return result.url;
|
|
72
|
+
},
|
|
73
|
+
async serveFileBrowser(directory) {
|
|
74
|
+
const result = await ipcPost(ipcPort, ipcSecret, '/serve-file-browser', { directory });
|
|
75
|
+
return result.url;
|
|
76
|
+
},
|
|
77
|
+
async previewServer(directory, command, ttl) {
|
|
78
|
+
const result = await ipcPost(ipcPort, ipcSecret, '/preview-server', { directory, command, ttl });
|
|
79
|
+
return { url: result.url, port: result.port };
|
|
80
|
+
},
|
|
81
|
+
async postMessage(chId, thId, text) {
|
|
82
|
+
await ipcPost(ipcPort, ipcSecret, '/post-message', {
|
|
83
|
+
channelId: chId,
|
|
84
|
+
threadId: thId,
|
|
85
|
+
text,
|
|
86
|
+
platform,
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
async saveUploadedFile(uploadId, destination, projDir) {
|
|
90
|
+
const result = await ipcPost(ipcPort, ipcSecret, '/save-uploaded-file', {
|
|
91
|
+
uploadId,
|
|
92
|
+
destination,
|
|
93
|
+
projectDir: projDir,
|
|
94
|
+
});
|
|
95
|
+
return result.path;
|
|
96
|
+
},
|
|
97
|
+
async scheduleSession(chId, thId, prompt, originalRequest, cronExpression, scheduledAt, title) {
|
|
98
|
+
const result = await ipcPost(ipcPort, ipcSecret, '/schedule-session', {
|
|
99
|
+
channelId: chId,
|
|
100
|
+
threadId: thId,
|
|
101
|
+
prompt,
|
|
102
|
+
originalRequest,
|
|
103
|
+
cronExpression,
|
|
104
|
+
scheduledAt,
|
|
105
|
+
title,
|
|
106
|
+
platform,
|
|
107
|
+
});
|
|
108
|
+
return { scheduleId: result.scheduleId };
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
console.error('[mcp-entry] starting MCP server for', { channelId, threadId, projectDir, platform });
|
|
112
|
+
await startMcpServer(context, callbacks);
|
|
113
|
+
console.error('[mcp-entry] MCP server connected via stdio');
|
|
114
|
+
}
|
|
115
|
+
main().catch((err) => {
|
|
116
|
+
console.error('[mcp-entry] fatal:', err);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/mcp/entry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal file browser HTTP server.
|
|
3
|
+
*
|
|
4
|
+
* Serves a directory listing as HTML. File requests stream the content
|
|
5
|
+
* with a basic Content-Type header. Runs on localhost:0 (random port).
|
|
6
|
+
*/
|
|
7
|
+
export interface FileBrowser {
|
|
8
|
+
port: number;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Start a file browser HTTP server for the given directory.
|
|
13
|
+
* Returns the port and a close function.
|
|
14
|
+
*/
|
|
15
|
+
export declare function startFileBrowser(directory: string): Promise<FileBrowser>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal file browser HTTP server.
|
|
3
|
+
*
|
|
4
|
+
* Serves a directory listing as HTML. File requests stream the content
|
|
5
|
+
* with a basic Content-Type header. Runs on localhost:0 (random port).
|
|
6
|
+
*/
|
|
7
|
+
import * as http from 'node:http';
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
/** Common MIME types for file serving. */
|
|
11
|
+
const MIME_TYPES = {
|
|
12
|
+
'.html': 'text/html',
|
|
13
|
+
'.css': 'text/css',
|
|
14
|
+
'.js': 'application/javascript',
|
|
15
|
+
'.json': 'application/json',
|
|
16
|
+
'.png': 'image/png',
|
|
17
|
+
'.jpg': 'image/jpeg',
|
|
18
|
+
'.jpeg': 'image/jpeg',
|
|
19
|
+
'.gif': 'image/gif',
|
|
20
|
+
'.svg': 'image/svg+xml',
|
|
21
|
+
'.pdf': 'application/pdf',
|
|
22
|
+
'.txt': 'text/plain',
|
|
23
|
+
'.md': 'text/plain',
|
|
24
|
+
'.ts': 'text/plain',
|
|
25
|
+
'.tsx': 'text/plain',
|
|
26
|
+
'.jsx': 'text/plain',
|
|
27
|
+
};
|
|
28
|
+
function getMimeType(filePath) {
|
|
29
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
30
|
+
return MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
31
|
+
}
|
|
32
|
+
/** Escape HTML special characters. */
|
|
33
|
+
function escapeHtml(str) {
|
|
34
|
+
return str
|
|
35
|
+
.replace(/&/g, '&')
|
|
36
|
+
.replace(/</g, '<')
|
|
37
|
+
.replace(/>/g, '>')
|
|
38
|
+
.replace(/"/g, '"');
|
|
39
|
+
}
|
|
40
|
+
/** Generate an HTML directory listing. */
|
|
41
|
+
function renderDirectoryListing(dirPath, urlPath, rootDir) {
|
|
42
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
43
|
+
const relativePath = path.relative(rootDir, dirPath) || '.';
|
|
44
|
+
let html = `<!DOCTYPE html>
|
|
45
|
+
<html><head><meta charset="utf-8"><title>Files: ${escapeHtml(relativePath)}</title>
|
|
46
|
+
<style>
|
|
47
|
+
body { font-family: monospace; max-width: 800px; margin: 20px auto; padding: 0 20px; }
|
|
48
|
+
a { text-decoration: none; color: #0066cc; }
|
|
49
|
+
a:hover { text-decoration: underline; }
|
|
50
|
+
.dir { font-weight: bold; }
|
|
51
|
+
ul { list-style: none; padding: 0; }
|
|
52
|
+
li { padding: 4px 0; }
|
|
53
|
+
</style>
|
|
54
|
+
</head><body>
|
|
55
|
+
<h2>${escapeHtml(relativePath)}</h2>
|
|
56
|
+
<ul>`;
|
|
57
|
+
// Parent directory link
|
|
58
|
+
if (urlPath !== '/') {
|
|
59
|
+
const parent = urlPath.endsWith('/') ? urlPath.slice(0, -1) : urlPath;
|
|
60
|
+
const parentUrl = parent.substring(0, parent.lastIndexOf('/')) || '/';
|
|
61
|
+
html += `<li><a href="${escapeHtml(parentUrl)}">..</a></li>`;
|
|
62
|
+
}
|
|
63
|
+
// Sort: directories first, then files
|
|
64
|
+
const dirs = entries.filter(e => e.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
|
|
65
|
+
const files = entries.filter(e => e.isFile()).sort((a, b) => a.name.localeCompare(b.name));
|
|
66
|
+
for (const dir of dirs) {
|
|
67
|
+
const href = urlPath.endsWith('/') ? `${urlPath}${dir.name}` : `${urlPath}/${dir.name}`;
|
|
68
|
+
html += `<li class="dir"><a href="${escapeHtml(href)}">${escapeHtml(dir.name)}/</a></li>`;
|
|
69
|
+
}
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
const href = urlPath.endsWith('/') ? `${urlPath}${file.name}` : `${urlPath}/${file.name}`;
|
|
72
|
+
const stat = fs.statSync(path.join(dirPath, file.name));
|
|
73
|
+
const size = stat.size < 1024 ? `${stat.size}B` : `${(stat.size / 1024).toFixed(1)}KB`;
|
|
74
|
+
html += `<li><a href="${escapeHtml(href)}">${escapeHtml(file.name)}</a> <span style="color:#888">(${size})</span></li>`;
|
|
75
|
+
}
|
|
76
|
+
html += `</ul></body></html>`;
|
|
77
|
+
return html;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Start a file browser HTTP server for the given directory.
|
|
81
|
+
* Returns the port and a close function.
|
|
82
|
+
*/
|
|
83
|
+
export function startFileBrowser(directory) {
|
|
84
|
+
const rootDir = path.resolve(directory);
|
|
85
|
+
const server = http.createServer((req, res) => {
|
|
86
|
+
const urlPath = decodeURIComponent(req.url ?? '/');
|
|
87
|
+
const filePath = path.resolve(rootDir, '.' + urlPath);
|
|
88
|
+
// Prevent path traversal
|
|
89
|
+
if (!filePath.startsWith(rootDir)) {
|
|
90
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
91
|
+
res.end('Forbidden');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const stat = fs.statSync(filePath);
|
|
96
|
+
if (stat.isDirectory()) {
|
|
97
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
98
|
+
res.end(renderDirectoryListing(filePath, urlPath, rootDir));
|
|
99
|
+
}
|
|
100
|
+
else if (stat.isFile()) {
|
|
101
|
+
res.writeHead(200, { 'Content-Type': getMimeType(filePath) });
|
|
102
|
+
fs.createReadStream(filePath).pipe(res);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
106
|
+
res.end('Not found');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
111
|
+
res.end('Not found');
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
server.listen(0, '127.0.0.1', () => {
|
|
116
|
+
const addr = server.address();
|
|
117
|
+
if (!addr || typeof addr === 'string') {
|
|
118
|
+
reject(new Error('Failed to get file browser address'));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const port = addr.port;
|
|
122
|
+
console.log(`[file-browser] serving ${rootDir} on 127.0.0.1:${port}`);
|
|
123
|
+
resolve({
|
|
124
|
+
port,
|
|
125
|
+
close() {
|
|
126
|
+
return new Promise((res, rej) => {
|
|
127
|
+
server.close((err) => (err ? rej(err) : res()));
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
server.on('error', reject);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=file-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-browser.js","sourceRoot":"","sources":["../../src/mcp/file-browser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAOlC,0CAA0C;AAC1C,MAAM,UAAU,GAA2B;IACzC,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,wBAAwB;IAC/B,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;AACvD,CAAC;AAED,sCAAsC;AACtC,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,0CAA0C;AAC1C,SAAS,sBAAsB,CAAC,OAAe,EAAE,OAAe,EAAE,OAAe;IAC/E,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC;IAE5D,IAAI,IAAI,GAAG;kDACqC,UAAU,CAAC,YAAY,CAAC;;;;;;;;;;MAUpE,UAAU,CAAC,YAAY,CAAC;KACzB,CAAC;IAEJ,wBAAwB;IACxB,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACtE,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;QACtE,IAAI,IAAI,gBAAgB,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC;IAC/D,CAAC;IAED,sCAAsC;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/F,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE3F,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACxF,IAAI,IAAI,4BAA4B,UAAU,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;IAC5F,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1F,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,IAAI,IAAI,gBAAgB,UAAU,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,kCAAkC,IAAI,eAAe,CAAC;IAC1H,CAAC;IAED,IAAI,IAAI,qBAAqB,CAAC;IAC9B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAEtD,yBAAyB;QACzB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEnC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9D,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;gBACzB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAC9D,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;gBACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtC,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAC;gBACxD,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,iBAAiB,IAAI,EAAE,CAAC,CAAC;YAEtE,OAAO,CAAC;gBACN,IAAI;gBACJ,KAAK;oBACH,OAAO,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;wBACpC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;oBAClD,CAAC,CAAC,CAAC;gBACL,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local HTTP IPC server for MCP callback communication.
|
|
3
|
+
*
|
|
4
|
+
* The bridge starts this on 127.0.0.1:0 (random port). The MCP entry
|
|
5
|
+
* script (grandchild process) makes fetch() calls to it when the agent
|
|
6
|
+
* invokes MCP tools like upload_file or preview_server.
|
|
7
|
+
*
|
|
8
|
+
* Auth: every request must include the ALASKA_IPC_SECRET header.
|
|
9
|
+
*/
|
|
10
|
+
/** Handler interface — the callback handler implements this. */
|
|
11
|
+
export interface IpcHandler {
|
|
12
|
+
uploadFile(channelId: string, threadId: string, filePath: string, platform: string): Promise<void>;
|
|
13
|
+
openTunnel(port: number, ttl: number): Promise<string>;
|
|
14
|
+
serveFileBrowser(directory: string): Promise<string>;
|
|
15
|
+
/** Start a preview server (static or command) and tunnel it. Returns { url, port }. */
|
|
16
|
+
previewServer(directory: string, command: string | undefined, ttl: number): Promise<{
|
|
17
|
+
url: string;
|
|
18
|
+
port: number;
|
|
19
|
+
}>;
|
|
20
|
+
postMessage(channelId: string, threadId: string, text: string, platform: string): Promise<void>;
|
|
21
|
+
/** Send a permission prompt to the user and return immediately (non-blocking). */
|
|
22
|
+
requestPermission?(channelId: string, threadId: string, toolName: string, toolInput: Record<string, unknown>, platform: string, requestId: string): Promise<void>;
|
|
23
|
+
/** Send an AskUserQuestion prompt to the user and return immediately (non-blocking). */
|
|
24
|
+
askUserQuestion?(channelId: string, threadId: string, questions: Array<{
|
|
25
|
+
question: string;
|
|
26
|
+
header: string;
|
|
27
|
+
options: Array<{
|
|
28
|
+
label: string;
|
|
29
|
+
description: string;
|
|
30
|
+
}>;
|
|
31
|
+
multiSelect: boolean;
|
|
32
|
+
}>, platform: string, requestId: string): Promise<void>;
|
|
33
|
+
/** Copy a staged uploaded file to a destination in the project directory. */
|
|
34
|
+
saveUploadedFile?(uploadId: string, destination: string, projectDir: string): Promise<string>;
|
|
35
|
+
/** Render a todo checklist in the chat thread (fire-and-forget, no pending state). */
|
|
36
|
+
renderTodos?(channelId: string, threadId: string, todos: Array<{
|
|
37
|
+
content: string;
|
|
38
|
+
status: string;
|
|
39
|
+
activeForm: string;
|
|
40
|
+
}>, platform: string): Promise<void>;
|
|
41
|
+
/** Register a scheduled session. Returns the schedule ID. */
|
|
42
|
+
scheduleSession?(channelId: string, threadId: string, prompt: string, originalRequest: string, cronExpression: string | undefined, scheduledAt: string | undefined, title: string | undefined): Promise<{
|
|
43
|
+
scheduleId: number;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
/** Resolve a pending permission request (called by adapters in-process). */
|
|
47
|
+
export declare function resolvePermission(requestId: string, decision: 'allow' | 'deny'): boolean;
|
|
48
|
+
/** Resolve a pending user question (called by adapters in-process). */
|
|
49
|
+
export declare function resolveUserQuestion(requestId: string, answer: string): boolean;
|
|
50
|
+
/** Resolve a pending user question by thread ID (called when user types instead of clicking).
|
|
51
|
+
* Returns the requestId if resolved, null otherwise (so caller can update the button message). */
|
|
52
|
+
export declare function resolveQuestionByThread(threadId: string, answer: string): string | null;
|
|
53
|
+
/** Check if a thread has a pending user question. */
|
|
54
|
+
export declare function hasPendingQuestion(threadId: string): boolean;
|
|
55
|
+
export interface IpcServer {
|
|
56
|
+
port: number;
|
|
57
|
+
secret: string;
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Start the IPC server on localhost with a random port.
|
|
62
|
+
* Returns the port, secret, and a close function.
|
|
63
|
+
*/
|
|
64
|
+
export declare function startIpcServer(handler: IpcHandler): Promise<IpcServer>;
|