sphica 0.6.16 → 0.6.17
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/0006.sql +20 -0
- package/db/schema.sql +19 -4
- package/dist/capture.js +11 -3
- package/dist/cli.js +11 -3
- package/dist/deliver.js +98 -33
- package/dist/mcp-record.js +11 -3
- package/dist/mcp.js +1 -1
- package/hooks/codex.json +12 -0
- package/hooks/hooks.json +11 -0
- 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.17",
|
|
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,20 @@
|
|
|
1
|
+
-- Revision 5 → 6 of generation 2: the subagent a delivery ran in (existing rows keep null, the main conversation), and a capture view
|
|
2
|
+
-- that writes it while capture_delivery keeps its columns. `sphica init` runs this in one transaction with foreign keys off, then checks
|
|
3
|
+
-- foreign_key_check. Every statement matches db/schema.sql at revision 6; server/test/migrate.test.ts compares the two.
|
|
4
|
+
|
|
5
|
+
alter table delivery add column agent_id text check (length(agent_id) between 1 and 200);
|
|
6
|
+
|
|
7
|
+
create view capture_delivery_scoped as
|
|
8
|
+
select session_id, agent_id, event, outcome, reason, path, eligible, omitted, chars, at, null as units from delivery;
|
|
9
|
+
create trigger capture_delivery_scoped_insert instead of insert on capture_delivery_scoped begin
|
|
10
|
+
select raise(abort, 'the unit and the delivered session belong to different projects')
|
|
11
|
+
where exists (select 1 from json_each(coalesce(new.units, '[]')) j
|
|
12
|
+
where (select project_id from unit where id = j.value) is not (select project_id from session where id = new.session_id));
|
|
13
|
+
insert into delivery (session_id, agent_id, event, outcome, reason, path, eligible, omitted, chars, at)
|
|
14
|
+
values (new.session_id, new.agent_id, new.event, new.outcome, new.reason, new.path, coalesce(new.eligible, 0),
|
|
15
|
+
coalesce(new.omitted, 0), coalesce(new.chars, 0), new.at);
|
|
16
|
+
insert into delivery_unit (delivery_id, unit_id)
|
|
17
|
+
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
18
|
+
end;
|
|
19
|
+
|
|
20
|
+
pragma user_version = 6;
|
package/db/schema.sql
CHANGED
|
@@ -934,8 +934,9 @@ create table work (
|
|
|
934
934
|
create index work_open on work (project_id, updated_at desc) where status in ('active', 'blocked', 'paused');
|
|
935
935
|
create index work_run on work (run_id) where run_id is not null;
|
|
936
936
|
|
|
937
|
-
-- What a delivery hook emitted or suppressed, and how many eligible units it left out
|
|
938
|
-
--
|
|
937
|
+
-- What a delivery hook emitted or suppressed, and how many eligible units it left out (no source text). chars leaves out the omission note,
|
|
938
|
+
-- since the read budget adds it up. A session_start's reason is the start source or 'subagent'; agent_id is the subagent (null: main),
|
|
939
|
+
-- written the way SQLite stores a column ALTER TABLE added, so a migrated database has the same definition.
|
|
939
940
|
create table delivery (
|
|
940
941
|
id integer primary key autoincrement not null,
|
|
941
942
|
session_id text references session (id) on delete cascade,
|
|
@@ -947,7 +948,7 @@ create table delivery (
|
|
|
947
948
|
omitted integer not null default 0 check (omitted >= 0 and omitted <= eligible),
|
|
948
949
|
chars integer not null default 0 check (chars >= 0),
|
|
949
950
|
at text not null check (strftime('%Y-%m-%dT%H:%M:%fZ', at) is at)
|
|
950
|
-
) strict;
|
|
951
|
+
, agent_id text check (length(agent_id) between 1 and 200)) strict;
|
|
951
952
|
create index delivery_session on delivery (session_id, at);
|
|
952
953
|
create table delivery_unit (
|
|
953
954
|
delivery_id integer not null references delivery (id) on delete cascade,
|
|
@@ -1024,5 +1025,19 @@ create trigger capture_delivery_insert instead of insert on capture_delivery beg
|
|
|
1024
1025
|
insert into delivery_unit (delivery_id, unit_id)
|
|
1025
1026
|
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
1026
1027
|
end;
|
|
1028
|
+
-- The same as capture_delivery with the subagent the delivery ran in. capture_delivery keeps its columns, since an older plugin's
|
|
1029
|
+
-- capture writes through it into a database of this revision
|
|
1030
|
+
create view capture_delivery_scoped as
|
|
1031
|
+
select session_id, agent_id, event, outcome, reason, path, eligible, omitted, chars, at, null as units from delivery;
|
|
1032
|
+
create trigger capture_delivery_scoped_insert instead of insert on capture_delivery_scoped begin
|
|
1033
|
+
select raise(abort, 'the unit and the delivered session belong to different projects')
|
|
1034
|
+
where exists (select 1 from json_each(coalesce(new.units, '[]')) j
|
|
1035
|
+
where (select project_id from unit where id = j.value) is not (select project_id from session where id = new.session_id));
|
|
1036
|
+
insert into delivery (session_id, agent_id, event, outcome, reason, path, eligible, omitted, chars, at)
|
|
1037
|
+
values (new.session_id, new.agent_id, new.event, new.outcome, new.reason, new.path, coalesce(new.eligible, 0),
|
|
1038
|
+
coalesce(new.omitted, 0), coalesce(new.chars, 0), new.at);
|
|
1039
|
+
insert into delivery_unit (delivery_id, unit_id)
|
|
1040
|
+
select last_insert_rowid(), j.value from json_each(coalesce(new.units, '[]')) j where true on conflict do nothing;
|
|
1041
|
+
end;
|
|
1027
1042
|
|
|
1028
|
-
pragma user_version =
|
|
1043
|
+
pragma user_version = 6;
|
package/dist/capture.js
CHANGED
|
@@ -11109,7 +11109,7 @@ var HOST_MARKS = new Set([".orphaned_at", ".in_use"]);
|
|
|
11109
11109
|
|
|
11110
11110
|
// server/src/sqlite.ts
|
|
11111
11111
|
var SCHEMA_GENERATION = 2;
|
|
11112
|
-
var SCHEMA_REVISION =
|
|
11112
|
+
var SCHEMA_REVISION = 6;
|
|
11113
11113
|
var sphicaHome = () => process.env.SPHICA_HOME || path2.join(os.homedir(), ".sphica");
|
|
11114
11114
|
var dbFile = () => process.env.SPHICA_DB || path2.join(sphicaHome(), "sphica.db");
|
|
11115
11115
|
function requireRuntime() {
|
|
@@ -11245,16 +11245,24 @@ var DDL = () => ddl ??= new Set([
|
|
|
11245
11245
|
return code;
|
|
11246
11246
|
}));
|
|
11247
11247
|
var readsDataVersion = (p1, p2) => p1 === "data_version" && p2 === null;
|
|
11248
|
-
var CAPTURE_VIEWS = new Set([
|
|
11248
|
+
var CAPTURE_VIEWS = new Set([
|
|
11249
|
+
"capture_session",
|
|
11250
|
+
"capture_message",
|
|
11251
|
+
"capture_edit",
|
|
11252
|
+
"capture_delivery",
|
|
11253
|
+
"capture_delivery_scoped"
|
|
11254
|
+
]);
|
|
11249
11255
|
var TRIGGER_WRITES = {
|
|
11250
11256
|
capture_session_insert: new Set(["session"]),
|
|
11251
11257
|
capture_message_insert: new Set(["source"]),
|
|
11252
11258
|
capture_edit_insert: new Set(["edit_observation"]),
|
|
11253
11259
|
capture_delivery_insert: new Set(["delivery", "delivery_unit"]),
|
|
11260
|
+
capture_delivery_scoped_insert: new Set(["delivery", "delivery_unit"]),
|
|
11254
11261
|
source_fts_ai: new Set(["source_fts"])
|
|
11255
11262
|
};
|
|
11256
11263
|
var TRIGGER_FUNCTIONS = {
|
|
11257
|
-
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
11264
|
+
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"]),
|
|
11265
|
+
capture_delivery_scoped_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
11258
11266
|
};
|
|
11259
11267
|
var CAPTURE_READS = {
|
|
11260
11268
|
project: new Set(["id", "key", "name"]),
|
package/dist/cli.js
CHANGED
|
@@ -3625,7 +3625,7 @@ ${indent}${caution(note)}` : ""}`);
|
|
|
3625
3625
|
|
|
3626
3626
|
// server/src/sqlite.ts
|
|
3627
3627
|
var SCHEMA_GENERATION = 2;
|
|
3628
|
-
var SCHEMA_REVISION =
|
|
3628
|
+
var SCHEMA_REVISION = 6;
|
|
3629
3629
|
var sphicaHome = () => process.env.SPHICA_HOME || path3.join(os2.homedir(), ".sphica");
|
|
3630
3630
|
var dbFile = () => process.env.SPHICA_DB || path3.join(sphicaHome(), "sphica.db");
|
|
3631
3631
|
function requireRuntime() {
|
|
@@ -14712,16 +14712,24 @@ var DDL = () => ddl ??= new Set([
|
|
|
14712
14712
|
return code;
|
|
14713
14713
|
}));
|
|
14714
14714
|
var readsDataVersion = (p1, p2) => p1 === "data_version" && p2 === null;
|
|
14715
|
-
var CAPTURE_VIEWS = new Set([
|
|
14715
|
+
var CAPTURE_VIEWS = new Set([
|
|
14716
|
+
"capture_session",
|
|
14717
|
+
"capture_message",
|
|
14718
|
+
"capture_edit",
|
|
14719
|
+
"capture_delivery",
|
|
14720
|
+
"capture_delivery_scoped"
|
|
14721
|
+
]);
|
|
14716
14722
|
var TRIGGER_WRITES = {
|
|
14717
14723
|
capture_session_insert: new Set(["session"]),
|
|
14718
14724
|
capture_message_insert: new Set(["source"]),
|
|
14719
14725
|
capture_edit_insert: new Set(["edit_observation"]),
|
|
14720
14726
|
capture_delivery_insert: new Set(["delivery", "delivery_unit"]),
|
|
14727
|
+
capture_delivery_scoped_insert: new Set(["delivery", "delivery_unit"]),
|
|
14721
14728
|
source_fts_ai: new Set(["source_fts"])
|
|
14722
14729
|
};
|
|
14723
14730
|
var TRIGGER_FUNCTIONS = {
|
|
14724
|
-
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
14731
|
+
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"]),
|
|
14732
|
+
capture_delivery_scoped_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
14725
14733
|
};
|
|
14726
14734
|
var CAPTURE_READS = {
|
|
14727
14735
|
project: new Set(["id", "key", "name"]),
|
package/dist/deliver.js
CHANGED
|
@@ -11134,7 +11134,7 @@ var HOST_MARKS = new Set([".orphaned_at", ".in_use"]);
|
|
|
11134
11134
|
|
|
11135
11135
|
// server/src/sqlite.ts
|
|
11136
11136
|
var SCHEMA_GENERATION = 2;
|
|
11137
|
-
var SCHEMA_REVISION =
|
|
11137
|
+
var SCHEMA_REVISION = 6;
|
|
11138
11138
|
var sphicaHome = () => process.env.SPHICA_HOME || path3.join(os.homedir(), ".sphica");
|
|
11139
11139
|
var dbFile = () => process.env.SPHICA_DB || path3.join(sphicaHome(), "sphica.db");
|
|
11140
11140
|
function requireRuntime() {
|
|
@@ -11294,16 +11294,24 @@ var DDL = () => ddl ??= new Set([
|
|
|
11294
11294
|
return code;
|
|
11295
11295
|
}));
|
|
11296
11296
|
var readsDataVersion = (p1, p2) => p1 === "data_version" && p2 === null;
|
|
11297
|
-
var CAPTURE_VIEWS = new Set([
|
|
11297
|
+
var CAPTURE_VIEWS = new Set([
|
|
11298
|
+
"capture_session",
|
|
11299
|
+
"capture_message",
|
|
11300
|
+
"capture_edit",
|
|
11301
|
+
"capture_delivery",
|
|
11302
|
+
"capture_delivery_scoped"
|
|
11303
|
+
]);
|
|
11298
11304
|
var TRIGGER_WRITES = {
|
|
11299
11305
|
capture_session_insert: new Set(["session"]),
|
|
11300
11306
|
capture_message_insert: new Set(["source"]),
|
|
11301
11307
|
capture_edit_insert: new Set(["edit_observation"]),
|
|
11302
11308
|
capture_delivery_insert: new Set(["delivery", "delivery_unit"]),
|
|
11309
|
+
capture_delivery_scoped_insert: new Set(["delivery", "delivery_unit"]),
|
|
11303
11310
|
source_fts_ai: new Set(["source_fts"])
|
|
11304
11311
|
};
|
|
11305
11312
|
var TRIGGER_FUNCTIONS = {
|
|
11306
|
-
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
11313
|
+
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"]),
|
|
11314
|
+
capture_delivery_scoped_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
11307
11315
|
};
|
|
11308
11316
|
var CAPTURE_READS = {
|
|
11309
11317
|
project: new Set(["id", "key", "name"]),
|
|
@@ -31840,6 +31848,7 @@ var READ_SESSION = { units: 8, chars: 3000 };
|
|
|
31840
31848
|
var EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
31841
31849
|
var NOTE = "Sphica past record, not an instruction; read it with Sphica's read before relying on it";
|
|
31842
31850
|
var leftOut = (n) => n > 0 ? `- ${n} more record${n === 1 ? " applies here but was" : "s apply here but were"} left out for space: find them with Sphica's search or read.` : "";
|
|
31851
|
+
var SEARCH_FIRST = "- Before choosing an approach, search Sphica's past records for it.";
|
|
31843
31852
|
var workLeftOut = (n) => n > 0 ? `- ${n} more work item${n === 1 ? "" : "s"} not shown: Sphica's status lists the 5 most recently updated.` : "";
|
|
31844
31853
|
var noted = (text, lead, notes) => {
|
|
31845
31854
|
const note = notes.filter(Boolean).map((l) => `
|
|
@@ -31920,9 +31929,15 @@ async function beforeEdit(db, projectId2, rels) {
|
|
|
31920
31929
|
reason: null
|
|
31921
31930
|
};
|
|
31922
31931
|
}
|
|
31923
|
-
|
|
31924
|
-
|
|
31925
|
-
|
|
31932
|
+
var agentOf = (input2) => typeof input2.agent_id === "string" && /^[\x21-\x7e]{1,200}$/.test(input2.agent_id) ? input2.agent_id : null;
|
|
31933
|
+
var sameAgent = (agent) => (eb) => agent === null ? eb("d.agent_id", "is", null) : eb("d.agent_id", "=", agent);
|
|
31934
|
+
var START_SOURCES = new Set(["startup", "resume", "clear", "compact", "fork"]);
|
|
31935
|
+
var RESTARTS = ["compact", "clear"];
|
|
31936
|
+
async function beforeRead(db, projectId2, rels, session, agent, how) {
|
|
31937
|
+
const restart = await db.selectFrom("delivery as d").where("d.session_id", "=", session).where(sameAgent(agent)).where("d.event", "=", "session_start").where("d.reason", "in", RESTARTS).select((eb) => eb.fn.max("d.id").as("id")).executeTakeFirst();
|
|
31938
|
+
const since = restart?.id ?? 0;
|
|
31939
|
+
const sent = await db.selectFrom("delivery as d").innerJoin("delivery_unit as x", "x.delivery_id", "d.id").where("d.session_id", "=", session).where(sameAgent(agent)).where("d.id", ">", since).where("d.outcome", "=", "emitted").select(["x.unit_id", "d.event"]).execute();
|
|
31940
|
+
const spent = await db.selectFrom("delivery as d").where("d.session_id", "=", session).where(sameAgent(agent)).where("d.id", ">", since).where("d.event", "=", "pre_read").where("d.outcome", "=", "emitted").where(({ exists, selectFrom }) => exists(selectFrom("delivery_unit as x").select("x.unit_id").whereRef("x.delivery_id", "=", "d.id"))).select("d.chars").execute();
|
|
31926
31941
|
const seen = new Set(sent.map((r) => r.unit_id));
|
|
31927
31942
|
const readUnits = sent.filter((r) => r.event === "pre_read").length;
|
|
31928
31943
|
const rows = (await anchoredTo(db, projectId2, rels).where("u.kind", "in", ["decision", "constraint"]).execute()).filter((u) => !seen.has(u.id));
|
|
@@ -32052,7 +32067,12 @@ async function atStart(db, projectId2, branch, place) {
|
|
|
32052
32067
|
const workLeft = Math.max((workTotal ?? 0) - f.kept.filter((i) => i < work.length).length, 0);
|
|
32053
32068
|
const broadLeft = Math.max((broadTotal ?? 0) - shownUnits.length, 0);
|
|
32054
32069
|
return {
|
|
32055
|
-
...noted(f.text, lead, [
|
|
32070
|
+
...noted(f.text, lead, [
|
|
32071
|
+
leftOut(broadLeft),
|
|
32072
|
+
workLeftOut(workLeft),
|
|
32073
|
+
await waiting(db, projectId2, place),
|
|
32074
|
+
place.subagent ? SEARCH_FIRST : ""
|
|
32075
|
+
]),
|
|
32056
32076
|
units: shownUnits,
|
|
32057
32077
|
eligible: (workTotal ?? 0) + (broadTotal ?? 0),
|
|
32058
32078
|
omitted: workLeft + broadLeft,
|
|
@@ -32120,34 +32140,62 @@ function markOnce(kind, key) {
|
|
|
32120
32140
|
function onceUnavailable(session) {
|
|
32121
32141
|
return markOnce("unavailable", session);
|
|
32122
32142
|
}
|
|
32123
|
-
async function
|
|
32143
|
+
async function write2(trx, e, plan) {
|
|
32144
|
+
const id = sessionId(e.projectId, e.host, e.external);
|
|
32145
|
+
const now = iso(Date.now());
|
|
32146
|
+
await trx.insertInto("capture_session").values({
|
|
32147
|
+
id,
|
|
32148
|
+
project_id: e.projectId,
|
|
32149
|
+
host: e.host,
|
|
32150
|
+
external_id: e.external,
|
|
32151
|
+
branch: e.branch,
|
|
32152
|
+
started_at: now
|
|
32153
|
+
}).execute();
|
|
32154
|
+
await trx.insertInto("capture_delivery_scoped").values({
|
|
32155
|
+
session_id: id,
|
|
32156
|
+
agent_id: e.agent,
|
|
32157
|
+
event: e.event,
|
|
32158
|
+
outcome: plan.text ? "emitted" : "nothing",
|
|
32159
|
+
reason: plan.reason,
|
|
32160
|
+
path: plan.path,
|
|
32161
|
+
eligible: plan.eligible,
|
|
32162
|
+
omitted: plan.omitted,
|
|
32163
|
+
chars: plan.text.length - plan.note.length,
|
|
32164
|
+
at: now,
|
|
32165
|
+
units: JSON.stringify(plan.units)
|
|
32166
|
+
}).execute();
|
|
32167
|
+
}
|
|
32168
|
+
async function log(file2, e, plan) {
|
|
32124
32169
|
const cap = openWriter("capture", file2, LOG_WAIT_MS);
|
|
32125
32170
|
try {
|
|
32126
|
-
|
|
32127
|
-
|
|
32171
|
+
await inTransaction(cap, (trx) => write2(trx, e, plan));
|
|
32172
|
+
} finally {
|
|
32173
|
+
await cap.destroy().catch(() => {});
|
|
32174
|
+
}
|
|
32175
|
+
}
|
|
32176
|
+
async function lockedPlan(file2, e, make, keep) {
|
|
32177
|
+
const cap = openWriter("capture", file2, LOG_WAIT_MS);
|
|
32178
|
+
let held = false;
|
|
32179
|
+
let plan = null;
|
|
32180
|
+
try {
|
|
32128
32181
|
await inTransaction(cap, async (trx) => {
|
|
32129
|
-
|
|
32130
|
-
await
|
|
32131
|
-
|
|
32132
|
-
|
|
32133
|
-
outcome,
|
|
32134
|
-
reason: plan.reason,
|
|
32135
|
-
path: plan.path,
|
|
32136
|
-
eligible: plan.eligible,
|
|
32137
|
-
omitted: plan.omitted,
|
|
32138
|
-
chars: plan.text.length - plan.note.length,
|
|
32139
|
-
at: now,
|
|
32140
|
-
units: JSON.stringify(plan.units)
|
|
32141
|
-
}).execute();
|
|
32182
|
+
held = true;
|
|
32183
|
+
plan = await make();
|
|
32184
|
+
if (keep(plan))
|
|
32185
|
+
await write2(trx, e, plan);
|
|
32142
32186
|
});
|
|
32187
|
+
} catch (err) {
|
|
32188
|
+
if (held && !plan)
|
|
32189
|
+
throw err;
|
|
32143
32190
|
} finally {
|
|
32144
32191
|
await cap.destroy().catch(() => {});
|
|
32145
32192
|
}
|
|
32193
|
+
return plan ?? make();
|
|
32146
32194
|
}
|
|
32147
32195
|
async function deliver(input2, host = "claude-code", file2 = dbFile()) {
|
|
32148
32196
|
const name = input2.hook_event_name;
|
|
32149
32197
|
const call = reviewCall(input2);
|
|
32150
|
-
const event = call ? "review" : name === "SessionStart" ? "session_start" : name === "UserPromptSubmit" ? "prompt" : name === "PreToolUse" ? input2.tool_name === "Read" || input2.tool_name === "Bash" && !(host === "codex" && shellPatch(input2)) ? "pre_read" : "pre_edit" : null;
|
|
32198
|
+
const event = call ? "review" : name === "SessionStart" || name === "SubagentStart" ? "session_start" : name === "UserPromptSubmit" ? "prompt" : name === "PreToolUse" ? input2.tool_name === "Read" || input2.tool_name === "Bash" && !(host === "codex" && shellPatch(input2)) ? "pre_read" : "pre_edit" : null;
|
|
32151
32199
|
if (!event || !input2.session_id)
|
|
32152
32200
|
return "";
|
|
32153
32201
|
if (event === "prompt" && !isOwnerTurn(input2, undefined, undefined, host === "codex" ? process.env.CODEX_THREAD_ID : undefined))
|
|
@@ -32181,21 +32229,38 @@ async function deliver(input2, host = "claude-code", file2 = dbFile()) {
|
|
|
32181
32229
|
return "";
|
|
32182
32230
|
}
|
|
32183
32231
|
if (event === "session_start" && input2.source === "resume") {
|
|
32184
|
-
const said = await db.selectFrom("delivery").select("id").where("session_id", "=", sessionId(pid, host, input2.session_id)).where("event", "=", "session_start").where("outcome", "=", "emitted").executeTakeFirst();
|
|
32232
|
+
const said = await db.selectFrom("delivery").select("id").where("session_id", "=", sessionId(pid, host, input2.session_id)).where("agent_id", "is", null).where("event", "=", "session_start").where((eb) => eb.or([eb("reason", "is", null), eb("reason", "!=", "subagent")])).where("outcome", "=", "emitted").executeTakeFirst();
|
|
32185
32233
|
if (said)
|
|
32186
32234
|
return "";
|
|
32187
32235
|
}
|
|
32188
|
-
const
|
|
32189
|
-
|
|
32190
|
-
|
|
32236
|
+
const reader = db;
|
|
32237
|
+
const session = input2.session_id;
|
|
32238
|
+
const make = async () => event === "pre_edit" ? await beforeEdit(reader, pid, rels) : event === "pre_read" ? await beforeRead(reader, pid, rels, sessionId(pid, host, session), agentOf(input2), shell ? "named" : "reading") : event === "prompt" ? await onPrompt(reader, pid, place.root, input2.prompt ?? "") : call ? await beforeReview(reader, pid, place.root, call) : {
|
|
32239
|
+
...await atStart(reader, pid, branchOf(place.root), {
|
|
32240
|
+
file: file2,
|
|
32241
|
+
key: place.key,
|
|
32242
|
+
host,
|
|
32243
|
+
subagent: name === "SubagentStart",
|
|
32244
|
+
owner: name !== "SubagentStart" && isOwnerTurn(input2, undefined, undefined, host === "codex" ? process.env.CODEX_THREAD_ID : undefined)
|
|
32245
|
+
}),
|
|
32246
|
+
reason: name === "SubagentStart" ? "subagent" : input2.source && START_SOURCES.has(input2.source) ? input2.source : null
|
|
32247
|
+
};
|
|
32248
|
+
const entry = {
|
|
32249
|
+
projectId: pid,
|
|
32191
32250
|
host,
|
|
32192
|
-
|
|
32193
|
-
|
|
32251
|
+
external: session,
|
|
32252
|
+
agent: agentOf(input2),
|
|
32253
|
+
event,
|
|
32254
|
+
branch: branchOf(place.root)
|
|
32255
|
+
};
|
|
32256
|
+
const keep = (p) => !(onPath && !p.text);
|
|
32257
|
+
if (event === "pre_read" || event === "session_start")
|
|
32258
|
+
return (await lockedPlan(file2, entry, make, keep)).text;
|
|
32259
|
+
const plan = await make();
|
|
32194
32260
|
if (call && plan.text && toldBefore(`${host}\x00${input2.session_id}`, plan.once ?? plan.text))
|
|
32195
32261
|
return "";
|
|
32196
|
-
if (
|
|
32197
|
-
|
|
32198
|
-
await log(file2, pid, host, input2.session_id, event, plan, plan.text ? "emitted" : "nothing", branchOf(place.root)).catch(() => {});
|
|
32262
|
+
if (keep(plan))
|
|
32263
|
+
await log(file2, entry, plan).catch(() => {});
|
|
32199
32264
|
return plan.text;
|
|
32200
32265
|
} catch (e) {
|
|
32201
32266
|
if (e instanceof RevisionMismatch)
|
package/dist/mcp-record.js
CHANGED
|
@@ -45869,7 +45869,7 @@ var HOST_MARKS = new Set([".orphaned_at", ".in_use"]);
|
|
|
45869
45869
|
|
|
45870
45870
|
// server/src/sqlite.ts
|
|
45871
45871
|
var SCHEMA_GENERATION = 2;
|
|
45872
|
-
var SCHEMA_REVISION =
|
|
45872
|
+
var SCHEMA_REVISION = 6;
|
|
45873
45873
|
var sphicaHome = () => process.env.SPHICA_HOME || path2.join(os.homedir(), ".sphica");
|
|
45874
45874
|
var dbFile = () => process.env.SPHICA_DB || path2.join(sphicaHome(), "sphica.db");
|
|
45875
45875
|
function requireRuntime() {
|
|
@@ -46005,16 +46005,24 @@ var DDL = () => ddl ??= new Set([
|
|
|
46005
46005
|
return code;
|
|
46006
46006
|
}));
|
|
46007
46007
|
var readsDataVersion = (p1, p2) => p1 === "data_version" && p2 === null;
|
|
46008
|
-
var CAPTURE_VIEWS = new Set([
|
|
46008
|
+
var CAPTURE_VIEWS = new Set([
|
|
46009
|
+
"capture_session",
|
|
46010
|
+
"capture_message",
|
|
46011
|
+
"capture_edit",
|
|
46012
|
+
"capture_delivery",
|
|
46013
|
+
"capture_delivery_scoped"
|
|
46014
|
+
]);
|
|
46009
46015
|
var TRIGGER_WRITES = {
|
|
46010
46016
|
capture_session_insert: new Set(["session"]),
|
|
46011
46017
|
capture_message_insert: new Set(["source"]),
|
|
46012
46018
|
capture_edit_insert: new Set(["edit_observation"]),
|
|
46013
46019
|
capture_delivery_insert: new Set(["delivery", "delivery_unit"]),
|
|
46020
|
+
capture_delivery_scoped_insert: new Set(["delivery", "delivery_unit"]),
|
|
46014
46021
|
source_fts_ai: new Set(["source_fts"])
|
|
46015
46022
|
};
|
|
46016
46023
|
var TRIGGER_FUNCTIONS = {
|
|
46017
|
-
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
46024
|
+
capture_delivery_insert: new Set(["coalesce", "json_each", "last_insert_rowid"]),
|
|
46025
|
+
capture_delivery_scoped_insert: new Set(["coalesce", "json_each", "last_insert_rowid"])
|
|
46018
46026
|
};
|
|
46019
46027
|
var CAPTURE_READS = {
|
|
46020
46028
|
project: new Set(["id", "key", "name"]),
|
package/dist/mcp.js
CHANGED
|
@@ -46030,7 +46030,7 @@ var HOST_MARKS = new Set([".orphaned_at", ".in_use"]);
|
|
|
46030
46030
|
|
|
46031
46031
|
// server/src/sqlite.ts
|
|
46032
46032
|
var SCHEMA_GENERATION = 2;
|
|
46033
|
-
var SCHEMA_REVISION =
|
|
46033
|
+
var SCHEMA_REVISION = 6;
|
|
46034
46034
|
var sphicaHome = () => process.env.SPHICA_HOME || path2.join(os.homedir(), ".sphica");
|
|
46035
46035
|
var dbFile = () => process.env.SPHICA_DB || path2.join(sphicaHome(), "sphica.db");
|
|
46036
46036
|
function requireRuntime() {
|
package/hooks/codex.json
CHANGED
|
@@ -18,6 +18,18 @@
|
|
|
18
18
|
]
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
|
+
"SubagentStart": [
|
|
22
|
+
{
|
|
23
|
+
"hooks": [
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"command": "node \"${PLUGIN_ROOT}/dist/deliver.js\" codex",
|
|
27
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -Command node $env:PLUGIN_ROOT/dist/deliver.js codex",
|
|
28
|
+
"timeout": 10
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
21
33
|
"UserPromptSubmit": [
|
|
22
34
|
{
|
|
23
35
|
"hooks": [
|
package/hooks/hooks.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sphica",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"description": "Records Claude Code and Codex sessions on your machine and keeps past implementation and decisions, with their sources, for your agent to find.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|