flowstatemcp 2.5.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.
- flowstate/__init__.py +34 -0
- flowstate/__main__.py +7 -0
- flowstate/activity.py +224 -0
- flowstate/agent_guide.py +251 -0
- flowstate/app_keys.py +141 -0
- flowstate/approvals.py +974 -0
- flowstate/approve_page.py +565 -0
- flowstate/ask.py +107 -0
- flowstate/autosession.py +480 -0
- flowstate/backup.py +201 -0
- flowstate/brief.py +420 -0
- flowstate/card_offer.py +208 -0
- flowstate/card_taps.py +165 -0
- flowstate/card_trust.py +127 -0
- flowstate/claims.py +461 -0
- flowstate/cleanup.py +619 -0
- flowstate/cli.py +728 -0
- flowstate/cli_data.py +434 -0
- flowstate/cli_more.py +302 -0
- flowstate/cli_review.py +459 -0
- flowstate/cloudflared_check.py +49 -0
- flowstate/conflict_card_ui.py +286 -0
- flowstate/conflict_cards.py +1193 -0
- flowstate/conflict_reopen.py +320 -0
- flowstate/conflicts.py +420 -0
- flowstate/connections.py +33 -0
- flowstate/database.py +2191 -0
- flowstate/dbconn.py +308 -0
- flowstate/deletes.py +860 -0
- flowstate/embeddings.py +354 -0
- flowstate/erase.py +1047 -0
- flowstate/extras.py +71 -0
- flowstate/git_capture.py +157 -0
- flowstate/guard.py +224 -0
- flowstate/handoffs.py +168 -0
- flowstate/history.py +755 -0
- flowstate/history_page.py +276 -0
- flowstate/http_app.py +204 -0
- flowstate/identity.py +387 -0
- flowstate/install_name.py +140 -0
- flowstate/ledger.py +272 -0
- flowstate/legacy_args.py +65 -0
- flowstate/links.py +609 -0
- flowstate/markdown_io.py +242 -0
- flowstate/meaning.py +398 -0
- flowstate/memory_import.py +92 -0
- flowstate/migrations/001_auto_sessions.sql +16 -0
- flowstate/migrations/002_review_queue.sql +33 -0
- flowstate/migrations/003_links.sql +47 -0
- flowstate/migrations/004_review_mode.sql +24 -0
- flowstate/migrations/005_history.sql +21 -0
- flowstate/migrations/006_activity.sql +26 -0
- flowstate/migrations/007_meaning_index.sql +16 -0
- flowstate/migrations/008_git_capture.sql +12 -0
- flowstate/migrations/009_hard_rules.sql +13 -0
- flowstate/migrations/010_handoffs.sql +14 -0
- flowstate/migrations/011_record_meta.sql +13 -0
- flowstate/migrations/012_accountability.sql +71 -0
- flowstate/migrations/013_todo_claims.sql +36 -0
- flowstate/migrations/014_decision_conflicts.sql +41 -0
- flowstate/migrations/015_session_runs.sql +17 -0
- flowstate/migrations/016_write_receipts.sql +35 -0
- flowstate/migrations/017_run_views.sql +26 -0
- flowstate/migrations/018_run_views_upto.sql +4 -0
- flowstate/migrations/019_approvals.sql +47 -0
- flowstate/migrations/020_source_stamps.sql +10 -0
- flowstate/migrations/021_review_links.sql +11 -0
- flowstate/migrations/022_review_start_tickets.sql +10 -0
- flowstate/migrations/023_conflict_cards.sql +68 -0
- flowstate/migrations/024_rule_confirmations.sql +7 -0
- flowstate/migrations/025_confirmed_hash.sql +7 -0
- flowstate/migrations/__init__.py +149 -0
- flowstate/models.py +307 -0
- flowstate/names.py +157 -0
- flowstate/offsite.py +386 -0
- flowstate/offsite_crypto.py +272 -0
- flowstate/paths.py +265 -0
- flowstate/popup.py +238 -0
- flowstate/priority.py +66 -0
- flowstate/privatefs.py +476 -0
- flowstate/project_history.py +710 -0
- flowstate/provenance.py +696 -0
- flowstate/receipts.py +377 -0
- flowstate/relay/__init__.py +72 -0
- flowstate/relay/acme.py +271 -0
- flowstate/relay/api.py +164 -0
- flowstate/relay/cli.py +344 -0
- flowstate/relay/crypto.py +137 -0
- flowstate/relay/ct.py +118 -0
- flowstate/relay/runner.py +177 -0
- flowstate/relay/store.py +191 -0
- flowstate/relay/tunnel.py +413 -0
- flowstate/release_signers +14 -0
- flowstate/remote_auth.py +1219 -0
- flowstate/review.py +320 -0
- flowstate/review_apply.py +140 -0
- flowstate/review_card_ui.py +241 -0
- flowstate/review_cards.py +564 -0
- flowstate/review_mode.py +274 -0
- flowstate/review_page.py +1361 -0
- flowstate/review_phone.py +465 -0
- flowstate/review_tunnel.py +338 -0
- flowstate/routing.py +392 -0
- flowstate/rules.py +418 -0
- flowstate/safety.py +98 -0
- flowstate/saves.py +83 -0
- flowstate/scheduler.py +160 -0
- flowstate/schema.sql +713 -0
- flowstate/search.py +355 -0
- flowstate/secret_store.py +271 -0
- flowstate/secrets_scan.py +135 -0
- flowstate/selfupdate.py +1020 -0
- flowstate/server.py +1299 -0
- flowstate/session_contents.py +382 -0
- flowstate/session_records.py +629 -0
- flowstate/site_style.py +46 -0
- flowstate/stored.py +158 -0
- flowstate/story.py +442 -0
- flowstate/surface.py +173 -0
- flowstate/tasks.py +231 -0
- flowstate/term.py +40 -0
- flowstate/tool_labels.py +104 -0
- flowstate/tooldefs.py +383 -0
- flowstate/tools/__init__.py +118 -0
- flowstate/tools/core.py +545 -0
- flowstate/tools/files.py +416 -0
- flowstate/tools/git_ops.py +1081 -0
- flowstate/tools/intelligence.py +376 -0
- flowstate/tools/learning.py +282 -0
- flowstate/tools/problems.py +159 -0
- flowstate/tools/sessions.py +266 -0
- flowstate/tools/story.py +48 -0
- flowstate/tools/todos.py +79 -0
- flowstate/tools/utils.py +71 -0
- flowstate/tools/variables.py +345 -0
- flowstate/updates.py +482 -0
- flowstate/urls.py +7 -0
- flowstate/waiting.py +828 -0
- flowstate/who.py +302 -0
- flowstatemcp-2.5.0.dist-info/METADATA +88 -0
- flowstatemcp-2.5.0.dist-info/RECORD +143 -0
- flowstatemcp-2.5.0.dist-info/WHEEL +4 -0
- flowstatemcp-2.5.0.dist-info/entry_points.txt +3 -0
flowstate/who.py
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Who did what: one list of recent recorded changes across FlowState's logs (v2, after
|
|
2
|
+
migration 012), newest first, with the app, model, machine and identity source of each.
|
|
3
|
+
|
|
4
|
+
Sources: edit history (edits and undos), the review queue (queued items, approvals,
|
|
5
|
+
rejections), links (added / removed), handoff notes (left / picked up), hard rules (added /
|
|
6
|
+
removed), review-mode changes, records created by a write (activity log), and todo claims
|
|
7
|
+
(claim, renew, release, handoff, override, cleared; migration 013), and possible conflicting
|
|
8
|
+
decisions (flagged, resolved by a replacing decision, dismissed as compatible; 014). Rows written
|
|
9
|
+
before migration 012 show the app name the older columns kept and "not recorded" for the
|
|
10
|
+
rest.
|
|
11
|
+
|
|
12
|
+
Used by the review page ("Who did what") and, read-only, by history(action="who").
|
|
13
|
+
Filters: app, model, machine (each: contains, any case), project id, since / until (local
|
|
14
|
+
time of this computer: "YYYY-MM-DD" or "YYYY-MM-DD HH:MM").
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import sqlite3
|
|
19
|
+
from datetime import datetime, timedelta, timezone
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Optional
|
|
22
|
+
|
|
23
|
+
from . import dbconn
|
|
24
|
+
from . import history, identity
|
|
25
|
+
|
|
26
|
+
PER_PAGE = 50
|
|
27
|
+
MAX_PER_PAGE = 100
|
|
28
|
+
_ID = ("app", "model", "machine", "identity_source")
|
|
29
|
+
_VIA_IN = ", ".join(f"'{x}'" for x in identity.VIA_SOURCES)
|
|
30
|
+
_SIGNED_IN = "instr(COALESCE(u.machine, ''), '(signed in as ')"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class WhoError(Exception):
|
|
34
|
+
def __init__(self, code: str, message: str):
|
|
35
|
+
super().__init__(message)
|
|
36
|
+
self.payload = {"error": code, "message": message}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _tables(conn) -> dict:
|
|
40
|
+
names = [r[0] for r in conn.execute("SELECT name FROM sqlite_master WHERE type='table'")]
|
|
41
|
+
return {n: {r[1] for r in conn.execute(f'PRAGMA table_info("{n}")')} for n in names}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _id_cols(cols: set, prefix: str = "", fallback_app: str = "NULL") -> str:
|
|
45
|
+
"""app, model, machine, identity_source expressions for one source (NULL before 012)."""
|
|
46
|
+
out = []
|
|
47
|
+
for f in _ID:
|
|
48
|
+
c = prefix + f
|
|
49
|
+
expr = c if c in cols else "NULL"
|
|
50
|
+
if f == "app":
|
|
51
|
+
expr = f"COALESCE({expr}, {fallback_app})" if expr != "NULL" else fallback_app
|
|
52
|
+
out.append(f"{expr} AS {f}")
|
|
53
|
+
return ", ".join(out)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _sel(at: str, ids: str, project: str, rtype: str, rid: str, what: str, kind: str,
|
|
57
|
+
extra: str, rest: str) -> str:
|
|
58
|
+
return (f"SELECT {at} AS at, {ids}, {project} AS project_id, {rtype} AS record_type, "
|
|
59
|
+
f"{rid} AS record_id, {what} AS what, '{kind}' AS kind, id AS ref, "
|
|
60
|
+
f"{extra} AS extra {rest}")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _sources(t: dict) -> list[str]:
|
|
64
|
+
"""One SELECT per kind of event, all with the same columns:
|
|
65
|
+
at, app, model, machine, identity_source, project_id, record_type, record_id, what,
|
|
66
|
+
kind, ref, extra."""
|
|
67
|
+
q = []
|
|
68
|
+
if "record_history" in t:
|
|
69
|
+
c = t["record_history"]
|
|
70
|
+
q.append(_sel("created_at", _id_cols(c, fallback_app="client"), "project_id",
|
|
71
|
+
"table_name", "record_id", "tool", "edit", "undone_at",
|
|
72
|
+
# a creation is listed once, from the activity log (and the review queue)
|
|
73
|
+
"FROM record_history WHERE NOT (old_row IS NULL AND (tool LIKE 'create/%' "
|
|
74
|
+
"OR tool LIKE 'approve/%'))"))
|
|
75
|
+
if "review_items" in t:
|
|
76
|
+
c = t["review_items"]
|
|
77
|
+
q.append(_sel("created_at", _id_cols(c, fallback_app="source"), "project_id",
|
|
78
|
+
"'review_item'", "id",
|
|
79
|
+
"'queued ' || kind || ' for review: ' || substr(summary, 1, 60)",
|
|
80
|
+
"queued", "NULL", "FROM review_items"))
|
|
81
|
+
q.append(_sel("decided_at", _id_cols(c, "decided_", "decided_by"), "project_id",
|
|
82
|
+
"'review_item'", "id",
|
|
83
|
+
"status || ' review item #' || id || CASE WHEN result_table IS NOT NULL "
|
|
84
|
+
"AND result_id IS NOT NULL THEN ' (became ' || result_table || ' #' "
|
|
85
|
+
"|| result_id || ')' ELSE '' END",
|
|
86
|
+
"decided", "NULL", "FROM review_items WHERE decided_at IS NOT NULL"))
|
|
87
|
+
if "record_links" in t:
|
|
88
|
+
c = t["record_links"]
|
|
89
|
+
target = "COALESCE(url, to_type || ' #' || to_id)"
|
|
90
|
+
q.append(_sel("created_at", _id_cols(c, fallback_app="created_by"), "from_project_id",
|
|
91
|
+
"'link'", "id",
|
|
92
|
+
f"'linked ' || from_type || ' #' || from_id || ' ' || link_type || ' ' "
|
|
93
|
+
f"|| {target}", "link_added", "NULL", "FROM record_links"))
|
|
94
|
+
q.append(_sel("removed_at", _id_cols(c, "removed_", "removed_by"), "from_project_id",
|
|
95
|
+
"'link'", "id",
|
|
96
|
+
f"'removed link #' || id || ' (' || link_type || ' ' || {target} || ')'",
|
|
97
|
+
"link_removed", "NULL", "FROM record_links WHERE removed_at IS NOT NULL"))
|
|
98
|
+
if "handoff_notes" in t:
|
|
99
|
+
c = t["handoff_notes"]
|
|
100
|
+
q.append(_sel("created_at", _id_cols(c, fallback_app="created_by"), "project_id",
|
|
101
|
+
"'handoff'", "id", "'left handoff: ' || substr(where_i_was, 1, 60)",
|
|
102
|
+
"handoff_left", "NULL", "FROM handoff_notes"))
|
|
103
|
+
q.append(_sel("picked_up_at", _id_cols(c, "picked_up_", "picked_up_by"), "project_id",
|
|
104
|
+
"'handoff'", "id", "'picked up handoff H' || id", "handoff_picked_up",
|
|
105
|
+
"NULL", "FROM handoff_notes WHERE picked_up_at IS NOT NULL"))
|
|
106
|
+
if "project_rules" in t:
|
|
107
|
+
c = t["project_rules"]
|
|
108
|
+
q.append(_sel("created_at", _id_cols(c, fallback_app="created_by"), "project_id",
|
|
109
|
+
"'rule'", "id", "'added hard rule: ' || substr(rule, 1, 60)",
|
|
110
|
+
"rule_added", "NULL", "FROM project_rules"))
|
|
111
|
+
q.append(_sel("removed_at", _id_cols(c, "removed_", "removed_by"), "project_id",
|
|
112
|
+
"'rule'", "id", "'removed hard rule R' || id", "rule_removed", "NULL",
|
|
113
|
+
"FROM project_rules WHERE removed_at IS NOT NULL"))
|
|
114
|
+
if "review_mode_log" in t:
|
|
115
|
+
c = t["review_mode_log"]
|
|
116
|
+
q.append(_sel("changed_at", _id_cols(c, fallback_app="client"),
|
|
117
|
+
"CASE WHEN scope LIKE 'project:%' THEN CAST(substr(scope, 9) AS INTEGER) END",
|
|
118
|
+
"'review_mode'", "id",
|
|
119
|
+
"'review mode ' || COALESCE(new_mode, 'override cleared') || ' (' || scope "
|
|
120
|
+
"|| ')'", "mode", "NULL", "FROM review_mode_log"))
|
|
121
|
+
if "activity_log" in t and "record_type" in t["activity_log"]:
|
|
122
|
+
c = t["activity_log"]
|
|
123
|
+
q.append(_sel("at", _id_cols(c, fallback_app="app"), "project_id", "record_type",
|
|
124
|
+
"record_id",
|
|
125
|
+
"'created ' || record_type || ' #' || record_id || ' (' || tool "
|
|
126
|
+
"|| COALESCE('/' || action, '') || ')'", "created", "NULL",
|
|
127
|
+
"FROM activity_log WHERE record_type IS NOT NULL AND ok = 1"))
|
|
128
|
+
if "todo_claim_events" in t:
|
|
129
|
+
c = t["todo_claim_events"]
|
|
130
|
+
q.append(f"SELECT at, {_id_cols(c)}, project_id, 'todo' AS record_type, todo_id AS "
|
|
131
|
+
f"record_id, summary AS what, 'todo_' || event AS kind, id AS ref, NULL AS "
|
|
132
|
+
f"extra FROM todo_claim_events")
|
|
133
|
+
if "decision_conflicts" in t:
|
|
134
|
+
c = t["decision_conflicts"]
|
|
135
|
+
pair = "'D' || new_id || ' vs D' || old_id"
|
|
136
|
+
q.append(_sel("created_at", _id_cols(c), "project_id", "'decision'", "new_id",
|
|
137
|
+
f"'possible conflict flagged: ' || {pair} || ' (score ' || "
|
|
138
|
+
f"printf('%.2f', score) || ')'", "conflict_flagged", "NULL",
|
|
139
|
+
"FROM decision_conflicts"))
|
|
140
|
+
q.append(_sel("resolved_at", _id_cols(c, "resolved_"), "project_id", "'decision'",
|
|
141
|
+
"new_id",
|
|
142
|
+
f"'possible conflict ' || {pair} || CASE status WHEN 'resolved_replaced' "
|
|
143
|
+
f"THEN ' resolved: D' || resolved_by_decision || ' replaced one' "
|
|
144
|
+
f"ELSE ' dismissed: the user said they are compatible' END",
|
|
145
|
+
"conflict_resolved", "NULL",
|
|
146
|
+
"FROM decision_conflicts WHERE resolved_at IS NOT NULL"))
|
|
147
|
+
return q
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def parse_time(value, end: bool = False) -> Optional[str]:
|
|
151
|
+
"""Local "YYYY-MM-DD[ HH:MM[:SS]]" -> UTC "YYYY-MM-DD HH:MM:SS" (how FlowState stores
|
|
152
|
+
times). A bare date as `end` means the end of that day."""
|
|
153
|
+
if value in (None, ""):
|
|
154
|
+
return None
|
|
155
|
+
text = str(value).strip().replace("T", " ")
|
|
156
|
+
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d"):
|
|
157
|
+
try:
|
|
158
|
+
dt = datetime.strptime(text, fmt)
|
|
159
|
+
except ValueError:
|
|
160
|
+
continue
|
|
161
|
+
if fmt == "%Y-%m-%d" and end:
|
|
162
|
+
dt += timedelta(days=1, seconds=-1)
|
|
163
|
+
return dt.astimezone().astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
|
164
|
+
raise WhoError("bad_time", f"Times look like 2026-10-17 or 2026-10-17 14:30 (local time), "
|
|
165
|
+
f"not {value!r}.")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def local_time(utc: Optional[str]) -> str:
|
|
169
|
+
if not utc:
|
|
170
|
+
return ""
|
|
171
|
+
try:
|
|
172
|
+
dt = datetime.strptime(utc[:19], "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
|
|
173
|
+
except ValueError:
|
|
174
|
+
return utc
|
|
175
|
+
return dt.astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _undoable(conn, row: dict) -> bool:
|
|
179
|
+
"""The edit history's own rule: the last not-undone edit of a record can be undone."""
|
|
180
|
+
if row["kind"] != "edit" or row["extra"] or row["project_id"] is None \
|
|
181
|
+
or row["record_type"] not in history.TYPE_OF:
|
|
182
|
+
return False
|
|
183
|
+
last = conn.execute("SELECT MAX(id) FROM record_history WHERE table_name = ? AND "
|
|
184
|
+
"record_id = ? AND undone_at IS NULL",
|
|
185
|
+
(row["record_type"], row["record_id"])).fetchone()[0]
|
|
186
|
+
return last == row["ref"]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _edit_what(conn, row: dict) -> str:
|
|
190
|
+
h = conn.execute("SELECT old_row, new_row, undo_of FROM record_history WHERE id = ?",
|
|
191
|
+
(row["ref"],)).fetchone()
|
|
192
|
+
if h is None:
|
|
193
|
+
return row["what"] or ""
|
|
194
|
+
old = json.loads(h["old_row"]) if h["old_row"] else None
|
|
195
|
+
new = json.loads(h["new_row"]) if h["new_row"] else None
|
|
196
|
+
ch = history._changed_fields(old, new)
|
|
197
|
+
what = "created" if ch.get("created") else "deleted" if ch.get("deleted") else \
|
|
198
|
+
", ".join(sorted(ch)) or "no field changes"
|
|
199
|
+
out = f"{row['what']}: {what}"
|
|
200
|
+
if row["extra"]:
|
|
201
|
+
out += " (undone)"
|
|
202
|
+
return out[:120]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
_TYPE_OF_EVENT = {"link_added": "link", "link_removed": "link", "handoff_left": "handoff",
|
|
206
|
+
"handoff_picked_up": "handoff", "rule_added": "rule", "rule_removed": "rule",
|
|
207
|
+
"queued": "review_item", "decided": "review_item", "mode": "review_mode_change"}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _session_of(conn, row: dict, rtype: Optional[str], has: dict) -> Optional[int]:
|
|
211
|
+
"""The automatic session (sessions.id) behind a row, from the 2.4 run ledger, so two
|
|
212
|
+
windows of one app are told apart. None when it wasn't recorded (before 2.4)."""
|
|
213
|
+
if "run_writes" not in has:
|
|
214
|
+
return None
|
|
215
|
+
if row["kind"] == "edit":
|
|
216
|
+
r = conn.execute("SELECT w.session_id FROM record_history h JOIN run_writes w "
|
|
217
|
+
"ON w.change_id = h.edit_id WHERE h.id = ?", (row["ref"],)).fetchone()
|
|
218
|
+
return r[0] if r else None
|
|
219
|
+
if row["kind"] == "queued" and "session_id" in has.get("review_items", ()):
|
|
220
|
+
r = conn.execute("SELECT session_id FROM review_items WHERE id = ?", (row["ref"],)).fetchone()
|
|
221
|
+
if r and r[0]:
|
|
222
|
+
return r[0]
|
|
223
|
+
if row["kind"].startswith("todo_") and "session_runs" in has:
|
|
224
|
+
r = conn.execute(
|
|
225
|
+
"SELECT r.session_id FROM todo_claim_events e JOIN session_runs r ON r.conn_key = e.session "
|
|
226
|
+
"JOIN auto_sessions a ON a.session_id = r.session_id AND a.project_id IS e.project_id "
|
|
227
|
+
"WHERE e.id = ? ORDER BY r.session_id DESC LIMIT 1", (row["ref"],)).fetchone()
|
|
228
|
+
return r[0] if r else None
|
|
229
|
+
kind = _TYPE_OF_EVENT.get(row["kind"], rtype)
|
|
230
|
+
if not kind or row["record_id"] is None:
|
|
231
|
+
return None
|
|
232
|
+
r = conn.execute("SELECT session_id FROM run_writes WHERE status = 'saved' AND records LIKE ? "
|
|
233
|
+
"ORDER BY abs(julianday(finished_at) - julianday(?)) LIMIT 1",
|
|
234
|
+
(f'%"{kind}:{row["record_id"]}"%', row["at"])).fetchone()
|
|
235
|
+
return r[0] if r else None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def recent(db_path: Path, app: Optional[str] = None, model: Optional[str] = None,
|
|
239
|
+
machine: Optional[str] = None, project_id: Optional[int] = None,
|
|
240
|
+
since=None, until=None, page: int = 1, per_page: int = PER_PAGE) -> dict:
|
|
241
|
+
"""{"rows": [...], "total": n, "page": p, "pages": n, "per_page": k}."""
|
|
242
|
+
page = max(1, int(page or 1))
|
|
243
|
+
per_page = max(1, min(int(per_page or PER_PAGE), MAX_PER_PAGE))
|
|
244
|
+
since_u, until_u = parse_time(since), parse_time(until, end=True)
|
|
245
|
+
conn = dbconn.connect(str(db_path), timeout=5.0)
|
|
246
|
+
conn.row_factory = sqlite3.Row
|
|
247
|
+
try:
|
|
248
|
+
has = _tables(conn)
|
|
249
|
+
parts = _sources(has)
|
|
250
|
+
if not parts:
|
|
251
|
+
return {"rows": [], "total": 0, "page": 1, "pages": 1, "per_page": per_page}
|
|
252
|
+
where, params = ["u.at IS NOT NULL"], []
|
|
253
|
+
for col, val in (("app", app), ("model", model), ("machine", machine)):
|
|
254
|
+
if val in (None, ""):
|
|
255
|
+
continue
|
|
256
|
+
test = f"instr(lower(COALESCE(u.{col}, '')), lower(?)) > 0"
|
|
257
|
+
params.append(str(val).strip())
|
|
258
|
+
if col == "app": # also the key / token the app signed in with (identity.via)
|
|
259
|
+
test = f"({test} OR (u.identity_source IN ({_VIA_IN}) AND {_SIGNED_IN} > 0 " \
|
|
260
|
+
f"AND instr(lower(substr(u.machine, {_SIGNED_IN})), lower(?)) > 0))"
|
|
261
|
+
params.append(str(val).strip())
|
|
262
|
+
where.append(test)
|
|
263
|
+
if project_id is not None:
|
|
264
|
+
where.append("u.project_id = ?")
|
|
265
|
+
params.append(int(project_id))
|
|
266
|
+
if since_u:
|
|
267
|
+
where.append("u.at >= ?")
|
|
268
|
+
params.append(since_u)
|
|
269
|
+
if until_u:
|
|
270
|
+
where.append("u.at <= ?")
|
|
271
|
+
params.append(until_u)
|
|
272
|
+
union = " UNION ALL ".join(parts)
|
|
273
|
+
cond = " AND ".join(where)
|
|
274
|
+
total = conn.execute(f"SELECT COUNT(*) FROM ({union}) u WHERE {cond}", params).fetchone()[0]
|
|
275
|
+
rows = [dict(r) for r in conn.execute(
|
|
276
|
+
f"""SELECT u.*, p.name AS project FROM ({union}) u
|
|
277
|
+
LEFT JOIN projects p ON p.id = u.project_id WHERE {cond}
|
|
278
|
+
ORDER BY u.at DESC, u.kind, u.ref DESC LIMIT ? OFFSET ?""",
|
|
279
|
+
(*params, per_page, (page - 1) * per_page))]
|
|
280
|
+
out = []
|
|
281
|
+
for r in rows:
|
|
282
|
+
undo = _undoable(conn, r)
|
|
283
|
+
what = _edit_what(conn, r) if r["kind"] == "edit" else (r["what"] or "")
|
|
284
|
+
rtype = history.type_of(r["record_type"]) if r["kind"] == "edit" else r["record_type"]
|
|
285
|
+
out.append({"at": local_time(r["at"]), "at_utc": r["at"], "app": r["app"],
|
|
286
|
+
"model": r["model"], "machine": r["machine"],
|
|
287
|
+
"identity_source": r["identity_source"],
|
|
288
|
+
"identity": identity.label(r["identity_source"]),
|
|
289
|
+
# the relay / own-tunnel sign-in the app came in on (its name is the
|
|
290
|
+
# app's own claim there)
|
|
291
|
+
**({"via": v} if (v := identity.via(r["machine"], r["identity_source"]))
|
|
292
|
+
else {}),
|
|
293
|
+
"session": _session_of(conn, r, rtype, has),
|
|
294
|
+
"project_id": r["project_id"], "project": r["project"],
|
|
295
|
+
"record_type": rtype, "record_id": r["record_id"],
|
|
296
|
+
"what": " ".join(what.split())[:120], "event": r["kind"],
|
|
297
|
+
"undo": {"record_type": rtype, "record_id": r["record_id"],
|
|
298
|
+
"project_id": r["project_id"]} if undo else None})
|
|
299
|
+
return {"rows": out, "total": total, "page": page, "per_page": per_page,
|
|
300
|
+
"pages": max(1, -(-total // per_page))}
|
|
301
|
+
finally:
|
|
302
|
+
conn.close()
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flowstatemcp
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: Local-first shared project memory for AI apps (MCP server)
|
|
5
|
+
Project-URL: Homepage, https://flowstatemcp.com
|
|
6
|
+
Project-URL: Repository, https://github.com/dialectforge/FlowState
|
|
7
|
+
Project-URL: Changelog, https://github.com/dialectforge/FlowState/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Hosted, https://flowstatemcp.com/hosted
|
|
9
|
+
Author: John Martin
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: ai,flowstatemcp,local-first,mcp,memory,model-context-protocol,sqlite
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: mcp<2,>=1.30
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: httpx2; extra == 'dev'
|
|
27
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: embeddings
|
|
31
|
+
Requires-Dist: sentence-transformers>=2.2.0; extra == 'embeddings'
|
|
32
|
+
Requires-Dist: sqlite-vec>=0.1.0; extra == 'embeddings'
|
|
33
|
+
Provides-Extra: offsite
|
|
34
|
+
Requires-Dist: cryptography>=42; extra == 'offsite'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# flowstatemcp
|
|
38
|
+
|
|
39
|
+
Local-first shared project memory for AI apps. One SQLite file on your computer holds the
|
|
40
|
+
todos, changes, decisions, problems, and lessons your AI apps share. The import package is
|
|
41
|
+
`flowstate`. The PyPI name is `flowstatemcp`, because `flowstate` is a different project.
|
|
42
|
+
|
|
43
|
+
- Site: https://flowstatemcp.com
|
|
44
|
+
- Hosted (no install): https://flowstatemcp.com/hosted
|
|
45
|
+
- Source: https://github.com/dialectforge/FlowState
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
You need Python 3.11+ and [uv](https://docs.astral.sh/uv/getting-started/installation/) for the
|
|
50
|
+
one-command form.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uvx flowstatemcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That starts the stdio MCP server. These do the same thing:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pipx run flowstatemcp
|
|
60
|
+
pip install flowstatemcp
|
|
61
|
+
flowstatemcp
|
|
62
|
+
flowstate
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`pip install flowstate` does not install this project.
|
|
66
|
+
|
|
67
|
+
The git clone is the fallback when you want `setup_flowstate.py` to write app configs, schedule
|
|
68
|
+
backups, and install the FlowState skill. See the repository
|
|
69
|
+
[README](https://github.com/dialectforge/FlowState/blob/main/README.md).
|
|
70
|
+
|
|
71
|
+
## Run
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
flowstatemcp # stdio (what desktop apps start)
|
|
75
|
+
flowstate # the same server
|
|
76
|
+
python -m flowstate --transport http --host 127.0.0.1 --port 8766
|
|
77
|
+
flowstate --help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The database is `FLOWSTATE_DB` if set, otherwise the per-OS default in the repository AGENTS.md.
|
|
81
|
+
|
|
82
|
+
A plain `pip install flowstatemcp` (or of a built wheel) includes the base schema
|
|
83
|
+
(`flowstate/schema.sql`), the migrations, and `release_signers`. `flowstate update` only works
|
|
84
|
+
in a git clone set up by `setup_flowstate.py`. Like every FlowState 2.4.0 or later, it checks
|
|
85
|
+
GitHub once a day for a newer release (nothing about you or your projects is sent);
|
|
86
|
+
`flowstate update check off` or `FLOWSTATE_UPDATE_CHECK=0` turns that off.
|
|
87
|
+
|
|
88
|
+
Search by meaning is optional; see "Honest limits" in the repository README.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
flowstate/__init__.py,sha256=aQCnanQZE_DnsFZjYUAScEExTYv8XNcR2avvXA0j924,829
|
|
2
|
+
flowstate/__main__.py,sha256=2RlXGEMr0aGU0JwKgyK19D08qnEWTeiqBPCAvcgOb9w,138
|
|
3
|
+
flowstate/activity.py,sha256=-4wht5c3LhGQff9cr0yvEsS31uQl3Wd9VGGiThtibAM,9944
|
|
4
|
+
flowstate/agent_guide.py,sha256=TA-QFlmovbC5U7xpkP8dnQsQBfYaFMFxQm5FZSF1bD4,16145
|
|
5
|
+
flowstate/app_keys.py,sha256=fduGUyoGDzLGqVhqvDtEvj6HIXrst3aYpN3c1h-Lu20,6680
|
|
6
|
+
flowstate/approvals.py,sha256=kCu1HSQ1vgKQdeB97EwqrSMLX1ImWY2h4m-vh8wUJyo,46646
|
|
7
|
+
flowstate/approve_page.py,sha256=deOdd2r8x9OiBlJgTL-PQLqS3DKHlKcigmcJHyDOOAE,29379
|
|
8
|
+
flowstate/ask.py,sha256=1--5VyUssbfIqplJOCX_zhCIF37_LjONuzdxVC6aOKE,5226
|
|
9
|
+
flowstate/autosession.py,sha256=XQVHeHrmLx7-uI56ev04oqCu5fzD1USMSd3vmjCfwhU,23180
|
|
10
|
+
flowstate/backup.py,sha256=2rhxbj5r3y2yd84v-qAmAT9-T4kopkyuUUsPQRoDUz8,7967
|
|
11
|
+
flowstate/brief.py,sha256=ZPgm7B_dNRgUZQkndMuAmKhDLrRMlK_aStJ-sLGbhg4,20529
|
|
12
|
+
flowstate/card_offer.py,sha256=QidtJY7UMeuA2Kr7cBoziyjgmIdhxESr2WUo6ot24NU,9854
|
|
13
|
+
flowstate/card_taps.py,sha256=6pFMLpNdGiBxrIBUOSEZfD8GuM1u5GjNL3eX9kPSX_w,6505
|
|
14
|
+
flowstate/card_trust.py,sha256=lv91lC5ItjhgOsPQeWHTHriEEp3iCF-e8mXTR-cn5wE,5873
|
|
15
|
+
flowstate/claims.py,sha256=5lGA75TUF0DyhvIc2K1Ktc4VrYkrfALjluaOWFtX-zI,21909
|
|
16
|
+
flowstate/cleanup.py,sha256=HjHaNE7u_1JytkXkdOt_uqAjrIXGlsmjHNlmZNY0rEM,31251
|
|
17
|
+
flowstate/cli.py,sha256=eEdu_bn5NTYjX6SdgdeBAUE9UJcH1FRHT9wYeAIs4oA,33122
|
|
18
|
+
flowstate/cli_data.py,sha256=ZY9MlUkYZSi3kUvig3s_Jtyxt9hQKwssorW4gr3b2qI,19169
|
|
19
|
+
flowstate/cli_more.py,sha256=AEM1-p_jjSkE8gcvej6z6I_BVCxTzJJgY648lpRbjiI,13640
|
|
20
|
+
flowstate/cli_review.py,sha256=TPAWHgcdL0Dv0FRQw1NjK302EOqCKAZ6PKJDj6AXpO0,22069
|
|
21
|
+
flowstate/cloudflared_check.py,sha256=54TxR-g6fSPf1gwJvKqeBDDgXa2xyPgCWKpSAYE2Q2o,2085
|
|
22
|
+
flowstate/conflict_card_ui.py,sha256=5TaSZ57Eul7Dgp_Z9MAprcO39FRrToUScWaySSmGQh0,12936
|
|
23
|
+
flowstate/conflict_cards.py,sha256=S7Vv7DObfe1LQK4-63O-BMZ3_sq9FnpgfkdTTKcjdVQ,56897
|
|
24
|
+
flowstate/conflict_reopen.py,sha256=Pfq6nexeWSHWTcNH_yO76m5VagUQDgHAo5-sibs71zI,17114
|
|
25
|
+
flowstate/conflicts.py,sha256=Dl6Gw6vouA6Viyb6TWDfYN4N8jHTfX5dh_2uwBzo2p8,20875
|
|
26
|
+
flowstate/connections.py,sha256=ot-_RdFaDVDWadR7mLjrlI593gShFFK0cBPOjLXjdOM,1424
|
|
27
|
+
flowstate/database.py,sha256=uXYw89wFhVCMCDhCShhn3-f9llrYPnUHbxm6i1Eu93M,83413
|
|
28
|
+
flowstate/dbconn.py,sha256=UiQWPip93ZevMJ_sNs0ZWQLYMYmdG1PLu2ul4-O51Uk,10936
|
|
29
|
+
flowstate/deletes.py,sha256=J8Y-YhVvMZ3Wp1kSAw92X4udZjr_9UFCHDwgtNZP7Ps,45116
|
|
30
|
+
flowstate/embeddings.py,sha256=DRBplRHI9sQPtVESWtp90bgbJxj36ma0xYh18awLN-o,11304
|
|
31
|
+
flowstate/erase.py,sha256=S0hLtjly6l6KM7yyHrAnh9SpHXsUWPBVomb8NEJ3Clg,54987
|
|
32
|
+
flowstate/extras.py,sha256=um5-tomr3tzPYQxGFDNa6xp2AoWnvhwt1OiA4a7K_-I,3693
|
|
33
|
+
flowstate/git_capture.py,sha256=c6DzO94c1RnlGWkf1ctfN43CQX7N3mXcpKSaYO6_io0,6151
|
|
34
|
+
flowstate/guard.py,sha256=i-hlDi4KqNBDzSFkbF3cHvCeNfWOOaHRVHYaIbO0KVU,9721
|
|
35
|
+
flowstate/handoffs.py,sha256=SN8AHwIKKwkmhQIZdZaf7VQ2Sy-naSJ2ZMjfM8yyk80,7644
|
|
36
|
+
flowstate/history.py,sha256=quTlCo8m5gQFREJxjB3YZBQioBqL4QxjLVf-ncuVzFM,37688
|
|
37
|
+
flowstate/history_page.py,sha256=MLoUr4BSaQGx0wJDvXXnbEI0MYNnSm9P3JWvjl1rw_4,15957
|
|
38
|
+
flowstate/http_app.py,sha256=NRXvCFCnvgjd7rXN7W3_J7sWhAFQJL4y7fccVqyDn-A,11142
|
|
39
|
+
flowstate/identity.py,sha256=af7bUvUbJ8hIjGk-sTIKVcHFFUvXqEFh7IcQohUEBVQ,18656
|
|
40
|
+
flowstate/install_name.py,sha256=XPmZtvl6eBqeORGT-irL4B242sc5IcjtCezP7Axfx54,6067
|
|
41
|
+
flowstate/ledger.py,sha256=jxMRPKN4XEOesDXXeOGFxUU9xcpVEK-nYuC9t9iP_r0,12304
|
|
42
|
+
flowstate/legacy_args.py,sha256=7LNYvMGtY4SB7sUCNK3nkru0WNH6aqVjBCzc9gWgBsU,2950
|
|
43
|
+
flowstate/links.py,sha256=uLDkO3BuBcvJEyhUCQV4e7ED0fh5wdE2pWDlFIfcXf4,28908
|
|
44
|
+
flowstate/markdown_io.py,sha256=4hoPgsFa4A_MiP6TNqmf8go6yAy6OyIhf1EZ8M0JGzg,12028
|
|
45
|
+
flowstate/meaning.py,sha256=1r3abM9MfL3bmfus-6uAFzo_MWWBGrdAcaj0E15Fj1Y,17313
|
|
46
|
+
flowstate/memory_import.py,sha256=dBNMq6vISnv0QLOTKXECYJd-jjU9AFrJI3mIl6Zoazc,3452
|
|
47
|
+
flowstate/models.py,sha256=_5siwfuw_Tc2qTYs2OuOTyvszfZLXdjIporPTQlIMTQ,10928
|
|
48
|
+
flowstate/names.py,sha256=o18363e19WGhN7VPAmRYB8FgMADtSc64ZydIBg2NYU0,8162
|
|
49
|
+
flowstate/offsite.py,sha256=5A1SB_BLqc9DMQh2jYZGGH7Y5W3hWqEo8wqftCednyY,17902
|
|
50
|
+
flowstate/offsite_crypto.py,sha256=PAHsGXAM-nxc-3oOoG07X20UMz-T7dfQlh-XVY-278g,12127
|
|
51
|
+
flowstate/paths.py,sha256=yBc2nY8H7HHuJdKJIED4vrcVpfqx8a47oNhVmbj9Fec,10093
|
|
52
|
+
flowstate/popup.py,sha256=vHnUDloDjH3caxeoHlCfJ8hNj19oS6XQMy-Ws-PaGM8,11373
|
|
53
|
+
flowstate/priority.py,sha256=WtCH8y43esvhp9wEJNRRIFVUh_79C_5HspFlsNH53kY,2654
|
|
54
|
+
flowstate/privatefs.py,sha256=0dX21cSCkOhj5j-385ELUfdCi-Rwi66asSIqxg-i0SI,20701
|
|
55
|
+
flowstate/project_history.py,sha256=OpL64Pw6KXFAU5eUnQGgzoO7rxaGh6qNZOXaTKThXTM,40092
|
|
56
|
+
flowstate/provenance.py,sha256=4qwOR7MfmIV574P8ZYaEAv5Dze3WBhtMoLQaANrwoeg,32167
|
|
57
|
+
flowstate/receipts.py,sha256=Kle_mBX_dIglXK6ttXKB1-HNoW2ykFsoep8B9e8dA4s,17200
|
|
58
|
+
flowstate/release_signers,sha256=CXagqqy01-k3SzP42sbQ2lPdTdzOehnXtB117xqbWag,839
|
|
59
|
+
flowstate/remote_auth.py,sha256=RA8Yl_Rj8BMZSpAruaWaxkqaLqY0RoLDbKs3gsAfTb4,65072
|
|
60
|
+
flowstate/review.py,sha256=6YG9PaFSkBfEMkjCWSvtWNpsvP7RRsDj061L8sU_zek,15017
|
|
61
|
+
flowstate/review_apply.py,sha256=XCwPhzK_qxybOW5hdQZNOVYTIAUpdm6ZkrGrRe1st_o,8053
|
|
62
|
+
flowstate/review_card_ui.py,sha256=WjseaOecFXq7vXNmuHiLoYxlZkLJdzb34esk0o1PT-w,11934
|
|
63
|
+
flowstate/review_cards.py,sha256=IjVl5Y1JdQMEcbUBw3luxMaelPCiGIhu0KrXqFP_Ciw,30509
|
|
64
|
+
flowstate/review_mode.py,sha256=LyieLtGrGTRXW7B3CuMYupKmjztOCko-d91vjW91Sss,11609
|
|
65
|
+
flowstate/review_page.py,sha256=cqGhhmhIqadyw1JUJAzDqlw1CsbH6tXl9XePSHWOLNY,85713
|
|
66
|
+
flowstate/review_phone.py,sha256=rqyPZ4NE4utx0M38GzDq0M07MUev5pOLVO4KlU1-Wn8,24159
|
|
67
|
+
flowstate/review_tunnel.py,sha256=LN3Huxk2bcHA6sRL7hDoomlqQZoCG_TO_QocJPx1mhU,15933
|
|
68
|
+
flowstate/routing.py,sha256=meX1tneapssf1uow7TfJrk9lRpeGvdvpHQivLq09CA4,14868
|
|
69
|
+
flowstate/rules.py,sha256=Nlf9sWMUgoQT-3nkfRc1cARpq54P6gfois8WewGXiTk,19964
|
|
70
|
+
flowstate/safety.py,sha256=zMsV0YK29thmunxUUsy3cgKlEnk-yhctxKAhCqQwkCM,4027
|
|
71
|
+
flowstate/saves.py,sha256=PsohfKICVYpCuRrmuqYR10Uo_v_NJNkylCu6_eTpCSE,3776
|
|
72
|
+
flowstate/scheduler.py,sha256=HX1YGj6QAPTKQZW1_Po349Fb7MKoDTvRcumTttHR97s,7272
|
|
73
|
+
flowstate/schema.sql,sha256=OePIjl8jpsmt_YQMU7tBYFkhCVxyW59tuw4oUXvVGEY,31330
|
|
74
|
+
flowstate/search.py,sha256=tf0aIwQrxSAii1P_Y8yQ3gP-JNBSxKUzAFsCPUyzt74,11495
|
|
75
|
+
flowstate/secret_store.py,sha256=1cVuLhHUXWHNVbeSZz4rU9X5vL3U5Gy9fJxpqeyXEmg,11798
|
|
76
|
+
flowstate/secrets_scan.py,sha256=xC3VXVy_QTdklibZLjMUVbDkYdkXxM4ym1mKs0z5png,5749
|
|
77
|
+
flowstate/selfupdate.py,sha256=KkOEfvP7LCKyXRlPcs7l1fcuOorRRWrAtXKDLPY3gWs,52546
|
|
78
|
+
flowstate/server.py,sha256=Ub7Seiz3GxivpKePAoGXisxL9N3a1bDxFjjq-iA1uw4,63883
|
|
79
|
+
flowstate/session_contents.py,sha256=0w66zI1fy8lKzTdBF6lpDvHUmJlV2RIcQrf_ZUIftXA,18404
|
|
80
|
+
flowstate/session_records.py,sha256=KwZjJ3yBAkXlpUkKHoOCC2MlClwjWCvrCYRoAESJltc,31410
|
|
81
|
+
flowstate/site_style.py,sha256=TxOi1PmychYxbUyfGAanh9n29idUIID_gKRgls_hlHc,2681
|
|
82
|
+
flowstate/stored.py,sha256=W8cg_p6XveN6kFIrf29qx2pu9FveXRev-msDCR0K2pA,7239
|
|
83
|
+
flowstate/story.py,sha256=AXb45TKbI248A531Ioe_X0LTXJctytZ5iDQN9G5mtvE,16194
|
|
84
|
+
flowstate/surface.py,sha256=QK6MGKyftjdGVFKiPfgaWC86lHWGPaW9TDBao0i49rY,8939
|
|
85
|
+
flowstate/tasks.py,sha256=CGCg0fAdcjCo6FFHwQgYNC9zrm6NObSCabyX_5dtJkE,11074
|
|
86
|
+
flowstate/term.py,sha256=NjrYMk5gZjF505NFpTJaEcMGCjJkHKhLETg3-EMPvsE,2021
|
|
87
|
+
flowstate/tool_labels.py,sha256=eKyuxTjkwfWP_JvePeFcMOcndtpcCcHSns6p4Kt6mYw,5849
|
|
88
|
+
flowstate/tooldefs.py,sha256=QXKOFyrWn6QgFetRcNH2HMjj_Raip5JiVqWevuDCMB4,22188
|
|
89
|
+
flowstate/updates.py,sha256=thVuZipaunMo717WC49qZhX2dYcZ4bFb74GSRcU93cs,20328
|
|
90
|
+
flowstate/urls.py,sha256=sw1ckqCJFeunIN8yT-NhIQNAFh6gieaYvF0RkgfsUjQ,334
|
|
91
|
+
flowstate/waiting.py,sha256=Ppi0WZhPJzC_t6qzpNTGZ_EkO0xbmZJohAJ5yHc4sCo,42008
|
|
92
|
+
flowstate/who.py,sha256=NWEoeV8B3adWP-WPI3ulLnSIB2pvbH7SBnLn1B5NHbg,16009
|
|
93
|
+
flowstate/migrations/001_auto_sessions.sql,sha256=mwVa4hxdYEbaZTVMfuiUn8F545HTVDyLheVQAqVL4IA,915
|
|
94
|
+
flowstate/migrations/002_review_queue.sql,sha256=DPTFULR1_IxEUFBHELmGydrWvbsoJB1YMpQKrSe32lE,1967
|
|
95
|
+
flowstate/migrations/003_links.sql,sha256=6uIqrm8wSwJQGxLQUAfBLxQhkzR7OWfSjgnCsnKoCtU,2683
|
|
96
|
+
flowstate/migrations/004_review_mode.sql,sha256=cTb3HNGGMv2pSfIautNrHVpUwn_kfxWAQ6vhSU62rxs,1124
|
|
97
|
+
flowstate/migrations/005_history.sql,sha256=n3jum_P7sQSA_hmh4QHjO_iGAF6IWyFNj1aaCaRjnOM,1159
|
|
98
|
+
flowstate/migrations/006_activity.sql,sha256=t6xk7vF1-W6JoS5Ai4ofaI_gkNQmkw-3n9ckh9h2-DQ,1200
|
|
99
|
+
flowstate/migrations/007_meaning_index.sql,sha256=Wc0eYw69zspFA1fjb-tVtxnBA9luWeSby6PsX2xbKdQ,916
|
|
100
|
+
flowstate/migrations/008_git_capture.sql,sha256=5nsldVzztZtjxxcPW0osb4ftklheDp-7Hbz38FNnlPw,602
|
|
101
|
+
flowstate/migrations/009_hard_rules.sql,sha256=xStRe0VCU6GHN7a1AZSGTkpSqPtioq_4-tV6DM3fJv4,680
|
|
102
|
+
flowstate/migrations/010_handoffs.sql,sha256=DVezwjuiKVAUKDCpb0Yzs1Yy1TfNLKSlj0Im5GwibGA,671
|
|
103
|
+
flowstate/migrations/011_record_meta.sql,sha256=KD1X-bAkLZv-PdUCRjqUEXZK4Z8s5LvdMxBgoNS1z7k,812
|
|
104
|
+
flowstate/migrations/012_accountability.sql,sha256=0Gq9shqM2Vncg2CUJFO08cCk28Z6gTyZ1oLsHylogUU,4242
|
|
105
|
+
flowstate/migrations/013_todo_claims.sql,sha256=f9M1TY-4POlL26crEc2OA5rQlhhHVhFKaqhnomZ3ilE,1505
|
|
106
|
+
flowstate/migrations/014_decision_conflicts.sql,sha256=uCR6pvujT7O0asUtP4h4H7U851umIQkjxmDgnnNajAA,2288
|
|
107
|
+
flowstate/migrations/015_session_runs.sql,sha256=jYk5YGkMQY8RxzUh6Sn6d81pydR1JjZ6sFItUCNSey8,1016
|
|
108
|
+
flowstate/migrations/016_write_receipts.sql,sha256=RA34y9ZoOZ1BaCUGxeqJIdvbLGy41H2EjIUiQlOpIkI,1769
|
|
109
|
+
flowstate/migrations/017_run_views.sql,sha256=OE0DrwxVTIsPHLOBRMWUtKfMfE3mNE60B4pxVWHivls,1301
|
|
110
|
+
flowstate/migrations/018_run_views_upto.sql,sha256=tMhT-tdlY3fwxwPXWRzfzILTHnjAhsCARLtFqyE6Csw,338
|
|
111
|
+
flowstate/migrations/019_approvals.sql,sha256=QS6mA5cXJ4Gdmgbgb_pl1HEeh3E2Smz0OU8TKGJE8JU,1916
|
|
112
|
+
flowstate/migrations/020_source_stamps.sql,sha256=BHJfz4ma65o5szS5Qbl-rWsT-GtDCdIivPvHmo8CB4s,764
|
|
113
|
+
flowstate/migrations/021_review_links.sql,sha256=2GnIiRP4ckaJK-9p0NAwqlgu6Wi-Mm4ovN_VvPDLSM4,646
|
|
114
|
+
flowstate/migrations/022_review_start_tickets.sql,sha256=G1vNvFMoWLJzbqp4FNhnyYI1MGxzScfa_2zYN0tiYYM,796
|
|
115
|
+
flowstate/migrations/023_conflict_cards.sql,sha256=PuLGIc8-ChNNqxhsHz9_ONypy6KvOCm-hCINFbsvdlc,2089
|
|
116
|
+
flowstate/migrations/024_rule_confirmations.sql,sha256=BXuYvtgqA5sv3cDPh2gnlNMZC_RNmqzLKR7eMtvHcsw,513
|
|
117
|
+
flowstate/migrations/025_confirmed_hash.sql,sha256=mzpbqWQkxm7ONgrbDaQY_Pz-5czMNShkJ-B6gyIiO-o,565
|
|
118
|
+
flowstate/migrations/__init__.py,sha256=SHxtjurrHdLBXBb2sAPyfus60SwhmiIRHVm1vqmdDMk,5964
|
|
119
|
+
flowstate/relay/__init__.py,sha256=Mob9HYojjcurqQPcTqM0vlEnOT_NBgQtVspfoGWHDE8,3363
|
|
120
|
+
flowstate/relay/acme.py,sha256=as72VQqq3Neb8GOngsxUKRRNxMids8enQuj2SWYBGk0,11693
|
|
121
|
+
flowstate/relay/api.py,sha256=nxJ3Pkef70oRXPZr8BRus0QfQTB4itOsx42fWGHlH80,7703
|
|
122
|
+
flowstate/relay/cli.py,sha256=F6lvMiceJaslnlE-_S6z7_kHZSC_eP7PONiUiWnWkto,14792
|
|
123
|
+
flowstate/relay/crypto.py,sha256=xwwkUbh1TKGb_jaurlkn2wqDQYefZYjNaQls7iG3YdY,5295
|
|
124
|
+
flowstate/relay/ct.py,sha256=nE0cifxkoL1u7-LNCAK-HWnJEF0r30PbpRtkPe7A8cE,5104
|
|
125
|
+
flowstate/relay/runner.py,sha256=xFaCDY7ZPL6Y5WZnnCaj_9tJ-3U_xLogM0UF1waOQlQ,7440
|
|
126
|
+
flowstate/relay/store.py,sha256=093IeUgzxJEbS9fubGlzZ4nVkDUXW--_z1rGIivbFIs,7567
|
|
127
|
+
flowstate/relay/tunnel.py,sha256=ONZUWWY32LPiAV-p-ieocA7LZ27bICjQHz-K4o070K8,17004
|
|
128
|
+
flowstate/tools/__init__.py,sha256=hItuhHfcjGc4t70GEVzHS1Nzt3Xl_HCp3tvpqc8V3nE,4097
|
|
129
|
+
flowstate/tools/core.py,sha256=Q62YPDrnwVHQ-Df8rEe_nXhO9wr_ns6qAlshtO6gpWg,16264
|
|
130
|
+
flowstate/tools/files.py,sha256=T8XcDpSo00zZSmk1P6a3fMIjrqRYhM4pNQ8MvO19rZo,15852
|
|
131
|
+
flowstate/tools/git_ops.py,sha256=el6KIhQf10CHXAPKL7w8ypANrLyVMz_7UvHd0ImTFrk,49044
|
|
132
|
+
flowstate/tools/intelligence.py,sha256=B_fLO6eWMtc3aMlbdTainwlN4tG3xAD7tyA4Cjsk6h0,10486
|
|
133
|
+
flowstate/tools/learning.py,sha256=RnVP9-qvaB_HcKsfYJUsCwAo7vPxsRtimIcNWaW51VQ,8088
|
|
134
|
+
flowstate/tools/problems.py,sha256=d_mluuEE10UgrrhluN84TkiAQVOGfobvjJPolyIQilg,4473
|
|
135
|
+
flowstate/tools/sessions.py,sha256=Y5lehaVpDmRkmrC1F6tBQB8pRZ572zkB2KhmzhwZpw4,7150
|
|
136
|
+
flowstate/tools/story.py,sha256=rp0-Za72Hs5ohQSfNPQfChT24ei3xc7PjxyHwTalqas,1287
|
|
137
|
+
flowstate/tools/todos.py,sha256=CSm9bjbZ7d6-PPbDsUHcmg_KwjSYU1SwVUIBQi_VdoQ,2074
|
|
138
|
+
flowstate/tools/utils.py,sha256=6TR3OBSQ3x31I0NGgZNM8oMvrEzeFyXzNVustmqSVRU,2224
|
|
139
|
+
flowstate/tools/variables.py,sha256=NMK9d8_P4YBoH56ON1j8aoYIevZLu3J9q6918jHocB0,9710
|
|
140
|
+
flowstatemcp-2.5.0.dist-info/METADATA,sha256=JWUUduMUnX0zXFuAjoOO_bopqLR-qyMiMQ8ipEesNyo,3398
|
|
141
|
+
flowstatemcp-2.5.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
142
|
+
flowstatemcp-2.5.0.dist-info/entry_points.txt,sha256=FgrKEw4VlR4l8k3G-gOHuqQKHnlKoXtDKqFdQsB-KYQ,89
|
|
143
|
+
flowstatemcp-2.5.0.dist-info/RECORD,,
|