@anvil-works/anvil-cli 0.7.0-canary.11 → 0.7.0-canary.13
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/WatchSession.d.ts +6 -0
- package/dist/WatchSession.d.ts.map +1 -1
- package/dist/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/cli.js +576 -29
- package/dist/commands/gitAuth.d.ts +89 -0
- package/dist/commands/gitAuth.d.ts.map +1 -0
- package/dist/commands/gitCredential.d.ts.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/index.js +559 -28
- package/dist/program.d.ts.map +1 -1
- package/dist/services/git-auth.d.ts.map +1 -1
- package/dist/services/git.d.ts +25 -1
- package/dist/services/git.d.ts.map +1 -1
- package/dist/watch/SaveProcessor.d.ts +6 -1
- package/dist/watch/SaveProcessor.d.ts.map +1 -1
- package/dist/watch/SyncManager.d.ts +4 -0
- package/dist/watch/SyncManager.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7371,6 +7371,7 @@ var __webpack_exports__ = {};
|
|
|
7371
7371
|
setConfig: ()=>setConfig,
|
|
7372
7372
|
getAccountsForUrl: ()=>auth_getAccountsForUrl,
|
|
7373
7373
|
AppIdWithContext: ()=>anvil_api_namespaceObject.AppIdWithContext,
|
|
7374
|
+
inspectCredentialHelperCommand: ()=>inspectCredentialHelperCommand,
|
|
7374
7375
|
executeCheckout: ()=>executeCheckout,
|
|
7375
7376
|
validateCheckoutDestination: ()=>validateCheckoutDestination,
|
|
7376
7377
|
DeviceAuthorizationResponse: ()=>oauth_login_namespaceObject.DeviceAuthorizationResponse,
|
|
@@ -7386,7 +7387,9 @@ var __webpack_exports__ = {};
|
|
|
7386
7387
|
verifyAndStoreTokens: ()=>auth_verifyAndStoreTokens,
|
|
7387
7388
|
formatValidationPath: ()=>formatValidationPath,
|
|
7388
7389
|
resolveAnvilUrl: ()=>resolveAnvilUrl,
|
|
7390
|
+
buildGitAuthDoctorReport: ()=>buildGitAuthDoctorReport,
|
|
7389
7391
|
parseCheckoutInput: ()=>parseCheckoutInput,
|
|
7392
|
+
formatGitAuthDoctorReport: ()=>formatGitAuthDoctorReport,
|
|
7390
7393
|
resetConfig: ()=>resetConfig,
|
|
7391
7394
|
FormTemplateValidationResult: ()=>validators_namespaceObject.FormTemplateValidationResult,
|
|
7392
7395
|
createWatchDiagnostic: ()=>createWatchDiagnostic,
|
|
@@ -7449,6 +7452,7 @@ var __webpack_exports__ = {};
|
|
|
7449
7452
|
executeGitCredentialOperation: ()=>executeGitCredentialOperation,
|
|
7450
7453
|
CheckoutResult: ()=>checkout_namespaceObject.CheckoutResult,
|
|
7451
7454
|
ParsedCheckoutInput: ()=>checkout_namespaceObject.ParsedCheckoutInput,
|
|
7455
|
+
parseCredentialHelperCommand: ()=>parseCredentialHelperCommand,
|
|
7452
7456
|
clearInMemoryTokens: ()=>clearInMemoryTokens,
|
|
7453
7457
|
getDefaultDestinationDirectory: ()=>getDefaultDestinationDirectory,
|
|
7454
7458
|
lookupByCommit: ()=>lookupByCommit,
|
|
@@ -13693,7 +13697,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13693
13697
|
}
|
|
13694
13698
|
function getCredentialHelperModulePath(options) {
|
|
13695
13699
|
const currentModulePath = options?.currentModulePath ?? __filename;
|
|
13696
|
-
if (isAnvilCliPackageFile(currentModulePath)) return currentModulePath;
|
|
13700
|
+
if (isAnvilCliPackageFile(currentModulePath) && "cli.js" !== external_path_default().basename(currentModulePath)) return currentModulePath;
|
|
13697
13701
|
return (options?.resolvePackageEntry ?? (()=>requireFromHere.resolve("@anvil-works/anvil-cli")))();
|
|
13698
13702
|
}
|
|
13699
13703
|
async function getRepositoryGitDir(repoPath, git = esm_default(repoPath)) {
|
|
@@ -14713,6 +14717,77 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14713
14717
|
throw errors_createGitError.commandFailed("status", e.message);
|
|
14714
14718
|
}
|
|
14715
14719
|
}
|
|
14720
|
+
async discardModeOnlyChanges(paths) {
|
|
14721
|
+
const discarded = [];
|
|
14722
|
+
for (const relativePath of paths)try {
|
|
14723
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14724
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14725
|
+
const contentUnchanged = await this.hasSameContentAsHead(relativePath);
|
|
14726
|
+
if (!contentUnchanged) continue;
|
|
14727
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14728
|
+
discarded.push(relativePath);
|
|
14729
|
+
} catch (e) {
|
|
14730
|
+
throw errors_createGitError.commandFailed("discard mode-only changes", e.message);
|
|
14731
|
+
}
|
|
14732
|
+
return discarded;
|
|
14733
|
+
}
|
|
14734
|
+
async discardStagedModeOnlyChanges(paths) {
|
|
14735
|
+
const discarded = [];
|
|
14736
|
+
for (const relativePath of paths)try {
|
|
14737
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14738
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14739
|
+
const indexContentUnchanged = await this.hasSameIndexContentAsHead(relativePath);
|
|
14740
|
+
if (!indexContentUnchanged) continue;
|
|
14741
|
+
await this.git.raw([
|
|
14742
|
+
"reset",
|
|
14743
|
+
"-q",
|
|
14744
|
+
"HEAD",
|
|
14745
|
+
"--",
|
|
14746
|
+
relativePath
|
|
14747
|
+
]);
|
|
14748
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14749
|
+
discarded.push(relativePath);
|
|
14750
|
+
} catch (e) {
|
|
14751
|
+
throw errors_createGitError.commandFailed("discard staged mode-only changes", e.message);
|
|
14752
|
+
}
|
|
14753
|
+
return discarded;
|
|
14754
|
+
}
|
|
14755
|
+
async getHeadFileMode(relativePath) {
|
|
14756
|
+
const output = await this.git.raw([
|
|
14757
|
+
"ls-tree",
|
|
14758
|
+
"HEAD",
|
|
14759
|
+
"--",
|
|
14760
|
+
relativePath
|
|
14761
|
+
]);
|
|
14762
|
+
const match = output.match(/^(\d{6})\s/);
|
|
14763
|
+
return match?.[1] ?? null;
|
|
14764
|
+
}
|
|
14765
|
+
async hasSameContentAsHead(relativePath) {
|
|
14766
|
+
const headHash = (await this.git.revparse([
|
|
14767
|
+
`HEAD:${relativePath}`
|
|
14768
|
+
])).trim();
|
|
14769
|
+
const worktreeHash = (await this.git.raw([
|
|
14770
|
+
"hash-object",
|
|
14771
|
+
"--",
|
|
14772
|
+
relativePath
|
|
14773
|
+
])).trim();
|
|
14774
|
+
return headHash === worktreeHash;
|
|
14775
|
+
}
|
|
14776
|
+
async hasSameIndexContentAsHead(relativePath) {
|
|
14777
|
+
const headHash = (await this.git.revparse([
|
|
14778
|
+
`HEAD:${relativePath}`
|
|
14779
|
+
])).trim();
|
|
14780
|
+
const indexHash = (await this.git.revparse([
|
|
14781
|
+
`:${relativePath}`
|
|
14782
|
+
])).trim();
|
|
14783
|
+
return headHash === indexHash;
|
|
14784
|
+
}
|
|
14785
|
+
async restoreExecutableBit(relativePath, executable) {
|
|
14786
|
+
const filePath = external_path_default().join(this.repoPath, relativePath);
|
|
14787
|
+
const stat = await external_fs_.promises.stat(filePath);
|
|
14788
|
+
const mode = executable ? 73 | stat.mode : -74 & stat.mode;
|
|
14789
|
+
if ((511 & stat.mode) !== (511 & mode)) await external_fs_.promises.chmod(filePath, mode);
|
|
14790
|
+
}
|
|
14716
14791
|
async hasUncommittedChanges() {
|
|
14717
14792
|
const status = await this.getStatus();
|
|
14718
14793
|
return !status.isClean;
|
|
@@ -14852,6 +14927,32 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14852
14927
|
throw errors_createGitError.commandFailed("rebase --abort", e.message);
|
|
14853
14928
|
}
|
|
14854
14929
|
}
|
|
14930
|
+
async isAncestor(ancestorRef, descendantRef) {
|
|
14931
|
+
try {
|
|
14932
|
+
const mergeBase = (await this.git.raw([
|
|
14933
|
+
"merge-base",
|
|
14934
|
+
ancestorRef,
|
|
14935
|
+
descendantRef
|
|
14936
|
+
])).trim();
|
|
14937
|
+
const ancestorCommit = (await this.git.revparse([
|
|
14938
|
+
ancestorRef
|
|
14939
|
+
])).trim();
|
|
14940
|
+
return mergeBase === ancestorCommit;
|
|
14941
|
+
} catch {
|
|
14942
|
+
return false;
|
|
14943
|
+
}
|
|
14944
|
+
}
|
|
14945
|
+
async mergeFastForward(ref) {
|
|
14946
|
+
try {
|
|
14947
|
+
await this.git.raw([
|
|
14948
|
+
"merge",
|
|
14949
|
+
"--ff-only",
|
|
14950
|
+
ref
|
|
14951
|
+
]);
|
|
14952
|
+
} catch (e) {
|
|
14953
|
+
throw errors_createGitError.commandFailed("merge --ff-only", e.message);
|
|
14954
|
+
}
|
|
14955
|
+
}
|
|
14855
14956
|
async deleteRef(ref) {
|
|
14856
14957
|
try {
|
|
14857
14958
|
await this.git.raw([
|
|
@@ -14896,11 +14997,12 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14896
14997
|
} catch (error) {}
|
|
14897
14998
|
}
|
|
14898
14999
|
}
|
|
14899
|
-
async function getStagedFileChanges(git) {
|
|
15000
|
+
async function getStagedFileChanges(git, gitService) {
|
|
14900
15001
|
try {
|
|
14901
15002
|
const status = await git.status();
|
|
14902
15003
|
const renames = status.renamed || [];
|
|
14903
15004
|
const stagedFiles = status.files.filter((f)=>" " !== f.index && "?" !== f.index);
|
|
15005
|
+
const stagedModeOnlyPaths = new Set(gitService ? await gitService.discardStagedModeOnlyChanges(stagedFiles.filter((f)=>"R" !== f.index && "D" !== f.index).map((f)=>f.path)) : []);
|
|
14904
15006
|
const stagedRenames = [];
|
|
14905
15007
|
for (const f of stagedFiles)if ("R" === f.index) {
|
|
14906
15008
|
const rename = renames.find((r)=>r.to === f.path);
|
|
@@ -14913,19 +15015,23 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14913
15015
|
const stagedRenamedFromPaths = new Set(stagedRenames.map((r)=>r.from));
|
|
14914
15016
|
const stagedRenamedToPaths = new Set(stagedRenames.map((r)=>r.path));
|
|
14915
15017
|
const changes = [];
|
|
14916
|
-
for (const f of stagedFiles)
|
|
14917
|
-
if (
|
|
14918
|
-
|
|
14919
|
-
|
|
14920
|
-
|
|
14921
|
-
|
|
14922
|
-
|
|
14923
|
-
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
15018
|
+
for (const f of stagedFiles){
|
|
15019
|
+
if ("R" !== f.index) {
|
|
15020
|
+
if (!stagedModeOnlyPaths.has(f.path)) {
|
|
15021
|
+
if (!(stagedRenamedFromPaths.has(f.path) || stagedRenamedToPaths.has(f.path))) if ("D" === f.index) changes.push({
|
|
15022
|
+
path: f.path,
|
|
15023
|
+
type: "unlink"
|
|
15024
|
+
});
|
|
15025
|
+
else if ("A" === f.index || "?" === f.index) changes.push({
|
|
15026
|
+
path: f.path,
|
|
15027
|
+
type: "add"
|
|
15028
|
+
});
|
|
15029
|
+
else changes.push({
|
|
15030
|
+
path: f.path,
|
|
15031
|
+
type: "change"
|
|
15032
|
+
});
|
|
15033
|
+
}
|
|
15034
|
+
}
|
|
14929
15035
|
}
|
|
14930
15036
|
changes.push(...stagedRenames);
|
|
14931
15037
|
return changes;
|
|
@@ -17681,13 +17787,14 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
17681
17787
|
}
|
|
17682
17788
|
async getStagedChanges() {
|
|
17683
17789
|
try {
|
|
17684
|
-
return await getStagedFileChanges(this.config.gitService.getGit());
|
|
17790
|
+
return await getStagedFileChanges(this.config.gitService.getGit(), this.config.gitService);
|
|
17685
17791
|
} catch (e) {
|
|
17686
17792
|
logger_logger.error(external_chalk_default().red(`Error getting staged changes: ${errors_getErrorMessage(e)}`));
|
|
17687
17793
|
return [];
|
|
17688
17794
|
}
|
|
17689
17795
|
}
|
|
17690
17796
|
async getUnstagedChanges(status) {
|
|
17797
|
+
const modeOnlyChanges = new Set(await this.config.gitService.discardModeOnlyChanges(status.modified));
|
|
17691
17798
|
const renames = status.renamed;
|
|
17692
17799
|
const stagedRenamedFromPaths = new Set(renames.map((r)=>r.from));
|
|
17693
17800
|
const stagedRenamedToPaths = new Set(renames.map((r)=>r.to));
|
|
@@ -17707,7 +17814,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
17707
17814
|
const allRenamedFromPaths = new Set(allRenames.map((r)=>r.from));
|
|
17708
17815
|
const allRenamedToPaths = new Set(allRenames.map((r)=>r.to));
|
|
17709
17816
|
return [
|
|
17710
|
-
...status.modified.map((f)=>({
|
|
17817
|
+
...status.modified.filter((f)=>!modeOnlyChanges.has(f)).map((f)=>({
|
|
17711
17818
|
path: f,
|
|
17712
17819
|
type: "change"
|
|
17713
17820
|
})),
|
|
@@ -17915,7 +18022,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
17915
18022
|
await this.handleConflict(json_resp, originalFilePaths, retryCount);
|
|
17916
18023
|
return;
|
|
17917
18024
|
}
|
|
17918
|
-
if (200 === resp.status) return void await this.handleSuccess(json_resp);
|
|
18025
|
+
if (200 === resp.status) return void await this.handleSuccess(json_resp, originalFilePaths);
|
|
17919
18026
|
logger_logger.error(`Unexpected response status: ${resp.status}`);
|
|
17920
18027
|
throw {
|
|
17921
18028
|
type: "server_error",
|
|
@@ -18018,13 +18125,20 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18018
18125
|
reason: "Unknown conflict"
|
|
18019
18126
|
};
|
|
18020
18127
|
}
|
|
18021
|
-
async handleSuccess(json_resp) {
|
|
18128
|
+
async handleSuccess(json_resp, originalFilePaths) {
|
|
18022
18129
|
const version = json_resp.version;
|
|
18023
|
-
|
|
18130
|
+
const oldCommitId = json_resp.previous_commit ?? null;
|
|
18131
|
+
const commitIdBeforePostSaveSync = this.config.getCommitId();
|
|
18132
|
+
this.emit("saved", {
|
|
18133
|
+
oldCommitId,
|
|
18134
|
+
newCommitId: version,
|
|
18135
|
+
branch: this.config.getCurrentBranch()
|
|
18136
|
+
});
|
|
18024
18137
|
if (this.postSaveCallback) {
|
|
18025
18138
|
logger_logger.progressUpdate("sync", "Syncing back");
|
|
18026
|
-
await this.postSaveCallback();
|
|
18139
|
+
await this.postSaveCallback(new Set(originalFilePaths));
|
|
18027
18140
|
}
|
|
18141
|
+
if (this.config.getCommitId() === commitIdBeforePostSaveSync) this.config.setCommitId(version);
|
|
18028
18142
|
}
|
|
18029
18143
|
async rerouteChanges(changes) {
|
|
18030
18144
|
logger_logger.verbose(external_chalk_default().blue(`Re-routing ${changes.length} local change(s)...`));
|
|
@@ -18095,12 +18209,22 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18095
18209
|
try {
|
|
18096
18210
|
const oldCommitId = this.config.getCommitId();
|
|
18097
18211
|
let locallyChangedFiles;
|
|
18212
|
+
let initialStatus;
|
|
18098
18213
|
if (knownLocalChanges) locallyChangedFiles = knownLocalChanges;
|
|
18099
18214
|
else {
|
|
18100
|
-
|
|
18101
|
-
locallyChangedFiles = buildLocalChangesSet(
|
|
18215
|
+
initialStatus = await this.config.gitService.getStatus();
|
|
18216
|
+
locallyChangedFiles = buildLocalChangesSet(initialStatus);
|
|
18102
18217
|
}
|
|
18103
|
-
|
|
18218
|
+
let syncMode;
|
|
18219
|
+
if (!knownLocalChanges && initialStatus && this.isCleanForFastForward(initialStatus)) syncMode = await this.fetchAndMoveCleanTreeToAnvilHead(oldCommitId, locallyChangedFiles);
|
|
18220
|
+
else {
|
|
18221
|
+
await this.fetchAndResetFromAnvil(locallyChangedFiles);
|
|
18222
|
+
syncMode = "preservation";
|
|
18223
|
+
}
|
|
18224
|
+
if ("clean-move" === syncMode) return {
|
|
18225
|
+
localOnlyChanges: [],
|
|
18226
|
+
conflicts: []
|
|
18227
|
+
};
|
|
18104
18228
|
const newCommitId = await this.config.gitService.getCommitId();
|
|
18105
18229
|
this.config.setCommitId(newCommitId);
|
|
18106
18230
|
const remoteChangedFiles = await detectRemoteChanges(this.config.gitService, oldCommitId, newCommitId);
|
|
@@ -18125,15 +18249,43 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18125
18249
|
}
|
|
18126
18250
|
}
|
|
18127
18251
|
async fetchAndResetFromAnvil(localChangesToPreserve = new Set()) {
|
|
18252
|
+
const oldCommitId = this.config.getCommitId();
|
|
18253
|
+
await this.withFetchedAnvilRef((tempRef)=>this.resetToFetchedAnvilRef(tempRef, oldCommitId, localChangesToPreserve));
|
|
18254
|
+
}
|
|
18255
|
+
async fetchAndMoveCleanTreeToAnvilHead(oldCommitId, locallyChangedFiles) {
|
|
18256
|
+
return this.withFetchedAnvilRef(async (tempRef)=>{
|
|
18257
|
+
const localHead = await this.config.gitService.getCommitId();
|
|
18258
|
+
if (await this.config.gitService.isAncestor(localHead, tempRef)) await this.config.gitService.mergeFastForward(tempRef);
|
|
18259
|
+
else {
|
|
18260
|
+
const statusBeforeHardReset = await this.config.gitService.getStatus();
|
|
18261
|
+
if (!this.isCleanForFastForward(statusBeforeHardReset)) {
|
|
18262
|
+
for (const filePath of buildLocalChangesSet(statusBeforeHardReset))locallyChangedFiles.add(filePath);
|
|
18263
|
+
await this.resetToFetchedAnvilRef(tempRef, oldCommitId, locallyChangedFiles);
|
|
18264
|
+
return "preservation";
|
|
18265
|
+
}
|
|
18266
|
+
await this.config.gitService.reset(tempRef, "hard");
|
|
18267
|
+
}
|
|
18268
|
+
const newCommitId = await this.config.gitService.getCommitId();
|
|
18269
|
+
this.config.setCommitId(newCommitId);
|
|
18270
|
+
await this.config.editorYaml.reload();
|
|
18271
|
+
return "clean-move";
|
|
18272
|
+
});
|
|
18273
|
+
}
|
|
18274
|
+
async withFetchedAnvilRef(callback) {
|
|
18128
18275
|
const validToken = await auth_getValidAuthToken(this.config.anvilUrl, this.config.username);
|
|
18129
18276
|
this.config.setAuthToken(validToken);
|
|
18130
18277
|
const httpUrl = anvil_api_getGitFetchUrl(this.config.appId, this.config.getAuthToken(), this.config.anvilUrl);
|
|
18131
18278
|
const currentBranch = this.config.getCurrentBranch();
|
|
18132
18279
|
const tempRef = `anvil-sync-temp-${Date.now()}`;
|
|
18133
|
-
|
|
18134
|
-
|
|
18280
|
+
try {
|
|
18281
|
+
await this.config.gitService.fetch(httpUrl, `+${currentBranch}:${tempRef}`);
|
|
18282
|
+
return await callback(tempRef);
|
|
18283
|
+
} finally{
|
|
18284
|
+
await this.config.gitService.deleteRef(`refs/heads/${tempRef}`);
|
|
18285
|
+
}
|
|
18286
|
+
}
|
|
18287
|
+
async resetToFetchedAnvilRef(tempRef, oldCommitId, localChangesToPreserve) {
|
|
18135
18288
|
await this.config.gitService.reset(tempRef, "mixed");
|
|
18136
|
-
await this.config.gitService.deleteRef(`refs/heads/${tempRef}`);
|
|
18137
18289
|
const newCommitId = await this.config.gitService.getCommitId();
|
|
18138
18290
|
await this.config.gitService.checkout([
|
|
18139
18291
|
".anvil_editor.yaml",
|
|
@@ -18143,6 +18295,9 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18143
18295
|
await this.deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId, localChangesToPreserve);
|
|
18144
18296
|
await this.discardFormattingOnlyYamlChanges();
|
|
18145
18297
|
}
|
|
18298
|
+
isCleanForFastForward(status) {
|
|
18299
|
+
return status.isClean && 0 === status.modified.length && 0 === status.notAdded.length && 0 === status.created.length && 0 === status.deleted.length && 0 === status.staged.length && 0 === status.renamed.length;
|
|
18300
|
+
}
|
|
18146
18301
|
async deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId, localChangesToPreserve) {
|
|
18147
18302
|
try {
|
|
18148
18303
|
const status = await this.config.gitService.getStatus();
|
|
@@ -18356,11 +18511,12 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18356
18511
|
isPaused: ()=>this.isPausedForUserInput
|
|
18357
18512
|
});
|
|
18358
18513
|
this.saveProcessor.setSyncCallback((filePaths)=>this.syncManager.syncRemoteChanges(filePaths));
|
|
18359
|
-
this.saveProcessor.setPostSaveCallback(()=>this.
|
|
18514
|
+
this.saveProcessor.setPostSaveCallback((filePaths)=>this.syncAfterSave(filePaths));
|
|
18360
18515
|
this.saveProcessor.on("save-started", (data)=>this.emit("save-started", data));
|
|
18361
18516
|
this.saveProcessor.on("save-succeeded", (data)=>this.emit("save-succeeded", data));
|
|
18362
18517
|
this.saveProcessor.on("save-failed", (data)=>this.emit("save-failed", data));
|
|
18363
18518
|
this.saveProcessor.on("save-complete", (data)=>this.emit("save-complete", data));
|
|
18519
|
+
this.saveProcessor.on("saved", (data)=>this.emit("saved", data));
|
|
18364
18520
|
this.saveProcessor.on("anvil-yaml-dependencies-changed", ()=>{
|
|
18365
18521
|
this.queueDependencyRefresh("anvil.yaml dependencies changed");
|
|
18366
18522
|
});
|
|
@@ -18368,6 +18524,12 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
18368
18524
|
this.saveProcessor.on("sync-conflict", (data)=>this.emit("sync-conflict", data));
|
|
18369
18525
|
this.saveProcessor.on("max-retries-exceeded", (data)=>this.emit("max-retries-exceeded", data));
|
|
18370
18526
|
}
|
|
18527
|
+
async syncAfterSave(savedFilePaths) {
|
|
18528
|
+
const status = await this.gitService.getStatus();
|
|
18529
|
+
const locallyChangedFiles = buildLocalChangesSet(status);
|
|
18530
|
+
if (!this.stagedOnly) for (const filePath of savedFilePaths)locallyChangedFiles.add(filePath);
|
|
18531
|
+
return this.syncManager.syncRemoteChanges(locallyChangedFiles);
|
|
18532
|
+
}
|
|
18371
18533
|
async connectWebSocket() {
|
|
18372
18534
|
this.wsClient = new WebSocketClient({
|
|
18373
18535
|
appId: this.appId,
|
|
@@ -19000,6 +19162,367 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
19000
19162
|
}
|
|
19001
19163
|
require("inquirer");
|
|
19002
19164
|
require("ora");
|
|
19165
|
+
const defaultGitAuthDoctorDeps = {
|
|
19166
|
+
getAppAuthBinding: git_auth_getAppAuthBinding,
|
|
19167
|
+
getAccountsForUrl: auth_getAccountsForUrl,
|
|
19168
|
+
hasTokensForUrl: auth_hasTokensForUrl,
|
|
19169
|
+
runCredentialFill: runGitCredentialFill
|
|
19170
|
+
};
|
|
19171
|
+
function getHighestStatus(statuses) {
|
|
19172
|
+
if (statuses.includes("error")) return "error";
|
|
19173
|
+
if (statuses.includes("warning")) return "warning";
|
|
19174
|
+
return "ok";
|
|
19175
|
+
}
|
|
19176
|
+
function finding(status, code, message) {
|
|
19177
|
+
return {
|
|
19178
|
+
status,
|
|
19179
|
+
code,
|
|
19180
|
+
message
|
|
19181
|
+
};
|
|
19182
|
+
}
|
|
19183
|
+
function redactSecrets(value) {
|
|
19184
|
+
return value.replace(/^password=.*$/gim, "password=<redacted>").replace(/(https?:\/\/git:)[^@\s]+@/g, "$1<redacted>@").replace(/(access[_-]?token=)[^&\s]+/gi, "$1<redacted>").replace(/(refresh[_-]?token=)[^&\s]+/gi, "$1<redacted>");
|
|
19185
|
+
}
|
|
19186
|
+
function splitShellCommand(command) {
|
|
19187
|
+
const tokens = [];
|
|
19188
|
+
let current = "";
|
|
19189
|
+
let state = "normal";
|
|
19190
|
+
for(let i = 0; i < command.length; i++){
|
|
19191
|
+
const ch = command[i];
|
|
19192
|
+
if ("single" === state) {
|
|
19193
|
+
if ("'" === ch) state = "normal";
|
|
19194
|
+
else current += ch;
|
|
19195
|
+
continue;
|
|
19196
|
+
}
|
|
19197
|
+
if ("double" === state) {
|
|
19198
|
+
if ("\"" === ch) state = "normal";
|
|
19199
|
+
else if ("\\" === ch && i + 1 < command.length && [
|
|
19200
|
+
"$",
|
|
19201
|
+
"`",
|
|
19202
|
+
"\"",
|
|
19203
|
+
"\\",
|
|
19204
|
+
"\n"
|
|
19205
|
+
].includes(command[i + 1])) current += command[++i];
|
|
19206
|
+
else current += ch;
|
|
19207
|
+
continue;
|
|
19208
|
+
}
|
|
19209
|
+
if (/\s/.test(ch)) {
|
|
19210
|
+
if (current) {
|
|
19211
|
+
tokens.push(current);
|
|
19212
|
+
current = "";
|
|
19213
|
+
}
|
|
19214
|
+
} else if ("'" === ch) state = "single";
|
|
19215
|
+
else if ("\"" === ch) state = "double";
|
|
19216
|
+
else if ("\\" === ch && i + 1 < command.length) current += command[++i];
|
|
19217
|
+
else current += ch;
|
|
19218
|
+
}
|
|
19219
|
+
if ("normal" !== state) throw new Error("Unterminated quote in helper command");
|
|
19220
|
+
if (current) tokens.push(current);
|
|
19221
|
+
return tokens;
|
|
19222
|
+
}
|
|
19223
|
+
function parseCredentialHelperCommand(command) {
|
|
19224
|
+
const trimmed = command.trim();
|
|
19225
|
+
if (!trimmed || !trimmed.startsWith("!")) return {};
|
|
19226
|
+
const tokens = splitShellCommand(trimmed.slice(1).trim());
|
|
19227
|
+
return {
|
|
19228
|
+
execPath: tokens[0],
|
|
19229
|
+
helperPath: tokens[1]
|
|
19230
|
+
};
|
|
19231
|
+
}
|
|
19232
|
+
function readHelperModulePath(helperPath) {
|
|
19233
|
+
try {
|
|
19234
|
+
const helperSource = external_fs_default().readFileSync(helperPath, "utf8");
|
|
19235
|
+
const match = helperSource.match(/executeGitCredentialOperation\s*}\s*=\s*require\((["'])(.*?)\1\)/);
|
|
19236
|
+
return match?.[2];
|
|
19237
|
+
} catch {
|
|
19238
|
+
return;
|
|
19239
|
+
}
|
|
19240
|
+
}
|
|
19241
|
+
function inspectCredentialHelperCommand(raw) {
|
|
19242
|
+
const details = {
|
|
19243
|
+
raw
|
|
19244
|
+
};
|
|
19245
|
+
try {
|
|
19246
|
+
const parsed = parseCredentialHelperCommand(raw);
|
|
19247
|
+
details.execPath = parsed.execPath;
|
|
19248
|
+
details.helperPath = parsed.helperPath;
|
|
19249
|
+
} catch (e) {
|
|
19250
|
+
details.parseError = e.message;
|
|
19251
|
+
return details;
|
|
19252
|
+
}
|
|
19253
|
+
if (details.execPath) details.execExists = external_fs_default().existsSync(details.execPath);
|
|
19254
|
+
if (details.helperPath) {
|
|
19255
|
+
details.helperExists = external_fs_default().existsSync(details.helperPath);
|
|
19256
|
+
if (details.helperExists) {
|
|
19257
|
+
try {
|
|
19258
|
+
const stat = external_fs_default().statSync(details.helperPath);
|
|
19259
|
+
details.helperExecutable = (73 & stat.mode) !== 0;
|
|
19260
|
+
} catch {
|
|
19261
|
+
details.helperExecutable = false;
|
|
19262
|
+
}
|
|
19263
|
+
details.modulePath = readHelperModulePath(details.helperPath);
|
|
19264
|
+
if (details.modulePath) details.moduleExists = external_fs_default().existsSync(details.modulePath);
|
|
19265
|
+
}
|
|
19266
|
+
}
|
|
19267
|
+
return details;
|
|
19268
|
+
}
|
|
19269
|
+
function detectAnvilRemote(remote) {
|
|
19270
|
+
const fetchUrl = remote.refs.fetch;
|
|
19271
|
+
const out = {
|
|
19272
|
+
name: remote.name,
|
|
19273
|
+
fetchUrl
|
|
19274
|
+
};
|
|
19275
|
+
if (!fetchUrl) return out;
|
|
19276
|
+
const httpMatch = fetchUrl.match(/^(https?):\/\/(?:[^@/?#]+@)?([^/?#]+)\/git\/([A-Z0-9]+)\.git(?:[?#].*)?$/);
|
|
19277
|
+
if (httpMatch) {
|
|
19278
|
+
const [, protocol, host, appId] = httpMatch;
|
|
19279
|
+
return {
|
|
19280
|
+
...out,
|
|
19281
|
+
appId,
|
|
19282
|
+
anvilUrl: config_normalizeAnvilUrl(`${protocol}://${host}`),
|
|
19283
|
+
transport: "https"
|
|
19284
|
+
};
|
|
19285
|
+
}
|
|
19286
|
+
const sshMatch = fetchUrl.match(/^ssh:\/\/(?:([^@]+)@)?([^:\/]+)(?::\d+)?\/(?:git\/)?([A-Z0-9]+)\.git(?:[?#].*)?$/);
|
|
19287
|
+
if (sshMatch) {
|
|
19288
|
+
const [, , host, appId] = sshMatch;
|
|
19289
|
+
return {
|
|
19290
|
+
...out,
|
|
19291
|
+
appId,
|
|
19292
|
+
anvilUrl: config_normalizeAnvilUrl(host),
|
|
19293
|
+
transport: "ssh"
|
|
19294
|
+
};
|
|
19295
|
+
}
|
|
19296
|
+
return out;
|
|
19297
|
+
}
|
|
19298
|
+
async function getLocalConfigValues(repoPath, key) {
|
|
19299
|
+
try {
|
|
19300
|
+
const output = await esm_default(repoPath).raw([
|
|
19301
|
+
"config",
|
|
19302
|
+
"--local",
|
|
19303
|
+
"--get-all",
|
|
19304
|
+
key
|
|
19305
|
+
]);
|
|
19306
|
+
const values = output.split(/\r?\n/);
|
|
19307
|
+
if ("" === values[values.length - 1]) values.pop();
|
|
19308
|
+
return values;
|
|
19309
|
+
} catch {
|
|
19310
|
+
return [];
|
|
19311
|
+
}
|
|
19312
|
+
}
|
|
19313
|
+
function buildCredentialInput(anvilUrl, appId) {
|
|
19314
|
+
const url = new URL(anvilUrl);
|
|
19315
|
+
return `protocol=${url.protocol.replace(/:$/, "")}\nhost=${url.host}\npath=git/${appId}.git\n\n`;
|
|
19316
|
+
}
|
|
19317
|
+
async function runGitCredentialFill(repoPath, input) {
|
|
19318
|
+
return new Promise((resolve)=>{
|
|
19319
|
+
const child = (0, external_child_process_namespaceObject.spawn)("git", [
|
|
19320
|
+
"credential",
|
|
19321
|
+
"fill"
|
|
19322
|
+
], {
|
|
19323
|
+
cwd: repoPath,
|
|
19324
|
+
env: {
|
|
19325
|
+
...process.env,
|
|
19326
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
19327
|
+
},
|
|
19328
|
+
stdio: [
|
|
19329
|
+
"pipe",
|
|
19330
|
+
"pipe",
|
|
19331
|
+
"pipe"
|
|
19332
|
+
]
|
|
19333
|
+
});
|
|
19334
|
+
let stdout = "";
|
|
19335
|
+
let stderr = "";
|
|
19336
|
+
child.stdout.setEncoding("utf8");
|
|
19337
|
+
child.stderr.setEncoding("utf8");
|
|
19338
|
+
child.stdout.on("data", (chunk)=>{
|
|
19339
|
+
stdout += chunk;
|
|
19340
|
+
});
|
|
19341
|
+
child.stderr.on("data", (chunk)=>{
|
|
19342
|
+
stderr += chunk;
|
|
19343
|
+
});
|
|
19344
|
+
child.on("error", (error)=>{
|
|
19345
|
+
resolve({
|
|
19346
|
+
exitCode: null,
|
|
19347
|
+
stdout: redactSecrets(stdout),
|
|
19348
|
+
stderr: redactSecrets(stderr),
|
|
19349
|
+
error: redactSecrets(error.message)
|
|
19350
|
+
});
|
|
19351
|
+
});
|
|
19352
|
+
child.on("close", (code)=>{
|
|
19353
|
+
resolve({
|
|
19354
|
+
exitCode: code,
|
|
19355
|
+
stdout: redactSecrets(stdout),
|
|
19356
|
+
stderr: redactSecrets(stderr)
|
|
19357
|
+
});
|
|
19358
|
+
});
|
|
19359
|
+
child.stdin.end(input);
|
|
19360
|
+
});
|
|
19361
|
+
}
|
|
19362
|
+
async function buildAppReport(repoPath, remote, deps) {
|
|
19363
|
+
const appId = remote.appId;
|
|
19364
|
+
const anvilUrl = remote.anvilUrl;
|
|
19365
|
+
const url = new URL(anvilUrl);
|
|
19366
|
+
const credentialScope = `${url.protocol}//${url.host}`;
|
|
19367
|
+
const helperConfigKey = `credential.${credentialScope}.helper`;
|
|
19368
|
+
const helperValues = await getLocalConfigValues(repoPath, helperConfigKey);
|
|
19369
|
+
const nonEmptyHelperValues = helperValues.filter((value)=>"" !== value.trim());
|
|
19370
|
+
const helperDetails = nonEmptyHelperValues.map(inspectCredentialHelperCommand);
|
|
19371
|
+
const findings = [];
|
|
19372
|
+
if (0 === helperValues.length) findings.push(finding("error", "missing_helper_config", `No local ${helperConfigKey} entries found.`));
|
|
19373
|
+
else if (0 === nonEmptyHelperValues.length) findings.push(finding("error", "missing_helper_command", `${helperConfigKey} only resets helpers; no Anvil helper command is configured.`));
|
|
19374
|
+
for (const helper of helperDetails){
|
|
19375
|
+
if (helper.parseError) findings.push(finding("error", "helper_parse_failed", `Could not parse helper command: ${helper.parseError}`));
|
|
19376
|
+
if (helper.execPath && false === helper.execExists) findings.push(finding("error", "helper_exec_missing", `Credential helper Node executable does not exist: ${helper.execPath}`));
|
|
19377
|
+
if (helper.helperPath) {
|
|
19378
|
+
if (false === helper.helperExists) findings.push(finding("error", "helper_file_missing", `Credential helper script does not exist: ${helper.helperPath}`));
|
|
19379
|
+
else if (false === helper.helperExecutable) findings.push(finding("warning", "helper_not_executable", `Credential helper script is not executable: ${helper.helperPath}`));
|
|
19380
|
+
} else findings.push(finding("error", "helper_path_missing", "Credential helper command does not include a helper script path."));
|
|
19381
|
+
if (helper.modulePath && false === helper.moduleExists) findings.push(finding("error", "helper_module_missing", `Generated helper points at a missing module: ${helper.modulePath}`));
|
|
19382
|
+
if (helper.modulePath && "cli.js" === external_path_default().basename(helper.modulePath)) findings.push(finding("error", "helper_module_cli_entry", `Generated helper points at the CLI entry instead of the API entry: ${helper.modulePath}`));
|
|
19383
|
+
}
|
|
19384
|
+
const binding = await deps.getAppAuthBinding(repoPath, appId);
|
|
19385
|
+
if (!binding.url) findings.push(finding("warning", "missing_app_binding_url", `No anvil.auth.${appId}.url binding is configured.`));
|
|
19386
|
+
if (!binding.username) findings.push(finding("warning", "missing_app_binding_username", `No anvil.auth.${appId}.username binding is configured.`));
|
|
19387
|
+
const authUrl = binding.url ? config_normalizeAnvilUrl(binding.url) : anvilUrl;
|
|
19388
|
+
let accounts = [];
|
|
19389
|
+
let authUsername = binding.username;
|
|
19390
|
+
let hasUsableAuth = false;
|
|
19391
|
+
try {
|
|
19392
|
+
accounts = await deps.getAccountsForUrl(authUrl);
|
|
19393
|
+
if (authUsername || 1 !== accounts.length) {
|
|
19394
|
+
if (!authUsername && accounts.length > 1) findings.push(finding("error", "multiple_accounts_without_binding", `Multiple accounts are logged in for ${authUrl}; bind one with anvil checkout --user.`));
|
|
19395
|
+
} else authUsername = accounts[0];
|
|
19396
|
+
hasUsableAuth = authUsername ? await deps.hasTokensForUrl(authUrl, authUsername) : accounts.length <= 1 && await deps.hasTokensForUrl(authUrl);
|
|
19397
|
+
if (!hasUsableAuth) findings.push(finding("error", "missing_usable_auth", authUsername ? `No usable auth tokens found for ${authUrl} as ${authUsername}.` : `No usable auth tokens found for ${authUrl}.`));
|
|
19398
|
+
} catch (e) {
|
|
19399
|
+
findings.push(finding("error", "auth_lookup_failed", `Auth lookup failed: ${redactSecrets(e.message)}`));
|
|
19400
|
+
}
|
|
19401
|
+
const fillResult = await deps.runCredentialFill(repoPath, buildCredentialInput(anvilUrl, appId));
|
|
19402
|
+
const credentialSimulation = {
|
|
19403
|
+
status: 0 === fillResult.exitCode && /^password=/im.test(fillResult.stdout) ? "ok" : "error",
|
|
19404
|
+
exitCode: fillResult.exitCode,
|
|
19405
|
+
stdout: redactSecrets(fillResult.stdout),
|
|
19406
|
+
stderr: redactSecrets(fillResult.stderr),
|
|
19407
|
+
error: fillResult.error ? redactSecrets(fillResult.error) : void 0
|
|
19408
|
+
};
|
|
19409
|
+
if ("ok" !== credentialSimulation.status) findings.push(finding("error", "credential_fill_failed", credentialSimulation.error || credentialSimulation.stderr.trim() || "git credential fill did not return a password."));
|
|
19410
|
+
const report = {
|
|
19411
|
+
appId,
|
|
19412
|
+
anvilUrl,
|
|
19413
|
+
remoteName: remote.name,
|
|
19414
|
+
remoteUrl: remote.fetchUrl,
|
|
19415
|
+
credentialScope,
|
|
19416
|
+
helperConfigKey,
|
|
19417
|
+
helperValues,
|
|
19418
|
+
helperDetails,
|
|
19419
|
+
binding: {
|
|
19420
|
+
url: binding.url,
|
|
19421
|
+
username: binding.username,
|
|
19422
|
+
hasUrl: !!binding.url,
|
|
19423
|
+
hasUsername: !!binding.username
|
|
19424
|
+
},
|
|
19425
|
+
auth: {
|
|
19426
|
+
url: authUrl,
|
|
19427
|
+
username: authUsername,
|
|
19428
|
+
accounts,
|
|
19429
|
+
hasUsableAuth
|
|
19430
|
+
},
|
|
19431
|
+
credentialSimulation,
|
|
19432
|
+
findings
|
|
19433
|
+
};
|
|
19434
|
+
return report;
|
|
19435
|
+
}
|
|
19436
|
+
async function buildGitAuthDoctorReport(repoPathInput = process.cwd(), options = {}) {
|
|
19437
|
+
const deps = options.deps ?? defaultGitAuthDoctorDeps;
|
|
19438
|
+
const inputPath = external_path_default().resolve(repoPathInput);
|
|
19439
|
+
const git = esm_default(inputPath);
|
|
19440
|
+
const repoPath = (await git.raw([
|
|
19441
|
+
"rev-parse",
|
|
19442
|
+
"--show-toplevel"
|
|
19443
|
+
])).trim();
|
|
19444
|
+
const rawGitDir = (await git.raw([
|
|
19445
|
+
"rev-parse",
|
|
19446
|
+
"--git-dir"
|
|
19447
|
+
])).trim();
|
|
19448
|
+
const gitDir = external_path_default().isAbsolute(rawGitDir) ? rawGitDir : external_path_default().resolve(inputPath, rawGitDir);
|
|
19449
|
+
auth_setRepoContext(repoPath);
|
|
19450
|
+
const remotes = (await git.getRemotes(true)).map(detectAnvilRemote);
|
|
19451
|
+
const anvilRemotes = remotes.filter((remote)=>remote.appId && remote.anvilUrl && "https" === remote.transport);
|
|
19452
|
+
const findings = [];
|
|
19453
|
+
if (0 === anvilRemotes.length) findings.push(finding("error", "missing_anvil_https_remote", "No HTTPS Anvil git remotes were detected."));
|
|
19454
|
+
const apps = await Promise.all(anvilRemotes.map((remote)=>buildAppReport(repoPath, remote, deps)));
|
|
19455
|
+
const status = getHighestStatus([
|
|
19456
|
+
...findings.map((item)=>item.status),
|
|
19457
|
+
...apps.flatMap((app)=>app.findings.map((item)=>item.status))
|
|
19458
|
+
]);
|
|
19459
|
+
return {
|
|
19460
|
+
repoPath,
|
|
19461
|
+
gitDir,
|
|
19462
|
+
remotes,
|
|
19463
|
+
apps,
|
|
19464
|
+
findings,
|
|
19465
|
+
status
|
|
19466
|
+
};
|
|
19467
|
+
}
|
|
19468
|
+
function formatStatus(status) {
|
|
19469
|
+
if ("ok" === status) return external_chalk_default().green("[ok]");
|
|
19470
|
+
if ("warning" === status) return external_chalk_default().yellow("[warn]");
|
|
19471
|
+
return external_chalk_default().red("[error]");
|
|
19472
|
+
}
|
|
19473
|
+
function formatGitAuthDoctorReport(report) {
|
|
19474
|
+
const lines = [];
|
|
19475
|
+
lines.push(external_chalk_default().bold("Git auth doctor"));
|
|
19476
|
+
lines.push(`Repository: ${report.repoPath}`);
|
|
19477
|
+
lines.push(`Git dir: ${report.gitDir}`);
|
|
19478
|
+
lines.push(`Overall: ${formatStatus(report.status)}`);
|
|
19479
|
+
lines.push("");
|
|
19480
|
+
lines.push(external_chalk_default().bold("Detected remotes:"));
|
|
19481
|
+
if (0 === report.remotes.length) lines.push(" (none)");
|
|
19482
|
+
else for (const remote of report.remotes){
|
|
19483
|
+
const appText = remote.appId && remote.anvilUrl ? ` -> ${remote.appId} on ${remote.anvilUrl}` : "";
|
|
19484
|
+
lines.push(` - ${remote.name}: ${remote.fetchUrl || "(no fetch URL)"}${appText}`);
|
|
19485
|
+
}
|
|
19486
|
+
for (const app of report.apps){
|
|
19487
|
+
lines.push("");
|
|
19488
|
+
lines.push(external_chalk_default().bold(`App ${app.appId} (${app.remoteName})`));
|
|
19489
|
+
lines.push(` URL: ${app.anvilUrl}`);
|
|
19490
|
+
lines.push(` Credential scope: ${app.credentialScope}`);
|
|
19491
|
+
lines.push(` Helper config: ${app.helperConfigKey}`);
|
|
19492
|
+
if (0 === app.helperValues.length) lines.push(" (none)");
|
|
19493
|
+
else for (const value of app.helperValues)lines.push(` - ${value || "(reset helper list)"}`);
|
|
19494
|
+
for (const helper of app.helperDetails){
|
|
19495
|
+
lines.push(` Helper command: ${helper.raw}`);
|
|
19496
|
+
lines.push(` Node: ${helper.execPath || "(missing)"} ${false === helper.execExists ? "[missing]" : ""}`.trimEnd());
|
|
19497
|
+
lines.push(` Script: ${helper.helperPath || "(missing)"} ${false === helper.helperExists ? "[missing]" : ""}`.trimEnd());
|
|
19498
|
+
if (helper.modulePath) lines.push(` Module: ${helper.modulePath} ${false === helper.moduleExists ? "[missing]" : ""}`.trimEnd());
|
|
19499
|
+
}
|
|
19500
|
+
lines.push(` Binding URL: ${app.binding.url || "(missing)"}`);
|
|
19501
|
+
lines.push(` Binding user: ${app.binding.username || "(missing)"}`);
|
|
19502
|
+
lines.push(` Auth tokens: ${app.auth.hasUsableAuth ? "available" : "not available"}${app.auth.username ? ` for ${app.auth.username}` : ""}`);
|
|
19503
|
+
if (app.credentialSimulation) {
|
|
19504
|
+
lines.push(` Credential fill: ${formatStatus(app.credentialSimulation.status)} exit=${app.credentialSimulation.exitCode}`);
|
|
19505
|
+
if (app.credentialSimulation.stdout.trim()) {
|
|
19506
|
+
lines.push(" stdout:");
|
|
19507
|
+
for (const line of app.credentialSimulation.stdout.trim().split(/\r?\n/))lines.push(` ${line}`);
|
|
19508
|
+
}
|
|
19509
|
+
if (app.credentialSimulation.stderr.trim()) {
|
|
19510
|
+
lines.push(" stderr:");
|
|
19511
|
+
for (const line of app.credentialSimulation.stderr.trim().split(/\r?\n/))lines.push(` ${line}`);
|
|
19512
|
+
}
|
|
19513
|
+
}
|
|
19514
|
+
if (app.findings.length > 0) {
|
|
19515
|
+
lines.push(" Findings:");
|
|
19516
|
+
for (const item of app.findings)lines.push(` ${formatStatus(item.status)} ${item.code}: ${item.message}`);
|
|
19517
|
+
}
|
|
19518
|
+
}
|
|
19519
|
+
if (report.findings.length > 0) {
|
|
19520
|
+
lines.push("");
|
|
19521
|
+
lines.push(external_chalk_default().bold("Repository findings:"));
|
|
19522
|
+
for (const item of report.findings)lines.push(` ${formatStatus(item.status)} ${item.code}: ${item.message}`);
|
|
19523
|
+
}
|
|
19524
|
+
return lines.join("\n");
|
|
19525
|
+
}
|
|
19003
19526
|
const gitCredential_defaultDeps = {
|
|
19004
19527
|
getValidAuthToken: auth_getValidAuthToken,
|
|
19005
19528
|
getAccountsForUrl: auth_getAccountsForUrl,
|
|
@@ -19457,6 +19980,7 @@ exports.ValidationIssue = __webpack_exports__.ValidationIssue;
|
|
|
19457
19980
|
exports.ValidationTarget = __webpack_exports__.ValidationTarget;
|
|
19458
19981
|
exports.WatchSession = __webpack_exports__.WatchSession;
|
|
19459
19982
|
exports.branchFromEnvironmentVersion = __webpack_exports__.branchFromEnvironmentVersion;
|
|
19983
|
+
exports.buildGitAuthDoctorReport = __webpack_exports__.buildGitAuthDoctorReport;
|
|
19460
19984
|
exports.checkUncommittedChanges = __webpack_exports__.checkUncommittedChanges;
|
|
19461
19985
|
exports.clearInMemoryTokens = __webpack_exports__.clearInMemoryTokens;
|
|
19462
19986
|
exports.createWatchDiagnostic = __webpack_exports__.createWatchDiagnostic;
|
|
@@ -19468,6 +19992,7 @@ exports.executeCheckout = __webpack_exports__.executeCheckout;
|
|
|
19468
19992
|
exports.executeGitCredentialOperation = __webpack_exports__.executeGitCredentialOperation;
|
|
19469
19993
|
exports.filterCandidates = __webpack_exports__.filterCandidates;
|
|
19470
19994
|
exports.formatCandidateLabel = __webpack_exports__.formatCandidateLabel;
|
|
19995
|
+
exports.formatGitAuthDoctorReport = __webpack_exports__.formatGitAuthDoctorReport;
|
|
19471
19996
|
exports.formatValidationPath = __webpack_exports__.formatValidationPath;
|
|
19472
19997
|
exports.getAccountsForUrl = __webpack_exports__.getAccountsForUrl;
|
|
19473
19998
|
exports.getAllConfig = __webpack_exports__.getAllConfig;
|
|
@@ -19483,6 +20008,7 @@ exports.getSettableConfigKeys = __webpack_exports__.getSettableConfigKeys;
|
|
|
19483
20008
|
exports.getValidAuthToken = __webpack_exports__.getValidAuthToken;
|
|
19484
20009
|
exports.getWebSocketUrl = __webpack_exports__.getWebSocketUrl;
|
|
19485
20010
|
exports.hasTokensForUrl = __webpack_exports__.hasTokensForUrl;
|
|
20011
|
+
exports.inspectCredentialHelperCommand = __webpack_exports__.inspectCredentialHelperCommand;
|
|
19486
20012
|
exports.isCommandAvailable = __webpack_exports__.isCommandAvailable;
|
|
19487
20013
|
exports.isDirectoryNonEmpty = __webpack_exports__.isDirectoryNonEmpty;
|
|
19488
20014
|
exports.isPathInsideGitRepo = __webpack_exports__.isPathInsideGitRepo;
|
|
@@ -19493,6 +20019,7 @@ exports.lookupRemoteInfoForAppId = __webpack_exports__.lookupRemoteInfoForAppId;
|
|
|
19493
20019
|
exports.normalizeAnvilUrl = __webpack_exports__.normalizeAnvilUrl;
|
|
19494
20020
|
exports.parseCheckoutInput = __webpack_exports__.parseCheckoutInput;
|
|
19495
20021
|
exports.parseConfigSetValue = __webpack_exports__.parseConfigSetValue;
|
|
20022
|
+
exports.parseCredentialHelperCommand = __webpack_exports__.parseCredentialHelperCommand;
|
|
19496
20023
|
exports.pollDeviceAuthorization = __webpack_exports__.pollDeviceAuthorization;
|
|
19497
20024
|
exports.preferredEditors = __webpack_exports__.preferredEditors;
|
|
19498
20025
|
exports.readEnvironmentPid = __webpack_exports__.readEnvironmentPid;
|
|
@@ -19544,6 +20071,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
19544
20071
|
"ValidationTarget",
|
|
19545
20072
|
"WatchSession",
|
|
19546
20073
|
"branchFromEnvironmentVersion",
|
|
20074
|
+
"buildGitAuthDoctorReport",
|
|
19547
20075
|
"checkUncommittedChanges",
|
|
19548
20076
|
"clearInMemoryTokens",
|
|
19549
20077
|
"createWatchDiagnostic",
|
|
@@ -19555,6 +20083,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
19555
20083
|
"executeGitCredentialOperation",
|
|
19556
20084
|
"filterCandidates",
|
|
19557
20085
|
"formatCandidateLabel",
|
|
20086
|
+
"formatGitAuthDoctorReport",
|
|
19558
20087
|
"formatValidationPath",
|
|
19559
20088
|
"getAccountsForUrl",
|
|
19560
20089
|
"getAllConfig",
|
|
@@ -19570,6 +20099,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
19570
20099
|
"getValidAuthToken",
|
|
19571
20100
|
"getWebSocketUrl",
|
|
19572
20101
|
"hasTokensForUrl",
|
|
20102
|
+
"inspectCredentialHelperCommand",
|
|
19573
20103
|
"isCommandAvailable",
|
|
19574
20104
|
"isDirectoryNonEmpty",
|
|
19575
20105
|
"isPathInsideGitRepo",
|
|
@@ -19580,6 +20110,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
19580
20110
|
"normalizeAnvilUrl",
|
|
19581
20111
|
"parseCheckoutInput",
|
|
19582
20112
|
"parseConfigSetValue",
|
|
20113
|
+
"parseCredentialHelperCommand",
|
|
19583
20114
|
"pollDeviceAuthorization",
|
|
19584
20115
|
"preferredEditors",
|
|
19585
20116
|
"readEnvironmentPid",
|