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
|
||||
/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.
|
||||
|
||||
<!-- 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
|
||||
|
||||
- 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
|
||||
- **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
|
||||
custom classes must fully style the input
|
||||
custom classes must fully style the input
|
||||
|
||||
### 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
|
||||
- Focus on **delightful details** like hover effects, loading states, and smooth page transitions
|
||||
|
||||
|
||||
<!-- usage-rules-start -->
|
||||
|
||||
<!-- phoenix:elixir-start -->
|
||||
|
||||
## Elixir guidelines
|
||||
|
||||
- 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)
|
||||
|
||||
- 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
|
||||
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
|
||||
- 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)
|
||||
assert_receive {:DOWN, ^ref, :process, ^pid, :normal}
|
||||
ref = Process.monitor(pid)
|
||||
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
|
||||
<!-- phoenix:elixir-end -->
|
||||
- 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:phoenix-start -->
|
||||
|
||||
## 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.
|
||||
@@ -122,6 +167,7 @@ custom classes must fully style the input
|
||||
<!-- phoenix:phoenix-end -->
|
||||
|
||||
<!-- phoenix:ecto-start -->
|
||||
|
||||
## 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`
|
||||
@@ -134,6 +180,7 @@ custom classes must fully style the input
|
||||
<!-- phoenix:ecto-end -->
|
||||
|
||||
<!-- phoenix:html-start -->
|
||||
|
||||
## Phoenix HTML guidelines
|
||||
|
||||
- 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 %>
|
||||
|
||||
- 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>
|
||||
let obj = {key: "val"}
|
||||
@@ -196,26 +243,28 @@ custom classes must fully style the input
|
||||
|
||||
**Always** do this:
|
||||
|
||||
<div id={@id}>
|
||||
{@my_assign}
|
||||
<%= if @some_block_condition do %>
|
||||
{@another_assign}
|
||||
<% end %>
|
||||
</div>
|
||||
<div id={@id}>
|
||||
{@my_assign}
|
||||
<%= if @some_block_condition do %>
|
||||
{@another_assign}
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
and **Never** do this – the program will terminate with a syntax error:
|
||||
|
||||
<%!-- THIS IS INVALID NEVER EVER DO THIS --%>
|
||||
<div id="<%= @invalid_interpolation %>">
|
||||
{if @invalid_block_construct do}
|
||||
{end}
|
||||
</div>
|
||||
<!-- phoenix:html-end -->
|
||||
<%!-- THIS IS INVALID NEVER EVER DO THIS --%>
|
||||
<div id="<%= @invalid_interpolation %>">
|
||||
{if @invalid_block_construct do}
|
||||
{end}
|
||||
</div>
|
||||
|
||||
<!-- phoenix:html-end -->
|
||||
|
||||
<!-- phoenix:liveview-start -->
|
||||
|
||||
## 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
|
||||
- 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>
|
||||
|
||||
- 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
|
||||
# re-fetch the messages based on the filter
|
||||
@@ -248,7 +297,7 @@ custom classes must fully style the input
|
||||
|> stream(:messages, messages, reset: true)}
|
||||
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 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
|
||||
<!-- 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