@open-agent-toolkit/cli 0.2.36 → 0.2.37

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 (183) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/backlog-lifecycle.md +18 -0
  3. package/assets/docs/cli-utilities/bootstrap.md +6 -3
  4. package/assets/docs/cli-utilities/config-and-local-state.md +26 -12
  5. package/assets/docs/cli-utilities/configuration.md +36 -13
  6. package/assets/docs/cli-utilities/tool-packs.md +423 -51
  7. package/assets/docs/provider-sync/scope-and-surface.md +4 -1
  8. package/assets/docs/reference/cli-reference.md +5 -3
  9. package/assets/docs/reference/file-locations.md +28 -4
  10. package/assets/docs/reference/troubleshooting.md +132 -2
  11. package/assets/docs/workflows/projects/lifecycle.md +21 -2
  12. package/assets/public-package-versions.json +4 -4
  13. package/assets/scripts/generate-oat-state.sh +441 -0
  14. package/assets/scripts/generate-thin-index.sh +200 -0
  15. package/assets/skills/oat-agent-instructions-analyze/SKILL.md +10 -5
  16. package/assets/skills/oat-agent-instructions-apply/SKILL.md +30 -5
  17. package/assets/skills/oat-brainstorm/SKILL.md +34 -8
  18. package/assets/skills/oat-brainstorm/references/destinations.md +6 -1
  19. package/assets/skills/oat-docs-analyze/SKILL.md +9 -4
  20. package/assets/skills/oat-docs-apply/SKILL.md +6 -3
  21. package/assets/skills/oat-pjm-add-backlog-item/SKILL.md +14 -1
  22. package/assets/skills/oat-pjm-decision/SKILL.md +22 -10
  23. package/assets/skills/oat-pjm-review-backlog/SKILL.md +20 -3
  24. package/assets/skills/oat-pjm-update-repo-reference/SKILL.md +20 -10
  25. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  26. package/assets/skills/oat-project-document/SKILL.md +21 -3
  27. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  28. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  29. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  30. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  31. package/assets/skills/oat-project-summary/SKILL.md +23 -11
  32. package/assets/skills/oat-repo-knowledge-index/SKILL.md +6 -3
  33. package/dist/commands/backlog/index.d.ts +2 -0
  34. package/dist/commands/backlog/index.d.ts.map +1 -1
  35. package/dist/commands/backlog/index.js +67 -23
  36. package/dist/commands/backlog/new.d.ts +3 -0
  37. package/dist/commands/backlog/new.d.ts.map +1 -1
  38. package/dist/commands/backlog/new.js +8 -21
  39. package/dist/commands/decision/agents-guidance.d.ts.map +1 -1
  40. package/dist/commands/decision/agents-guidance.js +2 -1
  41. package/dist/commands/decision/index.d.ts +2 -0
  42. package/dist/commands/decision/index.d.ts.map +1 -1
  43. package/dist/commands/decision/index.js +19 -3
  44. package/dist/commands/decision/new.d.ts +4 -0
  45. package/dist/commands/decision/new.d.ts.map +1 -1
  46. package/dist/commands/decision/new.js +11 -30
  47. package/dist/commands/doctor/index.d.ts +4 -0
  48. package/dist/commands/doctor/index.d.ts.map +1 -1
  49. package/dist/commands/doctor/index.js +254 -9
  50. package/dist/commands/init/tools/brainstorm/index.d.ts.map +1 -1
  51. package/dist/commands/init/tools/brainstorm/index.js +20 -6
  52. package/dist/commands/init/tools/docs/index.d.ts.map +1 -1
  53. package/dist/commands/init/tools/docs/index.js +4 -1
  54. package/dist/commands/init/tools/ideas/index.d.ts.map +1 -1
  55. package/dist/commands/init/tools/ideas/index.js +4 -1
  56. package/dist/commands/init/tools/index.d.ts +11 -2
  57. package/dist/commands/init/tools/index.d.ts.map +1 -1
  58. package/dist/commands/init/tools/index.js +459 -351
  59. package/dist/commands/init/tools/install-state.d.ts +2 -0
  60. package/dist/commands/init/tools/install-state.d.ts.map +1 -1
  61. package/dist/commands/init/tools/install-state.js +11 -0
  62. package/dist/commands/init/tools/project-management/agents-guidance.d.ts.map +1 -1
  63. package/dist/commands/init/tools/project-management/agents-guidance.js +3 -1
  64. package/dist/commands/init/tools/project-management/index.d.ts +1 -0
  65. package/dist/commands/init/tools/project-management/index.d.ts.map +1 -1
  66. package/dist/commands/init/tools/project-management/index.js +24 -55
  67. package/dist/commands/init/tools/project-management/install-project-management.d.ts +4 -0
  68. package/dist/commands/init/tools/project-management/install-project-management.d.ts.map +1 -1
  69. package/dist/commands/init/tools/project-management/install-project-management.js +4 -1
  70. package/dist/commands/init/tools/research/index.d.ts.map +1 -1
  71. package/dist/commands/init/tools/research/index.js +4 -1
  72. package/dist/commands/init/tools/shared/copy-helpers.d.ts.map +1 -1
  73. package/dist/commands/init/tools/shared/copy-helpers.js +10 -0
  74. package/dist/commands/init/tools/shared/skill-manifest.d.ts +15 -15
  75. package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
  76. package/dist/commands/init/tools/shared/skill-manifest.js +17 -122
  77. package/dist/commands/init/tools/utility/index.d.ts.map +1 -1
  78. package/dist/commands/init/tools/utility/index.js +4 -1
  79. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  80. package/dist/commands/init/tools/workflows/index.js +4 -1
  81. package/dist/commands/init/tools/workflows/install-workflows.d.ts.map +1 -1
  82. package/dist/commands/init/tools/workflows/install-workflows.js +2 -4
  83. package/dist/commands/pjm/adoption.d.ts +12 -0
  84. package/dist/commands/pjm/adoption.d.ts.map +1 -0
  85. package/dist/commands/pjm/adoption.js +47 -0
  86. package/dist/commands/pjm/doctor.d.ts +3 -2
  87. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  88. package/dist/commands/pjm/doctor.js +28 -13
  89. package/dist/commands/pjm/index.d.ts +2 -0
  90. package/dist/commands/pjm/index.d.ts.map +1 -1
  91. package/dist/commands/pjm/index.js +11 -3
  92. package/dist/commands/pjm/init.d.ts +3 -0
  93. package/dist/commands/pjm/init.d.ts.map +1 -1
  94. package/dist/commands/pjm/init.js +37 -32
  95. package/dist/commands/pjm/migrate.d.ts +1 -0
  96. package/dist/commands/pjm/migrate.d.ts.map +1 -1
  97. package/dist/commands/pjm/migrate.js +1 -0
  98. package/dist/commands/pjm/template-source.d.ts +14 -0
  99. package/dist/commands/pjm/template-source.d.ts.map +1 -0
  100. package/dist/commands/pjm/template-source.js +56 -0
  101. package/dist/commands/remove/skills/remove-skills.d.ts.map +1 -1
  102. package/dist/commands/remove/skills/remove-skills.js +10 -19
  103. package/dist/commands/status/index.d.ts +5 -0
  104. package/dist/commands/status/index.d.ts.map +1 -1
  105. package/dist/commands/status/index.js +203 -2
  106. package/dist/commands/sync/index.d.ts.map +1 -1
  107. package/dist/commands/sync/index.js +40 -7
  108. package/dist/commands/sync/sync.types.d.ts +4 -0
  109. package/dist/commands/sync/sync.types.d.ts.map +1 -1
  110. package/dist/commands/tools/has/has-pack.d.ts +11 -2
  111. package/dist/commands/tools/has/has-pack.d.ts.map +1 -1
  112. package/dist/commands/tools/has/has-pack.js +33 -20
  113. package/dist/commands/tools/index.d.ts.map +1 -1
  114. package/dist/commands/tools/index.js +3 -1
  115. package/dist/commands/tools/info/info-tool.d.ts +3 -0
  116. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  117. package/dist/commands/tools/info/info-tool.js +29 -4
  118. package/dist/commands/tools/list/list-tools.d.ts +3 -0
  119. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  120. package/dist/commands/tools/list/list-tools.js +31 -4
  121. package/dist/commands/tools/migrate/index.d.ts +26 -0
  122. package/dist/commands/tools/migrate/index.d.ts.map +1 -0
  123. package/dist/commands/tools/migrate/index.js +312 -0
  124. package/dist/commands/tools/migrate/migrate-pack.d.ts +81 -0
  125. package/dist/commands/tools/migrate/migrate-pack.d.ts.map +1 -0
  126. package/dist/commands/tools/migrate/migrate-pack.js +324 -0
  127. package/dist/commands/tools/outdated/outdated-tools.d.ts +11 -0
  128. package/dist/commands/tools/outdated/outdated-tools.d.ts.map +1 -1
  129. package/dist/commands/tools/outdated/outdated-tools.js +33 -5
  130. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  131. package/dist/commands/tools/remove/index.js +73 -20
  132. package/dist/commands/tools/remove/remove-tools.d.ts +28 -0
  133. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  134. package/dist/commands/tools/remove/remove-tools.js +156 -26
  135. package/dist/commands/tools/shared/apply-pack-reconcile.d.ts +41 -0
  136. package/dist/commands/tools/shared/apply-pack-reconcile.d.ts.map +1 -0
  137. package/dist/commands/tools/shared/apply-pack-reconcile.js +126 -0
  138. package/dist/commands/tools/shared/auto-sync.d.ts +5 -2
  139. package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
  140. package/dist/commands/tools/shared/auto-sync.js +1 -0
  141. package/dist/commands/tools/shared/content-digest.d.ts +3 -0
  142. package/dist/commands/tools/shared/content-digest.d.ts.map +1 -0
  143. package/dist/commands/tools/shared/content-digest.js +57 -0
  144. package/dist/commands/tools/shared/format-pack-inventory.d.ts +3 -0
  145. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -0
  146. package/dist/commands/tools/shared/format-pack-inventory.js +21 -0
  147. package/dist/commands/tools/shared/install-sync-context.d.ts.map +1 -1
  148. package/dist/commands/tools/shared/install-sync-context.js +2 -25
  149. package/dist/commands/tools/shared/pack-inventory.d.ts +46 -0
  150. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -0
  151. package/dist/commands/tools/shared/pack-inventory.js +207 -0
  152. package/dist/commands/tools/shared/pack-lifecycle.d.ts +34 -0
  153. package/dist/commands/tools/shared/pack-lifecycle.d.ts.map +1 -0
  154. package/dist/commands/tools/shared/pack-lifecycle.js +67 -0
  155. package/dist/commands/tools/shared/pack-manifest.d.ts +11 -0
  156. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -0
  157. package/dist/commands/tools/shared/pack-manifest.js +384 -0
  158. package/dist/commands/tools/shared/pack-paths.d.ts +21 -0
  159. package/dist/commands/tools/shared/pack-paths.d.ts.map +1 -0
  160. package/dist/commands/tools/shared/pack-paths.js +35 -0
  161. package/dist/commands/tools/shared/pack-reconcile.d.ts +64 -0
  162. package/dist/commands/tools/shared/pack-reconcile.d.ts.map +1 -0
  163. package/dist/commands/tools/shared/pack-reconcile.js +158 -0
  164. package/dist/commands/tools/shared/project-tools-config.d.ts.map +1 -1
  165. package/dist/commands/tools/shared/project-tools-config.js +12 -38
  166. package/dist/commands/tools/shared/scan-tools.js +2 -2
  167. package/dist/commands/tools/shared/scoped-pack-intent.d.ts +34 -0
  168. package/dist/commands/tools/shared/scoped-pack-intent.d.ts.map +1 -0
  169. package/dist/commands/tools/shared/scoped-pack-intent.js +116 -0
  170. package/dist/commands/tools/shared/types.d.ts +22 -0
  171. package/dist/commands/tools/shared/types.d.ts.map +1 -1
  172. package/dist/commands/tools/update/index.d.ts.map +1 -1
  173. package/dist/commands/tools/update/index.js +30 -5
  174. package/dist/commands/tools/update/update-tools.d.ts +9 -1
  175. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  176. package/dist/commands/tools/update/update-tools.js +176 -64
  177. package/dist/config/oat-config.d.ts +6 -0
  178. package/dist/config/oat-config.d.ts.map +1 -1
  179. package/dist/config/oat-config.js +49 -20
  180. package/dist/fs/paths.d.ts +12 -0
  181. package/dist/fs/paths.d.ts.map +1 -1
  182. package/dist/fs/paths.js +87 -1
  183. package/package.json +2 -2
