@servicenow/sdk-build-core 4.6.1 → 4.7.1
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/compiler.d.ts +2 -0
- package/dist/compiler.js +13 -7
- package/dist/compiler.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/now-config.d.ts +37 -0
- package/dist/now-config.js +9 -0
- package/dist/now-config.js.map +1 -1
- package/dist/package-inventory.d.ts +15 -0
- package/dist/package-inventory.js +59 -0
- package/dist/package-inventory.js.map +1 -0
- package/dist/plugins/context.d.ts +2 -2
- package/dist/plugins/index.d.ts +0 -1
- package/dist/plugins/index.js +0 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin.d.ts +41 -53
- package/dist/plugins/plugin.js +502 -160
- package/dist/plugins/plugin.js.map +1 -1
- package/dist/plugins/shape.d.ts +13 -2
- package/dist/plugins/shape.js +96 -15
- package/dist/plugins/shape.js.map +1 -1
- package/dist/taxonomy.js +7 -2
- package/dist/taxonomy.js.map +1 -1
- package/dist/telemetry/clients/detect-agent.d.ts +4 -0
- package/dist/telemetry/clients/detect-agent.js +84 -0
- package/dist/telemetry/clients/detect-agent.js.map +1 -0
- package/dist/telemetry/clients/node-client.d.ts +2 -0
- package/dist/telemetry/clients/node-client.js +10 -9
- package/dist/telemetry/clients/node-client.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -1
- package/now.config.schema.json +19 -0
- package/package.json +9 -5
- package/src/compiler.ts +14 -7
- package/src/index.ts +1 -0
- package/src/now-config.ts +11 -0
- package/src/package-inventory.ts +75 -0
- package/src/plugins/context.ts +2 -2
- package/src/plugins/index.ts +0 -1
- package/src/plugins/plugin.ts +682 -228
- package/src/plugins/shape.ts +115 -24
- package/src/taxonomy.ts +8 -2
- package/src/telemetry/clients/detect-agent.ts +88 -0
- package/src/telemetry/clients/node-client.ts +12 -8
- package/src/telemetry/index.ts +1 -1
- package/dist/plugins/cache.d.ts +0 -15
- package/dist/plugins/cache.js +0 -22
- package/dist/plugins/cache.js.map +0 -1
- package/dist/plugins/usage.d.ts +0 -11
- package/dist/plugins/usage.js +0 -26
- package/dist/plugins/usage.js.map +0 -1
- package/src/plugins/cache.ts +0 -23
- package/src/plugins/usage.ts +0 -26
package/src/plugins/shape.ts
CHANGED
|
@@ -575,22 +575,26 @@ export abstract class StringShape extends Shape<string> {
|
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
static escapeSingleQuotes(str: string): string {
|
|
578
|
-
|
|
578
|
+
// Escape \r last to avoid double-escaping the backslash we introduce
|
|
579
|
+
return str.replaceAll('\\', '\\\\').replaceAll("'", "\\'").replaceAll('\r', '\\r')
|
|
579
580
|
}
|
|
580
581
|
|
|
581
582
|
static escapeBackticks(str: string): string {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
583
|
+
// Escape \r last to avoid double-escaping the backslash we introduce
|
|
584
|
+
return str
|
|
585
|
+
.replace(/[`\\]|\${/g, (char) => {
|
|
586
|
+
switch (char) {
|
|
587
|
+
case '`':
|
|
588
|
+
return '\\`'
|
|
589
|
+
case '\\':
|
|
590
|
+
return '\\' + char
|
|
591
|
+
case '${':
|
|
592
|
+
return '\\${'
|
|
593
|
+
default:
|
|
594
|
+
return char
|
|
595
|
+
}
|
|
596
|
+
})
|
|
597
|
+
.replaceAll('\r', '\\r')
|
|
594
598
|
}
|
|
595
599
|
|
|
596
600
|
static escapeCdataTags(str: string): string {
|
|
@@ -611,7 +615,7 @@ export class StringLiteralShape extends StringShape {
|
|
|
611
615
|
}
|
|
612
616
|
|
|
613
617
|
override getCode(): string {
|
|
614
|
-
return this.includes('\n')
|
|
618
|
+
return this.literalText.includes('\n')
|
|
615
619
|
? `\`${StringShape.escapeBackticks(this.literalText)}\``
|
|
616
620
|
: `'${StringShape.escapeSingleQuotes(this.literalText)}'`
|
|
617
621
|
}
|
|
@@ -914,6 +918,7 @@ function assignWithoutOverwriting(target: NonNullable<object>, source: unknown)
|
|
|
914
918
|
type ObjectPropertyOptions = {
|
|
915
919
|
nonDefaultsOnly?: boolean
|
|
916
920
|
resolve?: boolean
|
|
921
|
+
keys?: string[]
|
|
917
922
|
}
|
|
918
923
|
|
|
919
924
|
export class ObjectShape extends Shape<globalThis.Record<string, unknown>> {
|
|
@@ -958,14 +963,16 @@ export class ObjectShape extends Shape<globalThis.Record<string, unknown>> {
|
|
|
958
963
|
properties({
|
|
959
964
|
nonDefaultsOnly = false,
|
|
960
965
|
resolve = true,
|
|
966
|
+
keys = undefined,
|
|
961
967
|
}: ObjectPropertyOptions = {}): globalThis.Record<string, Shape> {
|
|
962
968
|
const result: globalThis.Record<string, Shape> = {}
|
|
969
|
+
const selectedKeys = keys ?? Object.keys(this.setProperties)
|
|
963
970
|
|
|
964
971
|
if (nonDefaultsOnly) {
|
|
965
972
|
// Only include properties that differ from defaults
|
|
966
|
-
for (const k
|
|
973
|
+
for (const k of selectedKeys) {
|
|
967
974
|
const v = this.setProperties[k]
|
|
968
|
-
if (v
|
|
975
|
+
if (v?.isDefined() && !v.equals(this.getDefault(k))) {
|
|
969
976
|
result[k] = resolve && v.isResolvable() ? v.resolve() : v
|
|
970
977
|
}
|
|
971
978
|
}
|
|
@@ -973,14 +980,15 @@ export class ObjectShape extends Shape<globalThis.Record<string, unknown>> {
|
|
|
973
980
|
}
|
|
974
981
|
|
|
975
982
|
// Iterate set properties first to preserve ordering
|
|
976
|
-
for (const k
|
|
983
|
+
for (const k of selectedKeys) {
|
|
977
984
|
const v = this.setProperties[k]
|
|
978
985
|
if (v) {
|
|
979
986
|
result[k] = resolve && v.isResolvable() ? v.resolve() : v
|
|
980
987
|
}
|
|
981
988
|
}
|
|
982
989
|
|
|
983
|
-
|
|
990
|
+
const defaultKeys = keys ?? Object.keys(this.defaultProperties)
|
|
991
|
+
for (const k of defaultKeys) {
|
|
984
992
|
if (!this.setProperties[k] || this.setProperties[k].isUndefined()) {
|
|
985
993
|
const v = this.defaultProperties[k]
|
|
986
994
|
if (v) {
|
|
@@ -999,7 +1007,7 @@ export class ObjectShape extends Shape<globalThis.Record<string, unknown>> {
|
|
|
999
1007
|
get(propertyOrPath: string | [string, ...string[]], resolve = true): Shape {
|
|
1000
1008
|
const [property, next, ...rest] = typeof propertyOrPath === 'string' ? [propertyOrPath] : propertyOrPath
|
|
1001
1009
|
const propertyAliases = [property, ...this.getAliases(property)]
|
|
1002
|
-
const properties = this.properties({ resolve })
|
|
1010
|
+
const properties = this.properties({ resolve, keys: propertyAliases })
|
|
1003
1011
|
const match = propertyAliases.find((p) => p in properties)
|
|
1004
1012
|
const value = match !== undefined ? properties[match] : undefined
|
|
1005
1013
|
return (
|
|
@@ -1048,7 +1056,7 @@ export class ObjectShape extends Shape<globalThis.Record<string, unknown>> {
|
|
|
1048
1056
|
properties = typeof properties === 'string' ? [properties] : properties
|
|
1049
1057
|
const regex = new RegExp(`^(${properties.join('|')})$`)
|
|
1050
1058
|
return Object.fromEntries(
|
|
1051
|
-
this.entries(options)
|
|
1059
|
+
this.entries({ ...options, keys: properties })
|
|
1052
1060
|
.filter(([k]) => regex.test(k))
|
|
1053
1061
|
.map(([k, v]) => [k, v])
|
|
1054
1062
|
)
|
|
@@ -1348,17 +1356,62 @@ function getDefaultCategoryFromTable(table: string): InstallCategory {
|
|
|
1348
1356
|
}
|
|
1349
1357
|
|
|
1350
1358
|
function getInstallCategoryFromInstallMethod(installMethod: string): InstallCategory {
|
|
1351
|
-
|
|
1359
|
+
if (installMethod === 'demo') {
|
|
1360
|
+
return 'unload.demo'
|
|
1361
|
+
}
|
|
1362
|
+
if (installMethod === 'once') {
|
|
1363
|
+
return 'apply_once'
|
|
1364
|
+
}
|
|
1365
|
+
if (installMethod === 'first install') {
|
|
1366
|
+
return 'unload'
|
|
1367
|
+
}
|
|
1368
|
+
throw new Error(`Invalid installMethod: '${installMethod}'. Expected 'demo', 'first install', or 'once'.`)
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
export function getInstallCategoryFromPath(filePath: string): InstallCategory | undefined {
|
|
1372
|
+
const segments = filePath.split(/[/\\]/)
|
|
1373
|
+
if (segments.includes('unload.demo')) {
|
|
1374
|
+
return 'unload.demo'
|
|
1375
|
+
}
|
|
1376
|
+
if (segments.includes('unload')) {
|
|
1377
|
+
return 'unload'
|
|
1378
|
+
}
|
|
1379
|
+
if (segments.includes('apply_once')) {
|
|
1380
|
+
return 'apply_once'
|
|
1381
|
+
}
|
|
1382
|
+
return undefined
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
function isFile(source: Source): source is { path: string; content: string } {
|
|
1386
|
+
return typeof source === 'object' && source !== null && 'path' in source && 'content' in source
|
|
1352
1387
|
}
|
|
1353
1388
|
|
|
1354
1389
|
export function getInstallCategory(source: Source, table: string): InstallCategory {
|
|
1355
1390
|
let installCategory: InstallCategory = getDefaultCategoryFromTable(table)
|
|
1391
|
+
|
|
1392
|
+
// Check for $meta.installMethod in Fluent code (build direction)
|
|
1356
1393
|
if (source instanceof CallExpressionShape) {
|
|
1357
1394
|
const installMethod = source.getArgument(0).ifObject()?.get(['$meta', 'installMethod']).ifString()?.getValue()
|
|
1358
1395
|
if (installMethod) {
|
|
1359
1396
|
installCategory = getInstallCategoryFromInstallMethod(installMethod)
|
|
1360
1397
|
}
|
|
1361
1398
|
}
|
|
1399
|
+
// Check for source directory in XML file path (transform direction)
|
|
1400
|
+
else if (isFile(source)) {
|
|
1401
|
+
const categoryFromPath = getInstallCategoryFromPath(source.path)
|
|
1402
|
+
if (categoryFromPath) {
|
|
1403
|
+
installCategory = categoryFromPath
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
// Check for source directory from Product's original file path
|
|
1407
|
+
else if (source instanceof Product) {
|
|
1408
|
+
const filePath = source.getOriginalFilePath()
|
|
1409
|
+
const categoryFromPath = getInstallCategoryFromPath(filePath)
|
|
1410
|
+
if (categoryFromPath) {
|
|
1411
|
+
installCategory = categoryFromPath
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1362
1415
|
return installCategory
|
|
1363
1416
|
}
|
|
1364
1417
|
|
|
@@ -1369,6 +1422,8 @@ export class Record extends ObjectShape {
|
|
|
1369
1422
|
private readonly related: Record[] = []
|
|
1370
1423
|
private readonly action: Action
|
|
1371
1424
|
private readonly installCategory: InstallCategory
|
|
1425
|
+
private fieldAccessTracker: Set<string> | undefined
|
|
1426
|
+
private overrideKeys: Set<string> | undefined
|
|
1372
1427
|
|
|
1373
1428
|
constructor({
|
|
1374
1429
|
source,
|
|
@@ -1413,6 +1468,29 @@ export class Record extends ObjectShape {
|
|
|
1413
1468
|
return Record.isDeleteAction(this.getAction())
|
|
1414
1469
|
}
|
|
1415
1470
|
|
|
1471
|
+
startTracking(): void {
|
|
1472
|
+
this.fieldAccessTracker = new Set()
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
getTrackedFields(): Set<string> {
|
|
1476
|
+
return this.fieldAccessTracker ?? new Set()
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
withOverrideKeys(keys: Set<string>): this {
|
|
1480
|
+
this.overrideKeys = keys
|
|
1481
|
+
return this
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
getOverrideKeys(): Set<string> | undefined {
|
|
1485
|
+
return this.overrideKeys
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
override get(propertyOrPath: string | [string, ...string[]], resolve = true): Shape {
|
|
1489
|
+
const property = typeof propertyOrPath === 'string' ? propertyOrPath : propertyOrPath[0]
|
|
1490
|
+
this.fieldAccessTracker?.add(property)
|
|
1491
|
+
return super.get(propertyOrPath, resolve)
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1416
1494
|
// getUpdateName(): string {
|
|
1417
1495
|
// // TODO: Provide a way to override this for non-standard coalesce strategies, or
|
|
1418
1496
|
// // just hard-code the very short list of special cases from UpdateName.java
|
|
@@ -1428,7 +1506,8 @@ export class Record extends ObjectShape {
|
|
|
1428
1506
|
/**
|
|
1429
1507
|
* Returns the direct related records (one level deep only).
|
|
1430
1508
|
* Does not include nested descendants.
|
|
1431
|
-
* @deprecated
|
|
1509
|
+
* @deprecated Prefer `flat()` for read-only traversal of all descendants. Avoid `getRelated()`
|
|
1510
|
+
* unless you need the immediate-children relationship to reconstruct nested `.with()` chains.
|
|
1432
1511
|
*/
|
|
1433
1512
|
getRelated(): Record[] {
|
|
1434
1513
|
return this.related
|
|
@@ -1447,7 +1526,8 @@ export class Record extends ObjectShape {
|
|
|
1447
1526
|
}
|
|
1448
1527
|
|
|
1449
1528
|
override merge(other: NonNullable<object>): Record {
|
|
1450
|
-
|
|
1529
|
+
const otherKeys = other instanceof Record ? other.overrideKeys : undefined
|
|
1530
|
+
const merged = new Record({
|
|
1451
1531
|
source: this.getSource(),
|
|
1452
1532
|
id: this.getId(),
|
|
1453
1533
|
action: other instanceof Record ? other.getAction() : this.getAction(),
|
|
@@ -1456,6 +1536,10 @@ export class Record extends ObjectShape {
|
|
|
1456
1536
|
})
|
|
1457
1537
|
.setCreator(this.getCreator())
|
|
1458
1538
|
.with(...this.related)
|
|
1539
|
+
if (this.overrideKeys || otherKeys) {
|
|
1540
|
+
merged.withOverrideKeys(new Set([...(this.overrideKeys ?? []), ...(otherKeys ?? [])]))
|
|
1541
|
+
}
|
|
1542
|
+
return merged
|
|
1459
1543
|
}
|
|
1460
1544
|
|
|
1461
1545
|
override equals(other: unknown): boolean {
|
|
@@ -1497,6 +1581,7 @@ export type ResolvedCoalesceKeys = globalThis.Record<string, string>
|
|
|
1497
1581
|
export class RecordId extends StringShape {
|
|
1498
1582
|
private readonly table: string
|
|
1499
1583
|
private readonly guid: string | (() => string)
|
|
1584
|
+
private resolvedGuid: string | undefined
|
|
1500
1585
|
private readonly keys: CoalesceKeys | undefined
|
|
1501
1586
|
private readonly nowIdKey: string | number | undefined
|
|
1502
1587
|
|
|
@@ -1577,7 +1662,13 @@ export class RecordId extends StringShape {
|
|
|
1577
1662
|
}
|
|
1578
1663
|
|
|
1579
1664
|
override getValue(): string {
|
|
1580
|
-
|
|
1665
|
+
if (typeof this.guid === 'string') {
|
|
1666
|
+
return this.guid
|
|
1667
|
+
}
|
|
1668
|
+
if (!this.resolvedGuid) {
|
|
1669
|
+
this.resolvedGuid = this.guid()
|
|
1670
|
+
}
|
|
1671
|
+
return this.resolvedGuid
|
|
1581
1672
|
}
|
|
1582
1673
|
|
|
1583
1674
|
override equals(other: unknown): boolean {
|
package/src/taxonomy.ts
CHANGED
|
@@ -3,7 +3,6 @@ import kebabCase from 'lodash/kebabCase'
|
|
|
3
3
|
|
|
4
4
|
const TableNames = {
|
|
5
5
|
// Automation tables
|
|
6
|
-
SYS_ALIAS: 'sys_alias',
|
|
7
6
|
SYS_HUB_ACTION_TYPE_DEFINITION: 'sys_hub_action_type_definition',
|
|
8
7
|
SYS_HUB_TRIGGER_DEFINITION: 'sys_hub_trigger_definition',
|
|
9
8
|
SYS_HUB_FLOW: 'sys_hub_flow',
|
|
@@ -219,6 +218,11 @@ const TableNames = {
|
|
|
219
218
|
SYS_UX_PAGE_REGISTRY: 'sys_ux_page_registry',
|
|
220
219
|
SYS_TEMPLATE: 'sys_template',
|
|
221
220
|
SYSRULE_VIEW: 'sysrule_view',
|
|
221
|
+
|
|
222
|
+
//Connection & Credential Aliases
|
|
223
|
+
SYS_ALIAS: 'sys_alias',
|
|
224
|
+
SYS_ALIAS_TEMPLATES: 'sys_alias_templates',
|
|
225
|
+
SYS_RETRY_POLICY: 'sys_retry_policy',
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
// String format: one or more path segments separated by '/' (e.g., 'server-development/business-rule' or 'integration/outbound/rest-api')
|
|
@@ -231,7 +235,9 @@ const taxonomyMapping = z
|
|
|
231
235
|
[TableNames.SYS_HUB_ACTION_TYPE_DEFINITION]: taxonomyItem.default('automation/action'),
|
|
232
236
|
[TableNames.SYS_HUB_TRIGGER_DEFINITION]: taxonomyItem.default('automation/trigger'),
|
|
233
237
|
[TableNames.SYS_PD_ACTIVITY_DEFINITION]: taxonomyItem.default('automation/activity-definition'),
|
|
234
|
-
[TableNames.SYS_ALIAS]: taxonomyItem.default('automation/
|
|
238
|
+
[TableNames.SYS_ALIAS]: taxonomyItem.default('automation/connection-credential-aliases'),
|
|
239
|
+
[TableNames.SYS_ALIAS_TEMPLATES]: taxonomyItem.default('automation/connection-credential-aliases'),
|
|
240
|
+
[TableNames.SYS_RETRY_POLICY]: taxonomyItem.default('automation/connection-credential-aliases'),
|
|
235
241
|
[TableNames.SYS_DECISION]: taxonomyItem.default('automation/decision-table'),
|
|
236
242
|
[TableNames.SYSEVENT_EMAIL_TEMPLATE]: taxonomyItem.default('automation/email-template'),
|
|
237
243
|
[TableNames.SYSEVENT_EMAIL_ACTION]: taxonomyItem.default('automation/notification'),
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { path } from '../../path'
|
|
2
|
+
|
|
3
|
+
type Env = NodeJS.ProcessEnv
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks whether any directory segment of `fullPath` matches `name`
|
|
7
|
+
* (case-insensitive). Matches both the bare name and the `.app` bundle variant
|
|
8
|
+
* so it handles macOS (`/Applications/Cursor.app/...`) and Windows
|
|
9
|
+
* (`C:\Users\u\AppData\Local\Programs\cursor\...`) without the false positives
|
|
10
|
+
* that a plain substring check would produce on paths like `/home/cursor-fan/`.
|
|
11
|
+
*/
|
|
12
|
+
function pathHasSegment(fullPath: string, name: string): boolean {
|
|
13
|
+
const target = name.toLowerCase()
|
|
14
|
+
const targetApp = `${target}.app`
|
|
15
|
+
// pathe normalizes Windows separators to `/`, so a single split works on both platforms.
|
|
16
|
+
return path
|
|
17
|
+
.normalize(fullPath)
|
|
18
|
+
.split('/')
|
|
19
|
+
.some((segment) => {
|
|
20
|
+
const lower = segment.toLowerCase()
|
|
21
|
+
return lower === target || lower === targetApp
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function detectCodingAgent(env: Env): string | undefined {
|
|
26
|
+
if (env['CLAUDECODE']) {
|
|
27
|
+
return 'claudecode'
|
|
28
|
+
}
|
|
29
|
+
if (env['GEMINI_CLI']) {
|
|
30
|
+
return 'gemini'
|
|
31
|
+
}
|
|
32
|
+
if (env['CODEX_CI']) {
|
|
33
|
+
return 'codex'
|
|
34
|
+
}
|
|
35
|
+
if (env['CLINE_ACTIVE'] === 'true' || env['CLINE_WRAPPER_PATH']) {
|
|
36
|
+
return 'cline'
|
|
37
|
+
}
|
|
38
|
+
if (env['KIRO_SESSION_ID']) {
|
|
39
|
+
return 'kiro'
|
|
40
|
+
}
|
|
41
|
+
return undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function detectIde(env: Env, platform: NodeJS.Platform): string | undefined {
|
|
45
|
+
if (env['TERM_PROGRAM'] === 'kiro') {
|
|
46
|
+
return 'kiro'
|
|
47
|
+
}
|
|
48
|
+
if (env['ZED_TERM'] === 'true' || env['TERM_PROGRAM'] === 'zed') {
|
|
49
|
+
return 'zed'
|
|
50
|
+
}
|
|
51
|
+
if (env['TERMINAL_EMULATOR'] === 'JetBrains-JediTerm') {
|
|
52
|
+
return 'jetbrains'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Real paths on macOS are e.g. `/Applications/Cursor.app/Contents/...`
|
|
56
|
+
// and on Windows `C:\Users\...\Programs\cursor\...`. Match on a directory
|
|
57
|
+
// segment (case-insensitive, with optional `.app` suffix) rather than a
|
|
58
|
+
// raw substring so that user dir names containing 'cursor' / 'windsurf'
|
|
59
|
+
// don't produce false positives.
|
|
60
|
+
const askpassPath = env['VSCODE_GIT_ASKPASS_NODE']
|
|
61
|
+
if (askpassPath) {
|
|
62
|
+
if (pathHasSegment(askpassPath, 'cursor')) {
|
|
63
|
+
return 'cursor'
|
|
64
|
+
}
|
|
65
|
+
if (pathHasSegment(askpassPath, 'windsurf')) {
|
|
66
|
+
return 'windsurf'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (platform === 'darwin') {
|
|
71
|
+
const bundleId = env['__CFBundleIdentifier']?.toLowerCase()
|
|
72
|
+
if (bundleId?.includes('cursor')) {
|
|
73
|
+
return 'cursor'
|
|
74
|
+
}
|
|
75
|
+
if (bundleId?.includes('windsurf')) {
|
|
76
|
+
return 'windsurf'
|
|
77
|
+
}
|
|
78
|
+
if (bundleId === 'com.microsoft.vscode') {
|
|
79
|
+
return 'vscode'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (env['VSCODE_PID'] || env['VSCODE_IPC_HOOK'] || env['VSCODE_INJECTION'] || env['TERM_PROGRAM'] === 'vscode') {
|
|
84
|
+
return 'vscode'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return undefined
|
|
88
|
+
}
|
|
@@ -2,6 +2,7 @@ import * as os from 'os'
|
|
|
2
2
|
import ciInfo from 'ci-info'
|
|
3
3
|
import type { TelemetryEventData, InstanceSettings } from '../types'
|
|
4
4
|
import { AbstractAppSeeClient } from './abstract-client'
|
|
5
|
+
import { detectCodingAgent, detectIde } from './detect-agent'
|
|
5
6
|
|
|
6
7
|
export class NodeTelemetryClient extends AbstractAppSeeClient {
|
|
7
8
|
constructor(
|
|
@@ -40,13 +41,16 @@ export class NodeTelemetryClient extends AbstractAppSeeClient {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
override getDefaultDataValues() {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
const env = process.env
|
|
45
|
+
const agentData: TelemetryEventData<{ codingAgent?: string; ide?: string }> = {}
|
|
46
|
+
|
|
47
|
+
const codingAgent = detectCodingAgent(env)
|
|
48
|
+
if (codingAgent) {
|
|
49
|
+
agentData.codingAgent = codingAgent
|
|
50
|
+
}
|
|
51
|
+
const ide = detectIde(env, process.platform)
|
|
52
|
+
if (ide) {
|
|
53
|
+
agentData.ide = ide
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
return {
|
|
@@ -54,7 +58,7 @@ export class NodeTelemetryClient extends AbstractAppSeeClient {
|
|
|
54
58
|
version: this.sdkVersion || 'unknown',
|
|
55
59
|
nodeVersion: process.version,
|
|
56
60
|
clientName: this.clientName,
|
|
57
|
-
...
|
|
61
|
+
...agentData,
|
|
58
62
|
...this.applyCITelemetry(),
|
|
59
63
|
}
|
|
60
64
|
}
|
package/src/telemetry/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { Telemetry, TelemetryEvent } from './types'
|
|
1
|
+
export type { Telemetry, TelemetryEvent, TelemetryEventData } from './types'
|
|
2
2
|
export { TelemetryFactory } from './factory'
|
package/dist/plugins/cache.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
type CacheEntry<V> = {
|
|
2
|
-
success: true;
|
|
3
|
-
value: V;
|
|
4
|
-
} | {
|
|
5
|
-
success: false;
|
|
6
|
-
error: unknown;
|
|
7
|
-
};
|
|
8
|
-
export declare class Cache<K extends object, V> {
|
|
9
|
-
private cache;
|
|
10
|
-
get(key: K): CacheEntry<V> | undefined;
|
|
11
|
-
put<const T extends V>(key: K, value: T): T;
|
|
12
|
-
error<const T>(key: K, error: T): T;
|
|
13
|
-
clear(): void;
|
|
14
|
-
}
|
|
15
|
-
export {};
|
package/dist/plugins/cache.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Cache = void 0;
|
|
4
|
-
class Cache {
|
|
5
|
-
cache = new WeakMap();
|
|
6
|
-
get(key) {
|
|
7
|
-
return this.cache.get(key);
|
|
8
|
-
}
|
|
9
|
-
put(key, value) {
|
|
10
|
-
this.cache.set(key, { success: true, value });
|
|
11
|
-
return value;
|
|
12
|
-
}
|
|
13
|
-
error(key, error) {
|
|
14
|
-
this.cache.set(key, { success: false, error });
|
|
15
|
-
return error;
|
|
16
|
-
}
|
|
17
|
-
clear() {
|
|
18
|
-
this.cache = new WeakMap();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.Cache = Cache;
|
|
22
|
-
//# sourceMappingURL=cache.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/plugins/cache.ts"],"names":[],"mappings":";;;AAEA,MAAa,KAAK;IACN,KAAK,GAAG,IAAI,OAAO,EAAoB,CAAA;IAE/C,GAAG,CAAC,GAAM;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;IAED,GAAG,CAAoB,GAAM,EAAE,KAAQ;QACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7C,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,KAAK,CAAU,GAAM,EAAE,KAAQ;QAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9C,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,KAAK;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,OAAO,EAAE,CAAA;IAC9B,CAAC;CACJ;AApBD,sBAoBC"}
|
package/dist/plugins/usage.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Plugin, Shape, File, ts } from '..';
|
|
2
|
-
export declare class PluginUsageTracker {
|
|
3
|
-
private readonly trackedSources;
|
|
4
|
-
private readonly shapeCountPerPlugin;
|
|
5
|
-
clearPluginShapeUsage(): void;
|
|
6
|
-
addPluginShapeUsage(plugin: Plugin, source: ts.Node | Shape | File): void;
|
|
7
|
-
getShapeCountPerPlugin(): {
|
|
8
|
-
plugin: string;
|
|
9
|
-
count: number;
|
|
10
|
-
}[];
|
|
11
|
-
}
|
package/dist/plugins/usage.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PluginUsageTracker = void 0;
|
|
4
|
-
class PluginUsageTracker {
|
|
5
|
-
trackedSources = new Set();
|
|
6
|
-
shapeCountPerPlugin = new Map();
|
|
7
|
-
clearPluginShapeUsage() {
|
|
8
|
-
this.trackedSources.clear();
|
|
9
|
-
this.shapeCountPerPlugin.clear();
|
|
10
|
-
}
|
|
11
|
-
addPluginShapeUsage(plugin, source) {
|
|
12
|
-
if (!this.trackedSources.has(source)) {
|
|
13
|
-
this.trackedSources.add(source);
|
|
14
|
-
const existingCount = this.shapeCountPerPlugin.get(plugin) ?? 0;
|
|
15
|
-
this.shapeCountPerPlugin.set(plugin, existingCount + 1);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
getShapeCountPerPlugin() {
|
|
19
|
-
return [...this.shapeCountPerPlugin.entries()].map(([plugin, count]) => ({
|
|
20
|
-
plugin: plugin.getName().replace(/Plugin$/, ''), //Report just the names 'ACL', 'Record', etc for existing metrics compatibility
|
|
21
|
-
count,
|
|
22
|
-
}));
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
exports.PluginUsageTracker = PluginUsageTracker;
|
|
26
|
-
//# sourceMappingURL=usage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/plugins/usage.ts"],"names":[],"mappings":";;;AAEA,MAAa,kBAAkB;IACV,cAAc,GAAgC,IAAI,GAAG,EAAE,CAAA;IACvD,mBAAmB,GAAwB,IAAI,GAAG,EAAE,CAAA;IAErE,qBAAqB;QACjB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAC3B,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAA;IACpC,CAAC;IAED,mBAAmB,CAAC,MAAc,EAAE,MAA8B;QAC9D,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC/D,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,CAAC,CAAA;QAC3D,CAAC;IACL,CAAC;IAED,sBAAsB;QAClB,OAAO,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,+EAA+E;YAChI,KAAK;SACR,CAAC,CAAC,CAAA;IACP,CAAC;CACJ;AAvBD,gDAuBC"}
|
package/src/plugins/cache.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
type CacheEntry<V> = { success: true; value: V } | { success: false; error: unknown }
|
|
2
|
-
|
|
3
|
-
export class Cache<K extends object, V> {
|
|
4
|
-
private cache = new WeakMap<K, CacheEntry<V>>()
|
|
5
|
-
|
|
6
|
-
get(key: K): CacheEntry<V> | undefined {
|
|
7
|
-
return this.cache.get(key)
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
put<const T extends V>(key: K, value: T): T {
|
|
11
|
-
this.cache.set(key, { success: true, value })
|
|
12
|
-
return value
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
error<const T>(key: K, error: T): T {
|
|
16
|
-
this.cache.set(key, { success: false, error })
|
|
17
|
-
return error
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
clear(): void {
|
|
21
|
-
this.cache = new WeakMap()
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/plugins/usage.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Plugin, Shape, File, ts } from '..'
|
|
2
|
-
|
|
3
|
-
export class PluginUsageTracker {
|
|
4
|
-
private readonly trackedSources: Set<ts.Node | Shape | File> = new Set()
|
|
5
|
-
private readonly shapeCountPerPlugin: Map<Plugin, number> = new Map()
|
|
6
|
-
|
|
7
|
-
clearPluginShapeUsage() {
|
|
8
|
-
this.trackedSources.clear()
|
|
9
|
-
this.shapeCountPerPlugin.clear()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
addPluginShapeUsage(plugin: Plugin, source: ts.Node | Shape | File) {
|
|
13
|
-
if (!this.trackedSources.has(source)) {
|
|
14
|
-
this.trackedSources.add(source)
|
|
15
|
-
const existingCount = this.shapeCountPerPlugin.get(plugin) ?? 0
|
|
16
|
-
this.shapeCountPerPlugin.set(plugin, existingCount + 1)
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
getShapeCountPerPlugin() {
|
|
21
|
-
return [...this.shapeCountPerPlugin.entries()].map(([plugin, count]) => ({
|
|
22
|
-
plugin: plugin.getName().replace(/Plugin$/, ''), //Report just the names 'ACL', 'Record', etc for existing metrics compatibility
|
|
23
|
-
count,
|
|
24
|
-
}))
|
|
25
|
-
}
|
|
26
|
-
}
|