pipulate 2.59__tar.gz → 2.61__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.
- {pipulate-2.59/pipulate.egg-info → pipulate-2.61}/PKG-INFO +8 -8
- {pipulate-2.59 → pipulate-2.61}/README.md +7 -7
- {pipulate-2.59 → pipulate-2.61}/__init__.py +2 -2
- {pipulate-2.59 → pipulate-2.61}/config.py +23 -1
- {pipulate-2.59 → pipulate-2.61}/imports/ascii_displays.py +8 -8
- {pipulate-2.59 → pipulate-2.61/pipulate.egg-info}/PKG-INFO +8 -8
- {pipulate-2.59 → pipulate-2.61}/pyproject.toml +1 -1
- {pipulate-2.59 → pipulate-2.61}/tools/scraper_tools.py +16 -6
- {pipulate-2.59 → pipulate-2.61}/LICENSE +0 -0
- {pipulate-2.59 → pipulate-2.61}/MANIFEST.in +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/010_introduction.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/015_config.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/020_profiles.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/025_aspect.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/030_roles.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/040_hello_workflow.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/050_documentation.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/060_tasks.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/070_history.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/110_parameter_buster.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/120_link_graph.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/130_gap_analysis.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/200_workflow_genesis.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/210_widget_examples.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/220_roadmap.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/230_dev_assistant.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/240_simon_mcp.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/300_blank_placeholder.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/400_botify_trifecta.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/440_browser_automation.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/450_stream_simulator.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/510_text_field.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/520_text_area.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/530_dropdown.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/540_checkboxes.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/550_radios.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/560_range.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/570_switch.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/580_upload.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/610_markdown.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/620_mermaid.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/630_prism.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/640_javascript.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/710_pandas.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/720_rich.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/730_matplotlib.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/810_webbrowser.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/820_selenium.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/apps/830_pico_slider.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/cli.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/__init__.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/ai_dictdb.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/ai_tool_discovery_simple_parser.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/append_only_conversation.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/botify/__init__.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/botify/code_generators.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/botify/true_schema_discoverer.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/botify_code_generation.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/crud.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/database_safety_wrapper.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/dom_processing/__init__.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/dom_processing/ai_dom_beautifier.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/dom_processing/enhanced_dom_processor.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/durable_backup_system.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/mcp_orchestrator.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/server_logging.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/stream_orchestrator.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/imports/voice_synthesis.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate/__init__.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate/core.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate.egg-info/SOURCES.txt +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate.egg-info/dependency_links.txt +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate.egg-info/entry_points.txt +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate.egg-info/requires.txt +0 -0
- {pipulate-2.59 → pipulate-2.61}/pipulate.egg-info/top_level.txt +0 -0
- {pipulate-2.59 → pipulate-2.61}/server.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/setup.cfg +0 -0
- {pipulate-2.59 → pipulate-2.61}/tests/test_apply_airlock.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tests/test_mck_rep2.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/__init__.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/advanced_automation_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/botify_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/connector_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/conversation_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/dom_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/keychain_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/llm_optics.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/mcp_tools.py +0 -0
- {pipulate-2.59 → pipulate-2.61}/tools/system_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pipulate
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.61
|
|
4
4
|
Summary: The context compiler that helps you prompt well — local-first, Nix-reproducible, replayable. The successor to AI SEO software.
|
|
5
5
|
Author-email: Mike Levin <pipulate@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -62,13 +62,13 @@ Dynamic: license-file
|
|
|
62
62
|
# Pipulate: The Context Compiler That Helps You Prompt Well
|
|
63
63
|
|
|
64
64
|
```text
|
|
65
|
-
(
|
|
66
|
-
O /) ____
|
|
67
|
-
>
|
|
68
|
-
>
|
|
69
|
-
>
|
|
70
|
-
>
|
|
71
|
-
>
|
|
65
|
+
( "The AI said so" is a transcript, not a record. )
|
|
66
|
+
O /) ____ This drawing is checksummed.
|
|
67
|
+
> Same files, same words, same bytes: o /)\__// / \ If it reaches you altered, the
|
|
68
|
+
> a change you can replay is a change ___(/_ 0 0 | | model rewrote what it was told to
|
|
69
|
+
> you can put your name behind. *( ==(_T_)== NPvg | copy, and that is the finding.
|
|
70
|
+
> One diff per turn, a reading before \ ) ""\ | | Verify with nothing installed:
|
|
71
|
+
> and after, and a digest you can check. |__>-\_>_> \____/ python scripts/foo_cartridge.py foo.zip
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
## If you can't reproduce it, it didn't happen
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
# Pipulate: The Context Compiler That Helps You Prompt Well
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
|
-
(
|
|
9
|
-
O /) ____
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
8
|
+
( "The AI said so" is a transcript, not a record. )
|
|
9
|
+
O /) ____ This drawing is checksummed.
|
|
10
|
+
> Same files, same words, same bytes: o /)\__// / \ If it reaches you altered, the
|
|
11
|
+
> a change you can replay is a change ___(/_ 0 0 | | model rewrote what it was told to
|
|
12
|
+
> you can put your name behind. *( ==(_T_)== NPvg | copy, and that is the finding.
|
|
13
|
+
> One diff per turn, a reading before \ ) ""\ | | Verify with nothing installed:
|
|
14
|
+
> and after, and a digest you can check. |__>-\_>_> \____/ python scripts/foo_cartridge.py foo.zip
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## If you can't reproduce it, it didn't happen
|
|
@@ -12,7 +12,7 @@ Usage:
|
|
|
12
12
|
pipulate
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
__version__ = "2.
|
|
15
|
+
__version__ = "2.61"
|
|
16
16
|
# APOSTROPHES RESTORED (2026-08-04). They were stripped as a workaround for
|
|
17
17
|
# flake.nix's descMatch regex, whose character class excluded ' from the
|
|
18
18
|
# CAPTURE and truncated the banner to "(So)". That regex was fixed in the same
|
|
@@ -23,7 +23,7 @@ __version__ = "2.59"
|
|
|
23
23
|
# is not a property of the system; the regex is. Blast radius is one banner:
|
|
24
24
|
# nothing but flake.nix reads this name -- version_sync.py syncs __version__
|
|
25
25
|
# and __description__, never this. So'wI' chu' -- "engage the cloaking device."
|
|
26
|
-
__version_description__ = "
|
|
26
|
+
__version_description__ = "context, prompt, compile"
|
|
27
27
|
# SPDX expression, single source of truth, synced into pyproject.toml by
|
|
28
28
|
# scripts/release/version_sync.py. "-or-later" (not bare AGPL-3.0, which is
|
|
29
29
|
# deprecated SPDX) because the header below grants "any later version".
|
|
@@ -295,7 +295,7 @@ def get_botify_token():
|
|
|
295
295
|
"""Canonical accessor for the Botify API token.
|
|
296
296
|
|
|
297
297
|
Single source of truth: reads BOTIFY_API_TOKEN from the environment,
|
|
298
|
-
falling back to
|
|
298
|
+
falling back to the project-root .env, then the warm vault. Replaces the legacy
|
|
299
299
|
botify_token.txt file-based system. Returns the token string or None.
|
|
300
300
|
"""
|
|
301
301
|
token = os.environ.get('BOTIFY_API_TOKEN')
|
|
@@ -308,6 +308,28 @@ def get_botify_token():
|
|
|
308
308
|
token = os.environ.get('BOTIFY_API_TOKEN')
|
|
309
309
|
except Exception:
|
|
310
310
|
pass
|
|
311
|
+
if not token:
|
|
312
|
+
# THE VAULT IS THE THIRD PLACE (banked 2026-09-23, witnessed by the
|
|
313
|
+
# env -u BOTIFY_API_TOKEN straddle: the env var unset, no project-root
|
|
314
|
+
# .env present, dotenv importable, and get_botify_token still returned
|
|
315
|
+
# config=True -- the only source left was the vault, so the third place
|
|
316
|
+
# is what answered). `warm` writes paste-kind secrets to
|
|
317
|
+
# ~/.config/pipulate/.env (PIPULATE_DOTENV wins, exactly as wallet.py
|
|
318
|
+
# and the flake spell it), and the flake sources that file only at
|
|
319
|
+
# shell entry. So a token warmed after the shell opened was GREEN on
|
|
320
|
+
# the wallet's board, whose _check_env layers the vault under
|
|
321
|
+
# os.environ for its subprocess, and absent to a bare `botify` in the
|
|
322
|
+
# same shell, which reached this function with nothing but os.environ
|
|
323
|
+
# and the project .env. Same file, same precedence, no re-entry: read
|
|
324
|
+
# the one name, values-only, and export nothing else into this process.
|
|
325
|
+
try:
|
|
326
|
+
from dotenv import dotenv_values
|
|
327
|
+
vault = Path(os.environ.get('PIPULATE_DOTENV')
|
|
328
|
+
or Path.home() / '.config' / 'pipulate' / '.env').expanduser()
|
|
329
|
+
if vault.exists():
|
|
330
|
+
token = dotenv_values(vault).get('BOTIFY_API_TOKEN') or None
|
|
331
|
+
except Exception:
|
|
332
|
+
pass
|
|
311
333
|
return token
|
|
312
334
|
|
|
313
335
|
# Browser automation helper functions
|
|
@@ -53,7 +53,7 @@ console = Console()
|
|
|
53
53
|
# To add a new entry: print(binascii.crc32(your_art_string.encode('utf-8')))
|
|
54
54
|
|
|
55
55
|
FIGURATE_LEDGER: dict = {
|
|
56
|
-
"white_rabbit":
|
|
56
|
+
"white_rabbit": 3309949418,
|
|
57
57
|
"player_piano": 3357002674,
|
|
58
58
|
"clipboard": 858911667,
|
|
59
59
|
"bunny_trail": 615479347,
|
|
@@ -526,13 +526,13 @@ def _expand_color_bits_ai(text: str) -> str:
|
|
|
526
526
|
def _figurate_white_rabbit():
|
|
527
527
|
"""Render white_rabbit as (human, ai) tuple for FIGURATE_REGISTRY."""
|
|
528
528
|
art = r"""
|
|
529
|
-
|
|
530
|
-
O /) ____
|
|
531
|
-
>
|
|
532
|
-
>
|
|
533
|
-
>
|
|
534
|
-
>
|
|
535
|
-
>
|
|
529
|
+
( "The AI said so" is a transcript, not a record. )
|
|
530
|
+
O /) ____ This drawing is checksummed.
|
|
531
|
+
> Same files, same words, same bytes: o /)\__// / \ If it reaches you altered, the
|
|
532
|
+
> a change you can replay is a change ___(/_ 0 0 | | model rewrote what it was told to
|
|
533
|
+
> you can put your name behind. *( ==(_T_)== NPvg | copy, and that is the finding.
|
|
534
|
+
> One diff per turn, a reading before \ ) ""\ | | Verify with nothing installed:
|
|
535
|
+
> and after, and a digest you can check. |__>-\_>_> \____/ python scripts/foo_cartridge.py foo.zip
|
|
536
536
|
"""
|
|
537
537
|
ai_art = _expand_color_bits_ai(art)
|
|
538
538
|
human_art = _expand_color_bits_human(art)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pipulate
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.61
|
|
4
4
|
Summary: The context compiler that helps you prompt well — local-first, Nix-reproducible, replayable. The successor to AI SEO software.
|
|
5
5
|
Author-email: Mike Levin <pipulate@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -62,13 +62,13 @@ Dynamic: license-file
|
|
|
62
62
|
# Pipulate: The Context Compiler That Helps You Prompt Well
|
|
63
63
|
|
|
64
64
|
```text
|
|
65
|
-
(
|
|
66
|
-
O /) ____
|
|
67
|
-
>
|
|
68
|
-
>
|
|
69
|
-
>
|
|
70
|
-
>
|
|
71
|
-
>
|
|
65
|
+
( "The AI said so" is a transcript, not a record. )
|
|
66
|
+
O /) ____ This drawing is checksummed.
|
|
67
|
+
> Same files, same words, same bytes: o /)\__// / \ If it reaches you altered, the
|
|
68
|
+
> a change you can replay is a change ___(/_ 0 0 | | model rewrote what it was told to
|
|
69
|
+
> you can put your name behind. *( ==(_T_)== NPvg | copy, and that is the finding.
|
|
70
|
+
> One diff per turn, a reading before \ ) ""\ | | Verify with nothing installed:
|
|
71
|
+
> and after, and a digest you can check. |__>-\_>_> \____/ python scripts/foo_cartridge.py foo.zip
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
## If you can't reproduce it, it didn't happen
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pipulate"
|
|
7
7
|
# VERSION NOTE: Synced from pipulate/__init__.py.__version__ via python version_sync.py
|
|
8
|
-
version = "2.
|
|
8
|
+
version = "2.61"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name="Mike Levin", email="pipulate@gmail.com" },
|
|
11
11
|
]
|
|
@@ -72,16 +72,26 @@ def _guided_path_component(url: str) -> tuple[str, str]:
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
# --- Optional audio during browser startup ---
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
75
|
+
# tick.wav loops while the browser is opening; ding.wav plays once when the
|
|
76
|
+
# page-load phase ends. Both are CC0 and ship in assets/sounds/ (its README
|
|
77
|
+
# names the sources) since 2026-09-26, after a week in which the Mac was
|
|
78
|
+
# silent because the only copies lived under one home directory. A copy
|
|
79
|
+
# under ~/.local/share/pipulate still wins, so an operator can swap in their
|
|
80
|
+
# own. No file in either place means no sound. Linux uses aplay; Darwin
|
|
81
|
+
# uses afplay.
|
|
78
82
|
SCRAPE_MUSIC_MARKER = "pipulate-scrape-music"
|
|
79
|
-
|
|
83
|
+
SOUND_DIRS = (
|
|
84
|
+
Path.home() / ".local/share/pipulate",
|
|
85
|
+
Path(__file__).resolve().parent.parent / "assets" / "sounds",
|
|
86
|
+
)
|
|
80
87
|
|
|
81
88
|
|
|
82
89
|
def _sound_file(name):
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
for sound_dir in SOUND_DIRS:
|
|
91
|
+
path = sound_dir / name
|
|
92
|
+
if path.is_file():
|
|
93
|
+
return path
|
|
94
|
+
return None
|
|
85
95
|
|
|
86
96
|
|
|
87
97
|
def _player_args(sound):
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|