@@ -0,0 +1,441 @@
1
+ #!/usr/bin/env bash
2
+ # generate-oat-state.sh - Generate OAT repo state dashboard
3
+ # Usage: ./generate-oat-state.sh
4
+ # Exit codes: 0 = Success, 1 = Error (only for real failures, not missing data)
5
+
6
+ # Use -eu but NOT pipefail - we need graceful degradation for missing data
7
+ set -eu
8
+
9
+ # --- Configuration ---
10
+ DASHBOARD_PATH=".oat/state.md"
11
+
12
+ # --- Error Handling Pattern ---
13
+ # For best-effort parsing, use:
14
+ # result=$(command 2>/dev/null || echo "")
15
+ # result=$(grep ... || true)
16
+ # Never let missing frontmatter or files cause script exit.
17
+
18
+ # --- Functions ---
19
+
20
+ # Resolve PROJECTS_ROOT from env, file, or default
21
+ resolve_projects_root() {
22
+ local root="${OAT_PROJECTS_ROOT:-}"
23
+ if [[ -z "$root" ]] && [[ -f ".oat/projects-root" ]]; then
24
+ root=$(cat ".oat/projects-root" 2>/dev/null || true)
25
+ fi
26
+ root="${root:-.oat/projects/shared}"
27
+ echo "${root%/}" # Strip trailing slash
28
+ }
29
+
30
+ has_any_projects() {
31
+ local projects_root="$1"
32
+ local dir
33
+ [[ -d "$projects_root" ]] || return 1
34
+ for dir in "$projects_root"/*/; do
35
+ [[ -d "$dir" ]] || continue
36
+ return 0
37
+ done
38
+ return 1
39
+ }
40
+
41
+ # Read active project pointer (accepts path or name format)
42
+ # Sets: PROJECT_NAME, PROJECT_PATH, PROJECT_STATUS
43
+ read_active_project() {
44
+ local projects_root="$1"
45
+ local raw_value
46
+
47
+ PROJECT_NAME=""
48
+ PROJECT_PATH=""
49
+ PROJECT_STATUS="not set"
50
+
51
+ if [[ ! -f ".oat/active-project" ]]; then
52
+ return
53
+ fi
54
+
55
+ raw_value=$(cat ".oat/active-project" 2>/dev/null || true)
56
+ raw_value=$(echo "$raw_value" | tr -d '[:space:]')
57
+
58
+ if [[ -z "$raw_value" ]]; then
59
+ return
60
+ fi
61
+
62
+ # Detect format: path (contains /) or name-only
63
+ if [[ "$raw_value" == */* ]]; then
64
+ PROJECT_NAME=$(basename "$raw_value")
65
+ PROJECT_PATH="$raw_value"
66
+ else
67
+ PROJECT_NAME="$raw_value"
68
+ PROJECT_PATH="${projects_root}/${PROJECT_NAME}"
69
+ fi
70
+
71
+ # Validate directory exists
72
+ if [[ ! -d "$PROJECT_PATH" ]]; then
73
+ PROJECT_STATUS="directory missing"
74
+ return
75
+ fi
76
+
77
+ # Validate state.md exists
78
+ if [[ ! -f "${PROJECT_PATH}/state.md" ]]; then
79
+ PROJECT_STATUS="state.md missing"
80
+ return
81
+ fi
82
+
83
+ PROJECT_STATUS="active"
84
+ }
85
+
86
+ # Parse YAML frontmatter field from file (best-effort, never fails)
87
+ # Usage: parse_frontmatter "file.md" "field_name"
88
+ # Returns: Field value or empty string (never exits on missing data)
89
+ parse_frontmatter() {
90
+ local file="$1"
91
+ local field="$2"
92
+ local content value
93
+
94
+ if [[ ! -f "$file" ]]; then
95
+ echo ""
96
+ return 0
97
+ fi
98
+
99
+ # Extract frontmatter block, then find field - use || true to prevent exit
100
+ content=$(sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null) || true
101
+ if [[ -z "$content" ]]; then
102
+ echo ""
103
+ return 0
104
+ fi
105
+
106
+ # Find field value - grep returns 1 if no match, so use || true
107
+ value=$(echo "$content" | grep "^${field}:" | head -1 | sed "s/^${field}:[[:space:]]*//") || true
108
+ # Strip inline comments used by templates and trim trailing whitespace
109
+ value=$(echo "$value" | sed 's/[[:space:]]#.*$//' | sed 's/[[:space:]]*$//')
110
+ echo "$value"
111
+ }
112
+
113
+ # Read project state from state.md frontmatter
114
+ # Sets: OAT_PHASE, OAT_PHASE_STATUS, OAT_CURRENT_TASK, OAT_LIFECYCLE, OAT_BLOCKERS,
115
+ # OAT_HIL_CHECKPOINTS, OAT_HIL_COMPLETED, OAT_HIL_STATUS
116
+ read_project_state() {
117
+ local state_file="${PROJECT_PATH}/state.md"
118
+
119
+ OAT_PHASE=$(parse_frontmatter "$state_file" "oat_phase")
120
+ OAT_PHASE_STATUS=$(parse_frontmatter "$state_file" "oat_phase_status")
121
+ OAT_CURRENT_TASK=$(parse_frontmatter "$state_file" "oat_current_task")
122
+ OAT_LIFECYCLE=$(parse_frontmatter "$state_file" "oat_lifecycle")
123
+ OAT_BLOCKERS=$(parse_frontmatter "$state_file" "oat_blockers")
124
+ OAT_HIL_CHECKPOINTS=$(parse_frontmatter "$state_file" "oat_hil_checkpoints")
125
+ OAT_HIL_COMPLETED=$(parse_frontmatter "$state_file" "oat_hil_completed")
126
+ OAT_WORKFLOW_MODE=$(parse_frontmatter "$state_file" "oat_workflow_mode")
127
+
128
+ # Defaults
129
+ OAT_PHASE="${OAT_PHASE:-unknown}"
130
+ OAT_PHASE_STATUS="${OAT_PHASE_STATUS:-unknown}"
131
+ if [[ -z "${OAT_CURRENT_TASK:-}" ]] || [[ "${OAT_CURRENT_TASK}" == "null" ]]; then
132
+ OAT_CURRENT_TASK="-"
133
+ fi
134
+ OAT_LIFECYCLE="${OAT_LIFECYCLE:-active}"
135
+ OAT_BLOCKERS="${OAT_BLOCKERS:-[]}"
136
+ OAT_HIL_CHECKPOINTS="${OAT_HIL_CHECKPOINTS:-[]}"
137
+ OAT_HIL_COMPLETED="${OAT_HIL_COMPLETED:-[]}"
138
+ OAT_WORKFLOW_MODE="${OAT_WORKFLOW_MODE:-full}"
139
+
140
+ # Human-in-loop status for current phase
141
+ if phase_in_hil_list "$OAT_PHASE" "$OAT_HIL_CHECKPOINTS"; then
142
+ if phase_in_hil_list "$OAT_PHASE" "$OAT_HIL_COMPLETED"; then
143
+ OAT_HIL_STATUS="passed"
144
+ else
145
+ OAT_HIL_STATUS="pending"
146
+ fi
147
+ else
148
+ OAT_HIL_STATUS="n/a"
149
+ fi
150
+ }
151
+
152
+ # Check whether a phase token appears in a serialized YAML array string
153
+ phase_in_hil_list() {
154
+ local phase="$1"
155
+ local list="$2"
156
+ [[ "$list" == *"\"${phase}\""* ]]
157
+ }
158
+
159
+ # Read knowledge index status
160
+ # Sets: KNOWLEDGE_GENERATED_AT, KNOWLEDGE_MERGE_BASE_SHA, KNOWLEDGE_STATUS
161
+ read_knowledge_status() {
162
+ local index_file=".oat/repo/knowledge/project-index.md"
163
+
164
+ KNOWLEDGE_GENERATED_AT=""
165
+ KNOWLEDGE_MERGE_BASE_SHA=""
166
+ KNOWLEDGE_STATUS="not generated"
167
+
168
+ if [[ ! -f "$index_file" ]]; then
169
+ return
170
+ fi
171
+
172
+ KNOWLEDGE_GENERATED_AT=$(parse_frontmatter "$index_file" "oat_generated_at")
173
+ KNOWLEDGE_MERGE_BASE_SHA=$(parse_frontmatter "$index_file" "oat_source_main_merge_base_sha")
174
+
175
+ if [[ -n "$KNOWLEDGE_GENERATED_AT" ]]; then
176
+ KNOWLEDGE_STATUS="generated"
177
+ fi
178
+ }
179
+
180
+ # Calculate knowledge staleness via git diff (best-effort, never fails)
181
+ # Sets: FILES_CHANGED, KNOWLEDGE_AGE_DAYS, STALENESS_STATUS
182
+ calculate_staleness() {
183
+ FILES_CHANGED=0
184
+ KNOWLEDGE_AGE_DAYS=0
185
+ STALENESS_STATUS="fresh"
186
+
187
+ if [[ -z "$KNOWLEDGE_MERGE_BASE_SHA" ]]; then
188
+ STALENESS_STATUS="unknown"
189
+ return 0
190
+ fi
191
+
192
+ # Count files changed since merge base - git diff may fail if SHA is invalid
193
+ local diff_output
194
+ diff_output=$(git diff --name-only "$KNOWLEDGE_MERGE_BASE_SHA" HEAD 2>/dev/null) || true
195
+ if [[ -n "$diff_output" ]]; then
196
+ FILES_CHANGED=$(echo "$diff_output" | wc -l | awk '{print $1}')
197
+ fi
198
+
199
+ # Calculate age in days - handle both macOS and Linux date formats
200
+ if [[ -n "$KNOWLEDGE_GENERATED_AT" ]]; then
201
+ local gen_epoch today_epoch
202
+ # Try macOS format first
203
+ if gen_epoch=$(date -j -f "%Y-%m-%d" "$KNOWLEDGE_GENERATED_AT" "+%s" 2>/dev/null); then
204
+ : # Success on macOS
205
+ # Then try Linux format
206
+ elif gen_epoch=$(date -d "$KNOWLEDGE_GENERATED_AT" "+%s" 2>/dev/null); then
207
+ : # Success on Linux
208
+ else
209
+ # Fallback: cannot parse date
210
+ gen_epoch=0
211
+ fi
212
+ today_epoch=$(date "+%s")
213
+ if [[ "$gen_epoch" -gt 0 ]]; then
214
+ KNOWLEDGE_AGE_DAYS=$(( (today_epoch - gen_epoch) / 86400 ))
215
+ fi
216
+ fi
217
+
218
+ # Determine staleness
219
+ if [[ "$FILES_CHANGED" -gt 20 ]] || [[ "$KNOWLEDGE_AGE_DAYS" -gt 7 ]]; then
220
+ STALENESS_STATUS="stale"
221
+ elif [[ "$FILES_CHANGED" -gt 5 ]] || [[ "$KNOWLEDGE_AGE_DAYS" -gt 3 ]]; then
222
+ STALENESS_STATUS="aging"
223
+ fi
224
+ }
225
+
226
+ # Compute recommended next step based on state
227
+ # Sets: RECOMMENDED_STEP, RECOMMENDED_REASON
228
+ compute_next_step() {
229
+ RECOMMENDED_STEP=""
230
+ RECOMMENDED_REASON=""
231
+
232
+ # No active project
233
+ if [[ "$PROJECT_STATUS" == "not set" ]]; then
234
+ if [[ "${HAS_PROJECTS:-false}" == "true" ]]; then
235
+ RECOMMENDED_STEP="oat-project-open"
236
+ RECOMMENDED_REASON="Select an existing project to continue work"
237
+ else
238
+ RECOMMENDED_STEP="oat-project-new"
239
+ RECOMMENDED_REASON="Create a new project to start work"
240
+ fi
241
+ return
242
+ fi
243
+
244
+ # Project has issues
245
+ if [[ "$PROJECT_STATUS" != "active" ]]; then
246
+ RECOMMENDED_STEP="oat-project-open"
247
+ RECOMMENDED_REASON="Current project has issues: $PROJECT_STATUS"
248
+ return
249
+ fi
250
+
251
+ # Respect configured human-in-the-loop checkpoints before advancing phase
252
+ if [[ "$OAT_PHASE_STATUS" == "complete" ]] &&
253
+ phase_in_hil_list "$OAT_PHASE" "$OAT_HIL_CHECKPOINTS" &&
254
+ ! phase_in_hil_list "$OAT_PHASE" "$OAT_HIL_COMPLETED"; then
255
+ case "$OAT_PHASE" in
256
+ "discovery") RECOMMENDED_STEP="oat-project-discover" ;;
257
+ "spec") RECOMMENDED_STEP="oat-project-spec" ;;
258
+ "design") RECOMMENDED_STEP="oat-project-design" ;;
259
+ "plan") RECOMMENDED_STEP="oat-project-plan" ;;
260
+ "implement") RECOMMENDED_STEP="oat-project-implement" ;;
261
+ *) RECOMMENDED_STEP="oat-project-progress" ;;
262
+ esac
263
+ RECOMMENDED_REASON="Complete ${OAT_PHASE} HiL approval before advancing"
264
+ return
265
+ fi
266
+
267
+ # Map phase + status to next skill by workflow mode
268
+ case "${OAT_WORKFLOW_MODE}:${OAT_PHASE}:${OAT_PHASE_STATUS}" in
269
+ # full mode
270
+ "full:discovery:in_progress") RECOMMENDED_STEP="oat-project-discover"; RECOMMENDED_REASON="Continue discovery phase" ;;
271
+ "full:discovery:complete") RECOMMENDED_STEP="oat-project-spec"; RECOMMENDED_REASON="Create specification from discovery" ;;
272
+ "full:spec:in_progress") RECOMMENDED_STEP="oat-project-spec"; RECOMMENDED_REASON="Continue specification phase" ;;
273
+ "full:spec:complete") RECOMMENDED_STEP="oat-project-design"; RECOMMENDED_REASON="Create design from specification" ;;
274
+ "full:design:in_progress") RECOMMENDED_STEP="oat-project-design"; RECOMMENDED_REASON="Continue design phase" ;;
275
+ "full:design:complete") RECOMMENDED_STEP="oat-project-plan"; RECOMMENDED_REASON="Create implementation plan from design" ;;
276
+
277
+ # quick mode
278
+ "quick:discovery:in_progress") RECOMMENDED_STEP="oat-project-discover"; RECOMMENDED_REASON="Continue quick discovery phase" ;;
279
+ "quick:discovery:complete") RECOMMENDED_STEP="oat-project-plan"; RECOMMENDED_REASON="Generate plan directly for quick workflow" ;;
280
+
281
+ # import mode
282
+ "import:plan:in_progress") RECOMMENDED_STEP="oat-project-import-plan"; RECOMMENDED_REASON="Continue import-plan normalization" ;;
283
+
284
+ # shared routing
285
+ *":plan:in_progress") RECOMMENDED_STEP="oat-project-plan"; RECOMMENDED_REASON="Continue planning phase" ;;
286
+ *":plan:complete") RECOMMENDED_STEP="oat-project-implement"; RECOMMENDED_REASON="Start implementation" ;;
287
+ *":implement:in_progress") RECOMMENDED_STEP="oat-project-implement"; RECOMMENDED_REASON="Continue implementation" ;;
288
+ *":implement:complete") RECOMMENDED_STEP="oat-project-pr-final"; RECOMMENDED_REASON="Generate final PR description (final review passed)" ;;
289
+ *) RECOMMENDED_STEP="oat-project-progress"; RECOMMENDED_REASON="Check current progress" ;;
290
+ esac
291
+ }
292
+
293
+ # List available projects with their phases
294
+ # Output: Markdown formatted list
295
+ list_available_projects() {
296
+ local projects_root="$1"
297
+ local project_dir project_name phase
298
+
299
+ if [[ ! -d "$projects_root" ]]; then
300
+ echo "*(No projects directory found)*"
301
+ return
302
+ fi
303
+
304
+ local found=false
305
+ for project_dir in "$projects_root"/*/; do
306
+ [[ -d "$project_dir" ]] || continue
307
+ project_name=$(basename "$project_dir")
308
+
309
+ if [[ -f "${project_dir}state.md" ]]; then
310
+ phase=$(parse_frontmatter "${project_dir}state.md" "oat_phase")
311
+ phase="${phase:-unknown}"
312
+ echo "- **${project_name}** - ${phase}"
313
+ found=true
314
+ fi
315
+ done
316
+
317
+ if [[ "$found" == "false" ]]; then
318
+ echo "*(No projects found)*"
319
+ fi
320
+ }
321
+
322
+ # Generate the complete dashboard markdown
323
+ generate_dashboard() {
324
+ local projects_root="$1"
325
+ local timestamp
326
+ timestamp=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
327
+
328
+ cat > "$DASHBOARD_PATH" << EOF
329
+ ---
330
+ oat_generated: true
331
+ oat_generated_at: $(date -u +"%Y-%m-%d")
332
+ ---
333
+
334
+ # OAT Repo State Dashboard
335
+
336
+ **Generated:** ${timestamp}
337
+
338
+ ## Active Project
339
+
340
+ EOF
341
+
342
+ # Active project section
343
+ if [[ "$PROJECT_STATUS" == "not set" ]]; then
344
+ echo "*(not set)*" >> "$DASHBOARD_PATH"
345
+ else
346
+ echo "**${PROJECT_NAME}** (\`${PROJECT_PATH}\`)" >> "$DASHBOARD_PATH"
347
+ fi
348
+
349
+ echo "" >> "$DASHBOARD_PATH"
350
+
351
+ # Active project summary (thin; details live in project state.md)
352
+ if [[ "$PROJECT_STATUS" == "active" ]]; then
353
+ cat >> "$DASHBOARD_PATH" << EOF
354
+ ## Active Project Summary
355
+
356
+ | Field | Value |
357
+ |-------|-------|
358
+ | Mode | ${OAT_WORKFLOW_MODE} |
359
+ | Phase | ${OAT_PHASE} |
360
+ | Status | ${OAT_PHASE_STATUS} |
361
+ | HiL Gate | ${OAT_HIL_STATUS} |
362
+ | Current Task | ${OAT_CURRENT_TASK} |
363
+
364
+ EOF
365
+ echo "Details: \`${PROJECT_PATH}/state.md\`" >> "$DASHBOARD_PATH"
366
+ echo "" >> "$DASHBOARD_PATH"
367
+ elif [[ "$PROJECT_STATUS" != "not set" ]]; then
368
+ echo "**Warning:** ${PROJECT_STATUS}" >> "$DASHBOARD_PATH"
369
+ echo "" >> "$DASHBOARD_PATH"
370
+ fi
371
+
372
+ # Knowledge status section
373
+ cat >> "$DASHBOARD_PATH" << EOF
374
+ ## Knowledge Status
375
+
376
+ | Field | Value |
377
+ |-------|-------|
378
+ | Generated | ${KNOWLEDGE_GENERATED_AT:-N/A} |
379
+ | Age | ${KNOWLEDGE_AGE_DAYS} days |
380
+ | Files Changed | ${FILES_CHANGED} |
381
+ | Status | ${STALENESS_STATUS} |
382
+
383
+ EOF
384
+
385
+ # Recommended next step
386
+ cat >> "$DASHBOARD_PATH" << EOF
387
+ ## Recommended Next Step
388
+
389
+ **${RECOMMENDED_STEP}** - ${RECOMMENDED_REASON}
390
+
391
+ ## Quick Commands
392
+
393
+ - \`oat-project-progress\` - Check current status
394
+ - \`oat-repo-knowledge-index\` - Refresh knowledge base
395
+ - \`oat-project-new\` - Create a full-lifecycle project
396
+ - \`oat-project-quick-start\` - Create a quick workflow project
397
+ - \`oat-project-import-plan\` - Import an external provider plan
398
+ - \`oat-project-open\` - Switch active project
399
+ - \`oat-project-clear-active\` - Clear active project
400
+ - \`oat-project-complete\` - Mark project complete
401
+
402
+ ## Available Projects
403
+
404
+ EOF
405
+
406
+ list_available_projects "$projects_root" >> "$DASHBOARD_PATH"
407
+ }
408
+
409
+ # --- Main ---
410
+ main() {
411
+ # Validate we're in a git repo
412
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
413
+ echo "Error: Must be run from a git repository" >&2
414
+ exit 1
415
+ fi
416
+
417
+ local projects_root
418
+ projects_root=$(resolve_projects_root)
419
+
420
+ if has_any_projects "$projects_root"; then
421
+ HAS_PROJECTS="true"
422
+ else
423
+ HAS_PROJECTS="false"
424
+ fi
425
+
426
+ read_active_project "$projects_root"
427
+
428
+ if [[ "$PROJECT_STATUS" == "active" ]]; then
429
+ read_project_state
430
+ fi
431
+
432
+ read_knowledge_status
433
+ calculate_staleness
434
+ compute_next_step
435
+
436
+ generate_dashboard "$projects_root"
437
+
438
+ echo "Dashboard generated: $DASHBOARD_PATH"
439
+ }
440
+
441
+ main "$@"
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env bash
2
+ # generate-thin-index.sh - Generate thin project-index.md for quick orientation
3
+ #
4
+ # Usage: ./generate-thin-index.sh [HEAD_SHA] [MERGE_BASE_SHA]
5
+ #
6
+ # If SHAs not provided, computes them from current git state.
7
+ # Output: Writes .oat/repo/knowledge/project-index.md
8
+
9
+ set -euo pipefail
10
+
11
+ # Get SHAs from args or compute
12
+ HEAD_SHA="${1:-$(git rev-parse HEAD 2>/dev/null || echo "unknown")}"
13
+ MERGE_BASE_SHA="${2:-$(git merge-base HEAD origin/main 2>/dev/null || git rev-parse HEAD 2>/dev/null || echo "unknown")}"
14
+
15
+ # Current date (portable)
16
+ DATE=$(date +%F)
17
+
18
+ # Get repo name from package.json or directory (supports node, jq, or grep fallback)
19
+ REPO_NAME=""
20
+ if [ -f package.json ]; then
21
+ # Try node first
22
+ if command -v node >/dev/null 2>&1; then
23
+ REPO_NAME=$(node -pe "try{require('./package.json').name||''}catch(e){''}" 2>/dev/null)
24
+ # Try jq second
25
+ elif command -v jq >/dev/null 2>&1; then
26
+ REPO_NAME=$(jq -r '.name // ""' package.json 2>/dev/null)
27
+ # Fallback to grep
28
+ else
29
+ REPO_NAME=$(grep -m1 '"name"' package.json 2>/dev/null | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
30
+ fi
31
+ fi
32
+ if [ -z "$REPO_NAME" ]; then
33
+ REPO_NAME=$(basename "$(pwd)")
34
+ fi
35
+
36
+ # Quick directory tree (2 levels, exclude common noise)
37
+ TREE=$(find . -maxdepth 2 -mindepth 1 \
38
+ -not -path '*/.git/*' \
39
+ -not -path '*/node_modules/*' \
40
+ -not -path '*/dist/*' \
41
+ -not -path '*/build/*' \
42
+ -not -path '*/.next/*' \
43
+ -not -path '*/.turbo/*' \
44
+ -not -path '*/coverage/*' \
45
+ -print 2>/dev/null | sed 's#^\./##' | sort | head -200)
46
+
47
+ # Detect package manager
48
+ PKG_MANAGER="unknown"
49
+ [ -f pnpm-lock.yaml ] && PKG_MANAGER="pnpm"
50
+ [ -f yarn.lock ] && PKG_MANAGER="yarn"
51
+ [ -f package-lock.json ] && PKG_MANAGER="npm"
52
+ [ -f Pipfile.lock ] && PKG_MANAGER="pipenv"
53
+ [ -f poetry.lock ] && PKG_MANAGER="poetry"
54
+ [ -f Cargo.lock ] && PKG_MANAGER="cargo"
55
+ [ -f go.mod ] && PKG_MANAGER="go"
56
+
57
+ # Extract scripts from package.json if Node project (supports node, jq, or grep fallback)
58
+ SCRIPTS=""
59
+ if [ -f package.json ]; then
60
+ if command -v node >/dev/null 2>&1; then
61
+ SCRIPTS=$(node -pe "try{Object.keys(require('./package.json').scripts||{}).join(', ')}catch(e){''}" 2>/dev/null || echo "")
62
+ elif command -v jq >/dev/null 2>&1; then
63
+ SCRIPTS=$(jq -r '.scripts // {} | keys | join(", ")' package.json 2>/dev/null || echo "")
64
+ else
65
+ # Fallback: extract script names with grep (crude but works for most cases)
66
+ SCRIPTS=$(grep -E '^\s+"[a-zA-Z0-9:_-]+"\s*:' package.json 2>/dev/null | \
67
+ sed -n '/"scripts"/,/^[[:space:]]*}/p' | \
68
+ grep -E '^\s+"[a-zA-Z0-9:_-]+"\s*:' | \
69
+ sed 's/.*"\([^"]*\)".*/\1/' | \
70
+ tr '\n' ', ' | sed 's/, $//')
71
+ fi
72
+ fi
73
+
74
+ # Find entry points (cheap heuristics)
75
+ ENTRYPOINTS=$(find . -maxdepth 4 -type f \
76
+ \( -name 'index.*' -o -name 'main.*' -o -name 'app.*' -o -name 'server.*' -o -name 'cli.*' \) \
77
+ -not -path '*/node_modules/*' \
78
+ -not -path '*/.git/*' \
79
+ -not -path '*/dist/*' \
80
+ -not -path '*/build/*' \
81
+ -print 2>/dev/null | sed 's#^\./##' | sort | head -50)
82
+
83
+ # Detect key config files (portable - check each individually)
84
+ CONFIGS=""
85
+ for cfg in package.json pnpm-lock.yaml yarn.lock package-lock.json \
86
+ tsconfig.json biome.json eslint.config.js eslint.config.mjs .eslintrc.js .eslintrc.json \
87
+ vitest.config.ts vitest.config.js jest.config.ts jest.config.js pytest.ini pyproject.toml \
88
+ go.mod Cargo.toml Makefile; do
89
+ [ -f "$cfg" ] && CONFIGS="$CONFIGS $cfg"
90
+ done
91
+ CONFIGS=$(echo "$CONFIGS" | xargs) # trim whitespace
92
+
93
+ # Extract test command from scripts (supports node, jq, or grep fallback)
94
+ TEST_CMD=""
95
+ if [ -f package.json ]; then
96
+ if command -v node >/dev/null 2>&1; then
97
+ TEST_CMD=$(node -pe "try{require('./package.json').scripts?.test||''}catch(e){''}" 2>/dev/null || echo "")
98
+ elif command -v jq >/dev/null 2>&1; then
99
+ TEST_CMD=$(jq -r '.scripts.test // ""' package.json 2>/dev/null || echo "")
100
+ else
101
+ # Fallback: look for test script with grep
102
+ TEST_CMD=$(grep -A1 '"test"' package.json 2>/dev/null | grep -v '"test"' | head -1 | sed 's/.*"test"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' | tr -d ',')
103
+ fi
104
+ fi
105
+ if [ -z "$TEST_CMD" ] && [ -f Makefile ]; then
106
+ grep -q "^test:" Makefile 2>/dev/null && TEST_CMD="make test"
107
+ fi
108
+
109
+ # Format testing section
110
+ if [ -n "$TEST_CMD" ]; then
111
+ TESTING_SECTION="**Test Command:** \`${TEST_CMD}\`"
112
+ else
113
+ TESTING_SECTION="*Test command will be documented after analysis.*"
114
+ fi
115
+
116
+ # Format entry points as list
117
+ ENTRYPOINTS_LIST=""
118
+ if [ -n "$ENTRYPOINTS" ]; then
119
+ ENTRYPOINTS_LIST=$(echo "$ENTRYPOINTS" | while read -r ep; do echo "- \`$ep\`"; done)
120
+ else
121
+ ENTRYPOINTS_LIST="- None detected"
122
+ fi
123
+
124
+ # Format tree as markdown code block content
125
+ TREE_FORMATTED=$(echo "$TREE" | sed 's/^/ /')
126
+
127
+ # Format configs as list
128
+ CONFIGS_LIST=""
129
+ if [ -n "$CONFIGS" ]; then
130
+ for cfg in $CONFIGS; do
131
+ CONFIGS_LIST="$CONFIGS_LIST
132
+ - \`$cfg\`"
133
+ done
134
+ else
135
+ CONFIGS_LIST="
136
+ - None detected"
137
+ fi
138
+
139
+ # Ensure output directory exists
140
+ mkdir -p .oat/repo/knowledge
141
+
142
+ # Write the thin index
143
+ cat > .oat/repo/knowledge/project-index.md <<EOF
144
+ ---
145
+ oat_generated: true
146
+ oat_generated_at: ${DATE}
147
+ oat_source_head_sha: ${HEAD_SHA}
148
+ oat_source_main_merge_base_sha: ${MERGE_BASE_SHA}
149
+ oat_index_type: thin
150
+ oat_warning: "GENERATED FILE - Thin index, will be enriched after mapper completion"
151
+ ---
152
+
153
+ # ${REPO_NAME}
154
+
155
+ ## Overview
156
+
157
+ *Overview will be enriched after codebase analysis completes.*
158
+
159
+ ## Quick Orientation
160
+
161
+ **Package Manager:** ${PKG_MANAGER}
162
+
163
+ **Key Scripts:** ${SCRIPTS:-None detected}
164
+
165
+ **Entry Points:**
166
+ ${ENTRYPOINTS_LIST}
167
+
168
+ ## Project Structure (Top-Level)
169
+
170
+ \`\`\`
171
+ ${TREE_FORMATTED}
172
+ \`\`\`
173
+
174
+ ## Configuration Files
175
+ ${CONFIGS_LIST}
176
+
177
+ ## Testing
178
+
179
+ ${TESTING_SECTION}
180
+
181
+ ## Next Steps
182
+
183
+ This is a thin index generated for quick orientation. Full details will be available after codebase analysis completes in:
184
+
185
+ - [stack.md](stack.md) - Technologies and dependencies (pending)
186
+ - [architecture.md](architecture.md) - System design and patterns (pending)
187
+ - [structure.md](structure.md) - Directory layout (pending)
188
+ - [integrations.md](integrations.md) - External services (pending)
189
+ - [testing.md](testing.md) - Test structure and practices (pending)
190
+ - [conventions.md](conventions.md) - Code style and patterns (pending)
191
+ - [concerns.md](concerns.md) - Technical debt and issues (pending)
192
+ EOF
193
+
194
+ # Count non-empty lines for accurate entrypoint count
195
+ ENTRYPOINT_COUNT=$(printf "%s\n" "$ENTRYPOINTS" | sed '/^$/d' | wc -l | tr -d ' ')
196
+
197
+ echo "Generated .oat/repo/knowledge/project-index.md (thin index)"
198
+ echo " Repo: ${REPO_NAME}"
199
+ echo " Package Manager: ${PKG_MANAGER}"
200
+ echo " Entry Points: ${ENTRYPOINT_COUNT} detected"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-agent-instructions-analyze
3
- version: 1.11.2
3
+ version: 1.12.0
4
4
  description: Run when you need to evaluate agent instruction file coverage, quality, and drift. Produces a severity-rated analysis artifact. Run before oat-agent-instructions-apply to identify what needs improvement.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -78,8 +78,10 @@ or fill in missing evidence gaps on its own.
78
78
  **Resolve providers:**
79
79
 
80
80
  ```bash
