deepline 0.3.463 → 0.3.464

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 (158) hide show
  1. package/dist/bundling-sources/sdk/src/play.ts +3 -0
  2. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  3. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +3 -1
  4. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +16 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +98 -0
  6. package/dist/bundling-sources/shared_libs/plays/field-catalog.ts +353 -52
  7. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +63 -3
  8. package/dist/cli/{auth-LZLBR4C3.mjs → auth-GMSI6QWR.mjs} +5 -5
  9. package/dist/cli/auth-P4E7M3AV.js +41 -0
  10. package/dist/cli/{billing-OTOP5RE4.mjs → billing-6G2RFLM7.mjs} +6 -6
  11. package/dist/cli/{billing-6TJPNJQD.js → billing-MGH36CNP.js} +77 -77
  12. package/dist/cli/{chunk-5DRNNC72.js → chunk-2RFTOESC.js} +5 -5
  13. package/dist/cli/{chunk-NDHJR2WZ.js → chunk-3AIMFE3Z.js} +36 -36
  14. package/dist/cli/{chunk-S4XQCFES.mjs → chunk-3MKRAI6R.mjs} +5 -5
  15. package/dist/cli/{chunk-NTLI6P6Y.mjs → chunk-44BEFU62.mjs} +2 -2
  16. package/dist/cli/{chunk-3BOIOCNX.js → chunk-4XNXFHG6.js} +1 -1
  17. package/dist/cli/{chunk-F2RHUPVH.mjs → chunk-5CKIO7KA.mjs} +1 -1
  18. package/dist/cli/{chunk-2ZIRCBYG.js → chunk-5XIGEYYK.js} +6 -6
  19. package/dist/cli/{chunk-WUMIYOXQ.mjs → chunk-6A7OH2PV.mjs} +2 -2
  20. package/dist/cli/{chunk-3BVLLJ3H.mjs → chunk-6COF5LIE.mjs} +2 -2
  21. package/dist/cli/{chunk-O3BJYD6D.mjs → chunk-6E2KNNTD.mjs} +2 -2
  22. package/dist/cli/{chunk-UIURR26V.mjs → chunk-6KDOO7IM.mjs} +4 -4
  23. package/dist/cli/{chunk-5LEAXRHV.js → chunk-6P4OYABU.js} +54 -226
  24. package/dist/cli/chunk-7YDN6AEK.mjs +649 -0
  25. package/dist/cli/{chunk-UROQDCVW.js → chunk-ACZLDP7L.js} +3 -3
  26. package/dist/cli/{chunk-UC4SFYNU.js → chunk-BMUDQMYE.js} +6 -6
  27. package/dist/cli/{chunk-DHXCBITQ.mjs → chunk-CUZVOPPY.mjs} +3 -3
  28. package/dist/cli/{chunk-CTQ56DXP.mjs → chunk-DO3FSI4C.mjs} +1 -1
  29. package/dist/cli/{chunk-2NISBXMN.js → chunk-E4QJKJH6.js} +51 -51
  30. package/dist/cli/{chunk-WUZS2HK6.js → chunk-EQNJUG3N.js} +53 -53
  31. package/dist/cli/{chunk-CBZP6J3V.js → chunk-FEWZT4RV.js} +21 -21
  32. package/dist/cli/{chunk-NAPTMYTY.js → chunk-FVAB2JRO.js} +8 -8
  33. package/dist/cli/{chunk-BGNWI3KH.js → chunk-GVJVBBGV.js} +3 -3
  34. package/dist/cli/{chunk-GUT7CLOL.mjs → chunk-HGUHBLX5.mjs} +3 -3
  35. package/dist/cli/{chunk-6PMCRYDA.js → chunk-HIMV32ZX.js} +6 -4
  36. package/dist/cli/{chunk-MSY22NQW.mjs → chunk-I2TCWIW2.mjs} +44 -216
  37. package/dist/cli/{chunk-XDWS2JJT.mjs → chunk-J327QVQV.mjs} +1 -1
  38. package/dist/cli/chunk-JLZKF7EY.js +649 -0
  39. package/dist/cli/{chunk-FK2HNDCN.js → chunk-K3BARC72.js} +2 -2
  40. package/dist/cli/{chunk-TIRBDQ3W.js → chunk-K4DVRQTY.js} +16 -16
  41. package/dist/cli/{chunk-XQCTG5OO.js → chunk-L3U44YVO.js} +5 -5
  42. package/dist/cli/{chunk-XW2JIYG7.mjs → chunk-M4QVY6RW.mjs} +2 -2
  43. package/dist/cli/{chunk-I624J4H5.mjs → chunk-MP3O4ISC.mjs} +1 -1
  44. package/dist/cli/{chunk-3U5EAP6E.mjs → chunk-MQNBOSQP.mjs} +5 -5
  45. package/dist/cli/{chunk-TKAQR3IB.mjs → chunk-MUQAKLBP.mjs} +1 -1
  46. package/dist/cli/{chunk-YGGIZ3VT.js → chunk-NI3QFUK7.js} +4 -4
  47. package/dist/cli/{chunk-BAPTQDLF.mjs → chunk-O4AOYLZE.mjs} +2 -2
  48. package/dist/cli/{chunk-5LHXOIPT.js → chunk-O4ZMADW4.js} +7 -7
  49. package/dist/cli/{chunk-7D6X7IXW.mjs → chunk-OA7IIOLW.mjs} +4 -4
  50. package/dist/cli/{chunk-VPHN2HAL.mjs → chunk-OGCAGZXO.mjs} +6 -4
  51. package/dist/cli/{chunk-C25QE4CH.mjs → chunk-PPQL5F4P.mjs} +1 -1
  52. package/dist/cli/{chunk-4YZKBBLZ.mjs → chunk-RFOQRCMW.mjs} +5 -5
  53. package/dist/cli/{chunk-LYFKBLJI.mjs → chunk-TMVBBGSK.mjs} +1 -1
  54. package/dist/cli/{chunk-PVY4DPPF.js → chunk-TU3M7UXJ.js} +13 -13
  55. package/dist/cli/{chunk-VDGTTH7K.mjs → chunk-UM363DQF.mjs} +2 -2
  56. package/dist/cli/{chunk-VY2GBNTX.js → chunk-UOAHDEAI.js} +9 -9
  57. package/dist/cli/{chunk-RD6IQ2JY.mjs → chunk-VQHEMZ33.mjs} +1 -1
  58. package/dist/cli/{chunk-IKWRUNAP.mjs → chunk-VYDOPASG.mjs} +1 -1
  59. package/dist/cli/{chunk-JVDKZJUH.js → chunk-VZX4P5FT.js} +258 -258
  60. package/dist/cli/{chunk-ALZBANZI.js → chunk-WLIFUH6W.js} +8 -8
  61. package/dist/cli/{chunk-7FCYPAPP.js → chunk-X3XJ6ZSJ.js} +2 -2
  62. package/dist/cli/{chunk-CVQ7N5CV.mjs → chunk-XMDBN2K7.mjs} +11 -11
  63. package/dist/cli/{chunk-RGOUCIIZ.js → chunk-ZAB6KCZW.js} +3 -3
  64. package/dist/cli/{chunk-SKU6ECIY.js → chunk-ZIMCLWEW.js} +5 -5
  65. package/dist/cli/{chunk-7XYDDCQ2.js → chunk-ZQERHPZA.js} +26 -26
  66. package/dist/cli/command-docs.js +2 -2
  67. package/dist/cli/command-docs.mjs +1 -1
  68. package/dist/cli/{csv-OK45Z5XQ.mjs → csv-4ZVMBOCK.mjs} +4 -4
  69. package/dist/cli/{csv-EH5QWR4O.js → csv-W2JPV57R.js} +13 -13
  70. package/dist/cli/{db-3ESJKETS.js → db-6YNFDHEW.js} +27 -27
  71. package/dist/cli/{db-6Z5E4HKN.mjs → db-TVK6BLRB.mjs} +6 -6
  72. package/dist/cli/describe-APW5TWBT.js +48 -0
  73. package/dist/cli/{describe-PNDQB7YS.mjs → describe-JFN4ECPO.mjs} +20 -20
  74. package/dist/cli/describe-core.d.mts +3 -3
  75. package/dist/cli/describe-core.d.ts +3 -3
  76. package/dist/cli/describe-core.js +4 -4
  77. package/dist/cli/describe-core.mjs +3 -3
  78. package/dist/cli/{executions-2NTWQFEG.mjs → executions-2FK4FFKE.mjs} +6 -6
  79. package/dist/cli/{executions-KUOBRX5V.js → executions-J4CAN7RB.js} +8 -8
  80. package/dist/cli/{feedback-7RPRMSGY.mjs → feedback-EYRRLA2P.mjs} +4 -4
  81. package/dist/cli/{feedback-UPHAZJ4C.js → feedback-NOO4OM4U.js} +8 -8
  82. package/dist/cli/{git-SCYP6WSZ.mjs → git-D3Q4JKBC.mjs} +5 -5
  83. package/dist/cli/git-FPF6DT43.js +25 -0
  84. package/dist/cli/index.js +139 -139
  85. package/dist/cli/index.mjs +41 -41
  86. package/dist/cli/{legacy-noops-7XMFCVRG.js → legacy-noops-5ZGRKSN3.js} +8 -8
  87. package/dist/cli/{legacy-noops-A4KYAGI6.mjs → legacy-noops-SUFJWBLZ.mjs} +5 -5
  88. package/dist/cli/{monitors-NZV6IX5H.js → monitors-3QFJZA6Z.js} +91 -91
  89. package/dist/cli/{monitors-FLC5J7RI.mjs → monitors-IRDIIR6J.mjs} +7 -7
  90. package/dist/cli/{org-IZ7UP3XF.js → org-275OJJ7W.js} +68 -68
  91. package/dist/cli/{org-LUETJ7Z5.mjs → org-2VA2FSMG.mjs} +6 -6
  92. package/dist/cli/{pages-22ML3O7O.js → pages-SPRBOZRA.js} +17 -17
  93. package/dist/cli/{pages-EUX5EAGF.mjs → pages-WCUEBFYU.mjs} +6 -6
  94. package/dist/cli/{play-CDHPAKKM.mjs → play-7UL5H6QU.mjs} +18 -18
  95. package/dist/cli/{play-USJBQADG.js → play-NMHUWBET.js} +305 -305
  96. package/dist/cli/{providers-WFEUNPGC.js → providers-72LUJEAT.js} +9 -9
  97. package/dist/cli/{providers-CCXZ3SQF.mjs → providers-WSCKV557.mjs} +6 -6
  98. package/dist/cli/{quickstart-ZUULI635.mjs → quickstart-K4LAKJKJ.mjs} +4 -4
  99. package/dist/cli/{quickstart-O4JSUORZ.js → quickstart-XSUUAE2Y.js} +6 -6
  100. package/dist/cli/{run-ISDJYJMU.js → run-MLV2CLW7.js} +40 -40
  101. package/dist/cli/{run-QJ4NX5F5.mjs → run-R2MOXXHH.mjs} +25 -25
  102. package/dist/cli/search-AYFUV6YV.js +32 -0
  103. package/dist/cli/{search-IX3XKZJ3.mjs → search-WHJZNWKE.mjs} +7 -7
  104. package/dist/cli/{secrets-ELQSNCTR.js → secrets-7PXFBOFY.js} +15 -15
  105. package/dist/cli/{secrets-7VUDXTUZ.mjs → secrets-YGVOFLI5.mjs} +6 -6
  106. package/dist/cli/{sessions-A3FG3AZX.js → sessions-ASXXZI42.js} +6 -6
  107. package/dist/cli/{sessions-VOIQ62GB.mjs → sessions-G7I54W4L.mjs} +5 -5
  108. package/dist/cli/{settings-S6N6EFBG.mjs → settings-4GFO6JYO.mjs} +11 -11
  109. package/dist/cli/{settings-ZTXQEMZI.js → settings-RTEBMDPC.js} +78 -78
  110. package/dist/cli/{setup-AYPIK4JE.mjs → setup-4RJGKSDC.mjs} +9 -9
  111. package/dist/cli/{setup-Y3WOIFLS.js → setup-A6V2MJK7.js} +44 -44
  112. package/dist/cli/{skills-5SF5QWNI.mjs → skills-432W6EGS.mjs} +7 -7
  113. package/dist/cli/skills-GOQECD7H.js +31 -0
  114. package/dist/cli/tools-JXYN7WOE.js +55 -0
  115. package/dist/cli/{tools-3XNZ4J64.mjs → tools-SABREK3C.mjs} +18 -18
  116. package/dist/cli/update-BSB4TJER.js +33 -0
  117. package/dist/cli/{update-3U4OVX5R.mjs → update-F7NO5RDW.mjs} +9 -9
  118. package/dist/cli/{workflow-2M5JP7SA.mjs → workflow-F4N7CFUX.mjs} +7 -7
  119. package/dist/cli/{workflow-RM7H7555.js → workflow-TF6YDWTM.js} +17 -17
  120. package/dist/{client-DTwnz_AW.d.mts → client-ADFHNtFM.d.mts} +1 -1
  121. package/dist/{client-DS2IWYZF.d.ts → client-BClp2yrq.d.ts} +1 -1
  122. package/dist/{client-core-B_6HAIBy.d.ts → client-core-BFU73Ttw.d.ts} +1 -1
  123. package/dist/{client-core-DzBSlY1U.d.mts → client-core-DWLmmJWo.d.mts} +1 -1
  124. package/dist/{compiler-manifest-Dcyd3-Zd.d.ts → compiler-manifest-Cs17yO-H.d.mts} +321 -3
  125. package/dist/{compiler-manifest-Dcyd3-Zd.d.mts → compiler-manifest-Cs17yO-H.d.ts} +321 -3
  126. package/dist/{errors-yQwfgrcX.d.ts → errors-Dee-QpVS.d.ts} +1 -1
  127. package/dist/{errors-d-sTrZhe.d.mts → errors-qNfvQuRB.d.mts} +1 -1
  128. package/dist/{index-C6oXchjN.d.mts → index-BTqNNXmC.d.mts} +1 -1
  129. package/dist/{index-P56zy_z5.d.ts → index-DXTh1Lxe.d.ts} +1 -1
  130. package/dist/index.d.mts +7 -7
  131. package/dist/index.d.ts +7 -7
  132. package/dist/index.js +80 -13
  133. package/dist/index.mjs +76 -9
  134. package/dist/install-integrity.json +114 -114
  135. package/dist/plays/bundle-play-file.d.mts +3 -3
  136. package/dist/plays/bundle-play-file.d.ts +3 -3
  137. package/dist/plays/play-description.d.mts +2 -2
  138. package/dist/plays/play-description.d.ts +2 -2
  139. package/dist/plays/run-request.d.mts +2 -2
  140. package/dist/plays/run-request.d.ts +2 -2
  141. package/dist/release.d.mts +1 -1
  142. package/dist/release.d.ts +1 -1
  143. package/dist/release.js +2 -2
  144. package/dist/release.mjs +1 -1
  145. package/dist/server.d.mts +4 -4
  146. package/dist/server.d.ts +4 -4
  147. package/dist/server.js +5 -5
  148. package/dist/server.mjs +3 -3
  149. package/package.json +1 -1
  150. package/dist/cli/auth-XPGKBJKB.js +0 -41
  151. package/dist/cli/chunk-NA4T3B62.js +0 -286
  152. package/dist/cli/chunk-TXZVVBQZ.mjs +0 -286
  153. package/dist/cli/describe-QUF7VTTR.js +0 -48
  154. package/dist/cli/git-UH653WHV.js +0 -25
  155. package/dist/cli/search-TIFNLRPM.js +0 -32
  156. package/dist/cli/skills-MWFRMG3H.js +0 -31
  157. package/dist/cli/tools-XEC4OD3R.js +0 -55
  158. package/dist/cli/update-DWYEYTZE.js +0 -33
