The resolve step echoes the publish command with shlex.quote, which is shell
quoting rather than output escaping: it wraps a value holding a line break in
single quotes and leaves the break itself intact. A caller-supplied changelog,
categories or topics value carrying a newline therefore opened a second line
in the step log, and the runner parses each stdout line, so that second line
reached it as a workflow command.
Escape the parts that are not printable in the echo. The re-runnable .sh file
keeps plain shell quoting, because there the quoting is what makes the script
correct.
Every CI run on main since 2f428b4e fails at bun audit in ci:static, and the
five downstream jobs mirror that result, so main and every open pull request
show six red checks.
The advisories landed on versions the repository pins itself: the overrides
block held dompurify 3.4.12 and js-yaml 4.3.0, which the advisories name as
the last affected releases, and the mermaid range floor sat one patch below
the fixed version. nanoid reaches the tree through postcss and has no
override, so it needs one.
Bump the four to the first fixed release rather than extending the --ignore
list, since a patch exists for each.
Accept artifact-only publication for experimental Claws so ClawHub can attest, retry, and serve the exact stored bytes. Preserve exact actor, owner, and digest identity across staged retries and validate current release state before reuse. Add durable contract documentation and real-stack publish, poll, download, and retry proof.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Default the homepage Plugins catalog to Featured when switching from the Skills-only Trending tab, while preserving explicit valid plugin tabs and existing Skills behavior.\n\nCloses #3433
Restores homepage search and category discovery while preserving the canonical Trending feed contract. Adds the responsive control-group divider and closes#3417.
Remove Skill listing icons across discovery, retain Plugin recognition icons on desktop, and collapse both icon columns at the existing mobile breakpoints. Keep loading skeletons aligned with settled rows and cards.
Closes#3425.
Co-authored-by: Vyctor H. Brzezowski <krzyszchweski@gmail.com>
* fix: abort registry discovery fetch after a timeout
discoverRegistryFromSite called fetch without an AbortSignal, so a
site that accepts the request but never answers hung 'clawhub login'
and registry resolution forever. Wrap the fetch in a local
AbortController + setTimeout helper (mirroring fetchWithTimeout in
http.ts, which is not exported) with a 15s budget matching the
package's request timeout convention, and reject with a clear
'Request timed out after 15s' error. Both call sites already
degrade any discovery rejection to null via .catch(() => null).
* fix: extend timeout to cover JSON body parsing
ClawSweeper P2 finding: the timeout cleared after fetch() resolved,
but response.json() could still hang if the peer sent headers and
never completed the body.
Changes:
- fetchWithTimeout now returns {response, clearTimer} tuple
- Caller keeps timeout active through JSON parsing
- Only clears timer in finally after body consumed
- Added test: stalled body triggers timeout (4/4 → 8/8 passing)
Addresses: ClawSweeper review P2 finding
Fixes: Timeout now covers full request lifecycle
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): clear discovery timeout on fetch failure
* test: format discovery timeout regression
* fix(cli): normalize discovery timeout errors
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
* fix: Japanese searches skip the category and summary result tiers
The pre-split in tokenize() treats U+30FC (ー) and U+3005 (々) as separators, so
a katakana word is torn into fragments before Intl.Segmenter can segment it:
"データベース" tokenizes as ["デ", "タベ", "ス"]. Two consequences follow.
Exploratory search requires every query token to be at least three characters
(EXPLORATORY_SEARCH_MIN_TOKEN_LENGTH in search.ts, skills.ts and packages.ts),
so katakana queries never reach the category, topic and summary tiers. And
getFirstSearchToken feeds normalizedDisplayNameFirstToken, an indexed range-scan
bound, which collapses to the single character "デ".
detectCJKLanguage in the same file already counts ー as katakana when it picks a
segmenter; the pre-split now agrees with it.
* fix: resynchronize digest first tokens and keep marks in the fallback
Widening the CJK class moves the first token of any name containing a
prolonged sound mark or an iteration mark. skillSearchDigest rows recompute
that field only when their skill is written, so already-stored rows keep the
old one-character token while search uses the new longer token as a range
index bound - the row stays on disk and out of recall.
Add a cursor-paginated resynchronization next to the existing digest backfills
in maintenance.ts, and stop the no-Segmenter fallback from emitting those two
marks as standalone tokens that exploratory matching discards.
* fix: space the search digest backfill batches apart
The catalog search page subscribes to skillSearchDigest, so a backfill that
reschedules itself with no delay drives reactive re-reads back to back for the
whole run. .agents/skills/clawhub-convex/SKILL.md asks for a delay between
backfill batches that write reactively subscribed tables.
The delay is an optional argument clamped the same way the batch size is, and it
follows repairLegacyPublisherOwnershipForUserHandler, which is the one backfill
in this file that already spaces its batches.
* fix: reindex the mirrored catalog's first tokens too
The skills.sh mirror persists its own normalizedSlugFirstToken and
normalizedDisplayNameFirstToken, derived through the same tokenizer, and external
candidate search range-scans both. Widening the katakana class therefore strands
mirrored rows exactly the way it stranded native digest rows, and the previous
backfill only paged skillSearchDigest.
skillsShMirror.ts had its own copy of the first-token rule. Both callers now share
getMirrorFirstSearchToken so the two cannot drift apart again.
* fix: require confirmation before the first-token backfills write
Both backfills defaulted dryRun to false, and their public admin actions
forward omitted arguments straight through. A bare
`npx convex run maintenance:backfillSkillSearchDigestFirstTokens` therefore
patched skillSearchDigest and scheduled every remaining page, against a table
catalog search subscribes to. An operator typo was an immediate production
apply rather than a preview.
Both now follow the contract the plugin catalog-digest resync already uses:
preview unless dryRun is explicitly false, reject an apply whose confirm token
does not match, and carry that token into the scheduled continuation so the
run does not stall on its own guard after the first page. The native and
mirror paths take separate tokens, so neither unlocks the other.
* fix: catalog previews cut Chinese and Japanese summaries at the first Latin word
truncateText backtracks to the last space in the slice unconditionally. Scripts
that do not separate words with spaces usually carry a single Latin space near
the start of a summary, so that backtrack discards nearly the whole preview:
across fixtures/public-corpus/corpus.jsonl, 25 catalog entries render with a
handful of characters instead of their budget, one of them as just "|".
Honour the word boundary only when it keeps most of the slice. All 1362
space-separated previews in the same corpus are unchanged.
* fix: keep the word boundary for space-separated previews
The kept-ratio fallback was added for CJK summaries whose only Latin space
sits near the start, but it applied to every script. A space-separated
summary ending in a long token — a URL, a compound word — lost its word
boundary and was cut mid-token instead.
Gate the ratio on the discarded tail actually being non-spacing script,
reusing the character class the catalog search tokenizer already relies on
in convex/lib/searchText.ts.
* docs: document skill categories and topics
Add a Catalog metadata section to docs/publishing.md covering --categories
and --topics, the 14 valid category slugs, the limits ClawHub enforces, the
reserved topic names, the `other` default, and how stored values change on a
later publish. Cross-reference it from the skill publish and sync entries in
docs/cli.md.
Values read from packages/schema/src/catalogMetadata.ts,
convex/lib/skillPublish.ts, and packages/clawhub/src/cli.ts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: cover the CI and plugin paths for catalog metadata
Three gaps in the first pass, all the same shape as the one this PR set
out to fix -- a way to publish with no way to set catalog metadata:
The reusable skill-publish.yml workflow has no categories or topics
input. It builds the command with --owner and --tags only, so a catalog
repo publishing through CI lands every skill in `other`, exactly like
sync. The new section sat directly under the workflow snippet and said
"set both when you publish," which read as though the block above it
could. Documented in both files.
`package publish` takes the same two flag names against
PLUGIN_CATEGORY_DEFINITIONS -- a different 12-slug list documented
nowhere -- so a reader who followed the new link would try
`development` and have the publish rejected. The cli.md entry now names
the plugin slugs and says the topic rules are shared, which they are:
convex/packages.ts:8585 resolves through resolvePluginCategories but
reuses normalizeCatalogTopics.
Moved the metadata section above the catalog-repo prose so the flags sit
with the command they belong to, and gave the CI content its own
heading rather than leaving it to trail the section. No wording in the
moved block changed.
Also two enforced rules the first pass omitted: repeats are dropped
rather than rejected and are matched after normalization (so `git,Git`
is one topic, and both limits count what survives), and topics cannot
contain invisible formatting characters. Qualified the 3-category limit,
which is applied after `other` is dropped, so `other,development,
operations` stores two rather than failing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: scope plugin-category validation to code and bundle plugins
Review caught that the package-publish bullet claimed every publish
validates --categories against the 12 plugin slugs. The claw family
does not: convex/packages.ts branches on family === "claw" and stores
the declared slugs without resolvePluginCategories, while
normalizeCatalogTopics still runs for every family. The bullet now
limits the slug check to code and bundle plugins, links docs/claws.md
for the exception, and keeps the shared-topic-rules claim, which held.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixes#3384.
Generated skill cards now use plain Markdown instead of HTML-only line-break tags while retaining compatibility normalization for existing cards.
Co-authored-by: Vyctor H. Brzezowski <hi@vyctor.com.br>
Constrain the mobile app-category strip to the available content width while preserving internal horizontal scrolling. Scope the CSS regression contract to the exact nested mobile rule.