deepline 0.2.70 → 0.2.72
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/bundling-sources/sdk/src/client.ts +45 -12
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +67 -14
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +55 -14
- package/dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts +13 -3
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +12 -0
- package/dist/cli/index.js +428 -40
- package/dist/cli/index.mjs +465 -69
- package/dist/index.d.mts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +64 -26
- package/dist/index.mjs +64 -26
- package/dist/plays/bundle-play-file.mjs +35 -14
- package/package.json +1 -1
|
@@ -1156,16 +1156,16 @@ function isPrebuiltPlayDescription(
|
|
|
1156
1156
|
function preferPrebuiltPlayDescriptions<T extends PlayDescription>(
|
|
1157
1157
|
plays: T[],
|
|
1158
1158
|
): T[] {
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1159
|
+
return plays
|
|
1160
|
+
.map((play, index) => ({ play, index }))
|
|
1161
|
+
.sort(
|
|
1162
|
+
(left, right) =>
|
|
1163
|
+
Number(right.play.pinned) - Number(left.play.pinned) ||
|
|
1164
|
+
Number(isPrebuiltPlayDescription(right.play)) -
|
|
1165
|
+
Number(isPrebuiltPlayDescription(left.play)) ||
|
|
1166
|
+
left.index - right.index,
|
|
1167
|
+
)
|
|
1168
|
+
.map(({ play }) => play);
|
|
1169
1169
|
}
|
|
1170
1170
|
|
|
1171
1171
|
function isPlayRunPackage(value: unknown): value is PlayRunPackage {
|
|
@@ -1775,6 +1775,8 @@ export class DeeplineClient {
|
|
|
1775
1775
|
...(play.reference ? { reference: play.reference } : {}),
|
|
1776
1776
|
...(play.displayName ? { displayName: play.displayName } : {}),
|
|
1777
1777
|
...(description ? { description } : {}),
|
|
1778
|
+
pinned: Boolean(play.pinned),
|
|
1779
|
+
toolCategories: play.toolCategories ?? [],
|
|
1778
1780
|
origin: play.origin,
|
|
1779
1781
|
ownerType: play.ownerType,
|
|
1780
1782
|
canEdit: play.canEdit,
|
|
@@ -3778,9 +3780,24 @@ export class DeeplineClient {
|
|
|
3778
3780
|
origin?: 'prebuilt' | 'owned';
|
|
3779
3781
|
grep?: string;
|
|
3780
3782
|
grepMode?: 'all' | 'any' | 'phrase';
|
|
3783
|
+
categories?: string | string[];
|
|
3784
|
+
includeToolCategories?: boolean;
|
|
3785
|
+
includeArchived?: boolean;
|
|
3781
3786
|
}): Promise<PlayListItem[]> {
|
|
3782
3787
|
const params = new URLSearchParams();
|
|
3783
3788
|
if (options?.origin) params.set('origin', options.origin);
|
|
3789
|
+
if (options?.categories) {
|
|
3790
|
+
params.set(
|
|
3791
|
+
'categories',
|
|
3792
|
+
Array.isArray(options.categories)
|
|
3793
|
+
? options.categories.join(',')
|
|
3794
|
+
: options.categories,
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3797
|
+
if (options?.categories || options?.includeToolCategories) {
|
|
3798
|
+
params.set('include_tool_categories', '1');
|
|
3799
|
+
}
|
|
3800
|
+
if (options?.includeArchived) params.set('include_archived', '1');
|
|
3784
3801
|
if (options?.grep?.trim()) {
|
|
3785
3802
|
params.set('grep', options.grep.trim());
|
|
3786
3803
|
params.set('grep_mode', options.grepMode ?? 'all');
|
|
@@ -3793,6 +3810,16 @@ export class DeeplineClient {
|
|
|
3793
3810
|
return response.plays ?? [];
|
|
3794
3811
|
}
|
|
3795
3812
|
|
|
3813
|
+
/** Set whether an org-owned Play sorts before unpinned Plays. */
|
|
3814
|
+
async setPlayPinned(
|
|
3815
|
+
playName: string,
|
|
3816
|
+
pinned: boolean,
|
|
3817
|
+
): Promise<{ name: string; pinned: boolean }> {
|
|
3818
|
+
return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
|
|
3819
|
+
pinned,
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3796
3823
|
/** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
|
|
3797
3824
|
async getNotificationSettings(): Promise<ProductNotificationSettings> {
|
|
3798
3825
|
return this.http.get('/api/v2/settings/notifications');
|
|
@@ -3981,9 +4008,15 @@ export class DeeplineClient {
|
|
|
3981
4008
|
* console.log(`Total runs: ${detail.play.runCount}`);
|
|
3982
4009
|
* ```
|
|
3983
4010
|
*/
|
|
3984
|
-
async getPlay(
|
|
4011
|
+
async getPlay(
|
|
4012
|
+
name: string,
|
|
4013
|
+
options?: { source?: 'working' | 'live' | `version:${number}` },
|
|
4014
|
+
): Promise<PlayDetail> {
|
|
3985
4015
|
const encodedName = encodeURIComponent(name);
|
|
3986
|
-
|
|
4016
|
+
const query = options?.source
|
|
4017
|
+
? `?include=source&revision=${encodeURIComponent(options.source)}`
|
|
4018
|
+
: '';
|
|
4019
|
+
return this.http.get<PlayDetail>(`/api/v2/plays/${encodedName}${query}`);
|
|
3987
4020
|
}
|
|
3988
4021
|
|
|
3989
4022
|
/**
|
|
@@ -183,7 +183,7 @@ export const SDK_RELEASE = {
|
|
|
183
183
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
184
184
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
185
185
|
// release keeps lazy paging semantics independent of row residency.
|
|
186
|
-
version: '0.2.
|
|
186
|
+
version: '0.2.72',
|
|
187
187
|
contracts: {
|
|
188
188
|
api: {
|
|
189
189
|
name: 'sdk-http-api',
|
|
@@ -1010,6 +1010,10 @@ export interface PlayDefinitionDetail {
|
|
|
1010
1010
|
name: string;
|
|
1011
1011
|
/** Human-friendly display name for UI surfaces. */
|
|
1012
1012
|
displayName?: string;
|
|
1013
|
+
/** Whether this Play sorts before unpinned Plays. */
|
|
1014
|
+
pinned?: boolean;
|
|
1015
|
+
/** Canonical categories declared by tools used in this Play. */
|
|
1016
|
+
toolCategories?: string[];
|
|
1013
1017
|
/** Whether this entry comes from the Deepline prebuilt registry or the org-owned catalog. */
|
|
1014
1018
|
origin?: 'prebuilt' | 'owned';
|
|
1015
1019
|
/** Ownership class used for permissions and badges. */
|
|
@@ -1064,6 +1068,8 @@ export interface PlayListItem {
|
|
|
1064
1068
|
name: string;
|
|
1065
1069
|
displayName?: string;
|
|
1066
1070
|
description?: string | null;
|
|
1071
|
+
pinned?: boolean;
|
|
1072
|
+
toolCategories?: string[];
|
|
1067
1073
|
origin?: 'prebuilt' | 'owned';
|
|
1068
1074
|
ownerType?: 'deepline' | 'org';
|
|
1069
1075
|
ownerSlug?: string;
|
|
@@ -1135,6 +1141,8 @@ export interface PlayDescription {
|
|
|
1135
1141
|
reference?: string;
|
|
1136
1142
|
displayName?: string;
|
|
1137
1143
|
description?: string | null;
|
|
1144
|
+
pinned?: boolean;
|
|
1145
|
+
toolCategories?: string[];
|
|
1138
1146
|
origin?: 'prebuilt' | 'owned';
|
|
1139
1147
|
ownerType?: 'deepline' | 'org';
|
|
1140
1148
|
canEdit?: boolean;
|
|
@@ -1192,6 +1200,16 @@ export interface PlayDetail {
|
|
|
1192
1200
|
customerDbUrl: string;
|
|
1193
1201
|
/** Change cursor for incremental sync. */
|
|
1194
1202
|
deltaCursor: number;
|
|
1203
|
+
/**
|
|
1204
|
+
* Present only when requested through `getPlay(..., { source: ... })`.
|
|
1205
|
+
* `files` is the complete authored source tree, keyed by logical path.
|
|
1206
|
+
*/
|
|
1207
|
+
source?: {
|
|
1208
|
+
selector: 'working' | 'live' | `version:${number}`;
|
|
1209
|
+
revision: { id: string; version: number };
|
|
1210
|
+
entryFile: string;
|
|
1211
|
+
files: Record<string, string>;
|
|
1212
|
+
};
|
|
1195
1213
|
}
|
|
1196
1214
|
|
|
1197
1215
|
export interface ClearPlayHistoryRequest {
|
|
@@ -61,16 +61,60 @@ const liveToolResultListDatasets = new Map<
|
|
|
61
61
|
PlayDataset<Record<string, unknown>>
|
|
62
62
|
>();
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Keys that describe a field rather than carry it.
|
|
66
|
+
*
|
|
67
|
+
* These sit next to the real value under a similar name, so a substring match
|
|
68
|
+
* on the target name reaches them as soon as the real field is absent.
|
|
69
|
+
* `phone_status: "unfound"` is not a phone number and `email_type: "work"` is
|
|
70
|
+
* not an email address.
|
|
71
|
+
*/
|
|
72
|
+
const DESCRIPTOR_SUFFIX =
|
|
73
|
+
/_(status|type|score|count|id|verified|valid|confidence|quality|source)$/i;
|
|
74
|
+
|
|
75
|
+
/** A company-scoped key is never the person-scoped answer. */
|
|
76
|
+
const COMPANY_SCOPED = /company/i;
|
|
77
|
+
|
|
78
|
+
type TargetFallbackRule = {
|
|
79
|
+
/** Key names that may carry this target's value. */
|
|
80
|
+
match: readonly RegExp[];
|
|
81
|
+
/** Key names that must never be treated as this target's value. */
|
|
82
|
+
reject?: readonly RegExp[];
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const TARGET_FALLBACK_KEYS: Record<string, TargetFallbackRule> = {
|
|
86
|
+
email: {
|
|
87
|
+
match: [/^email$/i, /^address$/i, /email/i],
|
|
88
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
89
|
+
},
|
|
90
|
+
phone: {
|
|
91
|
+
match: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
|
|
92
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
93
|
+
},
|
|
94
|
+
linkedin: {
|
|
95
|
+
match: [/^linkedin_url$/i, /^linkedin$/i, /linkedin/i],
|
|
96
|
+
reject: [DESCRIPTOR_SUFFIX, COMPANY_SCOPED],
|
|
97
|
+
},
|
|
98
|
+
company_linkedin_url: {
|
|
99
|
+
match: [/company.*linkedin/i, /linkedin.*company/i],
|
|
100
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
101
|
+
},
|
|
102
|
+
company_domain: {
|
|
103
|
+
match: [/^company_domain$/i, /company.*domain/i],
|
|
104
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
105
|
+
},
|
|
106
|
+
company_name: {
|
|
107
|
+
match: [/^company_name$/i, /company.*name/i],
|
|
108
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
109
|
+
},
|
|
110
|
+
domain: {
|
|
111
|
+
match: [/^domain$/i, /company_domain/i, /domain/i],
|
|
112
|
+
reject: [DESCRIPTOR_SUFFIX],
|
|
113
|
+
},
|
|
114
|
+
// Status targets legitimately want the `_status` keys the suffix rule
|
|
115
|
+
// rejects elsewhere, so they carry no rejections.
|
|
116
|
+
status: { match: [/^email_status$/i, /^status$/i] },
|
|
117
|
+
email_status: { match: [/^email_status$/i, /^status$/i] },
|
|
74
118
|
};
|
|
75
119
|
|
|
76
120
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -586,12 +630,13 @@ function findFirstTargetByKey(
|
|
|
586
630
|
}
|
|
587
631
|
if (!isRecord(result)) return null;
|
|
588
632
|
|
|
589
|
-
const
|
|
590
|
-
new RegExp(`^${target}$`, 'i'),
|
|
591
|
-
|
|
633
|
+
const rule: TargetFallbackRule = TARGET_FALLBACK_KEYS[target] ?? {
|
|
634
|
+
match: [new RegExp(`^${target}$`, 'i')],
|
|
635
|
+
};
|
|
592
636
|
for (const [key, value] of Object.entries(result)) {
|
|
637
|
+
if (rule.reject?.some((pattern) => pattern.test(key))) continue;
|
|
593
638
|
if (
|
|
594
|
-
|
|
639
|
+
rule.match.some((pattern) => pattern.test(key)) &&
|
|
595
640
|
isMeaningfulValue(value)
|
|
596
641
|
) {
|
|
597
642
|
return { value, path: pathToString([...path, key]) };
|
|
@@ -896,6 +941,14 @@ function buildTargets(
|
|
|
896
941
|
targets[target] = fromMetadata;
|
|
897
942
|
continue;
|
|
898
943
|
}
|
|
944
|
+
// Declared paths are routinely incomplete against the shape a provider
|
|
945
|
+
// actually returns (zerobounce declares `result.data.email` and answers
|
|
946
|
+
// with `address`), so the key scan stays as the rescue. It is bounded by
|
|
947
|
+
// each target's `reject` rules: the scan runs precisely when the provider
|
|
948
|
+
// returned no value, which is when a same-named neighbour is most likely
|
|
949
|
+
// to be a different field. Without those rules a real Wiza miss resolved
|
|
950
|
+
// `phone` to `phone_status: "unfound"` and `linkedin` to
|
|
951
|
+
// `company_linkedin`, reporting a company page as the person's profile.
|
|
899
952
|
const fallback = findFirstTargetByKey(result, target);
|
|
900
953
|
if (fallback) {
|
|
901
954
|
targets[target] = fallback;
|
|
@@ -38,7 +38,7 @@ export const PLAY_AUTHORING_CONTRACT_CHANGELOG = [
|
|
|
38
38
|
changed:
|
|
39
39
|
'Materializes the declared input schema in the admitted snapshot so launch never reparses current source.',
|
|
40
40
|
compatibilityOwner: 'Plays Runtime',
|
|
41
|
-
newWritesEnd:
|
|
41
|
+
newWritesEnd: '2026-08-19',
|
|
42
42
|
readerRemoval: null,
|
|
43
43
|
},
|
|
44
44
|
] as const;
|
|
@@ -137,6 +137,18 @@ export type PlayBundlingAdapter = {
|
|
|
137
137
|
warnAboutNonDevelopmentBundling?(filePath: string): void;
|
|
138
138
|
};
|
|
139
139
|
|
|
140
|
+
type PathRelationshipApi = {
|
|
141
|
+
relative(from: string, to: string): string;
|
|
142
|
+
isAbsolute(path: string): boolean;
|
|
143
|
+
sep: string;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const defaultPathRelationshipApi: PathRelationshipApi = {
|
|
147
|
+
relative,
|
|
148
|
+
isAbsolute,
|
|
149
|
+
sep,
|
|
150
|
+
};
|
|
151
|
+
|
|
140
152
|
function assertValidExportName(exportName: string): void {
|
|
141
153
|
if (exportName === 'default') return;
|
|
142
154
|
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(exportName)) {
|
|
@@ -207,10 +219,10 @@ function sha256(value: string): string {
|
|
|
207
219
|
|
|
208
220
|
function sourceIdentityPath(
|
|
209
221
|
filePath: string,
|
|
210
|
-
|
|
222
|
+
sourceIdentityRoot: string | undefined,
|
|
211
223
|
): string {
|
|
212
|
-
if (!
|
|
213
|
-
const identityRoot = resolve(
|
|
224
|
+
if (!sourceIdentityRoot) return filePath;
|
|
225
|
+
const identityRoot = resolve(sourceIdentityRoot);
|
|
214
226
|
const logicalPath = relative(identityRoot, resolve(filePath));
|
|
215
227
|
if (
|
|
216
228
|
!logicalPath ||
|
|
@@ -254,8 +266,18 @@ function createPlayWorkspace(entryFile: string): PlayWorkspace {
|
|
|
254
266
|
};
|
|
255
267
|
}
|
|
256
268
|
|
|
257
|
-
function isPathInsideDirectory(
|
|
258
|
-
|
|
269
|
+
export function isPathInsideDirectory(
|
|
270
|
+
filePath: string,
|
|
271
|
+
directory: string,
|
|
272
|
+
pathApi: PathRelationshipApi = defaultPathRelationshipApi,
|
|
273
|
+
): boolean {
|
|
274
|
+
const relationship = pathApi.relative(directory, filePath);
|
|
275
|
+
return (
|
|
276
|
+
relationship === '' ||
|
|
277
|
+
(relationship !== '..' &&
|
|
278
|
+
!relationship.startsWith(`..${pathApi.sep}`) &&
|
|
279
|
+
!pathApi.isAbsolute(relationship))
|
|
280
|
+
);
|
|
259
281
|
}
|
|
260
282
|
|
|
261
283
|
function assertWithinPlayWorkspace(input: {
|
|
@@ -1851,6 +1873,7 @@ async function analyzeSourceGraph(
|
|
|
1851
1873
|
): Promise<SourceGraphAnalysis> {
|
|
1852
1874
|
const absoluteEntryFile = await normalizeLocalPath(entryFile);
|
|
1853
1875
|
const workspace = createPlayWorkspace(absoluteEntryFile);
|
|
1876
|
+
const sourceIdentityRoot = adapter.sourceIdentityRoot;
|
|
1854
1877
|
const localFiles = new Map<string, string>();
|
|
1855
1878
|
const nodeBuiltins = new Set<string>();
|
|
1856
1879
|
const packages = new Map<string, string | null>();
|
|
@@ -1961,10 +1984,10 @@ async function analyzeSourceGraph(
|
|
|
1961
1984
|
const sourceHash = sha256(sourceCode);
|
|
1962
1985
|
const graphHash = sha256(
|
|
1963
1986
|
JSON.stringify({
|
|
1964
|
-
entryFile: sourceIdentityPath(absoluteEntryFile,
|
|
1987
|
+
entryFile: sourceIdentityPath(absoluteEntryFile, sourceIdentityRoot),
|
|
1965
1988
|
localFiles: [...localFiles.entries()]
|
|
1966
1989
|
.map(([filePath, contents]) => ({
|
|
1967
|
-
filePath: sourceIdentityPath(filePath,
|
|
1990
|
+
filePath: sourceIdentityPath(filePath, sourceIdentityRoot),
|
|
1968
1991
|
hash: sha256(contents),
|
|
1969
1992
|
}))
|
|
1970
1993
|
.sort((left, right) => left.filePath.localeCompare(right.filePath)),
|
|
@@ -1974,7 +1997,7 @@ async function analyzeSourceGraph(
|
|
|
1974
1997
|
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
1975
1998
|
importedPlayDependencies: [...importedPlayDependencies.values()]
|
|
1976
1999
|
.map((dependency) => ({
|
|
1977
|
-
filePath: sourceIdentityPath(dependency.filePath,
|
|
2000
|
+
filePath: sourceIdentityPath(dependency.filePath, sourceIdentityRoot),
|
|
1978
2001
|
playName: dependency.playName,
|
|
1979
2002
|
}))
|
|
1980
2003
|
.sort((left, right) => left.filePath.localeCompare(right.filePath)),
|
|
@@ -2199,6 +2222,11 @@ export async function bundlePlayFile(
|
|
|
2199
2222
|
const exportName = options.exportName?.trim() || 'default';
|
|
2200
2223
|
assertValidExportName(exportName);
|
|
2201
2224
|
const absolutePath = await normalizeLocalPath(filePath);
|
|
2225
|
+
// Keep the existing absolute-path wire format unless a caller explicitly
|
|
2226
|
+
// opts into a logical identity root. Production's deployed checker still
|
|
2227
|
+
// uses absolute paths to reconcile bundled imports; source export normalizes
|
|
2228
|
+
// those paths into a portable tree at the API boundary.
|
|
2229
|
+
const sourceIdentityRoot = adapter.sourceIdentityRoot;
|
|
2202
2230
|
adapter.warnAboutNonDevelopmentBundling?.(absolutePath);
|
|
2203
2231
|
|
|
2204
2232
|
try {
|
|
@@ -2210,6 +2238,19 @@ export async function bundlePlayFile(
|
|
|
2210
2238
|
analysis.graphHash = sha256(
|
|
2211
2239
|
`${analysis.graphHash}\nentry-export:${exportName}\nauthoring-contract-edition:${PLAY_AUTHORING_CONTRACT_EDITION}`,
|
|
2212
2240
|
);
|
|
2241
|
+
const sourceFiles = Object.fromEntries(
|
|
2242
|
+
Object.entries(analysis.sourceFiles).map(([sourcePath, sourceCode]) => [
|
|
2243
|
+
sourceIdentityPath(sourcePath, sourceIdentityRoot),
|
|
2244
|
+
sourceCode,
|
|
2245
|
+
]),
|
|
2246
|
+
);
|
|
2247
|
+
const importPolicy: PlayImportPolicy = {
|
|
2248
|
+
...analysis.importPolicy,
|
|
2249
|
+
localFiles: analysis.importPolicy.localFiles.map((sourcePath) =>
|
|
2250
|
+
sourceIdentityPath(sourcePath, sourceIdentityRoot),
|
|
2251
|
+
),
|
|
2252
|
+
};
|
|
2253
|
+
const entryFile = sourceIdentityPath(absolutePath, sourceIdentityRoot);
|
|
2213
2254
|
try {
|
|
2214
2255
|
validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
|
|
2215
2256
|
} catch (error) {
|
|
@@ -2267,9 +2308,9 @@ export async function bundlePlayFile(
|
|
|
2267
2308
|
success: true,
|
|
2268
2309
|
artifact: {
|
|
2269
2310
|
...cachedArtifact,
|
|
2270
|
-
entryFile
|
|
2311
|
+
entryFile,
|
|
2271
2312
|
sourceHash: analysis.sourceHash,
|
|
2272
|
-
importPolicy
|
|
2313
|
+
importPolicy,
|
|
2273
2314
|
compatibility: buildPlayContractCompatibility({
|
|
2274
2315
|
toolErrorSchemaVersion:
|
|
2275
2316
|
analysis.toolErrorSchemaVersion ?? undefined,
|
|
@@ -2277,7 +2318,7 @@ export async function bundlePlayFile(
|
|
|
2277
2318
|
cacheHit: true,
|
|
2278
2319
|
},
|
|
2279
2320
|
sourceCode: analysis.sourceCode,
|
|
2280
|
-
sourceFiles
|
|
2321
|
+
sourceFiles,
|
|
2281
2322
|
filePath: absolutePath,
|
|
2282
2323
|
playName: analysis.playName,
|
|
2283
2324
|
playDescription: analysis.playDescription,
|
|
@@ -2330,7 +2371,7 @@ export async function bundlePlayFile(
|
|
|
2330
2371
|
const artifact: PlayBundleArtifact = {
|
|
2331
2372
|
codeFormat: 'cjs_module',
|
|
2332
2373
|
artifactKind: target,
|
|
2333
|
-
entryFile
|
|
2374
|
+
entryFile,
|
|
2334
2375
|
virtualFilename,
|
|
2335
2376
|
sourceHash: analysis.sourceHash,
|
|
2336
2377
|
graphHash: analysis.graphHash,
|
|
@@ -2338,7 +2379,7 @@ export async function bundlePlayFile(
|
|
|
2338
2379
|
sourceMapHash: sha256(normalizedSourceMap),
|
|
2339
2380
|
bundledCode: executableCode,
|
|
2340
2381
|
sourceMap: normalizedSourceMap,
|
|
2341
|
-
importPolicy
|
|
2382
|
+
importPolicy,
|
|
2342
2383
|
compatibility: buildPlayContractCompatibility({
|
|
2343
2384
|
toolErrorSchemaVersion: analysis.toolErrorSchemaVersion ?? undefined,
|
|
2344
2385
|
}),
|
|
@@ -2352,7 +2393,7 @@ export async function bundlePlayFile(
|
|
|
2352
2393
|
success: true,
|
|
2353
2394
|
artifact,
|
|
2354
2395
|
sourceCode: analysis.sourceCode,
|
|
2355
|
-
sourceFiles
|
|
2396
|
+
sourceFiles,
|
|
2356
2397
|
filePath: absolutePath,
|
|
2357
2398
|
playName: analysis.playName,
|
|
2358
2399
|
playDescription: analysis.playDescription,
|
|
@@ -691,10 +691,20 @@ export function compileEnrichConfigToPlaySource(
|
|
|
691
691
|
const runOptionsSource = options.failFast
|
|
692
692
|
? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }`
|
|
693
693
|
: `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
|
|
694
|
+
const describedColumns = config.commands
|
|
695
|
+
.filter((command) => isWaterfall(command) || !command.disabled)
|
|
696
|
+
.map((command) =>
|
|
697
|
+
(isWaterfall(command) ? command.with_waterfall : command.alias)
|
|
698
|
+
.replace(/[_-]+/g, ' ')
|
|
699
|
+
.trim(),
|
|
700
|
+
)
|
|
701
|
+
.filter(Boolean)
|
|
702
|
+
.slice(0, 3);
|
|
703
|
+
const generatedDescription = describedColumns.length
|
|
704
|
+
? `Enrich CSV rows with ${describedColumns.join(', ')}.`
|
|
705
|
+
: 'Prepare CSV rows for enrichment.';
|
|
694
706
|
const playOptionsSource = [
|
|
695
|
-
`description: ${stringLiteral(
|
|
696
|
-
'Read a CSV file, run the configured Deepline enrich commands, and return enriched rows.',
|
|
697
|
-
)}`,
|
|
707
|
+
`description: ${stringLiteral(generatedDescription)}`,
|
|
698
708
|
...(options.maxCreditsPerRun === undefined
|
|
699
709
|
? []
|
|
700
710
|
: [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]),
|
|
@@ -49,3 +49,15 @@ export const TOOL_CATEGORY_DESCRIPTIONS: Readonly<Record<string, string>> = {
|
|
|
49
49
|
export function describeToolCategory(category: string): string | null {
|
|
50
50
|
return TOOL_CATEGORY_DESCRIPTIONS[category] ?? null;
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
/** Human-readable label for a canonical tool-category slug. */
|
|
54
|
+
export function formatToolCategoryLabel(category: string): string {
|
|
55
|
+
const normalized = category
|
|
56
|
+
.trim()
|
|
57
|
+
.replace(/[_-]+/g, ' ')
|
|
58
|
+
.replace(/\s+/g, ' ')
|
|
59
|
+
.toLowerCase();
|
|
60
|
+
return normalized
|
|
61
|
+
? `${normalized[0]?.toUpperCase() ?? ''}${normalized.slice(1)}`
|
|
62
|
+
: '';
|
|
63
|
+
}
|