@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.
Files changed (109) hide show
  1. package/HANDBOOK.md +1511 -0
  2. package/README.md +122 -0
  3. package/assets/install-manifest.json +102 -0
  4. package/assets/payload/.agents/README.md +12 -0
  5. package/assets/payload/.agents/adapters/claude/README.md +5 -0
  6. package/assets/payload/.agents/adapters/codex/README.md +5 -0
  7. package/assets/payload/.agents/adapters/opencode/README.md +5 -0
  8. package/assets/payload/.agents/adapters/pi/README.md +5 -0
  9. package/assets/payload/.agents/common/README.md +3 -0
  10. package/assets/payload/.agents/hooks/README.md +11 -0
  11. package/assets/payload/.agents/hooks/bash-worktree-fix.sh +7 -0
  12. package/assets/payload/.agents/hooks/post-tool-logger.js +18 -0
  13. package/assets/payload/.agents/hooks/session-tracker.js +17 -0
  14. package/assets/payload/.agents/hooks/user-prompt-logger.js +18 -0
  15. package/assets/payload/.agents/logs/.gitkeep +0 -0
  16. package/assets/payload/.agents/logs/schema.md +42 -0
  17. package/assets/payload/.agents/rules/README.md +12 -0
  18. package/assets/payload/.agents/rules/agent-coordination.md +5 -0
  19. package/assets/payload/.agents/rules/datetime.md +5 -0
  20. package/assets/payload/.agents/rules/frontmatter-operations.md +6 -0
  21. package/assets/payload/.agents/rules/github-operations.md +5 -0
  22. package/assets/payload/.agents/rules/path-standards.md +5 -0
  23. package/assets/payload/.agents/rules/test-execution.md +5 -0
  24. package/assets/payload/.agents/rules/worktree-operations.md +5 -0
  25. package/assets/payload/.agents/scripts/README.md +31 -0
  26. package/assets/payload/.agents/scripts/check-path-standards.sh +26 -0
  27. package/assets/payload/.agents/scripts/fix-path-standards.sh +14 -0
  28. package/assets/payload/.agents/scripts/git-sparse-download.sh +162 -0
  29. package/assets/payload/.agents/scripts/log-event.js +33 -0
  30. package/assets/payload/.agents/scripts/log-event.sh +5 -0
  31. package/assets/payload/.agents/scripts/pm/blocked.sh +36 -0
  32. package/assets/payload/.agents/scripts/pm/epic-list.sh +34 -0
  33. package/assets/payload/.agents/scripts/pm/in-progress.sh +36 -0
  34. package/assets/payload/.agents/scripts/pm/init.sh +139 -0
  35. package/assets/payload/.agents/scripts/pm/next.sh +110 -0
  36. package/assets/payload/.agents/scripts/pm/prd-list.sh +34 -0
  37. package/assets/payload/.agents/scripts/pm/search.sh +13 -0
  38. package/assets/payload/.agents/scripts/pm/standup.sh +19 -0
  39. package/assets/payload/.agents/scripts/pm/status.sh +61 -0
  40. package/assets/payload/.agents/scripts/pm/validate.sh +309 -0
  41. package/assets/payload/.agents/scripts/query-log.sh +57 -0
  42. package/assets/payload/.agents/scripts/test-and-log.sh +28 -0
  43. package/assets/payload/.agents/skills/.gitkeep +0 -0
  44. package/assets/payload/.agents/skills/README.md +23 -0
  45. package/assets/payload/.agents/skills/breakdown-skill/SKILL.md +40 -0
  46. package/assets/payload/.agents/skills/breakdown-skill/references/runbook.md +16 -0
  47. package/assets/payload/.agents/skills/breakdown-skill/templates/ambiguity-report.md +11 -0
  48. package/assets/payload/.agents/skills/breakdown-skill/templates/task-batch-summary.md +11 -0
  49. package/assets/payload/.agents/skills/closeout-skill/SKILL.md +42 -0
  50. package/assets/payload/.agents/skills/closeout-skill/references/runbook.md +16 -0
  51. package/assets/payload/.agents/skills/closeout-skill/templates/closure-checklist.md +7 -0
  52. package/assets/payload/.agents/skills/closeout-skill/templates/outcome-review.md +11 -0
  53. package/assets/payload/.agents/skills/discovery-skill/SKILL.md +44 -0
  54. package/assets/payload/.agents/skills/discovery-skill/references/runbook.md +14 -0
  55. package/assets/payload/.agents/skills/discovery-skill/templates/clarification-questions.md +18 -0
  56. package/assets/payload/.agents/skills/discovery-skill/templates/discovery-summary.md +14 -0
  57. package/assets/payload/.agents/skills/execution-skill/SKILL.md +42 -0
  58. package/assets/payload/.agents/skills/execution-skill/references/runbook.md +16 -0
  59. package/assets/payload/.agents/skills/execution-skill/templates/blocker-update.md +13 -0
  60. package/assets/payload/.agents/skills/execution-skill/templates/stream-update.md +9 -0
  61. package/assets/payload/.agents/skills/learning-skill/SKILL.md +41 -0
  62. package/assets/payload/.agents/skills/learning-skill/references/runbook.md +13 -0
  63. package/assets/payload/.agents/skills/learning-skill/templates/improvement-backlog.md +10 -0
  64. package/assets/payload/.agents/skills/learning-skill/templates/retrospective.md +11 -0
  65. package/assets/payload/.agents/skills/planning-skill/SKILL.md +40 -0
  66. package/assets/payload/.agents/skills/planning-skill/references/runbook.md +15 -0
  67. package/assets/payload/.agents/skills/planning-skill/templates/architecture-decision.md +15 -0
  68. package/assets/payload/.agents/skills/planning-skill/templates/workstream-definition.md +13 -0
  69. package/assets/payload/.agents/skills/quality-skill/SKILL.md +40 -0
  70. package/assets/payload/.agents/skills/quality-skill/references/runbook.md +14 -0
  71. package/assets/payload/.agents/skills/quality-skill/templates/gate-decision.md +10 -0
  72. package/assets/payload/.agents/skills/quality-skill/templates/quality-evidence.md +16 -0
  73. package/assets/payload/.agents/skills/sync-skill/SKILL.md +41 -0
  74. package/assets/payload/.agents/skills/sync-skill/references/runbook.md +17 -0
  75. package/assets/payload/.agents/skills/sync-skill/templates/conflict-resolution-actions.md +10 -0
  76. package/assets/payload/.agents/skills/sync-skill/templates/drift-report.md +14 -0
  77. package/assets/payload/.delano/README.md +7 -0
  78. package/assets/payload/.gitattributes +14 -0
  79. package/assets/payload/.project/context/README.md +15 -0
  80. package/assets/payload/.project/context/gui-testing.md +20 -0
  81. package/assets/payload/.project/context/product-context.md +17 -0
  82. package/assets/payload/.project/context/progress.md +23 -0
  83. package/assets/payload/.project/context/project-brief.md +13 -0
  84. package/assets/payload/.project/context/project-overview.md +14 -0
  85. package/assets/payload/.project/context/project-structure.md +24 -0
  86. package/assets/payload/.project/context/project-style-guide.md +17 -0
  87. package/assets/payload/.project/context/system-patterns.md +22 -0
  88. package/assets/payload/.project/context/tech-context.md +19 -0
  89. package/assets/payload/.project/projects/.gitkeep +0 -0
  90. package/assets/payload/.project/registry/linear-map.json +6 -0
  91. package/assets/payload/.project/registry/migration-map.json +5 -0
  92. package/assets/payload/.project/templates/completion-summary.md +16 -0
  93. package/assets/payload/.project/templates/plan.md +30 -0
  94. package/assets/payload/.project/templates/progress-update.md +20 -0
  95. package/assets/payload/.project/templates/spec.md +42 -0
  96. package/assets/payload/.project/templates/task.md +33 -0
  97. package/assets/payload/.project/templates/workstream.md +19 -0
  98. package/assets/payload/HANDBOOK.md +1511 -0
  99. package/assets/payload/install-delano.sh +311 -0
  100. package/bin/delano.js +13 -0
  101. package/install-delano.sh +311 -0
  102. package/package.json +26 -0
  103. package/src/cli/commands/install.js +57 -0
  104. package/src/cli/commands/wrapper.js +26 -0
  105. package/src/cli/index.js +97 -0
  106. package/src/cli/lib/errors.js +11 -0
  107. package/src/cli/lib/install.js +261 -0
  108. package/src/cli/lib/pm.js +29 -0
  109. 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,5 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ node "$script_dir/log-event.js" "$@"
@@ -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