dsh-opencode 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,108 +1,59 @@
1
- # dsh-opencode — OpenCode Zen / Go live catalog plugin
1
+ # dsh-opencode
2
2
 
3
- An out-of-tree DSH bundle that serves the OpenCode **Zen** and **Go** products as two independent live LLM routes with a **dynamic model catalog**: models the official lists publish become selectable and executable without a plugin update, rebuild, or DSH restart, as long as they use a known wire protocol and publish the metadata the route needs.
3
+ OpenCode Zen / Go を動的カタログ付きのライブ LLM ルートとして DSH に追加するプラグイン。
4
4
 
5
- - `opencode-zen-live` — **OpenCode Zen (Live)**
6
- - `opencode-go-live` — **OpenCode Go (Live)**
5
+ - `opencode-zen-live` — OpenCode Zen (Live)
6
+ - `opencode-go-live` — OpenCode Go (Live)
7
7
 
8
- The plugin reuses DSH's public `PiAiAdapter` and pi-ai's public `createProvider()` for all message conversion, streaming, tool calls, images, replay state, usage, cancellation, and idle-timeout behavior. It does **not** port OAuth, does not modify the existing `llm-pi-ai` configuration, does not fail over between Zen and Go automatically, and never sends an inference request as part of a catalog refresh.
9
-
10
- ## Compatibility
11
-
12
- - DSH packages: `0.1.2-rc.1` (published release; peer range `^0.1.2-rc.1`)
13
- - pi-ai: pinned to the installed DSH adapter's range (`>=0.84.2 <0.86`, verified on `0.84.2`)
14
- - Cordis: `4.0.2`
15
- - Node: `^22.19.0 || >=24.0.0`
16
-
17
- ## Installation
8
+ ## インストール
18
9
 
19
10
  ```sh
20
11
  pnpm dsh plugin --profile web add github:askdkc/dsh-opencode
21
- pnpm dsh --profile web --dump-config
22
12
  ```
23
13
 
24
- The dump should contain the `opencode-live` row with both provider routes. A restart applies the bundle once; after that, catalog updates need no restart.
25
-
26
- To remove it:
14
+ 削除:
27
15
 
28
16
  ```sh
29
17
  pnpm dsh plugin --profile web remove dsh-opencode
30
18
  ```
31
19
 
32
- ## API key
33
-
34
- Both routes resolve the credential reference `apiKeyEnv` per request through the DSH credentials service (or the launch environment when no credential service is mounted). The default reference is `OPENCODE_API_KEY` for both products; set a different one per route in settings, e.g. `DSH_OPENCODE_ZEN_API_KEY` / `DSH_OPENCODE_GO_API_KEY`, and store the value through the standard credentials UI (the web Models page) or export it in the launch environment.
35
-
36
- - A missing or unusable key fails the request with `MISSING_CREDENTIAL`; the plugin never falls back to an unrelated ambient key (`OPENAI_API_KEY`, `GEMINI_API_KEY`, …).
37
- - Catalog fetches are unauthenticated and share no client with inference; keys never appear in URLs, logs, diagnostics, command output, or the cache.
38
- - Go requests carry an honest `x-opencode-client: opencode-live/<version>` header and an opaque, stable `x-opencode-session` value per DSH session; the plugin never impersonates OpenCode itself.
39
-
40
- ## How the catalog works
41
-
42
- Three public sources feed the catalog: the official Zen list, the official Go list, and the Models.dev `api.json` metadata for the `opencode` / `opencode-go` providers. The plugin joins them by exact model id and keeps every candidate visible:
43
-
44
- | State | Meaning | Selector | Diagnostics |
45
- |---|---|---|---|
46
- | `ready` | officially listed with complete metadata and a known wire API | shown | — |
47
- | `metadata-pending` | officially listed; missing name/context/output/input/api | hidden | shown with the missing fields |
48
- | `unsupported-protocol` | metadata names an unknown SDK | hidden | shown with the SDK id |
49
- | `catalog-only` | in Models.dev but absent from the official list | hidden | shown |
50
- | `removed` | was officially listed before; no longer present | hidden (history keeps the name) | shown |
20
+ ## 使い方
51
21
 
