dctracker 1.1.0__tar.gz → 1.2.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.
- {dctracker-1.1.0/dctracker.egg-info → dctracker-1.2.0}/PKG-INFO +26 -12
- {dctracker-1.1.0 → dctracker-1.2.0}/README.md +24 -11
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/__init__.py +1 -1
- dctracker-1.2.0/dct/assets/__init__.py +19 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/cli.py +231 -35
- dctracker-1.2.0/dct/config.py +269 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/plans/ingest.py +12 -3
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/projects.py +15 -1
- dctracker-1.2.0/dct/core/provenance.py +58 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/db.py +62 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/hooks/dct-task-mirror.sh +1 -1
- dctracker-1.2.0/dct/integrations/__init__.py +5 -0
- dctracker-1.1.0/dct/setup.py → dctracker-1.2.0/dct/integrations/claude.py +54 -19
- dctracker-1.2.0/dct/mcp/__init__.py +3 -0
- dctracker-1.2.0/dct/migrate.py +597 -0
- dctracker-1.2.0/dct/paths.py +103 -0
- dctracker-1.2.0/dct/server.py +10 -0
- dctracker-1.2.0/dct/services/__init__.py +5 -0
- dctracker-1.2.0/dct/setup.py +19 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/dct-init/SKILL.md +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/track-list/SKILL.md +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/update.py +12 -8
- dctracker-1.2.0/dct/workflows/__init__.py +3 -0
- {dctracker-1.1.0 → dctracker-1.2.0/dctracker.egg-info}/PKG-INFO +26 -12
- {dctracker-1.1.0 → dctracker-1.2.0}/dctracker.egg-info/SOURCES.txt +16 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/dctracker.egg-info/requires.txt +3 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/pyproject.toml +8 -2
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_adversarial.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_cli_web.py +76 -2
- dctracker-1.2.0/tests/test_config.py +300 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_hook_bypass.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_hook_changelog_stop.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_hook_plan_autoscan.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_hook_task_mirror.py +7 -5
- dctracker-1.2.0/tests/test_migrate.py +679 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_packaging.py +1 -1
- dctracker-1.2.0/tests/test_paths.py +189 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_plan_classify.py +68 -6
- dctracker-1.2.0/tests/test_provenance.py +153 -0
- dctracker-1.2.0/tests/test_restructure.py +66 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_server_acks.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_server_alwaysload.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_server_handoff_view.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_setup.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_setup_wiring.py +1 -1
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_update.py +48 -7
- dctracker-1.2.0/tests/test_windows_support.py +192 -0
- dctracker-1.1.0/dct/config.py +0 -170
- dctracker-1.1.0/tests/test_config.py +0 -55
- {dctracker-1.1.0 → dctracker-1.2.0}/LICENSE +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/MANIFEST.in +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/__init__.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/analytics.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/changelog.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/checkpoints.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/decisions.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/engine.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/handoff.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/ids.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/items.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/plans/__init__.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/plans/classify.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/plans/crud.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/plans/parser.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/sprint.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/sprints.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/core/version.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/export.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/hooks/check-changelog-on-stop.sh +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/hooks/check-changelog.sh +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/hooks/dct-plan-autoscan.sh +0 -0
- {dctracker-1.1.0/dct → dctracker-1.2.0/dct/mcp}/server.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/clog/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/commit/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/dct-import/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/handoff/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/pickup/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/plan-resolve-uncertain/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/plan-status/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/release/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/track/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/track-resolve/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/skills/track-update/SKILL.md +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/__init__.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/app.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/__init__.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/analytics.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/changelog.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/decisions.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/events.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/handoffs.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/home.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/items.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/plans.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/projects.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/blueprints/sprints.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/changes.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/serializers.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/app.css +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/app.js +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/vendor/SOURCES.txt +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/vendor/htmx.min.js +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.iife.min.js +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/static/vendor/uPlot.min.css +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/analytics.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/base.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/changelog/list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/decisions/list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/handoffs/list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/home.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/item_detail.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/items_list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/partials/_bars.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/partials/_checkpoint_steps.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/partials/_items_table.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/partials/_plan_section.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/partials/_project_card.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/plans/detail.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/plans/list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/project_home.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/sprints/detail.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dct/web/templates/sprints/list.html +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dctracker.egg-info/dependency_links.txt +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dctracker.egg-info/entry_points.txt +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/dctracker.egg-info/top_level.txt +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/setup.cfg +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_analytics.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_changelog.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_changes.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_checkpoints.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_cli_prompts.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_cli_sprints.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_decisions_crud.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_engine.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_export.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_handoff.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_ids.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_ingest_dogfood.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_items.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_migration.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_plan_ingest.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_plan_parser.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_plans_crud.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_projects.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_sprint.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_sprints_crud.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_version.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_web_analytics.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_web_app.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_web_items.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_web_structural.py +0 -0
- {dctracker-1.1.0 → dctracker-1.2.0}/tests/test_web_views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dctracker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Deterministic Context Tracker (dct) — cross-project tracking, changelog, and release tooling for Claude Code.
|
|
5
5
|
Author-email: fotodeveloper <dev@fotodeveloper.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,6 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: sqlalchemy>=2.0
|
|
23
23
|
Requires-Dist: python-ulid>=2.0
|
|
24
|
+
Requires-Dist: platformdirs>=4.9.6; sys_platform == "win32"
|
|
24
25
|
Provides-Extra: pg
|
|
25
26
|
Requires-Dist: psycopg[binary]; extra == "pg"
|
|
26
27
|
Provides-Extra: mcp
|
|
@@ -104,9 +105,9 @@ release day the changelog is already written:
|
|
|
104
105
|
|
|
105
106
|
```text
|
|
106
107
|
> /release
|
|
107
|
-
15 unreleased entries → stamped as 1.
|
|
108
|
+
15 unreleased entries → stamped as 1.4.0
|
|
108
109
|
changelog.md regenerated (Keep a Changelog format)
|
|
109
|
-
release: v1.
|
|
110
|
+
release: v1.4.0 committed, project version bumped
|
|
110
111
|
```
|
|
111
112
|
|
|
112
113
|
One command stamps the version, exports [Keep a Changelog](https://keepachangelog.com)
|
|
@@ -165,13 +166,13 @@ dct init
|
|
|
165
166
|
|
|
166
167
|
The interactive wizard walks through the one-time global bootstrap:
|
|
167
168
|
|
|
168
|
-
1. **Database backend** — `sqlite` (default, zero setup at `~/.
|
|
169
|
+
1. **Database backend** — `sqlite` (default, zero setup at the platform data dir, e.g. `~/.local/share/dctools/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
|
|
169
170
|
2. **Register projects** — for each project it asks slug / path / name, then **auto-detects the version** from `VERSION`, `pyproject.toml`, `package.json`, `Cargo.toml`, or `src-tauri/tauri.conf.json`. If none matches, you get an interactive prompt (`0.0.1` / `0.1.0` / `1.0.0` shortcuts); in non-tty contexts it stores `current_version=NULL` and reminds you to set it later. Register more any time with `dct project add`.
|
|
170
171
|
3. **MCP server** — registered at **user scope** in `~/.claude.json` (via `claude mcp add --scope user`, with a direct-edit fallback), so `/track`, `/clog`, `/release`, and the MCP tools are available in **every** Claude Code session, from any directory.
|
|
171
172
|
4. **Skills + hooks** — symlinks the skills into `~/.claude/skills/` and the four hooks into `~/.claude/hooks/`. Both ship inside the package; with an editable/dev install the symlinks point at the repo, so a fix goes live without reinstall.
|
|
172
173
|
5. **Hook wiring** — with your consent, merges the hooks into `~/.claude/settings.json`. The merge is idempotent, backs up the file before the first write, and never touches hooks you already have. Re-run any time with `dct hooks wire`.
|
|
173
174
|
|
|
174
|
-
`dct init` writes `~/.claude/dct.toml
|
|
175
|
+
`dct init` writes the config to the platform config dir (`~/.config/dctools/dct.toml`; existing `~/.claude/dct.toml` installs keep working — `dct migrate-home` moves them), `~/.claude.json` (MCP entry), the skill/hook symlinks, and (opt-in) the settings.json wiring — see [docs/architecture.md](docs/architecture.md) for the full config reference and scope model.
|
|
175
176
|
|
|
176
177
|
### Your first session
|
|
177
178
|
|
|
@@ -202,7 +203,7 @@ happens in the conversation you're already having.
|
|
|
202
203
|
|
|
203
204
|
### Updating
|
|
204
205
|
|
|
205
|
-
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in
|
|
206
|
+
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in the dct config file (`dct config path` shows where it lives). When a newer version exists:
|
|
206
207
|
|
|
207
208
|
```bash
|
|
208
209
|
dct upgrade # detects install method (uv tool / pipx / pip), upgrades, re-links skills + hooks
|
|
@@ -249,6 +250,19 @@ dct checkpoint add 42 "Write parser"
|
|
|
249
250
|
dct checkpoint list 42
|
|
250
251
|
dct checkpoint done 3 # Mark CP #3 as done
|
|
251
252
|
dct checkpoint reject 4 # Scope-change, keep in ledger
|
|
253
|
+
|
|
254
|
+
# Sprints (first-class, named units of work; /handoff manages the current-sprint set)
|
|
255
|
+
dct sprint list --status active
|
|
256
|
+
dct sprint create "Payments hardening" --code pay-1 --goal "Close the P1 backlog"
|
|
257
|
+
dct sprint show 3 # Details + linked items
|
|
258
|
+
dct sprint activate 3 # Shortcuts: activate / complete / defer
|
|
259
|
+
|
|
260
|
+
# Handoffs (amend an unconsumed handoff in place; creation is /handoff or MCP)
|
|
261
|
+
dct handoff update 12 --prompt "Wire the toggle into settings next"
|
|
262
|
+
|
|
263
|
+
# Config
|
|
264
|
+
dct config get integrations.claude.task_mirror # Read a dotted config key
|
|
265
|
+
dct config path # Show resolved config/data locations
|
|
252
266
|
```
|
|
253
267
|
|
|
254
268
|
## MCP Tools
|
|
@@ -288,7 +302,7 @@ dct web status # show pid + URL
|
|
|
288
302
|
dct web stop # SIGTERM the daemon
|
|
289
303
|
```
|
|
290
304
|
|
|
291
|
-
If the preferred port (default `8787`) is busy, the daemon auto-selects the next free port (disable with `--no-fallback`). Configure defaults under `[web]` in
|
|
305
|
+
If the preferred port (default `8787`) is busy, the daemon auto-selects the next free port (disable with `--no-fallback`). Configure defaults under `[web]` in the dct config file.
|
|
292
306
|
|
|
293
307
|

|
|
294
308
|
|
|
@@ -333,26 +347,26 @@ Manual wiring reference (full JSON) and the five rules every dct hook follows: [
|
|
|
333
347
|
|
|
334
348
|
## Configuration
|
|
335
349
|
|
|
336
|
-
dct reads `~/.claude/dct.toml
|
|
350
|
+
dct reads its config from the platform config dir — `~/.config/dctools/dct.toml` on Linux and macOS, `%LOCALAPPDATA%\dctools\dct.toml` on Windows — with a permanent fallback to a legacy `~/.claude/dct.toml` (run `dct migrate-home` to move an old install). The minimal config is just the database URL:
|
|
337
351
|
|
|
338
352
|
```toml
|
|
339
353
|
[database]
|
|
340
|
-
url = "sqlite:////
|
|
354
|
+
url = "sqlite:////home/you/.local/share/dctools/dct.db"
|
|
341
355
|
# or: url = "postgresql+psycopg://localhost:5432/dct"
|
|
342
356
|
```
|
|
343
357
|
|
|
344
|
-
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[
|
|
358
|
+
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[classification]`, `[integrations.claude]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
|
|
345
359
|
|
|
346
360
|
## Testing
|
|
347
361
|
|
|
348
362
|
```bash
|
|
349
|
-
.venv/bin/pytest -q # All tests (
|
|
363
|
+
.venv/bin/pytest -q # All tests (938)
|
|
350
364
|
.venv/bin/pytest tests/test_plan_parser.py -v # Parser only
|
|
351
365
|
.venv/bin/pytest tests/test_plan_ingest.py -v # Ingest + sticky-resolved semantics
|
|
352
366
|
|
|
353
367
|
# MCP server smoke (boot + tool list)
|
|
354
368
|
uv run --no-project --with 'mcp[cli]' --with sqlalchemy --with 'psycopg[binary]' \
|
|
355
|
-
python -c "import asyncio; from dct.server import mcp; \
|
|
369
|
+
python -c "import asyncio; from dct.mcp.server import mcp; \
|
|
356
370
|
print(len(asyncio.run(mcp.list_tools())), 'tools')"
|
|
357
371
|
```
|
|
358
372
|
|
|
@@ -62,9 +62,9 @@ release day the changelog is already written:
|
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
64
|
> /release
|
|
65
|
-
15 unreleased entries → stamped as 1.
|
|
65
|
+
15 unreleased entries → stamped as 1.4.0
|
|
66
66
|
changelog.md regenerated (Keep a Changelog format)
|
|
67
|
-
release: v1.
|
|
67
|
+
release: v1.4.0 committed, project version bumped
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
One command stamps the version, exports [Keep a Changelog](https://keepachangelog.com)
|
|
@@ -123,13 +123,13 @@ dct init
|
|
|
123
123
|
|
|
124
124
|
The interactive wizard walks through the one-time global bootstrap:
|
|
125
125
|
|
|
126
|
-
1. **Database backend** — `sqlite` (default, zero setup at `~/.
|
|
126
|
+
1. **Database backend** — `sqlite` (default, zero setup at the platform data dir, e.g. `~/.local/share/dctools/dct.db`) or `postgresql` (you supply the URL). It test-connects before saving.
|
|
127
127
|
2. **Register projects** — for each project it asks slug / path / name, then **auto-detects the version** from `VERSION`, `pyproject.toml`, `package.json`, `Cargo.toml`, or `src-tauri/tauri.conf.json`. If none matches, you get an interactive prompt (`0.0.1` / `0.1.0` / `1.0.0` shortcuts); in non-tty contexts it stores `current_version=NULL` and reminds you to set it later. Register more any time with `dct project add`.
|
|
128
128
|
3. **MCP server** — registered at **user scope** in `~/.claude.json` (via `claude mcp add --scope user`, with a direct-edit fallback), so `/track`, `/clog`, `/release`, and the MCP tools are available in **every** Claude Code session, from any directory.
|
|
129
129
|
4. **Skills + hooks** — symlinks the skills into `~/.claude/skills/` and the four hooks into `~/.claude/hooks/`. Both ship inside the package; with an editable/dev install the symlinks point at the repo, so a fix goes live without reinstall.
|
|
130
130
|
5. **Hook wiring** — with your consent, merges the hooks into `~/.claude/settings.json`. The merge is idempotent, backs up the file before the first write, and never touches hooks you already have. Re-run any time with `dct hooks wire`.
|
|
131
131
|
|
|
132
|
-
`dct init` writes `~/.claude/dct.toml
|
|
132
|
+
`dct init` writes the config to the platform config dir (`~/.config/dctools/dct.toml`; existing `~/.claude/dct.toml` installs keep working — `dct migrate-home` moves them), `~/.claude.json` (MCP entry), the skill/hook symlinks, and (opt-in) the settings.json wiring — see [docs/architecture.md](docs/architecture.md) for the full config reference and scope model.
|
|
133
133
|
|
|
134
134
|
### Your first session
|
|
135
135
|
|
|
@@ -160,7 +160,7 @@ happens in the conversation you're already having.
|
|
|
160
160
|
|
|
161
161
|
### Updating
|
|
162
162
|
|
|
163
|
-
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in
|
|
163
|
+
dct runs a passive, offline-safe update check — a cached PyPI probe (refreshed at most once a day, never blocking) surfaces a one-line "newer release available" nudge on the CLI and in the MCP server instructions. Opt out with `[update] check = false` in the dct config file (`dct config path` shows where it lives). When a newer version exists:
|
|
164
164
|
|
|
165
165
|
```bash
|
|
166
166
|
dct upgrade # detects install method (uv tool / pipx / pip), upgrades, re-links skills + hooks
|
|
@@ -207,6 +207,19 @@ dct checkpoint add 42 "Write parser"
|
|
|
207
207
|
dct checkpoint list 42
|
|
208
208
|
dct checkpoint done 3 # Mark CP #3 as done
|
|
209
209
|
dct checkpoint reject 4 # Scope-change, keep in ledger
|
|
210
|
+
|
|
211
|
+
# Sprints (first-class, named units of work; /handoff manages the current-sprint set)
|
|
212
|
+
dct sprint list --status active
|
|
213
|
+
dct sprint create "Payments hardening" --code pay-1 --goal "Close the P1 backlog"
|
|
214
|
+
dct sprint show 3 # Details + linked items
|
|
215
|
+
dct sprint activate 3 # Shortcuts: activate / complete / defer
|
|
216
|
+
|
|
217
|
+
# Handoffs (amend an unconsumed handoff in place; creation is /handoff or MCP)
|
|
218
|
+
dct handoff update 12 --prompt "Wire the toggle into settings next"
|
|
219
|
+
|
|
220
|
+
# Config
|
|
221
|
+
dct config get integrations.claude.task_mirror # Read a dotted config key
|
|
222
|
+
dct config path # Show resolved config/data locations
|
|
210
223
|
```
|
|
211
224
|
|
|
212
225
|
## MCP Tools
|
|
@@ -246,7 +259,7 @@ dct web status # show pid + URL
|
|
|
246
259
|
dct web stop # SIGTERM the daemon
|
|
247
260
|
```
|
|
248
261
|
|
|
249
|
-
If the preferred port (default `8787`) is busy, the daemon auto-selects the next free port (disable with `--no-fallback`). Configure defaults under `[web]` in
|
|
262
|
+
If the preferred port (default `8787`) is busy, the daemon auto-selects the next free port (disable with `--no-fallback`). Configure defaults under `[web]` in the dct config file.
|
|
250
263
|
|
|
251
264
|

|
|
252
265
|
|
|
@@ -291,26 +304,26 @@ Manual wiring reference (full JSON) and the five rules every dct hook follows: [
|
|
|
291
304
|
|
|
292
305
|
## Configuration
|
|
293
306
|
|
|
294
|
-
dct reads `~/.claude/dct.toml
|
|
307
|
+
dct reads its config from the platform config dir — `~/.config/dctools/dct.toml` on Linux and macOS, `%LOCALAPPDATA%\dctools\dct.toml` on Windows — with a permanent fallback to a legacy `~/.claude/dct.toml` (run `dct migrate-home` to move an old install). The minimal config is just the database URL:
|
|
295
308
|
|
|
296
309
|
```toml
|
|
297
310
|
[database]
|
|
298
|
-
url = "sqlite:////
|
|
311
|
+
url = "sqlite:////home/you/.local/share/dctools/dct.db"
|
|
299
312
|
# or: url = "postgresql+psycopg://localhost:5432/dct"
|
|
300
313
|
```
|
|
301
314
|
|
|
302
|
-
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[
|
|
315
|
+
The `DCT_DATABASE_URL` environment variable overrides `[database].url`. For the full reference (`[classification]`, `[integrations.claude]`, `[web]` sections), the database schema, MCP scope precedence, and project auto-detection mechanics, see **[docs/architecture.md](docs/architecture.md)**.
|
|
303
316
|
|
|
304
317
|
## Testing
|
|
305
318
|
|
|
306
319
|
```bash
|
|
307
|
-
.venv/bin/pytest -q # All tests (
|
|
320
|
+
.venv/bin/pytest -q # All tests (938)
|
|
308
321
|
.venv/bin/pytest tests/test_plan_parser.py -v # Parser only
|
|
309
322
|
.venv/bin/pytest tests/test_plan_ingest.py -v # Ingest + sticky-resolved semantics
|
|
310
323
|
|
|
311
324
|
# MCP server smoke (boot + tool list)
|
|
312
325
|
uv run --no-project --with 'mcp[cli]' --with sqlalchemy --with 'psycopg[binary]' \
|
|
313
|
-
python -c "import asyncio; from dct.server import mcp; \
|
|
326
|
+
python -c "import asyncio; from dct.mcp.server import mcp; \
|
|
314
327
|
print(len(asyncio.run(mcp.list_tools())), 'tools')"
|
|
315
328
|
```
|
|
316
329
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Packaged asset locations — the single indirection for skill/hook dirs.
|
|
2
|
+
|
|
3
|
+
The PHYSICAL directories stay at dct/skills and dct/hooks: the host's
|
|
4
|
+
~/.claude symlinks point into them, so moving them is a breaking change
|
|
5
|
+
reserved for 2.0.0 (ADR #52 froze every public surface for 1.2.0). When
|
|
6
|
+
that window opens, this module is the one place that changes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
_PKG_ROOT = Path(__file__).resolve().parent.parent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def skills_dir() -> Path:
|
|
15
|
+
return _PKG_ROOT / "skills"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def hooks_dir() -> Path:
|
|
19
|
+
return _PKG_ROOT / "hooks"
|