navori 0.7.4 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/core/core-assets/agents/researcher.md +1 -1
- package/dist/assets/core/core-assets/hooks/_partials/audit-arm.sh +38 -0
- package/dist/assets/core/core-assets/hooks/audit-mode-trigger.sh +14 -0
- package/dist/assets/core/core-assets/hooks/session-start-context.sh +31 -0
- package/dist/assets/core/core-assets/hooks/subagent-stop-handoff.sh +35 -9
- package/dist/assets/core/core-assets/managed/arranque-sesion.md +2 -0
- package/dist/assets/core/core-assets/managed/cierre-sesion.md +5 -0
- package/dist/assets/core/core-assets/settings/settings-base.json +1 -0
- package/dist/assets/core/core-assets/skills/structural-search.md +3 -1
- package/dist/index.js +280 -279
- package/package.json +1 -1
|
@@ -37,7 +37,7 @@ hypothetical future abstractions or optional edge cases as BLOCKER.
|
|
|
37
37
|
1. `CLAUDE.md` carries the repo's context — it is already in your context when your host injects it; read it from disk ONLY if your host did not inject it.
|
|
38
38
|
2. Work on ONE scoped question (the orchestrator already handed you the scope). If you discover it's actually >2 independent questions, return them as a list so the orchestrator distributes them across parallel researchers — don't chain them in series yourself.
|
|
39
39
|
3. Run the search:
|
|
40
|
-
- Primary method: the native `Grep` (content) and `Glob` (files by name/pattern) tools. They're read-only, fast (ripgrep), and don't ask for permission.
|
|
40
|
+
- Primary method: the native `Grep` (content) and `Glob` (files by name/pattern) tools. They're read-only, fast (ripgrep), and don't ask for permission. In auto mode the shell additionally pays a classifier round-trip per command — measured, a native search answers in ~0.08s against ~0.20s (p75 1.83s) for the same search through the shell — so the native lane is cheaper in every mode and much cheaper there.
|
|
41
41
|
- Fallback only for what the tools don't cover (git history with `git grep`, FS metadata with `find`): shell commands. Chained with pipes/redirects they ask for confirmation, so reserve the shell for when `Grep`/`Glob` fall short.
|
|
42
42
|
- For semantic questions (not just string match), apply `.claude/skills/structural-search/SKILL.md`: locate the right region and open only the confirmed span; don't read whole files by reflex.
|
|
43
43
|
4. Validate each finding: open the file, confirm the match means what it seems (sometimes a `grep` matches comments or strings unrelated to the concept).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Shared armed-audit consumption (#597, #599) — inlined into each consuming hook
|
|
2
|
+
# at render time (see lib/hook-includes.ts). Single source of truth for the flag
|
|
3
|
+
# protocol so the two consumers cannot drift apart:
|
|
4
|
+
#
|
|
5
|
+
# · SessionStart — arm BEFORE opening the session (original #597 flow).
|
|
6
|
+
# · UserPromptSubmit — arm the RUNNING session: `navori audit --arm` (from
|
|
7
|
+
# another terminal, or in-session via `! navori audit --arm`) and the NEXT
|
|
8
|
+
# message activates recording (#599). No restart, no lost context.
|
|
9
|
+
#
|
|
10
|
+
# The flag is `<audits-root>/<repo>/.armed`, written by `navori audit --arm`.
|
|
11
|
+
# Consumption comes FIRST: the flag arms exactly ONE session. If `--start` then
|
|
12
|
+
# fails, the arm is lost rather than latched — a flag that survives a failure
|
|
13
|
+
# would fire on some later unrelated session, which is worse than asking the
|
|
14
|
+
# user to arm again.
|
|
15
|
+
#
|
|
16
|
+
# CALLER CONTRACT: $1 is a session id ALREADY validated against the shared
|
|
17
|
+
# charset (#503) — this function trusts it into a command line, so an unvalidated
|
|
18
|
+
# id must never reach here. $2 is the payload's cwd (#454: never
|
|
19
|
+
# CLAUDE_PROJECT_DIR — they differ in worktrees, and --arm wrote the flag under
|
|
20
|
+
# the name basename(cwd) resolves to). $3 is the audits root.
|
|
21
|
+
#
|
|
22
|
+
# Fail-open and silent: returns 0 ONLY when audit-mode was actually started, so
|
|
23
|
+
# the caller can announce it; every other path returns 1 and changes nothing.
|
|
24
|
+
# Safe under `set -euo pipefail` and `set +e` alike.
|
|
25
|
+
navori_audit_consume_armed() {
|
|
26
|
+
narm_sid=$1
|
|
27
|
+
narm_cwd=$2
|
|
28
|
+
narm_root=$3
|
|
29
|
+
[ -n "$narm_sid" ] && [ -n "$narm_cwd" ] && [ -n "$narm_root" ] || return 1
|
|
30
|
+
narm_repo=$(basename "$narm_cwd" 2>/dev/null) || return 1
|
|
31
|
+
[ -n "$narm_repo" ] || return 1
|
|
32
|
+
narm_file=$narm_root/$narm_repo/.armed
|
|
33
|
+
[ -f "$narm_file" ] || return 1
|
|
34
|
+
command -v navori >/dev/null 2>&1 || return 1
|
|
35
|
+
rm -f "$narm_file" 2>/dev/null || true
|
|
36
|
+
navori audit --start "$narm_sid" --cwd "$narm_cwd" >/dev/null 2>&1 || return 1
|
|
37
|
+
return 0
|
|
38
|
+
}
|
|
@@ -61,6 +61,20 @@ else
|
|
|
61
61
|
fi
|
|
62
62
|
log_file=$audits_root/$repo/session-$session_id.log
|
|
63
63
|
|
|
64
|
+
# ─── Armed audit-mode for the RUNNING session (#599) ─────────────────────────
|
|
65
|
+
# `navori audit --arm` (another terminal, or `! navori audit --arm` in-session)
|
|
66
|
+
# → the NEXT prompt lands here, consumes the flag and starts recording. This is
|
|
67
|
+
# the UX the SessionStart-only flow lacked: no closing and reopening a session
|
|
68
|
+
# that is already warm. Costs one stat per prompt when not armed. The stdout
|
|
69
|
+
# line is deliberate — a UserPromptSubmit hook's stdout is injected as context,
|
|
70
|
+
# so the model learns it is being recorded the moment it starts to be.
|
|
71
|
+
# Mid-session coverage is already modeled by the report (recorder horizon), so a
|
|
72
|
+
# log that starts at prompt N is a smaller log, never a broken one.
|
|
73
|
+
# navori:include audit-arm
|
|
74
|
+
if navori_audit_consume_armed "$session_id" "$cwd" "$audits_root"; then
|
|
75
|
+
printf 'navori: audit-mode ACTIVE from this message on (armed via navori audit --arm; the hook ran --start %s).\n' "$session_id"
|
|
76
|
+
fi
|
|
77
|
+
|
|
64
78
|
# Not marked → not recording. This is also what makes the hook free outside
|
|
65
79
|
# audit-mode: one stat and out.
|
|
66
80
|
[ -f "$log_file" ] || exit 0
|
|
@@ -58,6 +58,37 @@ trap navori_audit_on_exit EXIT
|
|
|
58
58
|
ctx=""
|
|
59
59
|
add() { ctx="${ctx}${1}"$'\n'; }
|
|
60
60
|
|
|
61
|
+
# ─── Armed audit-mode (#597/#599): consume the flag `navori audit --arm` left.
|
|
62
|
+
# The consumption protocol lives in the shared partial (also inlined into the
|
|
63
|
+
# UserPromptSubmit recorder, which covers the RUNNING session); this hook covers
|
|
64
|
+
# "armed before the session opened".
|
|
65
|
+
# navori:include audit-arm
|
|
66
|
+
_armed_root=${NAVORI_AUDITS_ROOT:-${HOME:-}/.navori/audits}
|
|
67
|
+
# The authoritative repo comes from the payload's `cwd`, same as the recorder
|
|
68
|
+
# partial (#454): the hook process can start somewhere other than the session's
|
|
69
|
+
# repo, and `--arm` wrote the flag under the name `basename(cwd)` resolves to.
|
|
70
|
+
_armed_cwd=""
|
|
71
|
+
if command -v jq >/dev/null 2>&1; then
|
|
72
|
+
_armed_cwd=$(printf '%s' "$payload" | jq -r '.cwd // ""' 2>/dev/null || true)
|
|
73
|
+
fi
|
|
74
|
+
[ -n "$_armed_cwd" ] || _armed_cwd=${CLAUDE_PROJECT_DIR:-$PWD}
|
|
75
|
+
_armed_sid=""
|
|
76
|
+
if command -v jq >/dev/null 2>&1; then
|
|
77
|
+
_armed_sid=$(printf '%s' "$payload" | jq -r '.session_id // ""' 2>/dev/null || true)
|
|
78
|
+
fi
|
|
79
|
+
# Same charset guard the CLI and the recorder apply (#503): a path-shaped id
|
|
80
|
+
# means the payload is not what we think it is — do nothing rather than guess.
|
|
81
|
+
case "$_armed_sid" in
|
|
82
|
+
"" | *[!A-Za-z0-9_-]*) : ;;
|
|
83
|
+
*)
|
|
84
|
+
if navori_audit_consume_armed "$_armed_sid" "$_armed_cwd" "$_armed_root"; then
|
|
85
|
+
# Tell the MODEL, not just the log: the session should know it is being
|
|
86
|
+
# recorded, and the user should see the activation in the first turn.
|
|
87
|
+
add "navori: audit-mode ACTIVE for this session (armed via 'navori audit --arm'; the hook ran --start ${_armed_sid})."
|
|
88
|
+
fi
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
|
|
61
92
|
# UNTRUSTED-DATA FENCE (#511). Two of the three things this hook injects are
|
|
62
93
|
# repository CONTENT, not harness instruction: commit subjects and the body of
|
|
63
94
|
# `progress/current.md`. Anyone who can push can write either, and both land at
|
|
@@ -115,28 +115,54 @@ is_blank() { ! grep -q '[^[:space:]]' "$1" 2>/dev/null; }
|
|
|
115
115
|
problems=""
|
|
116
116
|
note() { problems="${problems}${problems:+; }$1"; }
|
|
117
117
|
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
|
|
118
|
+
# Only handoffs touched inside this window are checked (48h in minutes).
|
|
119
|
+
#
|
|
120
|
+
# The hook fires on SubagentStop, so the handoff it exists to police is the one
|
|
121
|
+
# just written. It used to check the WHOLE directory, which nothing prunes, and
|
|
122
|
+
# that broke it three ways on every repo measured (#606):
|
|
123
|
+
#
|
|
124
|
+
# 1. Handoffs written under an older format failed forever — 44 files in one
|
|
125
|
+
# repo, 19 in another. The `clean` verdict this script calls "the whole
|
|
126
|
+
# value of recording this hook" was unreachable in all four.
|
|
127
|
+
# 2. The stamp compares the full problem string, so a genuinely broken new
|
|
128
|
+
# handoff injected N+1 paths (44 of them from August in one repo) and
|
|
129
|
+
# fixing it re-injected the N old ones. The real warning arrived buried.
|
|
130
|
+
# 3. Two greps per file, unbounded: the median run tracked the file count
|
|
131
|
+
# almost linearly — 46 files/165ms, 57/197ms, 80/333ms, 138/419ms — making
|
|
132
|
+
# this the most expensive hook of the six, the other five sitting at
|
|
133
|
+
# 16-59ms.
|
|
134
|
+
#
|
|
135
|
+
# 48h and not less because a session can be long (10h41m measured) and a handoff
|
|
136
|
+
# written early in one must still be checked when it ends. Everything older is
|
|
137
|
+
# closed work: PRs in the repo this was measured on merge in under 10 hours,
|
|
138
|
+
# p90 8.5h.
|
|
139
|
+
HANDOFF_WINDOW_MIN=2880
|
|
140
|
+
|
|
141
|
+
# `find` replaces the globs rather than filtering inside them: it does the
|
|
142
|
+
# selection in ONE fork per directory instead of two greps per stale file, which
|
|
143
|
+
# is the cost above. Read through `while read` (not `$(...)` word-splitting) so
|
|
144
|
+
# a path with spaces survives, and via process substitution so `note` writes to
|
|
145
|
+
# the real `problems` and not to a subshell's copy.
|
|
146
|
+
#
|
|
123
147
|
# Reports are named by their PATH, not their basename: with more than one
|
|
124
148
|
# progress dir in play, `impl_x.md` alone wouldn't say which one to open.
|
|
125
149
|
for dir in "${dirs[@]}"; do
|
|
126
|
-
|
|
150
|
+
while IFS= read -r f; do
|
|
151
|
+
[ -n "$f" ] || continue
|
|
127
152
|
if is_blank "$f"; then
|
|
128
153
|
note "$f vacío"
|
|
129
154
|
elif ! grep -qiE '^\*{0,2}status:?\*{0,2}' "$f" 2>/dev/null; then
|
|
130
155
|
note "$f sin línea 'Status:'"
|
|
131
156
|
fi
|
|
132
|
-
done
|
|
133
|
-
|
|
157
|
+
done < <(find "$dir" -maxdepth 1 -name 'impl_*.md' -mmin -"$HANDOFF_WINDOW_MIN" 2>/dev/null)
|
|
158
|
+
while IFS= read -r f; do
|
|
159
|
+
[ -n "$f" ] || continue
|
|
134
160
|
if is_blank "$f"; then
|
|
135
161
|
note "$f vacío"
|
|
136
162
|
elif ! grep -qE 'APPROVED|CHANGES_REQUESTED' "$f" 2>/dev/null; then
|
|
137
163
|
note "$f sin veredicto (APPROVED/CHANGES_REQUESTED)"
|
|
138
164
|
fi
|
|
139
|
-
done
|
|
165
|
+
done < <(find "$dir" -maxdepth 1 -name 'review_*.md' -mmin -"$HANDOFF_WINDOW_MIN" 2>/dev/null)
|
|
140
166
|
done
|
|
141
167
|
|
|
142
168
|
# `clean` vs `dirty` is the whole value of recording this hook: it is the only
|
|
@@ -4,3 +4,5 @@ On Claude, a `SessionStart` hook injects the live context — branch, recent com
|
|
|
4
4
|
|
|
5
5
|
1. **Healthy config**: run `navori doctor` if `navori.config.json` / `.claude/` look inconsistent, or to confirm the declared quality gates can actually run.
|
|
6
6
|
2. **Scoped task**: one **user** task at a time; decompose and parallelize per your orchestrator role.
|
|
7
|
+
|
|
8
|
+
**Audit mode on request**: if the user asks for it in any wording ("audit mode", "con auditoría", "navori audit"), run `navori audit --start <this session's id>` as the FIRST action of that turn — before loading skills or starting any pipeline — and confirm the log path it prints. The phrase never activates anything by itself (by design); the command is the only switch. If the injected context already says audit-mode is ACTIVE (armed via `navori audit --arm` — which also applies to a RUNNING session on its next message), it is running — do not start it again, and never tell the user to close and reopen the session for this.
|
|
@@ -7,5 +7,10 @@ Before closing the session:
|
|
|
7
7
|
3. **Clear current**: leave `progress/current.md` at `idle` or with the explicit next step.
|
|
8
8
|
4. **No temporaries**: delete scratch files; don't leave `console.log`, `debugger`, or commented-out code.
|
|
9
9
|
5. **Conventional commit**: `feat|fix|chore|docs(scope): message`, atomic, in the language defined by the config's `commits`.
|
|
10
|
+
6. **Park on base**: once the cycle's work is committed and its branch pushed (PR opened when the flow calls for one), leave the repo standing on the base branch, synced: `git switch {{branchBase}}` then `git pull --ff-only`. The point is where the NEXT session starts from — a repo parked on last week's feature branch breeds branches cut from stale bases. Rules that make it safe:
|
|
11
|
+
- **Never delete the feature branch.** This is position hygiene, not history hygiene; the branch stays for its pending merge and for `babysit-prs`.
|
|
12
|
+
- Only with a **clean working tree** and the cycle's commits pushed. Anything unpushed or uncommitted → do NOT switch; say what was left and leave parking to the user.
|
|
13
|
+
- `--ff-only`, always: the base must never receive a surprise merge from a parking step. If it doesn't fast-forward, report it instead of resolving it here.
|
|
14
|
+
- If another session may be alive on this same working tree (a second terminal on this repo), switching yanks the branch out from under it — when in doubt, skip and say so.
|
|
10
15
|
|
|
11
16
|
**R1 lean close** — the three conditions are verifiable, so this is not a judgment call: the session ran the **R1** route, it covered **one** user task, and its diff touches no critical area (`{{project.criticalAreas}}`). All three hold → skip step 2 when nothing was committed, and whatever ceremony another block exempts under this same name. It never exempts the quality gate, nor the `history.md` entry whenever there WAS a commit: a change that shipped leaves a trace, however trivial.
|
|
@@ -20,8 +20,10 @@ Confirm every pointer with a cheap search. If the code contradicts memory, corre
|
|
|
20
20
|
|
|
21
21
|
Use it when you know a literal token: name, import, config key, error string.
|
|
22
22
|
|
|
23
|
+
Native `Grep` first — it IS ripgrep, pre-approved, ~0.08s vs ~0.20s (p75 1.83s) by shell, which in auto mode also pays a classifier round-trip. Shell `rg` is the fallback (git history, context flags), not the default.
|
|
24
|
+
|
|
23
25
|
1. Start narrow: file, directory or type obtained in Rung 0.
|
|
24
|
-
2. Ask first for files (`rg -l`) or `file:line` with at most two lines of context.
|
|
26
|
+
2. Ask first for files (`Grep` files mode; `rg -l` via shell) or `file:line` with at most two lines of context.
|
|
25
27
|
3. Dedup before reading.
|
|
26
28
|
4. Open only the span that confirms the hit.
|
|
27
29
|
|