81
- SCRIPT_DIR=".agents/skills/oat-agent-instructions-analyze/scripts"
82
- TRACKING_SCRIPT=".oat/scripts/resolve-tracking.sh"
81
+ # Set SKILL_DIR to the absolute directory containing this loaded SKILL.md.
82
+ SCRIPT_DIR="$SKILL_DIR/scripts"
83
+ SCOPE_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
84
+ TRACKING_SCRIPT="$SCOPE_ROOT/.oat/scripts/resolve-tracking.sh"
83
85
  PROVIDERS=$(bash "$SCRIPT_DIR/resolve-providers.sh" --non-interactive)
84
86
  # Or with explicit override:
85
87
  # PROVIDERS=$(bash "$SCRIPT_DIR/resolve-providers.sh" --providers claude,cursor)
@@ -468,7 +470,9 @@ If the loop is disabled, note `Auto artifact review: skipped (workflow.autoArtif
468
470
  **Update tracking:**
469
471
 
470
472
  ```bash
471
- TRACKING_SCRIPT=".oat/scripts/resolve-tracking.sh"
473
+ # Set SKILL_DIR to the absolute directory containing this loaded SKILL.md.
474
+ SCOPE_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
475
+ TRACKING_SCRIPT="$SCOPE_ROOT/.oat/scripts/resolve-tracking.sh"
472
476
  ROOT_TARGET=$(bash "$TRACKING_SCRIPT" root)
473
477
  ROOT_HASH=$(echo "$ROOT_TARGET" | jq -r '.commitHash')
474
478
  ROOT_BRANCH=$(echo "$ROOT_TARGET" | jq -r '.baseBranch')
@@ -526,6 +530,7 @@ Next step: Run oat-agent-instructions-apply to act on these findings.
526
530
  - Bundle summary template: `references/bundle-summary-template.md`
527
531
  - Bundle manifest template: `references/recommendations-manifest-template.yaml`
528
532
  - Recommendation pack template: `references/recommendation-pack-template.md`
529
- - Tracking script: `.oat/scripts/resolve-tracking.sh`
533
+ - Tracking script: `$SCOPE_ROOT/.oat/scripts/resolve-tracking.sh`, where
534
+ `SCOPE_ROOT` is derived from this loaded skill's directory.
530
535
  - Provider resolution: `scripts/resolve-providers.sh`
531
536
  - File discovery: `scripts/resolve-instruction-files.sh`