golem-cc 2.1.2 → 3.0.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.
Files changed (84) hide show
  1. package/.claude/commands/golem/build.md +18 -0
  2. package/.claude/commands/golem/config.md +39 -0
  3. package/.claude/commands/golem/continue.md +73 -0
  4. package/.claude/commands/golem/doctor.md +46 -0
  5. package/.claude/commands/golem/document.md +138 -0
  6. package/.claude/commands/golem/help.md +58 -0
  7. package/.claude/commands/golem/pause.md +130 -0
  8. package/.claude/commands/golem/plan.md +111 -0
  9. package/.claude/commands/golem/review.md +166 -0
  10. package/.claude/commands/golem/security.md +186 -0
  11. package/.claude/commands/golem/simplify.md +76 -0
  12. package/.claude/commands/golem/spec.md +105 -0
  13. package/.claude/commands/golem/status.md +33 -0
  14. package/.golem/agents/code-simplifier.md +54 -0
  15. package/.golem/agents/review-architecture.md +59 -0
  16. package/.golem/agents/review-logic.md +50 -0
  17. package/.golem/agents/review-security.md +50 -0
  18. package/.golem/agents/review-style.md +48 -0
  19. package/.golem/agents/review-tests.md +48 -0
  20. package/.golem/agents/spec-builder.md +60 -0
  21. package/.golem/bin/golem.mjs +270 -0
  22. package/.golem/lib/build.mjs +557 -0
  23. package/.golem/lib/claude.mjs +95 -0
  24. package/.golem/lib/config.mjs +421 -0
  25. package/.golem/lib/display.mjs +191 -0
  26. package/.golem/lib/doctor.mjs +197 -0
  27. package/.golem/lib/document.mjs +792 -0
  28. package/.golem/lib/gates.mjs +78 -0
  29. package/.golem/lib/init.mjs +166 -0
  30. package/.golem/lib/output.mjs +40 -0
  31. package/.golem/lib/ratelimit.mjs +86 -0
  32. package/.golem/lib/security.mjs +603 -0
  33. package/.golem/lib/simplify.mjs +101 -0
  34. package/.golem/lib/tui.mjs +368 -0
  35. package/.golem/lib/usage.mjs +119 -0
  36. package/.golem/lib/worktree.mjs +509 -0
  37. package/.golem/prompts/build.md +23 -0
  38. package/.golem/prompts/document-inline.md +66 -0
  39. package/.golem/prompts/document-markdown.md +80 -0
  40. package/.golem/prompts/simplify.md +35 -0
  41. package/README.md +141 -142
  42. package/bin/golem-shim.mjs +36 -0
  43. package/bin/install.mjs +193 -0
  44. package/package.json +27 -32
  45. package/.env.example +0 -17
  46. package/bin/golem +0 -1040
  47. package/commands/golem/build.md +0 -235
  48. package/commands/golem/config.md +0 -55
  49. package/commands/golem/doctor.md +0 -137
  50. package/commands/golem/help.md +0 -212
  51. package/commands/golem/plan.md +0 -214
  52. package/commands/golem/review.md +0 -376
  53. package/commands/golem/security.md +0 -204
  54. package/commands/golem/simplify.md +0 -94
  55. package/commands/golem/spec.md +0 -226
  56. package/commands/golem/status.md +0 -60
  57. package/dist/api/freshworks.d.ts +0 -61
  58. package/dist/api/freshworks.d.ts.map +0 -1
  59. package/dist/api/freshworks.js +0 -119
  60. package/dist/api/freshworks.js.map +0 -1
  61. package/dist/api/gitea.d.ts +0 -96
  62. package/dist/api/gitea.d.ts.map +0 -1
  63. package/dist/api/gitea.js +0 -154
  64. package/dist/api/gitea.js.map +0 -1
  65. package/dist/cli/index.d.ts +0 -9
  66. package/dist/cli/index.d.ts.map +0 -1
  67. package/dist/cli/index.js +0 -352
  68. package/dist/cli/index.js.map +0 -1
  69. package/dist/sync/ticket-sync.d.ts +0 -53
  70. package/dist/sync/ticket-sync.d.ts.map +0 -1
  71. package/dist/sync/ticket-sync.js +0 -226
  72. package/dist/sync/ticket-sync.js.map +0 -1
  73. package/dist/types.d.ts +0 -125
  74. package/dist/types.d.ts.map +0 -1
  75. package/dist/types.js +0 -5
  76. package/dist/types.js.map +0 -1
  77. package/dist/worktree/manager.d.ts +0 -54
  78. package/dist/worktree/manager.d.ts.map +0 -1
  79. package/dist/worktree/manager.js +0 -190
  80. package/dist/worktree/manager.js.map +0 -1
  81. package/golem/agents/code-simplifier.md +0 -81
  82. package/golem/agents/spec-builder.md +0 -90
  83. package/golem/prompts/PROMPT_build.md +0 -71
  84. package/golem/prompts/PROMPT_plan.md +0 -102
