omniconductor 0.3.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 (118) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +219 -0
  3. package/NOTICE +11 -0
  4. package/README.md +526 -0
  5. package/THIRD_PARTY_NOTICES.md +31 -0
  6. package/TRADEMARKS.md +26 -0
  7. package/VISION.md +106 -0
  8. package/adapters/README.md +121 -0
  9. package/adapters/claude/README.md +102 -0
  10. package/adapters/claude/SUPPORTED-FEATURES.md +66 -0
  11. package/adapters/claude/hookify-templates/.recipe-scoped +9 -0
  12. package/adapters/claude/hookify-templates/README.md +93 -0
  13. package/adapters/claude/hookify-templates/block-completion-claim-without-push.local.md.template +56 -0
  14. package/adapters/claude/hookify-templates/block-direct-push-protected-branch.local.md.template +18 -0
  15. package/adapters/claude/hookify-templates/block-force-push-protected-branch.local.md.template +42 -0
  16. package/adapters/claude/hookify-templates/block-server-secret-in-client.local.md.template +36 -0
  17. package/adapters/claude/hookify-templates/warn-any-type-added.local.md.template +44 -0
  18. package/adapters/claude/hookify-templates/warn-commit-without-pre-commit-review.local.md.template +52 -0
  19. package/adapters/claude/hookify-templates/warn-console-direct.local.md.template +55 -0
  20. package/adapters/claude/hookify-templates/warn-create-table-without-access-control.local.md.template +35 -0
  21. package/adapters/claude/hookify-templates/warn-current-work-without-remaining-tasks.local.md.template +36 -0
  22. package/adapters/claude/hookify-templates/warn-gh-pr-create-without-pre-merge-review.local.md.template +38 -0
  23. package/adapters/claude/hookify-templates/warn-hardcoded-text-without-i18n-key.local.md.template +21 -0
  24. package/adapters/claude/hookify-templates/warn-on-gh-pr-merge.local.md.template +33 -0
  25. package/adapters/claude/hookify-templates/warn-plan-spec-without-remaining-tasks.local.md.template +44 -0
  26. package/adapters/claude/hookify-templates/warn-raw-hex-instead-of-token.local.md.template +21 -0
  27. package/adapters/claude/hookify-templates/warn-security-definer-without-search-path.local.md.template +30 -0
  28. package/adapters/claude/hookify-templates/warn-stop-commit-without-current-work.local.md.template +47 -0
  29. package/adapters/claude/hookify-templates/warn-user-manual-completion.local.md.template +40 -0
  30. package/adapters/claude/transform-spec.md +140 -0
  31. package/adapters/claude/transform.sh +1169 -0
  32. package/adapters/codex/README.md +87 -0
  33. package/adapters/codex/SUPPORTED-FEATURES.md +66 -0
  34. package/adapters/codex/transform-spec.md +90 -0
  35. package/adapters/codex/transform.sh +748 -0
  36. package/adapters/copilot/README.md +88 -0
  37. package/adapters/copilot/SUPPORTED-FEATURES.md +73 -0
  38. package/adapters/copilot/transform-spec.md +111 -0
  39. package/adapters/copilot/transform.sh +757 -0
  40. package/adapters/cursor/README.md +87 -0
  41. package/adapters/cursor/SUPPORTED-FEATURES.md +90 -0
  42. package/adapters/cursor/transform-spec.md +124 -0
  43. package/adapters/cursor/transform.sh +731 -0
  44. package/adapters/gemini/README.md +93 -0
  45. package/adapters/gemini/SUPPORTED-FEATURES.md +80 -0
  46. package/adapters/gemini/transform-spec.md +102 -0
  47. package/adapters/gemini/transform.sh +844 -0
  48. package/adapters/windsurf/README.md +93 -0
  49. package/adapters/windsurf/SUPPORTED-FEATURES.md +67 -0
  50. package/adapters/windsurf/transform-spec.md +99 -0
  51. package/adapters/windsurf/transform.sh +727 -0
  52. package/bin/omniconductor.js +130 -0
  53. package/core/README.md +64 -0
  54. package/core/anti-patterns/README.md +142 -0
  55. package/core/anti-patterns/dynamic-system-prompt.md +113 -0
  56. package/core/anti-patterns/frequent-rule-file-edit.md +83 -0
  57. package/core/anti-patterns/large-file-read-no-range.md +90 -0
  58. package/core/anti-patterns/no-sub-agent-dispatch.md +89 -0
  59. package/core/anti-patterns/single-monolithic-rule-file.md +99 -0
  60. package/core/anti-patterns/skill-eager-load.md +83 -0
  61. package/core/anti-patterns/tool-call-spam.md +93 -0
  62. package/core/docs-templates/CURRENT_WORK.md +64 -0
  63. package/core/docs-templates/INDEX.md +57 -0
  64. package/core/docs-templates/PLANS.md +44 -0
  65. package/core/docs-templates/README.md +40 -0
  66. package/core/docs-templates/REMAINING_TASKS.md +43 -0
  67. package/core/docs-templates/TASKS.md +51 -0
  68. package/core/docs-templates/specs/_example.md +121 -0
  69. package/core/hooks/README.md +62 -0
  70. package/core/hooks/pretool-agent-routing.sh.template +97 -0
  71. package/core/hooks/pretool-commit-current-work-check.sh.template +103 -0
  72. package/core/hooks/pretool-commit-test-coverage-check.sh.template +116 -0
  73. package/core/hooks/pretool-large-file-read-guard.sh.template +117 -0
  74. package/core/hooks/stop-cache-hit-baseline-check.sh.template +133 -0
  75. package/core/hooks/stop-r6-review-check.sh.template +80 -0
  76. package/core/hooks/stop-session-log-check.sh.template +101 -0
  77. package/core/hooks/stop-trajectory-log.sh.template +96 -0
  78. package/core/memory-pattern/EXAMPLES.md +114 -0
  79. package/core/memory-pattern/README.md +133 -0
  80. package/core/recipes/README.md +46 -0
  81. package/core/recipes/auto-mock-data.md +82 -0
  82. package/core/recipes/branch-strategy.md +100 -0
  83. package/core/recipes/coding-conventions.md +123 -0
  84. package/core/recipes/database-discipline.md +65 -0
  85. package/core/recipes/debugging.md +143 -0
  86. package/core/recipes/design-system.md +30 -0
  87. package/core/recipes/i18n.md +118 -0
  88. package/core/recipes/monorepo.md +101 -0
  89. package/core/recipes/self-improvement.md +61 -0
  90. package/core/recipes/tdd.md +128 -0
  91. package/core/recipes/web-mobile-parity.md +87 -0
  92. package/core/reflector/SCHEDULING.md +83 -0
  93. package/core/reflector/prune-lessons.sh +105 -0
  94. package/core/reflector/reflect-brief.md +11 -0
  95. package/core/reflector/reflect.command.md +13 -0
  96. package/core/reflector/run-weekly.sh +54 -0
  97. package/core/reflector/trajectory-log.sh +55 -0
  98. package/core/roles/README.md +61 -0
  99. package/core/roles/builder.md +75 -0
  100. package/core/roles/designer.md +93 -0
  101. package/core/roles/helper.md +70 -0
  102. package/core/roles/planner.md +123 -0
  103. package/core/roles/reflector.md +72 -0
  104. package/core/roles/reviewer.md +104 -0
  105. package/core/roles/scribe.md +89 -0
  106. package/core/universal-rules/README.md +71 -0
  107. package/core/universal-rules/meta-discipline.md +292 -0
  108. package/core/universal-rules/operations.md +162 -0
  109. package/core/universal-rules/quality-gates.md +191 -0
  110. package/core/universal-rules/spec-as-you-go.md +123 -0
  111. package/core/universal-rules/workflow.md +153 -0
  112. package/core/workflow/PHASES.md +134 -0
  113. package/core/workflow/README.md +56 -0
  114. package/docs/MANUAL-INSTALL.md +456 -0
  115. package/package.json +52 -0
  116. package/tools/check-framework-purity.sh +91 -0
  117. package/tools/measure-tokens.sh +169 -0
  118. package/tools/validate-adapter-output.sh +611 -0
