claudius-core 0.9.2 → 0.9.5

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 (69) hide show
  1. package/.claude/agents/manager.md +3 -13
  2. package/.claude/agents/worker.md +50 -27
  3. package/.claude/rules/testing.md +7 -4
  4. package/.claude/scripts/merge-pr.sh +44 -57
  5. package/.claude/scripts/project-status.sh +8 -8
  6. package/.claude/skills/build/SKILL.md +3 -17
  7. package/.claude-plugin/marketplace.json +2 -2
  8. package/dist/lib/db.d.ts +30 -0
  9. package/dist/lib/db.d.ts.map +1 -0
  10. package/dist/lib/db.js +71 -0
  11. package/dist/lib/db.js.map +1 -0
  12. package/dist/lib/slack.d.ts +33 -0
  13. package/dist/lib/slack.d.ts.map +1 -0
  14. package/dist/lib/slack.js +79 -0
  15. package/dist/lib/slack.js.map +1 -0
  16. package/dist/studio/assets/{_basePickBy-DTKKNeX9.js → _basePickBy-BPyGSyjX.js} +1 -1
  17. package/dist/studio/assets/{_baseUniq-DY6ysp5o.js → _baseUniq-COXavBWr.js} +1 -1
  18. package/dist/studio/assets/{arc-Cy2QeHNO.js → arc-C6u7rWiy.js} +1 -1
  19. package/dist/studio/assets/{architectureDiagram-VXUJARFQ-D2MQHSaG.js → architectureDiagram-VXUJARFQ-CdgRZem0.js} +1 -1
  20. package/dist/studio/assets/{blockDiagram-VD42YOAC-Do1dNJrU.js → blockDiagram-VD42YOAC-Dzy--0Bk.js} +1 -1
  21. package/dist/studio/assets/{c4Diagram-YG6GDRKO-VcgRH2n1.js → c4Diagram-YG6GDRKO-CymHroyB.js} +1 -1
  22. package/dist/studio/assets/channel-DA6Vd3mS.js +1 -0
  23. package/dist/studio/assets/{chunk-4BX2VUAB-CkVBwsYG.js → chunk-4BX2VUAB-DNgeunAs.js} +1 -1
  24. package/dist/studio/assets/{chunk-55IACEB6-Djaa2sKP.js → chunk-55IACEB6-B9L9utip.js} +1 -1
  25. package/dist/studio/assets/{chunk-B4BG7PRW-Biwf9931.js → chunk-B4BG7PRW-mYytHwg8.js} +1 -1
  26. package/dist/studio/assets/{chunk-DI55MBZ5-PcotdTmK.js → chunk-DI55MBZ5-B_htrqq2.js} +1 -1
  27. package/dist/studio/assets/{chunk-FMBD7UC4-BxcM28ip.js → chunk-FMBD7UC4-De68-v5Z.js} +1 -1
  28. package/dist/studio/assets/{chunk-QN33PNHL-su83dkHq.js → chunk-QN33PNHL-BDHmOaWb.js} +1 -1
  29. package/dist/studio/assets/{chunk-QZHKN3VN-CXC633WZ.js → chunk-QZHKN3VN-CI4b_NjC.js} +1 -1
  30. package/dist/studio/assets/{chunk-TZMSLE5B-0zWkhgbg.js → chunk-TZMSLE5B-eE5xjTIx.js} +1 -1
  31. package/dist/studio/assets/classDiagram-2ON5EDUG-0FJ62Ib2.js +1 -0
  32. package/dist/studio/assets/classDiagram-v2-WZHVMYZB-0FJ62Ib2.js +1 -0
  33. package/dist/studio/assets/clone-BNX5khHw.js +1 -0
  34. package/dist/studio/assets/{cose-bilkent-S5V4N54A-DMQUn4Kn.js → cose-bilkent-S5V4N54A-CliUCU0O.js} +1 -1
  35. package/dist/studio/assets/{dagre-6UL2VRFP-BCrjX16f.js → dagre-6UL2VRFP-Euc9DolX.js} +1 -1
  36. package/dist/studio/assets/{diagram-PSM6KHXK-B0cHphWd.js → diagram-PSM6KHXK-wFCVz4Gf.js} +1 -1
  37. package/dist/studio/assets/{diagram-QEK2KX5R-BBvDN4Uv.js → diagram-QEK2KX5R-DW3TEVRg.js} +1 -1
  38. package/dist/studio/assets/{diagram-S2PKOQOG-CEl3flTh.js → diagram-S2PKOQOG-sRtmdfLP.js} +1 -1
  39. package/dist/studio/assets/{erDiagram-Q2GNP2WA-DKjjFIwQ.js → erDiagram-Q2GNP2WA-DhFEzcCs.js} +1 -1
  40. package/dist/studio/assets/{flowDiagram-NV44I4VS-BnnKOs8q.js → flowDiagram-NV44I4VS-DkGukznd.js} +1 -1
  41. package/dist/studio/assets/{ganttDiagram-JELNMOA3-BtcVr8xh.js → ganttDiagram-JELNMOA3-DWK7W0Dy.js} +1 -1
  42. package/dist/studio/assets/{gitGraphDiagram-V2S2FVAM-Cobid_XV.js → gitGraphDiagram-V2S2FVAM-BOCSCk6Z.js} +1 -1
  43. package/dist/studio/assets/{graph-Do6IuvE7.js → graph-BZL6SCOn.js} +1 -1
  44. package/dist/studio/assets/{index-P-gEEMhX.js → index-DheMq1DW.js} +2 -2
  45. package/dist/studio/assets/{infoDiagram-HS3SLOUP-CQzNDF01.js → infoDiagram-HS3SLOUP-DgPXbZVx.js} +1 -1
  46. package/dist/studio/assets/{journeyDiagram-XKPGCS4Q-BDWkdVsn.js → journeyDiagram-XKPGCS4Q-6xUT6AF4.js} +1 -1
  47. package/dist/studio/assets/{kanban-definition-3W4ZIXB7-Rwi_9qIm.js → kanban-definition-3W4ZIXB7-Dsvw_JdF.js} +1 -1
  48. package/dist/studio/assets/{layout-s7Ye3uwS.js → layout-DwiaZVEi.js} +1 -1
  49. package/dist/studio/assets/{linear-VKXk51SR.js → linear-B7fbgRMt.js} +1 -1
  50. package/dist/studio/assets/{mermaid.core-n8jibXOy.js → mermaid.core-wwLvzRgL.js} +4 -4
  51. package/dist/studio/assets/{mindmap-definition-VGOIOE7T-0VU8hCXF.js → mindmap-definition-VGOIOE7T-BIvanpwK.js} +1 -1
  52. package/dist/studio/assets/{pieDiagram-ADFJNKIX-D5aZDoXC.js → pieDiagram-ADFJNKIX-83imZrxP.js} +1 -1
  53. package/dist/studio/assets/{quadrantDiagram-AYHSOK5B-BlCmM4Qj.js → quadrantDiagram-AYHSOK5B-DHQawHwC.js} +1 -1
  54. package/dist/studio/assets/{requirementDiagram-UZGBJVZJ-DWUiTFOB.js → requirementDiagram-UZGBJVZJ-CJ8omiFk.js} +1 -1
  55. package/dist/studio/assets/{sankeyDiagram-TZEHDZUN-5DOpYn4g.js → sankeyDiagram-TZEHDZUN-DaO3BTC3.js} +1 -1
  56. package/dist/studio/assets/{sequenceDiagram-WL72ISMW-DNyOZZgz.js → sequenceDiagram-WL72ISMW-BaOOCdTf.js} +1 -1
  57. package/dist/studio/assets/{stateDiagram-FKZM4ZOC-BKuyFb4H.js → stateDiagram-FKZM4ZOC-BAmqIsET.js} +1 -1
  58. package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-BvS1aYAB.js +1 -0
  59. package/dist/studio/assets/{timeline-definition-IT6M3QCI-D_pEYPv6.js → timeline-definition-IT6M3QCI-BNMgBtHo.js} +1 -1
  60. package/dist/studio/assets/{treemap-GDKQZRPO-BF7TAkhx.js → treemap-GDKQZRPO-BFdbo85g.js} +1 -1
  61. package/dist/studio/assets/{xychartDiagram-PRI3JC2R-9k8KhSr3.js → xychartDiagram-PRI3JC2R-CTgS6W_y.js} +1 -1
  62. package/dist/studio/index.html +1 -1
  63. package/global/rules/global.md +2 -0
  64. package/package.json +1 -1
  65. package/dist/studio/assets/channel-q76EBT3W.js +0 -1
  66. package/dist/studio/assets/classDiagram-2ON5EDUG-DbZNbgXY.js +0 -1
  67. package/dist/studio/assets/classDiagram-v2-WZHVMYZB-DbZNbgXY.js +0 -1
  68. package/dist/studio/assets/clone-Cp4ZNmLY.js +0 -1
  69. package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-WOR4RPG7.js +0 -1
