publinker-cli 0.6.2__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.
- publinker_cli/__init__.py +14 -0
- publinker_cli/__main__.py +83 -0
- publinker_cli/audience.py +73 -0
- publinker_cli/auth.py +152 -0
- publinker_cli/client.py +166 -0
- publinker_cli/commands/__init__.py +0 -0
- publinker_cli/commands/auth_cmds.py +69 -0
- publinker_cli/commands/report_options.py +100 -0
- publinker_cli/commands/skill.py +46 -0
- publinker_cli/commands/token_cmd.py +97 -0
- publinker_cli/commands/update.py +207 -0
- publinker_cli/commands/use.py +100 -0
- publinker_cli/commands/write.py +72 -0
- publinker_cli/config.py +64 -0
- publinker_cli/dispatch_cli.py +394 -0
- publinker_cli/keyring_store.py +109 -0
- publinker_cli/manifest.py +409 -0
- publinker_cli/routes.yaml +1648 -0
- publinker_cli/skill/SKILL.md +61 -0
- publinker_cli/state.py +138 -0
- publinker_cli/version.py +58 -0
- publinker_cli/write_gate.py +51 -0
- publinker_cli-0.6.2.dist-info/METADATA +81 -0
- publinker_cli-0.6.2.dist-info/RECORD +26 -0
- publinker_cli-0.6.2.dist-info/WHEEL +4 -0
- publinker_cli-0.6.2.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publinker
|
|
3
|
+
description: Read and manage Publinker data (sites, ad revenue reports, pricing floors, site config) with the `publinker` CLI. Use when the user asks about their Publinker sites, revenue, reports, floors or config, or mentions publinker.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publinker CLI
|
|
7
|
+
|
|
8
|
+
The `publinker` command talks to the Publinker API as the logged-in user. It
|
|
9
|
+
only sees the sites that user can see on publinker.com.
|
|
10
|
+
|
|
11
|
+
## Before anything
|
|
12
|
+
|
|
13
|
+
1. `publinker whoami`. If it says you are not logged in, ask the user to run
|
|
14
|
+
`publinker login` themselves (it opens a browser to confirm a code). Never
|
|
15
|
+
run `publinker login` for them, and never print or store tokens.
|
|
16
|
+
2. `publinker site list` to see the sites, then `publinker use <site>` to set
|
|
17
|
+
the active one, or pass `--site <site>` on a single command.
|
|
18
|
+
|
|
19
|
+
## Find the right command
|
|
20
|
+
|
|
21
|
+
Every group and command has `--help`; read it instead of guessing flags.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
publinker --help
|
|
25
|
+
publinker site --help
|
|
26
|
+
publinker site report get --help
|
|
27
|
+
publinker site report list-options # valid --platform and --dimensions-keys values
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add `--json` to any read command when you need to process the output.
|
|
31
|
+
|
|
32
|
+
## Common reads
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
publinker site report get --platform google_admanager --account-id <network code> \
|
|
36
|
+
--dimensions-keys date --date-start 2026-01-01 --date-stop 2026-01-07 --json
|
|
37
|
+
publinker site pricing get --json
|
|
38
|
+
publinker site config get --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Changes (writes)
|
|
42
|
+
|
|
43
|
+
Commands that create, change or delete data are blocked by default, and
|
|
44
|
+
each one is unlocked on its own. Before a write:
|
|
45
|
+
|
|
46
|
+
1. Read the current value first, then tell the user exactly what will change
|
|
47
|
+
and get a clear yes for that exact command.
|
|
48
|
+
2. Run that one command with `PUBLINKER_ALLOW_WRITES=1` in front of it and an
|
|
49
|
+
explicit `--site <site>` (the active site from `publinker use` is not
|
|
50
|
+
enough for a write):
|
|
51
|
+
`PUBLINKER_ALLOW_WRITES=1 publinker site pricing adjust --site <site> ...`
|
|
52
|
+
3. Never `export PUBLINKER_ALLOW_WRITES`; nothing stays unlocked afterwards.
|
|
53
|
+
`publinker write allow` no longer opens a window.
|
|
54
|
+
4. Read the value again and show the user the result. If a write times out,
|
|
55
|
+
read before retrying; it may have gone through.
|
|
56
|
+
|
|
57
|
+
## Errors
|
|
58
|
+
|
|
59
|
+
- `401` / "not logged in": the user runs `publinker login`.
|
|
60
|
+
- `403`: the user has no access to that site. Do not retry with other sites.
|
|
61
|
+
- A newer version is announced: tell the user to run `pipx upgrade publinker-cli`.
|
publinker_cli/state.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""User-state persistence for publinker-cli.
|
|
2
|
+
|
|
3
|
+
The state file at ~/.config/publinker/state.json tracks the active site
|
|
4
|
+
(selected via `publinker use <site>`) so that site-scoped commands can be
|
|
5
|
+
called without `--site` every time.
|
|
6
|
+
|
|
7
|
+
The active site is NOT a secret (it's a domain you own). Plain file storage
|
|
8
|
+
beats keyring here: one less keyring read per command + easy inspection
|
|
9
|
+
(`jq .active_site ~/.config/publinker/state.json`).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
from dataclasses import asdict, dataclass
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
from publinker_cli import __version__
|
|
22
|
+
|
|
23
|
+
DEFAULT_STATE_DIR = Path.home() / ".config" / "publinker"
|
|
24
|
+
DEFAULT_STATE_FILE = DEFAULT_STATE_DIR / "state.json"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _state_path() -> Path:
|
|
28
|
+
"""Allow tests to override via PUBLINKER_STATE_FILE."""
|
|
29
|
+
override = os.environ.get("PUBLINKER_STATE_FILE")
|
|
30
|
+
return Path(override) if override else DEFAULT_STATE_FILE
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class State:
|
|
35
|
+
active_site: Optional[str] = None
|
|
36
|
+
set_at: Optional[str] = None # ISO 8601 UTC
|
|
37
|
+
set_by_cli_version: Optional[str] = None
|
|
38
|
+
# Retired file-backed write fields are parsed only so `publinker write block`
|
|
39
|
+
# can remove them during migration. Runtime authorization never reads them.
|
|
40
|
+
writes_allowed_until: Optional[str] = None
|
|
41
|
+
writes_persistent: Optional[bool] = None
|
|
42
|
+
|
|
43
|
+
def to_json(self) -> str:
|
|
44
|
+
# Only emit fields that are set, so the file stays clean.
|
|
45
|
+
return json.dumps(
|
|
46
|
+
{k: v for k, v in asdict(self).items() if v is not None}, indent=2
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load() -> State:
|
|
51
|
+
"""Read state from disk. Returns an empty State if the file is missing or unreadable."""
|
|
52
|
+
path = _state_path()
|
|
53
|
+
if not path.exists():
|
|
54
|
+
return State()
|
|
55
|
+
try:
|
|
56
|
+
data = json.loads(path.read_text())
|
|
57
|
+
except (json.JSONDecodeError, OSError):
|
|
58
|
+
# Corrupted file → treat as no state. Next save will overwrite cleanly.
|
|
59
|
+
return State()
|
|
60
|
+
return State(
|
|
61
|
+
active_site=data.get("active_site"),
|
|
62
|
+
set_at=data.get("set_at"),
|
|
63
|
+
set_by_cli_version=data.get("set_by_cli_version"),
|
|
64
|
+
writes_allowed_until=data.get("writes_allowed_until"),
|
|
65
|
+
writes_persistent=data.get("writes_persistent"),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def save(state: State) -> None:
|
|
70
|
+
"""Write state to disk, creating the parent directory if needed."""
|
|
71
|
+
path = _state_path()
|
|
72
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
path.write_text(state.to_json())
|
|
74
|
+
# 0644 — readable, not group-writable. Active site isn't sensitive.
|
|
75
|
+
os.chmod(path, 0o644)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def set_active_site(site: str) -> State:
|
|
79
|
+
"""Set (or replace) the active site and clear retired write-gate fields."""
|
|
80
|
+
state = State(
|
|
81
|
+
active_site=site,
|
|
82
|
+
set_at=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
83
|
+
set_by_cli_version=__version__,
|
|
84
|
+
)
|
|
85
|
+
save(state)
|
|
86
|
+
return state
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def update_write_gate(*, until: Optional[str], persistent: Optional[bool]) -> State:
|
|
90
|
+
"""Rewrite retired gate fields while preserving the active site.
|
|
91
|
+
|
|
92
|
+
Runtime authorization ignores these fields. Passing both values as ``None``
|
|
93
|
+
removes stale armed state written by older CLI versions.
|
|
94
|
+
"""
|
|
95
|
+
existing = load()
|
|
96
|
+
state = State(
|
|
97
|
+
active_site=existing.active_site,
|
|
98
|
+
set_at=existing.set_at,
|
|
99
|
+
set_by_cli_version=existing.set_by_cli_version,
|
|
100
|
+
writes_allowed_until=until,
|
|
101
|
+
writes_persistent=persistent,
|
|
102
|
+
)
|
|
103
|
+
save(state)
|
|
104
|
+
return state
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def clear() -> None:
|
|
108
|
+
"""Remove the state file entirely. Idempotent."""
|
|
109
|
+
path = _state_path()
|
|
110
|
+
if path.exists():
|
|
111
|
+
path.unlink()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def active_site() -> Optional[str]:
|
|
115
|
+
"""Return the currently selected site, or None."""
|
|
116
|
+
return load().active_site
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def resolve_site(explicit: Optional[str]) -> str:
|
|
120
|
+
"""Resolve the site to use for a command.
|
|
121
|
+
|
|
122
|
+
Precedence:
|
|
123
|
+
1. The explicit `--site` flag (passed in)
|
|
124
|
+
2. The active site from state.json
|
|
125
|
+
3. Raise NoSiteSelectedError so the caller can render a friendly message
|
|
126
|
+
"""
|
|
127
|
+
if explicit:
|
|
128
|
+
return explicit
|
|
129
|
+
selected = active_site()
|
|
130
|
+
if selected:
|
|
131
|
+
return selected
|
|
132
|
+
raise NoSiteSelectedError(
|
|
133
|
+
"no site selected. Run `publinker use <domain>` or pass --site <domain>."
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class NoSiteSelectedError(Exception):
|
|
138
|
+
"""Raised when a site-scoped command runs without a resolvable site."""
|
publinker_cli/version.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""CLI version comparison and the passive update notice (DEV-1973).
|
|
2
|
+
|
|
3
|
+
Every API request sends `User-Agent: publinker-cli/<version>`; publinker-api
|
|
4
|
+
answers with `X-Publinker-Cli-Latest`. `observe()` reads that header off a
|
|
5
|
+
response the command was making anyway — no extra request — and prints one
|
|
6
|
+
stderr line per process when a newer CLI exists. stdout and the exit status are
|
|
7
|
+
never touched, and a missing or malformed header is silently ignored.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
import sys
|
|
14
|
+
from typing import Mapping, Optional
|
|
15
|
+
|
|
16
|
+
from publinker_cli import __version__, audience
|
|
17
|
+
|
|
18
|
+
USER_AGENT = f"publinker-cli/{__version__}"
|
|
19
|
+
LATEST_HEADER = "X-Publinker-Cli-Latest"
|
|
20
|
+
|
|
21
|
+
_VERSION_RE = re.compile(r"^\d+(\.\d+)*$")
|
|
22
|
+
_notified = False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_version(value: str) -> tuple[int, ...]:
|
|
26
|
+
"""`"0.10.0"` -> `(0, 10, 0)`. Raises ValueError for anything else."""
|
|
27
|
+
value = value.strip()
|
|
28
|
+
if not _VERSION_RE.match(value):
|
|
29
|
+
raise ValueError(f"not a release version: {value!r}")
|
|
30
|
+
parts = [int(p) for p in value.split(".")]
|
|
31
|
+
# Pad so "0.3" and "0.3.0" compare equal.
|
|
32
|
+
return tuple(parts + [0] * (3 - len(parts)))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def is_newer(candidate: str, installed: str = __version__) -> bool:
|
|
36
|
+
"""True when `candidate` is strictly newer than `installed` (numeric order)."""
|
|
37
|
+
return parse_version(candidate) > parse_version(installed)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def observe(headers: Mapping[str, str]) -> None:
|
|
41
|
+
"""Print the update notice once if the response advertises a newer CLI."""
|
|
42
|
+
global _notified
|
|
43
|
+
# A customer build has no self-update source (see commands/update.py),
|
|
44
|
+
# so pointing it at `publinker update` would only produce a refusal.
|
|
45
|
+
if _notified or audience.is_customer_build():
|
|
46
|
+
return
|
|
47
|
+
latest: Optional[str] = headers.get(LATEST_HEADER)
|
|
48
|
+
try:
|
|
49
|
+
if not latest or not is_newer(latest):
|
|
50
|
+
return
|
|
51
|
+
except ValueError:
|
|
52
|
+
return
|
|
53
|
+
_notified = True
|
|
54
|
+
print(
|
|
55
|
+
f"publinker-cli {latest} is available (installed {__version__}). "
|
|
56
|
+
"Run: publinker update",
|
|
57
|
+
file=sys.stderr,
|
|
58
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Process-scoped write-gate policy for publinker-cli.
|
|
2
|
+
|
|
3
|
+
Mutations are blocked unless the current process receives
|
|
4
|
+
``PUBLINKER_ALLOW_WRITES=1`` (or another documented truthy value). Durable state
|
|
5
|
+
must never arm writes: a persisted allow window can outlive the reviewed command,
|
|
6
|
+
the authenticated user, or the intended API stage.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
|
|
14
|
+
from publinker_cli import state
|
|
15
|
+
|
|
16
|
+
ENV_VAR = "PUBLINKER_ALLOW_WRITES"
|
|
17
|
+
_TRUTHY = {"1", "true", "yes", "on"}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class GateStatus:
|
|
22
|
+
"""Snapshot of the process-scoped write-gate decision."""
|
|
23
|
+
|
|
24
|
+
allowed: bool
|
|
25
|
+
reason: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def status() -> GateStatus:
|
|
29
|
+
"""Return the current process gate without reading mutable state."""
|
|
30
|
+
value = os.environ.get(ENV_VAR, "").strip().lower()
|
|
31
|
+
if value in _TRUTHY:
|
|
32
|
+
return GateStatus(allowed=True, reason=f"process env {ENV_VAR}=1")
|
|
33
|
+
if value:
|
|
34
|
+
return GateStatus(allowed=False, reason=f"process env {ENV_VAR} is not enabled")
|
|
35
|
+
return GateStatus(allowed=False, reason="default (process gate absent)")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def is_allowed() -> bool:
|
|
39
|
+
"""Return whether a mutation may run in this process."""
|
|
40
|
+
return status().allowed
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def clear_legacy_state() -> GateStatus:
|
|
44
|
+
"""Delete retired file-backed gate fields without changing the active site."""
|
|
45
|
+
snapshot = state.load()
|
|
46
|
+
if (
|
|
47
|
+
snapshot.writes_allowed_until is not None
|
|
48
|
+
or snapshot.writes_persistent is not None
|
|
49
|
+
):
|
|
50
|
+
state.update_write_gate(until=None, persistent=None)
|
|
51
|
+
return GateStatus(allowed=False, reason="legacy file-backed gate cleared")
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: publinker-cli
|
|
3
|
+
Version: 0.6.2
|
|
4
|
+
Summary: Command line for Publinker: sites, reports, floors and config.
|
|
5
|
+
Project-URL: Homepage, https://publinker.com
|
|
6
|
+
Author: Martech-DM
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Keywords: auth0,cli,martech,publinker
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: keyring>=24.0.0
|
|
20
|
+
Requires-Dist: pyyaml>=6.0
|
|
21
|
+
Requires-Dist: requests>=2.31.0
|
|
22
|
+
Requires-Dist: typer[all]>=0.12.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: black==25.9.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: flake8>=7.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: responses>=0.25; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# publinker-cli
|
|
33
|
+
|
|
34
|
+
Command line for [Publinker](https://publinker.com): your sites, ad revenue
|
|
35
|
+
reports, pricing floors and site config, from the terminal and from AI
|
|
36
|
+
assistants like Claude Code and Codex.
|
|
37
|
+
|
|
38
|
+
You need a Publinker account. The CLI only sees the sites you can see on
|
|
39
|
+
publinker.com.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
Needs Python 3.10+ and [pipx](https://pipx.pypa.io/stable/installation/).
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pipx install publinker-cli
|
|
47
|
+
publinker skill install # teaches Claude Code and Codex to use publinker
|
|
48
|
+
publinker login # opens a browser to confirm a one-time code
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Update with `pipx upgrade publinker-cli`.
|
|
52
|
+
|
|
53
|
+
## Use
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
publinker site list # sites you can access
|
|
57
|
+
publinker use example.com # set your active site
|
|
58
|
+
publinker site report get --help # every command has --help
|
|
59
|
+
publinker site pricing get
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Commands that change data are blocked by default. Allow one command at a time
|
|
63
|
+
by prefixing it with `PUBLINKER_ALLOW_WRITES=1` and naming the site explicitly:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
PUBLINKER_ALLOW_WRITES=1 publinker site pricing adjust --site example.com ...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Nothing stays unlocked afterwards. Don't `export` the variable.
|
|
70
|
+
|
|
71
|
+
## Servers and CI
|
|
72
|
+
|
|
73
|
+
On a machine where you are logged in, run `publinker token`, then on the
|
|
74
|
+
server set `PUBLINKER_TOKEN` to that value. Treat it like a password; mint a
|
|
75
|
+
new one when it expires.
|
|
76
|
+
|
|
77
|
+
## AI assistants
|
|
78
|
+
|
|
79
|
+
`publinker skill install` copies a skill to `~/.claude/skills/publinker` and
|
|
80
|
+
`~/.agents/skills/publinker`. For any other assistant, point it at the file
|
|
81
|
+
that `publinker skill path` prints.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
publinker_cli/__init__.py,sha256=lNxLRBBaSEJQvjLBcIMSzm_K43eNXI6tppU9FSwvQ9Y,526
|
|
2
|
+
publinker_cli/__main__.py,sha256=VVzUKqRBm-Gy-Rbcx5cRKslUQLZCrDs8FKRG1mP-RDs,2604
|
|
3
|
+
publinker_cli/audience.py,sha256=fY9PRciHKqdLsP_p9JGPjD4cCTiYFoEg5NGYDnwbcQ4,2611
|
|
4
|
+
publinker_cli/auth.py,sha256=rAqzsVp6UBhJsBg3ihUwV4OLpo9vpl5VNFn9x6mU83Y,5070
|
|
5
|
+
publinker_cli/client.py,sha256=adv89_23T3nDg4rZR_sLG43zkdd9wZL29qXEMk9qs7Q,6941
|
|
6
|
+
publinker_cli/config.py,sha256=Bs-DWTwpMpdESqQcMtOBRBYUb8soD4KQzRKlRDx_Bxw,1799
|
|
7
|
+
publinker_cli/dispatch_cli.py,sha256=1_k-6o93GLGlLAqkiYN4nhi-kPheJeA8dNG9t0q1pk8,14206
|
|
8
|
+
publinker_cli/keyring_store.py,sha256=9JQbJVHk_eG_1YphEJFSkAOnQ3TQWrBM58S_1GLF-rw,3456
|
|
9
|
+
publinker_cli/manifest.py,sha256=kA9pEMAyL_3op9UXEs-3uy-jbzsje-dHjOjzHMB_Xec,15151
|
|
10
|
+
publinker_cli/routes.yaml,sha256=TsAy1zubWAufd0zv3F5uHkXHO1LIHZLwo9N64jeesY8,38345
|
|
11
|
+
publinker_cli/state.py,sha256=_N9bA4kcCfb6LEzQopNKFsSV1gMtBtTKs-28hxWSCuY,4420
|
|
12
|
+
publinker_cli/version.py,sha256=8kSbaUgMEqYvf_VBAuFpBs-RZihEKZCY6kvAJ5U4TSw,2060
|
|
13
|
+
publinker_cli/write_gate.py,sha256=F6a-SWrfDBwsEIzAvSwFmWc0Yd9ATEzcvqpXuP5FKnY,1625
|
|
14
|
+
publinker_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
publinker_cli/commands/auth_cmds.py,sha256=i4SNh16FeAKdLp4wAHsjwWFtAK3pbCpePPNTfcjFr4Y,2216
|
|
16
|
+
publinker_cli/commands/report_options.py,sha256=pQf-llhG4J1t22zA6giyv27_d2-6G1UtGmgj5cxie_Q,3146
|
|
17
|
+
publinker_cli/commands/skill.py,sha256=XEcHag0d8uJYtHuo83IK3jH3NwLaiXFYteGe2h-Qt4s,1493
|
|
18
|
+
publinker_cli/commands/token_cmd.py,sha256=jJgvDEvKwFWnkqJMHmyeQunYUxnXnDD7YizLp6hmXmU,3398
|
|
19
|
+
publinker_cli/commands/update.py,sha256=ToPDP7EEvmmPtHhP1husYj7WeG85rTONAqMUZ3tFhJI,7456
|
|
20
|
+
publinker_cli/commands/use.py,sha256=I44yJsswDuUoRzBit3xoeIw18f_J3LNGiwqh58ZUYCA,3262
|
|
21
|
+
publinker_cli/commands/write.py,sha256=zVZ8HV_vfDGu8TITyN2R-2Xbly3JoOw1iEbTsYSkwA0,2292
|
|
22
|
+
publinker_cli/skill/SKILL.md,sha256=Gh7AgNE5EwrDkq3LB2TpvphSW1lm2cWxN1nuM-8tjsU,2411
|
|
23
|
+
publinker_cli-0.6.2.dist-info/METADATA,sha256=jYPPS1TMh1kbhI6j98RQ6A0tGFWkGuC2_q8aabN4H6U,2715
|
|
24
|
+
publinker_cli-0.6.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
25
|
+
publinker_cli-0.6.2.dist-info/entry_points.txt,sha256=N6mAgefPEmix3dV1y3cKNs815txQVjas1NVXIO5Hmn4,57
|
|
26
|
+
publinker_cli-0.6.2.dist-info/RECORD,,
|