granite-sqlite-lfm 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,3 @@
1
+ """SQLite-backed local Ollama cascade orchestrator."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
@@ -0,0 +1,63 @@
1
+ """Command-line interface for granite-sqlite-lfm."""
2
+
3
+ import argparse
4
+ import logging
5
+ from typing import List, Optional, Sequence
6
+
7
+ from .config import DEFAULT_DB_PATH, DEFAULT_SESSION_ID, DEMO_PROMPTS
8
+ from .database import ContextDatabaseManager
9
+ from .orchestrator import CascadeOrchestrator
10
+
11
+
12
+ def build_parser() -> argparse.ArgumentParser:
13
+ parser = argparse.ArgumentParser(
14
+ prog="granite-sqlite-lfm",
15
+ description="Run a SQLite-backed local Ollama cascade orchestrator.",
16
+ )
17
+ parser.add_argument(
18
+ "--db-path",
19
+ default=DEFAULT_DB_PATH,
20
+ help=f"SQLite database path. Default: {DEFAULT_DB_PATH}",
21
+ )
22
+ parser.add_argument(
23
+ "--session-id",
24
+ default=DEFAULT_SESSION_ID,
25
+ help=f"Session identifier. Default: {DEFAULT_SESSION_ID}",
26
+ )
27
+ parser.add_argument(
28
+ "--prompt",
29
+ action="append",
30
+ dest="prompts",
31
+ help=(
32
+ "Prompt to process. May be passed multiple times. "
33
+ "When omitted, the original demo prompts are used."
34
+ ),
35
+ )
36
+ return parser
37
+
38
+
39
+ def configure_logging() -> None:
40
+ logging.basicConfig(
41
+ level=logging.INFO,
42
+ format="%(asctime)s [%(levelname)s] %(message)s",
43
+ handlers=[logging.StreamHandler()],
44
+ )
45
+
46
+
47
+ def main(argv: Optional[Sequence[str]] = None) -> int:
48
+ configure_logging()
49
+
50
+ parser = build_parser()
51
+ args = parser.parse_args(argv)
52
+
53
+ db_manager = ContextDatabaseManager(args.db_path)
54
+ orchestrator = CascadeOrchestrator(db_manager)
55
+
56
+ prompts: List[str] = list(args.prompts or DEMO_PROMPTS)
57
+
58
+ for prompt in prompts:
59
+ print(f"\n[USER PROMPT]: {prompt}")
60
+ result = orchestrator.run_pipeline(args.session_id, prompt)
61
+ print(f"[FINAL SYSTEM OUTPUT]:\n{result}\n")
62
+
63
+ return 0
@@ -0,0 +1,15 @@
1
+ """Default configuration values for granite-sqlite-lfm."""
2
+
3
+ DEFAULT_DB_PATH = "cascade_context.db"
4
+ DEFAULT_SESSION_ID = "enterprise_user_session_101"
5
+
6
+ STAGE1_MODEL = "lfm2.5:230m"
7
+ STAGE2_MODEL = "ibm-granite/granite-4.0-h-350m-instruct"
8
+ FALLBACK_MODEL = "granite4.1:3b"
9
+
10
+ DEMO_PROMPTS = (
11
+ "Book a conference package room for 15 attendees tomorrow at 3 PM named "
12
+ "'Project Kickoff'.",
13
+ "Change the attendee headcount for the Kickoff event to 45 people and "
14
+ "re-verify options.",
15
+ )
@@ -0,0 +1,215 @@
1
+ """SQLite persistence layer for cascade context state."""
2
+
3
+ import json
4
+ import logging
5
+ import sqlite3
6
+ from typing import Any, Dict, Optional
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class ContextDatabaseManager:
12
+ """Manages transactional CRUD operations against the relational state schema."""
13
+
14
+ def __init__(self, db_path: str = "cascade_context.db"):
15
+ self.db_path = db_path
16
+ self.initialize_schema()
17
+
18
+ def _get_connection(self) -> sqlite3.Connection:
19
+ """Create a connection and enforce WAL mode performance configurations."""
20
+ conn = sqlite3.connect(self.db_path)
21
+ conn.execute("PRAGMA foreign_keys = ON;")
22
+ conn.execute("PRAGMA journal_mode = WAL;")
23
+ conn.execute("PRAGMA synchronous = NORMAL;")
24
+ return conn
25
+
26
+ def initialize_schema(self) -> None:
27
+ """Create the relational state tables and virtual full-text search indexes."""
28
+ with self._get_connection() as conn:
29
+ cursor = conn.cursor()
30
+
31
+ cursor.execute(
32
+ """
33
+ CREATE TABLE IF NOT EXISTS session_state (
34
+ session_id TEXT PRIMARY KEY NOT NULL,
35
+ current_intent TEXT DEFAULT NULL,
36
+ is_escalated INTEGER DEFAULT 0 CHECK (is_escalated IN (0, 1)),
37
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
38
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
39
+ );
40
+ """
41
+ )
42
+
43
+ cursor.execute(
44
+ """
45
+ CREATE TABLE IF NOT EXISTS context_variables (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ session_id TEXT NOT NULL,
48
+ variable_key TEXT NOT NULL,
49
+ variable_value TEXT NOT NULL,
50
+ confidence_score REAL DEFAULT 1.0,
51
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
52
+ FOREIGN KEY(session_id) REFERENCES session_state(session_id)
53
+ ON DELETE CASCADE,
54
+ UNIQUE(session_id, variable_key)
55
+ );
56
+ """
57
+ )
58
+
59
+ cursor.execute(
60
+ """
61
+ CREATE TABLE IF NOT EXISTS semantic_history (
62
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
63
+ session_id TEXT NOT NULL,
64
+ role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
65
+ content TEXT NOT NULL,
66
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
67
+ FOREIGN KEY(session_id) REFERENCES session_state(session_id)
68
+ ON DELETE CASCADE
69
+ );
70
+ """
71
+ )
72
+
73
+ cursor.execute(
74
+ "CREATE INDEX IF NOT EXISTS idx_vars_session "
75
+ "ON context_variables(session_id);"
76
+ )
77
+ cursor.execute(
78
+ "CREATE INDEX IF NOT EXISTS idx_history_session "
79
+ "ON semantic_history(session_id);"
80
+ )
81
+
82
+ cursor.execute(
83
+ """
84
+ CREATE VIRTUAL TABLE IF NOT EXISTS history_fts
85
+ USING fts5(session_id UNINDEXED, content);
86
+ """
87
+ )
88
+
89
+ cursor.execute(
90
+ """
91
+ CREATE TRIGGER IF NOT EXISTS after_history_insert
92
+ AFTER INSERT ON semantic_history
93
+ BEGIN
94
+ INSERT INTO history_fts(session_id, content)
95
+ VALUES (new.session_id, new.content);
96
+ END;
97
+ """
98
+ )
99
+
100
+ conn.commit()
101
+ logger.info("SQLite database schema initialized with WAL mode enabled.")
102
+
103
+ def create_or_get_session(self, session_id: str) -> Dict[str, Any]:
104
+ """Fetch or register an active execution session state."""
105
+ with self._get_connection() as conn:
106
+ cursor = conn.cursor()
107
+ cursor.execute(
108
+ """
109
+ SELECT session_id, current_intent, is_escalated
110
+ FROM session_state
111
+ WHERE session_id = ?;
112
+ """,
113
+ (session_id,),
114
+ )
115
+ row = cursor.fetchone()
116
+
117
+ if not row:
118
+ cursor.execute(
119
+ "INSERT INTO session_state (session_id) VALUES (?);",
120
+ (session_id,),
121
+ )
122
+ conn.commit()
123
+ return {
124
+ "session_id": session_id,
125
+ "current_intent": None,
126
+ "is_escalated": 0,
127
+ }
128
+
129
+ return {
130
+ "session_id": row[0],
131
+ "current_intent": row[1],
132
+ "is_escalated": row[2],
133
+ }
134
+
135
+ def update_session_state(
136
+ self,
137
+ session_id: str,
138
+ intent: Optional[str],
139
+ is_escalated: int,
140
+ ) -> None:
141
+ """Update the root state matrix for a tracking session."""
142
+ with self._get_connection() as conn:
143
+ cursor = conn.cursor()
144
+ cursor.execute(
145
+ """
146
+ UPDATE session_state
147
+ SET current_intent = ?,
148
+ is_escalated = ?,
149
+ updated_at = CURRENT_TIMESTAMP
150
+ WHERE session_id = ?;
151
+ """,
152
+ (intent, is_escalated, session_id),
153
+ )
154
+ conn.commit()
155
+
156
+ def save_extracted_variables(
157
+ self,
158
+ session_id: str,
159
+ variables: Dict[str, Any],
160
+ ) -> None:
161
+ """Upsert key-value arguments extracted dynamically by the micro-model."""
162
+ with self._get_connection() as conn:
163
+ cursor = conn.cursor()
164
+
165
+ for key, val in variables.items():
166
+ val_str = json.dumps(val) if isinstance(val, (dict, list)) else str(val)
167
+ cursor.execute(
168
+ """
169
+ INSERT INTO context_variables
170
+ (session_id, variable_key, variable_value)
171
+ VALUES (?, ?, ?)
172
+ ON CONFLICT(session_id, variable_key)
173
+ DO UPDATE SET
174
+ variable_value = excluded.variable_value,
175
+ updated_at = CURRENT_TIMESTAMP;
176
+ """,
177
+ (session_id, key, val_str),
178
+ )
179
+
180
+ conn.commit()
181
+
182
+ def fetch_active_context(self, session_id: str) -> Dict[str, Any]:
183
+ """Compile clean variables into a native Python dictionary payload."""
184
+ with self._get_connection() as conn:
185
+ cursor = conn.cursor()
186
+ cursor.execute(
187
+ """
188
+ SELECT variable_key, variable_value
189
+ FROM context_variables
190
+ WHERE session_id = ?;
191
+ """,
192
+ (session_id,),
193
+ )
194
+
195
+ context_dict: Dict[str, Any] = {}
196
+ for key, value in cursor.fetchall():
197
+ try:
198
+ context_dict[key] = json.loads(value)
199
+ except json.JSONDecodeError:
200
+ context_dict[key] = value
201
+
202
+ return context_dict
203
+
204
+ def append_chat_history(self, session_id: str, role: str, content: str) -> None:
205
+ """Commit dialogue entries into standard and virtual index layers."""
206
+ with self._get_connection() as conn:
207
+ cursor = conn.cursor()
208
+ cursor.execute(
209
+ """
210
+ INSERT INTO semantic_history (session_id, role, content)
211
+ VALUES (?, ?, ?);
212
+ """,
213
+ (session_id, role, content),
214
+ )
215
+ conn.commit()
@@ -0,0 +1,190 @@
1
+ """Cascade orchestration logic for local Ollama models."""
2
+
3
+ import json
4
+ import logging
5
+ import re
6
+ from typing import Any, Dict, Optional, Tuple
7
+
8
+ import ollama
9
+
10
+ from .config import FALLBACK_MODEL, STAGE1_MODEL, STAGE2_MODEL
11
+ from .database import ContextDatabaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class CascadeOrchestrator:
17
+ """Orchestrates structured task execution across a cascade of models."""
18
+
19
+ def __init__(
20
+ self,
21
+ db_manager: ContextDatabaseManager,
22
+ stage1_model: str = STAGE1_MODEL,
23
+ stage2_model: str = STAGE2_MODEL,
24
+ fallback_model: str = FALLBACK_MODEL,
25
+ ):
26
+ self.db = db_manager
27
+ self.stage1_model = stage1_model
28
+ self.stage2_model = stage2_model
29
+ self.fallback_model = fallback_model
30
+
31
+ def _extract_json_block(self, text: str) -> Dict[str, Any]:
32
+ """Isolate and extract raw JSON strings from wrapper prose."""
33
+ try:
34
+ match = re.search(r"\{.*\}", text, re.DOTALL)
35
+ if match:
36
+ return json.loads(match.group(0))
37
+ return json.loads(text)
38
+ except (json.JSONDecodeError, AttributeError) as exc:
39
+ logger.warning("JSON validation extraction block parsing error: %s", exc)
40
+ return {}
41
+
42
+ def invoke_stage1_extractor(
43
+ self,
44
+ user_prompt: str,
45
+ ) -> Tuple[Optional[str], Dict[str, Any]]:
46
+ """Use the LFM model to parse structural tokens and intents."""
47
+ system_instructions = (
48
+ "You are a structural parser. Extract the target 'intent' and all key "
49
+ "entities or arguments from the prompt. Respond strictly using valid "
50
+ "JSON configuration with keys: 'intent' (string) and 'variables' "
51
+ "(object). Do not output markdown sentences outside the JSON layout."
52
+ )
53
+
54
+ try:
55
+ logger.info("Invoking Stage 1 Routing Parser (%s)...", self.stage1_model)
56
+ response = ollama.generate(
57
+ model=self.stage1_model,
58
+ prompt=f"System: {system_instructions}\nUser Prompt: {user_prompt}",
59
+ options={"temperature": 0.0},
60
+ )
61
+ parsed_data = self._extract_json_block(response.get("response", ""))
62
+ intent = parsed_data.get("intent")
63
+ variables = parsed_data.get("variables", {})
64
+ return intent, variables
65
+ except Exception as exc:
66
+ logger.error("Stage 1 extraction pipeline failure: %s", exc)
67
+ return None, {}
68
+
69
+ def invoke_stage2_worker(
70
+ self,
71
+ session_id: str,
72
+ current_intent: str,
73
+ active_context: Dict[str, Any],
74
+ ) -> str:
75
+ """Execute the task with the specialized Granite worker model."""
76
+ del session_id
77
+
78
+ serialized_context = json.dumps(active_context)
79
+ system_instructions = (
80
+ f"You are a specialized worker model executing the following action: "
81
+ f"{current_intent}. Your state variables are loaded cleanly from "
82
+ f"external database cells: {serialized_context}. Formulate an exact, "
83
+ "localized solution based on these database records."
84
+ )
85
+
86
+ try:
87
+ logger.info("Invoking Stage 2 Local Worker (%s)...", self.stage2_model)
88
+ response = ollama.generate(
89
+ model=self.stage2_model,
90
+ prompt=(
91
+ f"System: {system_instructions}\n"
92
+ "Process the step based on active memory states."
93
+ ),
94
+ options={"temperature": 0.3},
95
+ )
96
+ output_text = response.get("response", "").strip()
97
+
98
+ if not output_text or len(output_text) < 5:
99
+ raise ValueError(
100
+ "Stage 2 generation dropped below confidence threshold boundaries."
101
+ )
102
+
103
+ return output_text
104
+ except Exception as exc:
105
+ logger.warning(
106
+ "Stage 2 logic execution failed: %s. "
107
+ "Handing off execution to fallback engine.",
108
+ exc,
109
+ )
110
+ return "ESCALATE"
111
+
112
+ def escalate_to_3b(
113
+ self,
114
+ session_id: str,
115
+ user_prompt: str,
116
+ active_context: Dict[str, Any],
117
+ ) -> str:
118
+ """Handle complex or failed execution paths with the heavier Granite model."""
119
+ logger.info(
120
+ "Escalation triggered. Initializing Stage 3 Frontier Core (%s)...",
121
+ self.fallback_model,
122
+ )
123
+ self.db.update_session_state(
124
+ session_id,
125
+ intent="COMPLEX_FALLBACK",
126
+ is_escalated=1,
127
+ )
128
+
129
+ serialized_context = json.dumps(active_context)
130
+ system_instructions = (
131
+ "You are an enterprise coordinator processing an escalated edge case. "
132
+ "A fast sub-billion cascade pipeline was unable to resolve this task "
133
+ "safely. Review the user's prompt alongside the recovered database "
134
+ f"context states: {serialized_context}. Deliver a complete, "
135
+ "high-confidence response."
136
+ )
137
+
138
+ response = ollama.generate(
139
+ model=self.fallback_model,
140
+ prompt=f"System: {system_instructions}\nUser Request: {user_prompt}",
141
+ )
142
+ return response.get("response", "").strip()
143
+
144
+ def run_pipeline(self, session_id: str, user_prompt: str) -> str:
145
+ """Coordinate models and sync operational state."""
146
+ logger.info(
147
+ "--- Beginning Pipeline Processing Loop for Session: %s ---",
148
+ session_id,
149
+ )
150
+
151
+ session = self.db.create_or_get_session(session_id)
152
+ self.db.append_chat_history(session_id, "user", user_prompt)
153
+
154
+ if session["is_escalated"] == 1:
155
+ active_context = self.db.fetch_active_context(session_id)
156
+ final_output = self.escalate_to_3b(session_id, user_prompt, active_context)
157
+ self.db.append_chat_history(session_id, "assistant", final_output)
158
+ return final_output
159
+
160
+ intent, variables = self.invoke_stage1_extractor(user_prompt)
161
+
162
+ if intent:
163
+ logger.info(
164
+ "Stage 1 Success. Intent Extracted: '%s'. Variable Sync Count: %s",
165
+ intent,
166
+ len(variables),
167
+ )
168
+ self.db.update_session_state(session_id, intent=intent, is_escalated=0)
169
+ self.db.save_extracted_variables(session_id, variables)
170
+ else:
171
+ logger.warning(
172
+ "Stage 1 failed to interpret input safely. "
173
+ "Escalating straight to Stage 3."
174
+ )
175
+ active_context = self.db.fetch_active_context(session_id)
176
+ final_output = self.escalate_to_3b(session_id, user_prompt, active_context)
177
+ self.db.append_chat_history(session_id, "assistant", final_output)
178
+ return final_output
179
+
180
+ active_context = self.db.fetch_active_context(session_id)
181
+ worker_output = self.invoke_stage2_worker(session_id, intent, active_context)
182
+
183
+ if worker_output == "ESCALATE":
184
+ final_output = self.escalate_to_3b(session_id, user_prompt, active_context)
185
+ else:
186
+ logger.info("Stage 2 resolved task within safe confidence boundaries.")
187
+ final_output = worker_output
188
+
189
+ self.db.append_chat_history(session_id, "assistant", final_output)
190
+ return final_output
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: granite-sqlite-lfm
3
+ Version: 0.1.0
4
+ Summary: SQLite-backed local Ollama cascade orchestrator.
5
+ Author: Author Name
6
+ License: MIT
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: ollama
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest; extra == "dev"
13
+ Requires-Dist: ruff; extra == "dev"
14
+ Requires-Dist: build; extra == "dev"
15
+ Requires-Dist: twine; extra == "dev"
16
+ Dynamic: license-file
17
+
18
+ # granite-sqlite-lfm
19
+
20
+ SQLite-backed local Ollama cascade orchestrator.
21
+
22
+ This project runs a local multi-stage model pipeline using Ollama and SQLite. It stores session state, extracted context variables, and conversation history in a local SQLite database, then routes user prompts through a lightweight extraction model, a worker model, and a fallback escalation model when needed.
23
+
24
+ ## Features
25
+
26
+ * SQLite-backed session and context storage
27
+ * Full-text searchable conversation history using SQLite FTS5
28
+ * Local Ollama model orchestration
29
+ * Stage 1 intent and variable extraction
30
+ * Stage 2 task execution
31
+ * Stage 3 fallback escalation
32
+ * Import-safe package structure
33
+ * CLI support with custom prompts and database paths
34
+
35
+ ## Requirements
36
+
37
+ * Python 3.9+
38
+ * Ollama installed and running locally
39
+ * Local Ollama models available:
40
+
41
+ * `lfm2.5:230m`
42
+ * `ibm-granite/granite-4.0-h-350m-instruct`
43
+ * `granite4.1:3b`
44
+
45
+ ## Installation
46
+
47
+ Create and activate a virtual environment:
48
+
49
+ ```bash
50
+ python -m venv .venv
51
+ source .venv/bin/activate
52
+ ```
53
+
54
+ On Windows PowerShell:
55
+
56
+ ```powershell
57
+ .venv\Scripts\Activate.ps1
58
+ ```
59
+
60
+ Install the package in editable development mode:
61
+
62
+ ```bash
63
+ python -m pip install -e ".[dev]"
64
+ ```
65
+
66
+ ## Usage
67
+
68
+ Run the package with the default demo prompts:
69
+
70
+ ```bash
71
+ python -m granite_sqlite_lfm
72
+ ```
73
+
74
+ Or use the console command:
75
+
76
+ ```bash
77
+ granite-sqlite-lfm
78
+ ```
79
+
80
+ Run a custom prompt:
81
+
82
+ ```bash
83
+ granite-sqlite-lfm --prompt "Book a conference room for 15 attendees tomorrow at 3 PM."
84
+ ```
85
+
86
+ Use a custom SQLite database path:
87
+
88
+ ```bash
89
+ granite-sqlite-lfm --db-path ./local_context.db
90
+ ```
91
+
92
+ Use a custom session ID:
93
+
94
+ ```bash
95
+ granite-sqlite-lfm --session-id enterprise_user_session_101
96
+ ```
97
+
98
+ Run multiple prompts in sequence:
99
+
100
+ ```bash
101
+ granite-sqlite-lfm \
102
+ --prompt "Book a conference room for 15 attendees tomorrow." \
103
+ --prompt "Change the attendee count to 45."
104
+ ```
105
+
106
+ ## Project Structure
107
+
108
+ ```text
109
+ granite-sqlite-lfm/
110
+ ├── pyproject.toml
111
+ ├── README.md
112
+ ├── LICENSE
113
+ ├── .gitignore
114
+ ├── src/
115
+ │ └── granite_sqlite_lfm/
116
+ │ ├── __init__.py
117
+ │ ├── __main__.py
118
+ │ ├── cli.py
119
+ │ ├── config.py
120
+ │ ├── database.py
121
+ │ └── orchestrator.py
122
+ ├── tests/
123
+ │ ├── test_database.py
124
+ │ └── test_orchestrator.py
125
+ └── examples/
126
+ └── demo.py
127
+ ```
128
+
129
+ ## Development
130
+
131
+ Install development dependencies:
132
+
133
+ ```bash
134
+ python -m pip install -e ".[dev]"
135
+ ```
136
+
137
+ Run tests:
138
+
139
+ ```bash
140
+ pytest
141
+ ```
142
+
143
+ Run Ruff linting:
144
+
145
+ ```bash
146
+ ruff check .
147
+ ```
148
+
149
+ Build the package:
150
+
151
+ ```bash
152
+ python -m build
153
+ ```
154
+
155
+ Check distribution artifacts:
156
+
157
+ ```bash
158
+ twine check dist/*
159
+ ```
160
+
161
+ ## Publishing
162
+
163
+ Before publishing, review the package metadata in `pyproject.toml`, including:
164
+
165
+ * package name
166
+ * author name
167
+ * license
168
+ * description
169
+ * supported Python version
170
+ * dependencies
171
+ * console script name
172
+
173
+ Then build and upload:
174
+
175
+ ```bash
176
+ python -m build
177
+ twine check dist/*
178
+ twine upload dist/*
179
+ ```
180
+
181
+ ## Notes
182
+
183
+ This project depends on a working local Ollama installation. The included tests should avoid real model calls and focus on package importability, SQLite behavior, JSON parsing, and CLI smoke behavior.
184
+
185
+ The default SQLite database file is:
186
+
187
+ ```text
188
+ cascade_context.db
189
+ ```
190
+
191
+ This file is local runtime state and should not be committed to version control.
@@ -0,0 +1,12 @@
1
+ granite_sqlite_lfm/__init__.py,sha256=Y6r6RxuIOxtsbIL_1z0EOLxcevNv4rcTQrei1jkLZgg,79
2
+ granite_sqlite_lfm/__main__.py,sha256=8hlUU2E35-HG7k9rIAvKgkXhHEg8UMlqDeLCUg_sLTc,81
3
+ granite_sqlite_lfm/cli.py,sha256=7hJwF-kAlI1ZSwh6RvnLGe0exu9BNZs7nOF8MQ9e3SE,1854
4
+ granite_sqlite_lfm/config.py,sha256=bSNKMSQHgNYdskQ5FXBDkwy1dOty0V4hbVMsH2DKGw0,509
5
+ granite_sqlite_lfm/database.py,sha256=oRXIekU3S1nSzH_obXeklEnvGswLvH7mqt7lh8vdYUA,7893
6
+ granite_sqlite_lfm/orchestrator.py,sha256=iR_xF8j_CEtUMvFVOq9RIVK6hvrrhSEqldjpy3nQwVE,7580
7
+ granite_sqlite_lfm-0.1.0.dist-info/licenses/LICENSE,sha256=lNSfV6H9adn_yivkXZvLvJhSCFhUf5lC-5Z__FOWLvo,1094
8
+ granite_sqlite_lfm-0.1.0.dist-info/METADATA,sha256=AJSmCK6dnda2GrqR_BLHrLsHRIefEO2phvUg5If40hA,3963
9
+ granite_sqlite_lfm-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
10
+ granite_sqlite_lfm-0.1.0.dist-info/entry_points.txt,sha256=bJuscpx-RUBubQhwq7ZqW5t2t57lA3TkYvUYB42lKA0,67
11
+ granite_sqlite_lfm-0.1.0.dist-info/top_level.txt,sha256=Bx_UdOLlt8b5LJD_FYl7apCABCcCHg5tGLzJkIF80Zs,19
12
+ granite_sqlite_lfm-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ granite-sqlite-lfm = granite_sqlite_lfm.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Julian A. Gonzalez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ granite_sqlite_lfm