Skip to content

Commit b46650d

Browse files
fix: repair oc-switch agent model selection
1 parent 9a76905 commit b46650d

9 files changed

Lines changed: 91 additions & 10 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ After a tagged release is published, you can install the same CLI directly
327327
from GitHub without keeping a checkout:
328328

329329
```bash
330-
npm install --global "git+https://github.com/jcarlosrodicio/opencode-agent-orchestration-kit.git#v1.0.40"
330+
npm install --global "git+https://github.com/jcarlosrodicio/opencode-agent-orchestration-kit.git#v1.0.41"
331331
oc-switch
332332
```
333333

@@ -741,7 +741,7 @@ Validate only the canonical identity and current release note with:
741741

742742
```bash
743743
npm run check:version
744-
node scripts/version.mjs --check-tag v1.0.40
744+
node scripts/version.mjs --check-tag v1.0.41
745745
```
746746

747747
Tag validation compares an explicitly supplied tag with the package identity.

docs/models.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ oc-switch
2626
Once a release tag exists, a checkout is optional:
2727

2828
```bash
29-
npm install --global "git+https://github.com/jcarlosrodicio/opencode-agent-orchestration-kit.git#v1.0.40"
29+
npm install --global "git+https://github.com/jcarlosrodicio/opencode-agent-orchestration-kit.git#v1.0.41"
3030
oc-switch
3131
```
3232

docs/releases/v1.0.41.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# v1.0.41 - Safe lifecycle and canonical release identity
2+
3+
This patch release fixes agent-row selection in the interactive OpenCode model
4+
switcher. Selecting a model for an agent now updates the agent assignment instead
5+
of rejecting the selection as an invalid target.
6+
7+
## Highlights
8+
9+
- Fix `oc-switch` agent-row selections by mapping focused agent rows to the
10+
internal `agents` assignment target.
11+
- Add a regression test covering a focused agent selecting and saving a model.
12+
13+
## Installation or upgrade
14+
15+
Install or upgrade the public kit using the normal manifest-owned flow:
16+
17+
```bash
18+
./install.sh --dry-run
19+
./install.sh
20+
./upgrade.sh --dry-run
21+
./upgrade.sh
22+
```
23+
24+
After installation, run `oak check` and review the installed target before
25+
using the harness.
26+
27+
## Migration
28+
29+
No migration is required. Existing model-switcher state and shell routing
30+
remain compatible.
31+
32+
## Validation performed
33+
34+
The focused selector tests, full 1,068-test unit and script suite, contract
35+
check, package smoke, syntax checks, and dry-run package inspection passed.
36+
37+
## Public safety boundary
38+
39+
The public release excludes private OpenCode and Pi configuration, local
40+
providers and MCP wiring, credentials, authentication files, raw transcripts,
41+
private evidence, absolute machine paths, and runtime state. Pi uses its own
42+
native model catalog and is not included in this OpenCode package.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opencode-agent-orchestration-kit",
3-
"version": "1.0.40",
3+
"version": "1.0.41",
44
"private": false,
55
"license": "Apache-2.0",
66
"type": "module",

