oh-my-customcode 0.68.2 → 0.70.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.
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env bash
2
+ # SessionStart auto-update hook — interactive omcustom update check
3
+ # Trigger: SessionStart (runs BEFORE session-env-check.sh)
4
+ # Purpose: Check for oh-my-customcode updates, prompt user, optionally update
5
+ # Protocol: stdin JSON -> stdout pass-through, exit 0 ALWAYS
6
+ # Design: GitHub issue #752
7
+
8
+ # Pass through stdin immediately — capture for later output
9
+ input=$(cat)
10
+
11
+ # --- Guard: skip conditions ---
12
+
13
+ # Skip if explicitly disabled
14
+ if [ "${OMCUSTOM_SKIP_AUTO_UPDATE:-}" = "true" ]; then
15
+ echo "$input"
16
+ exit 0
17
+ fi
18
+
19
+ # Skip if /dev/tty not available (CI, Docker, non-interactive)
20
+ if ! [ -c /dev/tty ] 2>/dev/null; then
21
+ echo "$input"
22
+ exit 0
23
+ fi
24
+
25
+ # --- Configuration ---
26
+ CACHE_DIR="$HOME/.oh-my-customcode"
27
+ CACHE_FILE="${CACHE_DIR}/self-update-cache.json"
28
+ CACHE_MAX_AGE=3600 # 1 hour in seconds
29
+ NPM_TIMEOUT=3 # seconds for npm view
30
+ INPUT_TIMEOUT=10 # seconds for user prompt
31
+ PACKAGE_NAME="oh-my-customcode"
32
+
33
+ # --- Helper: semantic version compare ---
34
+ # Returns 0 if $1 < $2 (update available)
35
+ version_lt() {
36
+ local older
37
+ older=$(printf '%s\n' "$1" "$2" | sort -V | head -1)
38
+ [ "$older" = "$1" ] && [ "$1" != "$2" ]
39
+ }
40
+
41
+ # --- Step 1: Get current installed version ---
42
+ CURRENT_VERSION=""
43
+
44
+ # Try .omcustomrc.json in current directory
45
+ if [ -f ".omcustomrc.json" ]; then
46
+ CURRENT_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' .omcustomrc.json 2>/dev/null | head -1 | grep -o '"[^"]*"$' | tr -d '"')
47
+ fi
48
+
49
+ # Fallback: try npm list
50
+ if [ -z "$CURRENT_VERSION" ]; then
51
+ CURRENT_VERSION=$(npm list -g "$PACKAGE_NAME" --depth=0 2>/dev/null | grep -o "${PACKAGE_NAME}@[^ ]*" | cut -d'@' -f2)
52
+ fi
53
+
54
+ # Cannot determine current version — skip
55
+ if [ -z "$CURRENT_VERSION" ]; then
56
+ echo "$input"
57
+ exit 0
58
+ fi
59
+
60
+ # --- Step 2: Get latest version (cache-first, network fallback) ---
61
+ LATEST_VERSION=""
62
+ CACHE_HIT=false
63
+
64
+ # Ensure cache directory exists
65
+ mkdir -p "$CACHE_DIR" 2>/dev/null
66
+
67
+ # Check cache freshness
68
+ if [ -f "$CACHE_FILE" ]; then
69
+ CACHE_TIMESTAMP=$(grep -o '"timestamp"[[:space:]]*:[[:space:]]*[0-9]*' "$CACHE_FILE" 2>/dev/null | grep -o '[0-9]*$')
70
+ CACHED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$CACHE_FILE" 2>/dev/null | grep -o '"[^"]*"$' | tr -d '"')
71
+
72
+ if [ -n "$CACHE_TIMESTAMP" ] && [ -n "$CACHED_VERSION" ]; then
73
+ NOW=$(date +%s)
74
+ AGE=$((NOW - CACHE_TIMESTAMP))
75
+
76
+ if [ "$AGE" -lt "$CACHE_MAX_AGE" ]; then
77
+ LATEST_VERSION="$CACHED_VERSION"
78
+ CACHE_HIT=true
79
+ fi
80
+ fi
81
+ fi
82
+
83
+ # Cache miss or stale — fetch from npm registry
84
+ if [ "$CACHE_HIT" = false ]; then
85
+ if command -v npm >/dev/null 2>&1; then
86
+ LATEST_VERSION=$(timeout "$NPM_TIMEOUT" npm view "$PACKAGE_NAME" version 2>/dev/null || echo "")
87
+
88
+ # Update cache on successful fetch
89
+ if [ -n "$LATEST_VERSION" ]; then
90
+ NOW=$(date +%s)
91
+ cat > "$CACHE_FILE" << EOF
92
+ {
93
+ "version": "${LATEST_VERSION}",
94
+ "timestamp": ${NOW},
95
+ "source": "npm-registry"
96
+ }
97
+ EOF
98
+ fi
99
+ fi
100
+ fi
101
+
102
+ # Could not determine latest version — skip
103
+ if [ -z "$LATEST_VERSION" ]; then
104
+ echo "$input"
105
+ exit 0
106
+ fi
107
+
108
+ # --- Step 3: Compare versions ---
109
+ if ! version_lt "$CURRENT_VERSION" "$LATEST_VERSION"; then
110
+ # Already up to date
111
+ echo "$input"
112
+ exit 0
113
+ fi
114
+
115
+ # --- Step 4: Prompt user for update ---
116
+ echo "" >&2
117
+ echo "--- [oh-my-customcode Update Available] ---" >&2
118
+ echo " New version: v${LATEST_VERSION} (current: v${CURRENT_VERSION})" >&2
119
+ echo "" >&2
120
+
121
+ # Interactive prompt via /dev/tty (SessionStart stdin is JSON pipe)
122
+ printf " Update oh-my-customcode to v%s? [y/N] " "$LATEST_VERSION" >/dev/tty 2>/dev/null
123
+ if read -r -t "$INPUT_TIMEOUT" answer </dev/tty 2>/dev/null; then
124
+ case "$answer" in
125
+ [yY]|[yY][eE][sS])
126
+ echo " Installing oh-my-customcode@${LATEST_VERSION}..." >&2
127
+ if npm install -g "${PACKAGE_NAME}@latest" >&2 2>&1; then
128
+ echo " ✓ Updated to v${LATEST_VERSION}" >&2
129
+
130
+ # Check if project harness should be updated too
131
+ if [ -f ".omcustomrc.json" ]; then
132
+ printf " Update project harness too? [y/N] " >/dev/tty 2>/dev/null
133
+ if read -r -t "$INPUT_TIMEOUT" harness_answer </dev/tty 2>/dev/null; then
134
+ case "$harness_answer" in
135
+ [yY]|[yY][eE][sS])
136
+ echo " Updating project harness..." >&2
137
+ if command -v omcustom >/dev/null 2>&1; then
138
+ omcustom update --force >&2 2>&1 || echo " ⚠ Harness update failed (non-blocking)" >&2
139
+ echo " ✓ Project harness updated" >&2
140
+ else
141
+ echo " ⚠ omcustom command not found after install" >&2
142
+ fi
143
+ ;;
144
+ *)
145
+ echo " Skipped harness update" >&2
146
+ ;;
147
+ esac
148
+ else
149
+ echo "" >&2
150
+ echo " Timed out — skipped harness update" >&2
151
+ fi
152
+ fi
153
+ else
154
+ echo " ⚠ Update failed (non-blocking, continuing session)" >&2
155
+ fi
156
+ ;;
157
+ *)
158
+ echo " Skipped update" >&2
159
+ ;;
160
+ esac
161
+ else
162
+ echo "" >&2
163
+ echo " Timed out — skipped update" >&2
164
+ fi
165
+
166
+ echo "------------------------------------" >&2
167
+
168
+ # Always pass through and exit 0
169
+ echo "$input"
170
+ exit 0
@@ -427,7 +427,7 @@ agents:
427
427
  file_patterns: []