@@ -0,0 +1,727 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # CONDUCTOR — Windsurf adapter transform.sh
4
+ #
5
+ # Reads core/ assets and writes them into a target project as native Windsurf
6
+ # files: .windsurfrules (always-loaded baseline), .devin/rules/*.md, docs/*.
7
+ #
8
+ # Usage:
9
+ # bash adapters/windsurf/transform.sh <target-project> [--recipes=<comma-list>] [--dry-run]
10
+ # [--no-prompt]
11
+ # bash adapters/windsurf/transform.sh <target-project> --uninstall [--dry-run] [--force]
12
+ #
13
+ # Examples:
14
+ # bash adapters/windsurf/transform.sh ~/Projects/my-app
15
+ # bash adapters/windsurf/transform.sh ~/Projects/my-app --recipes=i18n,monorepo
16
+ # bash adapters/windsurf/transform.sh /tmp/test-project --dry-run
17
+ # bash adapters/windsurf/transform.sh . --no-prompt
18
+ # bash adapters/windsurf/transform.sh . --uninstall # revert install
19
+ # bash adapters/windsurf/transform.sh . --uninstall --force # bypass safety checks
20
+ #
21
+ # Layer 2 transformation (per ADR-004 honesty + ADR-021):
22
+ # core/universal-rules/*.md → <target>/.devin/rules/*.md (front-matter stripped; preferred over legacy .windsurf/rules/)
23
+ # <synthesized> → <target>/.windsurfrules (always-loaded baseline)
24
+ # core/recipes/*.md (selected) → <target>/.devin/rules/*.md (front-matter stripped)
25
+ # core/docs-templates/*.md → <target>/docs/*.md (CURRENT_WORK, REMAINING_TASKS, etc.)
26
+ # core/hooks/*.sh.template → SKIPPED (Reflector hook emitted via --recipes=self-improvement, ADR-032; other guards Claude-only, ADR-034)
27
+ # core/roles/*.md → SKIPPED (Windsurf has no sub-agent dispatch)
28
+ # adapters/claude/hookify-... → SKIPPED (Claude-only plugin)
29
+ #
30
+ # Windsurf has NO per-pattern glob scoping (all files in .devin/rules/ load
31
+ # together) and NO sub-agents. CONDUCTOR emits the Reflector hook when
32
+ # --recipes=self-improvement (ADR-032); other guards remain Claude-only (ADR-034)
33
+ # and are noted in .windsurfrules.
34
+
35
+ set -eu
36
+
37
+ # ----- arg parsing --------------------------------------------------------
38
+
39
+ TARGET=""
40
+ RECIPES=""
41
+ DRY_RUN="false"
42
+ NO_PROMPT="false"
43
+ UNINSTALL="false"
44
+ FORCE="false"
45
+
46
+ # Onboarding wizard state
47
+ WIZARD_APPLY_RULES="true"
48
+
49
+ while [ $# -gt 0 ]; do
50
+ case "$1" in
51
+ --recipes=*) RECIPES="${1#--recipes=}" ;;
52
+ --dry-run) DRY_RUN="true" ;;
53
+ --no-prompt) NO_PROMPT="true" ;;
54
+ --uninstall|--rollback) UNINSTALL="true" ;;
55
+ --force) FORCE="true" ;;
56
+ --help|-h)
57
+ /bin/cat <<EOF
58
+ Usage: bash adapters/windsurf/transform.sh <target-project> [options]
59
+
60
+ Options:
61
+ --recipes=A,B,C Comma-separated list of recipes to install
62
+ --dry-run Preview only — no files written
63
+ --no-prompt Skip all interactive prompts; apply sensible defaults (CI-safe)
64
+ --uninstall Revert a previous install using <target>/.conductor-manifest.json
65
+ (alias: --rollback). Restores backups when present, deletes
66
+ Conductor-emitted files when none. Customizations not in the
67
+ manifest are preserved.
68
+ --force Bypass uninstall safety checks (active worktrees, missing manifest)
69
+
70
+ Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement
71
+
72
+ What this adapter does NOT install (per ADR-004 honesty + ADR-021):
73
+ - Hook guards (CONDUCTOR emits the Reflector hook when --recipes=self-improvement, ADR-032; other guards remain Claude-only, ADR-034)
74
+ - Sub-agent personas (Windsurf has no sub-agent dispatch — single chat session per task)
75
+ - Per-pattern glob scoping (all .devin/rules/*.md load together)
76
+ - Hookify rule templates (Claude-only plugin)
77
+ EOF
78
+ exit 0
79
+ ;;
80
+ *)
81
+ if [ -z "$TARGET" ]; then
82
+ TARGET="$1"
83
+ else
84
+ echo "Unknown argument: $1" >&2
85
+ exit 1
86
+ fi
87
+ ;;
88
+ esac
89
+ shift
90
+ done
91
+
92
+ if [ -z "$TARGET" ]; then
93
+ echo "Error: target-project path is required." >&2
94
+ echo "Usage: bash adapters/windsurf/transform.sh <target-project> [--recipes=...]" >&2
95
+ exit 1
96
+ fi
97
+
98
+ # Resolve CONDUCTOR root (where this script lives: adapters/windsurf/).
99
+ CONDUCTOR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
100
+ CORE_ROOT="$CONDUCTOR_ROOT/core"
101
+ [ -d "$CORE_ROOT" ] || { echo "Error: core/ not found at $CORE_ROOT" >&2; exit 1; }
102
+
103
+ if [ "$DRY_RUN" = "true" ]; then
104
+ mkdir -p "$TARGET"
105
+ fi
106
+ TARGET_ABS="$(cd "$TARGET" 2>/dev/null && pwd)" || { echo "Error: target directory does not exist or is not a directory: $TARGET" >&2; exit 1; }
107
+
108
+ # ----- helpers ------------------------------------------------------------
109
+
110
+ log() {
111
+ if [ "$DRY_RUN" = "true" ]; then
112
+ echo "[dry-run] $*"
113
+ else
114
+ echo "[conductor] $*"
115
+ fi
116
+ }
117
+
118
+ mkdir_if_real() {
119
+ if [ "$DRY_RUN" = "true" ]; then
120
+ log "would mkdir -p $1"
121
+ else
122
+ mkdir -p "$1"
123
+ fi
124
+ }
125
+
126
+ # Strip the CONDUCTOR universal frontmatter (first --- ... --- block) from src body.
127
+ # Print body to stdout. Used by .devin/rules/*.md emit + .windsurfrules bundling.
128
+ strip_frontmatter() {
129
+ local src="$1"
130
+ /usr/bin/awk 'BEGIN{f=0} /^---$/{c++; if(c==2){f=1; next}} f==1' "$src"
131
+ }
132
+
133
+ # Emit a `.devin/rules/<name>.md` file from a `core/*.md` source.
134
+ # Windsurf does NOT use front-matter for filtering, so we strip it entirely and
135
+ # preserve the body verbatim.
136
+ # emit_rule <src> <dest>
137
+ emit_rule() {
138
+ local src="$1" dest="$2"
139
+ if [ "$DRY_RUN" = "true" ]; then
140
+ log "would write $dest (front-matter stripped)"
141
+ return
142
+ fi
143
+ strip_frontmatter "$src" > "$dest"
144
+ }
145
+
146
+ # backup_if_exists <dest>
147
+ # If <dest> is a regular file, copy it to <dest>.conductor-backup-<timestamp> before any
148
+ # downstream step overwrites it. Honors DRY_RUN. Idempotent across re-installs.
149
+ # Origin: ADR-019 (Claude adapter pattern, mirrored here per ADR-021).
150
+ backup_if_exists() {
151
+ local dest="$1"
152
+ if [ -f "$dest" ]; then
153
+ local ts
154
+ ts="$(/bin/date +%Y%m%d-%H%M%S)"
155
+ local backup="${dest}.conductor-backup-${ts}"
156
+ if [ "$DRY_RUN" = "true" ]; then
157
+ log "would back up existing $dest -> $backup"
158
+ else
159
+ /bin/cp "$dest" "$backup"
160
+ log " backed up existing $dest -> $backup"
161
+ fi
162
+ fi
163
+ }
164
+
165
+ # ----- manifest tracking (ADR-020, mirrored per ADR-021) ------------------
166
+ #
167
+ # Format identical to Claude/Cursor adapters' manifest. POSIX shell + sed only — no jq.
168
+
169
+ MANIFEST_PATH="$TARGET_ABS/.conductor-manifest.json"
170
+ MANIFEST_STAGE_PATH=""
171
+ MANIFEST_TS=""
172
+ MANIFEST_LAST_BACKUP=""
173
+
174
+ init_manifest() {
175
+ if [ "$DRY_RUN" = "true" ]; then
176
+ log "would init manifest staging at $MANIFEST_PATH.staging"
177
+ return
178
+ fi
179
+ MANIFEST_TS="$(/bin/date -u +%Y-%m-%dT%H:%M:%SZ)"
180
+ MANIFEST_STAGE_PATH="$TARGET_ABS/.conductor-manifest.json.staging"
181
+ /bin/rm -f "$MANIFEST_STAGE_PATH"
182
+ : > "$MANIFEST_STAGE_PATH"
183
+ }
184
+
185
+ record_emit() {
186
+ if [ "$DRY_RUN" = "true" ] || [ "$UNINSTALL" = "true" ]; then
187
+ return
188
+ fi
189
+ local relpath="$1" src="$2" backup="${3:-}"
190
+ local had_backup="false"
191
+ [ -n "$backup" ] && had_backup="true"
192
+ local esc_path esc_src esc_backup
193
+ esc_path="$(printf '%s' "$relpath" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
194
+ esc_src="$(printf '%s' "$src" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
195
+ esc_backup="$(printf '%s' "$backup" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
196
+ printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s"},\n' \
197
+ "$esc_path" "$esc_src" "$had_backup" "$esc_backup" >> "$MANIFEST_STAGE_PATH"
198
+ }
199
+
200
+ finalize_manifest() {
201
+ if [ "$DRY_RUN" = "true" ]; then
202
+ log "would finalize manifest -> $MANIFEST_PATH"
203
+ return
204
+ fi
205
+ [ -z "$MANIFEST_STAGE_PATH" ] && return
206
+ [ -f "$MANIFEST_STAGE_PATH" ] || return
207
+
208
+ if [ -f "$MANIFEST_PATH" ]; then
209
+ backup_if_exists "$MANIFEST_PATH"
210
+ fi
211
+
212
+ local recipes_json="[]"
213
+ if [ -n "$RECIPES" ]; then
214
+ recipes_json="["
215
+ local IFS_BAK=$IFS
216
+ IFS=','
217
+ local first="true"
218
+ for r in $RECIPES; do
219
+ r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
220
+ [ -z "$r" ] && continue
221
+ if [ "$first" = "true" ]; then
222
+ recipes_json="${recipes_json}\"$r\""
223
+ first="false"
224
+ else
225
+ recipes_json="${recipes_json}, \"$r\""
226
+ fi
227
+ done
228
+ IFS=$IFS_BAK
229
+ recipes_json="${recipes_json}]"
230
+ fi
231
+
232
+ local entries
233
+ if [ -s "$MANIFEST_STAGE_PATH" ]; then
234
+ entries="$(/usr/bin/sed -e '$ s/,$//' "$MANIFEST_STAGE_PATH")"
235
+ else
236
+ entries=""
237
+ fi
238
+
239
+ /bin/cat > "$MANIFEST_PATH" <<EOF
240
+ {
241
+ "version": "v0.2.0",
242
+ "adapter": "windsurf",
243
+ "install_timestamp": "$MANIFEST_TS",
244
+ "conductor_root": "$CONDUCTOR_ROOT",
245
+ "recipes_enabled": $recipes_json,
246
+ "emitted_files": [
247
+ $entries
248
+ ]
249
+ }
250
+ EOF
251
+ /bin/rm -f "$MANIFEST_STAGE_PATH"
252
+ log " wrote manifest $MANIFEST_PATH"
253
+ }
254
+
255
+ backup_and_remember() {
256
+ MANIFEST_LAST_BACKUP=""
257
+ if [ -f "$1" ]; then
258
+ if [ "$DRY_RUN" = "true" ]; then
259
+ log "would back up existing $1 -> $1.conductor-backup-<ts>"
260
+ MANIFEST_LAST_BACKUP=""
261
+ else
262
+ local ts
263
+ ts="$(/bin/date +%Y%m%d-%H%M%S)"
264
+ local backup="$1.conductor-backup-$ts"
265
+ /bin/cp "$1" "$backup"
266
+ log " backed up existing $1 -> $backup"
267
+ MANIFEST_LAST_BACKUP="${backup#$TARGET_ABS/}"
268
+ fi
269
+ fi
270
+ }
271
+
272
+ # ----- uninstall flow (mirrored from Cursor adapter) ----------------------
273
+
274
+ do_uninstall() {
275
+ log "uninstall mode (target: $TARGET_ABS)"
276
+
277
+ if [ ! -f "$MANIFEST_PATH" ]; then
278
+ if [ "$FORCE" = "true" ]; then
279
+ log "WARNING: no manifest at $MANIFEST_PATH — proceeding under --force (legacy backup scan only)"
280
+ uninstall_legacy_scan
281
+ return 0
282
+ fi
283
+ echo "Error: no manifest at $MANIFEST_PATH." >&2
284
+ echo " This target was either installed by a pre-manifest version or has already been uninstalled." >&2
285
+ echo " Re-run with --force to scan for legacy .conductor-backup-* files and delete them anyway:" >&2
286
+ echo " bash $0 $TARGET_ABS --uninstall --force" >&2
287
+ exit 1
288
+ fi
289
+
290
+ if [ -d "$TARGET_ABS/.git" ]; then
291
+ if [ -f "$TARGET_ABS/.git/MERGE_HEAD" ] || [ -f "$TARGET_ABS/.git/REBASE_HEAD" ] || [ -d "$TARGET_ABS/.git/rebase-merge" ]; then
292
+ if [ "$FORCE" != "true" ]; then
293
+ echo "Error: target has an active git operation (merge/rebase in progress)." >&2
294
+ echo " Resolve the in-flight operation first, or pass --force to override." >&2
295
+ exit 1
296
+ fi
297
+ log "WARNING: active git operation detected — proceeding under --force"
298
+ fi
299
+ fi
300
+
301
+ log "loading manifest entries..."
302
+ local entries_count=0
303
+ local restored=0
304
+ local deleted=0
305
+ local missing=0
306
+
307
+ while IFS= read -r line; do
308
+ case "$line" in
309
+ *'"path":'*'"source":'*'"had_backup":'*)
310
+ ;;
311
+ *) continue ;;
312
+ esac
313
+ entries_count=$((entries_count + 1))
314
+ local rel_path src had_backup backup_path
315
+ rel_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
316
+ src="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"source": *"([^"]*)".*/\1/')"
317
+ had_backup="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"had_backup": *(true|false).*/\1/')"
318
+ backup_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"backup_path": *"([^"]*)".*/\1/')"
319
+
320
+ local abs_dest="$TARGET_ABS/$rel_path"
321
+ local abs_backup=""
322
+ [ -n "$backup_path" ] && abs_backup="$TARGET_ABS/$backup_path"
323
+
324
+ if [ "$had_backup" = "true" ] && [ -n "$abs_backup" ]; then
325
+ if [ -f "$abs_backup" ]; then
326
+ if [ "$DRY_RUN" = "true" ]; then
327
+ log " would restore $abs_backup -> $abs_dest"
328
+ else
329
+ /bin/mv -f "$abs_backup" "$abs_dest"
330
+ log " restored $abs_backup -> $abs_dest"
331
+ fi
332
+ restored=$((restored + 1))
333
+ else
334
+ if [ "$DRY_RUN" = "true" ]; then
335
+ log " would delete $abs_dest (backup $abs_backup missing)"
336
+ else
337
+ /bin/rm -f "$abs_dest"
338
+ log " deleted $abs_dest (backup $abs_backup missing)"
339
+ fi
340
+ missing=$((missing + 1))
341
+ fi
342
+ else
343
+ if [ -f "$abs_dest" ]; then
344
+ if [ "$DRY_RUN" = "true" ]; then
345
+ log " would delete $abs_dest"
346
+ else
347
+ /bin/rm -f "$abs_dest"
348
+ log " deleted $abs_dest"
349
+ fi
350
+ deleted=$((deleted + 1))
351
+ else
352
+ log " skip $abs_dest (already absent)"
353
+ fi
354
+ fi
355
+ done < "$MANIFEST_PATH"
356
+
357
+ if [ "$DRY_RUN" = "true" ]; then
358
+ log " would delete $MANIFEST_PATH"
359
+ for mb in "$MANIFEST_PATH".conductor-backup-*; do
360
+ [ -e "$mb" ] && log " would delete $mb"
361
+ done
362
+ else
363
+ /bin/rm -f "$MANIFEST_PATH"
364
+ for mb in "$MANIFEST_PATH".conductor-backup-*; do
365
+ [ -e "$mb" ] && /bin/rm -f "$mb"
366
+ done
367
+ log " deleted $MANIFEST_PATH"
368
+ fi
369
+
370
+ # Try to clean up empty Conductor-emitted dirs left behind.
371
+ for d in .windsurf/rules .windsurf/workflows .windsurf/hooks .windsurf .devin/rules .devin .conductor/reflect .conductor; do
372
+ local abs_d="$TARGET_ABS/$d"
373
+ if [ -d "$abs_d" ]; then
374
+ if [ "$DRY_RUN" = "true" ]; then
375
+ if [ -z "$(/bin/ls -A "$abs_d" 2>/dev/null)" ]; then
376
+ log " would rmdir empty $abs_d"
377
+ fi
378
+ else
379
+ /bin/rmdir "$abs_d" 2>/dev/null && log " rmdir empty $abs_d" || true
380
+ fi
381
+ fi
382
+ done
383
+
384
+ echo ""
385
+ echo "========================================================"
386
+ if [ "$DRY_RUN" = "true" ]; then
387
+ echo " Uninstall preview (dry-run)"
388
+ else
389
+ echo " Uninstall complete"
390
+ fi
391
+ echo " Target: $TARGET_ABS"
392
+ echo " Entries processed: $entries_count"
393
+ echo " Backups restored: $restored"
394
+ echo " Files deleted: $deleted"
395
+ echo " Backup-missing deletes: $missing"
396
+ echo "========================================================"
397
+ }
398
+
399
+ uninstall_legacy_scan() {
400
+ log "legacy scan mode — searching for .conductor-backup-* files under $TARGET_ABS"
401
+ local found=0
402
+ while IFS= read -r f; do
403
+ found=$((found + 1))
404
+ if [ "$DRY_RUN" = "true" ]; then
405
+ log " would delete legacy backup $f"
406
+ else
407
+ /bin/rm -f "$f"
408
+ log " deleted legacy backup $f"
409
+ fi
410
+ done < <(/usr/bin/find "$TARGET_ABS" -type f -name '*.conductor-backup-*' 2>/dev/null)
411
+ log "legacy scan: $found backup file(s)"
412
+ log "WARNING: legacy mode does not delete Conductor-emitted source files (no manifest)."
413
+ log " Delete .windsurfrules and .devin/rules/*.md (or legacy .windsurf/rules/*.md) manually if desired."
414
+ }
415
+
416
+ if [ "$UNINSTALL" = "true" ]; then
417
+ do_uninstall
418
+ exit 0
419
+ fi
420
+
421
+ # ----- onboarding wizard --------------------------------------------------
422
+ # Wizard fires when adopter signal is detected: existing .windsurf/ OR existing .windsurfrules.
423
+ # Otherwise (truly fresh target) wizard is skipped.
424
+
425
+ IS_ADOPTER_CASE="false"
426
+ if [ -d "$TARGET_ABS/.windsurf" ] || [ -f "$TARGET_ABS/.windsurfrules" ]; then
427
+ IS_ADOPTER_CASE="true"
428
+ fi
429
+
430
+ if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN" = "false" ]; then
431
+ echo ""
432
+ echo "========================================================"
433
+ echo " Welcome to CONDUCTOR setup (Windsurf adapter)"
434
+ echo " Target: $TARGET_ABS"
435
+ echo "========================================================"
436
+ echo ""
437
+
438
+ printf "Detect existing rules? (y/N): "
439
+ read -r _detect_answer
440
+ if [ "$_detect_answer" = "y" ] || [ "$_detect_answer" = "Y" ]; then
441
+ _existing_rules=$(( $(ls "$TARGET_ABS/.devin/rules/" 2>/dev/null | wc -l | /usr/bin/tr -d ' ') + $(ls "$TARGET_ABS/.windsurf/rules/" 2>/dev/null | wc -l | /usr/bin/tr -d ' ') ))
442
+ _has_baseline="no"
443
+ [ -f "$TARGET_ABS/.windsurfrules" ] && _has_baseline="yes"
444
+ echo " Found $_existing_rules rule files in .devin/rules/ + .windsurf/rules/ (legacy), .windsurfrules present: $_has_baseline"
445
+ fi
446
+
447
+ printf "Apply universal-rules? (Y/n): "
448
+ read -r _apply_answer
449
+ if [ "$_apply_answer" = "n" ] || [ "$_apply_answer" = "N" ]; then
450
+ WIZARD_APPLY_RULES="false"
451
+ echo " Skipping universal-rules installation."
452
+ fi
453
+
454
+ echo ""
455
+ echo "Available recipes:"
456
+ echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement"
457
+ printf "Select recipes (comma-separated, or leave blank for none): "
458
+ read -r _recipe_answer
459
+ if [ -n "$_recipe_answer" ]; then
460
+ RECIPES="$_recipe_answer"
461
+ echo " Recipes selected: $RECIPES"
462
+ else
463
+ echo " No recipes selected."
464
+ fi
465
+
466
+ echo ""
467
+ elif [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "true" ]; then
468
+ log "Adopter case detected — applying defaults (--no-prompt): rules=yes, recipes=${RECIPES:-(none)}"
469
+ fi
470
+
471
+ # ----- step 1: synthesize .windsurfrules (always-loaded baseline) --------
472
+
473
+ init_manifest
474
+
475
+ UNIVERSAL_RULES="workflow spec-as-you-go quality-gates operations meta-discipline"
476
+
477
+ log "Step 1/4: synthesize .windsurfrules (always-loaded baseline)"
478
+ WINDSURFRULES_DEST="$TARGET_ABS/.windsurfrules"
479
+
480
+ if [ -f "$WINDSURFRULES_DEST" ]; then
481
+ log " $WINDSURFRULES_DEST exists — SKIP (exists), leaving in place"
482
+ elif [ "$DRY_RUN" = "true" ]; then
483
+ log "would write $WINDSURFRULES_DEST (orchestrator intro + ABSOLUTE rules summary + pointers)"
484
+ else
485
+ /bin/cat > "$WINDSURFRULES_DEST" <<'EOF'
486
+ # Project Orchestrator Manual (installed by CONDUCTOR)
487
+ # CONDUCTOR 가 설치한 프로젝트 오케스트레이터 매뉴얼
488
+
489
+ > This file is the always-loaded baseline for Windsurf. It loads on every session.
490
+ > 이 파일은 Windsurf 의 항상-로드 베이스라인입니다. 매 세션마다 자동 로드됩니다.
491
+
492
+ ## Role / 역할
493
+
494
+ You are the orchestrator: plan first, act deliberately, verify before declaring done.
495
+ 당신은 오케스트레이터입니다: 먼저 계획하고, 신중하게 실행하고, 완료 선언 전에 검증하세요.
496
+
497
+ Windsurf runs a single chat session per task (no sub-agent dispatch). You play
498
+ both planner and implementer; keep the plan explicit so it survives context resets.
499
+ Windsurf 는 작업당 단일 채팅 세션으로 동작합니다 (서브에이전트 디스패치 없음). 계획을
500
+ 명시적으로 유지해 컨텍스트 리셋에도 살아남게 하세요.
501
+
502
+ ## ABSOLUTE rules / 절대 규칙 (read before every change)
503
+
504
+ These are the universal floor. The full text loads from `.devin/rules/`.
505
+ 이것들이 보편 규칙의 최소선입니다. 전체 본문은 `.devin/rules/` 에서 로드됩니다.
506
+
507
+ | Rule | Summary |
508
+ |---|---|
509
+ | `workflow.md` | Plan-first, docs-first, 7-step process, process-over-speed, never-skip ABSOLUTE rules |
510
+ | `spec-as-you-go.md` | Update the spec in the SAME turn as the code edit; keep docs synced in real time |
511
+ | `quality-gates.md` | Pre-commit + pre-merge review, test coverage sync, verify-after-changes |
512
+ | `operations.md` | Session continuity, delete completed tasks, keep dev/prod in sync |
513
+ | `meta-discipline.md` | Originality, ambiguity AMB-1..7 triggers, token economy, model routing |
514
+
515
+ If you catch yourself about to break one, STOP and fix course. Silent recovery is
516
+ worse than explicit acknowledgment.
517
+ 하나라도 어기려는 자신을 발견하면 멈추고 바로잡으세요. 조용한 무마는 명시적 인정보다 나쁩니다.
518
+
519
+ ## Ambiguity policy / 모호성 정책
520
+
521
+ Default: ACT-WITH-DECLARATION — proceed with the best-guess interpretation and
522
+ surface the assumption at the top of your response.
523
+ 기본값: 선언과 함께 실행 — 최선의 해석으로 진행하되 가정을 응답 상단에 명시하세요.
524
+
525
+ Override to ASK (multiple-choice) when AMB-1..7 fires: deictic reference,
526
+ unspecified scope, external-system invocation, protected-branch merge, design
527
+ decisions, dependency add, or user-manual-action required. Full catalog:
528
+ `.devin/rules/meta-discipline.md`.
529
+
530
+ ## Session startup / 세션 시작
531
+
532
+ Read `docs/CURRENT_WORK.md` FIRST every session before touching code.
533
+ 매 세션마다 코드를 건드리기 전에 `docs/CURRENT_WORK.md` 를 먼저 읽으세요.
534
+
535
+ Lazy-load on demand: `docs/specs/<area>.md` when touching that area's code;
536
+ `docs/PLANS.md` / `docs/TASKS.md` for planning context.
537
+
538
+ ## Additional rules / 추가 규칙
539
+
540
+ Additional rules load from `.devin/rules/` (preferred; legacy `.windsurf/rules/`
541
+ is still read) — all files in that directory load together (Windsurf has no
542
+ per-pattern glob scoping). Selected recipes are emitted there too.
543
+ 추가 규칙은 `.devin/rules/` 에서 로드됩니다 (선호 경로; 레거시 `.windsurf/rules/` 도 계속
544
+ 읽힘) — 해당 디렉터리의 모든 파일이 함께 로드됩니다 (Windsurf 는 패턴별 glob 스코핑이
545
+ 없음). 선택한 recipe 도 이곳에 생성됩니다.
546
+
547
+ ## Not enforced on Windsurf / Windsurf 에서 미강제
548
+
549
+ Windsurf has no hooks and no sub-agent dispatch. The following are self-policed
550
+ reminders here (on Claude Code they are enforced by hooks):
551
+ Windsurf 는 훅과 서브에이전트 디스패치가 없습니다. 다음 항목은 여기서는 자율 준수 사항입니다
552
+ (Claude Code 에서는 훅으로 강제됨):
553
+
554
+ - Spec-as-you-go same-turn update — no Stop hook to block stale docs.
555
+ - Two-stage code review (pre-commit / pre-merge) — pair with a git pre-commit hook for mechanical enforcement.
556
+ - Model routing — Windsurf uses a single model per session; choose deliberately.
557
+ EOF
558
+ record_emit ".windsurfrules" "<synthesized>" ""
559
+ log " wrote $WINDSURFRULES_DEST"
560
+ fi
561
+
562
+ # ----- step 2: universal rules -> .devin/rules/*.md ----------------------
563
+
564
+ if [ "$WIZARD_APPLY_RULES" = "true" ]; then
565
+ log "Step 2/4: universal-rules → .devin/rules/ (preferred; legacy .windsurf/rules/ still read)"
566
+ mkdir_if_real "$TARGET_ABS/.devin/rules"
567
+
568
+ for rule in $UNIVERSAL_RULES; do
569
+ src="$CORE_ROOT/universal-rules/$rule.md"
570
+ dest="$TARGET_ABS/.devin/rules/$rule.md"
571
+ if [ ! -f "$src" ]; then
572
+ echo "Warning: $src not found; skipping" >&2
573
+ continue
574
+ fi
575
+ if [ -f "$dest" ] && [ "$DRY_RUN" = "false" ]; then
576
+ log " $dest exists — SKIP (exists)"
577
+ continue
578
+ fi
579
+ backup_and_remember "$dest"
580
+ emit_rule "$src" "$dest"
581
+ record_emit ".devin/rules/$rule.md" "core/universal-rules/$rule.md" "$MANIFEST_LAST_BACKUP"
582
+ done
583
+ else
584
+ log "Step 2/4: universal-rules — skipped (user opted out)"
585
+ fi
586
+
587
+ # ----- step 3: recipes (opt-in) -> .devin/rules/*.md ---------------------
588
+
589
+ log "Step 3/4: recipes (opt-in) → .devin/rules/ (preferred; legacy .windsurf/rules/ still read)"
590
+ INSTALLED_RECIPES=""
591
+ if [ -n "$RECIPES" ]; then
592
+ mkdir_if_real "$TARGET_ABS/.devin/rules"
593
+ IFS=',' read -ra RECIPE_LIST <<< "$RECIPES"
594
+ for r in "${RECIPE_LIST[@]}"; do
595
+ r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
596
+ [ -z "$r" ] && continue
597
+ src="$CORE_ROOT/recipes/$r.md"
598
+ dest="$TARGET_ABS/.devin/rules/$r.md"
599
+ if [ ! -f "$src" ]; then
600
+ echo "Warning: recipe '$r' not found at $src; skipping" >&2
601
+ continue
602
+ fi
603
+ if [ -f "$dest" ] && [ "$DRY_RUN" = "false" ]; then
604
+ log " $dest exists — SKIP (exists)"
605
+ INSTALLED_RECIPES="$INSTALLED_RECIPES $r"
606
+ continue
607
+ fi
608
+ backup_and_remember "$dest"
609
+ emit_rule "$src" "$dest"
610
+ record_emit ".devin/rules/$r.md" "core/recipes/$r.md" "$MANIFEST_LAST_BACKUP"
611
+ INSTALLED_RECIPES="$INSTALLED_RECIPES $r"
612
+ done
613
+ else
614
+ log " (no recipes selected — pass --recipes=name1,name2 to install)"
615
+ fi
616
+
617
+ # ----- step 3.5: self-improvement runtime (only with --recipes=self-improvement) ----
618
+
619
+ case ",$RECIPES," in
620
+ *",self-improvement,"*)
621
+ log "Step: self-improvement (Reflector) → hook/workflow/rule"
622
+ if [ "$DRY_RUN" != "true" ]; then
623
+ /bin/mkdir -p "$TARGET_ABS/.conductor/reflect" "$TARGET_ABS/.windsurf/workflows" "$TARGET_ABS/.devin/rules"
624
+ gi="$TARGET_ABS/.gitignore"
625
+ grep -qxF '.conductor/' "$gi" 2>/dev/null || printf '\n# CONDUCTOR runtime (local trajectories/lessons)\n.conductor/\n' >> "$gi"
626
+ for s in trajectory-log prune-lessons run-weekly; do
627
+ d="$TARGET_ABS/.conductor/reflect/$s.sh"
628
+ backup_and_remember "$d"; /bin/cp "$CORE_ROOT/reflector/$s.sh" "$d"; /bin/chmod +x "$d"
629
+ record_emit ".conductor/reflect/$s.sh" "core/reflector/$s.sh" "$MANIFEST_LAST_BACKUP"
630
+ done
631
+ # scheduling assets: run-weekly.sh needs the brief; SCHEDULING.md documents registration
632
+ for m in reflect-brief SCHEDULING; do
633
+ d="$TARGET_ABS/.conductor/reflect/$m.md"
634
+ backup_and_remember "$d"; /bin/cp "$CORE_ROOT/reflector/$m.md" "$d"
635
+ record_emit ".conductor/reflect/$m.md" "core/reflector/$m.md" "$MANIFEST_LAST_BACKUP"
636
+ done
637
+ hc="$TARGET_ABS/.windsurf/hooks.json"
638
+ if [ ! -f "$hc" ]; then
639
+ backup_and_remember "$hc"
640
+ /bin/cat > "$hc" <<'HOOK'
641
+ {
642
+ "hooks": {
643
+ "post_cascade_response_with_transcript": [
644
+ { "command": "./.conductor/reflect/trajectory-log.sh", "show_output": false }
645
+ ]
646
+ }
647
+ }
648
+ HOOK
649
+ record_emit ".windsurf/hooks.json" "<synthesized>" "$MANIFEST_LAST_BACKUP"
650
+ else
651
+ log " .windsurf/hooks.json exists — add a post_cascade_response_with_transcript hook calling ./.conductor/reflect/trajectory-log.sh manually"
652
+ fi
653
+ wf="$TARGET_ABS/.windsurf/workflows/reflect.md"
654
+ backup_and_remember "$wf"
655
+ { printf -- '---\ndescription: Run the CONDUCTOR Reflector — propose lessons from recent sessions (propose-only)\n---\n\n'; /bin/cat "$CORE_ROOT/reflector/reflect-brief.md"; } > "$wf"
656
+ record_emit ".windsurf/workflows/reflect.md" "core/reflector/reflect-brief.md" "$MANIFEST_LAST_BACKUP"
657
+ rl="$TARGET_ABS/.devin/rules/reflector.md"
658
+ backup_and_remember "$rl"
659
+ { printf -- '---\ntrigger: manual\ndescription: Reflector persona — propose lesson deltas, apply nothing.\n---\n\n'; strip_frontmatter "$CORE_ROOT/roles/reflector.md"; } > "$rl"
660
+ record_emit ".devin/rules/reflector.md" "core/roles/reflector.md" "$MANIFEST_LAST_BACKUP"
661
+ fi
662
+ ;;
663
+ esac
664
+
665
+ # ----- step 4: docs templates --------------------------------------------
666
+
667
+ log "Step 4/4: docs templates → docs/"
668
+ mkdir_if_real "$TARGET_ABS/docs"
669
+ mkdir_if_real "$TARGET_ABS/docs/specs"
670
+
671
+ for tpl in CURRENT_WORK REMAINING_TASKS PLANS TASKS INDEX; do
672
+ src="$CORE_ROOT/docs-templates/$tpl.md"
673
+ dest="$TARGET_ABS/docs/$tpl.md"
674
+ [ -f "$src" ] || continue
675
+ if [ -f "$dest" ]; then
676
+ log " $dest exists — leaving in place"
677
+ continue
678
+ fi
679
+ if [ "$DRY_RUN" = "true" ]; then
680
+ log "would copy $src -> $dest"
681
+ else
682
+ /bin/cp "$src" "$dest"
683
+ record_emit "docs/$tpl.md" "core/docs-templates/$tpl.md" ""
684
+ fi
685
+ done
686
+
687
+ if [ -f "$CORE_ROOT/docs-templates/specs/_example.md" ]; then
688
+ src="$CORE_ROOT/docs-templates/specs/_example.md"
689
+ dest="$TARGET_ABS/docs/specs/_example.md"
690
+ if [ ! -f "$dest" ]; then
691
+ if [ "$DRY_RUN" = "true" ]; then
692
+ log "would copy $src -> $dest"
693
+ else
694
+ /bin/cp "$src" "$dest"
695
+ record_emit "docs/specs/_example.md" "core/docs-templates/specs/_example.md" ""
696
+ fi
697
+ fi
698
+ fi
699
+
700
+ # Finalize manifest after all emits.
701
+ finalize_manifest
702
+
703
+ # ----- completion summary -------------------------------------------------
704
+
705
+ echo ""
706
+ echo "========================================================"
707
+ echo " Done."
708
+ echo " Target: $TARGET_ABS"
709
+ echo " Adapter: windsurf"
710
+ echo " Always-loaded baseline: .windsurfrules"
711
+ echo " Universal rules: 5 (.devin/rules/*.md, front-matter stripped)"
712
+ echo " Recipes installed:${INSTALLED_RECIPES:- (none)}"
713
+ echo ""
714
+ echo " Skipped (per ADR-004 honesty):"
715
+ echo " - Hooks: CONDUCTOR emits the Reflector hook when --recipes=self-improvement (ADR-032); other guards remain Claude-only (ADR-034)."
716
+ echo " - Sub-agent personas: Windsurf has no sub-agent dispatch — single chat session per task."
717
+ echo " - Per-pattern glob scoping: all .devin/rules/*.md load together."
718
+ echo " - Hookify rule templates: Claude-only plugin."
719
+ echo ""
720
+ echo " Activation: reopen the project in Windsurf so .windsurfrules + .devin/rules/ reload."
721
+ echo "========================================================"
722
+ echo ""
723
+ echo "Next steps for the project:"
724
+ echo " 1. Open $TARGET_ABS in Windsurf."
725
+ echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
726
+ echo " 3. Verify rule loading: confirm .windsurfrules + all .devin/rules/*.md show in the rule indicator."
727
+ echo " 4. Add .memory/ to .gitignore if you adopt the DIY memory pattern."