Commit Graph

35 Commits

Author SHA1 Message Date
ar9av 275ecc8095 fix(packaging): bundle scripts/ in the wheel (#152)
The daily-update skill's Setup Mode references scripts/daily-update.sh,
the launchd plist, and wiki-notify.sh via $OBSIDIAN_WIKI_REPO/scripts/ —
same class of gap as #143 (the Stop hook), which didn't cover this
directory. force-include scripts/ under obsidian_wiki/_data/scripts/ so
pip/uv installs actually have it, and exclude __pycache__/*.pyc from the
wheel target since force-include copies straight from the working tree
(a local scripts/__pycache__ was otherwise leaking stray .pyc files in).
2026-07-25 22:00:29 -07:00
Arnav ea4508114e feat(sync): share one GitHub-sync implementation across setup.sh and the CLI (#153) (#154)
setup.sh had an interactive git-sync flow (git init, .gitignore, remote,
a generated sync.sh, optional cron) that `obsidian-wiki setup` — the entry
point pip/uv installs actually run — never had, so those installs silently
skipped it and .env.example documented a var nothing ever read.

Move the git plumbing into obsidian_wiki/sync.py (configure_sync/run_sync/
get_remote) and expose it as `obsidian-wiki sync-setup <url>` and
`obsidian-wiki sync`. `obsidian-wiki setup` now offers the same interactive
prompt setup.sh always had (or accepts --remote non-interactively), and
setup.sh's own prompt delegates into the same module via the CLI instead of
re-implementing it. Sync status is read live from the vault's own `git
remote` (via `obsidian-wiki info`) rather than a config var that could drift.
2026-07-25 21:52:11 -07:00
Arnav 073a04cd37 feat(batch): make source discovery git-aware for repo ingestion (#148) (#150)
wiki-ingest previously walked repo folders with a hardcoded SKIP_DIRS
list, so custom-ignored paths (anything not literally node_modules/
.venv/dist/...) leaked into the ingest plan. batch-plan now detects a
`.git` folder and enumerates files via `git ls-files`, so a repo's own
.gitignore decides what's skipped. Docs updated to spell out the
"clone locally, add to OBSIDIAN_SOURCES_DIR" workflow for public/private
repos on any host.
2026-07-24 18:08:51 -07:00
Arnav 2363445eac fix(lint): stage trust-ledger enforcement behind strict_trust (#146) (#147)
Legacy vaults fail-closed on every pre-existing page after the trust-ledger
rollout: missing base_confidence/lifecycle and a missing ledger became
mandatory failures with no opt-out, skipping the staged migration from #28.

Split confidence/lifecycle out of the core required-frontmatter check into a
separate confidence_missing_fields finding, and add a strict_trust switch to
lint_vault (default off): missing trust fields, ledger errors, stale reviews,
and score mismatches now warn by default and only fail once a vault owner
opts in via --strict-trust or OBSIDIAN_TRUST_STRICT=1. Ledger presence alone
no longer silently enables strict mode.
2026-07-23 11:43:07 -07:00
Arnav 035dad5199 Merge pull request #145 from Ar9av/fix/cache-manifest-shapes-134
fix: make cache-check/cache-update work with the manifest shape the skills write (#134)
2026-07-18 10:11:16 -07:00
ar9av 5016cde0a5 fix(cache): support list-shaped manifests and prefixed hashes (#134)
cache-check / cache-update assumed a dict-keyed manifest with bare hex
hashes, but the wiki-ingest skill writes 'sources' as a list of entry
objects with sha256:-prefixed content_hash and vault-relative paths.
Against a skill-built manifest the commands crashed, then (once past the
crash) reported every file as modified/new. Both shapes occur in real
vaults.

- _load/_iter: read both dict- and list-shaped 'sources' transparently
- compare content_hash prefix-insensitively (strip optional algo: prefix)
- match paths across raw / absolute / vault-relative forms
- update_source edits in place, preserving manifest shape, duplicate-path
  entries, skill-written fields, and top-level keys (stats/version)
- don't flag URL / pseudo-path source keys as missing-on-disk
- add regression tests covering all four failure modes from the issue
2026-07-18 09:55:31 -07:00
ar9av 14bdb41096 fix(packaging): bundle wiki-stop-capture.sh in the wheel (#143)
The wiki-setup skill wires a Claude Code Stop hook pointing at
<REPO_PATH>/.claude/hooks/wiki-stop-capture.sh, but /.claude is pruned
from the sdist, so the script was missing from the published wheel and
the installed hook dangled at a nonexistent path.

- force-include the hook into the wheel under _data/hooks/ (and re-add it
  to the sdist, which the wheel is built from)
- wiki-setup now resolves the packaged hooks/ path, falls back to the
  source-checkout .claude/hooks/ path, then to a GitHub raw fetch
- wiki-setup now creates .manifest.json so 'obsidian-wiki doctor' passes
  its required-core-files check (secondary note in the issue)
- add regression tests pinning the packaging config and skill wiring
2026-07-18 09:37:34 -07:00
Arnav e508c528d3 Merge pull request #142 from mike840609/agent/readme-translation-sync
docs: advisory README translation drift check with backfill script
2026-07-18 09:33:34 -07:00
Mike Tsai e8172201fc refactor(ci): make README translation sync advisory, not a merge gate
The readme-sync workflow no longer fails when README.md and
README_TW.md don't change together. Instead, check_readme_sync.py
reports drift: it lists commits that touched README.md after the
last README_TW.md update, plus the pending English diff to translate
and backfill. CI surfaces drift as a warning annotation only.

Claude-Session: https://claude.ai/code/session_01PG9Pz6tcUfgpTHLjq3BT5Q
2026-07-18 10:35:45 +08:00
Mike Tsai dafc90aa4d fix(ci): compare README changes from PR merge base 2026-07-16 01:48:00 +08:00
Mike Tsai d2b89f15c4 docs: require synchronized README translations 2026-07-16 00:53:18 +08:00
Mike Tsai f4b6368f84 test: enforce paired README changes 2026-07-16 00:45:17 +08:00
Arnav 1951480ba6 Merge pull request #138 from mike840609/feat/pre-write-vault-snapshot
feat(skills): snapshot vault before destructive writes
2026-07-14 09:51:56 -07:00
ar9av 95424e4b91 fix(cache): resolve vault-relative manifest keys in cache-check
check_sources only matched a manifest entry by the passed key or its
abspath, and detected missing files with Path(key).exists() against CWD.
When the manifest stored vault-relative keys (e.g. _raw/articles/foo.md),
callers passing an absolute path got 'new' instead of 'unchanged', and
every relative key was reported 'missing' when CWD != vault root — so the
docstring's documented abs-or-rel key support was unusable.

Also try the vault-relative form on lookup, and resolve relative manifest
keys against the vault root when checking existence. Add relative-key
tests to close the CI gap (every prior test used absolute keys).

Fixes #136
2026-07-14 09:15:37 -07:00
Mike Tsai 9113e17065 fix(skills): harden pre-write vault snapshots 2026-07-15 00:06:31 +08:00
Arnav 50a8edfb60 Merge pull request #133 from mike840609/feature/wiki-narrate
feat: add wiki-narrate skill
2026-07-12 12:51:38 -07:00
Singgih Lukman Anggana e21b4781bb fix(trust): close metadata and relationship gaps
Validate updated timestamps before fingerprint comparison, support dash-only relationship list items, and reject ambiguous normalized qualified targets and unsupported relationship fields.
2026-07-12 19:20:16 +07:00
Singgih Lukman Anggana e5cd869fdb fix(trust): harden ledger validation
Reject symlinked writes and malformed or ambiguous trust data, enforce complete page coverage and strict timestamps/lifecycle values, and parse typed relationships independent of key order.
2026-07-12 19:06:44 +07:00
Singgih Lukman Anggana 6242472b8f fix(lint): add approved confidence trust ledger
Replace source-string confidence guesses with a manually approved, fingerprinted review ledger. Add exact relationship validation, fail-closed CLI checks, partial review recording, and regression coverage.
2026-07-12 18:24:38 +07:00
Mike Tsai 0158052289 test: enforce closed wiki narrate voices 2026-07-12 14:08:18 +08:00
Mike Tsai b539ede21e test: define wiki narrate contract 2026-07-12 14:08:18 +08:00
Yician Wang 69ff8cc36a fix(extract): check missing output before the --since gate
The staleness order still let --since suppress a missing output: a source
older than the cutoff with no output file was skipped, leaving the very bug
this branch fixes (never-extracted older sessions) partly alive and
contradicting needs_extraction's own docstring.

Move the "output missing -> extract" check ahead of the --since gate, so a
missing output is always (re)extracted and --since only narrows files that
already have an output. Add a regression test: missing output + future
--since still extracts.

AI-Agent: Claude Code
AI-Session-IDs: session_01PPCNXmXUvemmyvWxrJ3D5E
2026-07-03 22:48:16 +08:00
Yician Wang 754d917467 fix(manifest): stop normalize from corrupting relative source keys
cmd_normalize warned on relative keys but still ran them through
canonical() (os.path.abspath), which resolves them against the CWD and
rewrote e.g. "-Users-x-github/abc.jsonl" to "/cwd/-Users-x-github/abc.jsonl",
counted it as re-keyed, and persisted the corruption on a non-dry-run write.

Preserve relative keys untouched (ckey = key), skip the re-key count for
them, and only canonicalize absolute keys. normalize's dedup/canonicalize
purpose applies to absolute keys only; for relative keys it is now a safe
no-op. Collision merge logic is unchanged.

AI-Agent: Claude Code
AI-Session-IDs: session_01PPCNXmXUvemmyvWxrJ3D5E
2026-07-03 22:48:16 +08:00
Yician Wang 84cff259b2 fix(extract): key incremental staleness on output file, not manifest wallclock
extract-jsonl.py decided re-extraction from the .extract-manifest.json
extracted_at wallclock. A session whose output was missing or that landed
after the first run was treated as already-done and never re-extracted, so
downstream ingest saw it as missing until a manual rerun (e.g. session
2d83ed0d). --since additionally acted as a hard gate that hid never-extracted
older sessions.

Make needs_extraction idempotent on the output file: (re)extract when the
output is missing or the source is newer than it; --since only narrows the
scan range. The manifest (read by nothing else) is removed. Add
test_extract_staleness.py covering missing/newer/older cases.

AI-Agent: Claude Code
AI-Session-IDs: session_01PPCNXmXUvemmyvWxrJ3D5E
2026-07-03 22:48:16 +08:00
Yician Wang 99eb09f9ce fix(manifest): match relative source keys in delta scan
cmd_delta keyed every manifest source through canonical() (os.path.abspath),
which resolves relative keys (e.g. "-Users-x-github/abc.jsonl" under
~/.claude/projects/) against the CWD. Real vaults store most keys relatively,
so every already-ingested file was misreported as NEW (446 vs 384 known on the
live vault).

Add a basename-indexed suffix fallback: when a scanned absolute path has no
direct canonical match, look it up by basename and confirm the relative key is
a path suffix (O(1) avg, no O(n^2) scan). Absolute keys keep their exact prior
behavior. cmd_normalize is unchanged but now warns on relative keys, which it
would otherwise rewrite to CWD-based garbage.

AI-Agent: Claude Code
AI-Session-IDs: session_01PPCNXmXUvemmyvWxrJ3D5E
2026-07-03 22:48:16 +08:00
ar9av 7036ea812c Add obsidian-wiki query command 2026-07-01 22:15:19 -07:00
ar9av 87eefd8846 Add obsidian-wiki lint command 2026-07-01 22:14:08 -07:00
ar9av 1fae7928a4 Add obsidian-wiki doctor command 2026-07-01 22:11:29 -07:00
ar9av a7fb1d69fe feat(graphrag): graph-index query pre-pass eliminates speculative page reads
Adds obsidian-wiki graph-query <vault> "<question>" — queries the compiled
wikilink index before opening any page bodies, returning ranked candidates,
a should_read shortlist, and multi-hop paths. Replaces the current approach
of opening 5-10 pages speculatively per query.

- New obsidian_wiki/graphrag.py: build_index() (frontmatter + wikilinks,
  in/out degree, tier), rank_candidates() (score = title/tag/summary match
  + degree bonus + tier weight), find_path() (BFS multi-hop, max_depth=4),
  classify_query() (direct/path/gap/list routing), query() top-level entry.
- index_only=true when top candidate has exact title match + non-empty
  summary — skips page reads entirely for lookup queries.
- CLI: graph-query <vault> "<question>" [--top N] [--max-read N] [--pretty]
- wiki-query SKILL.md gets Step 0: run graph-query first; use should_read
  instead of speculative reads; skip to Step 5 when index_only=true.
- 34 new tests: index building, ranking, path finding, query classification,
  integration, and CLI.
2026-06-30 13:52:53 -07:00
ar9av 6069d775d6 feat(batch): parallel subagent batch planning for large-folder ingestion
Adds obsidian-wiki batch-plan <vault> <source-dir> — splits a source
directory into sized batches and emits a dispatch plan the skill uses
to spawn parallel Claude subagents, each handling one batch independently.

- New obsidian_wiki/batch.py: file classification (text/pdf/image/office/
  code/skip), discover_sources() directory walker (respects SKIP_DIRS,
  excludes code by default since ast-extract handles those), _make_batches()
  (byte + file-count limits), plan_batches() top-level entry that integrates
  with the cache module to skip unchanged files before splitting.
- CLI: batch-plan <vault> <source-dir> [--max-mb N] [--max-files N]
        [--no-cache] [--include-code] [--pretty]
- wiki-ingest SKILL.md gets Step 0: run batch-plan for directories >20 files,
  dispatch each batch as a parallel subagent, run cross-linker once all done.
- 30 new tests: classification, discovery, splitting, cache integration, CLI.
2026-06-30 13:49:53 -07:00
ar9av e87ef958b2 feat(graph-analysis): wikilink graph analysis with community detection and god nodes
Adds obsidian-wiki graph-analyse <vault> — computes god nodes, community
clusters, surprising cross-community connections, dead-ends, and isolated
pages from the vault's wikilink graph. No LLM, no API calls.

- New obsidian_wiki/graph_analysis.py: parse_vault_graph() (wikilink + tag
  extraction), god_nodes() (degree ranking), detect_communities_greedy()
  (label-propagation, pure Python, O(n·k)), detect_communities() (tries
  leidenalg+igraph first, falls back to greedy), surprising_connections()
  (cross-community edges ranked by inverse sqrt of cross-degree product),
  analyse_vault() top-level entry returning JSON-ready dict.
- CLI: graph-analyse <vault> [--top N] [--pretty]
- Optional obsidian-wiki[graph] extra for Leiden (leidenalg + igraph).
- wiki-status SKILL.md insights mode updated: now calls graph-analyse first
  instead of building the wikilink graph manually, with fallback instructions.
- 27 new tests covering parsing, metrics, community detection, surprising
  connections, full integration, and CLI.
2026-06-30 13:47:16 -07:00
ar9av b470eedf3e feat(cache): content-hash cache for reliable incremental ingestion
Replaces the manual sha256sum shell dance with a dedicated Python module
and three CLI subcommands. Pure stdlib — no new runtime dependencies.

- New obsidian_wiki/cache.py: sha256_file/sha256_dir (chunked, memory-safe),
  check_sources() classifies a list of paths as new/modified/unchanged/missing
  vs .manifest.json; update_source() records hash + pages_produced + timestamp
  after a successful ingest.
- CLI: cache-check <vault> <sources...> → JSON classification
       cache-update <vault> <source> [--pages ...] → write hash to manifest
       cache-hash <path> → just compute and return SHA-256
- wiki-ingest SKILL.md updated: append-mode section now uses cache-check /
  cache-update instead of platform-specific sha256sum invocations. Falls back
  to the old manual approach if obsidian-wiki is not installed.
- 25 new tests covering hash stability, mtime-independence, manifest round-trips,
  and all three CLI commands.
2026-06-30 13:42:54 -07:00
ar9av 7535910719 feat(ast-extractor): local code structure extraction with no LLM calls
Adds `obsidian-wiki ast-extract <path>` — a free, local pass that extracts
classes, functions, imports, and inheritance edges from code files using
deterministic regex patterns before any token is spent on the LLM.

- New `obsidian_wiki/ast_extractor.py`: Graph/Node/Edge datamodel + per-language
  LangSpec patterns for Python, JS/TS, Go, Rust, Java, Kotlin, Ruby, C/C++,
  Swift, Shell (12 languages). Outputs god_nodes (top hubs by degree), stats,
  and a node-link JSON dict compatible with any graph tool.
- New `ast-extract` CLI subcommand with `--pretty` flag.
- Optional `obsidian-wiki[ast]` extra for tree-sitter upgrade path.
- wiki-ingest SKILL.md gets Step 1c: run ast-extract first on code sources,
  seed entity pages from class nodes, skip sending code files to the LLM.
- 19 new tests covering file extraction, directory merge, CLI output, edge cases.
2026-06-30 13:27:30 -07:00
Arnav d6dee95ede Add inline vault targeting docs
Document @name named-vault routing across shared skills, bootstrap docs, and README; add regression tests for config-resolution consistency.
2026-06-29 16:24:47 -07:00
Arnav c4d27ecdc7 Fix OKF folder-note link roundtrip (#110) 2026-06-16 15:38:26 +05:30