codymaster 4.1.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 (193) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +285 -0
  3. package/adapters/antigravity.js +15 -0
  4. package/adapters/claude-code.js +17 -0
  5. package/adapters/cursor.js +16 -0
  6. package/commands/bootstrap.md +49 -0
  7. package/commands/build.md +48 -0
  8. package/commands/content.md +48 -0
  9. package/commands/continuity.md +60 -0
  10. package/commands/debug.md +51 -0
  11. package/commands/demo.md +96 -0
  12. package/commands/deploy.md +51 -0
  13. package/commands/plan.md +42 -0
  14. package/commands/review.md +55 -0
  15. package/commands/track.md +46 -0
  16. package/commands/ux.md +46 -0
  17. package/dist/agent-dispatch.js +161 -0
  18. package/dist/chains/builtin.js +85 -0
  19. package/dist/continuity.js +385 -0
  20. package/dist/dashboard.js +926 -0
  21. package/dist/data.js +122 -0
  22. package/dist/index.js +2434 -0
  23. package/dist/judge.js +252 -0
  24. package/dist/parallel-dispatch.js +359 -0
  25. package/dist/parallel-quality.js +172 -0
  26. package/dist/skill-chain.js +258 -0
  27. package/install.sh +513 -0
  28. package/package.json +79 -0
  29. package/skills/.content-factory-state.json +132 -0
  30. package/skills/.git 2/logs/refs/heads/main +1 -0
  31. package/skills/.git 2/logs/refs/remotes/origin/main +1 -0
  32. package/skills/.git 2/objects/02/fb0956734b5f8ba3f918b7defd04a89cfe0076 +0 -0
  33. package/skills/.git 2/objects/08/1e129d75dc6feac6c02037272e6bd1a04e3324 +0 -0
  34. package/skills/.git 2/objects/0c/5393416f3c5e01c9a655a802bff0dd52f76f0a +0 -0
  35. package/skills/.git 2/objects/10/0b9be46978a946a77188f68be725098a122001 +0 -0
  36. package/skills/.git 2/objects/10/cf041167fc9843610eb3d90259ef3396315fdc +0 -0
  37. package/skills/.git 2/objects/12/5e19538dd6e1338ffe74f6c4c165b00435bf48 +0 -0
  38. package/skills/.git 2/objects/16/a9b9d0088d5c1347628b45a2620b479d8ad57c +0 -0
  39. package/skills/.git 2/objects/17/8c2a9ef93c33ae4eec9d58e82321f9229843a1 +0 -0
  40. package/skills/.git 2/objects/25/397ae41d09104d763bdcac2695209d85cdea89 +0 -0
  41. package/skills/.git 2/objects/2f/a836b7947f2d458e1f639788bf4bb0983a3305 +0 -0
  42. package/skills/.git 2/objects/3a/baaaf0a1c0909c0828335791557125fba911e0 +0 -0
  43. package/skills/.git 2/objects/42/2924221b81f5ce3c4e4daac9a64a24f9b01f9a +0 -0
  44. package/skills/.git 2/objects/42/ec0ce707447dc11446a34c9995fb8533801731 +0 -0
  45. package/skills/.git 2/objects/46/e43ce92866d56ce74b1d750db307cfe6154a15 +0 -0
  46. package/skills/.git 2/objects/48/5e41b633c63f55b8277bcc59f44f67681f671a +0 -0
  47. package/skills/.git 2/objects/49/49c596a3a89fa240642acd95dd3258e261eb09 +0 -0
  48. package/skills/.git 2/objects/50/9d42d8412ef8eaf7f7e138476bac2e4d10ce60 +0 -0
  49. package/skills/.git 2/objects/55/0c8c389d981b463ef849aeb792d8be3ccb6ec8 +0 -0
  50. package/skills/.git 2/objects/5d/82d3b18410cdda3ace3677436f0cb599dbe2d2 +0 -0
  51. package/skills/.git 2/objects/60/0617c58e871a38b33bf29e282d132bb3c381ad +0 -0
  52. package/skills/.git 2/objects/6a/8369a99c687b7245c92ffaf0e0f0dab9014504 +0 -0
  53. package/skills/.git 2/objects/79/bea435d40ab531c1aaf6be0432c6a5b7aaed21 +0 -0
  54. package/skills/.git 2/objects/7e/5ebd79251c2f14e4aceb86c74b6b6daae6b500 +0 -0
  55. package/skills/.git 2/objects/81/98a822a60178d6d5023ddb3e222cddf048742e +0 -0
  56. package/skills/.git 2/objects/86/0a0e1943dfe53411d2e499a1f16f46a96ef758 +0 -0
  57. package/skills/.git 2/objects/86/971fb55fdc081fdbae52376f0f13e57a4e9b04 +0 -0
  58. package/skills/.git 2/objects/88/b89dd609a0a03f8d4fe8bfde20d5b8fc1d326d +0 -0
  59. package/skills/.git 2/objects/90/8737edb6b7809e32cc01590b4e08ba42a9d40d +0 -0
  60. package/skills/.git 2/objects/93/d5a8a9a7d4fb7f11491cb596a6880528725118 +0 -0
  61. package/skills/.git 2/objects/98/46a2ab81d0c3b3eb00ef88fc56989aa7e9f316 +0 -0
  62. package/skills/.git 2/objects/9b/d8dd1e49cf274eaf9c555f3ab39dce7af5715e +0 -0
  63. package/skills/.git 2/objects/a1/13329fb0cec96ae78b222d33a24c3b5bc7fa1f +0 -0
  64. package/skills/.git 2/objects/a9/e6effe626e8a3aea3a8fc3364b492191c6e7d0 +0 -0
  65. package/skills/.git 2/objects/ad/6de7e48d9782cca9353d1ff0aa1aab7fe1df85 +0 -0
  66. package/skills/.git 2/objects/af/54ae316f771ff692e299ffcd8bf2f06b413b59 +0 -0
  67. package/skills/.git 2/objects/b0/4cb8b0b00dad633e731c1472161419e738d674 +0 -0
  68. package/skills/.git 2/objects/b3/094abb0b9ed46419b269e4a4e36a459690e3b0 +0 -0
  69. package/skills/.git 2/objects/b9/435c5d4baac2cfc5c83009ddd27b46b60db5f1 +0 -0
  70. package/skills/.git 2/objects/ba/5da17dbaec5ec2dcfdfd126aead518d1171d5c +0 -0
  71. package/skills/.git 2/objects/c0/bf58703aa258ba5dd63083bebaec8f223d844c +0 -0
  72. package/skills/.git 2/objects/c4/701a34edf1fc1bad58ccc57bd03f9426acb59a +0 -0
  73. package/skills/.git 2/objects/c7/5ccce9a4e5cc74d9b3174550cf6d993ca43638 +0 -0
  74. package/skills/.git 2/objects/c7/710d59b5a35b0f1f0a0399386643a0bd94c929 +0 -0
  75. package/skills/.git 2/objects/d1/fe58237112e953e5fec52da22cf38e08be3df9 +5 -0
  76. package/skills/.git 2/objects/d2/2bbe9fd2f74c95bc5583e803f5e435f1e2cd86 +0 -0
  77. package/skills/.git 2/objects/d7/e72852ea2bff74581dbf247d400120086229f4 +0 -0
  78. package/skills/.git 2/objects/d8/d4c3b5553e4fd72807e1d4b49ef07d9ef3ac35 +0 -0
  79. package/skills/.git 2/objects/dc/75050c2876f6a02ae2a53a3c886f395b622977 +0 -0
  80. package/skills/.git 2/objects/ee/e8546f95acec500187c08a28a8b9ee02db0dec +0 -0
  81. package/skills/.git 2/objects/ef/263c059208b416c2146434f10cb2b9fabcba16 +0 -0
  82. package/skills/.git 2/objects/f3/ae597e84d9a59b88acd21c99bde2eaf686d785 +0 -0
  83. package/skills/.git 2/objects/f3/f6f5673c821d3d8e76fa267a9e882e7a5387ea +0 -0
  84. package/skills/.git 2/objects/f9/6e6d0ad02624dd11d5848594d056caef7a5e8b +0 -0
  85. package/skills/.git 2/objects/ff/278988fc1edf0db3abcf18de795f4cc0b4f3e1 +0 -0
  86. package/skills/.git 2/refs/heads/main +1 -0
  87. package/skills/.git 2/refs/remotes/origin/main +1 -0
  88. package/skills/.pytest_cache 2/v/cache/nodeids +76 -0
  89. package/skills/.pytest_cache 2/v/cache/stepwise +1 -0
  90. package/skills/_shared/helpers.md +123 -0
  91. package/skills/_shared/outputs-convention.md +24 -0
  92. package/skills/cm-ads-tracker/SKILL.md +109 -0
  93. package/skills/cm-ads-tracker/evals/evals.json +55 -0
  94. package/skills/cm-ads-tracker/references/gtm-architecture.md +321 -0
  95. package/skills/cm-ads-tracker/references/industry-events.md +294 -0
  96. package/skills/cm-ads-tracker/references/platforms-api.md +238 -0
  97. package/skills/cm-ads-tracker/templates/capi-payload.md +79 -0
  98. package/skills/cm-ads-tracker/templates/datalayer-push.js +104 -0
  99. package/skills/cm-ads-tracker/templates/gtm-variables.js +56 -0
  100. package/skills/cm-brainstorm-idea/SKILL.md +423 -0
  101. package/skills/cm-code-review/SKILL.md +151 -0
  102. package/skills/cm-content-factory/SKILL.md +416 -0
  103. package/skills/cm-continuity/SKILL.md +399 -0
  104. package/skills/cm-dashboard/SKILL.md +533 -0
  105. package/skills/cm-dashboard/ui/app.js +1270 -0
  106. package/skills/cm-dashboard/ui/index.html +206 -0
  107. package/skills/cm-dashboard/ui/style.css +440 -0
  108. package/skills/cm-debugging/SKILL.md +412 -0
  109. package/skills/cm-deep-search/SKILL.md +242 -0
  110. package/skills/cm-design-system/SKILL.md +97 -0
  111. package/skills/cm-design-system/resources/halo-modern.md +40 -0
  112. package/skills/cm-design-system/resources/lunaris-advanced.md +40 -0
  113. package/skills/cm-design-system/resources/nitro-enterprise.md +39 -0
  114. package/skills/cm-design-system/resources/shadcn-default.md +37 -0
  115. package/skills/cm-dockit/README.md +100 -0
  116. package/skills/cm-dockit/SKILL.md +302 -0
  117. package/skills/cm-dockit/index.html +443 -0
  118. package/skills/cm-dockit/package-lock.json +1850 -0
  119. package/skills/cm-dockit/package.json +14 -0
  120. package/skills/cm-dockit/prompts/analysis.md +34 -0
  121. package/skills/cm-dockit/prompts/api-reference.md +24 -0
  122. package/skills/cm-dockit/prompts/architecture.md +21 -0
  123. package/skills/cm-dockit/prompts/data-flow.md +20 -0
  124. package/skills/cm-dockit/prompts/database.md +21 -0
  125. package/skills/cm-dockit/prompts/deployment.md +22 -0
  126. package/skills/cm-dockit/prompts/flows.md +21 -0
  127. package/skills/cm-dockit/prompts/jtbd.md +20 -0
  128. package/skills/cm-dockit/prompts/personas.md +24 -0
  129. package/skills/cm-dockit/prompts/sop-modules.md +40 -0
  130. package/skills/cm-dockit/scripts/doc-gen.sh +121 -0
  131. package/skills/cm-dockit/scripts/dockit-dashboard.sh +142 -0
  132. package/skills/cm-dockit/scripts/dockit-runner.sh +607 -0
  133. package/skills/cm-dockit/scripts/dockit-task.sh +166 -0
  134. package/skills/cm-dockit/skills/analyze-codebase.md +174 -0
  135. package/skills/cm-dockit/skills/api-reference.md +237 -0
  136. package/skills/cm-dockit/skills/changelog-guide.md +195 -0
  137. package/skills/cm-dockit/skills/content-guidelines.md +190 -0
  138. package/skills/cm-dockit/skills/sop-guide.md +184 -0
  139. package/skills/cm-dockit/skills/tech-docs.md +287 -0
  140. package/skills/cm-dockit/templates/markdown/structure.md +60 -0
  141. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/config.mts +110 -0
  142. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/custom.css +189 -0
  143. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/index.ts +4 -0
  144. package/skills/cm-dockit/templates/vitepress-premium/package.json +19 -0
  145. package/skills/cm-dockit/templates/vitepress-premium/tests/frontend.test.ts +45 -0
  146. package/skills/cm-dockit/tests/runner.test.ts +66 -0
  147. package/skills/cm-dockit/workflows/export-markdown.md +82 -0
  148. package/skills/cm-dockit/workflows/generate-docs.md +68 -0
  149. package/skills/cm-dockit/workflows/setup-vitepress.md +181 -0
  150. package/skills/cm-example/SKILL.md +26 -0
  151. package/skills/cm-execution/SKILL.md +268 -0
  152. package/skills/cm-git-worktrees/SKILL.md +164 -0
  153. package/skills/cm-how-it-work/SKILL.md +189 -0
  154. package/skills/cm-identity-guard/SKILL.md +412 -0
  155. package/skills/cm-jtbd/SKILL.md +98 -0
  156. package/skills/cm-planning/SKILL.md +130 -0
  157. package/skills/cm-project-bootstrap/SKILL.md +161 -0
  158. package/skills/cm-project-bootstrap/templates/AGENTS.md +42 -0
  159. package/skills/cm-project-bootstrap/templates/frontend-safety.test.js +51 -0
  160. package/skills/cm-project-bootstrap/templates/i18n-sync.test.js +38 -0
  161. package/skills/cm-project-bootstrap/templates/pr-template.md +12 -0
  162. package/skills/cm-project-bootstrap/templates/project-identity.json +29 -0
  163. package/skills/cm-project-bootstrap/templates/vitest.config.js +10 -0
  164. package/skills/cm-quality-gate/SKILL.md +218 -0
  165. package/skills/cm-readit/SKILL.md +289 -0
  166. package/skills/cm-readit/audio-player.md +206 -0
  167. package/skills/cm-readit/examples/blog-reader.js +352 -0
  168. package/skills/cm-readit/examples/voice-cro.js +390 -0
  169. package/skills/cm-readit/tts-engine.md +262 -0
  170. package/skills/cm-readit/ui-patterns.md +362 -0
  171. package/skills/cm-readit/voice-cro.md +223 -0
  172. package/skills/cm-safe-deploy/SKILL.md +120 -0
  173. package/skills/cm-safe-deploy/templates/deploy.sh +89 -0
  174. package/skills/cm-safe-i18n/SKILL.md +473 -0
  175. package/skills/cm-secret-shield/SKILL.md +580 -0
  176. package/skills/cm-skill-chain/SKILL.md +78 -0
  177. package/skills/cm-skill-index/SKILL.md +318 -0
  178. package/skills/cm-skill-mastery/SKILL.md +169 -0
  179. package/skills/cm-start/SKILL.md +65 -0
  180. package/skills/cm-status/SKILL.md +12 -0
  181. package/skills/cm-tdd/SKILL.md +370 -0
  182. package/skills/cm-terminal/SKILL.md +177 -0
  183. package/skills/cm-test-gate/SKILL.md +242 -0
  184. package/skills/cm-ui-preview/SKILL.md +291 -0
  185. package/skills/cm-ux-master/DESIGN_STANDARD_TEMPLATE.md +54 -0
  186. package/skills/cm-ux-master/SKILL.md +114 -0
  187. package/skills/cro-methodology/SKILL.md +98 -0
  188. package/skills/cro-methodology/references/COPYWRITING.md +178 -0
  189. package/skills/cro-methodology/references/OBJECTIONS.md +135 -0
  190. package/skills/cro-methodology/references/PERSUASION.md +158 -0
  191. package/skills/cro-methodology/references/RESEARCH.md +220 -0
  192. package/skills/cro-methodology/references/funnel-analysis.md +365 -0
  193. package/skills/cro-methodology/references/testing-methodology.md +330 -0