package/bin/golem DELETED
@@ -1,1040 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # golem - Personal agentic workflow manager
4
- #
5
- # Integrates Freshworks tickets, Gitea issues, and Claude Code
6
- # for a unified development workflow.
7
- #
8
-
9
- set -euo pipefail
10
-
11
- VERSION="2.1.2"
12
- GOLEM_HOME="${GOLEM_HOME:-$HOME/.golem}"
13
- GOLEM_API="golem-api"
14
-
15
- # Colors
16
- RED='\033[0;31m'
17
- GREEN='\033[0;32m'
18
- YELLOW='\033[0;33m'
19
- BLUE='\033[0;34m'
20
- CYAN='\033[0;36m'
21
- DIM='\033[0;90m'
22
- BOLD='\033[1m'
23
- NC='\033[0m' # No Color
24
-
25
- # ============================================================================
26
- # Helpers
27
- # ============================================================================
28
-
29
- print_banner() {
30
- echo -e "${CYAN}"
31
- echo " ██████╗ ██████╗ ██╗ ███████╗███╗ ███╗"
32
- echo " ██╔════╝ ██╔═══██╗██║ ██╔════╝████╗ ████║"
33
- echo " ██║ ███╗██║ ██║██║ █████╗ ██╔████╔██║"
34
- echo " ██║ ██║██║ ██║██║ ██╔══╝ ██║╚██╔╝██║"
35
- echo " ╚██████╔╝╚██████╔╝███████╗███████╗██║ ╚═╝ ██║"
36
- echo " ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝"
37
- echo -e "${NC}"
38
- }
39
-
40
- die() {
41
- echo -e "${RED}Error:${NC} $1" >&2
42
- exit 1
43
- }
44
-
45
- info() {
46
- echo -e "${BLUE}→${NC} $1"
47
- }
48
-
49
- success() {
50
- echo -e "${GREEN}✓${NC} $1"
51
- }
52
-
53
- warn() {
54
- echo -e "${YELLOW}!${NC} $1"
55
- }
56
-
57
- dim() {
58
- echo -e "${DIM}$1${NC}"
59
- }
60
-
61
- # Load environment from multiple locations (safely handles special chars)
62
- load_env() {
63
- local env_file
64
- for env_file in "$GOLEM_HOME/.env" ".env"; do
65
- if [[ -f "$env_file" ]]; then
66
- while IFS='=' read -r key value; do
67
- # Skip comments and empty lines
68
- [[ -z "$key" || "$key" =~ ^[[:space:]]*# ]] && continue
69
- # Remove leading/trailing whitespace from key
70
- key="${key#"${key%%[![:space:]]*}"}"
71
- key="${key%"${key##*[![:space:]]}"}"
72
- # Skip if not a valid variable name
73
- [[ ! "$key" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && continue
74
- # Export the variable (value keeps quotes if present)
75
- export "$key=$value"
76
- done < "$env_file"
77
- fi
78
- done
79
- }
80
-
81
- # Check if golem-api is available
82
- check_api() {
83
- if ! command -v "$GOLEM_API" &>/dev/null; then
84
- die "golem-api not found. Run 'pnpm build' in golem directory first."
85
- fi
86
- }
87
-
88
- # Get current ticket ID from worktree path
89
- get_current_ticket() {
90
- local branch
91
- branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
92
- echo "$branch" | grep -oE '(INC|SR)-[0-9]+' || echo ""
93
- }
94
-
95
- # ============================================================================
96
- # Commands
97
- # ============================================================================
98
-
99
- cmd_help() {
100
- print_banner
101
- cat << 'EOF'
102
- USAGE:
103
- golem <command> [options]
104
-
105
- TICKET COMMANDS:
106
- new <subject> Create new ticket in Fresh + Gitea
107
- import <INC-XXXX> Import existing Fresh ticket
108
- list List all tracked tickets
109
- status [ticket] Show ticket status
110
-
111
- WORKTREE COMMANDS:
112
- worktree [ticket] Create/switch to worktree for ticket
113
- worktrees List all worktrees
114
-
115
- BUILD COMMANDS:
116
- build Run autonomous build loop (spawns Claude)
117
- plan Generate implementation plan
118
- simplify [files] Run code simplifier
119
- squash Squash current stage commits
120
-
121
- SYNC COMMANDS:
122
- sync Sync ticket status to Fresh/Gitea
123
- pr Create PR for current ticket
124
-
125
- OTHER:
126
- update [version] Update golem (default: latest)
127
- install Install golem globally
128
- uninstall Remove golem completely
129
- config Show current configuration
130
- doctor Diagnose setup issues
131
- init Initialize golem in current project
132
- version Show version
133
- help Show this help
134
-
135
- CLAUDE COMMANDS (inside Claude Code):
136
- /golem:spec Define specs (agent team: UX, Architect, Devil's Advocate)
137
- /golem:plan Create implementation plan (agent team per layer)
138
- /golem:build Build lead + builders (observable, interruptible)
139
- /golem:security Run security scans (gitleaks, semgrep, pnpm audit, trivy)
140
- /golem:review Security + code review (runs security first, then agent team)
141
- /golem:simplify Run code simplifier
142
- /golem:status Show current status
143
- /golem:help Show help
144
-
145
- EOF
146
- }
147
-
148
- cmd_version() {
149
- print_banner
150
- echo " v$VERSION"
151
- }
152
-
153
- cmd_init() {
154
- print_banner
155
-
156
- # Validate global installation
157
- if [[ ! -d "$GOLEM_HOME/lib" ]]; then
158
- warn "Golem is not installed globally."
159
- echo " Run: pnpm dlx golem-cc"
160
- echo ""
161
- fi
162
-
163
- info "Initializing golem in current project..."
164
-
165
- mkdir -p .golem/{specs,tickets,worktrees}
166
-
167
- if [[ ! -f .golem/AGENTS.md ]]; then
168
- cat > .golem/AGENTS.md << 'EOF'
169
- # Operational Guide
170
-
171
- ## Commands
172
-
173
- ### Testing
174
- ```bash
175
- pnpm test
176
- ```
177
-
178
- ### Type Checking
179
- ```bash
180
- pnpm typecheck
181
- ```
182
-
183
- ### Linting
184
- ```bash
185
- pnpm lint
186
- ```
187
-
188
- ## Learnings
189
- <!-- Updated during build iterations -->
190
- EOF
191
- success "Created .golem/AGENTS.md"
192
- fi
193
-
194
- # Link commands to Claude
195
- mkdir -p .claude/commands
196
- if [[ -d "$GOLEM_HOME/commands/golem" ]]; then
197
- ln -sf "$GOLEM_HOME/commands/golem" .claude/commands/golem 2>/dev/null || true
198
- success "Linked Claude commands"
199
- else
200
- warn "Claude commands not found (install golem globally first)"
201
- fi
202
-
203
- # Add .golem to .gitignore
204
- if [[ -f .gitignore ]]; then
205
- if ! grep -q "^\.golem/worktrees" .gitignore 2>/dev/null; then
206
- echo -e "\n# Golem worktrees\n.golem/worktrees/" >> .gitignore
207
- success "Updated .gitignore"
208
- fi
209
- fi
210
-
211
- success "Golem initialized"
212
- }
213
-
214
- cmd_new() {
215
- local subject="${1:-}"
216
- [[ -z "$subject" ]] && die "Usage: golem new <subject>"
217
-
218
- print_banner
219
- check_api
220
- load_env
221
-
222
- local repo="${GITEA_REPO:-}"
223
- [[ -z "$repo" ]] && die "GITEA_REPO not set"
224
-
225
- echo -e "${BOLD}Creating new ticket${NC}"
226
- echo ""
227
-
228
- read -p "Type (feat/fix/refactor/docs/test/chore) [fix]: " type
229
- type="${type:-fix}"
230
-
231
- read -p "Slug (for branch name): " slug
232
- [[ -z "$slug" ]] && die "Slug required"
233
-
234
- read -p "Description (optional): " description
235
- description="${description:-$subject}"
236
-
237
- read -p "Priority (1=Urgent, 2=High, 3=Medium, 4=Low) [3]: " priority
238
- priority="${priority:-3}"
239
-
240
- info "Creating ticket..."
241
- $GOLEM_API ticket:new \
242
- --subject "$subject" \
243
- --description "$description" \
244
- --type "$type" \
245
- --slug "$slug" \
246
- --priority "$priority" \
247
- --repo "$repo"
248
- }
249
-
250
- cmd_import() {
251
- local ticket_id="${1:-}"
252
- [[ -z "$ticket_id" ]] && die "Usage: golem import <INC-XXXX>"
253
-
254
- print_banner
255
- check_api
256
- load_env
257
-
258
- local repo="${GITEA_REPO:-}"
259
- [[ -z "$repo" ]] && die "GITEA_REPO not set"
260
-
261
- echo -e "${BOLD}Importing ticket $ticket_id${NC}"
262
- echo ""
263
-
264
- read -p "Type (feat/fix/refactor/docs/test/chore) [fix]: " type
265
- type="${type:-fix}"
266
-
267
- read -p "Slug (for branch name): " slug
268
- [[ -z "$slug" ]] && die "Slug required"
269
-
270
- info "Importing..."
271
- $GOLEM_API ticket:import "$ticket_id" \
272
- --type "$type" \
273
- --slug "$slug" \
274
- --repo "$repo"
275
- }
276
-
277
- cmd_list() {
278
- check_api
279
- load_env
280
- $GOLEM_API ticket:list
281
- }
282
-
283
- cmd_status() {
284
- local ticket_id="${1:-$(get_current_ticket)}"
285
-
286
- print_banner
287
-
288
- if [[ -z "$ticket_id" ]]; then
289
- # Show general status
290
- echo -e "${BOLD}Status${NC}"
291
- echo ""
292
-
293
- if [[ -d .golem ]]; then
294
- local spec_count=$(ls .golem/specs/*.md 2>/dev/null | wc -l | tr -d ' ')
295
- echo "Specs: $spec_count"
296
-
297
- if [[ -f .golem/IMPLEMENTATION_PLAN.md ]]; then
298
- local total=$(grep -cE '^(###|-) \[' .golem/IMPLEMENTATION_PLAN.md 2>/dev/null || echo 0)
299
- local done=$(grep -cE '^(###|-) \[x\]' .golem/IMPLEMENTATION_PLAN.md 2>/dev/null || echo 0)
300
- echo "Tasks: $done / $total"
301
- else
302
- dim "No implementation plan"
303
- fi
304
- else
305
- warn "Not a golem project. Run 'golem init'"
306
- fi
307
- else
308
- check_api
309
- load_env
310
- $GOLEM_API ticket:get "$ticket_id"
311
- fi
312
- }
313
-
314
- cmd_worktree() {
315
- local ticket_id="${1:-$(get_current_ticket)}"
316
- [[ -z "$ticket_id" ]] && die "Usage: golem worktree <INC-XXXX> or run from ticket branch"
317
-
318
- check_api
319
- load_env
320
-
321
- info "Creating worktree for $ticket_id..."
322
- local output
323
- output=$($GOLEM_API worktree:create "$ticket_id" 2>&1) || {
324
- echo "$output" >&2
325
- die "Failed to create worktree"
326
- }
327
-
328
- local path
329
- path=$(echo "$output" | tail -1)
330
-
331
- success "Worktree created at $path"
332
- echo ""
333
- echo "To switch to it:"
334
- echo " cd $path"
335
- }
336
-
337
- cmd_worktrees() {
338
- check_api
339
- $GOLEM_API worktree:list
340
- }
341
-
342
- cmd_build() {
343
- local ticket_id
344
- ticket_id=$(get_current_ticket)
345
-
346
- print_banner
347
-
348
- [[ -z "$ticket_id" ]] && warn "Not in a ticket worktree"
349
-
350
- if [[ ! -f .golem/IMPLEMENTATION_PLAN.md ]]; then
351
- die "No implementation plan. Run /golem:plan in Claude first."
352
- fi
353
-
354
- local remaining
355
- remaining=$(grep -cE '^(###|-) \[ \]' .golem/IMPLEMENTATION_PLAN.md 2>/dev/null || echo 0)
356
-
357
- if [[ "$remaining" -eq 0 ]]; then
358
- success "All tasks complete!"
359
- return 0
360
- fi
361
-
362
- info "Starting build loop ($remaining tasks remaining)"
363
- echo ""
364
-
365
- read -p "Continue? [y/N] " confirm
366
- [[ "$confirm" != "y" && "$confirm" != "Y" ]] && exit 0
367
-
368
- # Build the prompt from the build command file
369
- local build_prompt
370
- build_prompt=$(cat "$GOLEM_HOME/prompts/PROMPT_build.md")
371
-
372
- # Loop until done
373
- while true; do
374
- remaining=$(grep -cE '^(###|-) \[ \]' .golem/IMPLEMENTATION_PLAN.md 2>/dev/null || echo 0)
375
-
376
- if [[ "$remaining" -eq 0 ]]; then
377
- success "All tasks complete!"
378
- break
379
- fi
380
-
381
- info "Tasks remaining: $remaining"
382
- info "Running Claude (print mode)..."
383
- echo ""
384
-
385
- # Run Claude in print mode with the build prompt
386
- # --dangerously-skip-permissions allows tool use without confirmation
387
- claude -p "$build_prompt" --dangerously-skip-permissions || true
388
-
389
- echo ""
390
- read -p "Continue to next task? [Y/n] " continue_choice
391
- [[ "$continue_choice" == "n" || "$continue_choice" == "N" ]] && break
392
- done
393
- }
394
-
395
- cmd_plan() {
396
- print_banner
397
-
398
- if [[ ! -d .golem/specs ]] || [[ -z "$(ls .golem/specs/*.md 2>/dev/null)" ]]; then
399
- die "No specs found. Run /golem:spec in Claude first."
400
- fi
401
-
402
- info "Running Claude to generate plan..."
403
-
404
- local plan_prompt
405
- plan_prompt=$(cat "$GOLEM_HOME/prompts/PROMPT_plan.md")
406
-
407
- claude -p "$plan_prompt" --dangerously-skip-permissions
408
- }
409
-
410
- cmd_simplify() {
411
- print_banner
412
-
413
- local files="${*:-}"
414
-
415
- info "Running code simplifier..."
416
-
417
- local simplify_prompt
418
- simplify_prompt=$(cat "$GOLEM_HOME/agents/code-simplifier.md")
419
-
420
- if [[ -n "$files" ]]; then
421
- simplify_prompt="$simplify_prompt
422
-
423
- Files to simplify: $files"
424
- fi
425
-
426
- claude -p "$simplify_prompt" --dangerously-skip-permissions
427
- }
428
-
429
- cmd_squash() {
430
- local ticket_id message=""
431
- ticket_id=$(get_current_ticket)
432
- [[ -z "$ticket_id" ]] && die "Not in a ticket worktree"
433
-
434
- # Parse arguments for -m flag
435
- while [[ $# -gt 0 ]]; do
436
- case "$1" in
437
- -m|--message)
438
- message="$2"
439
- shift 2
440
- ;;
441
- *)
442
- shift
443
- ;;
444
- esac
445
- done
446
-
447
- check_api
448
- load_env
449
-
450
- if [[ ! -f .golem/IMPLEMENTATION_PLAN.md ]]; then
451
- die "No implementation plan found"
452
- fi
453
-
454
- echo -e "${BOLD}Squashing commits for $ticket_id${NC}"
455
- echo ""
456
-
457
- local commits
458
- commits=$(git log --oneline origin/main..HEAD 2>/dev/null | wc -l | tr -d ' ')
459
- echo "Commits to squash: $commits"
460
-
461
- if [[ "$commits" -eq 0 ]]; then
462
- warn "No commits to squash"
463
- return 0
464
- fi
465
-
466
- # If message not provided via flag, prompt interactively
467
- if [[ -z "$message" ]]; then
468
- echo ""
469
- read -p "Commit message: " message
470
- [[ -z "$message" ]] && die "Commit message required"
471
- fi
472
-
473
- info "Squashing..."
474
- $GOLEM_API git:squash "$ticket_id" -m "$message"
475
-
476
- success "Squashed to single commit"
477
- }
478
-
479
- cmd_sync() {
480
- local ticket_id
481
- ticket_id=$(get_current_ticket)
482
- [[ -z "$ticket_id" ]] && die "Not in a ticket worktree"
483
-
484
- check_api
485
- load_env
486
-
487
- local repo="${GITEA_REPO:-}"
488
- [[ -z "$repo" ]] && die "GITEA_REPO not set"
489
-
490
- read -p "Status (new/spec/planning/in-progress/review/done/blocked): " status
491
- read -p "Note (optional): " note
492
-
493
- info "Syncing..."
494
- $GOLEM_API ticket:status "$ticket_id" "$status" --repo "$repo" ${note:+--note "$note"}
495
- }
496
-
497
- cmd_pr() {
498
- local ticket_id
499
- ticket_id=$(get_current_ticket)
500
- [[ -z "$ticket_id" ]] && die "Not in a ticket worktree"
501
-
502
- check_api
503
- load_env
504
-
505
- # Push branch first
506
- info "Pushing branch..."
507
- $GOLEM_API git:push "$ticket_id"
508
-
509
- # Get ticket info for PR title/body
510
- local ticket_json
511
- ticket_json=$($GOLEM_API ticket:get "$ticket_id" 2>/dev/null)
512
-
513
- local subject
514
- subject=$(echo "$ticket_json" | grep -o '"subject":"[^"]*"' | cut -d'"' -f4 || echo "$ticket_id")
515
-
516
- local branch
517
- branch=$(git rev-parse --abbrev-ref HEAD)
518
-
519
- info "Creating PR..."
520
-
521
- # Use gh CLI
522
- gh pr create \
523
- --title "[$ticket_id] $subject" \
524
- --body "Closes Gitea issue.
525
-
526
- ---
527
- Ticket: $ticket_id
528
- Branch: $branch" \
529
- --head "$branch"
530
-
531
- # Update status
532
- local repo="${GITEA_REPO:-}"
533
- [[ -n "$repo" ]] && $GOLEM_API ticket:status "$ticket_id" "review" --repo "$repo" --note "PR created"
534
-
535
- success "PR created"
536
- }
537
-
538
- # Resolve the package root from this script's location.
539
- # When run via pnpm dlx, $0 lives inside a temp store.
540
- # When run from ~/.golem/lib, $0 is there.
541
- _resolve_pkg_root() {
542
- local script_path
543
- script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
544
- # bin/ is one level under package root
545
- echo "$(cd "$script_path/.." && pwd)"
546
- }
547
-
548
- # Bootstrap: copy package contents into ~/.golem/lib and wire everything up.
549
- cmd_bootstrap() {
550
- local pkg_root
551
- pkg_root="$(_resolve_pkg_root)"
552
-
553
- print_banner
554
- info "Installing golem to $GOLEM_HOME..."
555
-
556
- # ---- runtime ----
557
- mkdir -p "$GOLEM_HOME/lib"
558
- # Copy the package runtime (bin, dist, node_modules, package.json)
559
- for item in bin dist node_modules package.json; do
560
- if [[ -e "$pkg_root/$item" ]]; then
561
- rm -rf "$GOLEM_HOME/lib/$item"
562
- cp -R "$pkg_root/$item" "$GOLEM_HOME/lib/$item"
563
- fi
564
- done
565
- success "Installed runtime to $GOLEM_HOME/lib"
566
-
567
- # ---- assets ----
568
- mkdir -p "$GOLEM_HOME"/{commands,agents,prompts}
569
- if [[ -d "$pkg_root/commands/golem" ]]; then
570
- rm -rf "$GOLEM_HOME/commands/golem"
571
- cp -R "$pkg_root/commands/golem" "$GOLEM_HOME/commands/golem"
572
- fi
573
- if compgen -G "$pkg_root/golem/agents/"*.md &>/dev/null; then
574
- cp "$pkg_root/golem/agents/"*.md "$GOLEM_HOME/agents/"
575
- fi
576
- if compgen -G "$pkg_root/golem/prompts/"*.md &>/dev/null; then
577
- cp "$pkg_root/golem/prompts/"*.md "$GOLEM_HOME/prompts/"
578
- fi
579
- success "Installed assets (commands, agents, prompts)"
580
-
581
- # ---- symlinks in ~/.local/bin ----
582
- mkdir -p "$HOME/.local/bin"
583
- ln -sf "$GOLEM_HOME/lib/bin/golem" "$HOME/.local/bin/golem"
584
- ln -sf "$GOLEM_HOME/lib/dist/cli/index.js" "$HOME/.local/bin/golem-api"
585
- chmod +x "$GOLEM_HOME/lib/bin/golem"
586
- chmod +x "$GOLEM_HOME/lib/dist/cli/index.js" 2>/dev/null || true
587
- success "Linked binaries to ~/.local/bin"
588
-
589
- # ---- Claude slash-commands ----
590
- mkdir -p "$HOME/.claude/commands"
591
- ln -sf "$GOLEM_HOME/commands/golem" "$HOME/.claude/commands/golem" 2>/dev/null || true
592
- success "Linked Claude commands"
593
-
594
- # ---- .env template ----
595
- if [[ -f "$pkg_root/.env.example" ]]; then
596
- cp "$pkg_root/.env.example" "$GOLEM_HOME/.env.example"
597
- fi
598
- if [[ ! -f "$GOLEM_HOME/.env" ]]; then
599
- if [[ -f "$GOLEM_HOME/.env.example" ]]; then
600
- cp "$GOLEM_HOME/.env.example" "$GOLEM_HOME/.env"
601
- else
602
- cat > "$GOLEM_HOME/.env" << 'ENVEOF'
603
- # Freshworks/Freshservice
604
- FRESH_DOMAIN=yourcompany.freshservice.com
605
- FRESH_API_KEY=your_api_key_here
606
-
607
- # Gitea (on-prem)
608
- GITEA_URL=https://dev.pearlriverresort.com
609
- GITEA_TOKEN=your_token_here
610
- GITEA_ORG=CRDE
611
-
612
- # Default repo for issues (can be overridden per-project)
613
- GITEA_REPO=
614
- ENVEOF
615
- fi
616
- warn "Created $GOLEM_HOME/.env — edit with your credentials"
617
- fi
618
-
619
- # ---- PATH setup (idempotent) ----
620
- local shell_rc="$HOME/.zshrc"
621
- [[ -f "$HOME/.bashrc" && ! -f "$HOME/.zshrc" ]] && shell_rc="$HOME/.bashrc"
622
-
623
- if [[ -f "$shell_rc" ]]; then
624
- if ! grep -q '$HOME/.local/bin' "$shell_rc" 2>/dev/null; then
625
- echo '' >> "$shell_rc"
626
- echo '# golem: add ~/.local/bin to PATH' >> "$shell_rc"
627
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$shell_rc"
628
- success "Added ~/.local/bin to PATH in $(basename "$shell_rc")"
629
- fi
630
- fi
631
-
632
- echo ""
633
- success "Installation complete!"
634
- echo ""
635
- echo "Restart your shell (or run: source $shell_rc), then:"
636
- echo " golem doctor # verify setup"
637
- echo " golem config # show configuration"
638
- echo " cd <project> && golem init # set up a project"
639
- }
640
-
641
- cmd_uninstall() {
642
- print_banner
643
- echo -e "${BOLD}This will remove:${NC}"
644
- echo " $GOLEM_HOME (runtime, assets, config)"
645
- echo " ~/.local/bin/golem (symlink)"
646
- echo " ~/.local/bin/golem-api (symlink)"
647
- echo " ~/.claude/commands/golem (symlink)"
648
- echo ""
649
-
650
- # Check for .env with real credentials and warn
651
- if [[ -f "$GOLEM_HOME/.env" ]]; then
652
- warn "Your credentials in $GOLEM_HOME/.env will be deleted."
653
- echo " Back up now if needed: cp $GOLEM_HOME/.env ~/golem-env-backup"
654
- echo ""
655
- fi
656
-
657
- read -p "Are you sure? [y/N] " confirm
658
- [[ "$confirm" != "y" && "$confirm" != "Y" ]] && { echo "Aborted."; exit 0; }
659
-
660
- # Remove symlinks in ~/.local/bin
661
- for bin in golem golem-api; do
662
- local target="$HOME/.local/bin/$bin"
663
- if [[ -L "$target" || -f "$target" ]]; then
664
- rm -f "$target"
665
- success "Removed $target"
666
- fi
667
- done
668
-
669
- # Remove Claude commands symlink
670
- if [[ -L "$HOME/.claude/commands/golem" || -d "$HOME/.claude/commands/golem" ]]; then
671
- rm -rf "$HOME/.claude/commands/golem"
672
- success "Removed ~/.claude/commands/golem"
673
- fi
674
-
675
- # Remove ~/.golem entirely
676
- if [[ -d "$GOLEM_HOME" ]]; then
677
- rm -rf "$GOLEM_HOME"
678
- success "Removed $GOLEM_HOME"
679
- fi
680
-
681
- echo ""
682
- success "Golem uninstalled."
683
- echo ""
684
- dim "The PATH entry in your shell rc was left in place (it's harmless)."
685
- dim "To reinstall later: pnpm dlx golem-cc"
686
- }
687
-
688
- cmd_install() {
689
- # If --from <path> given, bootstrap from a local checkout (dev workflow)
690
- if [[ "${1:-}" == "--from" ]]; then
691
- local local_path="${2:-}"
692
- [[ -z "$local_path" ]] && die "Usage: golem install --from <path>"
693
- [[ ! -d "$local_path/bin" ]] && die "Not a golem package directory: $local_path"
694
-
695
- # Temporarily override _resolve_pkg_root
696
- _resolve_pkg_root() { echo "$local_path"; }
697
- cmd_bootstrap
698
- return
699
- fi
700
-
701
- # Default: install from npm
702
- local version="${1:-latest}"
703
- cmd_update "$version"
704
- }
705
-
706
- cmd_update() {
707
- local version="${1:-latest}"
708
-
709
- print_banner
710
- info "Fetching golem-cc@$version from npm..."
711
-
712
- # Download to temp directory
713
- local tmp
714
- tmp=$(mktemp -d)
715
- trap "rm -rf '$tmp'" EXIT
716
-
717
- if ! pnpm --prefix="$tmp" add "golem-cc@$version" --silent 2>/dev/null; then
718
- die "Failed to fetch golem-cc@$version"
719
- fi
720
-
721
- local pkg_path="$tmp/node_modules/golem-cc"
722
- [[ ! -d "$pkg_path/bin" ]] && die "Downloaded package is invalid"
723
-
724
- # Bootstrap from downloaded package
725
- _resolve_pkg_root() { echo "$pkg_path"; }
726
- cmd_bootstrap
727
-
728
- # Update current project if we're in one
729
- if [[ -d ".golem" ]]; then
730
- echo ""
731
- info "Updating project..."
732
- cmd_init
733
- fi
734
-
735
- trap - EXIT
736
- rm -rf "$tmp"
737
- }
738
-
739
- cmd_config() {
740
- print_banner
741
- load_env
742
-
743
- echo -e "${BOLD}Configuration${NC}"
744
- echo ""
745
-
746
- # Paths
747
- echo -e "${BOLD}Paths${NC}"
748
- echo " GOLEM_HOME: $GOLEM_HOME"
749
- echo ""
750
-
751
- # Env files
752
- echo -e "${BOLD}Environment Files${NC}"
753
- if [[ -f "$GOLEM_HOME/.env" ]]; then
754
- success "$GOLEM_HOME/.env"
755
- else
756
- warn "$GOLEM_HOME/.env (not found)"
757
- fi
758
- if [[ -f ".env" ]]; then
759
- success "./.env (local)"
760
- else
761
- dim " ./.env (not found)"
762
- fi
763
- echo ""
764
-
765
- # Helper to print var status
766
- print_var() {
767
- local name="$1"
768
- local value="$2"
769
- local required="$3"
770
- local secret="$4"
771
-
772
- if [[ -n "$value" ]]; then
773
- if [[ "$secret" == "true" ]]; then
774
- echo -e " ${GREEN}$name${NC}: (set)"
775
- else
776
- echo -e " ${GREEN}$name${NC}: $value"
777
- fi
778
- elif [[ "$required" == "true" ]]; then
779
- echo -e " ${RED}$name${NC}: (not set) - REQUIRED"
780
- else
781
- echo -e " ${YELLOW}$name${NC}: (not set)"
782
- fi
783
- }
784
-
785
- # Freshservice vars
786
- echo -e "${BOLD}Freshservice${NC}"
787
- print_var "FRESH_DOMAIN" "${FRESH_DOMAIN:-}" "true" "false"
788
- print_var "FRESH_API_KEY" "${FRESH_API_KEY:-}" "true" "true"
789
- print_var "FRESH_DEFAULT_GROUP_ID" "${FRESH_DEFAULT_GROUP_ID:-}" "false" "false"
790
- print_var "FRESH_DEFAULT_CATEGORY" "${FRESH_DEFAULT_CATEGORY:-}" "false" "false"
791
- print_var "FRESH_SOURCE_ID" "${FRESH_SOURCE_ID:-}" "false" "false"
792
- print_var "FRESH_DEFAULT_EMAIL" "${FRESH_DEFAULT_EMAIL:-}" "false" "false"
793
- echo ""
794
-
795
- # Gitea vars
796
- echo -e "${BOLD}Gitea${NC}"
797
- print_var "GITEA_URL" "${GITEA_URL:-}" "true" "false"
798
- print_var "GITEA_TOKEN" "${GITEA_TOKEN:-}" "true" "true"
799
- print_var "GITEA_ORG" "${GITEA_ORG:-}" "false" "false"
800
- print_var "GITEA_REPO" "${GITEA_REPO:-}" "false" "false"
801
- }
802
-
803
- cmd_doctor() {
804
- local check_apis=false
805
- [[ "${1:-}" == "--check-apis" ]] && check_apis=true
806
-
807
- print_banner
808
- load_env
809
-
810
- local passed=0
811
- local failed=0
812
-
813
- # Helper functions
814
- check_pass() {
815
- echo -e " ${GREEN}✓${NC} $1"
816
- passed=$((passed + 1))
817
- }
818
-
819
- check_fail() {
820
- echo -e " ${RED}✗${NC} $1"
821
- if [[ -n "${2:-}" ]]; then
822
- echo -e " ${DIM}→ $2${NC}"
823
- fi
824
- failed=$((failed + 1))
825
- }
826
-
827
- # Environment checks
828
- echo -e "${BOLD}Environment${NC}"
829
-
830
- if [[ -d "$GOLEM_HOME" ]]; then
831
- check_pass "$GOLEM_HOME directory exists"
832
- else
833
- check_fail "$GOLEM_HOME directory missing" "Run: mkdir -p $GOLEM_HOME"
834
- fi
835
-
836
- if [[ -f "$GOLEM_HOME/.env" ]]; then
837
- check_pass "$GOLEM_HOME/.env file exists"
838
- else
839
- check_fail "$GOLEM_HOME/.env file missing" "Run: cp $GOLEM_HOME/.env.example $GOLEM_HOME/.env"
840
- fi
841
-
842
- local missing_vars=()
843
- [[ -z "${FRESH_DOMAIN:-}" ]] && missing_vars+=("FRESH_DOMAIN")
844
- [[ -z "${FRESH_API_KEY:-}" ]] && missing_vars+=("FRESH_API_KEY")
845
- [[ -z "${GITEA_URL:-}" ]] && missing_vars+=("GITEA_URL")
846
- [[ -z "${GITEA_TOKEN:-}" ]] && missing_vars+=("GITEA_TOKEN")
847
-
848
- if [[ ${#missing_vars[@]} -eq 0 ]]; then
849
- check_pass "Required env vars set"
850
- else
851
- check_fail "Missing required env vars: ${missing_vars[*]}" "Edit $GOLEM_HOME/.env"
852
- fi
853
-
854
- echo ""
855
-
856
- # Dependency checks
857
- echo -e "${BOLD}Dependencies${NC}"
858
-
859
- if command -v node &>/dev/null; then
860
- local node_ver=$(node --version 2>/dev/null)
861
- check_pass "node $node_ver"
862
- else
863
- check_fail "node not found" "Install Node.js"
864
- fi
865
-
866
- if command -v pnpm &>/dev/null; then
867
- local pnpm_ver=$(pnpm --version 2>/dev/null)
868
- check_pass "pnpm $pnpm_ver"
869
- else
870
- check_fail "pnpm not found" "Run: npm install -g pnpm"
871
- fi
872
-
873
- if command -v git &>/dev/null; then
874
- local git_ver=$(git --version 2>/dev/null | cut -d' ' -f3)
875
- check_pass "git $git_ver"
876
- else
877
- check_fail "git not found" "Install git"
878
- fi
879
-
880
- if command -v golem-api &>/dev/null; then
881
- check_pass "golem-api accessible"
882
- else
883
- check_fail "golem-api not found" "Run: pnpm dlx golem-cc"
884
- fi
885
-
886
- echo ""
887
-
888
- # Installation checks
889
- echo -e "${BOLD}Installation${NC}"
890
-
891
- if [[ -d "$GOLEM_HOME/lib" ]]; then
892
- check_pass "Runtime installed ($GOLEM_HOME/lib)"
893
- else
894
- check_fail "Runtime not installed" "Run: pnpm dlx golem-cc"
895
- fi
896
-
897
- local prompt_count=$(ls "$GOLEM_HOME/prompts/"*.md 2>/dev/null | wc -l | tr -d ' ')
898
- if [[ "$prompt_count" -gt 0 ]]; then
899
- check_pass "Prompts installed ($prompt_count files)"
900
- else
901
- check_fail "No prompts installed" "Run: pnpm dlx golem-cc"
902
- fi
903
-
904
- local agent_count=$(ls "$GOLEM_HOME/agents/"*.md 2>/dev/null | wc -l | tr -d ' ')
905
- if [[ "$agent_count" -gt 0 ]]; then
906
- check_pass "Agents installed ($agent_count files)"
907
- else
908
- check_fail "No agents installed" "Run: pnpm dlx golem-cc"
909
- fi
910
-
911
- if [[ -d "$GOLEM_HOME/commands/golem" ]]; then
912
- check_pass "Commands installed"
913
- else
914
- check_fail "Commands not installed" "Run: pnpm dlx golem-cc"
915
- fi
916
-
917
- if [[ -L "$HOME/.claude/commands/golem" ]] && [[ -d "$HOME/.claude/commands/golem" ]]; then
918
- check_pass "Claude integration linked"
919
- else
920
- check_fail "Claude integration not linked" "Run: ln -sf $GOLEM_HOME/commands/golem ~/.claude/commands/golem"
921
- fi
922
-
923
- echo ""
924
-
925
- # Optional API checks
926
- if [[ "$check_apis" == "true" ]]; then
927
- echo -e "${BOLD}API Connectivity${NC}"
928
-
929
- if golem-api fresh:test &>/dev/null; then
930
- check_pass "Freshservice API responds"
931
- else
932
- check_fail "Freshservice API not responding" "Check FRESH_DOMAIN and FRESH_API_KEY"
933
- fi
934
-
935
- if golem-api gitea:test &>/dev/null; then
936
- check_pass "Gitea API responds"
937
- else
938
- check_fail "Gitea API not responding" "Check GITEA_URL and GITEA_TOKEN"
939
- fi
940
-
941
- echo ""
942
- fi
943
-
944
- # Summary
945
- local total=$((passed + failed))
946
- if [[ "$failed" -eq 0 ]]; then
947
- echo -e "${GREEN}Summary: $passed/$total checks passed${NC}"
948
- return 0
949
- else
950
- echo -e "${RED}Summary: $passed/$total checks passed ($failed failed)${NC}"
951
- return 1
952
- fi
953
- }
954
-
955
- # ============================================================================
956
- # Main
957
- # ============================================================================
958
-
959
- main() {
960
- local cmd="${1:-}"
961
- shift || true
962
-
963
- # No args: bootstrap if not installed, otherwise show help
964
- if [[ -z "$cmd" ]]; then
965
- if [[ -d "$GOLEM_HOME/lib" ]]; then
966
- cmd_help
967
- else
968
- cmd_bootstrap
969
- fi
970
- return
971
- fi
972
-
973
- case "$cmd" in
974
- help|--help|-h)
975
- cmd_help
976
- ;;
977
- version|--version|-v)
978
- cmd_version
979
- ;;
980
- init)
981
- cmd_init "$@"
982
- ;;
983
- new)
984
- cmd_new "$@"
985
- ;;
986
- import)
987
- cmd_import "$@"
988
- ;;
989
- list)
990
- cmd_list "$@"
991
- ;;
992
- status)
993
- cmd_status "$@"
994
- ;;
995
- worktree)
996
- cmd_worktree "$@"
997
- ;;
998
- worktrees)
999
- cmd_worktrees "$@"
1000
- ;;
1001
- build)
1002
- cmd_build "$@"
1003
- ;;
1004
- plan)
1005
- cmd_plan "$@"
1006
- ;;
1007
- simplify)
1008
- cmd_simplify "$@"
1009
- ;;
1010
- squash)
1011
- cmd_squash "$@"
1012
- ;;
1013
- sync)
1014
- cmd_sync "$@"
1015
- ;;
1016
- pr)
1017
- cmd_pr "$@"
1018
- ;;
1019
- config)
1020
- cmd_config "$@"
1021
- ;;
1022
- doctor)
1023
- cmd_doctor "$@"
1024
- ;;
1025
- update)
1026
- cmd_update "$@"
1027
- ;;
1028
- install)
1029
- cmd_install "$@"
1030
- ;;
1031
- uninstall)
1032
- cmd_uninstall "$@"
1033
- ;;
1034
- *)
1035
- die "Unknown command: $cmd. Run 'golem help' for usage."
1036
- ;;
1037
- esac
1038
- }
1039
-
1040
- main "$@"