@dench.com/cli 3.10.1-staging.423 → 3.10.2-staging.428
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/lib/enrichment-gateway.ts +5 -5
- package/lib/gateway-url.ts +12 -0
- package/lib/meetings-import.ts +91 -24
- package/package.json +1 -1
- package/search.ts +1 -4
- package/tools.ts +6 -7
- package/web.ts +1 -4
|
@@ -11,6 +11,7 @@ export type {
|
|
|
11
11
|
} from "./enrichment-shapes";
|
|
12
12
|
|
|
13
13
|
import { extractDomain } from "./crm-enrichment";
|
|
14
|
+
import { normalizeGatewayBaseUrl } from "./gateway-url";
|
|
14
15
|
|
|
15
16
|
export type FetchLike = (
|
|
16
17
|
input: string | URL,
|
|
@@ -274,7 +275,7 @@ export function resolveEnrichmentGatewayBaseUrl(
|
|
|
274
275
|
env: EnrichmentGatewayEnv = process.env,
|
|
275
276
|
): string {
|
|
276
277
|
const explicit = env.DENCH_GATEWAY_URL?.trim() || env.GATEWAY_URL?.trim();
|
|
277
|
-
if (explicit) return explicit
|
|
278
|
+
if (explicit) return normalizeGatewayBaseUrl(explicit);
|
|
278
279
|
|
|
279
280
|
const host = env.DENCH_HOST?.trim();
|
|
280
281
|
if (host && /localhost|127\.0\.0\.1/.test(host)) {
|
|
@@ -1690,10 +1691,9 @@ async function callGatewayJson(
|
|
|
1690
1691
|
}
|
|
1691
1692
|
|
|
1692
1693
|
function resolveBaseUrl(options: EnrichmentGatewayOptions): string {
|
|
1693
|
-
return
|
|
1694
|
-
options.baseUrl
|
|
1695
|
-
resolveEnrichmentGatewayBaseUrl(options.env)
|
|
1696
|
-
);
|
|
1694
|
+
return options.baseUrl != null
|
|
1695
|
+
? normalizeGatewayBaseUrl(options.baseUrl.trim())
|
|
1696
|
+
: resolveEnrichmentGatewayBaseUrl(options.env);
|
|
1697
1697
|
}
|
|
1698
1698
|
|
|
1699
1699
|
async function buildGatewayError(
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Remove a URL's trailing slashes in one pass, including long malformed input. */
|
|
2
|
+
export function stripTrailingSlashes(value: string): string {
|
|
3
|
+
let end = value.length;
|
|
4
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
5
|
+
return value.slice(0, end);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Gateway callers append their own /v1 path; accept either base URL form. */
|
|
9
|
+
export function normalizeGatewayBaseUrl(value: string): string {
|
|
10
|
+
const base = stripTrailingSlashes(value);
|
|
11
|
+
return base.endsWith("/v1") ? base.slice(0, -3) : base;
|
|
12
|
+
}
|
package/lib/meetings-import.ts
CHANGED
|
@@ -229,6 +229,44 @@ export function normalizeTranscript(value: unknown): ImportedSegment[] | null {
|
|
|
229
229
|
return null;
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
const LINE_BREAK = /[\r\n\u2028\u2029]/;
|
|
233
|
+
|
|
234
|
+
/** Inspect only the final owner delimiter instead of backtracking over the body. */
|
|
235
|
+
function actionItemOwner(
|
|
236
|
+
text: string,
|
|
237
|
+
): { text: string; ownerName: string } | null {
|
|
238
|
+
if (text.endsWith(")")) {
|
|
239
|
+
const open = text.lastIndexOf("(");
|
|
240
|
+
const owner = text.slice(open + 1, -1);
|
|
241
|
+
const body = text.slice(0, open).trimEnd();
|
|
242
|
+
if (
|
|
243
|
+
open >= 0 &&
|
|
244
|
+
owner.length > 0 &&
|
|
245
|
+
owner.length <= 60 &&
|
|
246
|
+
!owner.includes(")") &&
|
|
247
|
+
!LINE_BREAK.test(body)
|
|
248
|
+
) {
|
|
249
|
+
return { text: body.trim(), ownerName: owner.trim() };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
for (let index = text.length - 1; index >= 0; index--) {
|
|
253
|
+
if (!"-–—".includes(text[index])) continue;
|
|
254
|
+
// Only the last dash can separate an owner: owners cannot contain dashes.
|
|
255
|
+
if (
|
|
256
|
+
!/\s/.test(text[index - 1] ?? "") ||
|
|
257
|
+
!/\s/.test(text[index + 1] ?? "")
|
|
258
|
+
) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const owner = text.slice(index + 1).trimStart();
|
|
262
|
+
const body = text.slice(0, index).trimEnd();
|
|
263
|
+
return owner.length > 0 && owner.length <= 60 && !LINE_BREAK.test(body)
|
|
264
|
+
? { text: body.trim(), ownerName: owner.trim() }
|
|
265
|
+
: null;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
232
270
|
/**
|
|
233
271
|
* `- [x] Send the deck (Hank)` / `Send the deck — Hank` / `{text, owner,
|
|
234
272
|
* done}`. Markdown checkboxes carry completion; a trailing parenthesised
|
|
@@ -239,20 +277,18 @@ export function normalizeActionItem(value: unknown): ImportedActionItem | null {
|
|
|
239
277
|
let text = value.trim().replace(/^[-*•]\s+/, "");
|
|
240
278
|
if (!text) return null;
|
|
241
279
|
let done: boolean | undefined;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
280
|
+
if (text[0] === "[" && " xX".includes(text[1] ?? "") && text[2] === "]") {
|
|
281
|
+
const body = text.slice(3).trimStart();
|
|
282
|
+
if (!LINE_BREAK.test(body)) {
|
|
283
|
+
done = text[1] !== " ";
|
|
284
|
+
text = body.trim();
|
|
285
|
+
}
|
|
246
286
|
}
|
|
247
287
|
let ownerName: string | null = null;
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
ownerName = paren[2].trim();
|
|
253
|
-
} else if (dash) {
|
|
254
|
-
text = dash[1].trim();
|
|
255
|
-
ownerName = dash[2].trim();
|
|
288
|
+
const owner = actionItemOwner(text);
|
|
289
|
+
if (owner) {
|
|
290
|
+
text = owner.text;
|
|
291
|
+
ownerName = owner.ownerName;
|
|
256
292
|
}
|
|
257
293
|
if (!text) return null;
|
|
258
294
|
return { text, ownerName, ...(done !== undefined ? { done } : {}) };
|
|
@@ -303,15 +339,28 @@ export function normalizeAttendee(value: unknown): ImportedAttendee | null {
|
|
|
303
339
|
if (typeof value === "string") {
|
|
304
340
|
const raw = value.trim();
|
|
305
341
|
if (!raw) return null;
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
342
|
+
const markerStart = raw.lastIndexOf("(");
|
|
343
|
+
const marker = raw.slice(markerStart).toLowerCase();
|
|
344
|
+
const isHost = ["(host)", "(organizer)", "(organiser)"].includes(marker);
|
|
345
|
+
const cleaned = isHost ? raw.slice(0, markerStart).trimEnd() : raw;
|
|
346
|
+
if (cleaned.endsWith(">")) {
|
|
347
|
+
const open = cleaned.lastIndexOf("<");
|
|
348
|
+
const email = cleaned.slice(open + 1, -1);
|
|
349
|
+
const at = email.indexOf("@", 1);
|
|
350
|
+
const name = cleaned.slice(0, open).trimEnd();
|
|
351
|
+
if (
|
|
352
|
+
open >= 0 &&
|
|
353
|
+
at >= 1 &&
|
|
354
|
+
at < email.length - 1 &&
|
|
355
|
+
!/[<>\s]/.test(email) &&
|
|
356
|
+
!LINE_BREAK.test(name)
|
|
357
|
+
) {
|
|
358
|
+
return {
|
|
359
|
+
name: name.trim() || null,
|
|
360
|
+
email,
|
|
361
|
+
...(isHost ? { isHost } : {}),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
315
364
|
}
|
|
316
365
|
if (/^[^\s@]+@[^\s@]+$/.test(cleaned)) {
|
|
317
366
|
return { name: null, email: cleaned, ...(isHost ? { isHost } : {}) };
|
|
@@ -342,9 +391,27 @@ export function normalizeAttendees(value: unknown): ImportedAttendee[] | null {
|
|
|
342
391
|
// fall through
|
|
343
392
|
}
|
|
344
393
|
}
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
|
|
394
|
+
// A comma splits unless the next angle bracket is a closing one. Track
|
|
395
|
+
// that bracket while scanning backwards instead of rescanning the tail
|
|
396
|
+
// for every comma. Semicolons and newlines always separate attendees.
|
|
397
|
+
const parts: string[] = [];
|
|
398
|
+
let end = trimmed.length;
|
|
399
|
+
let nextAngleIsClose = false;
|
|
400
|
+
for (let index = trimmed.length - 1; index >= 0; index--) {
|
|
401
|
+
const char = trimmed[index];
|
|
402
|
+
if (char === ">") nextAngleIsClose = true;
|
|
403
|
+
else if (char === "<") nextAngleIsClose = false;
|
|
404
|
+
else if (
|
|
405
|
+
char === ";" ||
|
|
406
|
+
char === "\n" ||
|
|
407
|
+
(char === "," && !nextAngleIsClose)
|
|
408
|
+
) {
|
|
409
|
+
parts.push(trimmed.slice(index + 1, end));
|
|
410
|
+
end = index;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
parts.push(trimmed.slice(0, end));
|
|
414
|
+
return normalizeAttendees(parts.reverse());
|
|
348
415
|
}
|
|
349
416
|
if (Array.isArray(value)) {
|
|
350
417
|
return value
|
package/package.json
CHANGED
package/search.ts
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
personFullName,
|
|
37
37
|
} from "./lib/exa-people";
|
|
38
38
|
import { unsupportedParamsForCategory } from "./lib/exa-search-constraints";
|
|
39
|
+
import { normalizeGatewayBaseUrl } from "./lib/gateway-url";
|
|
39
40
|
|
|
40
41
|
type SearchCliContext = {
|
|
41
42
|
args: string[];
|
|
@@ -119,10 +120,6 @@ function assertFlagsSupportedForCategory(
|
|
|
119
120
|
);
|
|
120
121
|
}
|
|
121
122
|
|
|
122
|
-
function normalizeGatewayBaseUrl(value: string): string {
|
|
123
|
-
return value.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
123
|
function resolveGatewayBaseUrl(
|
|
127
124
|
ctx?: Pick<SearchCliContext, "gatewayBaseUrl">,
|
|
128
125
|
): string {
|
package/tools.ts
CHANGED
|
@@ -57,6 +57,10 @@ import {
|
|
|
57
57
|
type ConnectionSource,
|
|
58
58
|
connectionSource,
|
|
59
59
|
} from "./lib/connection-source";
|
|
60
|
+
import {
|
|
61
|
+
normalizeGatewayBaseUrl,
|
|
62
|
+
stripTrailingSlashes,
|
|
63
|
+
} from "./lib/gateway-url";
|
|
60
64
|
import {
|
|
61
65
|
isNativeToolRecord,
|
|
62
66
|
nativeToolkit,
|
|
@@ -673,9 +677,8 @@ async function runSlackConnectSubcommand(
|
|
|
673
677
|
toolkit: string,
|
|
674
678
|
): Promise<void> {
|
|
675
679
|
const slug = ctx.workspaceSlug?.trim() || (await resolveWorkspaceSlug(ctx));
|
|
676
|
-
const origin = (
|
|
677
|
-
|
|
678
|
-
"",
|
|
680
|
+
const origin = stripTrailingSlashes(
|
|
681
|
+
ctx.appOrigin?.trim() || resolveAppPublicOrigin(),
|
|
679
682
|
);
|
|
680
683
|
const redirectUrl = `${origin}/api/slack/install?slug=${
|
|
681
684
|
slug ? encodeURIComponent(slug) : "<workspace-slug>"
|
|
@@ -897,10 +900,6 @@ class GatewayHttpError extends ToolCliError {
|
|
|
897
900
|
}
|
|
898
901
|
}
|
|
899
902
|
|
|
900
|
-
function normalizeGatewayBaseUrl(value: string): string {
|
|
901
|
-
return value.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
902
|
-
}
|
|
903
|
-
|
|
904
903
|
function resolveGatewayBaseUrl(
|
|
905
904
|
ctx?: Pick<ToolCliContext, "gatewayBaseUrl">,
|
|
906
905
|
): string {
|
package/web.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { assertNoUnknownFlags, getFlag, hasFlag } from "./lib/cli-args";
|
|
10
|
+
import { normalizeGatewayBaseUrl } from "./lib/gateway-url";
|
|
10
11
|
|
|
11
12
|
type WebCliContext = {
|
|
12
13
|
args: string[];
|
|
@@ -32,10 +33,6 @@ function parsePositiveInt(
|
|
|
32
33
|
return Math.floor(parsed);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
function normalizeGatewayBaseUrl(value: string): string {
|
|
36
|
-
return value.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
function resolveGatewayBaseUrl(
|
|
40
37
|
ctx?: Pick<WebCliContext, "gatewayBaseUrl">,
|
|
41
38
|
): string {
|