Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions DIVERGENCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ from the squash message first, or use a plain merge.
| `packages/opencode/test/tool/write.test.ts` | "sets file permissions when writing sensitive data" asserts `stats.mode & 0o777` equals `0o666 & ~process.umask()` instead of a hardcoded `0o644` | The write tool never chmods — it calls `fs.writeWithDirs`, so the mode is just the 0o666 creation default masked by the process umask. `0o644` silently encodes the umask 022 that CI runners happen to use, and the test fails with `0o664` on any developer machine running the equally common umask 002. The assertion still pins the tool to the platform default (a stray chmod would break it). | Keep our umask-derived expectation; take upstream's test changes. If upstream ever makes the tool chmod explicitly, drop this row and assert the explicit mode. |
| `packages/opencode/test/provider/provider.test.ts`, `packages/opencode/test/provider/transform.test.ts` | Appended two fork-only blocks at the end of each file: an `it.instance` ("declared image modality makes a custom-provider model attachment capable") asserting a config model with no `modalities` resolves `attachment`/`input.image` to false while one carrying the `@codev/gateway` block resolves both true, and a `describe` ("ProviderTransform.message - image input on a custom provider") asserting `unsupportedParts` passes `image`/`file` parts through when the model declares image input and swaps them for the `ERROR: Cannot read …` note when it doesn't. No upstream test changed. | These pin the two upstream code paths the fork's config writer depends on (`provider.ts` modality→capability resolution, `transform.ts` part filtering); upstream leaves both untested, so a refactor there would silently re-break gateway image attachments. | Keep our appended blocks; take upstream's test changes. Append-only, so conflicts should be end-of-file context alone. |
| `packages/opencode/test/server/httpapi-exercise/environment.ts` | Exercise config/data dirs `config/opencode`,`data/opencode` → `…/codev`; seeds `codev.json` with `{"share":"manual"}` | Follows the `global.ts` app-dir rename (row above); the fork's `share: "disabled"` default (config.ts row) would 500 the share/unshare scenarios, so the isolated environment opts back in (network stays stubbed by `CODEV_DISABLE_SHARE`). Seed file follows the config-file rename row (global `config.json` is no longer read). | Keep our dir names + seeded config; take upstream's surrounding changes. |
| Skill Stack HTTP routes: `packages/protocol/src/api.ts`, `packages/server/src/handlers.ts`, `packages/server/package.json`, `packages/schema/src/index.ts` | `api.ts` imports and `.add(SkillHubGroup.middleware(locationMiddleware))` (last group; `src/groups/skillhub.ts` is fork-only); `handlers.ts` merges `SkillHubHandler` (`src/handlers/skillhub.ts`, fork-only); server `package.json` adds `"@codev/skillhub": "workspace:*"`; schema `index.ts` exports `SkillStack` (`src/skill-stack.ts`, fork-only). | The v2 group `server.skillhub` (`GET /api/skillhub/stack`, `POST …/:slug/prepare`, `POST …/install`, `DELETE …/staging/:stagingID`) puts all CoDev SkillHub Skill Stack traffic behind the server, so the TUI (which reaches the hub only through the SDK) and the desktop app share one implementation and installs land on the host that runs the agent. The dependency direction stays Schema → Protocol → Server; the server takes the wire types through the protocol group's re-export rather than a direct schema dependency, matching the other handlers. | Keep the import + `.add` line, the handler merge, the dependency, and the schema export; take upstream's surrounding changes. |
| Generated clients: `packages/client/src/contract.ts`, `packages/client/test/promise.test.ts`, `packages/client/src/generated/{client,types}.ts`, `packages/client/src/generated-effect/client.ts`, `packages/sdk/js/src/v2/gen/{sdk,types}.gen.ts` | `contract.ts` maps `"server.skillhub": "skillhub"` and names its endpoints `listStacks`/`prepareStack`/`installStack`/`discardStack`; `promise.test.ts` expects `"skillhub"` last in the group list; the generated trees carry the group. | The fork-only protocol group must reach both SDKs; the endpoint names are overridden because the codegen's default (last id segment) would give `list`/`prepare`/`install`, which collide once single-skill routes join the group. | Keep our `contract.ts` entries and the test expectation; never hand-merge the generated trees — run `bun run generate` in `packages/client` and `./packages/sdk/js/script/build.ts` after resolving the protocol. |
| `packages/opencode/test/server/httpapi-exercise/index.ts` | Imports and calls `installFakeSkillHub()` from the fork-only `skillhub-fake.ts` before the scenario list, and adds four `v2.skillhub.stack.*` scenarios after `v2.skill.list`. | CI runs the exerciser with `--fail-on-missing --fail-on-skip`, so every fork route needs a real passing scenario, and none may reach the live hub: the fake swaps in `@codev/skillhub`'s injectable transport (the same seam the desktop uses for Chromium's `net.fetch`), so the handler downloads, parses, plans, and stages a fixture stack exactly as it would against the hub. | Keep the import/call and the four scenarios; take upstream's surrounding scenario changes. |
| `sdks/vscode/package.json`, `sdks/vscode/src/extension.ts`, `sdks/vscode/README.md` | `name` `opencode` → `codev-code` (the extension ID is `publisher.name`); `displayName` "opencode" → "CoDev Code"; `publisher` `sst-dev` → `CoDev` (PLACEHOLDER — no such Marketplace publisher is registered; the mixed-case `CoDev` also isn't a valid Marketplace publisher id, which must be lowercase — fine for the sideloaded `.vsix` the fork ships, but replace with the real fork-owned lowercase publisher id before any `vsce publish`, and keep it in sync with the CLI auto-install target); `description` "opencode for VS Code" → "CoDev Code for VS Code"; `icon` `images/icon.png` is a fork-local generated PNG of the CoDev "c" badge (brand red `#ee0033` — the "dev" half of the wordmark, see `packages/tui/src/logo.ts` — on `#0a0a0a`), with `images/icon.svg` as its source of record — replacing the earlier symlink to the shared `packages/identity` bracket mark; the two per-theme command `icon` objects (`{light,dark}` → `images/button-{dark,light}.svg`) collapse to a single `"images/button.svg"` string and `extension.ts`'s terminal `iconPath` object collapses to a single `Uri`, both pointing at a fork-local transparent brand-red `#ee0033` "c" glyph that reads on light+dark themes (replacing the two `packages/identity` bracket-mark symlinks, now deleted); `repository.url` → `github.com/quickbeard/codev-code`; command IDs `opencode.*` → `codev.*` across `contributes.commands`/`menus`/`keybindings` and the `registerCommand` calls; command/keybinding titles "Open opencode…"/"Run opencode"/"opencode: Insert At-Mentioned" → "Open CoDev Code…"/"Run CoDev Code"/"CoDev Code: Insert At-Mentioned" (keys unchanged); `TERMINAL_NAME` `opencode` → `codev` and the terminal launches `codev --port <port>`; scripts gain `"vsix"` (`vsce package --no-dependencies --skip-license -o dist/`) with `@vscode/vsce` added as a pinned devDependency; README body rebranded and trimmed to the details-panel essentials — CoDev Code intro linking the fork repo, `npm install -g codev-code` prerequisite, and feature prose only; upstream's Support and Development/Making-Changes sections are dropped (they're contributor-facing, not end-user extension description) | The fork ships this extension as an installable `.vsix`, so every user-visible surface — palette titles, command IDs, terminal name, launched binary, details-panel README — must say codev, and the launched binary must be the fork's `codev` CLI. Distinct `codev.*` IDs also avoid clashing with upstream's extension if both are installed. `--no-dependencies` because the bundle is self-contained (no runtime deps, bun-managed lockfile); `--skip-license` because `sdks/vscode` has no LICENSE file and vsce aborts without it. | Keep our name + displayName + publisher + repository + description, command IDs + titles, `TERMINAL_NAME`, the `codev --port` launch line, the `vsix` script + `@vscode/vsce` devDependency, and the trimmed README (branding + dropped Support/Development sections); take upstream's extension-logic and manifest-structure changes. |
| `packages/opencode/src/ide/index.ts` | IDE auto-install target `sst-dev.opencode` → `CoDev.codev-code` (`publisher.name` from `sdks/vscode/package.json`) | The CLI must install the fork's extension ID (`publisher.name` from `sdks/vscode/package.json`), not upstream's Marketplace listing. `Ide.install` currently has no runtime caller (only its test imports the module), and the install only resolves once the extension is actually published — until then the local `.vsix` is the supported install path. | Keep our extension ID (and re-sync it if the registered publisher id changes); take upstream's install/detection logic changes. |
| Env-var rename, repo-wide (~230 files): both flag registries (`packages/core/src/flag/flag.ts`, `packages/opencode/src/effect/runtime-flags.ts`), every `process.env`/`Bun.env` read+set site across `packages/*`, `sdks/vscode`, `infra/enterprise.ts`, `nix/opencode.nix`, `turbo.json`, `.github/workflows/test.yml`, test preloads/fixtures/snapshots, docs (en + es), `SECURITY.md`, specs | `OPENCODE_*` env vars → `CODEV_*` (hard cutover, no legacy fallback), including the bundler define identifiers (`CODEV_VERSION`, `CODEV_CHANNEL`, `CODEV_MODELS_DEV`, `CODEV_LIBC`, `CODEV_CLI_NAME`, `CODEV_WORKER_PATH`), `VITE_OPENCODE_*` → `VITE_CODEV_*`, `import.meta.env.OPENCODE_CHANNEL` → `CODEV_CHANNEL`, the VSCode extension's `OPENCODE_CALLER`/`_EXTENSION_OPENCODE_PORT`, and the bare `OPENCODE=1` marker → `CODEV=1` | The fork's env surface uses the fork's name (reverses the earlier "internal names stay upstream" decision for env vars). NOT renamed: `__OPENCODE_PHOTON_WASM_PATH` and `__OPENCODE__` globals (not env vars; the photon name is baked into `patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch`), `patches/install-korean-ime-fix.sh` script-local shell vars, upstream secret names in workflow-deletion notes, lowercase identifiers (`@opencode-ai/*`, URLs, provider id) | Keep our names; rename any new upstream `OPENCODE_*` env var (or define/`VITE_` name) to `CODEV_*` when syncing. |
Expand Down
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/client/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ export const groupNames = {
"server.question": "questions",
"server.reference": "references",
"server.projectCopy": "projectCopies",
"server.skillhub": "skillhub",
} as const

