planflow-plugin 0.1.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/LICENSE +21 -0
- package/README.md +93 -0
- package/bin/cli.js +169 -0
- package/bin/postinstall.js +87 -0
- package/commands/pfActivity/SKILL.md +725 -0
- package/commands/pfAssign/SKILL.md +623 -0
- package/commands/pfCloudLink/SKILL.md +192 -0
- package/commands/pfCloudList/SKILL.md +222 -0
- package/commands/pfCloudNew/SKILL.md +187 -0
- package/commands/pfCloudUnlink/SKILL.md +152 -0
- package/commands/pfComment/SKILL.md +227 -0
- package/commands/pfComments/SKILL.md +159 -0
- package/commands/pfConnectionStatus/SKILL.md +433 -0
- package/commands/pfDiscord/SKILL.md +740 -0
- package/commands/pfGithubBranch/SKILL.md +672 -0
- package/commands/pfGithubIssue/SKILL.md +963 -0
- package/commands/pfGithubLink/SKILL.md +859 -0
- package/commands/pfGithubPr/SKILL.md +1335 -0
- package/commands/pfGithubUnlink/SKILL.md +401 -0
- package/commands/pfLive/SKILL.md +185 -0
- package/commands/pfLogin/SKILL.md +249 -0
- package/commands/pfLogout/SKILL.md +155 -0
- package/commands/pfMyTasks/SKILL.md +198 -0
- package/commands/pfNotificationSettings/SKILL.md +619 -0
- package/commands/pfNotifications/SKILL.md +420 -0
- package/commands/pfNotificationsClear/SKILL.md +421 -0
- package/commands/pfReact/SKILL.md +232 -0
- package/commands/pfSlack/SKILL.md +659 -0
- package/commands/pfSyncPull/SKILL.md +210 -0
- package/commands/pfSyncPush/SKILL.md +299 -0
- package/commands/pfSyncStatus/SKILL.md +212 -0
- package/commands/pfTeamInvite/SKILL.md +161 -0
- package/commands/pfTeamList/SKILL.md +253 -0
- package/commands/pfTeamRemove/SKILL.md +115 -0
- package/commands/pfTeamRole/SKILL.md +160 -0
- package/commands/pfTestWebhooks/SKILL.md +722 -0
- package/commands/pfUnassign/SKILL.md +134 -0
- package/commands/pfWhoami/SKILL.md +258 -0
- package/commands/pfWorkload/SKILL.md +219 -0
- package/commands/planExportCsv/SKILL.md +106 -0
- package/commands/planExportGithub/SKILL.md +222 -0
- package/commands/planExportJson/SKILL.md +159 -0
- package/commands/planExportSummary/SKILL.md +158 -0
- package/commands/planNew/SKILL.md +641 -0
- package/commands/planNext/SKILL.md +1200 -0
- package/commands/planSettingsAutoSync/SKILL.md +199 -0
- package/commands/planSettingsLanguage/SKILL.md +201 -0
- package/commands/planSettingsReset/SKILL.md +237 -0
- package/commands/planSettingsShow/SKILL.md +482 -0
- package/commands/planSpec/SKILL.md +929 -0
- package/commands/planUpdate/SKILL.md +2518 -0
- package/commands/team/SKILL.md +740 -0
- package/locales/en.json +1499 -0
- package/locales/ka.json +1499 -0
- package/package.json +48 -0
- package/templates/PROJECT_PLAN.template.md +157 -0
- package/templates/backend-api.template.md +562 -0
- package/templates/frontend-spa.template.md +610 -0
- package/templates/fullstack.template.md +397 -0
- package/templates/ka/backend-api.template.md +562 -0
- package/templates/ka/frontend-spa.template.md +610 -0
- package/templates/ka/fullstack.template.md +397 -0
- package/templates/sections/architecture.md +21 -0
- package/templates/sections/overview.md +15 -0
- package/templates/sections/tasks.md +22 -0
- package/templates/sections/tech-stack.md +19 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pfGithubUnlink
|
|
3
|
+
description: Unlink a GitHub repository from the current PlanFlow project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PlanFlow GitHub Unlink
|
|
7
|
+
|
|
8
|
+
Remove the GitHub repository link from the current PlanFlow cloud project.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/pfGithubUnlink # Unlink GitHub repository
|
|
14
|
+
/pfGithubUnlink --force # Skip confirmation
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Step 0: Load Configuration
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
function getMergedConfig() {
|
|
21
|
+
let globalConfig = {}
|
|
22
|
+
let localConfig = {}
|
|
23
|
+
|
|
24
|
+
const globalPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
25
|
+
if (fileExists(globalPath)) {
|
|
26
|
+
try { globalConfig = JSON.parse(readFile(globalPath)) } catch (e) {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (fileExists("./.plan-config.json")) {
|
|
30
|
+
try { localConfig = JSON.parse(readFile("./.plan-config.json")) } catch (e) {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
...globalConfig,
|
|
35
|
+
...localConfig,
|
|
36
|
+
cloud: {
|
|
37
|
+
...(globalConfig.cloud || {}),
|
|
38
|
+
...(localConfig.cloud || {})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const config = getMergedConfig()
|
|
44
|
+
const language = config.language || "en"
|
|
45
|
+
const cloudConfig = config.cloud || {}
|
|
46
|
+
const isAuthenticated = !!cloudConfig.apiToken
|
|
47
|
+
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"
|
|
48
|
+
const projectId = cloudConfig.projectId || null
|
|
49
|
+
|
|
50
|
+
const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Step 1: Validate Prerequisites
|
|
54
|
+
|
|
55
|
+
### Check Authentication
|
|
56
|
+
|
|
57
|
+
If not authenticated:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
61
|
+
│ ❌ ERROR │
|
|
62
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
63
|
+
│ │
|
|
64
|
+
│ {t.commands.sync.notAuthenticated} │
|
|
65
|
+
│ │
|
|
66
|
+
│ 💡 Next Steps: │
|
|
67
|
+
│ • /pfLogin Sign in to PlanFlow │
|
|
68
|
+
│ │
|
|
69
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Check Project Link
|
|
73
|
+
|
|
74
|
+
If not linked to a cloud project:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
78
|
+
│ ❌ ERROR │
|
|
79
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
80
|
+
│ │
|
|
81
|
+
│ {t.commands.sync.notLinked} │
|
|
82
|
+
│ │
|
|
83
|
+
│ 💡 Next Steps: │
|
|
84
|
+
│ • /pfCloudLink Link to existing project │
|
|
85
|
+
│ │
|
|
86
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Step 2: Check Current GitHub Link
|
|
90
|
+
|
|
91
|
+
Fetch current GitHub integration status:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
95
|
+
--connect-timeout 5 \
|
|
96
|
+
--max-time 10 \
|
|
97
|
+
-X GET \
|
|
98
|
+
-H "Accept: application/json" \
|
|
99
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
100
|
+
"${API_URL}/projects/${PROJECT_ID}/integrations/github")
|
|
101
|
+
|
|
102
|
+
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
103
|
+
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Not Linked
|
|
107
|
+
|
|
108
|
+
If no GitHub repository is linked:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
112
|
+
│ ℹ️ INFO │
|
|
113
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
114
|
+
│ │
|
|
115
|
+
│ {t.commands.github.notLinked} │
|
|
116
|
+
│ │
|
|
117
|
+
│ No GitHub repository is linked to this project. │
|
|
118
|
+
│ │
|
|
119
|
+
│ 💡 To link a repository: │
|
|
120
|
+
│ • /pfGithubLink owner/repo │
|
|
121
|
+
│ │
|
|
122
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Step 3: Confirm Unlink (Unless --force)
|
|
126
|
+
|
|
127
|
+
If `--force` flag is not provided, show confirmation:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
131
|
+
│ ⚠️ Confirm Unlink │
|
|
132
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
133
|
+
│ │
|
|
134
|
+
│ You are about to unlink the GitHub repository: │
|
|
135
|
+
│ │
|
|
136
|
+
│ 📦 Repository: owner/repo-name │
|
|
137
|
+
│ 🔗 URL: https://github.com/owner/repo-name │
|
|
138
|
+
│ │
|
|
139
|
+
│ ⚠️ This will: │
|
|
140
|
+
│ • Disconnect the repository from this project │
|
|
141
|
+
│ • Stop auto-completion of tasks on PR merge │
|
|
142
|
+
│ • Remove branch/issue linking features │
|
|
143
|
+
│ │
|
|
144
|
+
│ Note: This does NOT affect your GitHub repository or issues. │
|
|
145
|
+
│ │
|
|
146
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Use AskUserQuestion:
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
AskUserQuestion({
|
|
153
|
+
questions: [{
|
|
154
|
+
question: t.commands.github.confirmUnlink || "Unlink this repository?",
|
|
155
|
+
header: "Confirm",
|
|
156
|
+
multiSelect: false,
|
|
157
|
+
options: [
|
|
158
|
+
{ label: "Yes, unlink", description: "Remove GitHub connection" },
|
|
159
|
+
{ label: "Cancel", description: "Keep the connection" }
|
|
160
|
+
]
|
|
161
|
+
}]
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Step 4: Unlink Repository
|
|
166
|
+
|
|
167
|
+
Make API call to remove the GitHub integration:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
171
|
+
--connect-timeout 5 \
|
|
172
|
+
--max-time 15 \
|
|
173
|
+
-X DELETE \
|
|
174
|
+
-H "Accept: application/json" \
|
|
175
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
176
|
+
"${API_URL}/projects/${PROJECT_ID}/integrations/github")
|
|
177
|
+
|
|
178
|
+
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
179
|
+
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Step 5: Handle Response
|
|
183
|
+
|
|
184
|
+
### Success (200/204)
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
188
|
+
│ ✅ SUCCESS │
|
|
189
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
190
|
+
│ │
|
|
191
|
+
│ {t.commands.github.unlinkSuccess} │
|
|
192
|
+
│ │
|
|
193
|
+
│ GitHub repository unlinked. │
|
|
194
|
+
│ │
|
|
195
|
+
│ 📦 Removed: owner/repo-name │
|
|
196
|
+
│ │
|
|
197
|
+
│ The repository is no longer connected to this project. │
|
|
198
|
+
│ │
|
|
199
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
200
|
+
│ │
|
|
201
|
+
│ 💡 To link a different repository: │
|
|
202
|
+
│ • /pfGithubLink owner/repo │
|
|
203
|
+
│ │
|
|
204
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
205
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Permission Denied (403)
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
212
|
+
│ ❌ ERROR │
|
|
213
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
214
|
+
│ │
|
|
215
|
+
│ {t.commands.github.noPermission} │
|
|
216
|
+
│ │
|
|
217
|
+
│ You don't have permission to unlink repositories. │
|
|
218
|
+
│ │
|
|
219
|
+
│ Only project Admins and Owners can manage integrations. │
|
|
220
|
+
│ │
|
|
221
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Not Found (404)
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
228
|
+
│ ℹ️ INFO │
|
|
229
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
230
|
+
│ │
|
|
231
|
+
│ No GitHub repository was linked to this project. │
|
|
232
|
+
│ │
|
|
233
|
+
│ 💡 To link a repository: │
|
|
234
|
+
│ • /pfGithubLink owner/repo │
|
|
235
|
+
│ │
|
|
236
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Step 6: Update Local Config
|
|
240
|
+
|
|
241
|
+
Remove GitHub info from local config:
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
// Read current local config
|
|
245
|
+
let localConfig = {}
|
|
246
|
+
try {
|
|
247
|
+
localConfig = JSON.parse(readFile("./.plan-config.json"))
|
|
248
|
+
} catch {}
|
|
249
|
+
|
|
250
|
+
// Remove GitHub info
|
|
251
|
+
delete localConfig.github
|
|
252
|
+
|
|
253
|
+
// Save
|
|
254
|
+
writeFile("./.plan-config.json", JSON.stringify(localConfig, null, 2))
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Full Bash Implementation
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
#!/bin/bash
|
|
261
|
+
|
|
262
|
+
# Step 0: Load config
|
|
263
|
+
GLOBAL_CONFIG_PATH="$HOME/.config/claude/plan-plugin-config.json"
|
|
264
|
+
LOCAL_CONFIG_PATH="./.plan-config.json"
|
|
265
|
+
|
|
266
|
+
if [ -f "$GLOBAL_CONFIG_PATH" ]; then
|
|
267
|
+
API_TOKEN=$(jq -r '.cloud.apiToken // empty' "$GLOBAL_CONFIG_PATH")
|
|
268
|
+
API_URL=$(jq -r '.cloud.apiUrl // "https://api.planflow.tools"' "$GLOBAL_CONFIG_PATH")
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
if [ -f "$LOCAL_CONFIG_PATH" ]; then
|
|
272
|
+
PROJECT_ID=$(jq -r '.cloud.projectId // empty' "$LOCAL_CONFIG_PATH")
|
|
273
|
+
LOCAL_TOKEN=$(jq -r '.cloud.apiToken // empty' "$LOCAL_CONFIG_PATH")
|
|
274
|
+
[ -n "$LOCAL_TOKEN" ] && API_TOKEN="$LOCAL_TOKEN"
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# Parse flags
|
|
278
|
+
FORCE=false
|
|
279
|
+
if [ "$1" = "--force" ]; then
|
|
280
|
+
FORCE=true
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# Validate prerequisites
|
|
284
|
+
if [ -z "$API_TOKEN" ]; then
|
|
285
|
+
echo "❌ Not authenticated. Run /pfLogin first."
|
|
286
|
+
exit 1
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
if [ -z "$PROJECT_ID" ]; then
|
|
290
|
+
echo "❌ No project linked. Run /pfCloudLink first."
|
|
291
|
+
exit 1
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
# Check current GitHub link
|
|
295
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
296
|
+
--connect-timeout 5 \
|
|
297
|
+
--max-time 10 \
|
|
298
|
+
-X GET \
|
|
299
|
+
-H "Accept: application/json" \
|
|
300
|
+
-H "Authorization: Bearer $API_TOKEN" \
|
|
301
|
+
"${API_URL}/projects/${PROJECT_ID}/integrations/github")
|
|
302
|
+
|
|
303
|
+
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
304
|
+
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
305
|
+
|
|
306
|
+
if [ "$HTTP_CODE" -ne 200 ]; then
|
|
307
|
+
echo "ℹ️ No GitHub repository is linked to this project."
|
|
308
|
+
echo ""
|
|
309
|
+
echo "To link: /pfGithubLink owner/repo"
|
|
310
|
+
exit 0
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
OWNER=$(echo "$BODY" | jq -r '.data.owner // empty')
|
|
314
|
+
REPO=$(echo "$BODY" | jq -r '.data.repo // empty')
|
|
315
|
+
|
|
316
|
+
if [ -z "$OWNER" ] || [ -z "$REPO" ]; then
|
|
317
|
+
echo "ℹ️ No GitHub repository is linked to this project."
|
|
318
|
+
echo ""
|
|
319
|
+
echo "To link: /pfGithubLink owner/repo"
|
|
320
|
+
exit 0
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
# Show current link and confirm (unless --force)
|
|
324
|
+
if [ "$FORCE" != true ]; then
|
|
325
|
+
echo "⚠️ Confirm Unlink"
|
|
326
|
+
echo ""
|
|
327
|
+
echo " Repository: $OWNER/$REPO"
|
|
328
|
+
echo " URL: https://github.com/$OWNER/$REPO"
|
|
329
|
+
echo ""
|
|
330
|
+
echo "This will disconnect the repository from this project."
|
|
331
|
+
echo ""
|
|
332
|
+
# In actual implementation, use AskUserQuestion tool
|
|
333
|
+
# For bash script, we proceed
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
# Unlink
|
|
337
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
338
|
+
--connect-timeout 5 \
|
|
339
|
+
--max-time 15 \
|
|
340
|
+
-X DELETE \
|
|
341
|
+
-H "Accept: application/json" \
|
|
342
|
+
-H "Authorization: Bearer $API_TOKEN" \
|
|
343
|
+
"${API_URL}/projects/${PROJECT_ID}/integrations/github")
|
|
344
|
+
|
|
345
|
+
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
346
|
+
|
|
347
|
+
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
348
|
+
echo "✅ GitHub repository unlinked!"
|
|
349
|
+
echo ""
|
|
350
|
+
echo " Removed: $OWNER/$REPO"
|
|
351
|
+
echo ""
|
|
352
|
+
echo " To link a different repository:"
|
|
353
|
+
echo " • /pfGithubLink owner/repo"
|
|
354
|
+
|
|
355
|
+
# Remove from local config
|
|
356
|
+
if [ -f "$LOCAL_CONFIG_PATH" ]; then
|
|
357
|
+
jq 'del(.github)' "$LOCAL_CONFIG_PATH" > "${LOCAL_CONFIG_PATH}.tmp" && \
|
|
358
|
+
mv "${LOCAL_CONFIG_PATH}.tmp" "$LOCAL_CONFIG_PATH"
|
|
359
|
+
fi
|
|
360
|
+
elif [ "$HTTP_CODE" -eq 403 ]; then
|
|
361
|
+
echo "❌ Permission denied. Only Admins can manage integrations."
|
|
362
|
+
elif [ "$HTTP_CODE" -eq 401 ]; then
|
|
363
|
+
echo "❌ Authentication failed. Run /pfLogin to refresh."
|
|
364
|
+
else
|
|
365
|
+
echo "❌ Failed to unlink repository (HTTP $HTTP_CODE)"
|
|
366
|
+
fi
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Testing
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Test 1: Unlink when linked
|
|
373
|
+
/pfGithubUnlink
|
|
374
|
+
# Expected: Confirmation prompt, then success
|
|
375
|
+
|
|
376
|
+
# Test 2: Unlink with --force
|
|
377
|
+
/pfGithubUnlink --force
|
|
378
|
+
# Expected: Skip confirmation, direct unlink
|
|
379
|
+
|
|
380
|
+
# Test 3: Unlink when not linked
|
|
381
|
+
/pfGithubUnlink
|
|
382
|
+
# Expected: Info message "No repository linked"
|
|
383
|
+
|
|
384
|
+
# Test 4: Not authenticated
|
|
385
|
+
/pfGithubUnlink
|
|
386
|
+
# Expected: Error "Not authenticated"
|
|
387
|
+
|
|
388
|
+
# Test 5: Permission denied
|
|
389
|
+
# (As viewer role)
|
|
390
|
+
/pfGithubUnlink
|
|
391
|
+
# Expected: Error "Permission denied"
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Success Criteria
|
|
395
|
+
|
|
396
|
+
- [ ] Unlinks GitHub repository from project
|
|
397
|
+
- [ ] Shows confirmation before unlinking (unless --force)
|
|
398
|
+
- [ ] Handles "not linked" case gracefully
|
|
399
|
+
- [ ] Removes GitHub info from local config
|
|
400
|
+
- [ ] Shows helpful next steps
|
|
401
|
+
- [ ] Works in both English and Georgian
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# /pfLive Command
|
|
2
|
+
|
|
3
|
+
Control live updates display settings for real-time task notifications in terminal.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/pfLive [action] [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Actions
|
|
12
|
+
|
|
13
|
+
| Action | Description |
|
|
14
|
+
|--------|-------------|
|
|
15
|
+
| `on` | Enable live updates display |
|
|
16
|
+
| `off` | Disable live updates display |
|
|
17
|
+
| `status` | Show current settings and connection status |
|
|
18
|
+
| `mode <mode>` | Set display mode (minimal/normal/verbose/silent) |
|
|
19
|
+
| `mute <user>` | Mute updates from a specific user |
|
|
20
|
+
| `unmute <user>` | Unmute a previously muted user |
|
|
21
|
+
| `focus <taskId>` | Only show updates for specific task |
|
|
22
|
+
| `unfocus` | Disable focus mode, show all updates |
|
|
23
|
+
| `history [count]` | Show recent update history (default: 10) |
|
|
24
|
+
| `clear` | Clear update history |
|
|
25
|
+
|
|
26
|
+
## Display Modes
|
|
27
|
+
|
|
28
|
+
- **minimal**: Single-line compact updates
|
|
29
|
+
- **normal**: Standard multi-line format with details (default)
|
|
30
|
+
- **verbose**: Full details including timestamps and metadata
|
|
31
|
+
- **silent**: Log only, no terminal output
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Enable live updates
|
|
37
|
+
/pfLive on
|
|
38
|
+
|
|
39
|
+
# Set to minimal mode for less distraction
|
|
40
|
+
/pfLive mode minimal
|
|
41
|
+
|
|
42
|
+
# Mute a noisy teammate
|
|
43
|
+
/pfLive mute john@example.com
|
|
44
|
+
|
|
45
|
+
# Focus on a specific task
|
|
46
|
+
/pfLive focus T5.2
|
|
47
|
+
|
|
48
|
+
# View recent history
|
|
49
|
+
/pfLive history 20
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Implementation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
#!/bin/bash
|
|
56
|
+
# Source the live handler
|
|
57
|
+
source "$(dirname "$0")/../../skills/live-updates/live-handler.sh"
|
|
58
|
+
|
|
59
|
+
# Get command arguments
|
|
60
|
+
ACTION="${1:-status}"
|
|
61
|
+
OPTION="$2"
|
|
62
|
+
|
|
63
|
+
# Load translations
|
|
64
|
+
LANG=$(jq -r '.language // "en"' ~/.plan-config.json 2>/dev/null || echo "en")
|
|
65
|
+
LOCALE_FILE="$(dirname "$0")/../../locales/${LANG}.json"
|
|
66
|
+
|
|
67
|
+
t() {
|
|
68
|
+
local key="$1"
|
|
69
|
+
shift
|
|
70
|
+
local text=$(jq -r ".skills.liveUpdates.${key} // \"${key}\"" "$LOCALE_FILE" 2>/dev/null)
|
|
71
|
+
|
|
72
|
+
# Replace placeholders
|
|
73
|
+
while [[ $# -gt 0 ]]; do
|
|
74
|
+
local placeholder="$1"
|
|
75
|
+
local value="$2"
|
|
76
|
+
text="${text//\{$placeholder\}/$value}"
|
|
77
|
+
shift 2
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
echo "$text"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Execute the command
|
|
84
|
+
case "$ACTION" in
|
|
85
|
+
"on")
|
|
86
|
+
pf_live "on"
|
|
87
|
+
echo "$(t enabled)"
|
|
88
|
+
;;
|
|
89
|
+
"off")
|
|
90
|
+
pf_live "off"
|
|
91
|
+
echo "$(t disabled)"
|
|
92
|
+
;;
|
|
93
|
+
"status")
|
|
94
|
+
show_live_status
|
|
95
|
+
;;
|
|
96
|
+
"mode")
|
|
97
|
+
if [[ -z "$OPTION" ]]; then
|
|
98
|
+
echo "Usage: /pfLive mode <minimal|normal|verbose|silent>"
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
pf_live "mode" "$OPTION"
|
|
102
|
+
echo "$(t modeSet "mode" "$OPTION")"
|
|
103
|
+
;;
|
|
104
|
+
"mute")
|
|
105
|
+
if [[ -z "$OPTION" ]]; then
|
|
106
|
+
echo "Usage: /pfLive mute <user_email>"
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
pf_live "mute" "$OPTION"
|
|
110
|
+
echo "$(t muted "user" "$OPTION")"
|
|
111
|
+
;;
|
|
112
|
+
"unmute")
|
|
113
|
+
if [[ -z "$OPTION" ]]; then
|
|
114
|
+
echo "Usage: /pfLive unmute <user_email>"
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
pf_live "unmute" "$OPTION"
|
|
118
|
+
echo "$(t unmuted "user" "$OPTION")"
|
|
119
|
+
;;
|
|
120
|
+
"focus")
|
|
121
|
+
if [[ -z "$OPTION" ]]; then
|
|
122
|
+
echo "Usage: /pfLive focus <task_id>"
|
|
123
|
+
exit 1
|
|
124
|
+
fi
|
|
125
|
+
pf_live "focus" "$OPTION"
|
|
126
|
+
echo "$(t focusEnabled "taskId" "$OPTION")"
|
|
127
|
+
;;
|
|
128
|
+
"unfocus")
|
|
129
|
+
pf_live "unfocus"
|
|
130
|
+
echo "$(t focusDisabled)"
|
|
131
|
+
;;
|
|
132
|
+
"history")
|
|
133
|
+
show_history "${OPTION:-10}"
|
|
134
|
+
;;
|
|
135
|
+
"clear")
|
|
136
|
+
rm -f "$HISTORY_FILE"
|
|
137
|
+
echo "History cleared"
|
|
138
|
+
;;
|
|
139
|
+
*)
|
|
140
|
+
echo "Unknown action: $ACTION"
|
|
141
|
+
echo "Usage: /pfLive [on|off|status|mode|mute|unmute|focus|unfocus|history|clear]"
|
|
142
|
+
exit 1
|
|
143
|
+
;;
|
|
144
|
+
esac
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Configuration
|
|
148
|
+
|
|
149
|
+
Settings are stored in `~/.planflow-live-updates.json`:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"enabled": true,
|
|
154
|
+
"displayMode": "normal",
|
|
155
|
+
"mutedUsers": [],
|
|
156
|
+
"mutedTasks": [],
|
|
157
|
+
"focusTask": null,
|
|
158
|
+
"quietHours": {
|
|
159
|
+
"enabled": false,
|
|
160
|
+
"start": "22:00",
|
|
161
|
+
"end": "08:00"
|
|
162
|
+
},
|
|
163
|
+
"sounds": false
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Event Types Displayed
|
|
168
|
+
|
|
169
|
+
| Event | Description |
|
|
170
|
+
|-------|-------------|
|
|
171
|
+
| `task_updated` | Task status changes (started, completed, blocked) |
|
|
172
|
+
| `assignment` | Task assignments and unassignments |
|
|
173
|
+
| `comment` | New comments on tasks |
|
|
174
|
+
| `presence` | Team member online/offline status |
|
|
175
|
+
| `notification` | System notifications |
|
|
176
|
+
|
|
177
|
+
## Integration
|
|
178
|
+
|
|
179
|
+
This command works with the WebSocket connection established by `/pfSyncPush` or `/pfSyncPull`. Live updates are received automatically when connected to a cloud project.
|
|
180
|
+
|
|
181
|
+
## See Also
|
|
182
|
+
|
|
183
|
+
- [Live Updates Skill](/skills/live-updates/SKILL.md)
|
|
184
|
+
- [WebSocket Skill](/skills/websocket/SKILL.md)
|
|
185
|
+
- [Presence Broadcast Skill](/skills/presence-broadcast/SKILL.md)
|