@geminix/gxpm 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.
Files changed (299) hide show
  1. package/AGENTS.md +148 -0
  2. package/CANON.md +53 -0
  3. package/CLAUDE.md +60 -0
  4. package/CONTEXT.md +49 -0
  5. package/DEBUG.md +59 -0
  6. package/ISSUE_CONTEXT.md +25 -0
  7. package/README.md +143 -0
  8. package/VERSION +1 -0
  9. package/agents/cleanup-auditor/cleanup-auditor.md +56 -0
  10. package/agents/grill-master.md +26 -0
  11. package/agents/implementer.md +32 -0
  12. package/agents/review-army/accessibility-reviewer.md +54 -0
  13. package/agents/review-army/code-quality-reviewer.md +54 -0
  14. package/agents/review-army/security-reviewer.md +56 -0
  15. package/agents/review-army/spec-compliance-reviewer.md +51 -0
  16. package/agents/review-army/test-reviewer.md +55 -0
  17. package/agents/reviewer.md +59 -0
  18. package/agents/ship-audit-army/docs-auditor.md +53 -0
  19. package/agents/ship-audit-army/performance-auditor.md +52 -0
  20. package/agents/ship-audit-army/security-auditor.md +52 -0
  21. package/agents/specifier.md +55 -0
  22. package/agents/triage-officer.md +27 -0
  23. package/bin/gxpm +17 -0
  24. package/bin/gxpm-browser +17 -0
  25. package/bin/gxpm-config +15 -0
  26. package/bin/gxpm-eval +13 -0
  27. package/bin/gxpm-global-discover +15 -0
  28. package/bin/gxpm-init +38 -0
  29. package/bin/gxpm-investigate +194 -0
  30. package/bin/gxpm-uninstall +15 -0
  31. package/bin/gxpm-update-check +165 -0
  32. package/commands/build.md +40 -0
  33. package/commands/help.md +53 -0
  34. package/commands/plan.md +34 -0
  35. package/commands/refine.md +46 -0
  36. package/commands/review.md +34 -0
  37. package/commands/ship.md +37 -0
  38. package/core/ac-check.ts +20 -0
  39. package/core/agent-runtime.ts +363 -0
  40. package/core/artifact-validator.ts +151 -0
  41. package/core/artifacts.ts +313 -0
  42. package/core/autopilot.ts +250 -0
  43. package/core/capabilities.ts +779 -0
  44. package/core/checkpoint.ts +370 -0
  45. package/core/cleanup.ts +32 -0
  46. package/core/command-probe.ts +82 -0
  47. package/core/config.ts +533 -0
  48. package/core/contracts/behavior-spec.schema.ts +38 -0
  49. package/core/contracts/converter.ts +61 -0
  50. package/core/contracts/host.ts +43 -0
  51. package/core/converters/converter.ts +93 -0
  52. package/core/converters/index.ts +8 -0
  53. package/core/converters/managed-artifact.ts +119 -0
  54. package/core/converters/parser.ts +159 -0
  55. package/core/converters/template-renderer.ts +35 -0
  56. package/core/converters/writer.ts +61 -0
  57. package/core/dag-executor.ts +426 -0
  58. package/core/dag-loader.ts +292 -0
  59. package/core/dag-schemas.ts +150 -0
  60. package/core/dispatch.ts +125 -0
  61. package/core/evidence.ts +148 -0
  62. package/core/gate.ts +269 -0
  63. package/core/hook-engine.ts +566 -0
  64. package/core/host-probe.ts +64 -0
  65. package/core/implement.ts +16 -0
  66. package/core/isolation-errors.ts +174 -0
  67. package/core/isolation-resolver.ts +921 -0
  68. package/core/issue-context.ts +381 -0
  69. package/core/issue-readiness.ts +457 -0
  70. package/core/issue-sync.ts +427 -0
  71. package/core/issues.ts +132 -0
  72. package/core/land.ts +108 -0
  73. package/core/orchestrator.ts +54 -0
  74. package/core/phase-artifact.ts +32 -0
  75. package/core/phase-gates.ts +130 -0
  76. package/core/phase-rewind.ts +94 -0
  77. package/core/plan-lint.ts +61 -0
  78. package/core/plan.ts +77 -0
  79. package/core/port-allocation.ts +50 -0
  80. package/core/pr-check.ts +15 -0
  81. package/core/preset-system/preset-resolver.ts +221 -0
  82. package/core/project-init-status.ts +127 -0
  83. package/core/qa.ts +15 -0
  84. package/core/resilience.ts +165 -0
  85. package/core/runs.ts +288 -0
  86. package/core/safe-path.test.ts +80 -0
  87. package/core/safe-path.ts +60 -0
  88. package/core/sdd-gate.test.ts +98 -0
  89. package/core/sdd-gate.ts +134 -0
  90. package/core/self-review.ts +62 -0
  91. package/core/session.ts +70 -0
  92. package/core/ship.ts +86 -0
  93. package/core/specify.ts +173 -0
  94. package/core/state.ts +1002 -0
  95. package/core/template-engine.ts +152 -0
  96. package/core/template-resolver.test.ts +70 -0
  97. package/core/template-resolver.ts +156 -0
  98. package/core/triage.ts +26 -0
  99. package/core/verify.ts +15 -0
  100. package/core/wiki-native.ts +2423 -0
  101. package/core/wiki.ts +27 -0
  102. package/core/workflow-event-emitter.ts +163 -0
  103. package/core/workflows/engine.ts +273 -0
  104. package/core/workflows/expressions.ts +76 -0
  105. package/core/workflows/index.ts +38 -0
  106. package/core/workflows/steps/command.ts +43 -0
  107. package/core/workflows/steps/gate.ts +47 -0
  108. package/core/workflows/steps/gxpm.ts +44 -0
  109. package/core/workflows/steps/linear.ts +31 -0
  110. package/core/workflows/steps/shell.ts +65 -0
  111. package/core/workflows/types.ts +62 -0
  112. package/core/workspace-runtime.ts +227 -0
  113. package/core/worktree-init-steps.ts +647 -0
  114. package/core/worktree-init.ts +330 -0
  115. package/core/worktree-owner.ts +143 -0
  116. package/docs/GXPM_VERIFY.md +98 -0
  117. package/docs/INSTALL_FOR_AGENTS.md +113 -0
  118. package/docs/README.md +57 -0
  119. package/docs/adr/adr-005-multi-platform-skill-converter.md +72 -0
  120. package/docs/agents/domain.md +30 -0
  121. package/docs/agents/issue-tracker.md +30 -0
  122. package/docs/agents/triage-labels.md +32 -0
  123. package/docs/architecture/gxpm-architecture-diagram.md +265 -0
  124. package/docs/architecture/gxpm-current-architecture.md +175 -0
  125. package/docs/architecture/gxpm-current-flow.md +278 -0
  126. package/docs/architecture/gxpm-replacement-architecture.md +211 -0
  127. package/docs/architecture/gxpm-target-architecture.md +449 -0
  128. package/docs/architecture/gxpm-v0-contract.md +311 -0
  129. package/docs/architecture/layered-workflow-boundaries.md +193 -0
  130. package/docs/architecture/preset-system.md +126 -0
  131. package/docs/architecture/scaffold-northstar.md +23 -0
  132. package/docs/brainstorms/2026-05-14-bdd-then-tdd-design.md +320 -0
  133. package/docs/brainstorms/README.md +22 -0
  134. package/docs/brainstorms/docs-knowledge-system-requirements.md +29 -0
  135. package/docs/governance/beta-skill-promotion.md +39 -0
  136. package/docs/governance/development-contract.md +144 -0
  137. package/docs/governance/gherkin-style.md +90 -0
  138. package/docs/governance/host-adapter.md +56 -0
  139. package/docs/governance/skill-authoring.md +87 -0
  140. package/docs/governance/skill-testing.md +356 -0
  141. package/docs/governance/template-authoring.md +53 -0
  142. package/docs/migrations/v0.2.md +51 -0
  143. package/docs/plans/README.md +23 -0
  144. package/docs/plans/bdd-then-tdd-plan.md +1767 -0
  145. package/docs/plans/docs-knowledge-system-plan.md +31 -0
  146. package/docs/plans/spec-kit-sdd-adoption-plan.md +305 -0
  147. package/docs/research/agents-md-best-practices.md +207 -0
  148. package/docs/research/archon-study.md +351 -0
  149. package/docs/research/claude-hooks-study.md +440 -0
  150. package/docs/research/codex-hooks-study.md +624 -0
  151. package/docs/research/everything-claude-code-study.md +252 -0
  152. package/docs/research/from-skills-to-layered-workflow.md +322 -0
  153. package/docs/research/gsd-study.md +69 -0
  154. package/docs/research/kimi-hooks-study.md +274 -0
  155. package/docs/research/mattpocock-skills-comparison.md +429 -0
  156. package/docs/research/mattpocock-skills-study.md +275 -0
  157. package/docs/research/oh-my-codex-study.md +279 -0
  158. package/docs/research/perplexity-agent-skills-design.md +168 -0
  159. package/docs/research/pmc-gstack-skill-study.md +122 -0
  160. package/docs/research/spec-kit-study.md +224 -0
  161. package/docs/research/superpowers-study.md +209 -0
  162. package/docs/roadmap/initial-roadmap.md +53 -0
  163. package/docs/solutions/README.md +45 -0
  164. package/docs/solutions/artifact-nesting-recovery.md +58 -0
  165. package/docs/solutions/session-context-restore-practice.md +67 -0
  166. package/docs/solutions/workflow/version-drift-recovery.md +49 -0
  167. package/docs/solutions/worktree-gate-recovery.md +62 -0
  168. package/docs/specs/README.md +28 -0
  169. package/docs/specs/claude.md +45 -0
  170. package/docs/specs/codex.md +44 -0
  171. package/docs/specs/cursor.md +44 -0
  172. package/hosts/adapters/claude.ts +29 -0
  173. package/hosts/adapters/codex.ts +27 -0
  174. package/hosts/adapters/cursor.ts +27 -0
  175. package/hosts/adapters/kimi.ts +27 -0
  176. package/hosts/claude.ts +23 -0
  177. package/hosts/codex.ts +26 -0
  178. package/hosts/cursor.ts +19 -0
  179. package/hosts/index.ts +33 -0
  180. package/hosts/registry.test.ts +52 -0
  181. package/hosts/registry.ts +57 -0
  182. package/hosts/schema.ts +58 -0
  183. package/package.json +52 -0
  184. package/scripts/browser.ts +185 -0
  185. package/scripts/cleanup.ts +142 -0
  186. package/scripts/commands/artifact.ts +115 -0
  187. package/scripts/commands/autopilot.ts +143 -0
  188. package/scripts/commands/capability.ts +57 -0
  189. package/scripts/commands/config.ts +69 -0
  190. package/scripts/commands/dag.ts +126 -0
  191. package/scripts/commands/feedback.ts +123 -0
  192. package/scripts/commands/gate.ts +291 -0
  193. package/scripts/commands/helpers.ts +126 -0
  194. package/scripts/commands/hook.ts +66 -0
  195. package/scripts/commands/init.ts +515 -0
  196. package/scripts/commands/issue.ts +825 -0
  197. package/scripts/commands/phase.ts +61 -0
  198. package/scripts/commands/preset.ts +159 -0
  199. package/scripts/commands/runtime.ts +199 -0
  200. package/scripts/commands/specify.ts +71 -0
  201. package/scripts/commands/upgrade.ts +243 -0
  202. package/scripts/commands/verify.ts +183 -0
  203. package/scripts/commands/wiki.ts +242 -0
  204. package/scripts/commands/workflow.ts +131 -0
  205. package/scripts/dev-skill.ts +55 -0
  206. package/scripts/discover-skills.ts +116 -0
  207. package/scripts/doctor.ts +410 -0
  208. package/scripts/dogfood-check.ts +125 -0
  209. package/scripts/eval-functional.ts +218 -0
  210. package/scripts/eval.ts +246 -0
  211. package/scripts/gen-skill-docs.ts +201 -0
  212. package/scripts/global-discover.ts +217 -0
  213. package/scripts/governance-check.ts +75 -0
  214. package/scripts/gxpm-check.ts +12 -0
  215. package/scripts/gxpm.ts +216 -0
  216. package/scripts/host-config.ts +62 -0
  217. package/scripts/install-claude-hooks.ts +138 -0
  218. package/scripts/install-codex-hooks.ts +271 -0
  219. package/scripts/install-hooks.ts +128 -0
  220. package/scripts/install-kimi-hooks.ts +92 -0
  221. package/scripts/install-skill.ts +184 -0
  222. package/scripts/phase-artifact-commands.ts +100 -0
  223. package/scripts/post-land-sync.ts +46 -0
  224. package/scripts/scaffold-check.ts +85 -0
  225. package/scripts/skill-naming-check.ts +78 -0
  226. package/scripts/skill-structure-check.ts +157 -0
  227. package/scripts/skills-lock-check.ts +60 -0
  228. package/scripts/sync-markdown-artifacts.ts +172 -0
  229. package/scripts/uninstall.ts +162 -0
  230. package/scripts/version.ts +47 -0
  231. package/scripts/wait-pr-ready.ts +407 -0
  232. package/skills/gxpm/SKILL.md +485 -0
  233. package/skills/gxpm/SKILL.md.tmpl +422 -0
  234. package/skills/gxpm/references/CANON.md +53 -0
  235. package/skills/gxpm/references/key-rules.md +130 -0
  236. package/skills/gxpm-architecture/SKILL.md +106 -0
  237. package/skills/gxpm-architecture/references/DEEPENING.md +37 -0
  238. package/skills/gxpm-architecture/references/INTERFACE-DESIGN.md +44 -0
  239. package/skills/gxpm-autopilot/SKILL.md +116 -0
  240. package/skills/gxpm-autopilot/SKILL.md.tmpl +107 -0
  241. package/skills/gxpm-browser/SKILL.md +105 -0
  242. package/skills/gxpm-browser/SKILL.md.tmpl +41 -0
  243. package/skills/gxpm-browser/references/commands.md +43 -0
  244. package/skills/gxpm-browser/references/evidence-path.md +20 -0
  245. package/skills/gxpm-build/SKILL.md +78 -0
  246. package/skills/gxpm-cleanup/SKILL.md +76 -0
  247. package/skills/gxpm-debug-issue/SKILL.md +39 -0
  248. package/skills/gxpm-diagnose/SKILL.md +220 -0
  249. package/skills/gxpm-diagnose/SKILL.md.tmpl +31 -0
  250. package/skills/gxpm-diagnose/references/feedback-loop.md +34 -0
  251. package/skills/gxpm-diagnose/references/feedback-loops.md +43 -0
  252. package/skills/gxpm-diagnose/references/phases.md +60 -0
  253. package/skills/gxpm-eval/SKILL.md +78 -0
  254. package/skills/gxpm-explore-codebase/SKILL.md +36 -0
  255. package/skills/gxpm-explore-codebase/scripts/summarize-communities.ts +51 -0
  256. package/skills/gxpm-feedback/SKILL.md +122 -0
  257. package/skills/gxpm-grill/SKILL.md +159 -0
  258. package/skills/gxpm-grill/SKILL.md.tmpl +77 -0
  259. package/skills/gxpm-grill/references/documentation-templates.md +56 -0
  260. package/skills/gxpm-grill/references/process.md +25 -0
  261. package/skills/gxpm-handoff/SKILL.md +112 -0
  262. package/skills/gxpm-hygiene/SKILL.md +69 -0
  263. package/skills/gxpm-implementer/SKILL.md +142 -0
  264. package/skills/gxpm-implementer/SKILL.md.tmpl +141 -0
  265. package/skills/gxpm-linear/SKILL.md +282 -0
  266. package/skills/gxpm-linear/SKILL.md.tmpl +86 -0
  267. package/skills/gxpm-linear/references/commands.md +75 -0
  268. package/skills/gxpm-linear/references/workflows.md +120 -0
  269. package/skills/gxpm-planning/SKILL.md +134 -0
  270. package/skills/gxpm-prototype/SKILL.md +64 -0
  271. package/skills/gxpm-refactor-safely/SKILL.md +62 -0
  272. package/skills/gxpm-review-army/SKILL.md +117 -0
  273. package/skills/gxpm-review-changes/SKILL.md +36 -0
  274. package/skills/gxpm-setup/SKILL.md +101 -0
  275. package/skills/gxpm-specifier/SKILL.md +135 -0
  276. package/skills/gxpm-tdd/SKILL.md +187 -0
  277. package/skills/gxpm-tdd/references/interface-design.md +23 -0
  278. package/skills/gxpm-tdd/references/mocking.md +27 -0
  279. package/skills/gxpm-tdd/references/red-green-refactor.md +61 -0
  280. package/skills/gxpm-tdd/references/troubleshooting.md +28 -0
  281. package/skills/gxpm-tdd/references/workflow.md +50 -0
  282. package/skills/gxpm-tdd/testing-anti-patterns.tmpl +304 -0
  283. package/skills/gxpm-triage/SKILL.md +160 -0
  284. package/skills/gxpm-verify/SKILL.md +107 -0
  285. package/skills/gxpm-write-skill/SKILL.md +131 -0
  286. package/skills/gxpm-zoom-out/SKILL.md +69 -0
  287. package/skills/maintain-hygiene-skills-lock/SKILL.md +54 -0
  288. package/skills/maintain-hygiene-skills-lock/SKILL.md.tmpl +53 -0
  289. package/templates/constitution-template.md +63 -0
  290. package/templates/hooks/gxpm-commit-msg +16 -0
  291. package/templates/hooks/gxpm-post-checkout +19 -0
  292. package/templates/hooks/gxpm-post-commit +7 -0
  293. package/templates/hooks/gxpm-post-merge +29 -0
  294. package/templates/hooks/gxpm-pre-commit +39 -0
  295. package/templates/hooks/gxpm-pre-push +33 -0
  296. package/templates/plan-template.md.tmpl +46 -0
  297. package/templates/spec-template.md.tmpl +63 -0
  298. package/templates/specify-stub.tmpl +22 -0
  299. package/templates/tasks-template.md.tmpl +32 -0
