shipwright-cli 1.10.0 → 2.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 (108) hide show
  1. package/README.md +114 -36
  2. package/completions/_shipwright +212 -32
  3. package/completions/shipwright.bash +97 -25
  4. package/docs/strategy/01-market-research.md +619 -0
  5. package/docs/strategy/02-mission-and-brand.md +587 -0
  6. package/docs/strategy/03-gtm-and-roadmap.md +759 -0
  7. package/docs/strategy/QUICK-START.txt +289 -0
  8. package/docs/strategy/README.md +172 -0
  9. package/package.json +4 -2
  10. package/scripts/sw +208 -1
  11. package/scripts/sw-activity.sh +500 -0
  12. package/scripts/sw-adaptive.sh +925 -0
  13. package/scripts/sw-adversarial.sh +1 -1
  14. package/scripts/sw-architecture-enforcer.sh +1 -1
  15. package/scripts/sw-auth.sh +613 -0
  16. package/scripts/sw-autonomous.sh +664 -0
  17. package/scripts/sw-changelog.sh +704 -0
  18. package/scripts/sw-checkpoint.sh +1 -1
  19. package/scripts/sw-ci.sh +602 -0
  20. package/scripts/sw-cleanup.sh +1 -1
  21. package/scripts/sw-code-review.sh +637 -0
  22. package/scripts/sw-connect.sh +1 -1
  23. package/scripts/sw-context.sh +605 -0
  24. package/scripts/sw-cost.sh +1 -1
  25. package/scripts/sw-daemon.sh +432 -130
  26. package/scripts/sw-dashboard.sh +1 -1
  27. package/scripts/sw-db.sh +540 -0
  28. package/scripts/sw-decompose.sh +539 -0
  29. package/scripts/sw-deps.sh +551 -0
  30. package/scripts/sw-developer-simulation.sh +1 -1
  31. package/scripts/sw-discovery.sh +412 -0
  32. package/scripts/sw-docs-agent.sh +539 -0
  33. package/scripts/sw-docs.sh +1 -1
  34. package/scripts/sw-doctor.sh +59 -1
  35. package/scripts/sw-dora.sh +615 -0
  36. package/scripts/sw-durable.sh +710 -0
  37. package/scripts/sw-e2e-orchestrator.sh +535 -0
  38. package/scripts/sw-eventbus.sh +393 -0
  39. package/scripts/sw-feedback.sh +471 -0
  40. package/scripts/sw-fix.sh +1 -1
  41. package/scripts/sw-fleet-discover.sh +567 -0
  42. package/scripts/sw-fleet-viz.sh +404 -0
  43. package/scripts/sw-fleet.sh +8 -1
  44. package/scripts/sw-github-app.sh +596 -0
  45. package/scripts/sw-github-checks.sh +1 -1
  46. package/scripts/sw-github-deploy.sh +1 -1
  47. package/scripts/sw-github-graphql.sh +1 -1
  48. package/scripts/sw-guild.sh +569 -0
  49. package/scripts/sw-heartbeat.sh +1 -1
  50. package/scripts/sw-hygiene.sh +559 -0
  51. package/scripts/sw-incident.sh +617 -0
  52. package/scripts/sw-init.sh +88 -1
  53. package/scripts/sw-instrument.sh +699 -0
  54. package/scripts/sw-intelligence.sh +1 -1
  55. package/scripts/sw-jira.sh +1 -1
  56. package/scripts/sw-launchd.sh +363 -28
  57. package/scripts/sw-linear.sh +1 -1
  58. package/scripts/sw-logs.sh +1 -1
  59. package/scripts/sw-loop.sh +64 -3
  60. package/scripts/sw-memory.sh +1 -1
  61. package/scripts/sw-mission-control.sh +487 -0
  62. package/scripts/sw-model-router.sh +545 -0
  63. package/scripts/sw-otel.sh +596 -0
  64. package/scripts/sw-oversight.sh +689 -0
  65. package/scripts/sw-pipeline-composer.sh +1 -1
  66. package/scripts/sw-pipeline-vitals.sh +1 -1
  67. package/scripts/sw-pipeline.sh +687 -24
  68. package/scripts/sw-pm.sh +693 -0
  69. package/scripts/sw-pr-lifecycle.sh +522 -0
  70. package/scripts/sw-predictive.sh +1 -1
  71. package/scripts/sw-prep.sh +1 -1
  72. package/scripts/sw-ps.sh +1 -1
  73. package/scripts/sw-public-dashboard.sh +798 -0
  74. package/scripts/sw-quality.sh +595 -0
  75. package/scripts/sw-reaper.sh +1 -1
  76. package/scripts/sw-recruit.sh +573 -0
  77. package/scripts/sw-regression.sh +642 -0
  78. package/scripts/sw-release-manager.sh +736 -0
  79. package/scripts/sw-release.sh +706 -0
  80. package/scripts/sw-remote.sh +1 -1
  81. package/scripts/sw-replay.sh +520 -0
  82. package/scripts/sw-retro.sh +691 -0
  83. package/scripts/sw-scale.sh +444 -0
  84. package/scripts/sw-security-audit.sh +505 -0
  85. package/scripts/sw-self-optimize.sh +1 -1
  86. package/scripts/sw-session.sh +1 -1
  87. package/scripts/sw-setup.sh +1 -1
  88. package/scripts/sw-standup.sh +712 -0
  89. package/scripts/sw-status.sh +1 -1
  90. package/scripts/sw-strategic.sh +658 -0
  91. package/scripts/sw-stream.sh +450 -0
  92. package/scripts/sw-swarm.sh +583 -0
  93. package/scripts/sw-team-stages.sh +511 -0
  94. package/scripts/sw-templates.sh +1 -1
  95. package/scripts/sw-testgen.sh +515 -0
  96. package/scripts/sw-tmux-pipeline.sh +554 -0
  97. package/scripts/sw-tmux.sh +1 -1
  98. package/scripts/sw-trace.sh +485 -0
  99. package/scripts/sw-tracker-github.sh +188 -0
  100. package/scripts/sw-tracker-jira.sh +172 -0
  101. package/scripts/sw-tracker-linear.sh +251 -0
  102. package/scripts/sw-tracker.sh +117 -2
  103. package/scripts/sw-triage.sh +603 -0
  104. package/scripts/sw-upgrade.sh +1 -1
  105. package/scripts/sw-ux.sh +677 -0
  106. package/scripts/sw-webhook.sh +627 -0
  107. package/scripts/sw-widgets.sh +530 -0
  108. package/scripts/sw-worktree.sh +1 -1
