@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,311 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ REPO_URL="${DELANO_REPO_URL:-https://github.com/MajesteitBart/delano.git}"
5
+ TARGET_DIR="$(pwd)"
6
+ BRANCH=""
7
+ FORCE=false
8
+ ASSUME_YES=false
9
+ AGENTS_RAW=""
10
+
11
+ usage() {
12
+ cat <<USAGE
13
+ Delano legacy installer bridge (interactive by default)
14
+
15
+ Usage:
16
+ $0 [options]
17
+
18
+ Options:
19
+ --repo <url> Delano git repository URL
20
+ --target <dir> Target directory (default: current directory)
21
+ --branch <name> Branch/tag to install (default: remote default branch)
22
+ --agents <list> Comma-separated agents: claude,codex,opencode,pi
23
+ --force Overwrite existing files without prompting
24
+ --yes Assume yes for prompts
25
+ -h, --help Show this help
26
+
27
+ Notes:
28
+ - This script remains the shell-first migration bridge while @bvdm/delano matures.
29
+ - Prefer 'delano install' from @bvdm/delano for the allowlist-driven, conflict-first v1 install path when that package flow is available.
30
+ USAGE
31
+ }
32
+
33
+ log() { printf '%s\n' "$*"; }
34
+ warn() { printf '⚠️ %s\n' "$*" >&2; }
35
+ err() { printf '❌ %s\n' "$*" >&2; }
36
+
37
+ confirm() {
38
+ local prompt="$1"
39
+ if [[ "$ASSUME_YES" == "true" ]]; then
40
+ return 0
41
+ fi
42
+ read -r -p "$prompt [y/N]: " reply
43
+ [[ "$reply" =~ ^[Yy]$ ]]
44
+ }
45
+
46
+ parse_agents() {
47
+ local raw="$1"
48
+ local -n out_ref=$2
49
+ out_ref=()
50
+
51
+ IFS=',' read -r -a parts <<< "$raw"
52
+ for p in "${parts[@]}"; do
53
+ local a
54
+ a="$(echo "$p" | tr '[:upper:]' '[:lower:]' | xargs)"
55
+ case "$a" in
56
+ claude|codex|opencode|pi)
57
+ out_ref+=("$a")
58
+ ;;
59
+ "") ;;
60
+ *)
61
+ err "Unknown agent: $a"
62
+ exit 1
63
+ ;;
64
+ esac
65
+ done
66
+
67
+ # unique preserve order
68
+ local -A seen=()
69
+ local unique=()
70
+ for a in "${out_ref[@]}"; do
71
+ if [[ -z "${seen[$a]:-}" ]]; then
72
+ seen[$a]=1
73
+ unique+=("$a")
74
+ fi
75
+ done
76
+ out_ref=("${unique[@]}")
77
+ }
78
+
79
+ select_agents_interactive() {
80
+ cat <<MENU
81
+ Which coding agents do you use? (multi-select)
82
+
83
+ 1) Claude Code
84
+ 2) Codex CLI
85
+ 3) OpenCode
86
+ 4) Pi coding agent
87
+
88
+ Enter one or more numbers, comma-separated (example: 1,2)
89
+ MENU
90
+
91
+ read -r -p "Selection: " pick
92
+ pick="$(echo "$pick" | tr -d ' ')"
93
+ if [[ -z "$pick" ]]; then
94
+ err "No agents selected"
95
+ exit 1
96
+ fi
97
+
98
+ local mapped=()
99
+ IFS=',' read -r -a nums <<< "$pick"
100
+ for n in "${nums[@]}"; do
101
+ case "$n" in
102
+ 1) mapped+=("claude") ;;
103
+ 2) mapped+=("codex") ;;
104
+ 3) mapped+=("opencode") ;;
105
+ 4) mapped+=("pi") ;;
106
+ *) err "Invalid selection: $n"; exit 1 ;;
107
+ esac
108
+ done
109
+
110
+ # unique preserve order
111
+ local -A seen=()
112
+ AGENTS=()
113
+ for a in "${mapped[@]}"; do
114
+ if [[ -z "${seen[$a]:-}" ]]; then
115
+ seen[$a]=1
116
+ AGENTS+=("$a")
117
+ fi
118
+ done
119
+ }
120
+
121
+ while [[ $# -gt 0 ]]; do
122
+ case "$1" in
123
+ --repo)
124
+ REPO_URL="$2"; shift 2 ;;
125
+ --target)
126
+ TARGET_DIR="$2"; shift 2 ;;
127
+ --branch)
128
+ BRANCH="$2"; shift 2 ;;
129
+ --agents)
130
+ AGENTS_RAW="$2"; shift 2 ;;
131
+ --force)
132
+ FORCE=true; shift ;;
133
+ --yes)
134
+ ASSUME_YES=true; shift ;;
135
+ -h|--help)
136
+ usage; exit 0 ;;
137
+ *)
138
+ err "Unknown argument: $1"
139
+ usage
140
+ exit 1 ;;
141
+ esac
142
+ done
143
+
144
+ if ! command -v git >/dev/null 2>&1; then
145
+ err "git is required"
146
+ exit 1
147
+ fi
148
+
149
+ mkdir -p "$TARGET_DIR"
150
+ TARGET_DIR="$(cd "$TARGET_DIR" && pwd)"
151
+
152
+ AGENTS=()
153
+ if [[ -n "$AGENTS_RAW" ]]; then
154
+ parse_agents "$AGENTS_RAW" AGENTS
155
+ else
156
+ select_agents_interactive
157
+ fi
158
+
159
+ if [[ ${#AGENTS[@]} -eq 0 ]]; then
160
+ err "No agents selected"
161
+ exit 1
162
+ fi
163
+
164
+ CORE_PATHS=(
165
+ "HANDBOOK.md"
166
+ "AGENTS.md"
167
+ ".project"
168
+ ".delano"
169
+ ".agents/README.md"
170
+ ".agents/common"
171
+ ".agents/scripts"
172
+ ".agents/rules"
173
+ ".agents/hooks"
174
+ ".agents/skills"
175
+ ".agents/logs"
176
+ )
177
+
178
+ declare -A ADAPTER_PATHS
179
+ ADAPTER_PATHS[claude]=".agents/adapters/claude CLAUDE.md"
180
+ ADAPTER_PATHS[codex]=".agents/adapters/codex CODEX.md"
181
+ ADAPTER_PATHS[opencode]=".agents/adapters/opencode OPENCODE.md"
182
+ ADAPTER_PATHS[pi]=".agents/adapters/pi PI.md"
183
+
184
+ paths=("${CORE_PATHS[@]}")
185
+ for a in "${AGENTS[@]}"; do
186
+ # shellcheck disable=SC2206
187
+ extra=( ${ADAPTER_PATHS[$a]} )
188
+ paths+=("${extra[@]}")
189
+ done
190
+
191
+ # unique paths preserve order
192
+ unique_paths=()
193
+ declare -A path_seen=()
194
+ for p in "${paths[@]}"; do
195
+ if [[ -z "${path_seen[$p]:-}" ]]; then
196
+ path_seen[$p]=1
197
+ unique_paths+=("$p")
198
+ fi
199
+ done
200
+
201
+ if [[ -z "$BRANCH" ]]; then
202
+ BRANCH="$(git ls-remote --symref "$REPO_URL" HEAD 2>/dev/null | awk '/^ref:/ {sub("refs/heads/","",$2); print $2; exit}')"
203
+ BRANCH="${BRANCH:-main}"
204
+ fi
205
+
206
+ log "Installing Delano from: $REPO_URL"
207
+ log "Branch: $BRANCH"
208
+ log "Target: $TARGET_DIR"
209
+ log "Agents: ${AGENTS[*]}"
210
+ log "Mode: legacy bridge installer"
211
+ log ""
212
+
213
+ tmp="$(mktemp -d)"
214
+ cleanup() {
215
+ rm -rf "$tmp"
216
+ }
217
+ trap cleanup EXIT
218
+
219
+ git -C "$tmp" init -q
220
+ git -C "$tmp" remote add origin "$REPO_URL"
221
+ git -C "$tmp" config advice.detachedHead false
222
+
223
+ if git -C "$tmp" sparse-checkout init --cone >/dev/null 2>&1; then
224
+ git -C "$tmp" sparse-checkout set "${unique_paths[@]}" >/dev/null 2>&1 || true
225
+ else
226
+ mkdir -p "$tmp/.git/info"
227
+ : > "$tmp/.git/info/sparse-checkout"
228
+ for p in "${unique_paths[@]}"; do
229
+ printf '%s\n' "$p" >> "$tmp/.git/info/sparse-checkout"
230
+ printf '%s/**\n' "$p" >> "$tmp/.git/info/sparse-checkout"
231
+ done
232
+ git -C "$tmp" config core.sparseCheckout true
233
+ fi
234
+
235
+ if ! git -C "$tmp" fetch --depth 1 origin "$BRANCH" >/dev/null 2>&1; then
236
+ err "Could not fetch branch '$BRANCH' from $REPO_URL"
237
+ exit 1
238
+ fi
239
+ git -C "$tmp" checkout -q FETCH_HEAD
240
+
241
+ copy_item() {
242
+ local rel="$1"
243
+ local src="$tmp/$rel"
244
+ local dst="$TARGET_DIR/$rel"
245
+
246
+ if [[ ! -e "$src" && ! -L "$src" ]]; then
247
+ warn "Path not found in source repo, skipping: $rel"
248
+ return 0
249
+ fi
250
+
251
+ if [[ -e "$dst" || -L "$dst" ]]; then
252
+ if [[ "$FORCE" == "true" ]]; then
253
+ rm -rf "$dst"
254
+ else
255
+ if confirm "Overwrite existing '$rel'?"; then
256
+ rm -rf "$dst"
257
+ else
258
+ warn "Skipped existing: $rel"
259
+ return 0
260
+ fi
261
+ fi
262
+ fi
263
+
264
+ mkdir -p "$(dirname "$dst")"
265
+ if [[ -d "$src" && ! -L "$src" ]]; then
266
+ cp -a "$src" "$(dirname "$dst")/"
267
+ else
268
+ cp -a "$src" "$dst"
269
+ fi
270
+
271
+ log "✓ Installed: $rel"
272
+ }
273
+
274
+ for rel in "${unique_paths[@]}"; do
275
+ copy_item "$rel"
276
+ done
277
+
278
+ # Compatibility symlink for runtime scripts
279
+ if [[ -e "$TARGET_DIR/.agents" ]]; then
280
+ if [[ -L "$TARGET_DIR/.claude" ]]; then
281
+ current_target="$(readlink "$TARGET_DIR/.claude" || true)"
282
+ if [[ "$current_target" != ".agents" ]]; then
283
+ if [[ "$FORCE" == "true" ]] || confirm "Replace existing .claude symlink target '$current_target'?"; then
284
+ rm -f "$TARGET_DIR/.claude"
285
+ fi
286
+ fi
287
+ elif [[ -e "$TARGET_DIR/.claude" ]]; then
288
+ if [[ "$FORCE" == "true" ]] || confirm "Replace existing .claude directory/file with symlink?"; then
289
+ rm -rf "$TARGET_DIR/.claude"
290
+ fi
291
+ fi
292
+
293
+ if [[ ! -e "$TARGET_DIR/.claude" && ! -L "$TARGET_DIR/.claude" ]]; then
294
+ if (cd "$TARGET_DIR" && ln -s .agents .claude) 2>/dev/null; then
295
+ log "✓ Created compatibility symlink: .claude -> .agents"
296
+ else
297
+ warn "Could not create symlink (.claude). Falling back to directory copy."
298
+ cp -a "$TARGET_DIR/.agents" "$TARGET_DIR/.claude"
299
+ fi
300
+ fi
301
+ else
302
+ warn "Runtime missing at .agents, skipped .claude compatibility link"
303
+ fi
304
+
305
+ log ""
306
+ log "Done."
307
+ log "Next steps:"
308
+ log "1) Read HANDBOOK.md"
309
+ log "2) Read AGENTS.md"
310
+ log "3) Validate scaffold: bash .agents/scripts/pm/validate.sh"
311
+ log "4) Prefer @bvdm/delano for the conservative v1 install path when you adopt the npm CLI flow."
package/bin/delano.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { run } = require("../src/cli");
4
+
5
+ run(process.argv.slice(2))
6
+ .then((exitCode) => {
7
+ process.exitCode = exitCode;
8
+ })
9
+ .catch((error) => {
10
+ const message = error && error.message ? error.message : String(error);
11
+ console.error(message);
12
+ process.exitCode = typeof error?.exitCode === "number" ? error.exitCode : 1;
13
+ });
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ REPO_URL="${DELANO_REPO_URL:-https://github.com/MajesteitBart/delano.git}"
5
+ TARGET_DIR="$(pwd)"
6
+ BRANCH=""
7
+ FORCE=false
8
+ ASSUME_YES=false
9
+ AGENTS_RAW=""
10
+
11
+ usage() {
12
+ cat <<USAGE
13
+ Delano legacy installer bridge (interactive by default)
14
+
15
+ Usage:
16
+ $0 [options]
17
+
18
+ Options:
19
+ --repo <url> Delano git repository URL
20
+ --target <dir> Target directory (default: current directory)
21
+ --branch <name> Branch/tag to install (default: remote default branch)
22
+ --agents <list> Comma-separated agents: claude,codex,opencode,pi
23
+ --force Overwrite existing files without prompting
24
+ --yes Assume yes for prompts
25
+ -h, --help Show this help
26
+
27
+ Notes:
28
+ - This script remains the shell-first migration bridge while @bvdm/delano matures.
29
+ - Prefer 'delano install' from @bvdm/delano for the allowlist-driven, conflict-first v1 install path when that package flow is available.
30
+ USAGE
31
+ }
32
+
33
+ log() { printf '%s\n' "$*"; }
34
+ warn() { printf '⚠️ %s\n' "$*" >&2; }
35
+ err() { printf '❌ %s\n' "$*" >&2; }
36
+
37
+ confirm() {
38
+ local prompt="$1"
39
+ if [[ "$ASSUME_YES" == "true" ]]; then
40
+ return 0
41
+ fi
42
+ read -r -p "$prompt [y/N]: " reply
43
+ [[ "$reply" =~ ^[Yy]$ ]]
44
+ }
45
+
46
+ parse_agents() {
47
+ local raw="$1"
48
+ local -n out_ref=$2
49
+ out_ref=()
50
+
51
+ IFS=',' read -r -a parts <<< "$raw"
52
+ for p in "${parts[@]}"; do
53
+ local a
54
+ a="$(echo "$p" | tr '[:upper:]' '[:lower:]' | xargs)"
55
+ case "$a" in
56
+ claude|codex|opencode|pi)
57
+ out_ref+=("$a")
58
+ ;;
59
+ "") ;;
60
+ *)
61
+ err "Unknown agent: $a"
62
+ exit 1
63
+ ;;
64
+ esac
65
+ done
66
+
67
+ # unique preserve order
68
+ local -A seen=()
69
+ local unique=()
70
+ for a in "${out_ref[@]}"; do
71
+ if [[ -z "${seen[$a]:-}" ]]; then
72
+ seen[$a]=1
73
+ unique+=("$a")
74
+ fi
75
+ done
76
+ out_ref=("${unique[@]}")
77
+ }
78
+
79
+ select_agents_interactive() {
80
+ cat <<MENU
81
+ Which coding agents do you use? (multi-select)
82
+
83
+ 1) Claude Code
84
+ 2) Codex CLI
85
+ 3) OpenCode
86
+ 4) Pi coding agent
87
+
88
+ Enter one or more numbers, comma-separated (example: 1,2)
89
+ MENU
90
+
91
+ read -r -p "Selection: " pick
92
+ pick="$(echo "$pick" | tr -d ' ')"
93
+ if [[ -z "$pick" ]]; then
94
+ err "No agents selected"
95
+ exit 1
96
+ fi
97
+
98
+ local mapped=()
99
+ IFS=',' read -r -a nums <<< "$pick"
100
+ for n in "${nums[@]}"; do
101
+ case "$n" in
102
+ 1) mapped+=("claude") ;;
103
+ 2) mapped+=("codex") ;;
104
+ 3) mapped+=("opencode") ;;
105
+ 4) mapped+=("pi") ;;
106
+ *) err "Invalid selection: $n"; exit 1 ;;
107
+ esac
108
+ done
109
+
110
+ # unique preserve order
111
+ local -A seen=()
112
+ AGENTS=()
113
+ for a in "${mapped[@]}"; do
114
+ if [[ -z "${seen[$a]:-}" ]]; then
115
+ seen[$a]=1
116
+ AGENTS+=("$a")
117
+ fi
118
+ done
119
+ }
120
+
121
+ while [[ $# -gt 0 ]]; do
122
+ case "$1" in
123
+ --repo)
124
+ REPO_URL="$2"; shift 2 ;;
125
+ --target)
126
+ TARGET_DIR="$2"; shift 2 ;;
127
+ --branch)
128
+ BRANCH="$2"; shift 2 ;;
129
+ --agents)
130
+ AGENTS_RAW="$2"; shift 2 ;;
131
+ --force)
132
+ FORCE=true; shift ;;
133
+ --yes)
134
+ ASSUME_YES=true; shift ;;
135
+ -h|--help)
136
+ usage; exit 0 ;;
137
+ *)
138
+ err "Unknown argument: $1"
139
+ usage
140
+ exit 1 ;;
141
+ esac
142
+ done
143
+
144
+ if ! command -v git >/dev/null 2>&1; then
145
+ err "git is required"
146
+ exit 1
147
+ fi
148
+
149
+ mkdir -p "$TARGET_DIR"
150
+ TARGET_DIR="$(cd "$TARGET_DIR" && pwd)"
151
+
152
+ AGENTS=()
153
+ if [[ -n "$AGENTS_RAW" ]]; then
154
+ parse_agents "$AGENTS_RAW" AGENTS
155
+ else
156
+ select_agents_interactive
157
+ fi
158
+
159
+ if [[ ${#AGENTS[@]} -eq 0 ]]; then
160
+ err "No agents selected"
161
+ exit 1
162
+ fi
163
+
164
+ CORE_PATHS=(
165
+ "HANDBOOK.md"
166
+ "AGENTS.md"
167
+ ".project"
168
+ ".delano"
169
+ ".agents/README.md"
170
+ ".agents/common"
171
+ ".agents/scripts"
172
+ ".agents/rules"
173
+ ".agents/hooks"
174
+ ".agents/skills"
175
+ ".agents/logs"
176
+ )
177
+
178
+ declare -A ADAPTER_PATHS
179
+ ADAPTER_PATHS[claude]=".agents/adapters/claude CLAUDE.md"
180
+ ADAPTER_PATHS[codex]=".agents/adapters/codex CODEX.md"
181
+ ADAPTER_PATHS[opencode]=".agents/adapters/opencode OPENCODE.md"
182
+ ADAPTER_PATHS[pi]=".agents/adapters/pi PI.md"
183
+
184
+ paths=("${CORE_PATHS[@]}")
185
+ for a in "${AGENTS[@]}"; do
186
+ # shellcheck disable=SC2206
187
+ extra=( ${ADAPTER_PATHS[$a]} )
188
+ paths+=("${extra[@]}")
189
+ done
190
+
191
+ # unique paths preserve order
192
+ unique_paths=()
193
+ declare -A path_seen=()
194
+ for p in "${paths[@]}"; do
195
+ if [[ -z "${path_seen[$p]:-}" ]]; then
196
+ path_seen[$p]=1
197
+ unique_paths+=("$p")
198
+ fi
199
+ done
200
+
201
+ if [[ -z "$BRANCH" ]]; then
202
+ BRANCH="$(git ls-remote --symref "$REPO_URL" HEAD 2>/dev/null | awk '/^ref:/ {sub("refs/heads/","",$2); print $2; exit}')"
203
+ BRANCH="${BRANCH:-main}"
204
+ fi
205
+
206
+ log "Installing Delano from: $REPO_URL"
207
+ log "Branch: $BRANCH"
208
+ log "Target: $TARGET_DIR"
209
+ log "Agents: ${AGENTS[*]}"
210
+ log "Mode: legacy bridge installer"
211
+ log ""
212
+
213
+ tmp="$(mktemp -d)"
214
+ cleanup() {
215
+ rm -rf "$tmp"
216
+ }
217
+ trap cleanup EXIT
218
+
219
+ git -C "$tmp" init -q
220
+ git -C "$tmp" remote add origin "$REPO_URL"
221
+ git -C "$tmp" config advice.detachedHead false
222
+
223
+ if git -C "$tmp" sparse-checkout init --cone >/dev/null 2>&1; then
224
+ git -C "$tmp" sparse-checkout set "${unique_paths[@]}" >/dev/null 2>&1 || true
225
+ else
226
+ mkdir -p "$tmp/.git/info"
227
+ : > "$tmp/.git/info/sparse-checkout"
228
+ for p in "${unique_paths[@]}"; do
229
+ printf '%s\n' "$p" >> "$tmp/.git/info/sparse-checkout"
230
+ printf '%s/**\n' "$p" >> "$tmp/.git/info/sparse-checkout"
231
+ done
232
+ git -C "$tmp" config core.sparseCheckout true
233
+ fi
234
+
235
+ if ! git -C "$tmp" fetch --depth 1 origin "$BRANCH" >/dev/null 2>&1; then
236
+ err "Could not fetch branch '$BRANCH' from $REPO_URL"
237
+ exit 1
238
+ fi
239
+ git -C "$tmp" checkout -q FETCH_HEAD
240
+
241
+ copy_item() {
242
+ local rel="$1"
243
+ local src="$tmp/$rel"
244
+ local dst="$TARGET_DIR/$rel"
245
+
246
+ if [[ ! -e "$src" && ! -L "$src" ]]; then
247
+ warn "Path not found in source repo, skipping: $rel"
248
+ return 0
249
+ fi
250
+
251
+ if [[ -e "$dst" || -L "$dst" ]]; then
252
+ if [[ "$FORCE" == "true" ]]; then
253
+ rm -rf "$dst"
254
+ else
255
+ if confirm "Overwrite existing '$rel'?"; then
256
+ rm -rf "$dst"
257
+ else
258
+ warn "Skipped existing: $rel"
259
+ return 0
260
+ fi
261
+ fi
262
+ fi
263
+
264
+ mkdir -p "$(dirname "$dst")"
265
+ if [[ -d "$src" && ! -L "$src" ]]; then
266
+ cp -a "$src" "$(dirname "$dst")/"
267
+ else
268
+ cp -a "$src" "$dst"
269
+ fi
270
+
271
+ log "✓ Installed: $rel"
272
+ }
273
+
274
+ for rel in "${unique_paths[@]}"; do
275
+ copy_item "$rel"
276
+ done
277
+
278
+ # Compatibility symlink for runtime scripts
279
+ if [[ -e "$TARGET_DIR/.agents" ]]; then
280
+ if [[ -L "$TARGET_DIR/.claude" ]]; then
281
+ current_target="$(readlink "$TARGET_DIR/.claude" || true)"
282
+ if [[ "$current_target" != ".agents" ]]; then
283
+ if [[ "$FORCE" == "true" ]] || confirm "Replace existing .claude symlink target '$current_target'?"; then
284
+ rm -f "$TARGET_DIR/.claude"
285
+ fi
286
+ fi
287
+ elif [[ -e "$TARGET_DIR/.claude" ]]; then
288
+ if [[ "$FORCE" == "true" ]] || confirm "Replace existing .claude directory/file with symlink?"; then
289
+ rm -rf "$TARGET_DIR/.claude"
290
+ fi
291
+ fi
292
+
293
+ if [[ ! -e "$TARGET_DIR/.claude" && ! -L "$TARGET_DIR/.claude" ]]; then
294
+ if (cd "$TARGET_DIR" && ln -s .agents .claude) 2>/dev/null; then
295
+ log "✓ Created compatibility symlink: .claude -> .agents"
296
+ else
297
+ warn "Could not create symlink (.claude). Falling back to directory copy."
298
+ cp -a "$TARGET_DIR/.agents" "$TARGET_DIR/.claude"
299
+ fi
300
+ fi
301
+ else
302
+ warn "Runtime missing at .agents, skipped .claude compatibility link"
303
+ fi
304
+
305
+ log ""
306
+ log "Done."
307
+ log "Next steps:"
308
+ log "1) Read HANDBOOK.md"
309
+ log "2) Read AGENTS.md"
310
+ log "3) Validate scaffold: bash .agents/scripts/pm/validate.sh"
311
+ log "4) Prefer @bvdm/delano for the conservative v1 install path when you adopt the npm CLI flow."
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@bvdm/delano",
3
+ "version": "0.1.0",
4
+ "description": "Thin npm CLI for the Delano delivery runtime.",
5
+ "license": "UNLICENSED",
6
+ "bin": {
7
+ "delano": "bin/delano.js"
8
+ },
9
+ "type": "commonjs",
10
+ "engines": {
11
+ "node": ">=18"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "src/",
16
+ "assets/",
17
+ "README.md",
18
+ "HANDBOOK.md",
19
+ "install-delano.sh"
20
+ ],
21
+ "scripts": {
22
+ "build:assets": "node scripts/build-npm-assets.mjs",
23
+ "prepack": "npm run build:assets",
24
+ "test": "node --test"
25
+ }
26
+ }