@bvdm/delano 0.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/HANDBOOK.md +1511 -0
- package/README.md +122 -0
- package/assets/install-manifest.json +102 -0
- package/assets/payload/.agents/README.md +12 -0
- package/assets/payload/.agents/adapters/claude/README.md +5 -0
- package/assets/payload/.agents/adapters/codex/README.md +5 -0
- package/assets/payload/.agents/adapters/opencode/README.md +5 -0
- package/assets/payload/.agents/adapters/pi/README.md +5 -0
- package/assets/payload/.agents/common/README.md +3 -0
- package/assets/payload/.agents/hooks/README.md +11 -0
- package/assets/payload/.agents/hooks/bash-worktree-fix.sh +7 -0
- package/assets/payload/.agents/hooks/post-tool-logger.js +18 -0
- package/assets/payload/.agents/hooks/session-tracker.js +17 -0
- package/assets/payload/.agents/hooks/user-prompt-logger.js +18 -0
- package/assets/payload/.agents/logs/.gitkeep +0 -0
- package/assets/payload/.agents/logs/schema.md +42 -0
- package/assets/payload/.agents/rules/README.md +12 -0
- package/assets/payload/.agents/rules/agent-coordination.md +5 -0
- package/assets/payload/.agents/rules/datetime.md +5 -0
- package/assets/payload/.agents/rules/frontmatter-operations.md +6 -0
- package/assets/payload/.agents/rules/github-operations.md +5 -0
- package/assets/payload/.agents/rules/path-standards.md +5 -0
- package/assets/payload/.agents/rules/test-execution.md +5 -0
- package/assets/payload/.agents/rules/worktree-operations.md +5 -0
- package/assets/payload/.agents/scripts/README.md +31 -0
- package/assets/payload/.agents/scripts/check-path-standards.sh +26 -0
- package/assets/payload/.agents/scripts/fix-path-standards.sh +14 -0
- package/assets/payload/.agents/scripts/git-sparse-download.sh +162 -0
- package/assets/payload/.agents/scripts/log-event.js +33 -0
- package/assets/payload/.agents/scripts/log-event.sh +5 -0
- package/assets/payload/.agents/scripts/pm/blocked.sh +36 -0
- package/assets/payload/.agents/scripts/pm/epic-list.sh +34 -0
- package/assets/payload/.agents/scripts/pm/in-progress.sh +36 -0
- package/assets/payload/.agents/scripts/pm/init.sh +139 -0
- package/assets/payload/.agents/scripts/pm/next.sh +110 -0
- package/assets/payload/.agents/scripts/pm/prd-list.sh +34 -0
- package/assets/payload/.agents/scripts/pm/search.sh +13 -0
- package/assets/payload/.agents/scripts/pm/standup.sh +19 -0
- package/assets/payload/.agents/scripts/pm/status.sh +61 -0
- package/assets/payload/.agents/scripts/pm/validate.sh +309 -0
- package/assets/payload/.agents/scripts/query-log.sh +57 -0
- package/assets/payload/.agents/scripts/test-and-log.sh +28 -0
- package/assets/payload/.agents/skills/.gitkeep +0 -0
- package/assets/payload/.agents/skills/README.md +23 -0
- package/assets/payload/.agents/skills/breakdown-skill/SKILL.md +40 -0
- package/assets/payload/.agents/skills/breakdown-skill/references/runbook.md +16 -0
- package/assets/payload/.agents/skills/breakdown-skill/templates/ambiguity-report.md +11 -0
- package/assets/payload/.agents/skills/breakdown-skill/templates/task-batch-summary.md +11 -0
- package/assets/payload/.agents/skills/closeout-skill/SKILL.md +42 -0
- package/assets/payload/.agents/skills/closeout-skill/references/runbook.md +16 -0
- package/assets/payload/.agents/skills/closeout-skill/templates/closure-checklist.md +7 -0
- package/assets/payload/.agents/skills/closeout-skill/templates/outcome-review.md +11 -0
- package/assets/payload/.agents/skills/discovery-skill/SKILL.md +44 -0
- package/assets/payload/.agents/skills/discovery-skill/references/runbook.md +14 -0
- package/assets/payload/.agents/skills/discovery-skill/templates/clarification-questions.md +18 -0
- package/assets/payload/.agents/skills/discovery-skill/templates/discovery-summary.md +14 -0
- package/assets/payload/.agents/skills/execution-skill/SKILL.md +42 -0
- package/assets/payload/.agents/skills/execution-skill/references/runbook.md +16 -0
- package/assets/payload/.agents/skills/execution-skill/templates/blocker-update.md +13 -0
- package/assets/payload/.agents/skills/execution-skill/templates/stream-update.md +9 -0
- package/assets/payload/.agents/skills/learning-skill/SKILL.md +41 -0
- package/assets/payload/.agents/skills/learning-skill/references/runbook.md +13 -0
- package/assets/payload/.agents/skills/learning-skill/templates/improvement-backlog.md +10 -0
- package/assets/payload/.agents/skills/learning-skill/templates/retrospective.md +11 -0
- package/assets/payload/.agents/skills/planning-skill/SKILL.md +40 -0
- package/assets/payload/.agents/skills/planning-skill/references/runbook.md +15 -0
- package/assets/payload/.agents/skills/planning-skill/templates/architecture-decision.md +15 -0
- package/assets/payload/.agents/skills/planning-skill/templates/workstream-definition.md +13 -0
- package/assets/payload/.agents/skills/quality-skill/SKILL.md +40 -0
- package/assets/payload/.agents/skills/quality-skill/references/runbook.md +14 -0
- package/assets/payload/.agents/skills/quality-skill/templates/gate-decision.md +10 -0
- package/assets/payload/.agents/skills/quality-skill/templates/quality-evidence.md +16 -0
- package/assets/payload/.agents/skills/sync-skill/SKILL.md +41 -0
- package/assets/payload/.agents/skills/sync-skill/references/runbook.md +17 -0
- package/assets/payload/.agents/skills/sync-skill/templates/conflict-resolution-actions.md +10 -0
- package/assets/payload/.agents/skills/sync-skill/templates/drift-report.md +14 -0
- package/assets/payload/.delano/README.md +7 -0
- package/assets/payload/.gitattributes +14 -0
- package/assets/payload/.project/context/README.md +15 -0
- package/assets/payload/.project/context/gui-testing.md +20 -0
- package/assets/payload/.project/context/product-context.md +17 -0
- package/assets/payload/.project/context/progress.md +23 -0
- package/assets/payload/.project/context/project-brief.md +13 -0
- package/assets/payload/.project/context/project-overview.md +14 -0
- package/assets/payload/.project/context/project-structure.md +24 -0
- package/assets/payload/.project/context/project-style-guide.md +17 -0
- package/assets/payload/.project/context/system-patterns.md +22 -0
- package/assets/payload/.project/context/tech-context.md +19 -0
- package/assets/payload/.project/projects/.gitkeep +0 -0
- package/assets/payload/.project/registry/linear-map.json +6 -0
- package/assets/payload/.project/registry/migration-map.json +5 -0
- package/assets/payload/.project/templates/completion-summary.md +16 -0
- package/assets/payload/.project/templates/plan.md +30 -0
- package/assets/payload/.project/templates/progress-update.md +20 -0
- package/assets/payload/.project/templates/spec.md +42 -0
- package/assets/payload/.project/templates/task.md +33 -0
- package/assets/payload/.project/templates/workstream.md +19 -0
- package/assets/payload/HANDBOOK.md +1511 -0
- package/assets/payload/install-delano.sh +311 -0
- package/bin/delano.js +13 -0
- package/install-delano.sh +311 -0
- package/package.json +26 -0
- package/src/cli/commands/install.js +57 -0
- package/src/cli/commands/wrapper.js +26 -0
- package/src/cli/index.js +97 -0
- package/src/cli/lib/errors.js +11 -0
- package/src/cli/lib/install.js +261 -0
- package/src/cli/lib/pm.js +29 -0
- package/src/cli/lib/runtime.js +122 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Git Sparse Checkout - Download specific directories from GitHub repositories
|
|
4
|
+
# Usage: ./git-sparse-download.sh <repo_url> <directory_path> [target_name]
|
|
5
|
+
# Example: ./git-sparse-download.sh https://github.com/google/guava guava-gwt
|
|
6
|
+
# Example: ./git-sparse-download.sh https://github.com/ComposioHQ/awesome-claude-skills skill-creator skills/skill-creator
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
# Color codes for output
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[0;33m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
|
|
16
|
+
# Function to print colored output
|
|
17
|
+
print_error() { echo -e "${RED}❌ $1${NC}"; }
|
|
18
|
+
print_success() { echo -e "${GREEN}✅ $1${NC}"; }
|
|
19
|
+
print_info() { echo -e "${YELLOW}ℹ️ $1${NC}"; }
|
|
20
|
+
|
|
21
|
+
# Check arguments
|
|
22
|
+
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
|
23
|
+
echo "Usage: $0 <repo_url> <directory_path> [target_name]"
|
|
24
|
+
echo ""
|
|
25
|
+
echo "Arguments:"
|
|
26
|
+
echo " repo_url - GitHub repository URL (e.g., https://github.com/user/repo)"
|
|
27
|
+
echo " directory_path - Path to the directory in the repo (e.g., src/components)"
|
|
28
|
+
echo " target_name - Optional: Name for the downloaded directory (defaults to directory name)"
|
|
29
|
+
echo ""
|
|
30
|
+
echo "Examples:"
|
|
31
|
+
echo " $0 https://github.com/google/guava guava-gwt"
|
|
32
|
+
echo " $0 https://github.com/ComposioHQ/awesome-claude-skills skill-creator skills/my-skill"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
REPO_URL=$1
|
|
37
|
+
DIR_PATH=$2
|
|
38
|
+
TARGET_NAME=${3:-$(basename "$DIR_PATH")}
|
|
39
|
+
|
|
40
|
+
# Validate repo URL
|
|
41
|
+
if [[ ! "$REPO_URL" =~ ^https?://github\.com/.*$ ]]; then
|
|
42
|
+
print_error "Invalid GitHub URL. URL must start with https://github.com/"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Clean up directory path (remove leading/trailing slashes)
|
|
47
|
+
DIR_PATH=$(echo "$DIR_PATH" | sed 's|^/||;s|/$||')
|
|
48
|
+
|
|
49
|
+
print_info "Repository: $REPO_URL"
|
|
50
|
+
print_info "Directory: $DIR_PATH"
|
|
51
|
+
print_info "Target: $TARGET_NAME"
|
|
52
|
+
|
|
53
|
+
# Create a temporary directory for the operation
|
|
54
|
+
TEMP_DIR=$(mktemp -d)
|
|
55
|
+
trap "rm -rf $TEMP_DIR" EXIT
|
|
56
|
+
|
|
57
|
+
print_info "Initializing sparse checkout..."
|
|
58
|
+
|
|
59
|
+
# Navigate to temp directory
|
|
60
|
+
cd "$TEMP_DIR" || exit 1
|
|
61
|
+
|
|
62
|
+
# Initialize empty git repo
|
|
63
|
+
git init -q 2>/dev/null || {
|
|
64
|
+
print_error "Failed to initialize git repository"
|
|
65
|
+
exit 1
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Add remote
|
|
69
|
+
git remote add origin "$REPO_URL" 2>/dev/null || {
|
|
70
|
+
print_error "Failed to add remote repository"
|
|
71
|
+
exit 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Configure sparse checkout
|
|
75
|
+
git config core.sparseCheckout true
|
|
76
|
+
|
|
77
|
+
# Handle both old and new sparse-checkout patterns
|
|
78
|
+
# Try new way first (Git 2.25+), fall back to old way
|
|
79
|
+
if command -v git sparse-checkout >/dev/null 2>&1 && git sparse-checkout init --cone 2>/dev/null; then
|
|
80
|
+
# New sparse-checkout command available
|
|
81
|
+
git sparse-checkout set "$DIR_PATH" 2>/dev/null || echo "$DIR_PATH" >> .git/info/sparse-checkout
|
|
82
|
+
else
|
|
83
|
+
# Fall back to old method
|
|
84
|
+
echo "$DIR_PATH/*" >> .git/info/sparse-checkout
|
|
85
|
+
echo "$DIR_PATH/**" >> .git/info/sparse-checkout
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Attempt to fetch and checkout
|
|
89
|
+
print_info "Downloading $DIR_PATH from repository..."
|
|
90
|
+
|
|
91
|
+
# Determine the default branch
|
|
92
|
+
DEFAULT_BRANCH=$(git ls-remote --symref origin HEAD 2>/dev/null | grep "ref:" | sed 's/.*refs\/heads\///' | sed 's/[[:space:]].*$//')
|
|
93
|
+
if [ -z "$DEFAULT_BRANCH" ]; then
|
|
94
|
+
# Try common branch names
|
|
95
|
+
for branch in main master; do
|
|
96
|
+
if git ls-remote --heads origin $branch 2>/dev/null | grep -q $branch; then
|
|
97
|
+
DEFAULT_BRANCH=$branch
|
|
98
|
+
break
|
|
99
|
+
fi
|
|
100
|
+
done
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# If we still don't have a branch, default to main
|
|
104
|
+
DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
|
|
105
|
+
|
|
106
|
+
print_info "Using branch: $DEFAULT_BRANCH"
|
|
107
|
+
|
|
108
|
+
# Fetch with depth 1 for speed
|
|
109
|
+
if ! git fetch --depth=1 origin "$DEFAULT_BRANCH" 2>/dev/null; then
|
|
110
|
+
print_error "Failed to fetch from repository. Please check the URL and your internet connection."
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Checkout the fetched branch
|
|
115
|
+
if ! git checkout -f "origin/$DEFAULT_BRANCH" 2>/dev/null; then
|
|
116
|
+
print_error "Failed to checkout repository content"
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Check if the directory exists
|
|
121
|
+
if [ ! -d "$DIR_PATH" ]; then
|
|
122
|
+
print_error "Directory '$DIR_PATH' not found in repository"
|
|
123
|
+
print_info "Available directories in root:"
|
|
124
|
+
ls -d */ 2>/dev/null | head -10 || echo " (none found)"
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# Move the downloaded folder to the user's original location
|
|
129
|
+
print_info "Moving files to current directory..."
|
|
130
|
+
|
|
131
|
+
# Ensure we're back in the original directory
|
|
132
|
+
cd "$OLDPWD" || exit 1
|
|
133
|
+
|
|
134
|
+
# Check if target already exists
|
|
135
|
+
if [ -e "$TARGET_NAME" ]; then
|
|
136
|
+
print_error "Target '$TARGET_NAME' already exists in current directory"
|
|
137
|
+
echo "Please remove it first or choose a different target name"
|
|
138
|
+
exit 1
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Move the directory
|
|
142
|
+
if mv "$TEMP_DIR/$DIR_PATH" "$TARGET_NAME" 2>/dev/null; then
|
|
143
|
+
print_success "Successfully downloaded '$DIR_PATH' as '$TARGET_NAME'"
|
|
144
|
+
|
|
145
|
+
# Show what was downloaded
|
|
146
|
+
echo ""
|
|
147
|
+
echo "Downloaded structure:"
|
|
148
|
+
if command -v tree >/dev/null 2>&1; then
|
|
149
|
+
tree -L 2 "$TARGET_NAME" 2>/dev/null | head -20
|
|
150
|
+
else
|
|
151
|
+
ls -la "$TARGET_NAME" 2>/dev/null | head -10
|
|
152
|
+
fi
|
|
153
|
+
else
|
|
154
|
+
print_error "Failed to move directory to target location"
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Additional info
|
|
159
|
+
echo ""
|
|
160
|
+
print_info "To use this as a Delano skill, copy it to .agents/skills/"
|
|
161
|
+
print_info "Compatibility mirror: .claude/skills/ when present"
|
|
162
|
+
print_info "Example: mv $TARGET_NAME .agents/skills/"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
if (args.length < 2) {
|
|
7
|
+
console.error('Usage: log-event.js <type> <actor> [--key value ...]');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const [type, actor, ...rest] = args;
|
|
12
|
+
const event = {
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
type,
|
|
15
|
+
actor,
|
|
16
|
+
meta: {}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < rest.length; i++) {
|
|
20
|
+
const token = rest[i];
|
|
21
|
+
if (!token.startsWith('--')) continue;
|
|
22
|
+
const key = token.slice(2);
|
|
23
|
+
const value = rest[i + 1] && !rest[i + 1].startsWith('--') ? rest[++i] : 'true';
|
|
24
|
+
event.meta[key] = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const root = process.cwd();
|
|
28
|
+
const logDir = path.join(root, '.agents', 'logs');
|
|
29
|
+
const logFile = path.join(logDir, 'changes.jsonl');
|
|
30
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
31
|
+
fs.appendFileSync(logFile, JSON.stringify(event) + '\n', 'utf8');
|
|
32
|
+
|
|
33
|
+
console.log(`logged ${type}`);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
fm_get() {
|
|
8
|
+
local file="$1"
|
|
9
|
+
local key="$2"
|
|
10
|
+
awk -v key="$key" '
|
|
11
|
+
BEGIN {in_fm=0}
|
|
12
|
+
/^---[[:space:]]*$/ {if (in_fm==0) {in_fm=1; next} else {exit}}
|
|
13
|
+
in_fm==1 && $0 ~ "^" key ":[[:space:]]*" {
|
|
14
|
+
sub("^" key ":[[:space:]]*", "")
|
|
15
|
+
print
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
' "$file"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
found=0
|
|
22
|
+
for task in .project/projects/*/tasks/*.md; do
|
|
23
|
+
[[ -f "$task" ]] || continue
|
|
24
|
+
status="$(fm_get "$task" status 2>/dev/null || true)"
|
|
25
|
+
[[ "$status" == "blocked" ]] || continue
|
|
26
|
+
|
|
27
|
+
project="$(basename "$(dirname "$(dirname "$task")")")"
|
|
28
|
+
tid="$(fm_get "$task" id 2>/dev/null || basename "$task" .md)"
|
|
29
|
+
name="$(fm_get "$task" name 2>/dev/null || basename "$task" .md)"
|
|
30
|
+
echo "$project\t$tid\t$name\t$task"
|
|
31
|
+
found=1
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
if [[ $found -eq 0 ]]; then
|
|
35
|
+
echo "No blocked tasks."
|
|
36
|
+
fi
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
fm_get() {
|
|
8
|
+
local file="$1"
|
|
9
|
+
local key="$2"
|
|
10
|
+
awk -v key="$key" '
|
|
11
|
+
BEGIN {in_fm=0}
|
|
12
|
+
/^---[[:space:]]*$/ {if (in_fm==0) {in_fm=1; next} else {exit}}
|
|
13
|
+
in_fm==1 && $0 ~ "^" key ":[[:space:]]*" {
|
|
14
|
+
sub("^" key ":[[:space:]]*", "")
|
|
15
|
+
print
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
' "$file"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
found=0
|
|
22
|
+
for plan in .project/projects/*/plan.md; do
|
|
23
|
+
[[ -f "$plan" ]] || continue
|
|
24
|
+
slug="$(basename "$(dirname "$plan")")"
|
|
25
|
+
name="$(fm_get "$plan" name 2>/dev/null || echo "$slug")"
|
|
26
|
+
status="$(fm_get "$plan" status 2>/dev/null || echo "unknown")"
|
|
27
|
+
lead="$(fm_get "$plan" lead 2>/dev/null || true)"
|
|
28
|
+
echo "$slug\t$name\t$status\t$lead"
|
|
29
|
+
found=1
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
if [[ $found -eq 0 ]]; then
|
|
33
|
+
echo "No delivery plans found."
|
|
34
|
+
fi
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
fm_get() {
|
|
8
|
+
local file="$1"
|
|
9
|
+
local key="$2"
|
|
10
|
+
awk -v key="$key" '
|
|
11
|
+
BEGIN {in_fm=0}
|
|
12
|
+
/^---[[:space:]]*$/ {if (in_fm==0) {in_fm=1; next} else {exit}}
|
|
13
|
+
in_fm==1 && $0 ~ "^" key ":[[:space:]]*" {
|
|
14
|
+
sub("^" key ":[[:space:]]*", "")
|
|
15
|
+
print
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
' "$file"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
found=0
|
|
22
|
+
for task in .project/projects/*/tasks/*.md; do
|
|
23
|
+
[[ -f "$task" ]] || continue
|
|
24
|
+
status="$(fm_get "$task" status 2>/dev/null || true)"
|
|
25
|
+
if [[ "$status" == "in-progress" || "$status" == "review" ]]; then
|
|
26
|
+
project="$(basename "$(dirname "$(dirname "$task")")")"
|
|
27
|
+
tid="$(fm_get "$task" id 2>/dev/null || basename "$task" .md)"
|
|
28
|
+
name="$(fm_get "$task" name 2>/dev/null || basename "$task" .md)"
|
|
29
|
+
echo "$project\t$tid\t$status\t$name"
|
|
30
|
+
found=1
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
if [[ $found -eq 0 ]]; then
|
|
35
|
+
echo "No tasks in progress or review."
|
|
36
|
+
fi
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [[ "${1:-}" == "" || "${2:-}" == "" ]]; then
|
|
5
|
+
echo "Usage: $0 <slug> <project-name> [owner] [lead]"
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
slug="$1"
|
|
10
|
+
name="$2"
|
|
11
|
+
owner="${3:-team}"
|
|
12
|
+
lead="${4:-$owner}"
|
|
13
|
+
|
|
14
|
+
if [[ ! "$slug" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
|
15
|
+
echo "Error: slug must be kebab-case"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
20
|
+
project_dir="$root/.project/projects/$slug"
|
|
21
|
+
now="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
22
|
+
|
|
23
|
+
if [[ -d "$project_dir" ]]; then
|
|
24
|
+
echo "Error: project already exists at $project_dir"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
mkdir -p "$project_dir"/{tasks,workstreams,updates}
|
|
29
|
+
|
|
30
|
+
cat > "$project_dir/spec.md" <<SPEC
|
|
31
|
+
---
|
|
32
|
+
name: $name
|
|
33
|
+
slug: $slug
|
|
34
|
+
owner: $owner
|
|
35
|
+
status: draft
|
|
36
|
+
created: $now
|
|
37
|
+
updated: $now
|
|
38
|
+
outcome: <measurable target>
|
|
39
|
+
uncertainty: <low|medium|high>
|
|
40
|
+
probe_required: <true|false>
|
|
41
|
+
probe_status: <pending|skipped|completed>
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Spec: $name
|
|
45
|
+
|
|
46
|
+
## Executive Summary
|
|
47
|
+
|
|
48
|
+
## Problem and Users
|
|
49
|
+
|
|
50
|
+
## Outcome and Success Metrics
|
|
51
|
+
|
|
52
|
+
## Scope
|
|
53
|
+
### In Scope
|
|
54
|
+
### Out of Scope
|
|
55
|
+
|
|
56
|
+
## Functional Requirements
|
|
57
|
+
|
|
58
|
+
## Non-Functional Requirements
|
|
59
|
+
|
|
60
|
+
## Hypotheses and Unknowns
|
|
61
|
+
|
|
62
|
+
## Touchpoints to Exercise
|
|
63
|
+
|
|
64
|
+
## Probe Findings
|
|
65
|
+
|
|
66
|
+
## Footguns Discovered
|
|
67
|
+
|
|
68
|
+
## Remaining Unknowns
|
|
69
|
+
|
|
70
|
+
## Dependencies
|
|
71
|
+
|
|
72
|
+
## Approval Notes
|
|
73
|
+
SPEC
|
|
74
|
+
|
|
75
|
+
cat > "$project_dir/plan.md" <<PLAN
|
|
76
|
+
---
|
|
77
|
+
name: $name
|
|
78
|
+
status: planned
|
|
79
|
+
lead: $lead
|
|
80
|
+
created: $now
|
|
81
|
+
updated: $now
|
|
82
|
+
linear_project_id:
|
|
83
|
+
risk_level: <low|medium|high>
|
|
84
|
+
spec_status_at_plan_time: <approved|active>
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
# Delivery Plan: $name
|
|
88
|
+
|
|
89
|
+
## What Changed After Probe
|
|
90
|
+
|
|
91
|
+
## Architecture Decisions
|
|
92
|
+
|
|
93
|
+
## Probe-Driven Architecture Changes
|
|
94
|
+
|
|
95
|
+
## Workstream Design
|
|
96
|
+
|
|
97
|
+
## Milestone Strategy
|
|
98
|
+
|
|
99
|
+
## Rollout Strategy
|
|
100
|
+
|
|
101
|
+
## Test Strategy
|
|
102
|
+
|
|
103
|
+
## Rollback Strategy
|
|
104
|
+
|
|
105
|
+
## Remaining Delivery Risks
|
|
106
|
+
PLAN
|
|
107
|
+
|
|
108
|
+
cat > "$project_dir/decisions.md" <<'DECISIONS'
|
|
109
|
+
# Decisions
|
|
110
|
+
|
|
111
|
+
Track key project decisions with context and rationale.
|
|
112
|
+
DECISIONS
|
|
113
|
+
|
|
114
|
+
# Ensure registries exist
|
|
115
|
+
mkdir -p "$root/.project/registry"
|
|
116
|
+
if [[ ! -f "$root/.project/registry/linear-map.json" ]]; then
|
|
117
|
+
cat > "$root/.project/registry/linear-map.json" <<REG
|
|
118
|
+
{
|
|
119
|
+
"version": 1,
|
|
120
|
+
"updated": "$now",
|
|
121
|
+
"projects": {},
|
|
122
|
+
"tasks": {}
|
|
123
|
+
}
|
|
124
|
+
REG
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
if [[ ! -f "$root/.project/registry/migration-map.json" ]]; then
|
|
128
|
+
cat > "$root/.project/registry/migration-map.json" <<REG
|
|
129
|
+
{
|
|
130
|
+
"version": 1,
|
|
131
|
+
"updated": "$now",
|
|
132
|
+
"mappings": []
|
|
133
|
+
}
|
|
134
|
+
REG
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
echo "Created Delano project scaffold: .project/projects/$slug"
|
|
138
|
+
|
|
139
|
+
"$root/.agents/scripts/pm/validate.sh"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
python_cmd=()
|
|
8
|
+
|
|
9
|
+
resolve_python_cmd() {
|
|
10
|
+
if command -v python3 >/dev/null 2>&1 && python3 -c "import sys" >/dev/null 2>&1; then
|
|
11
|
+
python_cmd=(python3)
|
|
12
|
+
return 0
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if command -v py >/dev/null 2>&1 && py -3 -c "import sys" >/dev/null 2>&1; then
|
|
16
|
+
python_cmd=(py -3)
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
if command -v python >/dev/null 2>&1 && python -c "import sys" >/dev/null 2>&1; then
|
|
21
|
+
python_cmd=(python)
|
|
22
|
+
return 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
echo "No usable Python runtime found (tried: python3, py -3, python)." >&2
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
show_all=false
|
|
30
|
+
if [[ "${1:-}" == "--all" ]]; then
|
|
31
|
+
show_all=true
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [[ "$show_all" == "true" ]]; then
|
|
35
|
+
export DELANO_NEXT_ALL=1
|
|
36
|
+
else
|
|
37
|
+
export DELANO_NEXT_ALL=0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
resolve_python_cmd
|
|
41
|
+
|
|
42
|
+
"${python_cmd[@]}" - <<'PY'
|
|
43
|
+
import re
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
|
|
46
|
+
ROOT = Path('.')
|
|
47
|
+
TASK_STATUS_READY = 'ready'
|
|
48
|
+
|
|
49
|
+
rank = {'urgent': 0, 'high': 1, 'medium': 2, 'low': 3}
|
|
50
|
+
|
|
51
|
+
def parse_frontmatter(path: Path):
|
|
52
|
+
text = path.read_text(encoding='utf-8')
|
|
53
|
+
m = re.match(r'^---\n(.*?)\n---\n', text, re.S)
|
|
54
|
+
if not m:
|
|
55
|
+
return {}
|
|
56
|
+
data = {}
|
|
57
|
+
for line in m.group(1).splitlines():
|
|
58
|
+
if ':' not in line:
|
|
59
|
+
continue
|
|
60
|
+
k, v = line.split(':', 1)
|
|
61
|
+
data[k.strip()] = v.strip()
|
|
62
|
+
return data
|
|
63
|
+
|
|
64
|
+
def parse_list(raw: str):
|
|
65
|
+
raw = (raw or '[]').strip()
|
|
66
|
+
if raw.startswith('[') and raw.endswith(']'):
|
|
67
|
+
inner = raw[1:-1].strip()
|
|
68
|
+
if not inner:
|
|
69
|
+
return []
|
|
70
|
+
return [x.strip().strip('"\'') for x in inner.split(',') if x.strip()]
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
projects = sorted((ROOT / '.project' / 'projects').glob('*'))
|
|
74
|
+
all_candidates = []
|
|
75
|
+
for p in projects:
|
|
76
|
+
if not p.is_dir() or p.name == '.gitkeep':
|
|
77
|
+
continue
|
|
78
|
+
tasks = {}
|
|
79
|
+
for tf in sorted((p / 'tasks').glob('*.md')):
|
|
80
|
+
meta = parse_frontmatter(tf)
|
|
81
|
+
tid = meta.get('id', tf.stem)
|
|
82
|
+
tasks[tid] = {
|
|
83
|
+
'path': tf,
|
|
84
|
+
'name': meta.get('name', tf.stem),
|
|
85
|
+
'status': meta.get('status', ''),
|
|
86
|
+
'depends_on': parse_list(meta.get('depends_on', '[]')),
|
|
87
|
+
'priority': meta.get('priority', 'medium').lower(),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for tid, t in tasks.items():
|
|
91
|
+
if t['status'] != TASK_STATUS_READY:
|
|
92
|
+
continue
|
|
93
|
+
unmet = [d for d in t['depends_on'] if d in tasks and tasks[d]['status'] != 'done']
|
|
94
|
+
if unmet:
|
|
95
|
+
continue
|
|
96
|
+
all_candidates.append((rank.get(t['priority'], 4), p.name, tid, t['name'], t['priority'], str(t['path'])))
|
|
97
|
+
|
|
98
|
+
all_candidates.sort()
|
|
99
|
+
if not all_candidates:
|
|
100
|
+
print('No dependency-safe ready tasks found.')
|
|
101
|
+
raise SystemExit(0)
|
|
102
|
+
|
|
103
|
+
import os
|
|
104
|
+
show_all = os.environ.get('DELANO_NEXT_ALL', '0') == '1'
|
|
105
|
+
if not show_all:
|
|
106
|
+
all_candidates = all_candidates[:1]
|
|
107
|
+
|
|
108
|
+
for _, project, tid, name, prio, path in all_candidates:
|
|
109
|
+
print(f'{project}\t{tid}\t{prio}\t{name}\t{path}')
|
|
110
|
+
PY
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
fm_get() {
|
|
8
|
+
local file="$1"
|
|
9
|
+
local key="$2"
|
|
10
|
+
awk -v key="$key" '
|
|
11
|
+
BEGIN {in_fm=0}
|
|
12
|
+
/^---[[:space:]]*$/ {if (in_fm==0) {in_fm=1; next} else {exit}}
|
|
13
|
+
in_fm==1 && $0 ~ "^" key ":[[:space:]]*" {
|
|
14
|
+
sub("^" key ":[[:space:]]*", "")
|
|
15
|
+
print
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
' "$file"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
found=0
|
|
22
|
+
for spec in .project/projects/*/spec.md; do
|
|
23
|
+
[[ -f "$spec" ]] || continue
|
|
24
|
+
slug="$(basename "$(dirname "$spec")")"
|
|
25
|
+
name="$(fm_get "$spec" name 2>/dev/null || echo "$slug")"
|
|
26
|
+
status="$(fm_get "$spec" status 2>/dev/null || echo "unknown")"
|
|
27
|
+
outcome="$(fm_get "$spec" outcome 2>/dev/null || true)"
|
|
28
|
+
echo "$slug\t$name\t$status\t$outcome"
|
|
29
|
+
found=1
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
if [[ $found -eq 0 ]]; then
|
|
33
|
+
echo "No specs found."
|
|
34
|
+
fi
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [[ "${1:-}" == "" ]]; then
|
|
5
|
+
echo "Usage: $0 <query>"
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
query="$*"
|
|
10
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
11
|
+
cd "$root"
|
|
12
|
+
|
|
13
|
+
grep -R -n -- "$query" .project/projects .project/context .project/registry || true
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
echo "Daily standup snapshot ($(date -u +"%Y-%m-%dT%H:%M:%SZ"))"
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
echo "[Portfolio]"
|
|
11
|
+
"$root/.agents/scripts/pm/status.sh"
|
|
12
|
+
|
|
13
|
+
echo ""
|
|
14
|
+
echo "[In Progress]"
|
|
15
|
+
"$root/.agents/scripts/pm/in-progress.sh"
|
|
16
|
+
|
|
17
|
+
echo ""
|
|
18
|
+
echo "[Blocked]"
|
|
19
|
+
"$root/.agents/scripts/pm/blocked.sh"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
|
+
cd "$root"
|
|
6
|
+
|
|
7
|
+
fm_get() {
|
|
8
|
+
local file="$1"
|
|
9
|
+
local key="$2"
|
|
10
|
+
awk -v key="$key" '
|
|
11
|
+
BEGIN {in_fm=0}
|
|
12
|
+
/^---[[:space:]]*$/ {if (in_fm==0) {in_fm=1; next} else {exit}}
|
|
13
|
+
in_fm==1 && $0 ~ "^" key ":[[:space:]]*" {
|
|
14
|
+
sub("^" key ":[[:space:]]*", "")
|
|
15
|
+
print
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
' "$file"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
echo "Delano portfolio status"
|
|
22
|
+
echo "======================="
|
|
23
|
+
|
|
24
|
+
project_count=0
|
|
25
|
+
for project_dir in .project/projects/*; do
|
|
26
|
+
[[ -d "$project_dir" ]] || continue
|
|
27
|
+
[[ "$(basename "$project_dir")" == ".gitkeep" ]] && continue
|
|
28
|
+
project_count=$((project_count + 1))
|
|
29
|
+
|
|
30
|
+
slug="$(basename "$project_dir")"
|
|
31
|
+
spec_status="$(fm_get "$project_dir/spec.md" status 2>/dev/null || true)"
|
|
32
|
+
plan_status="$(fm_get "$project_dir/plan.md" status 2>/dev/null || true)"
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "Project: $slug"
|
|
36
|
+
echo " Spec status: ${spec_status:-unknown}"
|
|
37
|
+
echo " Plan status: ${plan_status:-unknown}"
|
|
38
|
+
|
|
39
|
+
total=0
|
|
40
|
+
for task in "$project_dir"/tasks/*.md; do
|
|
41
|
+
[[ -f "$task" ]] || continue
|
|
42
|
+
total=$((total + 1))
|
|
43
|
+
done
|
|
44
|
+
|
|
45
|
+
for st in backlog ready in-progress review done blocked canceled; do
|
|
46
|
+
count=0
|
|
47
|
+
for task in "$project_dir"/tasks/*.md; do
|
|
48
|
+
[[ -f "$task" ]] || continue
|
|
49
|
+
status="$(fm_get "$task" status 2>/dev/null || true)"
|
|
50
|
+
if [[ "$status" == "$st" ]]; then
|
|
51
|
+
count=$((count + 1))
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
[[ $count -gt 0 ]] && echo " $st: $count"
|
|
55
|
+
done
|
|
56
|
+
echo " total tasks: $total"
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
if [[ $project_count -eq 0 ]]; then
|
|
60
|
+
echo "No projects found. Create one with: .agents/scripts/pm/init.sh <slug> <project-name>"
|
|
61
|
+
fi
|