@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/loader.js
CHANGED
|
@@ -36,7 +36,7 @@ executionContext,
|
|
|
36
36
|
// Lock helper
|
|
37
37
|
withLock as withLockHelper,
|
|
38
38
|
// Middleware system
|
|
39
|
-
builtinRegistry, MiddlewareRegistry, buildMiddlewareChain, } from '@portel/photon-core';
|
|
39
|
+
builtinRegistry, MiddlewareRegistry, buildMiddlewareChain, detectNamespace, getCacheDir, } from '@portel/photon-core';
|
|
40
40
|
import { getDefaultContext } from './context.js';
|
|
41
41
|
import * as os from 'os';
|
|
42
42
|
import { MarketplaceManager } from './marketplace-manager.js';
|
|
@@ -332,7 +332,7 @@ export class PhotonLoader {
|
|
|
332
332
|
* Directory where MCP-specific dependencies are cached
|
|
333
333
|
*/
|
|
334
334
|
getDependencyCacheDir(cacheKey) {
|
|
335
|
-
return path.join(
|
|
335
|
+
return path.join(getCacheDir(), 'dependencies', cacheKey);
|
|
336
336
|
}
|
|
337
337
|
getBuildCacheDir(cacheKey) {
|
|
338
338
|
return path.join(this.getDependencyCacheDir(cacheKey), '.build');
|
|
@@ -402,7 +402,11 @@ export class PhotonLoader {
|
|
|
402
402
|
? this.dependenciesEqual(metadata.dependencies, dependencies)
|
|
403
403
|
: false;
|
|
404
404
|
const resolvedCoreVersion = getResolvedPhotonCoreVersion();
|
|
405
|
-
|
|
405
|
+
// Compare versions tolerantly: "2.17.6" matches "^2.17.6" and vice versa
|
|
406
|
+
// This prevents unnecessary cache clears when createRequire fallback returns a range
|
|
407
|
+
const storedVersion = metadata?.photonCoreVersion || '';
|
|
408
|
+
const coreVersionChanged = storedVersion !== resolvedCoreVersion &&
|
|
409
|
+
storedVersion.replace(/^[\^~]/, '') !== resolvedCoreVersion.replace(/^[\^~]/, '');
|
|
406
410
|
// Only clear dependency cache when deps or core version actually changed.
|
|
407
411
|
// Source-only changes just need a build cache clear (recompile is fast).
|
|
408
412
|
const needsDepClear = Boolean(metadata && (!depsMatch || coreVersionChanged));
|
|
@@ -457,24 +461,39 @@ export class PhotonLoader {
|
|
|
457
461
|
const message = error instanceof Error ? error.message : String(error);
|
|
458
462
|
return (message.includes('Cannot find package') ||
|
|
459
463
|
message.includes('ERR_MODULE_NOT_FOUND') ||
|
|
460
|
-
message.includes('Cannot find module')
|
|
464
|
+
message.includes('Cannot find module') ||
|
|
465
|
+
message.includes('require is not defined'));
|
|
461
466
|
}
|
|
462
467
|
static parseDependenciesFromSource(source) {
|
|
463
468
|
const deps = [];
|
|
469
|
+
// Only match @dependencies inside JSDoc blocks (/** ... */)
|
|
470
|
+
const jsdocBlocks = source.match(/\/\*\*[\s\S]*?\*\//g) || [];
|
|
471
|
+
const jsdocText = jsdocBlocks.join('\n');
|
|
464
472
|
const regex = /@dependencies\s+([^\r\n]+)/g;
|
|
465
473
|
let match;
|
|
466
|
-
while ((match = regex.exec(
|
|
474
|
+
while ((match = regex.exec(jsdocText)) !== null) {
|
|
467
475
|
const entries = match[1]
|
|
476
|
+
.replace(/\*\/$/, '') // strip trailing */ if on same line
|
|
468
477
|
.split(',')
|
|
469
478
|
.map((entry) => entry.trim())
|
|
470
479
|
.filter(Boolean);
|
|
471
480
|
for (const entry of entries) {
|
|
472
481
|
const atIndex = entry.lastIndexOf('@');
|
|
482
|
+
let name;
|
|
483
|
+
let version;
|
|
473
484
|
if (atIndex <= 0) {
|
|
485
|
+
// No version specified (e.g., "sharp") — default to latest
|
|
486
|
+
name = entry.trim();
|
|
487
|
+
version = '*';
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
name = entry.slice(0, atIndex).trim();
|
|
491
|
+
version = entry.slice(atIndex + 1).trim();
|
|
492
|
+
}
|
|
493
|
+
// Validate: npm package names are lowercase, may have @scope/, no spaces
|
|
494
|
+
if (name.includes(' ') || !/^(@[a-z0-9-]+\/)?[a-z0-9._-]+$/.test(name)) {
|
|
474
495
|
continue;
|
|
475
496
|
}
|
|
476
|
-
const name = entry.slice(0, atIndex).trim();
|
|
477
|
-
let version = entry.slice(atIndex + 1).trim();
|
|
478
497
|
// Trailing ? marks the dependency as optional (e.g. sharp@^0.33.0?)
|
|
479
498
|
const optional = version.endsWith('?');
|
|
480
499
|
if (optional) {
|
|
@@ -609,8 +628,9 @@ export class PhotonLoader {
|
|
|
609
628
|
this.logger.warn(`⚠️ ${name} loaded with configuration warnings:`);
|
|
610
629
|
this.logger.warn(String(configError));
|
|
611
630
|
}
|
|
612
|
-
// Set photon name for event source identification
|
|
631
|
+
// Set photon name and namespace for event source identification and data paths
|
|
613
632
|
instance._photonName = name;
|
|
633
|
+
instance._photonNamespace = this.resolveNamespace(absolutePath);
|
|
614
634
|
// Inject instance name for named instances (runtime concept, not code)
|
|
615
635
|
instance.instanceName = options?.instanceName ?? '';
|
|
616
636
|
// Inject file path for storage()/assets() resolution
|
|
@@ -686,9 +706,17 @@ export class PhotonLoader {
|
|
|
686
706
|
timestamp: Date.now(),
|
|
687
707
|
source: name,
|
|
688
708
|
})
|
|
689
|
-
.catch(() => {
|
|
709
|
+
.catch((e) => {
|
|
710
|
+
this.logger.debug('Failed to publish broker event', {
|
|
711
|
+
error: e?.message || e,
|
|
712
|
+
});
|
|
713
|
+
});
|
|
690
714
|
})
|
|
691
|
-
.catch(() => {
|
|
715
|
+
.catch((e) => {
|
|
716
|
+
this.logger.debug('Failed to import photon-core for broker', {
|
|
717
|
+
error: e?.message || e,
|
|
718
|
+
});
|
|
719
|
+
});
|
|
692
720
|
}
|
|
693
721
|
};
|
|
694
722
|
// Also inject render() — convenience wrapper around emit
|
|
@@ -702,11 +730,12 @@ export class PhotonLoader {
|
|
|
702
730
|
};
|
|
703
731
|
}
|
|
704
732
|
if (caps.has('memory')) {
|
|
705
|
-
// Inject lazy memory provider
|
|
733
|
+
// Inject lazy memory provider — capture baseDir from loader context
|
|
734
|
+
const memoryBaseDir = this.baseDir;
|
|
706
735
|
Object.defineProperty(instance, 'memory', {
|
|
707
736
|
get() {
|
|
708
737
|
if (!this._memory) {
|
|
709
|
-
this._memory = new MemoryProvider(name, this._sessionId);
|
|
738
|
+
this._memory = new MemoryProvider(name, this._sessionId, this._photonNamespace, memoryBaseDir);
|
|
710
739
|
}
|
|
711
740
|
return this._memory;
|
|
712
741
|
},
|
|
@@ -904,6 +933,42 @@ export class PhotonLoader {
|
|
|
904
933
|
}
|
|
905
934
|
this.log(`🔌 Injected channel event infrastructure into ${name}`);
|
|
906
935
|
}
|
|
936
|
+
// Inject this.channel() for channel notifications — works for both Photon
|
|
937
|
+
// subclasses and plain classes. Emits on '{photonName}:channel-push' daemon
|
|
938
|
+
// channel which the MCP server intercepts and translates to the client's
|
|
939
|
+
// notification method (e.g. notifications/claude/channel).
|
|
940
|
+
//
|
|
941
|
+
// this.channel(content, meta) — send a message to the client
|
|
942
|
+
// this.channel.respond(id, behavior) — respond to permission requests
|
|
943
|
+
// this.channel.onPermission(handler) — register permission request handler
|
|
944
|
+
if (typeof instance.emit === 'function') {
|
|
945
|
+
const emitFn = instance.emit.bind(instance);
|
|
946
|
+
// Permission handler stored locally — wired by server after load
|
|
947
|
+
let permissionHandler;
|
|
948
|
+
const channelFn = Object.assign((content, meta) => {
|
|
949
|
+
emitFn({
|
|
950
|
+
channel: `${name}:channel-push`,
|
|
951
|
+
event: 'channel',
|
|
952
|
+
data: { content, meta },
|
|
953
|
+
});
|
|
954
|
+
}, {
|
|
955
|
+
respond: (requestId, behavior) => {
|
|
956
|
+
emitFn({
|
|
957
|
+
channel: `${name}:channel-permission-response`,
|
|
958
|
+
event: 'permission-response',
|
|
959
|
+
data: { request_id: requestId, behavior },
|
|
960
|
+
});
|
|
961
|
+
},
|
|
962
|
+
onPermission: (handler) => {
|
|
963
|
+
permissionHandler = handler;
|
|
964
|
+
},
|
|
965
|
+
// Internal: called by the server when a permission request arrives
|
|
966
|
+
_dispatchPermission: (request) => {
|
|
967
|
+
permissionHandler?.(request);
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
instance.channel = channelFn;
|
|
971
|
+
}
|
|
907
972
|
// Check @cli dependencies (required system CLI tools)
|
|
908
973
|
if (tsContent) {
|
|
909
974
|
await this.checkCLIDependencies(tsContent, name);
|
|
@@ -1037,6 +1102,7 @@ export class PhotonLoader {
|
|
|
1037
1102
|
instance._photonConfigError = configError;
|
|
1038
1103
|
}
|
|
1039
1104
|
instance._photonName = name;
|
|
1105
|
+
instance._photonNamespace = this.resolveNamespace(absolutePath);
|
|
1040
1106
|
instance.instanceName = options?.instanceName ?? '';
|
|
1041
1107
|
// Inject file path for storage()/assets() resolution.
|
|
1042
1108
|
// For preloaded modules (compiled binaries), remap to ~/.photon/ so storage()
|
|
@@ -1100,9 +1166,15 @@ export class PhotonLoader {
|
|
|
1100
1166
|
timestamp: Date.now(),
|
|
1101
1167
|
source: name,
|
|
1102
1168
|
})
|
|
1103
|
-
.catch(() => {
|
|
1169
|
+
.catch((e) => {
|
|
1170
|
+
this.logger.debug('Failed to publish broker event', { error: e?.message || e });
|
|
1171
|
+
});
|
|
1104
1172
|
})
|
|
1105
|
-
.catch(() => {
|
|
1173
|
+
.catch((e) => {
|
|
1174
|
+
this.logger.debug('Failed to import photon-core for broker', {
|
|
1175
|
+
error: e?.message || e,
|
|
1176
|
+
});
|
|
1177
|
+
});
|
|
1106
1178
|
}
|
|
1107
1179
|
};
|
|
1108
1180
|
// Also inject render() — convenience wrapper around emit
|
|
@@ -1116,10 +1188,11 @@ export class PhotonLoader {
|
|
|
1116
1188
|
};
|
|
1117
1189
|
}
|
|
1118
1190
|
if (caps.has('memory')) {
|
|
1191
|
+
const memoryBaseDir = this.baseDir;
|
|
1119
1192
|
Object.defineProperty(instance, 'memory', {
|
|
1120
1193
|
get() {
|
|
1121
1194
|
if (!this._memory) {
|
|
1122
|
-
this._memory = new MemoryProvider(name, this._sessionId);
|
|
1195
|
+
this._memory = new MemoryProvider(name, this._sessionId, this._photonNamespace, memoryBaseDir);
|
|
1123
1196
|
}
|
|
1124
1197
|
return this._memory;
|
|
1125
1198
|
},
|
|
@@ -1945,7 +2018,7 @@ export class PhotonLoader {
|
|
|
1945
2018
|
}
|
|
1946
2019
|
// If configured but failed, provide more specific error
|
|
1947
2020
|
throw new Error(`MCP "${dep.name}" is configured but failed to connect: ${errorMsg}\n` +
|
|
1948
|
-
`Check your
|
|
2021
|
+
`Check your config.json configuration and ensure:\n` +
|
|
1949
2022
|
` • The command/URL is correct\n` +
|
|
1950
2023
|
` • Required environment variables are set\n` +
|
|
1951
2024
|
` • The MCP server is accessible`);
|
|
@@ -1984,6 +2057,7 @@ export class PhotonLoader {
|
|
|
1984
2057
|
}
|
|
1985
2058
|
// Resolve the Photon path
|
|
1986
2059
|
const resolvedPath = await this.resolvePhotonPath(dep, currentPhotonPath);
|
|
2060
|
+
await this.materializeSiblingDependencySymlink(dep, currentPhotonPath, resolvedPath);
|
|
1987
2061
|
// Cache key includes instance name to allow multiple instances of the same photon
|
|
1988
2062
|
const cacheKey = dep.instanceName ? `${resolvedPath}::${dep.instanceName}` : resolvedPath;
|
|
1989
2063
|
// Check cache
|
|
@@ -2047,14 +2121,15 @@ export class PhotonLoader {
|
|
|
2047
2121
|
* Resolve Photon dependency path based on source type
|
|
2048
2122
|
*/
|
|
2049
2123
|
async resolvePhotonPath(dep, currentPhotonPath) {
|
|
2124
|
+
const resolvedCurrentPhotonPath = await this.resolveRealPhotonPath(currentPhotonPath);
|
|
2050
2125
|
switch (dep.sourceType) {
|
|
2051
2126
|
case 'local':
|
|
2052
2127
|
if (dep.source.startsWith('./') || dep.source.startsWith('../')) {
|
|
2053
|
-
return path.resolve(path.dirname(
|
|
2128
|
+
return path.resolve(path.dirname(resolvedCurrentPhotonPath), dep.source);
|
|
2054
2129
|
}
|
|
2055
2130
|
return dep.source;
|
|
2056
2131
|
case 'marketplace':
|
|
2057
|
-
return await this.resolveMarketplacePhoton(dep,
|
|
2132
|
+
return await this.resolveMarketplacePhoton(dep, resolvedCurrentPhotonPath);
|
|
2058
2133
|
case 'github':
|
|
2059
2134
|
return await this.fetchGithubPhoton(dep);
|
|
2060
2135
|
case 'npm':
|
|
@@ -2136,6 +2211,48 @@ export class PhotonLoader {
|
|
|
2136
2211
|
throw new Error(`Photon "${dep.source}" not found in local paths or configured marketplaces. ` +
|
|
2137
2212
|
`Checked: ${candidates.join(', ')}`);
|
|
2138
2213
|
}
|
|
2214
|
+
async resolveRealPhotonPath(currentPhotonPath) {
|
|
2215
|
+
try {
|
|
2216
|
+
return await fs.realpath(currentPhotonPath);
|
|
2217
|
+
}
|
|
2218
|
+
catch {
|
|
2219
|
+
return currentPhotonPath;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
async materializeSiblingDependencySymlink(dep, currentPhotonPath, resolvedPath) {
|
|
2223
|
+
if (dep.sourceType !== 'marketplace')
|
|
2224
|
+
return;
|
|
2225
|
+
if (dep.source.includes(':'))
|
|
2226
|
+
return;
|
|
2227
|
+
if (dep.source.includes('/'))
|
|
2228
|
+
return;
|
|
2229
|
+
const realCurrentPhotonPath = await this.resolveRealPhotonPath(currentPhotonPath);
|
|
2230
|
+
if (realCurrentPhotonPath === currentPhotonPath)
|
|
2231
|
+
return;
|
|
2232
|
+
if (path.dirname(realCurrentPhotonPath) !== path.dirname(resolvedPath))
|
|
2233
|
+
return;
|
|
2234
|
+
const linkPath = path.join(this.baseDir, path.basename(resolvedPath));
|
|
2235
|
+
await this.createSymlinkIfMissing(resolvedPath, linkPath);
|
|
2236
|
+
const depName = path.basename(resolvedPath).replace(/\.photon\.(ts|js)$/, '');
|
|
2237
|
+
const sourceAssetDir = path.join(path.dirname(resolvedPath), depName);
|
|
2238
|
+
const targetAssetDir = path.join(this.baseDir, depName);
|
|
2239
|
+
if (existsSync(sourceAssetDir)) {
|
|
2240
|
+
await this.createSymlinkIfMissing(sourceAssetDir, targetAssetDir, 'dir');
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
async createSymlinkIfMissing(sourcePath, targetPath, type) {
|
|
2244
|
+
try {
|
|
2245
|
+
const existing = await fs.lstat(targetPath).catch(() => null);
|
|
2246
|
+
if (existing)
|
|
2247
|
+
return;
|
|
2248
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
2249
|
+
symlinkSync(sourcePath, targetPath, type);
|
|
2250
|
+
this.log(`🔗 Materialized sibling photon symlink: ${path.basename(targetPath)}`);
|
|
2251
|
+
}
|
|
2252
|
+
catch (error) {
|
|
2253
|
+
this.log(`⚠️ Failed to materialize sibling symlink ${path.basename(targetPath)}: ${getErrorMessage(error)}`);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2139
2256
|
normalizeMarketplaceSource(source) {
|
|
2140
2257
|
let slugSource = source;
|
|
2141
2258
|
let marketplaceHint;
|
|
@@ -2642,9 +2759,9 @@ Run: photon mcp ${mcpName} --config
|
|
|
2642
2759
|
if (process.env.PHOTON_DEBUG_EMIT === '1') {
|
|
2643
2760
|
console.error(`[EMIT-DEBUG] Sending event: method=${eventPayload.method}, channel=${eventData.channel}, hasMeta=${!!result?.__meta}`);
|
|
2644
2761
|
}
|
|
2645
|
-
// Cast to
|
|
2646
|
-
void Promise.resolve(options.outputHandler(eventData)).catch(() => {
|
|
2647
|
-
|
|
2762
|
+
// Cast to DaemonEventEnvelope - outputHandler is flexible and routes any object with channel property
|
|
2763
|
+
void Promise.resolve(options.outputHandler(eventData)).catch((e) => {
|
|
2764
|
+
this.logger.debug('Output handler failed for event', { error: e?.message || e });
|
|
2648
2765
|
});
|
|
2649
2766
|
if (process.env.PHOTON_DEBUG_EMIT === '1') {
|
|
2650
2767
|
console.error(`[EMIT-DEBUG] Event transmitted to outputHandler`);
|
|
@@ -2990,12 +3107,19 @@ Run: photon mcp ${mcpName} --config
|
|
|
2990
3107
|
return; // No emit function, can't wrap methods
|
|
2991
3108
|
}
|
|
2992
3109
|
// Get all public method names from the instance
|
|
3110
|
+
// Skip runtime-injected methods (emit, render, push, ask) — these are
|
|
3111
|
+
// capability methods injected by the loader, not user-defined tools
|
|
3112
|
+
const RUNTIME_METHODS = new Set(['emit', 'render', 'channel', 'ask', 'call']);
|
|
2993
3113
|
const proto = Object.getPrototypeOf(instance);
|
|
2994
3114
|
const methodNames = Object.getOwnPropertyNames(proto).filter((name) => {
|
|
2995
3115
|
// Skip constructor and private/protected methods
|
|
2996
3116
|
if (name === 'constructor' || name.startsWith('_')) {
|
|
2997
3117
|
return false;
|
|
2998
3118
|
}
|
|
3119
|
+
// Skip runtime-injected capability methods
|
|
3120
|
+
if (RUNTIME_METHODS.has(name)) {
|
|
3121
|
+
return false;
|
|
3122
|
+
}
|
|
2999
3123
|
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
|
|
3000
3124
|
return descriptor && typeof descriptor.value === 'function';
|
|
3001
3125
|
});
|
|
@@ -3016,7 +3140,11 @@ Run: photon mcp ${mcpName} --config
|
|
|
3016
3140
|
// Call the original method
|
|
3017
3141
|
const result = original.apply(this, args);
|
|
3018
3142
|
// Attach __meta to returned objects for audit trail
|
|
3019
|
-
|
|
3143
|
+
const resultObj = result;
|
|
3144
|
+
if (resultObj &&
|
|
3145
|
+
typeof resultObj === 'object' &&
|
|
3146
|
+
!Array.isArray(resultObj) &&
|
|
3147
|
+
!resultObj.__meta) {
|
|
3020
3148
|
const timestamp = new Date().toISOString();
|
|
3021
3149
|
Object.defineProperty(result, '__meta', {
|
|
3022
3150
|
value: {
|
|
@@ -3211,6 +3339,25 @@ Run: photon mcp ${mcpName} --config
|
|
|
3211
3339
|
check.on('error', () => resolve(false));
|
|
3212
3340
|
});
|
|
3213
3341
|
}
|
|
3342
|
+
/**
|
|
3343
|
+
* Resolve the namespace for a photon based on its file path.
|
|
3344
|
+
* Extracts the directory name between baseDir and the photon file.
|
|
3345
|
+
*
|
|
3346
|
+
* Examples:
|
|
3347
|
+
* ~/.photon/portel-dev/todo.photon.ts → 'portel-dev'
|
|
3348
|
+
* ~/.photon/acme/todo.photon.ts → 'acme'
|
|
3349
|
+
* ~/.photon/todo.photon.ts → detected from git or 'local'
|
|
3350
|
+
*/
|
|
3351
|
+
resolveNamespace(absolutePath) {
|
|
3352
|
+
const rel = path.relative(this.baseDir, absolutePath);
|
|
3353
|
+
const parts = rel.split(path.sep);
|
|
3354
|
+
// If file is in a subdirectory (namespace/photon.ts), use that as namespace
|
|
3355
|
+
if (parts.length >= 2) {
|
|
3356
|
+
return parts[0];
|
|
3357
|
+
}
|
|
3358
|
+
// Flat file at root — detect from git remote or default to 'local'
|
|
3359
|
+
return detectNamespace(this.baseDir);
|
|
3360
|
+
}
|
|
3214
3361
|
/**
|
|
3215
3362
|
* Discover and extract assets from a Photon file
|
|
3216
3363
|
* Uses shared discoverAssets from photon-core for core logic,
|