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.
- package/CHANGELOG.md +64 -0
- package/LICENSE +219 -0
- package/NOTICE +11 -0
- package/README.md +526 -0
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/TRADEMARKS.md +26 -0
- package/VISION.md +106 -0
- package/adapters/README.md +121 -0
- package/adapters/claude/README.md +102 -0
- package/adapters/claude/SUPPORTED-FEATURES.md +66 -0
- package/adapters/claude/hookify-templates/.recipe-scoped +9 -0
- package/adapters/claude/hookify-templates/README.md +93 -0
- package/adapters/claude/hookify-templates/block-completion-claim-without-push.local.md.template +56 -0
- package/adapters/claude/hookify-templates/block-direct-push-protected-branch.local.md.template +18 -0
- package/adapters/claude/hookify-templates/block-force-push-protected-branch.local.md.template +42 -0
- package/adapters/claude/hookify-templates/block-server-secret-in-client.local.md.template +36 -0
- package/adapters/claude/hookify-templates/warn-any-type-added.local.md.template +44 -0
- package/adapters/claude/hookify-templates/warn-commit-without-pre-commit-review.local.md.template +52 -0
- package/adapters/claude/hookify-templates/warn-console-direct.local.md.template +55 -0
- package/adapters/claude/hookify-templates/warn-create-table-without-access-control.local.md.template +35 -0
- package/adapters/claude/hookify-templates/warn-current-work-without-remaining-tasks.local.md.template +36 -0
- package/adapters/claude/hookify-templates/warn-gh-pr-create-without-pre-merge-review.local.md.template +38 -0
- package/adapters/claude/hookify-templates/warn-hardcoded-text-without-i18n-key.local.md.template +21 -0
- package/adapters/claude/hookify-templates/warn-on-gh-pr-merge.local.md.template +33 -0
- package/adapters/claude/hookify-templates/warn-plan-spec-without-remaining-tasks.local.md.template +44 -0
- package/adapters/claude/hookify-templates/warn-raw-hex-instead-of-token.local.md.template +21 -0
- package/adapters/claude/hookify-templates/warn-security-definer-without-search-path.local.md.template +30 -0
- package/adapters/claude/hookify-templates/warn-stop-commit-without-current-work.local.md.template +47 -0
- package/adapters/claude/hookify-templates/warn-user-manual-completion.local.md.template +40 -0
- package/adapters/claude/transform-spec.md +140 -0
- package/adapters/claude/transform.sh +1169 -0
- package/adapters/codex/README.md +87 -0
- package/adapters/codex/SUPPORTED-FEATURES.md +66 -0
- package/adapters/codex/transform-spec.md +90 -0
- package/adapters/codex/transform.sh +748 -0
- package/adapters/copilot/README.md +88 -0
- package/adapters/copilot/SUPPORTED-FEATURES.md +73 -0
- package/adapters/copilot/transform-spec.md +111 -0
- package/adapters/copilot/transform.sh +757 -0
- package/adapters/cursor/README.md +87 -0
- package/adapters/cursor/SUPPORTED-FEATURES.md +90 -0
- package/adapters/cursor/transform-spec.md +124 -0
- package/adapters/cursor/transform.sh +731 -0
- package/adapters/gemini/README.md +93 -0
- package/adapters/gemini/SUPPORTED-FEATURES.md +80 -0
- package/adapters/gemini/transform-spec.md +102 -0
- package/adapters/gemini/transform.sh +844 -0
- package/adapters/windsurf/README.md +93 -0
- package/adapters/windsurf/SUPPORTED-FEATURES.md +67 -0
- package/adapters/windsurf/transform-spec.md +99 -0
- package/adapters/windsurf/transform.sh +727 -0
- package/bin/omniconductor.js +130 -0
- package/core/README.md +64 -0
- package/core/anti-patterns/README.md +142 -0
- package/core/anti-patterns/dynamic-system-prompt.md +113 -0
- package/core/anti-patterns/frequent-rule-file-edit.md +83 -0
- package/core/anti-patterns/large-file-read-no-range.md +90 -0
- package/core/anti-patterns/no-sub-agent-dispatch.md +89 -0
- package/core/anti-patterns/single-monolithic-rule-file.md +99 -0
- package/core/anti-patterns/skill-eager-load.md +83 -0
- package/core/anti-patterns/tool-call-spam.md +93 -0
- package/core/docs-templates/CURRENT_WORK.md +64 -0
- package/core/docs-templates/INDEX.md +57 -0
- package/core/docs-templates/PLANS.md +44 -0
- package/core/docs-templates/README.md +40 -0
- package/core/docs-templates/REMAINING_TASKS.md +43 -0
- package/core/docs-templates/TASKS.md +51 -0
- package/core/docs-templates/specs/_example.md +121 -0
- package/core/hooks/README.md +62 -0
- package/core/hooks/pretool-agent-routing.sh.template +97 -0
- package/core/hooks/pretool-commit-current-work-check.sh.template +103 -0
- package/core/hooks/pretool-commit-test-coverage-check.sh.template +116 -0
- package/core/hooks/pretool-large-file-read-guard.sh.template +117 -0
- package/core/hooks/stop-cache-hit-baseline-check.sh.template +133 -0
- package/core/hooks/stop-r6-review-check.sh.template +80 -0
- package/core/hooks/stop-session-log-check.sh.template +101 -0
- package/core/hooks/stop-trajectory-log.sh.template +96 -0
- package/core/memory-pattern/EXAMPLES.md +114 -0
- package/core/memory-pattern/README.md +133 -0
- package/core/recipes/README.md +46 -0
- package/core/recipes/auto-mock-data.md +82 -0
- package/core/recipes/branch-strategy.md +100 -0
- package/core/recipes/coding-conventions.md +123 -0
- package/core/recipes/database-discipline.md +65 -0
- package/core/recipes/debugging.md +143 -0
- package/core/recipes/design-system.md +30 -0
- package/core/recipes/i18n.md +118 -0
- package/core/recipes/monorepo.md +101 -0
- package/core/recipes/self-improvement.md +61 -0
- package/core/recipes/tdd.md +128 -0
- package/core/recipes/web-mobile-parity.md +87 -0
- package/core/reflector/SCHEDULING.md +83 -0
- package/core/reflector/prune-lessons.sh +105 -0
- package/core/reflector/reflect-brief.md +11 -0
- package/core/reflector/reflect.command.md +13 -0
- package/core/reflector/run-weekly.sh +54 -0
- package/core/reflector/trajectory-log.sh +55 -0
- package/core/roles/README.md +61 -0
- package/core/roles/builder.md +75 -0
- package/core/roles/designer.md +93 -0
- package/core/roles/helper.md +70 -0
- package/core/roles/planner.md +123 -0
- package/core/roles/reflector.md +72 -0
- package/core/roles/reviewer.md +104 -0
- package/core/roles/scribe.md +89 -0
- package/core/universal-rules/README.md +71 -0
- package/core/universal-rules/meta-discipline.md +292 -0
- package/core/universal-rules/operations.md +162 -0
- package/core/universal-rules/quality-gates.md +191 -0
- package/core/universal-rules/spec-as-you-go.md +123 -0
- package/core/universal-rules/workflow.md +153 -0
- package/core/workflow/PHASES.md +134 -0
- package/core/workflow/README.md +56 -0
- package/docs/MANUAL-INSTALL.md +456 -0
- package/package.json +52 -0
- package/tools/check-framework-purity.sh +91 -0
- package/tools/measure-tokens.sh +169 -0
- 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."
|