@@ -4,22 +4,30 @@ import type { DeeplineExtractorTarget } from './extractor-targets';
4
4
  * The catalog of things a tool or play can take or return about a person or
5
5
  * a company, named by what they are instead of by what a provider calls them.
6
6
  *
7
- * An id is a dotted path that always ends in a leaf:
7
+ * An id is a dotted path that always ends in `.value`:
8
8
  *
9
9
  * person.email.value any email for the person
10
10
  * person.email.work.value their work email
11
- * person.email.work.validated whether that work email was validated
11
+ * person.email.work.validated.value whether it was validated
12
12
  *
13
- * It reads `<entity>.<group>[.<kind>].<leaf>`. A group is one thing about the
14
- * entity (an email). A leaf is one fact about that thing (its value, whether
15
- * it was validated). A kind narrows which one is meant (work, personal). No
16
- * id is both a field and a parent of fields, so `person.email` alone is never
17
- * a field; the plain value is `person.email.value`.
13
+ * It reads `<entity>.<group>[.<group>][.<kind>][.<leaf>].value`. A group is one thing
14
+ * about the entity (an email), and may hold groups of its own (a job's
15
+ * title). A leaf is one fact about that thing (its value, whether it was
16
+ * validated). A kind narrows which one is meant (work, personal). No id is
17
+ * both a field and a parent of fields, so `person.email` alone is never a
18
+ * field; the plain value is `person.email.value`.
18
19
  *
