pythia-plsql 0.6.0__tar.gz → 0.6.1__tar.gz
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.
- {pythia_plsql-0.6.0/scripts/pythia_plsql.egg-info → pythia_plsql-0.6.1}/PKG-INFO +1 -1
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/pyproject.toml +1 -1
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia.py +62 -2
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1/scripts/pythia_plsql.egg-info}/PKG-INFO +1 -1
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-setup/SKILL.md +1 -1
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/tests/test_phase1.py +40 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/tests/test_phase5.py +22 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/LICENSE +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/README.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/compile-errors.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/dependencies.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/impact.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/invalid-objects.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/name-occupants.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/object-names.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/object-source.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/plscope-enabled.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/plscope-statements.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/plscope-usages.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/session-privileges.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/similar-candidates.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/queries/source.sql +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/SOURCES.txt +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/dependency_links.txt +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/entry_points.txt +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/requires.txt +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/top_level.txt +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/setup.cfg +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-apply/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-conventions/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-explore/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-explore/reference/data-dictionary.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-impact/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-review/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-review/reference/antipatterns.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-skill-author/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-write/SKILL.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-write/reference/patterns.md +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/tests/test_install.py +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/tests/test_phase2.py +0 -0
- {pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/tests/test_phase3.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythia-plsql
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: PL/SQL development for AI agents on Oracle Database - expert data-dictionary queries, impact analysis, and a snapshot-verified write path with honest rollback.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/thaildhe172591/pythia
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pythia-plsql"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.1"
|
|
8
8
|
description = "PL/SQL development for AI agents on Oracle Database - expert data-dictionary queries, impact analysis, and a snapshot-verified write path with honest rollback."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -2000,6 +2000,10 @@ Nothing here writes. Reading is free; guessing is not.
|
|
|
2000
2000
|
|
|
2001
2001
|
the problem's shape deps · impact · plscope the exact graph, not a skim
|
|
2002
2002
|
the schema's truth src · args · cols · ddl · errors · invalid · check · ls · grep · sql
|
|
2003
|
+
what you can reach connections - names, users, targets. NEVER open
|
|
2004
|
+
connections.json yourself: it holds passwords, a
|
|
2005
|
+
permission gate should stop you, and this command
|
|
2006
|
+
is the answer you were reaching for.
|
|
2003
2007
|
the house style conventions (--scan / --check) · the project's conventions.md
|
|
2004
2008
|
how it is done here similar · history neighbours to imitate, versions that exist
|
|
2005
2009
|
|
|
@@ -2038,6 +2042,59 @@ This page is the contract; follow it as written.
|
|
|
2038
2042
|
"""
|
|
2039
2043
|
|
|
2040
2044
|
|
|
2045
|
+
def connection_summary(cfg):
|
|
2046
|
+
"""Everything about the configured connections except the secrets.
|
|
2047
|
+
|
|
2048
|
+
An agent has to know which connections exist. Without a sanctioned way to
|
|
2049
|
+
ask, it reads connections.json itself — which is exactly the access a
|
|
2050
|
+
permission classifier should stop, and did. So this exists, and it is
|
|
2051
|
+
built to be provably safe: fields are copied in by name, never by
|
|
2052
|
+
iterating the entry, so a key added to the config later cannot leak
|
|
2053
|
+
through here by accident.
|
|
2054
|
+
"""
|
|
2055
|
+
cfg = dict(cfg or {})
|
|
2056
|
+
default = cfg.pop("default", None)
|
|
2057
|
+
rows = []
|
|
2058
|
+
for name, entry in cfg.items():
|
|
2059
|
+
if not isinstance(entry, dict):
|
|
2060
|
+
continue
|
|
2061
|
+
dsn = entry.get("dsn") or ""
|
|
2062
|
+
if not dsn and entry.get("host"):
|
|
2063
|
+
svc = entry.get("service_name") or entry.get("sid") or ""
|
|
2064
|
+
dsn = f"{entry['host']}:{entry.get('port', 1521)}"
|
|
2065
|
+
if svc:
|
|
2066
|
+
dsn += f"/{svc}"
|
|
2067
|
+
user = str(entry.get("user") or "")
|
|
2068
|
+
rows.append({
|
|
2069
|
+
"name": name,
|
|
2070
|
+
"user": user,
|
|
2071
|
+
"target": dsn or "\u2014",
|
|
2072
|
+
"schema": (entry.get("schema") or user.split("[")[-1].rstrip("]")
|
|
2073
|
+
or "\u2014").upper(),
|
|
2074
|
+
"default": isinstance(default, str) and default.upper() == name.upper(),
|
|
2075
|
+
})
|
|
2076
|
+
return rows
|
|
2077
|
+
|
|
2078
|
+
|
|
2079
|
+
def cmd_connections(conn, schema, ns):
|
|
2080
|
+
cfg, _ = find_config(pathlib.Path.cwd(), os.environ)
|
|
2081
|
+
rows = connection_summary(cfg)
|
|
2082
|
+
if ns.json:
|
|
2083
|
+
print(json.dumps(rows, indent=2))
|
|
2084
|
+
return
|
|
2085
|
+
if not rows:
|
|
2086
|
+
print("No connections configured. "
|
|
2087
|
+
f"{invocation()} install scaffolds .pythia/connections.json.")
|
|
2088
|
+
return
|
|
2089
|
+
print(f"{'':1} {'NAME':<16} {'USER':<26} {'SCHEMA':<20} TARGET")
|
|
2090
|
+
for r in rows:
|
|
2091
|
+
mark = "*" if r["default"] else " "
|
|
2092
|
+
print(f"{mark} {r['name']:<16} {r['user']:<26} {r['schema']:<20} "
|
|
2093
|
+
f"{r['target']}")
|
|
2094
|
+
print("\n* default. Passwords are never printed — this command reads the "
|
|
2095
|
+
"config so you\n do not have to open it. Pick one with --conn NAME.")
|
|
2096
|
+
|
|
2097
|
+
|
|
2041
2098
|
def cmd_guide(conn, schema, ns):
|
|
2042
2099
|
print(OPERATING_GUIDE)
|
|
2043
2100
|
|
|
@@ -2435,11 +2492,11 @@ COMMANDS = {"check": cmd_check, "ls": cmd_ls, "src": cmd_src, "args": cmd_args,
|
|
|
2435
2492
|
"invalid": cmd_invalid, "errors": cmd_errors, "deps": cmd_deps,
|
|
2436
2493
|
"impact": cmd_impact, "similar": cmd_similar, "plscope": cmd_plscope,
|
|
2437
2494
|
"policy": cmd_policy, "journal": cmd_journal, "apply": cmd_apply,
|
|
2438
|
-
"conventions": cmd_conventions, "guide": cmd_guide, "install": cmd_install,
|
|
2495
|
+
"conventions": cmd_conventions, "guide": cmd_guide, "connections": cmd_connections, "install": cmd_install,
|
|
2439
2496
|
"unistr": cmd_unistr, "agent-user": cmd_agent_user,
|
|
2440
2497
|
"history": cmd_history}
|
|
2441
2498
|
|
|
2442
|
-
NO_DB_COMMANDS = {"policy", "journal", "install", "unistr", "guide",
|
|
2499
|
+
NO_DB_COMMANDS = {"policy", "journal", "install", "unistr", "guide", "connections",
|
|
2443
2500
|
"history"}
|
|
2444
2501
|
|
|
2445
2502
|
|
|
@@ -2537,6 +2594,9 @@ def build_parser():
|
|
|
2537
2594
|
help="apply without stopping; the full preview still prints and journals")
|
|
2538
2595
|
s.add_argument("--depth", type=int, default=3,
|
|
2539
2596
|
help="impact depth for the preview (default 3)")
|
|
2597
|
+
sub.add_parser("connections", parents=[common()],
|
|
2598
|
+
help="list configured connections — names, users, "
|
|
2599
|
+
"targets; never passwords")
|
|
2540
2600
|
sub.add_parser("guide", parents=[common()],
|
|
2541
2601
|
help="the operating model: Learn, Ask, Do — the whole "
|
|
2542
2602
|
"harness on one page, no database needed")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythia-plsql
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: PL/SQL development for AI agents on Oracle Database - expert data-dictionary queries, impact analysis, and a snapshot-verified write path with honest rollback.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/thaildhe172591/pythia
|
|
@@ -85,7 +85,7 @@ until you want it.
|
|
|
85
85
|
|
|
86
86
|
| File | Created by | What it does |
|
|
87
87
|
|---|---|---|
|
|
88
|
-
| `connections.json` | `pythia install` | Where to connect. Holds
|
|
88
|
+
| `connections.json` | `pythia install` | Where to connect. **Holds passwords — never open it**; `pythia connections` lists names, users, schemas and targets with no secrets. Gitignored. |
|
|
89
89
|
| `journal/` | first write or snapshot | Every captured version, with a runnable rollback per entry. |
|
|
90
90
|
| `conventions.json` | `pythia conventions --init` | Naming patterns per object type. Every apply preview warns when a new name drifts. |
|
|
91
91
|
| `conventions.md` | `pythia conventions --init` | The house rules in prose. **`pythia-write` reads this before writing anything**, and it outranks the generic patterns this pack ships with. |
|
|
@@ -327,6 +327,46 @@ def test_oracle_account_taken_from_a_proxy_connect_string():
|
|
|
327
327
|
assert pythia.authenticating_account(None) is None
|
|
328
328
|
|
|
329
329
|
|
|
330
|
+
SECRET = "hunter2-do-not-leak"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _cfg():
|
|
334
|
+
return {
|
|
335
|
+
"dev": {"host": "db.example.com", "port": 1521,
|
|
336
|
+
"service_name": "orcl", "user": "app_agent[app_owner]",
|
|
337
|
+
"password": SECRET, "schema": "APP_OWNER"},
|
|
338
|
+
"stage": {"dsn": "stage.example.com:1521/orcl", "user": "u2",
|
|
339
|
+
"password": SECRET},
|
|
340
|
+
"default": "dev",
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def test_connection_summary_never_carries_a_secret():
|
|
345
|
+
"""An agent needs to know which connections exist. Until it could ask,
|
|
346
|
+
it parsed connections.json itself -- which is exactly the read a
|
|
347
|
+
permission classifier should block. This is the sanctioned answer, so it
|
|
348
|
+
must be provably secret-free, in every field and both output modes."""
|
|
349
|
+
import json
|
|
350
|
+
rows = pythia.connection_summary(_cfg())
|
|
351
|
+
blob = json.dumps(rows)
|
|
352
|
+
assert SECRET not in blob
|
|
353
|
+
assert "password" not in blob.lower()
|
|
354
|
+
names = [r["name"] for r in rows]
|
|
355
|
+
assert names == ["dev", "stage"] # the "default" key is not one
|
|
356
|
+
dev = rows[0]
|
|
357
|
+
assert dev["default"] is True and rows[1]["default"] is False
|
|
358
|
+
assert dev["user"] == "app_agent[app_owner]" # proxy shape is safe to show
|
|
359
|
+
assert dev["target"] == "db.example.com:1521/orcl"
|
|
360
|
+
assert rows[1]["target"] == "stage.example.com:1521/orcl" # dsn form
|
|
361
|
+
assert dev["schema"] == "APP_OWNER"
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def test_connection_summary_survives_a_thin_entry():
|
|
365
|
+
rows = pythia.connection_summary({"env": {"user": "u"}})
|
|
366
|
+
assert rows[0]["target"] == "—" and rows[0]["schema"] == "U"
|
|
367
|
+
assert pythia.connection_summary(None) == []
|
|
368
|
+
|
|
369
|
+
|
|
330
370
|
def main():
|
|
331
371
|
failed = 0
|
|
332
372
|
for name, fn in sorted(globals().items()):
|
|
@@ -145,6 +145,28 @@ def test_every_skill_declares_its_phase():
|
|
|
145
145
|
f"{name}: phase must name Learn/Ask/Do, got {m.group(1)!r}"
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
def test_no_manifest_hardcodes_a_stale_skill_count():
|
|
149
|
+
"""The pack grew from seven skills to eight and three shipped manifests
|
|
150
|
+
still said seven. Counting in prose is a contradiction waiting to happen,
|
|
151
|
+
so the check is: no manifest states a number the code can disprove."""
|
|
152
|
+
import json
|
|
153
|
+
n = len(EXPECTED)
|
|
154
|
+
words = {7: "seven", 8: "eight", 9: "nine"}
|
|
155
|
+
stale = [w for k, w in words.items() if k != n]
|
|
156
|
+
for rel in (".claude-plugin/marketplace.json", "npm/package.json",
|
|
157
|
+
"npm/README.md"):
|
|
158
|
+
text = (ROOT / rel).read_text(encoding="utf-8").lower()
|
|
159
|
+
for word in stale:
|
|
160
|
+
assert word + " skill" not in text and word + "-skill" not in text, \
|
|
161
|
+
f"{rel} claims {word} skills; there are {n}"
|
|
162
|
+
mk = json.loads((ROOT / ".claude-plugin/marketplace.json")
|
|
163
|
+
.read_text(encoding="utf-8"))
|
|
164
|
+
declared = {p.rsplit("/", 1)[-1] for p in mk["plugins"][0]["skills"]}
|
|
165
|
+
assert declared == EXPECTED, (
|
|
166
|
+
f"marketplace.json and the pack disagree: "
|
|
167
|
+
f"missing {sorted(EXPECTED - declared)}, extra {sorted(declared - EXPECTED)}")
|
|
168
|
+
|
|
169
|
+
|
|
148
170
|
def main():
|
|
149
171
|
failed = 0
|
|
150
172
|
for name, fn in sorted(globals().items()):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/scripts/pythia_plsql.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythia_plsql-0.6.0 → pythia_plsql-0.6.1}/skills/pythia-explore/reference/data-dictionary.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|