Skip to content

Add UCSD skills marketplace catalog#15

Merged
dbalders merged 1 commit into
tritongptfrom
skills-marketplace-catalog
Jun 20, 2026
Merged

Add UCSD skills marketplace catalog#15
dbalders merged 1 commit into
tritongptfrom
skills-marketplace-catalog

Conversation

@dbalders

Copy link
Copy Markdown
Owner

Summary

  • Adds server/catalog contracts, RPC/IPC/local API plumbing, and OpenCode install/remove support for UCSD skills.
  • Adds a temporary Cloudflare-style static catalog under infra with bundled fallback catalog data.
  • Reworks Settings > Skills to show Recommended Skills, Community Skills, Add From Link, and Other OpenCode Skills, with installed catalog items staying in their original sections and switching to toggle/remove controls.
  • Adds guarded installs for HTTPS/loopback links, GitHub repo/tree/blob sources, size limits, symlink skipping, catalog bundle identity checks, and config rollback behavior.

Verification

  • Smoke-tested Settings > Skills in the worktree: removed/re-added a community catalog skill, installed/toggled/removed a link skill served from localhost, and confirmed UCSD OpenCode config path registration/unregistration.
  • RUN /Users/davidbalderston/Github/Citizen-Developer/t3code-skills-marketplace

Test Files 2 passed (2)
Tests 19 passed (19)
Start at 22:12:51
Duration 718ms (transform 347ms, setup 0ms, import 1.06s, tests 57ms, environment 0ms) (apps/server)

  • RUN /Users/davidbalderston/Github/Citizen-Developer/t3code-skills-marketplace

Test Files 1 passed (1)
Tests 19 passed (19)
Start at 22:12:52
Duration 1.16s (transform 371ms, setup 0ms, import 410ms, tests 625ms, environment 0ms) (apps/web)

  • ~/packages/contracts$ tsgo --noEmit ⊘ cache disabled
    ~/apps/marketing$ astro check ⊘ cache disabled

~/oxlint-plugin-t3code$ tsgo --noEmit ⊘ cache disabled

~/packages/effect-codex-app-server$ tsgo --noEmit ⊘ cache disabled
22:12:54 [WARN] [vite] warning: optimizeDeps.esbuildOptions option was specified by "astro:dev-toolbar" plugin. This option is deprecated, please use optimizeDeps.rolldownOptions instead.
22:12:54 [WARN] [vite] You or a plugin you are using have set optimizeDeps.esbuildOptions but this option is now deprecated. Vite now uses Rolldown to optimize the dependencies. Please use optimizeDeps.rolldownOptions instead.
22:12:54 [types] Generated 36ms
22:12:54 [check] Getting diagnostics for Astro files in /Users/davidbalderston/Github/Citizen-Developer/t3code-skills-marketplace/apps/marketing...
Result (10 files):

  • 0 errors
  • 0 warnings
  • 0 hints

~/packages/effect-acp$ tsgo --noEmit ⊘ cache disabled

~/packages/shared$ tsgo --noEmit ⊘ cache disabled

~/packages/client-runtime$ tsgo --noEmit ⊘ cache disabled

~/scripts$ tsgo --noEmit ⊘ cache disabled

~/packages/ssh$ tsgo --noEmit ⊘ cache disabled

~/packages/tailscale$ tsgo --noEmit ⊘ cache disabled

~/apps/web$ tsgo --noEmit ⊘ cache disabled

~/apps/mobile$ tsc --noEmit ⊘ cache disabled

~/infra/relay$ tsgo --noEmit ⊘ cache disabled

~/apps/desktop$ tsgo --noEmit ⊘ cache disabled

~/apps/server$ tsgo --noEmit ⊘ cache disabled


