@portel/photon 1.18.0 → 1.20.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/routes/api-browse.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +16 -4
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +4 -4
- package/dist/auto-ui/beam/routes/api-config.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 +14 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +196 -77
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +17 -0
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts +1 -0
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +64 -16
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +12 -0
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam-form.bundle.js +49 -6
- package/dist/beam-form.bundle.js.map +2 -2
- package/dist/beam.bundle.js +2090 -512
- package/dist/beam.bundle.js.map +4 -4
- package/dist/capability-negotiator.d.ts +67 -0
- package/dist/capability-negotiator.d.ts.map +1 -0
- package/dist/capability-negotiator.js +104 -0
- package/dist/capability-negotiator.js.map +1 -0
- package/dist/channel-manager.d.ts +122 -0
- package/dist/channel-manager.d.ts.map +1 -0
- package/dist/channel-manager.js +266 -0
- package/dist/channel-manager.js.map +1 -0
- package/dist/claude-code-plugin.js +1 -1
- package/dist/cli/commands/beam.d.ts.map +1 -1
- package/dist/cli/commands/beam.js +8 -2
- package/dist/cli/commands/beam.js.map +1 -1
- package/dist/cli/commands/changelog.d.ts +9 -0
- package/dist/cli/commands/changelog.d.ts.map +1 -0
- package/dist/cli/commands/changelog.js +133 -0
- package/dist/cli/commands/changelog.js.map +1 -0
- package/dist/cli/commands/maker.d.ts.map +1 -1
- package/dist/cli/commands/maker.js +23 -2
- package/dist/cli/commands/maker.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +53 -0
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/package.d.ts.map +1 -1
- package/dist/cli/commands/package.js +43 -9
- package/dist/cli/commands/package.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +1 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/update.d.ts +3 -2
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +50 -43
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +16 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli-alias.js +1 -1
- package/dist/cli-alias.js.map +1 -1
- package/dist/context-store.d.ts +23 -33
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +147 -97
- package/dist/context-store.js.map +1 -1
- package/dist/context.d.ts +15 -10
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +37 -13
- package/dist/context.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +12 -0
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/server.js +34 -51
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/worker-manager.d.ts.map +1 -1
- package/dist/daemon/worker-manager.js +21 -7
- package/dist/daemon/worker-manager.js.map +1 -1
- package/dist/data-migration.d.ts +27 -0
- package/dist/data-migration.d.ts.map +1 -0
- package/dist/data-migration.js +307 -0
- package/dist/data-migration.js.map +1 -0
- package/dist/editor-support/docblock-tag-catalog.d.ts.map +1 -1
- package/dist/editor-support/docblock-tag-catalog.js +6 -0
- package/dist/editor-support/docblock-tag-catalog.js.map +1 -1
- package/dist/loader.d.ts +13 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +169 -22
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.d.ts +6 -0
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +185 -62
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/namespace-migration.d.ts +1 -0
- package/dist/namespace-migration.d.ts.map +1 -1
- package/dist/namespace-migration.js +86 -0
- package/dist/namespace-migration.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +47 -21
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts +1 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +6 -0
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/readme-syncer.d.ts.map +1 -1
- package/dist/readme-syncer.js +6 -1
- package/dist/readme-syncer.js.map +1 -1
- package/dist/resource-server.d.ts +105 -0
- package/dist/resource-server.d.ts.map +1 -0
- package/dist/resource-server.js +723 -0
- package/dist/resource-server.js.map +1 -0
- package/dist/serv/auth/jwt.d.ts +2 -0
- package/dist/serv/auth/jwt.d.ts.map +1 -1
- package/dist/serv/auth/jwt.js +11 -5
- package/dist/serv/auth/jwt.js.map +1 -1
- package/dist/serv/vault/token-vault.d.ts +2 -0
- package/dist/serv/vault/token-vault.d.ts.map +1 -1
- package/dist/serv/vault/token-vault.js +6 -0
- package/dist/serv/vault/token-vault.js.map +1 -1
- package/dist/server.d.ts +30 -119
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +252 -1122
- package/dist/server.js.map +1 -1
- package/dist/shared/audit.d.ts.map +1 -1
- package/dist/shared/audit.js +11 -4
- package/dist/shared/audit.js.map +1 -1
- package/dist/shared/security.d.ts +10 -0
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +27 -0
- package/dist/shared/security.js.map +1 -1
- package/dist/task-executor.d.ts +69 -0
- package/dist/task-executor.d.ts.map +1 -0
- package/dist/task-executor.js +182 -0
- package/dist/task-executor.js.map +1 -0
- package/dist/tasks/store.d.ts.map +1 -1
- package/dist/tasks/store.js +6 -2
- package/dist/tasks/store.js.map +1 -1
- package/dist/types/photon-instance.d.ts +50 -0
- package/dist/types/photon-instance.d.ts.map +1 -0
- package/dist/types/photon-instance.js +9 -0
- package/dist/types/photon-instance.js.map +1 -0
- package/dist/types/server-types.d.ts +61 -0
- package/dist/types/server-types.d.ts.map +1 -0
- package/dist/types/server-types.js +8 -0
- package/dist/types/server-types.js.map +1 -0
- package/dist/version-notify.d.ts +27 -0
- package/dist/version-notify.d.ts.map +1 -0
- package/dist/version-notify.js +142 -0
- package/dist/version-notify.js.map +1 -0
- package/package.json +3 -3
- package/dist/auto-ui/bridge/openai-shim.d.ts +0 -20
- package/dist/auto-ui/bridge/openai-shim.d.ts.map +0 -1
- package/dist/auto-ui/bridge/openai-shim.js +0 -231
- package/dist/auto-ui/bridge/openai-shim.js.map +0 -1
- package/dist/auto-ui/bridge/photon-app.d.ts +0 -162
- package/dist/auto-ui/bridge/photon-app.d.ts.map +0 -1
- package/dist/auto-ui/bridge/photon-app.js +0 -460
- package/dist/auto-ui/bridge/photon-app.js.map +0 -1
- package/dist/auto-ui/daemon-tools.d.ts +0 -45
- package/dist/auto-ui/daemon-tools.d.ts.map +0 -1
- package/dist/auto-ui/daemon-tools.js +0 -581
- package/dist/auto-ui/daemon-tools.js.map +0 -1
- package/dist/auto-ui/design-system/index.d.ts +0 -21
- package/dist/auto-ui/design-system/index.d.ts.map +0 -1
- package/dist/auto-ui/design-system/index.js +0 -27
- package/dist/auto-ui/design-system/index.js.map +0 -1
- package/dist/auto-ui/design-system/transaction-ui.d.ts +0 -70
- package/dist/auto-ui/design-system/transaction-ui.d.ts.map +0 -1
- package/dist/auto-ui/design-system/transaction-ui.js +0 -982
- package/dist/auto-ui/design-system/transaction-ui.js.map +0 -1
- package/dist/auto-ui/playground-server.d.ts +0 -7
- package/dist/auto-ui/playground-server.d.ts.map +0 -1
- package/dist/auto-ui/playground-server.js +0 -840
- package/dist/auto-ui/playground-server.js.map +0 -1
- package/dist/auto-ui/rendering/components.d.ts +0 -29
- package/dist/auto-ui/rendering/components.d.ts.map +0 -1
- package/dist/auto-ui/rendering/components.js +0 -1341
- package/dist/auto-ui/rendering/components.js.map +0 -1
- package/dist/auto-ui/rendering/field-analyzer.d.ts +0 -104
- package/dist/auto-ui/rendering/field-analyzer.d.ts.map +0 -1
- package/dist/auto-ui/rendering/field-analyzer.js +0 -447
- package/dist/auto-ui/rendering/field-analyzer.js.map +0 -1
- package/dist/auto-ui/rendering/field-renderers.d.ts +0 -64
- package/dist/auto-ui/rendering/field-renderers.d.ts.map +0 -1
- package/dist/auto-ui/rendering/field-renderers.js +0 -317
- package/dist/auto-ui/rendering/field-renderers.js.map +0 -1
- package/dist/auto-ui/rendering/index.d.ts +0 -28
- package/dist/auto-ui/rendering/index.d.ts.map +0 -1
- package/dist/auto-ui/rendering/index.js +0 -60
- package/dist/auto-ui/rendering/index.js.map +0 -1
- package/dist/auto-ui/rendering/layout-selector.d.ts +0 -60
- package/dist/auto-ui/rendering/layout-selector.d.ts.map +0 -1
- package/dist/auto-ui/rendering/layout-selector.js +0 -476
- package/dist/auto-ui/rendering/layout-selector.js.map +0 -1
- package/dist/markdown-utils.d.ts +0 -8
- package/dist/markdown-utils.d.ts.map +0 -1
- package/dist/markdown-utils.js +0 -64
- package/dist/markdown-utils.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -9
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -11
- package/dist/mcp-client.js.map +0 -1
- package/dist/mcp-elicitation.d.ts +0 -32
- package/dist/mcp-elicitation.d.ts.map +0 -1
- package/dist/mcp-elicitation.js +0 -26
- package/dist/mcp-elicitation.js.map +0 -1
- package/dist/photons/builder-compass.photon.d.ts +0 -167
- package/dist/photons/builder-compass.photon.d.ts.map +0 -1
- package/dist/photons/builder-compass.photon.js +0 -816
- package/dist/photons/builder-compass.photon.js.map +0 -1
- package/dist/photons/builder-compass.photon.ts +0 -1129
- package/dist/photons/docs/ui/docs.html +0 -441
- package/dist/photons/docs.photon.d.ts +0 -237
- package/dist/photons/docs.photon.d.ts.map +0 -1
- package/dist/photons/docs.photon.js +0 -483
- package/dist/photons/docs.photon.js.map +0 -1
- package/dist/photons/docs.photon.ts +0 -536
- package/dist/photons/slides.photon.d.ts +0 -212
- package/dist/photons/slides.photon.d.ts.map +0 -1
- package/dist/photons/slides.photon.js +0 -355
- package/dist/photons/slides.photon.js.map +0 -1
- package/dist/photons/slides.photon.ts +0 -370
- package/dist/photons/spreadsheet/ui/spreadsheet.html +0 -779
- package/dist/photons/spreadsheet.photon.d.ts +0 -554
- package/dist/photons/spreadsheet.photon.d.ts.map +0 -1
- package/dist/photons/spreadsheet.photon.js +0 -1050
- package/dist/photons/spreadsheet.photon.js.map +0 -1
- package/dist/photons/spreadsheet.photon.ts +0 -1239
- package/dist/photons/ui/builder-compass.html +0 -1199
- package/dist/photons/ui/builder-compass.photon.html +0 -380
- package/dist/security-scanner.d.ts +0 -52
- package/dist/security-scanner.d.ts.map +0 -1
- package/dist/security-scanner.js +0 -181
- package/dist/security-scanner.js.map +0 -1
- package/dist/shared/performance.d.ts +0 -65
- package/dist/shared/performance.d.ts.map +0 -1
- package/dist/shared/performance.js +0 -136
- package/dist/shared/performance.js.map +0 -1
package/dist/auto-ui/beam.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as path from 'path';
|
|
|
14
14
|
import * as os from 'os';
|
|
15
15
|
import { fileURLToPath } from 'url';
|
|
16
16
|
import { createHash } from 'crypto';
|
|
17
|
-
import { setSecurityHeaders, SimpleRateLimiter, escapeHtml } from '../shared/security.js';
|
|
17
|
+
import { setSecurityHeaders, SimpleRateLimiter, escapeHtml, getCorsOrigin, } from '../shared/security.js';
|
|
18
18
|
/**
|
|
19
19
|
* Check if shell integration has been installed (photon init cli).
|
|
20
20
|
* Cached at module load since it won't change during a Beam session.
|
|
@@ -100,7 +100,7 @@ import { ensurePhotonEditorDeclaration, writePhotonEditorDeclaration, } from '..
|
|
|
100
100
|
import { ensureDaemon } from '../daemon/manager.js';
|
|
101
101
|
import { SchemaExtractor } from '@portel/photon-core';
|
|
102
102
|
import { generateServerCard } from '../server-card.js';
|
|
103
|
-
import { handleStreamableHTTP, broadcastNotification, broadcastToBeam, } from './streamable-http-transport.js';
|
|
103
|
+
import { handleStreamableHTTP, broadcastNotification, broadcastToBeam, stopSessionCleanup, } from './streamable-http-transport.js';
|
|
104
104
|
import { getBundledPhotonPath, BEAM_BUNDLED_PHOTONS } from '../shared-utils.js';
|
|
105
105
|
// BUNDLED_PHOTONS and getBundledPhotonPath are imported from shared-utils.js
|
|
106
106
|
// Extracted modules (Phase 5)
|
|
@@ -116,14 +116,40 @@ import { configurePhotonViaMCP, reloadPhotonViaMCP, removePhotonViaMCP, updateMe
|
|
|
116
116
|
import { generateAgentCard } from '../a2a/card-generator.js';
|
|
117
117
|
// Delegate to extracted module
|
|
118
118
|
const getConfigFilePath = getConfigFilePathFromModule;
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
120
|
+
// BEAM CONTEXT — all module-level mutable state lives here
|
|
121
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
122
|
+
class BeamContext {
|
|
123
|
+
/** External MCP server metadata */
|
|
124
|
+
externalMCPs = [];
|
|
125
|
+
/** Transport-level clients for external MCPs */
|
|
126
|
+
externalMCPClients = new Map();
|
|
127
|
+
/** SDK Client instances for tool calls with structuredContent */
|
|
128
|
+
externalMCPSDKClients = new Map();
|
|
129
|
+
/**
|
|
130
|
+
* Notification subscriptions per photon.
|
|
131
|
+
* Key: photon name, Value: list of event types this photon cares about
|
|
132
|
+
* Example: { "chat": ["mentions", "direct-messages"], "tasks": ["deadline", "assigned-to-me"] }
|
|
133
|
+
*/
|
|
134
|
+
photonNotificationSubscriptions = new Map();
|
|
135
|
+
/**
|
|
136
|
+
* Track which state-changed channels we've already subscribed to,
|
|
137
|
+
* so dynamically discovered photons can be subscribed without duplicates.
|
|
138
|
+
*/
|
|
139
|
+
subscribedStateChannels = new Set();
|
|
140
|
+
/** Convenience accessor matching the shape expected by external-mcp module */
|
|
141
|
+
get externalMCPState() {
|
|
142
|
+
return {
|
|
143
|
+
externalMCPs: this.externalMCPs,
|
|
144
|
+
externalMCPClients: this.externalMCPClients,
|
|
145
|
+
externalMCPSDKClients: this.externalMCPSDKClients,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const ctx = new BeamContext();
|
|
123
150
|
// Delegates — external MCP management now in beam/external-mcp.ts
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const reconnectExternalMCP = (name) => reconnectExternalMCPFromModule(name, externalMCPState);
|
|
151
|
+
const loadExternalMCPs = (config) => loadExternalMCPsFromModule(config, ctx.externalMCPState);
|
|
152
|
+
const reconnectExternalMCP = (name) => reconnectExternalMCPFromModule(name, ctx.externalMCPState);
|
|
127
153
|
// Delegates to extracted config module
|
|
128
154
|
const migrateConfig = migrateConfigFromModule;
|
|
129
155
|
const loadConfig = loadConfigFromModule;
|
|
@@ -135,19 +161,8 @@ const extractClassMetadataFromSource = extractClassMetadataFromModule;
|
|
|
135
161
|
const applyMethodVisibility = applyMethodVisibilityFromModule;
|
|
136
162
|
const extractCspFromSource = extractCspFromModule;
|
|
137
163
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
138
|
-
// NOTIFICATION SUBSCRIPTIONS
|
|
164
|
+
// NOTIFICATION SUBSCRIPTIONS (state lives in ctx: BeamContext)
|
|
139
165
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
140
|
-
/**
|
|
141
|
-
* Map to store notification subscriptions per photon
|
|
142
|
-
* Key: photon name, Value: list of event types this photon cares about
|
|
143
|
-
* Example: { "chat": ["mentions", "direct-messages"], "tasks": ["deadline", "assigned-to-me"] }
|
|
144
|
-
*/
|
|
145
|
-
const photonNotificationSubscriptions = new Map();
|
|
146
|
-
/**
|
|
147
|
-
* Track which state-changed channels we've already subscribed to,
|
|
148
|
-
* so dynamically discovered photons can be subscribed without duplicates.
|
|
149
|
-
*/
|
|
150
|
-
const subscribedStateChannels = new Set();
|
|
151
166
|
/**
|
|
152
167
|
* Generate the service worker JS that validates the Beam backend
|
|
153
168
|
* on PWA launch and shows a diagnostic page if something is wrong.
|
|
@@ -460,6 +475,16 @@ const BOOT_PAGE = \`<!DOCTYPE html>
|
|
|
460
475
|
export async function startBeam(rawWorkingDir, port) {
|
|
461
476
|
const workingDir = path.resolve(rawWorkingDir);
|
|
462
477
|
const { PHOTON_VERSION } = await import('../version.js');
|
|
478
|
+
// Run startup migrations (fast no-op when already applied)
|
|
479
|
+
try {
|
|
480
|
+
const { runNamespaceMigration } = await import('../namespace-migration.js');
|
|
481
|
+
await runNamespaceMigration();
|
|
482
|
+
const { runDataMigration } = await import('../data-migration.js');
|
|
483
|
+
await runDataMigration();
|
|
484
|
+
}
|
|
485
|
+
catch {
|
|
486
|
+
// Non-critical
|
|
487
|
+
}
|
|
463
488
|
// StartupSequencer manages ordered output during startup
|
|
464
489
|
const startup = new StartupSequencer(PHOTON_VERSION, workingDir);
|
|
465
490
|
const isTTY = process.stderr.isTTY;
|
|
@@ -513,7 +538,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
513
538
|
}
|
|
514
539
|
// Build photon list with short names plus a numeric suffix for duplicates.
|
|
515
540
|
// Also track resolved paths from namespace scan.
|
|
516
|
-
const
|
|
541
|
+
const photonRouteMeta = new Map(); // displayName → route metadata
|
|
517
542
|
const userPhotonList = [];
|
|
518
543
|
const duplicateIndex = new Map();
|
|
519
544
|
for (const p of userPhotonListDetailed) {
|
|
@@ -522,7 +547,12 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
522
547
|
duplicateIndex.set(p.name, nextIndex);
|
|
523
548
|
const displayName = duplicateCount > 1 ? `${p.name} (${nextIndex})` : p.name;
|
|
524
549
|
userPhotonList.push(displayName);
|
|
525
|
-
|
|
550
|
+
photonRouteMeta.set(displayName, {
|
|
551
|
+
filePath: p.filePath,
|
|
552
|
+
shortName: p.name,
|
|
553
|
+
namespace: p.namespace || undefined,
|
|
554
|
+
qualifiedName: p.qualifiedName || undefined,
|
|
555
|
+
});
|
|
526
556
|
}
|
|
527
557
|
// Add bundled photons with their paths
|
|
528
558
|
const bundledPhotonPaths = new Map();
|
|
@@ -562,10 +592,11 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
562
592
|
// Helper: load a single photon, returning the info to push into photons[]
|
|
563
593
|
async function loadSinglePhoton(name) {
|
|
564
594
|
const photonPath = bundledPhotonPaths.get(name) ||
|
|
565
|
-
|
|
595
|
+
photonRouteMeta.get(name)?.filePath ||
|
|
566
596
|
(await resolvePhotonPath(name, workingDir));
|
|
567
597
|
if (!photonPath)
|
|
568
598
|
return null;
|
|
599
|
+
const routeMeta = photonRouteMeta.get(name);
|
|
569
600
|
// Apply saved config to environment before loading
|
|
570
601
|
if (savedConfig.photons[name]) {
|
|
571
602
|
for (const [key, value] of Object.entries(savedConfig.photons[name])) {
|
|
@@ -580,7 +611,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
580
611
|
let isInternal;
|
|
581
612
|
try {
|
|
582
613
|
source = await readText(photonPath);
|
|
583
|
-
await ensurePhotonEditorDeclaration(photonPath, source, workingDir).catch(() => {
|
|
614
|
+
await ensurePhotonEditorDeclaration(photonPath, source, workingDir).catch((e) => {
|
|
615
|
+
logger.debug(`Failed to ensure editor declaration for ${photonPath}: ${e?.message || e}`);
|
|
616
|
+
});
|
|
584
617
|
}
|
|
585
618
|
catch {
|
|
586
619
|
// Can't read source
|
|
@@ -662,11 +695,11 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
662
695
|
mcp.schemas = schemas;
|
|
663
696
|
// Store notification subscriptions per photon
|
|
664
697
|
if (metadata.notificationSubscriptions?.watchFor) {
|
|
665
|
-
photonNotificationSubscriptions.set(name, metadata.notificationSubscriptions.watchFor);
|
|
698
|
+
ctx.photonNotificationSubscriptions.set(name, metadata.notificationSubscriptions.watchFor);
|
|
666
699
|
}
|
|
667
700
|
else {
|
|
668
701
|
// Clear previous subscription if photon no longer has @notify-on
|
|
669
|
-
photonNotificationSubscriptions.delete(name);
|
|
702
|
+
ctx.photonNotificationSubscriptions.delete(name);
|
|
670
703
|
}
|
|
671
704
|
// Get UI assets for linking
|
|
672
705
|
const uiAssets = mcp.assets?.ui || [];
|
|
@@ -804,6 +837,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
804
837
|
return {
|
|
805
838
|
id: generatePhotonId(photonPath),
|
|
806
839
|
name,
|
|
840
|
+
...(routeMeta?.shortName ? { shortName: routeMeta.shortName } : {}),
|
|
841
|
+
...(routeMeta?.namespace ? { namespace: routeMeta.namespace } : {}),
|
|
842
|
+
...(routeMeta?.qualifiedName ? { qualifiedName: routeMeta.qualifiedName } : {}),
|
|
807
843
|
path: photonPath,
|
|
808
844
|
configured: true,
|
|
809
845
|
methods,
|
|
@@ -834,6 +870,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
834
870
|
return {
|
|
835
871
|
id: generatePhotonId(photonPath),
|
|
836
872
|
name,
|
|
873
|
+
...(routeMeta?.shortName ? { shortName: routeMeta.shortName } : {}),
|
|
874
|
+
...(routeMeta?.namespace ? { namespace: routeMeta.namespace } : {}),
|
|
875
|
+
...(routeMeta?.qualifiedName ? { qualifiedName: routeMeta.qualifiedName } : {}),
|
|
837
876
|
path: photonPath,
|
|
838
877
|
configured: false,
|
|
839
878
|
label: prettifyName(name),
|
|
@@ -859,6 +898,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
859
898
|
if (!photon || !photon.configured)
|
|
860
899
|
return null;
|
|
861
900
|
const photonDir = path.dirname(photon.path);
|
|
901
|
+
const photonBaseName = path.basename(photon.path, '.photon.ts');
|
|
862
902
|
const asset = photon.assets?.ui?.find((u) => u.id === uiId);
|
|
863
903
|
let uiPath;
|
|
864
904
|
if (asset?.resolvedPath) {
|
|
@@ -866,8 +906,8 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
866
906
|
}
|
|
867
907
|
else {
|
|
868
908
|
// Prefer .photon.html, then .photon.md, fall back to .html
|
|
869
|
-
const photonHtmlPath = path.join(photonDir,
|
|
870
|
-
const photonMdPath = path.join(photonDir,
|
|
909
|
+
const photonHtmlPath = path.join(photonDir, photonBaseName, 'ui', `${uiId}.photon.html`);
|
|
910
|
+
const photonMdPath = path.join(photonDir, photonBaseName, 'ui', `${uiId}.photon.md`);
|
|
871
911
|
try {
|
|
872
912
|
await fs.access(photonHtmlPath);
|
|
873
913
|
uiPath = photonHtmlPath;
|
|
@@ -878,7 +918,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
878
918
|
uiPath = photonMdPath;
|
|
879
919
|
}
|
|
880
920
|
catch {
|
|
881
|
-
uiPath = path.join(photonDir,
|
|
921
|
+
uiPath = path.join(photonDir, photonBaseName, 'ui', `${uiId}.html`);
|
|
882
922
|
}
|
|
883
923
|
}
|
|
884
924
|
}
|
|
@@ -894,7 +934,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
894
934
|
// Convention: format-<name> maps to assets/formats/<name>.html
|
|
895
935
|
if (uiId.startsWith('format-')) {
|
|
896
936
|
const formatName = uiId.slice('format-'.length);
|
|
897
|
-
const formatPath = path.join(photonDir,
|
|
937
|
+
const formatPath = path.join(photonDir, photonBaseName, 'assets', 'formats', `${formatName}.html`);
|
|
898
938
|
try {
|
|
899
939
|
const content = await readText(formatPath);
|
|
900
940
|
return { content, isPhotonTemplate: false };
|
|
@@ -931,9 +971,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
931
971
|
savedConfig,
|
|
932
972
|
photons,
|
|
933
973
|
photonMCPs,
|
|
934
|
-
externalMCPs,
|
|
935
|
-
externalMCPClients,
|
|
936
|
-
externalMCPSDKClients,
|
|
974
|
+
externalMCPs: ctx.externalMCPs,
|
|
975
|
+
externalMCPClients: ctx.externalMCPClients,
|
|
976
|
+
externalMCPSDKClients: ctx.externalMCPSDKClients,
|
|
937
977
|
channelSubscriptions: new Map(),
|
|
938
978
|
channelEventBuffers: new Map(),
|
|
939
979
|
sessionViewState: new Map(),
|
|
@@ -983,10 +1023,11 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
983
1023
|
baseUrl: `http://${req.headers.host}`,
|
|
984
1024
|
version: PHOTON_VERSION,
|
|
985
1025
|
});
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1026
|
+
const cardHeaders = { 'Content-Type': 'application/json' };
|
|
1027
|
+
const cardCorsOrigin = getCorsOrigin(req);
|
|
1028
|
+
if (cardCorsOrigin)
|
|
1029
|
+
cardHeaders['Access-Control-Allow-Origin'] = cardCorsOrigin;
|
|
1030
|
+
res.writeHead(200, cardHeaders);
|
|
990
1031
|
res.end(JSON.stringify(card));
|
|
991
1032
|
return;
|
|
992
1033
|
}
|
|
@@ -1037,9 +1078,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1037
1078
|
const handled = await handleStreamableHTTP(req, res, {
|
|
1038
1079
|
photons, // Pass all photons including unconfigured for configurationSchema
|
|
1039
1080
|
photonMCPs,
|
|
1040
|
-
externalMCPs,
|
|
1041
|
-
externalMCPClients,
|
|
1042
|
-
externalMCPSDKClients, // SDK clients for tool calls with structuredContent
|
|
1081
|
+
externalMCPs: ctx.externalMCPs,
|
|
1082
|
+
externalMCPClients: ctx.externalMCPClients,
|
|
1083
|
+
externalMCPSDKClients: ctx.externalMCPSDKClients, // SDK clients for tool calls with structuredContent
|
|
1043
1084
|
reconnectExternalMCP,
|
|
1044
1085
|
loadUIAsset,
|
|
1045
1086
|
workingDir,
|
|
@@ -1049,8 +1090,12 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1049
1090
|
reloadPhoton: async (photonName) => {
|
|
1050
1091
|
return reloadPhotonViaMCP(photonName, photons, photonMCPs, loader, savedConfig, broadcastPhotonChange, activeLoads, (name, path, isStateful) => {
|
|
1051
1092
|
if (isStateful) {
|
|
1052
|
-
subscribeStatefulPhoton(name).catch(() => {
|
|
1053
|
-
|
|
1093
|
+
subscribeStatefulPhoton(name).catch((e) => {
|
|
1094
|
+
logger.debug(`Failed to subscribe stateful photon ${name}: ${e?.message || e}`);
|
|
1095
|
+
});
|
|
1096
|
+
reloadDaemonPhoton(name, path, workingDir).catch((e) => {
|
|
1097
|
+
logger.debug(`Failed to reload daemon photon ${name}: ${e?.message || e}`);
|
|
1098
|
+
});
|
|
1054
1099
|
}
|
|
1055
1100
|
});
|
|
1056
1101
|
},
|
|
@@ -1474,9 +1519,27 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1474
1519
|
appEl.appendChild(iframe);
|
|
1475
1520
|
initBridge(iframe, bridgeMethod);
|
|
1476
1521
|
} catch (err) {
|
|
1477
|
-
appEl.innerHTML = '
|
|
1478
|
-
|
|
1479
|
-
|
|
1522
|
+
appEl.innerHTML = '';
|
|
1523
|
+
const statusDiv = document.createElement('div');
|
|
1524
|
+
statusDiv.className = 'status-page show';
|
|
1525
|
+
|
|
1526
|
+
const icon = document.createElement('div');
|
|
1527
|
+
icon.className = 'icon';
|
|
1528
|
+
icon.textContent = '⚠️';
|
|
1529
|
+
|
|
1530
|
+
const h2 = document.createElement('h2');
|
|
1531
|
+
h2.textContent = 'Failed to load';
|
|
1532
|
+
|
|
1533
|
+
const p = document.createElement('p');
|
|
1534
|
+
p.textContent = err.message;
|
|
1535
|
+
|
|
1536
|
+
const btn = document.createElement('button');
|
|
1537
|
+
btn.className = 'retry-btn';
|
|
1538
|
+
btn.textContent = 'Retry';
|
|
1539
|
+
btn.addEventListener('click', () => checkAndLoad());
|
|
1540
|
+
|
|
1541
|
+
statusDiv.append(icon, h2, p, btn);
|
|
1542
|
+
appEl.appendChild(statusDiv);
|
|
1480
1543
|
}
|
|
1481
1544
|
}
|
|
1482
1545
|
|
|
@@ -1851,14 +1914,35 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1851
1914
|
const relativePath = path.relative(workingDir, changedPath);
|
|
1852
1915
|
// React to .photon.ts file changes — both top-level and namespaced subdirectories.
|
|
1853
1916
|
// Top-level: foo.photon.ts → "foo"
|
|
1854
|
-
// Namespaced:
|
|
1917
|
+
// Namespaced: Arul-/git-box.photon.ts → "git-box" (short name only)
|
|
1855
1918
|
if (relativePath.endsWith('.photon.ts')) {
|
|
1856
|
-
|
|
1919
|
+
// For namespaced paths, look up by file path first to respect disambiguated
|
|
1920
|
+
// names like "chat (1)" / "chat (2)" assigned at startup
|
|
1921
|
+
let resolvedPath;
|
|
1922
|
+
try {
|
|
1923
|
+
resolvedPath = realpathSync(changedPath);
|
|
1924
|
+
}
|
|
1925
|
+
catch {
|
|
1926
|
+
resolvedPath = changedPath;
|
|
1927
|
+
}
|
|
1928
|
+
const byPath = photons.find((p) => {
|
|
1929
|
+
try {
|
|
1930
|
+
return realpathSync(p.path) === resolvedPath;
|
|
1931
|
+
}
|
|
1932
|
+
catch {
|
|
1933
|
+
return p.path === changedPath;
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
if (byPath)
|
|
1937
|
+
return byPath.name;
|
|
1938
|
+
// New photon — derive short name from filename
|
|
1939
|
+
const withoutExt = relativePath.slice(0, -'.photon.ts'.length);
|
|
1940
|
+
const slashIndex = withoutExt.lastIndexOf(path.sep);
|
|
1941
|
+
return slashIndex >= 0 ? withoutExt.slice(slashIndex + 1) : withoutExt;
|
|
1857
1942
|
}
|
|
1858
|
-
// Detect asset
|
|
1859
|
-
//
|
|
1860
|
-
//
|
|
1861
|
-
// photon asset directories are relevant here, identified by the loaded photons list.
|
|
1943
|
+
// Detect asset changes for local (non-symlinked) photons.
|
|
1944
|
+
// Runtime data now lives in .data/ (filtered above), so any remaining
|
|
1945
|
+
// file under {photonName}/ is a legitimate asset (ui/, etc.).
|
|
1862
1946
|
for (const p of photons) {
|
|
1863
1947
|
if (relativePath.startsWith(p.name + path.sep)) {
|
|
1864
1948
|
return p.name;
|
|
@@ -1886,9 +1970,37 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1886
1970
|
try {
|
|
1887
1971
|
const photonIndex = photons.findIndex((p) => p.name === photonName);
|
|
1888
1972
|
const isNewPhoton = photonIndex === -1;
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1973
|
+
let photonPath;
|
|
1974
|
+
if (!isNewPhoton) {
|
|
1975
|
+
photonPath = photons[photonIndex].path;
|
|
1976
|
+
}
|
|
1977
|
+
else {
|
|
1978
|
+
// Try flat path first, then search namespace subdirectories
|
|
1979
|
+
const flatPath = path.join(workingDir, `${photonName}.photon.ts`);
|
|
1980
|
+
if (existsSync(flatPath)) {
|
|
1981
|
+
photonPath = flatPath;
|
|
1982
|
+
}
|
|
1983
|
+
else {
|
|
1984
|
+
// Search namespace dirs (one level deep) for the photon file
|
|
1985
|
+
let found = null;
|
|
1986
|
+
try {
|
|
1987
|
+
const entries = await fs.readdir(workingDir, { withFileTypes: true });
|
|
1988
|
+
for (const entry of entries) {
|
|
1989
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
1990
|
+
continue;
|
|
1991
|
+
const candidate = path.join(workingDir, entry.name, `${photonName}.photon.ts`);
|
|
1992
|
+
if (existsSync(candidate)) {
|
|
1993
|
+
found = candidate;
|
|
1994
|
+
break;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
catch {
|
|
1999
|
+
// readdir failed
|
|
2000
|
+
}
|
|
2001
|
+
photonPath = found || flatPath;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
1892
2004
|
const previouslyConfigured = !isNewPhoton && photons[photonIndex]?.configured === true;
|
|
1893
2005
|
// Handle file deletion - if file no longer exists and photon is in list, remove it
|
|
1894
2006
|
if (!isNewPhoton && photonPath && !existsSync(photonPath)) {
|
|
@@ -1961,7 +2073,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
1961
2073
|
let constructorParams = [];
|
|
1962
2074
|
try {
|
|
1963
2075
|
const source = await readText(photonPath);
|
|
1964
|
-
await writePhotonEditorDeclaration(photonPath, source, workingDir).catch(() => {
|
|
2076
|
+
await writePhotonEditorDeclaration(photonPath, source, workingDir).catch((e) => {
|
|
2077
|
+
logger.debug(`Failed to write editor declaration for ${photonPath}: ${e?.message || e}`);
|
|
2078
|
+
});
|
|
1965
2079
|
const params = extractor.extractConstructorParams(source);
|
|
1966
2080
|
constructorParams = params
|
|
1967
2081
|
.filter((p) => p.isPrimitive)
|
|
@@ -2016,10 +2130,10 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2016
2130
|
mcp.schemas = schemas; // Store schemas for result rendering
|
|
2017
2131
|
// Update notification subscriptions for reloaded photon
|
|
2018
2132
|
if (reloadMetadata.notificationSubscriptions?.watchFor) {
|
|
2019
|
-
photonNotificationSubscriptions.set(photonName, reloadMetadata.notificationSubscriptions.watchFor);
|
|
2133
|
+
ctx.photonNotificationSubscriptions.set(photonName, reloadMetadata.notificationSubscriptions.watchFor);
|
|
2020
2134
|
}
|
|
2021
2135
|
else {
|
|
2022
|
-
photonNotificationSubscriptions.delete(photonName);
|
|
2136
|
+
ctx.photonNotificationSubscriptions.delete(photonName);
|
|
2023
2137
|
}
|
|
2024
2138
|
const lifecycleMethods = ['onInitialize', 'onShutdown', 'constructor'];
|
|
2025
2139
|
const uiAssets = mcp.assets?.ui || [];
|
|
@@ -2242,6 +2356,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2242
2356
|
const watcher = watch(workingDir, { recursive: true }, (eventType, filename) => {
|
|
2243
2357
|
if (!filename)
|
|
2244
2358
|
return;
|
|
2359
|
+
// Skip all runtime data — .data/ contains all photon data, never source code
|
|
2360
|
+
if (filename.startsWith('.data' + path.sep) || filename === '.data')
|
|
2361
|
+
return;
|
|
2245
2362
|
const fullPath = path.join(workingDir, filename);
|
|
2246
2363
|
logger.debug(`📂 File event: ${eventType} ${filename}`);
|
|
2247
2364
|
const photonName = getPhotonForPath(fullPath);
|
|
@@ -2375,7 +2492,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2375
2492
|
}
|
|
2376
2493
|
// Load external MCPs from config
|
|
2377
2494
|
const externalMCPList = await loadExternalMCPs(savedConfig);
|
|
2378
|
-
externalMCPs.push(...externalMCPList);
|
|
2495
|
+
ctx.externalMCPs.push(...externalMCPList);
|
|
2379
2496
|
// Mark startup complete — flushes queued output and restores console
|
|
2380
2497
|
startup.ready();
|
|
2381
2498
|
// Notify connected clients that photon list is now available
|
|
@@ -2386,9 +2503,9 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2386
2503
|
const instanceNames = ['default'];
|
|
2387
2504
|
for (const instanceName of instanceNames) {
|
|
2388
2505
|
const channel = `${photonName}:${instanceName}:state-changed`;
|
|
2389
|
-
if (subscribedStateChannels.has(channel))
|
|
2506
|
+
if (ctx.subscribedStateChannels.has(channel))
|
|
2390
2507
|
continue;
|
|
2391
|
-
subscribedStateChannels.add(channel);
|
|
2508
|
+
ctx.subscribedStateChannels.add(channel);
|
|
2392
2509
|
subscribeChannel(photonName, channel, (message) => {
|
|
2393
2510
|
// Sync Beam's local instance from the daemon-persisted state file BEFORE
|
|
2394
2511
|
// notifying the frontend. The daemon persists state to disk after mutations,
|
|
@@ -2479,7 +2596,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2479
2596
|
// Subscribe to notifications channel (always-on, not just active)
|
|
2480
2597
|
const notificationChannel = `${photonName}:${instanceName}:notifications`;
|
|
2481
2598
|
// Get this photon's notification subscriptions from @notify-on tags
|
|
2482
|
-
const watchFor = photonNotificationSubscriptions.get(photonName);
|
|
2599
|
+
const watchFor = ctx.photonNotificationSubscriptions.get(photonName);
|
|
2483
2600
|
subscribeChannel(photonName, notificationChannel, (message) => {
|
|
2484
2601
|
// Check if this photon cares about this notification type
|
|
2485
2602
|
if (!watchFor || !watchFor.includes(message?.type)) {
|
|
@@ -2666,14 +2783,14 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2666
2783
|
// Remove MCPs — do all synchronous Map mutations first, then close async
|
|
2667
2784
|
const removedSdkClients = [];
|
|
2668
2785
|
for (const name of removed) {
|
|
2669
|
-
const idx = externalMCPs.findIndex((m) => m.name === name);
|
|
2786
|
+
const idx = ctx.externalMCPs.findIndex((m) => m.name === name);
|
|
2670
2787
|
if (idx !== -1)
|
|
2671
|
-
externalMCPs.splice(idx, 1);
|
|
2672
|
-
const sdkClient = externalMCPSDKClients.get(name);
|
|
2788
|
+
ctx.externalMCPs.splice(idx, 1);
|
|
2789
|
+
const sdkClient = ctx.externalMCPSDKClients.get(name);
|
|
2673
2790
|
if (sdkClient)
|
|
2674
2791
|
removedSdkClients.push({ name, client: sdkClient });
|
|
2675
|
-
externalMCPSDKClients.delete(name);
|
|
2676
|
-
externalMCPClients.delete(name);
|
|
2792
|
+
ctx.externalMCPSDKClients.delete(name);
|
|
2793
|
+
ctx.externalMCPClients.delete(name);
|
|
2677
2794
|
logger.info(`🔌 Removed external MCP: ${name}`);
|
|
2678
2795
|
}
|
|
2679
2796
|
// Close SDK clients after all Maps are consistent
|
|
@@ -2692,7 +2809,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2692
2809
|
mcpServers: Object.fromEntries(added.map((k) => [k, newServers[k]])),
|
|
2693
2810
|
};
|
|
2694
2811
|
const newMCPs = await loadExternalMCPs(addConfig);
|
|
2695
|
-
externalMCPs.push(...newMCPs);
|
|
2812
|
+
ctx.externalMCPs.push(...newMCPs);
|
|
2696
2813
|
for (const m of newMCPs) {
|
|
2697
2814
|
logger.info(`🔌 Added external MCP: ${m.name} (${m.connected ? m.methods.length + ' tools' : 'failed'})`);
|
|
2698
2815
|
}
|
|
@@ -2700,14 +2817,14 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2700
2817
|
// Reconnect modified MCPs — synchronous cleanup first, then async reconnect
|
|
2701
2818
|
const modifiedSdkClients = [];
|
|
2702
2819
|
for (const name of modified) {
|
|
2703
|
-
const idx = externalMCPs.findIndex((m) => m.name === name);
|
|
2820
|
+
const idx = ctx.externalMCPs.findIndex((m) => m.name === name);
|
|
2704
2821
|
if (idx !== -1)
|
|
2705
|
-
externalMCPs.splice(idx, 1);
|
|
2706
|
-
const sdkClient = externalMCPSDKClients.get(name);
|
|
2822
|
+
ctx.externalMCPs.splice(idx, 1);
|
|
2823
|
+
const sdkClient = ctx.externalMCPSDKClients.get(name);
|
|
2707
2824
|
if (sdkClient)
|
|
2708
2825
|
modifiedSdkClients.push({ name, client: sdkClient });
|
|
2709
|
-
externalMCPSDKClients.delete(name);
|
|
2710
|
-
externalMCPClients.delete(name);
|
|
2826
|
+
ctx.externalMCPSDKClients.delete(name);
|
|
2827
|
+
ctx.externalMCPClients.delete(name);
|
|
2711
2828
|
}
|
|
2712
2829
|
// Close old SDK clients
|
|
2713
2830
|
for (const { client } of modifiedSdkClients) {
|
|
@@ -2725,7 +2842,7 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2725
2842
|
mcpServers: { [name]: newServers[name] },
|
|
2726
2843
|
};
|
|
2727
2844
|
const reconnected = await loadExternalMCPs(modConfig);
|
|
2728
|
-
externalMCPs.push(...reconnected);
|
|
2845
|
+
ctx.externalMCPs.push(...reconnected);
|
|
2729
2846
|
logger.info(`🔌 Reconnected external MCP: ${name}`);
|
|
2730
2847
|
}
|
|
2731
2848
|
// Update savedConfig
|
|
@@ -2753,9 +2870,11 @@ export async function startBeam(rawWorkingDir, port) {
|
|
|
2753
2870
|
* Closes all external MCP SDK clients to prevent ugly tracebacks on shutdown.
|
|
2754
2871
|
*/
|
|
2755
2872
|
export async function stopBeam() {
|
|
2873
|
+
// Stop session cleanup timer
|
|
2874
|
+
stopSessionCleanup();
|
|
2756
2875
|
// Close all SDK clients gracefully
|
|
2757
2876
|
const closePromises = [];
|
|
2758
|
-
for (const [, client] of externalMCPSDKClients) {
|
|
2877
|
+
for (const [, client] of ctx.externalMCPSDKClients) {
|
|
2759
2878
|
closePromises.push(client.close().catch(() => {
|
|
2760
2879
|
// Ignore close errors - process is exiting anyway
|
|
2761
2880
|
}));
|
|
@@ -2764,7 +2883,7 @@ export async function stopBeam() {
|
|
|
2764
2883
|
if (closePromises.length > 0) {
|
|
2765
2884
|
await withTimeout(Promise.all(closePromises), 1000, 'MCP client close timeout').catch(() => { }); // Timeout during shutdown is expected
|
|
2766
2885
|
}
|
|
2767
|
-
externalMCPSDKClients.clear();
|
|
2768
|
-
externalMCPClients.clear();
|
|
2886
|
+
ctx.externalMCPSDKClients.clear();
|
|
2887
|
+
ctx.externalMCPClients.clear();
|
|
2769
2888
|
}
|
|
2770
2889
|
//# sourceMappingURL=beam.js.map
|