Skip to content

Commit 4faecd5

Browse files
committed
ci: rebuild and verify model preset successor
1 parent fcd0a24 commit 4faecd5

1 file changed

Lines changed: 174 additions & 0 deletions

File tree

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
name: Rebuild and verify model preset successor
2+
3+
on:
4+
push:
5+
branches:
6+
- successor/model-preset-default-action-current
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
rebuild:
13+
if: github.actor == 'twoimo'
14+
runs-on: ubuntu-22.04
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
ref: successor/model-preset-default-action-current
19+
fetch-depth: 0
20+
token: ${{ secrets.GITHUB_TOKEN }}
21+
22+
- name: Rebuild minimal diff on current upstream dev
23+
shell: bash
24+
run: |
25+
git config user.name "twoimo"
26+
git config user.email "32544727+twoimo@users.noreply.github.com"
27+
git remote add upstream https://github.com/Yeachan-Heo/gajae-code.git || true
28+
git fetch --no-tags upstream dev
29+
git reset --hard upstream/dev
30+
python3 - <<'PY'
31+
from pathlib import Path
32+
33+
selector_path = Path('packages/coding-agent/src/modes/components/model-selector.ts')
34+
selector = selector_path.read_text()
35+
replacements = {
36+
'const PRESET_SCOPE_LABELS = ["Apply for this session", "Set as default"];':
37+
'const PRESET_SCOPE_LABELS = ["Set as default", "Apply for this session"];',
38+
'const CUSTOM_PRESET_SCOPE_LABELS = ["Apply for this session", "Set as default", "Rename", "Delete"];':
39+
'const CUSTOM_PRESET_SCOPE_LABELS = ["Set as default", "Apply for this session", "Rename", "Delete"];',
40+
'this.#listContainer.addChild(new Text(theme.fg("muted", " Press Enter to apply this preset"), 0, 0));':
41+
'this.#listContainer.addChild(new Text(theme.fg("muted", " Press Enter to choose an action"), 0, 0));',
42+
'setDefault: this.#presetScopeIndex === 1,': 'setDefault: this.#presetScopeIndex === 0,',
43+
}
44+
for old, new in replacements.items():
45+
if old not in selector:
46+
raise SystemExit(f'model-selector anchor missing: {old}')
47+
selector = selector.replace(old, new, 1)
48+
selector_path.write_text(selector)
49+
50+
test_path = Path('packages/coding-agent/test/model-selector-profiles-redteam.test.ts')
51+
tests = test_path.read_text()
52+
old = '''\ttest("profile actions wire Apply for this session to persistDefault false and Set as default to true", async () => {
53+
\t\tconst selections: ModelSelectorSelection[] = [];
54+
\t\tconst applySelector = createSelector(selection => {
55+
\t\t\tselections.push(selection);
56+
\t\t});
57+
\t\tawait renderSelector(applySelector);
58+
\t\tapplySelector.handleInput("\\x1b[C");
59+
\t\tapplySelector.handleInput("\\x1b[B");
60+
\t\tapplySelector.handleInput("\\n");
61+
\t\tapplySelector.handleInput("\\n");
62+
\t\tapplySelector.handleInput("\\n");
63+
64+
\t\tconst defaultSelector = createSelector(selection => {
65+
\t\t\tselections.push(selection);
66+
\t\t});
67+
\t\tawait renderSelector(defaultSelector);
68+
\t\tdefaultSelector.handleInput("\\x1b[C");
69+
\t\tdefaultSelector.handleInput("\\x1b[B");
70+
\t\tdefaultSelector.handleInput("\\n");
71+
\t\tdefaultSelector.handleInput("\\n");
72+
\t\tdefaultSelector.handleInput("\\x1b[B");
73+
\t\tdefaultSelector.handleInput("\\n");
74+
75+
\t\texpect(selections).toEqual([
76+
\t\t\t{ kind: "profile", profileName: "profile-a", setDefault: false },
77+
\t\t\t{ kind: "profile", profileName: "profile-a", setDefault: true },
78+
\t\t]);
79+
\t});
80+
'''
81+
new = '''\ttest("profile actions default to persistence and retain session-only application", async () => {
82+
\t\tconst selections: ModelSelectorSelection[] = [];
83+
\t\tconst select = (selection: ModelSelectorSelection) => selections.push(selection);
84+
\t\tconst persistentSelector = createSelector(select);
85+
\t\tawait renderSelector(persistentSelector);
86+
\t\tpersistentSelector.handleInput("\\x1b[C");
87+
\t\tpersistentSelector.handleInput("\\x1b[B");
88+
\t\tpersistentSelector.handleInput("\\n");
89+
\t\tpersistentSelector.handleInput("\\n");
90+
\t\tconst menu = normalizeRenderedText(persistentSelector.render(240).join("\\n"));
91+
\t\texpect(menu).toContain("Set as default");
92+
\t\texpect(menu).toContain("Apply for this session");
93+
\t\tpersistentSelector.handleInput("\\n");
94+
95+
\t\tconst sessionSelector = createSelector(select);
96+
\t\tawait renderSelector(sessionSelector);
97+
\t\tsessionSelector.handleInput("\\x1b[C");
98+
\t\tsessionSelector.handleInput("\\x1b[B");
99+
\t\tsessionSelector.handleInput("\\n");
100+
\t\tsessionSelector.handleInput("\\n");
101+
\t\tsessionSelector.handleInput("\\x1b[B");
102+
\t\tsessionSelector.handleInput("\\n");
103+
104+
\t\texpect(selections).toEqual([
105+
\t\t\t{ kind: "profile", profileName: "profile-a", setDefault: true },
106+
\t\t\t{ kind: "profile", profileName: "profile-a", setDefault: false },
107+
\t\t]);
108+
\t});
109+
110+
\ttest("custom profile action indices retain rename and delete", async () => {
111+
\t\tconst renamed: ModelSelectorSelection[] = [];
112+
\t\tconst renameSelector = createSelector(selection => renamed.push(selection));
113+
\t\tawait renderSelector(renameSelector);
114+
\t\trenameSelector.refreshPresetProfiles("profile-a");
115+
\t\trenameSelector.handleInput("\\n");
116+
\t\trenameSelector.handleInput("\\x1b[B");
117+
\t\trenameSelector.handleInput("\\x1b[B");
118+
\t\trenameSelector.handleInput("\\n");
119+
120+
\t\tconst deleted: ModelSelectorSelection[] = [];
121+
\t\tconst deleteSelector = createSelector(selection => deleted.push(selection));
122+
\t\tawait renderSelector(deleteSelector);
123+
\t\tdeleteSelector.refreshPresetProfiles("profile-a");
124+
\t\tdeleteSelector.handleInput("\\n");
125+
\t\tdeleteSelector.handleInput("\\x1b[B");
126+
\t\tdeleteSelector.handleInput("\\x1b[B");
127+
\t\tdeleteSelector.handleInput("\\x1b[B");
128+
\t\tdeleteSelector.handleInput("\\n");
129+
130+
\t\texpect(renamed).toEqual([{ kind: "renameProfile", profileName: "profile-a" }]);
131+
\t\texpect(deleted).toEqual([{ kind: "deleteProfile", profileName: "profile-a" }]);
132+
\t});
133+
'''
134+
if old not in tests:
135+
raise SystemExit('model selector red-team anchor missing')
136+
test_path.write_text(tests.replace(old, new, 1))
137+
138+
changelog_path = Path('packages/coding-agent/CHANGELOG.md')
139+
changelog = changelog_path.read_text()
140+
entry = '- `/model` preset selection now offers `Set as default` as the first action while retaining `Apply for this session`, custom preset rename, and delete actions.\n'
141+
if entry not in changelog:
142+
marker = '### Changed\n\n'
143+
if marker not in changelog:
144+
changelog = changelog.replace('## [Unreleased]\n', '## [Unreleased]\n### Changed\n\n', 1)
145+
changelog = changelog.replace('### Changed\n\n', '### Changed\n\n' + entry, 1)
146+
changelog_path.write_text(changelog)
147+
PY
148+
149+
- uses: oven-sh/setup-bun@v2
150+
with:
151+
bun-version: '1.3'
152+
153+
- name: Install, format, and verify
154+
run: |
155+
bun install --frozen-lockfile
156+
bunx biome check --write \
157+
packages/coding-agent/src/modes/components/model-selector.ts \
158+
packages/coding-agent/test/model-selector-profiles-redteam.test.ts
159+
bun test --timeout 30000 \
160+
packages/coding-agent/test/model-selector-profiles.test.ts \
161+
packages/coding-agent/test/model-selector-profiles-redteam.test.ts \
162+
packages/coding-agent/test/model-preset-landing-redteam-qa.test.ts \
163+
packages/coding-agent/test/cli-args-mpreset.test.ts
164+
bun --cwd=packages/coding-agent run check
165+
166+
- name: Publish verified clean successor
167+
shell: bash
168+
run: |
169+
git add \
170+
packages/coding-agent/CHANGELOG.md \
171+
packages/coding-agent/src/modes/components/model-selector.ts \
172+
packages/coding-agent/test/model-selector-profiles-redteam.test.ts
173+
git commit -m "feat(coding-agent): default preset selection to persistence"
174+
git push --force origin HEAD:successor/model-preset-default-action-current

0 commit comments

Comments
 (0)