428
428
  actions: [review, analyze]
429
429
  base_confidence: 85
430
- routing_rule: "MUST use professor-triage skill for cross-analyzing GitHub issues with omc_issue_analyzer comments"
430
+ routing_rule: "MUST use professor-triage skill for codebase-driven issue analysis and automated triage"
431
431
 
432
432
  rtk-exec:
433
433
  keywords:
@@ -9,11 +9,11 @@ argument-hint: "[description or leave empty for interactive] [--anonymous]"
9
9
 
10
10
  # Feedback Submitter
11
11
 
12
- Submit feedback about oh-my-customcode (bugs, features, improvements, questions) directly from the CLI session. Supports anonymous submission via Airflow DAG when gh CLI is unavailable or when anonymity is requested.
12
+ Submit feedback about oh-my-customcode (bugs, features, improvements, questions) directly from the CLI session. Supports anonymous submission with `[Anonymous Feedback]` title prefix when `--anonymous` flag is used.
13
13
 
14
14
  ## Purpose
15
15
 
16
- Lowers the barrier for submitting feedback by allowing users to create GitHub issues or submit anonymously — without leaving their terminal session. All feedback is filed to the `baekenough/oh-my-customcode` repository.
16
+ Lowers the barrier for submitting feedback by allowing users to create GitHub issues — without leaving their terminal session. All feedback is filed to the `baekenough/oh-my-customcode` repository.
17
17
 
