Skip to content

Merge: promote staging → main — nested skill-repo import + shareAuth consolidation#162

Merged
DIodide merged 3 commits into
mainfrom
staging
Jul 4, 2026
Merged

Merge: promote staging → main — nested skill-repo import + shareAuth consolidation#162
DIodide merged 3 commits into
mainfrom
staging

Conversation

@DIodide

@DIodide DIodide commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Promotes staging to main. Carries:

All staging checks are green and both convex+web deployed cleanly to staging. On merge, the prod frontend (Convex + Cloudflare) and backend deploy.

DIodide and others added 3 commits July 3, 2026 22:51
…uthCore (#157)

Third deepening from the improve-codebase-architecture skill (design-it-twice →
Design #2). The grant-based access model was mirrored across shares.ts and
harnessShares.ts (two ~700-line files) — grantForToken, assertOwned*,
resolveRole, activeGrantForCaller all near-identical — and the mirror had
already rotted once (the sharedLocked cleanup fix landed on only one side).

New shareAuthCore.ts owns the ONE security machine: empty-token→null guard,
isActiveGrant (single impl) on the token lookup AND the per-user scan, opaque
"Not found" (never leak existence), owner-wins-first, the cross-entity fk gate,
editor-short-circuit / viewer-floor / max-role-wins, the truthy-userId guard
(an anonymous caller rides the token path only — never matches a
grantedToUserId===undefined row), and a required-projection sharedHeader (an
unredacted egress is unrepresentable). Each entity wires it with concretely-
typed closures via makeShareAuth(descriptor) — zero casts on the fk gate.

Entity POLICY stays in the wrappers: publicMessage / publicHarnessProjection
redaction, authorizeConversationWrite (owner|editor) vs editSharedHarness
(editor-only + the sharedLocked lock + field allowlist), mint/rotate/list
payloads, the harness lock-cleanup tail. Exported signatures unchanged
(resolveConversationRole / authorizeConversationWrite / isActiveGrant re-
exported from shares.ts) so messages.ts and other importers need zero edits.

Behaviour-preserving: the 48 existing share/role tests (shares 32 +
harnessShares 16) pass with ZERO expectation changes. New shareAuthCore.test.ts
(12 cases) pins the invariants directly, incl. the anonymous-privilege-
escalation negative and the cross-entity gate. convex 231 passed, tsc + biome
clean.

HOLD merge until AFTER v1.0 is cut (live authorization code — keep the release
clean; a human should read the final diff).
…d .env

The gateway's SKILL.md backfill (skill_content.py) calls the GitHub API
unauthenticated from one EC2 IP — 60 req/hr shared across every user. Write
the SKILLS_GITHUB_TOKEN secret into the host .env on deploy (replace-on-
deploy, so rotating the secret rotates the host; skipped when unset). The
Convex-side skill imports get the same token via the Convex env directly.
)

Importing a repo like mattpocock/skills failed with "no skills found": the repo
nests skills as skills/<category>/<id>/SKILL.md, but discovery only matched a
fixed set of top-level bases (skills, .claude/skills, .agents/skills) exactly,
so anything one folder deeper was invisible. Content-fetching already resolved
nested skills by leaf-dir name (Convex viewer + gateway backfill both do), so
only discovery was broken.

Backend (convex/skills.ts):
- discoverRepoSkills finds every SKILL.md at ANY depth in one git/trees call,
  derives a display "category" by stripping a recognized skills-root prefix
  (skills/.claude/.agents/.github), and skips node_modules. Leaf id must be
  unique within the repo (it's the fetch key) — first wins.
- New listRepoSkills action: discovers + fetches + caches each SKILL.md (so
  previews are instant) and returns them with category + description + the
  repo's AGENTS.md/CLAUDE.md, for a choose-what-you-want flow.
- importSkillRepo (curated templates, add-all) now shares the same discovery,
  so it benefits from nested support too. A repo that resolves but has no
  skills now reports "no skills found", not "repo not found".

Frontend:
- New RepoImportDialog: a two-pane browse-and-select modal — left is the
  discovered skills grouped by category with per-skill / per-group / select-all
  checkboxes and an added-already state; right is a live SKILL.md preview
  (rendered markdown, served from the browse cache so it's instant). Footer
  lets you also pull in AGENTS.md / CLAUDE.md. This brings repo import to
  parity with `npx skills add` (pick individual skills, see their contents).
- The pack editor's "Import a GitHub repo" now opens this dialog (Browse)
  instead of a blind "Import all".

Tests: convex/skills.test.ts stubs a nested (mattpocock-shaped) tree and pins
discovery-at-depth, category derivation, node_modules exclusion, URL
normalization, caching, and the no-skills vs not-found messages. convex 239
passed; web build + biome clean.
@DIodide
DIodide merged commit c5ea3d8 into main Jul 4, 2026
8 checks passed
Sign up for free to 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.

1 participant