claudius-core 0.9.3 → 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.
- package/.claude/agents/manager.md +3 -13
- package/.claude/agents/worker.md +50 -27
- package/.claude/rules/testing.md +7 -4
- package/.claude/scripts/merge-pr.sh +55 -24
- package/.claude/scripts/project-status.sh +8 -8
- package/.claude/skills/build/SKILL.md +3 -17
- package/.claude-plugin/marketplace.json +2 -2
- package/dist/lib/db.d.ts +30 -0
- package/dist/lib/db.d.ts.map +1 -0
- package/dist/lib/db.js +71 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/slack.d.ts +33 -0
- package/dist/lib/slack.d.ts.map +1 -0
- package/dist/lib/slack.js +79 -0
- package/dist/lib/slack.js.map +1 -0
- package/dist/studio/assets/{_basePickBy-CaRVkU_i.js → _basePickBy-BPyGSyjX.js} +1 -1
- package/dist/studio/assets/{_baseUniq-DB9CANVr.js → _baseUniq-COXavBWr.js} +1 -1
- package/dist/studio/assets/{arc-DwNKwVLD.js → arc-C6u7rWiy.js} +1 -1
- package/dist/studio/assets/{architectureDiagram-VXUJARFQ-CDW4khKr.js → architectureDiagram-VXUJARFQ-CdgRZem0.js} +1 -1
- package/dist/studio/assets/{blockDiagram-VD42YOAC-D6_LSve2.js → blockDiagram-VD42YOAC-Dzy--0Bk.js} +1 -1
- package/dist/studio/assets/{c4Diagram-YG6GDRKO-SFPE64AJ.js → c4Diagram-YG6GDRKO-CymHroyB.js} +1 -1
- package/dist/studio/assets/channel-DA6Vd3mS.js +1 -0
- package/dist/studio/assets/{chunk-4BX2VUAB-BqHoEHlQ.js → chunk-4BX2VUAB-DNgeunAs.js} +1 -1
- package/dist/studio/assets/{chunk-55IACEB6-DkHQ5WBd.js → chunk-55IACEB6-B9L9utip.js} +1 -1
- package/dist/studio/assets/{chunk-B4BG7PRW-CW_kq6KT.js → chunk-B4BG7PRW-mYytHwg8.js} +1 -1
- package/dist/studio/assets/{chunk-DI55MBZ5-DNDwEGQ5.js → chunk-DI55MBZ5-B_htrqq2.js} +1 -1
- package/dist/studio/assets/{chunk-FMBD7UC4-5PX-ftxQ.js → chunk-FMBD7UC4-De68-v5Z.js} +1 -1
- package/dist/studio/assets/{chunk-QN33PNHL-QkQfQaqN.js → chunk-QN33PNHL-BDHmOaWb.js} +1 -1
- package/dist/studio/assets/{chunk-QZHKN3VN-Do2RvhJA.js → chunk-QZHKN3VN-CI4b_NjC.js} +1 -1
- package/dist/studio/assets/{chunk-TZMSLE5B-xiebau4j.js → chunk-TZMSLE5B-eE5xjTIx.js} +1 -1
- package/dist/studio/assets/classDiagram-2ON5EDUG-0FJ62Ib2.js +1 -0
- package/dist/studio/assets/classDiagram-v2-WZHVMYZB-0FJ62Ib2.js +1 -0
- package/dist/studio/assets/clone-BNX5khHw.js +1 -0
- package/dist/studio/assets/{cose-bilkent-S5V4N54A-Apnpf-ki.js → cose-bilkent-S5V4N54A-CliUCU0O.js} +1 -1
- package/dist/studio/assets/{dagre-6UL2VRFP-BxyPIzB8.js → dagre-6UL2VRFP-Euc9DolX.js} +1 -1
- package/dist/studio/assets/{diagram-PSM6KHXK-24YoaI-e.js → diagram-PSM6KHXK-wFCVz4Gf.js} +1 -1
- package/dist/studio/assets/{diagram-QEK2KX5R-lHpdi46q.js → diagram-QEK2KX5R-DW3TEVRg.js} +1 -1
- package/dist/studio/assets/{diagram-S2PKOQOG-9u1_ee6B.js → diagram-S2PKOQOG-sRtmdfLP.js} +1 -1
- package/dist/studio/assets/{erDiagram-Q2GNP2WA-Dlmgb2ym.js → erDiagram-Q2GNP2WA-DhFEzcCs.js} +1 -1
- package/dist/studio/assets/{flowDiagram-NV44I4VS-5sj_GCzk.js → flowDiagram-NV44I4VS-DkGukznd.js} +1 -1
- package/dist/studio/assets/{ganttDiagram-JELNMOA3-CUJF-slV.js → ganttDiagram-JELNMOA3-DWK7W0Dy.js} +1 -1
- package/dist/studio/assets/{gitGraphDiagram-V2S2FVAM-CKpDBk3b.js → gitGraphDiagram-V2S2FVAM-BOCSCk6Z.js} +1 -1
- package/dist/studio/assets/{graph-BRYklN25.js → graph-BZL6SCOn.js} +1 -1
- package/dist/studio/assets/{index-WEgtt1oI.js → index-DheMq1DW.js} +2 -2
- package/dist/studio/assets/{infoDiagram-HS3SLOUP-DKF6awtp.js → infoDiagram-HS3SLOUP-DgPXbZVx.js} +1 -1
- package/dist/studio/assets/{journeyDiagram-XKPGCS4Q-CgrhL8R0.js → journeyDiagram-XKPGCS4Q-6xUT6AF4.js} +1 -1
- package/dist/studio/assets/{kanban-definition-3W4ZIXB7-28MC-pF6.js → kanban-definition-3W4ZIXB7-Dsvw_JdF.js} +1 -1
- package/dist/studio/assets/{layout-gwYv6lHv.js → layout-DwiaZVEi.js} +1 -1
- package/dist/studio/assets/{linear-Dl48BTRW.js → linear-B7fbgRMt.js} +1 -1
- package/dist/studio/assets/{mermaid.core-YPNEyw9M.js → mermaid.core-wwLvzRgL.js} +4 -4
- package/dist/studio/assets/{mindmap-definition-VGOIOE7T-CNO-62gT.js → mindmap-definition-VGOIOE7T-BIvanpwK.js} +1 -1
- package/dist/studio/assets/{pieDiagram-ADFJNKIX-DutNO8TU.js → pieDiagram-ADFJNKIX-83imZrxP.js} +1 -1
- package/dist/studio/assets/{quadrantDiagram-AYHSOK5B-CyL-T3po.js → quadrantDiagram-AYHSOK5B-DHQawHwC.js} +1 -1
- package/dist/studio/assets/{requirementDiagram-UZGBJVZJ-Decs2Rps.js → requirementDiagram-UZGBJVZJ-CJ8omiFk.js} +1 -1
- package/dist/studio/assets/{sankeyDiagram-TZEHDZUN-CXQHF2nL.js → sankeyDiagram-TZEHDZUN-DaO3BTC3.js} +1 -1
- package/dist/studio/assets/{sequenceDiagram-WL72ISMW-C9cFuo_6.js → sequenceDiagram-WL72ISMW-BaOOCdTf.js} +1 -1
- package/dist/studio/assets/{stateDiagram-FKZM4ZOC-Dvs2TeCM.js → stateDiagram-FKZM4ZOC-BAmqIsET.js} +1 -1
- package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-BvS1aYAB.js +1 -0
- package/dist/studio/assets/{timeline-definition-IT6M3QCI-BpsJlgf7.js → timeline-definition-IT6M3QCI-BNMgBtHo.js} +1 -1
- package/dist/studio/assets/{treemap-GDKQZRPO-DVxRTPr1.js → treemap-GDKQZRPO-BFdbo85g.js} +1 -1
- package/dist/studio/assets/{xychartDiagram-PRI3JC2R-QUfHK5a4.js → xychartDiagram-PRI3JC2R-CTgS6W_y.js} +1 -1
- package/dist/studio/index.html +1 -1
- package/global/rules/global.md +2 -0
- package/package.json +1 -1
- package/dist/studio/assets/channel-h6J62PW8.js +0 -1
- package/dist/studio/assets/classDiagram-2ON5EDUG-D8lIj2-P.js +0 -1
- package/dist/studio/assets/classDiagram-v2-WZHVMYZB-D8lIj2-P.js +0 -1
- package/dist/studio/assets/clone-Chwjzlof.js +0 -1
- package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-NKg7XNVy.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
|
|
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
|
|
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
|
-
**
|
|
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
|
package/.claude/agents/worker.md
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
126
|
+
**Update Project #6 Status → In Progress** — add to project if needed, then set status:
|
|
127
|
+
|
|
137
128
|
```bash
|
|
138
|
-
|
|
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
|
|
247
|
+
**Update Project #6 Status → Under Review** (best-effort):
|
|
250
248
|
```bash
|
|
251
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/.claude/rules/testing.md
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
-
|
|
44
|
+
- Changing `src/` without rebuilding and committing `dist/`
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# merge-pr.sh —
|
|
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
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
6
|
+
# Behavior:
|
|
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)
|
|
10
12
|
#
|
|
11
|
-
# Exit codes: 0 = merged, 1 = merge failed
|
|
13
|
+
# Exit codes: 0 = merged + synced, 1 = merge failed, 2 = sync failed
|
|
12
14
|
|
|
13
15
|
set -euo pipefail
|
|
14
16
|
|
|
@@ -18,31 +20,60 @@ if [[ -z "$PR" ]]; then
|
|
|
18
20
|
exit 1
|
|
19
21
|
fi
|
|
20
22
|
|
|
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"
|
|
28
|
+
|
|
29
|
+
# Get branch name before merging (needed for API fallback cleanup)
|
|
21
30
|
BRANCH=$(gh pr view "$PR" --json headRefName --jq '.headRefName' 2>/dev/null)
|
|
22
31
|
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null)
|
|
23
|
-
TITLE=$(gh pr view "$PR" --json title --jq '.title')
|
|
24
32
|
|
|
25
33
|
echo "Merging PR #$PR ($BRANCH) in $REPO..."
|
|
26
34
|
|
|
27
|
-
#
|
|
28
|
-
gh
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
42
|
+
TITLE=$(gh pr view "$PR" --json title --jq '.title')
|
|
43
|
+
gh api "repos/$REPO/pulls/$PR/merge" \
|
|
44
|
+
-X PUT \
|
|
45
|
+
-f merge_method=squash \
|
|
46
|
+
-f commit_title="$TITLE" \
|
|
47
|
+
--silent
|
|
33
48
|
|
|
34
|
-
echo "Merged
|
|
49
|
+
echo "Merged via API."
|
|
50
|
+
|
|
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
|
|
35
56
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
&& echo "Deleted remote branch: $BRANCH" \
|
|
39
|
-
|| echo "⚠ Could not delete remote branch: $BRANCH"
|
|
57
|
+
# Re-anchor to main root (gh pr merge may change CWD)
|
|
58
|
+
cd "$MAIN_ROOT"
|
|
40
59
|
|
|
41
|
-
#
|
|
42
|
-
|
|
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)
|
|
43
63
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
git
|
|
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
|
|
71
|
+
git checkout main 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
|
|
78
|
+
fi
|
|
48
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="
|
|
26
|
-
"In Progress") STATUS_OPT="
|
|
27
|
-
"Under Review") STATUS_OPT="
|
|
28
|
-
"Blocked") STATUS_OPT="
|
|
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="
|
|
35
|
-
"Running") EXECUTION_OPT="
|
|
36
|
-
"Review") EXECUTION_OPT="
|
|
37
|
-
"Blocked") EXECUTION_OPT="
|
|
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.
|
|
109
|
-
|
|
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.
|
|
24
|
+
"version": "0.9.5",
|
|
25
25
|
"strict": true,
|
|
26
26
|
"category": "development"
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
|
-
"version": "0.9.
|
|
29
|
+
"version": "0.9.5"
|
|
30
30
|
}
|
package/dist/lib/db.d.ts
ADDED
|
@@ -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":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,SAAS,GAAG,wCAAwC,CAAC;AAC3D,MAAM,SAAS,GAAG,eAAe,CAAC;AAQlC,SAAS,SAAS;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC1C,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,IAAI,CAClB,KAAa,EACb,OAAe,EACf,IAAY,EACZ,QAAiB;IAEjB,MAAM,IAAI,GAA2B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvD,IAAI,QAAQ;QAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAExC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;QACvC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,KAAK,EAAE;SAChC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC1B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,gBAAgB,QAAQ,CAAC,MAAM,iBAAiB,CAAC,CAAC;QAC/D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACxD,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA4B,CAAC;AAClD,CAAC;AAgBD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,EAAM;IACjC,OAAO;QACN,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,KAAa,EAAE,GAAW;YACxD,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG;gBAAE,OAAO;YAEjB,MAAM,IAAI,GAAG,iBAAiB,QAAQ,KAAK,KAAK,KAAK,GAAG,EAAE,CAAC;YAC3D,IAAI,CAAC;gBACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBACrD,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;oBACtB,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7C,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,iCAAiC,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC;YACjE,CAAC;QACF,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,IAAY;YAC3C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG;gBAAE,OAAO;YAEjB,MAAM,QAAQ,GAAG,EAAE,CAAC,GAAG,CAAS,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC7D,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAEtB,IAAI,CAAC;gBACJ,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,kCAAkC,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC;YAClE,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as x,c as b,g as m,k as P,h as p,j as w,l as N,m as c,n as I,t as A,o as M}from"./_baseUniq-
|
|
1
|
+
import{e as x,c as b,g as m,k as P,h as p,j as w,l as N,m as c,n as I,t as A,o as M}from"./_baseUniq-COXavBWr.js";import{aL as g,ar as E,aM as F,aN as T,aO as _,aP as l,aQ as $,aR as B,aS as S,aT as y}from"./mermaid.core-wwLvzRgL.js";var L=/\s/;function R(n){for(var r=n.length;r--&&L.test(n.charAt(r)););return r}var G=/^\s+/;function H(n){return n&&n.slice(0,R(n)+1).replace(G,"")}var o=NaN,q=/^[-+]0x[0-9a-f]+$/i,z=/^0b[01]+$/i,C=/^0o[0-7]+$/i,K=parseInt;function Q(n){if(typeof n=="number")return n;if(x(n))return o;if(g(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=g(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=H(n);var t=z.test(n);return t||C.test(n)?K(n.slice(2),t?2:8):q.test(n)?o:+n}var v=1/0,W=17976931348623157e292;function X(n){if(!n)return n===0?n:0;if(n=Q(n),n===v||n===-v){var r=n<0?-1:1;return r*W}return n===n?n:0}function Y(n){var r=X(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?b(n):[]}var O=Object.prototype,D=O.hasOwnProperty,dn=E(function(n,r){n=Object(n);var t=-1,i=r.length,a=i>2?r[2]:void 0;for(a&&F(r[0],r[1],a)&&(i=1);++t<i;)for(var f=r[t],e=T(f),s=-1,d=e.length;++s<d;){var u=e[s],h=n[u];(h===void 0||_(h,O[u])&&!D.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function J(n){return function(r,t,i){var a=Object(r);if(!l(r)){var f=m(t);r=P(r),t=function(s){return f(a[s],s,a)}}var e=n(r,t,i);return e>-1?a[f?r[e]:e]:void 0}}var U=Math.max;function Z(n,r,t){var i=n==null?0:n.length;if(!i)return-1;var a=t==null?0:Y(t);return a<0&&(a=U(i+a,0)),p(n,m(r),a)}var hn=J(Z);function V(n,r){var t=-1,i=l(n)?Array(n.length):[];return w(n,function(a,f,e){i[++t]=r(a,f,e)}),i}function gn(n,r){var t=$(n)?N:V;return t(n,m(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function mn(n,r){return n!=null&&c(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var i=-1,a=n.length;++i<a;){var f=n[i],e=r(f);if(e!=null&&(s===void 0?e===e&&!x(e):t(e,s)))var s=e,d=f}return d}function on(n){return n&&n.length?tn(n,B,rn):void 0}function an(n,r,t,i){if(!g(n))return n;r=I(r,n);for(var a=-1,f=r.length,e=f-1,s=n;s!=null&&++a<f;){var d=A(r[a]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(a!=e){var h=s[d];u=void 0,u===void 0&&(u=g(h)?h:S(r[a+1])?[]:{})}y(s,d,u),s=s[d]}return n}function vn(n,r,t){for(var i=-1,a=r.length,f={};++i<a;){var e=r[i],s=M(n,e);t(s,e)&&an(f,I(e,n),s)}return f}export{rn as a,tn as b,V as c,vn as d,on as e,fn as f,hn as g,mn as h,dn as i,Y as j,un as l,gn as m,X as t};
|