@@ -17,7 +17,7 @@ When asked who you are: "I am the Claudius manager. I route work, coordinate age
17
17
  2. Decide solo (XS/S) vs team (M+) based on scope
18
18
  3. Create feature branch from main — **unless already in a worktree** (see Branch Convention)
19
19
  4. For solo: implement directly with TDD
20
- 5. For team: spawn developer via Agent tool, then simplifier (best-effort), then reviewer
20
+ 5. For team: spawn developer via Agent tool, then reviewer
21
21
  6. **Validate before PR** — `bun test && bun run lint && bun run build` must all pass. Fix failures before creating PR. Never create a PR with known lint or build failures.
22
22
  7. Create PR
23
23
  8. Update issue checkboxes as criteria are met
@@ -43,19 +43,9 @@ Use the Agent tool with `subagent_type: "developer"`. Include in the prompt:
43
43
  - The constraint: only implement what's asked, no scope creep
44
44
  - **Reminder: developer must run `bun test`, `bun run lint`, and `bun run build` before pushing**
45
45
 
46
- The developer runs in an isolated worktree, implements via TDD, validates (test + lint + build), and returns its output. After it completes, verify the developer reported all three validations passing, then spawn the simplifier (best-effort), then create the PR: `gh pr create`. Only spawn the reviewer after the PR exists.
46
+ The developer runs in an isolated worktree, implements via TDD, validates (test + lint + build), and returns its output. After it completes, verify the developer reported all three validations passing, then create the PR: `gh pr create`.
47
47
 