18
18
  ## Usage
19
19
 
@@ -59,22 +59,13 @@ if [ "$GH_AVAILABLE" = "true" ]; then
59
59
  else
60
60
  GH_AUTHED=false
61
61
  fi
62
-
63
- # Check curl availability
64
- command -v curl >/dev/null 2>&1 && CURL_AVAILABLE=true || CURL_AVAILABLE=false
65
62
  ```
66
63
 
67
- **Route A**: `gh` available + authenticated + NOT anonymous
64
+ **Route A**: `gh` available + authenticated
68
65
  - Use GitHub Issue creation (see Phase 4A)
66
+ - If `--anonymous`: adds `[Anonymous Feedback]` prefix and `anonymous` label
69
67
 
70
- **Route B**: anonymous OR not authenticated (gh available)
71
- - Use `curl` to Airflow REST API (see Phase 4C)
72
- - Phase 4B (workflow_dispatch) reserved for future use
73
-
74
- **Route C**: `gh` NOT available (or Route B curl fallback)
75
- - Use `curl` to Airflow REST API (see Phase 4C)
76
-
77
- **Fallback**: Neither `gh` nor `curl` available
68
+ **Fallback**: `gh` NOT available or not authenticated
78
69
  - Save feedback locally and inform the user (see Phase 4D)
79
70
 
80
71
  ### Phase 3: Environment Collection
@@ -102,24 +93,30 @@ For anonymous submissions, do NOT include the project name. Offer to include pro
102
93
  - Ask: "Include environment info (version, OS) in the anonymous report? [Y/n]"
103
94
  - If declined, set `PROJECT_CONTEXT=""`
104
95
 
105
- ### Phase 4A: GitHub Issue Creation (Route A — gh + authenticated + not anonymous)
96
+ ### Phase 4A: GitHub Issue Creation (Route A — gh + authenticated)
106
97
 
107
- 1. Show the user a preview of the issue to be created:
98
+ 1. If `ANONYMOUS=true`, prepend `[Anonymous Feedback] ` to the title and add `anonymous` to the label list.
99
+
100
+ 2. Show the user a preview of the issue to be created:
108
101
  ```
109
102
  [Preview]
110
103
  ├── Title: {title}
111
104
  ├── Category: {category}
112
- ├── Labels: feedback, {category-label}
105
+ ├── Labels: feedback, {category-label}[, anonymous]
113
106
  └── Repo: baekenough/oh-my-customcode
114
107
  ```
115
- 2. Ask for confirmation before creating
108
+ 3. Ask for confirmation before creating
116
109
 
117
- 3. Ensure labels exist (defensive):
110
+ 4. Ensure labels exist (defensive):
118
111
  ```bash
119
112
  gh label create feedback --description "User feedback via /omcustom-feedback" --color 0E8A16 --repo baekenough/oh-my-customcode 2>/dev/null || true
113
+ # If anonymous, ensure the anonymous label exists
114
+ if [ "$ANONYMOUS" = "true" ]; then
115
+ gh label create anonymous --description "Anonymous feedback submission" --color C5DEF5 --repo baekenough/oh-my-customcode 2>/dev/null || true
116
+ fi
120
117
  ```
121
118
 
122
- 4. Create the issue using `--body-file` for safe markdown handling:
119
+ 5. Create the issue using `--body-file` for safe markdown handling:
123
120
  ```bash
124
121
  # Write body to temp file to avoid shell escaping issues
125
122
  cat > /tmp/omcustom-feedback-body.md << 'FEEDBACK_EOF'
@@ -141,64 +138,28 @@ For anonymous submissions, do NOT include the project name. Offer to include pro
141
138
  *Submitted via `/omcustom-feedback`*
142
139
  FEEDBACK_EOF
143
140
 
141
+ # Build label string
142
+ LABELS="feedback,${CATEGORY_LABEL}"
143
+ if [ "$ANONYMOUS" = "true" ]; then
144
+ LABELS="${LABELS},anonymous"
145
+ fi
146
+
144
147
  # Create issue
145
148
  gh issue create \
146
149
  --repo baekenough/oh-my-customcode \
147
150
  --title "{title}" \
148
- --label "feedback,{category_label}" \
151
+ --label "$LABELS" \
149
152
  --body-file /tmp/omcustom-feedback-body.md
