@portel/photon 1.17.5 → 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.
Files changed (37) hide show
  1. package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
  2. package/dist/auto-ui/beam/photon-management.js +28 -1
  3. package/dist/auto-ui/beam/photon-management.js.map +1 -1
  4. package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
  5. package/dist/auto-ui/beam/routes/api-marketplace.js +10 -5
  6. package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
  7. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  8. package/dist/auto-ui/streamable-http-transport.js +259 -88
  9. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  10. package/dist/auto-ui/types.d.ts +2 -0
  11. package/dist/auto-ui/types.d.ts.map +1 -1
  12. package/dist/auto-ui/types.js +5 -0
  13. package/dist/auto-ui/types.js.map +1 -1
  14. package/dist/beam.bundle.js +226 -29
  15. package/dist/beam.bundle.js.map +2 -2
  16. package/dist/loader.d.ts.map +1 -1
  17. package/dist/loader.js +9 -8
  18. package/dist/loader.js.map +1 -1
  19. package/dist/photon-cli-runner.d.ts.map +1 -1
  20. package/dist/photon-cli-runner.js +11 -0
  21. package/dist/photon-cli-runner.js.map +1 -1
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +155 -1
  24. package/dist/server.js.map +1 -1
  25. package/dist/tasks/executor.d.ts +47 -0
  26. package/dist/tasks/executor.d.ts.map +1 -0
  27. package/dist/tasks/executor.js +180 -0
  28. package/dist/tasks/executor.js.map +1 -0
  29. package/dist/tasks/store.d.ts +13 -6
  30. package/dist/tasks/store.d.ts.map +1 -1
  31. package/dist/tasks/store.js +50 -9
  32. package/dist/tasks/store.js.map +1 -1
  33. package/dist/tasks/types.d.ts +23 -2
  34. package/dist/tasks/types.d.ts.map +1 -1
  35. package/dist/tasks/types.js +23 -3
  36. package/dist/tasks/types.js.map +1 -1
  37. 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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"}
@@ -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
- * Consistent with existing photon file-based patterns (audit, runs, state).
6
+ * EventEmitter for state change notifications.
7
7
  */
8
- import type { Task } from './types.js';
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>): Task;
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
- export declare function cleanExpiredTasks(maxAgeMs: number): number;
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,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAgBvC,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,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAcjG;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAS/C;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC,CAAC,GACtE,IAAI,GAAG,IAAI,CAMb;AAED,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAejD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAqB1D;AAED,qCAAqC;AACrC,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
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"}
@@ -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
- * Consistent with existing photon file-based patterns (audit, runs, state).
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
- export function cleanExpiredTasks(maxAgeMs) {
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.updatedAt).getTime();
93
- if (age > maxAgeMs &&
94
- (task.state === 'completed' || task.state === 'failed' || task.state === 'cancelled')) {
95
- unlinkSync(join(TASKS_DIR, file));
96
- cleaned++;
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
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tasks/store.ts"],"names":[],"mappings":"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"}
@@ -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 (MCP 2025-11-25 spec).
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"}
@@ -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 (MCP 2025-11-25 spec).
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
@@ -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.17.5",
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": "npm run lint -- --quiet && tsc && cp -r src/photons dist/ && chmod +x dist/cli.js && tsx scripts/build-beam.ts",
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": "npm run test:all",
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.4",
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",