@portel/photon 1.33.1 → 1.33.3

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 (41) hide show
  1. package/README.md +74 -19
  2. package/dist/auto-ui/frontend/pure-view.html +5 -2
  3. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  4. package/dist/auto-ui/streamable-http-transport.js +62 -11
  5. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  6. package/dist/beam.bundle.js +19 -17
  7. package/dist/beam.bundle.js.map +2 -2
  8. package/dist/capability-negotiator.d.ts +11 -0
  9. package/dist/capability-negotiator.d.ts.map +1 -1
  10. package/dist/capability-negotiator.js +20 -0
  11. package/dist/capability-negotiator.js.map +1 -1
  12. package/dist/cli/commands/maker.d.ts.map +1 -1
  13. package/dist/cli/commands/maker.js +159 -27
  14. package/dist/cli/commands/maker.js.map +1 -1
  15. package/dist/daemon/worker-dep-proxy.d.ts +17 -0
  16. package/dist/daemon/worker-dep-proxy.d.ts.map +1 -0
  17. package/dist/daemon/worker-dep-proxy.js +92 -0
  18. package/dist/daemon/worker-dep-proxy.js.map +1 -0
  19. package/dist/daemon/worker-host.js +8 -28
  20. package/dist/daemon/worker-host.js.map +1 -1
  21. package/dist/deploy/cloudflare.d.ts.map +1 -1
  22. package/dist/deploy/cloudflare.js +15 -0
  23. package/dist/deploy/cloudflare.js.map +1 -1
  24. package/dist/photon-doc-extractor.d.ts +10 -0
  25. package/dist/photon-doc-extractor.d.ts.map +1 -1
  26. package/dist/photon-doc-extractor.js +26 -2
  27. package/dist/photon-doc-extractor.js.map +1 -1
  28. package/dist/resource-server.d.ts +15 -0
  29. package/dist/resource-server.d.ts.map +1 -1
  30. package/dist/resource-server.js +86 -5
  31. package/dist/resource-server.js.map +1 -1
  32. package/dist/server.d.ts.map +1 -1
  33. package/dist/server.js +20 -10
  34. package/dist/server.js.map +1 -1
  35. package/dist/template-manager.js +14 -14
  36. package/dist/version.d.ts +7 -0
  37. package/dist/version.d.ts.map +1 -1
  38. package/dist/version.js +8 -1
  39. package/dist/version.js.map +1 -1
  40. package/package.json +1 -1
  41. package/templates/cloudflare/worker.ts.template +26 -8
package/README.md CHANGED
@@ -12,16 +12,54 @@
12
12
 
13
13
  ### Define intent once. Deliver everywhere.
14
14
 
15
- Photon turns a single TypeScript file into:
15
+ Define the capability once. Photon turns it into the interfaces people now
16
+ expect around AI tools:
16
17
 
17
- - **MCP server** for AI agents
18
- - **CLI tool** for automation
19
- - **Web interface** for humans
18
+ - **MCP server** for Claude, ChatGPT, Cursor, and agents
19
+ - **Embedded app UI** for chat clients that support MCP app resources
20
+ - **CLI tool** for scripts, demos, and automation
21
+ - **Beam web interface** for humans
20
22
 
21
23
  Photon is free and open source software released under the [MIT license](./LICENSE).
22
24
 
23
25
  *Interfaces are optional. Intent is mandatory.*
24
26
 
27
+ ```bash
28
+ gh repo star portel-dev/photon
29
+ ```
30
+
31
+ ---
32
+
33
+ ## From one method to every surface
34
+
35
+ The weather example is intentionally small: one TypeScript method, a few
36
+ docblock tags, and one `@ui` HTML asset. Photon turns that into a CLI command,
37
+ Beam UI, MCP tool, and embedded app surface for MCP app-capable chat clients.
38
+ Claude Desktop can run it from a local stdio MCP command; ChatGPT developer
39
+ mode can connect to the same Photon over a public HTTPS `/mcp` endpoint.
40
+
41
+ <div align="center">
42
+ <img src="https://raw.githubusercontent.com/portel-dev/photon/main/assets/showcase/weather/photon-surface-map.svg" alt="Infographic showing one Photon method becoming CLI, Beam, MCP, Claude Desktop, ChatGPT, and other agent surfaces" width="100%">
43
+ </div>
44
+
45
+ Real clients, same Photon:
46
+
47
+ <div align="center">
48
+ <img src="https://raw.githubusercontent.com/portel-dev/photon/main/assets/showcase/weather/chatgpt-photon-weather-local-dot.png" alt="Real ChatGPT developer-mode session rendering the Photon weather app from a public HTTPS MCP endpoint" width="100%">
49
+ <p><sub>ChatGPT developer mode rendering the Photon weather UI from a public HTTPS <code>/mcp</code> endpoint.</sub></p>
50
+ </div>
51
+
52
+ <div align="center">
53
+ <img src="https://raw.githubusercontent.com/portel-dev/photon/main/assets/showcase/weather/claude-weather-real.png" alt="Real Claude Desktop session rendering the Photon weather app through local MCP" width="100%">
54
+ <p><sub>Claude Desktop rendering the same Photon through local MCP.</sub></p>
55
+ </div>
56
+
57
+ [Follow the step-by-step tutorial](./docs/tutorials/from-method-to-chat-app.md)
58
+ or open the runnable example in
59
+ [`examples/weather-showcase`](./examples/weather-showcase).
60
+ The tutorial also includes Beam, CLI, and a concept animation that explains the
61
+ transformation without pretending to be proof.
62
+
25
63
  ---