vp run: 0/15 cache hit (0%). (Run vp run --last-details for full details)

  • �[1m�[94mpass:�[39m�[0m All 1727 files are correctly formatted �[2m(787ms, 8 threads)�[0m
    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/CommandPalette.tsx:636:15]
    635 | valuePrefix: "project",
    636 | ,-> icon: (project) => (
    637 | | <ProjectFavicon
    638 | | environmentId={project.environmentId}
    639 | | cwd={project.cwd}
    640 | | className={ITEM_ICON_CLASS}
    641 | | />
    642 | -> ), 643 | runProject: openProjectFromSearch, ----
    help: Move this component definition out of the parent component OpenCommandPaletteDialog and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/CommandPalette.tsx:654:15]
    653 | shortcutCommand: "chat.new",
    654 | ,-> icon: (project) => (
    655 | | <ProjectFavicon
    656 | | environmentId={project.environmentId}
    657 | | cwd={project.cwd}
    658 | | className={ITEM_ICON_CLASS}
    659 | | />
    660 | -> ), 661 | runProject: async (project) => { ----
    help: Move this component definition out of the parent component OpenCommandPaletteDialog and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/mobile/src/features/review/ReviewSheet.tsx:224:24]
    223 | },
    224 | ,-> headerTitle: () => (
    225 | | <View style={{ alignItems: "center" }}>
    226 | | <NativeText
    227 | | numberOfLines={1}
    228 | | style={{
    229 | | fontFamily: "DMSans_700Bold",
    230 | | fontSize: 18,
    231 | | fontWeight: "900",
    232 | | color: headerForeground,
    233 | | letterSpacing: -0.4,
    234 | | }}
    235 | | >
    236 | | Files Changed
    237 | |
    238 | | <View
    239 | | style={{
    240 | | flexDirection: "row",
    241 | | alignItems: "center",
    242 | | justifyContent: "center",
    243 | | gap: 6,
    244 | | flexWrap: "wrap",
    245 | | }}
    246 | | >
    247 | | {headerDiffSummary.additions && headerDiffSummary.deletions ? (
    248 | | <>
    249 | | <NativeText
    250 | | style={{
    251 | | fontFamily: "DMSans_700Bold",
    252 | | fontSize: 12,
    253 | | fontWeight: "700",
    254 | | color: "#16a34a",
    255 | | }}
    256 | | >
    257 | | {headerDiffSummary.additions}
    258 | |
    259 | | <NativeText
    260 | | style={{
    261 | | fontFamily: "DMSans_700Bold",
    262 | | fontSize: 12,
    263 | | fontWeight: "700",
    264 | | color: "#e11d48",
    265 | | }}
    266 | | >
    267 | | {headerDiffSummary.deletions}
    268 | |
    269 | | {pendingReviewCommentCount > 0 ? (
    270 | | <NativeText
    271 | | style={{
    272 | | fontFamily: "DMSans_700Bold",
    273 | | fontSize: 12,
    274 | | fontWeight: "700",
    275 | | color: "#b45309",
    276 | | }}
    277 | | >
    278 | | {pendingReviewCommentCount} pending
    279 | |
    280 | | ) : null}
    281 | | </>
    282 | | ) : (
    283 | | <View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
    284 | | <NativeText
    285 | | numberOfLines={1}
    286 | | style={{
    287 | | fontFamily: "DMSans_700Bold",
    288 | | fontSize: 12,
    289 | | fontWeight: "700",
    290 | | color: headerMuted,
    291 | | }}
    292 | | >
    293 | | {selectedSection?.title ?? "Review changes"}
    294 | |
    295 | | {pendingReviewCommentCount > 0 ? (
    296 | | <NativeText
    297 | | style={{
    298 | | fontFamily: "DMSans_700Bold",
    299 | | fontSize: 12,
    300 | | fontWeight: "700",
    301 | | color: "#b45309",
    302 | | }}
    303 | | >
    304 | | {pendingReviewCommentCount} pending
    305 | |
    306 | | ) : null}
    307 | |
    308 | | )}
    309 | |
    310 | |
    311 | -> ), 312 | }} ----
    help: Move this component definition out of the parent component ReviewSheet and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1231:8]
    1230 | () => ({
    1231 | ,-> p({ node: _node, children, ...props }) {
    1232 | | return <p {...props}>{renderSkillInlineMarkdownChildren(children, skills)}

    ;
    1233 | -> }, 1234 | li({ node, children, ...props }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1234:9]
    1233 | },
    1234 | ,-> li({ node, children, ...props }) {
    1235 | | const listItemStart = node?.position?.start.offset;
    1236 | | const markerOffset =
    1237 | | typeof listItemStart === "number" ? findTaskListMarkerOffset(text, listItemStart) : null;
    1238 | | return (
    1239 | | <li {...props} data-task-marker-offset={markerOffset ?? undefined}>
    1240 | | {renderSkillInlineMarkdownChildren(children, skills)}
    1241 | |


  • 1242 | | );
    1243 | -> }, 1244 | input({ node: _node, type, checked, disabled: _disabled, ...props }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1244:12]
    1243 | },
    1244 | ,-> input({ node: _node, type, checked, disabled: _disabled, ...props }) {
    1245 | | if (type !== "checkbox" || !onTaskListChange) {
    1246 | | return (
    1247 | | <input
    1248 | | {...props}
    1249 | | type={type}
    1250 | | checked={checked}
    1251 | | disabled={_disabled}
    1252 | | readOnly={type === "checkbox"}
    1253 | | />
    1254 | | );
    1255 | | }
    1256 | | return (
    1257 | | <input
    1258 | | {...props}
    1259 | | type="checkbox"
    1260 | | name="markdown-task"
    1261 | | aria-label="Toggle task"
    1262 | | checked={checked}
    1263 | | onChange={(event) => {
    1264 | | const markerOffset = Number(
    1265 | | event.currentTarget.closest("li")?.dataset.taskMarkerOffset,
    1266 | | );
    1267 | | if (!Number.isSafeInteger(markerOffset)) return;
    1268 | | onTaskListChange({ markerOffset, checked: event.currentTarget.checked });
    1269 | | }}
    1270 | | />
    1271 | | );
    1272 | -> }, 1273 | a({ node, href, children, ...props }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1273:8]
    1272 | },
    1273 | ,-> a({ node, href, children, ...props }) {
    1274 | | const normalizedHref = href ? normalizeMarkdownLinkHrefKey(href) : "";
    1275 | | const fileLinkMeta = normalizedHref ? markdownFileLinkMetaByHref.get(normalizedHref) : null;
    1276 | | if (!fileLinkMeta) {
    1277 | | const faviconHost = resolveExternalLinkHost(href);
    1278 | | const isSameDocumentLink = href?.startsWith("#") ?? false;
    1279 | | const onClick = props.onClick;
    1280 | | const link = (
    1281 | | <MarkdownExternalLink
    1282 | | {...props}
    1283 | | href={href ?? ""}
    1284 | | threadRef={faviconHost && isPreviewSupportedInRuntime() ? threadRef : undefined}
    1285 | | target={isSameDocumentLink ? undefined : "_blank"}
    1286 | | rel={isSameDocumentLink ? undefined : "noopener noreferrer"}
    1287 | | onClick={(event) => {
    1288 | | onClick?.(event);
    1289 | | if (isSameDocumentLink && href) {
    1290 | | handleMarkdownFragmentClick(event, href);
    1291 | | }
    1292 | | }}
    1293 | | >
    1294 | | {faviconHost ? (
    1295 | |
    1296 | | {children}
    1297 | |
    1298 | | ) : (
    1299 | | children
    1300 | | )}
    1301 | |
    1302 | | );
    1303 | | if (!faviconHost || !href) {
    1304 | | return link;
    1305 | | }
    1306 | | return (
    1307 | |
    1308 | |
    1309 | | <TooltipPopup
    1310 | | side="top"
    1311 | | className="max-w-[min(36rem,calc(100vw-2rem))] whitespace-normal leading-tight wrap-anywhere"
    1312 | | >
    1313 | | {href}
    1314 | |
    1315 | |
    1316 | | );
    1317 | | }
    1318 | |
    1319 | | const parentSuffix = fileLinkParentSuffixByPath.get(fileLinkMeta.filePath);
    1320 | | const labelParts = [fileLinkMeta.basename];
    1321 | | if (typeof parentSuffix === "string" && parentSuffix.length > 0) {
    1322 | | labelParts.push(parentSuffix);
    1323 | | }
    1324 | | if (fileLinkMeta.line) {
    1325 | | labelParts.push(
    1326 | | L${fileLinkMeta.line}${fileLinkMeta.column ? :C${fileLinkMeta.column} : ""},
    1327 | | );
    1328 | | }
    1329 | |
    1330 | | return (
    1331 | | <MarkdownFileLink
    1332 | | href={fileLinkMeta.targetPath}
    1333 | | targetPath={fileLinkMeta.targetPath}
    1334 | | iconPath={fileLinkMeta.filePath}
    1335 | | displayPath={fileLinkMeta.displayPath}
    1336 | | workspaceRelativePath={fileLinkMeta.workspaceRelativePath}
    1337 | | line={fileLinkMeta.line}
    1338 | | label={labelParts.join(" · ")}
    1339 | | copyMarkdown={[${fileLinkMeta.basename}](${normalizedHref})}
    1340 | | theme={resolvedTheme}
    1341 | | threadRef={threadRef}
    1342 | | className={props.className}
    1343 | | />
    1344 | | );
    1345 | -> }, 1346 | table({ node: _node, ...props }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1346:12]
    1345 | },
    1346 | ,-> table({ node: _node, ...props }) {
    1347 | | return <MarkdownTable {...props} />;
    1348 | -> }, 1349 | details({ node: _node, children, open: detailsOpen }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1349:14]
    1348 | },
    1349 | ,-> details({ node: _node, children, open: detailsOpen }) {
    1350 | | return {children};
    1351 | -> }, 1352 | pre({ node, children, ...props }) { ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/web/src/components/ChatMarkdown.tsx:1352:10]
    1351 | },
    1352 | ,-> pre({ node, children, ...props }) {
    1353 | | const codeBlock = extractCodeBlock(children);
    1354 | | if (!codeBlock) {
    1355 | | return <pre {...props}>{children};
    1356 | | }
    1357 | |
    1358 | | const language = extractFenceLanguage(codeBlock.className);
    1359 | | const fenceTitle = extractFenceTitle(extractPreCodeMeta(node));
    1360 | | return (
    1361 | | <MarkdownCodeBlock
    1362 | | code={codeBlock.code}
    1363 | | language={language}
    1364 | | fenceTitle={fenceTitle}
    1365 | | theme={resolvedTheme}
    1366 | | >
    1367 | | <CodeHighlightErrorBoundary fallback={<pre {...props}>{children}}>
    1368 | | <Suspense fallback={<pre {...props}>{children}}>
    1369 | | <SuspenseShikiCodeBlock
    1370 | | className={codeBlock.className}
    1371 | | code={codeBlock.code}
    1372 | | themeName={diffThemeName}
    1373 | | isStreaming={isStreaming}
    1374 | | />
    1375 | |
    1376 | |
    1377 | |
    1378 | | );
    1379 | -> }, 1380 | }), ----
    help: Move this component definition out of the parent component ChatMarkdown and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/mobile/src/features/threads/ThreadRouteScreen.tsx:299:24]
    298 | headerBackTitle: "",
    299 | ,-> headerTitle: () => (
    300 | | <Pressable
    301 | | style={{ alignItems: "center", maxWidth: 200 }}
    302 | | onLongPress={() => {
    303 | | // TODO: trigger rename modal
    304 | | }}
    305 | | >
    306 | | <RNText
    307 | | numberOfLines={1}
    308 | | style={{
    309 | | fontFamily: "DMSans_700Bold",
    310 | | fontSize: 18,
    311 | | fontWeight: "900",
    312 | | color: foregroundColor,
    313 | | letterSpacing: -0.4,
    314 | | }}
    315 | | >
    316 | | {selectedThreadDetail.title}
    317 | |
    318 | | <RNText
    319 | | numberOfLines={1}
    320 | | style={{
    321 | | fontFamily: "DMSans_700Bold",
    322 | | fontSize: 12,
    323 | | fontWeight: "700",
    324 | | color: secondaryFg,
    325 | | letterSpacing: 0.3,
    326 | | }}
    327 | | >
    328 | | {headerSubtitle}
    329 | |
    330 | |
    331 | -> ), 332 | }} ----
    help: Move this component definition out of the parent component ThreadRouteScreen and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

    ! react(no-unstable-nested-components): Do not define components during render.
    ,-[apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx:947:24]
    946 | title: "",
    947 | ,-> headerTitle: () => (
    948 | | <View
    949 | | style={{
    950 | | alignItems: "center",
    951 | | gap: 1,
    952 | | maxWidth: 240,
    953 | | }}
    954 | | >
    955 | | <RNText
    956 | | numberOfLines={1}
    957 | | style={{
    958 | | color: terminalTheme.foreground,
    959 | | fontFamily: "DMSans_700Bold",
    960 | | fontSize: 13,
    961 | | lineHeight: 16,
    962 | | }}
    963 | | >
    964 | | {headerTitle.topLine}
    965 | |
    966 | | <RNText
    967 | | ellipsizeMode="middle"
    968 | | numberOfLines={1}
    969 | | style={{
    970 | | color: terminalTheme.mutedForeground,
    971 | | fontFamily: "Menlo",
    972 | | fontSize: 11,
    973 | | lineHeight: 14,
    974 | | }}
    975 | | >
    976 | | {headerTitle.bottomLine}
    977 | |
    978 | |
    979 | -> ), 980 | }} ----
    help: Move this component definition out of the parent component ThreadTerminalRouteScreen and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.

Found 0 errors and 12 warnings in 1620 files (1.2s, 8 threads) (passes with existing nested-component warnings outside this change)

  • autoreview target: local
    branch: skills-marketplace-catalog
    engine: codex
    model: gpt-5.5
    tools: on
    web_search: on
    bundle: 7982 chars
    autoreview clean: no accepted/actionable findings reported
    overall: patch is correct (0.97)
    The change bundle only adds a goal/progress documentation file under docs/goals and does not modify executable code, configuration, tests, or security-sensitive behavior. I found no actionable defects introduced by this change. clean

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jun 20, 2026
@dbalders
dbalders changed the base branch from feature/scheduled-automations to tritongpt June 20, 2026 05:17
@dbalders
dbalders merged commit fd3ee90 into tritongpt Jun 20, 2026
5 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant