dctracker 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dct/__init__.py +6 -0
- dct/cli.py +1659 -0
- dct/config.py +150 -0
- dct/core/__init__.py +0 -0
- dct/core/analytics.py +382 -0
- dct/core/changelog.py +112 -0
- dct/core/checkpoints.py +205 -0
- dct/core/decisions.py +238 -0
- dct/core/engine.py +32 -0
- dct/core/handoff.py +151 -0
- dct/core/ids.py +25 -0
- dct/core/items.py +382 -0
- dct/core/plans/__init__.py +6 -0
- dct/core/plans/classify.py +94 -0
- dct/core/plans/crud.py +680 -0
- dct/core/plans/ingest.py +408 -0
- dct/core/plans/parser.py +312 -0
- dct/core/projects.py +298 -0
- dct/core/sprint.py +315 -0
- dct/core/sprints.py +601 -0
- dct/core/version.py +116 -0
- dct/db.py +558 -0
- dct/export.py +107 -0
- dct/hooks/check-changelog-on-stop.sh +49 -0
- dct/hooks/check-changelog.sh +143 -0
- dct/hooks/dct-plan-autoscan.sh +54 -0
- dct/hooks/dct-task-mirror.sh +62 -0
- dct/server.py +1812 -0
- dct/setup.py +258 -0
- dct/skills/clog/SKILL.md +73 -0
- dct/skills/commit/SKILL.md +153 -0
- dct/skills/dct-import/SKILL.md +329 -0
- dct/skills/dct-init/SKILL.md +289 -0
- dct/skills/handoff/SKILL.md +136 -0
- dct/skills/pickup/SKILL.md +115 -0
- dct/skills/plan-resolve-uncertain/SKILL.md +82 -0
- dct/skills/plan-status/SKILL.md +79 -0
- dct/skills/release/SKILL.md +281 -0
- dct/skills/track/SKILL.md +121 -0
- dct/skills/track-list/SKILL.md +134 -0
- dct/skills/track-resolve/SKILL.md +53 -0
- dct/skills/track-update/SKILL.md +109 -0
- dct/web/__init__.py +1 -0
- dct/web/app.py +83 -0
- dct/web/blueprints/__init__.py +5 -0
- dct/web/blueprints/analytics.py +34 -0
- dct/web/blueprints/changelog.py +40 -0
- dct/web/blueprints/decisions.py +23 -0
- dct/web/blueprints/events.py +69 -0
- dct/web/blueprints/handoffs.py +26 -0
- dct/web/blueprints/home.py +15 -0
- dct/web/blueprints/items.py +128 -0
- dct/web/blueprints/plans.py +53 -0
- dct/web/blueprints/projects.py +23 -0
- dct/web/blueprints/sprints.py +71 -0
- dct/web/changes.py +77 -0
- dct/web/serializers.py +109 -0
- dct/web/static/app.css +609 -0
- dct/web/static/app.js +62 -0
- dct/web/static/vendor/SOURCES.txt +10 -0
- dct/web/static/vendor/htmx.min.js +1 -0
- dct/web/static/vendor/uPlot.iife.min.js +2 -0
- dct/web/static/vendor/uPlot.min.css +1 -0
- dct/web/templates/analytics.html +63 -0
- dct/web/templates/base.html +106 -0
- dct/web/templates/changelog/list.html +23 -0
- dct/web/templates/decisions/list.html +22 -0
- dct/web/templates/handoffs/list.html +45 -0
- dct/web/templates/home.html +20 -0
- dct/web/templates/item_detail.html +91 -0
- dct/web/templates/items_list.html +44 -0
- dct/web/templates/partials/_bars.html +15 -0
- dct/web/templates/partials/_checkpoint_steps.html +22 -0
- dct/web/templates/partials/_items_table.html +23 -0
- dct/web/templates/partials/_plan_section.html +24 -0
- dct/web/templates/partials/_project_card.html +24 -0
- dct/web/templates/plans/detail.html +16 -0
- dct/web/templates/plans/list.html +15 -0
- dct/web/templates/project_home.html +51 -0
- dct/web/templates/sprints/detail.html +37 -0
- dct/web/templates/sprints/list.html +35 -0
- dctracker-1.0.0.dist-info/METADATA +357 -0
- dctracker-1.0.0.dist-info/RECORD +87 -0
- dctracker-1.0.0.dist-info/WHEEL +5 -0
- dctracker-1.0.0.dist-info/entry_points.txt +2 -0
- dctracker-1.0.0.dist-info/licenses/LICENSE +21 -0
- dctracker-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: |
|
|
4
|
+
Bump project version and release changelog entries.
|
|
5
|
+
Use when: "release", "/release", "bump version", "nowa wersja",
|
|
6
|
+
"release X.Y", "wypuść wersję", "zamknij wersję".
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /release — Version Bump & Changelog Release
|
|
10
|
+
|
|
11
|
+
Zero-argument workflow. Auto-detects project from CWD.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
### Step 0: Ensure a clean working tree (auto-commit WIP first)
|
|
16
|
+
|
|
17
|
+
Run `git status --porcelain` in the project root.
|
|
18
|
+
|
|
19
|
+
**Clean (empty output)** → continue to Step 1.
|
|
20
|
+
|
|
21
|
+
**Dirty** → do NOT stop. The release commit (Step 7) must still contain ONLY the
|
|
22
|
+
changelog file + version-synced files, so auto-commit the working changes as
|
|
23
|
+
their OWN separate commit first, then continue. This preserves the reason the
|
|
24
|
+
gate existed — a clean release commit is a clean revert target — while removing
|
|
25
|
+
the manual interruption. The WIP simply lands in its own commit *below* the
|
|
26
|
+
release commit.
|
|
27
|
+
|
|
28
|
+
> Why a separate commit, not mixed in: mixing WIP code with a version bump
|
|
29
|
+
> pollutes `git log` and makes rollback risky. Committing the WIP first keeps the
|
|
30
|
+
> release commit changelog-only with zero friction.
|
|
31
|
+
|
|
32
|
+
Auto-commit procedure (same safety rules as `/commit` — never lose history,
|
|
33
|
+
never leak secrets):
|
|
34
|
+
|
|
35
|
+
1. **Only genuinely-unsafe state stops the flow.** If a merge / rebase /
|
|
36
|
+
cherry-pick is in progress (`.git/MERGE_HEAD`, `.git/rebase-merge/`,
|
|
37
|
+
`.git/CHERRY_PICK_HEAD`), STOP and report — an auto-commit mid-operation is
|
|
38
|
+
unsafe. This is the ONLY hard stop in Step 0.
|
|
39
|
+
2. **Stage explicitly — never `git add -A` / `git add .`.** Stage tracked
|
|
40
|
+
modifications and safe untracked files by path. EXCLUDE secrets and junk:
|
|
41
|
+
anything matching `.env*`, `*.pem`, `*.key`, `id_rsa*`, `*.p12`,
|
|
42
|
+
credential/token files, or large binaries. If such a file is dirty/untracked,
|
|
43
|
+
leave it unstaged and note it in the Step 9 report — do not commit it, do not
|
|
44
|
+
stop. Split into multiple logical commits when the changes cleanly separate by
|
|
45
|
+
file/concern (mirrors `/commit`); one commit is fine when they don't.
|
|
46
|
+
3. **Message** — follow the `/commit` conventions: conventional-commit subject
|
|
47
|
+
`<type>(<scope>): <description> (v<current_version>)` derived from the staged
|
|
48
|
+
diff, with the `Co-Authored-By` trailer. If the changes span too many concerns
|
|
49
|
+
to summarize, use `chore: commit work in progress before release
|
|
50
|
+
(v<current_version>)`.
|
|
51
|
+
4. **Commit.** If the pre-commit hook rejects, fix the underlying issue, re-stage,
|
|
52
|
+
and make a NEW commit (never `--amend`, never `--no-verify`).
|
|
53
|
+
5. Re-run `git status --porcelain`; it MUST now be empty (modulo any
|
|
54
|
+
intentionally-skipped secret/junk files from step 2). Then continue to Step 1.
|
|
55
|
+
|
|
56
|
+
### Step 1: Gather state
|
|
57
|
+
Call `mcp__dct__list_projects()` and match CWD to a registered project.
|
|
58
|
+
Call `mcp__dct__count_unreleased_changelog(project)`.
|
|
59
|
+
Call `mcp__dct__list_changelog(project, unreleased_only=true)`.
|
|
60
|
+
|
|
61
|
+
Present the state:
|
|
62
|
+
```
|
|
63
|
+
Project: myproj (My Project)
|
|
64
|
+
Current version: 1.0
|
|
65
|
+
Unreleased entries: 5
|
|
66
|
+
|
|
67
|
+
[added] New Python parser support
|
|
68
|
+
[added] Incremental indexing
|
|
69
|
+
[fixed] Parser crash on empty files
|
|
70
|
+
[fixed] Memory leak in watcher
|
|
71
|
+
[changed] Refactored graph schema
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If there are no unreleased entries, inform the user and stop.
|
|
75
|
+
|
|
76
|
+
### Step 2: Offer changelog review before bumping
|
|
77
|
+
|
|
78
|
+
After showing the unreleased entries in Step 1, ask via `AskUserQuestion`:
|
|
79
|
+
- question: "Ready to release, or review entries first?"
|
|
80
|
+
- options:
|
|
81
|
+
- `"Go ahead — entries look correct"` → proceed to Step 2b
|
|
82
|
+
- `"Amend one entry"` → free-text `AskUserQuestion` asking which (id) and the new text, call `mcp__dct__add_changelog` for the replacement and mark the old one via `/clog` amend flow; then re-show the list
|
|
83
|
+
- `"Drop one entry"` → free-text `AskUserQuestion` for id, soft-delete via direct DB update (or flag for post-release removal); re-show the list
|
|
84
|
+
- `"Cancel release"` → stop
|
|
85
|
+
|
|
86
|
+
This is the pre-stamp safety net — once Step 4 stamps, reverting requires
|
|
87
|
+
manual SQL. Offering an explicit review step prevents regret.
|
|
88
|
+
|
|
89
|
+
### Step 2b: Ask bump type
|
|
90
|
+
|
|
91
|
+
The bump type MUST be chosen through `AskUserQuestion` — do NOT substitute a
|
|
92
|
+
plain-text prompt, and do NOT infer it from the user's earlier words, even if
|
|
93
|
+
they seem decided. The bump is effectively irreversible once Step 4 stamps
|
|
94
|
+
(reverting needs manual SQL), so the structured options must show the semver
|
|
95
|
+
implication AND the concrete resulting version number before committing to it.
|
|
96
|
+
This overrides any general "a plain-text answer is fine" preference.
|
|
97
|
+
|
|
98
|
+
Compute the concrete next version from `current_version` (vX.Y.Z) for each label:
|
|
99
|
+
- question: `"What type of release? (current: v<current_version>)"`
|
|
100
|
+
- options:
|
|
101
|
+
- `"patch — v<X.Y.(Z+1)> (bug fixes only)"`
|
|
102
|
+
- `"minor — v<X.(Y+1).0> (new features, backward compatible)"`
|
|
103
|
+
- `"major — v<(X+1).0.0> (breaking changes)"`
|
|
104
|
+
- `"explicit version — I'll type one"` → follow-up free-text AskUserQuestion
|
|
105
|
+
|
|
106
|
+
### Step 3: Confirm
|
|
107
|
+
```
|
|
108
|
+
Release myproj 1.1?
|
|
109
|
+
5 changelog entries will be stamped
|
|
110
|
+
Version: 1.0 → 1.1
|
|
111
|
+
```
|
|
112
|
+
Wait for confirmation.
|
|
113
|
+
|
|
114
|
+
### Step 4: Stamp version in DB
|
|
115
|
+
|
|
116
|
+
Call `mcp__dct__release_changelog(project, version=<version>)`. This:
|
|
117
|
+
- Updates all unreleased changelog entries with the new `version`.
|
|
118
|
+
- Updates the project's `current_version` field.
|
|
119
|
+
- After this call, `count_unreleased_changelog(project)` will return 0.
|
|
120
|
+
|
|
121
|
+
### Step 5: Append the new version's section to the changelog file
|
|
122
|
+
|
|
123
|
+
The changelog file (`F`, resolved below) is an **append-only archive**. /release ADDS the just-released
|
|
124
|
+
version's section to the top of the existing file — it does NOT regenerate the
|
|
125
|
+
whole file from the DB.
|
|
126
|
+
|
|
127
|
+
> **Why append, not regenerate:** a full `export_changelog`
|
|
128
|
+
> renders the file from DB rows only. For a project that adopted dct mid-life,
|
|
129
|
+
> the DB holds only post-adoption versions, so overwriting `changelog.md`
|
|
130
|
+
> silently DROPS every pre-adoption section (one such project lost 18 versions
|
|
131
|
+
> / ~536 lines this way). An operation that only ever inserts cannot lose history.
|
|
132
|
+
|
|
133
|
+
Let `V` = the version just stamped in Step 4 and `F` = the project's changelog
|
|
134
|
+
file. **Resolve `F` via the project's `changelog_path`, do NOT hardcode
|
|
135
|
+
`changelog.md`:** `F = {project.path}/{changelog_path}`, where `changelog_path`
|
|
136
|
+
comes from the Step 1 `list_projects` result (default `changelog.md` when the
|
|
137
|
+
field is absent — e.g. a not-yet-restarted MCP server). A project that keeps its
|
|
138
|
+
changelog in a subdirectory (e.g. a monorepo with `packages/core/changelog.md`) is then
|
|
139
|
+
handled transparently. Authoritative cross-check, always live:
|
|
140
|
+
`dct project changelog-path <slug>` prints the resolved absolute path on its
|
|
141
|
+
`→` line.
|
|
142
|
+
|
|
143
|
+
**Case A — F does not exist (bootstrap / from-scratch project):**
|
|
144
|
+
Call `mcp__dct__export_changelog(project, include_unreleased=false)` and write
|
|
145
|
+
the full result to F. For a from-scratch project the full render equals the
|
|
146
|
+
incremental one, so this is safe. Then continue to Step 6.
|
|
147
|
+
|
|
148
|
+
**Case B — F already exists (the normal path):**
|
|
149
|
+
|
|
150
|
+
1. Render ONLY the new section:
|
|
151
|
+
`section = mcp__dct__export_changelog(project, version=V)`.
|
|
152
|
+
- If `isinstance(section, dict)` → it is an error: do NOT touch F, report it,
|
|
153
|
+
stop (the DB was already stamped in Step 4, so either fix the export error
|
|
154
|
+
and re-run Step 5, or manually revert the stamped entries).
|
|
155
|
+
- If `section == ""` → V has no entries (unexpected after Step 4): STOP and
|
|
156
|
+
report rather than writing an empty section.
|
|
157
|
+
2. Read F. Count its existing version-section markers — **lines that start with** `## [` (`grep -c '^## \['`) — call it `N`. Anchor to line start; an entry body may contain `## [` mid-text and MUST NOT be counted.
|
|
158
|
+
3. **Idempotency guard:** if a **line starting with** `## [V]` already appears in F (anchored — `grep -q '^## \[V\]'`), the section is
|
|
159
|
+
already archived (e.g. a re-run after a partial release). Do NOT write —
|
|
160
|
+
report "changelog.md already contains [V]" and continue to Step 6.
|
|
161
|
+
4. Insert `section` directly **below the `# Changelog` header** (keep exactly
|
|
162
|
+
one blank line after the header) so it becomes the TOP version section.
|
|
163
|
+
Every existing section MUST stay byte-for-byte unchanged below it.
|
|
164
|
+
- Preferred mechanism: an Edit whose `old_string` is the current top
|
|
165
|
+
`## [...] - ...` line and whose `new_string` is `section` + that same line
|
|
166
|
+
(i.e. prepend the new section in front of the previous top version).
|
|
167
|
+
- If F has only the `# Changelog` header and no version sections yet,
|
|
168
|
+
append `section` after the header instead.
|
|
169
|
+
5. **Safety check (mandatory):** re-read F and re-count **lines starting with** `## [` (`grep -c '^## \['`). The new
|
|
170
|
+
count MUST be exactly `N + 1` — one section added, zero lost. If it is not,
|
|
171
|
+
STOP, restore F to its pre-write contents, and report. NEVER commit a
|
|
172
|
+
changelog that lost history.
|
|
173
|
+
|
|
174
|
+
The DB stays the source of truth for the NEXT release's unreleased entries;
|
|
175
|
+
the FILE is the source of truth for shipped history.
|
|
176
|
+
|
|
177
|
+
### Step 6: Sync version-bearing files
|
|
178
|
+
|
|
179
|
+
If `{project.path}/scripts/dct-version-sync.sh` exists, run it:
|
|
180
|
+
```bash
|
|
181
|
+
bash scripts/dct-version-sync.sh <version>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The sync script is **project-specific** — each project uncomments the
|
|
185
|
+
relevant block in the template. Canonical patterns by project kind:
|
|
186
|
+
|
|
187
|
+
| Project kind | Files to bump | sed/jq snippet |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| Python package | `pyproject.toml` `[project].version` | `sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml` |
|
|
190
|
+
| Python package (fallback) | `<pkg>/__init__.py` `__version__` | `sed -i '' "s/__version__ = \".*\"/__version__ = \"$VERSION\"/" dct/__init__.py` |
|
|
191
|
+
| Rust | `Cargo.toml` `[package].version` | `sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml` |
|
|
192
|
+
| Node (npm/yarn) | `package.json` `.version` | `jq --arg v "$VERSION" '.version = $v' package.json > tmp && mv tmp package.json` |
|
|
193
|
+
| Tauri | `src-tauri/tauri.conf.json` `.version` | `jq --arg v "$VERSION" '.version = $v' src-tauri/tauri.conf.json > tmp && mv tmp src-tauri/tauri.conf.json` |
|
|
194
|
+
| Claude Code plugin | `plugin.json` `.version` | `jq --arg v "$VERSION" '.version = $v' plugin.json > tmp && mv tmp plugin.json` |
|
|
195
|
+
| Swift (Info.plist) | `CFBundleShortVersionString` | `/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" Info.plist` |
|
|
196
|
+
|
|
197
|
+
For **monorepos** with independently-versioned sub-packages, wrap each
|
|
198
|
+
block in `if has_changes "<path>"; then ... fi` so only sub-packages that
|
|
199
|
+
actually changed get bumped. `has_changes` is provided by the template.
|
|
200
|
+
|
|
201
|
+
For **dct itself** (Python package, single-version), the sync script is
|
|
202
|
+
uncommented to always bump `pyproject.toml` + `dct/__init__.py` fallback.
|
|
203
|
+
|
|
204
|
+
If the sync script doesn't exist, skip this step — DB is the source of
|
|
205
|
+
truth. Inform the user so they can add one if they have build files that
|
|
206
|
+
need sync.
|
|
207
|
+
|
|
208
|
+
### Step 7: Commit the release
|
|
209
|
+
|
|
210
|
+
Stage ONLY the artifacts touched by Steps 5 and 6:
|
|
211
|
+
- `changelog.md`
|
|
212
|
+
- Any files modified by `scripts/dct-version-sync.sh` (check `git status --porcelain` after Step 6)
|
|
213
|
+
|
|
214
|
+
Then commit with the **literal** release message format:
|
|
215
|
+
```bash
|
|
216
|
+
git commit -m "release: v<version>"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
No type, no scope, no version suffix — just `release: v1.1`. The dct global hook
|
|
220
|
+
recognizes this prefix and bypasses the changelog-presence check (which would otherwise
|
|
221
|
+
fail because all entries were just stamped).
|
|
222
|
+
|
|
223
|
+
### Step 8: Tag the release (mandatory)
|
|
224
|
+
|
|
225
|
+
Tag HEAD with the `v<version>` prefix:
|
|
226
|
+
```bash
|
|
227
|
+
git tag v<version>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Rationale: the tag is the canonical marker of "this commit = this release"
|
|
231
|
+
for git log, GitHub, and future `git describe` output. Conventional `v`
|
|
232
|
+
prefix matches npm, PyPI, Cargo, and GitHub release UI expectations.
|
|
233
|
+
|
|
234
|
+
**Do NOT `git push --tags`** automatically — pushing to remote is a
|
|
235
|
+
separate, user-confirmed action. Inform the user the tag is local; if
|
|
236
|
+
they want it on the remote, they run `git push origin v<version>` or
|
|
237
|
+
`git push --tags` themselves.
|
|
238
|
+
|
|
239
|
+
If a tag `v<version>` already exists (rare — usually indicates a failed
|
|
240
|
+
earlier release), ask the user via `AskUserQuestion`:
|
|
241
|
+
- "Tag v<version> exists. Move it to the new commit, or fail?"
|
|
242
|
+
- `"Move tag to new HEAD (--force)"`
|
|
243
|
+
- `"Leave tag alone, don't tag this commit"`
|
|
244
|
+
- `"Abort — the existing tag is correct, something is wrong with this release"`
|
|
245
|
+
|
|
246
|
+
### Step 9: Report
|
|
247
|
+
```
|
|
248
|
+
✓ myproj released as 1.1
|
|
249
|
+
5 entries stamped
|
|
250
|
+
changelog.md: [1.1] section prepended (older history preserved)
|
|
251
|
+
Version-synced files: pyproject.toml, myproj/__init__.py
|
|
252
|
+
Commit: release: v1.1 (abc1234)
|
|
253
|
+
Tag: v1.1 (local only — run `git push origin v1.1` to push)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Rules
|
|
257
|
+
- NEVER release without user confirmation.
|
|
258
|
+
- NEVER skip the bump type question, and NEVER substitute a plain-text prompt
|
|
259
|
+
for it — the bump type MUST be an AskUserQuestion (Step 2b). The pre-stamp
|
|
260
|
+
structured choice is the last reversible point.
|
|
261
|
+
- If `current_version` is not set, ask for explicit version instead of bump type.
|
|
262
|
+
- `changelog.md` is an **append-only archive**: /release only PREPENDS the new
|
|
263
|
+
version's section (Step 5 Case B), it does NOT regenerate the whole file.
|
|
264
|
+
Full-DB export is bootstrap-only (Case A, when no file exists yet). Rationale:
|
|
265
|
+
regenerating from the DB drops pre-adoption history.
|
|
266
|
+
- Editing an already-released entry in the DB will NOT re-render the file —
|
|
267
|
+
shipped history lives in `changelog.md`; correct it there directly.
|
|
268
|
+
- The release commit's `changelog.md` diff MUST be purely additive (one new
|
|
269
|
+
`## [vX]` section on top). If `git diff` shows deletions of older sections,
|
|
270
|
+
the append-only flow failed — STOP and investigate before committing.
|
|
271
|
+
- Release commit message MUST be exactly `release: vX.Y.Z` (no scope, no description).
|
|
272
|
+
The hook's release bypass depends on this prefix.
|
|
273
|
+
- The release commit contains ONLY changelog.md + version-synced files — no app
|
|
274
|
+
code. Step 0 guarantees this by auto-committing any WIP as a SEPARATE commit
|
|
275
|
+
first, so the release commit stays a clean revert target.
|
|
276
|
+
- Tag is **mandatory** — every release commit gets a `v<version>` tag (Step 8).
|
|
277
|
+
A release without a tag is not a release — it's a commit that happens to bump
|
|
278
|
+
`pyproject.toml`. Tags are the git-native marker for `git describe`,
|
|
279
|
+
`git log --decorate`, GitHub's release UI, and `pip install <pkg>==<version>`.
|
|
280
|
+
- Pushing the tag to remote is NOT automatic — inform the user the tag is local
|
|
281
|
+
and suggest `git push origin v<version>` (or `git push --tags`) as a separate step.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: track
|
|
3
|
+
description: |
|
|
4
|
+
Create a tracked item (issue, todo, feature, idea, improvement) in dct.
|
|
5
|
+
Use when: "track", "add issue", "add todo", "dodaj issue", "zanotuj",
|
|
6
|
+
"śledź", "track this", "new issue", "nowy issue", "zgłoś",
|
|
7
|
+
"dodaj jako problem", "problem", "bug", "błąd", "crash", "nie działa",
|
|
8
|
+
"dodaj feature", "ficzer", "dodaj ficzer", "dodaj todo",
|
|
9
|
+
"pomysł", "idea", "a może", "rozważ",
|
|
10
|
+
"poprawa", "ulepszenie", "poprawmy", "refactor", "cleanup".
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# /track — Create Tracked Item
|
|
14
|
+
|
|
15
|
+
## Type triggers — natural language → item_type
|
|
16
|
+
|
|
17
|
+
Map the phrase the user actually used to the closest type. Do NOT ask
|
|
18
|
+
about type unless the phrase is genuinely ambiguous. When in doubt, prefer
|
|
19
|
+
`todo` (the most neutral bucket).
|
|
20
|
+
|
|
21
|
+
| User says (EN / PL) | item_type | When to pick |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| "problem", "bug", "issue", "crash", "broken", "error", "doesn't work", "regression" / "problem", "błąd", "bug", "crash", "nie działa", "popsute", "zepsute" | **issue** | Observable defect in existing code/system. Reproducible wrong behavior. |
|
|
24
|
+
| "todo", "task", "action item", "need to", "must do" / "todo", "zadanie", "zrobić", "do zrobienia", "trzeba" | **todo** | Concrete work that's neither a bug nor a new user-visible capability. Generic "stuff to do". |
|
|
25
|
+
| "feature", "add X", "new capability", "let's build", "we should have" / "feature", "ficzer", "funkcja", "dodajmy", "zbudujmy", "nowa funkcja" | **feature** | New user-visible capability that doesn't exist yet. |
|
|
26
|
+
| "idea", "maybe", "what if", "consider", "brainstorm", "explore" / "pomysł", "idea", "a może", "rozważ", "zastanów się", "pomyślmy" | **idea** | Exploratory — not yet decided to build. May become a feature later. |
|
|
27
|
+
| "improvement", "refactor", "polish", "cleanup", "tidy up", "make X nicer" / "ulepszenie", "poprawa", "poprawmy", "polerka", "cleanup", "refactor", "uporządkuj" | **improvement** | Existing thing works but could be better (refactor, UX polish, perf, docs). |
|
|
28
|
+
|
|
29
|
+
### Examples
|
|
30
|
+
|
|
31
|
+
| Phrase | item_type | Why |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| "dodaj jako problem że parser się wywala na pustych plikach" | issue | "problem" + observable broken behavior |
|
|
34
|
+
| "dodaj ficzer, chcę zrobić dark mode" | feature | "ficzer" + new capability |
|
|
35
|
+
| "a może pomyślmy nad wtyczkami?" | idea | "a może" + exploratory |
|
|
36
|
+
| "trzeba uporządkować ten moduł parsera" | improvement | "uporządkować" + existing code |
|
|
37
|
+
| "dodaj todo — wysłać PR do review" | todo | explicit "todo", generic task |
|
|
38
|
+
|
|
39
|
+
## Workflow
|
|
40
|
+
|
|
41
|
+
### Step 1: Infer type, then gather rest
|
|
42
|
+
|
|
43
|
+
From the conversation context, determine:
|
|
44
|
+
|
|
45
|
+
- **project**: Detect from CWD using `mcp__dct__list_projects()` (longest path prefix), or ask if ambiguous
|
|
46
|
+
- **item_type**: Infer from the user's phrasing per the table above
|
|
47
|
+
- **title**: Concise summary (max ~80 chars)
|
|
48
|
+
- **priority**: P1 (blocks work / data loss / security), P2 (important — default), P3 (backlog), future (post-v1)
|
|
49
|
+
- **description**: Details, context, steps to reproduce (for issues) — prose, not checkbox lists
|
|
50
|
+
- **component**: Module or subsystem (optional)
|
|
51
|
+
- **source_file**: Relative path where the item lives (optional)
|
|
52
|
+
- **source_lines**: Line range, e.g. "42-58" (optional)
|
|
53
|
+
- **tags**: Comma-separated labels (optional)
|
|
54
|
+
|
|
55
|
+
### Step 2: Confirm with user
|
|
56
|
+
|
|
57
|
+
Present the proposed item (short form — no wall of JSON):
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Track this?
|
|
61
|
+
Type: issue
|
|
62
|
+
Priority: P1
|
|
63
|
+
Title: Parser crashes on empty files
|
|
64
|
+
File: cmd/parse.go:42-58
|
|
65
|
+
Tags: parser, crash
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Wait for confirmation or corrections. If user said "just add it" or similar,
|
|
69
|
+
skip confirmation.
|
|
70
|
+
|
|
71
|
+
### Step 3: Create
|
|
72
|
+
|
|
73
|
+
Call `mcp__dct__create_item(project, item_type, title, ...)` with all fields.
|
|
74
|
+
**REMEMBER the returned `id`** — needed for any follow-up (add_checkpoint,
|
|
75
|
+
update_item, resolve_item).
|
|
76
|
+
|
|
77
|
+
### Step 4: Sketch checkpoints (feature / improvement only)
|
|
78
|
+
|
|
79
|
+
If `item_type` ∈ {feature, improvement}, IMMEDIATELY after create_item,
|
|
80
|
+
call `add_checkpoint` 3-7 times to break the work into concrete steps.
|
|
81
|
+
Do this BEFORE starting any code. Remember each checkpoint id.
|
|
82
|
+
|
|
83
|
+
Skip for `issue`, `todo`, `idea` unless the user explicitly asks for a
|
|
84
|
+
checkpoint breakdown.
|
|
85
|
+
|
|
86
|
+
### Step 5: Report
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
✓ #42 issue/P1 — Parser crashes on empty files
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
For feature/improvement with checkpoints:
|
|
93
|
+
```
|
|
94
|
+
✓ #43 feature/P2 — Dark mode
|
|
95
|
+
Checkpoints: 5 (ready to track)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Priority mapping
|
|
99
|
+
|
|
100
|
+
P2 is the fallback ONLY when the user gives no priority cue. Read their
|
|
101
|
+
language first — urgency words trump the default.
|
|
102
|
+
|
|
103
|
+
| User phrasing | priority |
|
|
104
|
+
|---|---|
|
|
105
|
+
| "blocker", "blokuje", "data loss", "security", "critical", "pilne", "urgent", "krytyczne", "ważne" | **P1** |
|
|
106
|
+
| No urgency cue, neutral report | P2 (default) |
|
|
107
|
+
| "kiedyś", "backlog", "eventually", "nice to have", "low prio", "niski priorytet" | **P3** |
|
|
108
|
+
| "post-v1", "long-term", "someday", "może w przyszłości", "future" | **future** |
|
|
109
|
+
|
|
110
|
+
Never silently default to P2 when the user said "ważne" or "pilne" — that
|
|
111
|
+
would bury a P1 in the backlog.
|
|
112
|
+
|
|
113
|
+
## Rules
|
|
114
|
+
|
|
115
|
+
- **Never ask about type** if the phrase maps cleanly per the table. Claude's
|
|
116
|
+
job is to read the language, not interrogate the user.
|
|
117
|
+
- **Never silently create** — always show the draft and wait for confirmation
|
|
118
|
+
(exception: user explicitly waived with "just add it", "szybko", "don't ask").
|
|
119
|
+
- **REMEMBER the returned id** — it's the handle for every future operation.
|
|
120
|
+
- **Checkpoints are mandatory for feature/improvement** — the visible
|
|
121
|
+
plan is the contract. No "I'll add them later" — add before coding.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: track-list
|
|
3
|
+
description: |
|
|
4
|
+
List and search tracked items across projects. Supports priority grouping,
|
|
5
|
+
file hotspots, and cross-project aggregation.
|
|
6
|
+
Use when: "list issues", "show todos", "what's open", "pokaż issues",
|
|
7
|
+
"co mamy", "backlog", "track-list", "all items", "open issues".
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /track-list — List Tracked Items
|
|
11
|
+
|
|
12
|
+
Default: open items in the current project (auto-detected from CWD), grouped
|
|
13
|
+
by priority (P1 → P2 → P3 → future), compact `{cols, rows}` format. Resolved
|
|
14
|
+
items are hidden unless explicitly requested.
|
|
15
|
+
|
|
16
|
+
## Routing — direct vs subagent
|
|
17
|
+
|
|
18
|
+
Pick based on cost, not habit. Main context is precious.
|
|
19
|
+
|
|
20
|
+
**Run directly (main context)** when:
|
|
21
|
+
- Single project, ≤50 open items expected
|
|
22
|
+
- Single #ID lookup (`/track-list #42` → `mcp__dct__get_item(42)`)
|
|
23
|
+
- Simple filter (priority / type / component / in_sprint)
|
|
24
|
+
|
|
25
|
+
**Delegate to subagent** (`Agent` tool with `subagent_type=Explore` or `general-purpose`) when:
|
|
26
|
+
- **Cross-project aggregation** (no `project` filter, >1 registered project with >20 items each)
|
|
27
|
+
- **Hotspot detection** (needs to group by `source_file` across items — Python-side work, not SQL)
|
|
28
|
+
- **Cross-source matching** (e.g. "which items share a changelog entry? which are in the sprint AND have stale checkpoints?")
|
|
29
|
+
- Expected output >200 rows
|
|
30
|
+
- Long free-text search across large description bodies
|
|
31
|
+
|
|
32
|
+
Subagent returns a concise summary. You relay that summary, not the raw rows — keeps your context lean.
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
### Step 1: Parse user intent
|
|
37
|
+
|
|
38
|
+
Extract from the request:
|
|
39
|
+
- **project**: explicit slug, `--all`/"all"/"cross-project" → empty (cross-project), otherwise auto-detect from CWD via `mcp__dct__list_projects` longest-prefix match
|
|
40
|
+
- **status**: default `"open"`. Accepts `"in_progress"`, `"resolved"`, `"wont_fix"`, or `""` for all. Convenience aliases: `--all-statuses`, `--include-resolved`
|
|
41
|
+
- **item_type**: `issue`/`todo`/`feature`/`idea`/`improvement`, or empty
|
|
42
|
+
- **priority**: `P1`/`P2`/`P3`/`future`, or empty
|
|
43
|
+
- **component**: match exact component name
|
|
44
|
+
- **in_current_sprint**: `"true"` (only sprint), `"false"` (exclude sprint), or empty
|
|
45
|
+
- **search**: free-text, searched in `title` + `description`
|
|
46
|
+
- **limit**: default 50
|
|
47
|
+
|
|
48
|
+
ID normalization (from `#42`, `42`, `ITEM-42`, `item-42`, `ITEM_42`, `item_42`, `0042` → `42`): regex `^(#|ITEM-|item-|ITEM_|item_)?0*(\d+)$` — case-insensitive prefix strip, leading-zero strip, cast int. Uniform with /track-update and /track-resolve. If a single ID is given, skip listing and go to `mcp__dct__get_item(id)`.
|
|
49
|
+
|
|
50
|
+
### Step 2: Query
|
|
51
|
+
|
|
52
|
+
Call `mcp__dct__list_items(project, status, item_type, priority, component, in_current_sprint, search, limit, format="structured")`.
|
|
53
|
+
|
|
54
|
+
Response shape:
|
|
55
|
+
```
|
|
56
|
+
{"cols": ["id","item_type","priority","status","in_current_sprint","cp","component","tags","created_at","title","description"],
|
|
57
|
+
"rows": [[22,"improvement","P2","open",false,[0,0],"server",["mcp"],"2026-04-17","Optimize...","..."]]}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Step 3: Present — priority grouping
|
|
61
|
+
|
|
62
|
+
Group rows by priority (P1 → P2 → P3 → future). Within each group sort by `cp` progress descending (most-done first), then by `created_at` ascending (oldest first).
|
|
63
|
+
|
|
64
|
+
Render as markdown:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
## P1 — blocking (2)
|
|
68
|
+
| # | Type | Sprint | cp | Component | Title |
|
|
69
|
+
|-----|-------|--------|-------|-----------|-------------------------------|
|
|
70
|
+
| 42 | issue | ● | 2/3 | parser | Crash on empty files |
|
|
71
|
+
| 88 | todo | | 0/0 | auth | Rotate session tokens |
|
|
72
|
+
|
|
73
|
+
## P2 — important (11)
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
## P3 — backlog (4)
|
|
77
|
+
...
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Use `●` for `in_current_sprint=true`, blank for false. Use `cp` as `done/total` string (e.g. `2/5`) from the raw `[2,5]` array.
|
|
81
|
+
|
|
82
|
+
### Step 4: Hotspots (only if explicitly asked OR >1 hotspot auto-detected)
|
|
83
|
+
|
|
84
|
+
A **hotspot** is a file/component with ≥2 open items. Run Python-side aggregation on the rows (no extra DB call).
|
|
85
|
+
|
|
86
|
+
Trigger automatically when rows.length ≥ 20 AND at least one file has ≥2 items. The thresholds are empirical — below 20 items a hotspot section is noise (few rows, hotspots self-evident); above 20, the extra section reveals structural debt clusters. Otherwise show only on request (`/track-list --hotspots`).
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
## Hotspots (top 3 files by open-item count)
|
|
90
|
+
| Path | Open | P1 | Titles |
|
|
91
|
+
|--------------------------|------|----|-------------------------------------|
|
|
92
|
+
| dct/server.py | 4 | 0 | #22, #6, #14, #20 |
|
|
93
|
+
| dct/skills/track-list/SKILL.md | 3 | 0 | #6, #14, #19 |
|
|
94
|
+
| dct/core/items.py | 2 | 0 | #4, #23 (resolved) |
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If no source_file on items, skip this section.
|
|
98
|
+
|
|
99
|
+
### Step 5: Cross-project summary (only when no project filter)
|
|
100
|
+
|
|
101
|
+
When `project` is empty (cross-project mode), prepend a summary line:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Cross-project: 37 open items in 4 projects (dct: 13, proj-a: 87, proj-b: 63, proj-c: 35)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then show **top 3 priorities cross-project**, skipping detailed rows (delegate full listings to subagent if user asks).
|
|
108
|
+
|
|
109
|
+
### Step 6: Final summary line
|
|
110
|
+
|
|
111
|
+
Always end with a count:
|
|
112
|
+
```
|
|
113
|
+
Showing 13 open items in dct. Use /track-list --include-resolved to show closed.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Shortcuts
|
|
117
|
+
|
|
118
|
+
- `/track-list` — open items in current project
|
|
119
|
+
- `/track-list #42` — direct `get_item(42)` (skips list)
|
|
120
|
+
- `/track-list proj-a` — items in project `proj-a`
|
|
121
|
+
- `/track-list --all` — cross-project (delegate to subagent if >100 expected)
|
|
122
|
+
- `/track-list P1` — P1-only filter
|
|
123
|
+
- `/track-list parser` — search "parser" in title/description
|
|
124
|
+
- `/track-list --sprint` — only `in_current_sprint=true`
|
|
125
|
+
- `/track-list --hotspots` — force hotspot section
|
|
126
|
+
- `/track-list --include-resolved` — include resolved + wont_fix
|
|
127
|
+
|
|
128
|
+
## Rules
|
|
129
|
+
|
|
130
|
+
- **Always parse with ID normalization regex**. Do not reject `#42` because of the hash sign.
|
|
131
|
+
- **Default hides resolved** — do not surprise the user with closed items unless they ask.
|
|
132
|
+
- **Prefer subagent for cross-project** when ≥2 projects have ≥20 open items each. Tell the user: "Cross-project aggregation — delegating to subagent".
|
|
133
|
+
- **`cp` column is authoritative** — do not re-query per-item to compute progress (N+1).
|
|
134
|
+
- **Don't show `description` in the table** (it's in cols but too long for a grid row). Keep it available for follow-up `get_item` calls. Render only `title` in the grid.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: track-resolve
|
|
3
|
+
description: |
|
|
4
|
+
Resolve or close a tracked item in dct.
|
|
5
|
+
Use when: "resolve issue", "close item", "mark as done", "zamknij issue",
|
|
6
|
+
"track-resolve", "wont fix", "done with #42".
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /track-resolve — Resolve/Close Item
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
### Step 1: Identify item(s)
|
|
14
|
+
|
|
15
|
+
**ID normalization** — accept all of these forms:
|
|
16
|
+
- `#42`, `42`, `ITEM-42`, `item-42`, `0042`
|
|
17
|
+
|
|
18
|
+
Parse by: strip leading `#`, strip `ITEM-` / `item-` prefix (case-insensitive), strip leading zeros, cast to integer.
|
|
19
|
+
Regex: `^(#|ITEM-|item-|ITEM_|item_)?0*(\d+)$` — capture group 2 is the numeric id.
|
|
20
|
+
|
|
21
|
+
**Batch resolution** — user may pass multiple IDs separated by whitespace or commas:
|
|
22
|
+
```
|
|
23
|
+
/track-resolve #42 #45 #51 ← three items in one call
|
|
24
|
+
/track-resolve 42, 45, 51 ← comma form
|
|
25
|
+
/track-resolve ITEM-42 #45 ← mixed forms
|
|
26
|
+
```
|
|
27
|
+
Split input on whitespace and commas, normalize each id, then call `resolve_item` once per id.
|
|
28
|
+
|
|
29
|
+
Call `mcp__dct__get_item(item_id)` for each id to fetch current state.
|
|
30
|
+
|
|
31
|
+
### Step 2: Determine resolution
|
|
32
|
+
- **resolved**: Fixed, implemented, completed
|
|
33
|
+
- **wont_fix**: Intentionally not addressing
|
|
34
|
+
|
|
35
|
+
Build resolution note from context:
|
|
36
|
+
- If a commit was just made: "Fixed in commit {hash}"
|
|
37
|
+
- If decision: "Decision: {reason}"
|
|
38
|
+
- Ask user if context is insufficient
|
|
39
|
+
|
|
40
|
+
### Step 3: Confirm
|
|
41
|
+
```
|
|
42
|
+
Resolve #42 — Parser crashes on empty files?
|
|
43
|
+
Status: open → resolved
|
|
44
|
+
Resolution: Fixed in commit abc1234
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Step 4: Execute
|
|
48
|
+
Call `mcp__dct__resolve_item(item_id, status, resolution)`.
|
|
49
|
+
|
|
50
|
+
### Step 5: Report
|
|
51
|
+
```
|
|
52
|
+
✓ #42 → resolved
|
|
53
|
+
```
|