@jeiemgi/cckit 0.1.6

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.
Files changed (191) hide show
  1. package/.claude-plugin/plugin.json +22 -0
  2. package/AGENTS.md +101 -0
  3. package/LICENSE-APACHE +202 -0
  4. package/LICENSE-MIT +21 -0
  5. package/README.md +143 -0
  6. package/SECURITY.md +22 -0
  7. package/bin/cckit +215 -0
  8. package/cckit.config.json +34 -0
  9. package/commands/kit-add.md +42 -0
  10. package/commands/kit-docs.md +45 -0
  11. package/commands/kit-doctor.md +52 -0
  12. package/commands/kit-export-project.md +58 -0
  13. package/commands/kit-export-training.md +49 -0
  14. package/commands/kit-init.md +126 -0
  15. package/commands/kit-routines.md +59 -0
  16. package/commands/kit-update.md +132 -0
  17. package/docs/kit-annotate/01-explainer.html +225 -0
  18. package/docs/kit-annotate/02-implementation-plan.html +196 -0
  19. package/docs/media/.onboarding-capture.cast +5 -0
  20. package/docs/media/README.md +43 -0
  21. package/docs/media/build-demo.sh +63 -0
  22. package/docs/media/build-kit-init.sh +51 -0
  23. package/docs/media/build-onboarding.sh +51 -0
  24. package/docs/media/kit-dry-run.cast +107 -0
  25. package/docs/media/kit-dry-run.gif +0 -0
  26. package/docs/media/kit-init.cast +56 -0
  27. package/docs/media/kit-init.gif +0 -0
  28. package/docs/media/kit-onboarding.cast +148 -0
  29. package/docs/media/kit-onboarding.gif +0 -0
  30. package/githooks/pre-commit +18 -0
  31. package/kit.config.schema.json +105 -0
  32. package/package.json +54 -0
  33. package/privacy-denylist.example +8 -0
  34. package/profiles/automation.json +36 -0
  35. package/profiles/content.json +41 -0
  36. package/profiles/minimal.json +31 -0
  37. package/profiles/research.json +37 -0
  38. package/profiles/software.json +32 -0
  39. package/scripts/annotate-setup.sh +149 -0
  40. package/scripts/autopilot.sh +50 -0
  41. package/scripts/capture-project-ids.sh +53 -0
  42. package/scripts/check.sh +66 -0
  43. package/scripts/contribute.sh +48 -0
  44. package/scripts/debug.sh +54 -0
  45. package/scripts/init-upgrade-test.sh +99 -0
  46. package/scripts/init.sh +827 -0
  47. package/scripts/install.sh +24 -0
  48. package/scripts/kit-add-test.sh +62 -0
  49. package/scripts/kit-add.sh +115 -0
  50. package/scripts/kit-adopt-test.sh +61 -0
  51. package/scripts/kit-adopt.sh +122 -0
  52. package/scripts/kit-bump-version.sh +79 -0
  53. package/scripts/kit-digest.sh +126 -0
  54. package/scripts/kit-doctor.sh +663 -0
  55. package/scripts/kit-export-project-test.sh +82 -0
  56. package/scripts/kit-export-project.sh +245 -0
  57. package/scripts/kit-export-training-test.sh +51 -0
  58. package/scripts/kit-export-training.sh +175 -0
  59. package/scripts/kit-migrate-test.sh +80 -0
  60. package/scripts/kit-migrate.sh +190 -0
  61. package/scripts/kit-onboard-test.sh +63 -0
  62. package/scripts/kit-onboard.sh +69 -0
  63. package/scripts/kit-promote-test.sh +54 -0
  64. package/scripts/kit-promote.sh +102 -0
  65. package/scripts/kit-remove-test.sh +61 -0
  66. package/scripts/kit-remove.sh +84 -0
  67. package/scripts/kit-routines.sh +322 -0
  68. package/scripts/kit-version-check.sh +91 -0
  69. package/scripts/kit-wire-test.sh +54 -0
  70. package/scripts/kit-wire.sh +132 -0
  71. package/scripts/knowledge-lint.sh +96 -0
  72. package/scripts/lib/cckit-output.sh +36 -0
  73. package/scripts/lib/effort-metrics.sh +452 -0
  74. package/scripts/lib/effort-ops-test.sh +83 -0
  75. package/scripts/lib/effort-ops.sh +132 -0
  76. package/scripts/lib/effort-plan.sh +104 -0
  77. package/scripts/lib/effort.sh +191 -0
  78. package/scripts/lib/engine-adapter.sh +92 -0
  79. package/scripts/lib/gh-log.sh +58 -0
  80. package/scripts/lib/gh-project.sh +212 -0
  81. package/scripts/lib/handoff.sh +35 -0
  82. package/scripts/lib/kit-cli-test.sh +42 -0
  83. package/scripts/lib/kit-cli.sh +32 -0
  84. package/scripts/lib/kit-config-resolve.sh +145 -0
  85. package/scripts/lib/kit-config.sh +88 -0
  86. package/scripts/lib/kit-engine-test.sh +107 -0
  87. package/scripts/lib/kit-events.sh +62 -0
  88. package/scripts/lib/kit-gc.sh +117 -0
  89. package/scripts/lib/kit-interview-test.sh +77 -0
  90. package/scripts/lib/kit-interview.sh +203 -0
  91. package/scripts/lib/kit-local.sh +79 -0
  92. package/scripts/lib/kit-manifest.sh +127 -0
  93. package/scripts/lib/kit-mode-test.sh +49 -0
  94. package/scripts/lib/kit-mode.sh +67 -0
  95. package/scripts/lib/kit-operate.sh +105 -0
  96. package/scripts/lib/kit-profile-test.sh +62 -0
  97. package/scripts/lib/kit-profile.sh +115 -0
  98. package/scripts/lib/kit-task-ops-test.sh +63 -0
  99. package/scripts/lib/kit-task-ops.sh +341 -0
  100. package/scripts/lib/pr-evidence.sh +173 -0
  101. package/scripts/lib/project-scan.sh +16 -0
  102. package/scripts/lib/react-detect.sh +78 -0
  103. package/scripts/lib/role-identity.sh +47 -0
  104. package/scripts/lib/secret-guard.sh +96 -0
  105. package/scripts/lib/toon.sh +35 -0
  106. package/scripts/lib/ui.sh +42 -0
  107. package/scripts/lib/version-bump.sh +59 -0
  108. package/scripts/lib/worktree-issue-test.sh +45 -0
  109. package/scripts/lib/worktree-issue.sh +73 -0
  110. package/scripts/lib/worktree-start.sh +280 -0
  111. package/scripts/orchestrate.sh +160 -0
  112. package/scripts/portable-test.sh +53 -0
  113. package/scripts/publish.sh +94 -0
  114. package/scripts/setup-labels.sh +25 -0
  115. package/scripts/setup-milestones.sh +17 -0
  116. package/scripts/showcase.sh +64 -0
  117. package/scripts/status.sh +44 -0
  118. package/scripts/task-sync.sh +59 -0
  119. package/scripts/test.sh +48 -0
  120. package/scripts/web-install.sh +22 -0
  121. package/skills/kit-annotate/SKILL.md +107 -0
  122. package/skills/kit-autopilot/SKILL.md +108 -0
  123. package/skills/kit-contribute/SKILL.md +134 -0
  124. package/skills/kit-customize/SKILL.md +134 -0
  125. package/skills/kit-dev/SKILL.md +67 -0
  126. package/skills/kit-digest/SKILL.md +41 -0
  127. package/skills/kit-effort-close/SKILL.md +156 -0
  128. package/skills/kit-effort-new/SKILL.md +173 -0
  129. package/skills/kit-effort-pr/SKILL.md +139 -0
  130. package/skills/kit-effort-start/SKILL.md +85 -0
  131. package/skills/kit-gc/SKILL.md +80 -0
  132. package/skills/kit-onboard/SKILL.md +50 -0
  133. package/skills/kit-security-sweep/SKILL.md +57 -0
  134. package/skills/kit-ship/SKILL.md +43 -0
  135. package/skills/kit-task-close/SKILL.md +66 -0
  136. package/skills/kit-task-new/SKILL.md +51 -0
  137. package/skills/kit-task-pr/SKILL.md +43 -0
  138. package/skills/kit-task-pr-auto/SKILL.md +27 -0
  139. package/skills/kit-task-pr-merge/SKILL.md +53 -0
  140. package/skills/kit-task-start/SKILL.md +76 -0
  141. package/skills/kit-task-sync/SKILL.md +37 -0
  142. package/templates/CLAUDE.md.tmpl +106 -0
  143. package/templates/agents/analyst.md +55 -0
  144. package/templates/agents/auto-dev.md +93 -0
  145. package/templates/agents/backend.md +59 -0
  146. package/templates/agents/designer.md +73 -0
  147. package/templates/agents/devops.md +57 -0
  148. package/templates/agents/editor.md +48 -0
  149. package/templates/agents/frontend.md +81 -0
  150. package/templates/agents/generalist.md +46 -0
  151. package/templates/agents/local-delegate.md +70 -0
  152. package/templates/agents/n8n.md +65 -0
  153. package/templates/agents/pm.md +69 -0
  154. package/templates/agents/qa.md +66 -0
  155. package/templates/agents/researcher.md +57 -0
  156. package/templates/agents/security.md +65 -0
  157. package/templates/agents/tech-lead.md +75 -0
  158. package/templates/hooks/guard-base-branch-commit.sh.tmpl +45 -0
  159. package/templates/hooks/kit-local-status.sh.tmpl +34 -0
  160. package/templates/hooks/kit_version_check.sh.tmpl +6 -0
  161. package/templates/hooks/mempal_followup.sh.tmpl +97 -0
  162. package/templates/hooks/mempal_precompact.sh.tmpl +4 -0
  163. package/templates/hooks/mempal_save.sh.tmpl +4 -0
  164. package/templates/hooks/mempal_session_start.sh.tmpl +8 -0
  165. package/templates/hooks/prepush_gate.sh.tmpl +36 -0
  166. package/templates/hooks/repo-hygiene.sh.tmpl +72 -0
  167. package/templates/kit.config.json.tmpl +32 -0
  168. package/templates/knowledge-INDEX.md.tmpl +12 -0
  169. package/templates/lib/kit-sigil.sh.tmpl +124 -0
  170. package/templates/rules/branch-naming.md +104 -0
  171. package/templates/rules/communication-style.md +22 -0
  172. package/templates/rules/delegation-brief.md +40 -0
  173. package/templates/rules/design-routing.md +35 -0
  174. package/templates/rules/effort-model.md +122 -0
  175. package/templates/rules/knowledge-base.md +41 -0
  176. package/templates/rules/mempalace.md +110 -0
  177. package/templates/rules/plan-output-format.md +58 -0
  178. package/templates/rules/react-annotate.md +69 -0
  179. package/templates/rules/risk-tiered-review.md +62 -0
  180. package/templates/rules/skill-gaps.md +48 -0
  181. package/templates/rules/task-management.md +42 -0
  182. package/templates/settings/settings.local.json.tmpl +27 -0
  183. package/templates/skills/NAMESPACED +13 -0
  184. package/templates/skills/copywriting/SKILL.md +252 -0
  185. package/templates/skills/copywriting/references/copy-frameworks.md +344 -0
  186. package/templates/skills/copywriting/references/natural-transitions.md +272 -0
  187. package/templates/skills/feature-build-refine/SKILL.md +367 -0
  188. package/templates/skills/karpathy-guidelines/SKILL.md +69 -0
  189. package/templates/skills/morning-briefing/SKILL.md +46 -0
  190. package/templates/skills/speckit/SKILL.md +239 -0
  191. package/templates/skills/supabase-patterns/SKILL.md +88 -0
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+ # autopilot.sh - unattended multi-flow driver. A THIN wrapper over orchestrate.sh: pick the issues
3
+ # to run (explicit args, or auto-select the unblocked open issues from the board), then orchestrate
4
+ # them under a concurrency cap, detached, with no human present.
5
+ #
6
+ # This is the SCRIPT half of autopilot - it launches the flows. The "captain" half (decide, review,
7
+ # merge each PR, continue to the next wave) is the driving agent's job, not this script's.
8
+ #
9
+ # Usage:
10
+ # cckit autopilot # auto-select unblocked open issues from the board
11
+ # cckit autopilot 6 7 8 # drive exactly these issues
12
+ # cckit autopilot --cap 3 # cap concurrent flows (passed through to orchestrate)
13
+ # cckit autopilot --agent codex # drive a different agent CLI
14
+ # cckit autopilot --dry-run # print the plan, launch nothing
15
+ set -euo pipefail
16
+
17
+ PASS=() # flags forwarded to orchestrate
18
+ ISSUES=()
19
+ while [ "$#" -gt 0 ]; do
20
+ case "$1" in
21
+ --cap|--agent) PASS+=("$1" "$2"); shift 2 ;;
22
+ --cap=*|--agent=*|--dry-run|--no-seed|--force|--session=*) PASS+=("$1"); shift ;;
23
+ -h|--help) sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
24
+ [0-9]*) ISSUES+=("$1"); shift ;;
25
+ *) echo "autopilot: unknown arg '$1'" >&2; exit 2 ;;
26
+ esac
27
+ done
28
+
29
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
30
+ ROOT="$(git -C "$SCRIPT_DIR" worktree list --porcelain | awk '/^worktree /{print $2; exit}')"
31
+ [ -n "$ROOT" ] || { echo "autopilot: not in a git repo" >&2; exit 1; }
32
+
33
+ # No explicit issues -> auto-select from the board: open issues, minus effort PARENTS (the
34
+ # "[Effort] N ..." umbrella issues that decompose into subs, identified by label:effort OR the
35
+ # title convention) and minus anything blocked_by an open issue. orchestrate re-checks the
36
+ # blocked_by gate at launch; this is the coarse pre-filter so the board drives the wave.
37
+ if [ "${#ISSUES[@]}" -eq 0 ]; then
38
+ echo "autopilot: no issues passed - auto-selecting unblocked open issues from the board"
39
+ board="$(bash "$ROOT/scripts/task-sync.sh" --llm)"
40
+ while IFS= read -r n; do
41
+ [ -n "$n" ] && ISSUES+=("$n")
42
+ done < <(printf '%s' "$board" | jq -r '
43
+ .[]
44
+ | select((any(.labels[]; . == "effort")) or (.title | test("^\\[Effort\\] ")) | not)
45
+ | .number')
46
+ [ "${#ISSUES[@]}" -ge 1 ] || { echo "autopilot: nothing open to drive" >&2; exit 0; }
47
+ fi
48
+
49
+ echo "autopilot: driving ${#ISSUES[@]} issue(s) -> orchestrate (detached): ${ISSUES[*]}"
50
+ exec bash "$ROOT/scripts/orchestrate.sh" --detach "${PASS[@]+"${PASS[@]}"}" "${ISSUES[@]}"
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bash
2
+ # Capture Projects v2 field + option IDs into scripts/.project-ids.env.
3
+ # Reads owner + project number from .claude/kit.config.json. Run from project root.
4
+ # Handles "Status", "Role", and "Plan Link" fields by name (case-insensitive).
5
+ set -euo pipefail
6
+ source "$(dirname "$0")/lib/kit-config.sh" && load_kit_config
7
+
8
+ [[ "$KIT_PROJECTS_V2" != "true" ]] && { echo "Projects v2 not enabled for this project — nothing to capture."; exit 0; }
9
+
10
+ OUT="$(dirname "$0")/.project-ids.env"
11
+
12
+ DATA=$(gh api graphql -f query='
13
+ query($login:String!, $number:Int!){
14
+ user(login:$login){
15
+ projectV2(number:$number){
16
+ id
17
+ fields(first:50){ nodes{
18
+ __typename
19
+ ... on ProjectV2FieldCommon { id name }
20
+ ... on ProjectV2SingleSelectField { id name options { id name } }
21
+ }}
22
+ }
23
+ }
24
+ }' -f login="$KIT_OWNER" -F number="$KIT_PROJECT_NUMBER")
25
+
26
+ PROJECT_ID=$(echo "$DATA" | jq -r '.data.user.projectV2.id')
27
+ [[ -z "$PROJECT_ID" || "$PROJECT_ID" == "null" ]] && { echo "✗ Could not resolve project #$KIT_PROJECT_NUMBER for $KIT_OWNER"; exit 1; }
28
+
29
+ # jq filter: normalize an option/field label -> UPPER_SNAKE
30
+ norm='def n: ascii_upcase | gsub("[ -]";"_");'
31
+
32
+ {
33
+ echo "# Generated by capture-project-ids.sh — do not edit by hand."
34
+ echo "PROJECT_ID=$PROJECT_ID"
35
+
36
+ # Single-select fields -> <FIELD>_FIELD_ID + <FIELD>_OPT_<OPTION>
37
+ echo "$DATA" | jq -r "$norm"'
38
+ .data.user.projectV2.fields.nodes[]
39
+ | select(.options != null)
40
+ | (.name | n) as $f
41
+ | ([ "\($f)_FIELD_ID=\(.id)" ]
42
+ + (.options[] | "\($f)_OPT_\(.name | n)=\(.id)" | [.])) []'
43
+
44
+ # Text/other fields -> <FIELD>_FIELD_ID
45
+ echo "$DATA" | jq -r "$norm"'
46
+ .data.user.projectV2.fields.nodes[]
47
+ | select(.options == null) | select(.name != null)
48
+ | "\(.name | n)_FIELD_ID=\(.id)"'
49
+ } > "$OUT"
50
+
51
+ echo "✓ Wrote $OUT"
52
+ echo " Fields captured:"
53
+ grep -E '_FIELD_ID=' "$OUT" | sed 's/^/ /'
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bash
2
+ # check.sh - cckit local gate. Runs the fast, dependency-light checks that must pass before a PR.
3
+ # No CI required; this is the bar. Exit non-zero on the first failure.
4
+ set -uo pipefail
5
+ cd "$(cd "$(dirname "$0")/.." && pwd)"
6
+
7
+ fail=0
8
+ note() { printf '%s\n' "$*" >&2; }
9
+
10
+ # 1. Every shell script parses (bash -n).
11
+ note "==> shell syntax (bash -n)"
12
+ while IFS= read -r f; do
13
+ bash -n "$f" || { note "x syntax: $f"; fail=1; }
14
+ done < <(find bin scripts -type f \( -name '*.sh' -o -perm -u+x \) 2>/dev/null | sort -u)
15
+
16
+ # 1b. shellcheck at error severity — static analysis when available, skipped if not installed
17
+ # (like jq below) so the gate stays dependency-light. CI installs shellcheck so this always runs there.
18
+ note "==> shellcheck (errors)"
19
+ if command -v shellcheck >/dev/null 2>&1; then
20
+ find bin scripts -type f \( -name '*.sh' -o -name 'cckit' \) -print0 \
21
+ | xargs -0 shellcheck --severity=error || fail=1
22
+ else
23
+ note " (shellcheck absent - skipping)"
24
+ fi
25
+
26
+ # 2. The plugin manifest is valid JSON.
27
+ note "==> plugin manifest JSON"
28
+ if command -v jq >/dev/null 2>&1; then
29
+ jq -e . .claude-plugin/plugin.json >/dev/null || { note "x invalid plugin.json"; fail=1; }
30
+ jq -e . cckit.config.json >/dev/null || { note "x invalid cckit.config.json"; fail=1; }
31
+ else
32
+ note " (jq absent - skipping JSON validation)"
33
+ fi
34
+
35
+ # 3. No tedos branding leaked into what SHIPS (the de-tedos-ification gate). Scans TRACKED files
36
+ # only (git grep) so gitignored runtime state (.cckit/), build output (dist/), and deps never trip
37
+ # a false positive - only committed content must be tedos-free. Falls back to a filtered recursive
38
+ # grep outside a git work tree.
39
+ note "==> no tedos branding (tracked files)"
40
+ _tedos_scan() {
41
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
42
+ git grep -inI tedos -- . ':!scripts/check.sh'
43
+ else
44
+ grep -rniI --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.cckit \
45
+ --exclude-dir=dist --exclude=check.sh tedos .
46
+ fi
47
+ }
48
+ if _tedos_scan >/dev/null 2>&1; then
49
+ note "x found 'tedos' references - cckit must be tedos-free:"
50
+ _tedos_scan | head -20 >&2
51
+ fail=1
52
+ fi
53
+
54
+ # 4. Secret + privacy guard - no secrets, keys, env, or private data in anything publishable.
55
+ note "==> secret + privacy guard"
56
+ if [ -f scripts/lib/secret-guard.sh ]; then
57
+ . scripts/lib/secret-guard.sh
58
+ secret_guard_scan || fail=1
59
+ fi
60
+
61
+ # 5. Behavioral tests - run every *-test.sh through the test runner.
62
+ note "==> behavioral tests"
63
+ bash scripts/test.sh || fail=1
64
+
65
+ [ "$fail" -eq 0 ] && note "PASS cckit check passed" || note "FAIL cckit check FAILED"
66
+ exit "$fail"
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+ # contribute.sh - open a contribution PR to cckit, GATED on the local checks. The checks gate
3
+ # (scripts/check.sh: shell syntax, valid manifests, no stray branding, secret/privacy guard) MUST
4
+ # pass before anything is pushed - a red gate stops here. This is the agent-agnostic CLI half of
5
+ # the kit-contribute skill.
6
+ #
7
+ # Usage:
8
+ # cckit contribute "<one-line summary>" # gate -> push branch -> open PR to the upstream base
9
+ # cckit contribute --dry-run "<summary>" # run the gate + preconditions, push/PR nothing
10
+ set -euo pipefail
11
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
12
+ # shellcheck source=/dev/null
13
+ source "$ROOT/scripts/lib/kit-config.sh" && load_kit_config
14
+ repo="$KIT_REPO"; base="${KIT_BASE_BRANCH:-main}"
15
+
16
+ dry=0; summary=""
17
+ for a in "$@"; do
18
+ case "$a" in --dry-run) dry=1 ;; *) summary="${summary:+$summary }$a" ;; esac
19
+ done
20
+
21
+ branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
22
+ case "$branch" in
23
+ ""|main|develop|"$base") echo "contribute: start a feature branch first (cckit start <issue>)." >&2; exit 2 ;;
24
+ esac
25
+
26
+ echo "==> contribute: checks gate (scripts/check.sh)"
27
+ if ! bash "$ROOT/scripts/check.sh"; then
28
+ echo "contribute: checks gate FAILED - fix it before contributing (a green gate is the bar)." >&2
29
+ exit 1
30
+ fi
31
+
32
+ git fetch origin "$base" --quiet 2>/dev/null || true
33
+ if [ -z "$(git log --oneline "origin/$base..$branch" 2>/dev/null)" ]; then
34
+ echo "contribute: no commits ahead of $base on '$branch' - commit your change first." >&2; exit 2
35
+ fi
36
+
37
+ [ -n "$summary" ] || { echo "contribute: pass a one-line summary: cckit contribute \"<what + why>\"" >&2; exit 2; }
38
+
39
+ if [ "$dry" -eq 1 ]; then
40
+ echo "contribute: DRY RUN - gate green, '$branch' has commits ahead of $base."
41
+ echo " would: push '$branch' + open a PR to $repo ($base) titled: $summary"
42
+ exit 0
43
+ fi
44
+
45
+ git push -u origin "$branch" 2>&1 | tail -1
46
+ gh pr create --repo "$repo" --base "$base" --head "$branch" \
47
+ --title "$summary" \
48
+ --body "$(printf '## Contribution\n\n%s\n\nChecks gate (scripts/check.sh): green.\nDual-licensed MIT OR Apache-2.0 per CONTRIBUTING.md.\n' "$summary")"
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+ # debug.sh - OPTIONAL, auto-detected browser-debug capability via chrome-devtools-axi (Kun Chen,
3
+ # https://github.com/kunchenguid/chrome-devtools-axi). Token-efficient (TOON output), self-contained
4
+ # Chrome bridge. NOT a hard dependency: cckit is pure bash; axi needs Node + Chrome. When present,
5
+ # this drives axi; when absent, it prints how to enable it and exits 0 (degrade, never hard-fail an
6
+ # unattended run).
7
+ #
8
+ # Usage:
9
+ # cckit debug <axi-args...> drive axi (screenshot / a11y / console / network / lighthouse)
10
+ # cckit debug --check report whether the capability is available, then exit
11
+ #
12
+ # Resolution order for the axi command:
13
+ # 1. $CCKIT_AXI explicit command/path override
14
+ # 2. chrome-devtools-axi on PATH (npm i -g chrome-devtools-axi)
15
+ # 3. npx -y chrome-devtools-axi when node + npx are present
16
+ set -euo pipefail
17
+
18
+ have() { command -v "$1" >/dev/null 2>&1; }
19
+
20
+ chrome_present() {
21
+ have google-chrome || have chromium || have chromium-browser \
22
+ || [ -x "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ] \
23
+ || [ -x "/Applications/Chromium.app/Contents/MacOS/Chromium" ]
24
+ }
25
+
26
+ # Echo how to invoke axi, or return non-zero if unavailable.
27
+ axi_cmd() {
28
+ if [ -n "${CCKIT_AXI:-}" ]; then printf '%s' "$CCKIT_AXI"; return 0; fi
29
+ if have chrome-devtools-axi; then printf 'chrome-devtools-axi'; return 0; fi
30
+ if have npx && have node; then printf 'npx -y chrome-devtools-axi'; return 0; fi
31
+ return 1
32
+ }
33
+
34
+ cmd="$(axi_cmd || true)"
35
+
36
+ if [ "${1:-}" = "--check" ]; then
37
+ if [ -n "$cmd" ] && chrome_present; then
38
+ echo "cckit debug: AVAILABLE via '$cmd' (Chrome detected)"
39
+ else
40
+ echo "cckit debug: optional capability NOT available."
41
+ [ -n "$cmd" ] || echo " - axi: install with 'npm i -g chrome-devtools-axi' (or have node+npx)"
42
+ chrome_present || echo " - Chrome: not detected (install Google Chrome or Chromium)"
43
+ fi
44
+ exit 0
45
+ fi
46
+
47
+ if [ -z "$cmd" ] || ! chrome_present; then
48
+ echo "cckit debug: browser-debug capability unavailable - skipping (optional)." >&2
49
+ [ -n "$cmd" ] || echo " enable: npm i -g chrome-devtools-axi (needs Node + Chrome)" >&2
50
+ exit 0 # degrade, do not hard-fail an unattended run
51
+ fi
52
+
53
+ # shellcheck disable=SC2086
54
+ exec $cmd "$@"
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env bash
2
+ # init-upgrade-test.sh — self-test for the `init.sh --upgrade` clobber contract (#334).
3
+ #
4
+ # Reproduces the 2026-06-11 incident in a throwaway project and asserts the fix:
5
+ # 1. existing kit-owned files (scripts/) are PRESERVED, never downgraded to older templates;
6
+ # 2. paths the project removed/renamed (kit.config.json `upgrade.removed/renamed`) are
7
+ # NEVER re-added by "add missing files";
8
+ # 3. the net effect of an upgrade on a converged project is ONLY the kitVersion bump.
9
+ #
10
+ # Network-free: drives init.sh through the --upgrade path only (skips kit-doctor + gh).
11
+ # Run: bash scripts/init-upgrade-test.sh
12
+
13
+ set -uo pipefail
14
+ PLUGIN_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
15
+ INIT="$PLUGIN_DIR/scripts/init.sh"
16
+
17
+ fail=0
18
+ t() { # t <label> <got> <want>
19
+ if [ "$2" != "$3" ]; then echo "FAIL: $1 -> got '[$2]' want '[$3]'"; fail=1; else echo "ok: $1"; fi
20
+ }
21
+
22
+ command -v jq >/dev/null 2>&1 || { echo "SKIP: jq not available"; exit 0; }
23
+ command -v git >/dev/null 2>&1 || { echo "SKIP: git not available"; exit 0; }
24
+
25
+ PLUGIN_VERSION="$(jq -r '.version // "0.0.0"' "$PLUGIN_DIR/.claude-plugin/plugin.json" 2>/dev/null || echo 0.0.0)"
26
+
27
+ proj="$(mktemp -d)"; trap 'rm -rf "$proj"' EXIT
28
+ cd "$proj"
29
+ git init -q
30
+ git config user.email kit-test@example.com
31
+ git config user.name kit-test
32
+
33
+ # --- seed a minimal initialized project so the --upgrade path engages (no doctor/gh) ----
34
+ mkdir -p .claude
35
+ cat > .claude/kit.config.json <<JSON
36
+ {
37
+ "kitVersion": "0.0.1",
38
+ "profile": "software",
39
+ "project": { "name": "UpgradeTest", "slug": "upgrade-test" },
40
+ "github": { "repo": "example/upgrade-test", "owner": "example", "projectsV2": false }
41
+ }
42
+ JSON
43
+
44
+ # First upgrade = full scaffold via the upgrade path. --force skips the dirty-tree guard
45
+ # (the seed config is still untracked at this point).
46
+ CLAUDE_PLUGIN_ROOT="$PLUGIN_DIR" bash "$INIT" --upgrade --target "$proj" --force >/dev/null 2>&1 \
47
+ || { echo "FAIL: initial scaffold (--upgrade) exited non-zero"; exit 1; }
48
+
49
+ t "scaffold added morning-briefing skill" "$([ -f .claude/skills/morning-briefing/SKILL.md ] && echo yes || echo no)" "yes"
50
+ t "scaffold added speckit skill" "$([ -d .claude/skills/speckit ] && echo yes || echo no)" "yes"
51
+ t "scaffold added task-management rule" "$([ -f .claude/rules/task-management.md ] && echo yes || echo no)" "yes"
52
+ t "scaffold copied task-sync.sh" "$([ -f scripts/task-sync.sh ] && echo yes || echo no)" "yes"
53
+
54
+ git add -A && git commit -q -m "scaffold"
55
+
56
+ # --- simulate the project's deliberate divergence (the cckit state) --------------------
57
+ # rename a scaffolded skill, delete two scaffolded paths, register them in the upgrade block,
58
+ # and mark a kit-owned script so a downgrade would be detectable.
59
+ git mv .claude/skills/morning-briefing .claude/skills/kit-morning-briefing
60
+ git rm -q -r .claude/skills/speckit
61
+ git rm -q .claude/rules/task-management.md
62
+ MARKER="# LOCAL-FIX-MARKER-#334 (must survive upgrade)"
63
+ printf '\n%s\n' "$MARKER" >> scripts/task-sync.sh
64
+
65
+ jq --arg k "0.0.1" '
66
+ .kitVersion = $k
67
+ | .upgrade = {
68
+ removed: [ ".claude/skills/speckit", ".claude/rules/task-management.md" ],
69
+ renamed: { ".claude/skills/morning-briefing": ".claude/skills/kit-morning-briefing" }
70
+ }' .claude/kit.config.json > .claude/kit.config.json.tmp && mv .claude/kit.config.json.tmp .claude/kit.config.json
71
+
72
+ git add -A && git commit -q -m "diverge: rename + delete + register exclusions"
73
+
74
+ # --- the upgrade under test (clean tree, real un-forced path) --------------------------
75
+ CLAUDE_PLUGIN_ROOT="$PLUGIN_DIR" bash "$INIT" --upgrade --target "$proj" >/dev/null 2>&1 \
76
+ || { echo "FAIL: upgrade under test exited non-zero"; exit 1; }
77
+
78
+ # 1. removed/renamed are NOT resurrected
79
+ t "renamed morning-briefing NOT re-added" "$([ -e .claude/skills/morning-briefing ] && echo present || echo absent)" "absent"
80
+ t "removed speckit NOT re-added" "$([ -e .claude/skills/speckit ] && echo present || echo absent)" "absent"
81
+ t "removed rule NOT re-added" "$([ -e .claude/rules/task-management.md ] && echo present || echo absent)" "absent"
82
+ t "renamed target still present" "$([ -d .claude/skills/kit-morning-briefing ] && echo yes || echo no)" "yes"
83
+
84
+ # 2. kit-owned script PRESERVED (not downgraded — marker survives)
85
+ t "script not downgraded (marker kept)" "$(grep -cF "$MARKER" scripts/task-sync.sh)" "1"
86
+
87
+ # 3. net effect = ONLY the kitVersion bump
88
+ changed="$(git status --porcelain | awk '{print $2}' | sort | tr '\n' ' ' | sed 's/ $//')"
89
+ t "only kit.config.json changed" "$changed" ".claude/kit.config.json"
90
+
91
+ diff_body="$(git diff -- .claude/kit.config.json | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)')"
92
+ only_kitver="$(printf '%s\n' "$diff_body" | grep -vqE '"kitVersion"' && echo no || echo yes)"
93
+ t "diff is only the kitVersion line" "$only_kitver" "yes"
94
+ t "kitVersion bumped to plugin version" "$(jq -r '.kitVersion' .claude/kit.config.json)" "$PLUGIN_VERSION"
95
+ t "upgrade block preserved through merge" "$(jq -r '.upgrade.removed | length' .claude/kit.config.json)" "2"
96
+
97
+ echo ""
98
+ [ "$fail" -eq 0 ] && echo "PASS: init.sh --upgrade honors the preserve/exclude contract (#334)" || echo "FAILED"
99
+ exit "$fail"