150
153
 
151
154
  # Clean up
152
155
  rm -f /tmp/omcustom-feedback-body.md
153
156
  ```
154
157
 
155
- 5. If label creation fails AND issue creation fails due to labels, retry without labels as fallback
156
-
157
- 6. Return the issue URL to the user
158
-
159
- ### Phase 4B: Anonymous via GitHub Actions (Route B — FUTURE)
160
-
161
- > **Note**: This route is reserved for future implementation. The `feedback-submission.yml` workflow does not yet exist. All anonymous/unauthenticated submissions currently fall through to Route C (Airflow REST API).
162
-
163
- ```bash
164
- gh workflow run feedback-submission.yml \
165
- --repo baekenough/oh-my-customcode \
166
- -f title="$TITLE" \
167
- -f body="$BODY" \
168
- -f feedback_type="$TYPE" \
169
- -f anonymous=true \
170
- -f project_context="$PROJECT_CONTEXT"
171
- ```
172
-
173
- On success, inform the user:
174
- ```
175
- [Done] Anonymous feedback submitted via GitHub Actions workflow.
176
- ```
177
-
178
- If `gh workflow run` fails (e.g., permissions), fall through to Route C.
179
-
180
- ### Phase 4C: Anonymous via Airflow REST API (Route C — no gh)
181
-
182
- ```bash
183
- # Build JSON payload safely with jq
184
- PAYLOAD=$(jq -n --arg title "$TITLE" --arg body "$BODY" --arg type "$TYPE" --arg ctx "$PROJECT_CONTEXT" \
185
- '{"conf":{"title":$title,"body":$body,"feedback_type":$type,"anonymous":true,"submitter":"","project_context":$ctx}}')
186
-
187
- curl -X POST "https://airflow.baekenough.com/api/v2/dags/omc_feedback_collector/dagRuns" \
188
- -H "Content-Type: application/json" \
189
- -d "$PAYLOAD" \
190
- --silent --show-error \
191
- --max-time 15
192
- ```
193
-
194
- On HTTP 200/201, inform the user:
195
- ```
196
- [Done] Anonymous feedback submitted via Airflow.
197
- ```
158
+ 6. If label creation fails AND issue creation fails due to labels, retry without labels as fallback
198
159
 
199
- On failure (non-2xx or network error), fall through to Fallback.
160
+ 7. Return the issue URL to the user
200
161
 
201
- ### Phase 4D: Local Fallback (no gh, no curl, or all routes failed)
162
+ ### Phase 4D: Local Fallback (gh not available, not authenticated, or issue creation failed)
202
163
 
203
164
  ```bash
204
165
  mkdir -p ~/.omcustom/feedback
@@ -222,25 +183,23 @@ Inform the user:
222
183
  [Saved] Feedback saved locally to ~/.omcustom/feedback/{timestamp}.json
223
184
  Submit manually when connectivity is available:
224
185
  - GitHub Issues: https://github.com/baekenough/oh-my-customcode/issues/new
225
- - Or run /omcustom:feedback again when gh or curl is available
186
+ - Or run /omcustom:feedback again when gh is available
226
187
  ```
227
188
 
228
189
  ### Category-to-Label Mapping
229
190
 
230
- | Category | GitHub Label | Airflow feedback_type |
231
- |----------|--------------|-----------------------|
232
- | bug | bug | bug |
233
- | feature | enhancement | feature |
234
- | improvement | enhancement | improvement |
235
- | question | question | question |
236
- | (auto-detect fails) | (none) | general |
191
+ | Category | GitHub Label |
192
+ |----------|--------------|
193
+ | bug | bug |
194
+ | feature | enhancement |
195
+ | improvement | enhancement |
196
+ | question | question |
197
+ | (auto-detect fails) | (none) |
237
198
 
238
199
  ## Notes
239
200
 
240
201
  - Route A creates a visible GitHub issue attributed to the user's gh account
241
- - Routes B and C submit anonymously submitter identity is not recorded
242
- - Route B requires `gh` but NOT authentication to the repo (public workflow)
243
- - Route C requires `curl` (available on macOS/Linux by default)
202
+ - When `--anonymous` is used, the title is prefixed with `[Anonymous Feedback]` and the `anonymous` label is added
244
203
  - Fallback ensures no feedback is silently lost even in offline environments
245
204
  - `disable-model-invocation: true` ensures this skill only runs when explicitly invoked by the user
246
205
  - Target repo is hardcoded to `baekenough/oh-my-customcode` — feedback is always about omcustom itself