pstq 0.1.0__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.
- pstq-0.1.0/.devcontainer/Dockerfile +49 -0
- pstq-0.1.0/.devcontainer/devcontainer.json +24 -0
- pstq-0.1.0/.editorconfig +19 -0
- pstq-0.1.0/.github/workflows/ci.yml +36 -0
- pstq-0.1.0/.github/workflows/release.yml +166 -0
- pstq-0.1.0/.gitignore +106 -0
- pstq-0.1.0/.opencode/skills/pstq/SKILL.md +27 -0
- pstq-0.1.0/AGENTS.md +193 -0
- pstq-0.1.0/CHANGELOG.md +5 -0
- pstq-0.1.0/LICENSE +22 -0
- pstq-0.1.0/PKG-INFO +187 -0
- pstq-0.1.0/PST Search CLI /342/200/224 Implementation Brief.md" +958 -0
- pstq-0.1.0/README.md +168 -0
- pstq-0.1.0/backlog/config.yml +17 -0
- pstq-0.1.0/backlog/tasks/task-001 - Build-offline-PST-query-CLI.md +28 -0
- pstq-0.1.0/backlog/tasks/task-001.01 - Prepare-libpff-reader-integration.md +92 -0
- pstq-0.1.0/backlog/tasks/task-001.02 - Benchmark-PST-metadata-traversal-and-snapshots.md +84 -0
- pstq-0.1.0/backlog/tasks/task-001.03 - Create-SQLite-full-index-importer.md +79 -0
- pstq-0.1.0/backlog/tasks/task-001.04 - Implement-atomic-incremental-synchronization.md +73 -0
- pstq-0.1.0/backlog/tasks/task-001.05 - Add-FTS-search-and-message-retrieval-commands.md +120 -0
- pstq-0.1.0/backlog/tasks/task-001.06 - Clean-quoted-reply-history-for-indexing.md +79 -0
- pstq-0.1.0/backlog/tasks/task-001.07 - Add-thread-reconstruction-command.md +94 -0
- pstq-0.1.0/backlog/tasks/task-001.08 - Add-attachment-metadata-and-extraction.md +115 -0
- pstq-0.1.0/backlog/tasks/task-001.09 - Finalize-agent-CLI-contract-and-documentation.md +125 -0
- pstq-0.1.0/backlog/tasks/task-001.10 - Document-available-PST-query-commands.md +75 -0
- pstq-0.1.0/backlog/tasks/task-001.11 - Show-cleaned-body-by-default.md +60 -0
- pstq-0.1.0/backlog/tasks/task-001.12 - Render-HTML-bodies-with-image-markers.md +60 -0
- pstq-0.1.0/backlog/tasks/task-001.13 - Recover-owner-messages-from-quoted-history.md +90 -0
- pstq-0.1.0/backlog/tasks/task-001.14 - Search-recovered-owner-responses.md +94 -0
- pstq-0.1.0/backlog/tasks/task-001.15 - Resolve-quoted-CID-images-through-source-attachments.md +76 -0
- pstq-0.1.0/backlog/tasks/task-001.16 - Stop-persisting-raw-message-bodies.md +83 -0
- pstq-0.1.0/backlog/tasks/task-002 - Fail-snapshot-on-incomplete-traversal.md +75 -0
- pstq-0.1.0/backlog/tasks/task-003 - Align-attachment-overwrite-behavior-with-docs.md +78 -0
- pstq-0.1.0/backlog/tasks/task-004 - Remove-stray-tracked-test-artifacts.md +89 -0
- pstq-0.1.0/backlog/tasks/task-005 - Bound-thread-reconstruction-for-large-archives.md +77 -0
- pstq-0.1.0/backlog/tasks/task-006 - Reconcile-pypff-dependency-and-install-docs.md +97 -0
- pstq-0.1.0/backlog/tasks/task-007 - Harden-json-error-detection-and-no-command-UX.md +80 -0
- pstq-0.1.0/backlog/tasks/task-008 - Incrementally-rebuild-recovered-messages.md +89 -0
- pstq-0.1.0/backlog/tasks/task-009 - Simplify-redundant-history-sync-branching.md +94 -0
- pstq-0.1.0/backlog/tasks/task-010 - Own-and-distribute-the-libpff-integration.md +72 -0
- pstq-0.1.0/backlog/tasks/task-011 - Add-CI-and-PyPI-release-automation.md +66 -0
- pstq-0.1.0/backlog/tasks/task-012 - Restore-the-release-quality-gate.md +67 -0
- pstq-0.1.0/backlog/tasks/task-013 - Make-metadata-coverage-independent-of-pypff-availability.md +66 -0
- pstq-0.1.0/docs/adr/0001-expose-direct-pst-item-lookup.md +29 -0
- pstq-0.1.0/docs/adr/0002-use-stock-pypff-traversal-locators.md +32 -0
- pstq-0.1.0/docs/adr/0003-reconstruct-threads-from-indexed-relationship-metadata.md +49 -0
- pstq-0.1.0/docs/adr/0004-model-quoted-history-as-derived-messages.md +49 -0
- pstq-0.1.0/docs/adr/0005-unify-native-and-recovered-message-search.md +44 -0
- pstq-0.1.0/docs/code-review-2026-08-29.html +256 -0
- pstq-0.1.0/pstq/__init__.py +6 -0
- pstq-0.1.0/pstq/body.py +283 -0
- pstq-0.1.0/pstq/cli.py +700 -0
- pstq-0.1.0/pstq/default_config.yaml +33 -0
- pstq-0.1.0/pstq/index.py +2193 -0
- pstq-0.1.0/pstq/metadata.py +339 -0
- pstq-0.1.0/pstq/pst.py +595 -0
- pstq-0.1.0/pstq/pstq.py +11 -0
- pstq-0.1.0/pyproject.toml +65 -0
- pstq-0.1.0/tests/test_body.py +110 -0
- pstq-0.1.0/tests/test_index.py +2071 -0
- pstq-0.1.0/tests/test_metadata.py +361 -0
- pstq-0.1.0/tests/test_pst.py +660 -0
- pstq-0.1.0/tests/test_pstq.py +917 -0
- pstq-0.1.0/tox.ini +23 -0
- pstq-0.1.0/uv.lock +530 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
FROM python:3.13-slim AS pypff-builder
|
|
2
|
+
|
|
3
|
+
# Build a wheel from the immutable libpff Python source distribution.
|
|
4
|
+
ARG LIBPFF_VERSION=20231205
|
|
5
|
+
ARG LIBPFF_SHA256=06c218be51321b16dc3b835185ee1cd2fa5c2a1ca856e0390c1d6e4ddf329250
|
|
6
|
+
|
|
7
|
+
# Install the native build dependencies in the builder only.
|
|
8
|
+
RUN apt-get update \
|
|
9
|
+
&& apt-get install -y --no-install-recommends \
|
|
10
|
+
build-essential \
|
|
11
|
+
ca-certificates \
|
|
12
|
+
curl \
|
|
13
|
+
zlib1g-dev \
|
|
14
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
15
|
+
|
|
16
|
+
RUN curl --fail --location --silent --show-error \
|
|
17
|
+
--output /tmp/libpff-python.tar.gz \
|
|
18
|
+
"https://files.pythonhosted.org/packages/0b/a3/826777491832478f5e1555a16bc9de794ef0264eac53d213340dddae5bd4/libpff-python-${LIBPFF_VERSION}.tar.gz" \
|
|
19
|
+
&& printf '%s %s\n' "$LIBPFF_SHA256" /tmp/libpff-python.tar.gz \
|
|
20
|
+
| sha256sum --check \
|
|
21
|
+
&& python -m pip wheel --no-cache-dir --no-deps \
|
|
22
|
+
--wheel-dir /opt/pypff-wheel /tmp/libpff-python.tar.gz
|
|
23
|
+
|
|
24
|
+
FROM python:3.13-slim
|
|
25
|
+
|
|
26
|
+
COPY --from=pypff-builder /opt/pypff-wheel /tmp/pypff-wheel
|
|
27
|
+
|
|
28
|
+
RUN python -m pip install --no-cache-dir /tmp/pypff-wheel/*.whl \
|
|
29
|
+
&& python -c "import pypff" \
|
|
30
|
+
&& rm -rf /tmp/pypff-wheel
|
|
31
|
+
|
|
32
|
+
# Install git and other dependencies.
|
|
33
|
+
RUN apt-get update \
|
|
34
|
+
&& apt-get install -y --no-install-recommends bash ca-certificates curl git \
|
|
35
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
36
|
+
|
|
37
|
+
# Install uv
|
|
38
|
+
RUN pip install uv
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Install Backlog.md
|
|
42
|
+
RUN apt-get update \
|
|
43
|
+
&& apt-get install -y --no-install-recommends nodejs npm \
|
|
44
|
+
&& npm install -g backlog.md \
|
|
45
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Install OpenCode CLI
|
|
49
|
+
RUN curl -fsSL https://opencode.ai/install | bash
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Python 3.13",
|
|
3
|
+
"build": {
|
|
4
|
+
"dockerfile": "Dockerfile"
|
|
5
|
+
},
|
|
6
|
+
"customizations": {
|
|
7
|
+
"vscode": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"ms-python.python",
|
|
10
|
+
"ms-python.vscode-pylance",
|
|
11
|
+
"charliermarsh.ruff",
|
|
12
|
+
"sst-dev.opencode"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"remoteEnv": {
|
|
17
|
+
"OPENCODE_ENABLE_EXA": "true"
|
|
18
|
+
},
|
|
19
|
+
"mounts": [
|
|
20
|
+
"source=${localEnv:HOME}/.config/opencode,target=/root/.config/opencode,type=bind,consistency=cached",
|
|
21
|
+
"source=${localEnv:HOME}/.local/share/opencode,target=/root/.local/share/opencode,type=bind,consistency=cached"
|
|
22
|
+
],
|
|
23
|
+
"postCreateCommand": "if [ -f .backlog-config.yml ]; then git init && backlog init --defaults --backlog-dir backlog --config-location folder --task-prefix task --zero-padded-ids 3 --check-branches false --include-remote false --branch-days 30 --bypass-git-hooks true --web-port 6420 --auto-open-browser false --integration-mode cli --agent-instructions agents && mv .backlog-config.yml backlog/config.yml; fi && uv venv --clear --system-site-packages && uv sync --group dev && uv run python -c 'import pypff'"
|
|
24
|
+
}
|
pstq-0.1.0/.editorconfig
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# http://editorconfig.org
|
|
2
|
+
|
|
3
|
+
root = true
|
|
4
|
+
|
|
5
|
+
[*]
|
|
6
|
+
indent_style = space
|
|
7
|
+
indent_size = 4
|
|
8
|
+
trim_trailing_whitespace = true
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
charset = utf-8
|
|
11
|
+
end_of_line = lf
|
|
12
|
+
|
|
13
|
+
[*.bat]
|
|
14
|
+
indent_style = tab
|
|
15
|
+
end_of_line = crlf
|
|
16
|
+
|
|
17
|
+
[LICENSE]
|
|
18
|
+
insert_final_newline = false
|
|
19
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
quality:
|
|
21
|
+
name: Quality checks
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.13"
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Run quality checks
|
|
36
|
+
run: uv run tox
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag:
|
|
10
|
+
description: Existing vX.Y.Z tag to release
|
|
11
|
+
required: true
|
|
12
|
+
type: string
|
|
13
|
+
skip_pypi:
|
|
14
|
+
description: Skip PyPI only when this version is already published
|
|
15
|
+
required: true
|
|
16
|
+
default: false
|
|
17
|
+
type: boolean
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
|
24
|
+
cancel-in-progress: false
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
build:
|
|
28
|
+
name: Validate and build release artifacts
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
outputs:
|
|
31
|
+
tag: ${{ steps.release.outputs.tag }}
|
|
32
|
+
steps:
|
|
33
|
+
- name: Check out release tag
|
|
34
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
persist-credentials: false
|
|
39
|
+
|
|
40
|
+
- name: Validate release version
|
|
41
|
+
id: release
|
|
42
|
+
env:
|
|
43
|
+
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
|
44
|
+
run: |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
[[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
|
|
47
|
+
echo "Release tag must match vX.Y.Z: $RELEASE_TAG" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
}
|
|
50
|
+
git rev-parse --verify "refs/tags/$RELEASE_TAG" >/dev/null
|
|
51
|
+
python - "$RELEASE_TAG" <<'PY'
|
|
52
|
+
import ast
|
|
53
|
+
import re
|
|
54
|
+
import sys
|
|
55
|
+
import tomllib
|
|
56
|
+
|
|
57
|
+
tag = sys.argv[1]
|
|
58
|
+
with open("pyproject.toml", "rb") as pyproject:
|
|
59
|
+
version = tomllib.load(pyproject)["project"]["version"]
|
|
60
|
+
module = ast.parse(open("pstq/__init__.py", encoding="utf-8").read())
|
|
61
|
+
module_version = next(
|
|
62
|
+
(
|
|
63
|
+
ast.literal_eval(node.value)
|
|
64
|
+
for node in module.body
|
|
65
|
+
if isinstance(node, ast.Assign)
|
|
66
|
+
and any(
|
|
67
|
+
isinstance(target, ast.Name) and target.id == "__version__"
|
|
68
|
+
for target in node.targets
|
|
69
|
+
)
|
|
70
|
+
),
|
|
71
|
+
None,
|
|
72
|
+
)
|
|
73
|
+
changelog = open("CHANGELOG.md", encoding="utf-8").read()
|
|
74
|
+
|
|
75
|
+
if tag != f"v{version}":
|
|
76
|
+
raise SystemExit(
|
|
77
|
+
f"Release tag {tag!r} does not match package version {version!r}."
|
|
78
|
+
)
|
|
79
|
+
if module_version != version:
|
|
80
|
+
raise SystemExit(
|
|
81
|
+
"pstq.__version__ does not match the package version "
|
|
82
|
+
f"{version!r}."
|
|
83
|
+
)
|
|
84
|
+
if not re.search(rf"^## {re.escape(version)}(?: |$)", changelog, re.MULTILINE):
|
|
85
|
+
raise SystemExit(f"CHANGELOG.md has no heading for version {version!r}.")
|
|
86
|
+
PY
|
|
87
|
+
echo "tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
|
|
88
|
+
|
|
89
|
+
- name: Install uv
|
|
90
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
91
|
+
with:
|
|
92
|
+
python-version: "3.13"
|
|
93
|
+
|
|
94
|
+
- name: Install locked development dependencies
|
|
95
|
+
run: uv sync --group dev --locked
|
|
96
|
+
|
|
97
|
+
- name: Run quality checks
|
|
98
|
+
run: uv run tox
|
|
99
|
+
|
|
100
|
+
- name: Build distributions
|
|
101
|
+
run: uv build --out-dir dist --clear
|
|
102
|
+
|
|
103
|
+
- name: Validate distribution metadata
|
|
104
|
+
run: uv tool run twine check dist/*
|
|
105
|
+
|
|
106
|
+
- name: Smoke test the built wheel
|
|
107
|
+
run: |
|
|
108
|
+
uv venv --python 3.13 .release-venv
|
|
109
|
+
uv pip install --python .release-venv/bin/python dist/*.whl
|
|
110
|
+
.release-venv/bin/python - <<'PY'
|
|
111
|
+
import importlib.metadata
|
|
112
|
+
import pstq
|
|
113
|
+
|
|
114
|
+
assert importlib.metadata.version("pstq") == pstq.__version__
|
|
115
|
+
PY
|
|
116
|
+
.release-venv/bin/pstq --help >/dev/null
|
|
117
|
+
|
|
118
|
+
- name: Upload release distributions
|
|
119
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
120
|
+
with:
|
|
121
|
+
name: release-distributions
|
|
122
|
+
path: dist/
|
|
123
|
+
if-no-files-found: error
|
|
124
|
+
|
|
125
|
+
publish-pypi:
|
|
126
|
+
name: Publish to PyPI
|
|
127
|
+
needs: build
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
environment:
|
|
130
|
+
name: pypi
|
|
131
|
+
url: https://pypi.org/p/pstq
|
|
132
|
+
permissions:
|
|
133
|
+
id-token: write
|
|
134
|
+
steps:
|
|
135
|
+
- name: Download release distributions
|
|
136
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
137
|
+
with:
|
|
138
|
+
name: release-distributions
|
|
139
|
+
path: dist/
|
|
140
|
+
|
|
141
|
+
- name: Publish package distributions to PyPI
|
|
142
|
+
if: ${{ !inputs.skip_pypi }}
|
|
143
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
144
|
+
with:
|
|
145
|
+
packages-dir: dist/
|
|
146
|
+
|
|
147
|
+
create-github-release:
|
|
148
|
+
name: Create GitHub Release
|
|
149
|
+
needs:
|
|
150
|
+
- build
|
|
151
|
+
- publish-pypi
|
|
152
|
+
runs-on: ubuntu-latest
|
|
153
|
+
permissions:
|
|
154
|
+
contents: write
|
|
155
|
+
steps:
|
|
156
|
+
- name: Download release distributions
|
|
157
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
158
|
+
with:
|
|
159
|
+
name: release-distributions
|
|
160
|
+
path: dist/
|
|
161
|
+
|
|
162
|
+
- name: Create GitHub Release
|
|
163
|
+
env:
|
|
164
|
+
GH_TOKEN: ${{ github.token }}
|
|
165
|
+
RELEASE_TAG: ${{ needs.build.outputs.tag }}
|
|
166
|
+
run: gh release create "$RELEASE_TAG" dist/* --verify-tag --generate-notes
|
pstq-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
env/
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
|
|
28
|
+
# PyInstaller
|
|
29
|
+
# Usually these files are written by a python script from a template
|
|
30
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
31
|
+
*.manifest
|
|
32
|
+
*.spec
|
|
33
|
+
|
|
34
|
+
# Installer logs
|
|
35
|
+
pip-log.txt
|
|
36
|
+
pip-delete-this-directory.txt
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
.hypothesis/
|
|
48
|
+
.pytest_cache/
|
|
49
|
+
|
|
50
|
+
# Translations
|
|
51
|
+
*.mo
|
|
52
|
+
*.pot
|
|
53
|
+
|
|
54
|
+
# Django stuff:
|
|
55
|
+
*.log
|
|
56
|
+
local_settings.py
|
|
57
|
+
|
|
58
|
+
# Flask stuff:
|
|
59
|
+
instance/
|
|
60
|
+
.webassets-cache
|
|
61
|
+
|
|
62
|
+
# Scrapy stuff:
|
|
63
|
+
.scrapy
|
|
64
|
+
|
|
65
|
+
# PyBuilder
|
|
66
|
+
target/
|
|
67
|
+
|
|
68
|
+
# Jupyter Notebook
|
|
69
|
+
.ipynb_checkpoints
|
|
70
|
+
|
|
71
|
+
# pyenv
|
|
72
|
+
#.python-version
|
|
73
|
+
|
|
74
|
+
# celery beat schedule file
|
|
75
|
+
celerybeat-schedule
|
|
76
|
+
|
|
77
|
+
# SageMath parsed files
|
|
78
|
+
*.sage.py
|
|
79
|
+
|
|
80
|
+
# dotenv
|
|
81
|
+
.env
|
|
82
|
+
|
|
83
|
+
# virtualenv
|
|
84
|
+
.venv
|
|
85
|
+
venv/
|
|
86
|
+
ENV/
|
|
87
|
+
|
|
88
|
+
# Spyder project settings
|
|
89
|
+
.spyderproject
|
|
90
|
+
.spyproject
|
|
91
|
+
|
|
92
|
+
# Rope project settings
|
|
93
|
+
.ropeproject
|
|
94
|
+
|
|
95
|
+
# mypy
|
|
96
|
+
.mypy_cache/
|
|
97
|
+
alabaster
|
|
98
|
+
|
|
99
|
+
.vscode/
|
|
100
|
+
.idea/
|
|
101
|
+
.claude/
|
|
102
|
+
|
|
103
|
+
# temporary files
|
|
104
|
+
temp/
|
|
105
|
+
test.json
|
|
106
|
+
test_config.yaml
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pstq
|
|
3
|
+
description: Use when searching, retrieving, threading, or extracting content from an Outlook PST with pstq.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PST Query
|
|
7
|
+
|
|
8
|
+
Use `pstq` rather than parsing the PST or SQLite database directly. The PST is
|
|
9
|
+
read-only and authoritative; the SQLite index is a disposable local cache.
|
|
10
|
+
|
|
11
|
+
Before issuing an unfamiliar command, read its canonical documentation:
|
|
12
|
+
|
|
13
|
+
```console
|
|
14
|
+
pstq --help
|
|
15
|
+
pstq <command> --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use `--json` for programmatic work. On success it writes deterministic JSON to
|
|
19
|
+
stdout. On failure it writes a JSON error envelope to stderr and returns a
|
|
20
|
+
non-zero exit code. Do not infer JSON fields, ID formats, limits, cache access,
|
|
21
|
+
or synchronization behavior from this skill; command-level `--help` defines
|
|
22
|
+
the current contract.
|
|
23
|
+
|
|
24
|
+
The normal retrieval sequence is `status`, `folders` when needed, bounded
|
|
25
|
+
`search`, then `show` for selected message IDs. Use `thread`, `attachments`,
|
|
26
|
+
and `attachment` only after reading their help. Never modify the configured
|
|
27
|
+
PST or assume it is safe to access while Outlook is writing it.
|
pstq-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
## Backlog.md workflow
|
|
2
|
+
|
|
3
|
+
Backlog.md is the authoritative record of active and completed development work.
|
|
4
|
+
|
|
5
|
+
Tasks are living work records. Their initial descriptions and acceptance criteria may be incomplete and may evolve during implementation as the human and agent investigate the problem.
|
|
6
|
+
|
|
7
|
+
### General rules
|
|
8
|
+
|
|
9
|
+
1. Before beginning substantial work, identify the relevant Backlog task and read it in full.
|
|
10
|
+
2. Do not treat the initial task specification as immutable.
|
|
11
|
+
3. Keep the task synchronized with the current shared understanding throughout the development session.
|
|
12
|
+
4. Do not require the human to operate the Backlog CLI. Perform all necessary Backlog operations yourself.
|
|
13
|
+
5. Use Backlog.md tasks, comments, plans, notes, and final summaries.
|
|
14
|
+
6. Do not use Backlog.md decisions. Record durable architectural decisions as ADRs under `docs/adr/`.
|
|
15
|
+
7. Only the human may accept a task as complete.
|
|
16
|
+
|
|
17
|
+
### Comments
|
|
18
|
+
|
|
19
|
+
Use task comments as a concise chronological record of material human-agent discussion.
|
|
20
|
+
|
|
21
|
+
Add comments on behalf of both participants when the conversation produces information that would be useful in a future session, including:
|
|
22
|
+
|
|
23
|
+
* clarification of ambiguous requirements;
|
|
24
|
+
* answers to implementation questions;
|
|
25
|
+
* requested changes in behavior or scope;
|
|
26
|
+
* alternatives considered and rejected;
|
|
27
|
+
* explicit human approvals or objections;
|
|
28
|
+
* reasons for changing the implementation direction;
|
|
29
|
+
* unresolved questions that affect further work.
|
|
30
|
+
|
|
31
|
+
When recording comments:
|
|
32
|
+
|
|
33
|
+
* Attribute each comment clearly as `Human` or `Agent`.
|
|
34
|
+
* A comment attributed to `Human` must faithfully summarize something the human explicitly said or confirmed.
|
|
35
|
+
* Do not invent, extrapolate, or strengthen the human's position.
|
|
36
|
+
* Preserve important qualifications and uncertainty.
|
|
37
|
+
* Prefer concise summaries over verbatim transcripts.
|
|
38
|
+
* Do not record routine conversation, acknowledgements, minor corrections, or raw chat history.
|
|
39
|
+
* Group closely related discussion into one comment when appropriate.
|
|
40
|
+
* Record comments during the session when a material clarification occurs, rather than trying to reconstruct the entire conversation at the end.
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
|
|
44
|
+
> **Agent:** The existing importer permits identical entries from different source files. Should duplicate detection apply globally or only within one import?
|
|
45
|
+
|
|
46
|
+
> **Human:** Duplicate detection should apply only within one import process. Identical entries from separate imports are allowed.
|
|
47
|
+
|
|
48
|
+
Comments provide the historical trail, but they are not the canonical specification.
|
|
49
|
+
|
|
50
|
+
### Updating the canonical task
|
|
51
|
+
|
|
52
|
+
After a question is settled, update the relevant canonical part of the task:
|
|
53
|
+
|
|
54
|
+
* update the description when the intended behavior or scope changes;
|
|
55
|
+
* update acceptance criteria when testable requirements are clarified;
|
|
56
|
+
* update the implementation plan when the technical approach changes;
|
|
57
|
+
* update dependencies when newly discovered work blocks the task.
|
|
58
|
+
|
|
59
|
+
A future agent should be able to understand the current requirements without reconstructing them from comments.
|
|
60
|
+
|
|
61
|
+
Preserve the original intent where useful, but make the current description and acceptance criteria accurately represent the latest agreed behavior.
|
|
62
|
+
|
|
63
|
+
When requirements remain uncertain, state the uncertainty explicitly rather than silently selecting an interpretation.
|
|
64
|
+
|
|
65
|
+
### Notes
|
|
66
|
+
|
|
67
|
+
Use task notes as durable working memory for implementation-related knowledge discovered during the task.
|
|
68
|
+
|
|
69
|
+
Appropriate notes include:
|
|
70
|
+
|
|
71
|
+
* relevant existing code and where it is located;
|
|
72
|
+
* observed current behavior;
|
|
73
|
+
* investigation results;
|
|
74
|
+
* technical constraints;
|
|
75
|
+
* external API or library behavior relevant to the task;
|
|
76
|
+
* failed approaches and why they failed;
|
|
77
|
+
* commands useful for reproducing or verifying behavior;
|
|
78
|
+
* migration or compatibility concerns;
|
|
79
|
+
* assumptions that still require verification;
|
|
80
|
+
* risks and known limitations;
|
|
81
|
+
* useful context for continuing the task in another agent session.
|
|
82
|
+
|
|
83
|
+
Notes should contain distilled conclusions and evidence, not private reasoning or an exhaustive activity log.
|
|
84
|
+
|
|
85
|
+
Good note:
|
|
86
|
+
|
|
87
|
+
> Duplicate detection cannot use a database unique constraint because users may approve otherwise identical rows. Implement it in `ImportValidationService`, scoped by `ImportProcess.id`.
|
|
88
|
+
|
|
89
|
+
Bad note:
|
|
90
|
+
|
|
91
|
+
> I opened several files, thought about using a constraint, changed my mind, and then considered a service.
|
|
92
|
+
|
|
93
|
+
Keep notes current:
|
|
94
|
+
|
|
95
|
+
* correct notes that are proven wrong;
|
|
96
|
+
* remove or clearly mark obsolete information;
|
|
97
|
+
* preserve failed approaches only when knowing about them prevents repeated work;
|
|
98
|
+
* distinguish confirmed facts from assumptions.
|
|
99
|
+
|
|
100
|
+
### ADRs
|
|
101
|
+
|
|
102
|
+
Do not create or use Backlog.md decision records.
|
|
103
|
+
|
|
104
|
+
Create an ADR under `docs/adr/` when a decision:
|
|
105
|
+
|
|
106
|
+
* affects multiple tasks or components;
|
|
107
|
+
* defines a long-lived architectural rule;
|
|
108
|
+
* changes an important data model, interface, dependency, or deployment approach;
|
|
109
|
+
* involves meaningful alternatives and trade-offs;
|
|
110
|
+
* is likely to matter after the current task is completed.
|
|
111
|
+
|
|
112
|
+
Use the next available ADR number and the repository's ADR template.
|
|
113
|
+
|
|
114
|
+
A task should link to relevant ADRs, for example:
|
|
115
|
+
|
|
116
|
+
> Architectural context: `docs/adr/0012-store-monetary-values-as-integers.md`
|
|
117
|
+
|
|
118
|
+
Task-specific choices that have no wider architectural significance should remain in the task comments, notes, or implementation plan.
|
|
119
|
+
|
|
120
|
+
### Scope discovered during implementation
|
|
121
|
+
|
|
122
|
+
Do not silently expand a task.
|
|
123
|
+
|
|
124
|
+
When additional work is discovered:
|
|
125
|
+
|
|
126
|
+
* incorporate it into the active task only when it is small, necessary to satisfy the agreed acceptance criteria, and does not materially broaden the scope;
|
|
127
|
+
* otherwise create a separate Backlog task;
|
|
128
|
+
* link the new task from the active task;
|
|
129
|
+
* state whether it blocks the active task or is follow-up work.
|
|
130
|
+
|
|
131
|
+
### Session checkpoints
|
|
132
|
+
|
|
133
|
+
Update the Backlog task at natural checkpoints:
|
|
134
|
+
|
|
135
|
+
1. after initial investigation;
|
|
136
|
+
2. after a material requirement clarification;
|
|
137
|
+
3. after a significant change in implementation approach;
|
|
138
|
+
4. before ending a session with unfinished work;
|
|
139
|
+
5. before requesting human review.
|
|
140
|
+
|
|
141
|
+
Before ending an unfinished session, ensure that another agent can continue from the task without requiring access to the previous chat.
|
|
142
|
+
|
|
143
|
+
At minimum, record:
|
|
144
|
+
|
|
145
|
+
* the current state of implementation;
|
|
146
|
+
* settled requirements;
|
|
147
|
+
* remaining open questions;
|
|
148
|
+
* relevant findings;
|
|
149
|
+
* the next concrete action;
|
|
150
|
+
* commands or tests needed to continue.
|
|
151
|
+
|
|
152
|
+
### Completion
|
|
153
|
+
|
|
154
|
+
Before moving a task to human review:
|
|
155
|
+
|
|
156
|
+
1. Re-read the complete task.
|
|
157
|
+
2. Ensure the description and acceptance criteria reflect the final agreed scope.
|
|
158
|
+
3. Ensure all material session decisions are represented in the canonical task, comments, notes, or an ADR.
|
|
159
|
+
4. Update acceptance-criteria checkboxes based on verified behavior.
|
|
160
|
+
5. Add a final summary containing:
|
|
161
|
+
|
|
162
|
+
* what changed;
|
|
163
|
+
* important implementation choices;
|
|
164
|
+
* tests and checks performed;
|
|
165
|
+
* known limitations;
|
|
166
|
+
* follow-up tasks;
|
|
167
|
+
* ADRs created or referenced.
|
|
168
|
+
6. Move the task to the review state, not directly to accepted or complete.
|
|
169
|
+
7. Leave final acceptance to the human.
|
|
170
|
+
|
|
171
|
+
<!-- BACKLOG.MD GUIDELINES START -->
|
|
172
|
+
<!-- backlog.md-instructions-version: 1.50.1 -->
|
|
173
|
+
<CRITICAL_INSTRUCTION>
|
|
174
|
+
|
|
175
|
+
## Backlog.md Workflow
|
|
176
|
+
|
|
177
|
+
This project uses Backlog.md for task and project management.
|
|
178
|
+
|
|
179
|
+
**For every user request in this project, run `backlog instructions overview` before answering or taking action.**
|
|
180
|
+
|
|
181
|
+
Use the overview to decide whether to search, read, create, or update Backlog tasks.
|
|
182
|
+
|
|
183
|
+
Before task lifecycle actions, read the matching detailed guide:
|
|
184
|
+
- `backlog instructions task-creation` before creating or splitting tasks
|
|
185
|
+
- `backlog instructions task-execution` before planning, changing status or assignee, adding a plan or implementation notes, or implementing task work
|
|
186
|
+
- `backlog instructions task-finalization` before checking acceptance criteria, writing final summaries, or moving tasks to terminal statuses
|
|
187
|
+
|
|
188
|
+
Use `backlog <command> --help` before running unfamiliar commands. Help shows options, fields, and examples.
|
|
189
|
+
|
|
190
|
+
Do not edit Backlog task, draft, document, decision, or milestone markdown files directly. Use the `backlog` CLI so metadata, relationships, and history stay consistent.
|
|
191
|
+
|
|
192
|
+
</CRITICAL_INSTRUCTION>
|
|
193
|
+
<!-- BACKLOG.MD GUIDELINES END -->
|
pstq-0.1.0/CHANGELOG.md
ADDED
pstq-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Josef Nevrly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|