githits 0.4.2 → 0.4.4
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/README.md +43 -17
- package/dist/cli.js +1185 -397
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-jdygt0ra.js → chunk-96tjsv6y.js} +1 -1
- package/dist/shared/chunk-k35egwwf.js +15 -0
- package/dist/shared/{chunk-v8sths32.js → chunk-tfqxat16.js} +188 -59
- package/gemini-extension.json +1 -1
- package/package.json +4 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/dist/shared/chunk-q2mre780.js +0 -11
package/dist/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearAutoLoginAuthSessionMetadata,
|
|
3
|
+
createAuthCommandDependencies,
|
|
4
|
+
createAuthStatusDependencies,
|
|
5
|
+
createContainer,
|
|
6
|
+
loadAutoLoginAuthSessionMetadata
|
|
7
|
+
} from "./chunk-tfqxat16.js";
|
|
8
|
+
import"./chunk-96tjsv6y.js";
|
|
9
|
+
export {
|
|
10
|
+
loadAutoLoginAuthSessionMetadata,
|
|
11
|
+
createContainer,
|
|
12
|
+
createAuthStatusDependencies,
|
|
13
|
+
createAuthCommandDependencies,
|
|
14
|
+
clearAutoLoginAuthSessionMetadata
|
|
15
|
+
};
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__require,
|
|
3
3
|
version
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-96tjsv6y.js";
|
|
5
5
|
|
|
6
6
|
// src/services/app-config-paths.ts
|
|
7
7
|
var APP_DIR = "githits";
|
|
8
8
|
function getAppConfigDir(fs) {
|
|
9
9
|
const home = fs.getHomeDir();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return fs.joinPath(process.env.APPDATA ?? fs.joinPath(home, "AppData", "Roaming"), APP_DIR);
|
|
13
|
-
case "darwin":
|
|
14
|
-
return fs.joinPath(home, "Library", "Application Support", APP_DIR);
|
|
15
|
-
default:
|
|
16
|
-
return fs.joinPath(process.env.XDG_CONFIG_HOME ?? fs.joinPath(home, ".config"), APP_DIR);
|
|
10
|
+
if (process.platform === "win32") {
|
|
11
|
+
return fs.joinPath(process.env.APPDATA ?? fs.joinPath(home, "AppData", "Roaming"), APP_DIR);
|
|
17
12
|
}
|
|
13
|
+
return fs.joinPath(process.env.XDG_CONFIG_HOME ?? fs.joinPath(home, ".config"), APP_DIR);
|
|
18
14
|
}
|
|
19
15
|
function getAuthConfigPath(fs) {
|
|
20
16
|
return fs.joinPath(getAppConfigDir(fs), "config.toml");
|
|
@@ -25,6 +21,15 @@ function getAuthFileStorageDir(fs) {
|
|
|
25
21
|
function getLegacyAuthStorageDir(fs) {
|
|
26
22
|
return fs.joinPath(fs.getHomeDir(), ".githits");
|
|
27
23
|
}
|
|
24
|
+
function getLegacyMacAppConfigDir(fs) {
|
|
25
|
+
return fs.joinPath(fs.getHomeDir(), "Library", "Application Support", APP_DIR);
|
|
26
|
+
}
|
|
27
|
+
function getLegacyMacAuthConfigPath(fs) {
|
|
28
|
+
return fs.joinPath(getLegacyMacAppConfigDir(fs), "config.toml");
|
|
29
|
+
}
|
|
30
|
+
function getLegacyMacAuthFileStorageDir(fs) {
|
|
31
|
+
return fs.joinPath(getLegacyMacAppConfigDir(fs), "auth");
|
|
32
|
+
}
|
|
28
33
|
// src/services/auth-config.ts
|
|
29
34
|
import { parse as parseToml } from "smol-toml";
|
|
30
35
|
import { z } from "zod";
|
|
@@ -50,7 +55,7 @@ function parseAuthStorageMode(value) {
|
|
|
50
55
|
throw new AuthConfigError(`Invalid auth storage mode "${value}". Use "keychain" or "file". File mode stores OAuth credentials unencrypted on disk.`);
|
|
51
56
|
}
|
|
52
57
|
async function loadAuthConfig(fs) {
|
|
53
|
-
|
|
58
|
+
let configPath = getAuthConfigPath(fs);
|
|
54
59
|
const envMode = process.env.GITHITS_AUTH_STORAGE;
|
|
55
60
|
if (envMode !== undefined && envMode.trim() !== "") {
|
|
56
61
|
try {
|
|
@@ -63,7 +68,12 @@ async function loadAuthConfig(fs) {
|
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
if (!await fs.exists(configPath)) {
|
|
66
|
-
|
|
71
|
+
const legacyMacConfigPath = getLegacyMacAuthConfigPath(fs);
|
|
72
|
+
if (process.platform === "darwin" && await fs.exists(legacyMacConfigPath)) {
|
|
73
|
+
configPath = legacyMacConfigPath;
|
|
74
|
+
} else {
|
|
75
|
+
return { storage: "keychain", configPath };
|
|
76
|
+
}
|
|
67
77
|
}
|
|
68
78
|
let rawConfig;
|
|
69
79
|
try {
|
|
@@ -732,6 +742,70 @@ async function clearAuthSessionBestEffort(clearTokens, clearClient) {
|
|
|
732
742
|
if (firstError)
|
|
733
743
|
throw firstError;
|
|
734
744
|
}
|
|
745
|
+
|
|
746
|
+
// src/services/auth-session-metadata-storage.ts
|
|
747
|
+
var METADATA_FILE = "metadata.json";
|
|
748
|
+
var DIR_MODE2 = 448;
|
|
749
|
+
|
|
750
|
+
class AuthSessionMetadataStorage {
|
|
751
|
+
fs;
|
|
752
|
+
configDir;
|
|
753
|
+
metadataPath;
|
|
754
|
+
constructor(fs, configDir) {
|
|
755
|
+
this.fs = fs;
|
|
756
|
+
this.configDir = configDir ?? getAuthFileStorageDir(fs);
|
|
757
|
+
this.metadataPath = fs.joinPath(this.configDir, METADATA_FILE);
|
|
758
|
+
}
|
|
759
|
+
async load(baseUrl) {
|
|
760
|
+
const stored = await this.loadFile();
|
|
761
|
+
if (!stored)
|
|
762
|
+
return null;
|
|
763
|
+
const metadata = stored.sessions[normalizeBaseUrl(baseUrl)] ?? null;
|
|
764
|
+
return isAuthSessionMetadata(metadata) ? metadata : null;
|
|
765
|
+
}
|
|
766
|
+
async saveFromTokens(baseUrl, tokens) {
|
|
767
|
+
const stored = await this.loadFile() ?? {
|
|
768
|
+
version: 1,
|
|
769
|
+
sessions: {}
|
|
770
|
+
};
|
|
771
|
+
stored.sessions[normalizeBaseUrl(baseUrl)] = {
|
|
772
|
+
createdAt: tokens.createdAt,
|
|
773
|
+
expiresAt: tokens.expiresAt,
|
|
774
|
+
updatedAt: new Date().toISOString()
|
|
775
|
+
};
|
|
776
|
+
await this.fs.ensureDir(this.configDir, DIR_MODE2);
|
|
777
|
+
await this.fs.atomicWriteFile(this.metadataPath, JSON.stringify(stored, null, 2));
|
|
778
|
+
}
|
|
779
|
+
async clear(baseUrl) {
|
|
780
|
+
const stored = await this.loadFile();
|
|
781
|
+
if (!stored)
|
|
782
|
+
return;
|
|
783
|
+
delete stored.sessions[normalizeBaseUrl(baseUrl)];
|
|
784
|
+
if (Object.keys(stored.sessions).length === 0) {
|
|
785
|
+
await this.fs.deleteFile(this.metadataPath);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
await this.fs.atomicWriteFile(this.metadataPath, JSON.stringify(stored, null, 2));
|
|
789
|
+
}
|
|
790
|
+
async loadFile() {
|
|
791
|
+
if (!await this.fs.exists(this.metadataPath))
|
|
792
|
+
return null;
|
|
793
|
+
try {
|
|
794
|
+
const content = await this.fs.readFile(this.metadataPath);
|
|
795
|
+
const data = JSON.parse(content);
|
|
796
|
+
if (data.version !== 1 || !data.sessions)
|
|
797
|
+
return null;
|
|
798
|
+
return data;
|
|
799
|
+
} catch {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
function isAuthSessionMetadata(value) {
|
|
805
|
+
if (value === null || typeof value !== "object")
|
|
806
|
+
return false;
|
|
807
|
+
return typeof value.createdAt === "string" && value.createdAt.length > 0 && typeof value.updatedAt === "string" && value.updatedAt.length > 0 && (value.expiresAt === null || typeof value.expiresAt === "string" && value.expiresAt.length > 0);
|
|
808
|
+
}
|
|
735
809
|
// src/services/browser-service.ts
|
|
736
810
|
import open from "open";
|
|
737
811
|
|
|
@@ -1326,7 +1400,9 @@ class GitHitsServiceImpl {
|
|
|
1326
1400
|
method: "POST",
|
|
1327
1401
|
headers: this.headers(),
|
|
1328
1402
|
body: JSON.stringify({
|
|
1329
|
-
|
|
1403
|
+
...params.solutionId !== undefined && {
|
|
1404
|
+
solution_id: params.solutionId
|
|
1405
|
+
},
|
|
1330
1406
|
accepted: params.accepted,
|
|
1331
1407
|
feedback_text: params.feedbackText ?? null
|
|
1332
1408
|
})
|
|
@@ -3531,15 +3607,19 @@ class MigratingAuthStorage {
|
|
|
3531
3607
|
mode;
|
|
3532
3608
|
configPath;
|
|
3533
3609
|
onWarning;
|
|
3610
|
+
metadata;
|
|
3611
|
+
additionalLegacyStores;
|
|
3534
3612
|
warnedFileModeKeychainExport = false;
|
|
3535
3613
|
warnedAmbiguousPlaintext = false;
|
|
3536
|
-
constructor(primary, file, legacy, mode, configPath = "your GitHits config.toml", onWarning = () => {}) {
|
|
3614
|
+
constructor(primary, file, legacy, mode, configPath = "your GitHits config.toml", onWarning = () => {}, metadata, additionalLegacyStores = []) {
|
|
3537
3615
|
this.primary = primary;
|
|
3538
3616
|
this.file = file;
|
|
3539
3617
|
this.legacy = legacy;
|
|
3540
3618
|
this.mode = mode;
|
|
3541
3619
|
this.configPath = configPath;
|
|
3542
3620
|
this.onWarning = onWarning;
|
|
3621
|
+
this.metadata = metadata;
|
|
3622
|
+
this.additionalLegacyStores = additionalLegacyStores;
|
|
3543
3623
|
}
|
|
3544
3624
|
async loadTokens(baseUrl2) {
|
|
3545
3625
|
if (this.mode === "file") {
|
|
@@ -3550,10 +3630,12 @@ class MigratingAuthStorage {
|
|
|
3550
3630
|
async saveTokens(baseUrl2, data) {
|
|
3551
3631
|
if (this.mode === "file") {
|
|
3552
3632
|
await this.file.saveTokens(baseUrl2, data);
|
|
3633
|
+
await this.saveMetadataBestEffort(baseUrl2, data);
|
|
3553
3634
|
return;
|
|
3554
3635
|
}
|
|
3555
3636
|
try {
|
|
3556
3637
|
await this.primary.saveTokens(baseUrl2, data);
|
|
3638
|
+
await this.saveMetadataBestEffort(baseUrl2, data);
|
|
3557
3639
|
} catch (error) {
|
|
3558
3640
|
throw this.toPolicyError(error);
|
|
3559
3641
|
}
|
|
@@ -3569,6 +3651,10 @@ class MigratingAuthStorage {
|
|
|
3569
3651
|
const primaryError = await this.clearBestEffort(() => this.primary.clearTokens(baseUrl2));
|
|
3570
3652
|
await this.clearBestEffort(() => this.file.clearTokens(baseUrl2));
|
|
3571
3653
|
await this.clearBestEffort(() => this.legacy.clearTokens(baseUrl2));
|
|
3654
|
+
for (const legacy of this.additionalLegacyStores) {
|
|
3655
|
+
await this.clearBestEffort(() => legacy.clearTokens(baseUrl2));
|
|
3656
|
+
}
|
|
3657
|
+
await this.clearBestEffort(() => this.metadata?.clear(baseUrl2) ?? Promise.resolve());
|
|
3572
3658
|
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3573
3659
|
throw primaryError;
|
|
3574
3660
|
}
|
|
@@ -3601,6 +3687,9 @@ class MigratingAuthStorage {
|
|
|
3601
3687
|
const primaryError = await this.clearBestEffort(() => this.primary.clearClient(baseUrl2));
|
|
3602
3688
|
await this.clearBestEffort(() => this.file.clearClient(baseUrl2));
|
|
3603
3689
|
await this.clearBestEffort(() => this.legacy.clearClient(baseUrl2));
|
|
3690
|
+
for (const legacy of this.additionalLegacyStores) {
|
|
3691
|
+
await this.clearBestEffort(() => legacy.clearClient(baseUrl2));
|
|
3692
|
+
}
|
|
3604
3693
|
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3605
3694
|
throw primaryError;
|
|
3606
3695
|
}
|
|
@@ -3608,10 +3697,12 @@ class MigratingAuthStorage {
|
|
|
3608
3697
|
async saveAuthSession(baseUrl2, client, tokens) {
|
|
3609
3698
|
if (this.mode === "file") {
|
|
3610
3699
|
await this.file.saveAuthSession(baseUrl2, client, tokens);
|
|
3700
|
+
await this.saveMetadataBestEffort(baseUrl2, tokens);
|
|
3611
3701
|
return;
|
|
3612
3702
|
}
|
|
3613
3703
|
try {
|
|
3614
3704
|
await this.primary.saveAuthSession(baseUrl2, client, tokens);
|
|
3705
|
+
await this.saveMetadataBestEffort(baseUrl2, tokens);
|
|
3615
3706
|
} catch (error) {
|
|
3616
3707
|
throw this.toPolicyError(error);
|
|
3617
3708
|
}
|
|
@@ -3620,6 +3711,10 @@ class MigratingAuthStorage {
|
|
|
3620
3711
|
const primaryError = await this.clearBestEffort(() => this.primary.clearAuthSession(baseUrl2));
|
|
3621
3712
|
await this.clearBestEffort(() => this.file.clearAuthSession(baseUrl2));
|
|
3622
3713
|
await this.clearBestEffort(() => this.legacy.clearAuthSession(baseUrl2));
|
|
3714
|
+
for (const legacy of this.additionalLegacyStores) {
|
|
3715
|
+
await this.clearBestEffort(() => legacy.clearAuthSession(baseUrl2));
|
|
3716
|
+
}
|
|
3717
|
+
await this.clearBestEffort(() => this.metadata?.clear(baseUrl2) ?? Promise.resolve());
|
|
3623
3718
|
if (primaryError && !(primaryError instanceof KeychainUnavailableError)) {
|
|
3624
3719
|
throw primaryError;
|
|
3625
3720
|
}
|
|
@@ -3630,8 +3725,10 @@ class MigratingAuthStorage {
|
|
|
3630
3725
|
async loadTokensKeychainMode(baseUrl2) {
|
|
3631
3726
|
try {
|
|
3632
3727
|
const primaryTokens = await this.primary.loadTokens(baseUrl2);
|
|
3633
|
-
if (primaryTokens)
|
|
3728
|
+
if (primaryTokens) {
|
|
3729
|
+
await this.saveMetadataBestEffort(baseUrl2, primaryTokens);
|
|
3634
3730
|
return primaryTokens;
|
|
3731
|
+
}
|
|
3635
3732
|
} catch (error) {
|
|
3636
3733
|
if (!(error instanceof KeychainUnavailableError))
|
|
3637
3734
|
throw error;
|
|
@@ -3646,7 +3743,8 @@ class MigratingAuthStorage {
|
|
|
3646
3743
|
return candidate.data;
|
|
3647
3744
|
throw error;
|
|
3648
3745
|
}
|
|
3649
|
-
await this.clearMigratedPlaintext(baseUrl2, "tokens", candidate.source, candidate.ambiguous);
|
|
3746
|
+
await this.clearMigratedPlaintext(baseUrl2, "tokens", candidate.source, candidate.storage, candidate.ambiguous);
|
|
3747
|
+
await this.saveMetadataBestEffort(baseUrl2, candidate.data);
|
|
3650
3748
|
return candidate.data;
|
|
3651
3749
|
}
|
|
3652
3750
|
async loadTokensFileMode(baseUrl2) {
|
|
@@ -3654,8 +3752,9 @@ class MigratingAuthStorage {
|
|
|
3654
3752
|
if (candidate) {
|
|
3655
3753
|
if (candidate.source === "legacy") {
|
|
3656
3754
|
await this.file.saveTokens(baseUrl2, candidate.data);
|
|
3657
|
-
await this.clearBestEffort(() =>
|
|
3755
|
+
await this.clearBestEffort(() => candidate.storage.clearTokens(baseUrl2));
|
|
3658
3756
|
}
|
|
3757
|
+
await this.saveMetadataBestEffort(baseUrl2, candidate.data);
|
|
3659
3758
|
return candidate.data;
|
|
3660
3759
|
}
|
|
3661
3760
|
let primaryTokens = null;
|
|
@@ -3669,6 +3768,7 @@ class MigratingAuthStorage {
|
|
|
3669
3768
|
return null;
|
|
3670
3769
|
this.warnKeychainExport();
|
|
3671
3770
|
await this.file.saveTokens(baseUrl2, primaryTokens);
|
|
3771
|
+
await this.saveMetadataBestEffort(baseUrl2, primaryTokens);
|
|
3672
3772
|
return primaryTokens;
|
|
3673
3773
|
}
|
|
3674
3774
|
async loadClientKeychainMode(baseUrl2) {
|
|
@@ -3690,7 +3790,7 @@ class MigratingAuthStorage {
|
|
|
3690
3790
|
return candidate.data;
|
|
3691
3791
|
throw error;
|
|
3692
3792
|
}
|
|
3693
|
-
await this.clearMigratedPlaintext(baseUrl2, "client", candidate.source, candidate.ambiguous);
|
|
3793
|
+
await this.clearMigratedPlaintext(baseUrl2, "client", candidate.source, candidate.storage, candidate.ambiguous);
|
|
3694
3794
|
return candidate.data;
|
|
3695
3795
|
}
|
|
3696
3796
|
async loadClientFileMode(baseUrl2) {
|
|
@@ -3698,7 +3798,7 @@ class MigratingAuthStorage {
|
|
|
3698
3798
|
if (candidate) {
|
|
3699
3799
|
if (candidate.source === "legacy") {
|
|
3700
3800
|
await this.file.saveClient(baseUrl2, candidate.data);
|
|
3701
|
-
await this.clearBestEffort(() =>
|
|
3801
|
+
await this.clearBestEffort(() => candidate.storage.clearClient(baseUrl2));
|
|
3702
3802
|
}
|
|
3703
3803
|
return candidate.data;
|
|
3704
3804
|
}
|
|
@@ -3722,18 +3822,22 @@ class MigratingAuthStorage {
|
|
|
3722
3822
|
candidates.push({
|
|
3723
3823
|
data: fileTokens,
|
|
3724
3824
|
source: "file",
|
|
3825
|
+
storage: this.file,
|
|
3725
3826
|
timestamp: fileTokens.createdAt,
|
|
3726
3827
|
ambiguous: false
|
|
3727
3828
|
});
|
|
3728
3829
|
}
|
|
3729
|
-
const
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3830
|
+
for (const legacy of this.getLegacyStores()) {
|
|
3831
|
+
const legacyTokens = await legacy.loadTokens(baseUrl2);
|
|
3832
|
+
if (legacyTokens) {
|
|
3833
|
+
candidates.push({
|
|
3834
|
+
data: legacyTokens,
|
|
3835
|
+
source: "legacy",
|
|
3836
|
+
storage: legacy,
|
|
3837
|
+
timestamp: legacyTokens.createdAt,
|
|
3838
|
+
ambiguous: false
|
|
3839
|
+
});
|
|
3840
|
+
}
|
|
3737
3841
|
}
|
|
3738
3842
|
return this.selectNewestCandidate(candidates);
|
|
3739
3843
|
}
|
|
@@ -3744,18 +3848,22 @@ class MigratingAuthStorage {
|
|
|
3744
3848
|
candidates.push({
|
|
3745
3849
|
data: fileClient,
|
|
3746
3850
|
source: "file",
|
|
3851
|
+
storage: this.file,
|
|
3747
3852
|
timestamp: fileClient.registeredAt,
|
|
3748
3853
|
ambiguous: false
|
|
3749
3854
|
});
|
|
3750
3855
|
}
|
|
3751
|
-
const
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3856
|
+
for (const legacy of this.getLegacyStores()) {
|
|
3857
|
+
const legacyClient = await legacy.loadClient(baseUrl2);
|
|
3858
|
+
if (legacyClient) {
|
|
3859
|
+
candidates.push({
|
|
3860
|
+
data: legacyClient,
|
|
3861
|
+
source: "legacy",
|
|
3862
|
+
storage: legacy,
|
|
3863
|
+
timestamp: legacyClient.registeredAt,
|
|
3864
|
+
ambiguous: false
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3759
3867
|
}
|
|
3760
3868
|
return this.selectNewestCandidate(candidates);
|
|
3761
3869
|
}
|
|
@@ -3770,7 +3878,7 @@ class MigratingAuthStorage {
|
|
|
3770
3878
|
}));
|
|
3771
3879
|
if (parsed.some((entry) => Number.isNaN(entry.timestampMs))) {
|
|
3772
3880
|
this.warnAmbiguousPlaintext();
|
|
3773
|
-
const selected = candidates.find((candidate) => candidate.source === "file") ??
|
|
3881
|
+
const selected = candidates.find((candidate) => candidate.source === "file") ?? null;
|
|
3774
3882
|
if (selected)
|
|
3775
3883
|
selected.ambiguous = true;
|
|
3776
3884
|
return selected;
|
|
@@ -3782,16 +3890,20 @@ class MigratingAuthStorage {
|
|
|
3782
3890
|
return candidates[0] ?? null;
|
|
3783
3891
|
if (second && first.timestampMs === second.timestampMs) {
|
|
3784
3892
|
this.warnAmbiguousPlaintext();
|
|
3785
|
-
const selected = candidates.find((candidate) => candidate.source === "file") ??
|
|
3893
|
+
const selected = candidates.find((candidate) => candidate.source === "file") ?? null;
|
|
3894
|
+
if (!selected)
|
|
3895
|
+
return null;
|
|
3786
3896
|
selected.ambiguous = true;
|
|
3787
3897
|
return selected;
|
|
3788
3898
|
}
|
|
3789
3899
|
return first.candidate;
|
|
3790
3900
|
}
|
|
3791
|
-
async clearMigratedPlaintext(baseUrl2, kind, source, ambiguous = false) {
|
|
3901
|
+
async clearMigratedPlaintext(baseUrl2, kind, source, storage, ambiguous = false) {
|
|
3792
3902
|
if (!ambiguous) {
|
|
3793
3903
|
await this.clearPlaintextSource(this.file, baseUrl2, kind);
|
|
3794
|
-
|
|
3904
|
+
for (const legacy of this.getLegacyStores()) {
|
|
3905
|
+
await this.clearPlaintextSource(legacy, baseUrl2, kind);
|
|
3906
|
+
}
|
|
3795
3907
|
return;
|
|
3796
3908
|
}
|
|
3797
3909
|
if (source === "file") {
|
|
@@ -3799,9 +3911,12 @@ class MigratingAuthStorage {
|
|
|
3799
3911
|
return;
|
|
3800
3912
|
}
|
|
3801
3913
|
if (source === "legacy") {
|
|
3802
|
-
await this.clearPlaintextSource(
|
|
3914
|
+
await this.clearPlaintextSource(storage, baseUrl2, kind);
|
|
3803
3915
|
}
|
|
3804
3916
|
}
|
|
3917
|
+
getLegacyStores() {
|
|
3918
|
+
return [...this.additionalLegacyStores, this.legacy];
|
|
3919
|
+
}
|
|
3805
3920
|
async clearPlaintextSource(storage, baseUrl2, kind) {
|
|
3806
3921
|
await this.clearBestEffort(() => kind === "tokens" ? storage.clearTokens(baseUrl2) : storage.clearClient(baseUrl2));
|
|
3807
3922
|
}
|
|
@@ -3813,6 +3928,9 @@ class MigratingAuthStorage {
|
|
|
3813
3928
|
return error;
|
|
3814
3929
|
}
|
|
3815
3930
|
}
|
|
3931
|
+
async saveMetadataBestEffort(baseUrl2, tokens) {
|
|
3932
|
+
await this.clearBestEffort(() => this.metadata?.saveFromTokens(baseUrl2, tokens) ?? Promise.resolve());
|
|
3933
|
+
}
|
|
3816
3934
|
toPolicyError(error) {
|
|
3817
3935
|
if (!(error instanceof KeychainUnavailableError))
|
|
3818
3936
|
return error;
|
|
@@ -3985,10 +4103,6 @@ var packageSecurityOverviewSchema = z3.object({
|
|
|
3985
4103
|
hasCurrentVulnerabilities: z3.boolean().nullable().optional(),
|
|
3986
4104
|
recentVulnerabilities: z3.array(vulnerabilityOverviewSchema).nullable().optional()
|
|
3987
4105
|
}).nullable().optional();
|
|
3988
|
-
var quickstartInfoSchema = z3.object({
|
|
3989
|
-
installCommand: z3.string().nullable().optional(),
|
|
3990
|
-
usageExample: z3.string().nullable().optional()
|
|
3991
|
-
}).nullable().optional();
|
|
3992
4106
|
var changelogEntrySchema = z3.object({
|
|
3993
4107
|
version: z3.string().nullable().optional(),
|
|
3994
4108
|
publishedAt: z3.string().nullable().optional(),
|
|
@@ -3997,7 +4111,6 @@ var changelogEntrySchema = z3.object({
|
|
|
3997
4111
|
var packageSummaryResponseSchema = z3.object({
|
|
3998
4112
|
package: packageIdentitySchema.nullable().optional(),
|
|
3999
4113
|
security: packageSecurityOverviewSchema,
|
|
4000
|
-
quickstart: quickstartInfoSchema,
|
|
4001
4114
|
latestChangelogs: z3.array(changelogEntrySchema).nullable().optional()
|
|
4002
4115
|
});
|
|
4003
4116
|
var graphQLErrorSchema2 = z3.object({
|
|
@@ -4044,10 +4157,6 @@ query PackageSummary($registry: Registry!, $name: String!) {
|
|
|
4044
4157
|
publishedAt
|
|
4045
4158
|
}
|
|
4046
4159
|
}
|
|
4047
|
-
quickstart {
|
|
4048
|
-
installCommand
|
|
4049
|
-
usageExample
|
|
4050
|
-
}
|
|
4051
4160
|
latestChangelogs(limit: 3) {
|
|
4052
4161
|
version
|
|
4053
4162
|
publishedAt
|
|
@@ -4112,6 +4221,7 @@ query PackageVulnerabilities(
|
|
|
4112
4221
|
$version: String
|
|
4113
4222
|
$minSeverity: Float
|
|
4114
4223
|
$includeWithdrawn: Boolean
|
|
4224
|
+
$scope: VulnerabilityScope = AFFECTED
|
|
4115
4225
|
$after: String
|
|
4116
4226
|
) {
|
|
4117
4227
|
packageVulnerabilities(
|
|
@@ -4132,7 +4242,7 @@ query PackageVulnerabilities(
|
|
|
4132
4242
|
allVulnerabilityCount
|
|
4133
4243
|
currentVersionAffected
|
|
4134
4244
|
upgradePaths
|
|
4135
|
-
advisories(scope:
|
|
4245
|
+
advisories(scope: $scope, first: 100, after: $after) {
|
|
4136
4246
|
entries {
|
|
4137
4247
|
osvId
|
|
4138
4248
|
summary
|
|
@@ -4687,10 +4797,6 @@ class PackageIntelligenceServiceImpl {
|
|
|
4687
4797
|
publishedAt: vuln.publishedAt ?? undefined
|
|
4688
4798
|
})) ?? undefined
|
|
4689
4799
|
} : undefined;
|
|
4690
|
-
const quickstart = data.quickstart ? {
|
|
4691
|
-
installCommand: data.quickstart.installCommand ?? undefined,
|
|
4692
|
-
usageExample: data.quickstart.usageExample ?? undefined
|
|
4693
|
-
} : undefined;
|
|
4694
4800
|
const latestChangelogs = data.latestChangelogs?.map((entry) => ({
|
|
4695
4801
|
version: entry.version ?? undefined,
|
|
4696
4802
|
publishedAt: entry.publishedAt ?? undefined,
|
|
@@ -4699,7 +4805,6 @@ class PackageIntelligenceServiceImpl {
|
|
|
4699
4805
|
return {
|
|
4700
4806
|
package: identity,
|
|
4701
4807
|
security,
|
|
4702
|
-
quickstart,
|
|
4703
4808
|
latestChangelogs
|
|
4704
4809
|
};
|
|
4705
4810
|
}
|
|
@@ -4774,6 +4879,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
4774
4879
|
version: params.version,
|
|
4775
4880
|
minSeverity: params.minSeverity,
|
|
4776
4881
|
includeWithdrawn: params.includeWithdrawn,
|
|
4882
|
+
scope: params.advisoryScope,
|
|
4777
4883
|
after
|
|
4778
4884
|
},
|
|
4779
4885
|
fetchFn: this.fetchFn
|
|
@@ -5433,7 +5539,7 @@ var NPM_DIST_TAGS_URL = "https://registry.npmjs.org/-/package/githits/dist-tags"
|
|
|
5433
5539
|
var NPM_PACKAGE_VERSION_URL = "https://registry.npmjs.org/githits";
|
|
5434
5540
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
5435
5541
|
var FETCH_TIMEOUT_MS = 1000;
|
|
5436
|
-
var
|
|
5542
|
+
var DIR_MODE3 = 448;
|
|
5437
5543
|
var UPDATE_COMMAND = "npm i -g githits@latest";
|
|
5438
5544
|
var MAX_DEPRECATION_REASON_LENGTH = 200;
|
|
5439
5545
|
|
|
@@ -5623,7 +5729,7 @@ class NpmRegistryUpdateCheckService {
|
|
|
5623
5729
|
}
|
|
5624
5730
|
async saveCache(cache) {
|
|
5625
5731
|
try {
|
|
5626
|
-
await this.fs.ensureDir(this.configDir,
|
|
5732
|
+
await this.fs.ensureDir(this.configDir, DIR_MODE3);
|
|
5627
5733
|
if (typeof this.fs.atomicWriteFile === "function") {
|
|
5628
5734
|
await this.fs.atomicWriteFile(this.cachePath, `${JSON.stringify(cache, null, 2)}
|
|
5629
5735
|
`);
|
|
@@ -5760,10 +5866,29 @@ async function createAuthStorage(fileSystemService) {
|
|
|
5760
5866
|
function createAuthStorageForMode(fileSystemService, mode, configPath = "your GitHits config.toml") {
|
|
5761
5867
|
const fileStorage = new ModeAwareFileAuthStorage(new AuthStorageImpl(fileSystemService, getAuthFileStorageDir(fileSystemService)), mode, configPath);
|
|
5762
5868
|
const legacyStorage = new AuthStorageImpl(fileSystemService, getLegacyAuthStorageDir(fileSystemService));
|
|
5869
|
+
const additionalLegacyStores = process.platform === "darwin" ? [
|
|
5870
|
+
new AuthStorageImpl(fileSystemService, getLegacyMacAuthFileStorageDir(fileSystemService))
|
|
5871
|
+
] : [];
|
|
5763
5872
|
const rawKeyring = new KeyringServiceImpl;
|
|
5764
5873
|
const keyring = process.platform === "win32" ? new ChunkingKeyringService(rawKeyring, WINDOWS_MAX_ENTRY_SIZE) : rawKeyring;
|
|
5765
5874
|
const keychainStorage = new KeychainAuthStorage(keyring);
|
|
5766
|
-
|
|
5875
|
+
const metadataStorage = new AuthSessionMetadataStorage(fileSystemService);
|
|
5876
|
+
return new LockedAuthStorage(new MigratingAuthStorage(keychainStorage, fileStorage, legacyStorage, mode, configPath, (message) => console.error(message), metadataStorage, additionalLegacyStores), fileSystemService);
|
|
5877
|
+
}
|
|
5878
|
+
async function loadAutoLoginAuthSessionMetadata() {
|
|
5879
|
+
const envToken = getEnvApiToken();
|
|
5880
|
+
if (envToken) {
|
|
5881
|
+
const now = new Date().toISOString();
|
|
5882
|
+
return { createdAt: now, expiresAt: null, updatedAt: now };
|
|
5883
|
+
}
|
|
5884
|
+
const fileSystemService = new FileSystemServiceImpl;
|
|
5885
|
+
const metadataStorage = new AuthSessionMetadataStorage(fileSystemService);
|
|
5886
|
+
return metadataStorage.load(getMcpUrl());
|
|
5887
|
+
}
|
|
5888
|
+
async function clearAutoLoginAuthSessionMetadata() {
|
|
5889
|
+
const fileSystemService = new FileSystemServiceImpl;
|
|
5890
|
+
const metadataStorage = new AuthSessionMetadataStorage(fileSystemService);
|
|
5891
|
+
await metadataStorage.clear(getMcpUrl());
|
|
5767
5892
|
}
|
|
5768
5893
|
async function createAuthCommandDependencies() {
|
|
5769
5894
|
return withTelemetrySpan("container.create-auth-command", async () => {
|
|
@@ -5802,8 +5927,9 @@ function createStaticTokenProvider(token) {
|
|
|
5802
5927
|
}
|
|
5803
5928
|
};
|
|
5804
5929
|
}
|
|
5805
|
-
async function createContainer() {
|
|
5930
|
+
async function createContainer(options = {}) {
|
|
5806
5931
|
return withTelemetrySpan("container.create", async () => {
|
|
5932
|
+
const resolveStoredToken = options.resolveStoredToken ?? true;
|
|
5807
5933
|
const mcpUrl = getMcpUrl();
|
|
5808
5934
|
const apiUrl = getApiUrl();
|
|
5809
5935
|
const codeNavigationUrl = getCodeNavigationUrl();
|
|
@@ -5834,7 +5960,10 @@ async function createContainer() {
|
|
|
5834
5960
|
}
|
|
5835
5961
|
const authStorage = await createAuthStorage(fileSystemService);
|
|
5836
5962
|
const tokenManager = new TokenManager({ authService, authStorage, mcpUrl });
|
|
5837
|
-
const apiToken = await withTelemetrySpan("container.token.get", () => tokenManager.getToken());
|
|
5963
|
+
const apiToken = resolveStoredToken ? await withTelemetrySpan("container.token.get", () => tokenManager.getToken()) : undefined;
|
|
5964
|
+
if (resolveStoredToken && apiToken === undefined) {
|
|
5965
|
+
await new AuthSessionMetadataStorage(fileSystemService).clear(mcpUrl);
|
|
5966
|
+
}
|
|
5838
5967
|
const codeNavigationService = new CodeNavigationServiceImpl(codeNavigationUrl, tokenManager);
|
|
5839
5968
|
const packageIntelligenceService = new PackageIntelligenceServiceImpl(codeNavigationUrl, tokenManager);
|
|
5840
5969
|
return {
|
|
@@ -5855,4 +5984,4 @@ async function createContainer() {
|
|
|
5855
5984
|
});
|
|
5856
5985
|
}
|
|
5857
5986
|
|
|
5858
|
-
export { AuthConfigError, CLIENT_UPDATE_REQUIRED_REASON, ClientUpdateRequiredError, debugLog, setMcpClientVersionProvider, setClientMode, isTelemetryEnabled, withTelemetrySpan, startTelemetrySpan, endTelemetrySpan, flushTelemetry, AuthenticationError, CodeNavigationAccessError, CodeNavigationGraphQLError, CodeNavigationIndexingError, CodeNavigationUnresolvableError, MalformedCodeNavigationResponseError, CodeNavigationTargetNotFoundError, CodeNavigationFileNotFoundError, CodeNavigationVersionNotFoundError, CodeNavigationValidationError, CodeNavigationFeatureFlagRequiredError, CodeNavigationNetworkError, CodeNavigationBackendError, getCodeNavigationUrl, ExecServiceImpl, FileSystemServiceImpl, AuthStorageLockTimeoutError, AuthStoragePolicyError, PackageIntelligenceAccessError, PackageIntelligenceFeatureFlagRequiredError, PackageIntelligenceNetworkError, PackageIntelligenceBackendError, PackageIntelligenceGraphQLError, PackageIntelligenceTargetNotFoundError, PackageIntelligenceValidationError, PackageIntelligenceVersionNotFoundError, MalformedPackageIntelligenceResponseError, PackageIntelligenceChangelogSourceNotFoundError, PromptServiceImpl, refreshExpiredToken, NpmRegistryUpdateCheckService, shouldRunUpdateCheck, shouldRunRequiredUpdateEnforcement, formatUpdateNotice, formatRequiredUpdateNotice, createAuthCommandDependencies, createAuthStatusDependencies, createContainer };
|
|
5987
|
+
export { AuthConfigError, CLIENT_UPDATE_REQUIRED_REASON, ClientUpdateRequiredError, debugLog, setMcpClientVersionProvider, setClientMode, isTelemetryEnabled, withTelemetrySpan, startTelemetrySpan, endTelemetrySpan, flushTelemetry, AuthenticationError, CodeNavigationAccessError, CodeNavigationGraphQLError, CodeNavigationIndexingError, CodeNavigationUnresolvableError, MalformedCodeNavigationResponseError, CodeNavigationTargetNotFoundError, CodeNavigationFileNotFoundError, CodeNavigationVersionNotFoundError, CodeNavigationValidationError, CodeNavigationFeatureFlagRequiredError, CodeNavigationNetworkError, CodeNavigationBackendError, getCodeNavigationUrl, ExecServiceImpl, FileSystemServiceImpl, AuthStorageLockTimeoutError, AuthStoragePolicyError, PackageIntelligenceAccessError, PackageIntelligenceFeatureFlagRequiredError, PackageIntelligenceNetworkError, PackageIntelligenceBackendError, PackageIntelligenceGraphQLError, PackageIntelligenceTargetNotFoundError, PackageIntelligenceValidationError, PackageIntelligenceVersionNotFoundError, MalformedPackageIntelligenceResponseError, PackageIntelligenceChangelogSourceNotFoundError, PromptServiceImpl, refreshExpiredToken, NpmRegistryUpdateCheckService, shouldRunUpdateCheck, shouldRunRequiredUpdateEnforcement, formatUpdateNotice, formatRequiredUpdateNotice, loadAutoLoginAuthSessionMetadata, clearAutoLoginAuthSessionMetadata, createAuthCommandDependencies, createAuthStatusDependencies, createContainer };
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "githits",
|
|
3
3
|
"description": "CLI companion for GitHits - code examples from global open source for developers and AI assistants",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"inspector": "npx @modelcontextprotocol/inspector bun run dev mcp",
|
|
36
36
|
"smoke:cli": "bun run scripts/cli-smoke.ts",
|
|
37
37
|
"smoke:mcp": "bun run scripts/mcp-smoke.ts",
|
|
38
|
+
"audit:pkg-ecosystems": "bun run scripts/pkg-ecosystem-audit.ts",
|
|
39
|
+
"agent:e2e": "bun run scripts/agent-eval.ts",
|
|
40
|
+
"agent:e2e:report": "bun run scripts/agent-eval-report.ts",
|
|
38
41
|
"test": "bun test",
|
|
39
42
|
"typecheck": "tsc",
|
|
40
43
|
"format": "biome format --write .",
|