Repository navigation
feat: install skills from a source, view their files, and let agents change Tools #17691
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
juliusmarminge
wants to merge
37
commits into
main
Choose a base branch
from
t3code/skills-installer
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+11,127
−160
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
bf7dcb0
feat: manage skills and MCP servers in Settings → Tools
juliusmarminge ac5fcd3
fix(server): pass skill switches to Claude's query
juliusmarminge 280b497
fix: address review findings on Settings → Tools
juliusmarminge b41803b
fix(server): read the host platform through its injected reference
juliusmarminge ff2c815
fix: keep both secrets when a rename swaps two names, and group repo …
juliusmarminge e84b83f
fix(server): ask before Claude uses a Settings → Tools server in mode…
juliusmarminge a36b333
feat(server): install skills from a source with the bundled skills CLI
juliusmarminge 521fd05
feat: add skills from a source, view their files, and let agents chan…
juliusmarminge 3672e0d
fix: address review findings on the skills installer
juliusmarminge be96f89
fix: run skill changes one at a time, and keep the environment's spel…
juliusmarminge a54e27f
fix: rescan listed projects after a global skill change, and handle a…
juliusmarminge 48f0c33
fix: scan one folder's agents in turn, and ignore inherited server names
juliusmarminge 2381792
feat(web): Skills list and skill page in the style of #17513
juliusmarminge d22565d
fix(server): install and track skills by the skills CLI's own name
juliusmarminge 50f0ca5
fix: cap a skill install at 200 skills, and read large installer resu…
juliusmarminge 46468e1
fix(server): flush the skills installer's output by making stdout blo…
juliusmarminge b73344e
fix(web): name an open skill in the settings header, not above the page
juliusmarminge 736a2da
fix(web): show project skills only for the project picked, and line u…
juliusmarminge e471cc6
fix(web): mark skill packs with a heading band instead of an indent
juliusmarminge 7ece3d1
fix(web): put the Tools tabs on one row with each tab's controls
juliusmarminge f2250bb
fix(web): flag only skills that share a name, not ones some agents skip
juliusmarminge 32986bb
fix(web): pick skills to add from dense rows, with select all and a f…
juliusmarminge 7033214
fix(web): show a skill's whole description when its line is cut off
juliusmarminge 7f080a0
feat: remove any skill in the agents' own skill folders
juliusmarminge 8e056bf
fix(web): copy a skill's path from a button beside it
juliusmarminge 8d3c843
fix(web): show a skill's Update and Remove as buttons, not a menu
juliusmarminge 72d7a35
docs: a skill's page shows its files, there is no View files menu item
juliusmarminge 8f87d7a
fix(web): list T3 Code's own MCP server, always on
juliusmarminge 6cd39f9
feat: show which environments have each skill, and copy one to the rest
juliusmarminge d5ca1de
feat(server): list an MCP server's tools from Settings → Tools
juliusmarminge 9c923c2
feat(web): open an MCP server in Settings → Tools to see its tools
juliusmarminge 1ca79f0
chore(web): drop an unused import left by combining the Tools changes
juliusmarminge 30399ae
chore: fit the Tools changes to current main
juliusmarminge fcb20d8
fix(web): Settings → Tools shows a project's skills again on current …
juliusmarminge ba6a483
feat: tool presets turn a set of skills and MCP servers on or off for…
juliusmarminge dbbcb95
refactor(web): tool presets live in the composer; Settings holds defa…
juliusmarminge 819bd30
feat(web): tool presets save on every connected environment
juliusmarminge File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import * as Effect from "effect/Effect"; | ||
| import { Argument, Command } from "effect/cli"; | ||
|
|
||
| /** | ||
| * `t3 skills-cli <args…>` runs the bundled `skills` CLI (vercel-labs/skills, what | ||
| * `npx skills` runs), so installs need no Node or npm of their own. The server spawns | ||
| * it as a child, which keeps its `process.exit` and prompts out of the server. | ||
| */ | ||
| export async function runSkillsCli(args: ReadonlyArray<string>): Promise<void> { | ||
| // The CLI calls `process.exit` right after printing its `--json` result, and POSIX | ||
| // pipe writes are async, so a large result was cut at 64 KiB. A blocking pipe | ||
| // finishes each write first. Do not defer exit instead: the CLI relies on it. | ||
| const stdout = process.stdout as typeof process.stdout & { | ||
| readonly _handle?: { readonly setBlocking?: (blocking: boolean) => void }; | ||
| }; | ||
| stdout._handle?.setBlocking?.(true); | ||
| // The CLI reads its command from argv[2] onward. | ||
| process.argv = [process.argv[0] ?? "node", "skills", ...args]; | ||
| await import("skills/dist/cli.mjs"); | ||
| } | ||
|
|
||
| /** Real invocations dispatch through the bin.ts fast path before the CLI graph loads. */ | ||
| export const skillsCliCommand = Command.make("skills-cli", { | ||
| args: Argument.String("args").pipe(Argument.variadic()), | ||
| }).pipe( | ||
| Command.withDescription("Run the bundled skills installer."), | ||
| Command.unlisted, | ||
| Command.withHandler(({ args }) => Effect.promise(() => runSkillsCli(args))), | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { | ||
| ProjectId, | ||
| ResolvedMcpServer, | ||
| ServerSettings, | ||
| ThreadToolPresets, | ||
| } from "@t3tools/contracts"; | ||
| import { applyThreadToolPresets } from "@t3tools/shared/agentTools"; | ||
| import { resolveProjectSettings } from "@t3tools/shared/projectSettings"; | ||
|
|
||
| import type { McpProviderSessionTools } from "@t3tools/provider-core/server/mcpSession"; | ||
|
|
||
| /** | ||
| * A thread's tools from secret-materialized settings: project overrides, then | ||
| * the thread's presets, disabled servers dropped. The fingerprint covers the | ||
| * full config (a rotated secret counts) and is only compared, never sent. | ||
| */ | ||
| export function resolveAgentTools( | ||
| settings: ServerSettings, | ||
| projectId: ProjectId | null, | ||
| threadPresets?: ThreadToolPresets, | ||
| ): McpProviderSessionTools { | ||
| const effective = applyThreadToolPresets( | ||
| resolveProjectSettings(settings, projectId).settings, | ||
| settings.toolPresets, | ||
| threadPresets, | ||
| ); | ||
| const servers: ResolvedMcpServer[] = Object.entries(effective.mcpServers) | ||
| .filter(([, server]) => server.enabled) | ||
| .map(([name, server]) => ({ name, transport: server.transport })) | ||
| .toSorted((left, right) => left.name.localeCompare(right.name)); | ||
| const disabledSkills = [...new Set(effective.disabledSkills)].toSorted(); | ||
| const fingerprint = | ||
| servers.length === 0 && disabledSkills.length === 0 | ||
| ? "" | ||
| : JSON.stringify({ servers, disabledSkills }); | ||
| return { servers, disabledSkills, fingerprint }; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: pingdotgg/t3code
Length of output: 4930
Script executed:
Repository: pingdotgg/t3code
Length of output: 17050
Script executed:
Repository: pingdotgg/t3code
Length of output: 25375
Script executed:
Repository: pingdotgg/t3code
Length of output: 21607
Script executed:
Repository: pingdotgg/t3code
Length of output: 4471
Prevent stale project MCP entries from overwriting newer transports.
A
settings:writeclient can pass authorization with a previously stored transport, then write that stale project entry after aproviders:manageclient changes the transport. This can lose the newer provider-managed update. It does not cross the privilege boundary because the stale transport was already authorized for that client. Compare and write against the same locked snapshot, or reject the write when the stored entry changed.