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,844 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# CONDUCTOR — Gemini CLI adapter transform.sh
|
|
4
|
+
#
|
|
5
|
+
# Reads core/ assets and writes them into a target project as native Gemini CLI
|
|
6
|
+
# files: a single always-loaded GEMINI.md bundle, an optional .gemini/styleguide.md,
|
|
7
|
+
# and docs/* templates.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# bash adapters/gemini/transform.sh <target-project> [--recipes=<comma-list>] [--dry-run]
|
|
11
|
+
# [--no-prompt]
|
|
12
|
+
# bash adapters/gemini/transform.sh <target-project> --uninstall [--dry-run] [--force]
|
|
13
|
+
#
|
|
14
|
+
# Examples:
|
|
15
|
+
# bash adapters/gemini/transform.sh ~/Projects/my-app
|
|
16
|
+
# bash adapters/gemini/transform.sh ~/Projects/my-app --recipes=coding-conventions,i18n
|
|
17
|
+
# bash adapters/gemini/transform.sh /tmp/test-project --dry-run
|
|
18
|
+
# bash adapters/gemini/transform.sh . --no-prompt
|
|
19
|
+
# bash adapters/gemini/transform.sh . --uninstall # revert install
|
|
20
|
+
# bash adapters/gemini/transform.sh . --uninstall --force # bypass safety checks
|
|
21
|
+
#
|
|
22
|
+
# Layer 2 transformation (per ADR-004 honesty + ADR-021):
|
|
23
|
+
# core/universal-rules/*.md → <target>/GEMINI.md (all 5 bundled, single always-loaded file)
|
|
24
|
+
# core/workflow/PHASES.md → <target>/GEMINI.md (compressed workflow section)
|
|
25
|
+
# core/recipes/*.md (selected) → <target>/GEMINI.md (## Recipe — <name> sections; Gemini is single-file)
|
|
26
|
+
# core/recipes/coding-conventions → <target>/.gemini/styleguide.md (Gemini style-guide convention; opt-in)
|
|
27
|
+
# core/docs-templates/*.md → <target>/docs/*.md (CURRENT_WORK, REMAINING_TASKS, etc.)
|
|
28
|
+
# core/hooks/*.sh.template → SKIPPED (Reflector hook emitted via --recipes=self-improvement, ADR-032; other guards Claude-only, ADR-034)
|
|
29
|
+
# core/roles/*.md → SKIPPED (Gemini has no sub-agent dispatch)
|
|
30
|
+
#
|
|
31
|
+
# Gemini reality (per adapters/gemini/SUPPORTED-FEATURES.md):
|
|
32
|
+
# - Single always-loaded rule file (GEMINI.md). No per-pattern rule scoping.
|
|
33
|
+
# - No sub-agents, no per-call model routing, no built-in memory dir. CONDUCTOR
|
|
34
|
+
# emits the Reflector hook when --recipes=self-improvement (ADR-032); other
|
|
35
|
+
# guards remain Claude-only (ADR-034).
|
|
36
|
+
# The bundle below carries the rule TEXT honestly; Claude-only enforcement mechanisms
|
|
37
|
+
# are noted as self-policed for Gemini, never faked.
|
|
38
|
+
|
|
39
|
+
set -eu
|
|
40
|
+
|
|
41
|
+
# ----- arg parsing --------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
TARGET=""
|
|
44
|
+
RECIPES=""
|
|
45
|
+
DRY_RUN="false"
|
|
46
|
+
NO_PROMPT="false"
|
|
47
|
+
UNINSTALL="false"
|
|
48
|
+
FORCE="false"
|
|
49
|
+
|
|
50
|
+
# Onboarding wizard state
|
|
51
|
+
WIZARD_APPLY_RULES="true"
|
|
52
|
+
|
|
53
|
+
while [ $# -gt 0 ]; do
|
|
54
|
+
case "$1" in
|
|
55
|
+
--recipes=*) RECIPES="${1#--recipes=}" ;;
|
|
56
|
+
--dry-run) DRY_RUN="true" ;;
|
|
57
|
+
--no-prompt) NO_PROMPT="true" ;;
|
|
58
|
+
--uninstall|--rollback) UNINSTALL="true" ;;
|
|
59
|
+
--force) FORCE="true" ;;
|
|
60
|
+
--help|-h)
|
|
61
|
+
/bin/cat <<EOF
|
|
62
|
+
Usage: bash adapters/gemini/transform.sh <target-project> [options]
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
--recipes=A,B,C Comma-separated list of recipes to install (appended into GEMINI.md)
|
|
66
|
+
--dry-run Preview only — no files written
|
|
67
|
+
--no-prompt Skip all interactive prompts; apply sensible defaults (CI-safe)
|
|
68
|
+
--uninstall Revert a previous install using <target>/.conductor-manifest.json
|
|
69
|
+
(alias: --rollback). Restores backups when present, deletes
|
|
70
|
+
Conductor-emitted files when none. Customizations not in the
|
|
71
|
+
manifest are preserved.
|
|
72
|
+
--force Bypass uninstall safety checks (active worktrees, missing manifest)
|
|
73
|
+
|
|
74
|
+
Recipes available: web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement
|
|
75
|
+
|
|
76
|
+
Gemini single-file model:
|
|
77
|
+
- All 5 universal rules + selected recipes are bundled into one always-loaded GEMINI.md.
|
|
78
|
+
- There is NO per-pattern rule scoping (Gemini loads the whole file every session).
|
|
79
|
+
- The 'coding-conventions' recipe ALSO produces .gemini/styleguide.md (Gemini's
|
|
80
|
+
native style-guide convention).
|
|
81
|
+
|
|
82
|
+
What this adapter does NOT install (per ADR-004 honesty + ADR-021):
|
|
83
|
+
- Hook guards (CONDUCTOR emits the Reflector hook when --recipes=self-improvement, ADR-032; other guards remain Claude-only, ADR-034)
|
|
84
|
+
- Sub-agent personas (Gemini has no sub-agent dispatch — single chat session per task)
|
|
85
|
+
- Per-call model routing (single model per Gemini session)
|
|
86
|
+
- Built-in memory directory (DIY at .memory/ — see the note inside GEMINI.md)
|
|
87
|
+
EOF
|
|
88
|
+
exit 0
|
|
89
|
+
;;
|
|
90
|
+
*)
|
|
91
|
+
if [ -z "$TARGET" ]; then
|
|
92
|
+
TARGET="$1"
|
|
93
|
+
else
|
|
94
|
+
echo "Unknown argument: $1" >&2
|
|
95
|
+
exit 1
|
|
96
|
+
fi
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
99
|
+
shift
|
|
100
|
+
done
|
|
101
|
+
|
|
102
|
+
if [ -z "$TARGET" ]; then
|
|
103
|
+
echo "Error: target-project path is required." >&2
|
|
104
|
+
echo "Usage: bash adapters/gemini/transform.sh <target-project> [--recipes=...]" >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Resolve CONDUCTOR root (where this script lives: adapters/gemini/).
|
|
109
|
+
CONDUCTOR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
110
|
+
CORE_ROOT="$CONDUCTOR_ROOT/core"
|
|
111
|
+
[ -d "$CORE_ROOT" ] || { echo "Error: core/ not found at $CORE_ROOT" >&2; exit 1; }
|
|
112
|
+
|
|
113
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
114
|
+
mkdir -p "$TARGET"
|
|
115
|
+
fi
|
|
116
|
+
TARGET_ABS="$(cd "$TARGET" 2>/dev/null && pwd)" || { echo "Error: target directory does not exist or is not a directory: $TARGET" >&2; exit 1; }
|
|
117
|
+
|
|
118
|
+
# ----- helpers ------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
log() {
|
|
121
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
122
|
+
echo "[dry-run] $*"
|
|
123
|
+
else
|
|
124
|
+
echo "[conductor] $*"
|
|
125
|
+
fi
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
mkdir_if_real() {
|
|
129
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
130
|
+
log "would mkdir -p $1"
|
|
131
|
+
else
|
|
132
|
+
mkdir -p "$1"
|
|
133
|
+
fi
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Strip the CONDUCTOR universal frontmatter (first --- ... --- block) from src body.
|
|
137
|
+
# Print body to stdout.
|
|
138
|
+
strip_frontmatter() {
|
|
139
|
+
local src="$1"
|
|
140
|
+
/usr/bin/awk 'BEGIN{f=0} /^---$/{c++; if(c==2){f=1; next}} f==1' "$src"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Derive a section title from a rule/recipe markdown file: the first H1 after the
|
|
144
|
+
# frontmatter, with the leading "# " stripped. Falls back to the basename.
|
|
145
|
+
derive_title() {
|
|
146
|
+
local src="$1"
|
|
147
|
+
local title
|
|
148
|
+
title="$(strip_frontmatter "$src" | /usr/bin/grep -m1 '^# ' | /usr/bin/sed -e 's/^# *//')"
|
|
149
|
+
if [ -z "$title" ]; then
|
|
150
|
+
title="$(basename "$src" .md)"
|
|
151
|
+
fi
|
|
152
|
+
printf '%s' "$title"
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Emit a rule/recipe body into GEMINI.md as a section.
|
|
156
|
+
# The body (sans frontmatter) is demoted: its H1 "# Title" line is dropped (the
|
|
157
|
+
# caller supplies the "## " heading) and the Claude-only callout is rewritten for
|
|
158
|
+
# Gemini reality per transform-spec.md:
|
|
159
|
+
# "> **Claude-only mechanism**: ..." -> "> **Note (Gemini)**: enforced by hook
|
|
160
|
+
# on Claude Code; on Gemini CLI, follow self-policed."
|
|
161
|
+
# Honors DRY_RUN at the caller level (caller guards writes); this fn only prints.
|
|
162
|
+
emit_rule_body() {
|
|
163
|
+
local src="$1"
|
|
164
|
+
strip_frontmatter "$src" \
|
|
165
|
+
| /usr/bin/awk '
|
|
166
|
+
BEGIN{dropped=0}
|
|
167
|
+
# Drop the first H1 (the section title is provided by the caller as "## ").
|
|
168
|
+
dropped==0 && /^# /{dropped=1; next}
|
|
169
|
+
# Rewrite Claude-only mechanism callouts for Gemini self-policing.
|
|
170
|
+
/^> \*\*Claude-only mechanism\*\*/{
|
|
171
|
+
print "> **Note (Gemini)**: enforced by hook on Claude Code; on Gemini CLI, follow self-policed."
|
|
172
|
+
next
|
|
173
|
+
}
|
|
174
|
+
{print}
|
|
175
|
+
'
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# backup_if_exists <dest>
|
|
179
|
+
# If <dest> is a regular file, copy it to <dest>.conductor-backup-<timestamp> before any
|
|
180
|
+
# downstream step overwrites it. Honors DRY_RUN. Idempotent across re-installs.
|
|
181
|
+
# Origin: ADR-019 (Claude adapter pattern, mirrored here per ADR-021).
|
|
182
|
+
backup_if_exists() {
|
|
183
|
+
local dest="$1"
|
|
184
|
+
if [ -f "$dest" ]; then
|
|
185
|
+
local ts
|
|
186
|
+
ts="$(/bin/date +%Y%m%d-%H%M%S)"
|
|
187
|
+
local backup="${dest}.conductor-backup-${ts}"
|
|
188
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
189
|
+
log "would back up existing $dest -> $backup"
|
|
190
|
+
else
|
|
191
|
+
/bin/cp "$dest" "$backup"
|
|
192
|
+
log " backed up existing $dest -> $backup"
|
|
193
|
+
fi
|
|
194
|
+
fi
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# ----- manifest tracking (ADR-020, mirrored per ADR-021) ------------------
|
|
198
|
+
#
|
|
199
|
+
# Format identical to Claude/Cursor adapter manifests. POSIX shell + sed only — no jq.
|
|
200
|
+
|
|
201
|
+
MANIFEST_PATH="$TARGET_ABS/.conductor-manifest.json"
|
|
202
|
+
MANIFEST_STAGE_PATH=""
|
|
203
|
+
MANIFEST_TS=""
|
|
204
|
+
MANIFEST_LAST_BACKUP=""
|
|
205
|
+
|
|
206
|
+
init_manifest() {
|
|
207
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
208
|
+
log "would init manifest staging at $MANIFEST_PATH.staging"
|
|
209
|
+
return
|
|
210
|
+
fi
|
|
211
|
+
MANIFEST_TS="$(/bin/date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
212
|
+
MANIFEST_STAGE_PATH="$TARGET_ABS/.conductor-manifest.json.staging"
|
|
213
|
+
/bin/rm -f "$MANIFEST_STAGE_PATH"
|
|
214
|
+
: > "$MANIFEST_STAGE_PATH"
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
record_emit() {
|
|
218
|
+
if [ "$DRY_RUN" = "true" ] || [ "$UNINSTALL" = "true" ]; then
|
|
219
|
+
return
|
|
220
|
+
fi
|
|
221
|
+
local relpath="$1" src="$2" backup="${3:-}"
|
|
222
|
+
local had_backup="false"
|
|
223
|
+
[ -n "$backup" ] && had_backup="true"
|
|
224
|
+
local esc_path esc_src esc_backup
|
|
225
|
+
esc_path="$(printf '%s' "$relpath" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
226
|
+
esc_src="$(printf '%s' "$src" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
227
|
+
esc_backup="$(printf '%s' "$backup" | /usr/bin/sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
228
|
+
printf ' {"path": "%s", "source": "%s", "had_backup": %s, "backup_path": "%s"},\n' \
|
|
229
|
+
"$esc_path" "$esc_src" "$had_backup" "$esc_backup" >> "$MANIFEST_STAGE_PATH"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
finalize_manifest() {
|
|
233
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
234
|
+
log "would finalize manifest -> $MANIFEST_PATH"
|
|
235
|
+
return
|
|
236
|
+
fi
|
|
237
|
+
[ -z "$MANIFEST_STAGE_PATH" ] && return
|
|
238
|
+
[ -f "$MANIFEST_STAGE_PATH" ] || return
|
|
239
|
+
|
|
240
|
+
if [ -f "$MANIFEST_PATH" ]; then
|
|
241
|
+
backup_if_exists "$MANIFEST_PATH"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
local recipes_json="[]"
|
|
245
|
+
if [ -n "$RECIPES" ]; then
|
|
246
|
+
recipes_json="["
|
|
247
|
+
local IFS_BAK=$IFS
|
|
248
|
+
IFS=','
|
|
249
|
+
local first="true"
|
|
250
|
+
for r in $RECIPES; do
|
|
251
|
+
r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
|
|
252
|
+
[ -z "$r" ] && continue
|
|
253
|
+
if [ "$first" = "true" ]; then
|
|
254
|
+
recipes_json="${recipes_json}\"$r\""
|
|
255
|
+
first="false"
|
|
256
|
+
else
|
|
257
|
+
recipes_json="${recipes_json}, \"$r\""
|
|
258
|
+
fi
|
|
259
|
+
done
|
|
260
|
+
IFS=$IFS_BAK
|
|
261
|
+
recipes_json="${recipes_json}]"
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
local entries
|
|
265
|
+
if [ -s "$MANIFEST_STAGE_PATH" ]; then
|
|
266
|
+
entries="$(/usr/bin/sed -e '$ s/,$//' "$MANIFEST_STAGE_PATH")"
|
|
267
|
+
else
|
|
268
|
+
entries=""
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
/bin/cat > "$MANIFEST_PATH" <<EOF
|
|
272
|
+
{
|
|
273
|
+
"version": "v0.2.0",
|
|
274
|
+
"adapter": "gemini",
|
|
275
|
+
"install_timestamp": "$MANIFEST_TS",
|
|
276
|
+
"conductor_root": "$CONDUCTOR_ROOT",
|
|
277
|
+
"recipes_enabled": $recipes_json,
|
|
278
|
+
"emitted_files": [
|
|
279
|
+
$entries
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
EOF
|
|
283
|
+
/bin/rm -f "$MANIFEST_STAGE_PATH"
|
|
284
|
+
log " wrote manifest $MANIFEST_PATH"
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
backup_and_remember() {
|
|
288
|
+
MANIFEST_LAST_BACKUP=""
|
|
289
|
+
if [ -f "$1" ]; then
|
|
290
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
291
|
+
log "would back up existing $1 -> $1.conductor-backup-<ts>"
|
|
292
|
+
MANIFEST_LAST_BACKUP=""
|
|
293
|
+
else
|
|
294
|
+
local ts
|
|
295
|
+
ts="$(/bin/date +%Y%m%d-%H%M%S)"
|
|
296
|
+
local backup="$1.conductor-backup-$ts"
|
|
297
|
+
/bin/cp "$1" "$backup"
|
|
298
|
+
log " backed up existing $1 -> $backup"
|
|
299
|
+
MANIFEST_LAST_BACKUP="${backup#$TARGET_ABS/}"
|
|
300
|
+
fi
|
|
301
|
+
fi
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
# ----- uninstall flow (mirrored from Cursor/Claude adapter) ---------------
|
|
305
|
+
|
|
306
|
+
do_uninstall() {
|
|
307
|
+
log "uninstall mode (target: $TARGET_ABS)"
|
|
308
|
+
|
|
309
|
+
if [ ! -f "$MANIFEST_PATH" ]; then
|
|
310
|
+
if [ "$FORCE" = "true" ]; then
|
|
311
|
+
log "WARNING: no manifest at $MANIFEST_PATH — proceeding under --force (legacy backup scan only)"
|
|
312
|
+
uninstall_legacy_scan
|
|
313
|
+
return 0
|
|
314
|
+
fi
|
|
315
|
+
echo "Error: no manifest at $MANIFEST_PATH." >&2
|
|
316
|
+
echo " This target was either installed by a pre-manifest version or has already been uninstalled." >&2
|
|
317
|
+
echo " Re-run with --force to scan for legacy .conductor-backup-* files and delete them anyway:" >&2
|
|
318
|
+
echo " bash $0 $TARGET_ABS --uninstall --force" >&2
|
|
319
|
+
exit 1
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
if [ -d "$TARGET_ABS/.git" ]; then
|
|
323
|
+
if [ -f "$TARGET_ABS/.git/MERGE_HEAD" ] || [ -f "$TARGET_ABS/.git/REBASE_HEAD" ] || [ -d "$TARGET_ABS/.git/rebase-merge" ]; then
|
|
324
|
+
if [ "$FORCE" != "true" ]; then
|
|
325
|
+
echo "Error: target has an active git operation (merge/rebase in progress)." >&2
|
|
326
|
+
echo " Resolve the in-flight operation first, or pass --force to override." >&2
|
|
327
|
+
exit 1
|
|
328
|
+
fi
|
|
329
|
+
log "WARNING: active git operation detected — proceeding under --force"
|
|
330
|
+
fi
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
log "loading manifest entries..."
|
|
334
|
+
local entries_count=0
|
|
335
|
+
local restored=0
|
|
336
|
+
local deleted=0
|
|
337
|
+
local missing=0
|
|
338
|
+
|
|
339
|
+
while IFS= read -r line; do
|
|
340
|
+
case "$line" in
|
|
341
|
+
*'"path":'*'"source":'*'"had_backup":'*)
|
|
342
|
+
;;
|
|
343
|
+
*) continue ;;
|
|
344
|
+
esac
|
|
345
|
+
entries_count=$((entries_count + 1))
|
|
346
|
+
local rel_path src had_backup backup_path
|
|
347
|
+
rel_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"path": *"([^"]*)".*/\1/')"
|
|
348
|
+
src="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"source": *"([^"]*)".*/\1/')"
|
|
349
|
+
had_backup="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"had_backup": *(true|false).*/\1/')"
|
|
350
|
+
backup_path="$(printf '%s' "$line" | /usr/bin/sed -E 's/.*"backup_path": *"([^"]*)".*/\1/')"
|
|
351
|
+
|
|
352
|
+
local abs_dest="$TARGET_ABS/$rel_path"
|
|
353
|
+
local abs_backup=""
|
|
354
|
+
[ -n "$backup_path" ] && abs_backup="$TARGET_ABS/$backup_path"
|
|
355
|
+
|
|
356
|
+
if [ "$had_backup" = "true" ] && [ -n "$abs_backup" ]; then
|
|
357
|
+
if [ -f "$abs_backup" ]; then
|
|
358
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
359
|
+
log " would restore $abs_backup -> $abs_dest"
|
|
360
|
+
else
|
|
361
|
+
/bin/mv -f "$abs_backup" "$abs_dest"
|
|
362
|
+
log " restored $abs_backup -> $abs_dest"
|
|
363
|
+
fi
|
|
364
|
+
restored=$((restored + 1))
|
|
365
|
+
else
|
|
366
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
367
|
+
log " would delete $abs_dest (backup $abs_backup missing)"
|
|
368
|
+
else
|
|
369
|
+
/bin/rm -f "$abs_dest"
|
|
370
|
+
log " deleted $abs_dest (backup $abs_backup missing)"
|
|
371
|
+
fi
|
|
372
|
+
missing=$((missing + 1))
|
|
373
|
+
fi
|
|
374
|
+
else
|
|
375
|
+
if [ -f "$abs_dest" ]; then
|
|
376
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
377
|
+
log " would delete $abs_dest"
|
|
378
|
+
else
|
|
379
|
+
/bin/rm -f "$abs_dest"
|
|
380
|
+
log " deleted $abs_dest"
|
|
381
|
+
fi
|
|
382
|
+
deleted=$((deleted + 1))
|
|
383
|
+
else
|
|
384
|
+
log " skip $abs_dest (already absent)"
|
|
385
|
+
fi
|
|
386
|
+
fi
|
|
387
|
+
done < "$MANIFEST_PATH"
|
|
388
|
+
|
|
389
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
390
|
+
log " would delete $MANIFEST_PATH"
|
|
391
|
+
for mb in "$MANIFEST_PATH".conductor-backup-*; do
|
|
392
|
+
[ -e "$mb" ] && log " would delete $mb"
|
|
393
|
+
done
|
|
394
|
+
else
|
|
395
|
+
/bin/rm -f "$MANIFEST_PATH"
|
|
396
|
+
for mb in "$MANIFEST_PATH".conductor-backup-*; do
|
|
397
|
+
[ -e "$mb" ] && /bin/rm -f "$mb"
|
|
398
|
+
done
|
|
399
|
+
log " deleted $MANIFEST_PATH"
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
# Try to clean up empty dirs left behind (children before parents).
|
|
403
|
+
for d in .gemini/commands .gemini/agents .conductor/reflect .conductor .gemini; do
|
|
404
|
+
local abs_d="$TARGET_ABS/$d"
|
|
405
|
+
if [ -d "$abs_d" ]; then
|
|
406
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
407
|
+
if [ -z "$(/bin/ls -A "$abs_d" 2>/dev/null)" ]; then
|
|
408
|
+
log " would rmdir empty $abs_d"
|
|
409
|
+
fi
|
|
410
|
+
else
|
|
411
|
+
/bin/rmdir "$abs_d" 2>/dev/null && log " rmdir empty $abs_d" || true
|
|
412
|
+
fi
|
|
413
|
+
fi
|
|
414
|
+
done
|
|
415
|
+
|
|
416
|
+
echo ""
|
|
417
|
+
echo "========================================================"
|
|
418
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
419
|
+
echo " Uninstall preview (dry-run)"
|
|
420
|
+
else
|
|
421
|
+
echo " Uninstall complete"
|
|
422
|
+
fi
|
|
423
|
+
echo " Target: $TARGET_ABS"
|
|
424
|
+
echo " Entries processed: $entries_count"
|
|
425
|
+
echo " Backups restored: $restored"
|
|
426
|
+
echo " Files deleted: $deleted"
|
|
427
|
+
echo " Backup-missing deletes: $missing"
|
|
428
|
+
echo "========================================================"
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
uninstall_legacy_scan() {
|
|
432
|
+
log "legacy scan mode — searching for .conductor-backup-* files under $TARGET_ABS"
|
|
433
|
+
local found=0
|
|
434
|
+
while IFS= read -r f; do
|
|
435
|
+
found=$((found + 1))
|
|
436
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
437
|
+
log " would delete legacy backup $f"
|
|
438
|
+
else
|
|
439
|
+
/bin/rm -f "$f"
|
|
440
|
+
log " deleted legacy backup $f"
|
|
441
|
+
fi
|
|
442
|
+
done < <(/usr/bin/find "$TARGET_ABS" -type f -name '*.conductor-backup-*' 2>/dev/null)
|
|
443
|
+
log "legacy scan: $found backup file(s)"
|
|
444
|
+
log "WARNING: legacy mode does not delete Conductor-emitted source files (no manifest)."
|
|
445
|
+
log " Delete GEMINI.md and .gemini/styleguide.md manually if desired."
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if [ "$UNINSTALL" = "true" ]; then
|
|
449
|
+
do_uninstall
|
|
450
|
+
exit 0
|
|
451
|
+
fi
|
|
452
|
+
|
|
453
|
+
# ----- onboarding wizard --------------------------------------------------
|
|
454
|
+
# Wizard fires when adopter signal is detected: existing GEMINI.md OR existing .gemini/.
|
|
455
|
+
# Otherwise (truly fresh target) wizard is skipped.
|
|
456
|
+
|
|
457
|
+
IS_ADOPTER_CASE="false"
|
|
458
|
+
if [ -f "$TARGET_ABS/GEMINI.md" ] || [ -d "$TARGET_ABS/.gemini" ]; then
|
|
459
|
+
IS_ADOPTER_CASE="true"
|
|
460
|
+
fi
|
|
461
|
+
|
|
462
|
+
if [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "false" ] && [ "$DRY_RUN" = "false" ]; then
|
|
463
|
+
echo ""
|
|
464
|
+
echo "========================================================"
|
|
465
|
+
echo " Welcome to CONDUCTOR setup (Gemini CLI adapter)"
|
|
466
|
+
echo " Target: $TARGET_ABS"
|
|
467
|
+
echo "========================================================"
|
|
468
|
+
echo ""
|
|
469
|
+
|
|
470
|
+
printf "Detect existing config? (y/N): "
|
|
471
|
+
read -r _detect_answer
|
|
472
|
+
if [ "$_detect_answer" = "y" ] || [ "$_detect_answer" = "Y" ]; then
|
|
473
|
+
_has_gemini="no"
|
|
474
|
+
[ -f "$TARGET_ABS/GEMINI.md" ] && _has_gemini="yes"
|
|
475
|
+
_has_styleguide="no"
|
|
476
|
+
[ -f "$TARGET_ABS/.gemini/styleguide.md" ] && _has_styleguide="yes"
|
|
477
|
+
echo " GEMINI.md present: $_has_gemini, .gemini/styleguide.md present: $_has_styleguide"
|
|
478
|
+
fi
|
|
479
|
+
|
|
480
|
+
printf "Apply universal-rules bundle? (Y/n): "
|
|
481
|
+
read -r _apply_answer
|
|
482
|
+
if [ "$_apply_answer" = "n" ] || [ "$_apply_answer" = "N" ]; then
|
|
483
|
+
WIZARD_APPLY_RULES="false"
|
|
484
|
+
echo " Skipping universal-rules installation."
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
echo ""
|
|
488
|
+
echo "Available recipes:"
|
|
489
|
+
echo " web-mobile-parity, i18n, monorepo, branch-strategy, auto-mock-data, coding-conventions, tdd, debugging, database-discipline, design-system, self-improvement"
|
|
490
|
+
printf "Select recipes (comma-separated, or leave blank for none): "
|
|
491
|
+
read -r _recipe_answer
|
|
492
|
+
if [ -n "$_recipe_answer" ]; then
|
|
493
|
+
RECIPES="$_recipe_answer"
|
|
494
|
+
echo " Recipes selected: $RECIPES"
|
|
495
|
+
else
|
|
496
|
+
echo " No recipes selected."
|
|
497
|
+
fi
|
|
498
|
+
|
|
499
|
+
echo ""
|
|
500
|
+
elif [ "$IS_ADOPTER_CASE" = "true" ] && [ "$NO_PROMPT" = "true" ]; then
|
|
501
|
+
log "Adopter case detected — applying defaults (--no-prompt): rules=yes, recipes=${RECIPES:-(none)}"
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
# ----- step 1: GEMINI.md bundle (header + rules + workflow + pointers) ----
|
|
505
|
+
|
|
506
|
+
init_manifest
|
|
507
|
+
|
|
508
|
+
UNIVERSAL_RULES="workflow spec-as-you-go quality-gates operations meta-discipline"
|
|
509
|
+
GEMINI_DEST="$TARGET_ABS/GEMINI.md"
|
|
510
|
+
INSTALLED_RECIPES=""
|
|
511
|
+
|
|
512
|
+
# Detect whether the coding-conventions recipe is in the selection (drives styleguide emit).
|
|
513
|
+
WANT_STYLEGUIDE="false"
|
|
514
|
+
if [ -n "$RECIPES" ]; then
|
|
515
|
+
_old_ifs="$IFS"; IFS=','
|
|
516
|
+
for _r in $RECIPES; do
|
|
517
|
+
_r="$(printf '%s' "$_r" | /usr/bin/sed 's/^ *//; s/ *$//')"
|
|
518
|
+
[ "$_r" = "coding-conventions" ] && WANT_STYLEGUIDE="true"
|
|
519
|
+
done
|
|
520
|
+
IFS="$_old_ifs"
|
|
521
|
+
fi
|
|
522
|
+
|
|
523
|
+
log "Step 1/3: GEMINI.md bundle → $GEMINI_DEST"
|
|
524
|
+
|
|
525
|
+
if [ -f "$GEMINI_DEST" ] && [ "$DRY_RUN" = "false" ]; then
|
|
526
|
+
backup_and_remember "$GEMINI_DEST"
|
|
527
|
+
fi
|
|
528
|
+
|
|
529
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
530
|
+
log "would synthesize $GEMINI_DEST (bilingual header + ABSOLUTE rules summary + 5 universal rules + workflow + memory note)"
|
|
531
|
+
if [ "$WIZARD_APPLY_RULES" != "true" ]; then
|
|
532
|
+
log " (universal-rules opted out — header + workflow + docs pointer only)"
|
|
533
|
+
fi
|
|
534
|
+
if [ -n "$RECIPES" ]; then
|
|
535
|
+
log " would append recipe sections for: $RECIPES"
|
|
536
|
+
fi
|
|
537
|
+
else
|
|
538
|
+
# --- Header (synthesized inline; bilingual 한/영) ---
|
|
539
|
+
/bin/cat > "$GEMINI_DEST" <<'HEADER_EOF'
|
|
540
|
+
# CONDUCTOR — Orchestrator Manual (Gemini CLI)
|
|
541
|
+
|
|
542
|
+
> Installed by CONDUCTOR (Gemini adapter). Gemini CLI auto-loads this file every session.
|
|
543
|
+
> Replace `{{PROJECT_NAME}}` below with your project name.
|
|
544
|
+
|
|
545
|
+
## You are the orchestrator / 당신은 오케스트레이터입니다
|
|
546
|
+
|
|
547
|
+
**EN** — You are the lead orchestrator for **{{PROJECT_NAME}}**. You translate the
|
|
548
|
+
user's intent into a disciplined Plan → Architecture → Tasks → Implementation →
|
|
549
|
+
Review → Spec workflow. The universal rules below are your operating floor; every
|
|
550
|
+
turn inherits them. Gemini CLI runs a single chat session per task — there are no
|
|
551
|
+
sub-agents and no enforcement hooks here, so these rules are **self-policed**: you
|
|
552
|
+
follow them by reading them, not because a hook blocks you.
|
|
553
|
+
|
|
554
|
+
**KO** — 당신은 **{{PROJECT_NAME}}** 의 리드 오케스트레이터입니다. 사용자의 의도를
|
|
555
|
+
Plan → Architecture → Tasks → Implementation → Review → Spec 워크플로로 옮깁니다.
|
|
556
|
+
아래 universal rule 은 모든 턴이 상속하는 기본 규칙입니다. Gemini CLI 는 작업당 단일
|
|
557
|
+
세션으로 동작하며 sub-agent 나 enforcement hook 이 없습니다 — 따라서 이 규칙들은
|
|
558
|
+
**자기 규율(self-policed)** 로 지켜야 합니다.
|
|
559
|
+
|
|
560
|
+
> **Note (Gemini)**: Claude Code enforces parts of these rules with PreToolUse / Stop
|
|
561
|
+
> hooks and sub-agent dispatch. Gemini CLI has none of those surfaces. Where a rule
|
|
562
|
+
> mentions a Claude-only mechanism, treat it as self-policed: read the rule, follow it.
|
|
563
|
+
|
|
564
|
+
## ABSOLUTE rules (summary) / 절대 규칙 요약
|
|
565
|
+
|
|
566
|
+
These are ABSOLUTE — no user shortcut ("just do it", "skip", "fast") waives them.
|
|
567
|
+
The full text is in the universal-rule sections that follow.
|
|
568
|
+
|
|
569
|
+
1. **Plan-first / docs-first** — Plan → Architecture → Tasks → Implementation, in order.
|
|
570
|
+
Ad-hoc work is logged in `docs/CURRENT_WORK.md` BEFORE implementation. (Workflow)
|
|
571
|
+
2. **Spec-as-you-go** — a source edit and its spec/doc update happen in the SAME turn,
|
|
572
|
+
never batched for later. (Spec-as-you-go)
|
|
573
|
+
3. **Quality gates** — pre-commit + pre-merge review, test-coverage sync, and
|
|
574
|
+
verify-after-changes (evidence before any "done" claim). (Quality Gates)
|
|
575
|
+
4. **Operations hygiene** — read `docs/CURRENT_WORK.md` first every session; delete
|
|
576
|
+
completed tasks from active lists; keep dev/prod in parity. (Operations)
|
|
577
|
+
5. **Meta-discipline** — framework originality, ambiguity handling (ASK on the AMB
|
|
578
|
+
triggers), token economy, model-tier classification, flat-with-leader topology.
|
|
579
|
+
(Meta-Discipline)
|
|
580
|
+
|
|
581
|
+
> **Process over speed**: if a rule marked ABSOLUTE was skipped mid-turn, STOP, surface
|
|
582
|
+
> the violation in your next message, repair it, then continue. Silent recovery is worse
|
|
583
|
+
> than the original skip.
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
HEADER_EOF
|
|
588
|
+
|
|
589
|
+
# --- Universal rules (each as "## <title>" + body sans frontmatter) ---
|
|
590
|
+
if [ "$WIZARD_APPLY_RULES" = "true" ]; then
|
|
591
|
+
for rule in $UNIVERSAL_RULES; do
|
|
592
|
+
src="$CORE_ROOT/universal-rules/$rule.md"
|
|
593
|
+
if [ ! -f "$src" ]; then
|
|
594
|
+
echo "Warning: $src not found; skipping" >&2
|
|
595
|
+
continue
|
|
596
|
+
fi
|
|
597
|
+
title="$(derive_title "$src")"
|
|
598
|
+
{
|
|
599
|
+
echo "## $title"
|
|
600
|
+
echo ""
|
|
601
|
+
emit_rule_body "$src"
|
|
602
|
+
echo ""
|
|
603
|
+
echo "---"
|
|
604
|
+
echo ""
|
|
605
|
+
} >> "$GEMINI_DEST"
|
|
606
|
+
done
|
|
607
|
+
else
|
|
608
|
+
log " universal-rules — skipped (user opted out)"
|
|
609
|
+
fi
|
|
610
|
+
|
|
611
|
+
# --- Compressed workflow section from core/workflow/PHASES.md ---
|
|
612
|
+
PHASES_SRC="$CORE_ROOT/workflow/PHASES.md"
|
|
613
|
+
if [ -f "$PHASES_SRC" ]; then
|
|
614
|
+
{
|
|
615
|
+
echo "## Workflow phases (compressed)"
|
|
616
|
+
echo ""
|
|
617
|
+
echo "> Full reference: CONDUCTOR's core/workflow/PHASES.md. Compressed here for the"
|
|
618
|
+
echo "> single-file Gemini bundle. Phases scale with scope (see the table at the end)."
|
|
619
|
+
echo ""
|
|
620
|
+
# Compress: keep numbered phase headers + their Trigger/Owner/Inputs/Outputs
|
|
621
|
+
# lines and the scaling table; drop the "How to read this file" template
|
|
622
|
+
# preamble and the per-phase "P1 fill" scaffolding.
|
|
623
|
+
/usr/bin/awk '
|
|
624
|
+
/^## [0-9]+\. /{inphase=1; print "### " substr($0,4); next}
|
|
625
|
+
inphase==1 && /^\*\*Trigger\*\*/{print; next}
|
|
626
|
+
inphase==1 && /^\*\*Owner\*\*/{print; next}
|
|
627
|
+
inphase==1 && /^\*\*Inputs\*\*/{print; next}
|
|
628
|
+
inphase==1 && /^\*\*Outputs\*\*/{print; next}
|
|
629
|
+
/^## Phase scaling reminder/{inphase=0; intable=1; print "### Phase scaling"; next}
|
|
630
|
+
/^## Tool-agnostic enforcement reminder/{intable=0; next}
|
|
631
|
+
intable==1{print; next}
|
|
632
|
+
' "$PHASES_SRC"
|
|
633
|
+
echo ""
|
|
634
|
+
echo "---"
|
|
635
|
+
echo ""
|
|
636
|
+
} >> "$GEMINI_DEST"
|
|
637
|
+
fi
|
|
638
|
+
|
|
639
|
+
# --- Recipe sections (Gemini is single-file: append into GEMINI.md) ---
|
|
640
|
+
if [ -n "$RECIPES" ]; then
|
|
641
|
+
IFS=',' read -ra RECIPE_LIST <<< "$RECIPES"
|
|
642
|
+
for r in "${RECIPE_LIST[@]}"; do
|
|
643
|
+
r="$(printf '%s' "$r" | /usr/bin/sed 's/^ *//; s/ *$//')"
|
|
644
|
+
[ -z "$r" ] && continue
|
|
645
|
+
src="$CORE_ROOT/recipes/$r.md"
|
|
646
|
+
if [ ! -f "$src" ]; then
|
|
647
|
+
echo "Warning: recipe '$r' not found at $src; skipping" >&2
|
|
648
|
+
continue
|
|
649
|
+
fi
|
|
650
|
+
{
|
|
651
|
+
echo "## Recipe — $r"
|
|
652
|
+
echo ""
|
|
653
|
+
echo "> Opt-in recipe (installed via --recipes=$r). Gemini has no per-file rule"
|
|
654
|
+
echo "> scoping, so this is always-loaded alongside the universal rules."
|
|
655
|
+
echo ""
|
|
656
|
+
emit_rule_body "$src"
|
|
657
|
+
echo ""
|
|
658
|
+
echo "---"
|
|
659
|
+
echo ""
|
|
660
|
+
} >> "$GEMINI_DEST"
|
|
661
|
+
INSTALLED_RECIPES="$INSTALLED_RECIPES $r"
|
|
662
|
+
done
|
|
663
|
+
fi
|
|
664
|
+
|
|
665
|
+
# --- Docs pointer + memory note (footer) ---
|
|
666
|
+
/bin/cat >> "$GEMINI_DEST" <<'FOOTER_EOF'
|
|
667
|
+
## First read every session / 매 세션 첫 작업
|
|
668
|
+
|
|
669
|
+
**Read `docs/CURRENT_WORK.md` first every session.** It is the single source of
|
|
670
|
+
"what is happening right now" — current state, immediate next action, in-progress
|
|
671
|
+
items, blockers. Without it you risk duplicating finished work or pushing
|
|
672
|
+
conflicting changes. (See the Operations rule above.)
|
|
673
|
+
|
|
674
|
+
## Memory (.memory/) — DIY on Gemini / 메모리 설정
|
|
675
|
+
|
|
676
|
+
Gemini CLI has no built-in memory directory. CONDUCTOR's 4-type memory pattern
|
|
677
|
+
(user / feedback / project / reference) still applies — just host it yourself:
|
|
678
|
+
|
|
679
|
+
1. Create a `.memory/` directory at the project root.
|
|
680
|
+
2. Add `.memory/` to `.gitignore` so personal entries don't leak into the repo.
|
|
681
|
+
3. Keep a `.memory/MEMORY.md` index (≤ 200 lines) and `*.md` entries per type.
|
|
682
|
+
4. Gemini won't auto-load it — paste the relevant `.memory/*.md` entry into your
|
|
683
|
+
prompt (or @-mention the file) when it's relevant to the task.
|
|
684
|
+
|
|
685
|
+
Save: a user's role/preferences, corrections + validated approaches, ongoing
|
|
686
|
+
project goals/deadlines (use absolute dates), and pointers to external systems.
|
|
687
|
+
Do NOT save code patterns, file paths, git history, or anything already in the
|
|
688
|
+
rules above — verify before recommending from memory ("memory says X" ≠ "X is true now").
|
|
689
|
+
FOOTER_EOF
|
|
690
|
+
|
|
691
|
+
log " wrote $GEMINI_DEST ($(/usr/bin/wc -l < "$GEMINI_DEST" | /usr/bin/tr -d ' ') lines)"
|
|
692
|
+
|
|
693
|
+
# Gemini context-limit advisory (per transform-spec.md edge case).
|
|
694
|
+
_gemini_lines="$(/usr/bin/wc -l < "$GEMINI_DEST" | /usr/bin/tr -d ' ')"
|
|
695
|
+
if [ "$_gemini_lines" -gt 2000 ]; then
|
|
696
|
+
log " NOTE: GEMINI.md is large ($_gemini_lines lines). Most Gemini Pro models have a"
|
|
697
|
+
log " large context window, but if you hit a limit, trim recipes or move detail to docs/."
|
|
698
|
+
fi
|
|
699
|
+
fi
|
|
700
|
+
record_emit "GEMINI.md" "<synthesized:5-universal-rules+workflow>" "$MANIFEST_LAST_BACKUP"
|
|
701
|
+
|
|
702
|
+
# ----- step 2: .gemini/styleguide.md (opt-in: coding-conventions) ---------
|
|
703
|
+
|
|
704
|
+
log "Step 2/3: .gemini/styleguide.md (opt-in via --recipes=coding-conventions)"
|
|
705
|
+
if [ "$WANT_STYLEGUIDE" = "true" ]; then
|
|
706
|
+
STYLE_SRC="$CORE_ROOT/recipes/coding-conventions.md"
|
|
707
|
+
STYLE_DEST="$TARGET_ABS/.gemini/styleguide.md"
|
|
708
|
+
if [ ! -f "$STYLE_SRC" ]; then
|
|
709
|
+
echo "Warning: $STYLE_SRC not found; skipping styleguide" >&2
|
|
710
|
+
else
|
|
711
|
+
mkdir_if_real "$TARGET_ABS/.gemini"
|
|
712
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
713
|
+
log "would write $STYLE_DEST (coding-conventions body, header '# Code style guide')"
|
|
714
|
+
else
|
|
715
|
+
backup_and_remember "$STYLE_DEST"
|
|
716
|
+
{
|
|
717
|
+
echo "# Code style guide for {{PROJECT_NAME}}"
|
|
718
|
+
echo ""
|
|
719
|
+
echo "> Installed by CONDUCTOR (Gemini adapter) from the coding-conventions recipe."
|
|
720
|
+
echo "> Gemini CLI treats .gemini/styleguide.md as the canonical code-style reference."
|
|
721
|
+
echo "> Replace {{PROJECT_NAME}} with your project name."
|
|
722
|
+
echo ""
|
|
723
|
+
emit_rule_body "$STYLE_SRC"
|
|
724
|
+
} > "$STYLE_DEST"
|
|
725
|
+
record_emit ".gemini/styleguide.md" "core/recipes/coding-conventions.md" "$MANIFEST_LAST_BACKUP"
|
|
726
|
+
log " wrote $STYLE_DEST"
|
|
727
|
+
fi
|
|
728
|
+
fi
|
|
729
|
+
else
|
|
730
|
+
log " (coding-conventions not selected — pass --recipes=coding-conventions to emit styleguide)"
|
|
731
|
+
fi
|
|
732
|
+
|
|
733
|
+
# ----- self-improvement (opt-in: self-improvement recipe) ------------------
|
|
734
|
+
|
|
735
|
+
case ",$RECIPES," in
|
|
736
|
+
*",self-improvement,"*)
|
|
737
|
+
log "Step: self-improvement (Reflector) → .gemini hooks/command/agent"
|
|
738
|
+
if [ "$DRY_RUN" != "true" ]; then
|
|
739
|
+
/bin/mkdir -p "$TARGET_ABS/.conductor/reflect" "$TARGET_ABS/.gemini/commands" "$TARGET_ABS/.gemini/agents"
|
|
740
|
+
gi="$TARGET_ABS/.gitignore"
|
|
741
|
+
grep -qxF '.conductor/' "$gi" 2>/dev/null || printf '\n# CONDUCTOR runtime (local trajectories/lessons)\n.conductor/\n' >> "$gi"
|
|
742
|
+
for s in trajectory-log prune-lessons run-weekly; do
|
|
743
|
+
d="$TARGET_ABS/.conductor/reflect/$s.sh"
|
|
744
|
+
backup_and_remember "$d"; /bin/cp "$CORE_ROOT/reflector/$s.sh" "$d"; /bin/chmod +x "$d"
|
|
745
|
+
record_emit ".conductor/reflect/$s.sh" "core/reflector/$s.sh" "$MANIFEST_LAST_BACKUP"
|
|
746
|
+
done
|
|
747
|
+
# scheduling assets: run-weekly.sh needs the brief; SCHEDULING.md documents registration
|
|
748
|
+
for m in reflect-brief SCHEDULING; do
|
|
749
|
+
d="$TARGET_ABS/.conductor/reflect/$m.md"
|
|
750
|
+
backup_and_remember "$d"; /bin/cp "$CORE_ROOT/reflector/$m.md" "$d"
|
|
751
|
+
record_emit ".conductor/reflect/$m.md" "core/reflector/$m.md" "$MANIFEST_LAST_BACKUP"
|
|
752
|
+
done
|
|
753
|
+
# settings.json hooks — only if absent (merging JSON is unsafe in bash)
|
|
754
|
+
hc="$TARGET_ABS/.gemini/settings.json"
|
|
755
|
+
if [ ! -f "$hc" ]; then
|
|
756
|
+
backup_and_remember "$hc"
|
|
757
|
+
/bin/cat > "$hc" <<'HOOK'
|
|
758
|
+
{
|
|
759
|
+
"hooks": {
|
|
760
|
+
"SessionEnd": [
|
|
761
|
+
{ "matcher": "*", "hooks": [ { "type": "command", "command": "\"$GEMINI_PROJECT_DIR\"/.conductor/reflect/trajectory-log.sh", "timeout": 30000 } ] }
|
|
762
|
+
]
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
HOOK
|
|
766
|
+
record_emit ".gemini/settings.json" "<synthesized>" "$MANIFEST_LAST_BACKUP"
|
|
767
|
+
else
|
|
768
|
+
log " .gemini/settings.json exists — add a SessionEnd hook calling .conductor/reflect/trajectory-log.sh manually"
|
|
769
|
+
fi
|
|
770
|
+
cmd="$TARGET_ABS/.gemini/commands/reflect.toml"
|
|
771
|
+
backup_and_remember "$cmd"
|
|
772
|
+
{ printf 'description = "Run the CONDUCTOR Reflector — propose lessons from recent sessions (propose-only)."\nprompt = """\n'; /bin/cat "$CORE_ROOT/reflector/reflect-brief.md"; printf '\n"""\n'; } > "$cmd"
|
|
773
|
+
record_emit ".gemini/commands/reflect.toml" "core/reflector/reflect-brief.md" "$MANIFEST_LAST_BACKUP"
|
|
774
|
+
ag="$TARGET_ABS/.gemini/agents/reflector.md"
|
|
775
|
+
backup_and_remember "$ag"
|
|
776
|
+
{ printf -- '---\nname: reflector\ndescription: Reads session trajectories and proposes atomic lesson deltas. Propose-only; never applies.\n---\n\n'; strip_frontmatter "$CORE_ROOT/roles/reflector.md"; } > "$ag"
|
|
777
|
+
record_emit ".gemini/agents/reflector.md" "core/roles/reflector.md" "$MANIFEST_LAST_BACKUP"
|
|
778
|
+
fi
|
|
779
|
+
;;
|
|
780
|
+
esac
|
|
781
|
+
|
|
782
|
+
# ----- step 3: docs templates --------------------------------------------
|
|
783
|
+
|
|
784
|
+
log "Step 3/3: docs templates → docs/"
|
|
785
|
+
mkdir_if_real "$TARGET_ABS/docs"
|
|
786
|
+
mkdir_if_real "$TARGET_ABS/docs/specs"
|
|
787
|
+
|
|
788
|
+
for tpl in CURRENT_WORK REMAINING_TASKS PLANS TASKS INDEX; do
|
|
789
|
+
src="$CORE_ROOT/docs-templates/$tpl.md"
|
|
790
|
+
dest="$TARGET_ABS/docs/$tpl.md"
|
|
791
|
+
[ -f "$src" ] || continue
|
|
792
|
+
if [ -f "$dest" ]; then
|
|
793
|
+
log " $dest exists — leaving in place"
|
|
794
|
+
continue
|
|
795
|
+
fi
|
|
796
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
797
|
+
log "would copy $src -> $dest"
|
|
798
|
+
else
|
|
799
|
+
/bin/cp "$src" "$dest"
|
|
800
|
+
record_emit "docs/$tpl.md" "core/docs-templates/$tpl.md" ""
|
|
801
|
+
fi
|
|
802
|
+
done
|
|
803
|
+
|
|
804
|
+
if [ -f "$CORE_ROOT/docs-templates/specs/_example.md" ]; then
|
|
805
|
+
src="$CORE_ROOT/docs-templates/specs/_example.md"
|
|
806
|
+
dest="$TARGET_ABS/docs/specs/_example.md"
|
|
807
|
+
if [ ! -f "$dest" ]; then
|
|
808
|
+
if [ "$DRY_RUN" = "true" ]; then
|
|
809
|
+
log "would copy $src -> $dest"
|
|
810
|
+
else
|
|
811
|
+
/bin/cp "$src" "$dest"
|
|
812
|
+
record_emit "docs/specs/_example.md" "core/docs-templates/specs/_example.md" ""
|
|
813
|
+
fi
|
|
814
|
+
fi
|
|
815
|
+
fi
|
|
816
|
+
|
|
817
|
+
# Finalize manifest after all emits.
|
|
818
|
+
finalize_manifest
|
|
819
|
+
|
|
820
|
+
# ----- completion summary -------------------------------------------------
|
|
821
|
+
|
|
822
|
+
echo ""
|
|
823
|
+
echo "========================================================"
|
|
824
|
+
echo " Done."
|
|
825
|
+
echo " Target: $TARGET_ABS"
|
|
826
|
+
echo " Adapter: gemini"
|
|
827
|
+
echo " GEMINI.md: 1 bundled file (5 universal rules + workflow, always-loaded)"
|
|
828
|
+
echo " Style guide: $([ "$WANT_STYLEGUIDE" = "true" ] && echo ".gemini/styleguide.md emitted" || echo "(not emitted — select coding-conventions)")"
|
|
829
|
+
echo " Recipes installed:${INSTALLED_RECIPES:- (none)}"
|
|
830
|
+
echo ""
|
|
831
|
+
echo " Skipped (per ADR-004 honesty):"
|
|
832
|
+
echo " - Hooks: CONDUCTOR emits the Reflector hook when --recipes=self-improvement (ADR-032); other guards remain Claude-only (ADR-034)."
|
|
833
|
+
echo " - Sub-agent personas: Gemini has no sub-agent dispatch — single chat session per task."
|
|
834
|
+
echo " - Per-call model routing: single model per Gemini session."
|
|
835
|
+
echo " - Built-in memory: DIY at .memory/ (see the note inside GEMINI.md)."
|
|
836
|
+
echo ""
|
|
837
|
+
echo " Activation: open $TARGET_ABS with Gemini CLI — it loads GEMINI.md automatically."
|
|
838
|
+
echo "========================================================"
|
|
839
|
+
echo ""
|
|
840
|
+
echo "Next steps for the project:"
|
|
841
|
+
echo " 1. Replace {{PROJECT_NAME}} in GEMINI.md (and .gemini/styleguide.md if present)."
|
|
842
|
+
echo " 2. Edit docs/CURRENT_WORK.md with your project's current state."
|
|
843
|
+
echo " 3. Add .memory/ to .gitignore if you adopt the DIY memory pattern."
|
|
844
|
+
echo " 4. Rename docs/specs/_example.md → docs/specs/<your-area>.md."
|