@synity/bitrix-skills 1.3.0
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/CHANGELOG.md +169 -0
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/bin/bitrix-skills.js +3 -0
- package/dist/cli.js +1510 -0
- package/dist/features/bx-task/install.js +111 -0
- package/dist/features/task-sync/index.js +1053 -0
- package/package.json +69 -0
- package/src/features/bx/assets/SKILL.md +34 -0
- package/src/features/bx/feature.json +8 -0
- package/src/features/bx-calendar/assets/SKILL.md +61 -0
- package/src/features/bx-calendar/assets/availability.md +65 -0
- package/src/features/bx-calendar/assets/meeting.md +87 -0
- package/src/features/bx-calendar/assets/reminder.md +71 -0
- package/src/features/bx-calendar/assets/sync.md +70 -0
- package/src/features/bx-calendar/feature.json +10 -0
- package/src/features/bx-crm/assets/SKILL.md +59 -0
- package/src/features/bx-crm/assets/commerce.md +96 -0
- package/src/features/bx-crm/assets/onboard.md +127 -0
- package/src/features/bx-crm/assets/report.md +98 -0
- package/src/features/bx-crm/assets/research.md +71 -0
- package/src/features/bx-crm/feature.json +10 -0
- package/src/features/bx-task/assets/SKILL.md +148 -0
- package/src/features/bx-task/assets/lib/bx-api.sh +39 -0
- package/src/features/bx-task/assets/lib/bx-checklist.sh +127 -0
- package/src/features/bx-task/assets/lib/bx-resolve-task.sh +41 -0
- package/src/features/bx-task/assets/lib/bx-state.sh +131 -0
- package/src/features/bx-task/assets/lib/bx-tasks.sh +109 -0
- package/src/features/bx-task/assets/references/bootstrap.md +184 -0
- package/src/features/bx-task/assets/references/feature.md +97 -0
- package/src/features/bx-task/assets/references/init-templates/cli-tool.md +47 -0
- package/src/features/bx-task/assets/references/init-templates/generic.md +31 -0
- package/src/features/bx-task/assets/references/init-templates/library.md +45 -0
- package/src/features/bx-task/assets/references/init-templates/monorepo.md +38 -0
- package/src/features/bx-task/assets/references/init-templates/npm-package.md +40 -0
- package/src/features/bx-task/assets/references/init-templates/web-app.md +46 -0
- package/src/features/bx-task/assets/references/init.md +107 -0
- package/src/features/bx-task/assets/references/roadmap.md +93 -0
- package/src/features/bx-task/assets/references/summary.md +269 -0
- package/src/features/bx-task/assets/references/sync.md +104 -0
- package/src/features/bx-task/assets/references/time-log.md +214 -0
- package/src/features/bx-task/feature.json +10 -0
- package/src/features/bx-task/install.ts +117 -0
- package/src/features/task-sync/assets/docs/bitrix-task-reference.md +318 -0
- package/src/features/task-sync/assets/docs/bitrix-task-sync.md +254 -0
- package/src/features/task-sync/assets/githooks/commit-msg +44 -0
- package/src/features/task-sync/assets/githooks/install.sh +15 -0
- package/src/features/task-sync/assets/manifest.json +108 -0
- package/src/features/task-sync/assets/rules/00-bitrix-task-sync.md +161 -0
- package/src/features/task-sync/assets/scripts/bitrix-attach-files.sh +55 -0
- package/src/features/task-sync/assets/scripts/bitrix-lib.sh +540 -0
- package/src/features/task-sync/assets/scripts/bitrix-render-digest.sh +116 -0
- package/src/features/task-sync/assets/scripts/bitrix-session-check.sh +51 -0
- package/src/features/task-sync/assets/scripts/bitrix-session-sync.sh +89 -0
- package/src/features/task-sync/assets/scripts/bitrix-skill-end.sh +165 -0
- package/src/features/task-sync/assets/scripts/bitrix-skill-start.sh +58 -0
- package/src/features/task-sync/assets/scripts/lib/bb-formatter.sh +110 -0
- package/src/features/task-sync/assets/scripts/lib/bitrix-lib.sh +540 -0
- package/src/features/task-sync/assets/scripts/lib/time-helpers.sh +57 -0
- package/src/features/task-sync/assets/workflows/bitrix-sync.yml +85 -0
- package/src/features/task-sync/commands/install.ts +296 -0
- package/src/features/task-sync/commands/uninstall.ts +189 -0
- package/src/features/task-sync/commands/update.ts +11 -0
- package/src/features/task-sync/commands/verify.ts +141 -0
- package/src/features/task-sync/feature.json +12 -0
- package/src/features/task-sync/index.ts +121 -0
- package/src/features/task-sync/lib/dest-map.ts +96 -0
- package/src/features/task-sync/lib/drift-check.ts +47 -0
- package/src/features/task-sync/lib/file-ops.ts +36 -0
- package/src/features/task-sync/lib/manifest.ts +66 -0
- package/src/features/task-sync/lib/project-root.ts +38 -0
- package/src/features/task-sync/lib/settings-merge.ts +112 -0
- package/src/features/task-sync/lib/skill-refs.ts +106 -0
- package/src/features/task-sync/lib/task-id-finder.ts +31 -0
- package/src/features/task-sync/lib/token-extractor.ts +52 -0
- package/src/features/task-sync/lib/version.ts +36 -0
- package/src/features/task-sync/types.ts +40 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[B]{{PACKAGE_NAME}}[/B] — {{ONE_LINE_VALUE_PROP}}
|
|
2
|
+
|
|
3
|
+
[B]Install[/B]
|
|
4
|
+
[code]
|
|
5
|
+
{{INSTALL_COMMANDS}}
|
|
6
|
+
[/code]
|
|
7
|
+
|
|
8
|
+
[B]Commands[/B]
|
|
9
|
+
[code]
|
|
10
|
+
{{KEY_COMMANDS_OR_USAGE}}
|
|
11
|
+
[/code]
|
|
12
|
+
|
|
13
|
+
[B]Architecture[/B]
|
|
14
|
+
[code]
|
|
15
|
+
{{ASCII_DIAGRAM}}
|
|
16
|
+
[/code]
|
|
17
|
+
|
|
18
|
+
[B]Feature Matrix[/B]
|
|
19
|
+
[table]
|
|
20
|
+
[tr][th]Feature[/th][th]Target[/th][th]Trigger[/th][th]Lifecycle[/th][/tr]
|
|
21
|
+
{{FEATURE_MATRIX_ROWS}}
|
|
22
|
+
[/table]
|
|
23
|
+
|
|
24
|
+
[B]Phase Timeline[/B]
|
|
25
|
+
{{PHASE_TIMELINE}}
|
|
26
|
+
|
|
27
|
+
[B]Open Issues[/B]
|
|
28
|
+
{{OPEN_ISSUES}}
|
|
29
|
+
|
|
30
|
+
[B]Success Criteria[/B]
|
|
31
|
+
{{SUCCESS_CRITERIA}}
|
|
32
|
+
|
|
33
|
+
[B]Liên kết[/B]
|
|
34
|
+
• Repo: [URL={{REPO_URL}}]{{REPO_SHORT}}[/URL]
|
|
35
|
+
• npm: [URL=https://www.npmjs.com/package/{{PACKAGE_NAME}}]{{PACKAGE_NAME}}[/URL]
|
|
36
|
+
• Plan dir: {{PLAN_DIR}}
|
|
37
|
+
• Active phase: {{ACTIVE_PHASE_PATH}}
|
|
38
|
+
• Docs: docs/project-overview-pdr.md, docs/system-architecture.md, docs/codebase-summary.md
|
|
39
|
+
• README: README.md
|
|
40
|
+
• CHANGELOG: CHANGELOG.md
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[B]{{PACKAGE_NAME}}[/B] — {{ONE_LINE_VALUE_PROP}}
|
|
2
|
+
|
|
3
|
+
[B]Dev / Build / Deploy[/B]
|
|
4
|
+
[code]
|
|
5
|
+
{{INSTALL_COMMANDS}}
|
|
6
|
+
[/code]
|
|
7
|
+
|
|
8
|
+
[B]Routes / Pages[/B]
|
|
9
|
+
[table]
|
|
10
|
+
[tr][th]Path[/th][th]Component[/th][th]Purpose[/th][/tr]
|
|
11
|
+
{{ROUTES_ROWS}}
|
|
12
|
+
[/table]
|
|
13
|
+
|
|
14
|
+
[B]Architecture[/B]
|
|
15
|
+
[code]
|
|
16
|
+
{{ASCII_DIAGRAM}}
|
|
17
|
+
[/code]
|
|
18
|
+
|
|
19
|
+
[B]Components & State[/B]
|
|
20
|
+
[table]
|
|
21
|
+
[tr][th]Module[/th][th]Role[/th][/tr]
|
|
22
|
+
{{FEATURE_MATRIX_ROWS}}
|
|
23
|
+
[/table]
|
|
24
|
+
|
|
25
|
+
[B]API Endpoints[/B]
|
|
26
|
+
{{API_ENDPOINTS_OR_NONE}}
|
|
27
|
+
|
|
28
|
+
[B]Deploy Targets[/B]
|
|
29
|
+
{{DEPLOY_TARGETS}}
|
|
30
|
+
|
|
31
|
+
[B]Phase Timeline[/B]
|
|
32
|
+
{{PHASE_TIMELINE}}
|
|
33
|
+
|
|
34
|
+
[B]Open Issues[/B]
|
|
35
|
+
{{OPEN_ISSUES}}
|
|
36
|
+
|
|
37
|
+
[B]Success Criteria[/B]
|
|
38
|
+
{{SUCCESS_CRITERIA}}
|
|
39
|
+
|
|
40
|
+
[B]Liên kết[/B]
|
|
41
|
+
• Repo: [URL={{REPO_URL}}]{{REPO_SHORT}}[/URL]
|
|
42
|
+
• Live: [URL={{LIVE_URL}}]{{LIVE_URL_SHORT}}[/URL]
|
|
43
|
+
• Plan dir: {{PLAN_DIR}}
|
|
44
|
+
• Active phase: {{ACTIVE_PHASE_PATH}}
|
|
45
|
+
• Docs: docs/project-overview-pdr.md, docs/system-architecture.md, docs/codebase-summary.md
|
|
46
|
+
• README: README.md
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# /bx:task init — Initialize TASK_ID in CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Detect or insert a `TASK_ID` block into the nearest `CLAUDE.md`. No Bitrix API calls — filesystem only.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- Starting a new AI session in a project that hasn't set `TASK_ID` yet
|
|
8
|
+
- Switching to a different Bitrix task mid-project
|
|
9
|
+
- Setting up a new feature branch with its own task context
|
|
10
|
+
|
|
11
|
+
## Args
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/bx:task init [--task-id N]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- `--task-id N` — skip interactive prompt, use this value directly
|
|
18
|
+
|
|
19
|
+
## Algorithm
|
|
20
|
+
|
|
21
|
+
### Step 1 — Locate CLAUDE.md
|
|
22
|
+
|
|
23
|
+
Walk up from `$PWD` looking for `CLAUDE.md`:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
dir="$PWD"
|
|
27
|
+
CLAUDE_MD=""
|
|
28
|
+
while [[ "$dir" != "/" ]]; do
|
|
29
|
+
if [[ -f "$dir/CLAUDE.md" ]]; then
|
|
30
|
+
CLAUDE_MD="$dir/CLAUDE.md"
|
|
31
|
+
break
|
|
32
|
+
fi
|
|
33
|
+
dir="$(dirname "$dir")"
|
|
34
|
+
done
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If not found → will create `$PWD/CLAUDE.md`.
|
|
38
|
+
|
|
39
|
+
### Step 2 — Check existing TASK_ID
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
EXISTING_ID=$(grep -m1 '^TASK_ID:' "${CLAUDE_MD:-}" 2>/dev/null | awk '{print $2}')
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If `EXISTING_ID` found:
|
|
46
|
+
- Show: `Current TASK_ID: {EXISTING_ID} in {CLAUDE_MD}`
|
|
47
|
+
- Ask via `AskUserQuestion`: "TASK_ID đã tồn tại. Bạn muốn làm gì?"
|
|
48
|
+
- "Giữ nguyên #{EXISTING_ID}" → exit 0
|
|
49
|
+
- "Đổi sang task khác" → continue to Step 3
|
|
50
|
+
- "Cancel" → exit 0
|
|
51
|
+
|
|
52
|
+
### Step 3 — Get TASK_ID value
|
|
53
|
+
|
|
54
|
+
If `--task-id N` was passed → `NEW_ID=N`, skip prompt.
|
|
55
|
+
|
|
56
|
+
Otherwise use `AskUserQuestion`:
|
|
57
|
+
- question: "Nhập TASK_ID (số) cho project này:"
|
|
58
|
+
- options: leave as free-text (user types the number)
|
|
59
|
+
|
|
60
|
+
Validate: must be a positive integer. If invalid → error + re-prompt (max 3 attempts).
|
|
61
|
+
|
|
62
|
+
### Step 4 — Insert or update TASK_ID block
|
|
63
|
+
|
|
64
|
+
**If CLAUDE.md exists and has existing `## Bitrix Task` section:**
|
|
65
|
+
|
|
66
|
+
Find the section and update/insert `TASK_ID: N` line:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Check if ## Bitrix Task section exists
|
|
70
|
+
if grep -q '^## Bitrix Task' "$CLAUDE_MD"; then
|
|
71
|
+
# Update existing TASK_ID line if present
|
|
72
|
+
if grep -q '^TASK_ID:' "$CLAUDE_MD"; then
|
|
73
|
+
sed -i '' "s/^TASK_ID:.*/TASK_ID: ${NEW_ID}/" "$CLAUDE_MD"
|
|
74
|
+
else
|
|
75
|
+
# Insert TASK_ID after "## Bitrix Task" line
|
|
76
|
+
sed -i '' "/^## Bitrix Task/a\\
|
|
77
|
+
TASK_ID: ${NEW_ID}" "$CLAUDE_MD"
|
|
78
|
+
fi
|
|
79
|
+
else
|
|
80
|
+
# Append full block at end of file
|
|
81
|
+
printf '\n## Bitrix Task\nTASK_ID: %s\n' "$NEW_ID" >> "$CLAUDE_MD"
|
|
82
|
+
fi
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**If CLAUDE.md does not exist:**
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
printf '## Bitrix Task\nTASK_ID: %s\n' "$NEW_ID" > "$PWD/CLAUDE.md"
|
|
89
|
+
CLAUDE_MD="$PWD/CLAUDE.md"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Step 5 — Confirm result
|
|
93
|
+
|
|
94
|
+
Print:
|
|
95
|
+
```
|
|
96
|
+
✓ TASK_ID set to #{NEW_ID} in {CLAUDE_MD}
|
|
97
|
+
Hooks will now sync AI activity to: https://{portal}/workgroups/group/{GROUP_ID}/tasks/task/view/{NEW_ID}/
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If `BITRIX_WEBHOOK_URL` is set, extract portal domain from the URL for the confirmation link.
|
|
101
|
+
Otherwise: `✓ TASK_ID: {NEW_ID} saved to {CLAUDE_MD}`
|
|
102
|
+
|
|
103
|
+
## Error handling
|
|
104
|
+
|
|
105
|
+
- Invalid TASK_ID (non-integer) → `ERROR: TASK_ID must be a positive integer.`
|
|
106
|
+
- CLAUDE.md not writable → `ERROR: Cannot write to {path}. Check permissions.`
|
|
107
|
+
- No CLAUDE.md found and CWD not a git repo → warn "No CLAUDE.md found and CWD is not a git root. Creating {PWD}/CLAUDE.md anyway." → proceed
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# /bx:task roadmap — Manage Done/Doing/Plan checklist groups on main task
|
|
2
|
+
|
|
3
|
+
Two actions:
|
|
4
|
+
|
|
5
|
+
| Action | Effect |
|
|
6
|
+
|--------|--------|
|
|
7
|
+
| `add <group> <item>` | Append a new item to a group (Done/Doing/Plan) |
|
|
8
|
+
| `move <item> <from> <to>` | Mark item complete in `<from>`, add (possibly checked) in `<to>` |
|
|
9
|
+
|
|
10
|
+
`<group>` ∈ `done | doing | plan`. `<item>` = exact title text used during add/move.
|
|
11
|
+
|
|
12
|
+
## Args
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/bx:task roadmap add <group> <item-title>
|
|
16
|
+
/bx:task roadmap move <item-title> <from-group> <to-group>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Item title supports spaces (quote in shell or pass as-is from skill arg parser).
|
|
20
|
+
|
|
21
|
+
## Prerequisite
|
|
22
|
+
|
|
23
|
+
State must have all 3 `checklists.{done,doing,plan}.parentId` set. If missing → run
|
|
24
|
+
`/bx:task bootstrap` first.
|
|
25
|
+
|
|
26
|
+
## Algorithm — `add`
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
source ~/.claude/skills/bx-task/lib/bx-api.sh
|
|
30
|
+
source ~/.claude/skills/bx-task/lib/bx-state.sh
|
|
31
|
+
source ~/.claude/skills/bx-task/lib/bx-checklist.sh
|
|
32
|
+
source ~/.claude/skills/bx-task/lib/bx-tasks.sh
|
|
33
|
+
|
|
34
|
+
bx_preflight || exit 1
|
|
35
|
+
MAIN_ID=$(bx_state_get "mainTaskId")
|
|
36
|
+
PARENT=$(bx_state_get "checklists.${GROUP}.parentId")
|
|
37
|
+
if [[ -z "$MAIN_ID" || -z "$PARENT" ]]; then
|
|
38
|
+
echo "⛔ State not bootstrapped, or unknown group '$GROUP'." >&2
|
|
39
|
+
echo " Valid groups: done, doing, plan." >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Confirm before POST (AskUserQuestion: "Add '$ITEM' to $GROUP on task #$MAIN_ID?")
|
|
44
|
+
|
|
45
|
+
NEW_ID=$(bx_checklist_add "$MAIN_ID" "$GROUP" "$ITEM")
|
|
46
|
+
[[ "$GROUP" == "done" ]] && bx_checklist_toggle "$MAIN_ID" "$NEW_ID" "Y"
|
|
47
|
+
|
|
48
|
+
echo "✓ Added '$ITEM' to $GROUP (item #$NEW_ID)"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Algorithm — `move`
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bx_preflight || exit 1
|
|
55
|
+
MAIN_ID=$(bx_state_get "mainTaskId")
|
|
56
|
+
|
|
57
|
+
FROM_PID=$(bx_state_get "checklists.${FROM}.parentId")
|
|
58
|
+
TO_PID=$(bx_state_get "checklists.${TO}.parentId")
|
|
59
|
+
if [[ -z "$MAIN_ID" || -z "$FROM_PID" || -z "$TO_PID" ]]; then
|
|
60
|
+
echo "⛔ State not bootstrapped, or unknown group." >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Confirm before POST
|
|
65
|
+
|
|
66
|
+
NEW_ID=$(bx_checklist_move "$MAIN_ID" "$ITEM" "$FROM" "$TO")
|
|
67
|
+
if [[ -z "$NEW_ID" ]]; then
|
|
68
|
+
echo "ERROR: move failed — item '$ITEM' may not exist in $FROM" >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "✓ Moved '$ITEM' from $FROM → $TO (new item #$NEW_ID)"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Behavior notes
|
|
76
|
+
|
|
77
|
+
- **`add` to `done`** auto-toggles complete (`IS_COMPLETE=Y`).
|
|
78
|
+
- **`move`** preserves history by keeping the source item (marked complete) and creating a
|
|
79
|
+
new item in destination. This matches Bitrix UX (struck-through old + fresh new).
|
|
80
|
+
- **Title match in `move`** is exact (case-sensitive). If item title was renamed since add,
|
|
81
|
+
use `add` in target group + manually toggle source.
|
|
82
|
+
|
|
83
|
+
## Errors / UX
|
|
84
|
+
|
|
85
|
+
- Unknown group → exit 1 with valid list
|
|
86
|
+
- Item not found in source for `move` → exit 1, suggest `add` instead
|
|
87
|
+
- No state → exit 1, hint `bootstrap`
|
|
88
|
+
|
|
89
|
+
## What NOT to do
|
|
90
|
+
|
|
91
|
+
- ❌ Use `move` to undo a completion (instead: `bx_checklist_toggle <main> <itemId> N`)
|
|
92
|
+
- ❌ Add duplicate items to the same group (Bitrix allows it, but UX gets confusing)
|
|
93
|
+
- ❌ Skip the confirmation step (every POST goes through `AskUserQuestion`)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# /bx:task summary — Curated KB Result
|
|
2
|
+
|
|
3
|
+
Post a curated knowledge-base summary as a Bitrix Task Result entry (visible in task UI tab "Kết quả" / "Result"). Designed for moments worth pinning: releases, discoveries, bug post-mortems, ADRs, failed experiments.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- After shipping a release → `summary release`
|
|
8
|
+
- After investigating a bug → `summary bug-postmortem`
|
|
9
|
+
- After making an architecture decision → `summary adr`
|
|
10
|
+
- After learning something non-obvious → `summary discovery`
|
|
11
|
+
- After confirming a hypothesis is wrong → `summary failed-experiment`
|
|
12
|
+
|
|
13
|
+
If the user just wants to leave a chat note, the existing `bitrix-task-sync` hook auto-posts comments. This skill is for **persistent, structured KB entries** only.
|
|
14
|
+
|
|
15
|
+
## Args
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/bx:task summary [type] [--task-id N]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Arg | Required | Notes |
|
|
22
|
+
|-----|----------|-------|
|
|
23
|
+
| `type` | optional | One of: `release`, `discovery`, `bug-postmortem`, `adr`, `failed-experiment`. Omit → picker. |
|
|
24
|
+
| `--task-id N` | optional | Override CLAUDE.md walk-up. Useful when running outside a Bitrix project or targeting a different task. |
|
|
25
|
+
|
|
26
|
+
## Algorithm (Claude follows step by step)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
1. Source helpers + pre-flight:
|
|
30
|
+
source ~/.claude/skills/bx-task/lib/bx-resolve-task.sh
|
|
31
|
+
source ~/.claude/skills/bx-task/lib/bx-api.sh
|
|
32
|
+
bx_preflight || abort
|
|
33
|
+
|
|
34
|
+
2. Parse args:
|
|
35
|
+
- extract --task-id N if present, store in EXPLICIT_TASK_ID
|
|
36
|
+
- first positional = type (may be empty)
|
|
37
|
+
|
|
38
|
+
3. Resolve TASK_ID:
|
|
39
|
+
TASK_ID=$(bx_resolve_task_id "$EXPLICIT_TASK_ID") || abort
|
|
40
|
+
|
|
41
|
+
4. If type empty → AskUserQuestion picker (5 type options).
|
|
42
|
+
If type invalid → error: list valid types, exit 1.
|
|
43
|
+
|
|
44
|
+
5. Look up the field list for the chosen type (table below).
|
|
45
|
+
|
|
46
|
+
6. Collect each field via AskUserQuestion (one question per field).
|
|
47
|
+
Field labels in the table are the prompt wording.
|
|
48
|
+
Multi-line fields: ask user to write content as one paragraph; preserve newlines as-is.
|
|
49
|
+
|
|
50
|
+
7. Render BB content by substituting collected values into the template
|
|
51
|
+
for that type (templates below).
|
|
52
|
+
|
|
53
|
+
8. Show preview + confirm via AskUserQuestion:
|
|
54
|
+
Question: "Post this summary to Bitrix task #$TASK_ID?"
|
|
55
|
+
Preview field: raw BB code (KISS — exact text fidelity)
|
|
56
|
+
Options: [Confirm + Post (Recommended), Edit fields, Cancel]
|
|
57
|
+
|
|
58
|
+
9. On Confirm → POST:
|
|
59
|
+
PAYLOAD=$(jq -n --argjson tid "$TASK_ID" --arg txt "$BB_CONTENT" \
|
|
60
|
+
'{fields:{taskId:$tid, text:$txt}}')
|
|
61
|
+
RESP=$(bx_call_v3 "tasks.task.result.add" "$PAYLOAD")
|
|
62
|
+
# Extract result.id via grep — DO NOT use jq on the full response.
|
|
63
|
+
# Bitrix v3 returns malformed JSON (literal newlines inside string values),
|
|
64
|
+
# which strict jq rejects. The id field appears early and is safe to grep.
|
|
65
|
+
RESULT_ID=$(echo "$RESP" | grep -oE '"id":[[:space:]]*[0-9]+' | head -1 | grep -oE '[0-9]+')
|
|
66
|
+
if [[ -n "$RESULT_ID" ]]; then
|
|
67
|
+
echo "✅ Posted result #${RESULT_ID} to task #${TASK_ID}"
|
|
68
|
+
else
|
|
69
|
+
echo "❌ POST failed: $RESP" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
10. On Edit → loop back to step 6 (re-prompt fields, keep prior answers visible if AskUserQuestion supports defaults; otherwise re-ask).
|
|
74
|
+
On Cancel → exit 0 cleanly, no POST, no side effects.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Important:**
|
|
78
|
+
- Use `jq -n --arg txt "$BB_CONTENT"` for the REQUEST payload — NEVER string-concatenate user content into JSON. `jq --arg` handles quotes, newlines, and special chars (including `[/]`) safely.
|
|
79
|
+
- Do NOT use `jq` to parse the RESPONSE. Bitrix v3 returns JSON with literal (unescaped) newlines inside the `text` string value, which strict jq rejects. Use `grep -oE '"id":[[:space:]]*[0-9]+'` to extract the result id robustly.
|
|
80
|
+
|
|
81
|
+
## Type → Template (BB code)
|
|
82
|
+
|
|
83
|
+
All templates below render in Bitrix UI as bold headings + plain text body. **No markdown**. Use literal `\n` line breaks (real newlines in the rendered string).
|
|
84
|
+
|
|
85
|
+
### `release` 🚀
|
|
86
|
+
|
|
87
|
+
Fields: `VERSION`, `HIGHLIGHTS` (multi-line), `BREAKING`, `MIGRATION`
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
🚀 [b]Release {VERSION}[/b]
|
|
91
|
+
|
|
92
|
+
[b]Highlights:[/b]
|
|
93
|
+
{HIGHLIGHTS}
|
|
94
|
+
|
|
95
|
+
[b]Breaking changes:[/b]
|
|
96
|
+
{BREAKING}
|
|
97
|
+
|
|
98
|
+
[b]Migration:[/b]
|
|
99
|
+
{MIGRATION}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `discovery` 💡
|
|
103
|
+
|
|
104
|
+
Fields: `TOPIC`, `INSIGHT`, `APPLICATION`, `SOURCE`
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
💡 [b]Discovery: {TOPIC}[/b]
|
|
108
|
+
|
|
109
|
+
[b]Insight:[/b]
|
|
110
|
+
{INSIGHT}
|
|
111
|
+
|
|
112
|
+
[b]Application:[/b]
|
|
113
|
+
{APPLICATION}
|
|
114
|
+
|
|
115
|
+
[b]Source:[/b]
|
|
116
|
+
{SOURCE}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### `bug-postmortem` 🪲
|
|
120
|
+
|
|
121
|
+
Fields: `SYMPTOM`, `SYMPTOM_DETAIL`, `ROOT_CAUSE`, `FIX`, `PREVENTION`
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
🪲 [b]Bug post-mortem: {SYMPTOM}[/b]
|
|
125
|
+
|
|
126
|
+
[b]Triệu chứng:[/b]
|
|
127
|
+
{SYMPTOM_DETAIL}
|
|
128
|
+
|
|
129
|
+
[b]Nguyên nhân:[/b]
|
|
130
|
+
{ROOT_CAUSE}
|
|
131
|
+
|
|
132
|
+
[b]Fix:[/b]
|
|
133
|
+
{FIX}
|
|
134
|
+
|
|
135
|
+
[b]Phòng ngừa:[/b]
|
|
136
|
+
{PREVENTION}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `adr` 📐
|
|
140
|
+
|
|
141
|
+
Fields: `DECISION`, `CONTEXT`, `DECISION_DETAIL`, `CONSEQUENCES`, `STATUS`
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
📐 [b]ADR: {DECISION}[/b]
|
|
145
|
+
|
|
146
|
+
[b]Context:[/b]
|
|
147
|
+
{CONTEXT}
|
|
148
|
+
|
|
149
|
+
[b]Decision:[/b]
|
|
150
|
+
{DECISION_DETAIL}
|
|
151
|
+
|
|
152
|
+
[b]Consequences:[/b]
|
|
153
|
+
{CONSEQUENCES}
|
|
154
|
+
|
|
155
|
+
[b]Status:[/b] {STATUS}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`STATUS` ∈ {`Proposed`, `Accepted`, `Deprecated`, `Superseded`}.
|
|
159
|
+
|
|
160
|
+
### `failed-experiment` 🧪
|
|
161
|
+
|
|
162
|
+
Fields: `HYPOTHESIS`, `HYPOTHESIS_DETAIL`, `RESULT`, `LEARNING`
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
🧪 [b]Failed experiment: {HYPOTHESIS}[/b]
|
|
166
|
+
|
|
167
|
+
[b]Hypothesis:[/b]
|
|
168
|
+
{HYPOTHESIS_DETAIL}
|
|
169
|
+
|
|
170
|
+
[b]Result:[/b]
|
|
171
|
+
{RESULT}
|
|
172
|
+
|
|
173
|
+
[b]Learning:[/b]
|
|
174
|
+
{LEARNING}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Field-list quick reference
|
|
178
|
+
|
|
179
|
+
| Type | Fields (prompt order) |
|
|
180
|
+
|------|-----------------------|
|
|
181
|
+
| `release` | VERSION, HIGHLIGHTS, BREAKING, MIGRATION |
|
|
182
|
+
| `discovery` | TOPIC, INSIGHT, APPLICATION, SOURCE |
|
|
183
|
+
| `bug-postmortem` | SYMPTOM, SYMPTOM_DETAIL, ROOT_CAUSE, FIX, PREVENTION |
|
|
184
|
+
| `adr` | DECISION, CONTEXT, DECISION_DETAIL, CONSEQUENCES, STATUS |
|
|
185
|
+
| `failed-experiment` | HYPOTHESIS, HYPOTHESIS_DETAIL, RESULT, LEARNING |
|
|
186
|
+
|
|
187
|
+
## API payload shape
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"fields": {
|
|
192
|
+
"taskId": 2776,
|
|
193
|
+
"text": "🚀 [b]Release v0.0.1[/b]\n\n[b]Highlights:[/b]\n• ..."
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Endpoint: `tasks.task.result.add` on the v3 path (`/rest/api/<user>/<token>/`). `bx_call_v3` rewrites the URL automatically.
|
|
199
|
+
|
|
200
|
+
Response shape (success):
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"result": {
|
|
205
|
+
"item": {
|
|
206
|
+
"id": 123,
|
|
207
|
+
"taskId": 2776,
|
|
208
|
+
"createdBy": 614,
|
|
209
|
+
"messageId": null,
|
|
210
|
+
"text": "...",
|
|
211
|
+
"status": "open"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"time": {...}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`messageId` is `null` because we use direct `result.add` (no comment-pin chain).
|
|
219
|
+
|
|
220
|
+
## Error handling
|
|
221
|
+
|
|
222
|
+
| Failure | Behaviour |
|
|
223
|
+
|---------|-----------|
|
|
224
|
+
| `bx_preflight` fails | Exit 1, print env hint |
|
|
225
|
+
| `bx_resolve_task_id` fails | Exit 1, print "TASK_ID not found" hint |
|
|
226
|
+
| Invalid `type` arg | Exit 1, list 5 valid types |
|
|
227
|
+
| Network/HTTP error from `bx_call_v3` | Print raw response to stderr, exit 1 (NO retry — fail-fast, user re-runs) |
|
|
228
|
+
| User cancels at confirm | Exit 0, no POST, no side effects |
|
|
229
|
+
|
|
230
|
+
## Live test plan (Phase 2 verification)
|
|
231
|
+
|
|
232
|
+
Run on task #2776 (this repo's SSOT) once with each type, verify in Bitrix UI tab "Kết quả", capture each `result.id`, then cleanup:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# After each test posts, capture result.id from output, accumulate in $IDS array.
|
|
236
|
+
# Cleanup script:
|
|
237
|
+
for id in "${IDS[@]}"; do
|
|
238
|
+
bx_call_v3 "tasks.task.result.delete" "$(jq -n --argjson id "$id" '{id:$id}')"
|
|
239
|
+
done
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Examples
|
|
243
|
+
|
|
244
|
+
### Skip picker (advanced)
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
/bx:task summary release
|
|
248
|
+
```
|
|
249
|
+
→ Goes directly to release-type field prompts (VERSION, HIGHLIGHTS, ...).
|
|
250
|
+
|
|
251
|
+
### Picker mode (default)
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
/bx:task summary
|
|
255
|
+
```
|
|
256
|
+
→ AskUserQuestion shows 5 type options + Cancel.
|
|
257
|
+
|
|
258
|
+
### Override task
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
/bx:task summary adr --task-id 9999
|
|
262
|
+
```
|
|
263
|
+
→ Posts ADR to task #9999 instead of CLAUDE.md walk-up.
|
|
264
|
+
|
|
265
|
+
## Notes
|
|
266
|
+
|
|
267
|
+
- Webhook user 614 ("Claude") owns each posted result (`createdBy: 614`) → has `rights.edit/remove = true`. Cleanup is allowed.
|
|
268
|
+
- `tasks.task.result.list` filter shape on v3 is unknown (multiple shapes returned "Unknown filter condition" in research). v1 of this skill does NOT support listing; if needed, view results in Bitrix UI directly.
|
|
269
|
+
- Extending to a 6th type: add row to "Type → Template" + "Field-list" tables, add picker option in step 4.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# /bx:task sync — Session Digest to Task Comment
|
|
2
|
+
|
|
3
|
+
Post a manual session digest as a comment to the Bitrix task chat. Use when you want to sync progress mid-session or after a coding session without waiting for the Stop hook.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- After completing a significant chunk of work in a session
|
|
8
|
+
- When Stop hook didn't fire (e.g. session crash, manual exit)
|
|
9
|
+
- When working in a project that hasn't set up bitrix-task-sync hooks yet
|
|
10
|
+
- When you want to sync a specific context note manually
|
|
11
|
+
|
|
12
|
+
## Args
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/bx:task sync [--task-id N]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `--task-id N` — override TASK_ID resolution
|
|
19
|
+
|
|
20
|
+
## Pre-flight
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
source ~/.claude/skills/bx-task/lib/bx-resolve-task.sh
|
|
24
|
+
source ~/.claude/skills/bx-task/lib/bx-api.sh
|
|
25
|
+
bx_preflight || exit 1
|
|
26
|
+
TASK_ID=$(bx_resolve_task_id "${EXPLICIT_TASK_ID:-}") || exit 1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Algorithm
|
|
30
|
+
|
|
31
|
+
### Step 1 — Collect context
|
|
32
|
+
|
|
33
|
+
Run these bash commands silently (no output to user yet):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Recent commits (last 5, format: hash subject)
|
|
37
|
+
GIT_LOG=$(git log --oneline -5 2>/dev/null || echo "(no git history)")
|
|
38
|
+
|
|
39
|
+
# Files changed in last commit
|
|
40
|
+
GIT_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | head -10 || echo "")
|
|
41
|
+
|
|
42
|
+
# Current branch
|
|
43
|
+
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
44
|
+
|
|
45
|
+
# CWD project name (last dir component)
|
|
46
|
+
PROJECT=$(basename "$PWD")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Step 2 — Ask user for session note (optional)
|
|
50
|
+
|
|
51
|
+
Use `AskUserQuestion`:
|
|
52
|
+
- question: "Thêm ghi chú cho session này? (optional — Enter để bỏ qua)"
|
|
53
|
+
- options: 3-4 common options like "Bỏ qua", "Đã xong feature X", "Đang debug issue Y", "Other..."
|
|
54
|
+
|
|
55
|
+
If user picks "Bỏ qua" or empty → `SESSION_NOTE=""`
|
|
56
|
+
|
|
57
|
+
### Step 3 — Build BB comment
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
[b]⚡ Manual sync — {PROJECT}[/b]
|
|
61
|
+
|
|
62
|
+
[b]Branch:[/b] {GIT_BRANCH}
|
|
63
|
+
|
|
64
|
+
[b]Recent commits:[/b]
|
|
65
|
+
{GIT_LOG formatted as bullet list with • prefix}
|
|
66
|
+
|
|
67
|
+
{if GIT_FILES not empty:}
|
|
68
|
+
[b]Files changed:[/b]
|
|
69
|
+
{GIT_FILES formatted as • list}
|
|
70
|
+
{endif}
|
|
71
|
+
|
|
72
|
+
{if SESSION_NOTE not empty:}
|
|
73
|
+
[b]Ghi chú:[/b] {SESSION_NOTE}
|
|
74
|
+
{endif}
|
|
75
|
+
|
|
76
|
+
[i]Synced via /bx:task sync[/i]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Rules:
|
|
80
|
+
- Use `•` for bullet lists (not `-`)
|
|
81
|
+
- No markdown headers, no `**bold**` — BB only
|
|
82
|
+
- Max 2000 chars total; truncate git log lines to 72 chars each
|
|
83
|
+
|
|
84
|
+
### Step 4 — Confirm + POST
|
|
85
|
+
|
|
86
|
+
Show the BB text in an `AskUserQuestion`:
|
|
87
|
+
- question: "Post comment này lên task #{TASK_ID}?"
|
|
88
|
+
- options: "Yes, post it", "No, cancel"
|
|
89
|
+
|
|
90
|
+
If Yes:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bx_call_v1 "task.commentitem.add" \
|
|
94
|
+
"TASK_ID=${TASK_ID}&POST_MESSAGE=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.stdin.read()))" <<< "${BB_TEXT}")" \
|
|
95
|
+
|| exit 1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
On success: print `✓ Comment posted to task #${TASK_ID}`
|
|
99
|
+
|
|
100
|
+
## Error handling
|
|
101
|
+
|
|
102
|
+
- No git repo → skip git sections, post with note only
|
|
103
|
+
- Empty note + no git → warn "Nothing to sync. Add a --message or run from a git repo."
|
|
104
|
+
- API 5xx → fail-fast, print error, suggest retry
|