Compare commits

...
4 Commits
Author SHA1 Message Date
sudacode a30e1b5523 update 2026-10-29 22:34:30 -07:00
sudacode dc30c570ce update 2026-10-29 22:07:19 -07:00
sudacode e02279848d Merge remote-tracking branch 'refs/remotes/origin/master' 2026-10-12 21:34:41 -07:00
sudacode 8f0b3f10e7 update 2026-10-12 21:34:30 -07:00
27 changed files with 461 additions and 2237 deletions

No files matched your search

-187
View File
@@ -1,187 +0,0 @@
---
name: delegate
description: Delegate self-contained tasks to Claude or Codex subagents run as fresh CLI processes. Use proactively, without being asked, whenever work can be handed off — parallel research or code searches, bounded implementation chunks, independent reviews, second implementations for comparison. Pick the provider (Claude, Codex, or both) and tier that best fit each task. Not for consultations the user explicitly routed to a specific peer (use peer-consult for that).
---
# Delegate
Hand a self-contained task to a fresh `claude` or `codex` CLI process and get
back a structured report. Each invocation is one subagent; run several in
parallel for independent tasks.
You call the CLIs directly. The command shapes below are the default recipe,
not a fixed harness — adjust flags when the task needs it (extra directories,
different tools, a longer timeout), and say what you changed in your report.
## When to delegate
- Research or code searches whose details you don't need in your own context.
- Bounded implementation chunks that can be specified up front and verified.
- Independent review passes over a diff, file, or subsystem.
- Getting two independent takes by sending the same task to both providers.
Do not delegate work that needs mid-task input from you or the user, or tasks
so small that writing the brief costs more than doing the work.
## Route the task
Classify the smallest adequate tier:
| Tier | Signals | Codex | Claude |
|---|---|---|---|
| `quick` | Narrow, bounded, one component | `gpt-5.6-terra`, medium | `claude-sonnet-4-6`, medium |
| `quick-context` | Still bounded; more context or nuance | `gpt-5.6-terra`, high | `claude-sonnet-5`, high |
| `standard` | Multi-file feature, ordinary design/debugging, meaningful trade-offs | `gpt-5.6-sol`, medium | `claude-opus-4-8`, medium |
| `deep` | Architecture, concurrency, security, broad ambiguity, high-impact choice | `gpt-5.6-sol`, high | `claude-opus-4-8`, high |
Pick the provider by judgment:
- Either provider handles general coding, research, and review well; when the
task has no special pull, prefer the provider you are NOT running as, so the
subagent brings an independent perspective.
- Use **both** (two invocations, same task) when you want independent
perspectives on a risky or ambiguous problem, or when splitting parallel
work across providers to avoid rate-limit contention.
- Honor an explicit user model preference only if it is in the allowed list:
Codex `gpt-5.6-terra`/`gpt-5.6-sol`; Claude
`claude-sonnet-4-6`/`claude-sonnet-5`/`claude-opus-4-8`. Never silently
substitute another model.
Pick the mode:
- `read` (default): research, searches, reviews, second opinions. Subagent
cannot modify files.
- `write`: implementation and refactors. Subagent may edit files and run
commands inside the repo; it will not commit or push unless the task says to.
## Write the brief
The subagent starts with zero context. Write a self-contained task containing:
- The goal and definition of done.
- Relevant paths, symbols, error messages, or raw diff/plan text.
- Constraints (style, APIs to use or avoid, files off-limits).
- For `write` mode: how to verify (build/test commands).
Pass raw evidence; do not tell the subagent the answer you expect.
Wrap the brief in this scaffold. Keep the constraint block matching the mode
and keep the report sections verbatim — the result-handling steps below assume
them.
```
You are a subagent completing a delegated task inside the current repository.
Work independently; the caller cannot answer questions mid-task. If the task is
ambiguous, choose the safest reasonable interpretation and note the choice in
your report.
<constraints for the chosen mode — see below>
- Do not delegate further or invoke Claude or Codex recursively.
End your reply with a report containing these sections:
- Summary: what you did or found, in a few sentences.
- Details: key evidence, decisions, or findings, with file:line references.
- Files changed: list each changed file, or "none".
- Verification: what you ran and the outcome, or "not verified" and why.
- Open questions: anything unresolved the caller must decide, or "none".
Task:
<self-contained task brief>
```
`read` constraints:
```
Hard constraints:
- You are in read-only mode. Do not modify, create, rename, or delete files.
- Do not commit, branch, push, or contact external systems that change state.
- Base claims on repository evidence. Cite file paths and line numbers.
```
`write` constraints:
```
Hard constraints:
- Work only inside the given repository directory.
- Do not commit, branch, push, or open pull requests unless the task says to.
- Do not delete or rename files the task does not cover; if something looks
wrong or unexpected, stop and report instead of guessing.
- Verify your work (build, tests, or a targeted check) when feasible.
```
## Run it
Always send the prompt on stdin via a quoted heredoc (`<<'TASK'`) so nothing in
the brief is expanded or re-parsed by the shell. Run the CLI from the target
repo with `cd <repo> && ...`.
Codex, read-only:
```bash
cd /path/to/repo && codex exec \
--ignore-user-config \
--model gpt-5.6-sol \
--config model_reasoning_effort="medium" \
--config approval_policy="never" \
--sandbox read-only \
--ephemeral \
--skip-git-repo-check \
--output-last-message /tmp/delegate-codex-1.md \
--cd /path/to/repo - <<'TASK'
<scaffold + brief>
TASK
cat /tmp/delegate-codex-1.md
```
Codex, write mode: swap `--sandbox read-only` for `--sandbox workspace-write`.
`--output-last-message` writes just the final report; Codex's stdout also
carries its reasoning stream, which is useful when a run fails or you want to
see what it actually did. Add `--add-dir <dir>` for extra writable roots.
Claude, read-only:
```bash
cd /path/to/repo && claude --print \
--model claude-opus-4-8 \
--effort medium \
--disable-slash-commands \
--no-session-persistence \
--permission-mode plan \
--tools Read,Glob,Grep <<'TASK'
<scaffold + brief>
TASK
```
Claude, write mode: replace the last two lines with
```bash
--permission-mode acceptEdits \
--tools Read,Glob,Grep,Edit,Write,Bash \
--allowedTools Edit,Write,Bash
```
Claude prints the final message on stdout. Widen `--tools` when a task
genuinely needs more (for example `WebSearch` for external research, or
`Bash` in read mode for a `git diff` the subagent must see) — that is a
deliberate choice, so note it when you report back.
Give long runs a timeout that fits the task (the Bash tool's `timeout` is in
milliseconds; 1800000 is a reasonable ceiling for a `deep` tier run).
Parallel delegation: launch each invocation as a separate background shell
command, write each Codex report to its own `--output-last-message` path, then
collect the outputs. Never point two `write`-mode subagents at overlapping
files; split by file/directory or run them sequentially.
## Handle the result
- Treat the report as a subagent's claim, not ground truth: spot-check
load-bearing findings, and for `write` mode review the diff (`git diff`) and
re-run verification before building on it.
- Relay the outcome to the user in your own words; credit which provider/model
produced it when it matters.
- On failure, report the provider, model, and exact error. A nonzero exit or
empty output is a failure even if the CLI printed something — check both.
Retry once with the same route if transient; escalate tier or switch provider
only deliberately, and say you did.
-95
View File
@@ -1,95 +0,0 @@
---
name: peer-consult
description: Request an independent, read-only repository review or second opinion from the opposite model provider, using Claude from Codex or Codex from Claude. Use only when the user explicitly asks to consult, ask, review with, or get an opinion from Claude or Codex about an issue, feature, design, plan, diagnosis, or decision. Never invoke proactively. Never use for implementation or file changes.
---
# Peer Consult
Get one independent opinion from the opposite provider. Preserve the repository unchanged and return a standardized decision memo.
## Preconditions
- Require an explicit user request for cross-provider consultation. A normal request for review, planning, or advice is insufficient unless it names Claude, Codex, a peer model, or a second opinion.
- Run Claude only when the active agent is Codex. Run Codex only when the active agent is Claude.
- Do not use this skill from any other caller.
- Do not edit files, implement the recommendation, or perform follow-on changes unless the user separately requests them after seeing the memo.
## Route the request
Classify the smallest adequate tier:
| Tier | Signals | Codex peer | Claude peer |
|---|---|---|---|
| Quick | Narrow, bounded, one component | `gpt-5.6-terra`, medium | `claude-sonnet-4-6`, medium |
| Quick, context-heavy | Still bounded; more context or nuance | `gpt-5.6-terra`, high | `claude-sonnet-5`, high |
| Standard | Multi-file feature, ordinary design/debugging, meaningful trade-offs | `gpt-5.6-sol`, medium | `claude-opus-4-8`, medium |
| Deep | Architecture, concurrency, security, broad ambiguity, high-impact choice | `gpt-5.6-sol`, high | `claude-opus-4-8`, high |
Honor an explicit model override only when it is allowed for the target provider:
- Codex: `gpt-5.6-terra`, `gpt-5.6-sol`
- Claude: `claude-sonnet-4-6`, `claude-sonnet-5`, `claude-opus-4-8`
Reject GPT-5.6 Luna, pre-5.6 Codex models, Claude Haiku, every other Claude model, aliases, and cross-provider model names. Never silently fall back.
## Prepare independent context
Write a self-contained request containing:
- The question or decision to assess.
- Relevant constraints and success criteria.
- Relevant paths, symbols, errors, or raw plan text.
- Specific uncertainties the peer should resolve.
Pass raw evidence. Avoid telling the peer the expected answer or presenting the active agent's conclusion as fact. Let the peer inspect the current repository independently.
## Run the broker
Resolve `<skill-dir>` to the directory containing this `SKILL.md`. Send the request on stdin; do not interpolate it into a shell command.
From Codex:
```bash
python3 <skill-dir>/scripts/peer_consult.py \
--caller codex \
--complexity standard \
--repo "$PWD" <<'PEER_REQUEST'
<self-contained consultation request>
PEER_REQUEST
```
From Claude:
```bash
python3 <skill-dir>/scripts/peer_consult.py \
--caller claude \
--complexity standard \
--repo "$PWD" <<'PEER_REQUEST'
<self-contained consultation request>
PEER_REQUEST
```
Adjust only these routing flags when needed:
- `--complexity quick|standard|deep`
- `--context-heavy` for the context-heavy quick tier
- `--model <approved-model>` for an explicit allowed override
- `--timeout <seconds>` when the default 600 seconds is unsuitable
- `--dry-run` to inspect routing and command construction without calling a provider
The broker enforces pinned models, opposite-provider routing, nonpersistent execution, tool restrictions, structured output, and read-only repository access.
## Return the result
Return the broker's memo without changing its meaning. Keep its sections:
- Verdict
- Evidence
- Risks
- Alternatives
- Recommendation
- Confidence
Identify it as the peer provider's opinion. If useful, add a short, separately labeled synthesis explaining how the feedback affects the active discussion. Do not implement anything.
On failure, report the selected provider, model, and exact failure. Do not retry with another model unless the user explicitly requests it.
@@ -1,7 +0,0 @@
interface:
display_name: "Peer Consult"
short_description: "Independent cross-provider second opinions"
default_prompt: "Use $peer-consult to get an independent read-only second opinion on this decision."
policy:
allow_implicit_invocation: true
@@ -1,30 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"verdict": { "type": "string", "minLength": 1 },
"evidence": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"risks": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"alternatives": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"recommendation": { "type": "string", "minLength": 1 },
"confidence": { "type": "string", "enum": ["low", "medium", "high"] }
},
"required": [
"verdict",
"evidence",
"risks",
"alternatives",
"recommendation",
"confidence"
],
"additionalProperties": false
}
@@ -1,340 +0,0 @@
#!/usr/bin/env python3
"""Run a read-only consultation with the opposite model provider."""
import argparse
import json
import os
import shutil
import subprocess
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
ALLOWED_MODELS = {
"codex": frozenset({"gpt-5.6-terra", "gpt-5.6-sol"}),
"claude": frozenset(
{"claude-sonnet-4-6", "claude-sonnet-5", "claude-opus-4-8"}
),
}
def detect_caller(env: dict[str, str]) -> str:
is_codex = bool(env.get("CODEX_THREAD_ID"))
is_claude = env.get("CLAUDECODE") == "1" or bool(
env.get("CLAUDE_CODE_ENTRYPOINT")
)
if is_codex and is_claude:
raise ValueError("Ambiguous caller environment")
if is_codex:
return "codex"
if is_claude:
return "claude"
raise ValueError("Cannot detect caller; pass --caller claude or --caller codex")
@dataclass(frozen=True)
class Route:
provider: str
model: str
effort: str
def select_route(caller: str, complexity: str, context_heavy: bool = False) -> Route:
if complexity not in {"quick", "standard", "deep"}:
raise ValueError(f"Unknown complexity: {complexity}")
effort = (
"high"
if complexity == "deep" or (complexity == "quick" and context_heavy)
else "medium"
)
if caller == "claude":
model = "gpt-5.6-terra" if complexity == "quick" else "gpt-5.6-sol"
return Route("codex", model, effort)
if caller == "codex":
if complexity == "quick":
model = "claude-sonnet-5" if context_heavy else "claude-sonnet-4-6"
else:
model = "claude-opus-4-8"
return Route("claude", model, effort)
raise ValueError(f"Unknown caller: {caller}")
def apply_model_override(route: Route, model: str) -> Route:
if model not in ALLOWED_MODELS[route.provider]:
raise ValueError(f"Model {model!r} is not allowed for {route.provider}")
return Route(route.provider, model, route.effort)
def build_command(
route: Route,
repo: Path,
schema_path: Path,
output_path: Path | None = None,
) -> list[str]:
if route.provider == "codex":
if output_path is None:
raise ValueError("Codex requires an output path")
return [
"codex",
"exec",
"--ignore-user-config",
"--model",
route.model,
"--config",
f'model_reasoning_effort="{route.effort}"',
"--config",
'approval_policy="never"',
"--sandbox",
"read-only",
"--ephemeral",
"--skip-git-repo-check",
"--output-schema",
str(schema_path),
"--output-last-message",
str(output_path),
"--json",
"--cd",
str(repo),
"-",
]
schema = json.dumps(json.loads(schema_path.read_text()), separators=(",", ":"))
return [
"claude",
"--print",
"--safe-mode",
"--model",
route.model,
"--effort",
route.effort,
"--permission-mode",
"plan",
"--tools",
"Read,Glob,Grep",
"--disable-slash-commands",
"--no-session-persistence",
"--prompt-suggestions",
"false",
"--output-format",
"json",
"--json-schema",
schema,
]
def build_peer_prompt(question: str, route: Route) -> str:
return f"""You are an independent {route.provider} reviewer. Inspect the current repository in read-only mode and give a second opinion on the request below.
Hard constraints:
- Do not modify, create, rename, or delete files.
- Do not implement code or run commands that can change state.
- Do not commit, branch, push, open pull requests, or contact external systems.
- Do not delegate to subagents or invoke Claude, Codex, or peer-consult recursively.
- Base claims on repository evidence. Cite file paths and line numbers when available.
- Call out uncertainty and missing evidence. Do not pretend the caller's proposal is correct.
- Return only the structured decision memo required by the response schema.
Request:
{question.strip()}
"""
MEMO_FIELDS = {
"verdict",
"evidence",
"risks",
"alternatives",
"recommendation",
"confidence",
}
def validate_memo(value: object) -> dict[str, object]:
if not isinstance(value, dict) or set(value) != MEMO_FIELDS:
raise ValueError("Invalid decision memo fields")
if not isinstance(value["verdict"], str) or not value["verdict"].strip():
raise ValueError("Invalid decision memo verdict")
if not isinstance(value["recommendation"], str) or not value["recommendation"].strip():
raise ValueError("Invalid decision memo recommendation")
for field in ("evidence", "risks", "alternatives"):
items = value[field]
if not isinstance(items, list) or any(
not isinstance(item, str) or not item.strip() for item in items
):
raise ValueError(f"Invalid decision memo {field}")
if value["confidence"] not in {"low", "medium", "high"}:
raise ValueError("Invalid decision memo confidence")
return value
def parse_claude_output(output: str) -> object:
try:
envelope = json.loads(output)
except json.JSONDecodeError as error:
raise ValueError("Claude returned malformed JSON") from error
if isinstance(envelope, dict) and "structured_output" in envelope:
return envelope["structured_output"]
if isinstance(envelope, dict) and isinstance(envelope.get("result"), str):
try:
return json.loads(envelope["result"])
except json.JSONDecodeError as error:
raise ValueError("Claude result did not contain structured JSON") from error
return envelope
def _bullets(items: object) -> str:
values = items if isinstance(items, list) else []
return "\n".join(f"- {item}" for item in values) or "- None identified."
def render_memo(memo: dict[str, object], route: Route) -> str:
provider = route.provider.capitalize()
return f"""## Peer consultation
{provider} · {route.model} · {route.effort}
### Verdict
{memo['verdict']}
### Evidence
{_bullets(memo['evidence'])}
### Risks
{_bullets(memo['risks'])}
### Alternatives
{_bullets(memo['alternatives'])}
### Recommendation
{memo['recommendation']}
### Confidence
{memo['confidence']}
"""
def run_consultation(
route: Route,
repo: Path,
prompt: str,
schema_path: Path,
*,
timeout: int = 600,
env: dict[str, str] | None = None,
) -> dict[str, object]:
process_env = dict(os.environ if env is None else env)
if shutil.which(route.provider, path=process_env.get("PATH")) is None:
raise RuntimeError(f"Required CLI is not installed: {route.provider}")
with tempfile.TemporaryDirectory(prefix="peer-consult-") as temp_dir:
output_path = (
Path(temp_dir) / "memo.json" if route.provider == "codex" else None
)
command = build_command(route, repo, schema_path, output_path)
try:
result = subprocess.run(
command,
cwd=repo,
env=process_env,
input=prompt,
text=True,
capture_output=True,
timeout=timeout,
check=False,
)
except subprocess.TimeoutExpired as error:
raise RuntimeError(f"{route.provider} consultation timed out") from error
if result.returncode != 0:
detail = (result.stderr or result.stdout).strip() or "no error output"
raise RuntimeError(
f"{route.provider} consultation failed ({result.returncode}): {detail}"
)
if route.provider == "codex":
if output_path is None or not output_path.is_file():
raise RuntimeError("Codex did not produce a decision memo")
try:
value = json.loads(output_path.read_text())
except json.JSONDecodeError as error:
raise RuntimeError("Codex returned malformed JSON") from error
else:
value = parse_claude_output(result.stdout)
return validate_memo(value)
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Get a read-only second opinion from the opposite model provider."
)
parser.add_argument("--caller", choices=("claude", "codex"))
parser.add_argument(
"--complexity",
choices=("quick", "standard", "deep"),
default="standard",
)
parser.add_argument("--context-heavy", action="store_true")
parser.add_argument("--model", help="Approved target-model override")
parser.add_argument("--repo", type=Path, default=Path.cwd())
parser.add_argument("--timeout", type=int, default=600)
parser.add_argument("--dry-run", action="store_true")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
question = sys.stdin.read().strip()
if not question:
raise ValueError("Consultation request must be provided on stdin")
repo = args.repo.expanduser().resolve()
if not repo.is_dir():
raise ValueError(f"Repository directory does not exist: {repo}")
caller = args.caller or detect_caller(dict(os.environ))
route = select_route(caller, args.complexity, args.context_heavy)
if args.model:
route = apply_model_override(route, args.model)
prompt = build_peer_prompt(question, route)
schema_path = Path(__file__).with_name("memo.schema.json")
output_path = (
Path(tempfile.gettempdir()) / "peer-consult-dry-run-output.json"
if route.provider == "codex"
else None
)
command = build_command(route, repo, schema_path, output_path)
if args.dry_run:
print(
json.dumps(
{
"provider": route.provider,
"model": route.model,
"effort": route.effort,
"command": command,
"prompt": prompt,
},
indent=2,
)
)
return 0
memo = run_consultation(
route,
repo,
prompt,
schema_path,
timeout=args.timeout,
)
print(render_memo(memo, route), end="")
return 0
except (OSError, RuntimeError, ValueError) as error:
print(f"peer-consult: error: {error}", file=sys.stderr)
return 2
if __name__ == "__main__":
raise SystemExit(main())
@@ -1,366 +0,0 @@
import importlib.util
import json
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
SCRIPT = Path(__file__).parents[1] / "scripts" / "peer_consult.py"
def load_broker():
if not SCRIPT.exists():
raise AssertionError("peer_consult.py is missing")
spec = importlib.util.spec_from_file_location("peer_consult", SCRIPT)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
class RoutingTests(unittest.TestCase):
def test_routes_approved_models_and_effort(self):
broker = load_broker()
cases = {
("claude", "quick", False): ("codex", "gpt-5.6-terra", "medium"),
("claude", "quick", True): ("codex", "gpt-5.6-terra", "high"),
("claude", "standard", False): ("codex", "gpt-5.6-sol", "medium"),
("claude", "deep", False): ("codex", "gpt-5.6-sol", "high"),
("codex", "quick", False): ("claude", "claude-sonnet-4-6", "medium"),
("codex", "quick", True): ("claude", "claude-sonnet-5", "high"),
("codex", "standard", False): ("claude", "claude-opus-4-8", "medium"),
("codex", "deep", False): ("claude", "claude-opus-4-8", "high"),
}
for inputs, expected in cases.items():
with self.subTest(inputs=inputs):
route = broker.select_route(*inputs)
self.assertEqual(
(route.provider, route.model, route.effort),
expected,
)
def test_rejects_unknown_complexity(self):
broker = load_broker()
with self.assertRaisesRegex(ValueError, "Unknown complexity"):
broker.select_route("codex", "extreme")
def test_accepts_only_target_provider_model_overrides(self):
broker = load_broker()
self.assertTrue(
hasattr(broker, "apply_model_override"),
"model override validation is missing",
)
codex_route = broker.apply_model_override(
broker.select_route("claude", "quick"),
"gpt-5.6-sol",
)
claude_route = broker.apply_model_override(
broker.select_route("codex", "quick"),
"claude-opus-4-8",
)
self.assertEqual(codex_route.model, "gpt-5.6-sol")
self.assertEqual(claude_route.model, "claude-opus-4-8")
def test_rejects_disallowed_or_wrong_provider_model_overrides(self):
broker = load_broker()
self.assertTrue(
hasattr(broker, "apply_model_override"),
"model override validation is missing",
)
route = broker.select_route("claude", "quick")
for model in (
"gpt-5.6-luna",
"gpt-5.5",
"claude-sonnet-5",
"claude-haiku-4-5",
):
with self.subTest(model=model):
with self.assertRaisesRegex(ValueError, "not allowed"):
broker.apply_model_override(route, model)
class CallerDetectionTests(unittest.TestCase):
def test_detects_codex_and_claude_environments(self):
broker = load_broker()
self.assertTrue(hasattr(broker, "detect_caller"), "caller detection is missing")
self.assertEqual(broker.detect_caller({"CODEX_THREAD_ID": "abc"}), "codex")
self.assertEqual(broker.detect_caller({"CLAUDECODE": "1"}), "claude")
self.assertEqual(
broker.detect_caller({"CLAUDE_CODE_ENTRYPOINT": "cli"}),
"claude",
)
def test_rejects_missing_or_ambiguous_caller(self):
broker = load_broker()
self.assertTrue(hasattr(broker, "detect_caller"), "caller detection is missing")
with self.assertRaisesRegex(ValueError, "Cannot detect"):
broker.detect_caller({})
with self.assertRaisesRegex(ValueError, "Ambiguous"):
broker.detect_caller({"CODEX_THREAD_ID": "abc", "CLAUDECODE": "1"})
class CommandTests(unittest.TestCase):
def setUp(self):
self.broker = load_broker()
self.repo = Path("/tmp/example-repo")
self.schema = Path(__file__).parents[1] / "scripts" / "memo.schema.json"
def test_builds_read_only_ephemeral_codex_command(self):
self.assertTrue(hasattr(self.broker, "build_command"), "command builder is missing")
route = self.broker.select_route("claude", "standard")
command = self.broker.build_command(
route,
self.repo,
self.schema,
Path("/tmp/peer-output.json"),
)
self.assertEqual(command[:2], ["codex", "exec"])
self.assertIn("gpt-5.6-sol", command)
self.assertIn('model_reasoning_effort="medium"', command)
self.assertIn('approval_policy="never"', command)
self.assertIn("read-only", command)
self.assertIn("--ephemeral", command)
self.assertIn("--ignore-user-config", command)
self.assertIn("--json", command)
self.assertIn(str(self.schema), command)
self.assertIn("/tmp/peer-output.json", command)
self.assertEqual(command[-1], "-")
self.assertFalse(any("dangerously" in arg for arg in command))
def test_builds_safe_nonpersistent_claude_command(self):
self.assertTrue(hasattr(self.broker, "build_command"), "command builder is missing")
route = self.broker.select_route("codex", "deep")
command = self.broker.build_command(route, self.repo, self.schema)
self.assertEqual(command[0], "claude")
self.assertIn("--print", command)
self.assertIn("claude-opus-4-8", command)
self.assertIn("high", command)
self.assertIn("--safe-mode", command)
self.assertIn("--permission-mode", command)
self.assertIn("plan", command)
self.assertIn("--no-session-persistence", command)
self.assertIn("Read,Glob,Grep", command)
self.assertNotIn("Bash", command)
schema_arg = command[command.index("--json-schema") + 1]
self.assertEqual(json.loads(schema_arg)["additionalProperties"], False)
def test_peer_prompt_forbids_changes_and_requires_evidence(self):
self.assertTrue(hasattr(self.broker, "build_peer_prompt"), "peer prompt builder is missing")
route = self.broker.select_route("codex", "standard")
prompt = self.broker.build_peer_prompt("Should we split this service?", route)
for phrase in (
"read-only",
"Do not modify",
"Do not implement",
"Do not delegate",
"repository evidence",
"Should we split this service?",
):
with self.subTest(phrase=phrase):
self.assertIn(phrase, prompt)
class MemoTests(unittest.TestCase):
def setUp(self):
self.broker = load_broker()
self.memo = {
"verdict": "Split only after measuring coupling.",
"evidence": ["src/service.py:42 owns both workflows."],
"risks": ["A premature split adds coordination overhead."],
"alternatives": ["Extract an internal module first."],
"recommendation": "Instrument boundaries, then reassess.",
"confidence": "medium",
}
def test_validates_and_renders_standardized_memo(self):
self.assertTrue(hasattr(self.broker, "validate_memo"), "memo validation is missing")
self.assertTrue(hasattr(self.broker, "render_memo"), "memo rendering is missing")
route = self.broker.select_route("codex", "standard")
validated = self.broker.validate_memo(self.memo)
rendered = self.broker.render_memo(validated, route)
for heading in (
"## Peer consultation",
"### Verdict",
"### Evidence",
"### Risks",
"### Alternatives",
"### Recommendation",
"### Confidence",
):
with self.subTest(heading=heading):
self.assertIn(heading, rendered)
self.assertIn("Claude · claude-opus-4-8 · medium", rendered)
def test_rejects_malformed_memo(self):
self.assertTrue(hasattr(self.broker, "validate_memo"), "memo validation is missing")
malformed = dict(self.memo, confidence="certain", surprise="extra")
with self.assertRaisesRegex(ValueError, "memo"):
self.broker.validate_memo(malformed)
def test_extracts_claude_structured_output(self):
self.assertTrue(
hasattr(self.broker, "parse_claude_output"),
"Claude output parser is missing",
)
envelope = json.dumps({"type": "result", "structured_output": self.memo})
self.assertEqual(self.broker.parse_claude_output(envelope), self.memo)
class CliTests(unittest.TestCase):
def test_dry_run_prints_route_command_and_prompt_without_provider_call(self):
broker = load_broker()
self.assertTrue(hasattr(broker, "main"), "CLI entrypoint is missing")
with tempfile.TemporaryDirectory() as repo:
result = subprocess.run(
[
sys.executable,
str(SCRIPT),
"--caller",
"codex",
"--complexity",
"standard",
"--repo",
repo,
"--dry-run",
],
input="Should we split this service?",
text=True,
capture_output=True,
check=False,
)
self.assertEqual(result.returncode, 0, result.stderr)
payload = json.loads(result.stdout)
self.assertEqual(payload["provider"], "claude")
self.assertEqual(payload["model"], "claude-opus-4-8")
self.assertEqual(payload["effort"], "medium")
self.assertIn("--safe-mode", payload["command"])
self.assertIn("Should we split this service?", payload["prompt"])
def test_cli_rejects_luna_override_before_execution(self):
broker = load_broker()
self.assertTrue(hasattr(broker, "main"), "CLI entrypoint is missing")
result = subprocess.run(
[
sys.executable,
str(SCRIPT),
"--caller",
"claude",
"--complexity",
"quick",
"--model",
"gpt-5.6-luna",
"--dry-run",
],
input="Review this choice.",
text=True,
capture_output=True,
check=False,
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("not allowed", result.stderr)
class ExecutionTests(unittest.TestCase):
def setUp(self):
self.broker = load_broker()
self.memo = {
"verdict": "Keep the boundary for now.",
"evidence": ["src/core.py:10 has one caller."],
"risks": ["The caller may grow."],
"alternatives": ["Revisit after instrumentation."],
"recommendation": "Measure first.",
"confidence": "high",
}
def _write_executable(self, path, source):
path.write_text(source)
path.chmod(0o755)
def test_runs_claude_and_extracts_structured_memo(self):
self.assertTrue(
hasattr(self.broker, "run_consultation"),
"consultation runner is missing",
)
with tempfile.TemporaryDirectory() as root:
root_path = Path(root)
bin_dir = root_path / "bin"
repo = root_path / "repo"
bin_dir.mkdir()
repo.mkdir()
envelope = json.dumps({"structured_output": self.memo})
self._write_executable(
bin_dir / "claude",
"#!/bin/sh\nread request\nprintf '%s' '" + envelope + "'\n",
)
env = dict(os.environ, PATH=f"{bin_dir}:{os.environ['PATH']}")
route = self.broker.select_route("codex", "standard")
memo = self.broker.run_consultation(
route,
repo,
"Review this design.",
SCRIPT.with_name("memo.schema.json"),
env=env,
)
self.assertEqual(memo, self.memo)
def test_runs_codex_and_reads_temporary_structured_memo(self):
self.assertTrue(
hasattr(self.broker, "run_consultation"),
"consultation runner is missing",
)
with tempfile.TemporaryDirectory() as root:
root_path = Path(root)
bin_dir = root_path / "bin"
repo = root_path / "repo"
bin_dir.mkdir()
repo.mkdir()
memo_json = json.dumps(self.memo)
self._write_executable(
bin_dir / "codex",
"#!/bin/sh\n"
"while [ \"$#\" -gt 0 ]; do\n"
" if [ \"$1\" = \"--output-last-message\" ]; then\n"
" shift\n"
f" printf '%s' '{memo_json}' > \"$1\"\n"
" exit 0\n"
" fi\n"
" shift\n"
"done\n"
"exit 9\n",
)
env = dict(os.environ, PATH=f"{bin_dir}:{os.environ['PATH']}")
route = self.broker.select_route("claude", "standard")
memo = self.broker.run_consultation(
route,
repo,
"Review this design.",
SCRIPT.with_name("memo.schema.json"),
env=env,
)
self.assertEqual(memo, self.memo)
if __name__ == "__main__":
unittest.main()
+8
View File
@@ -7,7 +7,12 @@
<!-- Custom overrides for Ghostty --> <!-- Custom overrides for Ghostty -->
<!-- Force JetBrainsMono Nerd Font (and fallback to Noto Sans CJK JP) --> <!-- Force JetBrainsMono Nerd Font (and fallback to Noto Sans CJK JP) -->
<!-- prgname test keeps child processes (mpv, SubMiner, ...) that inherit
FONTCONFIG_FILE from the shell from having their fonts overridden -->
<match> <match>
<test name="prgname">
<string>ghostty</string>
</test>
<edit name="family" mode="prepend" binding="strong"> <edit name="family" mode="prepend" binding="strong">
<string>JetBrainsMono Nerd Font</string> <string>JetBrainsMono Nerd Font</string>
</edit> </edit>
@@ -21,6 +26,9 @@
<!-- For Japanese text, prefer Noto Sans CJK JP --> <!-- For Japanese text, prefer Noto Sans CJK JP -->
<match> <match>
<test name="prgname">
<string>ghostty</string>
</test>
<test name="lang" compare="contains"> <test name="lang" compare="contains">
<string>ja</string> <string>ja</string>
</test> </test>
-281
View File
@@ -1,281 +0,0 @@
# This is an example Hyprland config file.
# Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/
# Please note not all available settings / options are set here.
# For a full list, see the wiki
# You can split this configuration into multiple files
# Create your files separately and then link them to this file like this:
# source = ~/.config/hypr/myColors.conf
################
### MONITORS ###
################
# See https://wiki.hyprland.org/Configuring/Monitors/
# monitor=DP-1,2560x1440@144,0x0,1
# monitor=DP-3,2560x1440@144,2560x0,1
# vrr 2 enables vrr if application is fullscreen
# vrr 3 enables vrr if application is fullscreen and video or game content
# monitor = DP-1, 3440x1440@240,0x0,1,vrr,3
monitorv2 {
output = DP-1
mode = 3440x1440@240
position = 0x0
scale = 1
vrr = 2
# cm = srgb
# Optional HDR settings
cm = hdr
bitdepth = 10
sdr_min_luminance = 0.005
sdr_max_luminance = 200
min_luminance = 0
max_luminance = 1000
max_avg_luminance = 200
sdrbrightness = 1.0
sdrsaturation = 0.98
}
source = ~/.config/hypr/keybindings.conf
source = ~/.config/hypr/windowrules.conf
source = ~/.config/hypr/macchiato.conf
# unscale XWayland
xwayland {
force_zero_scaling = true
}
###################
### MY PROGRAMS ###
###################
# See https://wiki.hyprland.org/Configuring/Keywords/
# Set programs that you use
$terminal = uwsm app -- ghostty +new-window
$fileManager = uwsm app -- thunar
$menu = rofi -show drun -run-command "uwsm app -- {cmd}"
# $notification_daemon = dunst
$notification_daemon = uwsm app -- swaync -c ~/.config/swaync/config.json
#################
### AUTOSTART ###
#################
# Autostart necessary processes (like notifications daemons, status bars, etc.)
# Or execute your favorite apps at launch like this:
exec-once = $notification_daemon
exec-once = $terminal
exec-once = uwsm app -sb -S both -t scope -- hyprpm reload -n
exec-once = uwsm app -sb -t service -- nm-applet
exec-once = uwsm app -sb -t service -- waybar -c ~/.config/waybar/catppuccin-macchiato/config.jsonc -s ~/.config/waybar/catppuccin-macchiato/style.css
exec-once = uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1
exec-once = uwsm app -sb -t service -- gnome-keyring-daemon --start --components=secrets,ssh,pkcs11
exec-once = uwsm app -sb -t service -- tailscale systray
exec-once = ~/.local/bin/aria
# exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
#############################
### ENVIRONMENT VARIABLES ###
#############################
# See https://wiki.hyprland.org/Configuring/Environment-variables/
# env = XCURSOR_SIZE,24
# env = HYPRCURSOR_SIZE,24
# done in ../uswm/env and ../uswm/env-hyprland
#####################
### LOOK AND FEEL ###
#####################
# Refer to https://wiki.hyprland.org/Configuring/Variables/
# https://wiki.hyprland.org/Configuring/Variables/#general
general {
gaps_in = 5
gaps_out = 8
border_size = 2
# https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
# col.active_border = rgba($blueAlphaee) rgba($mauveAlphaee) 45deg
col.active_border = rgba($mauveAlphaee) 45deg
col.inactive_border = rgba($overlay0Alphaaa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
layout = scrolling
}
# https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration {
rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows
# active_opacity = 0.88
active_opacity = 1.0
# inactive_opacity = 0.88
inactive_opacity = 1.0
shadow {
enabled = true
range = 4
render_power = 3
color = rgba($surface0Alphaee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur
blur {
enabled = true
size = 7
passes = 2
xray = true
vibrancy = 0.1696
}
}
# https://wiki.hyprland.org/Configuring/Variables/#animations
animations {
enabled = yes, please :)
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
# slide, slidevert, fade, slidefade, slidefadevert
bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default
animation = border, 1, 5.39, easeOutQuint
animation = windows, 1, 4.79, easeOutQuint
# animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
# animation = windowsOut, 1, 1.49, linear, popin 87%
animation = windowsIn, 1, 4.1, easeOutQuint, slide
animation = windowsOut, 1, 1.49, linear, slide
animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, slidefade
animation = workspacesIn, 1, 1.21, almostLinear, slidefade
animation = workspacesOut, 1, 1.94, almostLinear, slidefade
}
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle {
pseudotile = false # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true
split_width_multiplier = 1.69
}
scrolling {
fullscreen_on_one_column = true
}
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master {
new_status = slave
allow_small_split = false
}
# https://wiki.hyprland.org/Configuring/Variables/#misc
misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
}
#############
### INPUT ###
#############
# https://wiki.hyprland.org/Configuring/Variables/#input
input {
kb_layout = us
kb_variant =
kb_model = pc86
kb_options = caps:escape_shifted_capslock
kb_rules =
follow_mouse = 1
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
touchpad {
natural_scroll = false
}
}
# https://wiki.hyprland.org/Configuring/Variables/#gestures
gestures {
# workspace_swipe = false
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device {
name = epic-mouse-v1
sensitivity = -0.5
}
render {
# explicit_sync = true
}
misc {
font_family = Manrope ExtraLight Medium, JetBrainsMono Nerd Font, M PLUS 1
}
# {{{ WORKSPACES - HANDLED IN WAYBAR CONFIG
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# workspace = name:,monitor:DP-1
# workspace = 2,monitor:DP-1,defaultName:
# workspace = 2,monitor:DP-1,persistent:false
# workspace = 3,monitor:DP-1,persistent:false
# workspace = 4,monitor:DP-1,persistent:false
# workspace = 5,monitor:DP-1,persistent:false
# workspace = 6,monitor:DP-3,persistent:false,default:true
# workspace = 7,monitor:DP-3,persistent:false
# workspace = 8,monitor:DP-3,persistent:false
# workspace = 9,monitor:DP-3,persistent:false
# workspace = 10,monitor:DP-3,persistent:false
# }}}
# windowrule = match:class my-window, border_size 10
debug {
disable_logs = true
enable_stdout_logs = false
}
layerrule {
name = fix-rofi
match:namespace = rofi
no_anim = true
}
-282
View File
@@ -1,282 +0,0 @@
# This is an example Hyprland config file.
# Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/
# Please note not all available settings / options are set here.
# For a full list, see the wiki
# You can split this configuration into multiple files
# Create your files separately and then link them to this file like this:
# source = ~/.config/hypr/myColors.conf
################
### MONITORS ###
################
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=eDP-1,3840x2160@60,0x0,2, vrr, 0
source = ~/.config/hypr/keybindings.conf
# source = ~/.config/hypr/env.conf
# unscale XWayland
xwayland {
force_zero_scaling = true
}
###################
### MY PROGRAMS ###
###################
# See https://wiki.hyprland.org/Configuring/Keywords/
# Set programs that you use
$terminal = uwsm app -- ghostty
$fileManager = uwsm app -- dolphin
$menu = rofi -show drun -run-command "uwsm app -- {cmd}"
# $notification_daemon = dunst
$notification_daemon = uwsm app -- swaync
#################
### AUTOSTART ###
#################
# Autostart necessary processes (like notifications daemons, status bars, etc.)
# Or execute your favorite apps at launch like this:
exec-once = uwsm app -sb -- hyprpm update -nn
exec-once = uwsm app -sb -- hyprpm reload -nn
exec-once = $notification_daemon
exec-once = $terminal
exec-once = uwsm app -sb -S both -t scope -- hyprpm update -nn
exec-once = uwsm app -sb -S both -t scope -- hyprpm reload -nn
exec-once = uwsm app -sb -t service -- nm-applet
exec-once = uwsm app -sb -t service -- hyprsunset
exec-once = uwsm app -sb -t service -- polkit-kde-authentication-agent-1.desktop
exec-once = uwsm app -sb -t service -- variety
exec-once = uwsm app -sb -t service -- fcitx5
exec-once = waybar -c $HOME/.config/waybar/catppuccin-macchiato/config-battery.jsonc -s $HOME/.config/waybar/catppuccin-macchiato/style.css
#############################
### ENVIRONMENT VARIABLES ###
#############################
# See https://wiki.hyprland.org/Configuring/Environment-variables/
# env = XCURSOR_SIZE,24
# env = HYPRCURSOR_SIZE,24
# done in ../uswm/env and ../uswm/env-hyprland
#####################
### LOOK AND FEEL ###
#####################
# Refer to https://wiki.hyprland.org/Configuring/Variables/
# https://wiki.hyprland.org/Configuring/Variables/#general
general {
gaps_in = 5
gaps_out = 8
border_size = 2
# https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
layout = dwindle
}
# https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration {
rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows
active_opacity = 1.0
inactive_opacity = 1.0
shadow {
enabled = true
range = 4
render_power = 3
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur
blur {
enabled = true
size = 7
passes = 2
xray = true
vibrancy = 0.1696
}
}
# https://wiki.hyprland.org/Configuring/Variables/#animations
animations {
enabled = yes, please :)
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default
animation = border, 1, 5.39, easeOutQuint
animation = windows, 1, 4.79, easeOutQuint
# animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
# animation = windowsOut, 1, 1.49, linear, popin 87%
animation = windowsIn, 1, 4.1, easeOutQuint, slide
animation = windowsOut, 1, 1.49, easeOutQuint, slide
animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, slidefade
animation = workspacesIn, 1, 1.21, almostLinear, slidefade
animation = workspacesOut, 1, 1.94, almostLinear, slidefade
}
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # You probably want this
}
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master {
new_status = master
}
# https://wiki.hyprland.org/Configuring/Variables/#misc
misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
}
#############
### INPUT ###
#############
# https://wiki.hyprland.org/Configuring/Variables/#input
input {
kb_layout = us
kb_variant =
kb_model = pc104
kb_options = caps:escape_shifted_capslock
kb_rules =
follow_mouse = 1
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
touchpad {
natural_scroll = true
}
}
# https://wiki.hyprland.org/Configuring/Variables/#gestures
gestures {
workspace_swipe = true
workspace_swipe_fingers = 3
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device {
name = epic-mouse-v1
sensitivity = -0.5
}
render {
explicit_sync = true
}
misc {
font_family = JetBrainsMono Nerd Font
}
# {{{ WORKSPACES
# workspace = name:,monitor:DP-1
# workspace = 2,monitor:DP-1,defaultName:
# workspace = 2,monitor:DP-1,persistent:false
# workspace = 3,monitor:DP-1,persistent:false
# workspace = 4,monitor:DP-1,persistent:false
# workspace = 5,monitor:DP-1,persistent:false
# workspace = 6,monitor:DP-3,persistent:false,default:true
# workspace = 7,monitor:DP-3,persistent:false
# workspace = 8,monitor:DP-3,persistent:false
# workspace = 9,monitor:DP-3,persistent:false
# workspace = 10,monitor:DP-3,persistent:false
workspace = w[1-10],monitor:eDP-1,persistent:false
# }}}
##############################
### WINDOWS AND WORKSPACES ###
##############################
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule v1
# windowrulev2 = float, class:com.mitchellh.ghostty
windowrulev2 = float, class:discord
windowrulev2 = float, class:mpv
windowrulev2 = workspace 10 silent, class:discord
windowrulev2 = opacity 0.88, class:.* fullscreen:0
# windowrulev2 = opacity 1, class:.* fullscreen:0
windowrulev2 = opacity 1, class:mpv fullscreen:0
windowrulev2 = opacity 1, class:anki fullscreen:0
windowrulev2 = opacity 1, class:remote-viewer
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
# https://github.com/hyprwm/Hyprland/issues/3835#issuecomment-2004448245
windowrulev2 = suppressevent maximize, class:^(zen)$
# exec-once = $HOME/.local/bin/bitwarden-nofloat.sh
# ENABLE_HDR_WSI=1 mpv --vo=gpu-next --target-colorspace-hint --gpu-api=vulkan --gpu-context=waylandvk "filename"
# {{{ Screen sharing workaround: https://wiki.hyprland.org/Useful-Utilities/Screen-Sharing/#xwayland
windowrulev2 = opacity 0.0 override, class:^(xwaylandvideobridge)$
windowrulev2 = noanim, class:^(xwaylandvideobridge)$
windowrulev2 = noinitialfocus, class:^(xwaylandvideobridge)$
windowrulev2 = maxsize 1 1, class:^(xwaylandvideobridge)$
windowrulev2 = noblur, class:^(xwaylandvideobridge)$
windowrulev2 = nofocus, class:^(xwaylandvideobridge)$
# }}}
+7 -4
View File
@@ -305,10 +305,10 @@ hl.config({
rounding = 10, rounding = 10,
rounding_power = 2, rounding_power = 2,
-- Change transparency of focused and unfocused windows -- Change transparency of focused and unfocused windows
-- active_opacity = 0.88 active_opacity = 0.95,
active_opacity = 1.0, -- active_opacity = 1.0,
-- inactive_opacity = 0.88 inactive_opacity = 0.88,
inactive_opacity = 1.0, -- inactive_opacity = 1.0,
shadow = { shadow = {
enabled = true, enabled = true,
range = 4, range = 4,
@@ -414,6 +414,9 @@ hl.on("hyprland.start", function()
hl.exec_cmd("uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1") hl.exec_cmd("uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1")
hl.exec_cmd("uwsm app -sb -t service -- gnome-keyring-daemon --start --components=secrets,ssh,pkcs11") hl.exec_cmd("uwsm app -sb -t service -- gnome-keyring-daemon --start --components=secrets,ssh,pkcs11")
hl.exec_cmd("uwsm app -sb -t service -- tailscale systray") hl.exec_cmd("uwsm app -sb -t service -- tailscale systray")
hl.exec_cmd(
'uwsm app -sb -t service -- mpvpaper -o "no-config no-audio loop-file=inf hwdec=auto panscan=1 video-pan-y=-0.05 scale=ewa_lanczossharp dscale=lanczos" ALL "$HOME/Pictures/wallpapers/lofi-hip-hop-ai-4k.mp4"'
)
hl.exec_cmd("~/.local/bin/aria") hl.exec_cmd("~/.local/bin/aria")
end) end)
@@ -0,0 +1,419 @@
-- This is an example Hyprland config file.
-- Refer to the wiki for more information.
-- https://wiki.hyprland.org/Configuring/
-- Please note not all available settings / options are set here.
-- For a full list, see the wiki
-- You can split this configuration into multiple files
-- Create your files separately and then link them to this file like this:
-- source = ~/.config/hypr/myColors.conf
--###############
--## MONITORS ###
--###############
-- See https://wiki.hyprland.org/Configuring/Monitors/
-- monitor=DP-1,2560x1440@144,0x0,1
-- monitor=DP-3,2560x1440@144,2560x0,1
-- vrr 2 enables vrr if application is fullscreen
-- vrr 3 enables vrr if application is fullscreen and video or game content
-- monitor = DP-1, 3440x1440@240,0x0,1,vrr,3
-- Generated by hyprlang2lua. Review TODOs before reloading Hyprland.
hl.monitor({
output = "DP-1",
mode = "3440x1440@240",
position = "0x0",
scale = 1,
vrr = 2,
cm = srgb,
-- Optional HDR settings
-- cm = "hdr",
bitdepth = 10,
sdr_min_luminance = 0.005,
sdr_max_luminance = 200,
min_luminance = 0,
max_luminance = 1000,
max_avg_luminance = 200,
sdrbrightness = 1.0,
sdrsaturation = 0.98,
})
-- Source: ~/.config/hypr/keybindings.conf — convert this file to Lua and ensure it is on Lua's package.path.
require("keybindings")
-- Source: ~/.config/hypr/windowrules.conf — convert this file to Lua and ensure it is on Lua's package.path.
require("windowrules")
-- Source: ~/.config/hypr/macchiato.conf — convert this file to Lua and ensure it is on Lua's package.path.
-- require("macchiato")
local rosewater = "rgb(f4dbd6)"
local rosewaterAlpha = "f4dbd6"
local flamingo = "rgb(f0c6c6)"
local flamingoAlpha = "f0c6c6"
local pink = "rgb(f5bde6)"
local pinkAlpha = "f5bde6"
local mauve = "rgb(c6a0f6)"
local mauveAlpha = "c6a0f6"
local red = "rgb(ed8796)"
local redAlpha = "ed8796"
local maroon = "rgb(ee99a0)"
local maroonAlpha = "ee99a0"
local peach = "rgb(f5a97f)"
local peachAlpha = "f5a97f"
local yellow = "rgb(eed49f)"
local yellowAlpha = "eed49f"
local green = "rgb(a6da95)"
local greenAlpha = "a6da95"
local teal = "rgb(8bd5ca)"
local tealAlpha = "8bd5ca"
local sky = "rgb(91d7e3)"
local skyAlpha = "91d7e3"
local sapphire = "rgb(7dc4e4)"
local sapphireAlpha = "7dc4e4"
local blue = "rgb(8aadf4)"
local blueAlpha = "8aadf4"
local lavender = "rgb(b7bdf8)"
local lavenderAlpha = "b7bdf8"
local text = "rgb(cad3f5)"
local textAlpha = "cad3f5"
local subtext1 = "rgb(b8c0e0)"
local subtext1Alpha = "b8c0e0"
local subtext0 = "rgb(a5adcb)"
local subtext0Alpha = "a5adcb"
local overlay2 = "rgb(939ab7)"
local overlay2Alpha = "939ab7"
local overlay1 = "rgb(8087a2)"
local overlay1Alpha = "8087a2"
local overlay0 = "rgb(6e738d)"
local overlay0Alpha = "6e738d"
local surface2 = "rgb(5b6078)"
local surface2Alpha = "5b6078"
local surface1 = "rgb(494d64)"
local surface1Alpha = "494d64"
local surface0 = "rgb(363a4f)"
local surface0Alpha = "363a4f"
local base = "rgb(24273a)"
local baseAlpha = "24273a"
local mantle = "rgb(1e2030)"
local mantleAlpha = "1e2030"
local crust = "rgb(181926)"
local crustAlpha = 181926
-- unscale XWayland
local terminal = "uwsm app -- ghostty +new-window"
local fileManager = "uwsm app -- thunar"
local menu = 'rofi -show drun -run-command "uwsm app -- {cmd}"'
local notification_daemon = "uwsm app -- swaync -c ~/.config/swaync/config.json"
hl.curve("easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } })
hl.curve("easeInOutCubic", { type = "bezier", points = { { 0.65, 0.05 }, { 0.36, 1 } } })
hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } })
hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1.0 } } })
hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } })
hl.animation({
leaf = "global",
enabled = true,
speed = 10,
bezier = "default",
})
hl.animation({
leaf = "border",
enabled = true,
speed = 5.39,
bezier = "easeOutQuint",
})
hl.animation({
leaf = "windows",
enabled = true,
speed = 4.79,
bezier = "easeOutQuint",
})
hl.animation({
leaf = "windowsIn",
enabled = true,
speed = 4.1,
bezier = "easeOutQuint",
style = "slide",
})
hl.animation({
leaf = "windowsOut",
enabled = true,
speed = 1.49,
bezier = "linear",
style = "slide",
})
hl.animation({
leaf = "fadeIn",
enabled = true,
speed = 1.73,
bezier = "almostLinear",
})
hl.animation({
leaf = "fadeOut",
enabled = true,
speed = 1.46,
bezier = "almostLinear",
})
hl.animation({
leaf = "fade",
enabled = true,
speed = 3.03,
bezier = "quick",
})
hl.animation({
leaf = "layers",
enabled = true,
speed = 3.81,
bezier = "easeOutQuint",
})
hl.animation({
leaf = "layersIn",
enabled = true,
speed = 4,
bezier = "easeOutQuint",
style = "fade",
})
hl.animation({
leaf = "layersOut",
enabled = true,
speed = 1.5,
bezier = "linear",
style = "fade",
})
hl.animation({
leaf = "fadeLayersIn",
enabled = true,
speed = 1.79,
bezier = "almostLinear",
})
hl.animation({
leaf = "fadeLayersOut",
enabled = true,
speed = 1.39,
bezier = "almostLinear",
})
hl.animation({
leaf = "workspaces",
enabled = true,
speed = 1.94,
bezier = "almostLinear",
style = "slidefade",
})
hl.animation({
leaf = "workspacesIn",
enabled = true,
speed = 1.21,
bezier = "almostLinear",
style = "slidefade",
})
hl.animation({
leaf = "workspacesOut",
enabled = true,
speed = 1.94,
bezier = "almostLinear",
style = "slidefade",
})
hl.device({
name = "epic-mouse-v1",
sensitivity = -0.5,
})
hl.layer_rule({
name = "fix-rofi",
match = {
namespace = "rofi",
},
-- TODO: manual review — unmapped layer rule: "no_anim"
})
hl.config({
xwayland = {
force_zero_scaling = true,
},
--##################
--## MY PROGRAMS ###
--##################
-- See https://wiki.hyprland.org/Configuring/Keywords/
-- Set programs that you use
-- $notification_daemon = dunst
--################
--## AUTOSTART ###
--################
-- Autostart necessary processes (like notifications daemons, status bars, etc.)
-- Or execute your favorite apps at launch like this:
-- exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
--############################
--## ENVIRONMENT VARIABLES ###
--############################
-- See https://wiki.hyprland.org/Configuring/Environment-variables/
-- env = XCURSOR_SIZE,24
-- env = HYPRCURSOR_SIZE,24
-- done in ../uswm/env and ../uswm/env-hyprland
--####################
--## LOOK AND FEEL ###
--####################
-- Refer to https://wiki.hyprland.org/Configuring/Variables/
-- https://wiki.hyprland.org/Configuring/Variables/#general
general = {
gaps_in = 5,
gaps_out = 8,
border_size = 2,
-- https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
col = {
active_border = {
colors = { "rgba(" .. mauveAlpha .. "ff)" },
angle = 45,
},
inactive_border = "rgba(" .. overlay0Alpha .. "ff)",
},
-- Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false,
-- Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false,
layout = "scrolling",
},
-- https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration = {
rounding = 10,
rounding_power = 2,
-- Change transparency of focused and unfocused windows
-- active_opacity = 0.88
active_opacity = 1.0,
-- inactive_opacity = 0.88
inactive_opacity = 1.0,
shadow = {
enabled = true,
range = 4,
render_power = 3,
color = "rgba(" .. surface0Alpha .. "ff)",
},
-- https://wiki.hyprland.org/Configuring/Variables/#blur
blur = {
enabled = true,
size = 7,
passes = 2,
xray = true,
vibrancy = 0.1696,
},
},
-- https://wiki.hyprland.org/Configuring/Variables/#animations
animations = {
enabled = true,
-- Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
-- slide, slidevert, fade, slidefade, slidefadevert
-- animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
-- animation = windowsOut, 1, 1.49, linear, popin 87%
},
-- Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
-- "Smart gaps" / "No gaps when only"
-- uncomment all if you wish to use that.
-- workspace = w[tv1], gapsout:0, gapsin:0
-- workspace = f[1], gapsout:0, gapsin:0
-- See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle = {
-- pseudotile = false, -- Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true,
split_width_multiplier = 1.69,
},
scrolling = {
fullscreen_on_one_column = true,
},
-- See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master = {
new_status = "slave",
allow_small_split = false,
},
-- https://wiki.hyprland.org/Configuring/Variables/#misc
misc = {
force_default_wallpaper = -1, -- Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false, -- If true disables the random hyprland logo / anime girl background. :(
font_family = "Manrope ExtraLight Medium, JetBrainsMono Nerd Font, M PLUS 1",
},
--############
--## INPUT ###
--############
-- https://wiki.hyprland.org/Configuring/Variables/#input
input = {
kb_layout = "us",
kb_variant = "",
kb_model = "pc86",
kb_options = "caps:escape_shifted_capslock",
kb_rules = "",
follow_mouse = 1,
sensitivity = 0, -- -1.0 - 1.0, 0 means no modification.
touchpad = {
natural_scroll = false,
},
},
-- https://wiki.hyprland.org/Configuring/Variables/#gestures
gestures = {
-- workspace_swipe = false
},
-- Example per-device config
-- See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
render = {
-- explicit_sync = true
},
-- {{{ WORKSPACES - HANDLED IN WAYBAR CONFIG
-- See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
-- workspace = name:,monitor:DP-1
-- workspace = 2,monitor:DP-1,defaultName:
-- workspace = 2,monitor:DP-1,persistent:false
-- workspace = 3,monitor:DP-1,persistent:false
-- workspace = 4,monitor:DP-1,persistent:false
-- workspace = 5,monitor:DP-1,persistent:false
-- workspace = 6,monitor:DP-3,persistent:false,default:true
-- workspace = 7,monitor:DP-3,persistent:false
-- workspace = 8,monitor:DP-3,persistent:false
-- workspace = 9,monitor:DP-3,persistent:false
-- workspace = 10,monitor:DP-3,persistent:false
-- }}}
-- windowrule = match:class my-window, border_size 10
debug = {
disable_logs = true,
enable_stdout_logs = false,
},
})
hl.on("hyprland.start", function()
hl.exec_cmd(notification_daemon)
hl.exec_cmd(terminal)
hl.exec_cmd("uwsm app -sb -S both -t scope -- hyprpm reload -n")
hl.exec_cmd("uwsm app -sb -t service -- nm-applet")
hl.exec_cmd(
"uwsm app -sb -t service -- waybar -c ~/.config/waybar/catppuccin-macchiato/config.jsonc -s ~/.config/waybar/catppuccin-macchiato/style.css"
)
hl.exec_cmd("uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1")
hl.exec_cmd("uwsm app -sb -t service -- gnome-keyring-daemon --start --components=secrets,ssh,pkcs11")
hl.exec_cmd("uwsm app -sb -t service -- tailscale systray")
hl.exec_cmd("~/.local/bin/aria")
end)
pcall(require, "/home/sudacode/.config/hypr/openwhispr-binds.lua")
-106
View File
@@ -1,106 +0,0 @@
# sample hyprlock.conf
# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock
#
# rendered text in all widgets supports pango markup (e.g. <b> or <i> tags)
# ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#general-remarks
#
# shortcuts to clear password buffer: ESC, Ctrl+U, Ctrl+Backspace
#
# you can get started by copying this config to ~/.config/hypr/hyprlock.conf
#
$font = Manrope ExtraLight
general {
hide_cursor = false
}
# uncomment to enable fingerprint authentication
auth {
fingerprint {
enabled = true
ready_message = Scan fingerprint to unlock
present_message = Scanning...
retry_delay = 250 # in milliseconds
}
}
animations {
enabled = true
bezier = linear, 1, 1, 0, 0
animation = fadeIn, 1, 5, linear
animation = fadeOut, 1, 5, linear
animation = inputFieldDots, 1, 2, linear
}
background {
monitor =
path = screenshot
blur_passes = 3
}
input-field {
monitor =
size = 20%, 5%
outline_thickness = 3
inner_color = rgba(0, 0, 0, 0.0) # no fill
outer_color = rgba(33ccffee) rgba(00ff99ee) 45deg
check_color = rgba(00ff99ee) rgba(ff6633ee) 120deg
fail_color = rgba(ff6633ee) rgba(ff0066ee) 40deg
font_color = rgb(143, 143, 143)
fade_on_empty = false
rounding = 15
font_family = $font
placeholder_text = Input password...
fail_text = $PAMFAIL
# uncomment to use a letter instead of a dot to indicate the typed password
# dots_text_format = *
# dots_size = 0.4
dots_spacing = 0.3
# uncomment to use an input indicator that does not show the password length (similar to swaylock's input indicator)
# hide_input = true
position = 0, -20
halign = center
valign = center
}
# TIME
label {
monitor =
text = $TIME # ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#variable-substitution
font_size = 90
font_family = $font
position = -30, 0
halign = right
valign = top
}
# DATE
label {
monitor =
text = cmd[update:60000] date +"%A, %d %B %Y" # update every 60 seconds
font_size = 25
font_family = $font
position = -30, -150
halign = right
valign = top
}
label {
monitor =
text = $LAYOUT[en,ru]
font_size = 24
onclick = hyprctl switchxkblayout all next
position = 250, -20
halign = center
valign = center
}
View File
Whitespace-only changes.
-10
View File
@@ -1,10 +0,0 @@
theme {
color_scheme = "/home/sudacode/.local/share/color-schemes/CatppuccinMacchiatoMauve.colors"
icon_theme = "Colloid-Purple-Catppuccin-Dark"
style = "kvantum-dark"
font_fixed = "JetBrainsMono Nerd Font"
font_fixed_size = 12
font = "Manrope ExtraLight"
font_size = 12
}
-12
View File
@@ -1,12 +0,0 @@
max-gamma = 100
profile {
time = 7:30
identity = true
}
profile {
time = 21:00
temperature = 5500
gamma = 1
}
-192
View File
@@ -1,192 +0,0 @@
# Set programs that you use
$terminal = FONTCONFIG_FILE=/home/sudacode/.config/ghostty/ghostty-fonts.conf uwsm app -sa -- ghostty
$fileManager = uwsm app -sa -- thunar
# $menu = rofi -show drun
# https://github.com/Vladimir-csp/uwsm#2-service-startup-notification-and-vars-set-by-compositor
# $menu = rofi -show drun -run-command "uwsm app -- {cmd}"
$menu = $HOME/.config/rofi/launchers/type-6/launcher.sh 1
# See https://wiki.hyprland.org/Configuring/Keywords/
$mainMod = ALT # Sets "Windows" key as main modifier
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = SUPER, SUPER_L, exec, $HOME/.config/rofi/launchers/type-2/launcher.sh 10
bind = $mainMod, RETURN, exec, $terminal
bind = $mainMod, Q, killactive,
bind = $mainMod SHIFT, M, exec, uwsm stop
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, d, exec, $menu
# bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod SHIFT, p, exec, "$HOME/.local/bin/hyprland-pin.sh"
# bind = $mainMod, t, togglesplit, # dwindle
bind = $mainMod, f, fullscreen,
bind = $mainMod, i, swapnext
# Move focus with mainMod + arrow keys
bind = $mainMod, h, movefocus, l
bind = $mainMod, l, movefocus, r
bind = $mainMod, k, movefocus, u
bind = $mainMod, j, movefocus, d
bind = $mainMod SHIFT, j, movewindow, d
bind = $mainMod SHIFT, k, movewindow, u
bind = $mainMod SHIFT, h, movewindow, l
bind = $mainMod SHIFT, l, movewindow, r
bind = $mainMod+SHIFT, c, centerwindow
# Move focus to next monitor
bind = CTRL+ALT, j, focusmonitor, r
bind = CTRL+ALT, k, focusmonitor, l
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspacesilent, 1
bind = $mainMod SHIFT, 2, movetoworkspacesilent, 2
bind = $mainMod SHIFT, 3, movetoworkspacesilent, 3
bind = $mainMod SHIFT, 4, movetoworkspacesilent, 4
bind = $mainMod SHIFT, 5, movetoworkspacesilent, 5
bind = $mainMod SHIFT, 6, movetoworkspacesilent, 6
bind = $mainMod SHIFT, 7, movetoworkspacesilent, 7
bind = $mainMod SHIFT, 8, movetoworkspacesilent, 8
bind = $mainMod SHIFT, 9, movetoworkspacesilent, 9
bind = $mainMod SHIFT, 0, movetoworkspacesilent, 10
# Example special workspace (scratchpad)
bind = SUPER, S, togglespecialworkspace, magic
bind = CTRL SHIFT, S, movetoworkspace, special:magic
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
bindel = ,F12, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,F11, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,F10, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
# Requires playerctl
bindl = , XF86AudioNext, exec, mpc next
bindl = , XF86AudioPause, exec, mpc toggle
bindl = , XF86AudioPlay, exec, mpc toggle
bindl = , XF86AudioPrev, exec, mpc prev
bindl = , F9, exec, playerctl next
bindl = , F8, exec, playerctl play-pause
bindl = , F7, exec, playerctl previous
# bindl = , XF86AudioStop, exec, mpc stop
# rofi
bind = $mainMod SHIFT, v, exec, uwsm app -sb -- rofi-rbw
# bind = $mainMod, w, exec, rofi -show window -theme $HOME/.config/rofi/launchers/type-2/style-2.rasi -dpi 96 -theme-str 'window {width: 35%;}'
bind = $mainMod SHIFT, w, exec, "$HOME/.config/rofi/scripts/rofi-wallpaper.sh"
bind = $mainMod SHIFT, d, exec, "$HOME/.config/rofi/scripts/rofi-docs.sh"
bind = SUPER SHIFT, j, exec, "$HOME/.config/rofi/scripts/rofi-jellyfin-dir.sh"
bind = SUPER, t, exec, "$HOME/.config/rofi/scripts/rofi-launch-texthooker-steam.sh"
bind = $mainMod SHIFT, t, exec, "$HOME/projects/scripts/popup-ai-translator.py"
# bind = SUPER SHIFT, g, exec, "$HOME/.config/rofi/scripts/rofi-vn-helper.sh"
bind = $mainMod SHIFT, i, exec, "$HOME/.config/rofi/scripts/rofi-image-browser.sh"
# ncmcppp
bind = $mainMod, n, exec, uwsm app -sb -- ghostty --command=/usr/bin/ncmpcpp
# notifications
bind = $mainMod SHIFT, n, exec, swaync-client -t
# mpv add
bind = SUPER, m, exec, ~/.local/bin/mpv-add.sh
bind = SUPER SHIFT, s, exec, slurp | grim -g - - | wl-copy
bind = ,code:107, exec, ~/.local/bin/screenshot
bind = SHIFT ,code:107, exec, ~/.local/bin/screenshot-active-window.sh
bind = SUPER,code:107, exec, ~/.local/bin/screenshot-active-window.sh -s
bind = SUPER, o, exec, ~/.local/bin/ocr.sh
bind = $mainMod, o, exec, ~/.local/bin/rofi-open tab
# bind = $mainMod SHIFT, o, exec, ~/.local/bin/rofi-open window
# change wallpaper
bind = $mainMod CTRL, n, exec, ~/.local/bin/change-wallpaper
# toggle focus between current and last focused window
bind = ALT, Tab, focuscurrentorlast
bind = CTRL, F9, pass, class:^(com\.obsproject\.Studio)$
bind = CTRL, F10, pass, class:^(com\.obsproject\.Studio)$
bind = CTRL SHIFT, D, exec, ~/.local/bin/dragon
bind = CTRL ALT, F, exec, ~/.local/bin/favorite-wallpaper
bind = $mainMod, z, exec, uwsm app -sb -- zen-browser
bind = $mainMod SHIFT, s, exec , rofi -show ssh -theme "$HOME/.config/rofi/launchers/type-2/style-2.rasi" -terminal -theme-str 'window{width: 25%;} listview {columns: 1; lines: 10;}' ghostty -ssh-command "ghostty --initial-command='TERM=kitty ssh {host}'"
# reload monitors
bind = CTRL $mainMod SHIFT, R, exec, hyprctl dispatch dpms off && sleep 1 && hyprctl dispatch dpms on
# Disable keybinds with one master keybind
# https://wiki.hypr.land/0.49.0/Configuring/Uncommon-tips--tricks/#disabling-keybinds-with-one-master-keybind
# PAGE DOWN
bind = $mainMod, code:117, exec, hyprctl eval 'hl.unbind("ALT + mouse:272"); hl.unbind("ALT + mouse:273")'
bind = $mainMod, code:117, submap, clean
submap = clean
# PAGE UP
bind = $mainMod, code:112, exec, hyprctl eval 'hl.bind("ALT + mouse:272", hl.dsp.window.drag(), { mouse = true }); hl.bind("ALT + mouse:273", hl.dsp.window.resize(), { mouse = true })'
bind = $mainMod, code:112, submap, reset
submap = reset
bind = SUPER, l, exec, hyprlock
# ANKI
bind = $mainMod, a, exec, ~/.config/rofi/scripts/rofi-anki-script.sh
# bind = $mainMod SHIFT, a, exec, ~/projects/scripts/screenshot-anki.sh -cdMinecraft
# GSM
# Side buttons intentionally unbound:
# mouse:275 / BTN_SIDE and mouse:276 / BTN_EXTRA pass through as native back/forward.
# bindl = , mouse:275, exec, xdotool key alt+w # top mouse to texthooker
# bindl = , mouse:276, exec, xdotool key alt+grave # bottom mouse to overlay
bind = ALT, g, exec, /opt/mpv-yomitan/mpv-yomitan.AppImage --toggle
# Hold Left Shift to show the GSM overlay while this submap is active.
bind = SUPER, g, submap, gsm
submap = gsm
bind = SHIFT SUPER, g, submap, reset
bind = SHIFT, Shift_L, pass, class:^(gsm_overlay)$
submap = reset
# F5
# bind = ,code:71, exec, ~/projects/scripts/whisper_record_transcribe.py --mode toggle --output type
bind = ,code:71, exec, uv run --directory ~/projects/scripts/faster-whisper-transcribe faster-whisper-transcribe --backend ctranslate2 --device cpu --mode toggle --output type
bind = ALT SHIFT, f, exec, uwsm app -sb -- flameshot gui
# SubMiner
bind = ALT SHIFT, O, pass, class:^(SubMiner)$
bind = ALT SHIFT, I, pass, class:^(SubMiner)$
bind = ALT SHIFT, C, pass, class:^(SubMiner)$
# {{{ scrolling
bind = $mainMod, comma, layoutmsg, swapcol l
bind = $mainMod, period, layoutmsg, fit all
bind = $mainMod, slash, layoutmsg, fit active
# }}}
-116
View File
@@ -1,116 +0,0 @@
# Set programs that you use
$terminal = uwsm app -sa -- ghostty
$fileManager = uwsm app -sa -- dolphin
# $menu = rofi -show drun
# https://github.com/Vladimir-csp/uwsm#2-service-startup-notification-and-vars-set-by-compositor
$menu = rofi -show drun -run-command "uwsm app -- {cmd}"
# See https://wiki.hyprland.org/Configuring/Keywords/
$mainMod = ALT # Sets "Windows" key as main modifier
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, RETURN, exec, $terminal
bind = $mainMod, Q, killactive,
bind = $mainMod, M, exec, uwsm stop
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, d, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, t, togglesplit, # dwindle
bind = $mainMod, f, fullscreen,
bind = $mainMod, i, swapactiveworkspaces, DP-1 DP-3
# Move focus with mainMod + arrow keys
bind = $mainMod, h, movefocus, l
bind = $mainMod, l, movefocus, r
bind = $mainMod, k, movefocus, u
bind = $mainMod, j, movefocus, d
bind = $mainMod SHIFT, j, movewindow, d
bind = $mainMod SHIFT, k, movewindow, u
bind = $mainMod SHIFT, h, movewindow, l
bind = $mainMod SHIFT, l, movewindow, r
# Move focus to next monitor
bind = CTRL+ALT, j, focusmonitor, r
bind = CTRL+ALT, k, focusmonitor, l
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspacesilent, 1
bind = $mainMod SHIFT, 2, movetoworkspacesilent, 2
bind = $mainMod SHIFT, 3, movetoworkspacesilent, 3
bind = $mainMod SHIFT, 4, movetoworkspacesilent, 4
bind = $mainMod SHIFT, 5, movetoworkspacesilent, 5
bind = $mainMod SHIFT, 6, movetoworkspacesilent, 6
bind = $mainMod SHIFT, 7, movetoworkspacesilent, 7
bind = $mainMod SHIFT, 8, movetoworkspacesilent, 8
bind = $mainMod SHIFT, 9, movetoworkspacesilent, 9
bind = $mainMod SHIFT, 0, movetoworkspacesilent, 10
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
# rofi
bind = $mainMod SHIFT, v, exec, uwsm app -sb -- rofi-rbw
# ncmcppp
bind = $mainMod, n, exec, uwsm app -sb -- ghostty --command=/usr/bin/ncmpcpp
# notifications
bind = $mainMod SHIFT, n, exec, swaync-client -t
# mpv add
bind = SUPER, m, exec, ~/.local/bin/mpv-add.sh
bind = SUPER SHIFT, s, exec, ~/.local/bin/screenshot.sh
bind = ,code:107, exec, ~/.local/bin/screenshot.sh
bind = SUPER SHIFT, o, exec, ~/.local/bin/ocr.sh
bind = $mainMod, o, exec, ~/.local/bin/ocr.sh
# change wallpaper
bind = $mainMod CTRL, n, exec, ~/.local/bin/change-wallpaper.sh
# toggle focus between current and last focused window
bind = ALT, Tab, focuscurrentorlast
bind = CTRL, F9, pass, class:^(com\.obsproject\.Studio)$
bind = CTRL, F10, pass, class:^(com\.obsproject\.Studio)$
bind = CTRL SHIFT, D, exec, ~/.local/bin/dragon
bind = CTRL ALT, F, exec, ~/.local/bin/favorite-wallpaper
+6 -1
View File
@@ -225,7 +225,12 @@ hl.define_submap("gsm", function()
hl.bind("SUPER + SHIFT + g", hl.dsp.submap("reset")) hl.bind("SUPER + SHIFT + g", hl.dsp.submap("reset"))
hl.bind("SHIFT + Shift_L", hl.dsp.global("com.beangate.gamesentenceminer:gsm:manual-show")) hl.bind("SHIFT + Shift_L", hl.dsp.global("com.beangate.gamesentenceminer:gsm:manual-show"))
hl.bind("SHIFT + SPACE", hl.dsp.global("com.beangate.gamesentenceminer:gsm:manual-show")) hl.bind("SHIFT + SPACE", hl.dsp.global("com.beangate.gamesentenceminer:gsm:manual-show"))
hl.bind("code:276", hl.dsp.global("com.beangate.gamesentenceminer:gsm:manual-show")) -- Use Right Shift to avoid the Left Shift binding; ydotool input reaches compositor shortcuts.
hl.bind(
"mouse:276",
hl.dsp.exec_cmd([[env YDOTOOL_SOCKET="$XDG_RUNTIME_DIR/.ydotool_socket" ydotool key 54:1 57:1 57:0 54:0]]),
{ release = true }
)
end) end)
hl.bind("ALT + SHIFT + f", hl.dsp.exec_cmd("uwsm app -sb -- flameshot gui")) hl.bind("ALT + SHIFT + f", hl.dsp.exec_cmd("uwsm app -sb -- flameshot gui"))
-78
View File
@@ -1,78 +0,0 @@
$rosewater = rgb(f4dbd6)
$rosewaterAlpha = f4dbd6
$flamingo = rgb(f0c6c6)
$flamingoAlpha = f0c6c6
$pink = rgb(f5bde6)
$pinkAlpha = f5bde6
$mauve = rgb(c6a0f6)
$mauveAlpha = c6a0f6
$red = rgb(ed8796)
$redAlpha = ed8796
$maroon = rgb(ee99a0)
$maroonAlpha = ee99a0
$peach = rgb(f5a97f)
$peachAlpha = f5a97f
$yellow = rgb(eed49f)
$yellowAlpha = eed49f
$green = rgb(a6da95)
$greenAlpha = a6da95
$teal = rgb(8bd5ca)
$tealAlpha = 8bd5ca
$sky = rgb(91d7e3)
$skyAlpha = 91d7e3
$sapphire = rgb(7dc4e4)
$sapphireAlpha = 7dc4e4
$blue = rgb(8aadf4)
$blueAlpha = 8aadf4
$lavender = rgb(b7bdf8)
$lavenderAlpha = b7bdf8
$text = rgb(cad3f5)
$textAlpha = cad3f5
$subtext1 = rgb(b8c0e0)
$subtext1Alpha = b8c0e0
$subtext0 = rgb(a5adcb)
$subtext0Alpha = a5adcb
$overlay2 = rgb(939ab7)
$overlay2Alpha = 939ab7
$overlay1 = rgb(8087a2)
$overlay1Alpha = 8087a2
$overlay0 = rgb(6e738d)
$overlay0Alpha = 6e738d
$surface2 = rgb(5b6078)
$surface2Alpha = 5b6078
$surface1 = rgb(494d64)
$surface1Alpha = 494d64
$surface0 = rgb(363a4f)
$surface0Alpha = 363a4f
$base = rgb(24273a)
$baseAlpha = 24273a
$mantle = rgb(1e2030)
$mantleAlpha = 1e2030
$crust = rgb(181926)
$crustAlpha = 181926
+2
View File
@@ -0,0 +1,2 @@
-- OpenWhispr keybinds (managed automatically)
-- If you delete this file, also remove the matching load line from your Hyprland config.
-111
View File
@@ -1,111 +0,0 @@
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# {{{ Floating windows
windowrule = float on, match:class discord
windowrule = float on, match:class mpv
windowrule = float on, match:class anki
windowrule = float on, match:class steam
windowrule = float on, match:class python, match:title Import
windowrule = float on, match:class zenity, match:title Japanese Analysis
windowrule = float on, match:class zenity, match:title Japanese Assistant
windowrule = min_size 1600 600, match:class anki
windowrule = max_size 2222 1234, match:class anki
windowrule = no_focus on, no_follow_mouse 1, float on, no_shadow on, no_anim on, match:class ueberzugpp.*
windowrule = size 1920 1080, match:class anki
# windowrule = min_size 1600 600, match:class anki
# windowrule = max_size 2222 1234, match:class anki
# }}}
# {{{ Workspace assignments
windowrule = workspace 3 silent, match:class Cursor
windowrule = workspace 5 silent, match:class GameSentenceMiner
windowrule = workspace 5 silent, match:class com.obsproject.Studio
windowrule = workspace 6 silent, match:class gamescope
windowrule = workspace 8 silent, match:class anki
windowrule = workspace 9 silent, match:class steam
windowrule = workspace 10 silent, match:class discord
# }}}
# {{{ Center floating windows
windowrule = match:float 1, match:class discord, center on
windowrule = match:float 1, match:class anki, center on
# }}}
# {{{ Opacity rules
# windowrule = opacity 0.88, match:class .* fullscreen:0
windowrule = opacity 1.0 override, match:class mpv
windowrule = opacity 1.0 override, match:class ^(remote-viewer)$
windowrule = opacity 1.0 override, match:class com.obsproject.Studio
windowrule = opacity 1.0 override, match:title (.*)(- YouTube(.*))
windowrule = opacity 1.0 override, match:class zen, match:title (.*)YouTube TV(.*)
windowrule = opacity 1.0 override, match:class anki
windowrule = opacity 1.0 override, match:title (.*)asbplayer
windowrule = opacity 1.0 override, match:class dolphin-emu
windowrule = opacity 1.0 override, match:class steam_app_default
windowrule = opacity 1.0 override, match:class steam_app.*
windowrule = opacity 1.0 override, match:class Rustdesk
windowrule = opacity 1.0 override, match:class google-chrome
# }}}
# {{{ Misc
windowrule = tile on, match:title (.*)asbplayer
# windowrule = size 2118 1182, match:class anki
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppress_event maximize, match:class .*
# Fix some dragging issues with XWayland
windowrule = no_focus on,match:class ^$,match:title ^$,match:xwayland 1,match:float 1,match:fullscreen 0,match:pin 0
# }}}
# {{{ Screen sharing workaround: https://wiki.hyprland.org/Useful-Utilities/Screen-Sharing/#xwayland
windowrule = opacity 0.0 override, match:class ^(xwaylandvideobridge)$
windowrule = no_anim on, match:class ^(xwaylandvideobridge)$
windowrule = no_initial_focus on, match:class ^(xwaylandvideobridge)$
windowrule = max_size 1 1, match:class ^(xwaylandvideobridge)$
windowrule = no_blur on, match:class ^(xwaylandvideobridge)$
windowrule = no_focus on, match:class ^(xwaylandvideobridge)$
# }}}
# {{{ GSM Overlay and LunaTranslator tweaks
windowrule = float on, match:class gsm_overlay
windowrule = border_size 0, match:class gsm_overlay
windowrule = xray off, match:class gsm_overlay
windowrule = no_shadow on, match:class gsm_overlay
windowrule = no_blur on, match:class gsm_overlay
windowrule = opacity 1.0 override, match:title LunaTranslator
windowrule = border_size 0, match:title LunaTranslator
windowrule = stay_focused on, match:class gsm_overlay
# windowrule = fullscreen_state 2, match:class gsm_overlay
windowrule = float on, match:class SubMiner
windowrule = border_size 0, match:class SubMiner
windowrule = xray off override, match:class SubMiner
windowrule = no_shadow on, match:class SubMiner
windowrule = no_blur on, match:class SubMiner
windowrule = no_dim on, match:class SubMiner
windowrule = opaque on, match:class SubMiner
windowrule = dim_around off, match:class SubMiner
windowrule = allows_input offf, match:class SubMiner
windowrule = border_size 0, match:class steam_app_1277940
windowrule = opacity 1.0 override, match:class SubMiner
windowrule = pin off, match:class SubMiner
# }}}
# {{{ FEH
windowrule = float on, match:class feh
windowrule = center on, match:class feh
windowrule = border_size 0, match:class feh
windowrule = no_shadow on, match:class feh
windowrule = no_blur on, match:class feh
windowrule = no_anim on, match:class feh
# }}}
windowrule = float on, match:title Picture in picture
windowrule = pin on, match:title Picture in picture
windowurle = no_vrr on, match:class mpv
# aibar popup (AI usage widget)
windowrule = float on, match:title aibar
windowrule = move 100%-374 50, match:title aibar
+1 -1
View File
@@ -185,7 +185,7 @@ hl.window_rule({
hl.window_rule({ hl.window_rule({
match = { match = {
title = "(.*)(- YouTube(.*))", title = ".*YouTube.*",
}, },
opacity = "1.0 override", opacity = "1.0 override",
}) })
+2 -2
View File
@@ -70,7 +70,7 @@ x-scheme-handler/tg=org.telegram.desktop.desktop;org.telegram.desktop._f79d601e2
x-scheme-handler/tonsite=org.telegram.desktop.desktop; x-scheme-handler/tonsite=org.telegram.desktop.desktop;
x-scheme-handler/tradingview=tradingview.desktop;TradingView.desktop; x-scheme-handler/tradingview=tradingview.desktop;TradingView.desktop;
application/x-wine-extension-ini=nvim.desktop; application/x-wine-extension-ini=nvim.desktop;
x-scheme-handler/subminer=subminer.desktop;SubMiner.desktop; x-scheme-handler/subminer=subminer.desktop;
x-scheme-handler/t3code=t3code-url-handler.desktop;t3code.desktop; x-scheme-handler/t3code=t3code-url-handler.desktop;t3code.desktop;
[Default Applications] [Default Applications]
@@ -156,7 +156,7 @@ text/vnd.trolltech.linguist=helium.desktop;zen.desktop
x-scheme-handler/nxm=modorganizer2-nxm-handler.desktop x-scheme-handler/nxm=modorganizer2-nxm-handler.desktop
x-scheme-handler/discord-1361252452329848892=discord-1361252452329848892.desktop x-scheme-handler/discord-1361252452329848892=discord-1361252452329848892.desktop
x-scheme-handler/opencode=opencode-desktop-handler.desktop x-scheme-handler/opencode=opencode-desktop-handler.desktop
x-scheme-handler/subminer=subminer.desktop x-scheme-handler/subminer=SubMiner.desktop
x-scheme-handler/claude-cli=claude-code-url-handler.desktop x-scheme-handler/claude-cli=claude-code-url-handler.desktop
x-scheme-handler/mux=mux.desktop x-scheme-handler/mux=mux.desktop
x-scheme-handler/claude=com.anthropic.claude-desktop.desktop x-scheme-handler/claude=com.anthropic.claude-desktop.desktop
+1 -1
View File
@@ -284,5 +284,5 @@ g-w script-binding select/select-watch-later
# }}} # }}}
# {{{ IMMERSION TRACKER # {{{ IMMERSION TRACKER
ctrl+t script-binding immersion_tracker/immersion_tracking # ctrl+t script-binding immersion_tracker/immersion_tracking
# }}} # }}}
+15 -15
View File
@@ -10,15 +10,15 @@
"cmp-nvim-lsp-document-symbol": { "branch": "main", "commit": "f94f7ba948e32cd302caba1c2ca3f7c697fb4fcf" }, "cmp-nvim-lsp-document-symbol": { "branch": "main", "commit": "f94f7ba948e32cd302caba1c2ca3f7c697fb4fcf" },
"cmp-nvim-lsp-signature-help": { "branch": "main", "commit": "fd3e882e56956675c620898bf1ffcf4fcbe7ec84" }, "cmp-nvim-lsp-signature-help": { "branch": "main", "commit": "fd3e882e56956675c620898bf1ffcf4fcbe7ec84" },
"cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" },
"codecompanion.nvim": { "branch": "main", "commit": "5319d842938d9a971d2aa38be57f4ecf120ef83b" }, "codecompanion.nvim": { "branch": "main", "commit": "052ad5ade662ea3e3a6b99bc39a6bf3ce1c42892" },
"conform.nvim": { "branch": "master", "commit": "016802de402556da54c36bd7359b441266b01cdd" }, "conform.nvim": { "branch": "master", "commit": "016802de402556da54c36bd7359b441266b01cdd" },
"copilot-cmp": { "branch": "master", "commit": "15fc12af3d0109fa76b60b5cffa1373697e261d1" }, "copilot-cmp": { "branch": "master", "commit": "15fc12af3d0109fa76b60b5cffa1373697e261d1" },
"copilot-lualine": { "branch": "main", "commit": "222e90bd8dcdf16ca1efc4e784416afb5f011c31" }, "copilot-lualine": { "branch": "main", "commit": "222e90bd8dcdf16ca1efc4e784416afb5f011c31" },
"copilot.lua": { "branch": "master", "commit": "f76a0a281de089e27b605ec8017093f1aab73b07" }, "copilot.lua": { "branch": "master", "commit": "82607bbb8528222a9a28bfcab0aceb3a7fed7e85" },
"diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" }, "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
"fidget.nvim": { "branch": "main", "commit": "9e0201673e08e997e7cf52afca5565c70bd117f3" }, "fidget.nvim": { "branch": "main", "commit": "9e0201673e08e997e7cf52afca5565c70bd117f3" },
"friendly-snippets": { "branch": "main", "commit": "b4d01b0fdf3c9a549961c2f9ffe8dc09be166219" }, "friendly-snippets": { "branch": "main", "commit": "b2ea5c41a150ba72fb656eedb4ed0a86d138d945" },
"gitsigns.nvim": { "branch": "main", "commit": "070a5d7b985546cc57e1fc61e5bc507fecac6045" }, "gitsigns.nvim": { "branch": "main", "commit": "1e9d0fbfe7ff848bc402d2c2e2854fb4eff2dce7" },
"goto-preview": { "branch": "main", "commit": "d2d6923c9b9e0e43f0b9b566f261a8b1ae016540" }, "goto-preview": { "branch": "main", "commit": "d2d6923c9b9e0e43f0b9b566f261a8b1ae016540" },
"hererocks": { "branch": "master", "commit": "5d77b0bafc8b96f82355ca2ce5637c00d78a065c" }, "hererocks": { "branch": "master", "commit": "5d77b0bafc8b96f82355ca2ce5637c00d78a065c" },
"image.nvim": { "branch": "master", "commit": "365e2ace0f619164ae6fd2f6f1d2807775dd6849" }, "image.nvim": { "branch": "master", "commit": "365e2ace0f619164ae6fd2f6f1d2807775dd6849" },
@@ -28,24 +28,24 @@
"lspkind.nvim": { "branch": "master", "commit": "c7274c48137396526b59d86232eabcdc7fed8a32" }, "lspkind.nvim": { "branch": "master", "commit": "c7274c48137396526b59d86232eabcdc7fed8a32" },
"lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" }, "lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" },
"mcphub.nvim": { "branch": "main", "commit": "7cd5db330f41b7bae02b2d6202218a061c3ebc1f" }, "mcphub.nvim": { "branch": "main", "commit": "7cd5db330f41b7bae02b2d6202218a061c3ebc1f" },
"mini.diff": { "branch": "main", "commit": "626b8a5b93874c4d05ca25aedec56cfff0b378fb" }, "mini.diff": { "branch": "main", "commit": "47ab8cf21c62cfd952008f2b9e79417c98173ec1" },
"mini.nvim": { "branch": "main", "commit": "561751e839b99a4baca36b9d963166b66d2536a6" }, "mini.nvim": { "branch": "main", "commit": "a03ad899bda446b5a81cfa99d8aeeb92241522f3" },
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" }, "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
"nui.nvim": { "branch": "main", "commit": "10fc361835c856ba4233ef5ea135b919bf3dce97" }, "nui.nvim": { "branch": "main", "commit": "10fc361835c856ba4233ef5ea135b919bf3dce97" },
"nvim-autopairs": { "branch": "master", "commit": "430522f95fe4fb7c511ec64f8c1a90cc6a66c05c" }, "nvim-autopairs": { "branch": "master", "commit": "3172f40c16563db871a58f20d205c710ad782311" },
"nvim-cmp": { "branch": "main", "commit": "2ffe79f1f021def8dd1fcd81deb16f1bb0d989f3" }, "nvim-cmp": { "branch": "main", "commit": "2ffe79f1f021def8dd1fcd81deb16f1bb0d989f3" },
"nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" }, "nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" },
"nvim-html-css": { "branch": "main", "commit": "3f246f6166e75fb8afc1866ce8f1e4cb8d95757a" }, "nvim-html-css": { "branch": "main", "commit": "3f246f6166e75fb8afc1866ce8f1e4cb8d95757a" },
"nvim-lint": { "branch": "master", "commit": "3d55c8f67c6ae5c15e1042571e107c7a3d5c5f4e" }, "nvim-lint": { "branch": "master", "commit": "52107ce2076a27a285af781248e2c59bad817cd0" },
"nvim-lspconfig": { "branch": "master", "commit": "046b1a797af1effe8e0474b9af9657a3761ec58a" }, "nvim-lspconfig": { "branch": "master", "commit": "4b2b045b8ceb035f5c8bc9cab19b95706bfa6a19" },
"nvim-nio": { "branch": "master", "commit": "edcc181a875301dd21840189aa2f2f9ad69fc172" }, "nvim-nio": { "branch": "master", "commit": "edcc181a875301dd21840189aa2f2f9ad69fc172" },
"nvim-treesitter": { "branch": "main", "commit": "f603a2f4da48728f80257fb5fbb90145fd1dc173" }, "nvim-treesitter": { "branch": "main", "commit": "a2f694478be07f89c2d03cc17858a8745a400c4b" },
"nvim-treesitter-context": { "branch": "master", "commit": "f3061339b8eaf9fda873600bc425b8d2d8502533" }, "nvim-treesitter-context": { "branch": "master", "commit": "8decd73460d26ef0a0befb745d022dd1fc2c38b8" },
"nvim-web-devicons": { "branch": "master", "commit": "58447c1fca354bbf184425e4a8d01deecbd6f3c4" }, "nvim-web-devicons": { "branch": "master", "commit": "ec309a0eaff6ea967e58c275996155ab5c16938d" },
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
"presence.nvim": { "branch": "main", "commit": "87c857a56b7703f976d3a5ef15967d80508df6e6" }, "presence.nvim": { "branch": "main", "commit": "87c857a56b7703f976d3a5ef15967d80508df6e6" },
"rainbow-delimiters.nvim": { "branch": "master", "commit": "3a0fc08dd39e8bf034a4cfef3f2845bd5f565a2e" }, "rainbow-delimiters.nvim": { "branch": "master", "commit": "65734f76783705255d9ede8a6e4692e1572801a5" },
"render-markdown.nvim": { "branch": "main", "commit": "640a3ec6d538bad17c328be373c7cad0293d9589" }, "render-markdown.nvim": { "branch": "main", "commit": "8e8795368391036643b622875a6da6a51bcd33f4" },
"snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" }, "snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" },
"telescope-color-names.nvim": { "branch": "main", "commit": "95b372b9a8ba0fc7cf6a67be637ee37453f322da" }, "telescope-color-names.nvim": { "branch": "main", "commit": "95b372b9a8ba0fc7cf6a67be637ee37453f322da" },
"telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" }, "telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" },
@@ -56,6 +56,6 @@
"vim-commentary": { "branch": "master", "commit": "64a654ef4a20db1727938338310209b6a63f60c9" }, "vim-commentary": { "branch": "master", "commit": "64a654ef4a20db1727938338310209b6a63f60c9" },
"vim-dotenv": { "branch": "master", "commit": "5c51cfcf8d87280d6414e03cd6b253eb70ecb800" }, "vim-dotenv": { "branch": "master", "commit": "5c51cfcf8d87280d6414e03cd6b253eb70ecb800" },
"vim-surround": { "branch": "master", "commit": "3d188ed2113431cf8dac77be61b842acb64433d9" }, "vim-surround": { "branch": "master", "commit": "3d188ed2113431cf8dac77be61b842acb64433d9" },
"vim-wakatime": { "branch": "master", "commit": "9f8a1d3b9c6f3a948988a0896b3227c1e1f74a58" }, "vim-wakatime": { "branch": "master", "commit": "98cb7a8a09f8a0cb225b5955bf491ffb9860569f" },
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
} }