prompt-diary 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.
- prompt_diary-0.1.0/PKG-INFO +121 -0
- prompt_diary-0.1.0/README.md +106 -0
- prompt_diary-0.1.0/pyproject.toml +172 -0
- prompt_diary-0.1.0/src/prompt_diary/__init__.py +5 -0
- prompt_diary-0.1.0/src/prompt_diary/agent.py +78 -0
- prompt_diary-0.1.0/src/prompt_diary/cli.py +42 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/__init__.py +1 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/common.py +53 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/config.py +207 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/generate.py +373 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/mcp.py +19 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/prepare.py +49 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/prompts.py +163 -0
- prompt_diary-0.1.0/src/prompt_diary/cmds/render.py +50 -0
- prompt_diary-0.1.0/src/prompt_diary/config.py +218 -0
- prompt_diary-0.1.0/src/prompt_diary/errors.py +11 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/__init__.py +0 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/__init__.py +5 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/build.py +338 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/citations.py +67 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/finalize.py +443 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/inputs.py +209 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/layout.py +562 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/mcp.py +485 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/model.py +417 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_client_adapter.py +124 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_publish.py +389 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_validate.py +79 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/render_markdown.py +266 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/render_notion.py +323 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/runner.py +250 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/__init__.py +19 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/inputs.py +124 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/mcp.py +323 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/model.py +458 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/runner.py +172 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/session_compaction.py +544 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/session_reader.py +300 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/pipeline.py +603 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/__init__.py +5 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/cards.py +120 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/inputs.py +108 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/mcp.py +336 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/model.py +487 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/runner.py +202 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/__init__.py +256 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/engagement.md +72 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/evidence-extractor-next-turn.md +28 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/evidence-extractor.md +195 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-summary.md +58 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-synthesizer-next.md +23 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-synthesizer.md +165 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/prompts/team-learning.md +92 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/workflow.py +296 -0
- prompt_diary-0.1.0/src/prompt_diary/generate/workspace.py +389 -0
- prompt_diary-0.1.0/src/prompt_diary/integrations/__init__.py +0 -0
- prompt_diary-0.1.0/src/prompt_diary/integrations/codex_runner.py +411 -0
- prompt_diary-0.1.0/src/prompt_diary/mcp/__init__.py +0 -0
- prompt_diary-0.1.0/src/prompt_diary/mcp/codex_config.py +94 -0
- prompt_diary-0.1.0/src/prompt_diary/mcp/server.py +149 -0
- prompt_diary-0.1.0/src/prompt_diary/models.py +69 -0
- prompt_diary-0.1.0/src/prompt_diary/paths.py +37 -0
- prompt_diary-0.1.0/src/prompt_diary/prepare/__init__.py +0 -0
- prompt_diary-0.1.0/src/prompt_diary/prepare/workspace.py +1850 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/__init__.py +39 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/console.py +148 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/events.py +99 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/log.py +81 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/reporter.py +63 -0
- prompt_diary-0.1.0/src/prompt_diary/progress/state.py +149 -0
- prompt_diary-0.1.0/src/prompt_diary/render/__init__.py +1 -0
- prompt_diary-0.1.0/src/prompt_diary/render/notion.py +112 -0
- prompt_diary-0.1.0/src/prompt_diary/secret.py +33 -0
- prompt_diary-0.1.0/src/prompt_diary/targeting/__init__.py +0 -0
- prompt_diary-0.1.0/src/prompt_diary/targeting/resolve.py +138 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: prompt-diary
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Review user prompts for evidence-backed improvement in AI coding collaboration.
|
|
5
|
+
Requires-Dist: jinja2>=3.1
|
|
6
|
+
Requires-Dist: mcp>=1.2
|
|
7
|
+
Requires-Dist: msgspec>=0.21.1
|
|
8
|
+
Requires-Dist: notion-client>=2.0
|
|
9
|
+
Requires-Dist: openai-codex>=0.1.0b2
|
|
10
|
+
Requires-Dist: platformdirs>=4.0
|
|
11
|
+
Requires-Dist: rich>=13
|
|
12
|
+
Requires-Dist: typer>=0.25.1
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# Prompt Diary
|
|
17
|
+
|
|
18
|
+
Language: English | [简体中文](README.zh-CN.md)
|
|
19
|
+
|
|
20
|
+
[](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml)
|
|
21
|
+
[](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml)
|
|
22
|
+
[](https://pypi.org/project/prompt-diary/)
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
Prompt Diary prepares bounded workspaces from local assistant session history and generates evidenced prompt diary reports that help users review and improve how they collaborate with AI coding agents.
|
|
26
|
+
|
|
27
|
+
The tool targets Python 3.10 and newer. The package exposes `report` and `prompt-diary`
|
|
28
|
+
console commands after installation.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
Install Prompt Diary from PyPI as an isolated uv tool:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv tool install prompt-diary
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
report --help
|
|
42
|
+
prompt-diary --help
|
|
43
|
+
report prepare --date 2026-05-12 --timezone Asia/Shanghai
|
|
44
|
+
report generate --date 2026-05-12 --timezone Asia/Shanghai
|
|
45
|
+
report render notion --date 2026-05-12 --timezone Asia/Shanghai
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Generation is an artifact-first pipeline with standalone phase commands:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
report generate evidence --date 2026-05-12 --timezone Asia/Shanghai --project-key <project> --session-ref S0001
|
|
52
|
+
report generate project --date 2026-05-12 --timezone Asia/Shanghai --project-key <project>
|
|
53
|
+
report generate daily --date 2026-05-12 --timezone Asia/Shanghai
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Once Notion is configured, `report render notion` can publish an already-generated report as a new
|
|
57
|
+
row in the Notion database. It resolves the existing workspace, requires `daily-report.json`,
|
|
58
|
+
regenerates the deterministic `report.notion.json` payload beside `report.md`, and publishes that
|
|
59
|
+
payload. `report generate` delegates to the same render path after a successful pipeline: by default
|
|
60
|
+
it publishes when Notion is configured; pass `--no-notion` to skip publishing, or `--notion` to
|
|
61
|
+
require it (which errors if Notion is not configured). Configure the Notion integration token and
|
|
62
|
+
target database id once with `prompt-diary config init` (see [Configuration](#configuration));
|
|
63
|
+
credentials never pass on the command line. Each run appends a new dated row; re-publishing never
|
|
64
|
+
edits or deletes existing rows.
|
|
65
|
+
|
|
66
|
+
Generation drives a three-phase, artifact-first pipeline — evidence extraction, then project
|
|
67
|
+
synthesis, then daily report synthesis — through the Codex CLI, producing `daily-report.json`, the
|
|
68
|
+
rendered `report.md`, and `report.notion.json`. It requires the `codex` CLI to be installed and
|
|
69
|
+
authenticated; the subcommands above run each phase standalone against an already-prepared workspace.
|
|
70
|
+
|
|
71
|
+
Prepared workspaces and generated reports are written under a per-user data directory by default
|
|
72
|
+
(`~/.local/share/prompt-diary/` on Linux; the platform equivalent on macOS and Windows), organized
|
|
73
|
+
by date as `<reports-root>/work/<YYYY-MM-DD>/`. Override the location with `--reports-root <path>` on
|
|
74
|
+
`prepare`, `generate`, and `render notion`, `PROMPT_DIARY_HOME`, or the stored config (see
|
|
75
|
+
[Configuration](#configuration)); precedence is `--reports-root` over `PROMPT_DIARY_HOME` over the
|
|
76
|
+
stored config over the default data directory. (Earlier versions wrote to `./.reports` in the current directory — pass
|
|
77
|
+
`--reports-root .reports` to keep using an existing local directory.)
|
|
78
|
+
|
|
79
|
+
Both `prepare` and `generate` show a live progress dashboard when running on a TTY and write
|
|
80
|
+
append-only log lines when output is piped, redirected, or running in CI. Pass `--quiet` to either
|
|
81
|
+
command to suppress the live output and print only the final summary.
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
Run `prompt-diary config init` once to set up credentials and settings interactively. It prompts for
|
|
86
|
+
the Notion integration token, an optional data folder, the Notion database id, and an optional
|
|
87
|
+
reporter name (a free-form label, like `git config user.name`, written into the `汇报人` column at
|
|
88
|
+
publish time). Each credential is validated live against the Notion API and saved the moment it
|
|
89
|
+
passes — the token check reports the
|
|
90
|
+
authenticated integration and workspace, and the database check reports the connected database's name
|
|
91
|
+
— so an interrupted run keeps whatever was already verified. Everything is written to a single config
|
|
92
|
+
file with `0600` permissions. The token is read only from that file or the environment — never passed
|
|
93
|
+
on the command line, and never printed (`config show` masks it).
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
prompt-diary config init # interactive setup; validates the token and database live
|
|
97
|
+
prompt-diary config show # print the configuration (token masked) and the file location
|
|
98
|
+
prompt-diary config path # print the config file location
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The config file lives under the per-user config directory (`~/.config/prompt-diary/config.json` on
|
|
102
|
+
Linux; the platform equivalent on macOS and Windows), overridable with `PROMPT_DIARY_CONFIG`. Each
|
|
103
|
+
setting is resolved from the first source that provides it: a CLI flag (where one exists), then the
|
|
104
|
+
environment, then the stored config, then a built-in default (where one exists). So `NOTION_API_KEY`
|
|
105
|
+
/ `NOTION_PAGE_ID` and `--reports-root` / `PROMPT_DIARY_HOME` still override the stored config (useful
|
|
106
|
+
in CI). Once Notion is configured — including via those environment variables — a bare `report
|
|
107
|
+
generate` publishes by default; pass `--no-notion` in CI or any pipeline that should not publish.
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
This project uses [`uv`](https://docs.astral.sh/uv/) for Python version, environment,
|
|
112
|
+
dependency, build, and release workflows.
|
|
113
|
+
|
|
114
|
+
Read [`docs/src/product.md`](docs/src/product.md) before designing new features, changing report
|
|
115
|
+
content, or modifying the generation pipeline. It defines the tool's purposes and principles that
|
|
116
|
+
downstream design must satisfy.
|
|
117
|
+
|
|
118
|
+
For environment setup, build commands, type checking, testing, coverage, linting, and pre-submit
|
|
119
|
+
checks, including the optional Ubuntu 24.04 devcontainer, see the
|
|
120
|
+
[Development Guide](docs/src/dev/guide.md). For codebase architecture and API design, see
|
|
121
|
+
[Architecture](docs/src/dev/architecture.md).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Prompt Diary
|
|
2
|
+
|
|
3
|
+
Language: English | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml)
|
|
7
|
+
[](https://pypi.org/project/prompt-diary/)
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
Prompt Diary prepares bounded workspaces from local assistant session history and generates evidenced prompt diary reports that help users review and improve how they collaborate with AI coding agents.
|
|
11
|
+
|
|
12
|
+
The tool targets Python 3.10 and newer. The package exposes `report` and `prompt-diary`
|
|
13
|
+
console commands after installation.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Install Prompt Diary from PyPI as an isolated uv tool:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv tool install prompt-diary
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then run:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
report --help
|
|
27
|
+
prompt-diary --help
|
|
28
|
+
report prepare --date 2026-05-12 --timezone Asia/Shanghai
|
|
29
|
+
report generate --date 2026-05-12 --timezone Asia/Shanghai
|
|
30
|
+
report render notion --date 2026-05-12 --timezone Asia/Shanghai
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Generation is an artifact-first pipeline with standalone phase commands:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
report generate evidence --date 2026-05-12 --timezone Asia/Shanghai --project-key <project> --session-ref S0001
|
|
37
|
+
report generate project --date 2026-05-12 --timezone Asia/Shanghai --project-key <project>
|
|
38
|
+
report generate daily --date 2026-05-12 --timezone Asia/Shanghai
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Once Notion is configured, `report render notion` can publish an already-generated report as a new
|
|
42
|
+
row in the Notion database. It resolves the existing workspace, requires `daily-report.json`,
|
|
43
|
+
regenerates the deterministic `report.notion.json` payload beside `report.md`, and publishes that
|
|
44
|
+
payload. `report generate` delegates to the same render path after a successful pipeline: by default
|
|
45
|
+
it publishes when Notion is configured; pass `--no-notion` to skip publishing, or `--notion` to
|
|
46
|
+
require it (which errors if Notion is not configured). Configure the Notion integration token and
|
|
47
|
+
target database id once with `prompt-diary config init` (see [Configuration](#configuration));
|
|
48
|
+
credentials never pass on the command line. Each run appends a new dated row; re-publishing never
|
|
49
|
+
edits or deletes existing rows.
|
|
50
|
+
|
|
51
|
+
Generation drives a three-phase, artifact-first pipeline — evidence extraction, then project
|
|
52
|
+
synthesis, then daily report synthesis — through the Codex CLI, producing `daily-report.json`, the
|
|
53
|
+
rendered `report.md`, and `report.notion.json`. It requires the `codex` CLI to be installed and
|
|
54
|
+
authenticated; the subcommands above run each phase standalone against an already-prepared workspace.
|
|
55
|
+
|
|
56
|
+
Prepared workspaces and generated reports are written under a per-user data directory by default
|
|
57
|
+
(`~/.local/share/prompt-diary/` on Linux; the platform equivalent on macOS and Windows), organized
|
|
58
|
+
by date as `<reports-root>/work/<YYYY-MM-DD>/`. Override the location with `--reports-root <path>` on
|
|
59
|
+
`prepare`, `generate`, and `render notion`, `PROMPT_DIARY_HOME`, or the stored config (see
|
|
60
|
+
[Configuration](#configuration)); precedence is `--reports-root` over `PROMPT_DIARY_HOME` over the
|
|
61
|
+
stored config over the default data directory. (Earlier versions wrote to `./.reports` in the current directory — pass
|
|
62
|
+
`--reports-root .reports` to keep using an existing local directory.)
|
|
63
|
+
|
|
64
|
+
Both `prepare` and `generate` show a live progress dashboard when running on a TTY and write
|
|
65
|
+
append-only log lines when output is piped, redirected, or running in CI. Pass `--quiet` to either
|
|
66
|
+
command to suppress the live output and print only the final summary.
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
Run `prompt-diary config init` once to set up credentials and settings interactively. It prompts for
|
|
71
|
+
the Notion integration token, an optional data folder, the Notion database id, and an optional
|
|
72
|
+
reporter name (a free-form label, like `git config user.name`, written into the `汇报人` column at
|
|
73
|
+
publish time). Each credential is validated live against the Notion API and saved the moment it
|
|
74
|
+
passes — the token check reports the
|
|
75
|
+
authenticated integration and workspace, and the database check reports the connected database's name
|
|
76
|
+
— so an interrupted run keeps whatever was already verified. Everything is written to a single config
|
|
77
|
+
file with `0600` permissions. The token is read only from that file or the environment — never passed
|
|
78
|
+
on the command line, and never printed (`config show` masks it).
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
prompt-diary config init # interactive setup; validates the token and database live
|
|
82
|
+
prompt-diary config show # print the configuration (token masked) and the file location
|
|
83
|
+
prompt-diary config path # print the config file location
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The config file lives under the per-user config directory (`~/.config/prompt-diary/config.json` on
|
|
87
|
+
Linux; the platform equivalent on macOS and Windows), overridable with `PROMPT_DIARY_CONFIG`. Each
|
|
88
|
+
setting is resolved from the first source that provides it: a CLI flag (where one exists), then the
|
|
89
|
+
environment, then the stored config, then a built-in default (where one exists). So `NOTION_API_KEY`
|
|
90
|
+
/ `NOTION_PAGE_ID` and `--reports-root` / `PROMPT_DIARY_HOME` still override the stored config (useful
|
|
91
|
+
in CI). Once Notion is configured — including via those environment variables — a bare `report
|
|
92
|
+
generate` publishes by default; pass `--no-notion` in CI or any pipeline that should not publish.
|
|
93
|
+
|
|
94
|
+
## Development
|
|
95
|
+
|
|
96
|
+
This project uses [`uv`](https://docs.astral.sh/uv/) for Python version, environment,
|
|
97
|
+
dependency, build, and release workflows.
|
|
98
|
+
|
|
99
|
+
Read [`docs/src/product.md`](docs/src/product.md) before designing new features, changing report
|
|
100
|
+
content, or modifying the generation pipeline. It defines the tool's purposes and principles that
|
|
101
|
+
downstream design must satisfy.
|
|
102
|
+
|
|
103
|
+
For environment setup, build commands, type checking, testing, coverage, linting, and pre-submit
|
|
104
|
+
checks, including the optional Ubuntu 24.04 devcontainer, see the
|
|
105
|
+
[Development Guide](docs/src/dev/guide.md). For codebase architecture and API design, see
|
|
106
|
+
[Architecture](docs/src/dev/architecture.md).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "prompt-diary"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Review user prompts for evidence-backed improvement in AI coding collaboration."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"jinja2>=3.1",
|
|
9
|
+
"mcp>=1.2",
|
|
10
|
+
"msgspec>=0.21.1",
|
|
11
|
+
"notion-client>=2.0",
|
|
12
|
+
"openai-codex>=0.1.0b2",
|
|
13
|
+
"platformdirs>=4.0",
|
|
14
|
+
"rich>=13",
|
|
15
|
+
"typer>=0.25.1",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
prompt-diary = "prompt_diary.cli:main"
|
|
20
|
+
report = "prompt_diary.cli:main"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["uv_build>=0.11.6,<0.12"]
|
|
24
|
+
build-backend = "uv_build"
|
|
25
|
+
|
|
26
|
+
[tool.basedpyright]
|
|
27
|
+
include = ["src", "tests"]
|
|
28
|
+
pythonVersion = "3.10"
|
|
29
|
+
typeCheckingMode = "strict"
|
|
30
|
+
reportMissingTypeStubs = false
|
|
31
|
+
venv = ".venv"
|
|
32
|
+
venvPath = "."
|
|
33
|
+
|
|
34
|
+
[tool.pytest.ini_options]
|
|
35
|
+
minversion = "9.0"
|
|
36
|
+
testpaths = ["tests"]
|
|
37
|
+
addopts = [
|
|
38
|
+
"--strict-config",
|
|
39
|
+
"--strict-markers",
|
|
40
|
+
]
|
|
41
|
+
markers = [
|
|
42
|
+
"codex_mcp: opt-in Codex MCP integration contract tests",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.coverage.run]
|
|
46
|
+
source = ["prompt_diary"]
|
|
47
|
+
omit = [
|
|
48
|
+
"src/prompt_diary/integrations/codex_runner.py",
|
|
49
|
+
"src/prompt_diary/progress/console.py",
|
|
50
|
+
# The real Notion SDK adapter is exercised by the live publish path, not the unit suite (the
|
|
51
|
+
# publisher logic is fully tested against a fake), like codex_runner.py above.
|
|
52
|
+
"src/prompt_diary/generate/daily_synthesis/notion_client_adapter.py",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[tool.coverage.report]
|
|
56
|
+
fail_under = 100
|
|
57
|
+
show_missing = true
|
|
58
|
+
exclude_also = [
|
|
59
|
+
# Unreachable defensive fallback: the loop always finds the trigger's own
|
|
60
|
+
# non-scaffolding record before exhausting all lines.
|
|
61
|
+
"return next_trigger_line - 1",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.uv]
|
|
65
|
+
dependency-metadata = [
|
|
66
|
+
# openai-codex 0.1.0b2 pins openai-codex-cli-bin==0.132.0, but that runtime
|
|
67
|
+
# release has no manylinux wheel. Prompt Diary passes an explicit local codex
|
|
68
|
+
# binary to CodexConfig, so the SDK package itself is the needed dependency.
|
|
69
|
+
{ name = "openai-codex", version = "0.1.0b2", requires-dist = ["pydantic>=2.12"], requires-python = ">=3.10" },
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 100
|
|
74
|
+
target-version = "py310"
|
|
75
|
+
src = ["src", "tests"]
|
|
76
|
+
extend-exclude = ["export_codex_user_history.py"]
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
select = [
|
|
80
|
+
# pycodestyle
|
|
81
|
+
"E",
|
|
82
|
+
"W",
|
|
83
|
+
# Pyflakes
|
|
84
|
+
"F",
|
|
85
|
+
# isort
|
|
86
|
+
"I",
|
|
87
|
+
# pyupgrade
|
|
88
|
+
"UP",
|
|
89
|
+
# flake8-bugbear
|
|
90
|
+
"B",
|
|
91
|
+
# flake8-builtins
|
|
92
|
+
"A",
|
|
93
|
+
# flake8-unused-arguments
|
|
94
|
+
"ARG",
|
|
95
|
+
# flake8-blind-except
|
|
96
|
+
"BLE",
|
|
97
|
+
# flake8-comprehensions
|
|
98
|
+
"C4",
|
|
99
|
+
# mccabe
|
|
100
|
+
"C90",
|
|
101
|
+
# flake8-datetimez
|
|
102
|
+
"DTZ",
|
|
103
|
+
# eradicate
|
|
104
|
+
"ERA",
|
|
105
|
+
# flake8-boolean-trap
|
|
106
|
+
"FBT",
|
|
107
|
+
# flake8-logging
|
|
108
|
+
"LOG",
|
|
109
|
+
# flake8-logging-format
|
|
110
|
+
"G",
|
|
111
|
+
# flake8-no-pep420
|
|
112
|
+
"INP",
|
|
113
|
+
# pep8-naming
|
|
114
|
+
"N",
|
|
115
|
+
# Perflint
|
|
116
|
+
"PERF",
|
|
117
|
+
# flake8-pie
|
|
118
|
+
"PIE",
|
|
119
|
+
# Pylint convention, error, and warning rules.
|
|
120
|
+
"PLC",
|
|
121
|
+
"PLE",
|
|
122
|
+
"PLW",
|
|
123
|
+
# flake8-pytest-style
|
|
124
|
+
"PT",
|
|
125
|
+
# flake8-use-pathlib
|
|
126
|
+
"PTH",
|
|
127
|
+
# flake8-return
|
|
128
|
+
"RET",
|
|
129
|
+
# flake8-raise
|
|
130
|
+
"RSE",
|
|
131
|
+
# flake8-bandit
|
|
132
|
+
"S",
|
|
133
|
+
# flake8-simplify
|
|
134
|
+
"SIM",
|
|
135
|
+
# flake8-type-checking
|
|
136
|
+
"TC",
|
|
137
|
+
# flake8-tidy-imports
|
|
138
|
+
"TID",
|
|
139
|
+
# tryceratops
|
|
140
|
+
"TRY",
|
|
141
|
+
# flake8-2020
|
|
142
|
+
"YTT",
|
|
143
|
+
# Ruff-specific rules
|
|
144
|
+
"RUF",
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
[tool.ruff.lint.per-file-ignores]
|
|
148
|
+
"tests/**" = [
|
|
149
|
+
# Allow pytest assertions in tests.
|
|
150
|
+
"S101",
|
|
151
|
+
# Test fixtures use fake/sentinel credentials, not real secrets.
|
|
152
|
+
"S105",
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
[tool.ruff.lint.isort]
|
|
156
|
+
known-first-party = ["prompt_diary"]
|
|
157
|
+
|
|
158
|
+
[tool.ruff.lint.mccabe]
|
|
159
|
+
max-complexity = 10
|
|
160
|
+
|
|
161
|
+
[tool.ruff.format]
|
|
162
|
+
quote-style = "double"
|
|
163
|
+
indent-style = "space"
|
|
164
|
+
line-ending = "lf"
|
|
165
|
+
|
|
166
|
+
[dependency-groups]
|
|
167
|
+
dev = [
|
|
168
|
+
"basedpyright>=1.39.4",
|
|
169
|
+
"coverage[toml]>=7.14.0",
|
|
170
|
+
"pytest>=9.0.3",
|
|
171
|
+
"ruff>=0.15.12",
|
|
172
|
+
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Neutral agent execution contract shared by generation phases and runner adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TYPE_CHECKING, Protocol
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from collections.abc import Mapping
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from types import TracebackType
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AgentConfig:
|
|
16
|
+
"""Per-conversation agent configuration."""
|
|
17
|
+
|
|
18
|
+
working_directory: Path
|
|
19
|
+
model: str | None = None
|
|
20
|
+
model_provider: str | None = None
|
|
21
|
+
reasoning_effort: str | None = None
|
|
22
|
+
approval_mode: str | None = None
|
|
23
|
+
sandbox: str | None = None
|
|
24
|
+
base_instructions: str | None = None
|
|
25
|
+
developer_instructions: str | None = None
|
|
26
|
+
personality: str | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class AgentTurnEvent:
|
|
31
|
+
"""Structured event summary emitted while running one agent turn."""
|
|
32
|
+
|
|
33
|
+
kind: str
|
|
34
|
+
summary: str
|
|
35
|
+
metadata: Mapping[str, object]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class AgentTurnResult:
|
|
40
|
+
"""Result from one agent turn."""
|
|
41
|
+
|
|
42
|
+
assistant_text: str
|
|
43
|
+
events: tuple[AgentTurnEvent, ...]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AgentRunner(Protocol):
|
|
47
|
+
"""One agent conversation. Turns run sequentially on a single instance."""
|
|
48
|
+
|
|
49
|
+
async def turn(
|
|
50
|
+
self,
|
|
51
|
+
prompt: str,
|
|
52
|
+
*,
|
|
53
|
+
timeout_seconds: float = 600.0,
|
|
54
|
+
output_schema: Mapping[str, object] | None = None,
|
|
55
|
+
) -> AgentTurnResult:
|
|
56
|
+
"""Run one prompt turn and return its structured result."""
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AgentSessionFactory(Protocol):
|
|
61
|
+
"""Owns one shared backend and mints a fresh agent conversation per call."""
|
|
62
|
+
|
|
63
|
+
async def __aenter__(self) -> AgentSessionFactory:
|
|
64
|
+
"""Start the shared backend."""
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
async def __aexit__(
|
|
68
|
+
self,
|
|
69
|
+
exc_type: type[BaseException] | None,
|
|
70
|
+
exc: BaseException | None,
|
|
71
|
+
traceback: TracebackType | None,
|
|
72
|
+
) -> bool | None:
|
|
73
|
+
"""Stop the shared backend."""
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
async def runner(self, config: AgentConfig) -> AgentRunner:
|
|
77
|
+
"""Return a fresh agent conversation bound to the shared backend."""
|
|
78
|
+
...
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Typer command-line entrypoint for Prompt Diary."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from prompt_diary import __version__
|
|
10
|
+
from prompt_diary.cmds import config, generate, mcp, prepare, prompts, render
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(
|
|
13
|
+
add_completion=False,
|
|
14
|
+
help="Prepare and generate evidence-backed prompt diary reports.",
|
|
15
|
+
invoke_without_command=True,
|
|
16
|
+
no_args_is_help=True,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
VersionOption = Annotated[
|
|
20
|
+
bool,
|
|
21
|
+
typer.Option("--version", help="Show the version and exit.", is_eager=True),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@app.callback()
|
|
26
|
+
def app_callback(*, version: VersionOption = False) -> None:
|
|
27
|
+
"""Prompt Diary command group."""
|
|
28
|
+
if version:
|
|
29
|
+
typer.echo(__version__)
|
|
30
|
+
raise typer.Exit
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
prepare.register(app)
|
|
34
|
+
generate.register(app)
|
|
35
|
+
config.register(app)
|
|
36
|
+
prompts.register(app)
|
|
37
|
+
render.register(app)
|
|
38
|
+
mcp.register(app)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main() -> None:
|
|
42
|
+
app()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Typer command modules for Prompt Diary."""
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Shared CLI helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Annotated, NoReturn
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from prompt_diary.progress.console import build_reporter
|
|
12
|
+
from prompt_diary.progress.reporter import select_reporter_mode
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Iterable
|
|
16
|
+
|
|
17
|
+
from prompt_diary.errors import PromptDiaryError
|
|
18
|
+
from prompt_diary.progress.reporter import ProgressReporter
|
|
19
|
+
|
|
20
|
+
DateOption = Annotated[str | None, typer.Option(help="Target local date in YYYY-MM-DD format.")]
|
|
21
|
+
TodayOption = Annotated[bool, typer.Option(help="Target the current local day.")]
|
|
22
|
+
TimezoneOption = Annotated[
|
|
23
|
+
str | None,
|
|
24
|
+
typer.Option(help="IANA timezone name, e.g. Asia/Shanghai."),
|
|
25
|
+
]
|
|
26
|
+
QuietOption = Annotated[bool, typer.Option(help="Suppress progress; print only the final summary.")]
|
|
27
|
+
ReportsRootOption = Annotated[
|
|
28
|
+
Path | None,
|
|
29
|
+
typer.Option(
|
|
30
|
+
help=(
|
|
31
|
+
"Directory for report workspaces. Defaults to the per-user data directory "
|
|
32
|
+
"(override with $PROMPT_DIARY_HOME)."
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def build_cli_reporter(*, quiet: bool) -> ProgressReporter:
|
|
39
|
+
"""Build the progress reporter for a CLI invocation."""
|
|
40
|
+
mode = select_reporter_mode(quiet=quiet, isatty=sys.stderr.isatty())
|
|
41
|
+
return build_reporter(mode)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def echo_messages(messages: Iterable[str]) -> None:
|
|
45
|
+
"""Print workflow messages."""
|
|
46
|
+
for message in messages:
|
|
47
|
+
typer.echo(message)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def exit_with_error(exc: PromptDiaryError) -> NoReturn:
|
|
51
|
+
"""Print an actionable error and exit with the workflow error code."""
|
|
52
|
+
typer.echo(f"Error: {exc}", err=True)
|
|
53
|
+
raise typer.Exit(2) from exc
|