48
- **Simplifier** (for M+ work, after developer completes and before reviewer):
49
- Use the Agent tool with `subagent_type: "general-purpose"` and `agent: "code-simplifier"`. Include in the prompt:
50
- - The git diff of all changes so far: output of `git diff main...HEAD`
51
- - The original issue acceptance criteria
52
- - Project conventions: contents of CLAUDE.md
53
- - Instruction: reduce complexity, improve reuse, fix quality issues — without changing behavior or adding new features
54
- - Constraint: only touch files already changed on this branch (visible in the diff above)
55
-
56
- The simplifier is **non-blocking**: if it returns no changes, errors, or is unavailable, log the outcome and continue to the reviewer. Never let the simplifier halt the pipeline.
57
-
58
- **Reviewer** (for M+ work, after simplifier completes and PR is created):
48
+ **Reviewer** (for M+ work, after PR is created):
59
49
  Use the Agent tool with `subagent_type: "reviewer"`. Include in the prompt:
60
50
  - The PR number to review
61
51
  - Return structured verdict: approve / request-changes / block
@@ -41,7 +41,6 @@ gh pr list --search "Closes #<N> in:body" --state open --json number --limit 1
41
41
  If no open PR found → stale claim → restore to ready:
42
42
  ```bash
43
43
  gh issue edit <N> --remove-label "in-progress,claude" --add-label "ready"
44
- bash .claude/scripts/project-status.sh <N> "Todo" "Queued"
45
44
  ```
46
45
 
47
46
  ## Guard Checks
@@ -63,26 +62,11 @@ tail -20 .claudius/job-runs.jsonl
63
62
  Before picking new work, merge any open XS/S/M PRs with passing CI:
64
63
 
65
64
  ```bash
66
- gh pr list --json number,title,headRefName,statusCheckRollup,mergeable --limit 20
65
+ gh pr list --json number,title,headRefName,statusCheckRollup --limit 20
66
+ bash .claude/scripts/merge-pr.sh <N>
67
+ gh issue close <issue-N> --comment "Closed by PR #<N>."
67
68
  ```
68
69
 
69
- For each PR with all checks passing:
70
- 1. **Check mergeability** — if `mergeable` is `CONFLICTING`, try rebasing first:
71
- ```bash
72
- gh pr view <N> --json mergeable --jq '.mergeable'
73
- # If CONFLICTING → attempt rebase:
74
- git fetch origin main
75
- git checkout <branch>
76
- git rebase origin/main
77
- git push --force-with-lease
78
- # If rebase fails: skip this PR, leave for human or next cycle
79
- ```
80
- 2. **Merge** — only if mergeable:
81
- ```bash
82
- bash .claude/scripts/merge-pr.sh <N>
83
- gh issue close <issue-N> --comment "Closed by PR #<N>."
84
- ```
85
-
86
70
  ## Step 2: Pick Top-3 Issues
87
71
 
88
72
  ```bash
@@ -113,7 +97,13 @@ PRIOR_ATTEMPTS=$(gh issue view <N> --json comments \
113
97
  if [ "${PRIOR_ATTEMPTS:-0}" -ge "$MAX_ATTEMPTS" ]; then
114
98
  gh issue edit <N> --remove-label "ready" --add-label "blocked"
115
99
  gh issue comment <N> --body "Claudius: exceeded ${MAX_ATTEMPTS} build attempts. Needs human review before retrying."
116
- bash .claude/scripts/project-status.sh <N> "Blocked" "Blocked"
100
+ REPO_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
101
+ ITEM_ID=$(gh api graphql -f query='{user(login:"SharadKumar"){projectV2(number:6){items(first:100){nodes{id content{...on Issue{number repository{nameWithOwner}}}}}}}}' \
102
+ --jq ".data.user.projectV2.items.nodes[] | select(.content.number == <N> and .content.repository.nameWithOwner == \"$REPO_NAME\") | .id" 2>/dev/null | head -1)
103
+ [ -n "$ITEM_ID" ] && gh project item-edit --id "$ITEM_ID" \
104
+ --project-id "PVT_kwHOAFO-EM4BRTW5" \
105
+ --field-id "PVTSSF_lAHOAFO-EM4BRTW5zg_K3tE" \
106
+ --single-select-option-id "d239ddb3" 2>/dev/null || true
117
107
  # skip this issue — continue to next candidate
118
108
  fi
119
109
  ```
@@ -133,9 +123,18 @@ NEW_ATTEMPTS=$(( ${PRIOR_ATTEMPTS:-0} + 1 ))
133
123
  bash .claude/scripts/workpad-upsert.sh <N> "🔄 Claimed — reading issue" "TBD" "- [ ] (loading)" "pending" "$NEW_ATTEMPTS"
134
124
  ```
135
125
 
136
- **Update Project #6 → In Progress / Running** (best-effort):
126
+ **Update Project #6 Status → In Progress** add to project if needed, then set status:
127
+
137
128
  ```bash
