@nlaprell/shipit 1.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 (160) hide show
  1. package/.cursor/commands/create_intent_from_issue.md +28 -0
  2. package/.cursor/commands/create_pr.md +28 -0
  3. package/.cursor/commands/dashboard.md +39 -0
  4. package/.cursor/commands/deploy.md +152 -0
  5. package/.cursor/commands/drift_check.md +36 -0
  6. package/.cursor/commands/fix.md +39 -0
  7. package/.cursor/commands/generate_release_plan.md +31 -0
  8. package/.cursor/commands/generate_roadmap.md +38 -0
  9. package/.cursor/commands/help.md +37 -0
  10. package/.cursor/commands/init_project.md +26 -0
  11. package/.cursor/commands/kill.md +72 -0
  12. package/.cursor/commands/new_intent.md +68 -0
  13. package/.cursor/commands/pr.md +77 -0
  14. package/.cursor/commands/revert-plan.md +58 -0
  15. package/.cursor/commands/risk.md +64 -0
  16. package/.cursor/commands/rollback.md +43 -0
  17. package/.cursor/commands/scope_project.md +53 -0
  18. package/.cursor/commands/ship.md +345 -0
  19. package/.cursor/commands/status.md +71 -0
  20. package/.cursor/commands/suggest.md +44 -0
  21. package/.cursor/commands/test_shipit.md +197 -0
  22. package/.cursor/commands/verify.md +50 -0
  23. package/.cursor/rules/architect.mdc +84 -0
  24. package/.cursor/rules/assumption-extractor.mdc +95 -0
  25. package/.cursor/rules/docs.mdc +66 -0
  26. package/.cursor/rules/implementer.mdc +112 -0
  27. package/.cursor/rules/pm.mdc +136 -0
  28. package/.cursor/rules/qa.mdc +97 -0
  29. package/.cursor/rules/security.mdc +90 -0
  30. package/.cursor/rules/steward.mdc +99 -0
  31. package/.cursor/rules/test-runner.mdc +196 -0
  32. package/AGENTS.md +121 -0
  33. package/README.md +264 -0
  34. package/_system/architecture/CANON.md +159 -0
  35. package/_system/architecture/invariants.yml +87 -0
  36. package/_system/architecture/project-schema.json +98 -0
  37. package/_system/architecture/workflow-state-layout.md +68 -0
  38. package/_system/artifacts/SYSTEM_STATE.md +43 -0
  39. package/_system/artifacts/confidence-calibration.json +16 -0
  40. package/_system/artifacts/dependencies.md +46 -0
  41. package/_system/artifacts/framework-files-manifest.json +179 -0
  42. package/_system/artifacts/usage.json +1 -0
  43. package/_system/behaviors/DO_RELEASE.md +371 -0
  44. package/_system/behaviors/DO_RELEASE_AI.md +329 -0
  45. package/_system/behaviors/PREPARE_RELEASE.md +373 -0
  46. package/_system/behaviors/PREPARE_RELEASE_AI.md +234 -0
  47. package/_system/behaviors/WORK_ROOT_PLATFORM_ISSUES.md +140 -0
  48. package/_system/behaviors/WORK_TEST_PLAN_ISSUES.md +380 -0
  49. package/_system/do-not-repeat/abandoned-designs.md +18 -0
  50. package/_system/do-not-repeat/bad-patterns.md +19 -0
  51. package/_system/do-not-repeat/failed-experiments.md +18 -0
  52. package/_system/do-not-repeat/rejected-libraries.md +19 -0
  53. package/_system/drift/baselines.md +49 -0
  54. package/_system/drift/metrics.md +33 -0
  55. package/_system/golden-data/.gitkeep +0 -0
  56. package/_system/golden-data/README.md +47 -0
  57. package/_system/reports/mutation/mutation.html +492 -0
  58. package/_system/security/audit-allowlist.json +4 -0
  59. package/bin/create-shipit-app +29 -0
  60. package/bin/shipit +183 -0
  61. package/cli/src/commands/check.js +82 -0
  62. package/cli/src/commands/create.js +195 -0
  63. package/cli/src/commands/init.js +267 -0
  64. package/cli/src/commands/upgrade.js +196 -0
  65. package/cli/src/utils/config.js +27 -0
  66. package/cli/src/utils/file-copy.js +144 -0
  67. package/cli/src/utils/gitignore-merge.js +44 -0
  68. package/cli/src/utils/manifest.js +105 -0
  69. package/cli/src/utils/package-json-merge.js +163 -0
  70. package/cli/src/utils/project-json-merge.js +57 -0
  71. package/cli/src/utils/prompts.js +30 -0
  72. package/cli/src/utils/stack-detection.js +56 -0
  73. package/cli/src/utils/stack-files.js +364 -0
  74. package/cli/src/utils/upgrade-backup.js +159 -0
  75. package/cli/src/utils/version.js +64 -0
  76. package/dashboard-app/README.md +73 -0
  77. package/dashboard-app/eslint.config.js +23 -0
  78. package/dashboard-app/index.html +13 -0
  79. package/dashboard-app/package.json +30 -0
  80. package/dashboard-app/pnpm-lock.yaml +2721 -0
  81. package/dashboard-app/public/dashboard.json +66 -0
  82. package/dashboard-app/public/vite.svg +1 -0
  83. package/dashboard-app/src/App.css +141 -0
  84. package/dashboard-app/src/App.tsx +155 -0
  85. package/dashboard-app/src/assets/react.svg +1 -0
  86. package/dashboard-app/src/index.css +68 -0
  87. package/dashboard-app/src/main.tsx +10 -0
  88. package/dashboard-app/tsconfig.app.json +28 -0
  89. package/dashboard-app/tsconfig.json +4 -0
  90. package/dashboard-app/tsconfig.node.json +26 -0
  91. package/dashboard-app/vite.config.ts +7 -0
  92. package/package.json +116 -0
  93. package/scripts/README.md +70 -0
  94. package/scripts/audit-check.sh +125 -0
  95. package/scripts/calibration-report.sh +198 -0
  96. package/scripts/check-readiness.sh +155 -0
  97. package/scripts/collect-metrics.sh +116 -0
  98. package/scripts/command-manifest.yml +131 -0
  99. package/scripts/create-test-plan-issue.sh +110 -0
  100. package/scripts/dashboard-start.sh +16 -0
  101. package/scripts/deploy.sh +170 -0
  102. package/scripts/drift-check.sh +93 -0
  103. package/scripts/execute-rollback.sh +177 -0
  104. package/scripts/export-dashboard-json.js +208 -0
  105. package/scripts/fix-intents.sh +239 -0
  106. package/scripts/generate-dashboard.sh +136 -0
  107. package/scripts/generate-docs.sh +279 -0
  108. package/scripts/generate-project-context.sh +142 -0
  109. package/scripts/generate-release-plan.sh +443 -0
  110. package/scripts/generate-roadmap.sh +189 -0
  111. package/scripts/generate-system-state.sh +95 -0
  112. package/scripts/gh/create-intent-from-issue.sh +82 -0
  113. package/scripts/gh/create-issue-from-intent.sh +59 -0
  114. package/scripts/gh/create-pr.sh +41 -0
  115. package/scripts/gh/link-issue.sh +44 -0
  116. package/scripts/gh/on-ship-update-issue.sh +42 -0
  117. package/scripts/headless/README.md +8 -0
  118. package/scripts/headless/call-llm.js +109 -0
  119. package/scripts/headless/run-phase.sh +99 -0
  120. package/scripts/help.sh +271 -0
  121. package/scripts/init-project.sh +976 -0
  122. package/scripts/kill-intent.sh +125 -0
  123. package/scripts/lib/common.sh +29 -0
  124. package/scripts/lib/intent.sh +61 -0
  125. package/scripts/lib/progress.sh +57 -0
  126. package/scripts/lib/suggest-next.sh +131 -0
  127. package/scripts/lib/validate-intents.sh +240 -0
  128. package/scripts/lib/verify-outputs.sh +55 -0
  129. package/scripts/lib/workflow_state.sh +201 -0
  130. package/scripts/new-intent.sh +271 -0
  131. package/scripts/publish-npm.sh +28 -0
  132. package/scripts/scope-project.sh +380 -0
  133. package/scripts/setup-worktrees.sh +125 -0
  134. package/scripts/status.sh +278 -0
  135. package/scripts/suggest.sh +173 -0
  136. package/scripts/test-headless.sh +47 -0
  137. package/scripts/test-shipit.sh +52 -0
  138. package/scripts/test-workflow-state.sh +49 -0
  139. package/scripts/usage-report.sh +47 -0
  140. package/scripts/usage.sh +58 -0
  141. package/scripts/validate-cursor.sh +151 -0
  142. package/scripts/validate-project.sh +71 -0
  143. package/scripts/validate-vscode.sh +146 -0
  144. package/scripts/verify.sh +153 -0
  145. package/scripts/workflow-orchestrator.sh +97 -0
  146. package/scripts/workflow-templates/01_analysis.md.tpl +25 -0
  147. package/scripts/workflow-templates/02_plan.md.tpl +30 -0
  148. package/scripts/workflow-templates/03_implementation.md.tpl +25 -0
  149. package/scripts/workflow-templates/04_verification.md.tpl +29 -0
  150. package/scripts/workflow-templates/05_release_notes.md.tpl +16 -0
  151. package/scripts/workflow-templates/05_verification_legacy.md.tpl +6 -0
  152. package/scripts/workflow-templates/active.md.tpl +18 -0
  153. package/scripts/workflow-templates/phases.yml +39 -0
  154. package/stryker.conf.json +8 -0
  155. package/work/intent/templates/api-endpoint.md +124 -0
  156. package/work/intent/templates/bugfix.md +116 -0
  157. package/work/intent/templates/frontend-feature.md +115 -0
  158. package/work/intent/templates/generic.md +122 -0
  159. package/work/intent/templates/infra-change.md +121 -0
  160. package/work/intent/templates/refactor.md +116 -0
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Export dashboard JSON for the React dashboard.
4
+ * Reads: work/intent/, work/workflow-state/, _system/artifacts/, _system/drift/
5
+ * Layout: Supports both flat and per-intent workflow-state per workflow-state-layout.md
6
+ * Output: dashboard-app/public/dashboard.json
7
+ */
8
+
9
+ import {
10
+ readFileSync,
11
+ readdirSync,
12
+ existsSync,
13
+ writeFileSync,
14
+ mkdirSync,
15
+ } from "node:fs";
16
+ import { join, dirname } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { execSync } from "node:child_process";
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const REPO_ROOT = join(__dirname, "..");
22
+
23
+ function readText(path) {
24
+ try {
25
+ return readFileSync(path, "utf-8");
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ function readJson(path) {
32
+ const text = readText(path);
33
+ if (!text) return null;
34
+ try {
35
+ return JSON.parse(text);
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function findIntentFiles(dir, files = []) {
42
+ if (!existsSync(dir)) return files;
43
+ const entries = readdirSync(dir, { withFileTypes: true });
44
+ for (const e of entries) {
45
+ const p = join(dir, e.name);
46
+ if (e.isDirectory()) {
47
+ if (e.name !== "templates") findIntentFiles(p, files);
48
+ } else if (e.name.endsWith(".md") && e.name !== "_TEMPLATE.md") {
49
+ files.push(p);
50
+ }
51
+ }
52
+ return files;
53
+ }
54
+
55
+ function parseIntentStatus(content) {
56
+ const m = content.match(/##\s*Status\s*\n\s*(\w+)/i);
57
+ return m ? m[1].toLowerCase() : "unknown";
58
+ }
59
+
60
+ function getIntentId(path) {
61
+ const base = path.split(/[/\\]/).pop() || "";
62
+ return base.replace(/\.md$/, "");
63
+ }
64
+
65
+ function collectIntents() {
66
+ const intentDir = join(REPO_ROOT, "work", "intent");
67
+ const files = findIntentFiles(intentDir);
68
+ const intents = [];
69
+ for (const f of files) {
70
+ const content = readText(f);
71
+ if (!content) continue;
72
+ const status = parseIntentStatus(content);
73
+ const id = getIntentId(f);
74
+ intents.push({ id, status });
75
+ }
76
+ const byStatus = { planned: 0, active: 0, shipped: 0, killed: 0 };
77
+ for (const i of intents) {
78
+ if (i.status in byStatus) byStatus[i.status]++;
79
+ }
80
+ return { intents, counts: byStatus };
81
+ }
82
+
83
+ function getWorkflowState() {
84
+ const flatActive = join(REPO_ROOT, "work", "workflow-state", "active.md");
85
+ const content = readText(flatActive);
86
+ let currentPhase = "none";
87
+ let activeIntent = "none";
88
+ const activeIntents = [];
89
+ let waitingForApproval = false;
90
+
91
+ const workflowDir = join(REPO_ROOT, "work", "workflow-state");
92
+ if (!existsSync(workflowDir)) {
93
+ return { currentPhase, activeIntent, activeIntents, waitingForApproval };
94
+ }
95
+
96
+ if (content) {
97
+ const phaseM = content.match(/Current Phase:\s*(\S+)/i);
98
+ const idM = content.match(/Intent ID:\s*(\S+)/i);
99
+ if (phaseM) currentPhase = phaseM[1];
100
+ if (idM && idM[1] !== "none") {
101
+ activeIntent = idM[1];
102
+ activeIntents.push(idM[1]);
103
+ }
104
+ // Multi-intent: parse "## Active intents" block (lines like "F-001 | Phase | active")
105
+ const activeSection = content.match(/##\s+Active intents\s*\n([\s\S]*?)(?=\n##|$)/i);
106
+ if (activeSection && activeSection[1]) {
107
+ const lines = activeSection[1].split("\n");
108
+ for (const line of lines) {
109
+ const m = line.match(/^(F-\d+|B-\d+|T-\d+)\s*\|/);
110
+ if (m && !activeIntents.includes(m[1])) activeIntents.push(m[1]);
111
+ }
112
+ if (activeIntents.length > 0 && activeIntent === "none")
113
+ activeIntent = activeIntents[0];
114
+ if (activeIntents.length > 1) currentPhase = "multiple";
115
+ }
116
+ waitingForApproval = /waiting|approval|gate/i.test(content);
117
+ }
118
+
119
+ return { currentPhase, activeIntent, activeIntents, waitingForApproval };
120
+ }
121
+
122
+ function getCalibration() {
123
+ try {
124
+ const out = execSync("pnpm calibration-report --json", {
125
+ cwd: REPO_ROOT,
126
+ encoding: "utf-8",
127
+ });
128
+ return JSON.parse(out);
129
+ } catch {
130
+ return { decisions_count: 0, message: "No calibration data" };
131
+ }
132
+ }
133
+
134
+ function getDocLinks() {
135
+ const base = REPO_ROOT;
136
+ const links = [];
137
+ const candidates = [
138
+ ["_system/artifacts/SYSTEM_STATE.md", "System State"],
139
+ ["work/release/plan.md", "Release Plan"],
140
+ ["work/roadmap/now.md", "Roadmap (Now)"],
141
+ ["work/roadmap/next.md", "Roadmap (Next)"],
142
+ ["work/roadmap/later.md", "Roadmap (Later)"],
143
+ ["_system/drift/metrics.md", "Drift Metrics"],
144
+ ["_system/artifacts/dependencies.md", "Dependencies"],
145
+ ];
146
+ for (const [rel, label] of candidates) {
147
+ if (existsSync(join(base, rel))) {
148
+ links.push({ path: rel, label });
149
+ }
150
+ }
151
+ return links;
152
+ }
153
+
154
+ function getDriftSummary() {
155
+ const p = join(REPO_ROOT, "_system", "drift", "metrics.md");
156
+ const content = readText(p);
157
+ if (!content) return null;
158
+ return { raw: content.slice(0, 2000), hasMetrics: true };
159
+ }
160
+
161
+ function getUsageSummary() {
162
+ const p = join(REPO_ROOT, "_system", "artifacts", "usage.json");
163
+ const data = readJson(p);
164
+ if (!data) return null;
165
+ const entries = Array.isArray(data) ? data : data.entries || [];
166
+ return { entryCount: entries.length, hasUsage: entries.length > 0 };
167
+ }
168
+
169
+ function getProjectName() {
170
+ const pj = readJson(join(REPO_ROOT, "project.json"));
171
+ if (pj?.name) return pj.name;
172
+ const pkg = readJson(join(REPO_ROOT, "package.json"));
173
+ return pkg?.name || "project";
174
+ }
175
+
176
+ function exportDashboard() {
177
+ const intents = collectIntents();
178
+ const workflow = getWorkflowState();
179
+ const calibration = getCalibration();
180
+ const docLinks = getDocLinks();
181
+ const drift = getDriftSummary();
182
+ const usage = getUsageSummary();
183
+
184
+ const payload = {
185
+ generated: new Date().toISOString(),
186
+ projectName: getProjectName(),
187
+ intents,
188
+ workflow,
189
+ calibration,
190
+ docLinks,
191
+ drift,
192
+ usage,
193
+ testSummary: null,
194
+ };
195
+
196
+ const outDir = join(REPO_ROOT, "dashboard-app", "public");
197
+ const outPath = join(outDir, "dashboard.json");
198
+ mkdirSync(outDir, { recursive: true });
199
+ writeFileSync(outPath, JSON.stringify(payload, null, 2), "utf-8");
200
+ console.log(`Wrote ${outPath}`);
201
+ }
202
+
203
+ try {
204
+ exportDashboard();
205
+ } catch (err) {
206
+ console.error(err);
207
+ process.exit(1);
208
+ }
@@ -0,0 +1,239 @@
1
+ #!/bin/bash
2
+
3
+ # Fix Intent Issues Script
4
+ # Detects and auto-fixes common intent issues
5
+
6
+ set -euo pipefail
7
+
8
+ error_exit() {
9
+ echo "ERROR: $1" >&2
10
+ exit "${2:-1}"
11
+ }
12
+
13
+ warning() {
14
+ echo "WARNING: $1" >&2
15
+ }
16
+
17
+ # Colors
18
+ RED='\033[0;31m'
19
+ YELLOW='\033[1;33m'
20
+ GREEN='\033[0;32m'
21
+ BLUE='\033[0;34m'
22
+ NC='\033[0m'
23
+
24
+ # Source validation library
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ source "$SCRIPT_DIR/lib/validate-intents.sh" || error_exit "Failed to load validation library" 1
27
+
28
+ INTENT_DIR="${INTENT_DIR:-work/intent}"
29
+
30
+ # Fix whitespace issues in dependencies
31
+ fix_whitespace() {
32
+ local intent_file="$1"
33
+ local temp_file=$(mktemp)
34
+
35
+ if ! awk '
36
+ BEGIN { in_deps=0 }
37
+ /^## Dependencies/ {
38
+ in_deps=1
39
+ print
40
+ next
41
+ }
42
+ in_deps && /^## / {
43
+ in_deps=0
44
+ print
45
+ next
46
+ }
47
+ in_deps && /^[[:space:]]+- / {
48
+ # Remove leading whitespace
49
+ sub(/^[[:space:]]+/, "")
50
+ print
51
+ next
52
+ }
53
+ { print }
54
+ ' "$intent_file" > "$temp_file"; then
55
+ rm -f "$temp_file"
56
+ return 1
57
+ fi
58
+
59
+ mv "$temp_file" "$intent_file"
60
+ echo "โœ“ Fixed whitespace in $(basename "$intent_file")"
61
+ }
62
+
63
+ # Fix dependency ordering by moving dependency to same/earlier release
64
+ fix_dependency_ordering() {
65
+ local intent_id="$1"
66
+ local dep_id="$2"
67
+ local intent_release="$3"
68
+
69
+ local dep_file=$(find "$INTENT_DIR" -type f -name "${dep_id}.md" -print -quit 2>/dev/null)
70
+ if [ -z "$dep_file" ] || [ ! -f "$dep_file" ]; then
71
+ warning "Cannot fix: $dep_id file not found"
72
+ return 1
73
+ fi
74
+
75
+ # Update dependency's release target to match or be earlier than dependent's release
76
+ local temp_file=$(mktemp)
77
+ if ! awk -v target_release="$intent_release" '
78
+ BEGIN { in_release=0; release_set=0 }
79
+ /^## Release Target/ {
80
+ in_release=1
81
+ # Check if inline format
82
+ if (match($0, /R[0-9]+/)) {
83
+ current_release = substr($0, RSTART, RLENGTH)
84
+ current_num = substr(current_release, 2)
85
+ target_num = substr(target_release, 2)
86
+ if (current_num > target_num) {
87
+ # Replace with target release
88
+ sub(/R[0-9]+/, target_release)
89
+ release_set=1
90
+ }
91
+ print
92
+ next
93
+ }
94
+ print
95
+ next
96
+ }
97
+ in_release && /^## / {
98
+ if (!release_set) {
99
+ # Release target not set yet, add it
100
+ print target_release
101
+ release_set=1
102
+ }
103
+ in_release=0
104
+ print
105
+ next
106
+ }
107
+ in_release && /R[0-9]+/ {
108
+ if (!/\|/) { # Not a template line
109
+ if (match($0, /R[0-9]+/)) {
110
+ current_release = substr($0, RSTART, RLENGTH)
111
+ current_num = substr(current_release, 2)
112
+ target_num = substr(target_release, 2)
113
+ if (current_num > target_num) {
114
+ # Replace with target release
115
+ sub(/R[0-9]+/, target_release)
116
+ release_set=1
117
+ }
118
+ }
119
+ }
120
+ print
121
+ next
122
+ }
123
+ { print }
124
+ END {
125
+ if (in_release && !release_set) {
126
+ print target_release
127
+ }
128
+ }
129
+ ' "$dep_file" > "$temp_file"; then
130
+ rm -f "$temp_file"
131
+ return 1
132
+ fi
133
+
134
+ mv "$temp_file" "$dep_file"
135
+ echo "โœ“ Moved $dep_id to $intent_release (to satisfy $intent_id dependency)"
136
+ }
137
+
138
+ # Main fix function
139
+ main() {
140
+ echo -e "${BLUE}Scanning for intent issues...${NC}"
141
+ echo ""
142
+
143
+ # Collect all issues
144
+ local all_issues=()
145
+ local intent_files=()
146
+
147
+ # Find all intent files recursively
148
+ intent_files=()
149
+ while IFS= read -r file; do
150
+ intent_files+=("$file")
151
+ done < <(find "$INTENT_DIR" -type f -name "*.md" ! -name "_TEMPLATE.md" 2>/dev/null)
152
+
153
+ if [ ${#intent_files[@]} -eq 0 ]; then
154
+ echo -e "${GREEN}โœ“ No intent files found${NC}"
155
+ return 0
156
+ fi
157
+
158
+ # Validate all intents and collect issues
159
+ for intent_file in "${intent_files[@]}"; do
160
+ while IFS= read -r issue; do
161
+ [ -n "$issue" ] && all_issues+=("$issue")
162
+ done < <(validate_intent "$intent_file" || true)
163
+ done
164
+
165
+ if [ ${#all_issues[@]} -eq 0 ]; then
166
+ echo -e "${GREEN}โœ“ No issues found${NC}"
167
+ return 0
168
+ fi
169
+
170
+ # Display issues
171
+ echo -e "${YELLOW}Found ${#all_issues[@]} issue(s):${NC}"
172
+ echo ""
173
+
174
+ local i=1
175
+ for issue in "${all_issues[@]}"; do
176
+ local issue_type=$(echo "$issue" | cut -d'|' -f1)
177
+ local intent_id=$(echo "$issue" | cut -d'|' -f2)
178
+ local message=$(echo "$issue" | cut -d'|' -f3)
179
+ local fix_suggestion=$(echo "$issue" | cut -d'|' -f4)
180
+
181
+ echo -e "${YELLOW}[$i]${NC} $intent_id: $message"
182
+ echo " Fix: $fix_suggestion"
183
+ echo ""
184
+ i=$((i + 1))
185
+ done
186
+
187
+ # Ask for confirmation
188
+ echo -e "${BLUE}Apply fixes? (y/n):${NC} "
189
+ read -r response
190
+
191
+ if [ "$response" != "y" ] && [ "$response" != "Y" ]; then
192
+ echo "Cancelled."
193
+ return 0
194
+ fi
195
+
196
+ echo ""
197
+ echo -e "${BLUE}Applying fixes...${NC}"
198
+ echo ""
199
+
200
+ # Apply fixes
201
+ local fixed_count=0
202
+ for issue in "${all_issues[@]}"; do
203
+ local issue_type=$(echo "$issue" | cut -d'|' -f1)
204
+ local intent_id=$(echo "$issue" | cut -d'|' -f2)
205
+ local intent_file=$(find "$INTENT_DIR" -type f -name "${intent_id}.md" -print -quit 2>/dev/null)
206
+ if [ -z "$intent_file" ] || [ ! -f "$intent_file" ]; then
207
+ warning "Intent file not found: $intent_id"
208
+ continue
209
+ fi
210
+
211
+ case "$issue_type" in
212
+ whitespace)
213
+ fix_whitespace "$intent_file"
214
+ fixed_count=$((fixed_count + 1))
215
+ ;;
216
+ dependency_ordering)
217
+ # Extract dependency ID from message
218
+ local dep_id=$(echo "$issue" | grep -o '[A-Z]-[0-9]*' | head -2 | tail -1)
219
+ local intent_release=$(echo "$issue" | grep -o 'R[0-9]*' | head -1)
220
+ if [ -n "$dep_id" ] && [ -n "$intent_release" ]; then
221
+ fix_dependency_ordering "$intent_id" "$dep_id" "$intent_release"
222
+ fixed_count=$((fixed_count + 1))
223
+ fi
224
+ ;;
225
+ missing_dependency|circular)
226
+ echo -e "${YELLOW}โš  Skipping $issue_type issue (requires manual intervention)${NC}"
227
+ ;;
228
+ esac
229
+ done
230
+
231
+ echo ""
232
+ if [ $fixed_count -gt 0 ]; then
233
+ echo -e "${GREEN}โœ“ Fixed $fixed_count issue(s)${NC}"
234
+ else
235
+ echo -e "${YELLOW}No automatic fixes applied${NC}"
236
+ fi
237
+ }
238
+
239
+ main "$@"
@@ -0,0 +1,136 @@
1
+ #!/bin/bash
2
+
3
+ # Generate Project Dashboard Script
4
+ # Creates a project status dashboard
5
+
6
+ set -euo pipefail
7
+
8
+ error_exit() {
9
+ echo "ERROR: $1" >&2
10
+ exit "${2:-1}"
11
+ }
12
+
13
+ # Colors
14
+ GREEN='\033[0;32m'
15
+ YELLOW='\033[1;33m'
16
+ BLUE='\033[0;34m'
17
+ NC='\033[0m'
18
+
19
+ DASHBOARD_FILE="DASHBOARD.md"
20
+
21
+ echo -e "${BLUE}Generating project dashboard...${NC}"
22
+
23
+ # Check prerequisites
24
+ if [ ! -f "project.json" ]; then
25
+ error_exit "project.json not found. Run /init-project first." 1
26
+ fi
27
+
28
+ PROJECT_NAME=$(jq -r '.name' project.json 2>/dev/null || echo "project")
29
+
30
+ # Collect metrics
31
+ intent_files=()
32
+ while IFS= read -r file; do
33
+ intent_files+=("$file")
34
+ done < <(find intent -type f -name "*.md" ! -name "_TEMPLATE.md" 2>/dev/null)
35
+
36
+ INTENT_TOTAL=${#intent_files[@]}
37
+ if [ "$INTENT_TOTAL" -gt 0 ]; then
38
+ INTENT_PLANNED=$(grep -l "Status.*planned" "${intent_files[@]}" 2>/dev/null | wc -l | tr -d ' ')
39
+ INTENT_ACTIVE=$(grep -l "Status.*active" "${intent_files[@]}" 2>/dev/null | wc -l | tr -d ' ')
40
+ INTENT_SHIPPED=$(grep -l "Status.*shipped" "${intent_files[@]}" 2>/dev/null | wc -l | tr -d ' ')
41
+ INTENT_BLOCKED=$(grep -l "Status.*blocked" "${intent_files[@]}" 2>/dev/null | wc -l | tr -d ' ')
42
+ else
43
+ INTENT_PLANNED=0
44
+ INTENT_ACTIVE=0
45
+ INTENT_SHIPPED=0
46
+ INTENT_BLOCKED=0
47
+ fi
48
+
49
+ # Calculate progress
50
+ if [ "$INTENT_TOTAL" -gt 0 ]; then
51
+ PROGRESS=$((INTENT_SHIPPED * 100 / INTENT_TOTAL))
52
+ else
53
+ PROGRESS=0
54
+ fi
55
+
56
+ # Get active intent details
57
+ ACTIVE_INTENT=$(grep -h "Intent ID:" work/workflow-state/active.md 2>/dev/null | grep -o "F-[0-9]*\|B-[0-9]*\|T-[0-9]*" | head -1 || echo "none")
58
+ ACTIVE_PHASE=$(grep -h "Current Phase:" work/workflow-state/active.md 2>/dev/null | sed 's/.*Current Phase: *//' || echo "unknown")
59
+
60
+ # Test coverage (if available)
61
+ if command -v pnpm >/dev/null 2>&1 && [ -f "package.json" ]; then
62
+ COVERAGE=$(pnpm test:coverage 2>/dev/null | grep -o "[0-9]*%" | head -1 || echo "N/A")
63
+ else
64
+ COVERAGE="N/A"
65
+ fi
66
+
67
+ # Generate dashboard
68
+ cat > "$DASHBOARD_FILE" << EOF || error_exit "Failed to generate dashboard"
69
+ # Project Dashboard: $PROJECT_NAME
70
+
71
+ **Last Updated:** $(date -u +"%Y-%m-%dT%H:%M:%SZ")
72
+
73
+ ## ๐Ÿ“Š Status Overview
74
+
75
+ | Metric | Value |
76
+ |--------|-------|
77
+ | **Total Intents** | $INTENT_TOTAL |
78
+ | **Planned** | $INTENT_PLANNED |
79
+ | **Active** | $INTENT_ACTIVE |
80
+ | **Shipped** | $INTENT_SHIPPED |
81
+ | **Blocked** | $INTENT_BLOCKED |
82
+ | **Progress** | $PROGRESS% |
83
+
84
+ ## ๐ŸŽฏ Current Work
85
+
86
+ - **Active Intent:** $ACTIVE_INTENT
87
+ - **Current Phase:** $ACTIVE_PHASE
88
+
89
+ ## ๐Ÿ“ˆ Progress Visualization
90
+
91
+ \`\`\`
92
+ Shipped: [$(printf '#%.0s' $(seq 1 $((PROGRESS / 2))))$(printf ' %.0s' $(seq 1 $((50 - PROGRESS / 2))))] $PROGRESS%
93
+ \`\`\`
94
+
95
+ ## ๐Ÿ”„ Intent Status Breakdown
96
+
97
+ - โœ… Shipped: $INTENT_SHIPPED
98
+ - ๐Ÿ”„ Active: $INTENT_ACTIVE
99
+ - ๐Ÿ“‹ Planned: $INTENT_PLANNED
100
+ - โ›” Blocked: $INTENT_BLOCKED
101
+
102
+ ## ๐Ÿงช Quality Metrics
103
+
104
+ - **Test Coverage:** $COVERAGE
105
+ - **Lint Status:** [Run: pnpm lint]
106
+ - **Type Check:** [Run: pnpm typecheck]
107
+
108
+ ## ๐Ÿ“‹ Recent Intents
109
+
110
+ $(if [ "$INTENT_TOTAL" -gt 0 ]; then printf "%s\n" "${intent_files[@]}" | head -5 | xargs -I{} basename "{}" .md | sed 's/^/- /'; else echo "No intents yet"; fi)
111
+
112
+ ## ๐Ÿ”— Quick Links
113
+
114
+ - [Project Context](./PROJECT_CONTEXT.md)
115
+ - [Roadmap](./work/roadmap/now.md)
116
+ - [Dependencies](./_system/artifacts/dependencies.md)
117
+ - [Deployment History](./deployment-history.md)
118
+
119
+ ## ๐Ÿš€ Next Actions
120
+
121
+ 1. Review active intent: $ACTIVE_INTENT
122
+ 2. Check workflow state: work/workflow-state/
123
+ 3. Update roadmap: work/roadmap/
124
+
125
+ ---
126
+
127
+ *This dashboard is auto-generated. Run \`pnpm generate-dashboard\` to update.*
128
+ EOF
129
+
130
+ echo -e "${GREEN}โœ“ Generated $DASHBOARD_FILE${NC}"
131
+ echo ""
132
+ echo -e "${YELLOW}Dashboard Metrics:${NC}"
133
+ echo " Total Intents: $INTENT_TOTAL"
134
+ echo " Progress: $PROGRESS%"
135
+ echo " Active: $ACTIVE_INTENT"
136
+ echo ""