19
- * A kind is a narrowing, so a field with a kind also answers for the same
20
- * field without it: a tool that returns `person.email.work.value` satisfies a
21
- * request for `person.email.value`. A tool that cannot tell which kind it has
22
- * declares the id without one.
20
+ * A narrower field answers for every more general one:
21
+ *
22
+ * person.email.work.value answers person.email.value (its kind dropped)
23
+ * person.email.value answers entity.email.value (a person or company)
24
+ *
25
+ * A tool that cannot tell which kind it has declares the id without one; a
26
+ * tool whose record may be a person or a company declares the `entity` id.
27
+ *
28
+ * `provider.<provider>.<...>.value` names a value that belongs to one
29
+ * provider and is not about a person or company (a HubSpot list's name). It
30
+ * is declared where the provider's tool is, and answers only for itself.
23
31
  *
24
32
  * This is an addition. Existing short names (`email`, `name`) keep working;
25
33
  * `EXTRACTOR_TARGET_FIELDS` records what each can mean.
@@ -28,9 +36,11 @@ type Leaf = { type: string; description: string };
28
36
 
29
37
  type Group = {
30
38
  description: string;
31
- leaves: Record<string, Leaf>;
39
+ leaves?: Record<string, Leaf>;
32
40
  /** Narrowings of this group. Each has every leaf the group has. */
33
41
  kinds?: Record<string, string>;
42
+ /** Things within this one, each a group of its own. */
43
+ groups?: Record<string, Group>;
34
44
  };
35
45
 
36
46
  const value = (description: string): Leaf => ({ type: 'string', description });
@@ -43,11 +53,12 @@ const SOURCE: Leaf = {
43
53
  export const FIELD_CATALOG = {
44
54
  person: {
45
55
  name: {
46
- description: "The person's name.",
47
- leaves: {
48
- value: value('Full name.'),
49
- first: value('First (given) name.'),
50
- last: value('Last (family) name.'),
56
+ description: "The person's name. Without a kind, a name in some form.",
57
+ leaves: { value: value('The name.') },
58
+ kinds: {
59
+ full: 'Their full name.',
60
+ first: 'Their first (given) name.',
61
+ last: 'Their last (family) name.',
51
62
  },
52
63
  },
53
64
  email: {
@@ -92,12 +103,25 @@ export const FIELD_CATALOG = {
92
103
  },
93
104
  linkedin: {
94
105
  description: "The person's LinkedIn profile.",
95
- leaves: { url: value('The profile URL.') },
106
+ leaves: {
107
+ url: value('The profile URL.'),
108
+ id: value("LinkedIn's id or public identifier for the profile."),
109
+ },
96
110
  },
97
111
  job: {
98
112
  description: "The person's current role.",
113
+ groups: {
114
+ title: {
115
+ description:
116
+ 'What their role is called. Without a kind, a job title or, failing one, their profile headline.',
117
+ leaves: { value: value('The title.') },
118
+ kinds: {
119
+ exact: 'Their job title, never a headline.',
120
+ headline: 'Their profile headline, used as a title.',
121
+ },
122
+ },
123
+ },
99
124
  leaves: {
100
- title: value('Job title.'),
101
125
  change: {
102
126
  type: 'JobChange',
103
127
  description: 'Whether they changed jobs, and to what.',
@@ -144,6 +168,72 @@ export const FIELD_CATALOG = {
144
168
  leaves: { id: value("The provider's id for the company.") },
145
169
  },
146
170
  },
171
+ job: {
172
+ posting: {
173
+ description: 'A job posting.',
174
+ groups: {
175
+ title: {
176
+ description: "The posting's title. Not a person's job title.",
177
+ leaves: { value: value('The title.') },
178
+ },
179
+ },
180
+ },
181
+ },
182
+ podcast: {
183
+ name: {
184
+ description: "A podcast's name.",
185
+ leaves: { value: value('The name.') },
186
+ },
187
+ website: {
188
+ description: "A podcast's own page.",
189
+ leaves: { url: value('The URL.') },
190
+ },
191
+ },
192
+ post: {
193
+ title: {
194
+ description: "A social or business post's title.",
195
+ leaves: { value: value('The title.') },
196
+ },
197
+ author: {
198
+ description: "A post's author, who may be a person or a company.",
199
+ groups: {
200
+ name: {
201
+ description: "The author's name.",
202
+ leaves: { value: value('The name.') },
203
+ },
204
+ },
205
+ },
206
+ },
207
+ page: {
208
+ title: {
209
+ description: "A web page's title.",
210
+ leaves: { value: value('The title.') },
211
+ },
212
+ },
213
+ // Some entity's value, when a tool cannot say whether it is a person's or a
214
+ // company's. Each field here is answered by the same field of either.
215
+ entity: {
216
+ name: {
217
+ description: "A person's or company's name.",
218
+ leaves: { value: value('The name.') },
219
+ },
220
+ email: {
221
+ description: 'An email address for a person or company.',
222
+ leaves: { value: value('The address.') },
223
+ },
224
+ phone: {
225
+ description: 'A phone number for a person or company.',
226
+ leaves: { value: value('The number.') },
227
+ },
228
+ linkedin: {
229
+ description: "A person's or company's LinkedIn page.",
230
+ leaves: { url: value('The page URL.') },
231
+ },
232
+ record: {
233
+ description: "A provider's own record of a person or company.",
234
+ leaves: { id: value("The provider's id for the record.") },
235
+ },
236
+ },
147
237
  } as const satisfies Record<string, Record<string, Group>>;
148
238
 
149
239
  export type FieldEntity = keyof typeof FIELD_CATALOG;
@@ -151,25 +241,51 @@ export type FieldEntity = keyof typeof FIELD_CATALOG;
151
241
  export type CatalogField = Leaf & {
152
242
  id: string;
153
243
  entity: FieldEntity;
244
+ /** The group's path within the entity, such as `email` or `job.title`. */
154
245
  group: string;
155
246
  kind?: string;
156
247
  leaf: string;
157
248
  };
158
249
 
250
+ // Every id ends in `.value`, so `.values` reads the same way on every field.
251
+ function fieldId(
252
+ entity: string,
253
+ group: string,
254
+ kind: string | undefined,
255
+ leaf: string,
256
+ ): string {
257
+ return [entity, group, kind, leaf === 'value' ? undefined : leaf, 'value']
258
+ .filter(Boolean)
259
+ .join('.');
260
+ }
261
+
262
+ function groupFields(
263
+ entity: FieldEntity,
264
+ group: string,
265
+ definition: Group,
266
+ ): CatalogField[] {
267
+ const own = [undefined, ...Object.keys(definition.kinds ?? {})].flatMap(
268
+ (kind) =>
269
+ Object.entries(definition.leaves ?? {}).map(([leaf, described]) => ({
270
+ ...described,
271
+ id: fieldId(entity, group, kind, leaf),
272
+ entity,
273
+ group,
274
+ ...(kind ? { kind } : {}),
275
+ leaf,
276
+ })),
277
+ );
278
+ const nested = Object.entries(definition.groups ?? {}).flatMap(
279
+ ([name, child]) => groupFields(entity, `${group}.${name}`, child),
280
+ );
281
+ return [...own, ...nested];
282
+ }
283
+
159
284
  /** Every field in the catalog, with and without each kind. */
160
285
  export function catalogFields(): CatalogField[] {
161
286
  return Object.entries(FIELD_CATALOG).flatMap(([entity, groups]) =>
162
287
  Object.entries<Group>(groups).flatMap(([group, definition]) =>
163
- [undefined, ...Object.keys(definition.kinds ?? {})].flatMap((kind) =>
164
- Object.entries(definition.leaves).map(([leaf, described]) => ({
165
- ...described,
166
- id: [entity, group, kind, leaf].filter(Boolean).join('.'),
167
- entity: entity as FieldEntity,
168
- group,
169
- ...(kind ? { kind } : {}),
170
- leaf,
171
- })),
172
- ),
288
+ groupFields(entity as FieldEntity, group, definition),
173
289
  ),
174
290
  );
175
291
  }
@@ -180,15 +296,45 @@ export function catalogField(id: string): CatalogField | undefined {
180
296
  return FIELDS_BY_ID.get(id);
181
297
  }
182
298
 
299
+ const PROVIDER_FIELD = /^provider\.[a-z0-9_-]+(\.[a-z0-9_]+)+\.value$/;
300
+
301
+ /**
302
+ * Whether `id` names a field: one in the catalog, or a provider's own
303
+ * (`provider.hubspot.list.name.value`).
304
+ */
305
+ export function isFieldId(id: string): boolean {
306
+ return FIELDS_BY_ID.has(id) || PROVIDER_FIELD.test(id);
307
+ }
308
+
183
309
  /** The same field without its kind, or null when it has none to drop. */
184
310
  export function generalField(id: string): string | null {
185
311
  const field = FIELDS_BY_ID.get(id);
186
- return field?.kind ? [field.entity, field.group, field.leaf].join('.') : null;
312
+ return field?.kind
313
+ ? fieldId(field.entity, field.group, undefined, field.leaf)
314
+ : null;
315
+ }
316
+
317
+ /**
318
+ * Every more general field this one answers for: without its kind, and as
319
+ * the `entity` field when there is one.
320
+ */
321
+ export function generalFields(id: string): string[] {
322
+ const field = FIELDS_BY_ID.get(id);
323
+ if (!field) return [];
324
+ const general = generalField(id);
325
+ const entity = fieldId('entity', field.group, undefined, field.leaf);
326
+ return [
327
+ ...(general ? [general] : []),
328
+ ...((field.entity === 'person' || field.entity === 'company') &&
329
+ FIELDS_BY_ID.has(entity)
330
+ ? [entity]
331
+ : []),
332
+ ];
187
333
  }
188
334
 
189
335
  /** Whether a tool returning `offered` gives a caller what `wanted` asks for. */
190
336
  export function fieldSatisfies(offered: string, wanted: string): boolean {
191
- return offered === wanted || generalField(offered) === wanted;
337
+ return offered === wanted || generalFields(offered).includes(wanted);
192
338
  }
193
339
 
194
340
  /**
@@ -204,50 +350,205 @@ export const EXTRACTOR_TARGET_FIELDS: Record<
204
350
  > = {
205
351
  email: ['person.email.value'],
206
352
  personal_email: ['person.email.personal.value'],
207
- email_status: ['person.email.status'],
353
+ email_status: ['person.email.status.value'],
208
354
  phone: ['person.phone.value', 'company.phone.value'],
209
- phone_status: ['person.phone.status'],
210
- first_name: ['person.name.first'],
211
- last_name: ['person.name.last'],
212
- full_name: ['person.name.value'],
355
+ phone_status: ['person.phone.status.value'],
356
+ first_name: ['person.name.first.value'],
357
+ last_name: ['person.name.last.value'],
358
+ full_name: ['person.name.full.value'],
213
359
  // Also used for a list name, a channel title and a search suggestion.
214
360
  name: ['person.name.value', 'company.name.value'],
215
- linkedin: ['person.linkedin.url', 'company.linkedin.url'],
216
- linkedin_url: ['person.linkedin.url'],
217
- title: ['person.job.title'],
218
- job_change: ['person.job.change'],
219
- job_change_status: ['person.job.change_status'],
361
+ linkedin: [
362
+ 'person.linkedin.url.value',
363
+ 'person.linkedin.id.value',
364
+ 'company.linkedin.url.value',
365
+ ],
366
+ linkedin_url: ['person.linkedin.url.value'],
367
+ title: ['person.job.title.value'],
368
+ job_change: ['person.job.change.value'],
369
+ job_change_status: ['person.job.change_status.value'],
220
370
  company: ['company.name.value'],
221
371
  company_name: ['company.name.value'],
222
372
  organization_name: ['company.name.value'],
223
373
  company_domain: ['company.domain.value'],
224
374
  domain: ['company.domain.value'],
225
- company_website: ['company.website.url'],
375
+ company_website: ['company.website.url.value'],
226
376
  // Also used for a podcast URL.
227
- website: ['company.website.url'],
228
- company_linkedin_url: ['company.linkedin.url'],
377
+ website: ['company.website.url.value'],
378
+ company_linkedin_url: ['company.linkedin.url.value'],
229
379
  industry: ['company.industry.value'],
230
- id: ['person.record.id', 'company.record.id'],
380
+ id: ['person.record.id.value', 'company.record.id.value'],
231
381
  // Used for unrelated provider statuses; none is a catalog field.
232
382
  status: [],
233
383
  };
234
384
 
235
385
  /**
236
- * The catalog field a short name stands for on one tool: what the tool
237
- * declares, or else the name's one meaning. Undefined when the name is
238
- * ambiguous and the tool has not said, or when what it said is not something
239
- * the name can mean.
386
+ * The field a short name stands for on one tool: what the tool declares, or
387
+ * else the name's one meaning. Undefined when the name is ambiguous and the
388
+ * tool has not said, or when what it said is not something the name can mean.
389
+ * Any name may be declared as a provider's own field, or as a field of a
390
+ * thing that is neither a person nor a company.
240
391
  */
241
392
  export function fieldOfName(
242
393
  name: string,
243
394
  declared?: string,
244
395
  ): string | undefined {
245
- const meanings: readonly string[] =
246
- EXTRACTOR_TARGET_FIELDS[name as DeeplineExtractorTarget] ?? [];
396
+ const meanings = nameMeanings(name);
247
397
  if (declared === undefined) {
248
398
  return meanings.length === 1 ? meanings[0] : undefined;
249
399
  }
250
- return meanings.some((meaning) => fieldSatisfies(declared, meaning))
400
+ return isOtherThing(declared) ||
401
+ meanings.some((meaning) => relatedFields(declared, meaning))
251
402
  ? declared
252
403
  : undefined;
253
404
  }
405
+
406
+ function nameMeanings(name: string): readonly string[] {
407
+ return EXTRACTOR_TARGET_FIELDS[name as DeeplineExtractorTarget] ?? [];
408
+ }
409
+
410
+ // A narrowing of a meaning (`email` as a work email), or a generalization of
411
+ // one (`name` as `entity.name.value` when the record may be either).
412
+ function relatedFields(a: string, b: string): boolean {
413
+ return fieldSatisfies(a, b) || fieldSatisfies(b, a);
414
+ }
415
+
416
+ /**
417
+ * A provider's own field, or a thing that is neither a person nor a company.
418
+ * Any output may be declared as one, whatever its name.
419
+ */
420
+ function isOtherThing(id: string): boolean {
421
+ if (PROVIDER_FIELD.test(id)) return true;
422
+ const entity = FIELDS_BY_ID.get(id)?.entity;
423
+ return (
424
+ entity !== undefined &&
425
+ entity !== 'person' &&
426
+ entity !== 'company' &&
427
+ entity !== 'entity'
428
+ );
429
+ }
430
+
431
+ /** One output of a tool, and the catalog field it is. */
432
+ export type FieldBinding = { name: string; id: string };
433
+
434
+ /**
435
+ * The one output a name stands for, among a result's bindings. A name is
436
+ * tried as an exact id, then as a more general id that exactly one declared
437
+ * field narrows, then as the output's own name, then as a short name the
438
+ * catalog knows. The first step with a single field wins. Two or more at a
439
+ * step is an error listing them: this never picks between candidates.
440
+ * Undefined when nothing matches, or when `name` is one of the target's
441
+ * `outputs` that is not a field: a tool's own name means its own output.
442
+ */
443
+ export function resolveFieldName(
444
+ name: string,
445
+ bindings: readonly FieldBinding[],
446
+ outputs: readonly string[] = [],
447
+ ): FieldBinding | undefined {
448
+ // Two outputs declared as the same field are the same field.
449
+ const byId = new Map<string, FieldBinding>();
450
+ for (const binding of bindings) {
451
+ if (!byId.has(binding.id)) byId.set(binding.id, binding);
452
+ }
453
+ const fields = [...byId.values()];
454
+ const pick = (matches: FieldBinding[]): FieldBinding | undefined => {
455
+ if (matches.length > 1) {
456
+ throw new Error(
457
+ `"${name}" could be ${matches.map((match) => `${match.id} (${match.name})`).join(' or ')}. Use one of those ids.`,
458
+ );
459
+ }
460
+ return matches[0];
461
+ };
462
+ const viaId = (id: string) =>
463
+ byId.get(id) ??
464
+ pick(fields.filter((field) => fieldSatisfies(field.id, id)));
465
+ if (isFieldId(name)) return viaId(name);
466
+ const own = bindings.find((binding) => binding.name === name);
467
+ // `company_name` that is declared as a podcast's name is not a company name,
468
+ // so it is read by its id, never by a name that says something else.
469
+ if (own) {
470
+ return nameMeanings(name).some((id) => relatedFields(own.id, id))
471
+ ? byId.get(own.id)
472
+ : undefined;
473
+ }
474
+ if (outputs.includes(name)) return undefined;
475
+ const found = nameMeanings(name).flatMap((id) => {
476
+ const binding = viaId(id);
477
+ return binding ? [binding] : [];
478
+ });
479
+ return pick([...new Set(found)]);
480
+ }
481
+
482
+ /** One place in `result.fields`, and the output that fills it. */
483
+ export type FieldPath = {
484
+ path: string[];
485
+ /** The id or short name `result.field()` resolves for this place. */
486
+ name: string;
487
+ /** The output read there. Null when two could be, so reading it throws. */
488
+ output: string | null;
489
+ list: boolean;
490
+ };
491
+
492
+ /**
493
+ * Where each known value of a target sits in `result.fields`. A catalog id
494
+ * sits at its own path (`person.email.work.value`), and so does the more
495
+ * general id it answers (`person.email.value`). A short name that resolves
496
+ * sits at `<name>.value`, as does each declared list. Throws when two land on
497
+ * the same place, so a tool that would collide fails its build.
498
+ */
499
+ export function fieldPaths(
500
+ bindings: readonly FieldBinding[],
501
+ outputs: readonly string[],
502
+ lists: readonly string[],
503
+ ): FieldPath[] {
504
+ const names = new Set<string>();
505
+ for (const binding of bindings) {
506
+ names.add(binding.id);
507
+ for (const general of generalFields(binding.id)) names.add(general);
508
+ names.add(binding.name);
509
+ }
510
+ for (const [name, ids] of Object.entries(EXTRACTOR_TARGET_FIELDS)) {
511
+ if (
512
+ ids.some((id) =>
513
+ bindings.some((binding) => fieldSatisfies(binding.id, id)),
514
+ )
515
+ ) {
516
+ names.add(name);
517
+ }
518
+ }
519
+ const paths: FieldPath[] = [];
520
+ for (const name of names) {
521
+ let output: string | null;
522
+ try {
523
+ const binding = resolveFieldName(name, bindings, outputs);
524
+ if (!binding) continue;
525
+ output = binding.name;
526
+ } catch {
527
+ // An ambiguous id stays, so reading it names the choices. An ambiguous
528
+ // short name or record field is only a convenience (a person's and a
529
+ // company's name are both an entity name), so it is left out.
530
+ if (!isFieldId(name) || name.startsWith('entity.')) continue;
531
+ output = null;
532
+ }
533
+ // A list keeps its own name; the value is still at its catalog id.
534
+ if (!isFieldId(name) && lists.includes(name)) continue;
535
+ const path = isFieldId(name) ? name.split('.') : [name, 'value'];
536
+ paths.push({ path, name, output, list: false });
537
+ }
538
+ for (const name of lists) {
539
+ paths.push({ path: [name, 'value'], name, output: name, list: true });
540
+ }
541
+ const seen = new Set<string>();
542
+ for (const { path } of paths) {
543
+ const key = path.join('.');
544
+ // A leaf cannot also be a parent, nor appear twice.
545
+ if (
546
+ seen.has(key) ||
547
+ paths.some((other) => other.path.join('.').startsWith(`${key}.`))
548
+ ) {
549
+ throw new Error(`Two outputs land on result.fields.${key}. Rename one.`);
550
+ }
551
+ seen.add(key);
552
+ }
553
+ return paths;
554
+ }
@@ -1,6 +1,50 @@
1
1
  import type { EmailStatusExtractorConfig } from './email-status';
2
2
  import type { DeeplineGetterValueMap } from './extractor-targets';
3
3
  import type { PlayDataset, SerializedPlayDataset } from './dataset';
4
+ import type { FIELD_CATALOG } from './field-catalog';
5
+
6
+ type Catalog = typeof FIELD_CATALOG;
7
+
8
+ type GroupLeaves<TGroup> = TGroup extends { leaves: infer TLeaves }
9
+ ? { readonly [Leaf in keyof TLeaves]?: unknown }
10
+ : unknown;
11
+
12
+ type CatalogGroupFields<TGroup> = GroupLeaves<TGroup> &
13
+ (TGroup extends { kinds: infer TKinds }
14
+ ? { readonly [Kind in keyof TKinds]?: GroupLeaves<TGroup> }
15
+ : unknown) &
16
+ (TGroup extends { groups: infer TGroups }
17
+ ? {
18
+ readonly [Child in keyof TGroups]?: CatalogGroupFields<TGroups[Child]>;
19
+ }
20
+ : unknown);
21
+
22
+ /** Every field the catalog defines, as `result.fields` lays them out. */
23
+ export type CatalogFields = {
24
+ readonly [Entity in keyof Catalog]?: {
25
+ readonly [Group in keyof Catalog[Entity]]?: CatalogGroupFields<
26
+ Catalog[Entity][Group]
27
+ >;
28
+ };
29
+ } & {
30
+ /** Provider-specific fields, `provider.<provider>.<...>.<leaf>`. */
31
+ readonly provider?: Readonly<Record<string, unknown>>;
32
+ };
33
+
34
+ /**
35
+ * The values a result is known to have, by field catalog id and short name,
36
+ * each ending in a leaf: `fields.person.email.value`,
37
+ * `fields.person.email.work.value`, `fields.email.value`. Declared lists are
38
+ * at `fields.<list>.value`, as their getter returns them. A value whose
39
+ * meaning is not known is absent; read it from `response`. Reading a field
40
+ * two outputs could be throws, naming both.
41
+ */
42
+ export type ToolResultFields<
43
+ TExtracted extends Record<string, unknown>,
44
+ TListValues extends Record<string, unknown>,
45
+ > = CatalogFields & {
46
+ readonly [K in keyof TExtracted]?: { readonly value: TExtracted[K] | null };
47
+ } & { readonly [K in keyof TListValues]?: { readonly value: TListValues[K] } };
4
48
 
5
49
  /**
6
50
  * Customer pricing reported by the execution API, never provider spend.
@@ -147,6 +191,10 @@ export type BasicToolExecuteResultAccessors<
147
191
  extractedLists: {
148
192
  [K in keyof TLists]: BasicToolResultListAccessor<TLists[K]>;
149
193
  };
194
+ readonly fields: ToolResultFields<
195
+ TExtracted,
196
+ { [K in keyof TLists]: TLists[K][] }
197
+ >;
150
198
  };
151
199
 
152
200
  /** Public source-SDK result for new Plays; receipts retain the canonical form. */
@@ -260,6 +308,10 @@ export type ToolExecuteResultBase<
260
308
  toolResponse: ToolResponseEnvelope<TResult, TMeta>;
261
309
  extractedValues: Record<string, ToolResultTargetAccessor>;
262
310
  extractedLists: Record<string, ToolResultListAccessor>;
311
+ /** One field by id or short name, as `fields` resolves it. */
312
+ field(name: string): unknown;
313
+ /** The complete parsed provider response (`toolResponse.rawV2`). */
314
+ readonly response: unknown;
263
315
  /** Convenience alias for play code. Serialized output uses toolResponse. */
264
316
  toolOutput: ToolResponseEnvelope<TResult, TMeta>;
265
317
  _metadata: {
@@ -295,15 +347,23 @@ export type ToolExecuteResultAccessors<
295
347
  extractedLists: {
296
348
  [K in keyof TLists]: ToolResultListAccessor<TLists[K]>;
297
349
  };
350
+ readonly fields: ToolResultFields<
351
+ TExtracted,
352
+ { [K in keyof TLists]: PlayDataset<TLists[K]> }
353
+ >;
298
354
  };
299
355
 
300
356
  /**
301
357
  * Canonical result returned by Deepline tool execution.
302
358
  *
303
- * Provider data: `toolResponse.rawV2`; metadata: `toolResponse.meta`.
304
- * Single-value getters: `extractedValues.<name>.get()`; lists: `extractedLists.<name>.get()`.
359
+ * Known values: `fields.person.email.value`, `fields.email.value`, and a
360
+ * declared list at `fields.<list>.value`; or `field('person.email.value')`.
361
+ * A value whose meaning is not known is absent: read it from `response`, the
362
+ * complete provider response. Metadata: `toolResponse.meta`. The older
363
+ * getters `extractedValues.<name>.get()` and `extractedLists.<name>.get()`
364
+ * return the same values and keep working.
305
365
  *
306
- * Prefer declared getters. Edition 10 and later Plays receive ordinary arrays from
366
+ * Edition 10 and later Plays receive ordinary arrays from
307
367
  * list `.get()` synchronously; persist explicitly with deepline.dataset. Lazy or
308
368
  * incomplete lists throw: use readList(result, path) for explicit dataset access.
309
369
  * Provider pagination requires a separate request; getters never fetch it.
@@ -13,14 +13,14 @@ import {
13
13
  reportSetupCompleted,
14
14
  resolvePendingAuthClaimForResume,
15
15
  statusBannerLine
16
- } from "./chunk-DHXCBITQ.mjs";
17
- import "./chunk-WUMIYOXQ.mjs";
18
- import "./chunk-F2RHUPVH.mjs";
19
- import "./chunk-I624J4H5.mjs";
16
+ } from "./chunk-CUZVOPPY.mjs";
17
+ import "./chunk-6A7OH2PV.mjs";
18
+ import "./chunk-5CKIO7KA.mjs";
19
+ import "./chunk-MP3O4ISC.mjs";
20
20
  import "./chunk-4QF2K7TM.mjs";
21
21
  import "./chunk-DLIRSHV6.mjs";
22
22
  import "./chunk-HBL4PM5Q.mjs";
23
- import "./chunk-XDWS2JJT.mjs";
23
+ import "./chunk-J327QVQV.mjs";
24
24
  import "./chunk-WZYKRD7T.mjs";
25
25
  import "./chunk-KRD6H754.mjs";
26
26
  export {
@@ -0,0 +1,41 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+ var _chunkE4QJKJH6js = require('./chunk-E4QJKJH6.js');
17
+ require('./chunk-O4ZMADW4.js');
18
+ require('./chunk-GVJVBBGV.js');
19
+ require('./chunk-NI3QFUK7.js');
20
+ require('./chunk-ALJJRZNJ.js');
21
+ require('./chunk-XNYIZMNQ.js');
22
+ require('./chunk-DIAWYWT5.js');
23
+ require('./chunk-4XNXFHG6.js');
24
+ require('./chunk-OG64RBAC.js');
25
+ require('./chunk-COGTRVWW.js');
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ exports.EXIT_WORKSPACE_MISMATCH = _chunkE4QJKJH6js.EXIT_WORKSPACE_MISMATCH; exports.authStatusLine = _chunkE4QJKJH6js.authStatusLine; exports.clearPendingClaim = _chunkE4QJKJH6js.clearPendingClaim; exports.clearSatisfiedPendingClaim = _chunkE4QJKJH6js.clearSatisfiedPendingClaim; exports.handleRegister = _chunkE4QJKJH6js.handleRegister; exports.handleStatus = _chunkE4QJKJH6js.handleStatus; exports.handleWait = _chunkE4QJKJH6js.handleWait; exports.httpJson = _chunkE4QJKJH6js.httpJson; exports.readPendingAuthClaim = _chunkE4QJKJH6js.readPendingAuthClaim; exports.readStatusBanner = _chunkE4QJKJH6js.readStatusBanner; exports.registerAuthCommands = _chunkE4QJKJH6js.registerAuthCommands; exports.reportSetupCompleted = _chunkE4QJKJH6js.reportSetupCompleted; exports.resolvePendingAuthClaimForResume = _chunkE4QJKJH6js.resolvePendingAuthClaimForResume; exports.statusBannerLine = _chunkE4QJKJH6js.statusBannerLine;