openplanr 3.0.0 → 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 (233) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/cli/commands/init-deterministic.d.ts.map +1 -1
  3. package/dist/cli/commands/init-deterministic.js +49 -6
  4. package/dist/cli/commands/init-deterministic.js.map +1 -1
  5. package/dist/cli/commands/upgrade.d.ts.map +1 -1
  6. package/dist/cli/commands/upgrade.js +4 -2
  7. package/dist/cli/commands/upgrade.js.map +1 -1
  8. package/dist/dashboard/.vite/manifest.json +2 -2
  9. package/dist/dashboard/assets/{index-Bk8DyO_2.css → index-BU5fzjyz.css} +1 -1
  10. package/dist/dashboard/assets/index-G7ygVDGg.js +572 -0
  11. package/dist/dashboard/assets/index-G7ygVDGg.js.map +1 -0
  12. package/dist/dashboard/dashboard-manifest.json +14 -14
  13. package/dist/dashboard/index.html +2 -2
  14. package/dist/models/types.d.ts +0 -46
  15. package/dist/models/types.d.ts.map +1 -1
  16. package/dist/services/capability-map-service.d.ts +4 -0
  17. package/dist/services/capability-map-service.d.ts.map +1 -1
  18. package/dist/services/capability-map-service.js +7 -1
  19. package/dist/services/capability-map-service.js.map +1 -1
  20. package/dist/services/claude-plugin-service.d.ts +15 -1
  21. package/dist/services/claude-plugin-service.d.ts.map +1 -1
  22. package/dist/services/claude-plugin-service.js +66 -15
  23. package/dist/services/claude-plugin-service.js.map +1 -1
  24. package/dist/services/config-service.d.ts +24 -1
  25. package/dist/services/config-service.d.ts.map +1 -1
  26. package/dist/services/config-service.js +69 -2
  27. package/dist/services/config-service.js.map +1 -1
  28. package/dist/services/git-service.d.ts +5 -0
  29. package/dist/services/git-service.d.ts.map +1 -1
  30. package/dist/services/git-service.js +27 -0
  31. package/dist/services/git-service.js.map +1 -1
  32. package/dist/services/linear-pull-service.d.ts.map +1 -1
  33. package/dist/services/linear-pull-service.js +1 -2
  34. package/dist/services/linear-pull-service.js.map +1 -1
  35. package/dist/services/pipeline-package-service.d.ts +2 -0
  36. package/dist/services/pipeline-package-service.d.ts.map +1 -1
  37. package/dist/services/pipeline-package-service.js +2 -1
  38. package/dist/services/pipeline-package-service.js.map +1 -1
  39. package/dist/services/runtime-change-summary.d.ts.map +1 -1
  40. package/dist/services/runtime-change-summary.js +4 -0
  41. package/dist/services/runtime-change-summary.js.map +1 -1
  42. package/dist/services/runtime-manager-service.d.ts.map +1 -1
  43. package/dist/services/runtime-manager-service.js +14 -3
  44. package/dist/services/runtime-manager-service.js.map +1 -1
  45. package/dist/services/spec-service.d.ts.map +1 -1
  46. package/dist/services/spec-service.js +11 -22
  47. package/dist/services/spec-service.js.map +1 -1
  48. package/dist/services/upgrade-report.d.ts.map +1 -1
  49. package/dist/services/upgrade-report.js +5 -2
  50. package/dist/services/upgrade-report.js.map +1 -1
  51. package/dist/services/upgrade-service.d.ts +14 -0
  52. package/dist/services/upgrade-service.d.ts.map +1 -1
  53. package/dist/services/upgrade-service.js +69 -11
  54. package/dist/services/upgrade-service.js.map +1 -1
  55. package/dist/templates/rules/shared/capability-map.md.hbs +2 -2
  56. package/lib/host-packages/adapter-registry.json +5 -5
  57. package/lib/host-packages/capability-map.json +89 -29
  58. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  59. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  60. package/lib/host-packages/claude/openplanr/.openplanr-content.json +70 -38
  61. package/lib/host-packages/claude/openplanr/CONNECTORS.md +62 -0
  62. package/lib/host-packages/claude/openplanr/README.md +1 -1
  63. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  64. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs +259 -36
  65. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +54 -54
  66. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  67. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +259 -36
  68. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  69. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  70. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +43 -24
  71. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +279 -58
  72. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +50 -42
  73. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +282 -146
  74. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +949 -316
  75. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +143 -87
  76. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +930 -183
  77. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +17 -15
  78. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +375 -191
  79. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +140 -105
  80. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  81. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +25 -25
  82. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +8 -4
  83. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +259 -36
  84. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +8 -4
  85. package/lib/host-packages/claude/openplanr/skills/connect/SKILL.md +60 -0
  86. package/lib/host-packages/claude/openplanr/skills/connect/references/connectors.md +62 -0
  87. package/lib/host-packages/claude/openplanr/skills/openplanr/SKILL.md +4 -0
  88. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +4 -1
  89. package/lib/host-packages/claude/openplanr/skills/plan/scripts/planning-ids.mjs +49 -3
  90. package/lib/host-packages/claude/openplanr/skills/share/SKILL.md +87 -0
  91. package/lib/host-packages/claude/openplanr/skills/share/references/connectors.md +62 -0
  92. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +6 -3
  93. package/lib/host-packages/claude/openplanr/skills/ship/scripts/discover-verification.mjs +2 -1
  94. package/lib/host-packages/claude/openplanr/skills/sprint/SKILL.md +15 -6
  95. package/lib/host-packages/claude/openplanr/skills/sprint/references/connectors.md +62 -0
  96. package/lib/host-packages/claude/openplanr/skills/sprint/references/tracker-connections.md +9 -13
  97. package/lib/host-packages/claude/openplanr/skills/status/SKILL.md +14 -3
  98. package/lib/host-packages/claude/openplanr/skills/status/references/connectors.md +62 -0
  99. package/lib/host-packages/claude/openplanr/skills/status/references/tracker-connections.md +9 -13
  100. package/lib/host-packages/claude/openplanr/skills/sync/SKILL.md +25 -10
  101. package/lib/host-packages/claude/openplanr/skills/sync/references/connectors.md +62 -0
  102. package/lib/host-packages/claude/openplanr/skills/sync/references/tracker-connections.md +9 -13
  103. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +69 -37
  104. package/lib/host-packages/cursor/openplanr/CONNECTORS.md +62 -0
  105. package/lib/host-packages/cursor/openplanr/manifest.json +4 -2
  106. package/lib/host-packages/cursor/openplanr/rules/planr-connect/references/connectors.md +62 -0
  107. package/lib/host-packages/cursor/openplanr/rules/planr-connect.mdc +58 -0
  108. package/lib/host-packages/cursor/openplanr/rules/planr-openplanr.mdc +4 -0
  109. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/planning-ids.mjs +49 -3
  110. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +4 -1
  111. package/lib/host-packages/cursor/openplanr/rules/planr-share/references/connectors.md +62 -0
  112. package/lib/host-packages/cursor/openplanr/rules/planr-share.mdc +85 -0
  113. package/lib/host-packages/cursor/openplanr/rules/planr-ship/scripts/discover-verification.mjs +2 -1
  114. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +6 -3
  115. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/connectors.md +62 -0
  116. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/tracker-connections.md +9 -13
  117. package/lib/host-packages/cursor/openplanr/rules/planr-sprint.mdc +15 -6
  118. package/lib/host-packages/cursor/openplanr/rules/planr-status/references/connectors.md +62 -0
  119. package/lib/host-packages/cursor/openplanr/rules/planr-status/references/tracker-connections.md +9 -13
  120. package/lib/host-packages/cursor/openplanr/rules/planr-status.mdc +14 -3
  121. package/lib/host-packages/cursor/openplanr/rules/planr-sync/references/connectors.md +62 -0
  122. package/lib/host-packages/cursor/openplanr/rules/planr-sync/references/tracker-connections.md +9 -13
  123. package/lib/host-packages/cursor/openplanr/rules/planr-sync.mdc +25 -10
  124. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  125. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs +259 -36
  126. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +54 -54
  127. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  128. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +259 -36
  129. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  130. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  131. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +43 -24
  132. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +279 -58
  133. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +50 -42
  134. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +282 -146
  135. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +949 -316
  136. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +143 -87
  137. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +930 -183
  138. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +17 -15
  139. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +375 -191
  140. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +140 -105
  141. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  142. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +25 -25
  143. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +8 -4
  144. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +259 -36
  145. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +8 -4
  146. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  147. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  148. package/lib/host-packages/openai/openplanr/.openplanr-content.json +88 -40
  149. package/lib/host-packages/openai/openplanr/CONNECTORS.md +62 -0
  150. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  151. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs +259 -36
  152. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +54 -54
  153. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  154. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +259 -36
  155. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  156. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  157. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +43 -24
  158. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +279 -58
  159. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +50 -42
  160. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +282 -146
  161. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +949 -316
  162. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +143 -87
  163. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +930 -183
  164. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +17 -15
  165. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +375 -191
  166. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +140 -105
  167. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +146 -54
  168. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +25 -25
  169. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +8 -4
  170. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +259 -36
  171. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +8 -4
  172. package/lib/host-packages/openai/openplanr/skills/connect/SKILL.md +59 -0
  173. package/lib/host-packages/openai/openplanr/skills/connect/agents/openai.yaml +6 -0
  174. package/lib/host-packages/openai/openplanr/skills/connect/openplanr.skill.json +37 -0
  175. package/lib/host-packages/openai/openplanr/skills/connect/references/connectors.md +62 -0
  176. package/lib/host-packages/openai/openplanr/skills/openplanr/SKILL.md +4 -0
  177. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +4 -1
  178. package/lib/host-packages/openai/openplanr/skills/plan/scripts/planning-ids.mjs +49 -3
  179. package/lib/host-packages/openai/openplanr/skills/share/SKILL.md +86 -0
  180. package/lib/host-packages/openai/openplanr/skills/share/agents/openai.yaml +6 -0
  181. package/lib/host-packages/openai/openplanr/skills/share/openplanr.skill.json +37 -0
  182. package/lib/host-packages/openai/openplanr/skills/share/references/connectors.md +62 -0
  183. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +6 -3
  184. package/lib/host-packages/openai/openplanr/skills/ship/scripts/discover-verification.mjs +2 -1
  185. package/lib/host-packages/openai/openplanr/skills/sprint/SKILL.md +15 -6
  186. package/lib/host-packages/openai/openplanr/skills/sprint/openplanr.skill.json +11 -0
  187. package/lib/host-packages/openai/openplanr/skills/sprint/references/connectors.md +62 -0
  188. package/lib/host-packages/openai/openplanr/skills/sprint/references/tracker-connections.md +9 -13
  189. package/lib/host-packages/openai/openplanr/skills/status/SKILL.md +14 -3
  190. package/lib/host-packages/openai/openplanr/skills/status/openplanr.skill.json +11 -0
  191. package/lib/host-packages/openai/openplanr/skills/status/references/connectors.md +62 -0
  192. package/lib/host-packages/openai/openplanr/skills/status/references/tracker-connections.md +9 -13
  193. package/lib/host-packages/openai/openplanr/skills/sync/SKILL.md +25 -10
  194. package/lib/host-packages/openai/openplanr/skills/sync/openplanr.skill.json +11 -0
  195. package/lib/host-packages/openai/openplanr/skills/sync/references/connectors.md +62 -0
  196. package/lib/host-packages/openai/openplanr/skills/sync/references/tracker-connections.md +9 -13
  197. package/lib/json-schema.mjs +313 -36
  198. package/lib/schemas/v1.0.0/spec.schema.json +120 -0
  199. package/lib/schemas/v1.0.0/story.schema.json +95 -0
  200. package/lib/schemas/v1.0.0/task.schema.json +171 -0
  201. package/lib/schemas/v1.7.0/spec.schema.json +117 -0
  202. package/lib/schemas/v1.7.0/story.schema.json +107 -0
  203. package/lib/schemas/v1.7.0/task.schema.json +217 -0
  204. package/package.json +32 -32
  205. package/dist/dashboard/assets/index-Csby7_ur.js +0 -557
  206. package/dist/dashboard/assets/index-Csby7_ur.js.map +0 -1
  207. package/dist/services/audit-log-service.d.ts +0 -47
  208. package/dist/services/audit-log-service.d.ts.map +0 -1
  209. package/dist/services/audit-log-service.js +0 -211
  210. package/dist/services/audit-log-service.js.map +0 -1
  211. package/dist/services/delta-apply-service.d.ts +0 -16
  212. package/dist/services/delta-apply-service.d.ts.map +0 -1
  213. package/dist/services/delta-apply-service.js +0 -74
  214. package/dist/services/delta-apply-service.js.map +0 -1
  215. package/dist/services/evidence-verifier.d.ts +0 -71
  216. package/dist/services/evidence-verifier.d.ts.map +0 -1
  217. package/dist/services/evidence-verifier.js +0 -174
  218. package/dist/services/evidence-verifier.js.map +0 -1
  219. package/dist/services/revise-apply-service.d.ts +0 -55
  220. package/dist/services/revise-apply-service.d.ts.map +0 -1
  221. package/dist/services/revise-apply-service.js +0 -265
  222. package/dist/services/revise-apply-service.js.map +0 -1
  223. package/dist/services/revise-cache-service.d.ts +0 -46
  224. package/dist/services/revise-cache-service.d.ts.map +0 -1
  225. package/dist/services/revise-cache-service.js +0 -89
  226. package/dist/services/revise-cache-service.js.map +0 -1
  227. package/dist/services/revise-plan-service.d.ts +0 -38
  228. package/dist/services/revise-plan-service.d.ts.map +0 -1
  229. package/dist/services/revise-plan-service.js +0 -153
  230. package/dist/services/revise-plan-service.js.map +0 -1
  231. /package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-runtime-support-336900df0d39.mjs → design-runtime-support-e34c388a8e59.mjs} +0 -0
  232. /package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-runtime-support-336900df0d39.mjs → design-runtime-support-e34c388a8e59.mjs} +0 -0
  233. /package/lib/host-packages/openai/openplanr/runtime/design/scripts/{design-runtime-support-336900df0d39.mjs → design-runtime-support-e34c388a8e59.mjs} +0 -0
