Publishing required a hand-made .zip. Local agent skills live as folders,
and repackaging them by hand often smuggles in tool metadata (__MACOSX/,
.DS_Store, ...) that clutters the package (#737).
Add an "upload a folder" option to the publish dropzone: pick a folder
(webkitdirectory), and the browser packages it into a clean STORE-method
zip via a dependency-free writer, dropping VCS/build/OS junk (.git/,
node_modules/, __pycache__/, .DS_Store, ...). The resulting zip flows
through the exact same upload/publish path, and the server already strips
a single root directory, so paths are preserved as-is.
Packaging (folder-zip.ts) is isolated and unit-tested (CRC-32 vectors, zip
structure, junk filtering); the UploadZone gains an optional onFolderSelect
prop so existing callers are unaffected.
Closes#737
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
Resolve open npm Dependabot alerts for the web app and docs site by refreshing dependency overrides and lockfiles.
Also sets the staging web forwarded-proto default so `make staging` can render the shared Nginx template when using the bare nginx image.
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Make skill-detail label chips navigate to /search?label=… and allow
the search filter row to wrap when many labels are present.
Signed-off-by: Mikhail Neradkov <michael.neradkov@gmail.com>
* fix(publish): delete review tasks of any status when replacing a version
Re-uploading a rejected version under the same version number returned
HTTP 500. deleteReplaceableVersionArtifacts only removed a PENDING review
task, but a rejected version owns a REJECTED one; that row kept a foreign
key on the skill_version, so the subsequent delete hit a constraint
violation that surfaced as a 500.
Delete every review task attached to the version instead.
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
* test(publish): drop the spring-test dependency from the new test
skillhub-domain has no spring-test on its test classpath, so
ReflectionTestUtils does not resolve there. Use plain JDK reflection for
setting the generated id and invoking the private method.
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
* fix(publish): constrain rejected version replacement
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
* test(publish): verify replaced review is deleted
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
* test(e2e): use generated API response types
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
---------
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
* feat(my-skills): add keyword search, namespace filter and clickable pagination
Add comprehensive filtering and search capabilities to the My Skills page:
- Keyword search: search by skill name, slug, or description
- Namespace filter: filter skills by namespace
- Clickable pagination: page number buttons with smart ellipsis
- State preservation: sync search state to URL, restore when returning from detail page
- Debounced search: 300ms debounce to avoid excessive queries
- Fix: hide stale rejected preview badge when newer version is published
Backend changes:
- MySkillAppService: add keyword and namespace filtering logic
- SkillLifecycleProjectionService: only show preview versions newer than published
- MeController: add keyword and namespace query parameters
- 6 new test cases covering search and filter scenarios
Frontend changes:
- my-skills.tsx: search input, namespace dropdown, URL state sync
- pagination.tsx: clickable page numbers with ellipsis
- use-user-queries.ts: prevent flicker on query transitions
- skill-detail.tsx: remove invalid rejected badge display
- router.tsx: URL parameter validation
- i18n: add search-related translation keys
Synced from SAAS commits:
- 939fa749 (feat: search and filters)
- dc14df6c (fix: search flicker)
- 0168ea81 (fix: rejected badge)
- c9eefa93 (fix: stale preview)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
* fix(tests): address test failures in PR #493
Backend test fixes:
- Remove unnecessary Mockito stubbing for filtered-out skills
- Add missing findBySkillIdAndStatus stub for published version lookup
- Update MeController test mocks to match new method signature (keyword, namespace params)
Frontend fixes:
- Fix TypeScript error: useMyNamespaces returns ManagedNamespace[] not PagedResponse
- Add type annotation for namespace map callback parameter
E2E test fix:
- Update URL regex to allow query parameters (returnTo from search page)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
* fix(tests): resolve test failures in PR #493
Backend:
- Remove unnecessary mock stubbings for skillId 2 and 3 in MySkillAppServiceTest.listMySkills_combinesKeywordNamespaceAndStatusFilters
- The test filters results to only return skill with id=1, so mocks for id 2 and 3 were never called, causing UnnecessaryStubbingException
Frontend:
- Add missing mocks for useLocation, useSearch, useMyNamespaces, and useDebounce in my-skills.test.ts
- MySkillsPage component uses these hooks but the test setup didn't provide mocks, causing 'No QueryClient set' and 'No export' errors
All 4 frontend tests now pass locally.
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
---------
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Vitest <4.1.0 allows arbitrary file read/execution when the UI server is
listening (GHSA-5xrq-8626-4rwp, severity: critical). Bumps vitest from
3.2.4 to 4.1.x, which also flows through to the bundled @vitest/* packages
in pnpm-lock.yaml.
Adjusts two tests for the stricter v4 mock contract: `new`-callable mocks
must be backed by a `function`/`class` implementation rather than an
arrow function (web/src/shared/lib/date-time.test.ts,
web/src/app/providers.test.ts).
Signed-off-by: dongmucat <1127093059@qq.com>
Use `namespace === 'global'` (without @ prefix) to match the actual
route parameter value. The previous check used '@global' which never
matched, causing anonymous users to be redirected to login even for
global PUBLIC skills.
Co-authored-by: dongmucat <1127093059qq.com>