@@ -0,0 +1,607 @@
1
+ #!/bin/bash
2
+ # ============================================================
3
+ # DocKit Master v2 — Task Runner (Orchestrator)
4
+ # Manages parallel doc generation with progress tracking
5
+ # ============================================================
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ SKILL_DIR="$(dirname "$SCRIPT_DIR")"
10
+
11
+ # ── Colors ──────────────────────────────────────────────────
12
+ RED='\033[0;31m'; GREEN='\033[0;32m'; BLUE='\033[0;34m'
13
+ CYAN='\033[0;36m'; YELLOW='\033[1;33m'; MAGENTA='\033[0;35m'
14
+ BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
15
+
16
+ # ── Helpers ─────────────────────────────────────────────────
17
+ log() { echo -e "${DIM}$(date +%H:%M:%S)${NC} $1"; }
18
+ info() { log "${CYAN}ℹ${NC} $1"; }
19
+ ok() { log "${GREEN}✅${NC} $1"; }
20
+ warn() { log "${YELLOW}⚠️${NC} $1"; }
21
+ err() { log "${RED}❌${NC} $1"; }
22
+ step() { log "${MAGENTA}▶${NC} ${BOLD}$1${NC}"; }
23
+
24
+ # ── Banner ──────────────────────────────────────────────────
25
+ show_banner() {
26
+ echo ""
27
+ echo -e "${CYAN}╔══════════════════════════════════════════════════════╗${NC}"
28
+ echo -e "${CYAN}║${NC} ${BOLD}📚 DocKit Master v2 — Task Runner${NC} ${CYAN}║${NC}"
29
+ echo -e "${CYAN}║${NC} ${DIM}Progress tracking • Multi-threading • Resume${NC} ${CYAN}║${NC}"
30
+ echo -e "${CYAN}╚══════════════════════════════════════════════════════╝${NC}"
31
+ echo ""
32
+ }
33
+
34
+ # ── Usage ───────────────────────────────────────────────────
35
+ show_usage() {
36
+ show_banner
37
+ echo -e "${BOLD}Usage:${NC}"
38
+ echo " dockit-runner.sh [options]"
39
+ echo ""
40
+ echo -e "${BOLD}Options:${NC}"
41
+ echo " -p, --project PATH Project root path (required)"
42
+ echo " -t, --type TYPE Doc type: knowledge|tech|sop|api|all (default: all)"
43
+ echo " -f, --format FORMAT Output: markdown|astro (default: astro)"
44
+ echo " -l, --lang LANG Language: vi|en|vi+en (default: vi)"
45
+ echo " -j, --jobs N Max parallel tasks (default: 3)"
46
+ echo " --dry-run Show task plan without executing"
47
+ echo " --resume Resume from last _progress.json"
48
+ echo " --audit Audit draft docs and promote to final"
49
+ echo " --no-draft Skip draft, write directly to docs/"
50
+ echo " --engine ENGINE gemini|antigravity (default: gemini)"
51
+ echo " -h, --help Show this help"
52
+ echo ""
53
+ echo -e "${BOLD}Monitor Progress:${NC}"
54
+ echo " In a separate terminal, run:"
55
+ echo -e " ${GREEN}bash $SCRIPT_DIR/dockit-dashboard.sh /path/to/project${NC}"
56
+ echo ""
57
+ echo -e "${BOLD}Examples:${NC}"
58
+ echo " # Full docs for a project"
59
+ echo " dockit-runner.sh -p ./my-project -t all"
60
+ echo ""
61
+ echo " # Resume interrupted run"
62
+ echo " dockit-runner.sh -p ./my-project --resume"
63
+ echo ""
64
+ echo " # Audit and promote drafts"
65
+ echo " dockit-runner.sh -p ./my-project --audit"
66
+ }
67
+
68
+ # ── Default Config ──────────────────────────────────────────
69
+ PROJECT_PATH=""
70
+ DOC_TYPE="all"
71
+ FORMAT="astro"
72
+ LANGUAGE="vi"
73
+ MAX_JOBS=3
74
+ DRY_RUN=false
75
+ RESUME=false
76
+ AUDIT_MODE=false
77
+ NO_DRAFT=false
78
+ ENGINE="gemini"
79
+
80
+ # ── Parse Args ──────────────────────────────────────────────
81
+ while [[ $# -gt 0 ]]; do
82
+ case $1 in
83
+ -p|--project) PROJECT_PATH="$2"; shift 2 ;;
84
+ -t|--type) DOC_TYPE="$2"; shift 2 ;;
85
+ -f|--format) FORMAT="$2"; shift 2 ;;
86
+ -l|--lang) LANGUAGE="$2"; shift 2 ;;
87
+ -j|--jobs) MAX_JOBS="$2"; shift 2 ;;
88
+ --dry-run) DRY_RUN=true; shift ;;
89
+ --resume) RESUME=true; shift ;;
90
+ --audit) AUDIT_MODE=true; shift ;;
91
+ --no-draft) NO_DRAFT=true; shift ;;
92
+ --engine) ENGINE="$2"; shift 2 ;;
93
+ -h|--help) show_usage; exit 0 ;;
94
+ *) err "Unknown option: $1"; show_usage; exit 1 ;;
95
+ esac
96
+ done
97
+
98
+ # ── Validation ──────────────────────────────────────────────
99
+ if [[ -z "$PROJECT_PATH" ]]; then
100
+ show_usage
101
+ err "Project path is required (-p /path/to/project)"
102
+ exit 1
103
+ fi
104
+
105
+ PROJECT_PATH="$(cd "$PROJECT_PATH" 2>/dev/null && pwd)" || {
106
+ err "Directory not found: $PROJECT_PATH"
107
+ exit 1
108
+ }
109
+
110
+ PROJECT_NAME="$(basename "$PROJECT_PATH")"
111
+ DRAFT_DIR="$PROJECT_PATH/docs/_draft"
112
+ FINAL_DIR="$PROJECT_PATH/docs"
113
+ PROGRESS_FILE="$PROJECT_PATH/docs/_progress.json"
114
+ LOG_FILE="$PROJECT_PATH/docs/_dockit.log"
115
+
116
+ # ── Check Engine ────────────────────────────────────────────
117
+ check_engine() {
118
+ if [[ "$ENGINE" == "gemini" ]]; then
119
+ if ! command -v gemini &>/dev/null; then
120
+ warn "Gemini CLI not found. Install: npm install -g @anthropic-ai/gemini-cli"
121
+ warn "Falling back to prompt-copy mode."
122
+ ENGINE="prompt"
123
+ else
124
+ ok "Gemini CLI found: $(which gemini)"
125
+ fi
126
+ fi
127
+ }
128
+
129
+ # ── Progress JSON ───────────────────────────────────────────
130
+ init_progress() {
131
+ mkdir -p "$DRAFT_DIR" "$(dirname "$PROGRESS_FILE")"
132
+
133
+ if [[ "$RESUME" == true ]] && [[ -f "$PROGRESS_FILE" ]]; then
134
+ info "Resuming from existing progress file"
135
+ return
136
+ fi
137
+
138
+ cat > "$PROGRESS_FILE" << PJSON
139
+ {
140
+ "project": "$PROJECT_NAME",
141
+ "project_path": "$PROJECT_PATH",
142
+ "started_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
143
+ "config": {
144
+ "type": "$DOC_TYPE",
145
+ "format": "$FORMAT",
146
+ "language": "$LANGUAGE",
147
+ "engine": "$ENGINE",
148
+ "max_jobs": $MAX_JOBS
149
+ },
150
+ "tasks": [],
151
+ "stats": { "total": 0, "done": 0, "running": 0, "pending": 0, "failed": 0 }
152
+ }
153
+ PJSON
154
+ ok "Progress file initialized: $PROGRESS_FILE"
155
+ }
156
+
157
+ # Update a task in _progress.json (uses temp file for atomicity)
158
+ update_task() {
159
+ local task_id="$1"
160
+ local status="$2"
161
+ local extra="${3:-}" # optional JSON fields
162
+
163
+ local now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
164
+ local tmp="$PROGRESS_FILE.tmp"
165
+
166
+ # Use Python for JSON manipulation (available on macOS)
167
+ python3 -c "
168
+ import json, sys
169
+ with open('$PROGRESS_FILE', 'r') as f:
170
+ data = json.load(f)
171
+
172
+ found = False
173
+ for t in data['tasks']:
174
+ if t['id'] == '$task_id':
175
+ t['status'] = '$status'
176
+ if '$status' == 'running':
177
+ t['started_at'] = '$now'
178
+ elif '$status' in ('done', 'failed'):
179
+ t['completed_at'] = '$now'
180
+ if '$status' == 'failed' and '$extra':
181
+ t['error'] = '$extra'
182
+ t['attempts'] = t.get('attempts', 0) + (1 if '$status' == 'running' else 0)
183
+ found = True
184
+ break
185
+
186
+ # Recount stats
187
+ stats = {'total': len(data['tasks']), 'done': 0, 'running': 0, 'pending': 0, 'failed': 0}
188
+ for t in data['tasks']:
189
+ s = t.get('status', 'pending')
190
+ if s in stats:
191
+ stats[s] += 1
192
+ data['stats'] = stats
193
+
194
+ with open('$tmp', 'w') as f:
195
+ json.dump(data, f, indent=2)
196
+ " 2>/dev/null && mv "$tmp" "$PROGRESS_FILE"
197
+ }
198
+
199
+ # Add a task to _progress.json
200
+ add_task() {
201
+ local task_id="$1"
202
+ local label="$2"
203
+ local output_file="$3"
204
+ local depends="${4:-}"
205
+
206
+ python3 -c "
207
+ import json
208
+ with open('$PROGRESS_FILE', 'r') as f:
209
+ data = json.load(f)
210
+
211
+ # Skip if already exists
212
+ if any(t['id'] == '$task_id' for t in data['tasks']):
213
+ pass
214
+ else:
215
+ data['tasks'].append({
216
+ 'id': '$task_id',
217
+ 'label': '$label',
218
+ 'status': 'pending',
219
+ 'output_file': '$output_file',
220
+ 'depends_on': '$depends' if '$depends' else None,
221
+ 'started_at': None,
222
+ 'completed_at': None,
223
+ 'attempts': 0,
224
+ 'error': None
225
+ })
226
+ data['stats']['total'] = len(data['tasks'])
227
+ data['stats']['pending'] = sum(1 for t in data['tasks'] if t['status'] == 'pending')
228
+
229
+ with open('$PROGRESS_FILE', 'w') as f:
230
+ json.dump(data, f, indent=2)
231
+ " 2>/dev/null
232
+ }
233
+
234
+ # ── Task Planning ───────────────────────────────────────────
235
+ plan_tasks() {
236
+ step "Planning tasks for type=$DOC_TYPE"
237
+
238
+ local output_base="$DRAFT_DIR"
239
+ [[ "$NO_DRAFT" == true ]] && output_base="$FINAL_DIR"
240
+
241
+ # Phase 0: Always analyze
242
+ add_task "analysis" "📊 Codebase Analysis" "$output_base/analysis.md" ""
243
+
244
+ if [[ "$DOC_TYPE" == "knowledge" || "$DOC_TYPE" == "all" ]]; then
245
+ add_task "personas" "👥 Personas" "$output_base/personas/index.md" "analysis"
246
+ add_task "jtbd" "🎯 JTBD Canvases" "$output_base/jtbd/index.md" "analysis"
247
+ add_task "flows" "🔄 Process Flows" "$output_base/flows/index.md" "analysis"
248
+ fi
249
+
250
+ if [[ "$DOC_TYPE" == "tech" || "$DOC_TYPE" == "all" ]]; then
251
+ add_task "architecture" "🏗️ Architecture" "$output_base/architecture.md" "analysis"
252
+ add_task "database" "🗄️ Database Schema" "$output_base/database.md" "analysis"
253
+ add_task "deployment" "🚀 Deployment Guide" "$output_base/deployment.md" "analysis"
254
+ add_task "data-flow" "📡 Data Flow" "$output_base/data-flow.md" "analysis"
255
+ fi
256
+
257
+ if [[ "$DOC_TYPE" == "sop" || "$DOC_TYPE" == "all" ]]; then
258
+ # SOPs depend on knowledge being done first
259
+ local sop_dep="analysis"
260
+ [[ "$DOC_TYPE" == "all" ]] && sop_dep="personas"
261
+ add_task "sop-index" "📋 SOP Index" "$output_base/sop/index.md" "$sop_dep"
262
+ # Individual SOPs will be discovered from codebase analysis
263
+ add_task "sop-modules" "📋 SOP Modules (batch)" "$output_base/sop/" "$sop_dep"
264
+ fi
265
+
266
+ if [[ "$DOC_TYPE" == "api" || "$DOC_TYPE" == "all" ]]; then
267
+ add_task "api-reference" "📡 API Reference" "$output_base/api/index.md" "analysis"
268
+ fi
269
+
270
+ if [[ "$FORMAT" == "astro" ]]; then
271
+ add_task "astro-site" "⭐ Astro Starlight Site" "$PROJECT_PATH/docs-site/" "sop-modules,api-reference"
272
+ fi
273
+
274
+ local total
275
+ total=$(python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); print(d['stats']['total'])")
276
+ ok "Planned $total tasks"
277
+ }
278
+
279
+ # ── Task Execution ──────────────────────────────────────────
280
+ run_task() {
281
+ local task_id="$1"
282
+
283
+ # Get task info
284
+ local task_label task_output task_status
285
+ task_label=$(python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); t=[x for x in d['tasks'] if x['id']=='$task_id'][0]; print(t['label'])")
286
+ task_output=$(python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); t=[x for x in d['tasks'] if x['id']=='$task_id'][0]; print(t['output_file'])")
287
+ task_status=$(python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); t=[x for x in d['tasks'] if x['id']=='$task_id'][0]; print(t['status'])")
288
+
289
+ # Skip already done tasks (for resume)
290
+ if [[ "$task_status" == "done" ]]; then
291
+ info "Skipping $task_id (already done)"
292
+ return 0
293
+ fi
294
+
295
+ step "[$task_id] $task_label"
296
+ update_task "$task_id" "running"
297
+
298
+ # Create output directory
299
+ mkdir -p "$(dirname "$task_output")"
300
+
301
+ # Run via dockit-task.sh
302
+ if bash "$SCRIPT_DIR/dockit-task.sh" \
303
+ --task-id "$task_id" \
304
+ --project "$PROJECT_PATH" \
305
+ --output "$task_output" \
306
+ --engine "$ENGINE" \
307
+ --skill-dir "$SKILL_DIR" \
308
+ --language "$LANGUAGE" \
309
+ >> "$LOG_FILE" 2>&1; then
310
+
311
+ update_task "$task_id" "done"
312
+ ok "[$task_id] ✓ Completed → $(basename "$task_output")"
313
+ return 0
314
+ else
315
+ local exit_code=$?
316
+ update_task "$task_id" "failed" "exit_code=$exit_code"
317
+ err "[$task_id] ✗ Failed (exit $exit_code). Check: $LOG_FILE"
318
+ return 1
319
+ fi
320
+ }
321
+
322
+ # Get tasks ready to run (pending + all deps done)
323
+ get_ready_tasks() {
324
+ python3 -c "
325
+ import json
326
+ with open('$PROGRESS_FILE', 'r') as f:
327
+ data = json.load(f)
328
+
329
+ done_ids = {t['id'] for t in data['tasks'] if t['status'] == 'done'}
330
+
331
+ for t in data['tasks']:
332
+ if t['status'] != 'pending':
333
+ continue
334
+ deps = t.get('depends_on') or ''
335
+ dep_ids = [d.strip() for d in deps.split(',') if d.strip()]
336
+ if all(d in done_ids for d in dep_ids):
337
+ print(t['id'])
338
+ " 2>/dev/null
339
+ }
340
+
341
+ # Count running tasks
342
+ count_running() {
343
+ python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); print(sum(1 for t in d['tasks'] if t['status']=='running'))" 2>/dev/null
344
+ }
345
+
346
+ # Check if all done
347
+ all_done() {
348
+ python3 -c "
349
+ import json
350
+ d = json.load(open('$PROGRESS_FILE'))
351
+ pending = sum(1 for t in d['tasks'] if t['status'] in ('pending', 'running'))
352
+ print('yes' if pending == 0 else 'no')
353
+ " 2>/dev/null
354
+ }
355
+
356
+ # ── Parallel Execution Loop ────────────────────────────────
357
+ run_all_tasks() {
358
+ step "Starting execution (max $MAX_JOBS parallel)"
359
+ echo "" >> "$LOG_FILE"
360
+ echo "═══ DocKit Master v2 — Run started $(date) ═══" >> "$LOG_FILE"
361
+
362
+ local pids=()
363
+ local pid_tasks=()
364
+
365
+ while true; do
366
+ # Reap finished background jobs
367
+ local new_pids=()
368
+ local new_pid_tasks=()
369
+ for i in "${!pids[@]}"; do
370
+ if kill -0 "${pids[$i]}" 2>/dev/null; then
371
+ new_pids+=("${pids[$i]}")
372
+ new_pid_tasks+=("${pid_tasks[$i]}")
373
+ fi
374
+ done
375
+ pids=("${new_pids[@]:-}")
376
+ pid_tasks=("${new_pid_tasks[@]:-}")
377
+
378
+ # Check if all done
379
+ if [[ "$(all_done)" == "yes" ]]; then
380
+ break
381
+ fi
382
+
383
+ # Launch ready tasks up to MAX_JOBS
384
+ local running="${#pids[@]}"
385
+ if (( running < MAX_JOBS )); then
386
+ local ready_tasks
387
+ ready_tasks=$(get_ready_tasks)
388
+
389
+ for task_id in $ready_tasks; do
390
+ if (( ${#pids[@]} >= MAX_JOBS )); then
391
+ break
392
+ fi
393
+
394
+ run_task "$task_id" &
395
+ local pid=$!
396
+ pids+=("$pid")
397
+ pid_tasks+=("$task_id")
398
+ info "Launched [$task_id] (PID $pid)"
399
+ done
400
+ fi
401
+
402
+ # If nothing ready and nothing running, we might be stuck
403
+ if [[ -z "$(get_ready_tasks)" ]] && (( ${#pids[@]} == 0 )); then
404
+ local has_failed
405
+ has_failed=$(python3 -c "import json; d=json.load(open('$PROGRESS_FILE')); print('yes' if any(t['status']=='failed' for t in d['tasks']) else 'no')")
406
+ if [[ "$has_failed" == "yes" ]]; then
407
+ err "Some tasks failed and are blocking others. Run with --resume to retry."
408
+ break
409
+ fi
410
+ fi
411
+
412
+ sleep 2
413
+ done
414
+
415
+ # Wait for all remaining
416
+ for pid in "${pids[@]}"; do
417
+ wait "$pid" 2>/dev/null || true
418
+ done
419
+ }
420
+
421
+ # ── Audit Mode ──────────────────────────────────────────────
422
+ run_audit() {
423
+ step "Auditing draft documents"
424
+
425
+ if [[ ! -d "$DRAFT_DIR" ]]; then
426
+ err "No draft directory found: $DRAFT_DIR"
427
+ exit 1
428
+ fi
429
+
430
+ local count=0
431
+ while IFS= read -r file; do
432
+ count=$((count + 1))
433
+ done < <(find "$DRAFT_DIR" -name "*.md" -type f 2>/dev/null)
434
+
435
+ info "Found $count draft files"
436
+ echo ""
437
+ echo -e "${BOLD}Draft files:${NC}"
438
+ find "$DRAFT_DIR" -name "*.md" -type f | sort | while read -r f; do
439
+ local size
440
+ size=$(wc -c < "$f" | tr -d ' ')
441
+ local rel="${f#"$DRAFT_DIR/"}"
442
+ echo -e " ${GREEN}✓${NC} $rel ${DIM}(${size}B)${NC}"
443
+ done
444
+
445
+ echo ""
446
+ echo -e "${YELLOW}Review the files in: $DRAFT_DIR${NC}"
447
+ echo ""
448
+ read -p "$(echo -e "${BLUE}Promote all drafts to final? [y/N]:${NC} ")" confirm
449
+
450
+ if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
451
+ step "Promoting drafts to final"
452
+ # Copy while preserving structure (skip _draft and _progress files)
453
+ find "$DRAFT_DIR" -name "*.md" -type f | while read -r f; do
454
+ local rel="${f#"$DRAFT_DIR/"}"
455
+ local dest="$FINAL_DIR/$rel"
456
+ mkdir -p "$(dirname "$dest")"
457
+ cp "$f" "$dest"
458
+ ok " $rel"
459
+ done
460
+ ok "All drafts promoted to docs/"
461
+ else
462
+ info "Cancelled. Drafts remain in _draft/"
463
+ fi
464
+ }
465
+
466
+ # ── Dry Run ─────────────────────────────────────────────────
467
+ show_dry_run() {
468
+ echo ""
469
+ echo -e "${BOLD}📋 Task Plan (dry-run):${NC}"
470
+ echo ""
471
+
472
+ python3 -c "
473
+ import json
474
+ with open('$PROGRESS_FILE', 'r') as f:
475
+ data = json.load(f)
476
+
477
+ print(f' Project: {data[\"project\"]}')
478
+ print(f' Type: {data[\"config\"][\"type\"]}')
479
+ print(f' Format: {data[\"config\"][\"format\"]}')
480
+ print(f' Language: {data[\"config\"][\"language\"]}')
481
+ print(f' Engine: {data[\"config\"][\"engine\"]}')
482
+ print(f' Jobs: {data[\"config\"][\"max_jobs\"]}')
483
+ print()
484
+
485
+ # Build dependency graph
486
+ done_ids = set()
487
+ waves = []
488
+ tasks_by_id = {t['id']: t for t in data['tasks']}
489
+ remaining = list(data['tasks'])
490
+
491
+ while remaining:
492
+ wave = []
493
+ for t in remaining:
494
+ deps = [d.strip() for d in (t.get('depends_on') or '').split(',') if d.strip()]
495
+ if all(d in done_ids for d in deps):
496
+ wave.append(t)
497
+ if not wave:
498
+ break
499
+ waves.append(wave)
500
+ for t in wave:
501
+ done_ids.add(t['id'])
502
+ remaining.remove(t)
503
+
504
+ for i, wave in enumerate(waves):
505
+ parallel = '∥' if len(wave) > 1 else '→'
506
+ print(f' Wave {i+1} ({parallel} {len(wave)} tasks):')
507
+ for t in wave:
508
+ deps = t.get('depends_on') or '-'
509
+ print(f' {t[\"label\"]:30s} deps={deps}')
510
+ print()
511
+
512
+ print(f' Total: {len(data[\"tasks\"])} tasks in {len(waves)} waves')
513
+ " 2>/dev/null
514
+
515
+ echo ""
516
+ echo -e "${DIM}Run without --dry-run to execute.${NC}"
517
+ }
518
+
519
+ # ── Show Pre-run Guide ──────────────────────────────────────
520
+ show_monitor_guide() {
521
+ echo ""
522
+ echo -e "${CYAN}━━━ 📊 Cách theo dõi tiến trình ━━━${NC}"
523
+ echo ""
524
+ echo -e " ${BOLD}1.${NC} Mở terminal mới và chạy dashboard:"
525
+ echo -e " ${GREEN}bash $SCRIPT_DIR/dockit-dashboard.sh $PROJECT_PATH${NC}"
526
+ echo ""
527
+ echo -e " ${BOLD}2.${NC} Hoặc xem log trực tiếp:"
528
+ echo -e " ${GREEN}tail -f $LOG_FILE${NC}"
529
+ echo ""
530
+ echo -e " ${BOLD}3.${NC} Xem progress JSON:"
531
+ echo -e " ${GREEN}cat $PROGRESS_FILE | python3 -m json.tool${NC}"
532
+ echo ""
533
+ echo -e " ${BOLD}4.${NC} Nếu bị ngắt giữa chừng, resume bằng:"
534
+ echo -e " ${GREEN}bash $SCRIPT_DIR/dockit-runner.sh -p $PROJECT_PATH --resume${NC}"
535
+ echo ""
536
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
537
+ echo ""
538
+ }
539
+
540
+ # ── Print Summary ───────────────────────────────────────────
541
+ show_summary() {
542
+ echo ""
543
+ echo -e "${CYAN}━━━ 📊 Summary ━━━${NC}"
544
+ python3 -c "
545
+ import json
546
+ with open('$PROGRESS_FILE', 'r') as f:
547
+ data = json.load(f)
548
+ s = data['stats']
549
+ print(f' ✅ Done: {s[\"done\"]}')
550
+ print(f' ❌ Failed: {s[\"failed\"]}')
551
+ print(f' 📊 Total: {s[\"total\"]}')
552
+ print()
553
+ for t in data['tasks']:
554
+ icon = {'done':'✅','failed':'❌','running':'⏳','pending':'⏸️'}.get(t['status'],'❓')
555
+ print(f' {icon} {t[\"label\"]:30s} {t[\"status\"]}')
556
+ " 2>/dev/null
557
+ echo ""
558
+
559
+ if [[ "$NO_DRAFT" == false ]]; then
560
+ echo -e " 📁 Draft files: ${GREEN}$DRAFT_DIR${NC}"
561
+ echo -e " Run ${GREEN}--audit${NC} to review and promote to final."
562
+ fi
563
+ echo -e " 📋 Progress: ${GREEN}$PROGRESS_FILE${NC}"
564
+ echo -e " 📝 Log: ${GREEN}$LOG_FILE${NC}"
565
+ echo ""
566
+ }
567
+
568
+ # ═══════════════════════════════════════════════════════════
569
+ # MAIN
570
+ # ═══════════════════════════════════════════════════════════
571
+
572
+ show_banner
573
+
574
+ # Handle audit mode
575
+ if [[ "$AUDIT_MODE" == true ]]; then
576
+ run_audit
577
+ exit 0
578
+ fi
579
+
580
+ # Setup
581
+ check_engine
582
+ init_progress
583
+ plan_tasks
584
+
585
+ # Dry run?
586
+ if [[ "$DRY_RUN" == true ]]; then
587
+ show_dry_run
588
+ exit 0
589
+ fi
590
+
591
+ # Show monitoring guide
592
+ show_monitor_guide
593
+
594
+ # Confirm
595
+ read -p "$(echo -e "${BLUE}Start generating documentation? [Y/n]:${NC} ")" start_confirm
596
+ if [[ "$start_confirm" == "n" || "$start_confirm" == "N" ]]; then
597
+ info "Cancelled."
598
+ exit 0
599
+ fi
600
+
601
+ # Execute
602
+ echo ""
603
+ step "Starting DocKit Master v2..."
604
+ echo ""
605
+
606
+ run_all_tasks
607
+ show_summary