52
- Wire APIs are chosen from the model-level `provider.npm` (falling back to the provider default) through a fixed allowlist: `@ai-sdk/openai-compatible` → Chat Completions, `@ai-sdk/openai` → Responses, `@ai-sdk/anthropic` → Anthropic Messages, `@ai-sdk/google` → Google Generative AI. Unknown SDK identifiers are never executed and nothing fetched is ever imported or installed. Reasoning-effort controls are offered only where the source publishes a verified effort list; toggle-only models keep the provider's default behavior.
22
+ 1. DSH を再起動すると両ルートが登録される(以降のカタログ更新に再起動は不要)
23
+ 2. Web の 設定 > モデル > OpenCode Zen (Live) の「編集」を開き、マスク済み API キー入力欄にキーを貼り付けて保存
24
+ 3. モデルセレクターから OpenCode のモデルを選んで使う
53
25
 
54
- Refreshes run single-flight per source (Models.dev once for both products) with conditional GET/304 handling, timeout and decoded-body caps, empty-list protection, and per-source failure isolation. An executable-set change re-registers the same routes in place, which publishes `llm/adapters-updated` so an open selection UI re-fetches. Snapshots are immutable and generation-bound; a prepared call cannot switch providers mid-request.
55
-
56
- ## Commands
57
-
58
- | Command | Effect |
26
+ | コマンド | 効果 |
59
27
  |---|---|
60
- | `/dsh-opencode` | After the key is stored securely, refreshes both catalogs and enables Zen/Go immediately; never accepts key values |
61
- | `/opencode-refresh [all\|zen\|go]` | Force a catalog refresh (joins in-flight fetches) |
62
- | `/opencode-status` | Freshness, per-source errors, ready/pending counts, credential presence |
63
- | `/opencode-models <zen\|go> [--all]` | Ready models, or every candidate with its state and reason |
28
+ | `/dsh-opencode` | ステータス表示とキー設定場所の案内 |
29
+ | `/opencode-refresh [all\|zen\|go]` | カタログを強制更新 |
30
+ | `/opencode-status` | 更新時刻・エラー・モデル数・キー設定状況 |
31
+ | `/opencode-models <zen\|go> [--all]` | モデル一覧(`--all` で非対応含む) |
64
32
 
65
- None of these commands displays key values or fragments, and none registers a model-visible tool.
33
+ ## 設定
66
34
 
67
- ## Configuration
68
-
69
- Namespace `opencode-live` (composition defaults in `cordis.patch.yml`):
35
+ 名前空間 `opencode-live`(デフォルトは `cordis.patch.yml` 参照):
70
36
 
71
37
  ```yaml
72
38
  providers:
73
39
  opencode-zen-live:
74
- product: zen # must match the route key
75
- apiKeyEnv: OPENCODE_API_KEY
40
+ product: zen
41
+ apiKeyEnv: OPENCODE_API_KEY # 両ルート既定は同一参照
76
42
  opencode-go-live:
77
43
  product: go
78
44
  apiKeyEnv: OPENCODE_API_KEY
79
45
  catalog:
80
- refreshIntervalMs: 900000 # periodic refresh (with jitter)
81
- listRevalidateAfterMs: 60000 # re-check TTL on display/selection
82
- timeoutMs: 15000 # per-request HTTP timeout
83
- maxStaleMs: 604800000 # 7 days; staleness display bound
84
- requireFresh: false # true refuses requests while the official list is stale
46
+ refreshIntervalMs: 900000
47
+ timeoutMs: 15000
48
+ requireFresh: false
85
49
  ```
86
50
 
87
- `cachePath` (optional) relocates the validated-source cache; it defaults to `cache/opencode-live/catalog.json` under the DSH home. The cache stores source payloads and freshness facts only — never normalized output, never secrets.
51
+ - API キーは設定 UI から保存(コマンド引数では受け付けない)。環境変数 `OPENCODE_API_KEY` でも可
52
+ - `cachePath` でキャッシュ位置を変更可能(既定は DSH ホーム下 `cache/opencode-live/catalog.json`)
88
53
 
89
- `limit.output` sizes the model's capability; it is never materialized as a per-request token default. `configuredMaxTokens` stays empty by design: only explicit per-model configuration belongs there, and this plugin defines none.
90
-
91
- ## Development
54
+ ## 開発
92
55
 
