@svayam-opensource/prj 0.5.1

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,163 @@
1
+ #!/usr/bin/env bash
2
+ # Script: merge-task
3
+ # Purpose: Merges a completed sub-branch back into the project integration branch.
4
+ # Archives sub-branch. Closes the GitHub Issue(s) it covers.
5
+ # Usage: bash merge-task.sh <project_id> <issue_url | task_branch>
6
+ # arg2 may be a GitHub issue URL (single-issue task) OR the task
7
+ # sub-branch itself (BRANCH.ISSUE-<n1>-<n2>), which the work flow passes
8
+ # directly so combined multi-issue branches merge correctly (POL-070).
9
+ # Compliance: C02 (POL-073 to POL-075)
10
+
11
+ set -euo pipefail
12
+ source "$(dirname "$0")/lib.sh"
13
+ load_config
14
+
15
+ # ── Inputs ────────────────────────────────────────────────────────────────────
16
+
17
+ PROJECT_ID="${1:-}"
18
+ TASK_ARG="${2:-}"
19
+
20
+ [[ -n "$PROJECT_ID" ]] || hard_stop "Usage: $0 <project_id> <issue_url | task_branch>"
21
+ [[ -n "$TASK_ARG" ]] || hard_stop "Usage: $0 <project_id> <issue_url | task_branch>"
22
+
23
+ echo "=== merge-task: $PROJECT_ID / $TASK_ARG"
24
+ echo ""
25
+
26
+ PROJECT_YAML=$(get_project_yaml "$PROJECT_ID")
27
+ check_project_exists "$PROJECT_ID"
28
+
29
+ # ── Pre-conditions ────────────────────────────────────────────────────────────
30
+
31
+ require_project_status "$PROJECT_YAML" "active"
32
+
33
+ # This op merges + pushes + archives branches + closes the issue — all mutating.
34
+ # Gate it on GitHub-Project write access like the other mutating scripts
35
+ # (create-task/seed/resume), per H9.
36
+ CURRENT_USER=$(git config user.email 2>/dev/null || echo "")
37
+ ASSIGNED_TO=$(yaml_get "$PROJECT_YAML" "assigned_to") # display/audit cache
38
+ GH_PROJECT=$(yaml_get "$PROJECT_YAML" "github_project")
39
+ is_authorized_for_project "$GH_PROJECT" "$ASSIGNED_TO" \
40
+ || hard_stop "You ($CURRENT_USER) are not authorized on this project — you need write access to its GitHub Project ($GH_PROJECT)."
41
+
42
+ BRANCH=$(project_branch_for_id "$PROJECT_ID")
43
+
44
+ # Resolve arg2 → the task sub-branch (TASK_ID) and every issue it closes.
45
+ # Scheme B (POL-070): sub-branch = BRANCH.ISSUE-<n1>-<n2>-…, keyed on issue NUMBERS.
46
+ # - issue URL → TASK_ID = BRANCH.ISSUE-<that number>; closes that one issue.
47
+ # - task branch → TASK_ID = the branch; closes every issue whose number it carries
48
+ # (resolved to a URL via the project board).
49
+ ISSUE_URLS=()
50
+
51
+ # resolve_board_issue_url <number> → the issue's URL on this project's board (or empty).
52
+ resolve_board_issue_url() {
53
+ local want="$1" pnum powner
54
+ pnum=$(echo "$GH_PROJECT" | grep -oE '/projects/[0-9]+' | grep -oE '[0-9]+')
55
+ powner=$(echo "$GH_PROJECT" | sed -E 's|.*/(orgs\|users)/([^/]+)/.*|\2|')
56
+ gh project item-list "$pnum" --owner "$powner" --format json --limit 200 2>/dev/null | python3 -c "
57
+ import sys, json
58
+ want = '$want'
59
+ try: d = json.load(sys.stdin)
60
+ except Exception: sys.exit(0)
61
+ for i in d.get('items', []):
62
+ c = i.get('content') or {}
63
+ if str(c.get('number')) == want and c.get('url'):
64
+ print(c['url']); break
65
+ "
66
+ }
67
+
68
+ if [[ "$TASK_ARG" == *"/issues/"* ]]; then
69
+ INUM=$(echo "$TASK_ARG" | grep -oE '/issues/[0-9]+' | grep -oE '[0-9]+$') \
70
+ || hard_stop "Could not parse an issue number from $TASK_ARG"
71
+ [[ -n "$INUM" ]] || hard_stop "Could not parse an issue number from $TASK_ARG"
72
+ TASK_ID="${BRANCH}.ISSUE-${INUM}"
73
+ ISSUE_URLS+=("$TASK_ARG")
74
+ else
75
+ TASK_ID="$TASK_ARG"
76
+ [[ "$TASK_ID" == "${BRANCH}".ISSUE-* ]] \
77
+ || hard_stop "'$TASK_ID' is not a task sub-branch of '$BRANCH' (expected ${BRANCH}.ISSUE-<n>)."
78
+ SUFFIX="${TASK_ID#"${BRANCH}".ISSUE-}"
79
+ IFS='-' read -ra TASK_NUMS <<< "$SUFFIX"
80
+ for n in "${TASK_NUMS[@]}"; do
81
+ [[ "$n" =~ ^[0-9]+$ ]] || continue
82
+ u="$(resolve_board_issue_url "$n")"
83
+ if [[ -n "$u" ]]; then ISSUE_URLS+=("$u"); else warn "Could not resolve issue #$n on the board — close it manually after merge."; fi
84
+ done
85
+ fi
86
+
87
+ # Verify the task sub-branch exists on the remote
88
+ git -C "$REPO_ROOT" ls-remote --exit-code --heads origin "$TASK_ID" >/dev/null 2>&1 \
89
+ || hard_stop "No sub-branch '$TASK_ID' on the remote — was the task created?"
90
+
91
+ # Check no uncommitted changes in workspace
92
+ check_clean "$REPO_ROOT"
93
+
94
+ # Check no uncommitted changes in code repos
95
+ while IFS= read -r repo_url; do
96
+ REPO_DIR="$(repo_clone_dir "$PROJECT_ID" "$(get_repo_name "$repo_url")")"
97
+ [[ -e "$REPO_DIR/.git" ]] && check_clean "$REPO_DIR"
98
+ done < <(get_project_repos "$PROJECT_YAML")
99
+
100
+ # ── Merge sub-branch into project branch ─────────────────────────────────────
101
+ # Multi-repo, not transactional: a conflict on a later repo leaves earlier repos
102
+ # already merged+pushed. To make a re-run safe (H5) we detect an already-merged
103
+ # sub-branch with `git merge-base --is-ancestor` and skip it, and we defer ALL
104
+ # archiving until every merge+push has succeeded — so a mid-loop failure never
105
+ # archives some repos and not others.
106
+
107
+ # Merge the sub-branch into the project branch in <path>, idempotently:
108
+ # if $TASK_ID is already an ancestor of $BRANCH, the merge is a no-op and we skip
109
+ # (no checkout/merge/push) so re-runs after a partial failure don't churn.
110
+ merge_task_into_branch() {
111
+ local path="$1" label="$2"
112
+ git -C "$path" fetch origin "$TASK_ID" 2>/dev/null || true
113
+ if git -C "$path" merge-base --is-ancestor "$TASK_ID" "$BRANCH" 2>/dev/null; then
114
+ info "'$TASK_ID' already merged into '$BRANCH' in $label — skipping."
115
+ return 0
116
+ fi
117
+ echo "Merging '$TASK_ID' → '$BRANCH' in $label..."
118
+ merge_branch "$path" "$TASK_ID" "$BRANCH"
119
+ git -C "$path" push origin "$BRANCH"
120
+ }
121
+
122
+ cd "$REPO_ROOT"
123
+ merge_task_into_branch "$REPO_ROOT" "workspace repo"
124
+
125
+ while IFS= read -r repo_url; do
126
+ REPO_NAME=$(get_repo_name "$repo_url")
127
+ REPO_DIR="$(repo_clone_dir "$PROJECT_ID" "$REPO_NAME")"
128
+ if [[ ! -e "$REPO_DIR/.git" ]]; then
129
+ warn "Repo $REPO_NAME not cloned locally — skipping merge."
130
+ continue
131
+ fi
132
+ merge_task_into_branch "$REPO_DIR" "$REPO_NAME"
133
+ done < <(get_project_repos "$PROJECT_YAML")
134
+
135
+ # Reaching here means every merge+push above succeeded (merge_branch exits 2 on
136
+ # conflict). Only now is it safe to archive sub-branches across all repos.
137
+
138
+ # ── Archive sub-branches ──────────────────────────────────────────────────────
139
+
140
+ echo ""
141
+ echo "Archiving sub-branches..."
142
+
143
+ archive_branch "$REPO_ROOT" "$TASK_ID"
144
+
145
+ while IFS= read -r repo_url; do
146
+ REPO_DIR="$(repo_clone_dir "$PROJECT_ID" "$(get_repo_name "$repo_url")")"
147
+ [[ -e "$REPO_DIR/.git" ]] && archive_branch "$REPO_DIR" "$TASK_ID"
148
+ done < <(get_project_repos "$PROJECT_YAML")
149
+
150
+ # ── Close every GitHub Issue the branch covers + mark Done on the board ───────
151
+ GHPROJ=$(yaml_get "$PROJECT_YAML" "github_project")
152
+ for u in "${ISSUE_URLS[@]}"; do
153
+ gh issue close "$u" --comment "Task \`$TASK_ID\` merged into \`$BRANCH\`." 2>/dev/null \
154
+ || warn "Could not close issue $u — close manually."
155
+ info "Closed issue: $u"
156
+ board_set_status "$GHPROJ" "$u" "Done" || true
157
+ done
158
+
159
+ echo ""
160
+ echo "=== Task merged successfully!"
161
+ echo " Task: $TASK_ID"
162
+ echo " Merged → $BRANCH"
163
+ echo " Issues: ${ISSUE_URLS[*]:-n/a} (closed)"
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env bash
2
+ # Script: onboard-repo
3
+ # Purpose: Initializes the knowledge/ folder structure in an existing code repo,
4
+ # bringing it under the Agentic Development Policy.
5
+ # Usage: bash onboard-repo.sh <repo_url> <repo_description> <repo_owner>
6
+ # Compliance: C02 — repo owner must approve the PR (POL-108)
7
+
8
+ set -euo pipefail
9
+ source "$(dirname "$0")/lib.sh"
10
+ load_config
11
+
12
+ # ── Inputs ────────────────────────────────────────────────────────────────────
13
+
14
+ REPO_URL="${1:-}"
15
+ REPO_DESC="${2:-}"
16
+ REPO_OWNER="${3:-}"
17
+
18
+ [[ -n "$REPO_URL" ]] || hard_stop "Usage: $0 <repo_url> <repo_description> <repo_owner>"
19
+ [[ -n "$REPO_DESC" ]] || hard_stop "Usage: $0 <repo_url> <repo_description> <repo_owner>"
20
+ [[ -n "$REPO_OWNER" ]] || hard_stop "Usage: $0 <repo_url> <repo_description> <repo_owner>"
21
+
22
+ REPO_NAME=$(get_repo_name "$REPO_URL")
23
+ ONBOARD_BRANCH="onboard-knowledge"
24
+
25
+ echo "=== onboard-repo: $REPO_URL"
26
+ echo " Description: $REPO_DESC"
27
+ echo " Owner: $REPO_OWNER"
28
+ echo ""
29
+
30
+ # ── Clone or locate repo ──────────────────────────────────────────────────────
31
+
32
+ TMP_CLONE=false
33
+ # #65/H6: $PRJ_GOV_LOC was never defined → aborted under `set -u`. Use the
34
+ # resolved AGENT_WORK_ROOT (set by load_config), matching seed.sh/join.sh.
35
+ REPO_DIR="$AGENT_WORK_ROOT/onboard/$REPO_NAME"
36
+
37
+ if [[ -e "$REPO_DIR/.git" ]]; then
38
+ info "Found existing clone at $REPO_DIR — fetching..."
39
+ git -C "$REPO_DIR" fetch origin
40
+ else
41
+ info "Cloning $REPO_URL → $REPO_DIR..."
42
+ mkdir -p "$AGENT_WORK_ROOT/onboard"
43
+ git clone "$REPO_URL" "$REPO_DIR" || hard_stop "Clone failed for $REPO_URL — verify access."
44
+ TMP_CLONE=true
45
+ fi
46
+
47
+ # Detect default branch
48
+ REPO_DEFAULT_BRANCH=$(git -C "$REPO_DIR" symbolic-ref refs/remotes/origin/HEAD 2>/dev/null \
49
+ | sed 's|refs/remotes/origin/||') || REPO_DEFAULT_BRANCH="main"
50
+
51
+ # ── Pre-conditions ────────────────────────────────────────────────────────────
52
+
53
+ if [[ -d "$REPO_DIR/knowledge" ]]; then
54
+ hard_stop "knowledge/ already exists in $REPO_NAME — investigate existing structure."
55
+ fi
56
+
57
+ if git -C "$REPO_DIR" ls-remote --exit-code origin "$ONBOARD_BRANCH" &>/dev/null; then
58
+ hard_stop "Branch '$ONBOARD_BRANCH' already exists in $REPO_NAME — investigate before proceeding."
59
+ fi
60
+
61
+ # ── Create onboard-knowledge branch ──────────────────────────────────────────
62
+
63
+ git -C "$REPO_DIR" checkout "$REPO_DEFAULT_BRANCH"
64
+ git -C "$REPO_DIR" pull origin "$REPO_DEFAULT_BRANCH" 2>/dev/null || true
65
+ git -C "$REPO_DIR" checkout -b "$ONBOARD_BRANCH"
66
+
67
+ # ── Scaffold knowledge/ folder ────────────────────────────────────────────────
68
+
69
+ mkdir -p "$REPO_DIR/knowledge/repo"
70
+
71
+ # knowledge/agent.md — from repo-agent-template
72
+ cat > "$REPO_DIR/knowledge/agent.md" <<MD
73
+ # $REPO_NAME — Agent Entry Point
74
+
75
+ **Repository:** $REPO_URL
76
+ **Purpose:** $REPO_DESC
77
+ **Owner:** $REPO_OWNER
78
+
79
+ ---
80
+
81
+ ## Important: Knowledge Layer Priority
82
+
83
+ This file represents the **repo-local knowledge layer** — third priority.
84
+
85
+ \`\`\`
86
+ 1. Org-wide knowledge → $WORKSPACE_REPO/knowledge/ [HIGHEST]
87
+ 2. Project knowledge → $WORKSPACE_REPO/projects/<project-id>/knowledge/
88
+ 3. This repo's knowledge → this file and knowledge/repo/ [THIS FILE]
89
+ 4. Your developer prefs → $AGENT_WORK_ROOT/preferences/<your-gh-login>.md
90
+ \`\`\`
91
+
92
+ **This file cannot override org-wide knowledge or policy.**
93
+ See \`$WORKSPACE_REPO/knowledge/policies/agentic-development-policy.md\`.
94
+
95
+ ---
96
+
97
+ ## Repo Knowledge
98
+
99
+ Read the following before working in this repository:
100
+
101
+ - \`knowledge/repo/structure.md\` — directory layout, modules, packages
102
+ - \`knowledge/repo/environment.md\` — build tools, dependencies, setup instructions
103
+ - \`knowledge/repo/patterns.md\` — coding conventions, architectural patterns
104
+
105
+ ---
106
+
107
+ ## Write Restrictions
108
+
109
+ During an active project:
110
+ - Do NOT modify \`knowledge/repo/\` directly
111
+ - All knowledge writes go to \`$WORKSPACE_REPO/projects/<project-id>/knowledge/\`
112
+ - Repo knowledge is updated only via the project's knowledge close PR
113
+
114
+ ---
115
+
116
+ ## Data Classification Reminder
117
+
118
+ Never commit credentials, secrets, API keys, or PII (C01).
119
+ See \`$WORKSPACE_REPO/knowledge/policies/data-classification.md\`.
120
+ MD
121
+
122
+ # knowledge/repo/structure.md — placeholder
123
+ cat > "$REPO_DIR/knowledge/repo/structure.md" <<MD
124
+ # $REPO_NAME — Repository Structure
125
+
126
+ **Owner:** $REPO_OWNER
127
+ **TODO:** Populate this file with the repository's directory layout.
128
+
129
+ ---
130
+
131
+ ## Directory Layout
132
+
133
+ \`\`\`
134
+ <describe the top-level directories and their purpose>
135
+ \`\`\`
136
+
137
+ ## Key Modules / Packages
138
+
139
+ - \`<module>\` — <description>
140
+
141
+ ## Entry Points
142
+
143
+ - \`<main file or command>\` — <description>
144
+ MD
145
+
146
+ # knowledge/repo/environment.md — placeholder
147
+ cat > "$REPO_DIR/knowledge/repo/environment.md" <<MD
148
+ # $REPO_NAME — Environment & Setup
149
+
150
+ **Owner:** $REPO_OWNER
151
+ **TODO:** Populate this file with build tools, dependencies, and local setup.
152
+
153
+ ---
154
+
155
+ ## Prerequisites
156
+
157
+ - <tool> <version>
158
+ - <tool> <version>
159
+
160
+ ## Local Setup
161
+
162
+ \`\`\`bash
163
+ # Steps to get this repo running locally
164
+ \`\`\`
165
+
166
+ ## Environment Variables
167
+
168
+ | Variable | Required | Description |
169
+ |---|---|---|
170
+ | \`ENV_VAR\` | Yes | Description |
171
+
172
+ ## Running Tests
173
+
174
+ \`\`\`bash
175
+ # How to run the test suite
176
+ \`\`\`
177
+ MD
178
+
179
+ # knowledge/repo/patterns.md — placeholder
180
+ cat > "$REPO_DIR/knowledge/repo/patterns.md" <<MD
181
+ # $REPO_NAME — Patterns & Conventions
182
+
183
+ **Owner:** $REPO_OWNER
184
+ **TODO:** Populate this file with coding conventions and architectural patterns.
185
+
186
+ ---
187
+
188
+ ## Coding Style
189
+
190
+ - Language: <language>
191
+ - Linter / formatter: <tool>
192
+ - Key conventions: <describe>
193
+
194
+ ## Architectural Patterns
195
+
196
+ - <pattern name>: <description>
197
+
198
+ ## Common Pitfalls
199
+
200
+ - <pitfall>: <how to avoid>
201
+ MD
202
+
203
+ info "Scaffolded knowledge/ folder."
204
+
205
+ # ── Commit and push ───────────────────────────────────────────────────────────
206
+
207
+ git -C "$REPO_DIR" add knowledge/
208
+ git -C "$REPO_DIR" commit -m "onboard: initialize knowledge/ folder for agentic development"
209
+ git -C "$REPO_DIR" push -u origin "$ONBOARD_BRANCH" \
210
+ || hard_stop "Push failed for $REPO_URL — verify push access."
211
+
212
+ info "Branch '$ONBOARD_BRANCH' pushed."
213
+
214
+ # ── Raise PR ──────────────────────────────────────────────────────────────────
215
+
216
+ echo "Raising PR..."
217
+
218
+ PR_BODY=$(cat <<MD
219
+ ## [Onboard] Initialize \`knowledge/\` folder for agentic development
220
+
221
+ This PR adds the \`knowledge/\` folder structure to bring **$REPO_NAME** under the
222
+ $ORG_NAME Agentic Development Policy.
223
+
224
+ ### What was added
225
+
226
+ - \`knowledge/agent.md\` — agent entry point with knowledge layer priority
227
+ - \`knowledge/repo/structure.md\` — placeholder for repo structure
228
+ - \`knowledge/repo/environment.md\` — placeholder for build/setup instructions
229
+ - \`knowledge/repo/patterns.md\` — placeholder for coding conventions
230
+
231
+ ### What the repo owner needs to do after merging
232
+
233
+ Please populate the placeholder files with accurate information:
234
+
235
+ 1. **\`knowledge/repo/structure.md\`** — describe the directory layout and key modules
236
+ 2. **\`knowledge/repo/environment.md\`** — document build tools, env vars, setup steps
237
+ 3. **\`knowledge/repo/patterns.md\`** — document coding conventions and architectural patterns
238
+
239
+ Submit these as a follow-up PR directly in this repo.
240
+
241
+ ### What this PR does NOT do
242
+
243
+ - Does not modify CI/CD pipelines
244
+ - Does not add application code
245
+ - Does not enforce any structural changes beyond adding \`knowledge/\`
246
+
247
+ *Generated by onboard-repo.sh*
248
+ MD
249
+ )
250
+
251
+ PR_URL=$(gh pr create \
252
+ --repo "$REPO_URL" \
253
+ --base "$REPO_DEFAULT_BRANCH" \
254
+ --head "$ONBOARD_BRANCH" \
255
+ --title "[Onboard] Initialize knowledge/ folder for agentic development" \
256
+ --body "$PR_BODY" \
257
+ 2>/dev/null) \
258
+ || {
259
+ warn "PR creation failed — retrying..."
260
+ PR_URL=$(gh pr create \
261
+ --repo "$REPO_URL" \
262
+ --base "$REPO_DEFAULT_BRANCH" \
263
+ --head "$ONBOARD_BRANCH" \
264
+ --title "[Onboard] Initialize knowledge/ folder for agentic development" \
265
+ --body "$PR_BODY")
266
+ }
267
+
268
+ echo ""
269
+ echo "=== Onboarding PR created!"
270
+ echo " PR: $PR_URL"
271
+ echo ""
272
+ echo " After the repo owner merges this PR, they should populate:"
273
+ echo " - knowledge/repo/structure.md"
274
+ echo " - knowledge/repo/environment.md"
275
+ echo " - knowledge/repo/patterns.md"
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+ # Script: pause
3
+ # Purpose: Transitions a project from ACTIVE to PAUSED.
4
+ # Preserves all state for later resumption.
5
+ # Usage: bash pause.sh <project_id>
6
+ # Compliance: C02 (POL-049, POL-051)
7
+
8
+ set -euo pipefail
9
+ source "$(dirname "$0")/lib.sh"
10
+ load_config
11
+
12
+ # ── Inputs ────────────────────────────────────────────────────────────────────
13
+
14
+ PROJECT_ID="${1:-}"
15
+ [[ -n "$PROJECT_ID" ]] || hard_stop "Usage: $0 <project_id>"
16
+
17
+ echo "=== pause: $PROJECT_ID"
18
+ echo ""
19
+
20
+ PROJECT_YAML=$(get_project_yaml "$PROJECT_ID")
21
+ check_project_exists "$PROJECT_ID"
22
+
23
+ # ── Pre-conditions ────────────────────────────────────────────────────────────
24
+
25
+ require_project_status "$PROJECT_YAML" "active"
26
+
27
+ CURRENT_USER=$(git config user.email 2>/dev/null || echo "")
28
+ ASSIGNED_TO=$(yaml_get "$PROJECT_YAML" "assigned_to") # display/audit cache
29
+ GH_PROJECT=$(yaml_get "$PROJECT_YAML" "github_project")
30
+ is_authorized_for_project "$GH_PROJECT" "$ASSIGNED_TO" \
31
+ || hard_stop "Not authorized to pause — '$CURRENT_USER' needs write access to the project's GitHub Project ($GH_PROJECT)."
32
+
33
+ BRANCH=$(project_branch_for_id "$PROJECT_ID")
34
+
35
+ echo "Checking for uncommitted changes..."
36
+
37
+ check_clean "$REPO_ROOT"
38
+
39
+ while IFS= read -r repo_url; do
40
+ REPO_DIR="$(repo_clone_dir "$PROJECT_ID" "$(get_repo_name "$repo_url")")"
41
+ [[ -e "$REPO_DIR/.git" ]] && check_clean "$REPO_DIR"
42
+ done < <(get_project_repos "$PROJECT_YAML")
43
+
44
+ info "All repos are clean."
45
+
46
+ # ── Update project.yaml ───────────────────────────────────────────────────────
47
+
48
+ TODAY=$(today)
49
+ yaml_set "$PROJECT_YAML" "status" "paused"
50
+ yaml_set "$PROJECT_YAML" "paused_at" "$TODAY"
51
+
52
+ # ── Push all branches ─────────────────────────────────────────────────────────
53
+
54
+ cd "$REPO_ROOT"
55
+ git checkout "$BRANCH"
56
+ git add "projects/$PROJECT_ID/project.yaml"
57
+ git commit -m "pause: $PROJECT_ID"
58
+ git push origin "$BRANCH"
59
+
60
+ while IFS= read -r repo_url; do
61
+ REPO_DIR="$(repo_clone_dir "$PROJECT_ID" "$(get_repo_name "$repo_url")")"
62
+ if [[ -e "$REPO_DIR/.git" ]]; then
63
+ git -C "$REPO_DIR" push origin "$BRANCH" 2>/dev/null || warn "Push skipped for $repo_url (nothing to push)"
64
+ fi
65
+ done < <(get_project_repos "$PROJECT_YAML")
66
+
67
+ # ── Reflect pause in the registry index on the default branch + README mirror ─
68
+ # project.yaml status lives on the project branch; the authoritative index lives
69
+ # on $DEFAULT_BRANCH. Flip it so `prj list`/`prj status` don't show a paused
70
+ # project as active.
71
+ registry_set_status_on_main "$PROJECT_ID" "paused"
72
+ project_readme_mirror "$PROJECT_ID" "$(yaml_get "$PROJECT_YAML" github_project)" "paused" \
73
+ "$(yaml_get "$PROJECT_YAML" assigned_to)" "$(yaml_get "$PROJECT_YAML" seeded_by)" "$BRANCH" || true
74
+
75
+ echo ""
76
+ echo "=== Project paused."
77
+ echo " Status: paused"
78
+ echo " paused_at: $TODAY"
79
+ echo ""
80
+ echo " Resume with: bash resume.sh $PROJECT_ID"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # Script: project-access
3
+ # Purpose: Grant or revoke WRITE access on a GitHub Project v2 — the ADR-0001
4
+ # Phase 3 source of truth for assignment (access = authorization).
5
+ # Wraps lib.sh's gh_* helpers so the prj CLI (which does not source
6
+ # lib.sh) can sync GitHub access from `manage assign/unassign/reassign`.
7
+ # Usage: bash project-access.sh <grant|revoke> <github_project_url> <login-or-@team>
8
+ # Note: MUTATES real GitHub Project permissions.
9
+ set -euo pipefail
10
+ source "$(dirname "$0")/lib.sh"
11
+ load_config
12
+
13
+ ACTION="${1:-}"; URL="${2:-}"; WHO="${3:-}"
14
+ [[ -n "$ACTION" && -n "$URL" && -n "$WHO" ]] \
15
+ || hard_stop "Usage: $0 <grant|revoke> <github_project_url> <login-or-@team>"
16
+
17
+ case "$ACTION" in
18
+ grant) ROLE=WRITER ;;
19
+ revoke) ROLE=NONE ;;
20
+ *) hard_stop "Unknown action '$ACTION' (expected grant|revoke)." ;;
21
+ esac
22
+
23
+ PROJ_ID=$(gh_project_node_id "$URL") \
24
+ || hard_stop "Could not resolve a GitHub Project from '$URL' (check access / token scopes)."
25
+
26
+ ACTOR=$(gh_resolve_actor "$WHO") \
27
+ || hard_stop "Could not resolve '$WHO' to a GitHub user or team. Use a GitHub login, or '@team-slug'."
28
+ read -r KIND AID <<< "$ACTOR"
29
+
30
+ if gh_project_set_access "$PROJ_ID" "$KIND" "$AID" "$ROLE"; then
31
+ info "GitHub Project access: ${ACTION}ed '$WHO' ($KIND) — role $ROLE."
32
+ else
33
+ hard_stop "GitHub API call failed. Set access manually in the Project's Manage access."
34
+ fi