138
- bash .claude/scripts/project-status.sh <N> "In Progress" "Running"
129
+ ISSUE_URL=$(gh issue view <N> --json url --jq '.url')
130
+ REPO_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
131
+ gh project item-add 6 --owner SharadKumar --url "$ISSUE_URL" 2>/dev/null || true
132
+ ITEM_ID=$(gh api graphql -f query='{user(login:"SharadKumar"){projectV2(number:6){items(first:100){nodes{id content{...on Issue{number repository{nameWithOwner}}}}}}}}' \
133
+ --jq ".data.user.projectV2.items.nodes[] | select(.content.number == <N> and .content.repository.nameWithOwner == \"$REPO_NAME\") | .id" 2>/dev/null | head -1)
134
+ [ -n "$ITEM_ID" ] && gh project item-edit --id "$ITEM_ID" \
135
+ --project-id "PVT_kwHOAFO-EM4BRTW5" \
136
+ --field-id "PVTSSF_lAHOAFO-EM4BRTW5zg_K3tE" \
137
+ --single-select-option-id "0d583361" 2>/dev/null || true
139
138
  ```
140
139
 
141
140
  ## Step 3: Develop in Parallel
@@ -178,7 +177,6 @@ Wait for all developer agents to complete before proceeding.
178
177
  ```bash
179
178
  gh issue edit <N> --remove-label "in-progress,claude" --add-label "ready"
180
179
  gh issue comment <N> --body "Worker: developer failed. Restored to ready queue."
181
- bash .claude/scripts/project-status.sh <N> "Todo" "Queued"
182
180
  ```
183
181
  Remove it from the active set and continue with the rest.
184
182
 
@@ -246,9 +244,15 @@ if [ -n "$SLACK_CHANNEL" ]; then
246
244
  fi
247
245
  ```
248
246
 
249
- **Update Project #6 → Under Review / Review** (best-effort):
247
+ **Update Project #6 Status → Under Review** (best-effort):
250
248
  ```bash
251
- bash .claude/scripts/project-status.sh <N> "Under Review" "Review"
249
+ REPO_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
250
+ ITEM_ID=$(gh api graphql -f query='{user(login:"SharadKumar"){projectV2(number:6){items(first:100){nodes{id content{...on Issue{number repository{nameWithOwner}}}}}}}}' \
251
+ --jq ".data.user.projectV2.items.nodes[] | select(.content.number == <N> and .content.repository.nameWithOwner == \"$REPO_NAME\") | .id" 2>/dev/null | head -1)
252
+ [ -n "$ITEM_ID" ] && gh project item-edit --id "$ITEM_ID" \
253
+ --project-id "PVT_kwHOAFO-EM4BRTW5" \
254
+ --field-id "PVTSSF_lAHOAFO-EM4BRTW5zg_K3tE" \
255
+ --single-select-option-id "173633ca" 2>/dev/null || true
252
256
  ```
253
257
 
254
258
  ## Step 5: Review in Parallel
@@ -272,7 +276,17 @@ Wait for all reviewer agents to complete.
272
276
  ```bash
273
277
  gh issue edit <N> --remove-label "in-progress,claude" --add-label "ready"
274
278
  gh issue comment <N> --body "Worker: reviewer blocked. Reason: <reason>."
275
- bash .claude/scripts/project-status.sh <N> "Todo" "Queued"
279
+ ```
280
+
281
+ **Update Project #6 Status → Blocked** (best-effort):
282
+ ```bash
283
+ REPO_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
284
+ ITEM_ID=$(gh api graphql -f query='{user(login:"SharadKumar"){projectV2(number:6){items(first:100){nodes{id content{...on Issue{number repository{nameWithOwner}}}}}}}}' \
285
+ --jq ".data.user.projectV2.items.nodes[] | select(.content.number == <N> and .content.repository.nameWithOwner == \"$REPO_NAME\") | .id" 2>/dev/null | head -1)
286
+ [ -n "$ITEM_ID" ] && gh project item-edit --id "$ITEM_ID" \
287
+ --project-id "PVT_kwHOAFO-EM4BRTW5" \
288
+ --field-id "PVTSSF_lAHOAFO-EM4BRTW5zg_K3tE" \
289
+ --single-select-option-id "d239ddb3" 2>/dev/null || true
276
290
  ```
277
291
 
278
292
  ## Step 6: Merge & Record
@@ -283,7 +297,16 @@ bash .claude/scripts/merge-pr.sh <PR-number>
283
297
  gh issue close <N> --comment "Closed by PR #<M>."
284
298
  ```
285
299
 
286
- Closing the issue removes it from the active Project #6 board no explicit "Done" status needed.
300
+ **Update Project #6 Status Done** (best-effort):
301
+ ```bash
302
+ REPO_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
303
+ ITEM_ID=$(gh api graphql -f query='{user(login:"SharadKumar"){projectV2(number:6){items(first:100){nodes{id content{...on Issue{number repository{nameWithOwner}}}}}}}}' \
304
+ --jq ".data.user.projectV2.items.nodes[] | select(.content.number == <N> and .content.repository.nameWithOwner == \"$REPO_NAME\") | .id" 2>/dev/null | head -1)
305
+ [ -n "$ITEM_ID" ] && gh project item-edit --id "$ITEM_ID" \
306
+ --project-id "PVT_kwHOAFO-EM4BRTW5" \
307
+ --field-id "PVTSSF_lAHOAFO-EM4BRTW5zg_K3tE" \
308
+ --single-select-option-id "b60a81d0" 2>/dev/null || true
309
+ ```
287
310
 
288
311
  After each merge, reply in the PR's Slack thread (best-effort):
289
312
  ```bash
@@ -25,17 +25,20 @@ Every change that can be tested locally MUST be tested locally before committing
25
25
 
26
26
  ### dist/ freshness
27
27
 
