higherdata 0.7.0 → 0.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.
Files changed (2) hide show
  1. package/dist/index.js +206 -83
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20522,14 +20522,20 @@ var init_keychain = __esm({
20522
20522
  });
20523
20523
 
20524
20524
  // src/config.ts
20525
+ import { AsyncLocalStorage } from "async_hooks";
20525
20526
  import { chmod, mkdir, open as open2, readFile, rename, unlink } from "fs/promises";
20526
20527
  import { homedir } from "os";
20527
20528
  import { dirname, join } from "path";
20528
20529
  import { randomUUID } from "crypto";
20530
+ function withConfigWarn(warn, run) {
20531
+ return configWarn.run(warn, run);
20532
+ }
20529
20533
  function warnAboutFileKeychainFallback() {
20530
20534
  if (warnedAboutFileKeychainFallback) return;
20531
20535
  warnedAboutFileKeychainFallback = true;
20532
- process.stderr.write("HigherData could not access a system keychain. Credentials will be stored in the config file with 0600 permissions.\n");
20536
+ const warn = configWarn.getStore();
20537
+ if (warn) warn(KEYCHAIN_FILE_FALLBACK);
20538
+ else process.stderr.write(KEYCHAIN_FILE_FALLBACK);
20533
20539
  }
20534
20540
  function configPath(home = homedir()) {
20535
20541
  return join(home, ".config", "higherdata", "config.json");
@@ -20639,7 +20645,7 @@ function resolveSettings(config2, options = {}, env = process.env) {
20639
20645
  space: profile.space
20640
20646
  };
20641
20647
  }
20642
- var DEFAULT_API_URL, apiUrlSchema, profileSchema, configSchema, ConfigError, warnedAboutFileKeychainFallback;
20648
+ var DEFAULT_API_URL, apiUrlSchema, profileSchema, configSchema, ConfigError, KEYCHAIN_FILE_FALLBACK, warnedAboutFileKeychainFallback, configWarn;
20643
20649
  var init_config = __esm({
20644
20650
  "src/config.ts"() {
20645
20651
  "use strict";
@@ -20674,7 +20680,9 @@ var init_config = __esm({
20674
20680
  this.name = "ConfigError";
20675
20681
  }
20676
20682
  };
20683
+ KEYCHAIN_FILE_FALLBACK = "HigherData could not access a system keychain. Credentials will be stored in the config file with 0600 permissions.\n";
20677
20684
  warnedAboutFileKeychainFallback = false;
20685
+ configWarn = new AsyncLocalStorage();
20678
20686
  }
20679
20687
  });
20680
20688
 
