@raquezha/norpiv 0.0.2

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,122 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # enforce-branch.sh
4
+ # Verifies the active branch before implementation.
5
+ # Prevents working on main/master and ensures alignment with task metadata.
6
+
7
+ set -euo pipefail
8
+
9
+ json_read() {
10
+ local file="$1"
11
+ local expr="$2"
12
+ python3 - "$file" "$expr" <<'PY'
13
+ import json
14
+ import re
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ path = Path(sys.argv[1])
19
+ expr = sys.argv[2]
20
+ try:
21
+ data = json.loads(path.read_text())
22
+ except Exception:
23
+ print("")
24
+ raise SystemExit
25
+
26
+ for part in [p.strip() for p in expr.split("//")]:
27
+ if part == "empty":
28
+ continue
29
+ match = re.fullmatch(r"\.([A-Za-z_][A-Za-z0-9_]*)", part)
30
+ if not match or not isinstance(data, dict):
31
+ continue
32
+ value = data.get(match.group(1))
33
+ if value not in (None, ""):
34
+ print(value)
35
+ raise SystemExit
36
+ print("")
37
+ PY
38
+ }
39
+
40
+ json_pretty() {
41
+ local file="$1"
42
+ python3 -m json.tool "$file"
43
+ }
44
+
45
+ # Find repo root to ensure paths are absolute and reliable
46
+ REPO_ROOT=$(git rev-parse --show-toplevel)
47
+ ACTIVE_TASK_FILE="$REPO_ROOT/.workflow/active_task.json"
48
+
49
+ if [[ ! -f "$ACTIVE_TASK_FILE" ]]; then
50
+ echo "ERROR: No active task found at $ACTIVE_TASK_FILE."
51
+ echo "Please run /triage [source]:[id] first."
52
+ exit 1
53
+ fi
54
+
55
+ # Read canonical active task fields
56
+ TASK_SOURCE=$(json_read "$ACTIVE_TASK_FILE" '.source // empty')
57
+ TASK_ID=$(json_read "$ACTIVE_TASK_FILE" '.sourceId // .id // empty')
58
+ TASK_PATH=$(json_read "$ACTIVE_TASK_FILE" '.taskPath // .path // empty')
59
+
60
+ # Prefer explicit taskPath when available (most reliable)
61
+ if [[ -n "$TASK_PATH" ]]; then
62
+ echo "INFO: Using taskPath from active_task.json: $TASK_PATH"
63
+ if [[ "$TASK_PATH" = /* ]]; then
64
+ WORK_MD="$TASK_PATH/WORK.md"
65
+ else
66
+ WORK_MD="$REPO_ROOT/$TASK_PATH/WORK.md"
67
+ fi
68
+
69
+ # If no taskPath, but we have a source+id, construct the folder name as '<source>-<id>'
70
+ elif [[ -n "$TASK_ID" ]]; then
71
+ echo "INFO: taskPath missing; deriving task folder from source+id"
72
+ if [[ -n "$TASK_SOURCE" ]]; then
73
+ TASK_FOLDER="${TASK_SOURCE}-${TASK_ID}"
74
+ else
75
+ TASK_FOLDER="$TASK_ID"
76
+ fi
77
+ WORK_MD="$REPO_ROOT/.workflow/tasks/$TASK_FOLDER/WORK.md"
78
+
79
+ else
80
+ echo "ERROR: No 'sourceId' or 'taskPath' found in $ACTIVE_TASK_FILE."
81
+ echo "Please run /triage [source]:[id] to initialize a task. Here are the file contents for debugging:"
82
+ json_pretty "$ACTIVE_TASK_FILE" || true
83
+ exit 1
84
+ fi
85
+
86
+ # Diagnostic output for easier debugging when things go wrong
87
+ echo "DEBUG: Computed WORK.md path: $WORK_MD"
88
+
89
+ if [[ ! -f "$WORK_MD" ]]; then
90
+ echo "ERROR: WORK.md not found at $WORK_MD."
91
+ echo "Checked active_task.json values:"
92
+ json_pretty "$ACTIVE_TASK_FILE" || true
93
+ echo "Please ensure the task was initialized with /triage and that WORK.md exists."
94
+ exit 1
95
+ fi
96
+
97
+ CURRENT_BRANCH=$(git branch --show-current)
98
+ echo "Current branch: $CURRENT_BRANCH"
99
+
100
+ # Check if we are on a protected branch
101
+ if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
102
+ echo "WARNING: Currently on protected branch '$CURRENT_BRANCH'."
103
+
104
+ # Generate a safe task branch name
105
+ # Prefer using the active_task folder name if available, else sanitize TASK_ID
106
+ if [[ -n "${TASK_FOLDER:-}" ]]; then
107
+ CLEAN_ID=$(echo "$TASK_FOLDER" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//;s/-$//')
108
+ else
109
+ CLEAN_ID=$(echo "$TASK_ID" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//;s/-$//')
110
+ fi
111
+ NEW_BRANCH="feat/${CLEAN_ID}"
112
+
113
+ echo "ACTION: Creating and switching to task branch: $NEW_BRANCH"
114
+ git checkout -b "$NEW_BRANCH"
115
+ echo "SUCCESS: Branch switched to $NEW_BRANCH."
116
+ echo "AGENT_INSTRUCTION: Update [META] in WORK.md to record 'Branch: $NEW_BRANCH'."
117
+ exit 0
118
+ fi
119
+
120
+ echo "Branch is not protected. Safe to proceed."
121
+ echo "AGENT_INSTRUCTION: Ensure $CURRENT_BRANCH is recorded in [META] of WORK.md."
122
+ exit 0
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@raquezha/norpiv",
3
+ "version": "0.0.2",
4
+ "description": "Bundled RPIV workflow skills for Pi, Claude, and Codex-style coding agents",
5
+ "type": "commonjs",
6
+ "bin": {
7
+ "norpiv-install": "bin/norpiv-install.cjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "cleanup",
12
+ "frame",
13
+ "grill-with-docs",
14
+ "implement",
15
+ "plan",
16
+ "scripts",
17
+ "sync",
18
+ "triage",
19
+ "update-docs",
20
+ "verify",
21
+ "README.md"
22
+ ],
23
+ "keywords": [
24
+ "agent-skills",
25
+ "pi-agent",
26
+ "claude-skills",
27
+ "codex",
28
+ "workflow",
29
+ "rpiv",
30
+ "pi-package"
31
+ ],
32
+ "license": "MIT",
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "pi": {
37
+ "skills": [
38
+ "triage",
39
+ "frame",
40
+ "grill-with-docs",
41
+ "plan",
42
+ "implement",
43
+ "verify",
44
+ "sync",
45
+ "update-docs",
46
+ "cleanup"
47
+ ]
48
+ }
49
+ }
package/plan/SKILL.md ADDED
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: plan
3
+ description: Create or revise vertical implementation slices in the active WORK.md. Use after /grill-with-docs to produce a concise, reviewable plan for implementation.
4
+ ---
5
+
6
+ # Skill: plan
7
+
8
+ Map the "how" into tracer-bullet vertical slices.
9
+
10
+ ## Guardrails
11
+ - READ: `.workflow/active_task.json` then active `WORK.md` `[BRIEF]` and `[GRILL]`.
12
+ - WRITE: `WORK.md` -> `[PLAN]` and append to `[LOG]` only.
13
+ - NEVER: implement code during planning.
14
+ - NEVER: create standalone `PLAN.md`.
15
+ - NEVER: ask whether to plan if the user invoked `/plan`; produce the plan.
16
+
17
+ ## Workflow
18
+ 1. Read the brief and grill decisions.
19
+ 2. **Branch Check**: Verify the current git branch. Planning on `main` is safe and encouraged. If you are on an unrelated feature branch, warn the human that the plan is being made on a stale or mismatched context.
20
+ 3. Draft thin vertical slices that are independently verifiable.
21
+ 4. Mark each slice:
22
+ - **AFK**: agent can implement with clear checks.
23
+ - **HITL**: human judgment, product decision, external access, or manual review required.
24
+ 5. Include dependencies and verification command(s) per slice.
25
+ 6. Write the plan into `[PLAN]` with checkboxes.
26
+ 7. **Log Activity**: Append a timestamped entry to `[LOG]` summarizing the plan or revision (Format: `YYYY-MM-DD hh:mm AM/PM`).
27
+ 8. Recommend `/sync` if the task has a tracker, then `/implement`.
28
+
29
+ ## Output contract
30
+ End with:
31
+ - **Slices**: count and names
32
+ - **AFK/HITL split**
33
+ - **Verification commands**
34
+ - **Next step**: `/sync` or `/implement`
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
6
+ cd "$REPO_ROOT"
7
+
8
+ ensure_reposcry_gitignore() {
9
+ local gitignore=".gitignore"
10
+ touch "$gitignore"
11
+
12
+ if ! grep -qxF ".reposcry/" "$gitignore"; then
13
+ {
14
+ printf '\n# RepoScry local cache\n'
15
+ printf '.reposcry/\n'
16
+ } >> "$gitignore"
17
+ echo "Added .reposcry/ to .gitignore"
18
+ fi
19
+ }
20
+
21
+ refuse_tracked_reposcry_cache() {
22
+ local tracked staged
23
+ tracked=$(git ls-files .reposcry 2>/dev/null || true)
24
+ staged=$(git diff --cached --name-only -- .reposcry 2>/dev/null || true)
25
+
26
+ if [[ -n "$tracked" || -n "$staged" ]]; then
27
+ echo "ERROR: .reposcry/ cache is tracked or staged. It is generated local state and must not be committed." >&2
28
+ if [[ -n "$tracked" ]]; then
29
+ echo "Tracked files:" >&2
30
+ printf '%s\n' "$tracked" >&2
31
+ fi
32
+ if [[ -n "$staged" ]]; then
33
+ echo "Staged files:" >&2
34
+ printf '%s\n' "$staged" >&2
35
+ fi
36
+ echo "Fix: git rm --cached -r .reposcry && keep .reposcry/ in .gitignore" >&2
37
+ exit 1
38
+ fi
39
+ }
40
+
41
+ reposcry_indexed_files() {
42
+ reposcry stats 2>/dev/null | awk '/Files indexed:/ {print $3; exit}'
43
+ }
44
+
45
+ ensure_reposcry_gitignore
46
+ refuse_tracked_reposcry_cache
47
+
48
+ if ! command -v reposcry >/dev/null 2>&1; then
49
+ echo "RepoScry not installed; skipping bootstrap."
50
+ exit 0
51
+ fi
52
+
53
+ HAD_REPOSCRYIGNORE=0
54
+ [[ -f .reposcryignore ]] && HAD_REPOSCRYIGNORE=1
55
+
56
+ FORCE_REINDEX=0
57
+ if [[ "${1:-}" == "--force" || "${1:-}" == "--reindex" ]]; then
58
+ FORCE_REINDEX=1
59
+ fi
60
+
61
+ if [[ ! -d .reposcry ]]; then
62
+ echo "Initializing RepoScry..."
63
+ reposcry init >/dev/null 2>&1 || reposcry init || {
64
+ echo "RepoScry init failed; continuing without RepoScry." >&2
65
+ exit 0
66
+ }
67
+ fi
68
+
69
+ INDEXED_FILES=$(reposcry_indexed_files || true)
70
+ INDEXED_FILES=${INDEXED_FILES:-0}
71
+
72
+ if [[ $FORCE_REINDEX -eq 1 || "$INDEXED_FILES" == "0" ]]; then
73
+ echo "Indexing repository with RepoScry (--no-semantic)..."
74
+ reposcry index --no-semantic || {
75
+ echo "RepoScry index failed; continuing without RepoScry." >&2
76
+ exit 0
77
+ }
78
+ else
79
+ echo "RepoScry index already present ($INDEXED_FILES files indexed)."
80
+ fi
81
+
82
+ if [[ $HAD_REPOSCRYIGNORE -eq 0 && -f .reposcryignore ]]; then
83
+ echo "RepoScry created .reposcryignore. Review and commit it if you want stable RepoScry indexing rules."
84
+ fi
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ BASE_REF=${1:-${REPOSCRY_BASE_REF:-main}}
6
+
7
+ if ! command -v reposcry-update >/dev/null 2>&1; then
8
+ echo "reposcry-update not installed; skipping refresh."
9
+ exit 0
10
+ fi
11
+
12
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
13
+ cd "$REPO_ROOT"
14
+
15
+ echo "Refreshing RepoScry for changed files against base '$BASE_REF'..."
16
+ if ! reposcry-update --changed --base "$BASE_REF"; then
17
+ echo "RepoScry refresh failed; continuing without refreshed graph state." >&2
18
+ exit 0
19
+ fi
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ TASK_TEXT=${*:-}
6
+ if [[ -z "$TASK_TEXT" ]]; then
7
+ echo "Usage: $0 <task summary>"
8
+ exit 1
9
+ fi
10
+
11
+ if ! command -v reposcry >/dev/null 2>&1; then
12
+ echo "RepoScry not installed; skipping task context generation."
13
+ exit 0
14
+ fi
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
18
+ cd "$REPO_ROOT"
19
+
20
+ "$SCRIPT_DIR/reposcry-bootstrap.sh" || true
21
+
22
+ mkdir -p .reposcry
23
+ BUDGET=${REPOSCRY_CONTEXT_BUDGET:-20000}
24
+ OUTPUT_PATH=".reposcry/AI_CONTEXT.md"
25
+
26
+ echo "Generating RepoScry task context at $OUTPUT_PATH..."
27
+ if reposcry context "$TASK_TEXT" --strict --budget "$BUDGET" --format markdown > "$OUTPUT_PATH"; then
28
+ echo "Wrote $OUTPUT_PATH"
29
+ else
30
+ echo "RepoScry context generation failed; leaving RPIV flow unchanged." >&2
31
+ rm -f "$OUTPUT_PATH"
32
+ fi