feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(dockerhub): add tags command to list public repository tags - #450

Open
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags
Open

feat(dockerhub): add tags command to list public repository tags#450
sreeramakhil wants to merge 17 commits into
agentrhq:mainfrom
sreeramakhil:feat/dockerhub-tags

Conversation

@sreeramakhil

Copy link
Copy Markdown
Contributor

This PR adds the dockerhub tags CLI command to the Docker Hub plugin.

Key Changes

  • New Command (dockerhub tags): Queries https://hub.docker.com/v2/repositories/<owner>/<name>/tags/ and projects columns: tag, lastUpdated, size (in MB), architectures, and url.
  • Refactoring: Extracted and exported the trimDate helper function in utils.js so it is shared by both image.js and tags.js.
  • Unit Tests: Added a complete suite in tags.test.js to cover happy paths, limits, invalid names, and error envelopes.

- Add webcmd npm versions <name> command that lists all published
versions of a package newest-first, with publishedAt, isLatest flag,
and a direct npmjs.com URL per version. Mirrors the pypi releases cmd.
- Add optional equest parameter to
pmFetch in utils.js so commands
can inject a fake fetch function in tests without patching globals
(matches the pattern used in the pypi plugin).
- Add test/npm.test.js with 14 tests covering all four commands:
package, versions, downloads, search. Includes happy paths, empty
result / 404 handling, input validation, and a contract test asserting
browser: false for every registered command.
- Expand README.md with a full command table (including the new versions
command), argument descriptions, and copy-paste examples for all four
commands.
Slicing publishedAt to 10 chars before sorting caused versions
published on the same calendar date to lose sub-day precision,
producing non-deterministic newest-first ordering.
Fix: sort on the raw full timestamp first, then format to date-only
inside .map(). Add a regression test with two versions sharing the
same date (08:00 and 14:00) to pin the correct ordering.
… entries
A version key can exist in body.time without a matching entry in
body.versions (e.g. yanked or unpublished releases). The previous code
returned bogus rows for those keys with an invalid URL and misleading
date.
Fix: cross-filter timeMap entries against body.versions so only keys
that exist in both are returned. Also guard that the timestamp is a
string before sorting.
Update the same-day regression fixture to include matching body.versions
entries and add a time-only ghost key (0.0.1-ghost) to assert it is
excluded from results.
…tests
feat(npm): add versions command, test suite, and expanded README
Reddit is one of the most valuable developer discussion platforms
(r/programming, r/webdev, r/javascript, r/rust, r/python, etc.) but
was missing from the omnisearch aggregator entirely.
- Add redditSearch() to sources.js using the free public JSON search
API (reddit.com/search.json, no auth or key required). Returns
normalized rows: platform/title/author/score/commentCount/createdAt/
url/text — matching the shared schema used by all other sources.
Falls back to permalink when the url field is absent (self posts).
- Wire redditSearch into research.js: added to the fetchers map and
included in the default sources string so every agent using
webcmd omnisearch research gets Reddit results automatically.
- Wire redditSearch into verdict.js so community sentiment analysis
now includes Reddit engagement alongside HN, SO, GitHub, arXiv,
Dev.to, and Lobsters.
- Expand test/research.test.js from 1 test to 8 tests:
- redditSearch: normalized rows, permalink fallback, empty results,
correct endpoint URL
- research command: Reddit rows returned, default sources includes
reddit, Reddit failure isolated via Promise.allSettled
- Original HN limit regression test preserved
A non-numeric or out-of-range created_utc value would cause
new Date(...).toISOString() to throw, rejecting the entire Reddit
result set for that query.
Fix: construct the Date object first, then check Number.isNaN on
getTime() before calling toISOString() — returning empty string
for malformed timestamps so one bad post never kills the whole fetch.
Add regression test: a post with created_utc='not-a-number' must
produce createdAt='' without throwing.
…tion
child?.data ?? {} silently converted null entries and entries missing
a data object into fake normalized rows, which downstream research
could count or render as real Reddit results.
Fix: filter children to only those where child.data is a non-null
object before slice/map. Add regression test: a mix of null, no-data,
and null-data children alongside one valid entry — only the valid
entry must appear in results.
typeof [] === 'object' is true in JavaScript, so {data:[]} passed the
previous filter and mapped to a fake row that could displace a valid
result when limit was applied after slicing.
Fix: add !Array.isArray(child.data) to the filter so only plain objects
are accepted as valid post data.
Add regression test: one array-data entry + one valid entry with limit=1
asserts the valid result is returned, not the array-shaped fake.
…imeout
Without a timeout, a slow or stalled Reddit connection could keep the
fetch pending indefinitely, blocking the entire research aggregation.
Fix: pass AbortSignal.timeout(10_000) in the get() init options so the
request is automatically aborted after 10 seconds. The existing headers
and response handling are preserved.
feat(omnisearch): add Reddit as a 7th research source
- Drop the equest parameter from
pmFetch and �ersionsNpm. Instead, use withFetch in tests to stub the global etch.
- Filter out pre-release and build versions by default. Add a --prereleases boolean flag (default alse) to allow including them when requested.
- Update and expand tests in est/npm.test.js to cover the new pre-release filtering behavior and verify that the --prereleases flag works correctly.
…ages)
- Create plugins/omnisearch/packages.js to query npm, crates.io, NuGet, RubyGems, Packagist, and Maven Central in parallel using Promise.allSettled for failure isolation.
- Add support for --limit and --registries options to customize the search.
- Normalize search results to a unified schema: registry, name, version, description, and url.
- Create plugins/omnisearch/test/packages.test.js to cover all happy paths, filtering, limits, failure isolation, and browserless compliance.
- Re-compile the plugin command manifest to register the new command.
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@sreeramakhil

sreeramakhil commented Aug 27, 2026

Copy link
Copy Markdown
ContributorAuthor

@adikulkarni006 Thanks for the approval! Let me know if there is anything else needed to get this merged.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sreeramakhil@adikulkarni006