@@ -120,17 +120,179 @@ var matchesType = (v, t) => {
120
120
  };
121
121
  var FORMAT_DATE = /^\d{4}-\d{2}-\d{2}$/;
122
122
  var FORMAT_DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
123
+ var SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["date", "date-time"]);
124
+ var ANNOTATION_KEYWORDS = [
125
+ "$schema",
126
+ "$id",
127
+ "$defs",
128
+ "$comment",
129
+ "title",
130
+ "description",
131
+ "default",
132
+ "examples",
133
+ "deprecated",
134
+ "readOnly",
135
+ "writeOnly"
136
+ ];
137
+ var VALIDATION_KEYWORDS = [
138
+ "$ref",
139
+ "type",
140
+ "const",
141
+ "enum",
142
+ "minLength",
143
+ "maxLength",
144
+ "pattern",
145
+ "format",
146
+ "minimum",
147
+ "maximum",
148
+ "exclusiveMinimum",
149
+ "minItems",
150
+ "maxItems",
151
+ "prefixItems",
152
+ "items",
153
+ "uniqueItems",
154
+ "contains",
155
+ "minContains",
156
+ "maxContains",
157
+ "required",
158
+ "properties",
159
+ "additionalProperties",
160
+ "maxProperties",
161
+ "dependentRequired",
162
+ "unevaluatedProperties",
163
+ "oneOf",
164
+ "anyOf",
165
+ "allOf",
166
+ "if",
167
+ "then",
168
+ "else",
169
+ "not"
170
+ ];
171
+ var KNOWN_KEYWORDS = /* @__PURE__ */ new Set([...ANNOTATION_KEYWORDS, ...VALIDATION_KEYWORDS]);
172
+ var TYPE_NAMES = /* @__PURE__ */ new Set(["array", "boolean", "integer", "null", "number", "object", "string"]);
173
+ var isSchema = (value) => typeof value === "boolean" || value !== null && typeof value === "object" && !Array.isArray(value);
174
+ var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
175
+ var isCount = (value) => Number.isSafeInteger(value) && value >= 0;
176
+ var isUniqueStrings = (value) => Array.isArray(value) && value.every((item2) => typeof item2 === "string") && new Set(value).size === value.length;
177
+ var isSchemaArray = (value) => Array.isArray(value) && value.length > 0 && value.every(isSchema);
178
+ var isSchemaMap = (value) => isPlainObject(value) && Object.values(value).every(isSchema);
179
+ var compiledPatterns = /* @__PURE__ */ new Map();
180
+ var MAX_COMPILED_PATTERNS = 1024;
181
+ var tryCompilePattern = (source) => {
182
+ try {
183
+ return new RegExp(source);
184
+ } catch (error) {
185
+ if (error instanceof SyntaxError) return null;
186
+ throw error;
187
+ }
188
+ };
189
+ var compilePattern = (source) => {
190
+ if (!compiledPatterns.has(source)) {
191
+ if (compiledPatterns.size >= MAX_COMPILED_PATTERNS) compiledPatterns.clear();
192
+ compiledPatterns.set(source, tryCompilePattern(source));
193
+ }
194
+ return compiledPatterns.get(source) ?? null;
195
+ };
196
+ var describeValue = (value) => {
197
+ const text3 = String(JSON.stringify(value));
198
+ return text3.length > 80 ? `${text3.slice(0, 77)}...` : text3;
199
+ };
200
+ var KEYWORD_SHAPES = {
201
+ $ref: ["a string", (value) => typeof value === "string"],
202
+ $defs: ["an object of schemas", isSchemaMap],
203
+ type: [
204
+ "a type name or a non-empty array of unique type names",
205
+ (value) => typeof value === "string" && TYPE_NAMES.has(value) || isUniqueStrings(value) && value.length > 0 && value.every((name) => TYPE_NAMES.has(name))
206
+ ],
207
+ enum: ["an array", Array.isArray],
208
+ minLength: ["a non-negative integer", isCount],
209
+ maxLength: ["a non-negative integer", isCount],
210
+ pattern: [
211
+ "a valid regular expression string",
212
+ (value) => typeof value === "string" && compilePattern(value) !== null
213
+ ],
214
+ minimum: ["a finite number", Number.isFinite],
215
+ maximum: ["a finite number", Number.isFinite],
216
+ exclusiveMinimum: ["a finite number", Number.isFinite],
217
+ minItems: ["a non-negative integer", isCount],
218
+ maxItems: ["a non-negative integer", isCount],
219
+ prefixItems: ["a non-empty array of schemas", isSchemaArray],
220
+ items: ["a schema", isSchema],
221
+ uniqueItems: ["a boolean", (value) => typeof value === "boolean"],
222
+ contains: ["a schema", isSchema],
223
+ minContains: ["a non-negative integer", isCount],
224
+ maxContains: ["a non-negative integer", isCount],
225
+ required: ["an array of unique strings", isUniqueStrings],
226
+ properties: ["an object of schemas", isSchemaMap],
227
+ additionalProperties: ["a schema", isSchema],
228
+ maxProperties: ["a non-negative integer", isCount],
229
+ dependentRequired: [
230
+ "an object of unique string arrays",
231
+ (value) => isPlainObject(value) && Object.values(value).every(isUniqueStrings)
232
+ ],
233
+ unevaluatedProperties: ["a schema", isSchema],
234
+ oneOf: ["a non-empty array of schemas", isSchemaArray],
235
+ anyOf: ["a non-empty array of schemas", isSchemaArray],
236
+ allOf: ["a non-empty array of schemas", isSchemaArray],
237
+ if: ["a schema", isSchema],
238
+ then: ["a schema", isSchema],
239
+ else: ["a schema", isSchema],
240
+ not: ["a schema", isSchema]
241
+ };
123
242
  function resolveJsonPointer(root, reference) {
124
243
  if (reference === "#") return root;
125
244
  if (!reference.startsWith("#/")) return null;
126
245
  return reference.slice(2).split("/").map((part) => part.replaceAll("~1", "/").replaceAll("~0", "~")).reduce((value, part) => value?.[part], root);
127
246
  }
