@swestash/agent-lens 0.17.0 → 0.17.1

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.
@@ -3729,6 +3729,77 @@ function xmlTag(text, tag) {
3729
3729
  return text.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`))?.[1]?.trim() ?? null;
3730
3730
  }
3731
3731
 
3732
+ // ../ingest/dist/skillslots.js
3733
+ var ARG_TRAILERS = ["\nARGUMENTS:", "\n## User Request\n"];
3734
+ var EMPTY_OUTPUT = "(Bash completed with no output)";
3735
+ var DYNAMIC_PLACEHOLDER = "(dynamic context: command output omitted)";
3736
+ var isMarker = (t) => t === EMPTY_OUTPUT || t === DYNAMIC_PLACEHOLDER;
3737
+ function uniqueLine(lines, text) {
3738
+ let at = -1;
3739
+ for (let i = 0; i < lines.length; i++) {
3740
+ if (lines[i].trim() !== text)
3741
+ continue;
3742
+ if (at >= 0)
3743
+ return -1;
3744
+ at = i;
3745
+ }
3746
+ return at;
3747
+ }
3748
+ function learnSlots(body) {
3749
+ const lines = body.split("\n");
3750
+ const trimmed = lines.map((l) => l.trim());
3751
+ const slots = [];
3752
+ for (let i = 0; i < lines.length; i++) {
3753
+ if (!isMarker(trimmed[i]))
3754
+ continue;
3755
+ let b = i - 1;
3756
+ while (b >= 0 && trimmed[b] === "")
3757
+ b--;
3758
+ let a = i + 1;
3759
+ while (a < lines.length && (trimmed[a] === "" || isMarker(trimmed[a])))
3760
+ a++;
3761
+ i = a - 1;
3762
+ if (b < 0 || a >= lines.length)
3763
+ continue;
3764
+ const slot = { before: trimmed[b], after: trimmed[a] };
3765
+ if (uniqueLine(lines, slot.before) < 0 || uniqueLine(lines, slot.after) < 0)
3766
+ continue;
3767
+ if (!slots.some((s) => s.before === slot.before && s.after === slot.after))
3768
+ slots.push(slot);
3769
+ }
3770
+ return slots;
3771
+ }
3772
+ function mergeSlots(into, body) {
3773
+ for (const s of learnSlots(body))
3774
+ if (!into.some((x) => x.before === s.before && x.after === s.after))
3775
+ into.push(s);
3776
+ return into;
3777
+ }
3778
+ function maskDynamic(body, slots) {
3779
+ let lines = body.split("\n");
3780
+ for (const { before, after } of slots) {
3781
+ const b = uniqueLine(lines, before);
3782
+ const a = uniqueLine(lines, after);
3783
+ if (b < 0 || a <= b)
3784
+ continue;
3785
+ lines = [...lines.slice(0, b + 1), "", DYNAMIC_PLACEHOLDER, "", ...lines.slice(a)];
3786
+ }
3787
+ return lines.join("\n");
3788
+ }
3789
+ var MIN_MASKED_ARGS = 8;
3790
+ function maskKnownValues(body, known) {
3791
+ const subs = [];
3792
+ const args = known.args?.trim();
3793
+ if (args && args.length >= MIN_MASKED_ARGS)
3794
+ subs.push([args, "$ARGUMENTS"]);
3795
+ if (known.baseDir)
3796
+ subs.push([known.baseDir, "${CLAUDE_SKILL_DIR}"]);
3797
+ if (known.sessionId)
3798
+ subs.push([known.sessionId, "${CLAUDE_SESSION_ID}"]);
3799
+ subs.sort((x, y) => y[0].length - x[0].length);
3800
+ return subs.reduce((out, [value, placeholder]) => out.split(value).join(placeholder), body);
3801
+ }
3802
+
3732
3803
  // ../ingest/dist/pipeline.js
3733
3804
  function newStats() {
3734
3805
  return { files: 0, skipped: 0, malformed: 0, newEvents: 0 };
@@ -3750,9 +3821,15 @@ function parseSkillInjection(text) {
3750
3821
  const baseDir = firstLine || null;
3751
3822
  let body = firstNl >= 0 ? text.slice(firstNl + 1) : "";
3752
3823
  let args = null;
3753
- const argIdx = body.lastIndexOf("\nARGUMENTS:");
3824
+ let argIdx = -1;
3825
+ let trailer = "";
3826
+ for (const t of ARG_TRAILERS) {
3827
+ const i = body.lastIndexOf(t);
3828
+ if (i > argIdx)
3829
+ [argIdx, trailer] = [i, t];
3830
+ }
3754
3831
  if (argIdx >= 0) {
3755
- args = body.slice(argIdx + "\nARGUMENTS:".length).trim() || null;
3832
+ args = body.slice(argIdx + trailer.length).trim() || null;
3756
3833
  body = body.slice(0, argIdx);
3757
3834
  }
3758
3835
  return { baseDir, nameKey: baseDir ? skillNameKey(baseDir) : "", body: body.trim(), args };
@@ -3916,6 +3993,15 @@ function linkSkillVersions(db, sessionIds) {
3916
3993
  first_seen = MIN(first_seen, excluded.first_seen),
3917
3994
  base_dir = excluded.base_dir`);
