@spences10/pi-context 0.0.2 → 0.0.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/policy.js ADDED
@@ -0,0 +1,30 @@
1
+ export const DEFAULT_CONTEXT_RETENTION_DAYS = 7;
2
+ export function parse_context_retention_policy(env = process.env) {
3
+ const retention_days = parse_optional_positive_number(env.MY_PI_CONTEXT_RETENTION_DAYS, DEFAULT_CONTEXT_RETENTION_DAYS);
4
+ const max_mb = parse_optional_positive_number(env.MY_PI_CONTEXT_MAX_MB, null);
5
+ return {
6
+ retention_days,
7
+ purge_on_shutdown: parse_boolean_env(env.MY_PI_CONTEXT_PURGE_ON_SHUTDOWN),
8
+ max_mb,
9
+ max_bytes: max_mb === null ? null : max_mb * 1024 * 1024,
10
+ };
11
+ }
12
+ function parse_optional_positive_number(value, fallback) {
13
+ if (value === undefined || value.trim() === '')
14
+ return fallback;
15
+ const normalized = value.trim().toLowerCase();
16
+ if (normalized === '0' ||
17
+ normalized === 'off' ||
18
+ normalized === 'false' ||
19
+ normalized === 'none' ||
20
+ normalized === 'disabled')
21
+ return null;
22
+ const parsed = Number(normalized);
23
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
24
+ }
25
+ function parse_boolean_env(value) {
26
+ if (!value)
27
+ return false;
28
+ return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
29
+ }
30
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAEhD,MAAM,UAAU,8BAA8B,CAC7C,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,cAAc,GAAG,8BAA8B,CACpD,GAAG,CAAC,4BAA4B,EAChC,8BAA8B,CAC9B,CAAC;IACF,MAAM,MAAM,GAAG,8BAA8B,CAC5C,GAAG,CAAC,oBAAoB,EACxB,IAAI,CACJ,CAAC;IACF,OAAO;QACN,cAAc;QACd,iBAAiB,EAAE,iBAAiB,CACnC,GAAG,CAAC,+BAA+B,CACnC;QACD,MAAM;QACN,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI;KACxD,CAAC;AACH,CAAC;AAED,SAAS,8BAA8B,CACtC,KAAyB,EACzB,QAAuB;IAEvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAChE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IACC,UAAU,KAAK,GAAG;QAClB,UAAU,KAAK,KAAK;QACpB,UAAU,KAAK,OAAO;QACtB,UAAU,KAAK,MAAM;QACrB,UAAU,KAAK,UAAU;QAEzB,OAAO,IAAI,CAAC;IACb,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAyB;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CACzC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export declare function apply_schema(db: DatabaseSync): void;
package/dist/schema.js ADDED
@@ -0,0 +1,45 @@
1
+ import { readFileSync } from 'node:fs';
2
+ const SCHEMA = readFileSync(new URL('./schema.sql', import.meta.url), 'utf8');
3
+ const LATEST_CONTEXT_SCHEMA_VERSION = 1;
4
+ const PERSISTENT_PRAGMAS = `
5
+ PRAGMA journal_mode = WAL;
6
+ `;
7
+ const CONNECTION_PRAGMAS = `
8
+ PRAGMA foreign_keys = ON;
9
+ PRAGMA busy_timeout = 5000;
10
+ `;
11
+ const MIGRATIONS = {
12
+ 1: SCHEMA,
13
+ };
14
+ function get_user_version(db) {
15
+ const row = db.prepare('PRAGMA user_version').get();
16
+ return row.user_version;
17
+ }
18
+ export function apply_schema(db) {
19
+ db.exec(PERSISTENT_PRAGMAS);
20
+ db.exec(CONNECTION_PRAGMAS);
21
+ const current_version = get_user_version(db);
22
+ if (current_version > LATEST_CONTEXT_SCHEMA_VERSION) {
23
+ db.close();
24
+ throw new Error(`Context database schema version ${current_version} is newer than supported version ${LATEST_CONTEXT_SCHEMA_VERSION}`);
25
+ }
26
+ for (let next_version = current_version + 1; next_version <= LATEST_CONTEXT_SCHEMA_VERSION; next_version++) {
27
+ const migration = MIGRATIONS[next_version];
28
+ if (!migration) {
29
+ db.close();
30
+ throw new Error(`Missing context migration for schema version ${next_version}`);
31
+ }
32
+ db.exec('BEGIN');
33
+ try {
34
+ db.exec(migration);
35
+ db.exec(`PRAGMA user_version = ${next_version}`);
36
+ db.exec('COMMIT');
37
+ }
38
+ catch (error) {
39
+ db.exec('ROLLBACK');
40
+ db.close();
41
+ throw error;
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,MAAM,GAAG,YAAY,CAC1B,IAAI,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EACxC,MAAM,CACN,CAAC;AACF,MAAM,6BAA6B,GAAG,CAAC,CAAC;AACxC,MAAM,kBAAkB,GAAG;;CAE1B,CAAC;AACF,MAAM,kBAAkB,GAAG;;;CAG1B,CAAC;AACF,MAAM,UAAU,GAA2B;IAC1C,CAAC,EAAE,MAAM;CACT,CAAC;AAEF,SAAS,gBAAgB,CAAC,EAAgB;IACzC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAEhD,CAAC;IACF,OAAO,GAAG,CAAC,YAAY,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAgB;IAC5C,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5B,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAE5B,MAAM,eAAe,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC7C,IAAI,eAAe,GAAG,6BAA6B,EAAE,CAAC;QACrD,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,mCAAmC,eAAe,oCAAoC,6BAA6B,EAAE,CACrH,CAAC;IACH,CAAC;IAED,KACC,IAAI,YAAY,GAAG,eAAe,GAAG,CAAC,EACtC,YAAY,IAAI,6BAA6B,EAC7C,YAAY,EAAE,EACb,CAAC;QACF,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACd,gDAAgD,YAAY,EAAE,CAC9D,CAAC;QACH,CAAC;QAED,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjB,IAAI,CAAC;YACJ,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACnB,EAAE,CAAC,IAAI,CAAC,yBAAyB,YAAY,EAAE,CAAC,CAAC;YACjD,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACpB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;AACF,CAAC"}
@@ -0,0 +1,49 @@
1
+ CREATE TABLE IF NOT EXISTS context_sources (
2
+ id TEXT PRIMARY KEY,
3
+ session_id TEXT,
4
+ project_path TEXT,
5
+ tool_name TEXT NOT NULL,
6
+ input_summary TEXT,
7
+ created_at INTEGER NOT NULL,
8
+ byte_count INTEGER NOT NULL,
9
+ line_count INTEGER NOT NULL,
10
+ content_hash TEXT NOT NULL,
11
+ preview_byte_count INTEGER NOT NULL DEFAULT 0,
12
+ returned_byte_count INTEGER NOT NULL DEFAULT 0
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS context_chunks (
16
+ id TEXT PRIMARY KEY,
17
+ source_id TEXT NOT NULL REFERENCES context_sources(id) ON DELETE CASCADE,
18
+ ordinal INTEGER NOT NULL,
19
+ title TEXT,
20
+ content TEXT NOT NULL,
21
+ byte_count INTEGER NOT NULL
22
+ );
23
+
24
+ CREATE VIRTUAL TABLE IF NOT EXISTS context_chunks_fts USING fts5(
25
+ title,
26
+ content,
27
+ content='context_chunks',
28
+ content_rowid='rowid'
29
+ );
30
+
31
+ CREATE TRIGGER IF NOT EXISTS context_chunks_ai AFTER INSERT ON context_chunks BEGIN
32
+ INSERT INTO context_chunks_fts(rowid, title, content) VALUES (new.rowid, new.title, new.content);
33
+ END;
34
+
35
+ CREATE TRIGGER IF NOT EXISTS context_chunks_ad AFTER DELETE ON context_chunks BEGIN
36
+ INSERT INTO context_chunks_fts(context_chunks_fts, rowid, title, content)
37
+ VALUES('delete', old.rowid, old.title, old.content);
38
+ END;
39
+
40
+ CREATE TRIGGER IF NOT EXISTS context_chunks_au AFTER UPDATE ON context_chunks BEGIN
41
+ INSERT INTO context_chunks_fts(context_chunks_fts, rowid, title, content)
42
+ VALUES('delete', old.rowid, old.title, old.content);
43
+ INSERT INTO context_chunks_fts(rowid, title, content) VALUES (new.rowid, new.title, new.content);
44
+ END;
45
+
46
+ CREATE INDEX IF NOT EXISTS idx_context_sources_created ON context_sources(created_at);
47
+ CREATE INDEX IF NOT EXISTS idx_context_sources_session ON context_sources(session_id);
48
+ CREATE INDEX IF NOT EXISTS idx_context_sources_project ON context_sources(project_path);
49
+ CREATE INDEX IF NOT EXISTS idx_context_chunks_source ON context_chunks(source_id, ordinal);
package/dist/store.d.ts CHANGED
@@ -1,69 +1,12 @@
1
- export declare const DEFAULT_CONTEXT_MAX_BYTES: number;
2
- export declare const DEFAULT_CONTEXT_MAX_LINES = 300;
3
- export interface ContextStoreOptions {
4
- db_path?: string;
5
- project_path?: string;
6
- session_id?: string | null;
7
- max_bytes?: number;
8
- max_lines?: number;
9
- }
10
- export interface StoreContextInput {
11
- text: string;
12
- tool_name: string;
13
- input_summary?: string | null;
14
- session_id?: string | null;
15
- project_path?: string | null;
16
- force?: boolean;
17
- }
18
- export interface StoredContextOutput {
19
- source_id: string;
20
- bytes: number;
21
- lines: number;
22
- preview: string;
23
- receipt: string;
24
- chunk_count: number;
25
- returned_bytes: number;
26
- }
27
- export interface ContextSearchResult {
28
- source_id: string;
29
- chunk_id: string;
30
- ordinal: number;
31
- title: string | null;
32
- content: string;
33
- tool_name: string;
34
- created_at: number;
35
- bytes: number;
36
- lines: number;
37
- rank: number;
38
- }
39
- export interface ContextStats {
40
- sources: number;
41
- chunks: number;
42
- bytes_stored: number;
43
- bytes_returned: number;
44
- bytes_saved: number;
45
- reduction_pct: number;
46
- db_bytes: number;
47
- wal_bytes: number;
48
- total_bytes: number;
49
- }
50
- interface ChunkRow {
51
- id: string;
52
- source_id: string;
53
- ordinal: number;
54
- title: string | null;
55
- content: string;
56
- byte_count: number;
57
- }
1
+ import type { ContextChunk, ContextCleanupResult, ContextListResult, ContextPurgeDetails, ContextRetentionPolicy, ContextScopeOptions, ContextSearchResult, ContextStats, ContextStoreOptions, StoreContextInput, StoredContextOutput } from './types.js';
2
+ export { DEFAULT_CONTEXT_RETENTION_DAYS, parse_context_retention_policy, } from './policy.js';
3
+ export { DEFAULT_CONTEXT_MAX_BYTES, DEFAULT_CONTEXT_MAX_LINES, count_lines, escape_fts5_query, make_preview, should_index_text, } from './text.js';
4
+ export type { ContextChunk, ContextCleanupResult, ContextListResult, ContextPurgeDetails, ContextRetentionPolicy, ContextScopeOptions, ContextSearchResult, ContextStats, ContextStoreOptions, StoreContextInput, StoredContextOutput, } from './types.js';
58
5
  export declare function default_context_db_path(): string;
59
6
  export declare function set_context_sidecar_enabled(enabled: boolean, options?: ContextStoreOptions): void;
60
7
  export declare function is_context_sidecar_enabled(): boolean;
61
8
  export declare function get_context_store(options?: ContextStoreOptions): ContextStore;
62
9
  export declare function maybe_store_context_output(input: StoreContextInput, options?: ContextStoreOptions): StoredContextOutput | null;
63
- export declare function count_lines(text: string): number;
64
- export declare function should_index_text(text: string, options?: Pick<ContextStoreOptions, 'max_bytes' | 'max_lines'>): boolean;
65
- export declare function escape_fts5_query(query: string): string;
66
- export declare function make_preview(text: string, max_lines?: number, max_bytes?: number): string;
67
10
  export declare class ContextStore {
68
11
  readonly db_path: string;
69
12
  private db;
@@ -72,18 +15,35 @@ export declare class ContextStore {
72
15
  private max_bytes;
73
16
  private max_lines;
74
17
  constructor(options?: ContextStoreOptions);
18
+ configure(options?: ContextStoreOptions): void;
19
+ private scoped_filter;
20
+ private find_duplicate_source;
75
21
  store(input: StoreContextInput): StoredContextOutput | null;
76
- search(query: string, options?: {
22
+ list(options?: ContextScopeOptions & {
23
+ source_id?: string;
24
+ tool_name?: string;
25
+ limit?: number;
26
+ offset?: number;
27
+ newer_than_days?: number;
28
+ older_than_days?: number;
29
+ }): ContextListResult[];
30
+ search(query: string, options?: ContextScopeOptions & {
77
31
  source_id?: string;
78
32
  limit?: number;
79
33
  tool_name?: string;
80
34
  }): ContextSearchResult[];
81
- get(source_id: string, chunk_id?: string): ChunkRow[];
82
- stats(): ContextStats;
83
- purge(options?: {
35
+ get(source_id: string, chunk_id?: string, options?: ContextScopeOptions): ContextChunk[];
36
+ private count_stats;
37
+ stats(options?: ContextScopeOptions): ContextStats;
38
+ cleanup(policy?: ContextRetentionPolicy): ContextCleanupResult;
39
+ private purge_to_max_stored_bytes;
40
+ purge(options?: ContextScopeOptions & {
84
41
  older_than_days?: number;
85
42
  source_id?: string;
86
43
  }): number;
44
+ purge_with_details(options?: ContextScopeOptions & {
45
+ older_than_days?: number;
46
+ source_id?: string;
47
+ }): ContextPurgeDetails;
87
48
  close(): void;
88
49
  }
89
- export {};