sphica 0.6.17 → 0.6.20
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/db/migrations/0007.sql +49 -0
- package/db/schema.sql +17 -2
- package/dist/capture.js +11 -2
- package/dist/cli.js +535 -2
- package/dist/deliver.js +15 -3
- package/dist/mcp-record.js +22 -13
- package/dist/mcp.js +676 -578
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "sphica",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.20",
|
|
5
5
|
"description": "Records Claude Code and Codex sessions on your machine and keeps past implementation and decisions, with their sources, for your agent to find.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "iroha924",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- Revision 6 → 7 of generation 2: capture prunes the deliveries of sessions idle past a cutoff, so delivery_unit loses its cascade from
|
|
2
|
+
-- delivery (capture may not delete through one) and delivery_ad removes the units. Runs in one transaction with foreign keys off; every
|
|
3
|
+
-- statement matches db/schema.sql at revision 7, and server/test/migrate.test.ts compares the two.
|
|
4
|
+
|
|
5
|
+
drop trigger capture_delivery_insert;
|
|
6
|
+
drop trigger capture_delivery_scoped_insert;
|
|
7
|
+
create table delivery_unit_new (
|
|
8
|
+
delivery_id integer not null references delivery (id),
|
|
9
|
+
unit_id integer not null references unit (id) on delete cascade,
|
|
10
|
+
primary key (delivery_id, unit_id)
|
|
11
|
+
) strict;
|
|
12
|
+
insert into delivery_unit_new (delivery_id, unit_id) select delivery_id, unit_id from delivery_unit;
|
|
13
|
+
drop table delivery_unit;
|
|
14
|
+
alter table delivery_unit_new rename to delivery_unit;
|
|
15
|
+
create index delivery_unit_unit on delivery_unit (unit_id);
|
|
16
|
+
create trigger delivery_ad after delete on delivery begin
|
|
17
|
+
delete from delivery_unit where delivery_id = old.id;
|
|
18
|
+
end;
|
|
19
|
+
create index delivery_at on delivery (at);
|
|
20
|
+
create trigger capture_delivery_insert instead of insert on capture_delivery begin
|
|
21
|
+
select raise(abort, 'the unit and the delivered session belong to different projects')
|
|
22
|
+
where exists (select 1 from json_each(coalesce(new.units, '[]')) j
|
|
23
|
+
where (select project_id from unit where id = j.value) is not (select project_id from session where id = new.session_id));
|
|
24
|
+
insert into delivery (session_id, event, outcome, reason, path, eligible, omitted, chars, at)
|
|
25
|
+
values (new.session_id, new.event, new.outcome, new.reason, new.path, coalesce(new.eligible, 0), coalesce(new.omitted, 0),
|
|
26
|
+
coalesce(new.chars, 0), new.at);
|
|
27
|
+
insert into delivery_unit (delivery_id, unit_id)
|
|
28
|
+
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
29
|
+
end;
|
|
30
|
+
create trigger capture_delivery_scoped_insert instead of insert on capture_delivery_scoped begin
|
|
31
|
+
select raise(abort, 'the unit and the delivered session belong to different projects')
|
|
32
|
+
where exists (select 1 from json_each(coalesce(new.units, '[]')) j
|
|
33
|
+
where (select project_id from unit where id = j.value) is not (select project_id from session where id = new.session_id));
|
|
34
|
+
insert into delivery (session_id, agent_id, event, outcome, reason, path, eligible, omitted, chars, at)
|
|
35
|
+
values (new.session_id, new.agent_id, new.event, new.outcome, new.reason, new.path, coalesce(new.eligible, 0),
|
|
36
|
+
coalesce(new.omitted, 0), coalesce(new.chars, 0), new.at);
|
|
37
|
+
insert into delivery_unit (delivery_id, unit_id)
|
|
38
|
+
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
39
|
+
end;
|
|
40
|
+
create view capture_delivery_prune as select null as cutoff, null as session_id;
|
|
41
|
+
create trigger capture_delivery_prune_insert instead of insert on capture_delivery_prune begin
|
|
42
|
+
delete from delivery where session_id = new.session_id
|
|
43
|
+
and not exists (select 1 from delivery n where n.session_id = new.session_id and n.at >= new.cutoff);
|
|
44
|
+
delete from delivery where id in (select d.id from delivery d where d.at < new.cutoff
|
|
45
|
+
and (d.session_id is null or not exists (select 1 from delivery n where n.session_id = d.session_id and n.at >= new.cutoff))
|
|
46
|
+
order by d.at, d.id limit 200);
|
|
47
|
+
end;
|
|
48
|
+
|
|
49
|
+
pragma user_version = 7;
|
package/db/schema.sql
CHANGED
|
@@ -950,12 +950,17 @@ create table delivery (
|
|
|
950
950
|
at text not null check (strftime('%Y-%m-%dT%H:%M:%fZ', at) is at)
|
|
951
951
|
, agent_id text check (length(agent_id) between 1 and 200)) strict;
|
|
952
952
|
create index delivery_session on delivery (session_id, at);
|
|
953
|
+
create index delivery_at on delivery (at);
|
|
954
|
+
-- A delivery's units go by delivery_ad, not a cascade: capture prunes deliveries, and its authorizer passes a delete only from a named trigger
|
|
953
955
|
create table delivery_unit (
|
|
954
|
-
delivery_id integer not null references delivery (id)
|
|
956
|
+
delivery_id integer not null references delivery (id),
|
|
955
957
|
unit_id integer not null references unit (id) on delete cascade,
|
|
956
958
|
primary key (delivery_id, unit_id)
|
|
957
959
|
) strict;
|
|
958
960
|
create index delivery_unit_unit on delivery_unit (unit_id);
|
|
961
|
+
create trigger delivery_ad after delete on delivery begin
|
|
962
|
+
delete from delivery_unit where delivery_id = old.id;
|
|
963
|
+
end;
|
|
959
964
|
|
|
960
965
|
-- The one way the record server writes a source. It has no session columns, so it can never write a session message: those are the
|
|
961
966
|
-- owner's own words, and only capture writes them. A view insert returns no id; the writer looks the row up by its item key
|
|
@@ -1039,5 +1044,15 @@ create trigger capture_delivery_scoped_insert instead of insert on capture_deliv
|
|
|
1039
1044
|
insert into delivery_unit (delivery_id, unit_id)
|
|
1040
1045
|
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
1041
1046
|
end;
|
|
1047
|
+
-- Deletes the deliveries of sessions whose last delivery is before cutoff: all of session_id's, then up to 200 of the oldest others (a row
|
|
1048
|
+
-- without a session goes by its own time). Capture inserts here before each delivery it logs, naming that delivery's session
|
|
1049
|
+
create view capture_delivery_prune as select null as cutoff, null as session_id;
|
|
1050
|
+
create trigger capture_delivery_prune_insert instead of insert on capture_delivery_prune begin
|
|
1051
|
+
delete from delivery where session_id = new.session_id
|
|
1052
|
+
and not exists (select 1 from delivery n where n.session_id = new.session_id and n.at >= new.cutoff);
|
|
1053
|
+
delete from delivery where id in (select d.id from delivery d where d.at < new.cutoff
|
|
1054
|
+
and (d.session_id is null or not exists (select 1 from delivery n where n.session_id = d.session_id and n.at >= new.cutoff))
|
|
1055
|
+
order by d.at, d.id limit 200);
|
|
1056
|
+
end;
|
|
1042
1057
|
|
|
1043
|
-
pragma user_version =
|
|
1058
|
+
pragma user_version = 7;
|
package/dist/capture.js
CHANGED
|
@@ -10900,6 +10900,7 @@ var QUESTION = new Set([
|
|
|
10900
10900
|
...["add", "get", "make", "have", "has", "not", "no", "yes", "reason"],
|
|
10901
10901
|
...["理由", "仕組", "何", "方", "場合", "今", "件"]
|
|
10902
10902
|
]);
|
|
10903
|
+
var FOLDED_QUESTION = new Set([...QUESTION].flatMap((w) => terms(w)));
|
|
10903
10904
|
var sha256 = (s) => crypto.createHash("sha256").update(s).digest();
|
|
10904
10905
|
function uuidFrom(...parts) {
|
|
10905
10906
|
const b = crypto.createHash("sha256").update(parts.join("\x00")).digest().subarray(0, 16);
|
|
@@ -11109,7 +11110,7 @@ var HOST_MARKS = new Set([".orphaned_at", ".in_use"]);
|
|
|
11109
11110
|
|
|
11110
11111
|
// server/src/sqlite.ts
|
|
11111
11112
|
var SCHEMA_GENERATION = 2;
|
|
11112
|
-
var SCHEMA_REVISION =
|
|
11113
|
+
var SCHEMA_REVISION = 7;
|
|
11113
11114
|
var sphicaHome = () => process.env.SPHICA_HOME || path2.join(os.homedir(), ".sphica");
|
|
11114
11115
|
var dbFile = () => process.env.SPHICA_DB || path2.join(sphicaHome(), "sphica.db");
|
|
11115
11116
|
function requireRuntime() {
|
|
@@ -11250,7 +11251,8 @@ var CAPTURE_VIEWS = new Set([
|
|
|
11250
11251
|
"capture_message",
|
|
11251
11252
|
"capture_edit",
|
|
11252
11253
|
"capture_delivery",
|
|
11253
|
-
"capture_delivery_scoped"
|
|
11254
|
+
"capture_delivery_scoped",
|
|
11255
|
+
"capture_delivery_prune"
|
|
11254
11256
|
]);
|
|
11255
11257
|
var TRIGGER_WRITES = {
|
|
11256
11258
|
capture_session_insert: new Set(["session"]),
|
|
@@ -11260,6 +11262,10 @@ var TRIGGER_WRITES = {
|
|
|
11260
11262
|
capture_delivery_scoped_insert: new Set(["delivery", "delivery_unit"]),
|
|
11261
11263
|
source_fts_ai: new Set(["source_fts"])
|
|
11262
11264
|
};
|
|
11265
|
+
var TRIGGER_DELETES = {
|
|
11266
|
+
capture_delivery_prune_insert: new Set(["delivery"]),
|
|
11267
|
+
delivery_ad: new Set(["delivery_unit"])
|
|
11268
|
+
};
|
|
11263
11269
|
var TRIGGER_FUNCTIONS = {
|
|
11264
11270
|
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"]),
|
|
11265
11271
|
capture_delivery_scoped_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
@@ -11279,6 +11285,8 @@ function captureAuthorizer(own, action, p1, p2, triggerOrView) {
|
|
|
11279
11285
|
return C2.SQLITE_OK;
|
|
11280
11286
|
return fts ? C2.SQLITE_OK : C2.SQLITE_DENY;
|
|
11281
11287
|
}
|
|
11288
|
+
if (action === C2.SQLITE_DELETE && triggerOrView !== null && TRIGGER_DELETES[triggerOrView]?.has(table))
|
|
11289
|
+
return C2.SQLITE_OK;
|
|
11282
11290
|
if (action === C2.SQLITE_UPDATE || action === C2.SQLITE_DELETE)
|
|
11283
11291
|
return fts ? C2.SQLITE_OK : C2.SQLITE_DENY;
|
|
11284
11292
|
if (action === C2.SQLITE_READ) {
|
|
@@ -11335,6 +11343,7 @@ var INGEST_TRIGGER_WRITES = {
|
|
|
11335
11343
|
source_fts_ad: ["delete source_fts"],
|
|
11336
11344
|
unit_state_apply: ["update unit"],
|
|
11337
11345
|
unit_state_restore: ["insert unit_state"],
|
|
11346
|
+
delivery_ad: ["delete delivery_unit"],
|
|
11338
11347
|
...Object.fromEntries([
|
|
11339
11348
|
"evidence_i",
|
|
11340
11349
|
"evidence_u",
|