@flydocs/cli 0.6.0-alpha.4 → 0.6.0-alpha.6
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/dist/cli.js +12 -16
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +11 -9
- package/template/.claude/commands/flydocs-setup.md +34 -19
- package/template/.claude/commands/knowledge.md +61 -0
- package/template/.claude/skills/flydocs-cloud/SKILL.md +43 -36
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +19 -2
- package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +3 -3
- package/template/.claude/skills/flydocs-cloud/scripts/delete_milestone.py +21 -0
- package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +9 -5
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +4 -0
- package/template/.claude/skills/flydocs-cloud/scripts/get_estimate_scale.py +23 -0
- package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +1 -1
- package/template/.claude/skills/flydocs-cloud/scripts/refresh_labels.py +87 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_identity.py +38 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_preferences.py +49 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +5 -4
- package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +22 -4
- package/template/.claude/skills/flydocs-cloud/scripts/update_milestone.py +42 -0
- package/template/.claude/skills/flydocs-workflow/SKILL.md +23 -18
- package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
- package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +105 -0
- package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
- package/template/.claude/skills/flydocs-workflow/session.md +24 -16
- package/template/.claude/skills/flydocs-workflow/stages/capture.md +8 -3
- package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
- package/template/.claude/skills/flydocs-workflow/stages/implement.md +28 -4
- package/template/.claude/skills/flydocs-workflow/stages/refine.md +20 -4
- package/template/.claude/skills/flydocs-workflow/stages/review.md +14 -2
- package/template/.flydocs/config.json +2 -2
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +8 -8
- package/template/flydocs/knowledge/INDEX.md +38 -53
- package/template/flydocs/knowledge/README.md +60 -9
- package/template/flydocs/knowledge/templates/decision.md +47 -0
- package/template/flydocs/knowledge/templates/feature.md +35 -0
- package/template/flydocs/knowledge/templates/note.md +25 -0
- package/template/manifest.json +8 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Refresh label config from the relay — validates and updates local config.
|
|
3
|
+
|
|
4
|
+
Fetches current team labels from the relay, compares against local config,
|
|
5
|
+
and reports any stale or missing label IDs. With --fix, updates local config
|
|
6
|
+
to match the relay's current state.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
14
|
+
from flydocs_api import get_client, output_json, fail
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
fix_mode = "--fix" in sys.argv
|
|
19
|
+
|
|
20
|
+
client = get_client()
|
|
21
|
+
|
|
22
|
+
# Fetch current labels from relay
|
|
23
|
+
labels = client.get("/labels")
|
|
24
|
+
label_map = {l["id"]: l["name"] for l in labels}
|
|
25
|
+
label_by_name = {l["name"].lower(): l["id"] for l in labels}
|
|
26
|
+
|
|
27
|
+
# Load local config
|
|
28
|
+
config_path = client.config_path
|
|
29
|
+
if not config_path.exists():
|
|
30
|
+
fail("No .flydocs/config.json found")
|
|
31
|
+
|
|
32
|
+
with open(config_path, "r") as f:
|
|
33
|
+
config = json.load(f)
|
|
34
|
+
|
|
35
|
+
issue_labels = config.get("issueLabels", {})
|
|
36
|
+
stale: list[dict] = []
|
|
37
|
+
valid: list[dict] = []
|
|
38
|
+
|
|
39
|
+
# Check each label ID in config against relay
|
|
40
|
+
for category, entries in issue_labels.items():
|
|
41
|
+
if isinstance(entries, dict):
|
|
42
|
+
for key, label_id in entries.items():
|
|
43
|
+
if label_id in label_map:
|
|
44
|
+
valid.append({"category": category, "key": key, "id": label_id, "name": label_map[label_id]})
|
|
45
|
+
else:
|
|
46
|
+
# Try to find by key name
|
|
47
|
+
resolved = label_by_name.get(key.lower())
|
|
48
|
+
stale.append({
|
|
49
|
+
"category": category,
|
|
50
|
+
"key": key,
|
|
51
|
+
"staleId": label_id,
|
|
52
|
+
"resolvedId": resolved,
|
|
53
|
+
"resolvedName": key if resolved else None,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if fix_mode and stale:
|
|
57
|
+
# Update stale IDs in config
|
|
58
|
+
fixed = 0
|
|
59
|
+
for item in stale:
|
|
60
|
+
if item["resolvedId"]:
|
|
61
|
+
issue_labels[item["category"]][item["key"]] = item["resolvedId"]
|
|
62
|
+
fixed += 1
|
|
63
|
+
|
|
64
|
+
with open(config_path, "w") as f:
|
|
65
|
+
json.dump(config, f, indent=2)
|
|
66
|
+
f.write("\n")
|
|
67
|
+
|
|
68
|
+
output_json({
|
|
69
|
+
"success": True,
|
|
70
|
+
"valid": len(valid),
|
|
71
|
+
"stale": len(stale),
|
|
72
|
+
"fixed": fixed,
|
|
73
|
+
"unfixable": len(stale) - fixed,
|
|
74
|
+
"details": stale,
|
|
75
|
+
})
|
|
76
|
+
else:
|
|
77
|
+
output_json({
|
|
78
|
+
"valid": len(valid),
|
|
79
|
+
"stale": len(stale),
|
|
80
|
+
"totalProviderLabels": len(labels),
|
|
81
|
+
"details": stale if stale else "All label IDs are current",
|
|
82
|
+
"hint": "Run with --fix to update stale IDs" if stale else None,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Set provider identity via the FlyDocs Relay API.
|
|
3
|
+
|
|
4
|
+
Binds the user's provider-specific ID to their FlyDocs user record.
|
|
5
|
+
Once set, ?mine=true resolves via exact provider ID matching.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
12
|
+
from flydocs_api import get_client, output_json, fail
|
|
13
|
+
|
|
14
|
+
VALID_PROVIDERS = ("linear", "jira", "gitlab")
|
|
15
|
+
|
|
16
|
+
if len(sys.argv) < 3:
|
|
17
|
+
fail(f"Usage: set_identity.py <provider> <provider-user-id>\n Providers: {', '.join(VALID_PROVIDERS)}")
|
|
18
|
+
|
|
19
|
+
provider = sys.argv[1].lower()
|
|
20
|
+
provider_id = sys.argv[2]
|
|
21
|
+
|
|
22
|
+
if provider not in VALID_PROVIDERS:
|
|
23
|
+
fail(f"Invalid provider: {provider}. Must be one of: {', '.join(VALID_PROVIDERS)}")
|
|
24
|
+
|
|
25
|
+
if not provider_id:
|
|
26
|
+
fail("Provider user ID cannot be empty")
|
|
27
|
+
|
|
28
|
+
client = get_client()
|
|
29
|
+
result = client.post("/auth/identity", {
|
|
30
|
+
"provider": provider,
|
|
31
|
+
"providerId": provider_id,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
output_json({
|
|
35
|
+
"success": result.get("success", True),
|
|
36
|
+
"provider": result.get("provider", provider),
|
|
37
|
+
"providerId": result.get("providerId", provider_id),
|
|
38
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Get or set user preferences via the FlyDocs Relay API.
|
|
3
|
+
|
|
4
|
+
With no arguments, returns current preferences (GET).
|
|
5
|
+
With flags, updates preferences (POST).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
13
|
+
from flydocs_api import get_client, output_json, fail
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main():
|
|
17
|
+
parser = argparse.ArgumentParser(description="Get or set user preferences")
|
|
18
|
+
parser.add_argument("--workspace", default=None, help="Default workspace ID")
|
|
19
|
+
parser.add_argument("--assignee", default=None, help="Default assignee ('self' or user ID)")
|
|
20
|
+
parser.add_argument("--display", default=None, help="Display preferences (JSON string)")
|
|
21
|
+
args = parser.parse_args()
|
|
22
|
+
|
|
23
|
+
client = get_client()
|
|
24
|
+
|
|
25
|
+
# If no flags provided, GET current preferences
|
|
26
|
+
if args.workspace is None and args.assignee is None and args.display is None:
|
|
27
|
+
result = client.get("/auth/preferences")
|
|
28
|
+
output_json(result)
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
# Build update body from provided flags
|
|
32
|
+
body: dict = {}
|
|
33
|
+
if args.workspace is not None:
|
|
34
|
+
body["defaultWorkspaceId"] = args.workspace
|
|
35
|
+
if args.assignee is not None:
|
|
36
|
+
body["defaultAssignee"] = args.assignee
|
|
37
|
+
if args.display is not None:
|
|
38
|
+
body["displayPreferences"] = args.display
|
|
39
|
+
|
|
40
|
+
result = client.post("/auth/preferences", body)
|
|
41
|
+
|
|
42
|
+
output_json({
|
|
43
|
+
"success": result.get("success", True),
|
|
44
|
+
"preferences": result.get("preferences", body),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main()
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Set team preference via the FlyDocs Relay API.
|
|
2
|
+
"""Set team/project preference via the FlyDocs Relay API.
|
|
3
3
|
|
|
4
4
|
Stores the team preference on the relay (for server-side scoping)
|
|
5
5
|
and updates the local config (for display/reference).
|
|
6
|
+
For Jira, this sets the active Jira project.
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
import argparse
|
|
@@ -15,8 +16,8 @@ from flydocs_api import get_client, output_json, fail
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def main():
|
|
18
|
-
parser = argparse.ArgumentParser(description="Set team preference")
|
|
19
|
-
parser.add_argument("team_id", help="
|
|
19
|
+
parser = argparse.ArgumentParser(description="Set team or project preference")
|
|
20
|
+
parser.add_argument("team_id", help="Provider team/workspace UUID")
|
|
20
21
|
args = parser.parse_args()
|
|
21
22
|
|
|
22
23
|
client = get_client()
|
|
@@ -28,7 +29,7 @@ def main():
|
|
|
28
29
|
with open(config_path, "r") as f:
|
|
29
30
|
config = json.load(f)
|
|
30
31
|
if "provider" not in config:
|
|
31
|
-
config["provider"] = {"type":
|
|
32
|
+
config["provider"] = {"type": None, "teamId": None}
|
|
32
33
|
config["provider"]["teamId"] = args.team_id
|
|
33
34
|
with open(config_path, "w") as f:
|
|
34
35
|
json.dump(config, f, indent=2)
|
|
@@ -13,13 +13,14 @@ def main():
|
|
|
13
13
|
parser = argparse.ArgumentParser(description="Update issue fields")
|
|
14
14
|
parser.add_argument("ref", help="Issue reference (e.g., ENG-123)")
|
|
15
15
|
parser.add_argument("--title", default=None)
|
|
16
|
-
parser.add_argument("--priority", type=int,
|
|
17
|
-
parser.add_argument("--estimate", type=int,
|
|
16
|
+
parser.add_argument("--priority", type=int, help="Priority (0-4, relay translates per provider)")
|
|
17
|
+
parser.add_argument("--estimate", type=int, help="Estimate points (relay translates per provider)")
|
|
18
18
|
parser.add_argument("--assignee", default=None)
|
|
19
19
|
parser.add_argument("--state", default=None)
|
|
20
20
|
parser.add_argument("--description", default=None)
|
|
21
21
|
parser.add_argument("--description-file", default=None)
|
|
22
22
|
parser.add_argument("--labels", default=None, help="Comma-separated label names")
|
|
23
|
+
parser.add_argument("--milestone", default=None, help="Milestone ID or name (resolved by name lookup)")
|
|
23
24
|
parser.add_argument("--comment", default=None)
|
|
24
25
|
args = parser.parse_args()
|
|
25
26
|
|
|
@@ -65,10 +66,27 @@ def main():
|
|
|
65
66
|
body["comment"] = args.comment
|
|
66
67
|
updated_fields.append("comment")
|
|
67
68
|
|
|
68
|
-
if not body:
|
|
69
|
-
fail("No fields to update. Use --title, --priority, --estimate, --assignee, --state, --description, --labels, or --comment")
|
|
69
|
+
if not body and args.milestone is None:
|
|
70
|
+
fail("No fields to update. Use --title, --priority, --estimate, --assignee, --state, --description, --labels, --milestone, or --comment")
|
|
70
71
|
|
|
71
72
|
client = get_client()
|
|
73
|
+
|
|
74
|
+
if args.milestone is not None:
|
|
75
|
+
milestone_id = args.milestone
|
|
76
|
+
# If it doesn't look like a UUID, resolve by name
|
|
77
|
+
if len(milestone_id) != 36 or "-" not in milestone_id:
|
|
78
|
+
milestones = client.get("/milestones")
|
|
79
|
+
match = None
|
|
80
|
+
for m in milestones:
|
|
81
|
+
if m["name"].lower() == milestone_id.lower():
|
|
82
|
+
match = m
|
|
83
|
+
break
|
|
84
|
+
if not match:
|
|
85
|
+
fail(f"Milestone not found: {milestone_id}")
|
|
86
|
+
milestone_id = match["id"]
|
|
87
|
+
body["milestoneId"] = milestone_id
|
|
88
|
+
updated_fields.append("milestone")
|
|
89
|
+
|
|
72
90
|
result = client.patch(f"/issues/{args.ref}", body)
|
|
73
91
|
|
|
74
92
|
output_json({
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Update a milestone via the FlyDocs Relay API."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
9
|
+
from flydocs_api import get_client, output_json, fail
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
parser = argparse.ArgumentParser(description="Update milestone")
|
|
14
|
+
parser.add_argument("milestone_id", help="Milestone UUID")
|
|
15
|
+
parser.add_argument("--name", default=None)
|
|
16
|
+
parser.add_argument("--target-date", default=None, dest="target_date")
|
|
17
|
+
parser.add_argument("--description", default=None)
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
body: dict = {}
|
|
21
|
+
if args.name is not None:
|
|
22
|
+
body["name"] = args.name
|
|
23
|
+
if args.target_date is not None:
|
|
24
|
+
body["targetDate"] = args.target_date
|
|
25
|
+
if args.description is not None:
|
|
26
|
+
body["description"] = args.description
|
|
27
|
+
|
|
28
|
+
if not body:
|
|
29
|
+
fail("No fields to update. Use --name, --target-date, or --description")
|
|
30
|
+
|
|
31
|
+
client = get_client()
|
|
32
|
+
result = client.patch(f"/milestones/{args.milestone_id}", body)
|
|
33
|
+
|
|
34
|
+
output_json({
|
|
35
|
+
"success": result.get("success", True),
|
|
36
|
+
"id": result.get("id", args.milestone_id),
|
|
37
|
+
"name": result.get("name", args.name),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
main()
|
|
@@ -17,6 +17,10 @@ triggers:
|
|
|
17
17
|
- transition
|
|
18
18
|
- status
|
|
19
19
|
- issue
|
|
20
|
+
- knowledge
|
|
21
|
+
- document
|
|
22
|
+
- PR
|
|
23
|
+
- pull request
|
|
20
24
|
---
|
|
21
25
|
|
|
22
26
|
# FlyDocs Workflow
|
|
@@ -35,32 +39,33 @@ Capture → Refine → Activate → Implement → Review → Validate → Close
|
|
|
35
39
|
|
|
36
40
|
## Stage Index
|
|
37
41
|
|
|
38
|
-
| Stage
|
|
39
|
-
|
|
40
|
-
| Capture
|
|
41
|
-
| Refine
|
|
42
|
-
| Activate
|
|
43
|
-
| Implement | stages/implement.md | Build + test + simplify
|
|
44
|
-
| Review
|
|
45
|
-
| Validate
|
|
46
|
-
| Close
|
|
42
|
+
| Stage | File | Intent | Agent |
|
|
43
|
+
| --------- | ------------------- | ------------------------ | -------------- |
|
|
44
|
+
| Capture | stages/capture.md | Create issue from input | PM |
|
|
45
|
+
| Refine | stages/refine.md | Triage + spec completion | PM |
|
|
46
|
+
| Activate | stages/activate.md | Assign + start work | PM |
|
|
47
|
+
| Implement | stages/implement.md | Build + test + simplify | Implementation |
|
|
48
|
+
| Review | stages/review.md | Code quality validation | Review |
|
|
49
|
+
| Validate | stages/validate.md | User acceptance testing | QE |
|
|
50
|
+
| Close | stages/close.md | Archive completed work | PM |
|
|
47
51
|
|
|
48
52
|
## Session
|
|
49
53
|
|
|
50
|
-
| Action
|
|
51
|
-
|
|
52
|
-
| Start session
|
|
53
|
-
| Wrap session
|
|
54
|
+
| Action | File |
|
|
55
|
+
| --------------- | ---------- |
|
|
56
|
+
| Start session | session.md |
|
|
57
|
+
| Wrap session | session.md |
|
|
54
58
|
| Stale detection | session.md |
|
|
55
59
|
|
|
56
60
|
## Reference
|
|
57
61
|
|
|
58
|
-
| Topic
|
|
59
|
-
|
|
60
|
-
| Comment templates
|
|
61
|
-
| Status transitions
|
|
62
|
+
| Topic | File |
|
|
63
|
+
| -------------------- | ------------------------------- |
|
|
64
|
+
| Comment templates | reference/comment-templates.md |
|
|
65
|
+
| Status transitions | reference/status-workflow.md |
|
|
62
66
|
| Priority & estimates | reference/priority-estimates.md |
|
|
63
|
-
|
|
|
67
|
+
| PR & git workflow | reference/pr-workflow.md |
|
|
68
|
+
| Golden rules | reference/golden-rules.md |
|
|
64
69
|
|
|
65
70
|
## Templates
|
|
66
71
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# PR & Git Workflow
|
|
2
|
+
|
|
3
|
+
## Branch Naming
|
|
4
|
+
|
|
5
|
+
Format: `<type>/<ref>-<slug>`
|
|
6
|
+
|
|
7
|
+
| Type | When |
|
|
8
|
+
| --------- | -------------------------------------- |
|
|
9
|
+
| `feature` | New functionality |
|
|
10
|
+
| `fix` | Bug fixes |
|
|
11
|
+
| `chore` | Maintenance, refactoring, dependencies |
|
|
12
|
+
| `docs` | Documentation only |
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
|
|
16
|
+
- `feature/FLY-255-knowledge-capture`
|
|
17
|
+
- `fix/FLY-301-login-timeout`
|
|
18
|
+
- `chore/FLY-290-upgrade-deps`
|
|
19
|
+
|
|
20
|
+
Keep the slug short (2-4 words, kebab-case). Include the issue reference.
|
|
21
|
+
|
|
22
|
+
## Commit Messages
|
|
23
|
+
|
|
24
|
+
Format: `<type>: <description> (<ref>)`
|
|
25
|
+
|
|
26
|
+
- Lead with what changed, not how
|
|
27
|
+
- Use imperative mood ("Add", not "Added")
|
|
28
|
+
- Keep the first line under 72 characters
|
|
29
|
+
- Add a body for non-obvious changes
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
feat: Add knowledge doc templates and /knowledge command (FLY-255)
|
|
35
|
+
fix: Handle null milestone in create_issue response (FLY-301)
|
|
36
|
+
chore: Remove deprecated auth middleware (FLY-290)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## When to Create a PR
|
|
40
|
+
|
|
41
|
+
**Create a PR when:**
|
|
42
|
+
|
|
43
|
+
- Changes affect shared code (not just local config or docs)
|
|
44
|
+
- Multiple files changed across different concerns
|
|
45
|
+
- Changes need review before merging
|
|
46
|
+
- Working on a branch (not committing directly to main)
|
|
47
|
+
|
|
48
|
+
**Commit directly when:**
|
|
49
|
+
|
|
50
|
+
- Single-file documentation updates
|
|
51
|
+
- Config changes for local development
|
|
52
|
+
- Trivial fixes (typos, formatting)
|
|
53
|
+
- The user explicitly requests direct commit
|
|
54
|
+
|
|
55
|
+
When in doubt, create a PR. It's easier to merge a PR than to revert a direct commit.
|
|
56
|
+
|
|
57
|
+
## PR Description Template
|
|
58
|
+
|
|
59
|
+
```markdown
|
|
60
|
+
## Summary
|
|
61
|
+
|
|
62
|
+
[1-3 bullet points describing what changed and why]
|
|
63
|
+
|
|
64
|
+
Closes [ISSUE-REF]
|
|
65
|
+
|
|
66
|
+
## Changes
|
|
67
|
+
|
|
68
|
+
- [Key change 1]
|
|
69
|
+
- [Key change 2]
|
|
70
|
+
- [Key change 3]
|
|
71
|
+
|
|
72
|
+
## Test Plan
|
|
73
|
+
|
|
74
|
+
- [ ] [How to verify change 1]
|
|
75
|
+
- [ ] [How to verify change 2]
|
|
76
|
+
|
|
77
|
+
## Notes
|
|
78
|
+
|
|
79
|
+
[Anything reviewers should know — tradeoffs, follow-up work, decisions made]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## PR Workflow in Practice
|
|
83
|
+
|
|
84
|
+
### During Implement Stage
|
|
85
|
+
|
|
86
|
+
After self-review (step 7 in `implement.md`), before handing off to review:
|
|
87
|
+
|
|
88
|
+
1. Create branch: `git checkout -b <type>/<ref>-<slug>`
|
|
89
|
+
2. Stage and commit changes with a descriptive message
|
|
90
|
+
3. Push branch: `git push -u origin <branch>`
|
|
91
|
+
4. Create PR with the template above, linking the issue
|
|
92
|
+
5. Include the PR link in the "Ready for Review" comment
|
|
93
|
+
|
|
94
|
+
### During Review Stage
|
|
95
|
+
|
|
96
|
+
The reviewer should:
|
|
97
|
+
|
|
98
|
+
- Review the PR diff (not just local git diff)
|
|
99
|
+
- Leave comments on the PR for specific code feedback
|
|
100
|
+
- Reference the PR in review comments on the issue
|
|
101
|
+
|
|
102
|
+
### After Review
|
|
103
|
+
|
|
104
|
+
- **Approved**: Merge the PR, then transition issue to Testing
|
|
105
|
+
- **Changes needed**: Push fixes to the same branch, re-request review
|
|
@@ -2,27 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
## Priority Values
|
|
4
4
|
|
|
5
|
-
| Value | Name
|
|
6
|
-
|
|
7
|
-
| 0
|
|
8
|
-
| 1
|
|
9
|
-
| 2
|
|
10
|
-
| 3
|
|
11
|
-
| 4
|
|
5
|
+
| Value | Name | Use When |
|
|
6
|
+
| ----- | ------ | ------------------------- |
|
|
7
|
+
| 0 | None | Not yet triaged |
|
|
8
|
+
| 1 | Urgent | Drop everything, fix now |
|
|
9
|
+
| 2 | High | Next up, unblocks others |
|
|
10
|
+
| 3 | Medium | Normal priority (default) |
|
|
11
|
+
| 4 | Low | Nice to have |
|
|
12
12
|
|
|
13
13
|
## Estimate Values (Complexity)
|
|
14
14
|
|
|
15
|
-
| Value | Name | Rough Effort
|
|
16
|
-
|
|
17
|
-
| 1
|
|
18
|
-
| 2
|
|
19
|
-
| 3
|
|
20
|
-
| 4
|
|
21
|
-
| 5
|
|
15
|
+
| Value | Name | Rough Effort |
|
|
16
|
+
| ----- | ---- | -------------------- |
|
|
17
|
+
| 1 | XS | < 1 hour |
|
|
18
|
+
| 2 | S | 1-4 hours |
|
|
19
|
+
| 3 | M | Half day to full day |
|
|
20
|
+
| 4 | L | 2-3 days |
|
|
21
|
+
| 5 | XL | Week+ |
|
|
22
22
|
|
|
23
23
|
## Guidance
|
|
24
24
|
|
|
25
25
|
- Set priority during Refine or Activate stages
|
|
26
26
|
- Set estimate during Refine stage (before Ready)
|
|
27
27
|
- If estimate is missing at Activate, set it before transitioning
|
|
28
|
-
-
|
|
28
|
+
- Estimate values may vary by provider — the relay translates per provider configuration
|
|
29
|
+
|
|
30
|
+
## Decomposition
|
|
31
|
+
|
|
32
|
+
When an estimate is large (XL / 5+ or provider equivalent), prompt for decomposition:
|
|
33
|
+
|
|
34
|
+
1. **Identify natural boundaries** — separate concerns, independent deliverables, sequential phases
|
|
35
|
+
2. **Create child issues** — each should be independently estimable at M or smaller
|
|
36
|
+
3. **Link parent to children** — use `link.py` with type `blocks` (parent blocks children conceptually)
|
|
37
|
+
4. **Re-estimate parent** — set to 0 or remove estimate, since children carry the work
|
|
38
|
+
5. **Move parent to a tracking role** — it becomes the "epic" or summary issue
|
|
39
|
+
|
|
40
|
+
**Split pattern:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Original: FLY-100 "Build auth system" (XL)
|
|
44
|
+
→ FLY-101 "Add login endpoint" (S)
|
|
45
|
+
→ FLY-102 "Add session management" (M)
|
|
46
|
+
→ FLY-103 "Add role-based access control" (M)
|
|
47
|
+
→ FLY-104 "Add password reset flow" (S)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Don't force decomposition on every large issue — some are genuinely large and atomic. Use judgment. The prompt is: "This is estimated as XL. Can it be broken into smaller, independently deliverable pieces?"
|
|
@@ -52,6 +52,7 @@ When a conversation begins or the user returns after a gap:
|
|
|
52
52
|
|
|
53
53
|
7. **Surface other product issues briefly** — If there are issues in the product scope
|
|
54
54
|
but outside the active project, mention the count with a one-line summary:
|
|
55
|
+
|
|
55
56
|
```
|
|
56
57
|
Also in [Product Name]: [N] issues across other projects (use --all to see)
|
|
57
58
|
```
|
|
@@ -69,10 +70,16 @@ automatically via the config cascade.
|
|
|
69
70
|
When the user indicates they're done for the session:
|
|
70
71
|
|
|
71
72
|
1. **Gather session data** — What was completed, what's in progress, what's blocked.
|
|
72
|
-
2. **
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
2. **Knowledge capture check** — Review the session's work for uncaptured knowledge:
|
|
74
|
+
- Were any architectural decisions made?
|
|
75
|
+
- Were any non-obvious behaviors or workarounds discovered?
|
|
76
|
+
- Were any patterns established that future work should follow?
|
|
77
|
+
- Did debugging reveal something worth documenting?
|
|
78
|
+
If yes, prompt the user: "This session involved [specific discovery]. Should we capture it in a knowledge doc before wrapping?" Use `/knowledge` if they agree.
|
|
79
|
+
3. **Compose summary** using the template below.
|
|
80
|
+
4. **Determine health status** — See health table.
|
|
81
|
+
5. **Post project update** — `project_update.py` with health and summary body.
|
|
82
|
+
6. **Record session in context graph** — Call `graph_session.py` with summary and issues worked on:
|
|
76
83
|
```
|
|
77
84
|
python3 .claude/skills/flydocs-context-graph/scripts/graph_session.py \
|
|
78
85
|
--summary "Brief summary of session outcomes" \
|
|
@@ -80,8 +87,8 @@ When the user indicates they're done for the session:
|
|
|
80
87
|
[--decision NNN]
|
|
81
88
|
```
|
|
82
89
|
This creates a session node for cross-session continuity. Skip silently if the script is not installed.
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
7. **Verify** — Confirm the project update was posted (update ID returned).
|
|
91
|
+
8. **Ask about uncommitted changes** — If git shows uncommitted work, offer to commit.
|
|
85
92
|
|
|
86
93
|
Do not just summarize in chat. Actually post the update. Do not skip if the user seems in a hurry.
|
|
87
94
|
|
|
@@ -104,15 +111,16 @@ Do not just summarize in chat. Actually post the update. Do not skip if the user
|
|
|
104
111
|
|
|
105
112
|
### Health Status
|
|
106
113
|
|
|
107
|
-
| Status
|
|
108
|
-
|
|
109
|
-
| onTrack
|
|
110
|
-
| atRisk
|
|
114
|
+
| Status | When to Use |
|
|
115
|
+
| -------- | ------------------------------- |
|
|
116
|
+
| onTrack | Progress made, no blockers |
|
|
117
|
+
| atRisk | Minor delays, attention needed |
|
|
111
118
|
| offTrack | Major blockers, behind schedule |
|
|
112
119
|
|
|
113
120
|
### Wrap Detection Phrases
|
|
114
121
|
|
|
115
122
|
Offer session wrap when the user says:
|
|
123
|
+
|
|
116
124
|
- "I'm done for today" / "wrapping up" / "that's it for now"
|
|
117
125
|
- "save progress" / "end of day" / "stopping here"
|
|
118
126
|
|
|
@@ -120,9 +128,9 @@ Offer session wrap when the user says:
|
|
|
120
128
|
|
|
121
129
|
Proactively surface issues that may be stuck:
|
|
122
130
|
|
|
123
|
-
| State
|
|
124
|
-
|
|
125
|
-
| Implementing | > 7 days without activity | Warn
|
|
126
|
-
| Review
|
|
127
|
-
| Testing/QA
|
|
128
|
-
| Blocked
|
|
131
|
+
| State | Threshold | Action |
|
|
132
|
+
| ------------ | ------------------------- | -------------- |
|
|
133
|
+
| Implementing | > 7 days without activity | Warn |
|
|
134
|
+
| Review | > 3 days without activity | Warn |
|
|
135
|
+
| Testing/QA | > 3 days without activity | Warn |
|
|
136
|
+
| Blocked | Any | Always surface |
|
|
@@ -21,9 +21,14 @@ When the user has enough context to describe the issue:
|
|
|
21
21
|
- **Why** — User story or business value
|
|
22
22
|
- **How** — Technical notes or approach (if known)
|
|
23
23
|
- **Done when** — Acceptance criteria as checkboxes
|
|
24
|
-
4. **
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
4. **Apply labels** — Include appropriate labels from config:
|
|
25
|
+
- **Category label**: Automatic from issue type (feature, bug, chore, idea) via `issueLabels.category` in config
|
|
26
|
+
- **Repo label**: If multi-repo workspace, apply the repo label from `issueLabels.repo` in config
|
|
27
|
+
- **Product labels**: Applied automatically by the mechanism scripts from `workspace.product.labelIds`
|
|
28
|
+
- **Ad-hoc labels**: Only if explicitly relevant (e.g., "accessibility", "performance")
|
|
29
|
+
5. **Create issue** — `create_issue.py` with title, type, description, priority, estimate (if known), and labels.
|
|
30
|
+
6. **Add comment** — Use the Capture template from `reference/comment-templates.md`.
|
|
31
|
+
7. **Verify** — Confirm issue identifier returned.
|
|
27
32
|
|
|
28
33
|
### Quick Capture
|
|
29
34
|
|
|
@@ -11,12 +11,13 @@ Archive verified and completed work.
|
|
|
11
11
|
## Steps
|
|
12
12
|
|
|
13
13
|
1. **Verify QE approval** — Check issue comments for a "QE Approved" comment. If not found, do not close — direct to Validate stage first.
|
|
14
|
-
2. **
|
|
14
|
+
2. **Final knowledge check** — If the issue involved significant implementation, verify `knowledge/INDEX.md` reflects any decisions or discoveries. This is informational — don't block close, but prompt the user if notable knowledge appears uncaptured.
|
|
15
|
+
3. **Determine terminal state:**
|
|
15
16
|
- **Done** — Work completed and verified (normal path)
|
|
16
17
|
- **Archived** — Deferring to a later date (not cancelled, may return)
|
|
17
18
|
- **Canceled** — Not pursuing (won't be done)
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
4. **Transition** — `transition.py` with the appropriate Close comment from `reference/comment-templates.md`.
|
|
20
|
+
5. **Verify** — Confirm terminal state reached.
|
|
20
21
|
|
|
21
22
|
## Gates
|
|
22
23
|
|