@portel/photon 1.17.6 → 1.18.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/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
- package/dist/auto-ui/beam/photon-management.js +28 -1
- package/dist/auto-ui/beam/photon-management.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js +10 -5
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +259 -88
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +2 -0
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js +5 -0
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam.bundle.js +226 -29
- package/dist/beam.bundle.js.map +2 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +9 -8
- package/dist/loader.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +11 -0
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +155 -1
- package/dist/server.js.map +1 -1
- package/dist/tasks/executor.d.ts +47 -0
- package/dist/tasks/executor.d.ts.map +1 -0
- package/dist/tasks/executor.js +180 -0
- package/dist/tasks/executor.js.map +1 -0
- package/dist/tasks/store.d.ts +13 -6
- package/dist/tasks/store.d.ts.map +1 -1
- package/dist/tasks/store.js +50 -9
- package/dist/tasks/store.js.map +1 -1
- package/dist/tasks/types.d.ts +23 -2
- package/dist/tasks/types.d.ts.map +1 -1
- package/dist/tasks/types.js +23 -3
- package/dist/tasks/types.js.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Task Executor (spec v2025-11-25)
|
|
3
|
+
*
|
|
4
|
+
* Runs tool execution in the background with support for input resumption.
|
|
5
|
+
* Decoupled from transport — works with both Streamable HTTP and STDIO.
|
|
6
|
+
*/
|
|
7
|
+
import { updateTask, unregisterController, taskEvents } from './store.js';
|
|
8
|
+
import { TERMINAL_STATES } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Pending input resolvers — when a task enters input_required,
|
|
11
|
+
* the generator blocks on a promise. resolveTaskInput() resolves it.
|
|
12
|
+
*/
|
|
13
|
+
const pendingInputs = new Map();
|
|
14
|
+
/**
|
|
15
|
+
* Resolve pending input for a task, resuming generator execution.
|
|
16
|
+
* Returns true if there was pending input to resolve.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveTaskInput(taskId, value) {
|
|
19
|
+
const pending = pendingInputs.get(taskId);
|
|
20
|
+
if (!pending)
|
|
21
|
+
return false;
|
|
22
|
+
pendingInputs.delete(taskId);
|
|
23
|
+
pending.resolve(value);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reject pending input (e.g., on cancellation or timeout).
|
|
28
|
+
*/
|
|
29
|
+
export function rejectTaskInput(taskId, reason) {
|
|
30
|
+
const pending = pendingInputs.get(taskId);
|
|
31
|
+
if (!pending)
|
|
32
|
+
return false;
|
|
33
|
+
pendingInputs.delete(taskId);
|
|
34
|
+
pending.reject(new Error(reason));
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a task has pending input waiting.
|
|
39
|
+
*/
|
|
40
|
+
export function hasPendingInput(taskId) {
|
|
41
|
+
return pendingInputs.has(taskId);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Wait for a task to reach a specific state (or any state change).
|
|
45
|
+
* Resolves with the updated task when the condition is met.
|
|
46
|
+
*/
|
|
47
|
+
export function waitForStateChange(taskId, predicate, signal) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
// Check abort
|
|
50
|
+
if (signal?.aborted) {
|
|
51
|
+
reject(new Error('Aborted'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const handler = (changedId, newState, task) => {
|
|
55
|
+
if (changedId !== taskId)
|
|
56
|
+
return;
|
|
57
|
+
if (!predicate || predicate(newState)) {
|
|
58
|
+
cleanup();
|
|
59
|
+
resolve(task);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const onAbort = () => {
|
|
63
|
+
cleanup();
|
|
64
|
+
reject(new Error('Aborted'));
|
|
65
|
+
};
|
|
66
|
+
const cleanup = () => {
|
|
67
|
+
taskEvents.removeListener('stateChange', handler);
|
|
68
|
+
signal?.removeEventListener('abort', onAbort);
|
|
69
|
+
};
|
|
70
|
+
taskEvents.on('stateChange', handler);
|
|
71
|
+
signal?.addEventListener('abort', onAbort);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Wait for a task to reach a terminal state or input_required.
|
|
76
|
+
* Used by tasks/result handler.
|
|
77
|
+
*/
|
|
78
|
+
export function waitForTerminalOrInput(taskId, signal) {
|
|
79
|
+
return waitForStateChange(taskId, (state) => TERMINAL_STATES.includes(state) || state === 'input_required', signal);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Run tool execution as a background task.
|
|
83
|
+
*
|
|
84
|
+
* Fire-and-forget — caller does not await this.
|
|
85
|
+
* Updates task state in store as execution progresses.
|
|
86
|
+
* Generator yields { ask } → task enters input_required, blocks until resolveTaskInput().
|
|
87
|
+
*/
|
|
88
|
+
export function runTaskExecution(taskId, executeFn, options) {
|
|
89
|
+
const { signal, outputHandler: externalOutputHandler } = options;
|
|
90
|
+
// inputProvider that blocks on pending input
|
|
91
|
+
const inputProvider = async (ask) => {
|
|
92
|
+
// Store the ask payload and transition to input_required
|
|
93
|
+
updateTask(taskId, {
|
|
94
|
+
state: 'input_required',
|
|
95
|
+
statusMessage: ask.message || 'Waiting for user input.',
|
|
96
|
+
input: ask,
|
|
97
|
+
});
|
|
98
|
+
// Block until resolveTaskInput() or rejectTaskInput() is called
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
pendingInputs.set(taskId, { resolve, reject });
|
|
101
|
+
// If already aborted, reject immediately
|
|
102
|
+
if (signal.aborted) {
|
|
103
|
+
pendingInputs.delete(taskId);
|
|
104
|
+
reject(new Error('Task cancelled'));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Listen for abort to clean up
|
|
108
|
+
const onAbort = () => {
|
|
109
|
+
if (pendingInputs.has(taskId)) {
|
|
110
|
+
pendingInputs.delete(taskId);
|
|
111
|
+
reject(new Error('Task cancelled'));
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
// outputHandler that updates task progress
|
|
118
|
+
const outputHandler = (data) => {
|
|
119
|
+
if (data?.emit === 'progress' && typeof data.value === 'number') {
|
|
120
|
+
updateTask(taskId, {
|
|
121
|
+
progress: { percent: data.value, message: data.message },
|
|
122
|
+
statusMessage: data.message || undefined,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (data?.emit === 'status') {
|
|
126
|
+
updateTask(taskId, {
|
|
127
|
+
statusMessage: data.message || 'Processing...',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Forward to external handler (e.g., SSE broadcast)
|
|
131
|
+
externalOutputHandler?.(data);
|
|
132
|
+
};
|
|
133
|
+
// Run in background
|
|
134
|
+
void (async () => {
|
|
135
|
+
try {
|
|
136
|
+
if (signal.aborted) {
|
|
137
|
+
updateTask(taskId, { state: 'cancelled', statusMessage: 'Task was cancelled.' });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// When input is provided and task resumes, transition back to working
|
|
141
|
+
const wrappedInputProvider = async (ask) => {
|
|
142
|
+
const result = await inputProvider(ask);
|
|
143
|
+
// Resume: transition back to working
|
|
144
|
+
updateTask(taskId, {
|
|
145
|
+
state: 'working',
|
|
146
|
+
statusMessage: 'Resuming execution...',
|
|
147
|
+
input: undefined,
|
|
148
|
+
});
|
|
149
|
+
return result;
|
|
150
|
+
};
|
|
151
|
+
const result = await executeFn(wrappedInputProvider, outputHandler);
|
|
152
|
+
if (!signal.aborted) {
|
|
153
|
+
updateTask(taskId, {
|
|
154
|
+
state: 'completed',
|
|
155
|
+
statusMessage: 'Operation completed successfully.',
|
|
156
|
+
result,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (signal.aborted) {
|
|
162
|
+
updateTask(taskId, { state: 'cancelled', statusMessage: 'Task was cancelled.' });
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
166
|
+
updateTask(taskId, {
|
|
167
|
+
state: 'failed',
|
|
168
|
+
statusMessage: message,
|
|
169
|
+
error: message,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
// Clean up any lingering pending input
|
|
175
|
+
pendingInputs.delete(taskId);
|
|
176
|
+
unregisterController(taskId);
|
|
177
|
+
}
|
|
178
|
+
})();
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tasks/executor.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/store.d.ts
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Task Store
|
|
2
|
+
* MCP Task Store (spec v2025-11-25)
|
|
3
3
|
*
|
|
4
4
|
* File-based persistence at ~/.photon/tasks/.
|
|
5
5
|
* Each task is a JSON file: {taskId}.json
|
|
6
|
-
*
|
|
6
|
+
* EventEmitter for state change notifications.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import { type Task } from './types.js';
|
|
10
|
+
/** Event emitter for task state changes */
|
|
11
|
+
export declare const taskEvents: EventEmitter<[never]>;
|
|
9
12
|
export declare function registerController(taskId: string, controller: AbortController): void;
|
|
10
13
|
export declare function unregisterController(taskId: string): void;
|
|
11
14
|
export declare function getController(taskId: string): AbortController | undefined;
|
|
12
|
-
export declare function createTask(photon: string, method: string, params?: Record<string, unknown
|
|
15
|
+
export declare function createTask(photon: string, method: string, params?: Record<string, unknown>, ttl?: number): Task;
|
|
13
16
|
export declare function getTask(id: string): Task | null;
|
|
14
|
-
export declare function updateTask(id: string, updates: Partial<Pick<Task, 'state' | 'progress' | 'result' | 'error'>>): Task | null;
|
|
17
|
+
export declare function updateTask(id: string, updates: Partial<Pick<Task, 'state' | 'statusMessage' | 'progress' | 'result' | 'error' | 'input'>>): Task | null;
|
|
15
18
|
export declare function listTasks(photon?: string): Task[];
|
|
16
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Clean expired tasks — removes terminal tasks past their TTL
|
|
21
|
+
* and also removes non-terminal tasks that have been alive longer than their TTL
|
|
22
|
+
*/
|
|
23
|
+
export declare function cleanExpiredTasks(): number;
|
|
17
24
|
/** Override tasks dir for testing */
|
|
18
25
|
export declare function _getTasksDir(): string;
|
|
19
26
|
//# sourceMappingURL=store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,KAAK,IAAI,EAAuD,MAAM,YAAY,CAAC;AAa5F,2CAA2C;AAC3C,eAAO,MAAM,UAAU,uBAAqB,CAAC;AAM7C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAEpF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEzE;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,GAAG,CAAC,EAAE,MAAM,GACX,IAAI,CAkBN;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAS/C;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CACd,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC,CAClF,GACA,IAAI,GAAG,IAAI,CAcb;AAED,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAejD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA+B1C;AAED,qCAAqC;AACrC,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
package/dist/tasks/store.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Task Store
|
|
2
|
+
* MCP Task Store (spec v2025-11-25)
|
|
3
3
|
*
|
|
4
4
|
* File-based persistence at ~/.photon/tasks/.
|
|
5
5
|
* Each task is a JSON file: {taskId}.json
|
|
6
|
-
*
|
|
6
|
+
* EventEmitter for state change notifications.
|
|
7
7
|
*/
|
|
8
8
|
import { mkdirSync, readdirSync, unlinkSync, existsSync } from 'fs';
|
|
9
9
|
import { readJSONSync, writeJSONSync } from '../shared/io.js';
|
|
10
10
|
import { join } from 'path';
|
|
11
11
|
import { homedir } from 'os';
|
|
12
12
|
import { randomUUID } from 'crypto';
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
import { TERMINAL_STATES, DEFAULT_TTL, DEFAULT_POLL_INTERVAL } from './types.js';
|
|
13
15
|
const TASKS_DIR = join(homedir(), '.photon', 'tasks');
|
|
14
16
|
/** Ensure tasks directory exists (idempotent) */
|
|
15
17
|
function ensureDir() {
|
|
@@ -18,6 +20,9 @@ function ensureDir() {
|
|
|
18
20
|
function taskPath(id) {
|
|
19
21
|
return join(TASKS_DIR, `${id}.json`);
|
|
20
22
|
}
|
|
23
|
+
/** Event emitter for task state changes */
|
|
24
|
+
export const taskEvents = new EventEmitter();
|
|
25
|
+
taskEvents.setMaxListeners(50); // Multiple SSE sessions may listen
|
|
21
26
|
/** Active task AbortControllers for cancellation */
|
|
22
27
|
const activeControllers = new Map();
|
|
23
28
|
export function registerController(taskId, controller) {
|
|
@@ -29,7 +34,7 @@ export function unregisterController(taskId) {
|
|
|
29
34
|
export function getController(taskId) {
|
|
30
35
|
return activeControllers.get(taskId);
|
|
31
36
|
}
|
|
32
|
-
export function createTask(photon, method, params) {
|
|
37
|
+
export function createTask(photon, method, params, ttl) {
|
|
33
38
|
ensureDir();
|
|
34
39
|
const now = new Date().toISOString();
|
|
35
40
|
const task = {
|
|
@@ -38,10 +43,14 @@ export function createTask(photon, method, params) {
|
|
|
38
43
|
method,
|
|
39
44
|
params,
|
|
40
45
|
state: 'working',
|
|
46
|
+
statusMessage: 'The operation is now in progress.',
|
|
47
|
+
ttl: ttl ?? DEFAULT_TTL,
|
|
48
|
+
pollInterval: DEFAULT_POLL_INTERVAL,
|
|
41
49
|
createdAt: now,
|
|
42
50
|
updatedAt: now,
|
|
43
51
|
};
|
|
44
52
|
writeJSONSync(taskPath(task.id), task);
|
|
53
|
+
taskEvents.emit('stateChange', task.id, task.state, task);
|
|
45
54
|
return task;
|
|
46
55
|
}
|
|
47
56
|
export function getTask(id) {
|
|
@@ -60,8 +69,13 @@ export function updateTask(id, updates) {
|
|
|
60
69
|
const task = getTask(id);
|
|
61
70
|
if (!task)
|
|
62
71
|
return null;
|
|
72
|
+
const oldState = task.state;
|
|
63
73
|
Object.assign(task, updates, { updatedAt: new Date().toISOString() });
|
|
64
74
|
writeJSONSync(taskPath(id), task);
|
|
75
|
+
// Emit on any state transition
|
|
76
|
+
if (updates.state && updates.state !== oldState) {
|
|
77
|
+
taskEvents.emit('stateChange', id, task.state, task);
|
|
78
|
+
}
|
|
65
79
|
return task;
|
|
66
80
|
}
|
|
67
81
|
export function listTasks(photon) {
|
|
@@ -81,7 +95,11 @@ export function listTasks(photon) {
|
|
|
81
95
|
}
|
|
82
96
|
return tasks.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
83
97
|
}
|
|
84
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Clean expired tasks — removes terminal tasks past their TTL
|
|
100
|
+
* and also removes non-terminal tasks that have been alive longer than their TTL
|
|
101
|
+
*/
|
|
102
|
+
export function cleanExpiredTasks() {
|
|
85
103
|
ensureDir();
|
|
86
104
|
const files = readdirSync(TASKS_DIR).filter((f) => f.endsWith('.json'));
|
|
87
105
|
const now = Date.now();
|
|
@@ -89,11 +107,24 @@ export function cleanExpiredTasks(maxAgeMs) {
|
|
|
89
107
|
for (const file of files) {
|
|
90
108
|
try {
|
|
91
109
|
const task = readJSONSync(join(TASKS_DIR, file));
|
|
92
|
-
const age = now - new Date(task.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
const age = now - new Date(task.createdAt).getTime();
|
|
111
|
+
const ttl = task.ttl || DEFAULT_TTL;
|
|
112
|
+
if (age > ttl) {
|
|
113
|
+
// Terminal tasks: always clean
|
|
114
|
+
// Non-terminal tasks past TTL: force-cancel and clean
|
|
115
|
+
if (TERMINAL_STATES.includes(task.state)) {
|
|
116
|
+
unlinkSync(join(TASKS_DIR, file));
|
|
117
|
+
cleaned++;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Force-cancel stale non-terminal tasks
|
|
121
|
+
const controller = getController(task.id);
|
|
122
|
+
if (controller)
|
|
123
|
+
controller.abort();
|
|
124
|
+
unregisterController(task.id);
|
|
125
|
+
unlinkSync(join(TASKS_DIR, file));
|
|
126
|
+
cleaned++;
|
|
127
|
+
}
|
|
97
128
|
}
|
|
98
129
|
}
|
|
99
130
|
catch {
|
|
@@ -106,4 +137,14 @@ export function cleanExpiredTasks(maxAgeMs) {
|
|
|
106
137
|
export function _getTasksDir() {
|
|
107
138
|
return TASKS_DIR;
|
|
108
139
|
}
|
|
140
|
+
// Startup cleanup
|
|
141
|
+
try {
|
|
142
|
+
const cleaned = cleanExpiredTasks();
|
|
143
|
+
if (cleaned > 0) {
|
|
144
|
+
console.error(`🗑️ Cleaned ${cleaned} expired task(s)`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Best effort
|
|
149
|
+
}
|
|
109
150
|
//# sourceMappingURL=store.js.map
|
package/dist/tasks/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/types.d.ts
CHANGED
|
@@ -1,24 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Tasks Types
|
|
2
|
+
* MCP Tasks Types (spec v2025-11-25)
|
|
3
3
|
*
|
|
4
|
-
* Task state machine for async long-running operations
|
|
4
|
+
* Task state machine for async long-running operations.
|
|
5
5
|
* States: working → completed | failed | cancelled
|
|
6
6
|
* working → input_required → working (when resuming)
|
|
7
7
|
*/
|
|
8
8
|
export type TaskState = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled';
|
|
9
|
+
export declare const TERMINAL_STATES: readonly TaskState[];
|
|
10
|
+
export declare const DEFAULT_TTL: number;
|
|
11
|
+
export declare const DEFAULT_POLL_INTERVAL = 2000;
|
|
9
12
|
export interface Task {
|
|
10
13
|
id: string;
|
|
11
14
|
photon: string;
|
|
12
15
|
method: string;
|
|
13
16
|
params?: Record<string, unknown>;
|
|
14
17
|
state: TaskState;
|
|
18
|
+
statusMessage?: string;
|
|
19
|
+
ttl: number;
|
|
20
|
+
pollInterval: number;
|
|
15
21
|
progress?: {
|
|
16
22
|
percent: number;
|
|
17
23
|
message?: string;
|
|
18
24
|
};
|
|
19
25
|
result?: unknown;
|
|
20
26
|
error?: string;
|
|
27
|
+
input?: unknown;
|
|
21
28
|
createdAt: string;
|
|
22
29
|
updatedAt: string;
|
|
23
30
|
}
|
|
31
|
+
/** MCP wire format — field names match the spec exactly */
|
|
32
|
+
export interface TaskWire {
|
|
33
|
+
taskId: string;
|
|
34
|
+
status: TaskState;
|
|
35
|
+
statusMessage?: string;
|
|
36
|
+
createdAt: string;
|
|
37
|
+
lastUpdatedAt: string;
|
|
38
|
+
ttl: number;
|
|
39
|
+
pollInterval: number;
|
|
40
|
+
}
|
|
41
|
+
/** Convert internal Task to MCP wire format */
|
|
42
|
+
export declare function toWireFormat(task: Task): TaskWire;
|
|
43
|
+
/** The _meta field for task-related messages */
|
|
44
|
+
export declare function relatedTaskMeta(taskId: string): Record<string, unknown>;
|
|
24
45
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE5F,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE5F,eAAO,MAAM,eAAe,EAAE,SAAS,SAAS,EAAyC,CAAC;AAE1F,eAAO,MAAM,WAAW,QAA0B,CAAC;AACnD,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2DAA2D;AAC3D,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAUjD;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIvE"}
|
package/dist/tasks/types.js
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Tasks Types
|
|
2
|
+
* MCP Tasks Types (spec v2025-11-25)
|
|
3
3
|
*
|
|
4
|
-
* Task state machine for async long-running operations
|
|
4
|
+
* Task state machine for async long-running operations.
|
|
5
5
|
* States: working → completed | failed | cancelled
|
|
6
6
|
* working → input_required → working (when resuming)
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
8
|
+
export const TERMINAL_STATES = ['completed', 'failed', 'cancelled'];
|
|
9
|
+
export const DEFAULT_TTL = 7 * 24 * 60 * 60 * 1000; // 1 week
|
|
10
|
+
export const DEFAULT_POLL_INTERVAL = 2000; // 2 seconds
|
|
11
|
+
/** Convert internal Task to MCP wire format */
|
|
12
|
+
export function toWireFormat(task) {
|
|
13
|
+
return {
|
|
14
|
+
taskId: task.id,
|
|
15
|
+
status: task.state,
|
|
16
|
+
...(task.statusMessage && { statusMessage: task.statusMessage }),
|
|
17
|
+
createdAt: task.createdAt,
|
|
18
|
+
lastUpdatedAt: task.updatedAt,
|
|
19
|
+
ttl: task.ttl,
|
|
20
|
+
pollInterval: task.pollInterval,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** The _meta field for task-related messages */
|
|
24
|
+
export function relatedTaskMeta(taskId) {
|
|
25
|
+
return {
|
|
26
|
+
'io.modelcontextprotocol/related-task': { taskId },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
9
29
|
//# sourceMappingURL=types.js.map
|
package/dist/tasks/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,eAAe,GAAyB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AAE1F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,CAAC,YAAY;AA8BvD,+CAA+C;AAC/C,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,MAAM,EAAE,IAAI,CAAC,KAAK;QAClB,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;QAChE,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,SAAS;QAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO;QACL,sCAAsC,EAAE,EAAE,MAAM,EAAE;KACnD,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portel/photon",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "You focus on the business logic. We'll enable the rest. Build MCP servers and CLI tools in a single TypeScript file.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
16
|
"prepare": "git config core.hooksPath .githooks || true",
|
|
17
|
-
"build": "
|
|
17
|
+
"build": "eslint src/ --quiet && tsc && cp -r src/photons dist/ && chmod +x dist/cli.js && tsx scripts/build-beam.ts",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
19
|
"lint": "eslint src/",
|
|
20
20
|
"lint:fix": "eslint src/ --fix",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"watch:beam": "tsx scripts/build-beam.ts --watch",
|
|
27
27
|
"dev:beam": "npm run build && npm run build:beam && (trap 'kill 0' EXIT; tsc --watch --preserveWatchOutput & tsx scripts/build-beam.ts --watch & sleep 1 && tsx watch src/cli.ts beam)",
|
|
28
28
|
"prepublishOnly": "node -e \"const p=require('./package.json'); if(JSON.stringify(p.dependencies).includes('file:')) { console.error('ERROR: file: dependency found.'); process.exit(1); }\" && node -e \"const fs=require('fs'),path=require('path'); const p=require('./package.json'); for(const d of Object.keys(p.dependencies||{})){const t=path.join('node_modules',d); if(fs.lstatSync(t).isSymbolicLink()){console.error('ERROR: '+d+' is npm-linked. Run: npm unlink '+d+' && npm install '+d); process.exit(1);}}\" && npm run build && npm run build:beam",
|
|
29
|
-
"test": "
|
|
29
|
+
"test": "bash scripts/run-tests.sh",
|
|
30
|
+
"test:chain": "npm run test:all",
|
|
30
31
|
"test:all": "npm run build && npm run test:security && npm run test:schema && npm run test:marketplace && npm run test:loader && npm run test:server && npm run test:integration && npm run test:ui-resources && npm run test:client-adaptive && npm run test:zero-config && npm run test:mcp-config && npm run test:cli && npm run test:logger && npm run test:error-handler && npm run test:validation && npm run test:daemon-pubsub && npm run test:daemon-buffer && npm run test:instance-drift && npm run test:daemon-watcher && npm run test:ui-rendering && npm run test:photon-instance-manager && npm run test:viewport-aware-proxy && npm run test:viewport-manager && npm run test:pagination-integration && npm run test:pagination-performance && npm run test:pagination-phase5 && npm run test:pagination-phase5c && npm run test:pagination-phase5d && npm run test:phase6a && npm run test:phase6b && npm run test:phase6c && npm run test:phase6d && npm run test:promises && npm run test:readme",
|
|
31
32
|
"test:daemon-watcher": "npx tsx tests/daemon-watcher.test.ts",
|
|
32
33
|
"test:instance-drift": "npx tsx tests/instance-drift.test.ts",
|
|
@@ -111,7 +112,7 @@
|
|
|
111
112
|
"@modelcontextprotocol/ext-apps": "^1.0.1",
|
|
112
113
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
113
114
|
"@portel/cli": "^1.1.0",
|
|
114
|
-
"@portel/photon-core": "^2.17.
|
|
115
|
+
"@portel/photon-core": "^2.17.6",
|
|
115
116
|
"boxen": "^8.0.1",
|
|
116
117
|
"chalk": "^5.4.1",
|
|
117
118
|
"chart.js": "^4.5.1",
|