Compare commits
6 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c97029f654 | ||
|
|
1fce1979c3 | ||
|
|
72afe790fd | ||
|
|
e073a17353 | ||
|
|
3865327c66 | ||
|
|
670cf22f2c |
41 changed files with 70136 additions and 11372 deletions
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
set -euo pipefail
|
||||
PKG_DIR="/srv/breadway-dl/dev/bread/${VERSION}"
|
||||
mkdir -p "${PKG_DIR}"
|
||||
for bin in breadd bread; do
|
||||
for bin in breadd bread bread-emit bread-module-host; do
|
||||
cp "src/target/release/${bin}" "${PKG_DIR}/${bin}-x86_64"
|
||||
strip "${PKG_DIR}/${bin}-x86_64"
|
||||
sha256sum "${PKG_DIR}/${bin}-x86_64" | awk '{print $1}' \
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ jobs:
|
|||
VERSION="${GITHUB_REF_NAME#v}"
|
||||
PKG_DIR="/srv/breadway-dl/beta/bread/${VERSION}"
|
||||
mkdir -p "${PKG_DIR}"
|
||||
for bin in breadd bread; do
|
||||
for bin in breadd bread bread-emit bread-module-host; do
|
||||
cp "src/target/release/${bin}" "${PKG_DIR}/${bin}-x86_64"
|
||||
strip "${PKG_DIR}/${bin}-x86_64"
|
||||
sha256sum "${PKG_DIR}/${bin}-x86_64" | awk '{print $1}' \
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
VERSION="${GITHUB_REF_NAME#v}"
|
||||
PKG_DIR="/srv/breadway-dl/bread/${VERSION}"
|
||||
mkdir -p "${PKG_DIR}"
|
||||
for bin in breadd bread; do
|
||||
for bin in breadd bread bread-emit bread-module-host; do
|
||||
cp "src/target/release/${bin}" "${PKG_DIR}/${bin}-x86_64"
|
||||
strip "${PKG_DIR}/${bin}-x86_64"
|
||||
sha256sum "${PKG_DIR}/${bin}-x86_64" | awk '{print $1}' \
|
||||
|
|
@ -48,9 +48,13 @@ jobs:
|
|||
echo "::error::BAKERY_MINISIGN_SEC_KEY_PATH secret not set — refusing to regenerate index.json unsigned (would leave a stale signature mismatched against fresh content and break bakery for everyone)"
|
||||
exit 1
|
||||
fi
|
||||
rm -rf /tmp/bread-ecosystem-ci
|
||||
git clone https://git.breadway.dev/Breadway/bread-ecosystem.git /tmp/bread-ecosystem-ci
|
||||
bash /tmp/bread-ecosystem-ci/scripts/gen-index.sh
|
||||
rm -rf /tmp/bread-ecosystem-ci-* 2>/dev/null || true
|
||||
# mktemp: a fixed clone path races when multiple repos' release
|
||||
# workflows run close together on the same self-hosted runner.
|
||||
ECOSYSTEM_CI_DIR="$(mktemp -d /tmp/bread-ecosystem-ci-XXXXXX)"
|
||||
git clone https://git.breadway.dev/Breadway/bread-ecosystem.git "${ECOSYSTEM_CI_DIR}"
|
||||
bash "${ECOSYSTEM_CI_DIR}/scripts/gen-index.sh"
|
||||
rm -rf "${ECOSYSTEM_CI_DIR}"
|
||||
|
||||
- name: upload to GitHub Release
|
||||
env:
|
||||
|
|
@ -64,6 +68,10 @@ jobs:
|
|||
gh release upload "${GITHUB_REF_NAME}" --repo Breadway/bread \
|
||||
"${PKG_DIR}/breadd-x86_64" \
|
||||
"${PKG_DIR}/bread-x86_64" \
|
||||
"${PKG_DIR}/bread-emit-x86_64" \
|
||||
"${PKG_DIR}/bread-module-host-x86_64" \
|
||||
"${PKG_DIR}/breadd-x86_64.sha256" \
|
||||
"${PKG_DIR}/bread-x86_64.sha256" \
|
||||
"${PKG_DIR}/bread-emit-x86_64.sha256" \
|
||||
"${PKG_DIR}/bread-module-host-x86_64.sha256" \
|
||||
--clobber
|
||||
|
|
|
|||
12
.grok/config.toml
Normal file
12
.grok/config.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Copied from .claude/settings.local.json
|
||||
[permission]
|
||||
allow = [
|
||||
"Bash(cargo test *)",
|
||||
"Bash(/home/breadway/Projects/bread/target/debug/bread health *)",
|
||||
"Bash(/home/breadway/Projects/bread/target/debug/bread sync *)",
|
||||
"Bash(python3 *)",
|
||||
"Bash(/home/breadway/Projects/bread/target/debug/bread modules *)",
|
||||
"Bash(/home/breadway/Projects/bread/target/debug/bread doctor *)",
|
||||
"Bash(/home/breadway/Projects/bread/target/debug/bread reload *)",
|
||||
"Bash(cargo build *)",
|
||||
]
|
||||
20
CLAUDE.md
Normal file
20
CLAUDE.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# CLAUDE.md — Repo hygiene
|
||||
|
||||
This repo follows the branch/release workflow documented in `CONTRIBUTING.md`
|
||||
— read and follow it for any git, branch, or release work here (the
|
||||
dev/beta/main lifecycle, `feature/x`/`fix/x` branch naming, when to cut or
|
||||
reset `beta`, etc). Don't improvise a different workflow.
|
||||
When starting work on a new feature, create branch "feature/<feature-name>" \
|
||||
When working on a bug or issue, create branch "fix/<issue you are fixing>"
|
||||
|
||||
## Remotes
|
||||
- `origin` — Forgejo (`git.breadway.dev` via Hestia, SSH) — authoritative.
|
||||
- `github` — GitHub mirror. Push both when publishing.
|
||||
|
||||
## CI
|
||||
- `dev-release.yml` triggers on `push: branches: ['dev']`; `beta-release.yml`
|
||||
on `push: branches: ['beta']`; `release.yml` on a `v*` tag push. `package.yml` triggers the same way for the pacman-channel package.
|
||||
None of these run on plain commits or PRs beyond what's listed.
|
||||
|
||||
## Don't
|
||||
- Don't embed credentials in remote URLs — SSH or a credential helper only.
|
||||
|
|
@ -237,6 +237,12 @@ bread modules audit <name> # Scan a module's Lua source and suggest a
|
|||
# Hooks
|
||||
bread hooks install-shell [shell] # Install precmd/preexec/chpwd shell hooks (auto-detects $SHELL)
|
||||
bread hooks install-git # Install git hooks (post-commit/checkout/merge) in the current repo
|
||||
|
||||
# Compositor integration
|
||||
bread init # Install breadbar's Hyprland layer-rule integration (shows a diff, asks to confirm)
|
||||
bread init --dry-run # Print the proposed diff only, change nothing
|
||||
bread init --yes # Skip the confirmation prompt (scripted/image builds)
|
||||
bread init --undo # Remove the previously installed integration
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -608,3 +608,8 @@ since = "0.7"
|
|||
name = "doctor"
|
||||
kind = "cli_command"
|
||||
since = "0.7"
|
||||
|
||||
[[entry]]
|
||||
name = "init"
|
||||
kind = "cli_command"
|
||||
since = "0.8"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,20 @@
|
|||
//! user later doesn't want it, an rc-file edit is much harder to notice and
|
||||
//! undo than a printed snippet they chose to paste in.
|
||||
//!
|
||||
//! `bread init` (`init.rs`) looks like it breaks this rule — it does
|
||||
//! propose an edit to a user's own `hyprland.lua` — but it's a narrower,
|
||||
//! consent-gated exception, not a reversal of it. The difference is what's
|
||||
//! silent about the failure mode: a missing shell hook is invisible
|
||||
//! enrichment (no telemetry, nothing looks wrong), so leaving it to the
|
||||
//! user to paste in at their own pace is the right default. A missing
|
||||
//! compositor layer rule is not invisible — breadbar renders unblurred and
|
||||
//! with the wrong opacity, which reads as "this app is broken," not
|
||||
//! "optional feature not enabled," and there's no snippet a user could be
|
||||
//! expected to reverse-engineer for that. `init.rs` earns the edit by
|
||||
//! showing the exact diff, requiring explicit consent (prompt, `--yes`, or
|
||||
//! nothing at all without a TTY), backing up the file first, and shipping
|
||||
//! a real `--undo`. See `init.rs`'s module docs for the full rationale.
|
||||
//!
|
||||
//! # Why bread-emit, not `bread emit`
|
||||
//!
|
||||
//! The generated hooks shell out to the separate `bread-emit` binary
|
||||
|
|
|
|||
1281
bread-cli/src/init.rs
Normal file
1281
bread-cli/src/init.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,4 @@
|
|||
mod init;
|
||||
mod hooks_git;
|
||||
mod hooks_shell;
|
||||
mod modules_mgmt;
|
||||
|
|
@ -99,6 +100,22 @@ enum Commands {
|
|||
#[arg(long)]
|
||||
json: bool,
|
||||
},
|
||||
/// Install bread's Hyprland compositor layer-rule integration
|
||||
/// (breadbar/breadbox blur, ignore_alpha, animation) into
|
||||
/// ~/.config/hypr/hyprland.lua, with consent, a backup, and full undo.
|
||||
/// See bread-cli/src/init.rs for the design rationale.
|
||||
Init {
|
||||
/// Print the proposed diff and change nothing
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
/// Skip the confirmation prompt (for scripted/image builds)
|
||||
#[arg(long)]
|
||||
yes: bool,
|
||||
/// Remove the previously installed marked block instead of
|
||||
/// installing it
|
||||
#[arg(long)]
|
||||
undo: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
|
|
@ -224,6 +241,9 @@ async fn main() -> Result<()> {
|
|||
print_doctor(&socket).await?;
|
||||
}
|
||||
}
|
||||
Commands::Init { dry_run, yes, undo } => {
|
||||
init::run(dry_run, yes, undo)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -691,6 +711,7 @@ async fn print_doctor(socket: &Path) -> Result<()> {
|
|||
println!();
|
||||
println!(" start the daemon: systemctl --user start breadd");
|
||||
println!(" view logs: journalctl --user -u breadd -f");
|
||||
print_compositor_doctor_section();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -775,6 +796,20 @@ fn render_doctor(health: &Value) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_compositor_doctor_section();
|
||||
}
|
||||
|
||||
/// Compositor integration status — pure filesystem check, independent of
|
||||
/// the daemon, so it prints the same whether breadd is up or not. Reports
|
||||
/// only; `bread doctor` never installs anything (that's `bread init`'s
|
||||
/// job).
|
||||
fn print_compositor_doctor_section() {
|
||||
println!();
|
||||
println!("compositor");
|
||||
for line in init::doctor_report(&init::hypr_dir()) {
|
||||
println!("{line}");
|
||||
}
|
||||
}
|
||||
|
||||
fn config_directory() -> PathBuf {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ pub enum IoCommand {
|
|||
},
|
||||
}
|
||||
|
||||
/// In-flight RPC calls awaiting a response, keyed by request id: each entry
|
||||
/// is the reply channel for the call that's blocked waiting on it.
|
||||
type PendingReplies = Arc<Mutex<HashMap<String, mpsc::Sender<Result<Value, String>>>>>;
|
||||
|
||||
/// Something the IO thread has for the Lua-driving thread: either an
|
||||
/// unsolicited push (a subscribed event fired, a timer fired) or "the
|
||||
/// connection is gone" (breadd exited, socket closed, etc).
|
||||
|
|
@ -148,8 +152,7 @@ pub fn run(
|
|||
// Lua-side call is blocked waiting for them; a dedicated thread
|
||||
// bridges the synchronous `cmd_rx` (fed from the Lua thread) onto an
|
||||
// async channel this task can select on.
|
||||
let pending: Arc<Mutex<HashMap<String, mpsc::Sender<Result<Value, String>>>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
let pending: PendingReplies = Arc::new(Mutex::new(HashMap::new()));
|
||||
|
||||
let (async_cmd_tx, mut async_cmd_rx) = tokio::sync::mpsc::unbounded_channel::<IoCommand>();
|
||||
std::thread::spawn(move || {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ fn json_to_lua<'lua>(lua: &'lua Lua, value: &JsonValue) -> mlua::Result<LuaValue
|
|||
JsonValue::Bool(b) => LuaValue::Boolean(*b),
|
||||
JsonValue::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
LuaValue::Integer(i as i64)
|
||||
LuaValue::Integer(i)
|
||||
} else {
|
||||
LuaValue::Number(n.as_f64().unwrap_or(0.0))
|
||||
}
|
||||
|
|
@ -243,7 +243,7 @@ impl ModuleHostLua {
|
|||
let decode_fn = lua.create_function(|lua, s: String| {
|
||||
match serde_json::from_str::<JsonValue>(&s) {
|
||||
Ok(v) => Ok((json_to_lua(lua, &v)?, LuaValue::Nil)),
|
||||
Err(e) => Ok((LuaValue::Nil, LuaValue::String(lua.create_string(&e.to_string())?))),
|
||||
Err(e) => Ok((LuaValue::Nil, LuaValue::String(lua.create_string(e.to_string())?))),
|
||||
}
|
||||
})?;
|
||||
json_tbl.set("decode", decode_fn)?;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ pub const KNOWN_APPS: &[&str] = &[
|
|||
/// `workspace`, `window`, and `monitor` added (event families the Hyprland
|
||||
/// and Bluetooth adapters already published under, but that were missing
|
||||
/// from this list) when this became a spoofing-prevention boundary and not
|
||||
/// just an app-id-conflict one. Since: v1.7 — command-bus exception.*
|
||||
/// just an app-id-conflict one. Since: v1.7 — command-bus exception.
|
||||
/// `module`, `state`, `widget`, and `reload` are daemon-synthesized
|
||||
/// families and must stay unclaimable.*
|
||||
const RESERVED_DOMAINS: &[&str] = &[
|
||||
"terminal",
|
||||
"git",
|
||||
|
|
@ -53,6 +55,10 @@ const RESERVED_DOMAINS: &[&str] = &[
|
|||
"workspace",
|
||||
"window",
|
||||
"monitor",
|
||||
"module",
|
||||
"state",
|
||||
"widget",
|
||||
"reload",
|
||||
];
|
||||
|
||||
/// Whether `id` is a registered sibling-app id.
|
||||
|
|
@ -174,6 +180,10 @@ mod tests {
|
|||
"monitor",
|
||||
"window",
|
||||
"system",
|
||||
"module",
|
||||
"state",
|
||||
"widget",
|
||||
"reload",
|
||||
] {
|
||||
assert!(
|
||||
is_reserved_domain(domain),
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ pub async fn run_state_engine(
|
|||
}
|
||||
|
||||
if let (Some(before), Some(after)) = (before_snapshot, after_snapshot) {
|
||||
for (_id, path) in watches.iter() {
|
||||
for path in watches.values() {
|
||||
let old_val = value_at_path(&before, path).unwrap_or(Value::Null);
|
||||
let new_val = value_at_path(&after, path).unwrap_or(Value::Null);
|
||||
if old_val != new_val {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
//! directly from Lua bypasses every check in this file — that's the
|
||||
//! scenario the sandbox exists for, not this file.
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use bread_shared::{glob, ModuleHostHello, ModuleHostPush, ModulePermission, PermissionKind};
|
||||
|
|
@ -349,10 +350,7 @@ impl Server {
|
|||
Ok(json!({ "ok": true }))
|
||||
}
|
||||
"module_host.fs_read" => {
|
||||
if !permissions
|
||||
.iter()
|
||||
.any(|p| p.kind == PermissionKind::FsRead)
|
||||
{
|
||||
if !permissions.iter().any(|p| p.kind == PermissionKind::FsRead) {
|
||||
return Err("fs.read not granted to this module".to_string());
|
||||
}
|
||||
let path = req
|
||||
|
|
@ -411,16 +409,17 @@ impl Server {
|
|||
.and_then(Value::as_str)
|
||||
.ok_or("missing cmd")?
|
||||
.to_string();
|
||||
if !bin_allowed(permissions, &cmd) {
|
||||
return Err("command is outside this module's granted exec bin scope".to_string());
|
||||
}
|
||||
let argv = exec_argv(permissions, &cmd)?;
|
||||
tokio::task::spawn_blocking(move || {
|
||||
match std::process::Command::new("sh").arg("-c").arg(&cmd).status() {
|
||||
match std::process::Command::new(&argv[0])
|
||||
.args(&argv[1..])
|
||||
.status()
|
||||
{
|
||||
Ok(status) if !status.success() => {
|
||||
warn!(cmd = %cmd, code = ?status.code(), "module_host.exec exited non-zero");
|
||||
warn!(cmd = %argv[0], code = ?status.code(), "module_host.exec exited non-zero");
|
||||
}
|
||||
Err(e) => {
|
||||
error!(cmd = %cmd, error = %e, "module_host.exec failed to spawn");
|
||||
error!(cmd = %argv[0], error = %e, "module_host.exec failed to spawn");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -437,17 +436,16 @@ impl Server {
|
|||
.and_then(Value::as_str)
|
||||
.ok_or("missing cmd")?
|
||||
.to_string();
|
||||
if !bin_allowed(permissions, &cmd) {
|
||||
return Err("command is outside this module's granted exec bin scope".to_string());
|
||||
}
|
||||
let argv = exec_argv(permissions, &cmd)?;
|
||||
let timeout_ms = req
|
||||
.params
|
||||
.get("timeout_ms")
|
||||
.and_then(Value::as_u64)
|
||||
.unwrap_or(2000);
|
||||
let handle =
|
||||
tokio::task::spawn_blocking(move || {
|
||||
std::process::Command::new("sh").arg("-c").arg(&cmd).output()
|
||||
let handle = tokio::task::spawn_blocking(move || {
|
||||
std::process::Command::new(&argv[0])
|
||||
.args(&argv[1..])
|
||||
.output()
|
||||
});
|
||||
match tokio::time::timeout(Duration::from_millis(timeout_ms + 500), handle).await {
|
||||
Ok(Ok(Ok(out))) => Ok(json!({
|
||||
|
|
@ -474,7 +472,9 @@ impl Server {
|
|||
(
|
||||
ModuleLoadState::LoadError,
|
||||
ModuleHostOutcome::LoadError(
|
||||
error.clone().unwrap_or_else(|| "module load failed".to_string()),
|
||||
error
|
||||
.clone()
|
||||
.unwrap_or_else(|| "module load failed".to_string()),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
|
@ -501,13 +501,14 @@ impl Server {
|
|||
|
||||
/// Belt-and-suspenders path scoping for `fs_read`/`fs_write`: if the
|
||||
/// manifest declared a `path` hint for this permission kind, the requested
|
||||
/// path (after `~`-expansion) must fall under at least one granted prefix.
|
||||
/// No hint at all means this RPC-level check stays permissive (matching
|
||||
/// Workstream D's existing "un-hinted grant = ungated within that
|
||||
/// namespace" behavior) — Landlock's own ruleset (built independently in
|
||||
/// `module_host::apply_sandbox`) does NOT grant a filesystem rule for an
|
||||
/// un-hinted permission, so the direct `os`/`io` escape hatch remains
|
||||
/// kernel-denied for that case regardless of what this function returns.
|
||||
/// path (after `~`-expansion and canonicalize) must be a real descendant
|
||||
/// of at least one granted prefix. No hint at all means this RPC-level
|
||||
/// check stays permissive (matching Workstream D's existing "un-hinted
|
||||
/// grant = ungated within that namespace" behavior) — Landlock's own
|
||||
/// ruleset (built independently in `module_host::apply_sandbox`) does NOT
|
||||
/// grant a filesystem rule for an un-hinted permission, so the direct
|
||||
/// `os`/`io` escape hatch remains kernel-denied for that case regardless
|
||||
/// of what this function returns.
|
||||
fn path_allowed(permissions: &[ModulePermission], kind: PermissionKind, path: &str) -> bool {
|
||||
let hints: Vec<&String> = permissions
|
||||
.iter()
|
||||
|
|
@ -517,18 +518,93 @@ fn path_allowed(permissions: &[ModulePermission], kind: PermissionKind, path: &s
|
|||
if hints.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let expanded = bread_shared::expand_path(path);
|
||||
let Some(requested) = resolve_scoped_path(path) else {
|
||||
return false;
|
||||
};
|
||||
hints.iter().any(|hint| {
|
||||
let hint_expanded = bread_shared::expand_path(hint);
|
||||
expanded.starts_with(&hint_expanded)
|
||||
let Some(granted) = resolve_scoped_path(hint) else {
|
||||
return false;
|
||||
};
|
||||
// Path::starts_with is component-wise; str::starts_with would let
|
||||
// `/Wallpapers-evil` match a `/Wallpapers` grant.
|
||||
requested.starts_with(&granted)
|
||||
})
|
||||
}
|
||||
|
||||
/// Same idea as [`path_allowed`] for `exec`'s `bin` hint: compares by file
|
||||
/// name (so `bin = "hyprpaper"` matches a command invoking
|
||||
/// `/usr/bin/hyprpaper` as well as a bare `hyprpaper`) or an exact leading
|
||||
/// token match.
|
||||
fn bin_allowed(permissions: &[ModulePermission], cmd: &str) -> bool {
|
||||
/// Canonicalize for containment: existing paths resolve symlinks and `..`;
|
||||
/// new files canonicalize the parent then re-join the filename. Anything
|
||||
/// that still contains `..` after lexical normalization is rejected.
|
||||
fn resolve_scoped_path(path: &str) -> Option<PathBuf> {
|
||||
let expanded = bread_shared::expand_path(path);
|
||||
if let Ok(canon) = expanded.canonicalize() {
|
||||
return Some(canon);
|
||||
}
|
||||
let parent = expanded.parent().filter(|p| !p.as_os_str().is_empty());
|
||||
if let (Some(parent), Some(name)) = (parent, expanded.file_name()) {
|
||||
if let Ok(parent_canon) = parent.canonicalize() {
|
||||
return Some(parent_canon.join(name));
|
||||
}
|
||||
}
|
||||
lexical_abs(&expanded)
|
||||
}
|
||||
|
||||
fn lexical_abs(path: &Path) -> Option<PathBuf> {
|
||||
let abs = if path.is_absolute() {
|
||||
path.to_path_buf()
|
||||
} else {
|
||||
std::path::absolute(path).ok()?
|
||||
};
|
||||
let mut out = PathBuf::new();
|
||||
for c in abs.components() {
|
||||
match c {
|
||||
Component::CurDir => {}
|
||||
Component::ParentDir => {
|
||||
if !out.pop() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
rest => out.push(rest),
|
||||
}
|
||||
}
|
||||
if out.components().any(|c| matches!(c, Component::ParentDir)) {
|
||||
return None;
|
||||
}
|
||||
Some(out)
|
||||
}
|
||||
|
||||
/// Split `cmd` into argv without a shell. Metacharacters are rejected so a
|
||||
/// hinted binary cannot smuggle extra commands (`hyprpaper; curl evil`).
|
||||
fn parse_exec_argv(cmd: &str) -> Option<Vec<String>> {
|
||||
if cmd.chars().any(|c| {
|
||||
matches!(
|
||||
c,
|
||||
'|' | ';' | '&' | '$' | '`' | '\n' | '\r' | '<' | '>' | '(' | ')'
|
||||
)
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
let argv: Vec<String> = cmd.split_whitespace().map(str::to_string).collect();
|
||||
if argv.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(argv)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse `cmd` and enforce the exec `bin` hint against argv[0].
|
||||
fn exec_argv(permissions: &[ModulePermission], cmd: &str) -> Result<Vec<String>, String> {
|
||||
let argv = parse_exec_argv(cmd)
|
||||
.ok_or_else(|| "command contains shell metacharacters or is empty".to_string())?;
|
||||
if !bin_allowed(permissions, &argv[0]) {
|
||||
return Err("command is outside this module's granted exec bin scope".to_string());
|
||||
}
|
||||
Ok(argv)
|
||||
}
|
||||
|
||||
/// Same idea as [`path_allowed`] for `exec`'s `bin` hint: compares argv[0]
|
||||
/// by file name (so `bin = "hyprpaper"` matches `/usr/bin/hyprpaper` as
|
||||
/// well as a bare `hyprpaper`) or an exact path match.
|
||||
fn bin_allowed(permissions: &[ModulePermission], program: &str) -> bool {
|
||||
let hints: Vec<&String> = permissions
|
||||
.iter()
|
||||
.filter(|p| p.kind == PermissionKind::Exec)
|
||||
|
|
@ -537,16 +613,109 @@ fn bin_allowed(permissions: &[ModulePermission], cmd: &str) -> bool {
|
|||
if hints.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let first_word = cmd.split_whitespace().next().unwrap_or("");
|
||||
let cmd_leaf = std::path::Path::new(first_word)
|
||||
let cmd_leaf = Path::new(program)
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or(first_word);
|
||||
.unwrap_or(program);
|
||||
hints.iter().any(|hint| {
|
||||
let hint_leaf = std::path::Path::new(hint.as_str())
|
||||
let hint_leaf = Path::new(hint.as_str())
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or(hint.as_str());
|
||||
cmd_leaf == hint_leaf || first_word == hint.as_str()
|
||||
cmd_leaf == hint_leaf || program == hint.as_str()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn fs_grant(kind: PermissionKind, path: &str) -> Vec<ModulePermission> {
|
||||
vec![ModulePermission {
|
||||
kind,
|
||||
path: Some(path.to_string()),
|
||||
bin: None,
|
||||
}]
|
||||
}
|
||||
|
||||
fn exec_grant(bin: &str) -> Vec<ModulePermission> {
|
||||
vec![ModulePermission {
|
||||
kind: PermissionKind::Exec,
|
||||
path: None,
|
||||
bin: Some(bin.to_string()),
|
||||
}]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_allowed_denies_dotdot_escape_from_granted_prefix() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let wallpapers = tmp.path().join("Wallpapers");
|
||||
std::fs::create_dir(&wallpapers).unwrap();
|
||||
let granted = wallpapers.to_str().unwrap();
|
||||
let perms = fs_grant(PermissionKind::FsRead, granted);
|
||||
|
||||
let escape = wallpapers.join("../../.ssh/id_rsa");
|
||||
assert!(
|
||||
!path_allowed(&perms, PermissionKind::FsRead, escape.to_str().unwrap()),
|
||||
"Wallpapers/../../.ssh/id_rsa must not match a Wallpapers grant"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_allowed_denies_string_prefix_sibling() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let wallpapers = tmp.path().join("Wallpapers");
|
||||
let evil = tmp.path().join("Wallpapers-evil");
|
||||
std::fs::create_dir(&wallpapers).unwrap();
|
||||
std::fs::create_dir(&evil).unwrap();
|
||||
let secret = evil.join("secret");
|
||||
std::fs::write(&secret, "x").unwrap();
|
||||
let perms = fs_grant(PermissionKind::FsRead, wallpapers.to_str().unwrap());
|
||||
assert!(!path_allowed(
|
||||
&perms,
|
||||
PermissionKind::FsRead,
|
||||
secret.to_str().unwrap()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_allowed_accepts_real_descendant_and_new_file() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let wallpapers = tmp.path().join("Wallpapers");
|
||||
std::fs::create_dir(&wallpapers).unwrap();
|
||||
let existing = wallpapers.join("bg.png");
|
||||
std::fs::write(&existing, "x").unwrap();
|
||||
let perms = fs_grant(PermissionKind::FsWrite, wallpapers.to_str().unwrap());
|
||||
assert!(path_allowed(
|
||||
&perms,
|
||||
PermissionKind::FsWrite,
|
||||
existing.to_str().unwrap()
|
||||
));
|
||||
let new_file = wallpapers.join("new.png");
|
||||
assert!(path_allowed(
|
||||
&perms,
|
||||
PermissionKind::FsWrite,
|
||||
new_file.to_str().unwrap()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_argv_denies_shell_chaining_when_bin_hinted() {
|
||||
let perms = exec_grant("hyprpaper");
|
||||
assert!(exec_argv(&perms, "hyprpaper; curl evil").is_err());
|
||||
assert!(exec_argv(&perms, "hyprpaper").is_ok());
|
||||
assert!(exec_argv(&perms, "/usr/bin/hyprpaper --config x").is_ok());
|
||||
assert!(exec_argv(&perms, "curl evil").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_exec_argv_rejects_metacharacters() {
|
||||
assert!(parse_exec_argv("hyprpaper; curl evil").is_none());
|
||||
assert!(parse_exec_argv("hyprpaper | curl evil").is_none());
|
||||
assert!(parse_exec_argv("hyprpaper && curl evil").is_none());
|
||||
assert_eq!(
|
||||
parse_exec_argv("hyprpaper --config x"),
|
||||
Some(vec!["hyprpaper".into(), "--config".into(), "x".into()])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,11 +137,9 @@ enabled = false
|
|||
async fn wait_until_ready(&self) -> Result<()> {
|
||||
let deadline = Instant::now() + Duration::from_secs(8);
|
||||
while Instant::now() < deadline {
|
||||
if self.socket_path.exists() {
|
||||
if self.send_request("ping", json!({})).await.is_ok() {
|
||||
if self.socket_path.exists() && self.send_request("ping", json!({})).await.is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
Err(anyhow!("daemon did not become ready in time"))
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ suggested `[[permissions]]` block for its own `bread.module.toml`.
|
|||
| `low-battery-warning.lua` | Critical notification once when the battery runs low; resets on AC. | none |
|
||||
| `pause-media-on-headphone-unplug.lua` | Runs `playerctl pause` when a headphone/earbud device disconnects. | none (needs `playerctl`) |
|
||||
| `dock-monitors.lua` | Applies a multi-monitor layout when an external display connects, reverts when removed. | edit output names/resolutions |
|
||||
| `external-monitors.lua` | Zero-config laptop displays: any HDMI/DP/USB-C head at its preferred mode, mirrored by default (or extended), lid-safe, restores the panel on unplug. | optional `ARRANGE` / `SCALE` at the top |
|
||||
| `active-window-widget.lua` | Shows the focused window next to the workspace pills in breadbar, via `bread.widget` + `bread.state.watch`. | none |
|
||||
| `cpu-temp-widget/` | Live CPU temperature readout in breadbar's stats area, via `bread.widget` + `bread.fs.read` on a timer. Directory module with a `bread.module.toml` declaring `fs.read` + `widget` — the permission-manifest worked example. | edit `TEMP_PATH` for your hwmon layout |
|
||||
| `bluetooth-toggle-widget.lua` | One-click Bluetooth power toggle in breadbar's tray, via `bread.widget` + a click handler. | none |
|
||||
|
|
|
|||
228
examples/modules/external-monitors.lua
Normal file
228
examples/modules/external-monitors.lua
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
-- external-monitors — behave like a normal laptop desktop
|
||||
--
|
||||
-- Plug in any display (HDMI, DisplayPort, USB-C dock, a random TV) and
|
||||
-- the session just works. No output names to edit.
|
||||
--
|
||||
-- • the laptop panel stays at its preferred (native) mode
|
||||
-- • each external uses its preferred mode and refresh
|
||||
-- • new screens clone the laptop (set ARRANGE = "extend" to sit to the right)
|
||||
-- • closing the lid does not sleep while an external is on
|
||||
-- • unplug everything and the laptop is the only display again
|
||||
--
|
||||
-- Drop-in: copy to ~/.config/bread/modules/ and `bread reload`.
|
||||
|
||||
local M = bread.module({
|
||||
name = "external-monitors",
|
||||
version = "1.0.0",
|
||||
after = { "bread.monitors" },
|
||||
})
|
||||
|
||||
-- "mirror" = every external clones the laptop (presentations, TVs)
|
||||
-- "extend" = extra desktop to the right
|
||||
local ARRANGE = "mirror"
|
||||
local SCALE = "auto"
|
||||
|
||||
local INTERNAL_RE = "^eDP"
|
||||
local INHIBITOR = "/tmp/bread-lid-inhibitor.pid"
|
||||
|
||||
local function inhibit_lid()
|
||||
if bread.fs.exists(INHIBITOR) then return end
|
||||
bread.exec(
|
||||
"bash -c 'systemd-inhibit --what=handle-lid-switch --who=bread "
|
||||
.. "--why=external-display sleep infinity & echo $! > "
|
||||
.. INHIBITOR
|
||||
.. "'"
|
||||
)
|
||||
end
|
||||
|
||||
local function release_lid()
|
||||
bread.exec(
|
||||
"bash -c 'kill $(cat " .. INHIBITOR .. " 2>/dev/null) 2>/dev/null; rm -f " .. INHIBITOR .. "'"
|
||||
)
|
||||
end
|
||||
|
||||
local function is_internal(name)
|
||||
return type(name) == "string" and name:match(INTERNAL_RE) ~= nil
|
||||
end
|
||||
|
||||
local function drm_status(name)
|
||||
for card = 0, 5 do
|
||||
local raw = bread.fs.read(string.format("/sys/class/drm/card%d-%s/status", card, name))
|
||||
if raw then
|
||||
return raw:match("^%s*(%S+)")
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function drm_first_mode(name)
|
||||
for card = 0, 5 do
|
||||
local raw = bread.fs.read(string.format("/sys/class/drm/card%d-%s/modes", card, name))
|
||||
if raw then
|
||||
local w, h = raw:match("(%d+)x(%d+)")
|
||||
if w then
|
||||
return tonumber(w), tonumber(h)
|
||||
end
|
||||
end
|
||||
end
|
||||
return 1920, 1080
|
||||
end
|
||||
|
||||
local function list_connectors()
|
||||
local names = {}
|
||||
local ok, out = bread.exec_capture("ls /sys/class/drm", { timeout_ms = 500 })
|
||||
if not ok or not out then
|
||||
return names
|
||||
end
|
||||
for ent in out:gmatch("[^%s]+") do
|
||||
local name = ent:match("^card%d+%-(.+)$")
|
||||
if name and not name:match("^Writeback") then
|
||||
names[#names + 1] = name
|
||||
end
|
||||
end
|
||||
table.sort(names)
|
||||
return names
|
||||
end
|
||||
|
||||
local function connected()
|
||||
local internal, externals = nil, {}
|
||||
for _, name in ipairs(list_connectors()) do
|
||||
if drm_status(name) == "connected" then
|
||||
if is_internal(name) then
|
||||
internal = internal or name
|
||||
else
|
||||
externals[#externals + 1] = name
|
||||
end
|
||||
end
|
||||
end
|
||||
return internal or "eDP-1", externals
|
||||
end
|
||||
|
||||
-- BOS Hyprland talks Lua (`hl.monitor`). Stock Hyprland uses the
|
||||
-- `monitor=` keyword. Try eval first, then keyword.
|
||||
local function apply_monitor(opts)
|
||||
local extra = ""
|
||||
if opts.mirror and opts.mirror ~= "" then
|
||||
extra = string.format(", mirror = %q", opts.mirror)
|
||||
end
|
||||
local expr = string.format(
|
||||
"hl.monitor({ output = %q, mode = %q, position = %q, scale = %q%s })",
|
||||
opts.output,
|
||||
opts.mode or "preferred",
|
||||
opts.position or "0x0",
|
||||
opts.scale or SCALE,
|
||||
extra
|
||||
)
|
||||
local resp = bread.hyprland.eval(expr)
|
||||
if type(resp) == "string" and resp:match("error") then
|
||||
local spec = string.format(
|
||||
"%s, %s, %s, %s",
|
||||
opts.output,
|
||||
opts.mode or "preferred",
|
||||
opts.position or "0x0",
|
||||
opts.scale or SCALE
|
||||
)
|
||||
if opts.mirror and opts.mirror ~= "" then
|
||||
spec = spec .. ", mirror, " .. opts.mirror
|
||||
end
|
||||
bread.hyprland.keyword("monitor", spec)
|
||||
end
|
||||
end
|
||||
|
||||
local function apply(internal, externals)
|
||||
apply_monitor({
|
||||
output = internal,
|
||||
mode = "preferred",
|
||||
position = "0x0",
|
||||
scale = SCALE,
|
||||
})
|
||||
|
||||
if ARRANGE == "mirror" then
|
||||
for _, name in ipairs(externals) do
|
||||
apply_monitor({
|
||||
output = name,
|
||||
mode = "preferred",
|
||||
position = "0x0",
|
||||
scale = SCALE,
|
||||
mirror = internal,
|
||||
})
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local x = select(1, drm_first_mode(internal)) or 1920
|
||||
for _, name in ipairs(externals) do
|
||||
apply_monitor({
|
||||
output = name,
|
||||
mode = "preferred",
|
||||
position = x .. "x0",
|
||||
scale = SCALE,
|
||||
})
|
||||
local w = select(1, drm_first_mode(name)) or 1920
|
||||
x = x + w
|
||||
end
|
||||
end
|
||||
|
||||
function M.on_load()
|
||||
local last = nil
|
||||
local applied = false
|
||||
|
||||
local function evaluate()
|
||||
local internal, externals = connected()
|
||||
local sig = internal .. "|" .. table.concat(externals, ",")
|
||||
if sig == last then
|
||||
return
|
||||
end
|
||||
last = sig
|
||||
|
||||
if #externals == 0 then
|
||||
if applied then
|
||||
apply_monitor({
|
||||
output = internal,
|
||||
mode = "preferred",
|
||||
position = "0x0",
|
||||
scale = SCALE,
|
||||
})
|
||||
release_lid()
|
||||
applied = false
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
apply(internal, externals)
|
||||
inhibit_lid()
|
||||
applied = true
|
||||
bread.log("[external-monitors] " .. internal .. " + " .. table.concat(externals, ", "))
|
||||
end
|
||||
|
||||
local settle = bread.debounce(1500, evaluate)
|
||||
|
||||
bread.on("bread.hyprland.monitor.connected", function(event)
|
||||
local name = event.data and event.data.name
|
||||
if name and not is_internal(name) then
|
||||
bread.notify("Display connected: " .. name, { urgency = "low" })
|
||||
end
|
||||
settle()
|
||||
end)
|
||||
|
||||
bread.on("bread.hyprland.monitor.disconnected", function()
|
||||
settle()
|
||||
end)
|
||||
|
||||
bread.on("bread.device.**", function(event)
|
||||
local sub = event.data and event.data.subsystem
|
||||
if sub == "drm" then
|
||||
settle()
|
||||
end
|
||||
end)
|
||||
|
||||
bread.hyprland.on_raw("configreloaded", function()
|
||||
last = nil
|
||||
evaluate()
|
||||
end)
|
||||
|
||||
bread.every(3000, evaluate)
|
||||
settle()
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"0": "lua/mod.rs",
|
||||
"0": "LuaEngine",
|
||||
"1": "RawEvent",
|
||||
"2": "config.rs",
|
||||
"3": "Server",
|
||||
|
|
@ -15,24 +15,24 @@
|
|||
"13": "bread-cli/src/main.rs",
|
||||
"14": "types.rs",
|
||||
"15": "podman.rs",
|
||||
"16": "StateHandle",
|
||||
"17": "run_udev_monitor",
|
||||
"16": "Value",
|
||||
"17": "Result",
|
||||
"18": "hooks_shell.rs",
|
||||
"19": "bluetooth.rs",
|
||||
"20": "SubscriptionId",
|
||||
"21": "glob.rs",
|
||||
"22": "run_state_engine",
|
||||
"23": "RtnetlinkAdapter",
|
||||
"22": "StateHandle",
|
||||
"23": "Adapter",
|
||||
"24": "network.rs",
|
||||
"25": "power.rs",
|
||||
"26": "hyprland.rs",
|
||||
"27": "Adapter",
|
||||
"28": "dl.breadway.dev Distribution",
|
||||
"27": "parse_upower_message",
|
||||
"28": "main Branch",
|
||||
"29": "git-branch-widget.lua",
|
||||
"30": "TestHarness",
|
||||
"31": "Sync",
|
||||
"32": "active-window-widget.lua",
|
||||
"33": "cpu-temp-widget.lua",
|
||||
"33": ".new",
|
||||
"34": "focus-mode-widget.lua",
|
||||
"35": "workflow-status-widget.lua",
|
||||
"36": "bread.widget API",
|
||||
|
|
@ -59,10 +59,10 @@
|
|||
"57": "bread.system.startup",
|
||||
"58": "Monitors Configuration Example",
|
||||
"59": "Binds Module (Built-in)",
|
||||
"60": "Bakery Package Manager",
|
||||
"61": "Phase 3: GUI Control Center",
|
||||
"62": "Phase 5: Cross-Device Mesh",
|
||||
"63": "Dev Version Computation",
|
||||
"60": "lua/mod.rs",
|
||||
"61": "external-monitors.lua",
|
||||
"62": "AGENTS.md — Repo hygiene",
|
||||
"63": "CLAUDE.md — Repo hygiene",
|
||||
"64": "ModuleHostLua",
|
||||
"65": "ModuleHostRegistry",
|
||||
"66": "xtask/src/main.rs",
|
||||
|
|
@ -86,5 +86,10 @@
|
|||
"84": "State",
|
||||
"85": "init.lua",
|
||||
"86": "Execution",
|
||||
"87": "packaging/README.md"
|
||||
"87": "packaging/README.md",
|
||||
"88": "PathBuf",
|
||||
"89": "build.sh",
|
||||
"90": "beta Release Track",
|
||||
"91": "dev Release Track",
|
||||
"92": "stable Release Track"
|
||||
}
|
||||
|
|
|
|||
1
graphify-out/.graphify_labels.json.sig
Normal file
1
graphify-out/.graphify_labels.json.sig
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"0": "dff8ca2baa85bb77", "1": "2213379d8e986e1b", "2": "055a5a9a2c0abb47", "3": "4e76d4b9b12f60a0", "4": "15d25492162f61da", "5": "c9e7c9b0b9f9532c", "6": "5dc03258b399572c", "7": "7e3d24ea3cd2b4cb", "8": "d2b23fb40be07856", "9": "c63bb5497aa74cc4", "10": "37be3ba834804202", "11": "e820233ee9e24e6c", "12": "90afbdba0e9131b5", "13": "a893df0933556d63", "14": "2b140ca807922de5", "15": "77fe3c708c10a92e", "16": "f46d2bf3ec15783d", "17": "9d5d3a5ebfca7e96", "18": "4b221b9f82894754", "19": "1af003225b1510f7", "20": "cec4f1891a3503a7", "21": "af54da4748cbfe19", "22": "755f92ef4fb448a8", "23": "8d61c62e8cd29e24", "24": "a6096a26ebcbe7ca", "25": "4bb3423b0748a5b8", "26": "f14069a977bb7109", "27": "c24364ae8589386f", "28": "b7dfd1e572840cf9", "29": "38bd4a3ed7d82df4", "30": "c7a227c868287ece", "31": "8298f357ade782b6", "32": "8c3f9c59418c0d78", "33": "d441528441bffad6", "34": "0ca065898bae7a4c", "35": "91d64164a425221e", "36": "8f4f1c63c1339596", "37": "f29f07965a593c46", "38": "69c04956206264ea", "39": "d5e6784916307537", "40": "9dd3e8ecc75d42d1", "41": "975bc2eaec9ade41", "42": "c119297bd4e771d7", "43": "5df098735d8e8ccf", "44": "3ea089711b226db5", "45": "937d314565bd1f7c", "46": "644deb50d1523213", "47": "a8ba58be12f4eaaf", "48": "07122a351039caad", "49": "85df939415e8bf76", "50": "ccecca45fa071d89", "51": "d12f6c2877bf28fc", "52": "8fde0947b8e44878", "53": "1894c9960c737861", "54": "8eb6456a35bc1424", "55": "266c21cbaa157140", "56": "3dd39e27b03e805b", "57": "9914e60060e52831", "58": "082ed57548a0aa26", "59": "1d8fa6f90af6c7a9", "60": "5b3a15eab473b681", "61": "53961581c79663fe", "62": "1c3daa39aab41ca2", "63": "cd7e1aedbdbb382a", "64": "793a68e5b584e15a", "65": "e5048b5a19d78c81", "66": "abaa846ce9fdc66e", "67": "a46e2827ad3261b0", "68": "56d1c4600f18d094", "69": "b29197139c1a5fc7", "70": "f6f5196c6a2f3084", "71": "f8b572524780f968", "72": "95bd136ecb3896b6", "73": "a2e1d482f5282a2b", "74": "96279e53156461bf", "75": "3c234d3ea2845544", "76": "37f5bfa38e9dda4b", "77": "c95e6689883cdc3d", "78": "784aa039bef2aabf", "79": "1e1cd6b488d8850c", "80": "42213e202400e524", "81": "bb8f3086e24c3f87", "82": "8f000e4f1c6edcd1", "83": "19573b318feb4438", "84": "47016ab7f59f2ab4", "85": "da1e8594a8fb071a", "86": "d730f8d81a4b91ff", "87": "af426938b90fa391", "88": "dce55fb2c83882bb", "89": "9d30c290d7898f81", "90": "356e8182b8067c22", "91": "825919e98a656895", "92": "c5d2ff6dacf845a7"}
|
||||
90
graphify-out/2026-08-16/.graphify_labels.json
Normal file
90
graphify-out/2026-08-16/.graphify_labels.json
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"0": "lua/mod.rs",
|
||||
"1": "RawEvent",
|
||||
"2": "config.rs",
|
||||
"3": "Server",
|
||||
"4": "widget.rs",
|
||||
"5": "Bread Daemon (breadd)",
|
||||
"6": "filesystem.rs",
|
||||
"7": "git.rs",
|
||||
"8": "Result",
|
||||
"9": "state_engine.rs",
|
||||
"10": "modules_mgmt.rs",
|
||||
"11": "systemd.rs",
|
||||
"12": "hooks_git.rs",
|
||||
"13": "bread-cli/src/main.rs",
|
||||
"14": "types.rs",
|
||||
"15": "podman.rs",
|
||||
"16": "StateHandle",
|
||||
"17": "run_udev_monitor",
|
||||
"18": "hooks_shell.rs",
|
||||
"19": "bluetooth.rs",
|
||||
"20": "SubscriptionId",
|
||||
"21": "glob.rs",
|
||||
"22": "run_state_engine",
|
||||
"23": "RtnetlinkAdapter",
|
||||
"24": "network.rs",
|
||||
"25": "power.rs",
|
||||
"26": "hyprland.rs",
|
||||
"27": "Adapter",
|
||||
"28": "dl.breadway.dev Distribution",
|
||||
"29": "git-branch-widget.lua",
|
||||
"30": "TestHarness",
|
||||
"31": "Sync",
|
||||
"32": "active-window-widget.lua",
|
||||
"33": "cpu-temp-widget.lua",
|
||||
"34": "focus-mode-widget.lua",
|
||||
"35": "workflow-status-widget.lua",
|
||||
"36": "bread.widget API",
|
||||
"37": "bluetooth-toggle-widget.lua",
|
||||
"38": "pause-media-on-headphone-unplug.lua",
|
||||
"39": "Autostart Example Module",
|
||||
"40": "dock-monitors.lua",
|
||||
"41": "dock-workflow.lua",
|
||||
"42": "low-battery-warning.lua",
|
||||
"43": "install.sh",
|
||||
"44": "Filesystem Adapter",
|
||||
"45": "Git Adapter",
|
||||
"46": "Podman Adapter",
|
||||
"47": "Systemd Adapter",
|
||||
"48": "bread.after(delay_ms, fn)",
|
||||
"49": "bread.bluetooth namespace",
|
||||
"50": "bread.every(interval_ms, fn)",
|
||||
"51": "bread.exec(cmd)",
|
||||
"52": "bread.hyprland namespace",
|
||||
"53": "bread.notify(message, opts)",
|
||||
"54": "bread.state.watch(path, fn)",
|
||||
"55": "bread-cli/src/lib.rs",
|
||||
"56": "core/mod.rs",
|
||||
"57": "bread.system.startup",
|
||||
"58": "Monitors Configuration Example",
|
||||
"59": "Binds Module (Built-in)",
|
||||
"60": "Bakery Package Manager",
|
||||
"61": "Phase 3: GUI Control Center",
|
||||
"62": "Phase 5: Cross-Device Mesh",
|
||||
"63": "Dev Version Computation",
|
||||
"64": "ModuleHostLua",
|
||||
"65": "ModuleHostRegistry",
|
||||
"66": "xtask/src/main.rs",
|
||||
"67": "Bread",
|
||||
"68": "rules.rs",
|
||||
"69": "Normalized events",
|
||||
"70": "Bread Documentation",
|
||||
"71": "udev.rs",
|
||||
"72": "Dictionary: Lua API",
|
||||
"73": "Out-of-process module sandboxing *(Since: v1.6)*",
|
||||
"74": "Dictionary: Built-in modules",
|
||||
"75": "Events",
|
||||
"76": "Machine and filesystem",
|
||||
"77": "Contributing",
|
||||
"78": "Bluetooth",
|
||||
"79": "Widgets *(Since: v1.3)*",
|
||||
"80": "Getting started",
|
||||
"81": "Capability-scoped modules *(Since: v1.5)*",
|
||||
"82": "Workflows *(Since: v1.2)*",
|
||||
"83": "Timers",
|
||||
"84": "State",
|
||||
"85": "init.lua",
|
||||
"86": "Execution",
|
||||
"87": "packaging/README.md"
|
||||
}
|
||||
397
graphify-out/2026-08-16/GRAPH_REPORT.md
Normal file
397
graphify-out/2026-08-16/GRAPH_REPORT.md
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
# Graph Report - bread (2026-08-15)
|
||||
|
||||
## Corpus Check
|
||||
- 62 files · ~88,250 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 1467 nodes · 3347 edges · 88 communities (64 shown, 24 thin omitted)
|
||||
- Extraction: 99% EXTRACTED · 1% INFERRED · 0% AMBIGUOUS · INFERRED: 48 edges (avg confidence: 0.78)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `a6973360`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- lua/mod.rs
|
||||
- RawEvent
|
||||
- config.rs
|
||||
- Server
|
||||
- widget.rs
|
||||
- Bread Daemon (breadd)
|
||||
- filesystem.rs
|
||||
- git.rs
|
||||
- Result
|
||||
- state_engine.rs
|
||||
- modules_mgmt.rs
|
||||
- systemd.rs
|
||||
- hooks_git.rs
|
||||
- bread-cli/src/main.rs
|
||||
- types.rs
|
||||
- podman.rs
|
||||
- StateHandle
|
||||
- run_udev_monitor
|
||||
- hooks_shell.rs
|
||||
- bluetooth.rs
|
||||
- SubscriptionId
|
||||
- glob.rs
|
||||
- run_state_engine
|
||||
- RtnetlinkAdapter
|
||||
- network.rs
|
||||
- power.rs
|
||||
- hyprland.rs
|
||||
- Adapter
|
||||
- dl.breadway.dev Distribution
|
||||
- git-branch-widget.lua
|
||||
- TestHarness
|
||||
- Sync
|
||||
- active-window-widget.lua
|
||||
- cpu-temp-widget.lua
|
||||
- focus-mode-widget.lua
|
||||
- workflow-status-widget.lua
|
||||
- bread.widget API
|
||||
- bluetooth-toggle-widget.lua
|
||||
- pause-media-on-headphone-unplug.lua
|
||||
- Autostart Example Module
|
||||
- install.sh
|
||||
- Filesystem Adapter
|
||||
- Git Adapter
|
||||
- Podman Adapter
|
||||
- Systemd Adapter
|
||||
- bread.after(delay_ms, fn)
|
||||
- bread.bluetooth namespace
|
||||
- bread.every(interval_ms, fn)
|
||||
- bread.exec(cmd)
|
||||
- bread.hyprland namespace
|
||||
- bread.notify(message, opts)
|
||||
- bread.state.watch(path, fn)
|
||||
- bread.system.startup
|
||||
- Monitors Configuration Example
|
||||
- Binds Module (Built-in)
|
||||
- Bakery Package Manager
|
||||
- Phase 3: GUI Control Center
|
||||
- Phase 5: Cross-Device Mesh
|
||||
- Dev Version Computation
|
||||
- ModuleHostLua
|
||||
- ModuleHostRegistry
|
||||
- xtask/src/main.rs
|
||||
- Bread
|
||||
- rules.rs
|
||||
- Normalized events
|
||||
- Bread Documentation
|
||||
- udev.rs
|
||||
- Dictionary: Lua API
|
||||
- Out-of-process module sandboxing *(Since: v1.6)*
|
||||
- Dictionary: Built-in modules
|
||||
- Events
|
||||
- Machine and filesystem
|
||||
- Contributing
|
||||
- Bluetooth
|
||||
- Widgets *(Since: v1.3)*
|
||||
- Getting started
|
||||
- Capability-scoped modules *(Since: v1.5)*
|
||||
- Workflows *(Since: v1.2)*
|
||||
- Timers
|
||||
- State
|
||||
- init.lua
|
||||
- Execution
|
||||
- packaging/README.md
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `LuaEngine` - 59 edges
|
||||
2. `RawEvent` - 49 edges
|
||||
3. `BreadEvent` - 38 edges
|
||||
4. `raw()` - 37 edges
|
||||
5. `RuntimeState` - 34 edges
|
||||
6. `StateHandle` - 28 edges
|
||||
7. `now_unix_ms()` - 26 edges
|
||||
8. `Adapter` - 25 edges
|
||||
9. `SubscriptionId` - 25 edges
|
||||
10. `ModuleHostLua` - 24 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `parse_bluetooth_message()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/bluetooth.rs → bread-shared/src/lib.rs
|
||||
- `try_enumerate()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/bluetooth.rs → bread-shared/src/lib.rs
|
||||
- `classify()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/filesystem.rs → bread-shared/src/lib.rs
|
||||
- `network_raw_event()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/network.rs → bread-shared/src/lib.rs
|
||||
- `power_raw_event()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/power.rs → bread-shared/src/lib.rs
|
||||
|
||||
## Import Cycles
|
||||
- 2-file cycle: `breadd/src/core/state_engine.rs -> breadd/src/lua/mod.rs -> breadd/src/core/state_engine.rs`
|
||||
- 2-file cycle: `bread-shared/src/lib.rs -> bread-shared/src/module_host_ipc.rs -> bread-shared/src/lib.rs`
|
||||
|
||||
## Hyperedges (group relationships)
|
||||
- **** — ci_dev_release, workflow_version_compute, release_track_dev, distribution_dl_breadway_dev, package_bakery [INFERRED]
|
||||
- **** — adapter_udev, adapter_hyprland, adapter_power, sys_bread_daemon, api_bread_on, sys_lua_runtime [INFERRED]
|
||||
- **** — config_init_lua, config_modules_dir, pattern_module_skeleton, api_bread_on, sys_lua_runtime [INFERRED]
|
||||
- **** — api_bread_workflow, api_bread_spawn, api_bread_wait, example_dock_workflow, api_bread_notify [INFERRED]
|
||||
- **** — api_bread_widget, api_bread_every, example_widget_cpu_temp, api_bread_state_watch [INFERRED]
|
||||
- **** — branch_main, ci_dev_release, ci_rc_release, ci_stable_release, release_track_dev, release_track_beta, release_track_stable [INFERRED]
|
||||
|
||||
## Communities (88 total, 24 thin omitted)
|
||||
|
||||
### Community 0 - "lua/mod.rs"
|
||||
Cohesion: 0.06
|
||||
Nodes (86): now_unix_ms(), ModulePermission, Option, String, WidgetSpec, RuntimeState, bluetooth_connect(), bluetooth_disconnect() (+78 more)
|
||||
|
||||
### Community 1 - "RawEvent"
|
||||
Cohesion: 0.05
|
||||
Nodes (67): adapter_source_is_hashable_and_eq(), AdapterSource, bread_event_new_accepts_owned_and_borrowed_names(), bread_event_new_assigns_unique_id_and_no_cause(), bread_event_new_sets_current_timestamp(), bread_event_with_timestamp_preserves_timestamp_and_assigns_id(), BreadEvent, DaemonSection (+59 more)
|
||||
|
||||
### Community 2 - "config.rs"
|
||||
Cohesion: 0.07
|
||||
Nodes (50): AdaptersConfig, AdapterToggle, compat_section_defaults_legacy_hyprland_names_to_true(), CompatConfig, Config, config_path(), config_path_falls_back_to_home_when_no_xdg(), config_path_respects_xdg_config_home() (+42 more)
|
||||
|
||||
### Community 3 - "Server"
|
||||
Cohesion: 0.05
|
||||
Nodes (41): A, command_target(), event_domain(), is_known_app(), is_reserved_domain(), Option, validate_app_namespace(), validate_command_event() (+33 more)
|
||||
|
||||
### Community 4 - "widget.rs"
|
||||
Cohesion: 0.07
|
||||
Nodes (32): accepts_node_count_at_max(), accepts_tree_at_max_depth(), Align, Background, box_of(), default_orientation(), FontWeight, is_valid_class() (+24 more)
|
||||
|
||||
### Community 5 - "Bread Daemon (breadd)"
|
||||
Cohesion: 0.06
|
||||
Nodes (39): Bluetooth Adapter, Hyprland Adapter, Network Adapter, Power Adapter, udev Adapter, bread.on(pattern, fn), bread.spawn(fn), bread.wait(pattern, opts) (+31 more)
|
||||
|
||||
### Community 6 - "filesystem.rs"
|
||||
Cohesion: 0.12
|
||||
Nodes (28): classify(), classify_build_artifact_created_in_target(), classify_debounces_rapid_repeat_events_for_same_path(), classify_file_changed_for_ordinary_source_file(), classify_silent_for_modify_in_target_not_create(), classify_silent_under_git(), classify_silent_under_node_modules(), detect_markers() (+20 more)
|
||||
|
||||
### Community 7 - "git.rs"
|
||||
Cohesion: 0.12
|
||||
Nodes (22): check_ahead_behind(), check_dirty(), discover_repos(), expand_roots(), expand_roots_globs_single_trailing_star(), expand_roots_skips_unreadable_glob_parent_without_panicking(), expand_roots_uses_literal_path_without_trailing_star(), GitAdapter (+14 more)
|
||||
|
||||
### Community 8 - "Result"
|
||||
Cohesion: 0.15
|
||||
Nodes (50): daemon_survives_repeated_reloads_and_pipeline_resumes(), emit_with_app_source_allows_command_to_another_app(), emit_with_app_source_rejects_wrong_namespace(), emit_with_app_source_still_rejects_foreign_app_namespace(), emit_with_internal_source_is_rejected(), emit_with_known_app_source_routes_through_normalizer(), emit_with_unregistered_app_source_is_rejected(), emit_without_event_errors() (+42 more)
|
||||
|
||||
### Community 9 - "state_engine.rs"
|
||||
Cohesion: 0.12
|
||||
Nodes (19): apply_device_change(), apply_event_to_state(), device_connect_adds_device_with_all_fields(), device_connect_is_idempotent_for_same_id(), device_disconnect_of_unknown_id_is_noop(), device_disconnect_removes_matching_id(), ev(), monitor_connect_adds_new_monitor() (+11 more)
|
||||
|
||||
### Community 10 - "modules_mgmt.rs"
|
||||
Cohesion: 0.11
|
||||
Nodes (36): audit_detects_fs_read_and_widget_from_cpu_temp_widget_style_module(), audit_extracts_exec_bin_hint_and_ignores_baseline_calls(), audit_module(), audit_scans_required_sibling_files_in_module_directory(), classify_call_site(), collect_lua_files(), copy_dir(), extract_first_string_arg() (+28 more)
|
||||
|
||||
### Community 11 - "systemd.rs"
|
||||
Cohesion: 0.12
|
||||
Nodes (17): active_state_to_kind(), failure_result(), get_unit_path(), handle_message(), is_failed_transition(), query_active_state(), Connection, HashMap (+9 more)
|
||||
|
||||
### Community 12 - "hooks_git.rs"
|
||||
Cohesion: 0.15
|
||||
Nodes (24): all_hook_scripts_exit_0_unconditionally(), all_hook_scripts_start_with_shebang_and_marker(), branch_changed_emit_line(), commit_created_emit_line(), emit_line_for(), git_dir(), hook_script(), hook_script_rejects_unknown_name() (+16 more)
|
||||
|
||||
### Community 13 - "bread-cli/src/main.rs"
|
||||
Cohesion: 0.19
|
||||
Nodes (29): CausalityTracker, Cli, Commands, config_directory(), daemon_socket_path(), format_timestamp(), handle_modules_cmd(), HooksCommand (+21 more)
|
||||
|
||||
### Community 14 - "types.rs"
|
||||
Cohesion: 0.17
|
||||
Nodes (21): Device, DeviceRule, DeviceTopology, InterfaceState, MatchCondition, ModuleStatus, Monitor, NetworkState (+13 more)
|
||||
|
||||
### Community 15 - "podman.rs"
|
||||
Cohesion: 0.15
|
||||
Nodes (17): container_event(), ignores_remove_event(), ignores_stop_event_to_avoid_double_emit_with_died(), ignores_unknown_action(), map_podman_event(), maps_died_event(), maps_health_status_event(), maps_start_event() (+9 more)
|
||||
|
||||
### Community 16 - "StateHandle"
|
||||
Cohesion: 0.14
|
||||
Nodes (10): condition_matches(), resolve_device(), Option, Result, String, Value, Vec, StateHandle (+2 more)
|
||||
|
||||
### Community 17 - "run_udev_monitor"
|
||||
Cohesion: 0.35
|
||||
Nodes (9): enumerate_with_udev(), Result, Self, Sender, String, Vec, run_udev_monitor(), ScannedDevice (+1 more)
|
||||
|
||||
### Community 18 - "hooks_shell.rs"
|
||||
Cohesion: 0.18
|
||||
Nodes (11): hook_scripts_background_every_emit_call(), hooks_dir(), install_shell(), join_line_continuations(), Option, PathBuf, Result, String (+3 more)
|
||||
|
||||
### Community 19 - "bluetooth.rs"
|
||||
Cohesion: 0.15
|
||||
Nodes (10): address_from_path(), BluetoothAdapter, parse_bluetooth_message(), Message, Option, Result, Self, Sender (+2 more)
|
||||
|
||||
### Community 20 - "SubscriptionId"
|
||||
Cohesion: 0.29
|
||||
Nodes (13): HashMap, String, Vec, Subscription, SubscriptionId, SubscriptionTable, table_add_assigns_provided_id_and_finds_match(), table_clear_removes_all() (+5 more)
|
||||
|
||||
### Community 22 - "run_state_engine"
|
||||
Cohesion: 0.27
|
||||
Nodes (12): dispatch_event(), handle_command(), Arc, AtomicU64, Receiver, RwLock, Self, Sender (+4 more)
|
||||
|
||||
### Community 23 - "RtnetlinkAdapter"
|
||||
Cohesion: 0.22
|
||||
Nodes (7): ip_from_bytes(), Option, Result, Self, Sender, String, RtnetlinkAdapter
|
||||
|
||||
### Community 24 - "network.rs"
|
||||
Cohesion: 0.27
|
||||
Nodes (9): has_default_route(), network_raw_event(), NetworkAdapter, NetworkSnapshot, read_network_state(), BTreeMap, Result, Sender (+1 more)
|
||||
|
||||
### Community 25 - "power.rs"
|
||||
Cohesion: 0.26
|
||||
Nodes (8): power_raw_event(), PowerAdapter, PowerSnapshot, read_power_state(), Option, Result, Self, Sender
|
||||
|
||||
### Community 26 - "hyprland.rs"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): hyprland_event_socket(), HyprlandAdapter, parse_hyprland_line(), PathBuf, Result, Sender, String
|
||||
|
||||
### Community 27 - "Adapter"
|
||||
Cohesion: 0.23
|
||||
Nodes (8): Adapter, parse_upower_message(), Message, Result, Self, Sender, UPowerAdapter, Send
|
||||
|
||||
### Community 28 - "dl.breadway.dev Distribution"
|
||||
Cohesion: 0.25
|
||||
Nodes (8): main Branch, dev-release.yml Workflow, rc-release.yml Workflow, release.yml Workflow, dl.breadway.dev Distribution, beta Release Track, dev Release Track, stable Release Track
|
||||
|
||||
### Community 29 - "git-branch-widget.lua"
|
||||
Cohesion: 0.62
|
||||
Nodes (6): focused_tab_cwd(), git_info(), M.on_load(), shell_quote(), update(), widget_root()
|
||||
|
||||
### Community 30 - "TestHarness"
|
||||
Cohesion: 0.16
|
||||
Nodes (16): main(), parse_args(), Option, String, killing_a_module_host_child_does_not_take_down_breadd_or_other_modules(), os_execute_and_io_open_are_denied_at_the_kernel_level_outside_granted_scope(), Child, Drop (+8 more)
|
||||
|
||||
### Community 31 - "Sync"
|
||||
Cohesion: 0.50
|
||||
Nodes (3): main(), Result, Sync
|
||||
|
||||
### Community 32 - "active-window-widget.lua"
|
||||
Cohesion: 0.83
|
||||
Nodes (3): label_for(), M.on_load(), widget_root()
|
||||
|
||||
### Community 33 - "cpu-temp-widget.lua"
|
||||
Cohesion: 0.83
|
||||
Nodes (3): M.on_load(), read_temp_c(), widget_root()
|
||||
|
||||
### Community 34 - "focus-mode-widget.lua"
|
||||
Cohesion: 1.00
|
||||
Nodes (3): is_focused(), M.on_load(), widget_root()
|
||||
|
||||
### Community 35 - "workflow-status-widget.lua"
|
||||
Cohesion: 0.83
|
||||
Nodes (3): M.on_load(), most_relevant(), widget_update()
|
||||
|
||||
### Community 36 - "bread.widget API"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): bread.widget API, CPU Temperature Widget Example, Live Widget Update Pattern
|
||||
|
||||
### Community 64 - "ModuleHostLua"
|
||||
Cohesion: 0.10
|
||||
Nodes (38): call(), HostMessage, IoCommand, RpcResponse, Duration, Option, PathBuf, Receiver (+30 more)
|
||||
|
||||
### Community 65 - "ModuleHostRegistry"
|
||||
Cohesion: 0.07
|
||||
Nodes (43): bin_allowed(), path_allowed(), HashMap, Option, OwnedWriteHalf, Result, Sender, String (+35 more)
|
||||
|
||||
### Community 66 - "xtask/src/main.rs"
|
||||
Cohesion: 0.11
|
||||
Nodes (36): BTreeSet, ExitCode, check(), CheckReport, clean_state_passes(), extract_cli_commands(), extract_enum_variants(), extract_ipc_methods() (+28 more)
|
||||
|
||||
### Community 67 - "Bread"
|
||||
Cohesion: 0.06
|
||||
Nodes (28): Deprecations, Hyprland legacy flat event names (since v1.5), Bread Examples, Example 1: Porting keyboard_and_display_watcher.sh (system script), Example 2: Porting autostart.lua, Example 3: Porting display/monitors.lua, Example 4: Multi-step automation workflows, Example 5: A live widget in breadbar (+20 more)
|
||||
|
||||
### Community 68 - "rules.rs"
|
||||
Cohesion: 0.14
|
||||
Nodes (27): empty_file_loads_with_no_rules(), empty_on_is_treated_as_missing(), invalid_toml_is_fatal(), load_rules(), missing_on_is_reported_with_index_and_no_on(), multiple_action_keys_is_reported(), one_bad_rule_does_not_block_other_valid_rules(), ParsedRule (+19 more)
|
||||
|
||||
### Community 69 - "Normalized events"
|
||||
Cohesion: 0.12
|
||||
Nodes (16): Bluetooth (BlueZ), Compatibility: `[compat]` config, Devices (udev / Bluetooth), Filesystem / project detection, Git (hooks + dirty-state poller), Hyprland, Network, Normalized events (+8 more)
|
||||
|
||||
### Community 70 - "Bread Documentation"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): API Stability & Versioning, Bread Documentation, Contents, Debugging tips, Dictionary: Event reference, Dictionary: IPC protocol, Dictionary: Runtime state schema, Integrating a bread\* app (+6 more)
|
||||
|
||||
### Community 71 - "udev.rs"
|
||||
Cohesion: 0.32
|
||||
Nodes (10): build_device_event(), build_event(), enumerate_payload_includes_classification_fields(), prop_bool(), prop_str(), Option, Value, udev_event_payload() (+2 more)
|
||||
|
||||
### Community 72 - "Dictionary: Lua API"
|
||||
Cohesion: 0.17
|
||||
Nodes (12): `bread.debounce(delay_ms, fn) -> wrapped_fn`, `bread.log(msg)` / `bread.warn(msg)` / `bread.error(msg)`, `bread.notify(message, opts)`, `bread.profile.activate(name)`, Dictionary: Lua API, Hyprland, Module declaration, Module lifecycle hooks (+4 more)
|
||||
|
||||
### Community 73 - "Out-of-process module sandboxing *(Since: v1.6)*"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): Architecture, Crash isolation, New IPC methods, Out-of-process module sandboxing *(Since: v1.6)*, RPC bridge coverage, The gap this closes, The Landlock sandbox, The token/identity handshake (+2 more)
|
||||
|
||||
### Community 74 - "Dictionary: Built-in modules"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): `bread.binds`, `bread.devices`, `bread.monitors`, `bread.rules` *(Since: v1.5)*, `bread.workspaces`, Device rule options, Dictionary: Built-in modules, Example: Dock-specific setup (+2 more)
|
||||
|
||||
### Community 75 - "Events"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): `bread.emit(event, data)`, `bread.filter(pattern, fn, opts) -> id`, `bread.off(id)`, `bread.on(pattern, fn) -> id`, `bread.once(pattern, fn) -> id`, `bread.spawn(fn)`, `bread.wait_all(patterns, opts) -> table` *(Since: v1.2)*, `bread.wait_any(patterns, opts) -> event | nil` *(Since: v1.2)* (+2 more)
|
||||
|
||||
### Community 76 - "Machine and filesystem"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): `bread.fs.exists(path) -> bool`, `bread.fs.expand(path) -> string`, `bread.fs.read(path) -> string | nil`, `bread.fs.readlink(path) -> string | nil`, `bread.fs.write(path, content)`, `bread.json.decode(str) -> table | nil`, `bread.machine.has_tag(tag) -> bool`, `bread.machine.name() -> string` (+2 more)
|
||||
|
||||
### Community 77 - "Contributing"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): Branches, CI, Contributing, Keeping the API docs honest, Local development, Questions, The release cycle, Tracks, from a user's perspective
|
||||
|
||||
### Community 78 - "Bluetooth"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): Bluetooth, `bread.bluetooth.connect(address)`, `bread.bluetooth.devices() -> table | nil`, `bread.bluetooth.disconnect(address)`, `bread.bluetooth.power(enabled)`, `bread.bluetooth.powered() -> bool | nil`, `bread.bluetooth.scan(enabled)`, Example: auto-connect headphones on AC power (+1 more)
|
||||
|
||||
### Community 79 - "Widgets *(Since: v1.3)*"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): `bread.widget.list() -> table`, `bread.widget.register(spec) -> ok, err`, `bread.widget.remove(id) -> bool`, `bread.widget.update(id, patch) -> ok, err`, Click events, Node types, `style` *(Since: v1.4)*, Style vs. `class` (+1 more)
|
||||
|
||||
### Community 80 - "Getting started"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): 1) Create a minimal config, 2) The fast path: `rules.toml` *(Since: v1.5)*, 3) Minimal `init.lua`, 4) Start the daemon, 5) Check that it's running, Getting started
|
||||
|
||||
### Community 81 - "Capability-scoped modules *(Since: v1.5)*"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): Baseline (always available, no manifest entry needed), `bread modules audit <name>`, Capability-scoped modules *(Since: v1.5)*, Gated — requires a matching `[[permissions]]` entry, `path`/`bin` enforcement depends on where the module runs, `require("bread.devices")` still works from a scoped module
|
||||
|
||||
### Community 82 - "Workflows *(Since: v1.2)*"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): `bread.workflow.define(name, fn)`, `bread.workflow.list() -> table`, `bread.workflow.start(name, opts)`, `bread.workflow.status(name) -> table | nil`, `bread.workflow.step(label)`, Workflows *(Since: v1.2)*
|
||||
|
||||
### Community 83 - "Timers"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): `bread.after(delay_ms, fn) -> id`, `bread.cancel(id)`, `bread.every(interval_ms, fn) -> id`, Timers
|
||||
|
||||
### Community 84 - "State"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): `bread.state.get(path)`, `bread.state.watch(path, fn) -> id`, State, Typed shorthands
|
||||
|
||||
### Community 85 - "init.lua"
|
||||
Cohesion: 0.83
|
||||
Nodes (3): M.on_load(), read_temp_c(), widget_root()
|
||||
|
||||
### Community 86 - "Execution"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): `bread.exec_capture(cmd, opts) -> ok, stdout`, `bread.exec(cmd)`, Execution
|
||||
|
||||
## Knowledge Gaps
|
||||
- **179 isolated node(s):** `install.sh script`, `Branches`, `The release cycle`, `Tracks, from a user's perspective`, `Keeping the API docs honest` (+174 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **24 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `RawEvent` connect `RawEvent` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `run_udev_monitor`, `bluetooth.rs`, `RtnetlinkAdapter`, `network.rs`, `power.rs`, `hyprland.rs`, `Adapter`?**
|
||||
_High betweenness centrality (0.094) - this node is a cross-community bridge._
|
||||
- **Why does `Adapter` connect `Adapter` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `run_udev_monitor`, `bluetooth.rs`, `RtnetlinkAdapter`, `network.rs`, `power.rs`, `hyprland.rs`, `Sync`?**
|
||||
_High betweenness centrality (0.077) - this node is a cross-community bridge._
|
||||
- **Why does `BreadEvent` connect `RawEvent` to `ModuleHostLua`, `lua/mod.rs`, `ModuleHostRegistry`, `Server`, `state_engine.rs`, `run_state_engine`?**
|
||||
_High betweenness centrality (0.063) - this node is a cross-community bridge._
|
||||
- **What connects `install.sh script`, `Branches`, `The release cycle` to the rest of the system?**
|
||||
_179 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `lua/mod.rs` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.056 - nodes in this community are weakly interconnected._
|
||||
- **Should `RawEvent` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.051842708517016396 - nodes in this community are weakly interconnected._
|
||||
- **Should `config.rs` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.07191780821917808 - nodes in this community are weakly interconnected._
|
||||
18
graphify-out/2026-08-16/cost.json
Normal file
18
graphify-out/2026-08-16/cost.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"runs": [
|
||||
{
|
||||
"date": "2026-08-04T09:09:09.071813+00:00",
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"files": 55
|
||||
},
|
||||
{
|
||||
"date": "2026-08-04T09:28:29.057021+00:00",
|
||||
"input_tokens": 72759,
|
||||
"output_tokens": 0,
|
||||
"files": 55
|
||||
}
|
||||
],
|
||||
"total_input_tokens": 72759,
|
||||
"total_output_tokens": 0
|
||||
}
|
||||
55512
graphify-out/2026-08-16/graph.json
Normal file
55512
graphify-out/2026-08-16/graph.json
Normal file
File diff suppressed because it is too large
Load diff
327
graphify-out/2026-08-16/manifest.json
Normal file
327
graphify-out/2026-08-16/manifest.json
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
{
|
||||
"bread-cli/src/hooks_git.rs": {
|
||||
"mtime": 1786800467.7200727,
|
||||
"ast_hash": "7a29b5d5d90170f0aef9cececc7d8656",
|
||||
"semantic_hash": "7a29b5d5d90170f0aef9cececc7d8656"
|
||||
},
|
||||
"bread-cli/src/hooks_shell.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"ast_hash": "c5d5b8922fcff79954ddb00496721603",
|
||||
"semantic_hash": "c5d5b8922fcff79954ddb00496721603"
|
||||
},
|
||||
"bread-cli/src/lib.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"ast_hash": "d1bf6e1c239498521c42418f672bc400",
|
||||
"semantic_hash": "d1bf6e1c239498521c42418f672bc400"
|
||||
},
|
||||
"bread-cli/src/main.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"ast_hash": "e1fbe63ea3b10e0887072ab7133d0508",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-cli/src/modules_mgmt.rs": {
|
||||
"mtime": 1786801244.1263742,
|
||||
"ast_hash": "1cb6f3e4fa26108f81215ab57bb02b91",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-cli/tests/modules.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "84fca8f87dc915b1cb523f8199e78521",
|
||||
"semantic_hash": "84fca8f87dc915b1cb523f8199e78521"
|
||||
},
|
||||
"bread-emit/src/main.rs": {
|
||||
"mtime": 1786800467.7206197,
|
||||
"ast_hash": "350cefbf697cfd93f7df7b7bcc45a101",
|
||||
"semantic_hash": "350cefbf697cfd93f7df7b7bcc45a101"
|
||||
},
|
||||
"bread-shared/src/apps.rs": {
|
||||
"mtime": 1786801218.1467261,
|
||||
"ast_hash": "e8419571e7a322019d71c89559fb02fb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/glob.rs": {
|
||||
"mtime": 1786800467.7210522,
|
||||
"ast_hash": "0594a313cb1909d1cca5fd5b8f241b68",
|
||||
"semantic_hash": "0594a313cb1909d1cca5fd5b8f241b68"
|
||||
},
|
||||
"bread-shared/src/lib.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "236b73bad29f1544a28fbf3ee1ccc795",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/widget.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "33272eb38c7fffbfa180cef7c5a286fc",
|
||||
"semantic_hash": "33272eb38c7fffbfa180cef7c5a286fc"
|
||||
},
|
||||
"breadd/src/adapters/bluetooth.rs": {
|
||||
"mtime": 1786800467.7214499,
|
||||
"ast_hash": "4d1df67347d5b7c9cdbcb12921a6ae28",
|
||||
"semantic_hash": "4d1df67347d5b7c9cdbcb12921a6ae28"
|
||||
},
|
||||
"breadd/src/adapters/filesystem.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "8ec9dcd8de13f30922cfbe9b4a3fff56",
|
||||
"semantic_hash": "8ec9dcd8de13f30922cfbe9b4a3fff56"
|
||||
},
|
||||
"breadd/src/adapters/git.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "6e6ff6ca318e28cd94690c30d41b520b",
|
||||
"semantic_hash": "6e6ff6ca318e28cd94690c30d41b520b"
|
||||
},
|
||||
"breadd/src/adapters/hyprland.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "71537dbd86b413d94476f8022054f1f4",
|
||||
"semantic_hash": "71537dbd86b413d94476f8022054f1f4"
|
||||
},
|
||||
"breadd/src/adapters/mod.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "63885887c2fc3ea2314d7fe095e5df61",
|
||||
"semantic_hash": "63885887c2fc3ea2314d7fe095e5df61"
|
||||
},
|
||||
"breadd/src/adapters/network.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "8706dc546b7e08d5aa084ca58c48559c",
|
||||
"semantic_hash": "8706dc546b7e08d5aa084ca58c48559c"
|
||||
},
|
||||
"breadd/src/adapters/network_rtnetlink.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "0c9d0bb2693bc46b11807f6b8ebb7c4c",
|
||||
"semantic_hash": "0c9d0bb2693bc46b11807f6b8ebb7c4c"
|
||||
},
|
||||
"breadd/src/adapters/podman.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "97c08551c0fe53b0a5888d98730d35db",
|
||||
"semantic_hash": "97c08551c0fe53b0a5888d98730d35db"
|
||||
},
|
||||
"breadd/src/adapters/power.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "987d202ec0d30ec26b1d747a6e320ed7",
|
||||
"semantic_hash": "987d202ec0d30ec26b1d747a6e320ed7"
|
||||
},
|
||||
"breadd/src/adapters/power_upower.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "fc0a36ca76d340c8be77644f63e462bf",
|
||||
"semantic_hash": "fc0a36ca76d340c8be77644f63e462bf"
|
||||
},
|
||||
"breadd/src/adapters/systemd.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "b3884dbecd39acc38abdf67589a8b954",
|
||||
"semantic_hash": "b3884dbecd39acc38abdf67589a8b954"
|
||||
},
|
||||
"breadd/src/adapters/udev.rs": {
|
||||
"mtime": 1786800978.7399695,
|
||||
"ast_hash": "568993c8c2dd218879eec57aee50a6b9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/config.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "7f479bfb51647e6131c14f0c2f153d95",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/mod.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "e38bfdb894eabd208941bd3ffb1ef464",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/normalizer.rs": {
|
||||
"mtime": 1786801218.2233918,
|
||||
"ast_hash": "1596f60df5049ff8715f66f64bee9f8a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/state_engine.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "84a35ee78f3881261a3ce378ea3c03a0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/subscriptions.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "8735d4717b74523c787dab9ea2b0bbd8",
|
||||
"semantic_hash": "8735d4717b74523c787dab9ea2b0bbd8"
|
||||
},
|
||||
"breadd/src/core/supervisor.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "403f7ba1807c71f9b89d81bfeff2681a",
|
||||
"semantic_hash": "403f7ba1807c71f9b89d81bfeff2681a"
|
||||
},
|
||||
"breadd/src/core/types.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "8bd070d4c09725d8717749a79aa42a92",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/ipc/mod.rs": {
|
||||
"mtime": 1786800912.9916558,
|
||||
"ast_hash": "54af229257e555313f7d4b59d57ff8d3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/lua/mod.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "ed13e2495399d532625653a22a4fee14",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/main.rs": {
|
||||
"mtime": 1786800467.722855,
|
||||
"ast_hash": "4b31888cc9e76210df0c7cff3a8b1e42",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/tests/ipc_integration.rs": {
|
||||
"mtime": 1786801218.36339,
|
||||
"ast_hash": "2b5bade2cc2e189a3af9c692232be258",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/active-window-widget.lua": {
|
||||
"mtime": 1786800467.7243168,
|
||||
"ast_hash": "a5f6fb2c54775a49ddaf29674f86571d",
|
||||
"semantic_hash": "a5f6fb2c54775a49ddaf29674f86571d"
|
||||
},
|
||||
"examples/modules/bluetooth-toggle-widget.lua": {
|
||||
"mtime": 1786800467.7243168,
|
||||
"ast_hash": "c8529dc45862adf4f63db48674a28277",
|
||||
"semantic_hash": "c8529dc45862adf4f63db48674a28277"
|
||||
},
|
||||
"examples/modules/dock-monitors.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "4abe51f19614d2bf117ac35e95324801",
|
||||
"semantic_hash": "4abe51f19614d2bf117ac35e95324801"
|
||||
},
|
||||
"examples/modules/dock-workflow.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "84cf81cfb7780e89a46e96a6ccfbad15",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/focus-mode-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "f62c366c2c85cfbe59eef663fc607230",
|
||||
"semantic_hash": "f62c366c2c85cfbe59eef663fc607230"
|
||||
},
|
||||
"examples/modules/git-branch-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "ebeeaebab5b5b29619f3db65c1df57d8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/low-battery-warning.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "e0ba79860562fc36fa8cb183bc576fb7",
|
||||
"semantic_hash": "e0ba79860562fc36fa8cb183bc576fb7"
|
||||
},
|
||||
"examples/modules/pause-media-on-headphone-unplug.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "6c4cf82b6963eb93df224bed60d06c2d",
|
||||
"semantic_hash": "6c4cf82b6963eb93df224bed60d06c2d"
|
||||
},
|
||||
"examples/modules/workflow-status-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "9f913a66a0f8654dadc1c5d6c2be0938",
|
||||
"semantic_hash": "9f913a66a0f8654dadc1c5d6c2be0938"
|
||||
},
|
||||
"scripts/install.sh": {
|
||||
"mtime": 1786800994.0764284,
|
||||
"ast_hash": "35d1a7f63824e9176bd105ab3d699576",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"CONTRIBUTING.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"ast_hash": "6d056fcf0dae29949d19c41b41792879",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"Documentation.md": {
|
||||
"mtime": 1786801027.2816515,
|
||||
"ast_hash": "7b8471e7ae45aed70682bb858826860c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"Examples.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"ast_hash": "6bcd7a14be53a9f67ef6912b160da8bc",
|
||||
"semantic_hash": "6bcd7a14be53a9f67ef6912b160da8bc"
|
||||
},
|
||||
"README.md": {
|
||||
"mtime": 1786800994.0964282,
|
||||
"ast_hash": "97ae9f7efb9f2cdceb615a47cf3dfa1a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/io.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "dbe04e05d1cfb02770db8d7c0bcc0b68",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/lua_env.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "97d009846e18d3c809663b1185c98bbb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/main.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "9a93253ae44c764b8273df40999ddede",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/module_host_ipc.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "fcdb4c03f242a5ea51fd3a096b711363",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/permissions.rs": {
|
||||
"mtime": 1786800467.7210522,
|
||||
"ast_hash": "800445ef9c90bdbf8f3ac9d4f1afd98e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/rules.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "bd430cf213f400b8d4e96ccc35a76ff1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/ipc/module_host_bridge.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "caa9cf82695e48c88758fcfa835e1871",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/module_host.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "228826ff3c8941ea5f9bb28b66d637a9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/tests/module_host_sandbox.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "7e637b3a950c510215a6f6a7b88dd404",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/cpu-temp-widget/init.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"ast_hash": "5ac893dd2f6af6d8b22dd290e3021f77",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"xtask/src/main.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"ast_hash": "e914dd77ac3241df09e3a681228961db",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/dev-release.yml": {
|
||||
"mtime": 1786800467.7161875,
|
||||
"ast_hash": "707129aa2fe79b4539d108c03e6d7abf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/rc-release.yml": {
|
||||
"mtime": 1786800467.7167187,
|
||||
"ast_hash": "3007d2c43d785cd72f0548096626a21d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/release.yml": {
|
||||
"mtime": 1786800467.7167187,
|
||||
"ast_hash": "3578aa39e7b2466822c8d85247489d36",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"DEPRECATIONS.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"ast_hash": "1685b60fad2ed4184e4119c30866ec12",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/README.md": {
|
||||
"mtime": 1786800467.7242541,
|
||||
"ast_hash": "dfa8a72f41c08bd5b8036b684092a93b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"packaging/README.md": {
|
||||
"mtime": 1786800994.0430956,
|
||||
"ast_hash": "caa295eed64de126874a2e48b8aed8a2",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
# Graph Report - bread (2026-08-15)
|
||||
# Graph Report - bread (2026-08-16)
|
||||
|
||||
## Corpus Check
|
||||
- 62 files · ~88,250 words
|
||||
- 66 files · ~90,429 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 1467 nodes · 3347 edges · 88 communities (64 shown, 24 thin omitted)
|
||||
- Extraction: 99% EXTRACTED · 1% INFERRED · 0% AMBIGUOUS · INFERRED: 48 edges (avg confidence: 0.78)
|
||||
- 1486 nodes · 3384 edges · 93 communities (68 shown, 25 thin omitted)
|
||||
- Extraction: 99% EXTRACTED · 1% INFERRED · 0% AMBIGUOUS · INFERRED: 47 edges (avg confidence: 0.78)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `a6973360`
|
||||
- Built from commit: `cdd5de8f`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- lua/mod.rs
|
||||
- LuaEngine
|
||||
- RawEvent
|
||||
- config.rs
|
||||
- Server
|
||||
|
|
@ -31,24 +31,24 @@
|
|||
- bread-cli/src/main.rs
|
||||
- types.rs
|
||||
- podman.rs
|
||||
- StateHandle
|
||||
- run_udev_monitor
|
||||
- Value
|
||||
- Result
|
||||
- hooks_shell.rs
|
||||
- bluetooth.rs
|
||||
- SubscriptionId
|
||||
- glob.rs
|
||||
- run_state_engine
|
||||
- RtnetlinkAdapter
|
||||
- StateHandle
|
||||
- Adapter
|
||||
- network.rs
|
||||
- power.rs
|
||||
- hyprland.rs
|
||||
- Adapter
|
||||
- dl.breadway.dev Distribution
|
||||
- parse_upower_message
|
||||
- main Branch
|
||||
- git-branch-widget.lua
|
||||
- TestHarness
|
||||
- Sync
|
||||
- active-window-widget.lua
|
||||
- cpu-temp-widget.lua
|
||||
- .new
|
||||
- focus-mode-widget.lua
|
||||
- workflow-status-widget.lua
|
||||
- bread.widget API
|
||||
|
|
@ -70,10 +70,10 @@
|
|||
- bread.system.startup
|
||||
- Monitors Configuration Example
|
||||
- Binds Module (Built-in)
|
||||
- Bakery Package Manager
|
||||
- Phase 3: GUI Control Center
|
||||
- Phase 5: Cross-Device Mesh
|
||||
- Dev Version Computation
|
||||
- lua/mod.rs
|
||||
- external-monitors.lua
|
||||
- AGENTS.md — Repo hygiene
|
||||
- CLAUDE.md — Repo hygiene
|
||||
- ModuleHostLua
|
||||
- ModuleHostRegistry
|
||||
- xtask/src/main.rs
|
||||
|
|
@ -98,15 +98,20 @@
|
|||
- init.lua
|
||||
- Execution
|
||||
- packaging/README.md
|
||||
- PathBuf
|
||||
- build.sh
|
||||
- beta Release Track
|
||||
- dev Release Track
|
||||
- stable Release Track
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `LuaEngine` - 59 edges
|
||||
2. `RawEvent` - 49 edges
|
||||
2. `RawEvent` - 50 edges
|
||||
3. `BreadEvent` - 38 edges
|
||||
4. `raw()` - 37 edges
|
||||
5. `RuntimeState` - 34 edges
|
||||
5. `RuntimeState` - 36 edges
|
||||
6. `StateHandle` - 28 edges
|
||||
7. `now_unix_ms()` - 26 edges
|
||||
7. `now_unix_ms()` - 25 edges
|
||||
8. `Adapter` - 25 edges
|
||||
9. `SubscriptionId` - 25 edges
|
||||
10. `ModuleHostLua` - 24 edges
|
||||
|
|
@ -118,31 +123,29 @@
|
|||
breadd/src/adapters/bluetooth.rs → bread-shared/src/lib.rs
|
||||
- `classify()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/filesystem.rs → bread-shared/src/lib.rs
|
||||
- `emit_topology_snapshot()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/hyprland.rs → bread-shared/src/lib.rs
|
||||
- `network_raw_event()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/network.rs → bread-shared/src/lib.rs
|
||||
- `power_raw_event()` --calls--> `now_unix_ms()` [INFERRED]
|
||||
breadd/src/adapters/power.rs → bread-shared/src/lib.rs
|
||||
|
||||
## Import Cycles
|
||||
- 2-file cycle: `breadd/src/core/state_engine.rs -> breadd/src/lua/mod.rs -> breadd/src/core/state_engine.rs`
|
||||
- 2-file cycle: `bread-shared/src/lib.rs -> bread-shared/src/module_host_ipc.rs -> bread-shared/src/lib.rs`
|
||||
|
||||
## Hyperedges (group relationships)
|
||||
- **** — ci_dev_release, workflow_version_compute, release_track_dev, distribution_dl_breadway_dev, package_bakery [INFERRED]
|
||||
- **** — adapter_udev, adapter_hyprland, adapter_power, sys_bread_daemon, api_bread_on, sys_lua_runtime [INFERRED]
|
||||
- **** — config_init_lua, config_modules_dir, pattern_module_skeleton, api_bread_on, sys_lua_runtime [INFERRED]
|
||||
- **** — api_bread_workflow, api_bread_spawn, api_bread_wait, example_dock_workflow, api_bread_notify [INFERRED]
|
||||
- **** — api_bread_widget, api_bread_every, example_widget_cpu_temp, api_bread_state_watch [INFERRED]
|
||||
- **** — branch_main, ci_dev_release, ci_rc_release, ci_stable_release, release_track_dev, release_track_beta, release_track_stable [INFERRED]
|
||||
|
||||
## Communities (88 total, 24 thin omitted)
|
||||
## Communities (93 total, 25 thin omitted)
|
||||
|
||||
### Community 0 - "lua/mod.rs"
|
||||
Cohesion: 0.06
|
||||
Nodes (86): now_unix_ms(), ModulePermission, Option, String, WidgetSpec, RuntimeState, bluetooth_connect(), bluetooth_disconnect() (+78 more)
|
||||
### Community 0 - "LuaEngine"
|
||||
Cohesion: 0.11
|
||||
Nodes (19): ErrorEntry, HandlerEntry, HandlerKind, LuaEngine, LuaMessage, ModuleInfo, AtomicU64, HashMap (+11 more)
|
||||
|
||||
### Community 1 - "RawEvent"
|
||||
Cohesion: 0.05
|
||||
Cohesion: 0.06
|
||||
Nodes (67): adapter_source_is_hashable_and_eq(), AdapterSource, bread_event_new_accepts_owned_and_borrowed_names(), bread_event_new_assigns_unique_id_and_no_cause(), bread_event_new_sets_current_timestamp(), bread_event_with_timestamp_preserves_timestamp_and_assigns_id(), BreadEvent, DaemonSection (+59 more)
|
||||
|
||||
### Community 2 - "config.rs"
|
||||
|
|
@ -155,11 +158,11 @@ Nodes (41): A, command_target(), event_domain(), is_known_app(), is_reserved_dom
|
|||
|
||||
### Community 4 - "widget.rs"
|
||||
Cohesion: 0.07
|
||||
Nodes (32): accepts_node_count_at_max(), accepts_tree_at_max_depth(), Align, Background, box_of(), default_orientation(), FontWeight, is_valid_class() (+24 more)
|
||||
Nodes (33): accepts_node_count_at_max(), accepts_tree_at_max_depth(), Align, Background, box_of(), default_orientation(), FontWeight, is_valid_class() (+25 more)
|
||||
|
||||
### Community 5 - "Bread Daemon (breadd)"
|
||||
Cohesion: 0.06
|
||||
Nodes (39): Bluetooth Adapter, Hyprland Adapter, Network Adapter, Power Adapter, udev Adapter, bread.on(pattern, fn), bread.spawn(fn), bread.wait(pattern, opts) (+31 more)
|
||||
Nodes (36): Bluetooth Adapter, Hyprland Adapter, Network Adapter, Power Adapter, udev Adapter, bread.on(pattern, fn), bread.spawn(fn), bread.wait(pattern, opts) (+28 more)
|
||||
|
||||
### Community 6 - "filesystem.rs"
|
||||
Cohesion: 0.12
|
||||
|
|
@ -175,7 +178,7 @@ Nodes (50): daemon_survives_repeated_reloads_and_pipeline_resumes(), emit_with_a
|
|||
|
||||
### Community 9 - "state_engine.rs"
|
||||
Cohesion: 0.12
|
||||
Nodes (19): apply_device_change(), apply_event_to_state(), device_connect_adds_device_with_all_fields(), device_connect_is_idempotent_for_same_id(), device_disconnect_of_unknown_id_is_noop(), device_disconnect_removes_matching_id(), ev(), monitor_connect_adds_new_monitor() (+11 more)
|
||||
Nodes (20): apply_device_change(), apply_event_to_state(), device_connect_adds_device_with_all_fields(), device_connect_is_idempotent_for_same_id(), device_disconnect_of_unknown_id_is_noop(), device_disconnect_removes_matching_id(), ev(), hyprland_snapshot_replaces_topology() (+12 more)
|
||||
|
||||
### Community 10 - "modules_mgmt.rs"
|
||||
Cohesion: 0.11
|
||||
|
|
@ -194,20 +197,20 @@ Cohesion: 0.19
|
|||
Nodes (29): CausalityTracker, Cli, Commands, config_directory(), daemon_socket_path(), format_timestamp(), handle_modules_cmd(), HooksCommand (+21 more)
|
||||
|
||||
### Community 14 - "types.rs"
|
||||
Cohesion: 0.17
|
||||
Nodes (21): Device, DeviceRule, DeviceTopology, InterfaceState, MatchCondition, ModuleStatus, Monitor, NetworkState (+13 more)
|
||||
Cohesion: 0.15
|
||||
Nodes (21): DeviceTopology, InterfaceState, MatchCondition, ModuleStatus, Monitor, NetworkState, PowerState, ProfileState (+13 more)
|
||||
|
||||
### Community 15 - "podman.rs"
|
||||
Cohesion: 0.15
|
||||
Nodes (17): container_event(), ignores_remove_event(), ignores_stop_event_to_avoid_double_emit_with_died(), ignores_unknown_action(), map_podman_event(), maps_died_event(), maps_health_status_event(), maps_start_event() (+9 more)
|
||||
|
||||
### Community 16 - "StateHandle"
|
||||
Cohesion: 0.14
|
||||
Nodes (10): condition_matches(), resolve_device(), Option, Result, String, Value, Vec, StateHandle (+2 more)
|
||||
### Community 16 - "Value"
|
||||
Cohesion: 0.17
|
||||
Nodes (14): active_window_from_data(), apply_hyprland_snapshot(), condition_matches(), hyprland_state_key(), json_stringish(), resolve_device(), Option, Result (+6 more)
|
||||
|
||||
### Community 17 - "run_udev_monitor"
|
||||
Cohesion: 0.35
|
||||
Nodes (9): enumerate_with_udev(), Result, Self, Sender, String, Vec, run_udev_monitor(), ScannedDevice (+1 more)
|
||||
### Community 17 - "Result"
|
||||
Cohesion: 0.13
|
||||
Nodes (26): bluetooth_connect(), bluetooth_disconnect(), bluetooth_find_adapter(), bluetooth_get_powered(), bluetooth_query(), bluetooth_set_powered(), bluetooth_set_scanning(), bluetooth_spawn() (+18 more)
|
||||
|
||||
### Community 18 - "hooks_shell.rs"
|
||||
Cohesion: 0.18
|
||||
|
|
@ -221,13 +224,13 @@ Nodes (10): address_from_path(), BluetoothAdapter, parse_bluetooth_message(), Me
|
|||
Cohesion: 0.29
|
||||
Nodes (13): HashMap, String, Vec, Subscription, SubscriptionId, SubscriptionTable, table_add_assigns_provided_id_and_finds_match(), table_clear_removes_all() (+5 more)
|
||||
|
||||
### Community 22 - "run_state_engine"
|
||||
Cohesion: 0.27
|
||||
Nodes (12): dispatch_event(), handle_command(), Arc, AtomicU64, Receiver, RwLock, Self, Sender (+4 more)
|
||||
### Community 22 - "StateHandle"
|
||||
Cohesion: 0.15
|
||||
Nodes (16): dispatch_event(), handle_command(), Arc, AtomicU64, HashMap, Receiver, RwLock, Self (+8 more)
|
||||
|
||||
### Community 23 - "RtnetlinkAdapter"
|
||||
Cohesion: 0.22
|
||||
Nodes (7): ip_from_bytes(), Option, Result, Self, Sender, String, RtnetlinkAdapter
|
||||
### Community 23 - "Adapter"
|
||||
Cohesion: 0.19
|
||||
Nodes (9): Adapter, ip_from_bytes(), Option, Result, Self, Sender, String, RtnetlinkAdapter (+1 more)
|
||||
|
||||
### Community 24 - "network.rs"
|
||||
Cohesion: 0.27
|
||||
|
|
@ -239,15 +242,11 @@ Nodes (8): power_raw_event(), PowerAdapter, PowerSnapshot, read_power_state(), O
|
|||
|
||||
### Community 26 - "hyprland.rs"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): hyprland_event_socket(), HyprlandAdapter, parse_hyprland_line(), PathBuf, Result, Sender, String
|
||||
Nodes (11): emit_topology_snapshot(), hyprland_event_socket(), hyprland_request_json(), hyprland_request_socket(), HyprlandAdapter, parse_hyprland_line(), PathBuf, Result (+3 more)
|
||||
|
||||
### Community 27 - "Adapter"
|
||||
Cohesion: 0.23
|
||||
Nodes (8): Adapter, parse_upower_message(), Message, Result, Self, Sender, UPowerAdapter, Send
|
||||
|
||||
### Community 28 - "dl.breadway.dev Distribution"
|
||||
Cohesion: 0.25
|
||||
Nodes (8): main Branch, dev-release.yml Workflow, rc-release.yml Workflow, release.yml Workflow, dl.breadway.dev Distribution, beta Release Track, dev Release Track, stable Release Track
|
||||
### Community 27 - "parse_upower_message"
|
||||
Cohesion: 0.27
|
||||
Nodes (6): parse_upower_message(), Message, Result, Self, Sender, UPowerAdapter
|
||||
|
||||
### Community 29 - "git-branch-widget.lua"
|
||||
Cohesion: 0.62
|
||||
|
|
@ -265,9 +264,9 @@ Nodes (3): main(), Result, Sync
|
|||
Cohesion: 0.83
|
||||
Nodes (3): label_for(), M.on_load(), widget_root()
|
||||
|
||||
### Community 33 - "cpu-temp-widget.lua"
|
||||
Cohesion: 0.83
|
||||
Nodes (3): M.on_load(), read_temp_c(), widget_root()
|
||||
### Community 33 - ".new"
|
||||
Cohesion: 0.16
|
||||
Nodes (15): ModulePermission, Option, String, bluetooth_list_devices(), builtin_module_decls(), is_lib_path(), list_lua_files(), module_name_from_path() (+7 more)
|
||||
|
||||
### Community 34 - "focus-mode-widget.lua"
|
||||
Cohesion: 1.00
|
||||
|
|
@ -281,8 +280,24 @@ Nodes (3): M.on_load(), most_relevant(), widget_update()
|
|||
Cohesion: 0.67
|
||||
Nodes (3): bread.widget API, CPU Temperature Widget Example, Live Widget Update Pattern
|
||||
|
||||
### Community 60 - "lua/mod.rs"
|
||||
Cohesion: 0.30
|
||||
Nodes (20): now_unix_ms(), RuntimeState, module_store_get(), module_store_set(), Arc, JsonValue, RwLock, widget_list_json() (+12 more)
|
||||
|
||||
### Community 61 - "external-monitors.lua"
|
||||
Cohesion: 0.29
|
||||
Nodes (8): apply(), apply_monitor(), connected(), drm_first_mode(), drm_status(), is_internal(), list_connectors(), M.on_load()
|
||||
|
||||
### Community 62 - "AGENTS.md — Repo hygiene"
|
||||
Cohesion: 0.33
|
||||
Nodes (5): AGENTS.md — Repo hygiene, CI, Don't, Local architecture (still true), Remotes
|
||||
|
||||
### Community 63 - "CLAUDE.md — Repo hygiene"
|
||||
Cohesion: 0.40
|
||||
Nodes (4): CI, CLAUDE.md — Repo hygiene, Don't, Remotes
|
||||
|
||||
### Community 64 - "ModuleHostLua"
|
||||
Cohesion: 0.10
|
||||
Cohesion: 0.09
|
||||
Nodes (38): call(), HostMessage, IoCommand, RpcResponse, Duration, Option, PathBuf, Receiver (+30 more)
|
||||
|
||||
### Community 65 - "ModuleHostRegistry"
|
||||
|
|
@ -310,8 +325,8 @@ Cohesion: 0.14
|
|||
Nodes (14): API Stability & Versioning, Bread Documentation, Contents, Debugging tips, Dictionary: Event reference, Dictionary: IPC protocol, Dictionary: Runtime state schema, Integrating a bread\* app (+6 more)
|
||||
|
||||
### Community 71 - "udev.rs"
|
||||
Cohesion: 0.32
|
||||
Nodes (10): build_device_event(), build_event(), enumerate_payload_includes_classification_fields(), prop_bool(), prop_str(), Option, Value, udev_event_payload() (+2 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (18): build_device_event(), build_event(), enumerate_payload_includes_classification_fields(), prop_bool(), prop_str(), Option, Result, Self (+10 more)
|
||||
|
||||
### Community 72 - "Dictionary: Lua API"
|
||||
Cohesion: 0.17
|
||||
|
|
@ -373,25 +388,29 @@ Nodes (3): M.on_load(), read_temp_c(), widget_root()
|
|||
Cohesion: 0.67
|
||||
Nodes (3): `bread.exec_capture(cmd, opts) -> ok, stdout`, `bread.exec(cmd)`, Execution
|
||||
|
||||
### Community 88 - "PathBuf"
|
||||
Cohesion: 1.00
|
||||
Nodes (3): dirs_home(), lua_expand_path(), PathBuf
|
||||
|
||||
## Knowledge Gaps
|
||||
- **179 isolated node(s):** `install.sh script`, `Branches`, `The release cycle`, `Tracks, from a user's perspective`, `Keeping the API docs honest` (+174 more)
|
||||
- **182 isolated node(s):** `build.sh script`, `install.sh script`, `Remotes`, `CI`, `Local architecture (still true)` (+177 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **24 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
- **25 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `RawEvent` connect `RawEvent` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `run_udev_monitor`, `bluetooth.rs`, `RtnetlinkAdapter`, `network.rs`, `power.rs`, `hyprland.rs`, `Adapter`?**
|
||||
_High betweenness centrality (0.094) - this node is a cross-community bridge._
|
||||
- **Why does `Adapter` connect `Adapter` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `run_udev_monitor`, `bluetooth.rs`, `RtnetlinkAdapter`, `network.rs`, `power.rs`, `hyprland.rs`, `Sync`?**
|
||||
_High betweenness centrality (0.077) - this node is a cross-community bridge._
|
||||
- **Why does `BreadEvent` connect `RawEvent` to `ModuleHostLua`, `lua/mod.rs`, `ModuleHostRegistry`, `Server`, `state_engine.rs`, `run_state_engine`?**
|
||||
_High betweenness centrality (0.063) - this node is a cross-community bridge._
|
||||
- **What connects `install.sh script`, `Branches`, `The release cycle` to the rest of the system?**
|
||||
_179 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `lua/mod.rs` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.056 - nodes in this community are weakly interconnected._
|
||||
- **Why does `Adapter` connect `Adapter` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `bluetooth.rs`, `network.rs`, `power.rs`, `hyprland.rs`, `parse_upower_message`, `Sync`?**
|
||||
_High betweenness centrality (0.089) - this node is a cross-community bridge._
|
||||
- **Why does `RawEvent` connect `RawEvent` to `Server`, `filesystem.rs`, `git.rs`, `udev.rs`, `systemd.rs`, `podman.rs`, `bluetooth.rs`, `Adapter`, `network.rs`, `power.rs`, `hyprland.rs`, `parse_upower_message`?**
|
||||
_High betweenness centrality (0.084) - this node is a cross-community bridge._
|
||||
- **Why does `BreadEvent` connect `RawEvent` to `ModuleHostLua`, `LuaEngine`, `.new`, `Server`, `ModuleHostRegistry`, `state_engine.rs`, `StateHandle`?**
|
||||
_High betweenness centrality (0.061) - this node is a cross-community bridge._
|
||||
- **What connects `build.sh script`, `install.sh script`, `Remotes` to the rest of the system?**
|
||||
_182 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `LuaEngine` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11153846153846154 - nodes in this community are weakly interconnected._
|
||||
- **Should `RawEvent` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.051842708517016396 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.05702970297029703 - nodes in this community are weakly interconnected._
|
||||
- **Should `config.rs` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.07191780821917808 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.0670122176971492 - nodes in this community are weakly interconnected._
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"nodes": [{"id": "$graphify-root$_deprecations_md", "label": "DEPRECATIONS.md", "file_type": "document", "source_file": "DEPRECATIONS.md", "source_location": "L1"}, {"id": "$graphify-root$_deprecations_deprecations", "label": "Deprecations", "file_type": "document", "source_file": "DEPRECATIONS.md", "source_location": "L1"}, {"id": "$graphify-root$_deprecations_hyprland_legacy_flat_event_names_since_v1_5", "label": "Hyprland legacy flat event names (since v1.5)", "file_type": "document", "source_file": "DEPRECATIONS.md", "source_location": "L8"}], "edges": [{"source": "$graphify-root$_deprecations_md", "target": "$graphify-root$_deprecations_deprecations", "relation": "contains", "confidence": "EXTRACTED", "source_file": "DEPRECATIONS.md", "source_location": "L1", "weight": 1.0}, {"source": "$graphify-root$_deprecations_md", "target": "$graphify-root$_documentation_md", "relation": "references", "confidence": "EXTRACTED", "source_file": "DEPRECATIONS.md", "source_location": "L4", "weight": 1.0, "target_file": "$graphify-root$/Documentation.md"}, {"source": "$graphify-root$_deprecations_deprecations", "target": "$graphify-root$_deprecations_hyprland_legacy_flat_event_names_since_v1_5", "relation": "contains", "confidence": "EXTRACTED", "source_file": "DEPRECATIONS.md", "source_location": "L8", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"nodes": [{"id": "$graphify-root$_claude_md", "label": "CLAUDE.md", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L1"}, {"id": "$graphify-root$_claude_claude_md_repo_hygiene", "label": "CLAUDE.md \u2014 Repo hygiene", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L1"}, {"id": "$graphify-root$_claude_remotes", "label": "Remotes", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L10"}, {"id": "$graphify-root$_claude_ci", "label": "CI", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L14"}, {"id": "$graphify-root$_claude_don_t", "label": "Don't", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L19"}], "edges": [{"source": "$graphify-root$_claude_md", "target": "$graphify-root$_claude_claude_md_repo_hygiene", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CLAUDE.md", "source_location": "L1", "weight": 1.0}, {"source": "$graphify-root$_claude_claude_md_repo_hygiene", "target": "$graphify-root$_claude_remotes", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CLAUDE.md", "source_location": "L10", "weight": 1.0}, {"source": "$graphify-root$_claude_claude_md_repo_hygiene", "target": "$graphify-root$_claude_ci", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CLAUDE.md", "source_location": "L14", "weight": 1.0}, {"source": "$graphify-root$_claude_claude_md_repo_hygiene", "target": "$graphify-root$_claude_don_t", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CLAUDE.md", "source_location": "L19", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
{"nodes": [{"id": "$graphify-root$_ci_build_sh", "label": "build.sh", "file_type": "code", "source_file": "ci/build.sh", "source_location": "L1", "metadata": {"language": "bash", "kind": "file"}}, {"id": "$graphify-root$_ci_build_sh__entry", "label": "build.sh script", "file_type": "code", "source_file": "ci/build.sh", "source_location": "L1", "metadata": {"language": "bash", "kind": "bash_entrypoint"}}], "edges": [{"source": "$graphify-root$_ci_build_sh", "target": "$graphify-root$_ci_build_sh__entry", "relation": "contains", "confidence": "EXTRACTED", "source_file": "ci/build.sh", "source_location": "L1", "weight": 1.0}], "raw_calls": [{"language": "bash", "callee": "set", "caller_nid": "$graphify-root$_ci_build_sh__entry", "source_file": "ci/build.sh", "source_location": "L9"}, {"language": "bash", "callee": "rm", "caller_nid": "$graphify-root$_ci_build_sh__entry", "source_file": "ci/build.sh", "source_location": "L16"}, {"language": "bash", "callee": "git", "caller_nid": "$graphify-root$_ci_build_sh__entry", "source_file": "ci/build.sh", "source_location": "L17"}], "bash_sources": []}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"nodes": [{"id": "$graphify-root$_examples_modules_readme_md", "label": "README.md", "file_type": "document", "source_file": "examples/modules/README.md", "source_location": "L1"}, {"id": "$graphify-root$_examples_modules_readme_example_bread_modules", "label": "Example bread modules", "file_type": "document", "source_file": "examples/modules/README.md", "source_location": "L1"}, {"id": "$graphify-root$_examples_modules_readme_installing", "label": "Installing", "file_type": "document", "source_file": "examples/modules/README.md", "source_location": "L7"}, {"id": "$graphify-root$_examples_modules_readme_modules", "label": "Modules", "file_type": "document", "source_file": "examples/modules/README.md", "source_location": "L33"}], "edges": [{"source": "$graphify-root$_examples_modules_readme_md", "target": "$graphify-root$_examples_modules_readme_example_bread_modules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L1", "weight": 1.0}, {"source": "$graphify-root$_examples_modules_readme_md", "target": "$graphify-root$_examples_md", "relation": "references", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L4", "weight": 1.0, "target_file": "$graphify-root$/Examples.md"}, {"source": "$graphify-root$_examples_modules_readme_example_bread_modules", "target": "$graphify-root$_examples_modules_readme_installing", "relation": "contains", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L7", "weight": 1.0}, {"source": "$graphify-root$_examples_modules_readme_md", "target": "$graphify-root$_examples_modules_permissions_md", "relation": "references", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L18", "weight": 1.0}, {"source": "$graphify-root$_examples_modules_readme_md", "target": "$graphify-root$_documentation_md", "relation": "references", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L19", "weight": 1.0, "target_file": "$graphify-root$/Documentation.md"}, {"source": "$graphify-root$_examples_modules_readme_example_bread_modules", "target": "$graphify-root$_examples_modules_readme_modules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "examples/modules/README.md", "source_location": "L33", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"nodes": [{"id": "$graphify-root$_agents_md", "label": "AGENTS.md", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L1"}, {"id": "$graphify-root$_agents_agents_md_repo_hygiene", "label": "AGENTS.md \u2014 Repo hygiene", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L1"}, {"id": "$graphify-root$_agents_remotes", "label": "Remotes", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L16"}, {"id": "$graphify-root$_agents_ci", "label": "CI", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L22"}, {"id": "$graphify-root$_agents_local_architecture_still_true", "label": "Local architecture (still true)", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L31"}, {"id": "$graphify-root$_agents_don_t", "label": "Don't", "file_type": "document", "source_file": "AGENTS.md", "source_location": "L39"}], "edges": [{"source": "$graphify-root$_agents_md", "target": "$graphify-root$_agents_agents_md_repo_hygiene", "relation": "contains", "confidence": "EXTRACTED", "source_file": "AGENTS.md", "source_location": "L1", "weight": 1.0}, {"source": "$graphify-root$_agents_agents_md_repo_hygiene", "target": "$graphify-root$_agents_remotes", "relation": "contains", "confidence": "EXTRACTED", "source_file": "AGENTS.md", "source_location": "L16", "weight": 1.0}, {"source": "$graphify-root$_agents_agents_md_repo_hygiene", "target": "$graphify-root$_agents_ci", "relation": "contains", "confidence": "EXTRACTED", "source_file": "AGENTS.md", "source_location": "L22", "weight": 1.0}, {"source": "$graphify-root$_agents_agents_md_repo_hygiene", "target": "$graphify-root$_agents_local_architecture_still_true", "relation": "contains", "confidence": "EXTRACTED", "source_file": "AGENTS.md", "source_location": "L31", "weight": 1.0}, {"source": "$graphify-root$_agents_agents_md_repo_hygiene", "target": "$graphify-root$_agents_don_t", "relation": "contains", "confidence": "EXTRACTED", "source_file": "AGENTS.md", "source_location": "L39", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
graphify-out/cache/last_query_stamp
vendored
2
graphify-out/cache/last_query_stamp
vendored
|
|
@ -1 +1 @@
|
|||
1785892770.494006
|
||||
1786850688.401695
|
||||
2
graphify-out/cache/stat-index.json
vendored
2
graphify-out/cache/stat-index.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
22866
graphify-out/graph.json
22866
graphify-out/graph.json
File diff suppressed because it is too large
Load diff
|
|
@ -1,327 +1,352 @@
|
|||
{
|
||||
"bread-cli/src/hooks_git.rs": {
|
||||
"mtime": 1786800467.7200727,
|
||||
"mtime": 1784781158.0572724,
|
||||
"ast_hash": "7a29b5d5d90170f0aef9cececc7d8656",
|
||||
"semantic_hash": "7a29b5d5d90170f0aef9cececc7d8656"
|
||||
},
|
||||
"bread-cli/src/hooks_shell.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"mtime": 1784781158.0582726,
|
||||
"ast_hash": "c5d5b8922fcff79954ddb00496721603",
|
||||
"semantic_hash": "c5d5b8922fcff79954ddb00496721603"
|
||||
},
|
||||
"bread-cli/src/lib.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"mtime": 1778512393.4941568,
|
||||
"ast_hash": "d1bf6e1c239498521c42418f672bc400",
|
||||
"semantic_hash": "d1bf6e1c239498521c42418f672bc400"
|
||||
},
|
||||
"bread-cli/src/main.rs": {
|
||||
"mtime": 1786800467.7201686,
|
||||
"mtime": 1785882914.3322613,
|
||||
"ast_hash": "e1fbe63ea3b10e0887072ab7133d0508",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-cli/src/modules_mgmt.rs": {
|
||||
"mtime": 1786801244.1263742,
|
||||
"mtime": 1785882914.3322613,
|
||||
"ast_hash": "1cb6f3e4fa26108f81215ab57bb02b91",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-cli/tests/modules.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1784781158.0602725,
|
||||
"ast_hash": "84fca8f87dc915b1cb523f8199e78521",
|
||||
"semantic_hash": "84fca8f87dc915b1cb523f8199e78521"
|
||||
},
|
||||
"bread-emit/src/main.rs": {
|
||||
"mtime": 1786800467.7206197,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "350cefbf697cfd93f7df7b7bcc45a101",
|
||||
"semantic_hash": "350cefbf697cfd93f7df7b7bcc45a101"
|
||||
},
|
||||
"bread-shared/src/apps.rs": {
|
||||
"mtime": 1786801218.1467261,
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "e8419571e7a322019d71c89559fb02fb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/glob.rs": {
|
||||
"mtime": 1786800467.7210522,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "0594a313cb1909d1cca5fd5b8f241b68",
|
||||
"semantic_hash": "0594a313cb1909d1cca5fd5b8f241b68"
|
||||
},
|
||||
"bread-shared/src/lib.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "236b73bad29f1544a28fbf3ee1ccc795",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/widget.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1784781173.9236407,
|
||||
"ast_hash": "33272eb38c7fffbfa180cef7c5a286fc",
|
||||
"semantic_hash": "33272eb38c7fffbfa180cef7c5a286fc"
|
||||
},
|
||||
"breadd/src/adapters/bluetooth.rs": {
|
||||
"mtime": 1786800467.7214499,
|
||||
"mtime": 1778843727.5135255,
|
||||
"ast_hash": "4d1df67347d5b7c9cdbcb12921a6ae28",
|
||||
"semantic_hash": "4d1df67347d5b7c9cdbcb12921a6ae28"
|
||||
},
|
||||
"breadd/src/adapters/filesystem.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "8ec9dcd8de13f30922cfbe9b4a3fff56",
|
||||
"semantic_hash": "8ec9dcd8de13f30922cfbe9b4a3fff56"
|
||||
},
|
||||
"breadd/src/adapters/git.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "6e6ff6ca318e28cd94690c30d41b520b",
|
||||
"semantic_hash": "6e6ff6ca318e28cd94690c30d41b520b"
|
||||
},
|
||||
"breadd/src/adapters/hyprland.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"ast_hash": "71537dbd86b413d94476f8022054f1f4",
|
||||
"semantic_hash": "71537dbd86b413d94476f8022054f1f4"
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "86056a351db61eb1788a2147d859fc5c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/adapters/mod.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "63885887c2fc3ea2314d7fe095e5df61",
|
||||
"semantic_hash": "63885887c2fc3ea2314d7fe095e5df61"
|
||||
},
|
||||
"breadd/src/adapters/network.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1778470615.8460202,
|
||||
"ast_hash": "8706dc546b7e08d5aa084ca58c48559c",
|
||||
"semantic_hash": "8706dc546b7e08d5aa084ca58c48559c"
|
||||
},
|
||||
"breadd/src/adapters/network_rtnetlink.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0616376,
|
||||
"ast_hash": "0c9d0bb2693bc46b11807f6b8ebb7c4c",
|
||||
"semantic_hash": "0c9d0bb2693bc46b11807f6b8ebb7c4c"
|
||||
},
|
||||
"breadd/src/adapters/podman.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0622723,
|
||||
"ast_hash": "97c08551c0fe53b0a5888d98730d35db",
|
||||
"semantic_hash": "97c08551c0fe53b0a5888d98730d35db"
|
||||
},
|
||||
"breadd/src/adapters/power.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1778470615.838569,
|
||||
"ast_hash": "987d202ec0d30ec26b1d747a6e320ed7",
|
||||
"semantic_hash": "987d202ec0d30ec26b1d747a6e320ed7"
|
||||
},
|
||||
"breadd/src/adapters/power_upower.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0622723,
|
||||
"ast_hash": "fc0a36ca76d340c8be77644f63e462bf",
|
||||
"semantic_hash": "fc0a36ca76d340c8be77644f63e462bf"
|
||||
},
|
||||
"breadd/src/adapters/systemd.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1784781158.0622723,
|
||||
"ast_hash": "b3884dbecd39acc38abdf67589a8b954",
|
||||
"semantic_hash": "b3884dbecd39acc38abdf67589a8b954"
|
||||
},
|
||||
"breadd/src/adapters/udev.rs": {
|
||||
"mtime": 1786800978.7399695,
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "568993c8c2dd218879eec57aee50a6b9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/config.rs": {
|
||||
"mtime": 1786800467.7215972,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "7f479bfb51647e6131c14f0c2f153d95",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/mod.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "e38bfdb894eabd208941bd3ffb1ef464",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/normalizer.rs": {
|
||||
"mtime": 1786801218.2233918,
|
||||
"ast_hash": "1596f60df5049ff8715f66f64bee9f8a",
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "3e0e6e0b46cc3d42dbfd6348fc5f0bb1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/state_engine.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"ast_hash": "84a35ee78f3881261a3ce378ea3c03a0",
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "0e54b3b7d1de26db074454d469543192",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/subscriptions.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"mtime": 1784781158.0632722,
|
||||
"ast_hash": "8735d4717b74523c787dab9ea2b0bbd8",
|
||||
"semantic_hash": "8735d4717b74523c787dab9ea2b0bbd8"
|
||||
},
|
||||
"breadd/src/core/supervisor.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"mtime": 1778680581.3778126,
|
||||
"ast_hash": "403f7ba1807c71f9b89d81bfeff2681a",
|
||||
"semantic_hash": "403f7ba1807c71f9b89d81bfeff2681a"
|
||||
},
|
||||
"breadd/src/core/types.rs": {
|
||||
"mtime": 1786800467.7223108,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "8bd070d4c09725d8717749a79aa42a92",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/ipc/mod.rs": {
|
||||
"mtime": 1786800912.9916558,
|
||||
"ast_hash": "54af229257e555313f7d4b59d57ff8d3",
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "d5bc8f1194e7356de3fe181c68133cba",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/lua/mod.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "ed13e2495399d532625653a22a4fee14",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/main.rs": {
|
||||
"mtime": 1786800467.722855,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "4b31888cc9e76210df0c7cff3a8b1e42",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/tests/ipc_integration.rs": {
|
||||
"mtime": 1786801218.36339,
|
||||
"mtime": 1786805047.7042425,
|
||||
"ast_hash": "2b5bade2cc2e189a3af9c692232be258",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/active-window-widget.lua": {
|
||||
"mtime": 1786800467.7243168,
|
||||
"mtime": 1784781173.9256406,
|
||||
"ast_hash": "a5f6fb2c54775a49ddaf29674f86571d",
|
||||
"semantic_hash": "a5f6fb2c54775a49ddaf29674f86571d"
|
||||
},
|
||||
"examples/modules/bluetooth-toggle-widget.lua": {
|
||||
"mtime": 1786800467.7243168,
|
||||
"mtime": 1784781173.9256406,
|
||||
"ast_hash": "c8529dc45862adf4f63db48674a28277",
|
||||
"semantic_hash": "c8529dc45862adf4f63db48674a28277"
|
||||
},
|
||||
"examples/modules/dock-monitors.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1784781158.0663679,
|
||||
"ast_hash": "4abe51f19614d2bf117ac35e95324801",
|
||||
"semantic_hash": "4abe51f19614d2bf117ac35e95324801"
|
||||
},
|
||||
"examples/modules/dock-workflow.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1785882914.337525,
|
||||
"ast_hash": "84cf81cfb7780e89a46e96a6ccfbad15",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/focus-mode-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1784781173.9256406,
|
||||
"ast_hash": "f62c366c2c85cfbe59eef663fc607230",
|
||||
"semantic_hash": "f62c366c2c85cfbe59eef663fc607230"
|
||||
},
|
||||
"examples/modules/git-branch-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1785882914.337525,
|
||||
"ast_hash": "ebeeaebab5b5b29619f3db65c1df57d8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/low-battery-warning.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1784781158.0663679,
|
||||
"ast_hash": "e0ba79860562fc36fa8cb183bc576fb7",
|
||||
"semantic_hash": "e0ba79860562fc36fa8cb183bc576fb7"
|
||||
},
|
||||
"examples/modules/pause-media-on-headphone-unplug.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1784781158.0663679,
|
||||
"ast_hash": "6c4cf82b6963eb93df224bed60d06c2d",
|
||||
"semantic_hash": "6c4cf82b6963eb93df224bed60d06c2d"
|
||||
},
|
||||
"examples/modules/workflow-status-widget.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1784781173.9256406,
|
||||
"ast_hash": "9f913a66a0f8654dadc1c5d6c2be0938",
|
||||
"semantic_hash": "9f913a66a0f8654dadc1c5d6c2be0938"
|
||||
},
|
||||
"scripts/install.sh": {
|
||||
"mtime": 1786800994.0764284,
|
||||
"mtime": 1786805047.710909,
|
||||
"ast_hash": "35d1a7f63824e9176bd105ab3d699576",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"CONTRIBUTING.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"mtime": 1785909683.2691193,
|
||||
"ast_hash": "6d056fcf0dae29949d19c41b41792879",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"Documentation.md": {
|
||||
"mtime": 1786801027.2816515,
|
||||
"ast_hash": "7b8471e7ae45aed70682bb858826860c",
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "e219e52fae2208f771d9b77d87d6790b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"Examples.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"mtime": 1784781173.9236407,
|
||||
"ast_hash": "6bcd7a14be53a9f67ef6912b160da8bc",
|
||||
"semantic_hash": "6bcd7a14be53a9f67ef6912b160da8bc"
|
||||
},
|
||||
"README.md": {
|
||||
"mtime": 1786800994.0964282,
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "97ae9f7efb9f2cdceb615a47cf3dfa1a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/io.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1786805041.5686455,
|
||||
"ast_hash": "dbe04e05d1cfb02770db8d7c0bcc0b68",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/lua_env.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1786805041.5686455,
|
||||
"ast_hash": "97d009846e18d3c809663b1185c98bbb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-module-host/src/main.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "9a93253ae44c764b8273df40999ddede",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/module_host_ipc.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "fcdb4c03f242a5ea51fd3a096b711363",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"bread-shared/src/permissions.rs": {
|
||||
"mtime": 1786800467.7210522,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "800445ef9c90bdbf8f3ac9d4f1afd98e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/core/rules.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "bd430cf213f400b8d4e96ccc35a76ff1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/ipc/module_host_bridge.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785882914.3346088,
|
||||
"ast_hash": "caa9cf82695e48c88758fcfa835e1871",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/src/module_host.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785895235.7449324,
|
||||
"ast_hash": "228826ff3c8941ea5f9bb28b66d637a9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"breadd/tests/module_host_sandbox.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1786805041.5686455,
|
||||
"ast_hash": "7e637b3a950c510215a6f6a7b88dd404",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/cpu-temp-widget/init.lua": {
|
||||
"mtime": 1786800467.724451,
|
||||
"mtime": 1785882914.337525,
|
||||
"ast_hash": "5ac893dd2f6af6d8b22dd290e3021f77",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"xtask/src/main.rs": {
|
||||
"mtime": 1786801244.1297076,
|
||||
"mtime": 1785909683.2724528,
|
||||
"ast_hash": "e914dd77ac3241df09e3a681228961db",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/dev-release.yml": {
|
||||
"mtime": 1786800467.7161875,
|
||||
"ast_hash": "707129aa2fe79b4539d108c03e6d7abf",
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "ee3f41732b4ca3f34718b9c4fee68a4c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/rc-release.yml": {
|
||||
"mtime": 1786800467.7167187,
|
||||
"ast_hash": "3007d2c43d785cd72f0548096626a21d",
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "ce93aea449f6698edb5e993a9f658392",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/release.yml": {
|
||||
"mtime": 1786800467.7167187,
|
||||
"ast_hash": "3578aa39e7b2466822c8d85247489d36",
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "aa3e2461c895d0e8ff0cf0fa5556694d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"DEPRECATIONS.md": {
|
||||
"mtime": 1786800467.716893,
|
||||
"ast_hash": "1685b60fad2ed4184e4119c30866ec12",
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "f3eb8f249d81c7c4faf2a131e890f459",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/README.md": {
|
||||
"mtime": 1786800467.7242541,
|
||||
"ast_hash": "dfa8a72f41c08bd5b8036b684092a93b",
|
||||
"mtime": 1786858478.390548,
|
||||
"ast_hash": "d47ad6c1a9775a44212b89e281aae907",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"packaging/README.md": {
|
||||
"mtime": 1786800994.0430956,
|
||||
"mtime": 1786805047.710909,
|
||||
"ast_hash": "caa295eed64de126874a2e48b8aed8a2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"ci/build.sh": {
|
||||
"mtime": 1786805047.7071788,
|
||||
"ast_hash": "363dbb1a10cf8e098a0451f43ff101cf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"examples/modules/external-monitors.lua": {
|
||||
"mtime": 1786858478.390548,
|
||||
"ast_hash": "ba0f44a4d84889b9828201aff9186466",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
".forgejo/workflows/check.yml": {
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "4ceb400224458b1a43c5ddc44cfbd187",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"AGENTS.md": {
|
||||
"mtime": 1786805047.7009091,
|
||||
"ast_hash": "513e4a05cbbcdcb47b208b781f4d78bb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"CLAUDE.md": {
|
||||
"mtime": 1784778267.6147587,
|
||||
"ast_hash": "589cfefd400c641c059a2f8516ff2037",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue