diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 22c5892..0c1dc52 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "ytstack", "description": "Claude Code plugin. Project-OS artifact discipline + curated superpowers and gstack skill wrappers + Agent Teams orchestration.", - "version": "0.4.2", + "version": "0.5.0", "source": "./", "author": { "name": "Yesterday", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e2d826e..da0bb05 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ytstack", - "version": "0.4.2", + "version": "0.5.0", "description": "BUNDLE: Yesterday Technologies Stack -- opinionated software-development OS for AI agents. Curated superpowers + gstack skills plus Project-OS artifact discipline (PROJECT.md, DECISIONS.md, KNOWLEDGE.md, milestone/slice/task hierarchy), orchestrated via SessionStart hooks.", "author": { "name": "Yesterday", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 1a62406..ad8f377 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ytstack", - "version": "0.4.2", + "version": "0.5.0", "description": "Project memory, milestone planning, and curated gstack and superpowers workflows for AI coding agents.", "author": { "name": "Yesterday", diff --git a/.ytstack/STATE.md b/.ytstack/STATE.md index 640f43f..cd4ddf6 100644 --- a/.ytstack/STATE.md +++ b/.ytstack/STATE.md @@ -1,7 +1,7 @@ --- project: ytstack slug: ytstack -last_updated: 2026-11-11T10:45:00Z +last_updated: 2026-11-11T10:53:05Z current_milestone: none active_slice: none active_task: none @@ -9,7 +9,7 @@ active_task: none # State -**Status (2026-11-11):** M021 DONE on branch `feat/status-segment` (issue #31): `bin/ytstack-status` status line segment, optional `progress` block in the STATE frontmatter, `yt_progress_parse` + lint W7, upkeep in `summarize-task` / `quick-task`, `docs/statusline.md`. 13 suites green on macOS, checker 27 warnings as on `main`, `claude plugin validate .` passed. Open as PR #32 (CI green on macOS and ubuntu); not merged, not released. M020 (Kimi adapter, issue #30) is planned in the main checkout and uncommitted there; it is the next pointer once both lines meet. +**Status (2026-11-11):** M021 DONE and merged as `b9daa42` (PR #32, issue #31 closed; review follow-up for ref selection and the `set -e` snippet in the next PR): `bin/ytstack-status` status line segment, optional `progress` block in the STATE frontmatter, `yt_progress_parse` + lint W7, upkeep in `summarize-task` / `quick-task`, `docs/statusline.md`. 13 suites green on macOS, checker 27 warnings as on `main`, `claude plugin validate .` passed. CI green on `main` (macOS and ubuntu). Released as 0.5.0 (manifests, badge and CHANGELOG in the follow-up PR; tag `v0.5.0` on its merge commit). M020 (Kimi adapter, issue #30) is planned in the main checkout and uncommitted there; it is the next pointer once both lines meet. **Previous status (2026-10-13, PR #23 correction):** Removed the generated Codex skill/hook copies and build tooling. Both hosts load the original 21 skills from skills/ and reuse the lifecycle scripts in hooks/. Codex-specific runtime instructions live only in codex/adapter.md, supplied at SessionStart or read explicitly without trusted hooks. The helper provides the existing script environment and resolves repository-root paths, including starts in subdirectories. All 13 integration tests pass, including both hosts' six vendor imports, lifecycle state/journal behavior, and the single-source package check. Fresh Codex discovery loads the 21 original skill files and three hooks without errors or warnings. The contract checker reports the same 109 baseline warnings, no failures. The interactive desktop walkthrough remains a manual follow-up. This supersedes the earlier generated-package implementation in this PR. @@ -85,7 +85,7 @@ M009 Docs & Community [####] 4/4 DONE ## Next action -**Operator actions for M021:** merge PR #32, cut the release, `/plugin update`, wire the snippet from `docs/statusline.md` into the status line script, close issue #31. Merging meets the uncommitted M020 planning in `STATE.md` and `DECISIONS.md`: keep both DECISIONS entries and the M020 pointer. +**Operator actions for M021:** `/plugin update` to 0.5.0, wire the snippet from `docs/statusline.md` into the status line script. Pulling `main` into the main checkout meets the uncommitted M020 planning in `STATE.md` and `DECISIONS.md`: keep both DECISIONS entries and the M020 pointer. **Previous status:** **M019 DONE -- delivered as 0.4.2 (0.4.0 -> 0.4.1 Codex-support merge of PR #23 -> 0.4.2 Linux `stat` fix), pushed, CI green on `f2a439c`, issues #18/#24/#25/#27 closed, installed plugin on 0.4.2, gstack v1.96.0.0 installed and live-validated (`tests/gstack-live.test.sh` 39/39).** The public catalog (`Yesterday-AI/skills`) pins no version, so it tracks `plugin.json`. No milestone open; M020 candidates are listed in ROADMAP. 0.4.0 bundles M010 (adopt-brownfield), M018 (ceremony dials, quick-task, reconcile, minimal-code, STATE lint, states, layouts) and M019 (`metadata:` frontmatter + trigger-only descriptions, `evals/` for `claude plugin eval` + CI, six lifecycle skills `code-review` / `finish-branch` / `grill` / `retro` / `ship` / `document-release`, worktree-subagent execution model with Agent Teams opt-in, Stop hook, no plugin dependencies). Clean clone at the release commit: 12 suites green, checker 0 fails, validate clean; evals 10/11 + re-run of the changed cases. **No milestone is open**: the modernisation programme from the 2026-11-07 research is complete; `ytstack:plan-milestone` for M020 when there is a next goal (candidates: live dogfooding of `spawn-milestone-team` 0.2.0 on a real milestone; PowerShell hook variants if a Windows consumer appears; per-worktree pointer if the orchestrator model needs it). **Operator actions:** `git push origin main --tags` (v0.2.0, v0.3.0, v0.4.0 are local), `gh issue close 24 25 27` (evidence posted), `/plugin update` to 0.4.0, gstack install one-liner (QUICKSTART) for the six gstack-backed skills, catalog sync in `Yesterday-AI/skills` (version 0.4.0, README skill table), skills.sh listing refresh. diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5459b..088dd4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.0] - 2026-11-11 + ### Added - **Status line segment** (`bin/ytstack-status`, issue #31): one compact @@ -17,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 current task pointer. Plan progress is read from the default branch when the checkout is on another branch (linked worktrees), the pointer from the checkout. Local refs only, no network. Integration in `docs/statusline.md`. + The default ref is `origin/`, or the local `` when it + contains the remote one; the two are compared by ancestry. - `yt_progress_parse` in the shared library and STATE lint finding W7 for a malformed `progress` block; a malformed block prints nothing. - `summarize-task` and `quick-task` update the `progress` block when they @@ -399,6 +403,7 @@ model). Research basis: `docs/research/2026-11-07-modernisierung-best-practices. `.ytstack/` artifact model (PROJECT / DECISIONS / KNOWLEDGE / STATE / milestone-slice-task hierarchy). +[0.5.0]: https://github.com/Yesterday-AI/ytstack/releases/tag/v0.5.0 [0.4.2]: https://github.com/Yesterday-AI/ytstack/releases/tag/v0.4.2 [0.4.1]: https://github.com/Yesterday-AI/ytstack/releases/tag/v0.4.1 [0.4.0]: https://github.com/Yesterday-AI/ytstack/releases/tag/v0.4.0 diff --git a/README.md b/README.md index 8db9606..5a69414 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

License ci - version + version Claude Code Codex skills @@ -327,7 +327,7 @@ Every hook and skill preamble resolves the checkout from where the agent actuall ## Status -**v0.4.0 -- shipping, actively dogfooded.** 0.2.0 made hooks and skills worktree-safe and moved volatile session state out of the repository (issues #24, #26, #27); 0.3.0 pulled superpowers to v7.0.2 and turned gstack into an installed, tag-pinned dependency (#25); 0.4.0 adds brownfield import (`adopt-brownfield`, #18), ceremony scaling (quick lane, reconcile, minimal-code guard, STATE lint), the 2026 skill bar (`metadata:` frontmatter, trigger-only descriptions measured by `evals/`, CI), six lifecycle skills (`code-review`, `finish-branch`, `grill`, `retro`, `ship`, `document-release`) and the worktree-subagent execution model. ytstack tracks its own development in `.ytstack/`; see `.ytstack/ROADMAP.md` for what is next. +**v0.5.0 -- shipping, actively dogfooded.** 0.5.0 adds the status line segment (`bin/ytstack-status`, #31). 0.2.0 made hooks and skills worktree-safe and moved volatile session state out of the repository (issues #24, #26, #27); 0.3.0 pulled superpowers to v7.0.2 and turned gstack into an installed, tag-pinned dependency (#25); 0.4.0 adds brownfield import (`adopt-brownfield`, #18), ceremony scaling (quick lane, reconcile, minimal-code guard, STATE lint), the 2026 skill bar (`metadata:` frontmatter, trigger-only descriptions measured by `evals/`, CI), six lifecycle skills (`code-review`, `finish-branch`, `grill`, `retro`, `ship`, `document-release`) and the worktree-subagent execution model. ytstack tracks its own development in `.ytstack/`; see `.ytstack/ROADMAP.md` for what is next. Ships: diff --git a/bin/ytstack-status b/bin/ytstack-status index 0382d8d..0e86032 100755 --- a/bin/ytstack-status +++ b/bin/ytstack-status @@ -13,8 +13,9 @@ # Colour is on by default; NO_COLOR or --no-color turns it off. # # Plan progress is repository-wide: on any branch other than the default one -# (a linked worktree carries a stale copy) STATE.md is read from the newer of -# origin/ and , and so is the slice plan of the fallback +# (a linked worktree carries a stale copy) STATE.md is read from +# origin/, or from the local when that contains it +# (unpushed commits), and so is the slice plan of the fallback # (the checkout's copy only when the slice plan does not exist there yet). # The task pointer is always the local one. # Local refs only: no network, no gh. See docs/statusline.md. @@ -57,8 +58,16 @@ if [ "$YT_IS_GIT" = yes ] && [ "$YT_SCOPE" = project ]; then done fi if [ -n "$DEF" ] && [ "$(git -C "$YT_TOPLEVEL" symbolic-ref --quiet --short HEAD 2>/dev/null)" != "$DEF" ]; then - REF=$(git -C "$YT_TOPLEVEL" for-each-ref --sort=-committerdate --count=1 --format='%(refname)' \ - "refs/heads/$DEF" "refs/remotes/origin/$DEF" 2>/dev/null) + # origin/ unless the local contains it (unpushed + # commits). Ancestry, not committer dates: dates tie and can run backwards. + LREF="refs/heads/$DEF"; OREF="refs/remotes/origin/$DEF" + if git -C "$YT_TOPLEVEL" show-ref --verify --quiet "$OREF"; then + REF="$OREF" + if git -C "$YT_TOPLEVEL" show-ref --verify --quiet "$LREF" \ + && git -C "$YT_TOPLEVEL" merge-base --is-ancestor "$OREF" "$LREF" 2>/dev/null; then REF="$LREF"; fi + elif git -C "$YT_TOPLEVEL" show-ref --verify --quiet "$LREF"; then + REF="$LREF" + fi [ -z "$REF" ] || PLAN_STATE=$(git -C "$YT_TOPLEVEL" show "$REF:.ytstack/STATE.md" 2>/dev/null) fi fi diff --git a/docs/statusline.md b/docs/statusline.md index 82f917c..b1720fd 100644 --- a/docs/statusline.md +++ b/docs/statusline.md @@ -49,7 +49,7 @@ Keeping it current: Plan progress belongs to the repository, the task pointer to the checkout. -- **Plan progress** is read from the default branch whenever the checkout is on another branch. A linked worktree or a feature branch carries a stale copy of `STATE.md`, so the script reads the file with `git show` from the newer of `origin/` and the local ``. The default branch is taken from `origin/HEAD`, else `main`, else `master`. On the default branch itself, and outside Git, the working tree file is used. +- **Plan progress** is read from the default branch whenever the checkout is on another branch. A linked worktree or a feature branch carries a stale copy of `STATE.md`, so the script reads the file with `git show` from `origin/`, or from the local `` when it contains `origin/` (unpushed commits). The two are compared by ancestry, not by commit date. The default branch is taken from `origin/HEAD`, else `main`, else `master`. On the default branch itself, and outside Git, the working tree file is used. - **The task pointer** (`M###/S##/T##`) always comes from the `STATE.md` of the directory you are in. - **The slice task count** of a project without a block follows the same rule as the block: off the default branch the slice plan named by the pointer is read from the default branch. Only when that slice plan does not exist there yet (a slice planned on the branch) is the copy in your directory counted. A slice that runs in a worktree therefore shows the merged count until its work lands. @@ -61,12 +61,14 @@ Your status line script receives a JSON object on stdin. Pass it on and append t ```bash input=$(cat) -yt=$(ls -d ~/.claude/plugins/cache/*/ytstack/*/bin/ytstack-status 2>/dev/null | sort -V | tail -1) -seg=$([ -n "$yt" ] && printf '%s' "$input" | "$yt") +yt=$(ls -d ~/.claude/plugins/cache/*/ytstack/*/bin/ytstack-status 2>/dev/null | sort -V | tail -1) || true +seg=$([ -n "$yt" ] && printf '%s' "$input" | "$yt") || true ``` Then print `$seg` where you want it, for example `printf '%s%s' "$line" "${seg:+ | $seg}"`. +The script exits 1 when it has nothing to print, and the glob fails while the plugin is not installed. The `|| true` on both lines keeps a status line script that runs under `set -e` or `set -o pipefail` alive in those cases; `$seg` is then empty. + The second line is the stable way to find the script. Plugin files live under a versioned directory that changes with every update, and Claude Code does not put a plugin's `bin/` on the `PATH` of the status line command. The glob picks the highest installed version, so the segment follows `/plugin update` without an edit. If you work from a local checkout, set `yt` to `/bin/ytstack-status` instead. The script reads only `cwd` from the JSON. If your script already knows the directory, `(cd "$dir" && "$yt" /dev/null ( cd "$C" && git config user.email t@t.t && git config user.name t && git config commit.gpgsign false && git checkout -q -b topic ) state "$D" M003 S01 T02 'progress:\n label: V2\n done: 8\n total: 10\n' -( cd "$D" && git add -A && GIT_COMMITTER_DATE="2099-01-01T00:00:00Z" git commit -qm "main state 8" ) >/dev/null 2>&1 +# The refs are compared by ancestry, not by committer date: the origin commit +# is ahead but carries an older timestamp (equal timestamps tie the same way). +( cd "$D" && git add -A && GIT_COMMITTER_DATE="2000-01-01T00:00:00Z" git commit -qm "main state 8" ) >/dev/null 2>&1 git -C "$C" fetch -q origin 2>/dev/null state "$C" M003 S01 T05 '' -eq "clone on a topic branch: newer origin/main wins" "0|V2 80% 8/10 · M003/S01/T05" "$(seg "$C")" +eq "clone on a topic branch: origin/main ahead wins" "0|V2 80% 8/10 · M003/S01/T05" "$(seg "$C")" +( cd "$C" && git checkout -q -f main && git merge -q --ff-only origin/main ) >/dev/null 2>&1 +state "$C" M003 S01 T02 'progress:\n label: V2\n done: 9\n total: 10\n' +( cd "$C" && git add -A && GIT_COMMITTER_DATE="1999-01-01T00:00:00Z" git commit -qm "local main state 9, unpushed" && git checkout -q topic ) >/dev/null 2>&1 +state "$C" M003 S01 T05 '' +eq "clone on a topic branch: unpushed local main wins" "0|V2 90% 9/10 · M003/S01/T05" "$(seg "$C")" # slice count without a block: same source rule as the block. Off the default # branch the slice plan is read from the default ref (PR #32 review); the