93
56
  ```sh
94
57
  pnpm install
95
- pnpm typecheck # tsc --noEmit
96
- pnpm test # vitest run (offline only; live tests skip)
97
- pnpm test:live # opt-in: hits the public GET endpoints, no key, no inference
98
- pnpm build # tsdown -> lib/
99
- pnpm pack:check # npm pack --dry-run
58
+ pnpm typecheck && pnpm test && pnpm build
100
59
  ```
101
-
102
- Tests mount a real Cordis context with the published DSH packages, stub the three catalog URLs, and cover the candidate states, refresh failure classes, wire-API selection, session headers, credential semantics, registry replacement, unload safety, and packaging.
103
-
104
- ## Scope notes
105
-
106
- - Catalog refreshes never generate inference traffic, and a Go auth/limit error never switches the request to Zen.
107
- - Model `limit.context` / `limit.output` come only from a validated source; unknown capacities never become fabricated numbers. Source pricing maps into pi-ai's descriptor; absent pricing is the absence of a fact, not a $0 claim.
108
- - The repository commits the built `lib/` so installation needs no runtime TypeScript compilation.
package/lib/commands.js CHANGED
@@ -2,7 +2,7 @@ import { PRODUCT_BY_ROUTE, ROUTE_BY_PRODUCT, describeNonReadyState } from "./nor
2
2
  //#region src/commands.ts
3
3
  const USAGE_REFRESH = "Usage: /opencode-refresh [all|zen|go]";
4
4
  const USAGE_MODELS = "Usage: /opencode-models <zen|go> [--all]";
5
- const USAGE_ENABLE = "Usage: /dsh-opencode — never pass the API key in the command line";
5
+ const USAGE_ENABLE = "Usage: /dsh-opencode — report status; store the API key through the web Models page";
6
6
  /** Whether one date stamp renders as a short local time. */
7
7
  function renderTime(timestamp) {
8
8
  if (timestamp === void 0) return "never";
@@ -130,12 +130,12 @@ function commandDefinitions(ctx, services) {
130
130
  },
131
131
  {
132
132
  name: "dsh-opencode",
133
- description: "Enable OpenCode Zen/Go immediately after the API key is stored securely",
133
+ description: "Show OpenCode status and where to store the API key",
134
134
  recordInput: false,
135
135
  handler: async (invocation) => {
136
136
  if (invocation.rawInput.trim().length > 0) return {
137
137
  kind: "error",
138
- text: USAGE_ENABLE
138
+ text: [USAGE_ENABLE, "This command never accepts the key as text; paste it into the masked API key input on the web Models page instead."].join("\n")
139
139
  };
140
140
  const routes = [ROUTE_BY_PRODUCT.zen, ROUTE_BY_PRODUCT.go];
141
141
  if (!(await Promise.all(routes.map(async (route) => {
@@ -144,9 +144,8 @@ function commandDefinitions(ctx, services) {
144
144
  kind: "success",
145
145
  text: [
146
146
  "No OpenCode API key is configured yet.",
147
- "Store it securely through the standard credentials input (the web Models page writes it),",
148
- "then run /dsh-opencode again to refresh both catalogs and enable the routes immediately.",
149
- "This command never accepts, records, or displays key values."
147
+ "Open Settings > Models, edit the OpenCode Zen (Live) provider, and paste the key into its masked API key input.",
148
+ "This command never displays key values."
150
149
  ].join("\n")
151
150
  };
152
151
  if (invocation.signal.aborted) return {
package/lib/transport.js CHANGED
@@ -27,7 +27,7 @@ import { openAIResponsesApi } from "@earendil-works/pi-ai/api/openai-responses.l
27
27
  */
28
28
  /** The plugin's honest client identification value. */
29
29
  const PLUGIN_ID = "opencode-live";
30
- const PLUGIN_VERSION = "0.1.0";
30
+ const PLUGIN_VERSION = "0.1.1";
31
31
  /** Header OpenCode Go documents for coding-agent session identification. */
32
32
  const SESSION_HEADER = "x-opencode-session";
33
33
  /** Header carrying this plugin's honest client identity alongside DSH attribution. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-opencode",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Out-of-tree DSH bundle with live dynamic OpenCode Zen / Go model catalogs",
5
5
  "private": false,
6
6
  "license": "MIT",