247
+ var wellFormedSchemas = /* @__PURE__ */ new WeakSet();
248
+ var isFrozenNode = (schema6) => Object.isFrozen(schema6) && Object.values(schema6).every(Object.isFrozen) && (!isPlainObject(schema6.dependentRequired) || Object.values(schema6.dependentRequired).every(Object.isFrozen));
249
+ var checkSchemaNode = (schema6, path, context) => {
250
+ if (wellFormedSchemas.has(schema6) || context.checkedSchemas.has(schema6)) return;
251
+ context.checkedSchemas.add(schema6);
252
+ const errorCount = context.schemaErrors.length;
253
+ for (const keyword of Object.keys(schema6)) {
254
+ if (!KNOWN_KEYWORDS.has(keyword) && !keyword.startsWith("x-")) {
255
+ context.schemaErrors.push({
256
+ path,
257
+ rule: "unsupported-keyword",
258
+ detail: `schema keyword '${keyword}' is not supported by this validator`
259
+ });
260
+ }
261
+ }
262
+ if (Object.hasOwn(schema6, "format") && !SUPPORTED_FORMATS.has(schema6.format)) {
263
+ context.schemaErrors.push({
264
+ path,
265
+ rule: "unsupported-format",
266
+ detail: `schema format ${JSON.stringify(schema6.format)} is not supported by this validator`
267
+ });
268
+ }
269
+ for (const [keyword, [expected, isValid]] of Object.entries(KEYWORD_SHAPES)) {
270
+ if (Object.hasOwn(schema6, keyword) && !isValid(schema6[keyword])) {
271
+ context.schemaErrors.push({
272
+ path,
273
+ rule: "schema",
274
+ detail: `schema keyword '${keyword}' must be ${expected}, got ${describeValue(schema6[keyword])}`
275
+ });
276
+ }
277
+ }
278
+ if (context.schemaErrors.length === errorCount && isFrozenNode(schema6)) {
279
+ wellFormedSchemas.add(schema6);
280
+ }
281
+ };
282
+ var reportReference = (schema6, path, detail, context) => {
283
+ if (context.reportedReferences.has(schema6)) return;
284
+ context.reportedReferences.add(schema6);
285
+ context.schemaErrors.push({ path, rule: "$ref", detail });
286
+ };
128
287
  var validateNode = (value, schema6, path, errs, context) => {
129
- if (schema6 === true) return;
288
+ const evaluated = /* @__PURE__ */ new Set();
289
+ if (schema6 === true) return evaluated;
130
290
  if (schema6 === false) {
131
291
  errs.push({ path, rule: "schema:false", detail: "value not allowed" });
132
- return;
292
+ return evaluated;
133
293
  }
294
+ if (!isSchema(schema6)) return evaluated;
295
+ checkSchemaNode(schema6, path, context);
134
296
  if (typeof schema6?.$ref === "string") {
135
297
  const reference = schema6.$ref;
136
298
  let resolved;
@@ -144,21 +306,23 @@ var validateNode = (value, schema6, path, errs, context) => {
144
306
  nextRoot = result?.rootSchema ?? resolved;
145
307
  resolvedBase = result?.base ?? resolved?.$id ?? context.base;
146
308
  }
147
- if (!resolved) {
148
- errs.push({ path, rule: "$ref", detail: `could not resolve schema reference ${reference}` });
149
- return;
309
+ if (!isSchema(resolved)) {
310
+ const detail = resolved === void 0 || resolved === null ? `could not resolve schema reference ${reference}` : `schema reference ${reference} resolved to ${typeOf(resolved)}, not a schema`;
311
+ reportReference(schema6, path, detail, context);
312
+ return evaluated;
150
313
  }
151
- const referenceKey = `${context.base ?? "<root>"}:${reference}`;
314
+ const referenceKey = `${path} ${context.base ?? "<root>"}:${reference}`;
152
315
  if (context.referenceStack.includes(referenceKey)) {
153
- errs.push({ path, rule: "$ref", detail: `circular schema reference ${reference}` });
154
- return;
316
+ reportReference(schema6, path, `circular schema reference ${reference}`, context);
317
+ return evaluated;
155
318
  }
156
- validateNode(value, resolved, path, errs, {
319
+ const referenced = validateNode(value, resolved, path, errs, {
157
320
  ...context,
158
321
  rootSchema: nextRoot,
159
322
  base: resolvedBase,
160
323
  referenceStack: [...context.referenceStack, referenceKey]
161
324
  });
325
+ for (const key of referenced) evaluated.add(key);
162
326
  }
163
327
  if (schema6.type !== void 0) {
164
328
  const types = Array.isArray(schema6.type) ? schema6.type : [schema6.type];
@@ -168,7 +332,7 @@ var validateNode = (value, schema6, path, errs, context) => {
168
332
  rule: "type",
169
333
  detail: `expected ${types.join("|")}, got ${typeOf(value)}`
170
334
  });
171
- return;
335
+ return evaluated;
172
336
  }
173
337
  }
174
338
  if (schema6.const !== void 0) {
@@ -204,22 +368,13 @@ var validateNode = (value, schema6, path, errs, context) => {
204
368
  detail: `length ${value.length} > ${schema6.maxLength}`
205
369
  });
206
370
  }
207
- if (typeof schema6.pattern === "string") {
208
- try {
209
- if (!new RegExp(schema6.pattern).test(value)) {
210
- errs.push({
211
- path,
212
- rule: "pattern",
213
- detail: `value ${JSON.stringify(value)} does not match /${schema6.pattern}/`
214
- });
215
- }
216
- } catch (e) {
217
- errs.push({
218
- path,
219
- rule: "pattern",
220
- detail: `invalid regex /${schema6.pattern}/: ${e instanceof Error ? e.message : String(e)}`
221
- });
222
- }
371
+ const pattern = typeof schema6.pattern === "string" ? compilePattern(schema6.pattern) : null;
372
+ if (pattern && !pattern.test(value)) {
373
+ errs.push({
374
+ path,
375
+ rule: "pattern",
376
+ detail: `value ${JSON.stringify(value)} does not match /${schema6.pattern}/`
377
+ });
223
378
  }
224
379
  if (typeof schema6.format === "string") {
225
380
  if (schema6.format === "date" && !FORMAT_DATE.test(value)) {
@@ -244,6 +399,13 @@ var validateNode = (value, schema6, path, errs, context) => {
244
399
  if (typeof schema6.maximum === "number" && value > schema6.maximum) {
245
400
  errs.push({ path, rule: "maximum", detail: `value ${value} > ${schema6.maximum}` });
246
401
  }
402
+ if (typeof schema6.exclusiveMinimum === "number" && value <= schema6.exclusiveMinimum) {
403
+ errs.push({
404
+ path,
405
+ rule: "exclusiveMinimum",
406
+ detail: `value ${value} <= ${schema6.exclusiveMinimum}`
407
+ });
408
+ }
247
409
  }
248
410
  if (Array.isArray(value)) {
249
411
  if (typeof schema6.minItems === "number" && value.length < schema6.minItems) {
@@ -307,8 +469,31 @@ var validateNode = (value, schema6, path, errs, context) => {
307
469
  }
308
470
  }
309
471
  }
472
+ if (typeof schema6.maxProperties === "number" && Object.keys(value).length > schema6.maxProperties) {
473
+ errs.push({
474
+ path,
475
+ rule: "maxProperties",
476
+ detail: `property count ${Object.keys(value).length} > ${schema6.maxProperties}`
477
+ });
478
+ }
479
+ if (schema6.dependentRequired !== null && typeof schema6.dependentRequired === "object") {
480
+ for (const [trigger, dependencies] of Object.entries(schema6.dependentRequired)) {
481
+ if (!Object.hasOwn(value, trigger) || !Array.isArray(dependencies)) continue;
482
+ for (const dependency of dependencies) {
483
+ if (!Object.hasOwn(value, dependency)) {
484
+ errs.push({
485
+ path,
486
+ rule: "dependentRequired",
487
+ detail: `property '${trigger}' requires property '${dependency}'`
488
+ });
489
+ }
490
+ }
491
+ }
492
+ }
310
493
  const props = schema6.properties || {};
311
494
  for (const [k, v] of Object.entries(value)) {
495
+ if (Object.hasOwn(props, k)) evaluated.add(k);
496
+ else if (schema6.additionalProperties !== void 0) evaluated.add(k);
312
497
  if (!Object.hasOwn(props, k)) {
313
498
  if (schema6.additionalProperties === false) {
314
499
  errs.push({ path, rule: "additionalProperties", detail: `unknown property '${k}'` });
@@ -325,8 +510,11 @@ var validateNode = (value, schema6, path, errs, context) => {
325
510
  let matched = 0;
326
511
  for (const sub of schema6.oneOf) {
327
512
  const e = [];
328
- validateNode(value, sub, path, e, context);
329
- if (e.length === 0) matched++;
513
+ const branch = validateNode(value, sub, path, e, context);
514
+ if (e.length === 0) {
515
+ matched++;
516
+ for (const key of branch) evaluated.add(key);
517
+ }
330
518
  }
331
519
  if (matched !== 1) {
332
520
  const titles = schema6.oneOf.map((s) => s.title || "(unnamed)").join(" | ");
@@ -341,8 +529,11 @@ var validateNode = (value, schema6, path, errs, context) => {
341
529
  let matched = 0;
342
530
  for (const sub of schema6.anyOf) {
343
531
  const candidateErrors = [];
344
- validateNode(value, sub, path, candidateErrors, context);
345
- if (candidateErrors.length === 0) matched += 1;
532
+ const branch = validateNode(value, sub, path, candidateErrors, context);
533
+ if (candidateErrors.length === 0) {
534
+ matched += 1;
535
+ for (const key of branch) evaluated.add(key);
536
+ }
346
537
  }
347
538
  if (matched === 0) {
348
539
  const titles = schema6.anyOf.map((sub) => sub.title || "(unnamed)").join(" | ");
@@ -355,14 +546,21 @@ var validateNode = (value, schema6, path, errs, context) => {
355
546
  }
356
547
  if (Array.isArray(schema6.allOf)) {
357
548
  for (const sub of schema6.allOf) {
358
- validateNode(value, sub, path, errs, context);
549
+ for (const key of validateNode(value, sub, path, errs, context)) evaluated.add(key);
359
550
  }
360
551
  }
361
552
  if (schema6.if !== void 0) {
362
553
  const conditionErrors = [];
363
- validateNode(value, schema6.if, path, conditionErrors, context);
364
- const branch = conditionErrors.length === 0 ? schema6.then : schema6.else;
365
- if (branch !== void 0) validateNode(value, branch, path, errs, context);
554
+ const condition = validateNode(value, schema6.if, path, conditionErrors, context);
555
+ const passed = conditionErrors.length === 0;
556
+ if (passed) for (const key of condition) evaluated.add(key);
557
+ const branch = passed ? schema6.then : schema6.else;
558
+ if (branch !== void 0) {
559
+ const branchErrors = [];
560
+ const branchEvaluated = validateNode(value, branch, path, branchErrors, context);
561
+ errs.push(...branchErrors);
562
+ if (branchErrors.length === 0) for (const key of branchEvaluated) evaluated.add(key);
563
+ }
366
564
  }
367
565
  if (schema6.not !== void 0) {
368
566
  const e = [];
@@ -371,6 +569,18 @@ var validateNode = (value, schema6, path, errs, context) => {
371
569
  errs.push({ path, rule: "not", detail: "value matched a forbidden subschema" });
372
570
  }
373
571
  }
572
+ if (schema6.unevaluatedProperties !== void 0 && value !== null && typeof value === "object" && !Array.isArray(value)) {
573
+ for (const [k, v] of Object.entries(value)) {
574
+ if (evaluated.has(k)) continue;
575
+ if (schema6.unevaluatedProperties === false) {
576
+ errs.push({ path, rule: "unevaluatedProperties", detail: `unevaluated property '${k}'` });
577
+ } else {
578
+ validateNode(v, schema6.unevaluatedProperties, `${path}.${k}`, errs, context);
579
+ }
580
+ evaluated.add(k);
581
+ }
582
+ }
583
+ return evaluated;
374
584
  };
375
585
  var validateJson = (value, schema6, {
376
586
  resolveRef,
@@ -380,13 +590,26 @@ var validateJson = (value, schema6, {
380
590
  )
381
591
  } = {}) => {
382
592
  const errs = [];
593
+ const schemaErrors = [];
594
+ if (!isSchema(schema6)) {
595
+ return [
596
+ {
597
+ path: "$",
598
+ rule: "schema",
599
+ detail: `expected a schema object or boolean, got ${typeOf(schema6)}`
600
+ }
601
+ ];
602
+ }
383
603
  validateNode(value, schema6, "$", errs, {
384
604
  rootSchema: schema6,
385
605
  resolveRef,
386
606
  base,
387
- referenceStack: []
607
+ referenceStack: [],
608
+ schemaErrors,
609
+ checkedSchemas: /* @__PURE__ */ new WeakSet(),
610
+ reportedReferences: /* @__PURE__ */ new WeakSet()
388
611
  });
389
- return errs;
612
+ return [...schemaErrors, ...errs];
390
613
  };
391
614
 
392
615
  // packages/protocol/src/enterprise-contracts.mjs
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -115,6 +115,10 @@
115
115
  "./sharing-security-contracts": {
116
116
  "types": "./src/sharing-security-contracts.d.mts",
117
117
  "import": "./src/sharing-security-contracts.mjs"
118
+ },
119
+ "./enterprise-journey-contracts": {
120
+ "types": "./src/enterprise-journey-contracts.d.mts",
121
+ "import": "./src/enterprise-journey-contracts.mjs"
118
122
  }
119
123
  },
120
124
  "files": [
@@ -143,9 +147,9 @@
143
147
  "access": "public"
144
148
  },
145
149
  "devDependencies": {
146
- "esbuild": "0.28.1",
147
- "miniflare": "4.20260708.1",
148
- "playwright": "1.61.1",
150
+ "esbuild": "0.28.2",
151
+ "miniflare": "4.20260730.0",
152
+ "playwright": "1.64.0",
149
153
  "typescript": "6.0.2"
150
154
  }
151
155
  }
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: connect
3
+ description: Report which chat, project tracker and source control connections the host has, and guide connecting the missing ones through the host. Use when the user wants to connect a service for OpenPlanr or asks what is connected.
4
+ argument-hint: "[chat|project-tracker|source-control|product]"
5
+ license: MIT
6
+ disable-model-invocation: true
7
+ ---
8
+
9
+ # OpenPlanr Connect
10
+
11
+ Report which service categories this host can reach and help the user connect
12
+ the missing ones through the host's own connectors. OpenPlanr installs no
13
+ connector and never handles a credential: the vendor publishes the connector and
14
+ the user signs in through the host.
15
+
16
+ ## Check each category
17
+
18
+ The categories are ~~chat, ~~project tracker and ~~source control; their
19
+ products and per-host steps are in [connectors](references/connectors.md). With an
20
+ argument, check only that category; a product name from connectors selects the
21
+ category it belongs to.
22
+
23
+ A category is connected when the host exposes a tool for one of its products,
24
+ loaded or deferred; search the host's deferred tool list by product name when it
25
+ has one. For ~~project tracker and ~~source control, a signed-in GitHub CLI also
26
+ counts: `gh auth status --hostname github.com` succeeds. Judge by the tools you
27
+ can see; never call a tool that writes, posts or changes anything to find out.
28
+
29
+ ## Connect a missing category
30
+
31
+ Work through these steps in order for each missing category:
32
+
33
+ 1. **Already available.** If a matching tool appeared since the last check,
34
+ report the category as connected and name the product. If the host lists the
35
+ product's connector but offers only a sign-in or authentication notice instead
36
+ of its tools, report it as configured but not signed in, tell the user to sign
37
+ in from the host's connector settings, and skip the next two steps for it.
38
+ 2. **Connector suggestions.** If the host offers a connector-suggestion
39
+ capability, such as a tool that searches its connector directory and another
40
+ that shows a Connect card from a search result, search with the category's
41
+ product names and the category name, show the card for the best match, and
42
+ wait for the user to connect. Do not assume any particular tool name.
43
+ 3. **Host step.** Otherwise print the current host's step and the vendor's
44
+ documentation link from [connectors](references/connectors.md).
45
+
46
+ Then ask the user to run `/planr:connect` again once signed in. Do not retry on
47
+ your own. If a workspace admin must approve the vendor's app first, say so.
48
+
49
+ ## Rules
50
+
51
+ - Never ask for, read, store or print a token, key or password. If the user
52
+ pastes one, do not repeat it, and tell them OpenPlanr does not need it.
53
+ - Never edit host configuration, run install or sign-in commands, or sign in on
54
+ the user's behalf.
55
+ - Recommend the vendor's own connector from the catalog, never a third-party one.
56
+
57
+ ## Return
58
+
59
+ One line per category: connected (product), configured but not signed in
60
+ (product), or missing with the step shown (Connect card or host step). End with what the user does next.
@@ -0,0 +1,62 @@
1
+ # Connectors
2
+
3
+ OpenPlanr skills name a kind of service, such as `~~chat`, instead of a product. Connect
4
+ the product your team uses through your host: the vendor publishes the connector, and
5
+ you sign in through the host. OpenPlanr bundles no connectors; they and their credentials
6
+ live in your host. Two optional features need a token: Linear sync (`openplanr linear`) and
7
+ company sign-in (`openplanr company login`). Only when you use them does OpenPlanr store a
8
+ token, in your OS keychain, or in an encrypted file at `~/.planr/credentials.enc` if you set
9
+ `PLANR_CREDENTIAL_FILE_PASSPHRASE`. Tokens are sent only to Linear or to the company server
10
+ you sign in to.
11
+ `openplanr company logout` removes company tokens.
12
+ Every skill also works with nothing connected and reports any remote step it skipped.
13
+
14
+ | Category | Placeholder | Products |
15
+ | --- | --- | --- |
16
+ | Chat | `~~chat` | Slack, Microsoft Teams |
17
+ | Project tracker | `~~project tracker` | Linear, GitHub Issues, Jira, Asana |
18
+ | Source control | `~~source control` | GitHub, GitLab, Bitbucket |
19
+
20
+ Never paste a token into a chat, file or command for OpenPlanr. After you connect a
21
+ service, start a new request so the host loads its tools.
22
+
23
+ ## Chat (`~~chat`)
24
+
25
+ Share a status report, sprint note or release notes as a message draft that you review and send yourself.
26
+
27
+ | Product | Use | Claude Code | Codex | Cursor |
28
+ | --- | --- | --- | --- | --- |
29
+ | Slack | Message drafts | Run `/plugin install slack@claude-plugins-official`, then sign in to Slack from `/mcp`. A workspace admin may need to approve the app. | Install Slack from `/plugins` and sign in when asked. A workspace admin may need to approve the app. | Run `/add-plugin slack`, or install Slack from Customize, then sign in when asked. A workspace admin may need to approve the app. |
30
+
31
+ Message format for Slack, drafting through the connector: standard Markdown, which the connector converts on send ([Slack's messaging guidance](https://github.com/slackapi/slack-mcp-plugin/blob/main/skills/slack-messaging/SKILL.md)): `**bold**`, `_italic_`, `[link text](https://example.com)`, `-` lists, `>` quotes. Do not use mrkdwn's `*bold*` or `<url|text>` here.
32
+
33
+ Message format for Slack, text to paste: Slack mrkdwn ([formatting](https://docs.slack.dev/messaging/formatting-message-text)): `*bold*`, `_italic_`, `<https://example.com|link text>`, lines starting with `•` or `-` for lists, `>` for quotes; no headings or tables; escape `&`, `<` and `>` as `&amp;`, `&lt;` and `&gt;`.
34
+
35
+ Also works with: [Microsoft Teams](https://learn.microsoft.com/en-us/microsoft-copilot-studio/mcp-teams-tools) (read for context). Add the vendor's connector in your host the same way.
36
+
37
+ Verified: [Slack](https://docs.slack.dev/ai/slack-mcp-server) on 2026-10-09, [Microsoft Teams](https://learn.microsoft.com/en-us/microsoft-copilot-studio/mcp-teams-tools) on 2026-10-09.
38
+
39
+ ## Project tracker (`~~project tracker`)
40
+
41
+ Push planning status to linked issues after you approve each change, and read issue state back.
42
+
43
+ | Product | Use | Claude Code | Codex | Cursor |
44
+ | --- | --- | --- | --- | --- |
45
+ | Linear | OpenPlanr syncs with it | Run `/plugin install linear@claude-plugins-official`, then sign in to Linear from `/mcp`. | Install Linear from `/plugins` and sign in when asked. | Run `/add-plugin linear`, or install Linear from Customize, then sign in when asked. |
46
+ | GitHub Issues | OpenPlanr syncs with it | Install the GitHub CLI from cli.github.com and run `gh auth login`. | Install GitHub from `/plugins` and sign in when asked, or install the GitHub CLI and run `gh auth login`. | Install the GitHub CLI from cli.github.com and run `gh auth login`. |
47
+
48
+ Also works with: [Jira](https://support.atlassian.com/atlassian-ai-gateway/docs/get-started-with-the-atlassian-remote-mcp-server/) (read for context), [Asana](https://developers.asana.com/docs/using-asanas-mcp-server) (read for context). Add the vendor's connector in your host the same way.
49
+
50
+ Verified: [Linear](https://linear.app/docs/mcp) on 2026-10-09, [GitHub Issues](https://cli.github.com/manual/gh_auth_login) on 2026-10-09, [Jira](https://support.atlassian.com/atlassian-ai-gateway/docs/get-started-with-the-atlassian-remote-mcp-server/) on 2026-10-09, [Asana](https://developers.asana.com/docs/using-asanas-mcp-server) on 2026-10-09.
51
+
52
+ ## Source control (`~~source control`)
53
+
54
+ Read pull request and branch state for status reports and sprint reviews.
55
+
56
+ | Product | Use | Claude Code | Codex | Cursor |
57
+ | --- | --- | --- | --- | --- |
58
+ | GitHub | Read for context | Install the GitHub CLI from cli.github.com and run `gh auth login`. | Install GitHub from `/plugins` and sign in when asked, or install the GitHub CLI and run `gh auth login`. | Install the GitHub CLI from cli.github.com and run `gh auth login`. |
59
+
60
+ Also works with: [GitLab](https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_server/) (read for context), [Bitbucket](https://support.atlassian.com/atlassian-ai-gateway/docs/get-started-with-the-atlassian-remote-mcp-server/) (read for context). Add the vendor's connector in your host the same way.
61
+
62
+ Verified: [GitHub](https://cli.github.com/manual/gh_auth_login) on 2026-10-09, [GitLab](https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_server/) on 2026-10-09, [Bitbucket](https://support.atlassian.com/atlassian-ai-gateway/docs/get-started-with-the-atlassian-remote-mcp-server/) on 2026-10-09.
@@ -31,6 +31,8 @@ Claude Code and `$planr:plan` in Codex). Do not perform the routed work here.
31
31
  | Refine the open backlog and select the sprint for the next release cut | `planr-sprint` |
32
32
  | See planning or Operate state in the browser | `planr-dashboard` |
33
33
  | Check artifacts for graph, status, or schema drift | `planr-sync` |
34
+ | Post a status, sprint, or release update to chat | `planr-share` (user-invoked) |
35
+ | Connect chat, a tracker, or source control, or see what is connected | `planr-connect` (user-invoked) |
34
36
  | Judge release readiness or prepare a landing sequence | `planr-land` |
35
37
  | Pick a versioning scheme, bump versions, write release notes | `planr-release` |
36
38
  | Diagnose the CLI, plugins, installation, or upgrade state | `planr-doctor` |
@@ -47,6 +49,8 @@ Claude Code and `$planr:plan` in Codex). Do not perform the routed work here.
47
49
  review code does not request implementation delegation.
48
50
  - PLAN and SHIP are separate user-invoked workflows. Route to one; never chain
49
51
  `planr-plan` into `planr-ship` on the user's behalf.
52
+ - `planr-share` and `planr-connect` run only when the user invokes them. When a
53
+ request matches one, name the command for the user to run instead of running it.
50
54
  - When a request spans several skills, route to the earliest step in that
51
55
  order (spec → plan → plan-review → ship → land → release) and name the rest.
52
56
  - When the request is not OpenPlanr work at all, say so and answer directly
@@ -77,7 +77,10 @@ Write stories and tasks directly in the repository's active planning mode.
77
77
 
78
78
  - Allocate project-global monotonic `US-NNN` and `T-NNN` IDs. Never reuse a
79
79
  deleted ID. The packaged [planning ID helper](scripts/planning-ids.mjs) may
80
- inspect or reserve IDs; it never generates content.
80
+ inspect or reserve IDs; it never generates content. Pass `--root` with the
81
+ `specs` folder under the project's configured planning path (`.planr/specs`
82
+ by default). It exits non-zero when that folder is missing or is not the one
83
+ `.planr/config.json` configures; never fall back to `US-001` or `T-001`.
81
84
  - Give each story stable acceptance IDs starting at `AC-001`.
82
85
  - Split each story into tasks that are coherent and independently verifiable.
83
86
  Separate by ownership first: UI work is a `UI` task for the frontend role and
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { mkdir, open, readdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
4
- import { resolve } from 'node:path';
3
+ import { open, readdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';
4
+ import { dirname, join, resolve } from 'node:path';
5
5
 
6
6
  const KINDS = Object.freeze(['SPEC', 'US', 'T']);
7
7
  const EMPTY = Object.freeze({ SPEC: 1, US: 1, T: 1 });
@@ -71,9 +71,55 @@ function parseArgs(argv) {
71
71
  return options;
72
72
  }
73
73
 
74
+ const shellQuote = (value) => (/^[\w./-]+$/u.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`);
75
+
76
+ /** Returns the nearest `.planr/config.json` at or above `directory` and the specs folder it configures. */
77
+ async function configuredRoot(directory) {
78
+ for (let current = directory; ; current = dirname(current)) {
79
+ const configPath = join(current, '.planr', 'config.json');
80
+ const raw = await readFile(configPath, 'utf8').catch((error) => {
81
+ if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return null;
82
+ throw error;
83
+ });
84
+ if (raw !== null) {
85
+ let agile;
86
+ try {
87
+ agile = JSON.parse(raw).outputPaths?.agile ?? '.planr';
88
+ } catch (error) {
89
+ throw new Error(`Project config ${configPath} is not valid JSON: ${error.message}`);
90
+ }
91
+ if (typeof agile !== 'string') throw new Error(`Project config ${configPath} has a non-string outputPaths.agile.`);
92
+ return { configPath, expected: resolve(current, agile, 'specs') };
93
+ }
94
+ if (dirname(current) === current) return null;
95
+ }
96
+ }
97
+
98
+ /** Accepts only an existing directory that the nearest project config names as its planning folder. */
99
+ async function assertPlanningRoot(planningRoot) {
100
+ const project = await configuredRoot(planningRoot);
101
+ if (!project) {
102
+ throw new Error(`Planning root ${planningRoot} is not inside an OpenPlanr project: no .planr/config.json in it or any parent directory.`);
103
+ }
104
+ const { configPath, expected } = project;
105
+ if (planningRoot !== expected) {
106
+ throw new Error(`Planning root ${planningRoot} is not the planning folder configured by ${configPath}, which expects ${expected}.`);
107
+ }
108
+ const status = await stat(planningRoot).catch((error) => {
109
+ if (error.code === 'ENOENT') return null;
110
+ throw error;
111
+ });
112
+ if (!status) {
113
+ throw new Error(
114
+ `Planning root ${planningRoot} does not exist; ${configPath} expects it. Create it with \`mkdir -p ${shellQuote(planningRoot)}\`, or fix outputPaths.agile in ${configPath}.`,
115
+ );
116
+ }
117
+ if (!status.isDirectory()) throw new Error(`Planning root ${planningRoot} is not a directory; ${configPath} expects a directory there.`);
118
+ }
119
+
74
120
  async function reserve({ root, preview, counts }) {
75
121
  const planningRoot = resolve(root);
76
- if (!preview) await mkdir(planningRoot, { recursive: true });
122
+ await assertPlanningRoot(planningRoot);
77
123
  const run = async () => {
78
124
  const sequence = await currentSequence(planningRoot);
79
125
  const ids = Object.fromEntries(