Commit Graph

5 Commits

Author SHA1 Message Date
bvandeusen e9cd3435ad test(acl): give search/inject fixtures real owner ids; fail soft on name lookup
CI & Build / Python lint (push) Successful in 3s
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 44s
CI & Build / Build & push image (push) Successful in 1m4s
Run 2892: 3 pre-existing tests broke, 392 passed. Same shape as the last
breakage — a DB-touching call landed in a path unit tests exercise, and their
fixtures had auto-MagicMock user_id attributes that compare as "someone else's",
sending the code off to look up a username.

Fixed the fixtures rather than the assertion: _fake_note in the search tests and
_note in the plugin-context tests now take a real user_id defaulting to the
caller those tests bind. That makes "is this shared?" meaningful in both files
instead of accidental, which is what the new provenance behaviour actually needs
from them.

Separately, and not as cover for the above: owner_names_for now fails soft.
A lookup error yields no names and callers render "another user". The part that
matters — that the record is NOT the caller's — comes from comparing owner ids,
not from this query, so losing an attribution is cosmetic where failing the whole
search would not be.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLwAaV4DQEmVyn496HnEvt
2026-07-25 23:10:12 -04:00
bvandeusen 8126db3203 feat(plugin): knowledge auto-inject (Path A) — title-first per-turn awareness
CI & Build / Python lint (push) Successful in 2s
CI & Build / integration (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 21s
CI & Build / Python tests (push) Successful in 43s
CI & Build / Build & push image (push) Successful in 55s
New UserPromptSubmit hook (scribe_autoinject.sh) + GET /api/plugin/retrieve that
surface the TITLES (never bodies) of the few notes clearing four anti-bloat
gates: a per-user confidence threshold (stricter than pull search), a margin
gate, per-session dedup (exclude_ids), and a top-k ceiling. Each retrieval is
logged to retrieval_logs as source=auto_inject so the threshold can be tuned
from data. Per-user config (enable / threshold / top-k) is DB-backed via
/api/settings with a Settings UI card; defaults enabled, threshold 0.55,
top-k 3 (conservative — tune once auto_inject telemetry accrues).

Scribe: project 2, milestone 93, task 1033.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xz4j1H7pjYSjKsEpgcNH5E
2026-06-22 20:31:07 -04:00
bvandeusen 33f9a0a4d4 feat(plugin): Phase 4 — Scribe Processes auto-surface as local skills
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 52s
CI & Build / Build & push image (push) Successful in 1m3s
#755 Phase 4. Saved Scribe Processes (DRY pass, Drift Audit, …) now surface as
auto-triggered Claude Code skills instead of pull-only get_process calls.

Design correction vs the plan: stubs live in the USER's ~/.claude/skills/, NOT
plugin/skills/_instance/. The plugin is git-cloned and identical per install, so
instance-specific generated files can't ride in it; personal skills are
live-detected within the session (verified via claude-code-guide). MCP prompts
were the alternative but are pull-only (no relevance auto-surface), so skills are
the right primitive.

- backend: GET /api/plugin/processes manifest (services/plugin_context.
  build_process_manifest) — {name, slug, description} per Process; description is
  the auto-surface trigger (title + preview); slugs deduped, blanks skipped.
- plugin: scribe_sync_processes.sh writes ~/.claude/skills/scribe-proc-<slug>/
  SKILL.md (body = "call get_process(name), follow verbatim") and PRUNES stale
  scribe-proc-* stubs. Fail-open + silent; a transient fetch failure never wipes
  existing stubs. Runs as a 2nd SessionStart hook + via the /scribe:sync command.
- plugin.json 0.1.7 → 0.1.8; README updated.
- tests: build_process_manifest (render, slug dedupe, blank-title skip, preview
  truncation). Sync script's write+prune validated in isolation (plugin/** is not
  CI-covered): correct stubs created, stale pruned, unrelated skills untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 13:00:32 -04:00
bvandeusen 8fe571e175 feat(plugin): resolve session project from git remote, not a pinned project_id
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 51s
CI & Build / Build & push image (push) Successful in 1m0s
The SessionStart hook asked for a project_id via plugin userConfig, which pins
one install to a single project — wrong for an operator working across many
repos/projects. Resolve the active project server-side from the working repo's
git remote instead (a stable identifier, not a dir-name guess).

- repo_bindings table (migration 0064) + RepoBinding model: (user, repo_key) ->
  project, FKs CASCADE.
- services/repo_bindings: normalize_repo_key collapses ssh/https/scp/creds/port/
  .git to host/owner/repo; resolve/set/list/delete.
- GET /api/plugin/context takes ?repo=<remote>; unbound repo -> a "bind this
  repo" hint with a ready bind_repo() call. project_id kept as manual override.
- MCP tools: bind_repo / list_repo_bindings / unbind_repo.
- Hook sends ?repo=$(git remote get-url origin) URL-encoded; all project_id
  handling removed. plugin.json drops the project_id userConfig (0.1.2 -> 0.1.3).
- Tests: normalize equivalence classes + unbound-hint rendering.

Refs task 755 (Scribe-as-plugin push channel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 01:33:58 -04:00
bvandeusen 3ab16fcbdb feat(plugin): add /api/plugin/context push-channel endpoint + dogfood hook
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 1m6s
Phase 1 of plan #755 (Scribe-as-plugin). Gives Scribe its own session-start
push channel so always-on rules + active-project context surface without being
asked — the gap behind 'I have to prompt for everything'.

- services/plugin_context.build_session_context: renders always-on rule titles
  grouped by topic (under the 10k additionalContext cap; full text stays one
  list_always_on_rules/get_rule call away) + optional project goal/open-task
  count + a recall/update-over-create reflex line. Capped at 9000 chars.
- routes/plugin GET /api/plugin/context (login_required already accepts Bearer
  fmcp_ keys; read scope suffices).
- tests: titles-not-statements, project scoping, length cap (pure mocks).
- scripts/scribe_session_context.sh: dogfood SessionStart hook, fail-open,
  reads url+token from .mcp.json. Superseded in Phase 2 by the plugin-bundled
  hook using userConfig.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 22:43:08 -04:00