@theglitchking/persistent-planning 3.0.0 → 3.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.documentation/INDEX.md +216 -0
- package/.documentation/README.md +90 -0
- package/.documentation/REGISTRY.md +80 -0
- package/.documentation/agents/INDEX.md +43 -0
- package/.documentation/agents/REGISTRY.md +38 -0
- package/.documentation/api/INDEX.md +43 -0
- package/.documentation/api/REGISTRY.md +38 -0
- package/.documentation/architecture/INDEX.md +48 -0
- package/.documentation/architecture/REGISTRY.md +53 -0
- package/{docs/reference.md → .documentation/architecture/context-engineering-principles.md} +20 -1
- package/{docs → .documentation/architecture}/lg-mode.md +17 -8
- package/.documentation/archive/README.md +46 -0
- package/.documentation/backups/INDEX.md +43 -0
- package/.documentation/backups/REGISTRY.md +38 -0
- package/.documentation/database/INDEX.md +43 -0
- package/.documentation/database/REGISTRY.md +38 -0
- package/.documentation/devops/INDEX.md +43 -0
- package/.documentation/devops/REGISTRY.md +38 -0
- package/.documentation/drafts/.gitkeep +1 -0
- package/.documentation/features/INDEX.md +43 -0
- package/.documentation/features/REGISTRY.md +38 -0
- package/.documentation/plans/INDEX.md +43 -0
- package/.documentation/plans/REGISTRY.md +38 -0
- package/.documentation/procedures/INDEX.md +42 -0
- package/.documentation/procedures/REGISTRY.md +51 -0
- package/.documentation/procedures/plan-completion-and-archive.md +151 -0
- package/.documentation/quickstart/INDEX.md +42 -0
- package/.documentation/quickstart/REGISTRY.md +51 -0
- package/{docs → .documentation/quickstart}/examples.md +20 -0
- package/.documentation/reference/INDEX.md +42 -0
- package/.documentation/reference/REGISTRY.md +51 -0
- package/{docs → .documentation/reference}/workspace-json.md +11 -5
- package/.documentation/security/INDEX.md +43 -0
- package/.documentation/security/REGISTRY.md +38 -0
- package/.documentation/standards/INDEX.md +43 -0
- package/.documentation/standards/REGISTRY.md +53 -0
- package/{docs → .documentation/standards}/atom-granularity.md +12 -5
- package/.documentation/standards/mandatory-closing-phases.md +125 -0
- package/.documentation/testing/INDEX.md +42 -0
- package/.documentation/testing/REGISTRY.md +51 -0
- package/.documentation/testing/test-suite.md +88 -0
- package/.documentation/troubleshooting/INDEX.md +43 -0
- package/.documentation/troubleshooting/REGISTRY.md +38 -0
- package/.documentation/workflows/INDEX.md +43 -0
- package/.documentation/workflows/REGISTRY.md +38 -0
- package/CHANGELOG.md +59 -0
- package/README.md +67 -7
- package/commands/archive-plan.md +66 -0
- package/commands/plan-status.md +62 -0
- package/commands/start-atom.md +3 -3
- package/commands/start-planning.md +2 -2
- package/commands/start-task.md +2 -2
- package/hooks/session-start.js +79 -8
- package/package.json +8 -4
- package/scripts/archive-plan.sh +146 -0
- package/scripts/detect-mode.sh +67 -0
- package/scripts/init-atom.sh +139 -0
- package/scripts/init-phase.sh +141 -0
- package/scripts/init-planning.sh +256 -0
- package/scripts/init-task.sh +118 -0
- package/scripts/lib/planning.sh +161 -0
- package/scripts/plan-status.sh +121 -0
- package/skills/persistent-planning/SKILL.md +34 -9
- package/templates/lg/atom.md +45 -0
- package/templates/lg/notes.md +40 -0
- package/templates/lg/phase.md +58 -0
- package/templates/lg/task.md +54 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
###############################################################################
|
|
3
|
+
# init-phase.sh - Create a new phase in lg-mode persistent-planning
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash scripts/init-phase.sh "Phase Name"
|
|
7
|
+
#
|
|
8
|
+
# Creates:
|
|
9
|
+
# .planning/<phase-slug>/phase.md (HEWTD-frontmattered phase template)
|
|
10
|
+
# .planning/<phase-slug>/notes.md (cross-cutting notes for the phase)
|
|
11
|
+
# .planning/.meta/workspace.json (mode = lg, on first phase init)
|
|
12
|
+
#
|
|
13
|
+
# Refuses to run unless mode is lg. Run init-planning.sh for sm-mode tasks.
|
|
14
|
+
###############################################################################
|
|
15
|
+
set -e
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
source "${SCRIPT_DIR}/lib/planning.sh"
|
|
19
|
+
|
|
20
|
+
case "${1:-}" in
|
|
21
|
+
-h|--help)
|
|
22
|
+
cat <<EOF
|
|
23
|
+
Usage: bash scripts/init-phase.sh "Phase Name"
|
|
24
|
+
|
|
25
|
+
Creates:
|
|
26
|
+
.planning/<phase-slug>/phase.md
|
|
27
|
+
.planning/<phase-slug>/notes.md
|
|
28
|
+
.planning/.meta/workspace.json (on first phase init, with mode=lg)
|
|
29
|
+
|
|
30
|
+
Refuses to run unless mode is lg. Run init-planning.sh for sm-mode tasks.
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
bash scripts/init-phase.sh "Foundation"
|
|
34
|
+
bash scripts/init-phase.sh "Multi-corpus refactor"
|
|
35
|
+
EOF
|
|
36
|
+
exit 0
|
|
37
|
+
;;
|
|
38
|
+
"")
|
|
39
|
+
planning_err "Phase name required."
|
|
40
|
+
echo ""
|
|
41
|
+
echo "Usage: bash scripts/init-phase.sh \"Phase Name\""
|
|
42
|
+
echo " bash scripts/init-phase.sh --help"
|
|
43
|
+
exit 1
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
PHASE_NAME="$1"
|
|
48
|
+
PHASE_SLUG=$(planning_slugify "$PHASE_NAME")
|
|
49
|
+
|
|
50
|
+
if [[ -z "$PHASE_SLUG" ]]; then
|
|
51
|
+
planning_err "Phase name must contain at least one alphanumeric character."
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Refuse to run in sm mode
|
|
56
|
+
MODE=$(planning_mode)
|
|
57
|
+
if [[ "$MODE" != "lg" ]]; then
|
|
58
|
+
planning_err "Current mode is '$MODE' but init-phase.sh requires lg mode."
|
|
59
|
+
echo ""
|
|
60
|
+
echo "Switch to lg mode by running:"
|
|
61
|
+
echo " /start-planning --mode lg \"<phase name>\""
|
|
62
|
+
echo "or by editing .planning/.meta/workspace.json directly."
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
ROOT=$(planning_root)
|
|
67
|
+
PLANNING="$(planning_dir)"
|
|
68
|
+
META="$(planning_meta_dir)"
|
|
69
|
+
WORKSPACE_JSON="$(planning_workspace_json)"
|
|
70
|
+
TODAY=$(planning_today)
|
|
71
|
+
PHASE_DIR="${PLANNING}/${PHASE_SLUG}"
|
|
72
|
+
TEMPLATE_DIR="${ROOT}/templates/lg"
|
|
73
|
+
|
|
74
|
+
# Fallback: when run from the installed plugin location, templates live in the
|
|
75
|
+
# plugin's own directory, not the project root.
|
|
76
|
+
if [[ ! -d "$TEMPLATE_DIR" ]]; then
|
|
77
|
+
TEMPLATE_DIR="${SCRIPT_DIR}/../templates/lg"
|
|
78
|
+
fi
|
|
79
|
+
if [[ ! -d "$TEMPLATE_DIR" ]]; then
|
|
80
|
+
planning_err "Cannot locate templates/lg directory. Tried:"
|
|
81
|
+
echo " ${ROOT}/templates/lg"
|
|
82
|
+
echo " ${SCRIPT_DIR}/../templates/lg"
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
planning_log "Initializing phase: ${PHASE_NAME}"
|
|
87
|
+
|
|
88
|
+
# Bootstrap .planning/.meta/workspace.json if missing
|
|
89
|
+
mkdir -p "$META"
|
|
90
|
+
if [[ ! -f "$WORKSPACE_JSON" ]]; then
|
|
91
|
+
CONTRIB=0
|
|
92
|
+
if command -v git >/dev/null 2>&1 && git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1; then
|
|
93
|
+
CONTRIB=$(git -C "$ROOT" log --since="90 days ago" --format='%ae' 2>/dev/null | sort -u | wc -l | tr -d ' ')
|
|
94
|
+
fi
|
|
95
|
+
cat > "$WORKSPACE_JSON" <<EOF
|
|
96
|
+
{
|
|
97
|
+
"schema_version": "1.0",
|
|
98
|
+
"mode": "lg",
|
|
99
|
+
"auto_detected": true,
|
|
100
|
+
"detected_contributors": ${CONTRIB},
|
|
101
|
+
"created_at": "$(date -Iseconds)"
|
|
102
|
+
}
|
|
103
|
+
EOF
|
|
104
|
+
planning_ok "Created .planning/.meta/workspace.json (mode=lg, contributors=${CONTRIB})"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# Create phase directory
|
|
108
|
+
mkdir -p "$PHASE_DIR"
|
|
109
|
+
|
|
110
|
+
# Render phase.md
|
|
111
|
+
planning_render_and_log \
|
|
112
|
+
"${TEMPLATE_DIR}/phase.md" \
|
|
113
|
+
"${PHASE_DIR}/phase.md" \
|
|
114
|
+
"phase.md at ${PHASE_DIR}/phase.md" \
|
|
115
|
+
"PHASE_TITLE_PLACEHOLDER=${PHASE_NAME}" \
|
|
116
|
+
"PHASE_SLUG_PLACEHOLDER=${PHASE_SLUG}" \
|
|
117
|
+
"PHASE_DATE_PLACEHOLDER=${TODAY}"
|
|
118
|
+
|
|
119
|
+
# Render notes.md (scoped to the phase)
|
|
120
|
+
planning_render_and_log \
|
|
121
|
+
"${TEMPLATE_DIR}/notes.md" \
|
|
122
|
+
"${PHASE_DIR}/notes.md" \
|
|
123
|
+
"notes.md at ${PHASE_DIR}/notes.md" \
|
|
124
|
+
"NOTES_TITLE_PLACEHOLDER=${PHASE_NAME} — Notes" \
|
|
125
|
+
"NOTES_SCOPE_PLACEHOLDER=${PHASE_SLUG}" \
|
|
126
|
+
"NOTES_DATE_PLACEHOLDER=${TODAY}"
|
|
127
|
+
|
|
128
|
+
# Add .planning/ to .gitignore if missing (preserve existing behavior)
|
|
129
|
+
GITIGNORE="${ROOT}/.gitignore"
|
|
130
|
+
if [[ -f "$GITIGNORE" ]] && ! grep -q "^\.planning/" "$GITIGNORE"; then
|
|
131
|
+
echo ".planning/" >> "$GITIGNORE"
|
|
132
|
+
planning_ok "Added .planning/ to .gitignore"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
echo ""
|
|
136
|
+
planning_ok "Phase '${PHASE_NAME}' ready at .planning/${PHASE_SLUG}/"
|
|
137
|
+
echo ""
|
|
138
|
+
echo "Next steps:"
|
|
139
|
+
echo " 1. Edit .planning/${PHASE_SLUG}/phase.md to describe the phase goal"
|
|
140
|
+
echo " 2. Add tasks with: /start-task \"<task name>\" --parent ${PHASE_SLUG}"
|
|
141
|
+
echo " 3. Add cross-cutting context to .planning/${PHASE_SLUG}/notes.md"
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
###############################################################################
|
|
4
|
+
# init-planning.sh - Persistent Planning Directory Setup
|
|
5
|
+
#
|
|
6
|
+
# Part of the persistent-planning plugin by TheGlitchKing
|
|
7
|
+
# https://github.com/TheGlitchKing/persistent-planning
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# bash scripts/init-planning.sh [task-name]
|
|
11
|
+
# bash scripts/init-planning.sh "Refactor database layer"
|
|
12
|
+
#
|
|
13
|
+
# What it does:
|
|
14
|
+
# 1. Creates .planning/[task-slug]/ directory (separate per task)
|
|
15
|
+
# 2. Creates task_plan.md with templates
|
|
16
|
+
# 3. Creates notes.md with templates
|
|
17
|
+
# 4. Adds .planning/ to .gitignore (optional)
|
|
18
|
+
# 5. Confirms creation and provides next steps
|
|
19
|
+
#
|
|
20
|
+
# Multiple tasks example:
|
|
21
|
+
# /start-planning "Refactor auth" -> .planning/refactor-auth/
|
|
22
|
+
# /start-planning "Debug memory leak" -> .planning/debug-memory-leak/
|
|
23
|
+
# Both plans coexist without conflicts!
|
|
24
|
+
###############################################################################
|
|
25
|
+
|
|
26
|
+
set -e
|
|
27
|
+
|
|
28
|
+
# Validate that task name was provided
|
|
29
|
+
if [ -z "$1" ]; then
|
|
30
|
+
echo "Error: Task name required"
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Usage: bash scripts/init-planning.sh \"Your Task Name\""
|
|
33
|
+
echo ""
|
|
34
|
+
echo "Examples:"
|
|
35
|
+
echo " bash scripts/init-planning.sh \"Refactor authentication\""
|
|
36
|
+
echo " bash scripts/init-planning.sh \"Debug API performance\""
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
TASK_NAME="$1"
|
|
41
|
+
|
|
42
|
+
# Convert task name to slug
|
|
43
|
+
# "Refactor Authentication" -> "refactor-authentication"
|
|
44
|
+
task_name_to_slug() {
|
|
45
|
+
local name="$1"
|
|
46
|
+
name=$(echo "$name" | tr '[:upper:]' '[:lower:]')
|
|
47
|
+
name=$(echo "$name" | sed 's/[[:space:]_]\+/-/g')
|
|
48
|
+
name=$(echo "$name" | sed 's/[^a-z0-9-]//g')
|
|
49
|
+
name=$(echo "$name" | sed 's/^-\+\|-\+$//g')
|
|
50
|
+
name=$(echo "$name" | sed 's/-\+/-/g')
|
|
51
|
+
echo "$name"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
TASK_SLUG=$(task_name_to_slug "$TASK_NAME")
|
|
55
|
+
|
|
56
|
+
# Validate slug
|
|
57
|
+
if [ -z "$TASK_SLUG" ]; then
|
|
58
|
+
echo "Error: Task name must contain at least one alphanumeric character"
|
|
59
|
+
echo "Provided: $TASK_NAME"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Determine project root
|
|
64
|
+
PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
65
|
+
PLANNING_DIR="${PROJECT_ROOT}/.planning"
|
|
66
|
+
TASK_DIR="${PLANNING_DIR}/${TASK_SLUG}"
|
|
67
|
+
|
|
68
|
+
# Color codes
|
|
69
|
+
GREEN='\033[0;32m'
|
|
70
|
+
BLUE='\033[0;34m'
|
|
71
|
+
YELLOW='\033[1;33m'
|
|
72
|
+
CYAN='\033[0;36m'
|
|
73
|
+
NC='\033[0m'
|
|
74
|
+
|
|
75
|
+
echo -e "${BLUE}Initializing Planning Structure${NC}"
|
|
76
|
+
echo ""
|
|
77
|
+
|
|
78
|
+
# Step 1: Create .planning directory
|
|
79
|
+
if [ ! -d "$PLANNING_DIR" ]; then
|
|
80
|
+
mkdir -p "$PLANNING_DIR"
|
|
81
|
+
echo -e "${GREEN}+${NC} Created .planning/ directory"
|
|
82
|
+
else
|
|
83
|
+
echo -e "${YELLOW}*${NC} .planning/ directory exists"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Step 2: Create task directory
|
|
87
|
+
if [ ! -d "$TASK_DIR" ]; then
|
|
88
|
+
mkdir -p "$TASK_DIR"
|
|
89
|
+
echo -e "${GREEN}+${NC} Created task directory: ${CYAN}.planning/${TASK_SLUG}/${NC}"
|
|
90
|
+
else
|
|
91
|
+
echo -e "${YELLOW}*${NC} Task directory already exists: ${CYAN}.planning/${TASK_SLUG}/${NC}"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Step 3: Create task_plan.md
|
|
95
|
+
TASK_PLAN_FILE="${TASK_DIR}/task_plan.md"
|
|
96
|
+
if [ ! -f "$TASK_PLAN_FILE" ]; then
|
|
97
|
+
cat > "$TASK_PLAN_FILE" << 'EOF'
|
|
98
|
+
# Task Plan: TASK_NAME_PLACEHOLDER
|
|
99
|
+
|
|
100
|
+
## Goal
|
|
101
|
+
[One sentence describing the end state]
|
|
102
|
+
|
|
103
|
+
## Phases
|
|
104
|
+
- [ ] Phase 1: Plan and setup
|
|
105
|
+
- [ ] Phase 2: Research/gather information
|
|
106
|
+
- [ ] Phase 3: Execute/build
|
|
107
|
+
- [ ] Phase 4: Review and deliver
|
|
108
|
+
- [ ] Phase 5: Validate success through comprehensive testing (MANDATORY)
|
|
109
|
+
- [ ] Phase 6: Documentation pass -- create/update/deprecate docs (MANDATORY)
|
|
110
|
+
|
|
111
|
+
> Phases 5 and 6 are mandatory and MUST stay the last two phases of this plan.
|
|
112
|
+
> Insert new work above them; never after. Renumber them if you add phases.
|
|
113
|
+
>
|
|
114
|
+
> - **Validate success**: prove the work with tests that fail if the change breaks.
|
|
115
|
+
> - **Documentation pass**: create/update/deprecate every doc this change touches --
|
|
116
|
+
> what it is, where it lives, how to fix it, how to operate it, why it matters.
|
|
117
|
+
> If hit-em-with-the-docs is installed, use it for this pass.
|
|
118
|
+
|
|
119
|
+
## Key Questions
|
|
120
|
+
1. [Question to answer]
|
|
121
|
+
2. [Question to answer]
|
|
122
|
+
|
|
123
|
+
## Decisions Made
|
|
124
|
+
- [Decision]: [Rationale]
|
|
125
|
+
|
|
126
|
+
## Errors Encountered
|
|
127
|
+
- [Error]: [Resolution]
|
|
128
|
+
|
|
129
|
+
## Status
|
|
130
|
+
**Currently in Phase 1** - Setting up planning structure
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Notes
|
|
135
|
+
- This file persists across sessions
|
|
136
|
+
- Update status after each phase
|
|
137
|
+
- Mark completed phases with [x]
|
|
138
|
+
- Save research to notes.md instead of stuffing context
|
|
139
|
+
|
|
140
|
+
## On Completion
|
|
141
|
+
This plan is complete when every checkbox above is checked. That IS the
|
|
142
|
+
completion signal -- there is no separate status to remember to flip.
|
|
143
|
+
|
|
144
|
+
When complete, archive it instead of deleting it:
|
|
145
|
+
|
|
146
|
+
/plan-status # confirm this plan reads COMPLETE
|
|
147
|
+
/archive-plan TASK_SLUG_PLACEHOLDER # -> .planning/.archive/TASK_SLUG_PLACEHOLDER/
|
|
148
|
+
|
|
149
|
+
Archiving moves this directory to the gitignored .planning/.archive/ and stamps
|
|
150
|
+
it archived. Nothing is destroyed.
|
|
151
|
+
EOF
|
|
152
|
+
|
|
153
|
+
sed -i "s/TASK_NAME_PLACEHOLDER/${TASK_NAME}/g" "$TASK_PLAN_FILE"
|
|
154
|
+
sed -i "s/TASK_SLUG_PLACEHOLDER/${TASK_SLUG}/g" "$TASK_PLAN_FILE"
|
|
155
|
+
echo -e "${GREEN}+${NC} Created task_plan.md"
|
|
156
|
+
else
|
|
157
|
+
echo -e "${YELLOW}*${NC} task_plan.md already exists (not overwritten)"
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
# Step 4: Create notes.md
|
|
161
|
+
NOTES_FILE="${TASK_DIR}/notes.md"
|
|
162
|
+
if [ ! -f "$NOTES_FILE" ]; then
|
|
163
|
+
cat > "$NOTES_FILE" << 'EOF'
|
|
164
|
+
# Notes: TASK_NAME_PLACEHOLDER
|
|
165
|
+
|
|
166
|
+
## Key Findings
|
|
167
|
+
- [Finding 1]
|
|
168
|
+
- [Finding 2]
|
|
169
|
+
|
|
170
|
+
## Research Sources
|
|
171
|
+
- [Source 1]: [URL or reference]
|
|
172
|
+
- [Source 2]: [URL or reference]
|
|
173
|
+
|
|
174
|
+
## Synthesized Findings
|
|
175
|
+
|
|
176
|
+
### [Category/Topic 1]
|
|
177
|
+
- [Finding]
|
|
178
|
+
- [Finding]
|
|
179
|
+
|
|
180
|
+
### [Category/Topic 2]
|
|
181
|
+
- [Finding]
|
|
182
|
+
- [Finding]
|
|
183
|
+
|
|
184
|
+
## Decisions Made
|
|
185
|
+
- [Decision]: [Rationale]
|
|
186
|
+
- [Decision]: [Rationale]
|
|
187
|
+
|
|
188
|
+
## Errors & Solutions
|
|
189
|
+
- [Error]: [Resolution]
|
|
190
|
+
- [Error]: [Resolution]
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Append-Only Log
|
|
195
|
+
Store findings here as you discover them. This builds a searchable history.
|
|
196
|
+
|
|
197
|
+
### [Date/Time]
|
|
198
|
+
- [What I found/did]
|
|
199
|
+
EOF
|
|
200
|
+
|
|
201
|
+
sed -i "s/TASK_NAME_PLACEHOLDER/${TASK_NAME}/g" "$NOTES_FILE"
|
|
202
|
+
echo -e "${GREEN}+${NC} Created notes.md"
|
|
203
|
+
else
|
|
204
|
+
echo -e "${YELLOW}*${NC} notes.md already exists (not overwritten)"
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# Step 5: Update .gitignore
|
|
208
|
+
if [ -f "${PROJECT_ROOT}/.gitignore" ]; then
|
|
209
|
+
if ! grep -q "^\.planning/" "${PROJECT_ROOT}/.gitignore"; then
|
|
210
|
+
echo ".planning/" >> "${PROJECT_ROOT}/.gitignore"
|
|
211
|
+
echo -e "${GREEN}+${NC} Added .planning/ to .gitignore"
|
|
212
|
+
else
|
|
213
|
+
echo -e "${YELLOW}*${NC} .planning/ already in .gitignore"
|
|
214
|
+
fi
|
|
215
|
+
else
|
|
216
|
+
echo -e "${YELLOW}*${NC} No .gitignore found (not added)"
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
# Step 6: List other active tasks
|
|
220
|
+
OTHER_TASKS=$(find "$PLANNING_DIR" -maxdepth 1 -type d -not -name ".planning" -not -path "$TASK_DIR" 2>/dev/null | wc -l)
|
|
221
|
+
if [ "$OTHER_TASKS" -gt 0 ]; then
|
|
222
|
+
echo ""
|
|
223
|
+
echo -e "${CYAN}Other active tasks:${NC}"
|
|
224
|
+
find "$PLANNING_DIR" -maxdepth 1 -type d -not -name ".planning" -not -path "$TASK_DIR" | sort | while read dir; do
|
|
225
|
+
task_slug=$(basename "$dir")
|
|
226
|
+
echo " .planning/${task_slug}/"
|
|
227
|
+
done
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
# Step 7: Confirmation
|
|
231
|
+
echo ""
|
|
232
|
+
echo -e "${GREEN}=====================================${NC}"
|
|
233
|
+
echo -e "${GREEN}Task Plan Ready${NC}"
|
|
234
|
+
echo -e "${GREEN}=====================================${NC}"
|
|
235
|
+
echo ""
|
|
236
|
+
|
|
237
|
+
echo -e "${BLUE}Task:${NC} ${TASK_NAME}"
|
|
238
|
+
echo -e "${BLUE}Location:${NC} .planning/${TASK_SLUG}/"
|
|
239
|
+
echo ""
|
|
240
|
+
|
|
241
|
+
echo -e "${BLUE}Files:${NC}"
|
|
242
|
+
echo " task_plan.md (your task plan)"
|
|
243
|
+
echo " notes.md (research & findings)"
|
|
244
|
+
echo ""
|
|
245
|
+
|
|
246
|
+
echo -e "${BLUE}Next steps:${NC}"
|
|
247
|
+
echo " 1. Edit .planning/${TASK_SLUG}/task_plan.md to define your phases"
|
|
248
|
+
echo " 2. As you work, update the Status section"
|
|
249
|
+
echo " 3. Save findings to .planning/${TASK_SLUG}/notes.md"
|
|
250
|
+
echo " 4. Re-read task_plan.md before major decisions"
|
|
251
|
+
echo ""
|
|
252
|
+
|
|
253
|
+
echo -e "${BLUE}Cleanup:${NC}"
|
|
254
|
+
echo " rm -rf .planning/${TASK_SLUG}/ # Remove this task"
|
|
255
|
+
echo " rm -rf .planning/ # Remove all tasks"
|
|
256
|
+
echo ""
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
###############################################################################
|
|
3
|
+
# init-task.sh - Create a new task under a phase in lg-mode persistent-planning
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash scripts/init-task.sh "Task Name" --parent <phase-slug>
|
|
7
|
+
#
|
|
8
|
+
# Creates:
|
|
9
|
+
# .planning/<phase-slug>/<task-slug>/task.md
|
|
10
|
+
# .planning/<phase-slug>/<task-slug>/notes.md
|
|
11
|
+
# .planning/<phase-slug>/<task-slug>/atoms/ (empty dir for future atoms)
|
|
12
|
+
#
|
|
13
|
+
# Refuses if mode is not lg, or if --parent doesn't reference an existing phase.
|
|
14
|
+
###############################################################################
|
|
15
|
+
set -e
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
source "${SCRIPT_DIR}/lib/planning.sh"
|
|
19
|
+
|
|
20
|
+
# Parse arguments
|
|
21
|
+
TASK_NAME=""
|
|
22
|
+
PARENT_PHASE=""
|
|
23
|
+
while [[ $# -gt 0 ]]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
--parent)
|
|
26
|
+
PARENT_PHASE="$2"
|
|
27
|
+
shift 2
|
|
28
|
+
;;
|
|
29
|
+
-h|--help)
|
|
30
|
+
cat <<EOF
|
|
31
|
+
Usage: bash scripts/init-task.sh "Task Name" --parent <phase-slug>
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
bash scripts/init-task.sh "HEWTD schema extension" --parent foundation
|
|
35
|
+
bash scripts/init-task.sh "Multi-corpus refactor" --parent semantic-memory-core
|
|
36
|
+
EOF
|
|
37
|
+
exit 0
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
if [[ -z "$TASK_NAME" ]]; then
|
|
41
|
+
TASK_NAME="$1"
|
|
42
|
+
fi
|
|
43
|
+
shift
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
if [[ -z "$TASK_NAME" || -z "$PARENT_PHASE" ]]; then
|
|
49
|
+
planning_err "Both task name and --parent <phase-slug> are required."
|
|
50
|
+
echo "Usage: bash scripts/init-task.sh \"Task Name\" --parent <phase-slug>"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
TASK_SLUG=$(planning_slugify "$TASK_NAME")
|
|
55
|
+
|
|
56
|
+
if [[ -z "$TASK_SLUG" ]]; then
|
|
57
|
+
planning_err "Task name must contain at least one alphanumeric character."
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Refuse non-lg
|
|
62
|
+
MODE=$(planning_mode)
|
|
63
|
+
if [[ "$MODE" != "lg" ]]; then
|
|
64
|
+
planning_err "Current mode is '$MODE' but init-task.sh requires lg mode."
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
ROOT=$(planning_root)
|
|
69
|
+
PLANNING="$(planning_dir)"
|
|
70
|
+
TODAY=$(planning_today)
|
|
71
|
+
PHASE_DIR="${PLANNING}/${PARENT_PHASE}"
|
|
72
|
+
TASK_DIR="${PHASE_DIR}/${TASK_SLUG}"
|
|
73
|
+
TEMPLATE_DIR="${ROOT}/templates/lg"
|
|
74
|
+
|
|
75
|
+
if [[ ! -d "$TEMPLATE_DIR" ]]; then
|
|
76
|
+
TEMPLATE_DIR="${SCRIPT_DIR}/../templates/lg"
|
|
77
|
+
fi
|
|
78
|
+
if [[ ! -d "$TEMPLATE_DIR" ]]; then
|
|
79
|
+
planning_err "Cannot locate templates/lg directory."
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Validate parent phase exists
|
|
84
|
+
if [[ ! -f "${PHASE_DIR}/phase.md" ]]; then
|
|
85
|
+
planning_err "Parent phase not found: .planning/${PARENT_PHASE}/phase.md"
|
|
86
|
+
echo "Create the phase first with:"
|
|
87
|
+
echo " /start-planning \"<phase name>\" (which runs init-phase.sh in lg mode)"
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
planning_log "Initializing task: ${TASK_NAME} (parent: ${PARENT_PHASE})"
|
|
92
|
+
|
|
93
|
+
mkdir -p "${TASK_DIR}/atoms"
|
|
94
|
+
|
|
95
|
+
planning_render_and_log \
|
|
96
|
+
"${TEMPLATE_DIR}/task.md" \
|
|
97
|
+
"${TASK_DIR}/task.md" \
|
|
98
|
+
"task.md at ${TASK_DIR}/task.md" \
|
|
99
|
+
"TASK_TITLE_PLACEHOLDER=${TASK_NAME}" \
|
|
100
|
+
"TASK_SLUG_PLACEHOLDER=${TASK_SLUG}" \
|
|
101
|
+
"PHASE_SLUG_PLACEHOLDER=${PARENT_PHASE}" \
|
|
102
|
+
"TASK_DATE_PLACEHOLDER=${TODAY}"
|
|
103
|
+
|
|
104
|
+
planning_render_and_log \
|
|
105
|
+
"${TEMPLATE_DIR}/notes.md" \
|
|
106
|
+
"${TASK_DIR}/notes.md" \
|
|
107
|
+
"notes.md at ${TASK_DIR}/notes.md" \
|
|
108
|
+
"NOTES_TITLE_PLACEHOLDER=${TASK_NAME} — Notes" \
|
|
109
|
+
"NOTES_SCOPE_PLACEHOLDER=${PARENT_PHASE}/${TASK_SLUG}" \
|
|
110
|
+
"NOTES_DATE_PLACEHOLDER=${TODAY}"
|
|
111
|
+
|
|
112
|
+
echo ""
|
|
113
|
+
planning_ok "Task '${TASK_NAME}' ready at .planning/${PARENT_PHASE}/${TASK_SLUG}/"
|
|
114
|
+
echo ""
|
|
115
|
+
echo "Next steps:"
|
|
116
|
+
echo " 1. Edit .planning/${PARENT_PHASE}/${TASK_SLUG}/task.md to describe the goal"
|
|
117
|
+
echo " 2. Add atoms with: /start-atom \"<atom name>\" --parent ${TASK_SLUG}"
|
|
118
|
+
echo " (or add inline atom checkboxes in task.md for simple atoms)"
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
###############################################################################
|
|
3
|
+
# scripts/lib/planning.sh - Shared helpers for persistent-planning init scripts
|
|
4
|
+
#
|
|
5
|
+
# Source this file from init-phase.sh, init-task.sh, init-atom.sh, and any
|
|
6
|
+
# other planning-related script that needs slug, root, mode, or template
|
|
7
|
+
# rendering helpers.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# #!/bin/bash
|
|
11
|
+
# set -e
|
|
12
|
+
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
# source "${SCRIPT_DIR}/lib/planning.sh"
|
|
14
|
+
#
|
|
15
|
+
# Provides:
|
|
16
|
+
# - planning_slugify "Some Name" → "some-name" (echoed)
|
|
17
|
+
# - planning_root → prints project root (CLAUDE_PROJECT_DIR or pwd)
|
|
18
|
+
# - planning_dir → prints "<root>/.planning"
|
|
19
|
+
# - planning_meta_dir → prints "<root>/.planning/.meta"
|
|
20
|
+
# - planning_workspace_json → prints "<meta>/workspace.json"
|
|
21
|
+
# - planning_mode → prints active mode (sm | lg) via detect-mode.sh
|
|
22
|
+
# - planning_today → prints today's date as YYYY-MM-DD
|
|
23
|
+
# - planning_render_template "<src>" "<dest>" "PLACEHOLDER1=value1" "PLACEHOLDER2=value2" ...
|
|
24
|
+
# Renders a template file by sed-substituting PLACEHOLDER tokens.
|
|
25
|
+
# Refuses to overwrite existing dest unless PLANNING_FORCE=1 in env.
|
|
26
|
+
# - planning_color_<name> → ANSI color codes (green, blue, yellow, cyan, red, reset)
|
|
27
|
+
# (only set when stdout is a tty; empty otherwise)
|
|
28
|
+
# - Color-coded log helpers: planning_log, planning_ok, planning_warn, planning_err
|
|
29
|
+
###############################################################################
|
|
30
|
+
|
|
31
|
+
# Color codes (only when stdout is a tty)
|
|
32
|
+
if [[ -t 1 ]]; then
|
|
33
|
+
planning_color_green='\033[0;32m'
|
|
34
|
+
planning_color_blue='\033[0;34m'
|
|
35
|
+
planning_color_yellow='\033[1;33m'
|
|
36
|
+
planning_color_cyan='\033[0;36m'
|
|
37
|
+
planning_color_red='\033[0;31m'
|
|
38
|
+
planning_color_reset='\033[0m'
|
|
39
|
+
else
|
|
40
|
+
planning_color_green=''
|
|
41
|
+
planning_color_blue=''
|
|
42
|
+
planning_color_yellow=''
|
|
43
|
+
planning_color_cyan=''
|
|
44
|
+
planning_color_red=''
|
|
45
|
+
planning_color_reset=''
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
planning_log() { printf "${planning_color_blue}[planning]${planning_color_reset} %s\n" "$*"; }
|
|
49
|
+
planning_ok() { printf "${planning_color_green}[planning]${planning_color_reset} %s\n" "$*"; }
|
|
50
|
+
planning_warn() { printf "${planning_color_yellow}[planning]${planning_color_reset} %s\n" "$*"; }
|
|
51
|
+
planning_err() { printf "${planning_color_red}[planning]${planning_color_reset} %s\n" "$*" >&2; }
|
|
52
|
+
|
|
53
|
+
planning_slugify() {
|
|
54
|
+
local name="$1"
|
|
55
|
+
name=$(echo "$name" | tr '[:upper:]' '[:lower:]')
|
|
56
|
+
name=$(echo "$name" | sed 's/[[:space:]_]\+/-/g')
|
|
57
|
+
name=$(echo "$name" | sed 's/[^a-z0-9-]//g')
|
|
58
|
+
name=$(echo "$name" | sed 's/^-\+\|-\+$//g')
|
|
59
|
+
name=$(echo "$name" | sed 's/-\+/-/g')
|
|
60
|
+
echo "$name"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
planning_root() {
|
|
64
|
+
echo "${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
planning_dir() {
|
|
68
|
+
echo "$(planning_root)/.planning"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
planning_meta_dir() {
|
|
72
|
+
echo "$(planning_dir)/.meta"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
planning_workspace_json() {
|
|
76
|
+
echo "$(planning_meta_dir)/workspace.json"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
planning_today() {
|
|
80
|
+
date '+%Y-%m-%d'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
planning_mode() {
|
|
84
|
+
# Resolve via detect-mode.sh (in the same scripts/ dir as the caller's library).
|
|
85
|
+
local lib_dir
|
|
86
|
+
lib_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
87
|
+
local detect="${lib_dir}/../detect-mode.sh"
|
|
88
|
+
if [[ -x "$detect" ]]; then
|
|
89
|
+
bash "$detect"
|
|
90
|
+
else
|
|
91
|
+
echo "sm"
|
|
92
|
+
fi
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# planning_render_template <template_src> <dest_path> <PLACEHOLDER1=value1> ...
|
|
96
|
+
# Renders a template file by sed-substituting placeholders.
|
|
97
|
+
#
|
|
98
|
+
# Return codes:
|
|
99
|
+
# 0 → rendered fresh
|
|
100
|
+
# 2 → skipped (dest already exists; pass PLANNING_FORCE=1 to overwrite)
|
|
101
|
+
# 1 → error (template not found, etc.)
|
|
102
|
+
#
|
|
103
|
+
# Callers can branch on the return code to log accurately.
|
|
104
|
+
planning_render_template() {
|
|
105
|
+
local src="$1"
|
|
106
|
+
local dest="$2"
|
|
107
|
+
shift 2
|
|
108
|
+
|
|
109
|
+
if [[ ! -f "$src" ]]; then
|
|
110
|
+
planning_err "Template not found: $src"
|
|
111
|
+
return 1
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [[ -f "$dest" && "${PLANNING_FORCE:-0}" != "1" ]]; then
|
|
115
|
+
planning_warn "Destination already exists, skipping: $dest"
|
|
116
|
+
planning_warn " (re-run with PLANNING_FORCE=1 to overwrite)"
|
|
117
|
+
return 2
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Copy template to dest
|
|
121
|
+
cp "$src" "$dest"
|
|
122
|
+
|
|
123
|
+
# Apply substitutions
|
|
124
|
+
for kv in "$@"; do
|
|
125
|
+
local key="${kv%%=*}"
|
|
126
|
+
local value="${kv#*=}"
|
|
127
|
+
# Use a safe delimiter (~) since values may contain /
|
|
128
|
+
# Escape & and ~ in value
|
|
129
|
+
local escaped_value
|
|
130
|
+
escaped_value=$(printf '%s\n' "$value" | sed -e 's/[\&~]/\\&/g')
|
|
131
|
+
sed -i "s~${key}~${escaped_value}~g" "$dest"
|
|
132
|
+
done
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# planning_render_and_log <template_src> <dest_path> <relative_label> <PLACEHOLDER=val> ...
|
|
137
|
+
# Wraps planning_render_template with accurate logging:
|
|
138
|
+
# - Prints "Created <relative_label>" only when the template was actually rendered
|
|
139
|
+
# - Prints nothing extra when skipped (the warn from render_template already covered it)
|
|
140
|
+
# - Lets the script continue (set -e tolerant) regardless of skip vs render
|
|
141
|
+
planning_render_and_log() {
|
|
142
|
+
local src="$1"
|
|
143
|
+
local dest="$2"
|
|
144
|
+
local label="$3"
|
|
145
|
+
shift 3
|
|
146
|
+
|
|
147
|
+
local rc=0
|
|
148
|
+
planning_render_template "$src" "$dest" "$@" || rc=$?
|
|
149
|
+
case $rc in
|
|
150
|
+
0)
|
|
151
|
+
planning_ok "Created ${label}"
|
|
152
|
+
;;
|
|
153
|
+
2)
|
|
154
|
+
# Already covered by the warn inside planning_render_template
|
|
155
|
+
;;
|
|
156
|
+
*)
|
|
157
|
+
planning_err "Failed to render ${label} (rc=$rc)"
|
|
158
|
+
return $rc
|
|
159
|
+
;;
|
|
160
|
+
esac
|
|
161
|
+
}
|