export const endpointNames = {
"skillhub.stack.list": "listStacks",
"skillhub.stack.prepare": "prepareStack",
"skillhub.stack.install": "installStack",
"skillhub.stack.discard": "discardStack",
"session.messages": "list",
"integration.connect.key": "connectKey",
"integration.connect.oauth": "connectOauth",
Expand Down
57 changes: 57 additions & 0 deletions packages/client/src/generated-effect/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,62 @@ const adaptGroup17 = (raw: RawClient["server.projectCopy"]) => ({
refresh: Endpoint17_2(raw),
})

type Endpoint18_0Request = Parameters<RawClient["server.skillhub"]["skillhub.stack.list"]>[0]
type Endpoint18_0Input = {
readonly location?: Endpoint18_0Request["query"]["location"]
readonly search?: Endpoint18_0Request["query"]["search"]
readonly page?: Endpoint18_0Request["query"]["page"]
readonly limit?: Endpoint18_0Request["query"]["limit"]
}
const Endpoint18_0 = (raw: RawClient["server.skillhub"]) => (input?: Endpoint18_0Input) =>
raw["skillhub.stack.list"]({
query: { location: input?.["location"], search: input?.["search"], page: input?.["page"], limit: input?.["limit"] },
}).pipe(Effect.mapError(mapClientError))

type Endpoint18_1Request = Parameters<RawClient["server.skillhub"]["skillhub.stack.prepare"]>[0]
type Endpoint18_1Input = {
readonly slug: Endpoint18_1Request["params"]["slug"]
readonly location?: Endpoint18_1Request["query"]["location"]
readonly scope: Endpoint18_1Request["payload"]["scope"]
readonly agents: Endpoint18_1Request["payload"]["agents"]
}
const Endpoint18_1 = (raw: RawClient["server.skillhub"]) => (input: Endpoint18_1Input) =>
raw["skillhub.stack.prepare"]({
params: { slug: input["slug"] },
query: { location: input["location"] },
payload: { scope: input["scope"], agents: input["agents"] },
}).pipe(Effect.mapError(mapClientError))

type Endpoint18_2Request = Parameters<RawClient["server.skillhub"]["skillhub.stack.install"]>[0]
type Endpoint18_2Input = {
readonly location?: Endpoint18_2Request["query"]["location"]
readonly stagingID: Endpoint18_2Request["payload"]["stagingID"]
readonly mode: Endpoint18_2Request["payload"]["mode"]
}
const Endpoint18_2 = (raw: RawClient["server.skillhub"]) => (input: Endpoint18_2Input) =>
raw["skillhub.stack.install"]({
query: { location: input["location"] },
payload: { stagingID: input["stagingID"], mode: input["mode"] },
}).pipe(Effect.mapError(mapClientError))

type Endpoint18_3Request = Parameters<RawClient["server.skillhub"]["skillhub.stack.discard"]>[0]
type Endpoint18_3Input = {
readonly stagingID: Endpoint18_3Request["params"]["stagingID"]
readonly location?: Endpoint18_3Request["query"]["location"]
}
const Endpoint18_3 = (raw: RawClient["server.skillhub"]) => (input: Endpoint18_3Input) =>
raw["skillhub.stack.discard"]({
params: { stagingID: input["stagingID"] },
query: { location: input["location"] },
}).pipe(Effect.mapError(mapClientError))

const adaptGroup18 = (raw: RawClient["server.skillhub"]) => ({
listStacks: Endpoint18_0(raw),
prepareStack: Endpoint18_1(raw),
installStack: Endpoint18_2(raw),
discardStack: Endpoint18_3(raw),
})

const adaptClient = (raw: RawClient) => ({
health: adaptGroup0(raw["server.health"]),
location: adaptGroup1(raw["server.location"]),
Expand All @@ -700,6 +756,7 @@ const adaptClient = (raw: RawClient) => ({
questions: adaptGroup15(raw["server.question"]),
references: adaptGroup16(raw["server.reference"]),
projectCopies: adaptGroup17(raw["server.projectCopy"]),
skillhub: adaptGroup18(raw["server.skillhub"]),
})

export const make = (options?: { readonly baseUrl?: URL | string }) =>
Expand Down
65 changes: 65 additions & 0 deletions packages/client/src/generated/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ import type {
ProjectCopiesRemoveOutput,
ProjectCopiesRefreshInput,
ProjectCopiesRefreshOutput,
SkillhubListStacksInput,
SkillhubListStacksOutput,
SkillhubPrepareStackInput,
SkillhubPrepareStackOutput,
SkillhubInstallStackInput,
SkillhubInstallStackOutput,
SkillhubDiscardStackInput,
SkillhubDiscardStackOutput,
} from "./types"
import { ClientError } from "./client-error"

Expand Down Expand Up @@ -987,6 +995,63 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
skillhub: {
listStacks: (input?: SkillhubListStacksInput, requestOptions?: RequestOptions) =>
request<SkillhubListStacksOutput>(
{
method: "GET",
path: `/api/skillhub/stack`,
query: {
location: input?.["location"],
search: input?.["search"],
page: input?.["page"],
limit: input?.["limit"],
},
successStatus: 200,
declaredStatuses: [400, 401],
empty: false,
},
requestOptions,
),
prepareStack: (input: SkillhubPrepareStackInput, requestOptions?: RequestOptions) =>
request<SkillhubPrepareStackOutput>(
{
method: "POST",
path: `/api/skillhub/stack/${encodeURIComponent(input.slug)}/prepare`,
query: { location: input["location"] },
body: { scope: input["scope"], agents: input["agents"] },
successStatus: 200,
declaredStatuses: [400, 401],
empty: false,
},
requestOptions,
),
installStack: (input: SkillhubInstallStackInput, requestOptions?: RequestOptions) =>
request<SkillhubInstallStackOutput>(
{
method: "POST",
path: `/api/skillhub/stack/install`,
query: { location: input["location"] },
body: { stagingID: input["stagingID"], mode: input["mode"] },
successStatus: 200,
declaredStatuses: [400, 401],
empty: false,
},
requestOptions,
),
discardStack: (input: SkillhubDiscardStackInput, requestOptions?: RequestOptions) =>
request<SkillhubDiscardStackOutput>(
{
method: "DELETE",
path: `/api/skillhub/stack/staging/${encodeURIComponent(input.stagingID)}`,
query: { location: input["location"] },
successStatus: 204,
declaredStatuses: [400, 401],
empty: true,
},
requestOptions,
),
},
}
}

Expand Down
Loading
Loading