fraim-framework 1.0.9 β†’ 1.0.10

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.
@@ -0,0 +1,218 @@
1
+ name: Phase Change Handler
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ permissions:
8
+ issues: write
9
+ pull-requests: write
10
+ contents: write
11
+
12
+ jobs:
13
+ handle-phase-change:
14
+ runs-on: ubuntu-latest
15
+ if: |
16
+ contains(github.event.label.name, 'phase:') ||
17
+ (github.event.action == 'unlabeled' && contains(github.event.label.name, 'phase:'))
18
+
19
+ steps:
20
+ - name: Checkout repository
21
+ uses: actions/checkout@v4
22
+ with:
23
+ token: ${{ secrets.GITHUB_TOKEN }}
24
+ fetch-depth: 0
25
+
26
+ - name: Setup Git
27
+ run: |
28
+ git config --global user.name "github-actions[bot]"
29
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
30
+
31
+ - name: Auth GitHub CLI
32
+ run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token
33
+
34
+ - name: Extract issue details
35
+ id: issue-details
36
+ run: |
37
+ ISSUE_NUMBER="${{ github.event.issue.number }}"
38
+ ISSUE_TITLE="${{ github.event.issue.title }}"
39
+ BRANCH_NAME="feature/${ISSUE_NUMBER}-$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')"
40
+
41
+ echo "issue_number=$ISSUE_NUMBER" >> $GITHUB_OUTPUT
42
+ echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
43
+ echo "issue_title=$ISSUE_TITLE" >> $GITHUB_OUTPUT
44
+
45
+ - name: Determine current phase
46
+ id: current-phase
47
+ run: |
48
+ LABELS='${{ toJson(github.event.issue.labels) }}'
49
+ CURRENT_PHASE=""
50
+
51
+ # Extract current phase from labels
52
+ for label in $(echo "$LABELS" | jq -r '.[].name'); do
53
+ if [[ $label == phase:* ]]; then
54
+ CURRENT_PHASE=$label
55
+ break
56
+ fi
57
+ done
58
+
59
+ echo "current_phase=$CURRENT_PHASE" >> $GITHUB_OUTPUT
60
+ echo "Current phase: $CURRENT_PHASE"
61
+
62
+ - name: Ensure branch exists and sync
63
+ run: |
64
+ BRANCH_NAME="${{ steps.issue-details.outputs.branch_name }}"
65
+ BASE="master"
66
+
67
+ git fetch origin "$BASE"
68
+
69
+ if git ls-remote --exit-code --heads origin "$BRANCH_NAME" >/dev/null 2>&1; then
70
+ echo "Branch $BRANCH_NAME exists, syncing..."
71
+ git fetch origin "$BRANCH_NAME"
72
+ git switch "$BRANCH_NAME"
73
+ git pull --rebase origin "$BRANCH_NAME"
74
+ else
75
+ echo "Branch $BRANCH_NAME does not exist, creating from $BASE..."
76
+ git switch -c "$BRANCH_NAME" "origin/$BASE"
77
+ git push -u origin "$BRANCH_NAME"
78
+ fi
79
+
80
+ # Design: add EMPTY commit to guarantee a diff
81
+ - name: phase:design β†’ ensure empty commit (commit if missing)
82
+ if: steps.current-phase.outputs.current_phase == 'phase:design'
83
+ shell: bash
84
+ env:
85
+ ISSUE: ${{ github.event.issue.number }}
86
+ run: |
87
+ ISSUE_NUMBER="${{ steps.issue-details.outputs.issue_number }}"
88
+ ISSUE_TITLE="${{ steps.issue-details.outputs.issue_title }}"
89
+ BRANCH_NAME="${{ steps.issue-details.outputs.branch_name }}"
90
+
91
+ # Create empty commit to guarantee branch has commits
92
+ git commit --allow-empty -m "Design phase initiated for Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
93
+ git push origin "$BRANCH_NAME"
94
+
95
+ # Create or update Design PR
96
+ PR_TITLE="[Design] RFC for Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
97
+ PR_BODY="## Design RFC for Issue #$ISSUE_NUMBER
98
+
99
+ This PR contains the design RFC for: $ISSUE_TITLE
100
+
101
+ **Phase:** Design
102
+ **Issue:** #$ISSUE_NUMBER
103
+ **Branch:** \`$BRANCH_NAME\`
104
+
105
+ ### RFC Document
106
+ - πŸ“‹ [RFC Document]($RFC_FILE)
107
+
108
+ **Note:** This is a Design PR. Implementation will follow in a separate PR after design approval.
109
+
110
+ "
111
+
112
+ # Check if PR already exists
113
+ EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' 2>/dev/null || echo "")
114
+
115
+ if [ -n "$EXISTING_PR" ]; then
116
+ echo "Updating existing PR #$EXISTING_PR"
117
+ gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY"
118
+ gh pr edit "$EXISTING_PR" --add-label "phase:design" --remove-label "phase:tests" --remove-label "phase:impl"
119
+ else
120
+ echo "Creating new Design PR"
121
+ gh pr create --title "$PR_TITLE" --body "$PR_BODY" --base master --head "$BRANCH_NAME" --draft
122
+ # Add labels to the new PR
123
+ sleep 2 # Brief delay to ensure PR is created
124
+ NEW_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number')
125
+ gh pr edit "$NEW_PR" --add-label "phase:design" --remove-label "phase:tests" --remove-label "phase:impl"
126
+ fi
127
+
128
+ - name: Handle test phase
129
+ if: steps.current-phase.outputs.current_phase == 'phase:tests'
130
+ run: |
131
+ ISSUE_NUMBER="${{ steps.issue-details.outputs.issue_number }}"
132
+ ISSUE_TITLE="${{ steps.issue-details.outputs.issue_title }}"
133
+ BRANCH_NAME="${{ steps.issue-details.outputs.branch_name }}"
134
+
135
+ # Create or update Test Implementation PR
136
+ PR_TITLE="[Testing] Test Cases for Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
137
+ PR_BODY="## Test cases for Issue #$ISSUE_NUMBER
138
+
139
+ This PR contains the test cases for: $ISSUE_TITLE
140
+
141
+ **Phase:** Tests
142
+ **Issue:** #$ISSUE_NUMBER
143
+ **Branch:** \`$BRANCH_NAME\`
144
+
145
+ ### Test Cases
146
+
147
+
148
+ **Note:** This is a Test PR. Implementation will follow after test approval.
149
+
150
+ "
151
+
152
+ # Check if PR already exists
153
+ EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' 2>/dev/null || echo "")
154
+
155
+ if [ -n "$EXISTING_PR" ]; then
156
+ echo "Updating existing PR #$EXISTING_PR"
157
+ gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY"
158
+ gh pr edit "$EXISTING_PR" --add-label "phase:tests" --remove-label "phase:design" --remove-label "phase:impl"
159
+ else
160
+ echo "Creating new Test Plan PR"
161
+ gh pr create --title "$PR_TITLE" --body "$PR_BODY" --base master --head "$BRANCH_NAME" --draft
162
+ # Add labels to the new PR
163
+ sleep 2 # Brief delay to ensure PR is created
164
+ NEW_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number')
165
+ gh pr edit "$NEW_PR" --add-label "phase:tests" --remove-label "phase:design" --remove-label "phase:impl"
166
+ fi
167
+
168
+ - name: Handle implementation phase
169
+ if: steps.current-phase.outputs.current_phase == 'phase:impl'
170
+ run: |
171
+ ISSUE_NUMBER="${{ steps.issue-details.outputs.issue_number }}"
172
+ ISSUE_TITLE="${{ steps.issue-details.outputs.issue_title }}"
173
+ BRANCH_NAME="${{ steps.issue-details.outputs.branch_name }}"
174
+
175
+ # Create or update Implementation PR
176
+ PR_TITLE="[Implementation] Fixes for Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
177
+ PR_BODY="## Fixes for Issue #$ISSUE_NUMBER
178
+
179
+ This PR contains the fixes for: $ISSUE_TITLE
180
+
181
+ **Phase:** Implementation
182
+ **Issue:** #$ISSUE_NUMBER
183
+ **Branch:** \`$BRANCH_NAME\`
184
+
185
+ ### Fixes
186
+
187
+
188
+ Closes #$ISSUE_NUMBER
189
+
190
+ "
191
+
192
+ # Check if PR already exists
193
+ EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' 2>/dev/null || echo "")
194
+
195
+ if [ -n "$EXISTING_PR" ]; then
196
+ echo "Updating existing PR #$EXISTING_PR"
197
+ gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY"
198
+ gh pr edit "$EXISTING_PR" --add-label "phase:impl" --remove-label "phase:design" --remove-label "phase:tests"
199
+ else
200
+ echo "Creating new Implementation PR"
201
+ gh pr create --title "$PR_TITLE" --body "$PR_BODY" --base master --head "$BRANCH_NAME" --draft
202
+ # Add labels to the new PR
203
+ sleep 2 # Brief delay to ensure PR is created
204
+ NEW_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number')
205
+ gh pr edit "$NEW_PR" --add-label "phase:impl" --remove-label "phase:design" --remove-label "phase:tests"
206
+ fi
207
+
208
+ - name: Normalize ISSUE and PR status to WIP (authoritative)
209
+ run: |
210
+ gh issue edit ${{ github.event.issue.number }} --add-label "status:wip" --remove-label "status:needs-review" --remove-label "status:complete" || true
211
+
212
+ # Get the PR number for the current branch and normalize its status
213
+ BRANCH_NAME="${{ steps.issue-details.outputs.branch_name }}"
214
+ PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' 2>/dev/null || echo "")
215
+
216
+ if [ -n "$PR_NUMBER" ]; then
217
+ gh pr edit "$PR_NUMBER" --add-label "status:wip" --remove-label "status:needs-review" --remove-label "status:complete" || true
218
+ fi
@@ -0,0 +1,68 @@
1
+ name: Status Change β†’ Flip PR Draft/Ready
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ permissions:
8
+ pull-requests: write
9
+ issues: read
10
+ contents: write
11
+
12
+ # Serialize per ISSUE; last status wins
13
+ concurrency:
14
+ group: status-change-${{ github.event.issue.number }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ status-change:
19
+ if: startsWith(github.event.label.name, 'status:')
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v4
24
+ with:
25
+ token: ${{ secrets.GITHUB_TOKEN }}
26
+ fetch-depth: 0
27
+
28
+ - name: Setup Git
29
+ run: |
30
+ git config --global user.name "github-actions[bot]"
31
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
32
+
33
+ - name: Auth GitHub CLI
34
+ run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token
35
+
36
+ - name: Derive branch + find PR
37
+ id: pr
38
+ shell: bash
39
+ env:
40
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
41
+ ISSUE_TITLE: ${{ github.event.issue.title }}
42
+ run: |
43
+ set -euo pipefail
44
+ slug=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g;s/^-+|-+$//g')
45
+ BR="feature/${ISSUE_NUMBER}-${slug}"
46
+ PR=$(gh pr list --state open --head "$BR" --json number --jq '.[0].number')
47
+ echo "pr=$PR" >> $GITHUB_OUTPUT
48
+ echo "label=${{ github.event.label.name }}" >> $GITHUB_OUTPUT
49
+
50
+ - name: Flip PR state (Draft/Ready) based on label
51
+ if: steps.pr.outputs.pr != ''
52
+ shell: bash
53
+ env:
54
+ PR: ${{ steps.pr.outputs.pr }}
55
+ LABEL: ${{ steps.pr.outputs.label }}
56
+ run: |
57
+ set -euo pipefail
58
+ case "$LABEL" in
59
+ status:needs-review)
60
+ gh pr ready "$PR"
61
+ gh pr edit "$PR" --add-label "status:needs-review" --remove-label "status:wip" --remove-label "status:complete" || true
62
+ ;;
63
+ status:wip)
64
+ gh pr edit "$PR" --add-label "status:wip" --remove-label "status:needs-review" --remove-label "status:complete" || true
65
+ ;;
66
+ *)
67
+ echo "No action for label: $LABEL" ;;
68
+ esac
@@ -0,0 +1,66 @@
1
+ name: Sync Issue on PR Review
2
+ on:
3
+ pull_request_review:
4
+ types: [submitted]
5
+
6
+ permissions:
7
+ pull-requests: write
8
+ issues: write
9
+
10
+ concurrency:
11
+ group: review-sync-${{ github.event.pull_request.number }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ sync-on-review:
16
+ runs-on: ubuntu-latest
17
+ # no job-level `if` β€” we branch inside the script
18
+ env:
19
+ GH_TOKEN: ${{ secrets.PR_AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }}
20
+ REPO: ${{ github.repository }}
21
+ steps:
22
+ - name: Derive review state, issue number, and branch
23
+ id: vars
24
+ shell: bash
25
+ run: |
26
+ set -euo pipefail
27
+ STATE="${{ github.event.review.state }}"
28
+ BR="${{ github.event.pull_request.head.ref }}" # e.g., feature/26-slug
29
+ ISSUE="$(sed -nE 's#^feature/([0-9]+)-.*#\1#p' <<< "$BR" || true)"
30
+ echo "state=$STATE" >> $GITHUB_OUTPUT
31
+ echo "issue=$ISSUE" >> $GITHUB_OUTPUT
32
+ echo "branch=$BR" >> $GITHUB_OUTPUT
33
+ echo "Detected review state: $STATE; branch: $BR; issue: $ISSUE"
34
+
35
+ - name: Handle review states
36
+ if: steps.vars.outputs.issue != ''
37
+ shell: bash
38
+ env:
39
+ STATE: ${{ steps.vars.outputs.state }}
40
+ ISSUE: ${{ steps.vars.outputs.issue }}
41
+ PRNUM: ${{ github.event.pull_request.number }}
42
+ REPO: ${{ env.REPO }}
43
+ run: |
44
+ set -euo pipefail
45
+ case "$STATE" in
46
+ changes_requested)
47
+ # Flip to WIP
48
+ gh issue edit "$ISSUE" --repo "$REPO" \
49
+ --add-label "status:wip" --remove-label "status:needs-review" --remove-label "status:complete" || true
50
+ gh pr edit "$PRNUM" --repo "$REPO" \
51
+ --add-label "status:wip" --remove-label "status:needs-review" --remove-label "status:complete" || true
52
+ ;;
53
+ approved)
54
+ # Flip to Complete
55
+ gh issue edit "$ISSUE" --repo "$REPO" \
56
+ --add-label "status:complete" --remove-label "status:wip" --remove-label "status:needs-review" || true
57
+ gh pr edit "$PRNUM" --repo "$REPO" --add-label "status:complete" --remove-label "status:wip" --remove-label "status:needs-review" || true
58
+ ;;
59
+ commented)
60
+ # No-op; comments don’t change state
61
+ echo "Review was 'commented' β€” no state change."
62
+ ;;
63
+ *)
64
+ echo "Unknown review state: $STATE"
65
+ ;;
66
+ esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "FRAIM: Framework for Rigor-based AI Management - Where humans become AI managers through rigorous methodology",
5
5
  "main": "index.js",
6
6
  "bin": {
package/setup.js CHANGED
@@ -285,98 +285,17 @@ function createLabelsConfigFile() {
285
285
  }
286
286
 
287
287
  function createGitHubWorkflows() {
288
- // Phase change workflow
289
- const phaseChangeWorkflow = `name: Phase Change Automation
290
-
291
- on:
292
- issues:
293
- types: [labeled, unlabeled]
294
-
295
- jobs:
296
- phase-change:
297
- runs-on: ubuntu-latest
298
- if: contains(github.event.issue.labels.*.name, 'phase:') || contains(github.event.label.name, 'phase:')
299
- steps:
300
- - name: Checkout
301
- uses: actions/checkout@v4
302
-
303
- - name: Phase Change Handler
304
- run: |
305
- echo "Phase change detected for issue #\${{ github.event.issue.number }}"
306
- echo "New phase: \${{ github.event.label.name || 'phase removed' }}"
307
-
308
- - name: Update Issue Status
309
- if: contains(github.event.label.name, 'phase:')
310
- run: |
311
- gh issue edit \${{ github.event.issue.number }} --add-label "status:wip"
312
- echo "Status updated to WIP for new phase"
313
- `;
314
-
315
- // Status change workflow
316
- const statusChangeWorkflow = `name: Status Change Automation
317
-
318
- on:
319
- issues:
320
- types: [labeled, unlabeled]
321
-
322
- jobs:
323
- status-change:
324
- runs-on: ubuntu-latest
325
- if: contains(github.event.issue.labels.*.name, 'status:') || contains(github.event.label.name, 'status:')
326
- steps:
327
- - name: Checkout
328
- uses: actions/checkout@v4
329
-
330
- - name: Status Change Handler
331
- run: |
332
- echo "Status change detected for issue #\${{ github.event.issue.number }}"
333
- echo "New status: \${{ github.event.label.name || 'status removed' }}"
334
-
335
- - name: Notify Team
336
- if: contains(github.event.label.name, 'status:needs-review')
337
- run: |
338
- echo "Issue ready for review - notifying team"
339
- `;
340
-
341
- // Sync on PR review workflow
342
- const syncOnPRReviewWorkflow = `name: Sync on PR Review
343
-
344
- on:
345
- pull_request_review:
346
- types: [submitted, edited, dismissed]
347
-
348
- jobs:
349
- sync-review:
350
- runs-on: ubuntu-latest
351
- steps:
352
- - name: Checkout
353
- uses: actions/checkout@v4
354
-
355
- - name: Sync Review Status
356
- env:
357
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
358
- run: |
359
- PR_NUMBER="\${{ github.event.pull_request.number }}"
360
- REVIEW_STATE="\${{ github.event.review.state }}"
361
-
362
- echo "PR #\$PR_NUMBER review state: \$REVIEW_STATE"
363
-
364
- if [ "\$REVIEW_STATE" = "approved" ]; then
365
- echo "PR approved - updating status"
366
- gh pr edit \$PR_NUMBER --add-label "status:approved"
367
- elif [ "\$REVIEW_STATE" = "changes_requested" ]; then
368
- echo "Changes requested - updating status"
369
- gh pr edit \$PR_NUMBER --add-label "status:changes-requested"
370
- fi
371
-
372
- echo "Review sync complete"
373
- `;
374
-
375
- writeFile('.github/workflows/phase-change.yml', phaseChangeWorkflow);
376
- writeFile('.github/workflows/status-change.yml', statusChangeWorkflow);
377
- writeFile('.github/workflows/sync-on-pr-review.yml', syncOnPRReviewWorkflow);
288
+ // Get the directory where this script is located (FRAIM package directory)
289
+ const fraimDir = __dirname;
378
290
 
379
- logSuccess('GitHub workflows created');
291
+ // Copy actual workflow files from FRAIM/github folder
292
+ const workflowsSrc = path.join(fraimDir, 'github');
293
+ if (fs.existsSync(workflowsSrc)) {
294
+ copyDirectory(workflowsSrc, '.github/workflows');
295
+ logSuccess('GitHub workflows copied from FRAIM/github folder');
296
+ } else {
297
+ logWarning(`github folder not found at ${workflowsSrc}, skipping workflow creation`);
298
+ }
380
299
  }
381
300
 
382
301
  function createAgentFolders() {