@signetai/connector-forge 0.185.3 → 0.185.5

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.
Files changed (2) hide show
  1. package/dist/index.js +485 -25
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { dirname as dirname5, isAbsolute, join as join3, relative, sep } from "n
21
21
  import { createRequire } from "node:module";
22
22
  import { dirname, join } from "node:path";
23
23
  import { fileURLToPath } from "node:url";
24
+ import { createHash } from "node:crypto";
24
25
  import { homedir as homedir2 } from "os";
25
26
  import { join as join2 } from "path";
26
27
  import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
@@ -10557,6 +10558,224 @@ function up116(db) {
10557
10558
  ON cross_agent_messages(delivery_path, delivery_state, delivery_lease_expires_at, delivery_updated_at);
10558
10559
  `);
10559
10560
  }
10561
+ function hasTable4(db, table) {
10562
+ return db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) != null;
10563
+ }
10564
+ function addColumnIfMissing25(db, table, column, definition) {
10565
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
10566
+ if (columns.some((row) => row.name === column))
10567
+ return;
10568
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
10569
+ }
10570
+ function tableColumns(db, table) {
10571
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
10572
+ return new Set(rows.map((row) => typeof row.name === "string" ? row.name : ""));
10573
+ }
10574
+ function hashTranscript(content) {
10575
+ return createHash("sha256").update(content, "utf8").digest("hex");
10576
+ }
10577
+ function backfillTranscriptHashes(db) {
10578
+ const columns = tableColumns(db, "session_transcripts");
10579
+ if (!columns.has("content_hash") || !columns.has("content"))
10580
+ return;
10581
+ const rows = db.prepare("SELECT session_key, agent_id, content FROM session_transcripts WHERE content_hash IS NULL").all();
10582
+ const update = db.prepare("UPDATE session_transcripts SET content_hash = ? WHERE agent_id = ? AND session_key = ? AND content_hash IS NULL");
10583
+ for (const row of rows) {
10584
+ if (typeof row.content !== "string" || typeof row.session_key !== "string")
10585
+ continue;
10586
+ update.run(hashTranscript(row.content), typeof row.agent_id === "string" ? row.agent_id : "default", row.session_key);
10587
+ }
10588
+ }
10589
+ var COMPLETION_BOUNDARY_REASONS = new Set(["session_closed", "session_clear", "stale_session", "ttl_expired"]);
10590
+ function summaryJobTimestamp(job) {
10591
+ return job.completed_at ?? job.ended_at ?? job.captured_at ?? job.created_at ?? new Date(0).toISOString();
10592
+ }
10593
+ function laterTimestamp(current, candidate) {
10594
+ if (current === null)
10595
+ return candidate;
10596
+ if (candidate === null)
10597
+ return current;
10598
+ const currentMillis = Date.parse(current);
10599
+ const candidateMillis = Date.parse(candidate);
10600
+ if (Number.isFinite(currentMillis) && Number.isFinite(candidateMillis)) {
10601
+ return candidateMillis > currentMillis ? candidate : current;
10602
+ }
10603
+ return candidate > current ? candidate : current;
10604
+ }
10605
+ function isCompletionBoundary(job, columns) {
10606
+ return columns.has("trigger") && job.trigger === "session_end" || columns.has("boundary_reason") && COMPLETION_BOUNDARY_REASONS.has(job.boundary_reason ?? "");
10607
+ }
10608
+ function mergeTranscriptContent(current, next) {
10609
+ if (current.length === 0)
10610
+ return next;
10611
+ if (next.length === 0 || current === next || current.includes(next))
10612
+ return current;
10613
+ if (next.includes(current))
10614
+ return next;
10615
+ return `${current}
10616
+ ${next}`;
10617
+ }
10618
+ function backfillTranscriptsFromSummaryJobs(db) {
10619
+ if (!hasTable4(db, "summary_jobs"))
10620
+ return;
10621
+ const summaryColumns = tableColumns(db, "summary_jobs");
10622
+ if (!summaryColumns.has("transcript"))
10623
+ return;
10624
+ const select = (name) => summaryColumns.has(name) ? `"${name}" AS "${name}"` : `NULL AS "${name}"`;
10625
+ const jobs = db.prepare(`SELECT ${[
10626
+ "id",
10627
+ "session_key",
10628
+ "transcript",
10629
+ "harness",
10630
+ "project",
10631
+ "agent_id",
10632
+ "trigger",
10633
+ "boundary_reason",
10634
+ "captured_at",
10635
+ "ended_at",
10636
+ "completed_at",
10637
+ "created_at"
10638
+ ].map(select).join(", ")} FROM summary_jobs`).all();
10639
+ const candidates = new Map;
10640
+ for (const job of jobs) {
10641
+ if (typeof job.transcript !== "string" || job.transcript.trim().length === 0)
10642
+ continue;
10643
+ const agentId = typeof job.agent_id === "string" && job.agent_id.length > 0 ? job.agent_id : "default";
10644
+ const sessionKey = typeof job.session_key === "string" && job.session_key.trim().length > 0 ? job.session_key : `legacy-summary-job:${job.id ?? hashTranscript(`${summaryJobTimestamp(job)}\x00${job.transcript}`)}`;
10645
+ const key = `${agentId}\x00${sessionKey}`;
10646
+ const current = candidates.get(key);
10647
+ const timestamp = summaryJobTimestamp(job);
10648
+ const boundary = isCompletionBoundary(job, summaryColumns);
10649
+ const createdAt = job.captured_at ?? job.created_at ?? job.ended_at ?? timestamp;
10650
+ if (!current) {
10651
+ candidates.set(key, {
10652
+ sessionKey,
10653
+ job: { ...job, agent_id: agentId },
10654
+ content: job.transcript,
10655
+ createdAt,
10656
+ completedAt: boundary ? timestamp : null
10657
+ });
10658
+ continue;
10659
+ }
10660
+ const currentTimestamp = summaryJobTimestamp(current.job);
10661
+ const preferred = timestamp > currentTimestamp || timestamp === currentTimestamp && job.transcript.length > current.content.length ? { ...job, agent_id: agentId } : current.job;
10662
+ candidates.set(key, {
10663
+ sessionKey,
10664
+ job: preferred,
10665
+ content: mergeTranscriptContent(current.content, job.transcript),
10666
+ createdAt: current.createdAt < createdAt ? current.createdAt : createdAt,
10667
+ completedAt: laterTimestamp(current.completedAt, boundary ? timestamp : null)
10668
+ });
10669
+ }
10670
+ const transcriptColumns = tableColumns(db, "session_transcripts");
10671
+ const hasUpdated = transcriptColumns.has("updated_at");
10672
+ const hasCompleted = transcriptColumns.has("completed_at");
10673
+ const hasHash = transcriptColumns.has("content_hash");
10674
+ const insertColumns = ["session_key", "content", "harness", "project", "agent_id", "created_at"];
10675
+ if (hasUpdated)
10676
+ insertColumns.push("updated_at");
10677
+ if (hasCompleted)
10678
+ insertColumns.push("completed_at");
10679
+ if (hasHash)
10680
+ insertColumns.push("content_hash");
10681
+ const insert = db.prepare(`INSERT OR IGNORE INTO session_transcripts (${insertColumns.join(", ")}) VALUES (${insertColumns.map(() => "?").join(", ")})`);
10682
+ const existing = db.prepare("SELECT content, completed_at FROM session_transcripts WHERE agent_id = ? AND session_key = ?");
10683
+ for (const candidate of candidates.values()) {
10684
+ const job = candidate.job;
10685
+ const agentId = job.agent_id ?? "default";
10686
+ const existingRow = existing.get(agentId, candidate.sessionKey);
10687
+ if (existingRow != null) {
10688
+ const previousContent = typeof existingRow.content === "string" ? existingRow.content : "";
10689
+ const mergedContent = mergeTranscriptContent(previousContent, candidate.content);
10690
+ const completedAt = typeof existingRow.completed_at === "string" && existingRow.completed_at.length > 0 ? existingRow.completed_at : candidate.completedAt;
10691
+ const assignments = ["content = ?"];
10692
+ const values2 = [mergedContent];
10693
+ if (hasUpdated && mergedContent !== previousContent) {
10694
+ assignments.push("updated_at = ?");
10695
+ values2.push(candidate.createdAt);
10696
+ }
10697
+ if (hasCompleted && completedAt && !existingRow.completed_at) {
10698
+ assignments.push("completed_at = ?");
10699
+ values2.push(completedAt);
10700
+ }
10701
+ if (hasHash) {
10702
+ assignments.push("content_hash = ?");
10703
+ values2.push(hashTranscript(mergedContent));
10704
+ }
10705
+ values2.push(agentId, candidate.sessionKey);
10706
+ db.prepare(`UPDATE session_transcripts SET ${assignments.join(", ")} WHERE agent_id = ? AND session_key = ?`).run(...values2);
10707
+ continue;
10708
+ }
10709
+ const values = [
10710
+ candidate.sessionKey,
10711
+ candidate.content,
10712
+ job.harness ?? null,
10713
+ job.project ?? null,
10714
+ agentId,
10715
+ candidate.createdAt
10716
+ ];
10717
+ if (hasUpdated)
10718
+ values.push(candidate.createdAt);
10719
+ if (hasCompleted)
10720
+ values.push(candidate.completedAt);
10721
+ if (hasHash)
10722
+ values.push(hashTranscript(candidate.content));
10723
+ insert.run(...values);
10724
+ }
10725
+ }
10726
+ function up117(db) {
10727
+ if (!hasTable4(db, "session_transcripts"))
10728
+ return;
10729
+ addColumnIfMissing25(db, "session_transcripts", "completed_at", "TEXT");
10730
+ addColumnIfMissing25(db, "session_transcripts", "content_hash", "TEXT");
10731
+ backfillTranscriptHashes(db);
10732
+ if (hasTable4(db, "transcript_capture_jobs")) {
10733
+ const captureColumns = db.prepare("PRAGMA table_info(transcript_capture_jobs)").all();
10734
+ if (captureColumns.some((row) => row.name === "summary_status")) {
10735
+ db.exec("UPDATE transcript_capture_jobs SET summary_status = 'not_requested' WHERE summary_status IN ('pending', 'failed', 'skipped')");
10736
+ }
10737
+ }
10738
+ if (hasTable4(db, "summary_jobs")) {
10739
+ backfillTranscriptsFromSummaryJobs(db);
10740
+ backfillTranscriptHashes(db);
10741
+ const summaryColumns = tableColumns(db, "summary_jobs");
10742
+ const timestampParts = ["completed_at", "ended_at", "captured_at", "created_at"].filter((column) => summaryColumns.has(column)).map((column) => `sj.${column}`);
10743
+ const timestampValue = timestampParts.length === 1 ? timestampParts[0] : `COALESCE(${timestampParts.join(", ")})`;
10744
+ const completionTimestamp = timestampValue ? `MAX(${timestampValue})` : "NULL";
10745
+ const boundaryParts = [
10746
+ summaryColumns.has("trigger") ? "sj.trigger = 'session_end'" : null,
10747
+ summaryColumns.has("boundary_reason") ? "sj.boundary_reason IN ('session_closed', 'session_clear', 'stale_session', 'ttl_expired')" : null
10748
+ ].filter((part) => part !== null);
10749
+ const boundaryPredicate = boundaryParts.length > 0 ? `(${boundaryParts.join(" OR ")})` : "1=1";
10750
+ const agentPredicate = summaryColumns.has("agent_id") ? "sj.agent_id = session_transcripts.agent_id" : "session_transcripts.agent_id = 'default'";
10751
+ if (completionTimestamp !== "NULL") {
10752
+ db.exec(`
10753
+ UPDATE session_transcripts
10754
+ SET completed_at = COALESCE(
10755
+ completed_at,
10756
+ (
10757
+ SELECT ${completionTimestamp}
10758
+ FROM summary_jobs AS sj
10759
+ WHERE ${agentPredicate}
10760
+ AND sj.session_key = session_transcripts.session_key
10761
+ AND ${boundaryPredicate}
10762
+ )
10763
+ )
10764
+ WHERE completed_at IS NULL;
10765
+ `);
10766
+ }
10767
+ db.exec("DELETE FROM summary_jobs");
10768
+ }
10769
+ const completionIndexColumns = ["agent_id", "completed_at"];
10770
+ if (tableColumns(db, "session_transcripts").has("updated_at"))
10771
+ completionIndexColumns.push("updated_at");
10772
+ db.exec(`
10773
+ CREATE INDEX IF NOT EXISTS idx_st_agent_completed
10774
+ ON session_transcripts(${completionIndexColumns.join(", ")});
10775
+ CREATE INDEX IF NOT EXISTS idx_st_agent_hash
10776
+ ON session_transcripts(agent_id, content_hash);
10777
+ `);
10778
+ }
10560
10779
  var MIGRATIONS = [
10561
10780
  {
10562
10781
  version: 1,
@@ -11496,6 +11715,17 @@ var MIGRATIONS = [
11496
11715
  { table: "cross_agent_messages", column: "acp_target_agent_name" }
11497
11716
  ]
11498
11717
  }
11718
+ },
11719
+ {
11720
+ version: 117,
11721
+ name: "retire-summary-worker",
11722
+ up: up117,
11723
+ artifacts: {
11724
+ columns: [
11725
+ { table: "session_transcripts", column: "completed_at" },
11726
+ { table: "session_transcripts", column: "content_hash" }
11727
+ ]
11728
+ }
11499
11729
  }
11500
11730
  ];
11501
11731
  var LATEST_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
@@ -12060,6 +12290,7 @@ function resolveRemoteDaemonUrl() {
12060
12290
  import { createRequire as createRequire3 } from "node:module";
12061
12291
  import { dirname as dirname6, join as join4 } from "node:path";
12062
12292
  import { fileURLToPath as fileURLToPath2 } from "node:url";
12293
+ import { createHash as createHash2 } from "node:crypto";
12063
12294
  import { homedir as homedir22 } from "os";
12064
12295
  import { join as join22 } from "path";
12065
12296
  import { createRequire as createRequire22 } from "node:module";
@@ -19017,7 +19248,7 @@ function memoriesFtsNeedsTokenizerRepair2(sql) {
19017
19248
  return true;
19018
19249
  return !normalized.includes(`tokenize='${MEMORIES_FTS_TOKENIZER2}'`);
19019
19250
  }
19020
- function up117(db) {
19251
+ function up118(db) {
19021
19252
  db.exec(`
19022
19253
  CREATE TABLE IF NOT EXISTS schema_migrations (
19023
19254
  version INTEGER PRIMARY KEY,
@@ -19110,27 +19341,27 @@ function hasColumn22(db, table, column) {
19110
19341
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
19111
19342
  return rows.some((r) => r.name === column);
19112
19343
  }
19113
- function addColumnIfMissing25(db, table, column, definition) {
19344
+ function addColumnIfMissing26(db, table, column, definition) {
19114
19345
  if (!hasColumn22(db, table, column)) {
19115
19346
  db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
19116
19347
  }
19117
19348
  }
19118
19349
  function up210(db) {
19119
- addColumnIfMissing25(db, "memories", "content_hash", "TEXT");
19120
- addColumnIfMissing25(db, "memories", "normalized_content", "TEXT");
19121
- addColumnIfMissing25(db, "memories", "is_deleted", "INTEGER DEFAULT 0");
19122
- addColumnIfMissing25(db, "memories", "deleted_at", "TEXT");
19123
- addColumnIfMissing25(db, "memories", "extraction_status", "TEXT DEFAULT 'none'");
19124
- addColumnIfMissing25(db, "memories", "embedding_model", "TEXT");
19125
- addColumnIfMissing25(db, "memories", "extraction_model", "TEXT");
19126
- addColumnIfMissing25(db, "memories", "update_count", "INTEGER DEFAULT 0");
19127
- addColumnIfMissing25(db, "memories", "who", "TEXT");
19128
- addColumnIfMissing25(db, "memories", "why", "TEXT");
19129
- addColumnIfMissing25(db, "memories", "project", "TEXT");
19130
- addColumnIfMissing25(db, "memories", "pinned", "INTEGER DEFAULT 0");
19131
- addColumnIfMissing25(db, "memories", "importance", "REAL DEFAULT 0.5");
19132
- addColumnIfMissing25(db, "memories", "last_accessed", "TEXT");
19133
- addColumnIfMissing25(db, "memories", "access_count", "INTEGER DEFAULT 0");
19350
+ addColumnIfMissing26(db, "memories", "content_hash", "TEXT");
19351
+ addColumnIfMissing26(db, "memories", "normalized_content", "TEXT");
19352
+ addColumnIfMissing26(db, "memories", "is_deleted", "INTEGER DEFAULT 0");
19353
+ addColumnIfMissing26(db, "memories", "deleted_at", "TEXT");
19354
+ addColumnIfMissing26(db, "memories", "extraction_status", "TEXT DEFAULT 'none'");
19355
+ addColumnIfMissing26(db, "memories", "embedding_model", "TEXT");
19356
+ addColumnIfMissing26(db, "memories", "extraction_model", "TEXT");
19357
+ addColumnIfMissing26(db, "memories", "update_count", "INTEGER DEFAULT 0");
19358
+ addColumnIfMissing26(db, "memories", "who", "TEXT");
19359
+ addColumnIfMissing26(db, "memories", "why", "TEXT");
19360
+ addColumnIfMissing26(db, "memories", "project", "TEXT");
19361
+ addColumnIfMissing26(db, "memories", "pinned", "INTEGER DEFAULT 0");
19362
+ addColumnIfMissing26(db, "memories", "importance", "REAL DEFAULT 0.5");
19363
+ addColumnIfMissing26(db, "memories", "last_accessed", "TEXT");
19364
+ addColumnIfMissing26(db, "memories", "access_count", "INTEGER DEFAULT 0");
19134
19365
  db.exec(`
19135
19366
  CREATE TABLE IF NOT EXISTS memory_history (
19136
19367
  id TEXT PRIMARY KEY,
@@ -19226,7 +19457,7 @@ function up210(db) {
19226
19457
  ON memory_entity_mentions(entity_id);
19227
19458
  `);
19228
19459
  }
19229
- function addColumnIfMissing26(db, table, column, definition) {
19460
+ function addColumnIfMissing27(db, table, column, definition) {
19230
19461
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
19231
19462
  if (rows.some((r) => r.name === column))
19232
19463
  return false;
@@ -19234,8 +19465,8 @@ function addColumnIfMissing26(db, table, column, definition) {
19234
19465
  return true;
19235
19466
  }
19236
19467
  function up310(db) {
19237
- addColumnIfMissing26(db, "memories", "why", "TEXT");
19238
- addColumnIfMissing26(db, "memories", "project", "TEXT");
19468
+ addColumnIfMissing27(db, "memories", "why", "TEXT");
19469
+ addColumnIfMissing27(db, "memories", "project", "TEXT");
19239
19470
  db.exec(`DROP INDEX IF EXISTS idx_memories_content_hash`);
19240
19471
  db.exec(`
19241
19472
  UPDATE memories
@@ -19440,7 +19671,7 @@ function up1010(db) {
19440
19671
  )
19441
19672
  `);
19442
19673
  }
19443
- function up118(db) {
19674
+ function up119(db) {
19444
19675
  db.exec(`
19445
19676
  CREATE TABLE IF NOT EXISTS session_scores (
19446
19677
  id TEXT PRIMARY KEY,
@@ -20661,7 +20892,7 @@ function up492(db) {
20661
20892
  );
20662
20893
  `);
20663
20894
  }
20664
- function hasTable4(db, name) {
20895
+ function hasTable5(db, name) {
20665
20896
  return db.prepare(`SELECT name
20666
20897
  FROM sqlite_master
20667
20898
  WHERE type = 'table' AND name = ?
@@ -20691,7 +20922,7 @@ function up502(db) {
20691
20922
  CREATE INDEX IF NOT EXISTS idx_entity_dependency_history_created
20692
20923
  ON entity_dependency_history(created_at DESC);
20693
20924
  `);
20694
- if (!hasTable4(db, "entity_dependencies"))
20925
+ if (!hasTable5(db, "entity_dependencies"))
20695
20926
  return;
20696
20927
  db.exec("DROP TRIGGER IF EXISTS trg_entity_dependencies_related_to_reason_insert");
20697
20928
  db.exec("DROP TRIGGER IF EXISTS trg_entity_dependencies_related_to_reason_update");
@@ -22593,11 +22824,229 @@ function up1162(db) {
22593
22824
  ON cross_agent_messages(delivery_path, delivery_state, delivery_lease_expires_at, delivery_updated_at);
22594
22825
  `);
22595
22826
  }
22827
+ function hasTable42(db, table) {
22828
+ return db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) != null;
22829
+ }
22830
+ function addColumnIfMissing252(db, table, column, definition) {
22831
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
22832
+ if (columns.some((row) => row.name === column))
22833
+ return;
22834
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
22835
+ }
22836
+ function tableColumns2(db, table) {
22837
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
22838
+ return new Set(rows.map((row) => typeof row.name === "string" ? row.name : ""));
22839
+ }
22840
+ function hashTranscript2(content) {
22841
+ return createHash2("sha256").update(content, "utf8").digest("hex");
22842
+ }
22843
+ function backfillTranscriptHashes2(db) {
22844
+ const columns = tableColumns2(db, "session_transcripts");
22845
+ if (!columns.has("content_hash") || !columns.has("content"))
22846
+ return;
22847
+ const rows = db.prepare("SELECT session_key, agent_id, content FROM session_transcripts WHERE content_hash IS NULL").all();
22848
+ const update = db.prepare("UPDATE session_transcripts SET content_hash = ? WHERE agent_id = ? AND session_key = ? AND content_hash IS NULL");
22849
+ for (const row of rows) {
22850
+ if (typeof row.content !== "string" || typeof row.session_key !== "string")
22851
+ continue;
22852
+ update.run(hashTranscript2(row.content), typeof row.agent_id === "string" ? row.agent_id : "default", row.session_key);
22853
+ }
22854
+ }
22855
+ var COMPLETION_BOUNDARY_REASONS2 = new Set(["session_closed", "session_clear", "stale_session", "ttl_expired"]);
22856
+ function summaryJobTimestamp2(job) {
22857
+ return job.completed_at ?? job.ended_at ?? job.captured_at ?? job.created_at ?? new Date(0).toISOString();
22858
+ }
22859
+ function laterTimestamp2(current, candidate) {
22860
+ if (current === null)
22861
+ return candidate;
22862
+ if (candidate === null)
22863
+ return current;
22864
+ const currentMillis = Date.parse(current);
22865
+ const candidateMillis = Date.parse(candidate);
22866
+ if (Number.isFinite(currentMillis) && Number.isFinite(candidateMillis)) {
22867
+ return candidateMillis > currentMillis ? candidate : current;
22868
+ }
22869
+ return candidate > current ? candidate : current;
22870
+ }
22871
+ function isCompletionBoundary2(job, columns) {
22872
+ return columns.has("trigger") && job.trigger === "session_end" || columns.has("boundary_reason") && COMPLETION_BOUNDARY_REASONS2.has(job.boundary_reason ?? "");
22873
+ }
22874
+ function mergeTranscriptContent2(current, next) {
22875
+ if (current.length === 0)
22876
+ return next;
22877
+ if (next.length === 0 || current === next || current.includes(next))
22878
+ return current;
22879
+ if (next.includes(current))
22880
+ return next;
22881
+ return `${current}
22882
+ ${next}`;
22883
+ }
22884
+ function backfillTranscriptsFromSummaryJobs2(db) {
22885
+ if (!hasTable42(db, "summary_jobs"))
22886
+ return;
22887
+ const summaryColumns = tableColumns2(db, "summary_jobs");
22888
+ if (!summaryColumns.has("transcript"))
22889
+ return;
22890
+ const select = (name) => summaryColumns.has(name) ? `"${name}" AS "${name}"` : `NULL AS "${name}"`;
22891
+ const jobs = db.prepare(`SELECT ${[
22892
+ "id",
22893
+ "session_key",
22894
+ "transcript",
22895
+ "harness",
22896
+ "project",
22897
+ "agent_id",
22898
+ "trigger",
22899
+ "boundary_reason",
22900
+ "captured_at",
22901
+ "ended_at",
22902
+ "completed_at",
22903
+ "created_at"
22904
+ ].map(select).join(", ")} FROM summary_jobs`).all();
22905
+ const candidates = new Map;
22906
+ for (const job of jobs) {
22907
+ if (typeof job.transcript !== "string" || job.transcript.trim().length === 0)
22908
+ continue;
22909
+ const agentId = typeof job.agent_id === "string" && job.agent_id.length > 0 ? job.agent_id : "default";
22910
+ const sessionKey = typeof job.session_key === "string" && job.session_key.trim().length > 0 ? job.session_key : `legacy-summary-job:${job.id ?? hashTranscript2(`${summaryJobTimestamp2(job)}\x00${job.transcript}`)}`;
22911
+ const key = `${agentId}\x00${sessionKey}`;
22912
+ const current = candidates.get(key);
22913
+ const timestamp = summaryJobTimestamp2(job);
22914
+ const boundary = isCompletionBoundary2(job, summaryColumns);
22915
+ const createdAt = job.captured_at ?? job.created_at ?? job.ended_at ?? timestamp;
22916
+ if (!current) {
22917
+ candidates.set(key, {
22918
+ sessionKey,
22919
+ job: { ...job, agent_id: agentId },
22920
+ content: job.transcript,
22921
+ createdAt,
22922
+ completedAt: boundary ? timestamp : null
22923
+ });
22924
+ continue;
22925
+ }
22926
+ const currentTimestamp = summaryJobTimestamp2(current.job);
22927
+ const preferred = timestamp > currentTimestamp || timestamp === currentTimestamp && job.transcript.length > current.content.length ? { ...job, agent_id: agentId } : current.job;
22928
+ candidates.set(key, {
22929
+ sessionKey,
22930
+ job: preferred,
22931
+ content: mergeTranscriptContent2(current.content, job.transcript),
22932
+ createdAt: current.createdAt < createdAt ? current.createdAt : createdAt,
22933
+ completedAt: laterTimestamp2(current.completedAt, boundary ? timestamp : null)
22934
+ });
22935
+ }
22936
+ const transcriptColumns = tableColumns2(db, "session_transcripts");
22937
+ const hasUpdated = transcriptColumns.has("updated_at");
22938
+ const hasCompleted = transcriptColumns.has("completed_at");
22939
+ const hasHash = transcriptColumns.has("content_hash");
22940
+ const insertColumns = ["session_key", "content", "harness", "project", "agent_id", "created_at"];
22941
+ if (hasUpdated)
22942
+ insertColumns.push("updated_at");
22943
+ if (hasCompleted)
22944
+ insertColumns.push("completed_at");
22945
+ if (hasHash)
22946
+ insertColumns.push("content_hash");
22947
+ const insert = db.prepare(`INSERT OR IGNORE INTO session_transcripts (${insertColumns.join(", ")}) VALUES (${insertColumns.map(() => "?").join(", ")})`);
22948
+ const existing = db.prepare("SELECT content, completed_at FROM session_transcripts WHERE agent_id = ? AND session_key = ?");
22949
+ for (const candidate of candidates.values()) {
22950
+ const job = candidate.job;
22951
+ const agentId = job.agent_id ?? "default";
22952
+ const existingRow = existing.get(agentId, candidate.sessionKey);
22953
+ if (existingRow != null) {
22954
+ const previousContent = typeof existingRow.content === "string" ? existingRow.content : "";
22955
+ const mergedContent = mergeTranscriptContent2(previousContent, candidate.content);
22956
+ const completedAt = typeof existingRow.completed_at === "string" && existingRow.completed_at.length > 0 ? existingRow.completed_at : candidate.completedAt;
22957
+ const assignments = ["content = ?"];
22958
+ const values2 = [mergedContent];
22959
+ if (hasUpdated && mergedContent !== previousContent) {
22960
+ assignments.push("updated_at = ?");
22961
+ values2.push(candidate.createdAt);
22962
+ }
22963
+ if (hasCompleted && completedAt && !existingRow.completed_at) {
22964
+ assignments.push("completed_at = ?");
22965
+ values2.push(completedAt);
22966
+ }
22967
+ if (hasHash) {
22968
+ assignments.push("content_hash = ?");
22969
+ values2.push(hashTranscript2(mergedContent));
22970
+ }
22971
+ values2.push(agentId, candidate.sessionKey);
22972
+ db.prepare(`UPDATE session_transcripts SET ${assignments.join(", ")} WHERE agent_id = ? AND session_key = ?`).run(...values2);
22973
+ continue;
22974
+ }
22975
+ const values = [
22976
+ candidate.sessionKey,
22977
+ candidate.content,
22978
+ job.harness ?? null,
22979
+ job.project ?? null,
22980
+ agentId,
22981
+ candidate.createdAt
22982
+ ];
22983
+ if (hasUpdated)
22984
+ values.push(candidate.createdAt);
22985
+ if (hasCompleted)
22986
+ values.push(candidate.completedAt);
22987
+ if (hasHash)
22988
+ values.push(hashTranscript2(candidate.content));
22989
+ insert.run(...values);
22990
+ }
22991
+ }
22992
+ function up1172(db) {
22993
+ if (!hasTable42(db, "session_transcripts"))
22994
+ return;
22995
+ addColumnIfMissing252(db, "session_transcripts", "completed_at", "TEXT");
22996
+ addColumnIfMissing252(db, "session_transcripts", "content_hash", "TEXT");
22997
+ backfillTranscriptHashes2(db);
22998
+ if (hasTable42(db, "transcript_capture_jobs")) {
22999
+ const captureColumns = db.prepare("PRAGMA table_info(transcript_capture_jobs)").all();
23000
+ if (captureColumns.some((row) => row.name === "summary_status")) {
23001
+ db.exec("UPDATE transcript_capture_jobs SET summary_status = 'not_requested' WHERE summary_status IN ('pending', 'failed', 'skipped')");
23002
+ }
23003
+ }
23004
+ if (hasTable42(db, "summary_jobs")) {
23005
+ backfillTranscriptsFromSummaryJobs2(db);
23006
+ backfillTranscriptHashes2(db);
23007
+ const summaryColumns = tableColumns2(db, "summary_jobs");
23008
+ const timestampParts = ["completed_at", "ended_at", "captured_at", "created_at"].filter((column) => summaryColumns.has(column)).map((column) => `sj.${column}`);
23009
+ const timestampValue = timestampParts.length === 1 ? timestampParts[0] : `COALESCE(${timestampParts.join(", ")})`;
23010
+ const completionTimestamp = timestampValue ? `MAX(${timestampValue})` : "NULL";
23011
+ const boundaryParts = [
23012
+ summaryColumns.has("trigger") ? "sj.trigger = 'session_end'" : null,
23013
+ summaryColumns.has("boundary_reason") ? "sj.boundary_reason IN ('session_closed', 'session_clear', 'stale_session', 'ttl_expired')" : null
23014
+ ].filter((part) => part !== null);
23015
+ const boundaryPredicate = boundaryParts.length > 0 ? `(${boundaryParts.join(" OR ")})` : "1=1";
23016
+ const agentPredicate = summaryColumns.has("agent_id") ? "sj.agent_id = session_transcripts.agent_id" : "session_transcripts.agent_id = 'default'";
23017
+ if (completionTimestamp !== "NULL") {
23018
+ db.exec(`
23019
+ UPDATE session_transcripts
23020
+ SET completed_at = COALESCE(
23021
+ completed_at,
23022
+ (
23023
+ SELECT ${completionTimestamp}
23024
+ FROM summary_jobs AS sj
23025
+ WHERE ${agentPredicate}
23026
+ AND sj.session_key = session_transcripts.session_key
23027
+ AND ${boundaryPredicate}
23028
+ )
23029
+ )
23030
+ WHERE completed_at IS NULL;
23031
+ `);
23032
+ }
23033
+ db.exec("DELETE FROM summary_jobs");
23034
+ }
23035
+ const completionIndexColumns = ["agent_id", "completed_at"];
23036
+ if (tableColumns2(db, "session_transcripts").has("updated_at"))
23037
+ completionIndexColumns.push("updated_at");
23038
+ db.exec(`
23039
+ CREATE INDEX IF NOT EXISTS idx_st_agent_completed
23040
+ ON session_transcripts(${completionIndexColumns.join(", ")});
23041
+ CREATE INDEX IF NOT EXISTS idx_st_agent_hash
23042
+ ON session_transcripts(agent_id, content_hash);
23043
+ `);
23044
+ }
22596
23045
  var MIGRATIONS2 = [
22597
23046
  {
22598
23047
  version: 1,
22599
23048
  name: "baseline",
22600
- up: up117,
23049
+ up: up118,
22601
23050
  artifacts: { tables: ["memories", "conversations", "embeddings"] }
22602
23051
  },
22603
23052
  {
@@ -22663,7 +23112,7 @@ var MIGRATIONS2 = [
22663
23112
  {
22664
23113
  version: 11,
22665
23114
  name: "session-scores",
22666
- up: up118,
23115
+ up: up119,
22667
23116
  artifacts: { tables: ["session_scores"] }
22668
23117
  },
22669
23118
  {
@@ -23532,6 +23981,17 @@ var MIGRATIONS2 = [
23532
23981
  { table: "cross_agent_messages", column: "acp_target_agent_name" }
23533
23982
  ]
23534
23983
  }
23984
+ },
23985
+ {
23986
+ version: 117,
23987
+ name: "retire-summary-worker",
23988
+ up: up1172,
23989
+ artifacts: {
23990
+ columns: [
23991
+ { table: "session_transcripts", column: "completed_at" },
23992
+ { table: "session_transcripts", column: "content_hash" }
23993
+ ]
23994
+ }
23535
23995
  }
23536
23996
  ];
23537
23997
  var LATEST_SCHEMA_VERSION2 = MIGRATIONS2[MIGRATIONS2.length - 1]?.version ?? 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signetai/connector-forge",
3
- "version": "0.185.3",
3
+ "version": "0.185.5",
4
4
  "description": "Signet connector for ForgeCode - installs MCP, identity, and skills integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,8 +24,8 @@
24
24
  "typecheck": "tsc --noEmit"
25
25
  },
26
26
  "dependencies": {
27
- "@signetai/connector-base": "0.185.3",
28
- "@signetai/core": "0.185.3"
27
+ "@signetai/connector-base": "0.185.5",
28
+ "@signetai/core": "0.185.5"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.0.0",