@wrongstack/core 0.306.4 → 0.307.0
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/dist/chronicle/index.js +957 -953
- package/dist/chronicle/metrics-ingest.d.ts +55 -0
- package/dist/chronicle/metrics-schema.d.ts +86 -0
- package/dist/chronicle/metrics-store.d.ts +5 -120
- package/dist/chronicle/project-server.js +1083 -1084
- package/dist/chronicle/sqlite-journal-quota.d.ts +39 -0
- package/dist/chronicle/sqlite-journal-schema.d.ts +25 -0
- package/dist/chronicle/sqlite-journal.d.ts +12 -177
- package/dist/coordination/agents/index.js +1738 -1690
- package/dist/coordination/agents/project-agent-capture.d.ts +48 -0
- package/dist/coordination/agents/project-agent-identity.d.ts +3 -129
- package/dist/coordination/agents/project-agent-roster.d.ts +17 -0
- package/dist/coordination/index.js +6011 -5894
- package/dist/coordination/mail-tools.d.ts +1 -1
- package/dist/coordination/mailbox-http-actor-query.d.ts +16 -0
- package/dist/coordination/mailbox-http-router.d.ts +0 -48
- package/dist/coordination/mailbox-http-sse.d.ts +12 -0
- package/dist/coordination/mailbox-message-types.d.ts +71 -0
- package/dist/coordination/mailbox-predicates.d.ts +13 -0
- package/dist/coordination/mailbox-project-server.js +1 -1
- package/dist/coordination/mailbox-session-sync.d.ts +8 -0
- package/dist/coordination/mailbox-types.d.ts +6 -793
- package/dist/core/agent-loop-context.d.ts +28 -0
- package/dist/core/agent-loop-detector.d.ts +25 -0
- package/dist/core/fallback-doctor.d.ts +72 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1159 -888
- package/dist/defaults/index.js +3579 -3545
- package/dist/execution/autonomy-brain-llm.d.ts +55 -0
- package/dist/execution/autonomy-brain.d.ts +3 -156
- package/dist/execution/compaction-budget.d.ts +38 -0
- package/dist/execution/compaction-core.d.ts +3 -170
- package/dist/execution/compaction-elision.d.ts +58 -0
- package/dist/execution/council-orchestrator-helpers.d.ts +39 -0
- package/dist/execution/council-orchestrator.d.ts +3 -42
- package/dist/execution/council-response-parser.d.ts +56 -0
- package/dist/execution/index.js +2415 -2443
- package/dist/execution/prompt-enhancer.js +11 -3
- package/dist/execution/tool-executor-guard.d.ts +18 -0
- package/dist/execution/tool-executor-runner.d.ts +12 -0
- package/dist/execution/tool-executor.d.ts +0 -75
- package/dist/goal/index.js +19 -6
- package/dist/hq/index.js +8 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7813 -7292
- package/dist/infrastructure/index.js +3 -1
- package/dist/kernel/events/agent-events.d.ts +2 -0
- package/dist/kernel/events/provider-events.d.ts +13 -0
- package/dist/plugin/index.js +2590 -2561
- package/dist/plugins/auto-review-config.d.ts +53 -0
- package/dist/plugins/auto-review-git.d.ts +19 -0
- package/dist/plugins/auto-review-plugin.d.ts +2 -140
- package/dist/plugins/review-finding-verification.d.ts +7 -0
- package/dist/prompts/index.d.ts +1 -0
- package/dist/prompts/prompt-journal.d.ts +94 -0
- package/dist/security/index.js +627 -652
- package/dist/security/permission-explain.d.ts +19 -0
- package/dist/security/permission-policy.d.ts +0 -101
- package/dist/security/yolo-risk.d.ts +5 -4
- package/dist/session-catalog/index.js +220 -212
- package/dist/session-catalog/project-server.js +227 -219
- package/dist/session-catalog/store-rebuild.d.ts +9 -0
- package/dist/session-catalog/store-schema.d.ts +48 -0
- package/dist/session-catalog/store.d.ts +0 -17
- package/dist/storage/director-state.d.ts +6 -0
- package/dist/storage/file-session-writer.d.ts +2 -58
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +2057 -1925
- package/dist/storage/orphan-lock-cleaner.d.ts +15 -0
- package/dist/storage/session-recovery.d.ts +9 -0
- package/dist/storage/session-store/rename-session.d.ts +16 -0
- package/dist/storage/session-store/resume-session.d.ts +26 -0
- package/dist/storage/session-store/session-store-clear.d.ts +11 -0
- package/dist/storage/session-store/session-store-index.d.ts +13 -0
- package/dist/storage/session-store.d.ts +1 -129
- package/dist/storage/session-summary-tracker.d.ts +39 -0
- package/dist/storage/session-write-buffer.d.ts +43 -0
- package/dist/storage/session-writer/session-writer-flush.d.ts +4 -0
- package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +28 -0
- package/dist/tools/fallback-agent-model-assign-tool.d.ts +18 -0
- package/dist/tools/fallback-leader-model-set-tool.d.ts +18 -0
- package/dist/tools/fallback-manage-tools.d.ts +8 -45
- package/dist/tools/fallback-profile-manage-tool.d.ts +16 -0
- package/dist/tools/fallback-provider-key-set-tool.d.ts +17 -0
- package/dist/tools/fallback-provider-manage-tool.d.ts +26 -0
- package/dist/tools/index.js +5070 -5071
- package/dist/types/config/root.d.ts +7 -2
- package/dist/types/default-config.d.ts +1 -1
- package/dist/types/index.d.ts +54 -55
- package/dist/types/index.js +953 -932
- package/dist/types/runtime-capability-manifest.d.ts +5 -5
- package/dist/types/session-markers.d.ts +12 -0
- package/dist/types/session-markers.js +19 -0
- package/dist/worktree/worktree-manager.d.ts +1 -1
- package/instructions/coordination/subagent-baseline.md +2 -2
- package/instructions/llm/prompt-enhancer.md +2 -1
- package/instructions/sections/tool/common-patterns.md +21 -0
- package/instructions/sections/tool/delegation-compact.md +3 -1
- package/instructions/sections/tool/delegation-full.md +5 -1
- package/instructions/system-lite.md +28 -3
- package/instructions/system-pro.md +37 -8
- package/instructions/system.md +4 -2
- package/package.json +5 -5
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { randomBytes as randomBytes2, randomUUID as randomUUID2 } from "node:crypto";
|
|
5
5
|
import * as fsp from "node:fs/promises";
|
|
6
6
|
import * as net from "node:net";
|
|
7
|
-
import * as
|
|
7
|
+
import * as path4 from "node:path";
|
|
8
8
|
import { bindProjectEndpoint } from "@wrongstack/persistence";
|
|
9
9
|
|
|
10
10
|
// src/security/file-permissions.ts
|
|
@@ -179,9 +179,9 @@ function sessionCatalogProjectServerMetadataPath(projectDir) {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// src/session-catalog/store.ts
|
|
182
|
-
import {
|
|
183
|
-
import * as
|
|
184
|
-
import * as
|
|
182
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
183
|
+
import * as fs2 from "node:fs";
|
|
184
|
+
import * as path3 from "node:path";
|
|
185
185
|
|
|
186
186
|
// src/coordination/sqlite-mailbox-schema.ts
|
|
187
187
|
import { createRequire } from "node:module";
|
|
@@ -556,6 +556,10 @@ function isPidAlive(pid) {
|
|
|
556
556
|
}
|
|
557
557
|
}
|
|
558
558
|
|
|
559
|
+
// src/session-catalog/store-rebuild.ts
|
|
560
|
+
import * as fs from "node:fs";
|
|
561
|
+
import * as path2 from "node:path";
|
|
562
|
+
|
|
559
563
|
// src/utils/session-scoped-path.ts
|
|
560
564
|
var SESSION_SIDECAR_JSONL_SUFFIXES = [
|
|
561
565
|
".replay.jsonl",
|
|
@@ -572,7 +576,8 @@ function isSessionTranscriptFileName(name) {
|
|
|
572
576
|
return !SESSION_SIDECAR_JSONL_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
573
577
|
}
|
|
574
578
|
|
|
575
|
-
// src/session-catalog/store.ts
|
|
579
|
+
// src/session-catalog/store-schema.ts
|
|
580
|
+
import { createHash as createHash2, timingSafeEqual } from "node:crypto";
|
|
576
581
|
var SCHEMA_VERSION = 1;
|
|
577
582
|
var MAX_LEASE_MS = 12e4;
|
|
578
583
|
var MAX_RESERVATION_MS = 6e4;
|
|
@@ -617,12 +622,192 @@ function boundPresenceValue(value, depth) {
|
|
|
617
622
|
}
|
|
618
623
|
return result;
|
|
619
624
|
}
|
|
625
|
+
function configureCatalogDatabase(db) {
|
|
626
|
+
db.exec(
|
|
627
|
+
"PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON; PRAGMA busy_timeout=5000; PRAGMA synchronous=NORMAL;"
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
function initializeCatalogSchema(db) {
|
|
631
|
+
db.exec(`
|
|
632
|
+
CREATE TABLE IF NOT EXISTS catalog_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
633
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
634
|
+
session_id TEXT PRIMARY KEY,
|
|
635
|
+
transcript_relative_path TEXT NOT NULL,
|
|
636
|
+
summary_relative_path TEXT NOT NULL,
|
|
637
|
+
summary_json TEXT NOT NULL,
|
|
638
|
+
transcript_size INTEGER NOT NULL DEFAULT 0,
|
|
639
|
+
transcript_mtime_ms REAL NOT NULL DEFAULT 0,
|
|
640
|
+
summary_revision INTEGER NOT NULL DEFAULT 1,
|
|
641
|
+
indexed_at TEXT NOT NULL,
|
|
642
|
+
damaged INTEGER NOT NULL DEFAULT 0
|
|
643
|
+
);
|
|
644
|
+
CREATE TABLE IF NOT EXISTS session_leases (
|
|
645
|
+
session_id TEXT PRIMARY KEY,
|
|
646
|
+
lease_id TEXT NOT NULL UNIQUE,
|
|
647
|
+
lease_secret_hash TEXT NOT NULL,
|
|
648
|
+
owner_instance_id TEXT NOT NULL,
|
|
649
|
+
owner_pid INTEGER NOT NULL,
|
|
650
|
+
owner_started_at TEXT NOT NULL,
|
|
651
|
+
entry_json TEXT NOT NULL,
|
|
652
|
+
agent_revision INTEGER NOT NULL DEFAULT 0,
|
|
653
|
+
status TEXT NOT NULL,
|
|
654
|
+
last_heartbeat_at INTEGER NOT NULL,
|
|
655
|
+
lease_expires_at INTEGER NOT NULL
|
|
656
|
+
);
|
|
657
|
+
CREATE TABLE IF NOT EXISTS resume_reservations (
|
|
658
|
+
reservation_id TEXT PRIMARY KEY,
|
|
659
|
+
target_session_id TEXT NOT NULL UNIQUE,
|
|
660
|
+
requester_instance_id TEXT NOT NULL,
|
|
661
|
+
current_session_id TEXT,
|
|
662
|
+
created_at INTEGER NOT NULL,
|
|
663
|
+
expires_at INTEGER NOT NULL
|
|
664
|
+
);
|
|
665
|
+
CREATE TABLE IF NOT EXISTS maintenance_leases (
|
|
666
|
+
session_id TEXT PRIMARY KEY,
|
|
667
|
+
operation TEXT NOT NULL,
|
|
668
|
+
holder_id TEXT NOT NULL,
|
|
669
|
+
lease_id TEXT NOT NULL UNIQUE,
|
|
670
|
+
acquired_at INTEGER NOT NULL,
|
|
671
|
+
expires_at INTEGER NOT NULL
|
|
672
|
+
);
|
|
673
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_activity ON sessions(indexed_at DESC);
|
|
674
|
+
CREATE INDEX IF NOT EXISTS idx_leases_expiry ON session_leases(lease_expires_at);
|
|
675
|
+
CREATE INDEX IF NOT EXISTS idx_reservations_expiry ON resume_reservations(expires_at);
|
|
676
|
+
CREATE INDEX IF NOT EXISTS idx_maintenance_expiry ON maintenance_leases(expires_at);
|
|
677
|
+
`);
|
|
678
|
+
db.prepare("INSERT INTO catalog_meta(key,value) VALUES (?,?) ON CONFLICT(key) DO NOTHING").run("schema_version", String(SCHEMA_VERSION));
|
|
679
|
+
db.prepare("INSERT INTO catalog_meta(key,value) VALUES (?,?) ON CONFLICT(key) DO NOTHING").run("generation", "0");
|
|
680
|
+
const row = db.prepare("SELECT value FROM catalog_meta WHERE key=?").get("schema_version");
|
|
681
|
+
if (Number(row.value) !== SCHEMA_VERSION)
|
|
682
|
+
throw new Error(`Unsupported session catalog schema ${row.value}`);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/session-catalog/store-rebuild.ts
|
|
686
|
+
function walkSessionFiles(root, suffix) {
|
|
687
|
+
const result = [];
|
|
688
|
+
const visit = (dir) => {
|
|
689
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
690
|
+
if (entry.isDirectory()) {
|
|
691
|
+
if (entry.name !== "_cas" && entry.name !== "_trash") visit(path2.join(dir, entry.name));
|
|
692
|
+
} else if (entry.isFile() && entry.name.endsWith(suffix))
|
|
693
|
+
result.push(path2.join(dir, entry.name));
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
visit(root);
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
699
|
+
function summarizeTranscriptFile(transcriptFilePath, id) {
|
|
700
|
+
const lines = fs.readFileSync(transcriptFilePath, "utf8").split(/\r?\n/);
|
|
701
|
+
let start;
|
|
702
|
+
let endedAt;
|
|
703
|
+
let lastActivityAt;
|
|
704
|
+
let messageCount = 0;
|
|
705
|
+
let iterationCount = 0;
|
|
706
|
+
let toolCallCount = 0;
|
|
707
|
+
let compactionCount = 0;
|
|
708
|
+
let tokenTotal = 0;
|
|
709
|
+
for (const line of lines) {
|
|
710
|
+
if (!line) continue;
|
|
711
|
+
let event;
|
|
712
|
+
try {
|
|
713
|
+
event = parseJson(line);
|
|
714
|
+
} catch {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
lastActivityAt = event.ts;
|
|
718
|
+
if (event.type === "session_start") start = event;
|
|
719
|
+
if (event.type === "session_end") endedAt = event.ts;
|
|
720
|
+
if (event.type === "message_appended" && (event.message.role === "user" || event.message.role === "assistant"))
|
|
721
|
+
messageCount++;
|
|
722
|
+
if (event.type === "llm_response") {
|
|
723
|
+
iterationCount++;
|
|
724
|
+
tokenTotal += event.usage.input + event.usage.output + (event.usage.cacheRead ?? 0) + (event.usage.cacheWrite ?? 0);
|
|
725
|
+
}
|
|
726
|
+
if (event.type === "tool_call_end") toolCallCount++;
|
|
727
|
+
if (event.type === "compaction") compactionCount++;
|
|
728
|
+
}
|
|
729
|
+
if (!start) throw new Error("missing session_start");
|
|
730
|
+
return {
|
|
731
|
+
id,
|
|
732
|
+
title: id,
|
|
733
|
+
startedAt: start.ts,
|
|
734
|
+
...endedAt ? { endedAt } : {},
|
|
735
|
+
model: start.model,
|
|
736
|
+
provider: start.provider,
|
|
737
|
+
tokenTotal,
|
|
738
|
+
...lastActivityAt ? { lastActivityAt } : {},
|
|
739
|
+
messageCount,
|
|
740
|
+
iterationCount,
|
|
741
|
+
toolCallCount,
|
|
742
|
+
compactionCount
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
function rebuildCatalogIndex(db, sessionsDir, containedPathFn, transactionFn, bumpGenerationFn) {
|
|
746
|
+
const summaries = walkSessionFiles(sessionsDir, ".summary.json");
|
|
747
|
+
const transcripts = walkSessionFiles(sessionsDir, ".jsonl").filter(
|
|
748
|
+
(file) => isSessionTranscriptFileName(path2.basename(file))
|
|
749
|
+
);
|
|
750
|
+
const ids = /* @__PURE__ */ new Set();
|
|
751
|
+
for (const file of [...summaries, ...transcripts]) {
|
|
752
|
+
const relative3 = path2.relative(sessionsDir, file).replaceAll("\\", "/");
|
|
753
|
+
ids.add(relative3.replace(/\.summary\.json$|\.jsonl$/, ""));
|
|
754
|
+
}
|
|
755
|
+
let indexed = 0;
|
|
756
|
+
let damaged = 0;
|
|
757
|
+
transactionFn(() => {
|
|
758
|
+
db.prepare("DELETE FROM sessions").run();
|
|
759
|
+
for (const id of ids) {
|
|
760
|
+
try {
|
|
761
|
+
const summaryFile = containedPathFn(`${id}.summary.json`);
|
|
762
|
+
const summary = fs.existsSync(summaryFile) ? parseJson(fs.readFileSync(summaryFile, "utf8")) : summarizeTranscriptFile(containedPathFn(`${id}.jsonl`), id);
|
|
763
|
+
if (!summary || summary.id !== id) throw new Error("summary identity mismatch");
|
|
764
|
+
const transcript = containedPathFn(`${id}.jsonl`);
|
|
765
|
+
const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
|
|
766
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
767
|
+
db.prepare(
|
|
768
|
+
"INSERT INTO sessions(session_id,transcript_relative_path,summary_relative_path,summary_json,transcript_size,transcript_mtime_ms,summary_revision,indexed_at,damaged) VALUES (?,?,?,?,?,?,?,?,0)"
|
|
769
|
+
).run(
|
|
770
|
+
id,
|
|
771
|
+
`${id}.jsonl`,
|
|
772
|
+
`${id}.summary.json`,
|
|
773
|
+
JSON.stringify(summary),
|
|
774
|
+
stat?.size ?? 0,
|
|
775
|
+
stat?.mtimeMs ?? 0,
|
|
776
|
+
1,
|
|
777
|
+
now
|
|
778
|
+
);
|
|
779
|
+
indexed++;
|
|
780
|
+
} catch {
|
|
781
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
782
|
+
const fallback = {
|
|
783
|
+
id,
|
|
784
|
+
title: id,
|
|
785
|
+
startedAt: now,
|
|
786
|
+
model: "",
|
|
787
|
+
provider: "",
|
|
788
|
+
tokenTotal: 0
|
|
789
|
+
};
|
|
790
|
+
db.prepare(
|
|
791
|
+
"INSERT INTO sessions(session_id,transcript_relative_path,summary_relative_path,summary_json,summary_revision,indexed_at,damaged) VALUES (?,?,?,?,1,?,1)"
|
|
792
|
+
).run(id, `${id}.jsonl`, `${id}.summary.json`, JSON.stringify(fallback), now);
|
|
793
|
+
damaged++;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
db.prepare(
|
|
797
|
+
"INSERT INTO catalog_meta(key,value) VALUES ('last_reconciliation',?) ON CONFLICT(key) DO UPDATE SET value=excluded.value"
|
|
798
|
+
).run((/* @__PURE__ */ new Date()).toISOString());
|
|
799
|
+
bumpGenerationFn();
|
|
800
|
+
});
|
|
801
|
+
return { indexed, damaged };
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// src/session-catalog/store.ts
|
|
620
805
|
var SessionCatalogStore = class {
|
|
621
806
|
constructor(projectDir) {
|
|
622
807
|
this.projectDir = projectDir;
|
|
623
|
-
this.sessionsDir =
|
|
624
|
-
|
|
625
|
-
this.databasePath =
|
|
808
|
+
this.sessionsDir = path3.join(projectDir, "sessions");
|
|
809
|
+
fs2.mkdirSync(this.sessionsDir, { recursive: true, mode: 448 });
|
|
810
|
+
this.databasePath = path3.join(this.sessionsDir, "catalog.sqlite");
|
|
626
811
|
const Database = loadDatabaseSync();
|
|
627
812
|
this.db = new Database(this.databasePath);
|
|
628
813
|
try {
|
|
@@ -639,12 +824,12 @@ var SessionCatalogStore = class {
|
|
|
639
824
|
this.db.close();
|
|
640
825
|
const quarantine = `${this.databasePath}.corrupt-${Date.now()}`;
|
|
641
826
|
try {
|
|
642
|
-
|
|
827
|
+
fs2.renameSync(this.databasePath, quarantine);
|
|
643
828
|
} catch {
|
|
644
829
|
}
|
|
645
830
|
for (const suffix of ["-wal", "-shm"]) {
|
|
646
831
|
try {
|
|
647
|
-
|
|
832
|
+
fs2.renameSync(`${this.databasePath}${suffix}`, `${quarantine}${suffix}`);
|
|
648
833
|
} catch {
|
|
649
834
|
}
|
|
650
835
|
}
|
|
@@ -656,7 +841,7 @@ var SessionCatalogStore = class {
|
|
|
656
841
|
const rowCount = Number(
|
|
657
842
|
this.db.prepare("SELECT COUNT(*) AS count FROM sessions").get().count
|
|
658
843
|
);
|
|
659
|
-
if (rowCount === 0 &&
|
|
844
|
+
if (rowCount === 0 && walkSessionFiles(this.sessionsDir, ".jsonl").some((file) => !file.endsWith("_index.jsonl"))) {
|
|
660
845
|
this.rebuildCatalog();
|
|
661
846
|
}
|
|
662
847
|
}
|
|
@@ -666,66 +851,13 @@ var SessionCatalogStore = class {
|
|
|
666
851
|
db;
|
|
667
852
|
scrubber = new DefaultSecretScrubber();
|
|
668
853
|
configureDatabase() {
|
|
669
|
-
this.db
|
|
670
|
-
"PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON; PRAGMA busy_timeout=5000; PRAGMA synchronous=NORMAL;"
|
|
671
|
-
);
|
|
854
|
+
configureCatalogDatabase(this.db);
|
|
672
855
|
}
|
|
673
856
|
close() {
|
|
674
857
|
this.db.close();
|
|
675
858
|
}
|
|
676
859
|
initialize() {
|
|
677
|
-
this.db
|
|
678
|
-
CREATE TABLE IF NOT EXISTS catalog_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
679
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
680
|
-
session_id TEXT PRIMARY KEY,
|
|
681
|
-
transcript_relative_path TEXT NOT NULL,
|
|
682
|
-
summary_relative_path TEXT NOT NULL,
|
|
683
|
-
summary_json TEXT NOT NULL,
|
|
684
|
-
transcript_size INTEGER NOT NULL DEFAULT 0,
|
|
685
|
-
transcript_mtime_ms REAL NOT NULL DEFAULT 0,
|
|
686
|
-
summary_revision INTEGER NOT NULL DEFAULT 1,
|
|
687
|
-
indexed_at TEXT NOT NULL,
|
|
688
|
-
damaged INTEGER NOT NULL DEFAULT 0
|
|
689
|
-
);
|
|
690
|
-
CREATE TABLE IF NOT EXISTS session_leases (
|
|
691
|
-
session_id TEXT PRIMARY KEY,
|
|
692
|
-
lease_id TEXT NOT NULL UNIQUE,
|
|
693
|
-
lease_secret_hash TEXT NOT NULL,
|
|
694
|
-
owner_instance_id TEXT NOT NULL,
|
|
695
|
-
owner_pid INTEGER NOT NULL,
|
|
696
|
-
owner_started_at TEXT NOT NULL,
|
|
697
|
-
entry_json TEXT NOT NULL,
|
|
698
|
-
agent_revision INTEGER NOT NULL DEFAULT 0,
|
|
699
|
-
status TEXT NOT NULL,
|
|
700
|
-
last_heartbeat_at INTEGER NOT NULL,
|
|
701
|
-
lease_expires_at INTEGER NOT NULL
|
|
702
|
-
);
|
|
703
|
-
CREATE TABLE IF NOT EXISTS resume_reservations (
|
|
704
|
-
reservation_id TEXT PRIMARY KEY,
|
|
705
|
-
target_session_id TEXT NOT NULL UNIQUE,
|
|
706
|
-
requester_instance_id TEXT NOT NULL,
|
|
707
|
-
current_session_id TEXT,
|
|
708
|
-
created_at INTEGER NOT NULL,
|
|
709
|
-
expires_at INTEGER NOT NULL
|
|
710
|
-
);
|
|
711
|
-
CREATE TABLE IF NOT EXISTS maintenance_leases (
|
|
712
|
-
session_id TEXT PRIMARY KEY,
|
|
713
|
-
operation TEXT NOT NULL,
|
|
714
|
-
holder_id TEXT NOT NULL,
|
|
715
|
-
lease_id TEXT NOT NULL UNIQUE,
|
|
716
|
-
acquired_at INTEGER NOT NULL,
|
|
717
|
-
expires_at INTEGER NOT NULL
|
|
718
|
-
);
|
|
719
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_activity ON sessions(indexed_at DESC);
|
|
720
|
-
CREATE INDEX IF NOT EXISTS idx_leases_expiry ON session_leases(lease_expires_at);
|
|
721
|
-
CREATE INDEX IF NOT EXISTS idx_reservations_expiry ON resume_reservations(expires_at);
|
|
722
|
-
CREATE INDEX IF NOT EXISTS idx_maintenance_expiry ON maintenance_leases(expires_at);
|
|
723
|
-
`);
|
|
724
|
-
this.db.prepare("INSERT INTO catalog_meta(key,value) VALUES (?,?) ON CONFLICT(key) DO NOTHING").run("schema_version", String(SCHEMA_VERSION));
|
|
725
|
-
this.db.prepare("INSERT INTO catalog_meta(key,value) VALUES (?,?) ON CONFLICT(key) DO NOTHING").run("generation", "0");
|
|
726
|
-
const row = this.db.prepare("SELECT value FROM catalog_meta WHERE key=?").get("schema_version");
|
|
727
|
-
if (Number(row.value) !== SCHEMA_VERSION)
|
|
728
|
-
throw new Error(`Unsupported session catalog schema ${row.value}`);
|
|
860
|
+
initializeCatalogSchema(this.db);
|
|
729
861
|
}
|
|
730
862
|
transaction(run) {
|
|
731
863
|
this.db.exec("BEGIN IMMEDIATE");
|
|
@@ -766,21 +898,6 @@ var SessionCatalogStore = class {
|
|
|
766
898
|
leaseRow(sessionId) {
|
|
767
899
|
return this.db.prepare("SELECT * FROM session_leases WHERE session_id=?").get(sessionId);
|
|
768
900
|
}
|
|
769
|
-
/**
|
|
770
|
-
* True when `sessionId` has a live `session_leases` row owned by a
|
|
771
|
-
* different OS process than the *caller*. Used by
|
|
772
|
-
* `acquireMaintenance` to distinguish "another running wstack" (which
|
|
773
|
-
* must be fenced off) from "this very TUI owning its own session"
|
|
774
|
-
* (which is allowed to claim a non-destructive maintenance lease on
|
|
775
|
-
* its own transcript).
|
|
776
|
-
*
|
|
777
|
-
* `callerPid` must be the pid of the process that asked for the lease,
|
|
778
|
-
* NOT `process.pid`. In the built runtime this store lives inside the
|
|
779
|
-
* detached project-catalog daemon, so `process.pid` is the daemon's and
|
|
780
|
-
* would mark every lease — including the caller's own session — foreign,
|
|
781
|
-
* making `/clear` and `/rewind` fail with "Session … is live". Callers
|
|
782
|
-
* that run the store in-process may omit it.
|
|
783
|
-
*/
|
|
784
901
|
foreignLiveLease(sessionId, callerPid = process.pid) {
|
|
785
902
|
const live = this.leaseRow(sessionId);
|
|
786
903
|
return Boolean(live) && live.owner_pid !== callerPid;
|
|
@@ -870,7 +987,7 @@ var SessionCatalogStore = class {
|
|
|
870
987
|
if (this.maintenanceExists(targetSessionId))
|
|
871
988
|
throw conflict(`Session ${targetSessionId} is under maintenance`);
|
|
872
989
|
const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
|
|
873
|
-
if (!catalog && !
|
|
990
|
+
if (!catalog && !fs2.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
|
|
874
991
|
throw new Error(`Session not found: ${targetSessionId}`);
|
|
875
992
|
const reservationId = randomUUID();
|
|
876
993
|
const now = Date.now();
|
|
@@ -998,9 +1115,9 @@ var SessionCatalogStore = class {
|
|
|
998
1115
|
}
|
|
999
1116
|
containedPath(relative3) {
|
|
1000
1117
|
assertId(relative3.replace(/\.(jsonl|summary\.json)$/, ""), "session path");
|
|
1001
|
-
const root =
|
|
1002
|
-
const candidate =
|
|
1003
|
-
const prefix = `${root}${
|
|
1118
|
+
const root = path3.resolve(this.sessionsDir);
|
|
1119
|
+
const candidate = path3.resolve(root, relative3);
|
|
1120
|
+
const prefix = `${root}${path3.sep}`;
|
|
1004
1121
|
if (candidate !== root && !(process.platform === "win32" ? candidate.toLowerCase().startsWith(prefix.toLowerCase()) : candidate.startsWith(prefix)))
|
|
1005
1122
|
throw new TypeError("Session path escapes sessions directory");
|
|
1006
1123
|
return candidate;
|
|
@@ -1016,7 +1133,7 @@ var SessionCatalogStore = class {
|
|
|
1016
1133
|
transcriptRelativePath = normalizedTranscript;
|
|
1017
1134
|
summaryRelativePath = normalizedSummary;
|
|
1018
1135
|
const transcript = this.containedPath(transcriptRelativePath);
|
|
1019
|
-
const stat =
|
|
1136
|
+
const stat = fs2.existsSync(transcript) ? fs2.statSync(transcript) : void 0;
|
|
1020
1137
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1021
1138
|
return this.transaction(() => {
|
|
1022
1139
|
const prior = this.db.prepare("SELECT summary_revision FROM sessions WHERE session_id=?").get(summary.id);
|
|
@@ -1139,7 +1256,7 @@ var SessionCatalogStore = class {
|
|
|
1139
1256
|
if (trimmed) summary.name = this.scrubber.scrub(trimmed).slice(0, 500);
|
|
1140
1257
|
else delete summary.name;
|
|
1141
1258
|
const summaryPath = this.containedPath(current.summaryRelativePath);
|
|
1142
|
-
|
|
1259
|
+
fs2.mkdirSync(path3.dirname(summaryPath), { recursive: true, mode: 448 });
|
|
1143
1260
|
await atomicWrite(summaryPath, `${JSON.stringify(summary)}
|
|
1144
1261
|
`, { mode: 384 });
|
|
1145
1262
|
try {
|
|
@@ -1199,16 +1316,16 @@ var SessionCatalogStore = class {
|
|
|
1199
1316
|
this.containedPath(`${sessionId}.plan.json`),
|
|
1200
1317
|
this.containedPath(`${sessionId}.tasks.json`),
|
|
1201
1318
|
this.containedPath(`${sessionId}.todos.json`),
|
|
1202
|
-
|
|
1319
|
+
path3.join(path3.dirname(transcript), path3.basename(sessionId))
|
|
1203
1320
|
];
|
|
1204
|
-
const trashRoot =
|
|
1205
|
-
|
|
1321
|
+
const trashRoot = path3.join(this.sessionsDir, "_trash", lease.leaseId);
|
|
1322
|
+
fs2.mkdirSync(trashRoot, { recursive: true, mode: 448 });
|
|
1206
1323
|
const moved = [];
|
|
1207
1324
|
try {
|
|
1208
1325
|
artifacts.forEach((artifact, index) => {
|
|
1209
|
-
if (!
|
|
1210
|
-
const target =
|
|
1211
|
-
|
|
1326
|
+
if (!fs2.existsSync(artifact)) return;
|
|
1327
|
+
const target = path3.join(trashRoot, `${index}-${path3.basename(artifact)}`);
|
|
1328
|
+
fs2.renameSync(artifact, target);
|
|
1212
1329
|
moved.push({ from: artifact, to: target });
|
|
1213
1330
|
});
|
|
1214
1331
|
this.transaction(() => {
|
|
@@ -1223,17 +1340,17 @@ var SessionCatalogStore = class {
|
|
|
1223
1340
|
} catch (error) {
|
|
1224
1341
|
for (const item of moved.reverse()) {
|
|
1225
1342
|
try {
|
|
1226
|
-
|
|
1227
|
-
|
|
1343
|
+
fs2.mkdirSync(path3.dirname(item.from), { recursive: true, mode: 448 });
|
|
1344
|
+
fs2.renameSync(item.to, item.from);
|
|
1228
1345
|
} catch {
|
|
1229
1346
|
}
|
|
1230
1347
|
}
|
|
1231
1348
|
throw error;
|
|
1232
1349
|
}
|
|
1233
1350
|
try {
|
|
1234
|
-
|
|
1235
|
-
const trashParent =
|
|
1236
|
-
if (
|
|
1351
|
+
fs2.rmSync(trashRoot, { recursive: true, force: true });
|
|
1352
|
+
const trashParent = path3.dirname(trashRoot);
|
|
1353
|
+
if (fs2.readdirSync(trashParent).length === 0) fs2.rmdirSync(trashParent);
|
|
1237
1354
|
} catch {
|
|
1238
1355
|
}
|
|
1239
1356
|
}
|
|
@@ -1254,122 +1371,13 @@ var SessionCatalogStore = class {
|
|
|
1254
1371
|
return deleted;
|
|
1255
1372
|
}
|
|
1256
1373
|
rebuildCatalog() {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1374
|
+
return rebuildCatalogIndex(
|
|
1375
|
+
this.db,
|
|
1376
|
+
this.sessionsDir,
|
|
1377
|
+
(rel) => this.containedPath(rel),
|
|
1378
|
+
(run) => this.transaction(run),
|
|
1379
|
+
() => this.bumpGeneration()
|
|
1260
1380
|
);
|
|
1261
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1262
|
-
for (const file of [...summaries, ...transcripts]) {
|
|
1263
|
-
const relative3 = path2.relative(this.sessionsDir, file).replaceAll("\\", "/");
|
|
1264
|
-
ids.add(relative3.replace(/\.summary\.json$|\.jsonl$/, ""));
|
|
1265
|
-
}
|
|
1266
|
-
let indexed = 0;
|
|
1267
|
-
let damaged = 0;
|
|
1268
|
-
this.transaction(() => {
|
|
1269
|
-
this.db.prepare("DELETE FROM sessions").run();
|
|
1270
|
-
for (const id of ids) {
|
|
1271
|
-
try {
|
|
1272
|
-
const summaryFile = this.containedPath(`${id}.summary.json`);
|
|
1273
|
-
const summary = fs.existsSync(summaryFile) ? parseJson(fs.readFileSync(summaryFile, "utf8")) : this.summarizeTranscript(id);
|
|
1274
|
-
if (!summary || summary.id !== id) throw new Error("summary identity mismatch");
|
|
1275
|
-
const transcript = this.containedPath(`${id}.jsonl`);
|
|
1276
|
-
const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
|
|
1277
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1278
|
-
this.db.prepare(
|
|
1279
|
-
"INSERT INTO sessions(session_id,transcript_relative_path,summary_relative_path,summary_json,transcript_size,transcript_mtime_ms,summary_revision,indexed_at,damaged) VALUES (?,?,?,?,?,?,?,?,0)"
|
|
1280
|
-
).run(
|
|
1281
|
-
id,
|
|
1282
|
-
`${id}.jsonl`,
|
|
1283
|
-
`${id}.summary.json`,
|
|
1284
|
-
JSON.stringify(summary),
|
|
1285
|
-
stat?.size ?? 0,
|
|
1286
|
-
stat?.mtimeMs ?? 0,
|
|
1287
|
-
1,
|
|
1288
|
-
now
|
|
1289
|
-
);
|
|
1290
|
-
indexed++;
|
|
1291
|
-
} catch {
|
|
1292
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1293
|
-
const fallback = {
|
|
1294
|
-
id,
|
|
1295
|
-
title: id,
|
|
1296
|
-
startedAt: now,
|
|
1297
|
-
model: "",
|
|
1298
|
-
provider: "",
|
|
1299
|
-
tokenTotal: 0
|
|
1300
|
-
};
|
|
1301
|
-
this.db.prepare(
|
|
1302
|
-
"INSERT INTO sessions(session_id,transcript_relative_path,summary_relative_path,summary_json,summary_revision,indexed_at,damaged) VALUES (?,?,?,?,1,?,1)"
|
|
1303
|
-
).run(id, `${id}.jsonl`, `${id}.summary.json`, JSON.stringify(fallback), now);
|
|
1304
|
-
damaged++;
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
this.db.prepare(
|
|
1308
|
-
"INSERT INTO catalog_meta(key,value) VALUES ('last_reconciliation',?) ON CONFLICT(key) DO UPDATE SET value=excluded.value"
|
|
1309
|
-
).run((/* @__PURE__ */ new Date()).toISOString());
|
|
1310
|
-
this.bumpGeneration();
|
|
1311
|
-
});
|
|
1312
|
-
return { indexed, damaged };
|
|
1313
|
-
}
|
|
1314
|
-
walkFiles(root, suffix) {
|
|
1315
|
-
const result = [];
|
|
1316
|
-
const visit = (dir) => {
|
|
1317
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
1318
|
-
if (entry.isDirectory()) {
|
|
1319
|
-
if (entry.name !== "_cas" && entry.name !== "_trash") visit(path2.join(dir, entry.name));
|
|
1320
|
-
} else if (entry.isFile() && entry.name.endsWith(suffix))
|
|
1321
|
-
result.push(path2.join(dir, entry.name));
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
visit(root);
|
|
1325
|
-
return result;
|
|
1326
|
-
}
|
|
1327
|
-
summarizeTranscript(id) {
|
|
1328
|
-
const file = this.containedPath(`${id}.jsonl`);
|
|
1329
|
-
const lines = fs.readFileSync(file, "utf8").split(/\r?\n/);
|
|
1330
|
-
let start;
|
|
1331
|
-
let endedAt;
|
|
1332
|
-
let lastActivityAt;
|
|
1333
|
-
let messageCount = 0;
|
|
1334
|
-
let iterationCount = 0;
|
|
1335
|
-
let toolCallCount = 0;
|
|
1336
|
-
let compactionCount = 0;
|
|
1337
|
-
let tokenTotal = 0;
|
|
1338
|
-
for (const line of lines) {
|
|
1339
|
-
if (!line) continue;
|
|
1340
|
-
let event;
|
|
1341
|
-
try {
|
|
1342
|
-
event = parseJson(line);
|
|
1343
|
-
} catch {
|
|
1344
|
-
continue;
|
|
1345
|
-
}
|
|
1346
|
-
lastActivityAt = event.ts;
|
|
1347
|
-
if (event.type === "session_start") start = event;
|
|
1348
|
-
if (event.type === "session_end") endedAt = event.ts;
|
|
1349
|
-
if (event.type === "message_appended" && (event.message.role === "user" || event.message.role === "assistant"))
|
|
1350
|
-
messageCount++;
|
|
1351
|
-
if (event.type === "llm_response") {
|
|
1352
|
-
iterationCount++;
|
|
1353
|
-
tokenTotal += event.usage.input + event.usage.output + (event.usage.cacheRead ?? 0) + (event.usage.cacheWrite ?? 0);
|
|
1354
|
-
}
|
|
1355
|
-
if (event.type === "tool_call_end") toolCallCount++;
|
|
1356
|
-
if (event.type === "compaction") compactionCount++;
|
|
1357
|
-
}
|
|
1358
|
-
if (!start) throw new Error("missing session_start");
|
|
1359
|
-
return {
|
|
1360
|
-
id,
|
|
1361
|
-
title: id,
|
|
1362
|
-
startedAt: start.ts,
|
|
1363
|
-
...endedAt ? { endedAt } : {},
|
|
1364
|
-
model: start.model,
|
|
1365
|
-
provider: start.provider,
|
|
1366
|
-
tokenTotal,
|
|
1367
|
-
...lastActivityAt ? { lastActivityAt } : {},
|
|
1368
|
-
messageCount,
|
|
1369
|
-
iterationCount,
|
|
1370
|
-
toolCallCount,
|
|
1371
|
-
compactionCount
|
|
1372
|
-
};
|
|
1373
1381
|
}
|
|
1374
1382
|
health(base) {
|
|
1375
1383
|
this.reapExpired();
|
|
@@ -1401,13 +1409,13 @@ function parseArgs(argv) {
|
|
|
1401
1409
|
const projectRoot = values.get("--project-root");
|
|
1402
1410
|
if (!projectDir) throw new Error("Session Catalog project server requires --project-dir");
|
|
1403
1411
|
if (!projectRoot) throw new Error("Session Catalog project server requires --project-root");
|
|
1404
|
-
return { projectDir:
|
|
1412
|
+
return { projectDir: path4.resolve(projectDir), projectRoot: path4.resolve(projectRoot) };
|
|
1405
1413
|
}
|
|
1406
1414
|
useDaemonPerfDefaults();
|
|
1407
1415
|
var parsed = parseArgs(process.argv.slice(2));
|
|
1408
1416
|
var endpoint = sessionCatalogProjectServerEndpoint(parsed.projectDir);
|
|
1409
1417
|
var metadataPath = sessionCatalogProjectServerMetadataPath(parsed.projectDir);
|
|
1410
|
-
var databasePath =
|
|
1418
|
+
var databasePath = path4.join(parsed.projectDir, "sessions", "catalog.sqlite");
|
|
1411
1419
|
var startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1412
1420
|
var instanceId = randomUUID2();
|
|
1413
1421
|
var authToken = randomBytes2(32).toString("hex");
|
|
@@ -1424,7 +1432,7 @@ var serverInfo = {
|
|
|
1424
1432
|
instanceId,
|
|
1425
1433
|
startedAt
|
|
1426
1434
|
};
|
|
1427
|
-
process.title = `wrongstack-session-catalog:${
|
|
1435
|
+
process.title = `wrongstack-session-catalog:${path4.basename(parsed.projectRoot)}`;
|
|
1428
1436
|
var store;
|
|
1429
1437
|
var activeRequests = 0;
|
|
1430
1438
|
var stopping = false;
|
|
@@ -1528,13 +1536,13 @@ function validateOperationArgs(op, args) {
|
|
|
1528
1536
|
if (record["entry"] !== void 0) exact(record["entry"], `${op}.entry`, entryKeys);
|
|
1529
1537
|
if (record["entry"] && typeof record["entry"] === "object") {
|
|
1530
1538
|
const entry = record["entry"];
|
|
1531
|
-
if (typeof entry["projectRoot"] !== "string" || (process.platform === "win32" ?
|
|
1539
|
+
if (typeof entry["projectRoot"] !== "string" || (process.platform === "win32" ? path4.resolve(entry["projectRoot"]).toLowerCase() !== parsed.projectRoot.toLowerCase() : path4.resolve(entry["projectRoot"]) !== parsed.projectRoot)) {
|
|
1532
1540
|
throw new TypeError(`${op}.entry project identity does not match this daemon`);
|
|
1533
1541
|
}
|
|
1534
1542
|
if (typeof entry["workingDir"] !== "string")
|
|
1535
1543
|
throw new TypeError(`${op}.entry workingDir is required`);
|
|
1536
|
-
const relative3 =
|
|
1537
|
-
if (relative3 === ".." || relative3.startsWith(`..${
|
|
1544
|
+
const relative3 = path4.relative(parsed.projectRoot, path4.resolve(entry["workingDir"]));
|
|
1545
|
+
if (relative3 === ".." || relative3.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative3)) {
|
|
1538
1546
|
throw new TypeError(`${op}.entry workingDir is outside the project root`);
|
|
1539
1547
|
}
|
|
1540
1548
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { SessionSummary } from '../types/session.js';
|
|
3
|
+
export declare function walkSessionFiles(root: string, suffix: string): string[];
|
|
4
|
+
export declare function summarizeTranscriptFile(transcriptFilePath: string, id: string): SessionSummary;
|
|
5
|
+
export declare function rebuildCatalogIndex(db: DatabaseSync, sessionsDir: string, containedPathFn: (relative: string) => string, transactionFn: <T>(run: () => T) => T, bumpGenerationFn: () => number): {
|
|
6
|
+
indexed: number;
|
|
7
|
+
damaged: number;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=store-rebuild.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { SessionRegistryEntry } from '../session-registry-types.js';
|
|
3
|
+
export declare const SCHEMA_VERSION = 1;
|
|
4
|
+
export declare const MAX_LEASE_MS = 120000;
|
|
5
|
+
export declare const MAX_RESERVATION_MS = 60000;
|
|
6
|
+
export declare const MAX_MAINTENANCE_MS: number;
|
|
7
|
+
export declare const MAX_PAGE = 1000;
|
|
8
|
+
export interface LeaseRow {
|
|
9
|
+
session_id: string;
|
|
10
|
+
lease_id: string;
|
|
11
|
+
lease_secret_hash: string;
|
|
12
|
+
owner_instance_id: string;
|
|
13
|
+
owner_pid: number;
|
|
14
|
+
owner_started_at: string;
|
|
15
|
+
entry_json: string;
|
|
16
|
+
agent_revision: number;
|
|
17
|
+
status: SessionRegistryEntry['status'];
|
|
18
|
+
last_heartbeat_at: number;
|
|
19
|
+
lease_expires_at: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ReservationRow {
|
|
22
|
+
reservation_id: string;
|
|
23
|
+
target_session_id: string;
|
|
24
|
+
requester_instance_id: string;
|
|
25
|
+
current_session_id: string | null;
|
|
26
|
+
expires_at: number;
|
|
27
|
+
}
|
|
28
|
+
export interface CatalogRow {
|
|
29
|
+
session_id: string;
|
|
30
|
+
transcript_relative_path: string;
|
|
31
|
+
summary_relative_path: string;
|
|
32
|
+
summary_json: string;
|
|
33
|
+
transcript_size: number;
|
|
34
|
+
transcript_mtime_ms: number;
|
|
35
|
+
summary_revision: number;
|
|
36
|
+
indexed_at: string;
|
|
37
|
+
damaged: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function hashSecret(secret: string): string;
|
|
40
|
+
export declare function secretMatches(secret: string, expectedHex: string): boolean;
|
|
41
|
+
export declare function boundedMs(value: number | undefined, fallback: number, max: number): number;
|
|
42
|
+
export declare function parseJson<T>(value: string): T;
|
|
43
|
+
export declare function conflict(message: string): Error;
|
|
44
|
+
export declare function assertId(value: string, label?: string): void;
|
|
45
|
+
export declare function boundPresenceValue(value: unknown, depth: number): unknown;
|
|
46
|
+
export declare function configureCatalogDatabase(db: DatabaseSync): void;
|
|
47
|
+
export declare function initializeCatalogSchema(db: DatabaseSync): void;
|
|
48
|
+
//# sourceMappingURL=store-schema.d.ts.map
|