scripts/benchmark-tool-paths.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ async function benchmarkFixture(fixture, iterations, temporaryRoot) {
143143
const result = await createInstallationManager({
144144
sourceRoot: fixture.sourceRoot,
145145
repositoryRoot: fixture.root,
146-
versionProvider: () => "1.0.40",
146+
versionProvider: () => "1.0.41",
147147
}).run("install", { targetRoot });
148148
if (result.exitCode !== 0) throw invalid(`installation benchmark failed for ${fixture.id}`);
149149
} finally {

scripts/oc-switch.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ export async function runTerminalOcSwitcher({ input = process.stdin, output = pr
411411
const targetAgents = pickerTarget.kind === "agent"
412412
? [...(selectedAgents.size ? selectedAgents : new Set([pickerTarget.key]))]
413413
: [];
414-
state = applyModelSelection(state, { target: pickerTarget.key, agents: targetAgents, modelRef: available[pickerFocusedIndex] });
414+
const target = pickerTarget.kind === "agent" ? "agents" : pickerTarget.key;
415+
state = applyModelSelection(state, { target, agents: targetAgents, modelRef: available[pickerFocusedIndex] });
415416
dirty = true; selectedAgents.clear(); screen = "main"; status = "Change pending save.";
416417
} else if (name === "escape") { screen = "main"; pickerQuery = ""; }
417418
else if (name === "backspace") { pickerQuery = pickerQuery.slice(0, -1); pickerFocusedIndex = 0; }

scripts/oc-switch.test.mjs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,44 @@ test("OpenCode TUI changes the default model and persists on q", async () => {
139139
assert.match(output.writes.join(""), /Loading models/);
140140
});
141141

142+
test("OpenCode TUI changes the focused agent model", async () => {
143+
const input = createTuiInput();
144+
const output = { isTTY: true, rows: 30, writes: [], write(chunk) { this.writes.push(String(chunk)); } };
145+
const saved = [];
146+
const state = {
147+
schemaVersion: 1,
148+
defaultModel: "nan/model-a",
149+
smallModel: "nan/model-a",
150+
agents: Object.fromEntries(AGENT_IDS.map((agent) => [agent, "nan/model-a"])),
151+
};
152+
const running = runTerminalOcSwitcher({
153+
input,
154+
output,
155+
initialState: state,
156+
initialModels: ["nan/model-a", "openai/model-b"],
157+
refreshModels: async () => ["nan/model-a", "openai/model-b"],
158+
saveState: async (nextState) => {
159+
saved.push(nextState);
160+
return nextState;
161+
},
162+
});
163+
164+
await nextTick();
165+
emitKey(input, "down");
166+
emitKey(input, "down");
167+
emitKey(input, "return", "\r");
168+
await nextTick();
169+
emitKey(input, "down");
170+
emitKey(input, "return", "\r");
171+
await nextTick();
172+
emitKey(input, "q");
173+
const result = await running;
174+
175+
assert.equal(result.status, "saved");
176+
assert.equal(saved.length, 1);
177+
assert.equal(saved[0].agents.lead, "openai/model-b");
178+
});
179+
142180
test("OpenCode search treats shortcut letters as query text", async () => {
143181
const input = createTuiInput();
144182
const output = { isTTY: true, rows: 30, writes: [], write(chunk) { this.writes.push(String(chunk)); } };

scripts/package-smoke.test.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717

1818
const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
1919
const HASH = "a".repeat(64);
20-
const BASENAME = "opencode-agent-orchestration-kit-1.0.40.tgz";
20+
const BASENAME = "opencode-agent-orchestration-kit-1.0.41.tgz";
2121
const REQUIRED = [
2222
"package/package.json",
2323
"package/supply-chain.json",
@@ -210,7 +210,7 @@ test("smokeTarball validates both archive listings before extraction", async ()
210210
await assert.rejects(
211211
smokeTarball({
212212
repositoryRoot: ROOT,
213-
tarball: "/public/opencode-agent-orchestration-kit-1.0.40.tgz",
213+
tarball: "/public/opencode-agent-orchestration-kit-1.0.41.tgz",
214214
captureTarball(_source, destination) {
215215
fs.writeFileSync(destination, "fixture");
216216
return { size: 1 };

scripts/version.test.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ test("[V004] direct version entrypoints are exact and mutation-free", (t) => {
109109
for (const args of [["scripts/version.mjs"], ["scripts/manage-installation.mjs", "--version"]]) {
110110
const result = run(process.execPath, args, { HOME: home });
111111
assert.equal(result.status, 0, result.stderr);
112-
assert.equal(result.stdout, "opencode-agent-orchestration-kit 1.0.40\n");
112+
assert.equal(result.stdout, "opencode-agent-orchestration-kit 1.0.41\n");
113113
assert.equal(fs.existsSync(target), false);
114114
}
115115
});
@@ -118,7 +118,7 @@ test("[V005] all lifecycle wrappers expose the canonical version", () => {
118118
for (const wrapper of ["install.sh", "upgrade.sh", "doctor.sh", "uninstall.sh", "rollback.sh"]) {
119119
const result = run(path.join(REPOSITORY_ROOT, wrapper), ["--version"]);
120120
assert.equal(result.status, 0, `${wrapper}: ${result.stderr}`);
121-
assert.equal(result.stdout, "opencode-agent-orchestration-kit 1.0.40\n", wrapper);
121+
assert.equal(result.stdout, "opencode-agent-orchestration-kit 1.0.41\n", wrapper);
122122
}
123123
});
124124

0 commit comments

Comments
 (0)