@portel/photon-core 2.22.0 → 2.24.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/base.d.ts +56 -0
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +100 -2
- package/dist/base.js.map +1 -1
- package/dist/bases-registry.d.ts +57 -0
- package/dist/bases-registry.d.ts.map +1 -0
- package/dist/bases-registry.js +127 -0
- package/dist/bases-registry.js.map +1 -0
- package/dist/data-paths.d.ts +31 -18
- package/dist/data-paths.d.ts.map +1 -1
- package/dist/data-paths.js +42 -43
- package/dist/data-paths.js.map +1 -1
- package/dist/description-sanitizer.d.ts +34 -0
- package/dist/description-sanitizer.d.ts.map +1 -0
- package/dist/description-sanitizer.js +80 -0
- package/dist/description-sanitizer.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +109 -1
- package/dist/memory.js.map +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +96 -0
- package/dist/middleware.js.map +1 -1
- package/dist/mixins.d.ts.map +1 -1
- package/dist/mixins.js +9 -2
- package/dist/mixins.js.map +1 -1
- package/dist/path-resolver.d.ts +13 -1
- package/dist/path-resolver.d.ts.map +1 -1
- package/dist/path-resolver.js +23 -1
- package/dist/path-resolver.js.map +1 -1
- package/dist/photon-loader-lite.d.ts +17 -2
- package/dist/photon-loader-lite.d.ts.map +1 -1
- package/dist/photon-loader-lite.js +203 -26
- package/dist/photon-loader-lite.js.map +1 -1
- package/dist/schedule.d.ts +10 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +20 -10
- package/dist/schedule.js.map +1 -1
- package/dist/schema-extractor.d.ts +9 -3
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +149 -17
- package/dist/schema-extractor.js.map +1 -1
- package/dist/stateful.d.ts +3 -2
- package/dist/stateful.d.ts.map +1 -1
- package/dist/stateful.js +18 -6
- package/dist/stateful.js.map +1 -1
- package/dist/types.d.ts +9 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/base.ts +123 -2
- package/src/bases-registry.ts +141 -0
- package/src/data-paths.ts +43 -49
- package/src/description-sanitizer.ts +102 -0
- package/src/index.ts +20 -1
- package/src/memory.ts +109 -0
- package/src/middleware.ts +98 -0
- package/src/mixins.ts +14 -2
- package/src/path-resolver.ts +26 -1
- package/src/photon-loader-lite.ts +214 -33
- package/src/schedule.ts +26 -10
- package/src/schema-extractor.ts +164 -17
- package/src/stateful.ts +19 -6
- package/src/types.ts +9 -0
package/src/schema-extractor.ts
CHANGED
|
@@ -13,6 +13,25 @@ import * as ts from 'typescript';
|
|
|
13
13
|
import { ExtractedSchema, ConstructorParam, TemplateInfo, StaticInfo, OutputFormat, YieldInfo, MCPDependency, PhotonDependency, CLIDependency, ResolvedInjection, PhotonAssets, UIAsset, PromptAsset, ResourceAsset, ConfigSchema, ConfigParam, SettingsSchema, SettingsProperty, NotificationSubscription } from './types.js';
|
|
14
14
|
import { parseDuration, parseRate } from './utils/duration.js';
|
|
15
15
|
import { builtinRegistry, type MiddlewareDeclaration } from './middleware.js';
|
|
16
|
+
import { sanitizeDescription } from './description-sanitizer.js';
|
|
17
|
+
|
|
18
|
+
// Warn once per unique (method, rule) pair so poisoned photons don't spam.
|
|
19
|
+
const sanitizeWarnings = new Set<string>();
|
|
20
|
+
|
|
21
|
+
// Track which `handle*` method names have already emitted a deprecation
|
|
22
|
+
// warning this process so large photons don't spam the console.
|
|
23
|
+
const handlePrefixWarned = new Set<string>();
|
|
24
|
+
|
|
25
|
+
function warnHandlePrefixOnce(methodName: string): void {
|
|
26
|
+
if (handlePrefixWarned.has(methodName)) return;
|
|
27
|
+
handlePrefixWarned.add(methodName);
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
29
|
+
console.error(
|
|
30
|
+
`[photon] deprecation: method "${methodName}" is being auto-registered as a ` +
|
|
31
|
+
`webhook via the legacy handle* prefix. Add an explicit "@webhook" JSDoc ` +
|
|
32
|
+
`tag; the prefix convention will be removed in the next minor release.`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
16
35
|
|
|
17
36
|
export interface ExtractedMetadata {
|
|
18
37
|
tools: ExtractedSchema[];
|
|
@@ -381,6 +400,33 @@ export class SchemaExtractor {
|
|
|
381
400
|
|
|
382
401
|
const properties: SettingsProperty[] = [];
|
|
383
402
|
|
|
403
|
+
// Inline-JSDoc helper: pull the description from a /** ... */ comment
|
|
404
|
+
// that immediately precedes a property assignment inside the object
|
|
405
|
+
// literal. Class-level @property tags still win when both are
|
|
406
|
+
// present (so existing photons aren't disrupted).
|
|
407
|
+
const sourceText = sourceFile.text;
|
|
408
|
+
const inlineDescriptionFor = (prop: ts.Node): string | undefined => {
|
|
409
|
+
const ranges = ts.getLeadingCommentRanges(sourceText, prop.pos);
|
|
410
|
+
if (!ranges || ranges.length === 0) return undefined;
|
|
411
|
+
// Use the last comment block before the property (closest to it).
|
|
412
|
+
const block = ranges[ranges.length - 1];
|
|
413
|
+
if (
|
|
414
|
+
sourceText[block.pos] !== '/' ||
|
|
415
|
+
sourceText[block.pos + 1] !== '*' ||
|
|
416
|
+
sourceText[block.pos + 2] !== '*'
|
|
417
|
+
) {
|
|
418
|
+
return undefined;
|
|
419
|
+
}
|
|
420
|
+
const raw = sourceText.slice(block.pos + 3, block.end - 2);
|
|
421
|
+
// Strip leading "*" markers, trim, collapse whitespace.
|
|
422
|
+
return raw
|
|
423
|
+
.split('\n')
|
|
424
|
+
.map((line) => line.replace(/^\s*\*\s?/, '').trim())
|
|
425
|
+
.filter(Boolean)
|
|
426
|
+
.join(' ')
|
|
427
|
+
.trim();
|
|
428
|
+
};
|
|
429
|
+
|
|
384
430
|
for (const prop of member.initializer.properties) {
|
|
385
431
|
if (!ts.isPropertyAssignment(prop)) continue;
|
|
386
432
|
const propName = prop.name.getText(sourceFile);
|
|
@@ -437,7 +483,7 @@ export class SchemaExtractor {
|
|
|
437
483
|
properties.push({
|
|
438
484
|
name: propName,
|
|
439
485
|
type,
|
|
440
|
-
description: propertyDocs.get(propName),
|
|
486
|
+
description: propertyDocs.get(propName) ?? inlineDescriptionFor(prop),
|
|
441
487
|
default: defaultValue,
|
|
442
488
|
required,
|
|
443
489
|
});
|
|
@@ -981,10 +1027,36 @@ export class SchemaExtractor {
|
|
|
981
1027
|
true
|
|
982
1028
|
);
|
|
983
1029
|
|
|
1030
|
+
// Per-parameter JSDoc: prefer an inline /** ... */ block immediately
|
|
1031
|
+
// before the parameter (the natural way authors write it), fall back
|
|
1032
|
+
// to a constructor-level @param tag.
|
|
1033
|
+
const sourceText = sourceFile.text;
|
|
1034
|
+
const inlineDescriptionFor = (param: ts.Node): string | undefined => {
|
|
1035
|
+
const ranges = ts.getLeadingCommentRanges(sourceText, param.pos);
|
|
1036
|
+
if (!ranges || ranges.length === 0) return undefined;
|
|
1037
|
+
const block = ranges[ranges.length - 1];
|
|
1038
|
+
if (
|
|
1039
|
+
sourceText[block.pos] !== '/' ||
|
|
1040
|
+
sourceText[block.pos + 1] !== '*' ||
|
|
1041
|
+
sourceText[block.pos + 2] !== '*'
|
|
1042
|
+
) {
|
|
1043
|
+
return undefined;
|
|
1044
|
+
}
|
|
1045
|
+
const raw = sourceText.slice(block.pos + 3, block.end - 2);
|
|
1046
|
+
return raw
|
|
1047
|
+
.split('\n')
|
|
1048
|
+
.map((line) => line.replace(/^\s*\*\s?/, '').trim())
|
|
1049
|
+
.filter(Boolean)
|
|
1050
|
+
.join(' ')
|
|
1051
|
+
.trim();
|
|
1052
|
+
};
|
|
1053
|
+
|
|
984
1054
|
const visit = (node: ts.Node) => {
|
|
985
1055
|
if (ts.isClassDeclaration(node)) {
|
|
986
1056
|
node.members.forEach((member) => {
|
|
987
1057
|
if (ts.isConstructorDeclaration(member)) {
|
|
1058
|
+
const ctorJsdoc = this.getJSDocComment(member as any, sourceFile);
|
|
1059
|
+
const ctorParamDocs = this.extractParamDocs(ctorJsdoc);
|
|
988
1060
|
member.parameters.forEach((param) => {
|
|
989
1061
|
if (param.name && ts.isIdentifier(param.name)) {
|
|
990
1062
|
const name = param.name.getText(sourceFile);
|
|
@@ -1004,6 +1076,7 @@ export class SchemaExtractor {
|
|
|
1004
1076
|
hasDefault,
|
|
1005
1077
|
defaultValue,
|
|
1006
1078
|
isPrimitive: this.isPrimitiveType(type),
|
|
1079
|
+
description: inlineDescriptionFor(param) ?? ctorParamDocs.get(name),
|
|
1007
1080
|
});
|
|
1008
1081
|
}
|
|
1009
1082
|
});
|
|
@@ -1249,6 +1322,29 @@ export class SchemaExtractor {
|
|
|
1249
1322
|
declarations.push({ name: 'locked', config: { name: lockName }, phase: def?.phase ?? 60 });
|
|
1250
1323
|
}
|
|
1251
1324
|
|
|
1325
|
+
// @mask <field1,field2,...> — redact named fields from the response.
|
|
1326
|
+
// Accepts comma- or whitespace-separated field names.
|
|
1327
|
+
const maskMatch = jsdocContent.match(/@mask\s+([^\n@]+)/i);
|
|
1328
|
+
if (maskMatch) {
|
|
1329
|
+
const def = builtinRegistry.get('mask');
|
|
1330
|
+
const rawValue = maskMatch[1].trim();
|
|
1331
|
+
const config = def?.parseShorthand
|
|
1332
|
+
? def.parseShorthand(rawValue)
|
|
1333
|
+
: { fields: rawValue.split(/[,\s]+/).filter(Boolean), placeholder: '[REDACTED]' };
|
|
1334
|
+
declarations.push({ name: 'mask', config, phase: def?.phase ?? 85 });
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// @maxResponseBytes <N> — cap serialized response size.
|
|
1338
|
+
const maxBytesMatch = jsdocContent.match(/@maxResponseBytes\s+(\d+)/i);
|
|
1339
|
+
if (maxBytesMatch) {
|
|
1340
|
+
const def = builtinRegistry.get('maxResponseBytes');
|
|
1341
|
+
const rawValue = maxBytesMatch[1];
|
|
1342
|
+
const config = def?.parseShorthand
|
|
1343
|
+
? def.parseShorthand(rawValue)
|
|
1344
|
+
: { limit: parseInt(rawValue, 10) || 0 };
|
|
1345
|
+
declarations.push({ name: 'maxResponseBytes', config, phase: def?.phase ?? 88 });
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1252
1348
|
// 2. Extract @use declarations
|
|
1253
1349
|
const useDecls = this.extractUseDeclarations(jsdocContent);
|
|
1254
1350
|
for (const { name, rawConfig } of useDecls) {
|
|
@@ -1276,7 +1372,7 @@ export class SchemaExtractor {
|
|
|
1276
1372
|
private extractDescription(jsdocContent: string): string {
|
|
1277
1373
|
// Split by @tags that appear at start of a JSDoc line (after optional * prefix)
|
|
1278
1374
|
// This avoids matching @tag references inline in description text
|
|
1279
|
-
const beforeTags = jsdocContent.split(/(?:^|\n)\s*\*?\s*@(?:param|example|returns?|throws?|see|since|deprecated|version|author|license|ui|icon|format|stateful|autorun|async|webhook|cron|scheduled|locked|fallback|logged|circuitBreaker|cached|timeout|retryable|throttled|debounced|queued|validate|use|Template|Static|mcp|photon|cli|tags|dependencies|csp|visibility|auth)\b/)[0];
|
|
1375
|
+
const beforeTags = jsdocContent.split(/(?:^|\n)\s*\*?\s*@(?:param|example|returns?|throws?|see|since|deprecated|version|author|license|ui|icon|format|stateful|autorun|async|webhook|cron|scheduled|locked|fallback|logged|circuitBreaker|cached|timeout|retryable|throttled|debounced|queued|validate|use|Template|Static|mcp|photon|cli|tags|dependencies|csp|visibility|auth|mask|maxResponseBytes)\b/)[0];
|
|
1280
1376
|
|
|
1281
1377
|
// Remove leading * from each line and trim
|
|
1282
1378
|
const lines = beforeTags
|
|
@@ -1313,8 +1409,26 @@ export class SchemaExtractor {
|
|
|
1313
1409
|
|
|
1314
1410
|
const description = parts.join('');
|
|
1315
1411
|
|
|
1316
|
-
// Clean up multiple spaces
|
|
1317
|
-
|
|
1412
|
+
// Clean up multiple spaces, then defend against tool-description poisoning.
|
|
1413
|
+
const collapsed = description.replace(/\s+/g, ' ').trim() || 'No description';
|
|
1414
|
+
const { cleaned, warnings, truncated } = sanitizeDescription(collapsed);
|
|
1415
|
+
if (warnings.length > 0 || truncated) {
|
|
1416
|
+
for (const w of warnings) {
|
|
1417
|
+
const key = `${w.rule}|${w.sample}`;
|
|
1418
|
+
if (sanitizeWarnings.has(key)) continue;
|
|
1419
|
+
sanitizeWarnings.add(key);
|
|
1420
|
+
// eslint-disable-next-line no-console
|
|
1421
|
+
console.warn(
|
|
1422
|
+
`[photon] description sanitizer: redacted ${w.rule} (sample: "${w.sample}")`
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
if (truncated && !sanitizeWarnings.has('truncated')) {
|
|
1426
|
+
sanitizeWarnings.add('truncated');
|
|
1427
|
+
// eslint-disable-next-line no-console
|
|
1428
|
+
console.warn('[photon] description sanitizer: truncated oversized description');
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return cleaned;
|
|
1318
1432
|
}
|
|
1319
1433
|
|
|
1320
1434
|
/**
|
|
@@ -2048,10 +2162,15 @@ export class SchemaExtractor {
|
|
|
2048
2162
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2049
2163
|
|
|
2050
2164
|
/**
|
|
2051
|
-
* Extract webhook configuration from @webhook tag or handle* prefix
|
|
2165
|
+
* Extract webhook configuration from @webhook tag or handle* prefix.
|
|
2052
2166
|
* - @webhook → use method name as path
|
|
2053
2167
|
* - @webhook stripe → custom path "stripe"
|
|
2054
|
-
* - handle* prefix → auto-detected as webhook
|
|
2168
|
+
* - handle* prefix → auto-detected as webhook (DEPRECATED)
|
|
2169
|
+
*
|
|
2170
|
+
* The handle* prefix is a legacy convention being removed. It still
|
|
2171
|
+
* works for one release but emits a one-time stderr warning per
|
|
2172
|
+
* method so users can migrate to the explicit @webhook tag before
|
|
2173
|
+
* the convention is dropped.
|
|
2055
2174
|
*/
|
|
2056
2175
|
private extractWebhook(jsdocContent: string, methodName: string): boolean | string | undefined {
|
|
2057
2176
|
// Check for @webhook tag with optional path
|
|
@@ -2063,8 +2182,9 @@ export class SchemaExtractor {
|
|
|
2063
2182
|
return path || true;
|
|
2064
2183
|
}
|
|
2065
2184
|
|
|
2066
|
-
// Check for handle* prefix (convention)
|
|
2185
|
+
// Check for handle* prefix (legacy convention — deprecated).
|
|
2067
2186
|
if (methodName.startsWith('handle')) {
|
|
2187
|
+
warnHandlePrefixOnce(methodName);
|
|
2068
2188
|
return true;
|
|
2069
2189
|
}
|
|
2070
2190
|
|
|
@@ -2391,6 +2511,11 @@ export class SchemaExtractor {
|
|
|
2391
2511
|
return format as OutputFormat;
|
|
2392
2512
|
}
|
|
2393
2513
|
|
|
2514
|
+
// Match declarative UI formats (A2UI v0.9 rides on AG-UI)
|
|
2515
|
+
if (format === 'a2ui') {
|
|
2516
|
+
return 'a2ui' as OutputFormat;
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2394
2519
|
return undefined;
|
|
2395
2520
|
}
|
|
2396
2521
|
|
|
@@ -3004,25 +3129,47 @@ export class SchemaExtractor {
|
|
|
3004
3129
|
*/
|
|
3005
3130
|
export type PhotonCapability = 'emit' | 'memory' | 'call' | 'mcp' | 'lock' | 'instanceMeta' | 'allInstances' | 'caller';
|
|
3006
3131
|
|
|
3132
|
+
/**
|
|
3133
|
+
* Match a `this`-like base in source code. Covers:
|
|
3134
|
+
* this — literal
|
|
3135
|
+
* (this as any) — TS `as` cast (the most common workaround when
|
|
3136
|
+
* TypeScript can't see a runtime-injected method)
|
|
3137
|
+
* (this as SomeClass), (this as unknown as T)
|
|
3138
|
+
* (<any>this), (<T>this) — older angle-bracket cast syntax
|
|
3139
|
+
*
|
|
3140
|
+
* Not covered: aliasing (`const self = this`), destructuring
|
|
3141
|
+
* (`const { call } = this`), or bracket access (`this['call']`).
|
|
3142
|
+
* Those require dataflow analysis which a regex can't do; the loader
|
|
3143
|
+
* compensates by always-injecting the cheap convenience methods whose
|
|
3144
|
+
* gating would otherwise silently fail for those patterns.
|
|
3145
|
+
*/
|
|
3146
|
+
const THIS_BASE =
|
|
3147
|
+
String.raw`(?:\bthis\b|\(\s*<[^>]+>\s*this\s*\)|\(\s*this\s+as\s+[^)]+\))`;
|
|
3148
|
+
|
|
3149
|
+
function memberAccess(name: string, trailing: '\\(' | '\\b'): RegExp {
|
|
3150
|
+
return new RegExp(`${THIS_BASE}\\s*\\.\\s*${name}\\s*${trailing}`);
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3007
3153
|
/**
|
|
3008
3154
|
* Detect capabilities used by a Photon from its source code.
|
|
3009
3155
|
*
|
|
3010
3156
|
* Scans for `this.emit(`, `this.memory`, `this.call(`, etc. patterns
|
|
3011
|
-
*
|
|
3157
|
+
* (including typed-access workarounds like `(this as any).call(`) and
|
|
3158
|
+
* returns the set of capabilities that the runtime should inject.
|
|
3012
3159
|
*
|
|
3013
3160
|
* This enables plain classes (no extends Photon) to use all framework
|
|
3014
3161
|
* features — the loader detects usage and injects automatically.
|
|
3015
3162
|
*/
|
|
3016
3163
|
export function detectCapabilities(source: string): Set<PhotonCapability> {
|
|
3017
3164
|
const caps = new Set<PhotonCapability>();
|
|
3018
|
-
if (
|
|
3019
|
-
if (
|
|
3020
|
-
if (
|
|
3021
|
-
if (
|
|
3022
|
-
if (
|
|
3023
|
-
if (
|
|
3024
|
-
if (
|
|
3025
|
-
if (
|
|
3026
|
-
if (
|
|
3165
|
+
if (memberAccess('emit', '\\(').test(source)) caps.add('emit');
|
|
3166
|
+
if (memberAccess('render', '\\(').test(source)) caps.add('emit'); // render() needs emit injection
|
|
3167
|
+
if (memberAccess('memory', '\\b').test(source)) caps.add('memory');
|
|
3168
|
+
if (memberAccess('call', '\\(').test(source)) caps.add('call');
|
|
3169
|
+
if (memberAccess('mcp', '\\(').test(source)) caps.add('mcp');
|
|
3170
|
+
if (memberAccess('withLock', '\\(').test(source)) caps.add('lock');
|
|
3171
|
+
if (memberAccess('instanceMeta', '\\b').test(source)) caps.add('instanceMeta');
|
|
3172
|
+
if (memberAccess('allInstances', '\\(').test(source)) caps.add('allInstances');
|
|
3173
|
+
if (memberAccess('caller', '\\b').test(source)) caps.add('caller');
|
|
3027
3174
|
return caps;
|
|
3028
3175
|
}
|
package/src/stateful.ts
CHANGED
|
@@ -87,10 +87,21 @@ import {
|
|
|
87
87
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
90
|
+
* Resolve the default runs directory at call time so a long-lived daemon
|
|
91
|
+
* that serves multiple PHOTON_DIRs picks up each base's runs. Previously
|
|
92
|
+
* a module-level const frozen at import time.
|
|
93
|
+
* @deprecated Use getPhotonRunsDir(namespace, photonName, baseDir) for per-photon runs.
|
|
92
94
|
*/
|
|
93
|
-
|
|
95
|
+
function defaultRunsDir(): string {
|
|
96
|
+
return getLegacyRunsDir();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Back-compat export. Resolved at import time — kept for consumers that
|
|
101
|
+
* read `RUNS_DIR` as a constant. New code should call getPhotonRunsDir().
|
|
102
|
+
* @deprecated Use getPhotonRunsDir(namespace, photonName, baseDir).
|
|
103
|
+
*/
|
|
104
|
+
export const RUNS_DIR = defaultRunsDir();
|
|
94
105
|
|
|
95
106
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
96
107
|
// CHECKPOINT YIELD TYPE
|
|
@@ -136,7 +147,9 @@ export class StateLog {
|
|
|
136
147
|
private logPath: string;
|
|
137
148
|
|
|
138
149
|
constructor(runId: string, runsDir?: string) {
|
|
139
|
-
|
|
150
|
+
// Resolve runs dir at call time so the current PHOTON_DIR is honored
|
|
151
|
+
// even when a long-lived process has served earlier bases.
|
|
152
|
+
this.logPath = path.join(runsDir || defaultRunsDir(), `${runId}.jsonl`);
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
/**
|
|
@@ -573,7 +586,7 @@ export async function executeStatefulGenerator<T>(
|
|
|
573
586
|
* List all workflow runs
|
|
574
587
|
*/
|
|
575
588
|
export async function listRuns(runsDir?: string): Promise<WorkflowRun[]> {
|
|
576
|
-
const dir = runsDir ||
|
|
589
|
+
const dir = runsDir || defaultRunsDir();
|
|
577
590
|
const runs: WorkflowRun[] = [];
|
|
578
591
|
|
|
579
592
|
try {
|
|
@@ -639,7 +652,7 @@ export async function getRunInfo(runId: string, runsDir?: string): Promise<Workf
|
|
|
639
652
|
* Delete a workflow run
|
|
640
653
|
*/
|
|
641
654
|
export async function deleteRun(runId: string, runsDir?: string): Promise<void> {
|
|
642
|
-
const logPath = path.join(runsDir ||
|
|
655
|
+
const logPath = path.join(runsDir || defaultRunsDir(), `${runId}.jsonl`);
|
|
643
656
|
await fs.unlink(logPath);
|
|
644
657
|
}
|
|
645
658
|
|
package/src/types.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - Visualization: chart, chart:<type>, metric, gauge, timeline, dashboard, cart
|
|
10
10
|
* - Content: json, markdown, yaml, xml, html, mermaid, code, code:<lang>, slides
|
|
11
11
|
* - Container: panels, tabs, accordion, stack, columns
|
|
12
|
+
* - Declarative: a2ui (A2UI v0.9 JSONL — emits createSurface/updateComponents/updateDataModel)
|
|
12
13
|
*/
|
|
13
14
|
export type OutputFormat =
|
|
14
15
|
| 'primitive' | 'table' | 'tree' | 'list' | 'none'
|
|
@@ -16,6 +17,7 @@ export type OutputFormat =
|
|
|
16
17
|
| 'card' | 'grid' | 'chips' | 'kv' | 'qr'
|
|
17
18
|
| 'chart' | `chart:${string}` | 'metric' | 'gauge' | 'timeline' | 'dashboard' | 'cart'
|
|
18
19
|
| 'panels' | 'tabs' | 'accordion' | 'stack' | 'columns'
|
|
20
|
+
| 'a2ui'
|
|
19
21
|
| `code` | `code:${string}`;
|
|
20
22
|
|
|
21
23
|
export interface PhotonTool {
|
|
@@ -299,6 +301,13 @@ export interface ConstructorParam {
|
|
|
299
301
|
defaultValue?: any;
|
|
300
302
|
/** True if type is string, number, or boolean (inject from env var) */
|
|
301
303
|
isPrimitive: boolean;
|
|
304
|
+
/**
|
|
305
|
+
* Per-parameter JSDoc description, taken from an inline `/** ... *\/`
|
|
306
|
+
* comment immediately before the parameter, or from a constructor-level
|
|
307
|
+
* `@param <name>` tag when the inline form is absent. Used by the Beam
|
|
308
|
+
* Setup form for field help text.
|
|
309
|
+
*/
|
|
310
|
+
description?: string;
|
|
302
311
|
}
|
|
303
312
|
|
|
304
313
|
/**
|