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.
Files changed (75) hide show
  1. prompt_diary-0.1.0/PKG-INFO +121 -0
  2. prompt_diary-0.1.0/README.md +106 -0
  3. prompt_diary-0.1.0/pyproject.toml +172 -0
  4. prompt_diary-0.1.0/src/prompt_diary/__init__.py +5 -0
  5. prompt_diary-0.1.0/src/prompt_diary/agent.py +78 -0
  6. prompt_diary-0.1.0/src/prompt_diary/cli.py +42 -0
  7. prompt_diary-0.1.0/src/prompt_diary/cmds/__init__.py +1 -0
  8. prompt_diary-0.1.0/src/prompt_diary/cmds/common.py +53 -0
  9. prompt_diary-0.1.0/src/prompt_diary/cmds/config.py +207 -0
  10. prompt_diary-0.1.0/src/prompt_diary/cmds/generate.py +373 -0
  11. prompt_diary-0.1.0/src/prompt_diary/cmds/mcp.py +19 -0
  12. prompt_diary-0.1.0/src/prompt_diary/cmds/prepare.py +49 -0
  13. prompt_diary-0.1.0/src/prompt_diary/cmds/prompts.py +163 -0
  14. prompt_diary-0.1.0/src/prompt_diary/cmds/render.py +50 -0
  15. prompt_diary-0.1.0/src/prompt_diary/config.py +218 -0
  16. prompt_diary-0.1.0/src/prompt_diary/errors.py +11 -0
  17. prompt_diary-0.1.0/src/prompt_diary/generate/__init__.py +0 -0
  18. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/__init__.py +5 -0
  19. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/build.py +338 -0
  20. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/citations.py +67 -0
  21. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/finalize.py +443 -0
  22. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/inputs.py +209 -0
  23. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/layout.py +562 -0
  24. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/mcp.py +485 -0
  25. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/model.py +417 -0
  26. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_client_adapter.py +124 -0
  27. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_publish.py +389 -0
  28. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/notion_validate.py +79 -0
  29. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/render_markdown.py +266 -0
  30. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/render_notion.py +323 -0
  31. prompt_diary-0.1.0/src/prompt_diary/generate/daily_synthesis/runner.py +250 -0
  32. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/__init__.py +19 -0
  33. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/inputs.py +124 -0
  34. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/mcp.py +323 -0
  35. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/model.py +458 -0
  36. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/runner.py +172 -0
  37. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/session_compaction.py +544 -0
  38. prompt_diary-0.1.0/src/prompt_diary/generate/evidence_extraction/session_reader.py +300 -0
  39. prompt_diary-0.1.0/src/prompt_diary/generate/pipeline.py +603 -0
  40. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/__init__.py +5 -0
  41. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/cards.py +120 -0
  42. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/inputs.py +108 -0
  43. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/mcp.py +336 -0
  44. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/model.py +487 -0
  45. prompt_diary-0.1.0/src/prompt_diary/generate/project_synthesis/runner.py +202 -0
  46. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/__init__.py +256 -0
  47. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/engagement.md +72 -0
  48. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/evidence-extractor-next-turn.md +28 -0
  49. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/evidence-extractor.md +195 -0
  50. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-summary.md +58 -0
  51. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-synthesizer-next.md +23 -0
  52. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/project-synthesizer.md +165 -0
  53. prompt_diary-0.1.0/src/prompt_diary/generate/prompts/team-learning.md +92 -0
  54. prompt_diary-0.1.0/src/prompt_diary/generate/workflow.py +296 -0
  55. prompt_diary-0.1.0/src/prompt_diary/generate/workspace.py +389 -0
  56. prompt_diary-0.1.0/src/prompt_diary/integrations/__init__.py +0 -0
  57. prompt_diary-0.1.0/src/prompt_diary/integrations/codex_runner.py +411 -0
  58. prompt_diary-0.1.0/src/prompt_diary/mcp/__init__.py +0 -0
  59. prompt_diary-0.1.0/src/prompt_diary/mcp/codex_config.py +94 -0
  60. prompt_diary-0.1.0/src/prompt_diary/mcp/server.py +149 -0
  61. prompt_diary-0.1.0/src/prompt_diary/models.py +69 -0
  62. prompt_diary-0.1.0/src/prompt_diary/paths.py +37 -0
  63. prompt_diary-0.1.0/src/prompt_diary/prepare/__init__.py +0 -0
  64. prompt_diary-0.1.0/src/prompt_diary/prepare/workspace.py +1850 -0
  65. prompt_diary-0.1.0/src/prompt_diary/progress/__init__.py +39 -0
  66. prompt_diary-0.1.0/src/prompt_diary/progress/console.py +148 -0
  67. prompt_diary-0.1.0/src/prompt_diary/progress/events.py +99 -0
  68. prompt_diary-0.1.0/src/prompt_diary/progress/log.py +81 -0
  69. prompt_diary-0.1.0/src/prompt_diary/progress/reporter.py +63 -0
  70. prompt_diary-0.1.0/src/prompt_diary/progress/state.py +149 -0
  71. prompt_diary-0.1.0/src/prompt_diary/render/__init__.py +1 -0
  72. prompt_diary-0.1.0/src/prompt_diary/render/notion.py +112 -0
  73. prompt_diary-0.1.0/src/prompt_diary/secret.py +33 -0
  74. prompt_diary-0.1.0/src/prompt_diary/targeting/__init__.py +0 -0
  75. 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
+ [![CI](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml/badge.svg)](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml)
21
+ [![Publish](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml/badge.svg)](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml)
22
+ [![PyPI](https://img.shields.io/pypi/v/prompt-diary.svg)](https://pypi.org/project/prompt-diary/)
23
+ ![Coverage budget](https://img.shields.io/badge/coverage%20budget-100%25-brightgreen.svg)
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
+ [![CI](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml/badge.svg)](https://github.com/OptimalCNC/prompt-diary/actions/workflows/ci.yml)
6
+ [![Publish](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml/badge.svg)](https://github.com/OptimalCNC/prompt-diary/actions/workflows/publish.yml)
7
+ [![PyPI](https://img.shields.io/pypi/v/prompt-diary.svg)](https://pypi.org/project/prompt-diary/)
8
+ ![Coverage budget](https://img.shields.io/badge/coverage%20budget-100%25-brightgreen.svg)
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,5 @@
1
+ """Prompt Diary package."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.1.0"
@@ -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