mirror of
https://github.com/TheRealOwenRees/chess-endgame-trainer.git
synced 2026-09-19 11:03:52 +00:00
allow graft mcp to be used within opencode
This commit is contained in:
@@ -35,3 +35,6 @@ chesstrainer-*.tar
|
|||||||
npm-debug.log
|
npm-debug.log
|
||||||
/assets/node_modules/
|
/assets/node_modules/
|
||||||
|
|
||||||
|
|
||||||
|
# graft's local graph cache — regenerable, not committed (run `graft build`).
|
||||||
|
graft/
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# graft's cards are gitignored but should stay greppable: ripgrep reads
|
||||||
|
# .ignore before .gitignore, so this re-admits the tree to search only.
|
||||||
|
!graft/
|
||||||
|
graft/.cache/
|
||||||
|
graft/.graph/
|
||||||
@@ -1,5 +1,49 @@
|
|||||||
This is a web application written using the Phoenix web framework.
|
This is a web application written using the Phoenix web framework.
|
||||||
|
|
||||||
|
<!-- graft:start -->
|
||||||
|
|
||||||
|
## Graft — repo context graph
|
||||||
|
|
||||||
|
This repo is indexed in `graft/`: small linked markdown nodes that explain each
|
||||||
|
system and carry exact file:line spans, kept in sync with the code through git.
|
||||||
|
|
||||||
|
For ANY task here — understanding how something works, finding where code lives,
|
||||||
|
or scoping a change — get context from the graph before grepping or opening
|
||||||
|
source files. Re-ask freely (it's cheap) and reuse literal identifiers you
|
||||||
|
already have (symbol, error string, file name) as the query. New to this repo?
|
||||||
|
Run `graft map` first — a token-budgeted orientation (dir clusters, hubs,
|
||||||
|
hotspots), no LLM, no key.
|
||||||
|
|
||||||
|
- Run `graft ask "<your question>" --source` → ranked nodes with the relevant
|
||||||
|
code spans inlined (each hit's ≤8-line crux by default; `--full` for whole
|
||||||
|
definitions when the crux isn't enough). Match the tool to the task shape:
|
||||||
|
for understanding or editing, the top node IS the answer — cite its
|
||||||
|
`covers:` file:line spans and edit straight from `--source`. For
|
||||||
|
exhaustive tasks ("every occurrence / every caller of this pattern"), ranked
|
||||||
|
results are top-N, not complete — run `graft grep "<literal>"` instead
|
||||||
|
(exhaustive over indexed files, grouped by enclosing symbol), falling back
|
||||||
|
to raw `grep -rn` only for unindexed files.
|
||||||
|
- `graft skeleton <file>` → every definition's signature + span, ~10× cheaper
|
||||||
|
than reading the file; use it to skim an API surface.
|
||||||
|
- `graft callers <symbol>` gives precomputed, exact edges — who calls this.
|
||||||
|
Add `--direction out` for what it calls, or `--depth N` to walk
|
||||||
|
transitively for the full blast radius. For structural questions, skip
|
||||||
|
ranking and use this directly.
|
||||||
|
- Or browse: `graft/INDEX.md` lists every node; follow the links.
|
||||||
|
- Monorepos and folders of multiple repos rank fairly across sub-projects —
|
||||||
|
hits carry `[scope/]` labels naming which one they're from. Narrow with
|
||||||
|
`graft ask "<task>" --in <scope>/` once you know where you're working.
|
||||||
|
|
||||||
|
If a returned span is truncated ("+N more lines"), open the file at that exact
|
||||||
|
range before finalizing. Only open source files when a node genuinely lacks a
|
||||||
|
needed detail, and then at the exact file:line the node points to — never
|
||||||
|
re-read whole files.
|
||||||
|
|
||||||
|
After big code changes, refresh the graph with `graft build` (deterministic,
|
||||||
|
no API key, $0).
|
||||||
|
|
||||||
|
<!-- graft:end -->
|
||||||
|
|
||||||
## Project guidelines
|
## Project guidelines
|
||||||
|
|
||||||
- Use `mix precommit` alias when you are done with all changes and fix any pending issues
|
- Use `mix precommit` alias when you are done with all changes and fix any pending issues
|
||||||
@@ -16,7 +60,7 @@ This is a web application written using the Phoenix web framework.
|
|||||||
- Out of the box, `core_components.ex` imports an `<.icon name="hero-x-mark" class="w-5 h-5"/>` component for hero icons. **Always** use the `<.icon>` component for icons, **never** use `Heroicons` modules or similar
|
- Out of the box, `core_components.ex` imports an `<.icon name="hero-x-mark" class="w-5 h-5"/>` component for hero icons. **Always** use the `<.icon>` component for icons, **never** use `Heroicons` modules or similar
|
||||||
- **Always** use the imported `<.input>` component for form inputs from `core_components.ex` when available. `<.input>` is imported and using it will save steps and prevent errors
|
- **Always** use the imported `<.input>` component for form inputs from `core_components.ex` when available. `<.input>` is imported and using it will save steps and prevent errors
|
||||||
- If you override the default input classes (`<.input class="myclass px-2 py-1 rounded-lg">)`) class with your own values, no default classes are inherited, so your
|
- If you override the default input classes (`<.input class="myclass px-2 py-1 rounded-lg">)`) class with your own values, no default classes are inherited, so your
|
||||||
custom classes must fully style the input
|
custom classes must fully style the input
|
||||||
|
|
||||||
### JS and CSS guidelines
|
### JS and CSS guidelines
|
||||||
|
|
||||||
@@ -43,10 +87,10 @@ custom classes must fully style the input
|
|||||||
- Ensure **clean typography, spacing, and layout balance** for a refined, premium look
|
- Ensure **clean typography, spacing, and layout balance** for a refined, premium look
|
||||||
- Focus on **delightful details** like hover effects, loading states, and smooth page transitions
|
- Focus on **delightful details** like hover effects, loading states, and smooth page transitions
|
||||||
|
|
||||||
|
|
||||||
<!-- usage-rules-start -->
|
<!-- usage-rules-start -->
|
||||||
|
|
||||||
<!-- phoenix:elixir-start -->
|
<!-- phoenix:elixir-start -->
|
||||||
|
|
||||||
## Elixir guidelines
|
## Elixir guidelines
|
||||||
|
|
||||||
- Elixir lists **do not support index based access via the access syntax**
|
- Elixir lists **do not support index based access via the access syntax**
|
||||||
@@ -64,7 +108,7 @@ custom classes must fully style the input
|
|||||||
Enum.at(mylist, i)
|
Enum.at(mylist, i)
|
||||||
|
|
||||||
- Elixir variables are immutable, but can be rebound, so for block expressions like `if`, `case`, `cond`, etc
|
- Elixir variables are immutable, but can be rebound, so for block expressions like `if`, `case`, `cond`, etc
|
||||||
you *must* bind the result of the expression to a variable if you want to use it and you CANNOT rebind the result inside the expression, ie:
|
you _must_ bind the result of the expression to a variable if you want to use it and you CANNOT rebind the result inside the expression, ie:
|
||||||
|
|
||||||
# INVALID: we are rebinding inside the `if` and the result never gets assigned
|
# INVALID: we are rebinding inside the `if` and the result never gets assigned
|
||||||
if connected?(socket) do
|
if connected?(socket) do
|
||||||
@@ -97,13 +141,14 @@ custom classes must fully style the input
|
|||||||
- **Avoid** `Process.sleep/1` and `Process.alive?/1` in tests
|
- **Avoid** `Process.sleep/1` and `Process.alive?/1` in tests
|
||||||
- Instead of sleeping to wait for a process to finish, **always** use `Process.monitor/1` and assert on the DOWN message:
|
- Instead of sleeping to wait for a process to finish, **always** use `Process.monitor/1` and assert on the DOWN message:
|
||||||
|
|
||||||
ref = Process.monitor(pid)
|
ref = Process.monitor(pid)
|
||||||
assert_receive {:DOWN, ^ref, :process, ^pid, :normal}
|
assert_receive {:DOWN, ^ref, :process, ^pid, :normal}
|
||||||
|
|
||||||
- Instead of sleeping to synchronize before the next call, **always** use `_ = :sys.get_state/1` to ensure the process has handled prior messages
|
- Instead of sleeping to synchronize before the next call, **always** use `_ = :sys.get_state/1` to ensure the process has handled prior messages
|
||||||
<!-- phoenix:elixir-end -->
|
<!-- phoenix:elixir-end -->
|
||||||
|
|
||||||
<!-- phoenix:phoenix-start -->
|
<!-- phoenix:phoenix-start -->
|
||||||
|
|
||||||
## Phoenix guidelines
|
## Phoenix guidelines
|
||||||
|
|
||||||
- Remember Phoenix router `scope` blocks include an optional alias which is prefixed for all routes within the scope. **Always** be mindful of this when creating routes within a scope to avoid duplicate module prefixes.
|
- Remember Phoenix router `scope` blocks include an optional alias which is prefixed for all routes within the scope. **Always** be mindful of this when creating routes within a scope to avoid duplicate module prefixes.
|
||||||
@@ -122,6 +167,7 @@ custom classes must fully style the input
|
|||||||
<!-- phoenix:phoenix-end -->
|
<!-- phoenix:phoenix-end -->
|
||||||
|
|
||||||
<!-- phoenix:ecto-start -->
|
<!-- phoenix:ecto-start -->
|
||||||
|
|
||||||
## Ecto Guidelines
|
## Ecto Guidelines
|
||||||
|
|
||||||
- **Always** preload Ecto associations in queries when they'll be accessed in templates, ie a message that needs to reference the `message.user.email`
|
- **Always** preload Ecto associations in queries when they'll be accessed in templates, ie a message that needs to reference the `message.user.email`
|
||||||
@@ -134,6 +180,7 @@ custom classes must fully style the input
|
|||||||
<!-- phoenix:ecto-end -->
|
<!-- phoenix:ecto-end -->
|
||||||
|
|
||||||
<!-- phoenix:html-start -->
|
<!-- phoenix:html-start -->
|
||||||
|
|
||||||
## Phoenix HTML guidelines
|
## Phoenix HTML guidelines
|
||||||
|
|
||||||
- Phoenix templates **always** use `~H` or .html.heex files (known as HEEx), **never** use `~E`
|
- Phoenix templates **always** use `~H` or .html.heex files (known as HEEx), **never** use `~E`
|
||||||
@@ -163,7 +210,7 @@ custom classes must fully style the input
|
|||||||
...
|
...
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
- HEEx require special tag annotation if you want to insert literal curly's like `{` or `}`. If you want to show a textual code snippet on the page in a `<pre>` or `<code>` block you *must* annotate the parent tag with `phx-no-curly-interpolation`:
|
- HEEx require special tag annotation if you want to insert literal curly's like `{` or `}`. If you want to show a textual code snippet on the page in a `<pre>` or `<code>` block you _must_ annotate the parent tag with `phx-no-curly-interpolation`:
|
||||||
|
|
||||||
<code phx-no-curly-interpolation>
|
<code phx-no-curly-interpolation>
|
||||||
let obj = {key: "val"}
|
let obj = {key: "val"}
|
||||||
@@ -196,26 +243,28 @@ custom classes must fully style the input
|
|||||||
|
|
||||||
**Always** do this:
|
**Always** do this:
|
||||||
|
|
||||||
<div id={@id}>
|
<div id={@id}>
|
||||||
{@my_assign}
|
{@my_assign}
|
||||||
<%= if @some_block_condition do %>
|
<%= if @some_block_condition do %>
|
||||||
{@another_assign}
|
{@another_assign}
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
and **Never** do this – the program will terminate with a syntax error:
|
and **Never** do this – the program will terminate with a syntax error:
|
||||||
|
|
||||||
<%!-- THIS IS INVALID NEVER EVER DO THIS --%>
|
<%!-- THIS IS INVALID NEVER EVER DO THIS --%>
|
||||||
<div id="<%= @invalid_interpolation %>">
|
<div id="<%= @invalid_interpolation %>">
|
||||||
{if @invalid_block_construct do}
|
{if @invalid_block_construct do}
|
||||||
{end}
|
{end}
|
||||||
</div>
|
</div>
|
||||||
<!-- phoenix:html-end -->
|
|
||||||
|
<!-- phoenix:html-end -->
|
||||||
|
|
||||||
<!-- phoenix:liveview-start -->
|
<!-- phoenix:liveview-start -->
|
||||||
|
|
||||||
## Phoenix LiveView guidelines
|
## Phoenix LiveView guidelines
|
||||||
|
|
||||||
- **Never** use the deprecated `live_redirect` and `live_patch` functions, instead **always** use the `<.link navigate={href}>` and `<.link patch={href}>` in templates, and `push_navigate` and `push_patch` functions LiveViews
|
- **Never** use the deprecated `live_redirect` and `live_patch` functions, instead **always** use the `<.link navigate={href}>` and `<.link patch={href}>` in templates, and `push_navigate` and `push_patch` functions LiveViews
|
||||||
- **Avoid LiveComponent's** unless you have a strong, specific need for them
|
- **Avoid LiveComponent's** unless you have a strong, specific need for them
|
||||||
- LiveViews should be named like `AppWeb.WeatherLive`, with a `Live` suffix. When you go to add LiveView routes to the router, the default `:browser` scope is **already aliased** with the `AppWeb` module, so you can just do `live "/weather", WeatherLive`
|
- LiveViews should be named like `AppWeb.WeatherLive`, with a `Live` suffix. When you go to add LiveView routes to the router, the default `:browser` scope is **already aliased** with the `AppWeb` module, so you can just do `live "/weather", WeatherLive`
|
||||||
|
|
||||||
@@ -235,7 +284,7 @@ custom classes must fully style the input
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
- LiveView streams are *not* enumerable, so you cannot use `Enum.filter/2` or `Enum.reject/2` on them. Instead, if you want to filter, prune, or refresh a list of items on the UI, you **must refetch the data and re-stream the entire stream collection, passing reset: true**:
|
- LiveView streams are _not_ enumerable, so you cannot use `Enum.filter/2` or `Enum.reject/2` on them. Instead, if you want to filter, prune, or refresh a list of items on the UI, you **must refetch the data and re-stream the entire stream collection, passing reset: true**:
|
||||||
|
|
||||||
def handle_event("filter", %{"filter" => filter}, socket) do
|
def handle_event("filter", %{"filter" => filter}, socket) do
|
||||||
# re-fetch the messages based on the filter
|
# re-fetch the messages based on the filter
|
||||||
@@ -248,7 +297,7 @@ custom classes must fully style the input
|
|||||||
|> stream(:messages, messages, reset: true)}
|
|> stream(:messages, messages, reset: true)}
|
||||||
end
|
end
|
||||||
|
|
||||||
- LiveView streams *do not support counting or empty states*. If you need to display a count, you must track it using a separate assign. For empty states, you can use Tailwind classes:
|
- LiveView streams _do not support counting or empty states_. If you need to display a count, you must track it using a separate assign. For empty states, you can use Tailwind classes:
|
||||||
|
|
||||||
<div id="tasks" phx-update="stream">
|
<div id="tasks" phx-update="stream">
|
||||||
<div class="hidden only:block">No tasks yet</div>
|
<div class="hidden only:block">No tasks yet</div>
|
||||||
@@ -446,4 +495,4 @@ And **never** do this:
|
|||||||
- **Never** use `<.form let={f} ...>` in the template, instead **always use `<.form for={@form} ...>`**, then drive all form references from the form assign as in `@form[:field]`. The UI should **always** be driven by a `to_form/2` assigned in the LiveView module that is derived from a changeset
|
- **Never** use `<.form let={f} ...>` in the template, instead **always use `<.form for={@form} ...>`**, then drive all form references from the form assign as in `@form[:field]`. The UI should **always** be driven by a `to_form/2` assigned in the LiveView module that is derived from a changeset
|
||||||
<!-- phoenix:liveview-end -->
|
<!-- phoenix:liveview-end -->
|
||||||
|
|
||||||
<!-- usage-rules-end -->
|
<!-- usage-rules-end -->
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
"mcp": {
|
||||||
|
"graft": {
|
||||||
|
"type": "local",
|
||||||
|
"command": ["npx", "-y", "@nanonets/graft", "mcp"],
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user