@callumvass/forgeflow-dev 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,3 +35,7 @@ npx pi install @callumvass/forgeflow-dev
35
35
  - **opensrc** — Fetch library source code for reference
36
36
  - **stitch** — UI design reference integration
37
37
  - **plugins** — Domain-specific review plugin router
38
+
39
+ ## Usage examples
40
+
41
+ See the [root README](../../README.md#commands) for detailed usage examples of each command.
@@ -89,6 +89,20 @@ Scan `<cwd>/.forgeflow/plugins/*/PLUGIN.md` for plugins matching the `implement`
89
89
 
90
90
  For each matched plugin, read the plugin body and follow its guidance — framework-specific idioms, API patterns, common pitfalls, and conventions for the project's tech stack.
91
91
 
92
+ ## Creating PRs
93
+
94
+ When creating a PR with `gh pr create`, ALWAYS write the body to a temp file and use `--body-file` instead of `--body`. The `--body` flag breaks markdown formatting due to shell escaping. Example:
95
+
96
+ ```bash
97
+ cat > /tmp/pr-body.md << 'PRBODY'
98
+ ## Summary
99
+ - description here
100
+
101
+ Closes #123
102
+ PRBODY
103
+ gh pr create --title "My title" --body-file /tmp/pr-body.md
104
+ ```
105
+
92
106
  ## Before Committing
93
107
 
94
108
  - **Reachability check**: Every new module, class, or function you created must be imported and called from production code — not just from tests. Trace from the entry point to your new code.
@@ -377,6 +377,7 @@ function exec(cmd, cwd) {
377
377
 
378
378
  // src/utils/git.ts
379
379
  import * as fs3 from "fs";
380
+ import * as os2 from "os";
380
381
  import * as path4 from "path";
381
382
  var PR_TEMPLATE_PATHS = [
382
383
  ".github/pull_request_template.md",
@@ -401,6 +402,18 @@ ${template}`;
401
402
  }
402
403
  return defaultBody;
403
404
  }
405
+ async function createPr(cwd, title, body, branch) {
406
+ const tmp = path4.join(os2.tmpdir(), `forgeflow-pr-${Date.now()}.md`);
407
+ try {
408
+ fs3.writeFileSync(tmp, body, "utf-8");
409
+ await exec(`gh pr create --title "${title}" --body-file "${tmp}" --head ${branch}`, cwd);
410
+ } finally {
411
+ try {
412
+ fs3.unlinkSync(tmp);
413
+ } catch {
414
+ }
415
+ }
416
+ }
404
417
  function slugify(text, maxLen = 40) {
405
418
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, maxLen).replace(/-$/, "");
406
419
  }
@@ -746,7 +759,7 @@ ${flags.customPrompt}` : "";
746
759
  if (parseInt(ahead, 10) > 0) {
747
760
  await exec(`git push -u origin ${resolved.branch}`, cwd);
748
761
  const prBody = buildPrBody(cwd, resolved);
749
- await exec(`gh pr create --title "${resolved.title}" --body "${prBody}" --head ${resolved.branch}`, cwd);
762
+ await createPr(cwd, resolved.title, prBody, resolved.branch);
750
763
  const stages2 = [];
751
764
  await refactorAndReview(cwd, signal, onUpdate, ctx, stages2, flags.skipReview);
752
765
  return {
@@ -836,7 +849,7 @@ ${plan}` : "";
836
849
  const prNote = resolved.existingPR ? `
837
850
  - PR #${resolved.existingPR} already exists for this branch.` : "";
838
851
  const closeNote = isGitHub ? `
839
- - The PR body MUST include 'Closes #${resolved.number}' so the issue auto-closes on merge.` : `
852
+ - The PR body MUST end with a blank line then 'Closes #${resolved.number}' on its own line (not inline with other text), so the issue auto-closes on merge.` : `
840
853
  - The PR body should reference Jira issue ${resolved.key}.`;
841
854
  const unresolvedNote = flags.autonomous ? `
842
855
  - If the plan has unresolved questions, resolve them yourself using sensible defaults. Do NOT stop and wait.` : "";
@@ -873,7 +886,7 @@ ${reason}` }],
873
886
  prNumber = await exec(`gh pr list --head "${resolved.branch}" --json number --jq '.[0].number'`, cwd);
874
887
  if (!prNumber || prNumber === "null") {
875
888
  const prBody = buildPrBody(cwd, resolved);
876
- await exec(`gh pr create --title "${resolved.title}" --body "${prBody}" --head ${resolved.branch}`, cwd);
889
+ await createPr(cwd, resolved.title, prBody, resolved.branch);
877
890
  prNumber = await exec(`gh pr list --head "${resolved.branch}" --json number --jq '.[0].number'`, cwd);
878
891
  }
879
892
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@callumvass/forgeflow-dev",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Dev pipeline for Pi — TDD implementation, code review, architecture, and skill discovery.",
6
6
  "keywords": [