@@ -0,0 +1,569 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ shipwright guild — Knowledge Guilds & Cross-Team Learning ║
4
+ # ║ Patterns · Best Practices · Cross-Pollination · Guild Intelligence ║
5
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
6
+ set -euo pipefail
7
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
+
9
+ VERSION="2.0.0"
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+
12
+ # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
13
+ CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
14
+ PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
15
+ BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
16
+ GREEN='\033[38;2;74;222;128m' # success
17
+ YELLOW='\033[38;2;250;204;21m' # warning
18
+ RED='\033[38;2;248;113;113m' # error
19
+ DIM='\033[2m'
20
+ BOLD='\033[1m'
21
+ RESET='\033[0m'
22
+
23
+ # ─── Cross-platform compatibility ──────────────────────────────────────────
24
+ # shellcheck source=lib/compat.sh
25
+ [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
26
+
27
+ # ─── Output Helpers ─────────────────────────────────────────────────────────
28
+ info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
29
+ success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
30
+ warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*" >&2; }
31
+ error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
32
+
33
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
34
+
35
+ # ─── Guild Storage Paths ───────────────────────────────────────────────────
36
+ GUILD_ROOT="${HOME}/.shipwright/guilds"
37
+ GUILD_CONFIG="${GUILD_ROOT}/config.json"
38
+ GUILD_DATA="${GUILD_ROOT}/guilds.json"
39
+
40
+ # ─── Event Logging ────────────────────────────────────────────────────────
41
+ EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
42
+
43
+ emit_event() {
44
+ local event_type="$1"
45
+ shift
46
+ local json_fields=""
47
+ for kv in "$@"; do
48
+ local key="${kv%%=*}"
49
+ local val="${kv#*=}"
50
+ if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
51
+ json_fields="${json_fields},\"${key}\":${val}"
52
+ else
53
+ val="${val//\"/\\\"}"
54
+ json_fields="${json_fields},\"${key}\":\"${val}\""
55
+ fi
56
+ done
57
+ mkdir -p "${HOME}/.shipwright"
58
+ echo "{\"ts\":\"$(now_iso)\",\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
59
+ }
60
+
61
+ # ─── Initialization ────────────────────────────────────────────────────────
62
+ ensure_guild_dir() {
63
+ mkdir -p "$GUILD_ROOT"
64
+
65
+ if [[ ! -f "$GUILD_CONFIG" ]]; then
66
+ cat > "$GUILD_CONFIG" << 'EOF'
67
+ {
68
+ "version": "1.0",
69
+ "created_at": "NOW",
70
+ "guild_definitions": {
71
+ "security": {
72
+ "description": "Security patterns, vulnerability fixes, threat modeling",
73
+ "members": [],
74
+ "pattern_count": 0,
75
+ "practice_count": 0
76
+ },
77
+ "performance": {
78
+ "description": "Optimization patterns, caching, bottleneck analysis",
79
+ "members": [],
80
+ "pattern_count": 0,
81
+ "practice_count": 0
82
+ },
83
+ "testing": {
84
+ "description": "Test strategies, coverage patterns, edge cases",
85
+ "members": [],
86
+ "pattern_count": 0,
87
+ "practice_count": 0
88
+ },
89
+ "architecture": {
90
+ "description": "Design patterns, layering, dependency management",
91
+ "members": [],
92
+ "pattern_count": 0,
93
+ "practice_count": 0
94
+ },
95
+ "documentation": {
96
+ "description": "Doc patterns, clarity, examples, API docs",
97
+ "members": [],
98
+ "pattern_count": 0,
99
+ "practice_count": 0
100
+ },
101
+ "reliability": {
102
+ "description": "Error handling, observability, resilience patterns",
103
+ "members": [],
104
+ "pattern_count": 0,
105
+ "practice_count": 0
106
+ },
107
+ "cost-optimization": {
108
+ "description": "Resource efficiency, token optimization, cost patterns",
109
+ "members": [],
110
+ "pattern_count": 0,
111
+ "practice_count": 0
112
+ }
113
+ }
114
+ }
115
+ EOF
116
+ sed -i "" "s/NOW/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/g" "$GUILD_CONFIG" 2>/dev/null || true
117
+ fi
118
+
119
+ if [[ ! -f "$GUILD_DATA" ]]; then
120
+ echo '{"patterns":{},"practices":{},"cross_pollination":[]}' > "$GUILD_DATA"
121
+ fi
122
+ }
123
+
124
+ # ─── List Guilds ──────────────────────────────────────────────────────────
125
+ cmd_list() {
126
+ ensure_guild_dir
127
+
128
+ info "Available Guilds"
129
+ echo ""
130
+
131
+ jq -r '.guild_definitions | to_entries[] |
132
+ "\(.key | ascii_upcase): \(.value.description)\n Patterns: \(.value.pattern_count) | Practices: \(.value.practice_count)"' \
133
+ "$GUILD_CONFIG" 2>/dev/null | while read -r line; do
134
+ if [[ "$line" =~ ^[A-Z] ]]; then
135
+ echo -e "${CYAN}${BOLD}${line}${RESET}"
136
+ else
137
+ echo -e " ${DIM}${line}${RESET}"
138
+ fi
139
+ done
140
+ }
141
+
142
+ # ─── Show Guild Details ───────────────────────────────────────────────────
143
+ cmd_show() {
144
+ local guild="${1:-}"
145
+
146
+ if [[ -z "$guild" ]]; then
147
+ error "Guild name required. Usage: shipwright guild show <guild>"
148
+ return 1
149
+ fi
150
+
151
+ ensure_guild_dir
152
+
153
+ # Validate guild exists
154
+ if ! jq -e ".guild_definitions[\"$guild\"]" "$GUILD_CONFIG" >/dev/null 2>&1; then
155
+ error "Guild not found: $guild"
156
+ return 1
157
+ fi
158
+
159
+ info "Guild: ${CYAN}${BOLD}${guild}${RESET}"
160
+
161
+ jq -r ".guild_definitions[\"$guild\"] |
162
+ \"Description: \(.description)\n\" +
163
+ \"Members: \(.members | length)\n\" +
164
+ \"Patterns: \(.pattern_count)\n\" +
165
+ \"Practices: \(.practice_count)\"" \
166
+ "$GUILD_CONFIG"
167
+
168
+ echo ""
169
+ info "Patterns:"
170
+ jq -r ".patterns[\"$guild\"] // [] | .[] |
171
+ \" • \(.title) (confidence: \(.confidence | tostring)%, used \(.usage_count) times)\"" \
172
+ "$GUILD_DATA" | head -10 || echo " ${DIM}(none)${RESET}"
173
+
174
+ echo ""
175
+ info "Best Practices:"
176
+ jq -r ".practices[\"$guild\"] // [] | .[] |
177
+ \" • \(.title) (confidence: \(.confidence | tostring)%, adopted \(.adoption_count) times)\"" \
178
+ "$GUILD_DATA" | head -10 || echo " ${DIM}(none)${RESET}"
179
+ }
180
+
181
+ # ─── Search Knowledge Base ────────────────────────────────────────────────
182
+ cmd_search() {
183
+ local query="${1:-}"
184
+ local domain="${2:-}"
185
+
186
+ if [[ -z "$query" ]]; then
187
+ error "Search query required. Usage: shipwright guild search <query> [domain]"
188
+ return 1
189
+ fi
190
+
191
+ ensure_guild_dir
192
+
193
+ info "Searching knowledge base for: ${CYAN}${query}${RESET}"
194
+ [[ -n "$domain" ]] && info "Domain filter: ${CYAN}${domain}${RESET}"
195
+
196
+ echo ""
197
+
198
+ # Search patterns
199
+ local pattern_count=0
200
+ jq -r ".patterns | to_entries[] |
201
+ select(.value | length > 0) |
202
+ select((.key | contains(\"$domain\")) or (\"$domain\" == \"\")) |
203
+ .value[] |
204
+ select((.title | test(\"$query\"; \"i\")) or (.description | test(\"$query\"; \"i\"))) |
205
+ \"PATTERN: \(.title) [\(.source.pipeline // \"unknown\")]\\n \(.description)\"" \
206
+ "$GUILD_DATA" 2>/dev/null | while read -r line; do
207
+ echo -e "${GREEN}${line}${RESET}"
208
+ done
209
+ pattern_count=$(jq -r ".patterns | to_entries[] |
210
+ select(.value | length > 0) |
211
+ select((.key | contains(\"$domain\")) or (\"$domain\" == \"\")) |
212
+ .value[] |
213
+ select((.title | test(\"$query\"; \"i\")) or (.description | test(\"$query\"; \"i\"))) | \"1\"" \
214
+ "$GUILD_DATA" 2>/dev/null | wc -l)
215
+
216
+ # Search practices
217
+ jq -r ".practices | to_entries[] |
218
+ select(.value | length > 0) |
219
+ select((.key | contains(\"$domain\")) or (\"$domain\" == \"\")) |
220
+ .value[] |
221
+ select((.title | test(\"$query\"; \"i\")) or (.description | test(\"$query\"; \"i\"))) |
222
+ \"PRACTICE: \(.title) [confidence: \(.confidence)%]\\n \(.description)\"" \
223
+ "$GUILD_DATA" 2>/dev/null | while read -r line; do
224
+ echo -e "${BLUE}${line}${RESET}"
225
+ done
226
+
227
+ local practice_count=0
228
+ practice_count=$(jq -r ".practices | to_entries[] |
229
+ select(.value | length > 0) |
230
+ select((.key | contains(\"$domain\")) or (\"$domain\" == \"\")) |
231
+ .value[] |
232
+ select((.title | test(\"$query\"; \"i\")) or (.description | test(\"$query\"; \"i\"))) | \"1\"" \
233
+ "$GUILD_DATA" 2>/dev/null | wc -l)
234
+
235
+ if [[ $pattern_count -eq 0 && $practice_count -eq 0 ]]; then
236
+ warn "No matches found"
237
+ return 1
238
+ fi
239
+ }
240
+
241
+ # ─── Add Pattern or Practice ──────────────────────────────────────────────
242
+ cmd_add() {
243
+ local type="${1:-}"
244
+ local guild="${2:-}"
245
+ local title="${3:-}"
246
+
247
+ if [[ -z "$type" || -z "$guild" || -z "$title" ]]; then
248
+ error "Usage: shipwright guild add <pattern|practice> <guild> <title>"
249
+ return 1
250
+ fi
251
+
252
+ [[ "$type" != "pattern" && "$type" != "practice" ]] && { error "Type must be pattern or practice"; return 1; }
253
+
254
+ ensure_guild_dir
255
+
256
+ if ! jq -e ".guild_definitions[\"$guild\"]" "$GUILD_CONFIG" >/dev/null 2>&1; then
257
+ error "Guild not found: $guild"
258
+ return 1
259
+ fi
260
+
261
+ # Read description from stdin if piped
262
+ local description="${4:-}"
263
+ if [[ -z "$description" && -t 0 ]]; then
264
+ echo -n "Description: "
265
+ read -r description
266
+ fi
267
+
268
+ local tmp_file
269
+ tmp_file=$(mktemp "$GUILD_DATA.tmp.XXXXXX")
270
+
271
+ if [[ "$type" == "pattern" ]]; then
272
+ jq --arg guild "$guild" \
273
+ --arg title "$title" \
274
+ --arg desc "$description" \
275
+ --arg ts "$(now_iso)" \
276
+ ".patterns[\$guild] //= [] |
277
+ .patterns[\$guild] += [{
278
+ title: \$title,
279
+ description: \$desc,
280
+ confidence: 75,
281
+ usage_count: 1,
282
+ source: {pipeline: \"manual\", created_at: \$ts},
283
+ tags: []
284
+ }]" \
285
+ "$GUILD_DATA" > "$tmp_file" && mv "$tmp_file" "$GUILD_DATA"
286
+ success "Pattern added to ${CYAN}${guild}${RESET}"
287
+ else
288
+ jq --arg guild "$guild" \
289
+ --arg title "$title" \
290
+ --arg desc "$description" \
291
+ --arg ts "$(now_iso)" \
292
+ ".practices[\$guild] //= [] |
293
+ .practices[\$guild] += [{
294
+ title: \$title,
295
+ description: \$desc,
296
+ confidence: 80,
297
+ adoption_count: 0,
298
+ source: {pipeline: \"manual\", created_at: \$ts},
299
+ tags: []
300
+ }]" \
301
+ "$GUILD_DATA" > "$tmp_file" && mv "$tmp_file" "$GUILD_DATA"
302
+ success "Practice added to ${CYAN}${guild}${RESET}"
303
+ fi
304
+
305
+ emit_event "guild.add" "type=${type}" "guild=${guild}" "title=${title}"
306
+ }
307
+
308
+ # ─── Learn from Pipeline ──────────────────────────────────────────────────
309
+ cmd_learn() {
310
+ local pipeline_dir="${1:-}"
311
+
312
+ if [[ -z "$pipeline_dir" || ! -d "$pipeline_dir" ]]; then
313
+ error "Pipeline artifacts directory required. Usage: shipwright guild learn <artifacts_dir>"
314
+ return 1
315
+ fi
316
+
317
+ ensure_guild_dir
318
+
319
+ info "Extracting learnings from pipeline: ${CYAN}${pipeline_dir}${RESET}"
320
+
321
+ # This would be called by the pipeline with artifacts directory
322
+ # For now, emit a learning event that signals a Claude agent to analyze
323
+ emit_event "guild.learn_requested" "pipeline_dir=${pipeline_dir}"
324
+
325
+ success "Learning extraction queued (requires Claude analysis)"
326
+ }
327
+
328
+ # ─── Inject Knowledge into Prompt ────────────────────────────────────────
329
+ cmd_inject() {
330
+ local task_type="${1:-}"
331
+ local context="${2:-}"
332
+
333
+ if [[ -z "$task_type" ]]; then
334
+ error "Task type required. Usage: shipwright guild inject <task_type> [context]"
335
+ return 1
336
+ fi
337
+
338
+ ensure_guild_dir
339
+
340
+ info "Relevant guild knowledge for ${CYAN}${task_type}${RESET}:"
341
+ echo ""
342
+
343
+ # Map task types to relevant guilds
344
+ case "$task_type" in
345
+ security|auth|vulnerability)
346
+ echo "# Security Guild Knowledge"
347
+ jq -r ".practices.security // [] | .[0:3] | .[] |
348
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
349
+ ;;
350
+ performance|optimization)
351
+ echo "# Performance Guild Knowledge"
352
+ jq -r ".practices.performance // [] | .[0:3] | .[] |
353
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
354
+ ;;
355
+ testing|test|coverage)
356
+ echo "# Testing Guild Knowledge"
357
+ jq -r ".practices.testing // [] | .[0:3] | .[] |
358
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
359
+ ;;
360
+ architecture|design|refactor)
361
+ echo "# Architecture Guild Knowledge"
362
+ jq -r ".practices.architecture // [] | .[0:3] | .[] |
363
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
364
+ ;;
365
+ docs|documentation)
366
+ echo "# Documentation Guild Knowledge"
367
+ jq -r ".practices.documentation // [] | .[0:3] | .[] |
368
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
369
+ ;;
370
+ reliability|error|observability)
371
+ echo "# Reliability Guild Knowledge"
372
+ jq -r ".practices.reliability // [] | .[0:3] | .[] |
373
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
374
+ ;;
375
+ cost|budget|tokens)
376
+ echo "# Cost Optimization Guild Knowledge"
377
+ jq -r ".practices.cost-optimization // [] | .[0:3] | .[] |
378
+ \"- \(.title): \(.description)\"" "$GUILD_DATA"
379
+ ;;
380
+ *)
381
+ info "Top practices across all guilds:"
382
+ jq -r ".practices | to_entries[] | .value[] |
383
+ select(.confidence >= 80) |
384
+ \"- \(.title) [\(.source.pipeline // \"unknown\")]\"" \
385
+ "$GUILD_DATA" | head -5 || true
386
+ ;;
387
+ esac
388
+ }
389
+
390
+ # ─── Guild Reports ───────────────────────────────────────────────────────
391
+ cmd_report() {
392
+ local guild="${1:-all}"
393
+
394
+ ensure_guild_dir
395
+
396
+ if [[ "$guild" == "all" ]]; then
397
+ info "Guild Knowledge Growth Report"
398
+ echo ""
399
+
400
+ jq -r '.guild_definitions | to_entries[] |
401
+ "\(.key | ascii_upcase):\n Patterns: \(.value.pattern_count)\n Practices: \(.value.practice_count)"' \
402
+ "$GUILD_CONFIG" | while read -r line; do
403
+ if [[ "$line" =~ ^[A-Z] ]]; then
404
+ echo -e "${CYAN}${BOLD}${line}${RESET}"
405
+ else
406
+ echo -e " ${DIM}${line}${RESET}"
407
+ fi
408
+ done
409
+ else
410
+ if ! jq -e ".guild_definitions[\"$guild\"]" "$GUILD_CONFIG" >/dev/null 2>&1; then
411
+ error "Guild not found: $guild"
412
+ return 1
413
+ fi
414
+
415
+ info "Guild Report: ${CYAN}${BOLD}${guild}${RESET}"
416
+ echo ""
417
+
418
+ local pattern_count
419
+ pattern_count=$(jq -r ".patterns[\"$guild\"] // [] | length" "$GUILD_DATA")
420
+ local practice_count
421
+ practice_count=$(jq -r ".practices[\"$guild\"] // [] | length" "$GUILD_DATA")
422
+
423
+ echo -e " Patterns: ${CYAN}${pattern_count}${RESET}"
424
+ echo -e " Practices: ${CYAN}${practice_count}${RESET}"
425
+
426
+ local avg_conf
427
+ avg_conf=$(jq -r ".practices[\"$guild\"] // [] |
428
+ if length > 0 then map(.confidence) | add / length | floor else 0 end" \
429
+ "$GUILD_DATA")
430
+ echo -e " Avg Confidence: ${GREEN}${avg_conf}%${RESET}"
431
+ fi
432
+ }
433
+
434
+ # ─── Export Knowledge ────────────────────────────────────────────────────
435
+ cmd_export() {
436
+ local format="${1:-json}"
437
+ local output_file="${2:-}"
438
+
439
+ [[ "$format" != "json" && "$format" != "markdown" ]] && { error "Format must be json or markdown"; return 1; }
440
+
441
+ ensure_guild_dir
442
+
443
+ if [[ -z "$output_file" ]]; then
444
+ output_file="${GUILD_ROOT}/export.${format}"
445
+ fi
446
+
447
+ if [[ "$format" == "json" ]]; then
448
+ cp "$GUILD_DATA" "$output_file"
449
+ success "Exported to ${CYAN}${output_file}${RESET}"
450
+ else
451
+ {
452
+ echo "# Shipwright Guild Knowledge Base"
453
+ echo ""
454
+ echo "Generated: $(date)"
455
+ echo ""
456
+
457
+ jq -r '.guild_definitions | keys[]' "$GUILD_CONFIG" | while read -r guild; do
458
+ local guild_title
459
+ guild_title=$(echo "$guild" | sed 's/^./\U&/')
460
+ echo "## $guild_title"
461
+ jq -r ".guild_definitions[\"$guild\"].description" "$GUILD_CONFIG"
462
+ echo ""
463
+
464
+ echo "### Patterns"
465
+ jq -r ".patterns[\"$guild\"] // [] | .[] |
466
+ \"- **\(.title)**: \(.description) (confidence: \(.confidence)%, used \(.usage_count) times)\"" \
467
+ "$GUILD_DATA" || echo "No patterns yet."
468
+ echo ""
469
+
470
+ echo "### Best Practices"
471
+ jq -r ".practices[\"$guild\"] // [] | .[] |
472
+ \"- **\(.title)**: \(.description) (confidence: \(.confidence)%, adopted \(.adoption_count) times)\"" \
473
+ "$GUILD_DATA" || echo "No practices yet."
474
+ echo ""
475
+ done
476
+ } > "$output_file"
477
+ success "Exported to ${CYAN}${output_file}${RESET}"
478
+ fi
479
+ }
480
+
481
+ # ─── Help ──────────────────────────────────────────────────────────────────
482
+ show_help() {
483
+ cat << EOF
484
+ ${CYAN}${BOLD}shipwright guild${RESET} — Knowledge Guilds & Cross-Team Learning
485
+
486
+ ${BOLD}USAGE${RESET}
487
+ ${CYAN}shipwright guild${RESET} <command> [options]
488
+
489
+ ${BOLD}COMMANDS${RESET}
490
+ ${CYAN}list${RESET} List all guilds and their knowledge stats
491
+ ${CYAN}show${RESET} <guild> Show guild details, patterns, and practices
492
+ ${CYAN}search${RESET} <query> Search knowledge base by keyword
493
+ ${CYAN}add${RESET} <type> <guild> <title>
494
+ Manually add a pattern or best practice
495
+ ${CYAN}learn${RESET} <dir> Extract patterns from pipeline artifacts
496
+ ${CYAN}inject${RESET} <task> Show knowledge to inject for a task type
497
+ ${CYAN}report${RESET} [guild] Guild knowledge growth report
498
+ ${CYAN}export${RESET} [format] Export knowledge as JSON or Markdown
499
+ ${CYAN}help${RESET} Show this help message
500
+
501
+ ${BOLD}GUILDS${RESET}
502
+ • ${CYAN}security${RESET} Security patterns, vulnerability fixes
503
+ • ${CYAN}performance${RESET} Optimization patterns, caching strategies
504
+ • ${CYAN}testing${RESET} Test strategies, coverage patterns
505
+ • ${CYAN}architecture${RESET} Design patterns, layering rules
506
+ • ${CYAN}documentation${RESET} Doc patterns, clarity guidelines
507
+ • ${CYAN}reliability${RESET} Error handling, observability patterns
508
+ • ${CYAN}cost-optimization${RESET} Resource efficiency patterns
509
+
510
+ ${BOLD}EXAMPLES${RESET}
511
+ ${DIM}shipwright guild list${RESET}
512
+ ${DIM}shipwright guild show security${RESET}
513
+ ${DIM}shipwright guild search "error handling" reliability${RESET}
514
+ ${DIM}shipwright guild add pattern testing "Unit test template" < description.txt${RESET}
515
+ ${DIM}shipwright guild inject security${RESET}
516
+ ${DIM}shipwright guild report performance${RESET}
517
+ ${DIM}shipwright guild export markdown knowledge-base.md${RESET}
518
+
519
+ EOF
520
+ }
521
+
522
+ # ─── Main Router ───────────────────────────────────────────────────────────
523
+ main() {
524
+ local cmd="${1:-}"
525
+
526
+ case "$cmd" in
527
+ list)
528
+ cmd_list
529
+ ;;
530
+ show)
531
+ cmd_show "${2:-}"
532
+ ;;
533
+ search)
534
+ cmd_search "${2:-}" "${3:-}"
535
+ ;;
536
+ add)
537
+ cmd_add "${2:-}" "${3:-}" "${4:-}" "${5:-}"
538
+ ;;
539
+ learn)
540
+ cmd_learn "${2:-}"
541
+ ;;
542
+ inject)
543
+ cmd_inject "${2:-}" "${3:-}"
544
+ ;;
545
+ report)
546
+ cmd_report "${2:-all}"
547
+ ;;
548
+ export)
549
+ cmd_export "${2:-json}" "${3:-}"
550
+ ;;
551
+ help|--help|-h)
552
+ show_help
553
+ ;;
554
+ *)
555
+ if [[ -z "$cmd" ]]; then
556
+ show_help
557
+ else
558
+ error "Unknown command: ${cmd}"
559
+ echo ""
560
+ show_help
561
+ exit 1
562
+ fi
563
+ ;;
564
+ esac
565
+ }
566
+
567
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
568
+ main "$@"
569
+ fi
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="1.10.0"
9
+ VERSION="2.0.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────