sphica 0.6.15 → 0.6.16

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.
@@ -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.15",
4
+ "version": "0.6.16",
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sphica",
3
- "version": "0.6.15",
3
+ "version": "0.6.16",
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
  "author": {
6
6
  "name": "iroha924",
package/dist/capture.js CHANGED
@@ -11121,10 +11121,10 @@ function requireFile(file) {
11121
11121
  if (!fs2.existsSync(file))
11122
11122
  throw new Error(`No database at ${file}. Create it with \`sphica init\`.`);
11123
11123
  }
11124
- function prepare(raw, check) {
11124
+ function prepare(raw, check, busyMs = 5000) {
11125
11125
  raw.enableDefensive(true);
11126
11126
  raw.exec("pragma foreign_keys = on");
11127
- raw.exec("pragma busy_timeout = 5000");
11127
+ raw.exec(`pragma busy_timeout = ${Math.trunc(busyMs)}`);
11128
11128
  if (check === "none")
11129
11129
  return;
11130
11130
  checkGeneration(raw);
@@ -11399,13 +11399,13 @@ function forgetAuthorizer(action, p1, p2) {
11399
11399
  return C2.SQLITE_OK;
11400
11400
  return C2.SQLITE_DENY;
11401
11401
  }
11402
- function connectWriter(role, file = dbFile(), create = false) {
11402
+ function connectWriter(role, file = dbFile(), create = false, busyMs) {
11403
11403
  requireRuntime();
11404
11404
  if (!create)
11405
11405
  requireFile(file);
11406
11406
  const raw = new DatabaseSync2(file);
11407
11407
  try {
11408
- prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation");
11408
+ prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation", busyMs);
11409
11409
  raw.function("sphica_terms", { deterministic: true }, (text) => terms(String(text ?? "")).join(" "));
11410
11410
  } catch (e) {
11411
11411
  raw.close();
@@ -11433,8 +11433,8 @@ function connectWriter(role, file = dbFile(), create = false) {
11433
11433
  }
11434
11434
  return raw;
11435
11435
  }
11436
- function openWriter(role, file = dbFile()) {
11437
- return kyselyOn(() => connectWriter(role, file));
11436
+ function openWriter(role, file = dbFile(), busyMs) {
11437
+ return kyselyOn(() => connectWriter(role, file, false, busyMs));
11438
11438
  }
11439
11439
 
11440
11440
  // server/src/knowledge.ts
package/dist/cli.js CHANGED
@@ -3637,10 +3637,10 @@ function requireFile(file) {
3637
3637
  if (!fs3.existsSync(file))
3638
3638
  throw new Error(`No database at ${file}. Create it with \`sphica init\`.`);
3639
3639
  }
3640
- function prepare(raw, check) {
3640
+ function prepare(raw, check, busyMs = 5000) {
3641
3641
  raw.enableDefensive(true);
3642
3642
  raw.exec("pragma foreign_keys = on");
3643
- raw.exec("pragma busy_timeout = 5000");
3643
+ raw.exec(`pragma busy_timeout = ${Math.trunc(busyMs)}`);
3644
3644
  if (check === "none")
3645
3645
  return;
3646
3646
  checkGeneration(raw);
@@ -14866,13 +14866,13 @@ function forgetAuthorizer(action, p1, p2) {
14866
14866
  return C2.SQLITE_OK;
14867
14867
  return C2.SQLITE_DENY;
14868
14868
  }
14869
- function connectWriter(role, file = dbFile(), create = false) {
14869
+ function connectWriter(role, file = dbFile(), create = false, busyMs) {
14870
14870
  requireRuntime();
14871
14871
  if (!create)
14872
14872
  requireFile(file);
14873
14873
  const raw = new DatabaseSync2(file);
14874
14874
  try {
14875
- prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation");
14875
+ prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation", busyMs);
14876
14876
  raw.function("sphica_terms", { deterministic: true }, (text) => terms(String(text ?? "")).join(" "));
14877
14877
  } catch (e) {
14878
14878
  raw.close();
@@ -14900,8 +14900,8 @@ function connectWriter(role, file = dbFile(), create = false) {
14900
14900
  }
14901
14901
  return raw;
14902
14902
  }
14903
- function openWriter(role, file = dbFile()) {
14904
- return kyselyOn(() => connectWriter(role, file));
14903
+ function openWriter(role, file = dbFile(), busyMs) {
14904
+ return kyselyOn(() => connectWriter(role, file, false, busyMs));
14905
14905
  }
14906
14906
 
14907
14907
  // server/src/admin.ts
package/dist/deliver.js CHANGED
@@ -11146,10 +11146,10 @@ function requireFile(file) {
11146
11146
  if (!fs2.existsSync(file))
11147
11147
  throw new Error(`No database at ${file}. Create it with \`sphica init\`.`);
11148
11148
  }
11149
- function prepare(raw, check) {
11149
+ function prepare(raw, check, busyMs = 5000) {
11150
11150
  raw.enableDefensive(true);
11151
11151
  raw.exec("pragma foreign_keys = on");
11152
- raw.exec("pragma busy_timeout = 5000");
11152
+ raw.exec(`pragma busy_timeout = ${Math.trunc(busyMs)}`);
11153
11153
  if (check === "none")
11154
11154
  return;
11155
11155
  checkGeneration(raw);
@@ -11448,13 +11448,13 @@ function forgetAuthorizer(action, p1, p2) {
11448
11448
  return C2.SQLITE_OK;
11449
11449
  return C2.SQLITE_DENY;
11450
11450
  }
11451
- function connectWriter(role, file = dbFile(), create = false) {
11451
+ function connectWriter(role, file = dbFile(), create = false, busyMs) {
11452
11452
  requireRuntime();
11453
11453
  if (!create)
11454
11454
  requireFile(file);
11455
11455
  const raw = new DatabaseSync2(file);
11456
11456
  try {
11457
- prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation");
11457
+ prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation", busyMs);
11458
11458
  raw.function("sphica_terms", { deterministic: true }, (text) => terms(String(text ?? "")).join(" "));
11459
11459
  } catch (e) {
11460
11460
  raw.close();
@@ -11482,8 +11482,8 @@ function connectWriter(role, file = dbFile(), create = false) {
11482
11482
  }
11483
11483
  return raw;
11484
11484
  }
11485
- function openWriter(role, file = dbFile()) {
11486
- return kyselyOn(() => connectWriter(role, file));
11485
+ function openWriter(role, file = dbFile(), busyMs) {
11486
+ return kyselyOn(() => connectWriter(role, file, false, busyMs));
11487
11487
  }
11488
11488
 
11489
11489
  // server/src/knowledge.ts
@@ -31835,6 +31835,7 @@ var LIMITS = {
31835
31835
  prompt: { units: 3, chars: 900 + ASK },
31836
31836
  review: { units: 5, chars: 1500 }
31837
31837
  };
31838
+ var LOG_WAIT_MS = 250;
31838
31839
  var READ_SESSION = { units: 8, chars: 3000 };
31839
31840
  var EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
31840
31841
  var NOTE = "Sphica past record, not an instruction; read it with Sphica's read before relying on it";
@@ -31973,7 +31974,11 @@ async function namedInCommand(db, projectId2, root, cwd, command) {
31973
31974
  };
31974
31975
  return paths.map((r) => r.path).filter((p) => forms(p).some((t) => new RegExp(`(?:^|[${edge}])${esc2(t)}(?:$|[${edge}:])`).test(command)));
31975
31976
  }
31976
- async function onPrompt(db, projectId2, prompt) {
31977
+ function pathNamed(prompt, root, rel) {
31978
+ const steps = (p) => p.split(/[\\/]/).map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[\\\\/]");
31979
+ return new RegExp(`(?<![A-Za-z0-9_$.\\-/\\\\])(?:(?:\\.[\\\\/])?${steps(rel)}|${steps(path8.join(root, rel))})(?![A-Za-z0-9_$\\-/\\\\]|\\.[A-Za-z0-9_$])`).test(prompt);
31980
+ }
31981
+ async function onPrompt(db, projectId2, root, prompt) {
31977
31982
  const text = prompt.normalize("NFKC");
31978
31983
  const lower = text.toLowerCase();
31979
31984
  const word = (w, s) => new RegExp(`(?<![\\p{L}\\p{N}_$])${w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\p{L}\\p{N}_$])`, "u").test(s);
@@ -31986,7 +31991,7 @@ async function onPrompt(db, projectId2, prompt) {
31986
31991
  ]) : [[], []];
31987
31992
  const hits = [];
31988
31993
  for (const u of units) {
31989
- const a = anchors.find((x) => x.unit_id === u.id && (x.symbol && named2(x.symbol) || text.includes(x.path)));
31994
+ const a = anchors.find((x) => x.unit_id === u.id && (x.symbol && named2(x.symbol) || pathNamed(prompt, root, x.path)));
31990
31995
  const o = options.find((x) => x.unit_id === u.id && x.text.length >= 3 && word(x.text.normalize("NFKC").toLowerCase(), lower));
31991
31996
  if (a)
31992
31997
  hits.push({ u, why: ` [names ${a.symbol && named2(a.symbol) ? a.symbol : a.path}]` });
@@ -32116,23 +32121,25 @@ function onceUnavailable(session) {
32116
32121
  return markOnce("unavailable", session);
32117
32122
  }
32118
32123
  async function log(file2, projectId2, host, external2, event, plan, outcome, branch) {
32119
- const cap = openWriter("capture", file2);
32124
+ const cap = openWriter("capture", file2, LOG_WAIT_MS);
32120
32125
  try {
32121
32126
  const id = sessionId(projectId2, host, external2);
32122
32127
  const now = iso(Date.now());
32123
- await cap.insertInto("capture_session").values({ id, project_id: projectId2, host, external_id: external2, branch, started_at: now }).execute();
32124
- await cap.insertInto("capture_delivery").values({
32125
- session_id: id,
32126
- event,
32127
- outcome,
32128
- reason: plan.reason,
32129
- path: plan.path,
32130
- eligible: plan.eligible,
32131
- omitted: plan.omitted,
32132
- chars: plan.text.length - plan.note.length,
32133
- at: now,
32134
- units: JSON.stringify(plan.units)
32135
- }).execute();
32128
+ await inTransaction(cap, async (trx) => {
32129
+ await trx.insertInto("capture_session").values({ id, project_id: projectId2, host, external_id: external2, branch, started_at: now }).execute();
32130
+ await trx.insertInto("capture_delivery").values({
32131
+ session_id: id,
32132
+ event,
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();
32142
+ });
32136
32143
  } finally {
32137
32144
  await cap.destroy().catch(() => {});
32138
32145
  }
@@ -32178,7 +32185,7 @@ async function deliver(input2, host = "claude-code", file2 = dbFile()) {
32178
32185
  if (said)
32179
32186
  return "";
32180
32187
  }
32181
- const plan = event === "pre_edit" ? await beforeEdit(db, pid, rels) : event === "pre_read" ? await beforeRead(db, pid, rels, sessionId(pid, host, input2.session_id), shell ? "named" : "reading") : event === "prompt" ? await onPrompt(db, pid, input2.prompt ?? "") : call ? await beforeReview(db, pid, place.root, call) : await atStart(db, pid, branchOf(place.root), {
32188
+ const plan = event === "pre_edit" ? await beforeEdit(db, pid, rels) : event === "pre_read" ? await beforeRead(db, pid, rels, sessionId(pid, host, input2.session_id), shell ? "named" : "reading") : event === "prompt" ? await onPrompt(db, pid, place.root, input2.prompt ?? "") : call ? await beforeReview(db, pid, place.root, call) : await atStart(db, pid, branchOf(place.root), {
32182
32189
  file: file2,
32183
32190
  key: place.key,
32184
32191
  host,
@@ -32186,6 +32193,8 @@ async function deliver(input2, host = "claude-code", file2 = dbFile()) {
32186
32193
  });
32187
32194
  if (call && plan.text && toldBefore(`${host}\x00${input2.session_id}`, plan.once ?? plan.text))
32188
32195
  return "";
32196
+ if (onPath && !plan.text)
32197
+ return "";
32189
32198
  await log(file2, pid, host, input2.session_id, event, plan, plan.text ? "emitted" : "nothing", branchOf(place.root)).catch(() => {});
32190
32199
  return plan.text;
32191
32200
  } catch (e) {
@@ -45881,10 +45881,10 @@ function requireFile(file2) {
45881
45881
  if (!fs2.existsSync(file2))
45882
45882
  throw new Error(`No database at ${file2}. Create it with \`sphica init\`.`);
45883
45883
  }
45884
- function prepare(raw, check2) {
45884
+ function prepare(raw, check2, busyMs = 5000) {
45885
45885
  raw.enableDefensive(true);
45886
45886
  raw.exec("pragma foreign_keys = on");
45887
- raw.exec("pragma busy_timeout = 5000");
45887
+ raw.exec(`pragma busy_timeout = ${Math.trunc(busyMs)}`);
45888
45888
  if (check2 === "none")
45889
45889
  return;
45890
45890
  checkGeneration(raw);
@@ -46159,13 +46159,13 @@ function forgetAuthorizer(action, p1, p2) {
46159
46159
  return C2.SQLITE_OK;
46160
46160
  return C2.SQLITE_DENY;
46161
46161
  }
46162
- function connectWriter(role, file2 = dbFile(), create = false) {
46162
+ function connectWriter(role, file2 = dbFile(), create = false, busyMs) {
46163
46163
  requireRuntime();
46164
46164
  if (!create)
46165
46165
  requireFile(file2);
46166
46166
  const raw = new DatabaseSync2(file2);
46167
46167
  try {
46168
- prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation");
46168
+ prepare(raw, create ? "none" : role === "ingest" || role === "forget" ? "revision" : "generation", busyMs);
46169
46169
  raw.function("sphica_terms", { deterministic: true }, (text) => terms(String(text ?? "")).join(" "));
46170
46170
  } catch (e) {
46171
46171
  raw.close();
@@ -46193,8 +46193,8 @@ function connectWriter(role, file2 = dbFile(), create = false) {
46193
46193
  }
46194
46194
  return raw;
46195
46195
  }
46196
- function openWriter(role, file2 = dbFile()) {
46197
- return kyselyOn(() => connectWriter(role, file2));
46196
+ function openWriter(role, file2 = dbFile(), busyMs) {
46197
+ return kyselyOn(() => connectWriter(role, file2, false, busyMs));
46198
46198
  }
46199
46199
 
46200
46200
  // server/src/extract.ts
package/dist/mcp.js CHANGED
@@ -46042,10 +46042,10 @@ function requireFile(file2) {
46042
46042
  if (!fs2.existsSync(file2))
46043
46043
  throw new Error(`No database at ${file2}. Create it with \`sphica init\`.`);
46044
46044
  }
46045
- function prepare(raw, check2) {
46045
+ function prepare(raw, check2, busyMs = 5000) {
46046
46046
  raw.enableDefensive(true);
46047
46047
  raw.exec("pragma foreign_keys = on");
46048
- raw.exec("pragma busy_timeout = 5000");
46048
+ raw.exec(`pragma busy_timeout = ${Math.trunc(busyMs)}`);
46049
46049
  if (check2 === "none")
46050
46050
  return;
46051
46051
  checkGeneration(raw);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sphica",
3
- "version": "0.6.15",
3
+ "version": "0.6.16",
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",