28
- `dist/` is gitignored and built at install time via the `prepare` script. Do NOT commit `dist/` it is a build artifact.
28
+ `dist/` is committed to the repo. The `prepare` script skips building when `dist/` already exists. This means stale `dist/` = users run old code.
29
29
 
30
- **After changing any `src/` file, always verify the build succeeds:**
30
+ **After changing any `src/` file, always rebuild and commit dist/:**
31
31
  ```bash
32
- bun run build
32
+ bun run build:server
33
+ git add dist/
33
34
  ```
34
35
 
36
+ If you forget, `npx github:SharadKumar/claudius` will silently run old code — the most dangerous kind of bug.
37
+
35
38
  ### Anti-patterns
36
39
 
37
40
  - Committing install commands without testing them in the target environment
38
41
  - Assuming package managers behave identically (they don't — especially for private repos, workspaces, lockfiles)
39
42
  - Shipping a fix for a fix for a fix instead of reverting and getting it right once
40
43
  - Trusting `bun run build` as sufficient validation when the change is user-facing
41
- - Committing `dist/` it is gitignored and built at install time
44
+ - Changing `src/` without rebuilding and committing `dist/`
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env bash
2
- # merge-pr.sh — Worktree-safe PR merge.
2
+ # merge-pr.sh — Robust PR merge that works regardless of CWD or worktree state.
3
3
  #
4
4
  # Usage: bash .claude/scripts/merge-pr.sh <PR-number>
5
5
  #
6
6
  # Behavior:
7
- # - From a worktree: API-only merge. NEVER touches the main checkout.
8
- # - From the main checkout: gh pr merge with fallback to API merge.
7
+ # 1. Resolve the main repo root via git-common-dir (CWD-agnostic)
8
+ # 2. cd to main root before any git/gh operations
9
+ # 3. Try gh pr merge (happy path — works when main is not checked out elsewhere)
10
+ # 4. On failure, fall back to GitHub API merge + remote branch deletion
11
+ # 5. Sync home branch inline (no external script dependency)
9
12
  #
10
- # Exit codes: 0 = merged, 1 = merge failed
13
+ # Exit codes: 0 = merged + synced, 1 = merge failed, 2 = sync failed
11
14
 
12
15
  set -euo pipefail
13
16
 
@@ -17,23 +20,25 @@ if [[ -z "$PR" ]]; then
17
20
  exit 1
18
21
  fi
19
22
 
20
- # Detect context BEFORE any cd
21
- ORIGINAL_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
22
- IN_WORKTREE=false
23
- if [[ "$ORIGINAL_GIT_DIR" == */.git/worktrees/* ]] || [[ "$ORIGINAL_GIT_DIR" == */worktrees/* ]]; then
24
- IN_WORKTREE=true
25
- fi
23
+ # Resolve main repo root — works from any CWD (worktree, subdir, main checkout)
24
+ GIT_COMMON_DIR=$(git rev-parse --git-common-dir 2>/dev/null)
25
+ MAIN_ROOT=$(cd "$(git rev-parse --show-toplevel)" && cd "$(git rev-parse --git-common-dir)/.." && pwd)
26
+
27
+ cd "$MAIN_ROOT"
26
28
 
27
- # Get PR metadata (works from any context)
29
+ # Get branch name before merging (needed for API fallback cleanup)
28
30
  BRANCH=$(gh pr view "$PR" --json headRefName --jq '.headRefName' 2>/dev/null)
29
31
  REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null)
30
32
 
31
33
  echo "Merging PR #$PR ($BRANCH) in $REPO..."
32
34
 
33
- if $IN_WORKTREE; then
34
- # --- WORKTREE PATH ---
35
- # CRITICAL: Never cd to main checkout. Never run git checkout.
36
- # Use GitHub API only — zero local branch operations.
35
+ # Happy path: gh pr merge handles everything locally
36
+ if gh pr merge "$PR" --squash --delete-branch 2>/dev/null; then
37
+ echo "Merged via gh pr merge."
38
+ else
39
+ echo "gh pr merge failed (likely worktree conflict) — falling back to API merge..."
40
+
41
+ # API merge
37
42
  TITLE=$(gh pr view "$PR" --json title --jq '.title')
38
43
  gh api "repos/$REPO/pulls/$PR/merge" \
39
44
  -X PUT \
@@ -41,52 +46,34 @@ if $IN_WORKTREE; then
41
46
  -f commit_title="$TITLE" \
42
47
  --silent
43
48
 
44
- echo "Merged via API (worktree-safe)."
45
-
46
- # Delete remote branch via API (no local git operations)
47
- gh api "repos/$REPO/git/refs/heads/$BRANCH" -X DELETE --silent 2>/dev/null \
48
- && echo "Deleted remote branch: $BRANCH" \
49
- || echo "⚠ Could not delete remote branch: $BRANCH"
50
-
51
- # Fetch latest main (doesn't change any local branch)
52
- git fetch origin main 2>/dev/null || true
53
-
54
- else
55
- # --- MAIN CHECKOUT PATH ---
56
- # Save current branch to restore after merge
57
- SAVED_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
58
-
59
- # Try gh pr merge (happy path)
60
- if gh pr merge "$PR" --squash --delete-branch 2>/dev/null; then
61
- echo "Merged via gh pr merge."
62
- else
63
- echo "gh pr merge failed — falling back to API merge..."
49
+ echo "Merged via API."
64
50
 
65
- TITLE=$(gh pr view "$PR" --json title --jq '.title')
66
- gh api "repos/$REPO/pulls/$PR/merge" \
67
- -X PUT \
68
- -f merge_method=squash \
69
- -f commit_title="$TITLE" \
70
- --silent
51
+ # Delete remote branch
52
+ if git ls-remote --exit-code origin "$BRANCH" &>/dev/null; then
53
+ git push origin --delete "$BRANCH" 2>/dev/null && echo "Deleted remote branch: $BRANCH" || echo "⚠ Could not delete remote branch: $BRANCH"
54
+ fi
55
+ fi
71
56
 
72
- echo "Merged via API."
57
+ # Re-anchor to main root (gh pr merge may change CWD)
58
+ cd "$MAIN_ROOT"
73
59
 
74
- # Delete remote branch
75
- if git ls-remote --exit-code origin "$BRANCH" &>/dev/null; then
76
- git push origin --delete "$BRANCH" 2>/dev/null \
77
- && echo "Deleted remote branch: $BRANCH" \
78
- || echo "⚠ Could not delete remote branch: $BRANCH"
79
- fi
80
- fi
60
+ # Inline sync: return to home branch
61
+ # Detect if this script was invoked from a worktree context
62
+ GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
81
63
 
82
- # Sync main
64
+ if [[ "$GIT_DIR" == */.git/worktrees/* ]]; then
65
+ WORKTREE_NAME=$(basename "$GIT_DIR")
66
+ HOME_BRANCH="worktree-$WORKTREE_NAME"
67
+ git checkout "$HOME_BRANCH" 2>/dev/null || true
68
+ echo "Returned to home branch: $HOME_BRANCH"
69
+ else
70
+ # Root repo — return to main and sync
83
71
  git checkout main 2>/dev/null || true
84
- git pull --ff-only origin main 2>/dev/null || {
85
- echo "main has diverged — fast-forward not possible."
86
- }
87
-
88
- # Restore original branch if it still exists and wasn't the merged branch
89
- if [[ -n "$SAVED_BRANCH" ]] && [[ "$SAVED_BRANCH" != "$BRANCH" ]] && [[ "$SAVED_BRANCH" != "main" ]]; then
90
- git checkout "$SAVED_BRANCH" 2>/dev/null || true
72
+ if git pull --ff-only origin main 2>/dev/null; then
73
+ echo "main synced to latest."
74
+ else
75
+ echo "⚠ main has diverged from origin/main — fast-forward not possible."
76
+ echo " Resolve manually: git fetch origin && git rebase origin/main"
77
+ exit 2
91
78
  fi
92
79
  fi
@@ -22,19 +22,19 @@ EXECUTION_FIELD="PVTSSF_lAHOAFO-EM4BRTW5zg_Lokk"
22
22
 
23
23
  # Resolve Status option ID
24
24
  case "$STATUS" in
25
- "Todo") STATUS_OPT="6ed537f9" ;;
26
- "In Progress") STATUS_OPT="0d583361" ;;
27
- "Under Review") STATUS_OPT="173633ca" ;;
28
- "Blocked") STATUS_OPT="d239ddb3" ;;
25
+ "Todo") STATUS_OPT="59debf59" ;;
26
+ "In Progress") STATUS_OPT="6e8991c5" ;;
27
+ "Under Review") STATUS_OPT="a6a6dc32" ;;
28
+ "Blocked") STATUS_OPT="f77fb75d" ;;
29
29
  *) echo "[project-status] Unknown status: $STATUS" >&2; exit 1 ;;
30
30
  esac
31
31
 
32
32
  # Resolve Execution option ID
33
33
  case "$EXECUTION" in
34
- "Queued") EXECUTION_OPT="f00eea4e" ;;
35
- "Running") EXECUTION_OPT="14585208" ;;
36
- "Review") EXECUTION_OPT="8e0939cc" ;;
37
- "Blocked") EXECUTION_OPT="65e212b0" ;;
34
+ "Queued") EXECUTION_OPT="b2b4bd91" ;;
35
+ "Running") EXECUTION_OPT="e632d881" ;;
36
+ "Review") EXECUTION_OPT="4098f421" ;;
37
+ "Blocked") EXECUTION_OPT="70bc5d52" ;;
38
38
  *) echo "[project-status] Unknown execution: $EXECUTION" >&2; exit 1 ;;
39
39
  esac
40
40
 
@@ -105,23 +105,9 @@ Also read: `.claudius/design/tokens.css` for token values, `.claudius/design/com
105
105
  1. Write failing test from first acceptance criterion
106
106
  2. Implement until test passes
107
107
  3. Repeat for each AC
108
- 4. Invoke `/simplify` on the changed files to reduce complexity before validating (best-effort: if it returns no changes or errors, log and continue)
109
- 5. Run full suite: `bun test`
110
-
111
- **Team (M+ — >2 files, >100 lines):** Use the Agent tool to spawn developer, simplifier, and reviewer agents in sequence.
112
-
113
- 1. **Spawn builder** — developer agent implements the issue with TDD (full cycle: failing tests → implementation → passing tests)
114
- 2. **Spawn simplifier** — after builder completes, spawn the `code-simplifier` agent (best-effort: if it returns no changes or errors, log and continue to reviewer):
115
- ```
116
- Agent tool, subagent_type: general-purpose, agent: code-simplifier
117
- Prompt:
118
- <git diff of all changes: `git diff main...HEAD`>
119
- <original issue ACs>
120
- Project conventions: see CLAUDE.md
121
- Task: Reduce complexity, improve reuse, fix quality issues — without changing behavior or adding new features.
122
- Constraint: Only touch files already changed on this branch (visible in the diff above).
123
- ```
124
- 3. **Spawn reviewer** — reviewer agent runs quality gate after simplifier completes (or after simplifier is skipped due to error)
108
+ 4. Run full suite: `bun test`
109
+
110
+ **Team (M+ — >2 files, >100 lines):** Use the Agent tool to spawn developer and reviewer agents.
125
111
 
126
112
  ### 5. Validate
127
113
 
@@ -21,10 +21,10 @@
21
21
  "name": "claudius",
22
22
  "source": "./",
23
23
  "description": "Autonomous orchestration layer for Claude Code — agents, skills, hooks, and heartbeat daemon for round-the-clock development",
24
- "version": "0.9.2",
24
+ "version": "0.9.5",
25
25
  "strict": true,
26
26
  "category": "development"
27
27
  }
28
28
  ],
29
- "version": "0.9.2"
29
+ "version": "0.9.5"
30
30
  }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Generic local store — Convex-ready interface.
3
+ *
4
+ * Interface mirrors Convex query/mutation shape:
5
+ * - namespace = table name
6
+ * - key = document id
7
+ *
8
+ * Backed by `.claudius/db.json` with atomic writes (tmp + rename) so the
9
+ * file is always valid JSON even if the process is killed mid-write.
10
+ *
11
+ * Swap path: replace `createDb` with a Convex adapter that implements the
12
+ * same `Db` interface — callers don't change.
13
+ */
14
+ /** Convex-compatible store interface. */
15
+ export interface Db {
16
+ /** Read a document by namespace (table) and key (doc id). */
17
+ get<T = unknown>(namespace: string, key: string): T | undefined;
18
+ /** Write a document. Overwrites if it already exists. */
19
+ set(namespace: string, key: string, value: unknown): void;
20
+ /** Delete a document. No-op if it doesn't exist. */
21
+ del(namespace: string, key: string): void;
22
+ }
23
+ /**
24
+ * Create a `Db` instance scoped to `projectDir`.
25
+ *
26
+ * @param projectDir - root of the project (where `.claudius/` lives).
27
+ * Defaults to `"."` (current working directory).
28
+ */
29
+ export declare function createDb(projectDir?: string): Db;
30
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,yCAAyC;AACzC,MAAM,WAAW,EAAE;IAClB,6DAA6D;IAC7D,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAChE,yDAAyD;IACzD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1D,oDAAoD;IACpD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAiCD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,UAAU,SAAM,GAAG,EAAE,CAqB7C"}
package/dist/lib/db.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Generic local store — Convex-ready interface.
3
+ *
4
+ * Interface mirrors Convex query/mutation shape:
5
+ * - namespace = table name
6
+ * - key = document id
7
+ *
8
+ * Backed by `.claudius/db.json` with atomic writes (tmp + rename) so the
9
+ * file is always valid JSON even if the process is killed mid-write.
10
+ *
11
+ * Swap path: replace `createDb` with a Convex adapter that implements the
12
+ * same `Db` interface — callers don't change.
13
+ */
14
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
15
+ import { dirname, resolve } from "node:path";
16
+ const DB_FILENAME = ".claudius/db.json";
17
+ function dbPath(projectDir) {
18
+ return resolve(projectDir, DB_FILENAME);
19
+ }
20
+ function read(projectDir) {
21
+ const path = dbPath(projectDir);
22
+ if (!existsSync(path))
23
+ return {};
24
+ try {
25
+ return JSON.parse(readFileSync(path, "utf-8"));
26
+ }
27
+ catch {
28
+ return {};
29
+ }
30
+ }
31
+ function write(projectDir, store) {
32
+ const path = dbPath(projectDir);
33
+ const dir = dirname(path);
34
+ if (!existsSync(dir)) {
35
+ mkdirSync(dir, { recursive: true });
36
+ }
37
+ // Atomic write: write to tmp then rename.
38
+ // pid + random suffix prevents collisions under concurrent writes.
39
+ const tmp = `${path}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;
40
+ writeFileSync(tmp, JSON.stringify(store, null, 2));
41
+ renameSync(tmp, path);
42
+ }
43
+ /**
44
+ * Create a `Db` instance scoped to `projectDir`.
45
+ *
46
+ * @param projectDir - root of the project (where `.claudius/` lives).
47
+ * Defaults to `"."` (current working directory).
48
+ */
49
+ export function createDb(projectDir = ".") {
50
+ return {
51
+ get(namespace, key) {
52
+ const store = read(projectDir);
53
+ return store[namespace]?.[key] ?? undefined;
54
+ },
55
+ set(namespace, key, value) {
56
+ const store = read(projectDir);
57
+ if (!store[namespace])
58
+ store[namespace] = {};
59
+ store[namespace][key] = value;
60
+ write(projectDir, store);
61
+ },
62
+ del(namespace, key) {
63
+ const store = read(projectDir);
64
+ if (!store[namespace])
65
+ return;
66
+ delete store[namespace][key];
67
+ write(projectDir, store);
68
+ },
69
+ };
70
+ }
71
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAc7C,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAExC,SAAS,MAAM,CAAC,UAAkB;IACjC,OAAO,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,IAAI,CAAC,UAAkB;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAU,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED,SAAS,KAAK,CAAC,UAAkB,EAAE,KAAY;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,0CAA0C;IAC1C,mEAAmE;IACnE,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,UAAU,GAAG,GAAG;IACxC,OAAO;QACN,GAAG,CAAc,SAAiB,EAAE,GAAW;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,OAAQ,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAO,IAAI,SAAS,CAAC;QACpD,CAAC;QAED,GAAG,CAAC,SAAiB,EAAE,GAAW,EAAE,KAAc;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YAC7C,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC9B,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;QAED,GAAG,CAAC,SAAiB,EAAE,GAAW;YACjC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,OAAO;YAC9B,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC;YAC7B,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Slack PR notification layer.
3
+ *
4
+ * Announces PRs as channel messages and routes all follow-up activity
5
+ * (approvals, merges, CI failures) as thread replies on the original post.
6
+ *
7
+ * Thread timestamps are persisted via the `Db` store under the
8
+ * `slack_threads` namespace so they survive process restarts.
9
+ *
10
+ * Environment variables:
11
+ * SLACK_BOT_TOKEN — required; xoxb-… bot token
12
+ * SLACK_CHANNEL — required; channel ID (C123…) or name
13
+ */
14
+ import type { Db } from "./db.js";
15
+ export interface SlackNotifier {
16
+ /**
17
+ * Post a new channel message announcing PR creation.
18
+ * Stores the message timestamp in db for thread replies.
19
+ */
20
+ postPR(prNumber: number, title: string, url: string): Promise<void>;
21
+ /**
22
+ * Reply to the original PR announcement thread.
23
+ * No-ops if no thread is found in db or if Slack is unconfigured.
24
+ */
25
+ replyPR(prNumber: number, text: string): Promise<void>;
26
+ }
27
+ /**
28
+ * Create a `SlackNotifier` backed by the given `Db` instance.
29
+ *
30
+ * @param db - db instance for persisting thread timestamps.
31
+ */
32
+ export declare function createSlack(db: Db): SlackNotifier;
33
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/lib/slack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AA4ClC,MAAM,WAAW,aAAa;IAC7B;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,aAAa,CA+BjD"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Slack PR notification layer.
3
+ *
4
+ * Announces PRs as channel messages and routes all follow-up activity
5
+ * (approvals, merges, CI failures) as thread replies on the original post.
6
+ *
7
+ * Thread timestamps are persisted via the `Db` store under the
8
+ * `slack_threads` namespace so they survive process restarts.
9
+ *
10
+ * Environment variables:
11
+ * SLACK_BOT_TOKEN — required; xoxb-… bot token
12
+ * SLACK_CHANNEL — required; channel ID (C123…) or name
13
+ */
14
+ const SLACK_API = "https://slack.com/api/chat.postMessage";
15
+ const NAMESPACE = "slack_threads";
16
+ function getConfig() {
17
+ const token = process.env.SLACK_BOT_TOKEN;
18
+ const channel = process.env.SLACK_CHANNEL;
19
+ if (!token || !channel)
20
+ return null;
21
+ return { token, channel };
22
+ }
23
+ async function post(token, channel, text, threadTs) {
24
+ const body = { channel, text };
25
+ if (threadTs)
26
+ body.thread_ts = threadTs;
27
+ const response = await fetch(SLACK_API, {
28
+ method: "POST",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ Authorization: `Bearer ${token}`,
32
+ },
33
+ body: JSON.stringify(body),
34
+ });
35
+ if (!response.ok) {
36
+ console.warn(`[slack] HTTP ${response.status} from Slack API`);
37
+ return { ok: false, error: `http_${response.status}` };
38
+ }
39
+ return response.json();
40
+ }
41
+ /**
42
+ * Create a `SlackNotifier` backed by the given `Db` instance.
43
+ *
44
+ * @param db - db instance for persisting thread timestamps.
45
+ */
46
+ export function createSlack(db) {
47
+ return {
48
+ async postPR(prNumber, title, url) {
49
+ const cfg = getConfig();
50
+ if (!cfg)
51
+ return;
52
+ const text = `\u{1F500} PR #${prNumber}: ${title}\n${url}`;
53
+ try {
54
+ const res = await post(cfg.token, cfg.channel, text);
55
+ if (res.ok && res.ts) {
56
+ db.set(NAMESPACE, String(prNumber), res.ts);
57
+ }
58
+ }
59
+ catch (err) {
60
+ console.warn(`[slack] postPR failed for PR #${prNumber}:`, err);
61
+ }
62
+ },
63
+ async replyPR(prNumber, text) {
64
+ const cfg = getConfig();
65
+ if (!cfg)
66
+ return;
67
+ const threadTs = db.get(NAMESPACE, String(prNumber));
68
+ if (!threadTs)
69
+ return;
70
+ try {
71
+ await post(cfg.token, cfg.channel, text, threadTs);
72
+ }
73
+ catch (err) {
74
+ console.warn(`[slack] replyPR failed for PR #${prNumber}:`, err);
75
+ }
76
+ },
77
+ };
78
+ }
79
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/lib/slack.ts"],"names":[],"mappings":"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"}