3918
3995
  const linkCall = db.prepare("UPDATE tool_calls SET skill_id = ? WHERE id = ?");
3996
+ const selLinkedVersions = db.prepare("SELECT id, base_dir, body, first_seen, last_seen FROM skills WHERE name = ? AND id IN (SELECT skill_id FROM tool_calls WHERE skill_id IS NOT NULL)");
3997
+ const upsertRemasked = db.prepare(`INSERT INTO skills (id, name, base_dir, body, summary, body_bytes, first_seen, last_seen)
3998
+ VALUES (@id, @name, @base_dir, @body, @summary, @body_bytes, @first_seen, @last_seen)
3999
+ ON CONFLICT(id) DO UPDATE SET
4000
+ last_seen = MAX(last_seen, excluded.last_seen),
4001
+ first_seen = MIN(first_seen, excluded.first_seen)`);
4002
+ const relinkVersion = db.prepare("UPDATE tool_calls SET skill_id = ? WHERE skill_id = ?");
4003
+ const delVersion = db.prepare("DELETE FROM skills WHERE id = ?");
4004
+ const matches = [];
3919
4005
  const linkTx = transaction(db, () => {
3920
4006
  for (const { id: sid } of sessionIds) {
3921
4007
  const calls = selSkillCalls.all(sid);
@@ -3965,18 +4051,53 @@ function linkSkillVersions(db, sessionIds) {
3965
4051
  idx = 0;
3966
4052
  const [match] = queue.splice(idx, 1);
3967
4053
  const c = calls.find((x) => x.id === match.id);
3968
- const name = c.skill_name;
3969
- const vid = skillVersionId(name, inj.body);
3970
- upsertSkill.run({
4054
+ const body = maskKnownValues(inj.body, { args: match.args ?? inj.args, baseDir: inj.baseDir, sessionId: sid });
4055
+ matches.push({ callId: match.id, name: c.skill_name, baseDir: inj.baseDir, body, ts: e.timestamp });
4056
+ }
4057
+ }
4058
+ const slotsByName = /* @__PURE__ */ new Map();
4059
+ const addSlots = (name, body) => slotsByName.set(name, mergeSlots(slotsByName.get(name) ?? [], body));
4060
+ for (const m of matches)
4061
+ addSlots(m.name, m.body);
4062
+ for (const name of slotsByName.keys()) {
4063
+ for (const v of selLinkedVersions.all(name))
4064
+ addSlots(name, v.body);
4065
+ }
4066
+ for (const m of matches) {
4067
+ const body = maskDynamic(m.body, slotsByName.get(m.name));
4068
+ const vid = skillVersionId(m.name, body);
4069
+ upsertSkill.run({
4070
+ id: vid,
4071
+ name: m.name,
4072
+ base_dir: m.baseDir,
4073
+ body,
4074
+ summary: skillSummary(body),
4075
+ body_bytes: Buffer.byteLength(body, "utf8"),
4076
+ ts: m.ts
4077
+ });
4078
+ linkCall.run(vid, m.callId);
4079
+ }
4080
+ for (const [name, slots] of slotsByName) {
4081
+ if (!slots.length)
4082
+ continue;
4083
+ const versions = selLinkedVersions.all(name);
4084
+ for (const v of versions) {
4085
+ const body = maskDynamic(v.body, slots);
4086
+ if (body === v.body)
4087
+ continue;
4088
+ const vid = skillVersionId(name, body);
4089
+ upsertRemasked.run({
3971
4090
  id: vid,
3972
4091
  name,
3973
- base_dir: inj.baseDir,
3974
- body: inj.body,
3975
- summary: skillSummary(inj.body),
3976
- body_bytes: Buffer.byteLength(inj.body, "utf8"),
3977
- ts: e.timestamp
4092
+ base_dir: v.base_dir,
4093
+ body,
4094
+ summary: skillSummary(body),
4095
+ body_bytes: Buffer.byteLength(body, "utf8"),
4096
+ first_seen: v.first_seen,
4097
+ last_seen: v.last_seen
3978
4098
  });
3979
- linkCall.run(vid, match.id);
4099
+ relinkVersion.run(vid, v.id);
4100
+ delVersion.run(v.id);
3980
4101
  }
3981
4102
  }
3982
4103
  });