@cerefox/memory 1.15.2 → 1.16.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/AGENT_GUIDE.md +1 -1
- package/AGENT_QUICK_REFERENCE.md +1 -1
- package/dist/bin/cerefox.js +236 -129
- package/dist/frontend/assets/{index-DWeD_pcf.js → index-C5878rMW.js} +27 -27
- package/dist/frontend/assets/{index-DWeD_pcf.js.map → index-C5878rMW.js.map} +1 -1
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +3 -3
- package/dist/server-assets/_shared/embeddings/onnx-embedder.ts +34 -0
- package/dist/server-assets/_shared/mcp-tools/delete-document.ts +11 -2
- package/dist/server-assets/_shared/mcp-tools/get-help-content.ts +2 -2
- package/dist/server-assets/_shared/mcp-tools/ingest.ts +7 -6
- package/dist/server-assets/db/migrations/0033_trash_auto_purge.sql +288 -0
- package/dist/server-assets/db/rpcs.sql +101 -3
- package/dist/server-assets/db/schema.sql +10 -1
- package/dist/server-assets/supabase/functions/cerefox-ingest/index.ts +2 -2
- package/docs/api/openapi.json +5815 -0
- package/docs/guides/access-paths.md +16 -0
- package/docs/guides/api.md +297 -0
- package/docs/guides/configuration.md +47 -0
- package/docs/guides/linking.md +118 -0
- package/docs/guides/securing-local-access.md +253 -0
- package/docs/guides/staging-env.md +334 -0
- package/package.json +2 -2
|
@@ -1103,6 +1103,82 @@ AS $$
|
|
|
1103
1103
|
ORDER BY created_at DESC;
|
|
1104
1104
|
$$;
|
|
1105
1105
|
|
|
1106
|
+
-- ── cerefox_purge_expired_trash (#251, 0.17.0) ───────────────────────────────
|
|
1107
|
+
-- Permanently purges documents that have been in the trash longer than
|
|
1108
|
+
-- `trash_retention_days`, when `trash_auto_purge_enabled` is exactly 'true'.
|
|
1109
|
+
-- Called by cerefox_delete_document after every real soft delete: the write
|
|
1110
|
+
-- that adds to the trash also sweeps it. There is no scheduler, by decision
|
|
1111
|
+
-- (docs/specs/trash-auto-purge.md): the trash only grows through deletes, so
|
|
1112
|
+
-- this keeps it bounded on every deployment without pg_cron or a daemon.
|
|
1113
|
+
--
|
|
1114
|
+
-- Safeguards, each load-bearing:
|
|
1115
|
+
-- * at most p_max documents per call, oldest first (partial index on
|
|
1116
|
+
-- deleted_at), so a large first backlog drains over several deletes;
|
|
1117
|
+
-- * FOR UPDATE SKIP LOCKED, so concurrent deletes sweep disjoint rows;
|
|
1118
|
+
-- * an unparsable or < 1 retention purges NOTHING (never "purge everything");
|
|
1119
|
+
-- * one audit entry per purge, authored 'trash-retention' / 'user': the
|
|
1120
|
+
-- authority is the operator's setting, not whoever's delete triggered it.
|
|
1121
|
+
-- Not exposed on MCP, the Edge Functions or the CLI: there is still no
|
|
1122
|
+
-- agent-callable purge (access-paths.md → trust model).
|
|
1123
|
+
CREATE OR REPLACE FUNCTION cerefox_purge_expired_trash(
|
|
1124
|
+
p_max INT DEFAULT 100
|
|
1125
|
+
)
|
|
1126
|
+
RETURNS INT
|
|
1127
|
+
LANGUAGE plpgsql
|
|
1128
|
+
SECURITY DEFINER
|
|
1129
|
+
SET search_path = public, pg_catalog
|
|
1130
|
+
AS $$
|
|
1131
|
+
DECLARE
|
|
1132
|
+
v_enabled TEXT;
|
|
1133
|
+
v_days_txt TEXT;
|
|
1134
|
+
v_days INT;
|
|
1135
|
+
v_cutoff TIMESTAMPTZ;
|
|
1136
|
+
v_count INT := 0;
|
|
1137
|
+
r RECORD;
|
|
1138
|
+
BEGIN
|
|
1139
|
+
SELECT value INTO v_enabled FROM cerefox_config WHERE key = 'trash_auto_purge_enabled';
|
|
1140
|
+
IF v_enabled IS DISTINCT FROM 'true' THEN
|
|
1141
|
+
RETURN 0;
|
|
1142
|
+
END IF;
|
|
1143
|
+
|
|
1144
|
+
SELECT value INTO v_days_txt FROM cerefox_config WHERE key = 'trash_retention_days';
|
|
1145
|
+
IF v_days_txt IS NULL OR BTRIM(v_days_txt) !~ '^[0-9]{1,6}$' THEN
|
|
1146
|
+
RETURN 0;
|
|
1147
|
+
END IF;
|
|
1148
|
+
v_days := BTRIM(v_days_txt)::INT;
|
|
1149
|
+
IF v_days < 1 THEN
|
|
1150
|
+
RETURN 0;
|
|
1151
|
+
END IF;
|
|
1152
|
+
v_cutoff := NOW() - make_interval(days => v_days);
|
|
1153
|
+
|
|
1154
|
+
FOR r IN
|
|
1155
|
+
SELECT id, title, total_chars, deleted_at
|
|
1156
|
+
FROM cerefox_documents
|
|
1157
|
+
WHERE deleted_at IS NOT NULL AND deleted_at < v_cutoff
|
|
1158
|
+
ORDER BY deleted_at
|
|
1159
|
+
LIMIT GREATEST(COALESCE(p_max, 0), 0)
|
|
1160
|
+
FOR UPDATE SKIP LOCKED
|
|
1161
|
+
LOOP
|
|
1162
|
+
PERFORM cerefox_create_audit_entry(
|
|
1163
|
+
p_document_id := r.id,
|
|
1164
|
+
p_operation := 'delete',
|
|
1165
|
+
p_author := 'trash-retention',
|
|
1166
|
+
p_author_type := 'user',
|
|
1167
|
+
p_size_before := r.total_chars,
|
|
1168
|
+
p_size_after := 0,
|
|
1169
|
+
p_description := 'Auto-purged from the trash (trash_retention_days = ' || v_days ||
|
|
1170
|
+
'; trashed ' || to_char(r.deleted_at AT TIME ZONE 'UTC', 'YYYY-MM-DD') ||
|
|
1171
|
+
'): ' || COALESCE(r.title, '(untitled)') ||
|
|
1172
|
+
' (' || COALESCE(r.total_chars, 0) || ' chars)'
|
|
1173
|
+
);
|
|
1174
|
+
DELETE FROM cerefox_documents WHERE id = r.id;
|
|
1175
|
+
v_count := v_count + 1;
|
|
1176
|
+
END LOOP;
|
|
1177
|
+
|
|
1178
|
+
RETURN v_count;
|
|
1179
|
+
END;
|
|
1180
|
+
$$;
|
|
1181
|
+
|
|
1106
1182
|
-- ── cerefox_delete_document (soft delete) ────────────────────────────────────
|
|
1107
1183
|
-- Soft-deletes a document by setting deleted_at = NOW(). The document, its
|
|
1108
1184
|
-- chunks, and versions remain in the database but are excluded from search.
|
|
@@ -1123,6 +1199,12 @@ $$;
|
|
|
1123
1199
|
--
|
|
1124
1200
|
-- Deleting an already-deleted document is a reported no-op: the original
|
|
1125
1201
|
-- deleted_at is preserved and no duplicate audit entry is written.
|
|
1202
|
+
--
|
|
1203
|
+
-- 0.17.0 (#251): a real soft delete then sweeps the trash
|
|
1204
|
+
-- (cerefox_purge_expired_trash) and reports how many documents it purged as
|
|
1205
|
+
-- `auto_purged`. The sweep runs in its own sub-block: if it fails, only its
|
|
1206
|
+
-- savepoint rolls back, a WARNING is raised, and the delete commits exactly as
|
|
1207
|
+
-- it would with auto-purge off. A sweep can never fail a delete.
|
|
1126
1208
|
|
|
1127
1209
|
DROP FUNCTION IF EXISTS cerefox_delete_document(UUID, TEXT, TEXT, TEXT, TEXT);
|
|
1128
1210
|
DROP FUNCTION IF EXISTS cerefox_delete_document(UUID, TEXT, TEXT);
|
|
@@ -1144,6 +1226,7 @@ DECLARE
|
|
|
1144
1226
|
v_total_chars INT;
|
|
1145
1227
|
v_current_hash TEXT;
|
|
1146
1228
|
v_deleted_at TIMESTAMPTZ;
|
|
1229
|
+
v_auto_purged INT := 0;
|
|
1147
1230
|
BEGIN
|
|
1148
1231
|
-- FOR UPDATE: makes the hash check atomic with the delete — a concurrent
|
|
1149
1232
|
-- content update serializes here, and a stale deleter sees its hash.
|
|
@@ -1202,12 +1285,21 @@ BEGIN
|
|
|
1202
1285
|
COALESCE('; reason: ' || NULLIF(BTRIM(p_reason), ''), '')
|
|
1203
1286
|
);
|
|
1204
1287
|
|
|
1288
|
+
BEGIN
|
|
1289
|
+
v_auto_purged := cerefox_purge_expired_trash(100);
|
|
1290
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1291
|
+
v_auto_purged := 0;
|
|
1292
|
+
RAISE WARNING 'cerefox: trash auto-purge skipped after deleting %: % (%)',
|
|
1293
|
+
p_document_id, SQLERRM, SQLSTATE;
|
|
1294
|
+
END;
|
|
1295
|
+
|
|
1205
1296
|
RETURN jsonb_build_object(
|
|
1206
1297
|
'document_id', p_document_id,
|
|
1207
1298
|
'title', v_title,
|
|
1208
1299
|
'total_chars', v_total_chars,
|
|
1209
1300
|
'deleted_at', v_deleted_at,
|
|
1210
|
-
'already_deleted', FALSE
|
|
1301
|
+
'already_deleted', FALSE,
|
|
1302
|
+
'auto_purged', v_auto_purged
|
|
1211
1303
|
);
|
|
1212
1304
|
END;
|
|
1213
1305
|
$$;
|
|
@@ -2742,7 +2834,10 @@ DECLARE
|
|
|
2742
2834
|
-- (0 = off). Partial edits make writes cheap, so an insert-only agent
|
|
2743
2835
|
-- never assembles the document and never sees it grow past its split
|
|
2744
2836
|
-- point. A signal in the write's response, never a refusal.
|
|
2745
|
-
'document_size_warning_chars'
|
|
2837
|
+
'document_size_warning_chars',
|
|
2838
|
+
-- #251: trash auto-purge, off by default; read by
|
|
2839
|
+
-- cerefox_purge_expired_trash on every soft delete.
|
|
2840
|
+
'trash_auto_purge_enabled', 'trash_retention_days'
|
|
2746
2841
|
];
|
|
2747
2842
|
v_old TEXT;
|
|
2748
2843
|
BEGIN
|
|
@@ -3091,6 +3186,9 @@ SET search_path = public, pg_catalog
|
|
|
3091
3186
|
AS $$
|
|
3092
3187
|
-- Keep in lockstep with the `@version:` marker in schema.sql (cut_release.ts
|
|
3093
3188
|
-- enforces it). Bump whenever schema.sql OR rpcs.sql changes.
|
|
3189
|
+
-- 0.17.0 (#251): trash auto-purge. New cerefox_purge_expired_trash, called
|
|
3190
|
+
-- by cerefox_delete_document after a real soft delete (which now returns
|
|
3191
|
+
-- `auto_purged`); two config keys, off by default. Migration 0033.
|
|
3094
3192
|
-- 0.16.2 (#26 follow-up): the Data API grant list is DERIVED from pg_class
|
|
3095
3193
|
-- rather than a hand-written array that has to match the set of tables. The
|
|
3096
3194
|
-- array had drifted (cerefox_document_relations), which only a FRESH cloud
|
|
@@ -3129,7 +3227,7 @@ AS $$
|
|
|
3129
3227
|
-- 0.11.0 supersedes 0.10.6 (v1.2.1, #191): this branch carries that fix plus
|
|
3130
3228
|
-- the partial-edit surface, and both migrations (0019, 0020) are in the
|
|
3131
3229
|
-- sequence, so a store deploying this gets everything from both lines.
|
|
3132
|
-
SELECT '0.
|
|
3230
|
+
SELECT '0.17.0'::TEXT;
|
|
3133
3231
|
$$;
|
|
3134
3232
|
|
|
3135
3233
|
-- ── cerefox_find_dead_links ──────────────────────────────────────────────────
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
-- Requires extensions: vector (pgvector), uuid-ossp
|
|
6
6
|
-- These are enabled at the top of db_deploy.py before this file is applied.
|
|
7
7
|
--
|
|
8
|
-
-- @version: 0.
|
|
8
|
+
-- @version: 0.17.0
|
|
9
9
|
-- The `@version` marker above is read by the schema-version-mismatch banner
|
|
10
10
|
-- (see /api/v1/schema-version). Bump it whenever schema.sql OR rpcs.sql
|
|
11
11
|
-- changes in a way that requires `cerefox server deploy` to be re-run —
|
|
@@ -413,6 +413,15 @@ ON CONFLICT (key) DO NOTHING;
|
|
|
413
413
|
INSERT INTO cerefox_config (key, value)
|
|
414
414
|
VALUES ('review_workflow_enabled', 'false')
|
|
415
415
|
ON CONFLICT (key) DO NOTHING;
|
|
416
|
+
-- Trash auto-purge (#251): OFF by default. When on, the soft delete that adds
|
|
417
|
+
-- to the trash also purges documents trashed more than trash_retention_days
|
|
418
|
+
-- ago (cerefox_purge_expired_trash). Design: docs/specs/trash-auto-purge.md.
|
|
419
|
+
INSERT INTO cerefox_config (key, value)
|
|
420
|
+
VALUES ('trash_auto_purge_enabled', 'false')
|
|
421
|
+
ON CONFLICT (key) DO NOTHING;
|
|
422
|
+
INSERT INTO cerefox_config (key, value)
|
|
423
|
+
VALUES ('trash_retention_days', '60')
|
|
424
|
+
ON CONFLICT (key) DO NOTHING;
|
|
416
425
|
|
|
417
426
|
|
|
418
427
|
-- ── Usage log ────────────────────────────────────────────────────────────────
|
|
@@ -374,7 +374,7 @@ Deno.serve(async (req: Request) => {
|
|
|
374
374
|
|
|
375
375
|
// Content unchanged -- skip re-indexing
|
|
376
376
|
if (existingDoc.content_hash === contentHash) {
|
|
377
|
-
const note = update_if_exists
|
|
377
|
+
const note = body.update_if_exists === false ? "update_if_exists flag was overridden by document_id" : undefined;
|
|
378
378
|
return new Response(
|
|
379
379
|
JSON.stringify({
|
|
380
380
|
document_id: existingDoc.id,
|
|
@@ -462,7 +462,7 @@ Deno.serve(async (req: Request) => {
|
|
|
462
462
|
await ensureDocumentInProject(supabase, existingDoc.id, project_name, { author, authorType: author_type });
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
const note = update_if_exists
|
|
465
|
+
const note = body.update_if_exists === false ? "update_if_exists flag was overridden by document_id" : undefined;
|
|
466
466
|
return new Response(
|
|
467
467
|
JSON.stringify({
|
|
468
468
|
document_id: existingDoc.id,
|