@@ -0,0 +1,44 @@
1
+ # Cursor Host 规范镜像
2
+
3
+ ## 平台标识
4
+
5
+ - **名称**: Cursor IDE
6
+ - **上下文长度**: ~200K tokens(Claude 3.5 Sonnet / GPT-4o)
7
+ - **工具支持**: MCP、Composer、Tab
8
+
9
+ ## 上下文格式
10
+
11
+ - 优先使用 `.cursorrules` 或项目根目录的规则文件
12
+ - 支持 `AGENTS.md` 和 `CLAUDE.md` 作为补充契约
13
+ - Composer 模式支持多文件编辑和全局上下文
14
+
15
+ ## 工具调用约定
16
+
17
+ - **MCP**: 通过 Cursor Settings 中的 MCP 配置添加
18
+ - **Composer**: 支持 `@` 引用文件、符号、文档
19
+ - **Tab**: 自动补全基于当前文件和打开的标签页上下文
20
+
21
+ ## 已知限制
22
+
23
+ - 无原生 hooks 系统,需通过 gxpm 的 IDE 插件或外部脚本模拟
24
+ - `.cursorrules` 长度受限,复杂规则需拆分到 `docs/governance/`
25
+ - 不区分 Skills 和 Plugins 概念
26
+
27
+ ## gxpm 集成点
28
+
29
+ - `hosts/cursor.ts` — Cursor 宿主适配器
30
+ - `docs/governance/cursor-rules.md` — Cursor 专属规则(如存在)
31
+ - 通过 gxpm CLI 在终端中查询 issue 状态,再复制关键信息到 Composer
32
+
33
+ ## 工作流差异
34
+
35
+ | 阶段 | Cursor 行为 |
36
+ |------|-------------|
37
+ | 启动 | 加载 .cursorrules + 打开的文件上下文 |
38
+ | 用户提示 | Composer 支持多文件 @ 引用 |
39
+ | 文件编辑 | 内联 diff 或 Composer 批量编辑 |
40
+ | 终端集成 | 内置终端可直接运行 gxpm CLI |
41
+
42
+ ## 同步策略
43
+
44
+ 当 `hosts/cursor.ts` 或 Cursor 专属规则文件发生变更时,同步更新本文档。
@@ -0,0 +1,29 @@
1
+ import type { HostAdapter, CommandDef } from "../schema";
2
+
3
+ export const claudeAdapter: HostAdapter = {
4
+ key: "claude",
5
+ name: "Claude Code",
6
+ cliCommand: "claude",
7
+
8
+ detect(): boolean {
9
+ try {
10
+ return Bun.which("claude") !== null;
11
+ } catch {
12
+ return false;
13
+ }
14
+ },
15
+
16
+ install(_command: CommandDef, _projectRoot: string): void {
17
+ // TODO: integrate with scripts/install-skill.ts for host-specific install
18
+ throw new Error("Claude Code install not yet implemented via registry");
19
+ },
20
+
21
+ uninstall(_commandName: string, _projectRoot: string): void {
22
+ // TODO: integrate with host-specific uninstall
23
+ throw new Error("Claude Code uninstall not yet implemented via registry");
24
+ },
25
+
26
+ preferredFormat(): "markdown" {
27
+ return "markdown";
28
+ },
29
+ };
@@ -0,0 +1,27 @@
1
+ import type { HostAdapter, CommandDef } from "../schema";
2
+
3
+ export const codexAdapter: HostAdapter = {
4
+ key: "codex",
5
+ name: "OpenAI Codex CLI",
6
+ cliCommand: "codex",
7
+
8
+ detect(): boolean {
9
+ try {
10
+ return Bun.which("codex") !== null;
11
+ } catch {
12
+ return false;
13
+ }
14
+ },
15
+
16
+ install(_command: CommandDef, _projectRoot: string): void {
17
+ throw new Error("Codex CLI install not yet implemented via registry");
18
+ },
19
+
20
+ uninstall(_commandName: string, _projectRoot: string): void {
21
+ throw new Error("Codex CLI uninstall not yet implemented via registry");
22
+ },
23
+
24
+ preferredFormat(): "skills" {
25
+ return "skills";
26
+ },
27
+ };
@@ -0,0 +1,27 @@
1
+ import type { HostAdapter, CommandDef } from "../schema";
2
+
3
+ export const cursorAdapter: HostAdapter = {
4
+ key: "cursor",
5
+ name: "Cursor",
6
+ cliCommand: "cursor",
7
+
8
+ detect(): boolean {
9
+ try {
10
+ return Bun.which("cursor") !== null;
11
+ } catch {
12
+ return false;
13
+ }
14
+ },
15
+
16
+ install(_command: CommandDef, _projectRoot: string): void {
17
+ throw new Error("Cursor install not yet implemented via registry");
18
+ },
19
+
20
+ uninstall(_commandName: string, _projectRoot: string): void {
21
+ throw new Error("Cursor uninstall not yet implemented via registry");
22
+ },
23
+
24
+ preferredFormat(): "markdown" {
25
+ return "markdown";
26
+ },
27
+ };
@@ -0,0 +1,27 @@
1
+ import type { HostAdapter, CommandDef } from "../schema";
2
+
3
+ export const kimiAdapter: HostAdapter = {
4
+ key: "kimi",
5
+ name: "Kimi Code CLI",
6
+ cliCommand: "kimi",
7
+
8
+ detect(): boolean {
9
+ try {
10
+ return Bun.which("kimi") !== null;
11
+ } catch {
12
+ return false;
13
+ }
14
+ },
15
+
16
+ install(_command: CommandDef, _projectRoot: string): void {
17
+ throw new Error("Kimi CLI install not yet implemented via registry");
18
+ },
19
+
20
+ uninstall(_commandName: string, _projectRoot: string): void {
21
+ throw new Error("Kimi CLI uninstall not yet implemented via registry");
22
+ },
23
+
24
+ preferredFormat(): "skills" {
25
+ return "skills";
26
+ },
27
+ };
@@ -0,0 +1,23 @@
1
+ import type { HostConfig } from "../core/contracts/host";
2
+
3
+ export const claudeHostConfig: HostConfig = {
4
+ name: "claude",
5
+ displayName: "Claude Code",
6
+ cliCommand: "claude",
7
+ hostSubdir: ".claude",
8
+ globalRoot: ".claude/skills/gxpm",
9
+ localSkillRoot: ".claude/skills/gxpm",
10
+ usesEnvVars: false,
11
+ frontmatter: {
12
+ mode: "preserve",
13
+ },
14
+ install: {
15
+ strategy: "copy",
16
+ },
17
+ hooks: {
18
+ configFileName: "settings.json",
19
+ configFormat: "json",
20
+ configPathSegments: [".claude", "settings.json"],
21
+ featureFlagRequired: false,
22
+ },
23
+ };
package/hosts/codex.ts ADDED
@@ -0,0 +1,26 @@
1
+ import type { HostConfig } from "../core/contracts/host";
2
+
3
+ export const codexHostConfig: HostConfig = {
4
+ name: "codex",
5
+ displayName: "OpenAI Codex CLI",
6
+ cliCommand: "codex",
7
+ hostSubdir: ".agents",
8
+ globalRoot: ".codex/skills/gxpm",
9
+ localSkillRoot: ".agents/skills/gxpm",
10
+ usesEnvVars: true,
11
+ frontmatter: {
12
+ mode: "allowlist",
13
+ keys: ["name", "description"],
14
+ },
15
+ install: {
16
+ strategy: "copy",
17
+ },
18
+ hooks: {
19
+ configFileName: "hooks.json",
20
+ configFormat: "json",
21
+ configPathSegments: [".codex", "hooks.json"],
22
+ featureFlagRequired: true,
23
+ featureFlagKey: "codex_hooks",
24
+ featureFlagSection: "[features]",
25
+ },
26
+ };
@@ -0,0 +1,19 @@
1
+ import type { HostConfig } from "../core/contracts/host";
2
+
3
+ export const cursorHostConfig: HostConfig = {
4
+ name: "cursor",
5
+ displayName: "Cursor",
6
+ cliCommand: "cursor",
7
+ hostSubdir: ".cursor",
8
+ globalRoot: ".cursor/skills/gxpm",
9
+ localSkillRoot: ".cursor/skills/gxpm",
10
+ usesEnvVars: false,
11
+ frontmatter: {
12
+ mode: "preserve",
13
+ },
14
+ install: {
15
+ strategy: "copy",
16
+ },
17
+ // Cursor does not currently expose a native hooks system.
18
+ // Rules (.cursor/rules/*.md) and skills are the primary extension points.
19
+ };
package/hosts/index.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { HOST_REGISTRY, registerHost } from "./registry";
2
+ import { claudeAdapter } from "./adapters/claude";
3
+ import { codexAdapter } from "./adapters/codex";
4
+ import { cursorAdapter } from "./adapters/cursor";
5
+ import { kimiAdapter } from "./adapters/kimi";
6
+
7
+ // Register built-in host adapters (idempotent for test isolation)
8
+ if (!HOST_REGISTRY.has(claudeAdapter.key)) registerHost(claudeAdapter);
9
+ if (!HOST_REGISTRY.has(codexAdapter.key)) registerHost(codexAdapter);
10
+ if (!HOST_REGISTRY.has(cursorAdapter.key)) registerHost(cursorAdapter);
11
+ if (!HOST_REGISTRY.has(kimiAdapter.key)) registerHost(kimiAdapter);
12
+
13
+ // Backward-compatible HostConfig exports
14
+ import { claudeHostConfig } from "./claude";
15
+ import { codexHostConfig } from "./codex";
16
+ import { cursorHostConfig } from "./cursor";
17
+
18
+ export const ALL_HOST_CONFIGS = [claudeHostConfig, codexHostConfig, cursorHostConfig] as const;
19
+ export const ALL_HOST_NAMES = ALL_HOST_CONFIGS.map((host) => host.name);
20
+
21
+ export type HostName = (typeof ALL_HOST_NAMES)[number];
22
+
23
+ export function getHostConfig(name: string) {
24
+ const config = ALL_HOST_CONFIGS.find((host) => host.name === name);
25
+ if (!config) {
26
+ throw new Error(`Unknown gxpm host: ${name}`);
27
+ }
28
+ return config;
29
+ }
30
+
31
+ // Re-export new registry system
32
+ export { HOST_REGISTRY, registerHost };
33
+ export type { HostAdapter, HostConfig, CommandDef } from "./schema";
@@ -0,0 +1,52 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { HostRegistry, registerHost, HOST_REGISTRY } from "./registry";
3
+ import { claudeAdapter } from "./adapters/claude";
4
+ import { codexAdapter } from "./adapters/codex";
5
+
6
+ describe("HostRegistry", () => {
7
+ it("registers and retrieves adapters", () => {
8
+ const registry = new HostRegistry();
9
+ registry.register(claudeAdapter);
10
+ expect(registry.get("claude")).toBe(claudeAdapter);
11
+ });
12
+
13
+ it("throws on duplicate registration", () => {
14
+ const registry = new HostRegistry();
15
+ registry.register(claudeAdapter);
16
+ expect(() => registry.register(claudeAdapter)).toThrow("already registered");
17
+ });
18
+
19
+ it("unregisters adapters", () => {
20
+ const registry = new HostRegistry();
21
+ registry.register(claudeAdapter);
22
+ expect(registry.unregister("claude")).toBe(true);
23
+ expect(registry.has("claude")).toBe(false);
24
+ });
25
+
26
+ it("lists registered keys", () => {
27
+ const registry = new HostRegistry();
28
+ registry.register(claudeAdapter);
29
+ registry.register(codexAdapter);
30
+ expect(registry.list()).toEqual(["claude", "codex"]);
31
+ });
32
+
33
+ it("detects active hosts", () => {
34
+ const registry = new HostRegistry();
35
+ registry.register(claudeAdapter);
36
+ // Detection depends on whether 'claude' is in PATH; test shape only
37
+ const active = registry.detectAll();
38
+ expect(Array.isArray(active)).toBe(true);
39
+ });
40
+ });
41
+
42
+ describe("registerHost", () => {
43
+ it("adds to global registry", () => {
44
+ // If index.ts side-effect already ran, codex is present; test idempotent path
45
+ if (HOST_REGISTRY.has("codex")) {
46
+ expect(HOST_REGISTRY.get("codex")).toBe(codexAdapter);
47
+ } else {
48
+ registerHost(codexAdapter);
49
+ expect(HOST_REGISTRY.has("codex")).toBe(true);
50
+ }
51
+ });
52
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Host Registry — registry-driven host adapter system.
3
+ *
4
+ * Eliminates hard-coded host arrays in favor of dynamic registration.
5
+ * New hosts require only a single adapter file + registerHost() call.
6
+ */
7
+
8
+ import type { HostAdapter } from "./schema";
9
+
10
+ export class HostRegistry {
11
+ private adapters = new Map<string, HostAdapter>();
12
+
13
+ register(adapter: HostAdapter): void {
14
+ if (this.adapters.has(adapter.key)) {
15
+ throw new Error(`Host adapter '${adapter.key}' is already registered`);
16
+ }
17
+ this.adapters.set(adapter.key, adapter);
18
+ }
19
+
20
+ unregister(key: string): boolean {
21
+ return this.adapters.delete(key);
22
+ }
23
+
24
+ get(key: string): HostAdapter | undefined {
25
+ return this.adapters.get(key);
26
+ }
27
+
28
+ has(key: string): boolean {
29
+ return this.adapters.has(key);
30
+ }
31
+
32
+ /** List all registered host keys */
33
+ list(): string[] {
34
+ return Array.from(this.adapters.keys());
35
+ }
36
+
37
+ /** Find the first host whose detect() returns true */
38
+ detectActive(): HostAdapter | undefined {
39
+ for (const adapter of this.adapters.values()) {
40
+ if (adapter.detect()) return adapter;
41
+ }
42
+ return undefined;
43
+ }
44
+
45
+ /** Get all adapters whose detect() returns true */
46
+ detectAll(): HostAdapter[] {
47
+ return Array.from(this.adapters.values()).filter((a) => a.detect());
48
+ }
49
+ }
50
+
51
+ /** Global singleton registry */
52
+ export const HOST_REGISTRY = new HostRegistry();
53
+
54
+ /** Convenience shorthand for HOST_REGISTRY.register */
55
+ export function registerHost(adapter: HostAdapter): void {
56
+ HOST_REGISTRY.register(adapter);
57
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Host Schema — declarative host adapter protocol.
3
+ *
4
+ * Defines the contract that every host CLI must satisfy to integrate with gxpm.
5
+ */
6
+
7
+ export type CommandFormat = "markdown" | "toml" | "yaml" | "skills";
8
+
9
+ export interface CommandDef {
10
+ name: string;
11
+ description: string;
12
+ format: CommandFormat;
13
+ /** Whether this command requires an interactive session */
14
+ interactive?: boolean;
15
+ }
16
+
17
+ export interface HostAdapter {
18
+ /** Unique host identifier (e.g. 'claude', 'codex', 'cursor') */
19
+ key: string;
20
+ /** Human-readable display name */
21
+ name: string;
22
+ /** CLI executable name used for detection */
23
+ cliCommand: string;
24
+ /** Detect whether this host is installed/available */
25
+ detect(): boolean;
26
+ /** Install a gxpm command into the host's command system */
27
+ install(command: CommandDef, projectRoot: string): void;
28
+ /** Uninstall a command from the host */
29
+ uninstall(commandName: string, projectRoot: string): void;
30
+ /** Return the host's preferred command format */
31
+ preferredFormat(): CommandFormat;
32
+ }
33
+
34
+ /** Raw host config used for static declarations (before adapter instantiation) */
35
+ export interface HostConfig {
36
+ name: string;
37
+ displayName: string;
38
+ cliCommand: string;
39
+ hostSubdir: string;
40
+ globalRoot: string;
41
+ localSkillRoot: string;
42
+ usesEnvVars: boolean;
43
+ frontmatter: {
44
+ mode: "preserve" | "allowlist";
45
+ keys?: string[];
46
+ };
47
+ install: {
48
+ strategy: "copy" | "symlink";
49
+ };
50
+ hooks?: {
51
+ configFileName: string;
52
+ configFormat: "json" | "toml";
53
+ configPathSegments: string[];
54
+ featureFlagRequired?: boolean;
55
+ featureFlagKey?: string;
56
+ featureFlagSection?: string;
57
+ };
58
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@geminix/gxpm",
3
+ "version": "0.1.0",
4
+ "description": "Second-generation project management runtime designed to replace PMC and gstack.",
5
+ "type": "module",
6
+ "bin": {
7
+ "gxpm": "./bin/gxpm",
8
+ "gxpm-config": "./bin/gxpm-config",
9
+ "gxpm-investigate": "./bin/gxpm-investigate",
10
+ "gxpm-init": "./bin/gxpm-init",
11
+ "gxpm-uninstall": "./bin/gxpm-uninstall",
12
+ "gxpm-update-check": "./bin/gxpm-update-check"
13
+ },
14
+ "files": [
15
+ "bin/",
16
+ "core/",
17
+ "scripts/",
18
+ "hosts/",
19
+ "skills/",
20
+ "templates/",
21
+ "agents/",
22
+ "docs/",
23
+ "commands/",
24
+ "CANON.md",
25
+ "AGENTS.md",
26
+ "CONTEXT.md",
27
+ "CLAUDE.md",
28
+ "DEBUG.md",
29
+ "README.md",
30
+ "ISSUE_CONTEXT.md",
31
+ "VERSION"
32
+ ],
33
+ "scripts": {
34
+ "check": "bun run scripts/gxpm-check.ts",
35
+ "dev:skill": "bun run scripts/dev-skill.ts",
36
+ "gen:skill-docs": "bun run scripts/gen-skill-docs.ts",
37
+ "sync:markdown": "bun run scripts/sync-markdown-artifacts.ts",
38
+ "test": "bun test"
39
+ },
40
+ "devDependencies": {
41
+ "@types/bun": "latest",
42
+ "typescript": "^6.0.3"
43
+ },
44
+ "engines": {
45
+ "bun": ">=1.0.0"
46
+ },
47
+ "dependencies": {
48
+ "playwright": "^1.59.1",
49
+ "yaml": "^2.8.4",
50
+ "zod": "^4.4.3"
51
+ }
52
+ }
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * gxpm-browser — minimal headless browser CLI for QA evidence capture.
4
+ *
5
+ * Uses Playwright to drive Chromium/Chrome in headless mode.
6
+ * Screenshots and evidence are written to the gxpm evidence store when
7
+ * an issue-id is provided.
8
+ */
9
+
10
+ import { chromium } from "playwright";
11
+ import { writeFileSync, mkdirSync } from "node:fs";
12
+ import { join, resolve } from "node:path";
13
+ import { homedir } from "node:os";
14
+
15
+ const args = process.argv.slice(2);
16
+ const command = args[0];
17
+
18
+ function usage() {
19
+ console.log(`gxpm-browser — headless browser for QA evidence
20
+
21
+ Usage:
22
+ gxpm-browser navigate <url> [--json]
23
+ gxpm-browser screenshot <url> [--out <path>] [--full-page] [--json]
24
+ gxpm-browser assert <url> --selector <css> --text <expected> [--json]
25
+ gxpm-browser click <url> --selector <css> [--json]
26
+ gxpm-browser type <url> --selector <css> --text <value> [--json]
27
+
28
+ Options:
29
+ --out <path> Screenshot output path (default: /tmp/gxpm-browser-<ts>.png)
30
+ --full-page Capture full page instead of viewport
31
+ --selector <css> CSS selector for element interaction
32
+ --text <value> Text to assert or type
33
+ --json Output JSON
34
+ --headless Run headless (default: true)
35
+ --no-headless Run headed for debugging
36
+ `);
37
+ }
38
+
39
+ function parseFlags(argv: string[]) {
40
+ const flags: Record<string, string | boolean> = {};
41
+ const positional: string[] = [];
42
+ for (let i = 0; i < argv.length; i++) {
43
+ const arg = argv[i];
44
+ if (arg === "--json") {
45
+ flags.json = true;
46
+ } else if (arg === "--full-page") {
47
+ flags.fullPage = true;
48
+ } else if (arg === "--headless") {
49
+ flags.headless = true;
50
+ } else if (arg === "--no-headless") {
51
+ flags.headless = false;
52
+ } else if (arg.startsWith("--")) {
53
+ const key = arg.replace(/^--/, "").replace(/-/g, "");
54
+ const next = argv[i + 1];
55
+ if (next && !next.startsWith("--")) {
56
+ flags[key] = next;
57
+ i++;
58
+ } else {
59
+ flags[key] = true;
60
+ }
61
+ } else {
62
+ positional.push(arg);
63
+ }
64
+ }
65
+ return { flags, positional };
66
+ }
67
+
68
+ function output(data: unknown, asJson: boolean) {
69
+ if (asJson) {
70
+ console.log(JSON.stringify(data, null, 2));
71
+ } else {
72
+ console.log(data);
73
+ }
74
+ }
75
+
76
+ function resolveEvidencePath(issueId: string | undefined, label: string): string | undefined {
77
+ if (!issueId) return undefined;
78
+ const repoRoot = process.cwd();
79
+ const evidenceDir = join(repoRoot, ".gxpm", "issues", issueId, "evidence", "browser");
80
+ mkdirSync(evidenceDir, { recursive: true });
81
+ const ts = Date.now();
82
+ const filename = `${label}-${ts}.png`;
83
+ return join(evidenceDir, filename);
84
+ }
85
+
86
+ async function run() {
87
+ if (!command || command === "--help" || command === "-h") {
88
+ usage();
89
+ process.exit(0);
90
+ }
91
+
92
+ const { flags, positional } = parseFlags(args.slice(1));
93
+ const asJson = !!flags.json;
94
+ const headless = flags.headless !== false;
95
+ const url = positional[0];
96
+
97
+ if (!url) {
98
+ output({ error: "Missing URL" }, asJson);
99
+ process.exit(1);
100
+ }
101
+
102
+ const browser = await chromium.launch({
103
+ headless,
104
+ executablePath: process.env.GXPM_BROWSER_EXECUTABLE || undefined,
105
+ });
106
+
107
+ const context = await browser.newContext({
108
+ viewport: { width: 1280, height: 720 },
109
+ });
110
+ const page = await context.newPage();
111
+
112
+ try {
113
+ await page.goto(url, { waitUntil: "networkidle" });
114
+
115
+ switch (command) {
116
+ case "navigate": {
117
+ const title = await page.title();
118
+ output({ url: page.url(), title }, asJson);
119
+ break;
120
+ }
121
+
122
+ case "screenshot": {
123
+ const outPath =
124
+ (flags.out as string) ||
125
+ resolveEvidencePath(flags.issueid as string | undefined, "screenshot") ||
126
+ `/tmp/gxpm-browser-${Date.now()}.png`;
127
+ const fullPage = !!flags.fullPage;
128
+ await page.screenshot({ path: outPath, fullPage });
129
+ output({ screenshot: resolve(outPath), url: page.url(), fullPage }, asJson);
130
+ break;
131
+ }
132
+
133
+ case "assert": {
134
+ const selector = flags.selector as string;
135
+ const expected = flags.text as string;
136
+ if (!selector || expected === undefined) {
137
+ output({ error: "Missing --selector or --text" }, asJson);
138
+ process.exit(1);
139
+ }
140
+ const el = await page.locator(selector).first();
141
+ const text = await el.textContent();
142
+ const pass = text?.includes(expected) ?? false;
143
+ output({ pass, expected, actual: text, selector }, asJson);
144
+ if (!pass) process.exit(1);
145
+ break;
146
+ }
147
+
148
+ case "click": {
149
+ const selector = flags.selector as string;
150
+ if (!selector) {
151
+ output({ error: "Missing --selector" }, asJson);
152
+ process.exit(1);
153
+ }
154
+ await page.locator(selector).first().click();
155
+ output({ clicked: selector, url: page.url() }, asJson);
156
+ break;
157
+ }
158
+
159
+ case "type": {
160
+ const selector = flags.selector as string;
161
+ const value = flags.text as string;
162
+ if (!selector || value === undefined) {
163
+ output({ error: "Missing --selector or --text" }, asJson);
164
+ process.exit(1);
165
+ }
166
+ await page.locator(selector).first().fill(value);
167
+ output({ filled: selector, value, url: page.url() }, asJson);
168
+ break;
169
+ }
170
+
171
+ default: {
172
+ output({ error: `Unknown command: ${command}` }, asJson);
173
+ process.exit(1);
174
+ }
175
+ }
176
+ } finally {
177
+ await context.close();
178
+ await browser.close();
179
+ }
180
+ }
181
+
182
+ run().catch((err) => {
183
+ console.error(err);
184
+ process.exit(1);
185
+ });