@@ -26576,31 +26584,29 @@ var init_generated = __esm({
26576
26584
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
26577
26585
  },
26578
26586
  "titleKeywords": {
26579
- "description": "Job title keywords to match. A person can match any of them.",
26587
+ "description": "Job title keywords to match, at least 3 characters each after trimming. A person can match any of them.",
26580
26588
  "minItems": 1,
26581
26589
  "maxItems": 50,
26582
26590
  "type": "array",
26583
26591
  "items": {
26584
26592
  "type": "string",
26585
- "minLength": 1,
26586
- "maxLength": 120,
26587
- "pattern": "\\S"
26593
+ "minLength": 3,
26594
+ "maxLength": 120
26588
26595
  }
26589
26596
  },
26590
26597
  "requiredTitleKeywords": {
26591
- "description": "Job title keywords the person must match.",
26598
+ "description": "Job title keywords the person must match, at least 3 characters each after trimming.",
26592
26599
  "minItems": 1,
26593
26600
  "maxItems": 50,
26594
26601
  "type": "array",
26595
26602
  "items": {
26596
26603
  "type": "string",
26597
- "minLength": 1,
26598
- "maxLength": 120,
26599
- "pattern": "\\S"
26604
+ "minLength": 3,
26605
+ "maxLength": 120
26600
26606
  }
26601
26607
  },
26602
26608
  "requiredTitleKeywordGroups": {
26603
- "description": "Job title keyword groups. The person must match every group, and any keyword inside a group.",
26609
+ "description": "Job title keyword groups, at least 3 characters per keyword after trimming. The person must match every group, and any keyword inside a group.",
26604
26610
  "maxItems": 10,
26605
26611
  "type": "array",
26606
26612
  "items": {
@@ -26609,22 +26615,20 @@ var init_generated = __esm({
26609
26615
  "type": "array",
26610
26616
  "items": {
26611
26617
  "type": "string",
26612
- "minLength": 1,
26613
- "maxLength": 120,
26614
- "pattern": "\\S"
26618
+ "minLength": 3,
26619
+ "maxLength": 120
26615
26620
  }
26616
26621
  }
26617
26622
  },
26618
26623
  "excludeTitleKeywords": {
26619
- "description": "Job title keywords that remove a person.",
26624
+ "description": "Job title keywords that remove a person, at least 3 characters each after trimming.",
26620
26625
  "minItems": 1,
26621
26626
  "maxItems": 50,
26622
26627
  "type": "array",
26623
26628
  "items": {
26624
26629
  "type": "string",
26625
- "minLength": 1,
26626
- "maxLength": 120,
26627
- "pattern": "\\S"
26630
+ "minLength": 3,
26631
+ "maxLength": 120
26628
26632
  }
26629
26633
  },
26630
26634
  "jobFunctions": {
@@ -26875,6 +26879,31 @@ var init_generated = __esm({
26875
26879
  "additionalProperties": false
26876
26880
  }
26877
26881
  },
26882
+ {
26883
+ "name": "lists.delete",
26884
+ "description": "Delete a saved list and its membership and refresh history. Records and CRM data are unchanged. Dry run previews the deletion.",
26885
+ "risk": "destructive",
26886
+ "scopes": [
26887
+ "data:read",
26888
+ "data:write"
26889
+ ],
26890
+ "input": {
26891
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
26892
+ "type": "object",
26893
+ "properties": {
26894
+ "id": {
26895
+ "type": "string",
26896
+ "format": "uuid",
26897
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
26898
+ "description": "Saved list id in the current space."
26899
+ }
26900
+ },
26901
+ "required": [
26902
+ "id"
26903
+ ],
26904
+ "additionalProperties": false
26905
+ }
26906
+ },
26878
26907
  {
26879
26908
  "name": "lists.export",
26880
26909
  "description": "Export a saved list as paged CSV or JSONL with opaque ids. CSV escapes spreadsheet formulas. Pages contain at most 50 records.Insights fields and filters require the Insights or Complete plan.",
@@ -26962,6 +26991,15 @@ var init_generated = __esm({
26962
26991
  "type": "string",
26963
26992
  "format": "uuid",
26964
26993
  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
26994
+ },
26995
+ "sort": {
26996
+ "description": "List records sorted by name or date added.",
26997
+ "type": "string",
26998
+ "enum": [
26999
+ "name_asc",
27000
+ "name_desc",
27001
+ "added_desc"
27002
+ ]
26965
27003
  }
26966
27004
  },
26967
27005
  "additionalProperties": false
@@ -26999,6 +27037,75 @@ var init_generated = __esm({
26999
27037
  "additionalProperties": false
27000
27038
  }
27001
27039
  },
27040
+ {
27041
+ "name": "lists.remove",
27042
+ "description": "Remove up to 50 saved row ids from a list. A later dynamic refresh may add matching records again. Dry run previews the removal count.",
27043
+ "risk": "destructive",
27044
+ "scopes": [
27045
+ "data:read",
27046
+ "data:write"
27047
+ ],
27048
+ "input": {
27049
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
27050
+ "type": "object",
27051
+ "properties": {
27052
+ "id": {
27053
+ "type": "string",
27054
+ "format": "uuid",
27055
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
27056
+ "description": "Saved list id in the current space."
27057
+ },
27058
+ "ids": {
27059
+ "minItems": 1,
27060
+ "maxItems": 50,
27061
+ "type": "array",
27062
+ "items": {
27063
+ "type": "string",
27064
+ "format": "uuid",
27065
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
27066
+ },
27067
+ "description": "Saved row ids returned by lists.get, at most 50 per call."
27068
+ }
27069
+ },
27070
+ "required": [
27071
+ "id",
27072
+ "ids"
27073
+ ],
27074
+ "additionalProperties": false
27075
+ }
27076
+ },
27077
+ {
27078
+ "name": "lists.rename",
27079
+ "description": "Rename a saved list. Dry run previews the name.",
27080
+ "risk": "write_local",
27081
+ "scopes": [
27082
+ "data:read",
27083
+ "data:write"
27084
+ ],
27085
+ "input": {
27086
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
27087
+ "type": "object",
27088
+ "properties": {
27089
+ "id": {
27090
+ "type": "string",
27091
+ "format": "uuid",
27092
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
27093
+ "description": "Saved list id in the current space."
27094
+ },
27095
+ "name": {
27096
+ "type": "string",
27097
+ "minLength": 1,
27098
+ "maxLength": 80,
27099
+ "description": "New name for the saved list."
27100
+ }
27101
+ },
27102
+ "required": [
27103
+ "id",
27104
+ "name"
27105
+ ],
27106
+ "additionalProperties": false
27107
+ }
27108
+ },
27002
27109
  {
27003
27110
  "name": "lists.run",
27004
27111
  "description": "Queue a background preview or refresh. Only one job runs per list. Owners and admins can refresh dynamic lists now, including the current release. Dry run reports the proposed release without queueing.",
@@ -29520,7 +29627,7 @@ var init_generated = __esm({
29520
29627
  },
29521
29628
  {
29522
29629
  "name": "search.count_people",
29523
- "description": "Count people once by primary current job before suppression using release-built aggregates; search results may match other current jobs. Names and email use exact indexed counts. Unsupported refinements return an unavailable count, never a total that ignores them. exact: true explicitly requests one capped detailed count of matching people; never use it for live filtering.",
29630
+ "description": "Count people once by primary current job before suppression using the search index; search results may match other current jobs. Title keywords, required titles, title groups or seniorities can be used without company filters. Empty and exclusion-only counts are rejected. Broad counts are approximate. exact: true explicitly requests one capped detailed count of matching people; never use it for live filtering.",
29524
29631
  "risk": "read",
29525
29632
  "scopes": [
29526
29633
  "data:read"
@@ -30004,31 +30111,29 @@ var init_generated = __esm({
30004
30111
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
30005
30112
  },
30006
30113
  "titleKeywords": {
30007
- "description": "Job title keywords to match. A person can match any of them.",
30114
+ "description": "Job title keywords to match, at least 3 characters each after trimming. A person can match any of them.",
30008
30115
  "minItems": 1,
30009
30116
  "maxItems": 50,
30010
30117
  "type": "array",
30011
30118
  "items": {
30012
30119
  "type": "string",
30013
- "minLength": 1,
30014
- "maxLength": 120,
30015
- "pattern": "\\S"
30120
+ "minLength": 3,
30121
+ "maxLength": 120
30016
30122
  }
30017
30123
  },
30018
30124
  "requiredTitleKeywords": {
30019
- "description": "Job title keywords the person must match.",
30125
+ "description": "Job title keywords the person must match, at least 3 characters each after trimming.",
30020
30126
  "minItems": 1,
30021
30127
  "maxItems": 50,
30022
30128
  "type": "array",
30023
30129
  "items": {
30024
30130
  "type": "string",
30025
- "minLength": 1,
30026
- "maxLength": 120,
30027
- "pattern": "\\S"
30131
+ "minLength": 3,
30132
+ "maxLength": 120
30028
30133
  }
30029
30134
  },
30030
30135
  "requiredTitleKeywordGroups": {
30031
- "description": "Job title keyword groups. The person must match every group, and any keyword inside a group.",
30136
+ "description": "Job title keyword groups, at least 3 characters per keyword after trimming. The person must match every group, and any keyword inside a group.",
30032
30137
  "maxItems": 10,
30033
30138
  "type": "array",
30034
30139
  "items": {
@@ -30037,22 +30142,20 @@ var init_generated = __esm({
30037
30142
  "type": "array",
30038
30143
  "items": {
30039
30144
  "type": "string",
30040
- "minLength": 1,
30041
- "maxLength": 120,
30042
- "pattern": "\\S"
30145
+ "minLength": 3,
30146
+ "maxLength": 120
30043
30147
  }
30044
30148
  }
30045
30149
  },
30046
30150
  "excludeTitleKeywords": {
30047
- "description": "Job title keywords that remove a person.",
30151
+ "description": "Job title keywords that remove a person, at least 3 characters each after trimming.",
30048
30152
  "minItems": 1,
30049
30153
  "maxItems": 50,
30050
30154
  "type": "array",
30051
30155
  "items": {
30052
30156
  "type": "string",
30053
- "minLength": 1,
30054
- "maxLength": 120,
30055
- "pattern": "\\S"
30157
+ "minLength": 3,
30158
+ "maxLength": 120
30056
30159
  }
30057
30160
  },
30058
30161
  "jobFunctions": {
@@ -30346,7 +30449,7 @@ var init_generated = __esm({
30346
30449
  },
30347
30450
  {
30348
30451
  "name": "search.people",
30349
- "description": "Find people in HigherData Core, with 1 to 5 positive company HQ country codes or industries required unless a company id, company name, domain or indexed email scopes the search. Unscoped person names use indexed tokens and bounded, ranked pages. Person, job and company location use distinct filters; each city filter requires its corresponding country. Company-scoped contacts also support legacy contactLocation filters. Interactive pages contain at most 50 people. A download (download: true) contains at most 500 people and opaque ids. ",
30452
+ "description": "Find people in HigherData Core. A title keyword, required title, title group or seniority is enough to search without a company filter. Otherwise use 1 to 5 positive company HQ countries or industries, a company id, company name, domain, email or person name. Empty and exclusion-only searches are rejected. Unscoped person names use indexed tokens and bounded, ranked pages. Person, job and company location use distinct filters; each city filter requires its corresponding country. Company-scoped contacts also support legacy contactLocation filters. Interactive pages contain at most 50 people. A download (download: true) contains at most 500 people and opaque ids. ",
30350
30453
  "risk": "read",
30351
30454
  "scopes": [
30352
30455
  "data:read"
@@ -30827,31 +30930,29 @@ var init_generated = __esm({
30827
30930
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
30828
30931
  },
30829
30932
  "titleKeywords": {
30830
- "description": "Job title keywords to match. A person can match any of them.",
30933
+ "description": "Job title keywords to match, at least 3 characters each after trimming. A person can match any of them.",
30831
30934
  "minItems": 1,
30832
30935
  "maxItems": 50,
30833
30936
  "type": "array",
30834
30937
  "items": {
30835
30938
  "type": "string",
30836
- "minLength": 1,
30837
- "maxLength": 120,
30838
- "pattern": "\\S"
30939
+ "minLength": 3,
30940
+ "maxLength": 120
30839
30941
  }
30840
30942
  },
30841
30943
  "requiredTitleKeywords": {
30842
- "description": "Job title keywords the person must match.",
30944
+ "description": "Job title keywords the person must match, at least 3 characters each after trimming.",
30843
30945
  "minItems": 1,
30844
30946
  "maxItems": 50,
30845
30947
  "type": "array",
30846
30948
  "items": {
30847
30949
  "type": "string",
30848
- "minLength": 1,
30849
- "maxLength": 120,
30850
- "pattern": "\\S"
30950
+ "minLength": 3,
30951
+ "maxLength": 120
30851
30952
  }
30852
30953
  },
30853
30954
  "requiredTitleKeywordGroups": {
30854
- "description": "Job title keyword groups. The person must match every group, and any keyword inside a group.",
30955
+ "description": "Job title keyword groups, at least 3 characters per keyword after trimming. The person must match every group, and any keyword inside a group.",
30855
30956
  "maxItems": 10,
30856
30957
  "type": "array",
30857
30958
  "items": {
@@ -30860,22 +30961,20 @@ var init_generated = __esm({
30860
30961
  "type": "array",
30861
30962
  "items": {
30862
30963
  "type": "string",
30863
- "minLength": 1,
30864
- "maxLength": 120,
30865
- "pattern": "\\S"
30964
+ "minLength": 3,
30965
+ "maxLength": 120
30866
30966
  }
30867
30967
  }
30868
30968
  },
30869
30969
  "excludeTitleKeywords": {
30870
- "description": "Job title keywords that remove a person.",
30970
+ "description": "Job title keywords that remove a person, at least 3 characters each after trimming.",
30871
30971
  "minItems": 1,
30872
30972
  "maxItems": 50,
30873
30973
  "type": "array",
30874
30974
  "items": {
30875
30975
  "type": "string",
30876
- "minLength": 1,
30877
- "maxLength": 120,
30878
- "pattern": "\\S"
30976
+ "minLength": 3,
30977
+ "maxLength": 120
30879
30978
  }
30880
30979
  },
30881
30980
  "jobFunctions": {
@@ -33703,31 +33802,29 @@ var init_generated = __esm({
33703
33802
  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
33704
33803
  },
33705
33804
  "titleKeywords": {
33706
- "description": "Job title keywords to match. A person can match any of them.",
33805
+ "description": "Job title keywords to match, at least 3 characters each after trimming. A person can match any of them.",
33707
33806
  "minItems": 1,
33708
33807
  "maxItems": 50,
33709
33808
  "type": "array",
33710
33809
  "items": {
33711
33810
  "type": "string",
33712
- "minLength": 1,
33713
- "maxLength": 120,
33714
- "pattern": "\\S"
33811
+ "minLength": 3,
33812
+ "maxLength": 120
33715
33813
  }
33716
33814
  },
33717
33815
  "requiredTitleKeywords": {
33718
- "description": "Job title keywords the person must match.",
33816
+ "description": "Job title keywords the person must match, at least 3 characters each after trimming.",
33719
33817
  "minItems": 1,
33720
33818
  "maxItems": 50,
33721
33819
  "type": "array",
33722
33820
  "items": {
33723
33821
  "type": "string",
33724
- "minLength": 1,
33725
- "maxLength": 120,
33726
- "pattern": "\\S"
33822
+ "minLength": 3,
33823
+ "maxLength": 120
33727
33824
  }
33728
33825
  },
33729
33826
  "requiredTitleKeywordGroups": {
33730
- "description": "Job title keyword groups. The person must match every group, and any keyword inside a group.",
33827
+ "description": "Job title keyword groups, at least 3 characters per keyword after trimming. The person must match every group, and any keyword inside a group.",
33731
33828
  "maxItems": 10,
33732
33829
  "type": "array",
33733
33830
  "items": {
@@ -33736,22 +33833,20 @@ var init_generated = __esm({
33736
33833
  "type": "array",
33737
33834
  "items": {
33738
33835
  "type": "string",
33739
- "minLength": 1,
33740
- "maxLength": 120,
33741
- "pattern": "\\S"
33836
+ "minLength": 3,
33837
+ "maxLength": 120
33742
33838
  }
33743
33839
  }
33744
33840
  },
33745
33841
  "excludeTitleKeywords": {
33746
- "description": "Job title keywords that remove a person.",
33842
+ "description": "Job title keywords that remove a person, at least 3 characters each after trimming.",
33747
33843
  "minItems": 1,
33748
33844
  "maxItems": 50,
33749
33845
  "type": "array",
33750
33846
  "items": {
33751
33847
  "type": "string",
33752
- "minLength": 1,
33753
- "maxLength": 120,
33754
- "pattern": "\\S"
33848
+ "minLength": 3,
33849
+ "maxLength": 120
33755
33850
  }
33756
33851
  },
33757
33852
  "jobFunctions": {
@@ -38138,7 +38233,7 @@ var init_package = __esm({
38138
38233
  "package.json"() {
38139
38234
  package_default = {
38140
38235
  name: "higherdata",
38141
- version: "0.7.0",
38236
+ version: "0.7.1",
38142
38237
  type: "module",
38143
38238
  bin: {
38144
38239
  higherdata: "dist/index.js"
@@ -47424,7 +47519,7 @@ function BusyMark({ color, size = "large", options = animationOptions(), env = p
47424
47519
  }, [animate]);
47425
47520
  return /* @__PURE__ */ jsx5(Mark, { lines: animate ? busyFrame(frame, size) : markFrame(size), color });
47426
47521
  }
47427
- function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "default", space = "Default", workspace = "HigherOps", remaining = "--", profiles = [], fullScreen = false, identity = "API key", plan = "Plan unavailable", used = "--" }) {
47522
+ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "default", space = "Default", workspace = "HigherOps", remaining = "--", profiles = [], fullScreen = false, identity = "API key", plan = "Plan unavailable", used = "--", keychainNotice = "" }) {
47428
47523
  const width = Math.max(16, columns), color = colors ? "#f2b705" : void 0;
47429
47524
  const limit = Math.max(2, rows - (fullScreen ? 12 : 15));
47430
47525
  const extraRows = [state.error, state.notice].reduce((count, text2) => count + Math.ceil(clean(text2).length / (width - 4)), 0);
@@ -47707,6 +47802,7 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
47707
47802
  if (fullScreen) return /* @__PURE__ */ jsx5(PaletteContext.Provider, { value: colors, children: /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", width, height: rows, overflow: "hidden", backgroundColor: colors ? "#09090b" : void 0, children: [
47708
47803
  /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", flexGrow: 1, children: [
47709
47804
  /* @__PURE__ */ jsx5(AppBar, { columns: width, active: state.appTab ?? 0, colors, workspace, space, identity, plan, used, remaining }),
47805
+ keychainNotice && /* @__PURE__ */ jsx5(Box4, { flexShrink: 0, paddingX: 1, children: /* @__PURE__ */ jsx5(Text, { wrap: "wrap", children: clean(keychainNotice) }) }),
47710
47806
  /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: content })
47711
47807
  ] }),
47712
47808
  state.error && /* @__PURE__ */ jsx5(Text, { wrap: "truncate-end", color: colors ? "#ffe37a" : void 0, children: clean(state.error) }),
@@ -47762,6 +47858,7 @@ function TerminalScreen({ state, columns, rows = 28, colors = true, profile = "d
47762
47858
  ] })
47763
47859
  ] }),
47764
47860
  /* @__PURE__ */ jsx5(Text, { dimColor: true, children: "\u2550".repeat(Math.max(1, width - 4)) }),
47861
+ keychainNotice && /* @__PURE__ */ jsx5(Text, { wrap: "wrap", children: clean(keychainNotice) }),
47765
47862
  /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", width: width - 4, minHeight: largeHome ? 0 : Math.max(0, Math.min(rows - 16, 13)), children: content }),
47766
47863
  state.error && /* @__PURE__ */ jsx5(Text, { color: colors ? "red" : void 0, children: clean(state.error) }),
47767
47864
  state.notice && state.screen !== "busy" && /* @__PURE__ */ jsx5(Text, { dimColor: true, children: clean(state.notice) }),
@@ -47829,10 +47926,22 @@ import { open as open7 } from "fs/promises";
47829
47926
  import { useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
47830
47927
  import { render, useApp, useInput, useWindowSize } from "ink";
47831
47928
  import { jsx as jsx6 } from "react/jsx-runtime";
47929
+ function recordLabel(value, fallback) {
47930
+ if (!value || typeof value !== "object") return fallback;
47931
+ const record2 = value;
47932
+ if (typeof record2.name === "string" && record2.name.trim()) return record2.name.trim();
47933
+ if (typeof record2.slug === "string" && record2.slug.trim()) return record2.slug.trim();
47934
+ return fallback;
47935
+ }
47936
+ function principalLabel(principal) {
47937
+ const type = principal && typeof principal === "object" ? principal.type : void 0;
47938
+ return type === "api_key" ? "Signed in with API key" : "Signed in";
47939
+ }
47832
47940
  function InteractiveApp({ session, fullScreen = true, events }) {
47833
47941
  const { exit } = useApp(), { columns, rows } = useWindowSize();
47834
47942
  const settings = session.settings();
47835
- const [chrome, setChrome] = useState2({ workspace: "Workspace", remaining: "--", identity: "Signed out", plan: "Plan unavailable", used: "--" });
47943
+ const signedIn = Boolean(settings.apiKey);
47944
+ const [chrome, setChrome] = useState2({ workspace: "Workspace", space: "", remaining: "--", identity: "Signed in", plan: "Plan unavailable", used: "--" });
47836
47945
  const targets = useRef2(/* @__PURE__ */ new Map());
47837
47946
  const pages = useRef2([]);
47838
47947
  const pressed = useRef2(void 0);
@@ -47849,12 +47958,11 @@ function InteractiveApp({ session, fullScreen = true, events }) {
47849
47958
  }, []);
47850
47959
  useEffect3(() => {
47851
47960
  let active = true;
47852
- if (!settings.apiKey || !settings.space) return;
47961
+ if (!settings.apiKey) return;
47853
47962
  void Promise.all([session.call("account.whoami", {}), session.call("account.usage", {})]).then(([identity, usage]) => {
47854
- const tenant = identity.tenant;
47855
- if (active) setChrome({ workspace: tenant?.slug ?? "Workspace", remaining: typeof usage.verificationsRemaining === "number" ? usage.verificationsRemaining.toLocaleString("en-US") : "--", plan: typeof usage.plan === "string" ? usage.plan : "Plan unavailable", used: String(usage.verificationsUsed ?? "--"), identity: identity.principal?.type === "api_key" ? "Signed in with API key" : "Signed in" });
47963
+ if (active) setChrome({ workspace: recordLabel(identity.tenant, "Workspace"), space: recordLabel(identity.space, ""), remaining: typeof usage.verificationsRemaining === "number" ? usage.verificationsRemaining.toLocaleString("en-US") : "--", plan: typeof usage.plan === "string" ? usage.plan : "Plan unavailable", used: String(usage.verificationsUsed ?? "--"), identity: principalLabel(identity.principal) });
47856
47964
  }).catch(() => {
47857
- if (active) setChrome({ workspace: "Account unavailable", remaining: "--", identity: "Account unavailable", plan: "Plan unavailable", used: "--" });
47965
+ if (active) setChrome({ workspace: "Account unavailable", space: "Account unavailable", remaining: "--", identity: "Account unavailable", plan: "Plan unavailable", used: "--" });
47858
47966
  });
47859
47967
  return () => {
47860
47968
  active = false;
@@ -47950,7 +48058,7 @@ function InteractiveApp({ session, fullScreen = true, events }) {
47950
48058
  });
47951
48059
  else if (item.id === "login") void work("Waiting for browser approval...", async () => {
47952
48060
  await session.login((code, url2) => patch({ notice: `Approve ${code} at ${url2}` }));
47953
- return { screen: "home", notice: "Signed in. Choose a space to begin." };
48061
+ return { screen: "home", notice: "Signed in." };
47954
48062
  });
47955
48063
  else if (item.id === "ask") void work("Loading your private conversation...", async () => ({ screen: "ask", ask: await session.call("agent.get", {}), text: "" }));
47956
48064
  else patch({ screen: "tools", group: item.id, selected: 0, appTab: Math.max(0, TAB_GROUPS.indexOf(item.id)) });
@@ -48231,7 +48339,8 @@ function InteractiveApp({ session, fullScreen = true, events }) {
48231
48339
  }
48232
48340
  }
48233
48341
  useInput(handleInput);
48234
- return /* @__PURE__ */ jsx6(PointerContext.Provider, { value: targets.current, children: /* @__PURE__ */ jsx6(TerminalScreen, { state, columns, rows, colors: !Object.hasOwn(session.runtime.env, "NO_COLOR") && session.runtime.env.TERM !== "dumb", profile: settings.profile, profiles: Object.keys(session.config.profiles), space: settings.space ?? "Choose a space", workspace: settings.apiKey && settings.space ? chrome.workspace : "Sign in and choose a space", remaining: settings.apiKey && settings.space ? chrome.remaining : "--", fullScreen, identity: settings.apiKey ? chrome.identity : "Signed out", plan: settings.apiKey ? chrome.plan : "Sign in", used: chrome.used }) });
48342
+ const space = signedIn ? chrome.space || settings.space || "Choose a space" : "Signed out";
48343
+ return /* @__PURE__ */ jsx6(PointerContext.Provider, { value: targets.current, children: /* @__PURE__ */ jsx6(TerminalScreen, { state, columns, rows, colors: !Object.hasOwn(session.runtime.env, "NO_COLOR") && session.runtime.env.TERM !== "dumb", profile: settings.profile, profiles: Object.keys(session.config.profiles), space, workspace: signedIn ? chrome.workspace : "Signed out", remaining: signedIn ? chrome.remaining : "--", fullScreen, identity: signedIn ? chrome.identity : "Signed out", plan: signedIn ? chrome.plan : "Sign in", used: signedIn ? chrome.used : "--", keychainNotice: session.keychainNotice }) });
48235
48344
  }
48236
48345
  async function launchInteractive(runtime, options) {
48237
48346
  if (options.idempotencyKey) throw new CliError("Omit --idempotency-key in the interactive app. Each confirmed action gets its own key.");
@@ -48314,8 +48423,18 @@ var init_app = __esm({
48314
48423
  runtime;
48315
48424
  options;
48316
48425
  config = { activeProfile: "default", profiles: { default: {} } };
48426
+ keychainNotice = "";
48427
+ rememberKeychainWarning = (message) => {
48428
+ this.keychainNotice = message.replace(/\s+$/u, "");
48429
+ };
48430
+ loadConfig() {
48431
+ return withConfigWarn(this.rememberKeychainWarning, () => this.runtime.readConfig());
48432
+ }
48433
+ saveConfig(config2 = this.config) {
48434
+ return withConfigWarn(this.rememberKeychainWarning, () => this.runtime.writeConfig(config2));
48435
+ }
48317
48436
  async load() {
48318
- this.config = await this.runtime.readConfig();
48437
+ this.config = await this.loadConfig();
48319
48438
  }
48320
48439
  async lookup(query) {
48321
48440
  const result = await this.call("lookup.find", { query });
@@ -48338,19 +48457,20 @@ var init_app = __esm({
48338
48457
  async selectSpace(space) {
48339
48458
  await this.api(space).tool("account.whoami", {});
48340
48459
  this.config.profiles[this.config.activeProfile].space = space;
48341
- await this.runtime.writeConfig(this.config);
48460
+ await this.saveConfig();
48342
48461
  }
48343
48462
  async selectProfile(profile) {
48344
48463
  if (this.runtime.env.HIGHERDATA_API_KEY) throw new CliError("Unset HIGHERDATA_API_KEY to switch saved workspace profiles.");
48345
48464
  if (!Object.hasOwn(this.config.profiles, profile)) throw new CliError("Choose a saved profile.");
48346
48465
  const config2 = { ...this.config, activeProfile: profile };
48347
48466
  await new ApiClient(resolveSettings(config2, this.options, this.runtime.env), this.runtime.fetchImpl).tool("account.whoami", {});
48348
- await this.runtime.writeConfig(config2);
48467
+ await this.saveConfig(config2);
48349
48468
  this.config = config2;
48350
48469
  }
48351
48470
  async logout() {
48352
48471
  delete this.config.profiles[this.config.activeProfile].apiKey;
48353
- await this.runtime.writeConfig(this.config);
48472
+ await this.saveConfig();
48473
+ this.config = await this.loadConfig();
48354
48474
  }
48355
48475
  async install(kind, input2, print) {
48356
48476
  const options = { agent: input2.agent, scope: input2.scope, profile: input2.profile, print };
@@ -48358,8 +48478,11 @@ var init_app = __esm({
48358
48478
  }
48359
48479
  async login(prompt) {
48360
48480
  const settings = this.settings(), key = await deviceLogin(this.api(), { now: this.runtime.now, sleep: this.runtime.sleep, openBrowser: this.runtime.openBrowser, prompt });
48361
- this.config.profiles[this.config.activeProfile] = { apiUrl: settings.apiUrl, apiKey: key };
48362
- await this.runtime.writeConfig(this.config);
48481
+ const profile = this.config.profiles[this.config.activeProfile];
48482
+ this.config.profiles[this.config.activeProfile] = { ...profile, apiUrl: settings.apiUrl, apiKey: key };
48483
+ delete this.config.profiles[this.config.activeProfile].space;
48484
+ await this.saveConfig();
48485
+ this.config = await this.loadConfig();
48363
48486
  }
48364
48487
  async download(state, path2, options = {}) {
48365
48488
  if (!path2.trim()) throw new CliError("Enter a new destination file.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "higherdata",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "higherdata": "dist/index.js"