engrm 0.3.1 → 0.3.4
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/cli.js +54 -1
- package/dist/hooks/elicitation-result.js +53 -1
- package/dist/hooks/post-tool-use.js +53 -1
- package/dist/hooks/pre-compact.js +51 -0
- package/dist/hooks/sentinel.js +58 -0
- package/dist/hooks/session-start.js +51 -0
- package/dist/hooks/stop.js +51 -0
- package/dist/server.js +53 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -548,6 +548,56 @@ function runMigrations(db) {
|
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
|
+
function ensureObservationTypes(db) {
|
|
552
|
+
try {
|
|
553
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
554
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
555
|
+
} catch {
|
|
556
|
+
db.exec("BEGIN TRANSACTION");
|
|
557
|
+
try {
|
|
558
|
+
db.exec(`
|
|
559
|
+
CREATE TABLE observations_repair (
|
|
560
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
561
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
562
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
563
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
564
|
+
'refactor','digest','standard','message')),
|
|
565
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
566
|
+
files_read TEXT, files_modified TEXT,
|
|
567
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
568
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
569
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
570
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
571
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
572
|
+
archived_at_epoch INTEGER,
|
|
573
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
574
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
575
|
+
remote_source_id TEXT
|
|
576
|
+
);
|
|
577
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
578
|
+
DROP TABLE observations;
|
|
579
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
580
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
581
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
582
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
583
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
584
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
585
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
586
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
587
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
588
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
589
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
590
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
591
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
592
|
+
);
|
|
593
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
594
|
+
`);
|
|
595
|
+
db.exec("COMMIT");
|
|
596
|
+
} catch (err) {
|
|
597
|
+
db.exec("ROLLBACK");
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
551
601
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
552
602
|
|
|
553
603
|
// src/storage/sqlite.ts
|
|
@@ -614,6 +664,7 @@ class MemDatabase {
|
|
|
614
664
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
615
665
|
this.vecAvailable = this.loadVecExtension();
|
|
616
666
|
runMigrations(this.db);
|
|
667
|
+
ensureObservationTypes(this.db);
|
|
617
668
|
}
|
|
618
669
|
loadVecExtension() {
|
|
619
670
|
try {
|
|
@@ -1905,7 +1956,8 @@ var VALID_TYPES = [
|
|
|
1905
1956
|
"feature",
|
|
1906
1957
|
"refactor",
|
|
1907
1958
|
"digest",
|
|
1908
|
-
"standard"
|
|
1959
|
+
"standard",
|
|
1960
|
+
"message"
|
|
1909
1961
|
];
|
|
1910
1962
|
async function saveObservation(db, config, input) {
|
|
1911
1963
|
if (!VALID_TYPES.includes(input.type)) {
|
|
@@ -2166,6 +2218,7 @@ switch (command) {
|
|
|
2166
2218
|
printUsage();
|
|
2167
2219
|
break;
|
|
2168
2220
|
}
|
|
2221
|
+
process.exit(0);
|
|
2169
2222
|
async function handleInit(flags) {
|
|
2170
2223
|
const tokenFlag = flags.find((f) => f.startsWith("--token"));
|
|
2171
2224
|
if (tokenFlag) {
|
|
@@ -514,6 +514,56 @@ function runMigrations(db) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
|
+
function ensureObservationTypes(db) {
|
|
518
|
+
try {
|
|
519
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
520
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
521
|
+
} catch {
|
|
522
|
+
db.exec("BEGIN TRANSACTION");
|
|
523
|
+
try {
|
|
524
|
+
db.exec(`
|
|
525
|
+
CREATE TABLE observations_repair (
|
|
526
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
527
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
528
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
529
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
530
|
+
'refactor','digest','standard','message')),
|
|
531
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
532
|
+
files_read TEXT, files_modified TEXT,
|
|
533
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
534
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
535
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
536
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
537
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
538
|
+
archived_at_epoch INTEGER,
|
|
539
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
540
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
remote_source_id TEXT
|
|
542
|
+
);
|
|
543
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
544
|
+
DROP TABLE observations;
|
|
545
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
546
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
554
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
555
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
556
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
557
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
558
|
+
);
|
|
559
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
560
|
+
`);
|
|
561
|
+
db.exec("COMMIT");
|
|
562
|
+
} catch (err) {
|
|
563
|
+
db.exec("ROLLBACK");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
518
568
|
|
|
519
569
|
// src/storage/sqlite.ts
|
|
@@ -580,6 +630,7 @@ class MemDatabase {
|
|
|
580
630
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
581
631
|
this.vecAvailable = this.loadVecExtension();
|
|
582
632
|
runMigrations(this.db);
|
|
633
|
+
ensureObservationTypes(this.db);
|
|
583
634
|
}
|
|
584
635
|
loadVecExtension() {
|
|
585
636
|
try {
|
|
@@ -1537,7 +1588,8 @@ var VALID_TYPES = [
|
|
|
1537
1588
|
"feature",
|
|
1538
1589
|
"refactor",
|
|
1539
1590
|
"digest",
|
|
1540
|
-
"standard"
|
|
1591
|
+
"standard",
|
|
1592
|
+
"message"
|
|
1541
1593
|
];
|
|
1542
1594
|
async function saveObservation(db, config, input) {
|
|
1543
1595
|
if (!VALID_TYPES.includes(input.type)) {
|
|
@@ -514,6 +514,56 @@ function runMigrations(db) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
|
+
function ensureObservationTypes(db) {
|
|
518
|
+
try {
|
|
519
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
520
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
521
|
+
} catch {
|
|
522
|
+
db.exec("BEGIN TRANSACTION");
|
|
523
|
+
try {
|
|
524
|
+
db.exec(`
|
|
525
|
+
CREATE TABLE observations_repair (
|
|
526
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
527
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
528
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
529
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
530
|
+
'refactor','digest','standard','message')),
|
|
531
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
532
|
+
files_read TEXT, files_modified TEXT,
|
|
533
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
534
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
535
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
536
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
537
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
538
|
+
archived_at_epoch INTEGER,
|
|
539
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
540
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
remote_source_id TEXT
|
|
542
|
+
);
|
|
543
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
544
|
+
DROP TABLE observations;
|
|
545
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
546
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
554
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
555
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
556
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
557
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
558
|
+
);
|
|
559
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
560
|
+
`);
|
|
561
|
+
db.exec("COMMIT");
|
|
562
|
+
} catch (err) {
|
|
563
|
+
db.exec("ROLLBACK");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
518
568
|
|
|
519
569
|
// src/storage/sqlite.ts
|
|
@@ -580,6 +630,7 @@ class MemDatabase {
|
|
|
580
630
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
581
631
|
this.vecAvailable = this.loadVecExtension();
|
|
582
632
|
runMigrations(this.db);
|
|
633
|
+
ensureObservationTypes(this.db);
|
|
583
634
|
}
|
|
584
635
|
loadVecExtension() {
|
|
585
636
|
try {
|
|
@@ -1743,7 +1794,8 @@ var VALID_TYPES = [
|
|
|
1743
1794
|
"feature",
|
|
1744
1795
|
"refactor",
|
|
1745
1796
|
"digest",
|
|
1746
|
-
"standard"
|
|
1797
|
+
"standard",
|
|
1798
|
+
"message"
|
|
1747
1799
|
];
|
|
1748
1800
|
async function saveObservation(db, config, input) {
|
|
1749
1801
|
if (!VALID_TYPES.includes(input.type)) {
|
|
@@ -514,6 +514,56 @@ function runMigrations(db) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
|
+
function ensureObservationTypes(db) {
|
|
518
|
+
try {
|
|
519
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
520
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
521
|
+
} catch {
|
|
522
|
+
db.exec("BEGIN TRANSACTION");
|
|
523
|
+
try {
|
|
524
|
+
db.exec(`
|
|
525
|
+
CREATE TABLE observations_repair (
|
|
526
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
527
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
528
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
529
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
530
|
+
'refactor','digest','standard','message')),
|
|
531
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
532
|
+
files_read TEXT, files_modified TEXT,
|
|
533
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
534
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
535
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
536
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
537
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
538
|
+
archived_at_epoch INTEGER,
|
|
539
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
540
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
remote_source_id TEXT
|
|
542
|
+
);
|
|
543
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
544
|
+
DROP TABLE observations;
|
|
545
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
546
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
554
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
555
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
556
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
557
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
558
|
+
);
|
|
559
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
560
|
+
`);
|
|
561
|
+
db.exec("COMMIT");
|
|
562
|
+
} catch (err) {
|
|
563
|
+
db.exec("ROLLBACK");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
518
568
|
|
|
519
569
|
// src/storage/sqlite.ts
|
|
@@ -580,6 +630,7 @@ class MemDatabase {
|
|
|
580
630
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
581
631
|
this.vecAvailable = this.loadVecExtension();
|
|
582
632
|
runMigrations(this.db);
|
|
633
|
+
ensureObservationTypes(this.db);
|
|
583
634
|
}
|
|
584
635
|
loadVecExtension() {
|
|
585
636
|
try {
|
package/dist/hooks/sentinel.js
CHANGED
|
@@ -514,6 +514,56 @@ function runMigrations(db) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
|
+
function ensureObservationTypes(db) {
|
|
518
|
+
try {
|
|
519
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
520
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
521
|
+
} catch {
|
|
522
|
+
db.exec("BEGIN TRANSACTION");
|
|
523
|
+
try {
|
|
524
|
+
db.exec(`
|
|
525
|
+
CREATE TABLE observations_repair (
|
|
526
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
527
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
528
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
529
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
530
|
+
'refactor','digest','standard','message')),
|
|
531
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
532
|
+
files_read TEXT, files_modified TEXT,
|
|
533
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
534
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
535
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
536
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
537
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
538
|
+
archived_at_epoch INTEGER,
|
|
539
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
540
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
remote_source_id TEXT
|
|
542
|
+
);
|
|
543
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
544
|
+
DROP TABLE observations;
|
|
545
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
546
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
554
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
555
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
556
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
557
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
558
|
+
);
|
|
559
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
560
|
+
`);
|
|
561
|
+
db.exec("COMMIT");
|
|
562
|
+
} catch (err) {
|
|
563
|
+
db.exec("ROLLBACK");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
518
568
|
|
|
519
569
|
// src/storage/sqlite.ts
|
|
@@ -580,6 +630,7 @@ class MemDatabase {
|
|
|
580
630
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
581
631
|
this.vecAvailable = this.loadVecExtension();
|
|
582
632
|
runMigrations(this.db);
|
|
633
|
+
ensureObservationTypes(this.db);
|
|
583
634
|
}
|
|
584
635
|
loadVecExtension() {
|
|
585
636
|
try {
|
|
@@ -1165,6 +1216,13 @@ async function main() {
|
|
|
1165
1216
|
}
|
|
1166
1217
|
try {
|
|
1167
1218
|
const filePath = String(event.tool_input["file_path"] ?? "unknown");
|
|
1219
|
+
const defaultSkips = [/migrations?\./, /\.test\./, /\.spec\./, /\.lock$/, /package\.json$/];
|
|
1220
|
+
const customSkips = (config.sentinel.skip_patterns || []).map((p) => new RegExp(p));
|
|
1221
|
+
const allSkips = [...defaultSkips, ...customSkips];
|
|
1222
|
+
if (allSkips.some((re) => re.test(filePath))) {
|
|
1223
|
+
db.close();
|
|
1224
|
+
process.exit(0);
|
|
1225
|
+
}
|
|
1168
1226
|
const content = event.tool_name === "Write" ? String(event.tool_input["content"] ?? "") : String(event.tool_input["new_string"] ?? "");
|
|
1169
1227
|
const result = await auditCodeChange(config, db, event.tool_name, filePath, content);
|
|
1170
1228
|
if (result.verdict === "PASS") {
|
|
@@ -515,6 +515,56 @@ function runMigrations(db) {
|
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
}
|
|
518
|
+
function ensureObservationTypes(db) {
|
|
519
|
+
try {
|
|
520
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
521
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
522
|
+
} catch {
|
|
523
|
+
db.exec("BEGIN TRANSACTION");
|
|
524
|
+
try {
|
|
525
|
+
db.exec(`
|
|
526
|
+
CREATE TABLE observations_repair (
|
|
527
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
528
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
529
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
530
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
531
|
+
'refactor','digest','standard','message')),
|
|
532
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
533
|
+
files_read TEXT, files_modified TEXT,
|
|
534
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
535
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
536
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
537
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
538
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
539
|
+
archived_at_epoch INTEGER,
|
|
540
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
542
|
+
remote_source_id TEXT
|
|
543
|
+
);
|
|
544
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
545
|
+
DROP TABLE observations;
|
|
546
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
554
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
555
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
556
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
557
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
558
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
559
|
+
);
|
|
560
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
561
|
+
`);
|
|
562
|
+
db.exec("COMMIT");
|
|
563
|
+
} catch (err) {
|
|
564
|
+
db.exec("ROLLBACK");
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
518
568
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
519
569
|
|
|
520
570
|
// src/storage/sqlite.ts
|
|
@@ -581,6 +631,7 @@ class MemDatabase {
|
|
|
581
631
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
582
632
|
this.vecAvailable = this.loadVecExtension();
|
|
583
633
|
runMigrations(this.db);
|
|
634
|
+
ensureObservationTypes(this.db);
|
|
584
635
|
}
|
|
585
636
|
loadVecExtension() {
|
|
586
637
|
try {
|
package/dist/hooks/stop.js
CHANGED
|
@@ -514,6 +514,56 @@ function runMigrations(db) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
|
+
function ensureObservationTypes(db) {
|
|
518
|
+
try {
|
|
519
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
520
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
521
|
+
} catch {
|
|
522
|
+
db.exec("BEGIN TRANSACTION");
|
|
523
|
+
try {
|
|
524
|
+
db.exec(`
|
|
525
|
+
CREATE TABLE observations_repair (
|
|
526
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
527
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
528
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
529
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
530
|
+
'refactor','digest','standard','message')),
|
|
531
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
532
|
+
files_read TEXT, files_modified TEXT,
|
|
533
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
534
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
535
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
536
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
537
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
538
|
+
archived_at_epoch INTEGER,
|
|
539
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
540
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
541
|
+
remote_source_id TEXT
|
|
542
|
+
);
|
|
543
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
544
|
+
DROP TABLE observations;
|
|
545
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
546
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
547
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
548
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
549
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
550
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
551
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
552
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
553
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
554
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
555
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
556
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
557
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
558
|
+
);
|
|
559
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
560
|
+
`);
|
|
561
|
+
db.exec("COMMIT");
|
|
562
|
+
} catch (err) {
|
|
563
|
+
db.exec("ROLLBACK");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
518
568
|
|
|
519
569
|
// src/storage/sqlite.ts
|
|
@@ -580,6 +630,7 @@ class MemDatabase {
|
|
|
580
630
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
581
631
|
this.vecAvailable = this.loadVecExtension();
|
|
582
632
|
runMigrations(this.db);
|
|
633
|
+
ensureObservationTypes(this.db);
|
|
583
634
|
}
|
|
584
635
|
loadVecExtension() {
|
|
585
636
|
try {
|
package/dist/server.js
CHANGED
|
@@ -14064,6 +14064,56 @@ function runMigrations(db) {
|
|
|
14064
14064
|
}
|
|
14065
14065
|
}
|
|
14066
14066
|
}
|
|
14067
|
+
function ensureObservationTypes(db) {
|
|
14068
|
+
try {
|
|
14069
|
+
db.exec("INSERT INTO observations (session_id, project_id, type, title, user_id, device_id, agent, created_at, created_at_epoch) " + "VALUES ('_typecheck', 1, 'message', '_test', '_test', '_test', '_test', '2000-01-01', 0)");
|
|
14070
|
+
db.exec("DELETE FROM observations WHERE session_id = '_typecheck'");
|
|
14071
|
+
} catch {
|
|
14072
|
+
db.exec("BEGIN TRANSACTION");
|
|
14073
|
+
try {
|
|
14074
|
+
db.exec(`
|
|
14075
|
+
CREATE TABLE observations_repair (
|
|
14076
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,
|
|
14077
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
14078
|
+
type TEXT NOT NULL CHECK (type IN (
|
|
14079
|
+
'bugfix','discovery','decision','pattern','change','feature',
|
|
14080
|
+
'refactor','digest','standard','message')),
|
|
14081
|
+
title TEXT NOT NULL, narrative TEXT, facts TEXT, concepts TEXT,
|
|
14082
|
+
files_read TEXT, files_modified TEXT,
|
|
14083
|
+
quality REAL DEFAULT 0.5 CHECK (quality BETWEEN 0.0 AND 1.0),
|
|
14084
|
+
lifecycle TEXT DEFAULT 'active' CHECK (lifecycle IN ('active','aging','archived','purged','pinned')),
|
|
14085
|
+
sensitivity TEXT DEFAULT 'shared' CHECK (sensitivity IN ('shared','personal','secret')),
|
|
14086
|
+
user_id TEXT NOT NULL, device_id TEXT NOT NULL, agent TEXT DEFAULT 'claude-code',
|
|
14087
|
+
created_at TEXT NOT NULL, created_at_epoch INTEGER NOT NULL,
|
|
14088
|
+
archived_at_epoch INTEGER,
|
|
14089
|
+
compacted_into INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
14090
|
+
superseded_by INTEGER REFERENCES observations(id) ON DELETE SET NULL,
|
|
14091
|
+
remote_source_id TEXT
|
|
14092
|
+
);
|
|
14093
|
+
INSERT INTO observations_repair SELECT * FROM observations;
|
|
14094
|
+
DROP TABLE observations;
|
|
14095
|
+
ALTER TABLE observations_repair RENAME TO observations;
|
|
14096
|
+
CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project_id);
|
|
14097
|
+
CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
|
|
14098
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch);
|
|
14099
|
+
CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
|
|
14100
|
+
CREATE INDEX IF NOT EXISTS idx_observations_lifecycle ON observations(lifecycle);
|
|
14101
|
+
CREATE INDEX IF NOT EXISTS idx_observations_quality ON observations(quality);
|
|
14102
|
+
CREATE INDEX IF NOT EXISTS idx_observations_user ON observations(user_id);
|
|
14103
|
+
CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
|
|
14104
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_remote_source ON observations(remote_source_id) WHERE remote_source_id IS NOT NULL;
|
|
14105
|
+
DROP TABLE IF EXISTS observations_fts;
|
|
14106
|
+
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
|
14107
|
+
title, narrative, facts, concepts, content=observations, content_rowid=id
|
|
14108
|
+
);
|
|
14109
|
+
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
|
14110
|
+
`);
|
|
14111
|
+
db.exec("COMMIT");
|
|
14112
|
+
} catch (err) {
|
|
14113
|
+
db.exec("ROLLBACK");
|
|
14114
|
+
}
|
|
14115
|
+
}
|
|
14116
|
+
}
|
|
14067
14117
|
var LATEST_SCHEMA_VERSION = MIGRATIONS.filter((m) => !m.condition).reduce((max, m) => Math.max(max, m.version), 0);
|
|
14068
14118
|
|
|
14069
14119
|
// src/storage/sqlite.ts
|
|
@@ -14130,6 +14180,7 @@ class MemDatabase {
|
|
|
14130
14180
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
14131
14181
|
this.vecAvailable = this.loadVecExtension();
|
|
14132
14182
|
runMigrations(this.db);
|
|
14183
|
+
ensureObservationTypes(this.db);
|
|
14133
14184
|
}
|
|
14134
14185
|
loadVecExtension() {
|
|
14135
14186
|
try {
|
|
@@ -15098,7 +15149,8 @@ var VALID_TYPES = [
|
|
|
15098
15149
|
"feature",
|
|
15099
15150
|
"refactor",
|
|
15100
15151
|
"digest",
|
|
15101
|
-
"standard"
|
|
15152
|
+
"standard",
|
|
15153
|
+
"message"
|
|
15102
15154
|
];
|
|
15103
15155
|
async function saveObservation(db, config2, input) {
|
|
15104
15156
|
if (!VALID_TYPES.includes(input.type)) {
|