feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard. Lanes: a durable unit of parallel agent work, one per working directory, tracked across session restarts. Managed lanes are git worktrees the dashboard provisions and can reset or remove behind a three-check destroy guard and a counted preflight; adopted lanes are directories you already own and are never destroyable. Pipelines: a lane moves through pipeline stages. A stage the agent declares with evidence renders green; a stage inferred from the tool-event stream renders dashed amber and never counts as done. Detection is forward-only within a 30-minute window, and never writes the declared stage. Workspace: one page at /run with a lane grid, the selected lane's pipeline, and a full Claude console behind a disclosure.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
---
|
||||
name: file-headers
|
||||
description: MANDATORY for every coding agent (Claude Code, Codex, or any other) on every change-set — every applicable source file the agent creates or updates MUST start with the project's copyright/authorship header (file overview + exact author line). Use automatically whenever writing a new file or editing an existing one; do not wait to be asked. Covers JS/TS/TSX/CJS/MJS, Python, shell, and CSS. Includes the audit script to verify repo-wide compliance.
|
||||
---
|
||||
|
||||
# File Headers — Copyright Comment + File Overview
|
||||
|
||||
Every applicable source file in this repository starts with a header comment
|
||||
containing a **file overview** and the **exact author line**:
|
||||
|
||||
```
|
||||
@author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
```
|
||||
|
||||
The name and email must be exactly as above — no variations, no substitutions,
|
||||
no other names. This applies to **every coding agent** working in this repo
|
||||
(Claude Code, Codex, or any other tool): when you **create** a new applicable
|
||||
file, write the header first; when you **update** an existing applicable file
|
||||
that is missing the header, add it as part of the same change.
|
||||
|
||||
## Applicable files
|
||||
|
||||
| Included | Excluded |
|
||||
| -------- | -------- |
|
||||
| `*.js`, `*.ts`, `*.tsx`, `*.cjs`, `*.mjs` | anything under `node_modules/`, `dist/`, `build/`, `data/` |
|
||||
| `*.py`, `*.sh` | vendored/minified files (`*.min.js`) |
|
||||
| `*.css` | generated files (they carry their own AUTO-GENERATED banner) |
|
||||
| | snapshots (`__snapshots__/`), lockfiles, JSON/YAML/Markdown |
|
||||
|
||||
## Header formats by file type
|
||||
|
||||
**JS / TS / TSX — server & scripts style** (overview inline in `@file`):
|
||||
|
||||
```js
|
||||
/**
|
||||
* @file One-to-few-sentence overview of what this file does and why it
|
||||
* exists. Mention the key contracts or invariants the file owns.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
```
|
||||
|
||||
**JS / TS / TSX — client style** (`@file` name + `@description` overview), used
|
||||
under `client/src/`:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* @file ComponentName.tsx
|
||||
* @description What the component/module renders or provides and how it fits
|
||||
* into the app.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
```
|
||||
|
||||
**CSS** (same block-comment shape as `client/src/index.css`):
|
||||
|
||||
```css
|
||||
/**
|
||||
* @file file.css
|
||||
* @description What these styles cover.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
```
|
||||
|
||||
**Shell** (`#` block right after the shebang; existing overview comments count —
|
||||
just make sure the `@author` line is in the block):
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# script-name.sh — what the script does, one to few lines.
|
||||
# @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
```
|
||||
|
||||
**Python** (inside the module docstring):
|
||||
|
||||
```python
|
||||
"""
|
||||
module.py — what the module does.
|
||||
|
||||
@author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
"""
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
1. **New file → header first.** Any applicable file you create starts with the
|
||||
header before any code (after the shebang for scripts).
|
||||
2. **Touched file missing header → add it.** If you edit a file that lacks the
|
||||
header, add one in the same commit. Write a real overview — describe what
|
||||
the file actually does; never a placeholder like "TODO" or "utility file".
|
||||
3. **Exact author line.** `@author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>` —
|
||||
byte-exact, in every file type (shell and Python use it inside `#` / docstring
|
||||
comments).
|
||||
4. **Don't churn existing headers.** If a file already has a compliant header,
|
||||
leave it alone unless the file's purpose changed (then update the overview).
|
||||
5. **Overviews must stay truthful.** When an edit changes what a file does,
|
||||
update its `@file`/`@description` overview in the same change.
|
||||
|
||||
## Audit
|
||||
|
||||
Run the bundled checker to list any applicable file missing the header:
|
||||
|
||||
```bash
|
||||
bash .claude/skills/file-headers/scripts/check-headers.sh
|
||||
```
|
||||
|
||||
Exit code `0` = fully compliant; `1` = the printed files are missing headers.
|
||||
Run it before finishing any change-set that adds files, and during reviews.
|
||||
|
||||
On every pull request, GitHub Actions runs
|
||||
`.claude/skills/file-headers/scripts/check-headers-pr.sh` against only the
|
||||
files changed in the PR diff (added, copied, renamed, or modified). Test locally
|
||||
before pushing:
|
||||
|
||||
```bash
|
||||
bash .claude/skills/file-headers/scripts/check-headers-pr.sh origin/master HEAD
|
||||
```
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env bash
|
||||
# check-headers-pr.sh — verify that applicable files touched in a git diff carry
|
||||
# the mandatory copyright/authorship header. Used locally before opening a PR and
|
||||
# by the file-headers GitHub Actions workflow on every pull request.
|
||||
#
|
||||
# Usage:
|
||||
# check-headers-pr.sh [<base-sha> <head-sha>]
|
||||
#
|
||||
# When omitted, compares the current branch against origin/master (or master).
|
||||
# @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
|
||||
AUTHOR_MARK="@author Nguyễn Ngọc Trí Vĩ"
|
||||
AUTHOR_EMAIL="vinnt@smartgift.vn"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: check-headers-pr.sh [<base-sha> <head-sha>]
|
||||
|
||||
Checks only added/copied/renamed/modified files in the diff between base and
|
||||
head. Applicable extensions: .js .ts .tsx .cjs .mjs .py .sh .css
|
||||
|
||||
The author line must appear in the file header using the syntax for that type:
|
||||
JS/TS/CSS — block comment (/** ... @author ... */)
|
||||
Shell — # comment after the shebang
|
||||
Python — module docstring (""" ... @author ... """)
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BASE_SHA="${1:-}"
|
||||
HEAD_SHA="${2:-}"
|
||||
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ -z "$BASE_SHA" || -z "$HEAD_SHA" ]]; then
|
||||
if git show-ref --verify --quiet refs/remotes/origin/master; then
|
||||
BASE_SHA="$(git merge-base HEAD origin/master)"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
BASE_SHA="$(git merge-base HEAD master)"
|
||||
else
|
||||
echo "error: could not resolve base ref; pass <base-sha> <head-sha>" >&2
|
||||
exit 1
|
||||
fi
|
||||
HEAD_SHA="HEAD"
|
||||
fi
|
||||
|
||||
# Return 0 when the path is subject to the header policy (keep in sync with
|
||||
# check-headers.sh exclusions).
|
||||
is_applicable_file() {
|
||||
local f="$1"
|
||||
|
||||
case "$f" in
|
||||
*/node_modules/*|*/dist/*|*/build/*|*/.git/*|*/data/*)
|
||||
return 1
|
||||
;;
|
||||
*/monitoring/.bin/*|*/monitoring/.data/*|*/__snapshots__/*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$f" in
|
||||
esac
|
||||
|
||||
case "$f" in
|
||||
*.js|*.ts|*.tsx|*.cjs|*.mjs|*.py|*.sh|*.css)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Best-effort hint for contributors when a file fails.
|
||||
header_hint_for() {
|
||||
local f="$1"
|
||||
case "$f" in
|
||||
*.py)
|
||||
echo ' expected: module docstring with @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>'
|
||||
;;
|
||||
*.sh)
|
||||
echo ' expected: # block after shebang with @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>'
|
||||
;;
|
||||
*.css)
|
||||
echo ' expected: /** @file ... @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn> */'
|
||||
;;
|
||||
*)
|
||||
echo ' expected: /** @file ... @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn> */'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Require the exact author mark anywhere in the file (same rule as check-headers.sh).
|
||||
has_author_header() {
|
||||
local f="$1"
|
||||
grep -q "$AUTHOR_MARK" "$f" && grep -q "$AUTHOR_EMAIL" "$f"
|
||||
}
|
||||
|
||||
BASE_SHORT="$(git rev-parse --short "${BASE_SHA}" 2>/dev/null || echo "${BASE_SHA}")"
|
||||
HEAD_SHORT="$(git rev-parse --short "${HEAD_SHA}" 2>/dev/null || echo "${HEAD_SHA}")"
|
||||
|
||||
checked=0
|
||||
missing=0
|
||||
skipped=0
|
||||
|
||||
echo "Checking authorship headers for files changed between ${BASE_SHORT}..${HEAD_SHORT}"
|
||||
|
||||
while IFS= read -r f; do
|
||||
[[ -z "$f" ]] && continue
|
||||
|
||||
if ! is_applicable_file "$f"; then
|
||||
skipped=$((skipped + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ ! -f "$f" ]]; then
|
||||
echo "SKIP (missing on disk): $f"
|
||||
skipped=$((skipped + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
checked=$((checked + 1))
|
||||
|
||||
if ! has_author_header "$f"; then
|
||||
echo "MISSING HEADER: $f"
|
||||
header_hint_for "$f"
|
||||
missing=1
|
||||
fi
|
||||
done < <(git diff --name-only --diff-filter=ACMR "${BASE_SHA}" "${HEAD_SHA}")
|
||||
|
||||
if [[ "$checked" -eq 0 ]]; then
|
||||
echo "✔ No applicable source files changed in this diff (skipped ${skipped} path(s))."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$missing" -eq 0 ]]; then
|
||||
echo "✔ All ${checked} applicable changed file(s) carry the authorship header."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Add the project header to each file listed above."
|
||||
echo "See .claude/skills/file-headers/SKILL.md for per-type examples."
|
||||
exit 1
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# check-headers.sh — audit the repo for applicable source files missing the
|
||||
# mandatory copyright/authorship header (see .claude/skills/file-headers).
|
||||
# Prints each non-compliant file; exits 0 when fully compliant, 1 otherwise.
|
||||
# @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
|
||||
AUTHOR_MARK="@author Nguyễn Ngọc Trí Vĩ"
|
||||
|
||||
missing=0
|
||||
while IFS= read -r f; do
|
||||
if ! grep -q "$AUTHOR_MARK" "$f"; then
|
||||
echo "MISSING HEADER: ${f#"$ROOT"/}"
|
||||
missing=1
|
||||
fi
|
||||
done < <(
|
||||
find "$ROOT" \
|
||||
\( -name node_modules -o -name dist -o -name build -o -name .git \
|
||||
-o -path "$ROOT/data" -o -path "$ROOT/monitoring/.bin" \
|
||||
-o -path "$ROOT/monitoring/.data" -o -name "__snapshots__" \) -prune -o \
|
||||
-type f \( -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.cjs" \
|
||||
-o -name "*.mjs" -o -name "*.py" -o -name "*.sh" -o -name "*.css" \) \
|
||||
! -name "*.min.js" -print
|
||||
)
|
||||
|
||||
if [ "$missing" -eq 0 ]; then
|
||||
echo "✔ All applicable files carry the authorship header."
|
||||
fi
|
||||
exit "$missing"
|
||||
Reference in New Issue
Block a user