26
64
 
27
65
  ## One definition. Multiple interfaces.
@@ -32,6 +70,26 @@ Photon is free and open source software released under the [MIT license](./LICEN
32
70
 
33
71
  ---
34
72
 
73
+ ## The Promise
74
+
75
+ Photon is the modern dev stack for the agentic age: each photon is a small,
76
+ auditable brick that can be used by humans, agents, schedulers, webhooks, and
77
+ apps without rewriting the same capability for every interface.
78
+
79
+ | Define once | Photon derives |
80
+ |---|---|
81
+ | TypeScript method | MCP tool, CLI command, Beam action |
82
+ | JSDoc intent | AI descriptions, human docs, form labels |
83
+ | Types and tags | Validation, output formats, safety hints |
84
+ | `@ui`, `@get`, `@post` | Embedded apps and web routes |
85
+ | `@scheduled`, `@webhook`, `@locked` | Automation, integration, coordination |
86
+ | `@auth`, scopes, JWT | Agent-safe deployed access |
87
+
88
+ That is the core idea: **tiny trusted capabilities compose into larger
89
+ systems**.
90
+
91
+ ---
92
+
35
93
  ### Example
36
94
 
37
95
  ```typescript
@@ -98,16 +156,6 @@ pnpm dlx @portel/photon mcp install my-tool
98
156
  >
99
157
  > **Where do photon files live?** `./` (a project directory you cd into) or `~/.photon/` (global, auto-discovered). User settings persist under `~/.photon/state/<photon>/`. See [Where things live](docs/getting-started.md#where-things-live).
100
158
 
101
- <div align="center">
102
-
103
- <a href="https://www.youtube.com/watch?v=FI0M8s6ZKv4">
104
- <img src="https://img.youtube.com/vi/FI0M8s6ZKv4/maxresdefault.jpg" alt="Watch: Why Photon? (2 min)" width="100%">
105
- </a>
106
-
107
- </div>
108
-
109
- ---
110
-
111
159
  ### How It Works
112
160
 
113
161
  You write a TypeScript class. Methods are your capabilities. Types describe what's valid. Comments explain the intent. Photon reads all of it and generates three interfaces from one file. Same logic. Same validation. Same data.
@@ -423,15 +471,17 @@ Full reference: [`docs/reference/CLAIM-CODES.md`](docs/reference/CLAIM-CODES.md)
423
471
 
424
472
  ## Marketplace
425
473
 
426
- 32 photons ready to install: databases, APIs, developer tools, and more.
474
+ A curated set of photons is ready to install. The public gallery is now kept
475
+ small on purpose: polished apps and tools in one place, teaching examples in
476
+ another.
427
477
 
428
478
  <div align="center">
429
479
  <img src="https://raw.githubusercontent.com/portel-dev/photon/main/assets/beam-marketplace.png" alt="Marketplace" width="100%">
430
480
  </div>
431
481
 
432
482
  ```bash
433
- photon search postgres
434
- photon add postgres
483
+ photon search boards
484
+ photon add boards
435
485
  ```
436
486
 
437
487
  You can also install directly from any GitHub repository using qualified refs:
@@ -440,7 +490,11 @@ You can also install directly from any GitHub repository using qualified refs:
440
490
  photon add owner/repo/photon-name
441
491
  ```
442
492
 
443
- Browse the full catalog in the [official photons repository](https://github.com/portel-dev/photons). You can also host a private marketplace for your team: internal tools that stay off the public internet.
493
+ Browse the [Photon Apps marketplace](https://github.com/portel-dev/photons)
494
+ for ready-to-use photons, or the
495
+ [Photon Examples marketplace](https://github.com/portel-dev/photon-examples)
496
+ for focused learning examples. You can also host a private marketplace for your
497
+ team: internal tools that stay off the public internet.
444
498
 
445
499
  ---
446
500
 
@@ -575,6 +629,7 @@ Uses Bun's compiler under the hood. The binary bundles the photon, its `@depende
575
629
  | Guide | |
576
630
  |---|---|
577
631
  | [Getting Started](./docs/getting-started.md) | Install, build, and run your first photon in 5 minutes |
632
+ | [From Method to Chat App](./docs/tutorials/from-method-to-chat-app.md) | Weather showcase: CLI, Beam, MCP, and embedded app UI from one method |
578
633
  | [Core Concepts](./docs/concepts.md) | The 6 ideas behind Photon |
579
634
  | [Tag Reference](./docs/reference/DOCBLOCK-TAGS.md) | Public reference for every docblock tag Photon understands |
580
635
  | [Output Formats](./docs/formats.md) | Visual gallery of every `@format` type |
@@ -617,6 +672,6 @@ Photon is free and open source under the [MIT license](./LICENSE).
617
672
 
618
673
  The project is still evolving and contributions are welcome.
619
674
 
620
- - Star the repository if the idea resonates
675
+ - Star the repository if the idea resonates: `gh repo star portel-dev/photon`
621
676
  - [Report issues](https://github.com/portel-dev/photon/issues)
622
677
  - [Contribute improvements or examples](./CONTRIBUTING.md)
@@ -236,9 +236,12 @@
236
236
  // Handle JSON-RPC tools/call from bridge and form components
237
237
  if (msg.jsonrpc === '2.0' && msg.method === 'tools/call' && msg.id != null) {
238
238
  var rawName = (msg.params && msg.params.name) || '';
239
- // Don't double-prefix: invoke-form sends fully-qualified names (photon/method),
239
+ // Don't double-prefix: invoke-form sends fully-qualified names (photon.method),
240
240
  // bridge sends unqualified names (just method). Check for prefix before adding.
241
- var toolName = rawName.indexOf('/') !== -1 ? rawName : photonName + '/' + rawName;
241
+ var toolName =
242
+ rawName.indexOf('.') !== -1 || rawName.indexOf('/') !== -1
243
+ ? rawName
244
+ : photonName + '.' + rawName;
242
245
  var args = (msg.params && msg.params.arguments) || {};
243
246
 
244
247
  var doCall = function() {
@@ -1 +1 @@
1
- {"version":3,"file":"streamable-http-transport.d.ts","sourceRoot":"","sources":["../../src/auto-ui/streamable-http-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"streamable-http-transport.d.ts","sourceRoot":"","sources":["../../src/auto-ui/streamable-http-transport.ts"],"names":[],"mappings":"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"}
@@ -148,6 +148,33 @@ function decodeJWTCaller(authHeader) {
148
148
  return undefined;
149
149
  }
150
150
  }
151
+ function isOpenAIAppSession(session) {
152
+ const name = session.clientInfo?.name?.toLowerCase();
153
+ return name === 'chatgpt' || !!name?.includes('openai');
154
+ }
155
+ function namespacedToolName(serverName, methodName) {
156
+ return `${serverName}.${methodName}`;
157
+ }
158
+ function toolNameForSession(session, photonName, methodName) {
159
+ return isOpenAIAppSession(session) ? methodName : namespacedToolName(photonName, methodName);
160
+ }
161
+ function splitNamespacedToolName(name) {
162
+ const dotIndex = name.indexOf('.');
163
+ if (dotIndex !== -1) {
164
+ return {
165
+ serverName: name.slice(0, dotIndex),
166
+ methodName: name.slice(dotIndex + 1),
167
+ };
168
+ }
169
+ const slashIndex = name.indexOf('/');
170
+ if (slashIndex !== -1) {
171
+ return {
172
+ serverName: name.slice(0, slashIndex),
173
+ methodName: name.slice(slashIndex + 1),
174
+ };
175
+ }
176
+ return null;
177
+ }
151
178
  // ════════════════════════════════════════════════════════════════════════════════
152
179
  // SESSION MANAGEMENT
153
180
  // ════════════════════════════════════════════════════════════════════════════════
@@ -1150,7 +1177,7 @@ const handlers = {
1150
1177
  : undefined;
1151
1178
  const meta = buildToolMCPMeta(method, { uiResourceUri });
1152
1179
  tools.push({
1153
- name: `${photon.name}/${method.name}`,
1180
+ name: toolNameForSession(session, photon.name, method.name),
1154
1181
  description: method.description || `Execute ${method.name}`,
1155
1182
  inputSchema: method.params || { type: 'object', properties: {} },
1156
1183
  'x-photon-id': photon.id, // Unique ID (hash of path) for subscriptions
@@ -1186,7 +1213,7 @@ const handlers = {
1186
1213
  if (!photon.configured || !photon.stateful)
1187
1214
  continue;
1188
1215
  tools.push({
1189
- name: `${photon.name}/_use`,
1216
+ name: namespacedToolName(photon.name, '_use'),
1190
1217
  description: `Switch to a named instance of ${photon.name}. Omit name to select interactively.`,
1191
1218
  inputSchema: {
1192
1219
  type: 'object',
@@ -1201,21 +1228,21 @@ const handlers = {
1201
1228
  'x-photon-internal': true,
1202
1229
  });
1203
1230
  tools.push({
1204
- name: `${photon.name}/_instances`,
1231
+ name: namespacedToolName(photon.name, '_instances'),
1205
1232
  description: `List all available instances of ${photon.name}.`,
1206
1233
  inputSchema: { type: 'object', properties: {} },
1207
1234
  'x-photon-id': photon.id,
1208
1235
  'x-photon-internal': true,
1209
1236
  });
1210
1237
  tools.push({
1211
- name: `${photon.name}/_undo`,
1238
+ name: namespacedToolName(photon.name, '_undo'),
1212
1239
  description: `Undo the last state mutation on ${photon.name}. Reverts the most recent change.`,
1213
1240
  inputSchema: { type: 'object', properties: {} },
1214
1241
  'x-photon-id': photon.id,
1215
1242
  'x-photon-internal': true,
1216
1243
  });
1217
1244
  tools.push({
1218
- name: `${photon.name}/_redo`,
1245
+ name: namespacedToolName(photon.name, '_redo'),
1219
1246
  description: `Redo the last undone mutation on ${photon.name}. Re-applies a previously undone change.`,
1220
1247
  inputSchema: { type: 'object', properties: {} },
1221
1248
  'x-photon-id': photon.id,
@@ -1230,7 +1257,7 @@ const handlers = {
1230
1257
  for (const method of mcp.methods) {
1231
1258
  const meta = buildToolMCPMeta(method, { uiResourceUri: method.linkedUi });
1232
1259
  tools.push({
1233
- name: `${mcp.name}/${method.name}`,
1260
+ name: namespacedToolName(mcp.name, method.name),
1234
1261
  description: method.description || `Execute ${method.name}`,
1235
1262
  inputSchema: method.params || { type: 'object', properties: {} },
1236
1263
  'x-external-mcp': true, // Marker for frontend to identify external MCPs
@@ -1542,9 +1569,31 @@ const handlers = {
1542
1569
  if (name === 'beam/studio-parse') {
1543
1570
  return handleBeamStudioParse(req, args || {});
1544
1571
  }
1545
- // Parse tool name: server-name/method-name or namespace:server-name/method-name
1546
- const slashIndex = name.indexOf('/');
1547
- if (slashIndex === -1) {
1572
+ // Parse tool name: server-name.method-name.
1573
+ // ChatGPT/OpenAI app sessions receive slashless names in tools/list because
1574
+ // their connector layer treats slash-qualified names as app resource paths.
1575
+ let serverName;
1576
+ let methodName;
1577
+ const namespacedName = splitNamespacedToolName(name);
1578
+ if (!namespacedName && isOpenAIAppSession(session)) {
1579
+ const matches = ctx.photons.filter((photon) => photon.configured && photon.methods?.some((method) => method.name === name));
1580
+ if (matches.length === 1) {
1581
+ const photon = matches[0];
1582
+ serverName = photon.name;
1583
+ methodName = name;
1584
+ }
1585
+ else {
1586
+ return {
1587
+ jsonrpc: '2.0',
1588
+ id: req.id,
1589
+ result: {
1590
+ content: [{ type: 'text', text: `Invalid tool name: ${name}` }],
1591
+ isError: true,
1592
+ },
1593
+ };
1594
+ }
1595
+ }
1596
+ else if (!namespacedName) {
1548
1597
  return {
1549
1598
  jsonrpc: '2.0',
1550
1599
  id: req.id,
@@ -1554,8 +1603,10 @@ const handlers = {
1554
1603
  },
1555
1604
  };
1556
1605
  }
1557
- const serverName = name.slice(0, slashIndex);
1558
- const methodName = name.slice(slashIndex + 1);
1606
+ else {
1607
+ serverName = namespacedName.serverName;
1608
+ methodName = namespacedName.methodName;
1609
+ }
1559
1610
  // Per-photon auth check: if this photon requires auth but caller is anonymous, reject
1560
1611
  const targetPhoton = ctx.photons.find((p) => p.name === serverName);
1561
1612
  // Claim-code scope enforcement: filtering tools/list alone is not a