@tznthou/ccrecall 0.7.2 → 0.8.0
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/README.md +31 -16
- package/README_ZH.md +29 -16
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +25 -10
- package/dist/api/routes.js.map +1 -1
- package/dist/core/database.d.ts +52 -0
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +173 -23
- package/dist/core/database.js.map +1 -1
- package/dist/core/integrity-monitor.d.ts.map +1 -1
- package/dist/core/integrity-monitor.js +7 -3
- package/dist/core/integrity-monitor.js.map +1 -1
- package/dist/core/recall-telemetry.d.ts.map +1 -1
- package/dist/core/recall-telemetry.js +9 -3
- package/dist/core/recall-telemetry.js.map +1 -1
- package/dist/core/secure-dir.d.ts +7 -0
- package/dist/core/secure-dir.d.ts.map +1 -0
- package/dist/core/secure-dir.js +64 -0
- package/dist/core/secure-dir.js.map +1 -0
- package/dist/core/token-budget.d.ts +59 -3
- package/dist/core/token-budget.d.ts.map +1 -1
- package/dist/core/token-budget.js +115 -11
- package/dist/core/token-budget.js.map +1 -1
- package/dist/mcp/tools.d.ts +2 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +51 -3
- package/dist/mcp/tools.js.map +1 -1
- package/hooks/lib/secure-dir.mjs +52 -0
- package/hooks/session-start.mjs +20 -3
- package/package.json +3 -2
- package/scripts/extraction-prompt.md +52 -1
- package/scripts/l3-prescription-position.py +835 -0
- package/scripts/post-session-extract.sh +36 -4
|
@@ -168,7 +168,14 @@ ccrecall-extract() {
|
|
|
168
168
|
if [[ -f "$prompt_file" ]]; then
|
|
169
169
|
prompt=$(cat "$prompt_file")
|
|
170
170
|
else
|
|
171
|
-
|
|
171
|
+
# Keep the "lead with the prescription" rule in sync with
|
|
172
|
+
# extraction-prompt.md — only the first 149 chars of a memory survive
|
|
173
|
+
# injection, so a memory that opens with narrative arrives unactionable.
|
|
174
|
+
# tests/extraction-prompt-prescription.test.ts pins the rule AND the number
|
|
175
|
+
# below against token-budget.ts, in both copies. 🔴 Until 2026-09-08 this
|
|
176
|
+
# comment already said that while no test read this line's number at all:
|
|
177
|
+
# it could say 999 and stay green. Verified by mutation, both directions.
|
|
178
|
+
prompt="You are a memory extraction agent. Save 0-5 lasting insights via recall_save. Each memory must be self-contained with a key slug for dedup. Only the first 149 characters survive injection into a future session, so lead with what a future reader should DO and put the evidence, file names and war story after it. Set projectId to \"${project_id}\" for project-specific knowledge; omit for cross-project knowledge. Always pass origin=\"agent-inferred\": you are reading a finished transcript with nobody watching, and that flag is what stops your save from overwriting a memory the user wrote by hand under the same key. Pass messageId: the uuid in the \"--- human [<uuid>] ---\" header of the one message a memory came from, copied verbatim — omit it when no single message is the source, and never guess a uuid."
|
|
172
179
|
fi
|
|
173
180
|
|
|
174
181
|
# Append runtime context (projectId) to the prompt
|
|
@@ -196,21 +203,46 @@ ccrecall-extract() {
|
|
|
196
203
|
local session_transcript
|
|
197
204
|
# A2: -R + fromjson? skips malformed JSONL lines instead of aborting
|
|
198
205
|
# A1+A5: head -c 200000 + iconv -c strips incomplete UTF-8 at boundary
|
|
206
|
+
#
|
|
207
|
+
# Q1 (2026-09-11): each header carries the message uuid, so a memory can
|
|
208
|
+
# name the message it came from (`memories.message_id`, 0/1639 filled
|
|
209
|
+
# before this). The transcript was the blocker, not the schema: the
|
|
210
|
+
# column and the recall_save parameter both already existed, and the
|
|
211
|
+
# model had nothing to point at.
|
|
212
|
+
#
|
|
213
|
+
# Costs ~40 bytes per message against the 200KB cap. Measured on a real
|
|
214
|
+
# 151-message session: 119,507 -> 125,396 bytes, +4.93%. (The share is
|
|
215
|
+
# higher on an English-heavy session — that one is mostly CJK, where the
|
|
216
|
+
# body text costs 3 bytes a character and dilutes the ASCII uuids. head
|
|
217
|
+
# -c counts bytes, not characters.) A session already at the cap loses
|
|
218
|
+
# that much off its tail, which is a real cost, accepted because the tail
|
|
219
|
+
# is what the model has most recently read in full, while provenance is
|
|
220
|
+
# unrecoverable after the fact — 65.6% of stored memories have already
|
|
221
|
+
# been rewritten by compression.
|
|
222
|
+
#
|
|
223
|
+
# gsub keeps the header structurally intact: the transcript is untrusted
|
|
224
|
+
# data, and a uuid holding `] ---` would otherwise let a crafted JSONL
|
|
225
|
+
# forge message boundaries. Restricting the characters rather than
|
|
226
|
+
# matching a uuid shape is deliberate — a format gate would stop printing
|
|
227
|
+
# citations the day Claude Code changes its id format, silently. A value
|
|
228
|
+
# mangled by gsub simply fails verification on the write side.
|
|
199
229
|
session_transcript=$(jq -R -r '
|
|
200
230
|
fromjson? // empty |
|
|
231
|
+
(((.uuid | strings) // "") | gsub("[^A-Za-z0-9-]"; "")) as $u |
|
|
232
|
+
(if $u == "" then "" else " [" + $u + "]" end) as $cite |
|
|
201
233
|
if .type == "user" and .message then
|
|
202
234
|
.message.content |
|
|
203
235
|
if type == "array" then
|
|
204
236
|
[.[] | select(.type == "text") | .text // empty] | join("\n") |
|
|
205
|
-
if . != "" then "--- human ---\n" + . else empty end
|
|
237
|
+
if . != "" then "--- human" + $cite + " ---\n" + . else empty end
|
|
206
238
|
elif type == "string" then
|
|
207
|
-
if . != "" then "--- human ---\n" + . else empty end
|
|
239
|
+
if . != "" then "--- human" + $cite + " ---\n" + . else empty end
|
|
208
240
|
else empty end
|
|
209
241
|
elif .type == "assistant" and .message then
|
|
210
242
|
.message.content |
|
|
211
243
|
if type == "array" then
|
|
212
244
|
[.[] | select(.type == "text") | .text // empty] | join("\n") |
|
|
213
|
-
if . != "" then "--- assistant ---\n" + . else empty end
|
|
245
|
+
if . != "" then "--- assistant" + $cite + " ---\n" + . else empty end
|
|
214
246
|
else empty end
|
|
215
247
|
else empty end
|
|
216
248
|
' "$jsonl_path" 2>/dev/null | head -c 200000 | iconv -c -f utf-8 -t utf-8)
|