@antora/content-aggregator 3.1.0 → 3.2.0-alpha.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.
@@ -188,8 +188,7 @@ async function loadRepository (url, opts) {
188
188
  await git
189
189
  .fetch(fetchOpts)
190
190
  .then(() => {
191
- const credentialManager = gitPlugins.credentialManager
192
- authStatus = credentials ? 'auth-embedded' : credentialManager.status({ url }) ? 'auth-required' : undefined
191
+ authStatus = identifyAuthStatus(gitPlugins.credentialManager, credentials, url)
193
192
  return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
194
193
  })
195
194
  .catch((fetchErr) => {
@@ -210,8 +209,7 @@ async function loadRepository (url, opts) {
210
209
  .clone(fetchOpts)
211
210
  .then(() => git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo)))
212
211
  .then(() => {
213
- const credentialManager = gitPlugins.credentialManager
214
- authStatus = credentials ? 'auth-embedded' : credentialManager.status({ url }) ? 'auth-required' : undefined
212
+ authStatus = identifyAuthStatus(gitPlugins.credentialManager, credentials, url)
215
213
  return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
216
214
  })
217
215
  .catch((cloneErr) => {
@@ -223,8 +221,15 @@ async function loadRepository (url, opts) {
223
221
  .then(() => fetchOpts.onProgress && fetchOpts.onProgress.finish())
224
222
  }
225
223
  } else if (await isDirectory((dir = expandPath(url, { dot: opts.startDir })))) {
226
- const gitdir = ospath.join(dir, '.git')
227
- repo = (await isDirectory(gitdir)) ? { cache, dir, fs, gitdir } : { cache, dir, fs, gitdir: dir, noCheckout: true }
224
+ const dotgit = ospath.join(dir, '.git')
225
+ const dotgitStat = await fsp.stat(dotgit).catch(() => ({ isFile: invariably.false, isDirectory: invariably.false }))
226
+ if (dotgitStat.isDirectory()) {
227
+ repo = { cache, dir, fs, gitdir: dotgit }
228
+ } else if (dotgitStat.isFile()) {
229
+ repo = await resolveRepositoryFromWorktree({ cache, dir, fs, gitdir: dotgit })
230
+ } else {
231
+ repo = { cache, dir, fs, gitdir: dir, noCheckout: true }
232
+ }
228
233
  try {
229
234
  await git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo))
230
235
  } catch {
@@ -273,7 +278,7 @@ async function collectFilesFromSource (source, repo, remoteName, authStatus) {
273
278
 
274
279
  // QUESTION should we resolve HEAD to a ref eagerly to avoid having to do a match on it?
275
280
  async function selectReferences (source, repo, remote) {
276
- let { branches: branchPatterns, tags: tagPatterns, worktrees: worktreePatterns = '.' } = source
281
+ let { branches: branchPatterns, tags: tagPatterns, worktrees: worktreePatterns } = source
277
282
  const isBare = repo.noCheckout
278
283
  const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
279
284
  const noWorktree = repo.url ? undefined : false
@@ -293,6 +298,12 @@ async function selectReferences (source, repo, remote) {
293
298
  }
294
299
  }
295
300
  if (!branchPatterns) return [...refs.values()]
301
+ branchPatterns = Array.isArray(branchPatterns)
302
+ ? branchPatterns.map((pattern) => String(pattern))
303
+ : splitRefPatterns(String(branchPatterns))
304
+ if (!branchPatterns.length) return [...refs.values()]
305
+ const worktreeName = repo.worktreeName // possibly switch to worktree property ({ name, dir}) in future
306
+ if (worktreeName) branchPatterns = branchPatterns.map((it) => (it === 'HEAD' ? 'HEAD@' + worktreeName : it))
296
307
  if (worktreePatterns) {
297
308
  if (worktreePatterns === '.') {
298
309
  worktreePatterns = ['.']
@@ -302,10 +313,12 @@ async function selectReferences (source, repo, remote) {
302
313
  worktreePatterns = Array.isArray(worktreePatterns)
303
314
  ? worktreePatterns.map((pattern) => String(pattern))
304
315
  : splitRefPatterns(String(worktreePatterns))
316
+ if (worktreeName) worktreePatterns = worktreePatterns.map((it) => (it === '@' ? worktreeName : it))
305
317
  }
318
+ } else {
319
+ worktreePatterns = worktreePatterns === undefined ? [worktreeName || '.'] : []
306
320
  }
307
- const branchPatternsString = String(branchPatterns)
308
- if (branchPatternsString === 'HEAD' || branchPatternsString === '.') {
321
+ if (branchPatterns.length === 1 && (branchPatterns[0] === 'HEAD' || branchPatterns[0] === '.')) {
309
322
  const currentBranch = await getCurrentBranchName(repo, remote)
310
323
  if (currentBranch) {
311
324
  branchPatterns = [currentBranch]
@@ -317,11 +330,7 @@ async function selectReferences (source, repo, remote) {
317
330
  refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
318
331
  return [...refs.values()]
319
332
  }
320
- } else if (
321
- (branchPatterns = Array.isArray(branchPatterns)
322
- ? branchPatterns.map((pattern) => String(pattern))
323
- : splitRefPatterns(branchPatternsString)).length
324
- ) {
333
+ } else {
325
334
  let headBranchIdx
326
335
  // NOTE we can assume at least two entries if HEAD or . are present
327
336
  if (~(headBranchIdx = branchPatterns.indexOf('HEAD')) || ~(headBranchIdx = branchPatterns.indexOf('.'))) {
@@ -346,8 +355,6 @@ async function selectReferences (source, repo, remote) {
346
355
  branchPatterns.splice(headBranchIdx, 1)
347
356
  }
348
357
  }
349
- } else {
350
- return [...refs.values()]
351
358
  }
352
359
  // NOTE isomorphic-git includes HEAD in list of remote branches (see https://isomorphic-git.org/docs/listBranches)
353
360
  const remoteBranches = (await git.listBranches(Object.assign({ remote }, repo))).filter((it) => it !== 'HEAD')
@@ -362,8 +369,20 @@ async function selectReferences (source, repo, remote) {
362
369
  const localBranches = await git.listBranches(repo)
363
370
  if (localBranches.length) {
364
371
  const worktrees = await findWorktrees(repo, worktreePatterns)
365
- for (const shortname of filterRefs(localBranches, branchPatterns, patternCache)) {
366
- const head = worktrees.get(shortname) || noWorktree
372
+ let onMatch
373
+ if ((worktreePatterns.join('') || '.') !== '.') {
374
+ const symbolicNames = new Map()
375
+ worktrees.forEach(({ name, symbolicName = 'HEAD@' + name }, shortname) => {
376
+ localBranches.push(symbolicName)
377
+ symbolicNames.set(symbolicName, shortname)
378
+ })
379
+ onMatch = (candidate, { pattern }) => {
380
+ const shortname = symbolicNames.get(candidate)
381
+ return shortname ? (pattern.startsWith('HEAD@') ? shortname : undefined) : candidate
382
+ }
383
+ }
384
+ for (const shortname of filterRefs(localBranches, branchPatterns, patternCache, onMatch)) {
385
+ const head = (worktrees.get(shortname) || { head: noWorktree }).head
367
386
  refs.set(shortname, { shortname, fullname: 'heads/' + shortname, type: 'branch', head })
368
387
  }
369
388
  }
@@ -382,15 +401,13 @@ async function selectReferences (source, repo, remote) {
382
401
  * Returns the current branch name unless the HEAD is detached.
383
402
  */
384
403
  function getCurrentBranchName (repo, remote) {
385
- let refPromise
386
- if (repo.noCheckout) {
387
- refPromise = git
388
- .resolveRef(Object.assign({ ref: 'refs/remotes/' + remote + '/HEAD', depth: 2 }, repo))
389
- .catch(() => git.resolveRef(Object.assign({ ref: 'HEAD', depth: 2 }, repo)))
390
- } else {
391
- refPromise = git.resolveRef(Object.assign({ ref: 'HEAD', depth: 2 }, repo))
392
- }
393
- return refPromise.then((ref) => (ref.startsWith('refs/') ? ref.replace(SHORTEN_REF_RX, '') : undefined))
404
+ return (
405
+ repo.noCheckout && remote
406
+ ? git
407
+ .resolveRef(Object.assign({ ref: 'refs/remotes/' + remote + '/HEAD', depth: 2 }, repo))
408
+ .catch(() => git.resolveRef(Object.assign({ ref: 'HEAD', depth: 2 }, repo)))
409
+ : git.resolveRef(Object.assign({ ref: 'HEAD', depth: 2 }, repo))
410
+ ).then((ref) => (ref.startsWith('refs/') ? ref.replace(SHORTEN_REF_RX, '') : undefined))
394
411
  }
395
412
 
396
413
  async function collectFilesFromReference (source, repo, remoteName, authStatus, ref, originUrl) {
@@ -459,17 +476,16 @@ function readFilesFromWorktree (origin) {
459
476
  }
460
477
 
461
478
  function srcFs (cwd, origin) {
462
- const relpathStart = cwd.length + 1
463
- return new Promise((resolve, reject, cache = Object.create(null), files = []) =>
479
+ return new Promise((resolve, reject, cache = Object.create(null), files = [], relpathStart = cwd.length + 1) =>
464
480
  pipeline(
465
481
  globStream(CONTENT_SRC_GLOB, Object.assign({ cache, cwd }, CONTENT_SRC_OPTS)),
466
482
  forEach(({ path: abspathPosix }, _, done) => {
467
- if (Array.isArray(cache[abspathPosix])) return done() // detects some directories, but not all
483
+ if ((cache[abspathPosix] || {}).constructor === Array) return done() // detects some directories
468
484
  const abspath = posixify ? ospath.normalize(abspathPosix) : abspathPosix
469
485
  const relpath = abspath.substr(relpathStart)
470
486
  symlinkAwareStat(abspath).then(
471
487
  (stat) => {
472
- if (stat.isDirectory()) return done() // detects remaining directories
488
+ if (stat.isDirectory()) return done() // detects directories that slipped through cache check
473
489
  fsp.readFile(abspath).then(
474
490
  (contents) => {
475
491
  files.push(new File({ path: posixify ? posixify(relpath) : relpath, contents, stat, src: { abspath } }))
@@ -824,11 +840,14 @@ function onGitComplete (err) {
824
840
  }
825
841
 
826
842
  function resolveCredentials (credentialsFromUrlHolder, url, auth) {
827
- const credentialsFromUrl = credentialsFromUrlHolder.get()
843
+ const credentialsFromUrl = credentialsFromUrlHolder.get() || {}
828
844
  if ('Authorization' in auth.headers) {
829
- if (!credentialsFromUrl) return this.rejected({ url, auth })
830
- credentialsFromUrlHolder.clear()
831
- } else if (credentialsFromUrl) {
845
+ if ('username' in credentialsFromUrl) {
846
+ credentialsFromUrlHolder.clear()
847
+ } else {
848
+ return this.rejected({ url, auth })
849
+ }
850
+ } else if ('username' in credentialsFromUrl) {
832
851
  return credentialsFromUrl
833
852
  } else {
834
853
  auth = undefined
@@ -840,6 +859,15 @@ function resolveCredentials (credentialsFromUrlHolder, url, auth) {
840
859
  )
841
860
  }
842
861
 
862
+ function identifyAuthStatus (credentialManager, credentials, url) {
863
+ const status = credentialManager.status({ url })
864
+ if (credentials) {
865
+ return typeof status === 'string' && status.startsWith('requested,') ? 'auth-required' : 'auth-embedded'
866
+ } else if (status != null) {
867
+ return 'auth-required'
868
+ }
869
+ }
870
+
843
871
  /**
844
872
  * Generates a safe, unique folder name for a git URL.
845
873
  *
@@ -852,13 +880,9 @@ function resolveCredentials (credentialsFromUrlHolder, url, auth) {
852
880
  * @returns {String} The generated folder name.
853
881
  */
854
882
  function generateCloneFolderName (url) {
855
- let normalizedUrl = url.toLowerCase()
856
- if (posixify) normalizedUrl = posixify(normalizedUrl)
857
- normalizedUrl = removeGitSuffix(normalizedUrl)
883
+ const normalizedUrl = removeGitSuffix(posixify ? posixify(url.toLowerCase()) : url.toLowerCase())
858
884
  const basename = normalizedUrl.split(ANY_SEPARATOR_RX).pop()
859
- const hash = createHash('sha1')
860
- hash.update(normalizedUrl)
861
- return basename + '-' + hash.digest('hex') + '.git'
885
+ return basename + '-' + createHash('sha1').update(normalizedUrl).digest('hex') + '.git'
862
886
  }
863
887
 
864
888
  /**
@@ -888,7 +912,7 @@ function resolveRemoteUrl (repo, remoteName) {
888
912
  * Checks whether the specified URL matches a directory on the local filesystem.
889
913
  *
890
914
  * @param {String} url - The URL to check.
891
- * @return {Boolean} A flag indicating whether the URL matches a directory on the local filesystem.
915
+ * @returns {Boolean} A flag indicating whether the URL matches a directory on the local filesystem.
892
916
  */
893
917
  function isDirectory (url) {
894
918
  return fsp.stat(url).then((stat) => stat.isDirectory(), invariably.false)
@@ -1011,39 +1035,54 @@ function coerceToString (value) {
1011
1035
  return value == null ? '' : String(value)
1012
1036
  }
1013
1037
 
1038
+ async function resolveRepositoryFromWorktree (repo) {
1039
+ return fsp
1040
+ .readFile(repo.gitdir, 'utf8')
1041
+ .then((contents) => contents.trimRight().substr(8))
1042
+ .then((worktreeGitdir) => {
1043
+ const worktreeName = ospath.basename(worktreeGitdir)
1044
+ return fsp.readFile(ospath.join(worktreeGitdir, 'commondir'), 'utf8').then(
1045
+ (contents) => {
1046
+ const gitdir = ospath.join(worktreeGitdir, contents.trimRight())
1047
+ return ospath.basename(gitdir) === '.git'
1048
+ ? Object.assign(repo, { dir: ospath.dirname(gitdir), gitdir, worktreeName })
1049
+ : Object.assign(repo, { dir: gitdir, gitdir, worktreeName })
1050
+ },
1051
+ () => repo
1052
+ )
1053
+ })
1054
+ }
1055
+
1014
1056
  function findWorktrees (repo, patterns) {
1015
1057
  if (!patterns.length) return new Map()
1016
- const linkedOnly = patterns[0] === '.' ? !(patterns = patterns.slice(1)) : true
1017
- let worktreesDir
1058
+ const mainWorktree =
1059
+ patterns[0] === '.' && (patterns = patterns.slice(1))
1060
+ ? getCurrentBranchName(repo).then((branch) => (branch ? [branch, { head: repo.dir, name: '.' }] : undefined))
1061
+ : Promise.resolve()
1062
+ const worktreesDir = patterns.length ? ospath.join(repo.dir, '.git', 'worktrees') : undefined
1018
1063
  const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
1019
1064
  return (
1020
- patterns.length
1065
+ worktreesDir
1021
1066
  ? fsp
1022
- .readdir((worktreesDir = ospath.join(repo.dir, '.git', 'worktrees')))
1067
+ .readdir(worktreesDir)
1023
1068
  .then((worktreeNames) => filterRefs(worktreeNames, patterns, patternCache), invariably.emptyArray)
1024
1069
  .then((worktreeNames) =>
1025
- worktreeNames.length
1026
- ? Promise.all(
1027
- worktreeNames.map((worktreeName) => {
1028
- const gitdir = ospath.resolve(worktreesDir, worktreeName)
1029
- // NOTE uses name of worktree as branch name if HEAD is detached
1030
- return git
1031
- .currentBranch(Object.assign({}, repo, { gitdir }))
1032
- .then((branch = worktreeName) =>
1033
- fsp
1034
- .readFile(ospath.join(gitdir, 'gitdir'), 'utf8')
1035
- .then((contents) => ({ branch, dir: ospath.dirname(contents.trimRight()) }))
1036
- )
1037
- })
1038
- ).then((entries) => entries.reduce((accum, it) => accum.set(it.branch, it.dir), new Map()))
1039
- : new Map()
1070
+ Promise.all(
1071
+ worktreeNames.map((worktreeName) => {
1072
+ const gitdir = ospath.resolve(worktreesDir, worktreeName)
1073
+ // NOTE branch name defaults to worktree name if HEAD is detached
1074
+ return git
1075
+ .currentBranch(Object.assign({}, repo, { gitdir }))
1076
+ .then((branch = worktreeName) =>
1077
+ fsp
1078
+ .readFile(ospath.join(gitdir, 'gitdir'), 'utf8')
1079
+ .then((contents) => [branch, { head: ospath.dirname(contents.trimRight()), name: worktreeName }])
1080
+ )
1081
+ })
1082
+ )
1040
1083
  )
1041
- : Promise.resolve(new Map())
1042
- ).then((worktrees) =>
1043
- linkedOnly
1044
- ? worktrees
1045
- : git.currentBranch(repo).then((branch) => (branch ? worktrees.set(branch, repo.dir) : worktrees))
1046
- )
1084
+ : Promise.resolve()
1085
+ ).then((entries = []) => mainWorktree.then((entry) => new Map(entry ? entries.push(entry) && entries : entries)))
1047
1086
  }
1048
1087
 
1049
1088
  module.exports = aggregateContent
@@ -4,7 +4,7 @@ const { posix: path } = require('path')
4
4
  const posixify = require('./posixify')
5
5
  const removeGitSuffix = require('./remove-git-suffix')
6
6
 
7
- const EDIT_URL_TEMPLATE_VAR_RX = /\{(web_url|ref(?:hash|name|type)|path)\}/g
7
+ const EDIT_URL_TEMPLATE_VAR_RX = /\{(web_url|ref(?:hash|name|type)?|path)\}/g
8
8
  const HOSTED_GIT_REPO_RX = /^(?:https?:\/\/|.+@)(git(?:hub|lab)\.com|bitbucket\.org|pagure\.io)[/:](.+?)(?:\.git)?$/
9
9
 
10
10
  function computeOrigin (url, authStatus, gitdir, ref, startPath, worktreePath = undefined, editUrl = true) {
@@ -41,6 +41,7 @@ function computeOrigin (url, authStatus, gitdir, ref, startPath, worktreePath =
41
41
  } else if (editUrl) {
42
42
  const vars = {
43
43
  path: () => (startPath ? path.join(startPath, '%s') : '%s'),
44
+ ref: () => 'refs/' + (reftype === 'branch' ? 'heads' : reftype) + '/' + refname,
44
45
  refhash: () => refhash,
45
46
  reftype: () => reftype,
46
47
  refname: () => refname,
package/lib/constants.js CHANGED
@@ -4,7 +4,7 @@ module.exports = Object.freeze({
4
4
  COMPONENT_DESC_FILENAME: 'antora.yml',
5
5
  CONTENT_CACHE_FOLDER: 'content',
6
6
  CONTENT_SRC_GLOB: '**/*[!~]',
7
- CONTENT_SRC_OPTS: { follow: true, nomount: true, nosort: true, nounique: true, strict: false, uniqueBy: (m) => m },
7
+ CONTENT_SRC_OPTS: { follow: true, nomount: true, nosort: true, nounique: true, strict: false },
8
8
  FILE_MODES: { 100644: 0o100666 & ~process.umask(), 100755: 0o100777 & ~process.umask() },
9
9
  GIT_CORE: 'antora',
10
10
  GIT_OPERATION_LABEL_LENGTH: 8,
@@ -4,9 +4,11 @@ const { makeMatcherRx, refMatcherOpts: getMatcherOpts, MATCH_ALL_RX } = require(
4
4
 
5
5
  function compileRx (pattern, opts) {
6
6
  if (pattern === '*' || pattern === '**') return MATCH_ALL_RX
7
- return pattern.charAt() === '!' // do our own negate
8
- ? Object.defineProperty(makeMatcherRx(pattern.substr(1), opts), 'negated', { value: true })
9
- : makeMatcherRx(pattern, opts)
7
+ const rx =
8
+ pattern.charAt() === '!' // we handle negate ourselves
9
+ ? Object.defineProperty(makeMatcherRx((pattern = pattern.substr(1)), opts), 'negated', { value: true })
10
+ : makeMatcherRx(pattern, opts)
11
+ return Object.defineProperty(rx, 'pattern', { value: pattern })
10
12
  }
11
13
 
12
14
  function createMatcher (patterns, cache, opts) {
@@ -15,8 +17,8 @@ function createMatcher (patterns, cache, opts) {
15
17
  cache.get(pattern) || cache.set(pattern, compileRx(pattern, opts || (opts = getMatcherOpts(cache)))).get(pattern)
16
18
  )
17
19
  if (rxs[0].negated) rxs.unshift(MATCH_ALL_RX)
18
- return (candidate) => {
19
- let matched
20
+ return (candidate, onMatch) => {
21
+ let matched, symbolic
20
22
  for (const rx of rxs) {
21
23
  let voteIfMatched = true
22
24
  if (matched) {
@@ -25,16 +27,22 @@ function createMatcher (patterns, cache, opts) {
25
27
  } else if (rx.negated) {
26
28
  continue
27
29
  }
28
- if (rx.test(candidate)) matched = voteIfMatched
30
+ if (rx.test(candidate) || (symbolic && rx.test(symbolic) && (candidate = symbolic))) {
31
+ if (onMatch) {
32
+ if (!(matched = onMatch(candidate, rx))) continue
33
+ ;[symbolic, candidate] = [candidate, matched]
34
+ }
35
+ matched = voteIfMatched && candidate
36
+ }
29
37
  }
30
38
  return matched
31
39
  }
32
40
  }
33
41
 
34
- function filterRefs (candidates, patterns, cache = Object.assign(new Map(), { braces: new Map() })) {
35
- const isMatch = createMatcher(patterns, cache)
42
+ function filterRefs (candidates, patterns, cache = Object.assign(new Map(), { braces: new Map() }), onMatch) {
43
+ const match = createMatcher(patterns, cache)
36
44
  return candidates.reduce((accum, candidate) => {
37
- if (isMatch(candidate)) accum.push(candidate)
45
+ if ((candidate = match(candidate, onMatch))) accum.push(candidate)
38
46
  return accum
39
47
  }, [])
40
48
  }
@@ -86,11 +86,11 @@ class GitCredentialManagerStore {
86
86
  }
87
87
 
88
88
  async approved ({ url }) {
89
- this.urls[url] = 'approved'
89
+ this.urls[url] = (url in this.urls ? this.urls[url] + ',' : '') + 'approved'
90
90
  }
91
91
 
92
92
  async rejected ({ url, auth }) {
93
- this.urls[url] = 'rejected'
93
+ this.urls[url] = (url in this.urls ? this.urls[url] + ',' : '') + 'rejected'
94
94
  const statusCode = 401
95
95
  const statusMessage = 'HTTP Basic: Access Denied'
96
96
  const err = new Error(`HTTP Error: ${statusCode} ${statusMessage}`)
package/lib/matcher.js CHANGED
@@ -22,7 +22,7 @@ function makeMatcherRx (input, opts) {
22
22
  }
23
23
 
24
24
  module.exports = {
25
- MATCH_ALL_RX: { test: () => true },
25
+ MATCH_ALL_RX: Object.defineProperty({ test: () => true }, 'pattern', { value: '*' }),
26
26
  expandBraces,
27
27
  makeMatcherRx,
28
28
  pathMatcherOpts: Object.assign({}, BASE_OPTS, { dot: false }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/content-aggregator",
3
- "version": "3.1.0",
3
+ "version": "3.2.0-alpha.1",
4
4
  "description": "Fetches and aggregates content from distributed sources for use in an Antora documentation pipeline.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -29,13 +29,13 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@antora/expand-path-helper": "~2.0",
32
- "@antora/logger": "3.1.0",
32
+ "@antora/logger": "3.2.0-alpha.1",
33
33
  "@antora/user-require-helper": "~2.0",
34
34
  "braces": "~3.0",
35
35
  "cache-directory": "~2.0",
36
36
  "glob-stream": "~7.0",
37
- "hpagent": "~1.0",
38
- "isomorphic-git": "~1.19",
37
+ "hpagent": "~1.1",
38
+ "isomorphic-git": "~1.21",
39
39
  "js-yaml": "~4.1",
40
40
  "multi-progress": "~4.0",
41
41
  "picomatch": "~2.3",