cortexhawk 3.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.
Files changed (136) hide show
  1. package/.cortexhawk-team.yml +65 -0
  2. package/CHANGELOG.md +268 -0
  3. package/CLAUDE.md +96 -0
  4. package/LICENSE +21 -0
  5. package/PACKS.md +14 -0
  6. package/README.md +418 -0
  7. package/REGISTRY.md +23 -0
  8. package/agents/architect.md +46 -0
  9. package/agents/brainstormer.md +57 -0
  10. package/agents/code-simplifier.md +56 -0
  11. package/agents/codebase-mapper.md +63 -0
  12. package/agents/copywriter.md +48 -0
  13. package/agents/debugger.md +44 -0
  14. package/agents/designer.md +53 -0
  15. package/agents/devops.md +49 -0
  16. package/agents/docs-manager.md +50 -0
  17. package/agents/fullstack-developer.md +55 -0
  18. package/agents/git-manager.md +63 -0
  19. package/agents/implementer.md +30 -0
  20. package/agents/journal-writer.md +53 -0
  21. package/agents/planner.md +52 -0
  22. package/agents/project-manager.md +50 -0
  23. package/agents/researcher.md +46 -0
  24. package/agents/reviewer.md +63 -0
  25. package/agents/security-auditor.md +92 -0
  26. package/agents/teacher.md +71 -0
  27. package/agents/tester.md +41 -0
  28. package/commands/api-gen.md +17 -0
  29. package/commands/backlog.md +26 -0
  30. package/commands/bootstrap.md +32 -0
  31. package/commands/brainstorm.md +18 -0
  32. package/commands/build.md +16 -0
  33. package/commands/chain.md +46 -0
  34. package/commands/changelog.md +16 -0
  35. package/commands/check.md +40 -0
  36. package/commands/ci.md +32 -0
  37. package/commands/context.md +35 -0
  38. package/commands/debug.md +16 -0
  39. package/commands/deploy.md +16 -0
  40. package/commands/doc.md +15 -0
  41. package/commands/export.md +17 -0
  42. package/commands/journal.md +18 -0
  43. package/commands/learn.md +16 -0
  44. package/commands/map.md +16 -0
  45. package/commands/migrate.md +17 -0
  46. package/commands/monitor.md +16 -0
  47. package/commands/optimize.md +17 -0
  48. package/commands/plan.md +17 -0
  49. package/commands/pulse.md +46 -0
  50. package/commands/refactor.md +16 -0
  51. package/commands/research.md +18 -0
  52. package/commands/review.md +16 -0
  53. package/commands/scan.md +19 -0
  54. package/commands/ship.md +17 -0
  55. package/commands/simplify.md +16 -0
  56. package/commands/task.md +32 -0
  57. package/commands/tdd.md +17 -0
  58. package/commands/test.md +16 -0
  59. package/commands/upgrade.md +27 -0
  60. package/cortexhawk +450 -0
  61. package/hooks/agent-analytics.sh +67 -0
  62. package/hooks/branch-guard.sh +56 -0
  63. package/hooks/codex-dispatcher.sh +84 -0
  64. package/hooks/commit-guard.sh +71 -0
  65. package/hooks/compose.yml +47 -0
  66. package/hooks/dependency-check.sh +56 -0
  67. package/hooks/file-guard.sh +69 -0
  68. package/hooks/hooks.json +46 -0
  69. package/hooks/self-review.sh +71 -0
  70. package/hooks/session-start.sh +132 -0
  71. package/hooks/session-telemetry.sh +60 -0
  72. package/hooks/test-reminder.sh +75 -0
  73. package/install.sh +3805 -0
  74. package/mcp/README.md +37 -0
  75. package/mcp/context7.json +8 -0
  76. package/mcp/puppeteer.json +8 -0
  77. package/mcp/sequential-thinking.json +8 -0
  78. package/modes/default.md +5 -0
  79. package/modes/fast.md +5 -0
  80. package/modes/learn.md +9 -0
  81. package/modes/orchestration.md +5 -0
  82. package/modes/pair.md +10 -0
  83. package/modes/research.md +5 -0
  84. package/modes/review.md +5 -0
  85. package/package.json +32 -0
  86. package/profiles/api.json +27 -0
  87. package/profiles/data.json +23 -0
  88. package/profiles/fullstack.json +27 -0
  89. package/scripts/autodetect-profile.sh +68 -0
  90. package/scripts/benchmark.sh +106 -0
  91. package/scripts/chain-post-save.sh +23 -0
  92. package/scripts/generate-plans-index.sh +50 -0
  93. package/scripts/git-workflow-init.sh +115 -0
  94. package/scripts/install-codex.sh +128 -0
  95. package/scripts/interactive-init.sh +264 -0
  96. package/scripts/post-install-audit.sh +130 -0
  97. package/scripts/validate.sh +214 -0
  98. package/settings.json +90 -0
  99. package/setup.sh +67 -0
  100. package/skills/databases/schema-designer/SKILL.md +54 -0
  101. package/skills/databases/sql-optimizer/SKILL.md +37 -0
  102. package/skills/devops/ci-cd/SKILL.md +59 -0
  103. package/skills/devops/deployment/SKILL.md +49 -0
  104. package/skills/devops/docker/SKILL.md +57 -0
  105. package/skills/frameworks/api-design/SKILL.md +103 -0
  106. package/skills/frameworks/fastapi/SKILL.md +68 -0
  107. package/skills/frameworks/nextjs/SKILL.md +74 -0
  108. package/skills/frameworks/python/SKILL.md +89 -0
  109. package/skills/frameworks/react/SKILL.md +83 -0
  110. package/skills/frameworks/sveltekit/SKILL.md +69 -0
  111. package/skills/frameworks/tailwindcss/SKILL.md +75 -0
  112. package/skills/frameworks/typescript/SKILL.md +94 -0
  113. package/skills/meta/mcp-builder/SKILL.md +54 -0
  114. package/skills/meta/skill-creator/SKILL.md +43 -0
  115. package/skills/optimization/performance/SKILL.md +70 -0
  116. package/skills/quality/complexity-analyzer/SKILL.md +52 -0
  117. package/skills/quality/error-handling/SKILL.md +123 -0
  118. package/skills/quality/log-analyzer/SKILL.md +31 -0
  119. package/skills/quality/pattern-detector/SKILL.md +50 -0
  120. package/skills/security/auth-analyzer/SKILL.md +96 -0
  121. package/skills/security/compliance-checker/SKILL.md +92 -0
  122. package/skills/security/container-security/SKILL.md +128 -0
  123. package/skills/security/dependency-auditor/SKILL.md +100 -0
  124. package/skills/security/encryption/SKILL.md +94 -0
  125. package/skills/security/incident-response/SKILL.md +127 -0
  126. package/skills/security/secrets/SKILL.md +93 -0
  127. package/skills/security/security-headers/SKILL.md +83 -0
  128. package/skills/security/security-logging/SKILL.md +107 -0
  129. package/skills/security/vulnerability-scanner/SKILL.md +114 -0
  130. package/skills/testing/e2e-testing/SKILL.md +119 -0
  131. package/skills/testing/tdd/SKILL.md +40 -0
  132. package/skills/testing/test-generator/SKILL.md +39 -0
  133. package/skills/workflow/commit/SKILL.md +61 -0
  134. package/skills/workflow/confidence-check/SKILL.md +90 -0
  135. package/skills/workflow/pr-review-comments/SKILL.md +81 -0
  136. package/skills/workflow/pr-review-comments/scripts/fetch_comments.py +237 -0
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Fetch all PR conversation comments + reviews + review threads (inline threads)
4
+ for the PR associated with the current git branch, by shelling out to:
5
+
6
+ gh api graphql
7
+
8
+ Requires:
9
+ - `gh auth login` already set up
10
+ - current branch has an associated (open) PR
11
+
12
+ Usage:
13
+ python fetch_comments.py > pr_comments.json
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ import subprocess
20
+ import sys
21
+ from typing import Any
22
+
23
+ QUERY = """\
24
+ query(
25
+ $owner: String!,
26
+ $repo: String!,
27
+ $number: Int!,
28
+ $commentsCursor: String,
29
+ $reviewsCursor: String,
30
+ $threadsCursor: String
31
+ ) {
32
+ repository(owner: $owner, name: $repo) {
33
+ pullRequest(number: $number) {
34
+ number
35
+ url
36
+ title
37
+ state
38
+
39
+ # Top-level "Conversation" comments (issue comments on the PR)
40
+ comments(first: 100, after: $commentsCursor) {
41
+ pageInfo { hasNextPage endCursor }
42
+ nodes {
43
+ id
44
+ body
45
+ createdAt
46
+ updatedAt
47
+ author { login }
48
+ }
49
+ }
50
+
51
+ # Review submissions (Approve / Request changes / Comment), with body if present
52
+ reviews(first: 100, after: $reviewsCursor) {
53
+ pageInfo { hasNextPage endCursor }
54
+ nodes {
55
+ id
56
+ state
57
+ body
58
+ submittedAt
59
+ author { login }
60
+ }
61
+ }
62
+
63
+ # Inline review threads (grouped), includes resolved state
64
+ reviewThreads(first: 100, after: $threadsCursor) {
65
+ pageInfo { hasNextPage endCursor }
66
+ nodes {
67
+ id
68
+ isResolved
69
+ isOutdated
70
+ path
71
+ line
72
+ diffSide
73
+ startLine
74
+ startDiffSide
75
+ originalLine
76
+ originalStartLine
77
+ resolvedBy { login }
78
+ comments(first: 100) {
79
+ nodes {
80
+ id
81
+ body
82
+ createdAt
83
+ updatedAt
84
+ author { login }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ """
93
+
94
+
95
+ def _run(cmd: list[str], stdin: str | None = None) -> str:
96
+ p = subprocess.run(cmd, input=stdin, capture_output=True, text=True)
97
+ if p.returncode != 0:
98
+ raise RuntimeError(f"Command failed: {' '.join(cmd)}\n{p.stderr}")
99
+ return p.stdout
100
+
101
+
102
+ def _run_json(cmd: list[str], stdin: str | None = None) -> dict[str, Any]:
103
+ out = _run(cmd, stdin=stdin)
104
+ try:
105
+ return json.loads(out)
106
+ except json.JSONDecodeError as e:
107
+ raise RuntimeError(f"Failed to parse JSON from command output: {e}\nRaw:\n{out}") from e
108
+
109
+
110
+ def _ensure_gh_authenticated() -> None:
111
+ try:
112
+ _run(["gh", "auth", "status"])
113
+ except RuntimeError:
114
+ print("run `gh auth login` to authenticate the GitHub CLI", file=sys.stderr)
115
+ raise RuntimeError("gh auth status failed; run `gh auth login` to authenticate the GitHub CLI") from None
116
+
117
+
118
+ def gh_pr_view_json(fields: str) -> dict[str, Any]:
119
+ # fields is a comma-separated list like: "number,headRepositoryOwner,headRepository"
120
+ return _run_json(["gh", "pr", "view", "--json", fields])
121
+
122
+
123
+ def get_current_pr_ref() -> tuple[str, str, int]:
124
+ """
125
+ Resolve the PR for the current branch (whatever gh considers associated).
126
+ Works for cross-repo PRs too, by reading head repository owner/name.
127
+ """
128
+ pr = gh_pr_view_json("number,headRepositoryOwner,headRepository")
129
+ owner = pr["headRepositoryOwner"]["login"]
130
+ repo = pr["headRepository"]["name"]
131
+ number = int(pr["number"])
132
+ return owner, repo, number
133
+
134
+
135
+ def gh_api_graphql(
136
+ owner: str,
137
+ repo: str,
138
+ number: int,
139
+ comments_cursor: str | None = None,
140
+ reviews_cursor: str | None = None,
141
+ threads_cursor: str | None = None,
142
+ ) -> dict[str, Any]:
143
+ """
144
+ Call `gh api graphql` using -F variables, avoiding JSON blobs with nulls.
145
+ Query is passed via stdin using query=@- to avoid shell newline/quoting issues.
146
+ """
147
+ cmd = [
148
+ "gh",
149
+ "api",
150
+ "graphql",
151
+ "-F",
152
+ "query=@-",
153
+ "-F",
154
+ f"owner={owner}",
155
+ "-F",
156
+ f"repo={repo}",
157
+ "-F",
158
+ f"number={number}",
159
+ ]
160
+ if comments_cursor:
161
+ cmd += ["-F", f"commentsCursor={comments_cursor}"]
162
+ if reviews_cursor:
163
+ cmd += ["-F", f"reviewsCursor={reviews_cursor}"]
164
+ if threads_cursor:
165
+ cmd += ["-F", f"threadsCursor={threads_cursor}"]
166
+
167
+ return _run_json(cmd, stdin=QUERY)
168
+
169
+
170
+ def fetch_all(owner: str, repo: str, number: int) -> dict[str, Any]:
171
+ conversation_comments: list[dict[str, Any]] = []
172
+ reviews: list[dict[str, Any]] = []
173
+ review_threads: list[dict[str, Any]] = []
174
+
175
+ comments_cursor: str | None = None
176
+ reviews_cursor: str | None = None
177
+ threads_cursor: str | None = None
178
+
179
+ pr_meta: dict[str, Any] | None = None
180
+
181
+ while True:
182
+ payload = gh_api_graphql(
183
+ owner=owner,
184
+ repo=repo,
185
+ number=number,
186
+ comments_cursor=comments_cursor,
187
+ reviews_cursor=reviews_cursor,
188
+ threads_cursor=threads_cursor,
189
+ )
190
+
191
+ if "errors" in payload and payload["errors"]:
192
+ raise RuntimeError(f"GitHub GraphQL errors:\n{json.dumps(payload['errors'], indent=2)}")
193
+
194
+ pr = payload["data"]["repository"]["pullRequest"]
195
+ if pr_meta is None:
196
+ pr_meta = {
197
+ "number": pr["number"],
198
+ "url": pr["url"],
199
+ "title": pr["title"],
200
+ "state": pr["state"],
201
+ "owner": owner,
202
+ "repo": repo,
203
+ }
204
+
205
+ c = pr["comments"]
206
+ r = pr["reviews"]
207
+ t = pr["reviewThreads"]
208
+
209
+ conversation_comments.extend(c.get("nodes") or [])
210
+ reviews.extend(r.get("nodes") or [])
211
+ review_threads.extend(t.get("nodes") or [])
212
+
213
+ comments_cursor = c["pageInfo"]["endCursor"] if c["pageInfo"]["hasNextPage"] else None
214
+ reviews_cursor = r["pageInfo"]["endCursor"] if r["pageInfo"]["hasNextPage"] else None
215
+ threads_cursor = t["pageInfo"]["endCursor"] if t["pageInfo"]["hasNextPage"] else None
216
+
217
+ if not (comments_cursor or reviews_cursor or threads_cursor):
218
+ break
219
+
220
+ assert pr_meta is not None
221
+ return {
222
+ "pull_request": pr_meta,
223
+ "conversation_comments": conversation_comments,
224
+ "reviews": reviews,
225
+ "review_threads": review_threads,
226
+ }
227
+
228
+
229
+ def main() -> None:
230
+ _ensure_gh_authenticated()
231
+ owner, repo, number = get_current_pr_ref()
232
+ result = fetch_all(owner, repo, number)
233
+ print(json.dumps(result, indent=2))
234
+
235
+
236
+ if __name__ == "__main__":
237
+ main()