dsh-packycode-api 1.1.4 → 1.1.5

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.5
4
+
5
+ - Added `grok-4.7`, displayed as **Grok 4.7**, to the PackyCode `openai-responses` route at `https://cf.api.fan/v1`. [The official Grok 4.7 guide](https://docs.x.ai/developers/grok-4-7) declares a 500,000-token context, text/image input, text output, and `low` / `medium` / `high` / `xhigh` reasoning (default `high`, no off or max). There is no separate documented text-output cap; the numeric pi-ai ceiling is 500,000, bounded by remaining context per request. Only GPT Responses requests keep `prompt_cache_key`: the gateway's Grok route rejects this field with a misleading `Incorrect API key provided` error. Non-GPT Responses requests use pi-ai's `cacheRetention: 'none'` to omit it; the model, protocol, effort and plugin-owned credential stay the same.
6
+ - Settings now has a model checkbox list with Select all / Select none. All models, including newly added catalog entries, are visible by default. The profile stores exclusions, and DSH's picker refreshes when they change. Hiding a model does not prevent an existing session or prepared turn from using it.
7
+ - Fixed saving Auto web search on DSH 0.2 (including the reported macOS Intel installation): require `@deepseek-ai/schemastery` 3.18.4+, which declares volatile preference fields. The previous 3.18.2 dependency silently left them non-volatile, so DSH 0.2 refused the write. All RPC failures now carry Connection's required `code`, `message`, and empty `details`, preserving a safe error instead of `connection: invalid server-response failure`.
8
+ - The live checker now reads only the plugin-owned `packycode-api/keys` credential record, selecting the active usable key or `--key-label LABEL`; legacy references and environment credentials never substitute for it. Invalid YAML produces a safe error without quoting secret-bearing source lines, and checks never modify the stored record.
9
+ - Validation: 276 offline tests, both regenerated bundles and the versioned tarball; built settings UI checkbox/all/none/save-failure checks; the bundled DSH 0.2 Connection parser accepts the fixed failure. Built live gateway checks answered through DeepSeek Flash, GPT-6.1 Sol, GPT-6 Astra and Grok 4.7 and passed key rotation and secret-free projections. All four Grok efforts returned `ok` with a plugin-stored Grok-group key; xhigh first encountered a transient upstream 400 and succeeded on an identical retry. The user confirmed the local desktop build passed testing. The physical Intel desktop UI has not been retested.
10
+
3
11
  ## 1.1.4
4
12
 
5
13
  - **Carry the reviewed plan into the next CLI turn.** The plan previously existed only in `exit_plan_mode` arguments, which the delegated transcript dropped; a fresh CLI then saw only “Plan approved”. The latest complete plan and its matching review result are now recovered from durable native or adapter-generated PTC tool calls, so approval, revision, resume and fork keep their constraints. They are reserved before trimming older chat; an oversized plan/request fails explicitly rather than silently losing constraints. Unrelated tool arguments and arbitrary PTC programs are not forwarded.
package/README.en.md CHANGED
@@ -25,6 +25,7 @@ The `PackyCode` model group ships with the plugin. No YAML edits and no separate
25
25
  | Capability | What it does |
26
26
  | --- | --- |
27
27
  | **Built-in model route** | Adds a `PackyCode` group to the model picker. No provider configuration and no `cordis.patch.yml` edits |
28
+ | **Choose visible models** | All models are selected by default in Settings. Unchecking a model immediately hides it from the picker; existing sessions can keep using it |
28
29
  | **Keys used in order** | An exhausted or rejected key is disabled and the next usable key takes over; the failed step is retried on that key |
29
30
  | **Keys chosen by group** | Each key lists its PackyCode groups and the models they reach; when the active key's groups cannot reach the selected model (no `cc` group for Claude, say), that turn runs on a stored key whose groups can |
30
31
  | **Visible balance** | Settings lists each key's remaining, used, limit, reset period, and a usage bar, plus a total of those keys. The composer shows the active key's remaining balance |
@@ -44,7 +45,7 @@ Open the desktop application's **Plugins** page, click **Add plugin**, and enter
44
45
  dsh-packycode-api
45
46
  ```
46
47
 
47
- Choose the **official** install source, then click **Install**. To pin a version, enter `dsh-packycode-api@1.1.4`.
48
+ Choose the **official** install source, then click **Install**. To pin a version, enter `dsh-packycode-api@1.1.5`.
48
49
 
49
50
  Then **manually restart the desktop application**. Refreshing the page does not reload the plugin inside the Host process.
50
51
 
@@ -56,14 +57,14 @@ Open **Settings → PackyCode**. Paste the API key under **Add a key**. A label
56
57
 
57
58
  ### 3. Select a model
58
59
 
59
- Choose a model from the `PackyCode` group. `deepseek-flash`, `gpt-6.1-sol`, and `gpt-6-astra` work once a key is stored. The three Claude models also need the Claude Code CLI on this device; see below.
60
+ Choose a model from the `PackyCode` group. `deepseek-flash`, `gpt-6.1-sol`, `gpt-6-astra`, and `grok-4.7` use HTTP. The three Claude models also need the Claude Code CLI on this device; see below. Your key's groups must cover the selected model.
60
61
 
61
62
  <details>
62
63
  <summary>Verify the install / other profiles / a local checkout</summary>
63
64
 
64
65
  The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
65
66
 
66
- **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.4`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
67
+ **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.5`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
67
68
 
68
69
  A local checkout can be linked with `dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`.
69
70
 
@@ -73,6 +74,8 @@ A profile without a browser can still use the model route. It just has no settin
73
74
 
74
75
  ## Daily use
75
76
 
77
+ **Choose visible models.** Under **Settings → PackyCode → Visible models**, check the models you want in the picker. All are selected by default, with Select all / Select none controls. The selection is saved in the current profile and applies immediately; unchecking a model does not interrupt an existing session. New catalog models are selected by default.
78
+
76
79
  **Switch keys.** Keys are used in the order they were added. **Use this key** picks the preferred key, effective from the next turn; **Rename** changes its label (at most 60 characters, empty names are refused); **Re-enable** puts a disabled key back after a top-up or replacement.
77
80
 
78
81
  **See groups.** Under **Accounts and keys**, each key lists its PackyCode groups (hover for the group's description) and which models they reach: ✓ yes, ◐ partly, ✕ no. The groups come from the gateway itself (its refusal of a model id it cannot route names the token's groups; nothing is billed), matched against PackyCode's public model-group table. Claude needs one of `cc` / `cc-sale` / `cc-expensive` / `claude-officially` (`claude-haiku-5-5` only `cc` and `claude-officially`); GPT needs `codex` / `codex-sale`; DeepSeek needs `deepseek-officially` / `deepseek-sale`.
@@ -138,12 +141,17 @@ Claude Code CLI → temporary local MCP web_search → selected PackyCode DeepSe
138
141
  | `deepseek-flash` | HTTP, chat/completions | Can be off; `low` / `high` / `max` | `deepseek-officially`, `deepseek-sale` |
139
142
  | `gpt-6.1-sol` | HTTP, Responses, images allowed | Cannot be off; `low` / `medium` / `high` / `xhigh` / `max` | `codex`, `codex-sale` |
140
143
  | `gpt-6-astra` | Same | Same | Same |
144
+ | `grok-4.7` (Grok 4.7) | HTTP, Responses, text/image input; 500K context | Cannot be off; `low` / `medium` / `high` / `xhigh` | The Grok coverage read from the gateway in Settings |
141
145
  | `claude-opus-5-5` | Local Claude Code CLI | The picker offers the same levels; the CLI chooses the actual effort | A group the official CLI is allowed to use; see below |
142
146
  | `claude-sonnet-5-5` | Same | Same | Same |
143
147
  | `claude-haiku-5-5` | Same; session titles always use this model | Same | Same |
144
148
 
145
149
  A model in the list does not mean the current token group allows it. When changing groups, do not drop the group that serves the model you still want.
146
150
 
151
+ Grok 4.7's context and reasoning levels follow the [official guide](https://docs.x.ai/developers/grok-4-7). There is no separate text-output limit; the plugin uses the context size as its numeric output ceiling, bounded by the remaining context per request.
152
+
153
+ Only GPT Responses requests keep `prompt_cache_key`; other Responses models omit it by default. This gateway's Grok route reports a misleading `Incorrect API key provided` error when the field is present.
154
+
147
155
  <details>
148
156
  <summary>Protocol, group, and CLI constraints</summary>
149
157
 
package/README.md CHANGED
@@ -25,6 +25,7 @@
25
25
  | 能力 | 使用体验 |
26
26
  | --- | --- |
27
27
  | **自带模型路由** | 安装后模型选择器出现 `PackyCode` 分组,不需要配置 provider,也不用改 `cordis.patch.yml` |
28
+ | **自选显示的模型** | 设置页的模型列表默认全选;取消勾选后,切换列表立即隐藏该模型,已有会话仍可继续使用 |
28
29
  | **多 Key 按顺序使用** | 额度用尽或 Key 被拒绝时自动切到下一个可用 Key;失败的那一步由重试接手 |
29
30
  | **按分组选 Key** | 每个 Key 后面列出它所在的 PackyCode 分组和能用的模型;当前 Key 的分组用不了所选模型(例如没有 cc 分组却选了 Claude)时,这一轮自动改用分组合适的 Key |
30
31
  | **余额一眼可见** | 设置页列出每个 Key 的剩余、已用、额度、重置周期和用量条,并给出这些 Key 的合计;输入框右侧显示当前 Key 的剩余额度 |
@@ -48,7 +49,7 @@
48
49
  dsh-packycode-api
49
50
  ```
50
51
 
51
- 在**安装源**中选择**官方源**,然后点击**安装**。需要固定版本时填入 `dsh-packycode-api@1.1.4`。
52
+ 在**安装源**中选择**官方源**,然后点击**安装**。需要固定版本时填入 `dsh-packycode-api@1.1.5`。
52
53
 
53
54
  完成后**手动重启桌面应用**。仅刷新页面不会重新加载 Host 里的插件。
54
55
 
@@ -60,14 +61,14 @@ dsh-packycode-api
60
61
 
61
62
  ### 3. 选择模型
62
63
 
63
- 回到对话,在模型选择器里选 `PackyCode` 分组下的模型。`deepseek-flash`、`gpt-6.1-sol` 和 `gpt-6-astra` 添加 Key 后即可用。三个 Claude 模型还需要本机装有 Claude Code CLI,见下文。
64
+ 回到对话,在模型选择器里选 `PackyCode` 分组下的模型。`deepseek-flash`、`gpt-6.1-sol`、`gpt-6-astra` 和 `grok-4.7` 通过 HTTP 调用;三个 Claude 模型还需要本机装有 Claude Code CLI,见下文。Key 的分组必须覆盖所选模型。
64
65
 
65
66
  <details>
66
67
  <summary>检查安装 / 其它 profile / 本地目录</summary>
67
68
 
68
69
  桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
69
70
 
70
- **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.4`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
71
+ **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.5`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
71
72
 
72
73
  本地开发可以用绝对路径:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。
73
74
 
@@ -77,6 +78,8 @@ dsh-packycode-api
77
78
 
78
79
  ## 日常使用
79
80
 
81
+ **选择显示的模型。** 在 **设置 → PackyCode → 显示的模型** 中勾选要在切换列表里看到的模型,默认全选,也支持「全选」和「全不选」。选择保存在当前 profile,修改后立即生效;取消勾选不会中断已有会话。后续新增的模型默认勾选。
82
+
80
83
  **换 Key。** Key 按添加顺序使用。点「切到此 Key」指定优先使用的 Key,下一轮就生效;「重命名」改备注(最多 60 字,不能为空);充值或更换后点「重新启用」。
81
84
 
82
85
  **看分组。** 「账户与 Key」里每个 Key 下面列出它所在的 PackyCode 分组(鼠标悬停可看分组说明),以及能用哪些模型:✓ 可用、◐ 部分可用、✕ 不可用。分组由网关自己报出(对一个不存在的模型 id 的拒绝里会写明「已选分组」,不产生费用),再对照 PackyCode 公开的模型分组表。Claude 需要 `cc` / `cc-sale` / `cc-expensive` / `claude-officially` 之一(`claude-haiku-5-5` 只在 `cc` 和 `claude-officially`);GPT 需要 `codex` / `codex-sale`;DeepSeek 需要 `deepseek-officially` / `deepseek-sale`。
@@ -142,12 +145,17 @@ Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT
142
145
  | `deepseek-flash` | HTTP,chat/completions | 可关;`low` / `high` / `max` | `deepseek-officially`、`deepseek-sale` |
143
146
  | `gpt-6.1-sol` | HTTP,Responses,可带图 | 不能关;`low` / `medium` / `high` / `xhigh` / `max` | `codex`、`codex-sale` |
144
147
  | `gpt-6-astra` | 同上 | 同上 | 同上 |
148
+ | `grok-4.7`(Grok 4.7) | HTTP,Responses,可带图;500k 上下文 | 不能关;`low` / `medium` / `high` / `xhigh` | 以设置页从网关读取的 Grok 分组覆盖为准 |
145
149
  | `claude-opus-5-5` | 本机 Claude Code CLI | 选择器档位同上,实际档位由 CLI 决定 | 能给官方 CLI 用的分组,比如cc分组 |
146
150
  | `claude-sonnet-5-5` | 同上 | 同上 | 同上 |
147
151
  | `claude-haiku-5-5` | 同上;会话标题也固定走它 | 同上 | 同上 |
148
152
 
149
153
  列表里看得到模型,不代表当前令牌分组一定放行。换分组时不要把对应分组一起去掉。
150
154
 
155
+ Grok 4.7 的上下文与推理档位来自 [官方文档](https://docs.x.ai/developers/grok-4-7)。官方没有单独限制文字输出长度;插件将输出上限设为上下文大小,并按每次请求的剩余上下文收紧。
156
+
157
+ Responses 请求只有 GPT 模型保留 `prompt_cache_key`,其他 Responses 模型默认省略。当前网关的 Grok 路由会将这个字段误报成 `Incorrect API key provided`。
158
+
151
159
  <details>
152
160
  <summary>协议、分组和 CLI 的具体约束</summary>
153
161
 
package/lib/client.js CHANGED
@@ -84,6 +84,14 @@ window.__ModuleLoader__.load({
84
84
  groupsMiss: "不可用",
85
85
  groupsPartial: "部分",
86
86
  groupsStale: "分组为上次读取的结果",
87
+ modelsTitle: "显示的模型",
88
+ modelsIntro: "切换模型时只显示已勾选的 PackyCode 模型,默认全选。修改后立即生效;已有会话仍可继续使用原模型。",
89
+ modelsChecking: "正在读取模型设置…",
90
+ modelsFailed: "模型设置读取或保存失败",
91
+ modelsAll: "全选",
92
+ modelsNone: "全不选",
93
+ modelsCount: "已选 {count} / {total}",
94
+ modelsEmpty: "未勾选任何模型,切换列表将隐藏 PackyCode 的模型。",
87
95
  advanced: "高级:接口地址",
88
96
  apiHost: "模型接口地址",
89
97
  statusHost: "余额接口地址",
@@ -162,6 +170,14 @@ window.__ModuleLoader__.load({
162
170
  };
163
171
  const en = {
164
172
  nav: "PackyCode",
173
+ modelsTitle: "Visible models",
174
+ modelsIntro: "Only selected PackyCode models appear when switching models. All are selected by default. Changes apply immediately; existing sessions can keep their current model.",
175
+ modelsChecking: "Reading model settings…",
176
+ modelsFailed: "Could not read or save model settings",
177
+ modelsAll: "Select all",
178
+ modelsNone: "Select none",
179
+ modelsCount: "{count} / {total} selected",
180
+ modelsEmpty: "No models selected. PackyCode models are hidden from the picker.",
165
181
  intro: "Paste a PackyCode (PackyAPI) API key to use the built-in model route. Keys are used in order: an exhausted or rejected key hands over to the next one, and a key whose groups cannot reach the selected model is passed over for one whose groups can.",
166
182
  accountsTitle: "Accounts and keys",
167
183
  refresh: "Refresh",
@@ -364,6 +380,13 @@ window.__ModuleLoader__.load({
364
380
  .pkc-reach>span[data-state=no]{color:var(--dsw-alias-label-caption);text-decoration:line-through}
365
381
  .pkc-add{display:flex;flex-direction:column;gap:8px;padding-top:14px;border-top:.5px solid var(--dsw-alias-border-l2)}
366
382
 
383
+ .pkc-models{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0;padding:0;min-width:0;border:0}
384
+ .pkc-model{display:flex;align-items:center;gap:10px;min-width:0;padding:10px 12px;border-radius:var(--dsw-radius-md,12px);background:var(--dsw-alias-interactive-bg-hover);cursor:pointer}
385
+ .pkc-model>input{flex:none;width:16px;height:16px;margin:0;accent-color:var(--dsw-alias-state-business-primary)}
386
+ .pkc-model>span{display:flex;flex-direction:column;min-width:0;gap:2px}
387
+ .pkc-model b{font-size:13px;font-weight:500}
388
+ .pkc-models:disabled .pkc-model{opacity:.5;cursor:not-allowed}
389
+
367
390
  .pkc-setting{display:grid;grid-template-columns:112px minmax(0,1fr);gap:6px 16px;align-items:start}
368
391
  .pkc-setting>.pkc-label{padding-top:5px}
369
392
  .pkc-setting>div{display:flex;flex-direction:column;gap:6px;min-width:0}
@@ -389,6 +412,7 @@ window.__ModuleLoader__.load({
389
412
  @media (max-width:640px){
390
413
  .pkc-stats{grid-template-columns:1fr}
391
414
  .pkc-setting{grid-template-columns:1fr}
415
+ .pkc-models{grid-template-columns:1fr}
392
416
  .pkc-setting>.pkc-label{padding-top:0}
393
417
  }
394
418
  `;
@@ -473,6 +497,7 @@ window.__ModuleLoader__.load({
473
497
  const MODEL_FAMILIES = [
474
498
  ["DeepSeek", ["deepseek-flash"]],
475
499
  ["GPT", ["gpt-6.1-sol", "gpt-6-astra"]],
500
+ ["Grok", ["grok-4.7"]],
476
501
  ["Claude", [
477
502
  "claude-opus-5-5",
478
503
  "claude-sonnet-5-5",
@@ -1006,6 +1031,95 @@ window.__ModuleLoader__.load({
1006
1031
  ]
1007
1032
  });
1008
1033
  }
1034
+ function ModelsCard({ call, t }) {
1035
+ const [state, setState] = react.useState();
1036
+ const [busy, setBusy] = react.useState(false);
1037
+ const [error, setError] = react.useState();
1038
+ react.useEffect(() => {
1039
+ let live = true;
1040
+ call("models/status").then((value) => {
1041
+ if (live) setState(value);
1042
+ }).catch((failure) => {
1043
+ if (live) setError(clearMessage(failure));
1044
+ });
1045
+ return () => {
1046
+ live = false;
1047
+ };
1048
+ }, [call]);
1049
+ const models = state?.models ?? [];
1050
+ const selectedIds = models.filter((model) => model.selected).map((model) => model.id);
1051
+ const disabled = busy || state?.writable !== true;
1052
+ const update = (ids) => {
1053
+ if (disabled) return;
1054
+ setBusy(true);
1055
+ setError(void 0);
1056
+ call("models/update", { selectedIds: ids }).then(setState).catch((failure) => setError(clearMessage(failure))).finally(() => setBusy(false));
1057
+ };
1058
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, {
1059
+ title: t("modelsTitle"),
1060
+ aside: state !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1061
+ className: "pkc-meta",
1062
+ children: fill(t("modelsCount"), {
1063
+ count: selectedIds.length,
1064
+ total: models.length
1065
+ })
1066
+ }),
1067
+ children: [
1068
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1069
+ className: "pkc-note",
1070
+ children: t("modelsIntro")
1071
+ }),
1072
+ state === void 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1073
+ className: "pkc-note",
1074
+ role: "status",
1075
+ children: t("modelsChecking")
1076
+ }),
1077
+ state !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1078
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1079
+ className: "pkc-actions",
1080
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1081
+ disabled: disabled || selectedIds.length === models.length,
1082
+ onClick: () => update(models.map((model) => model.id)),
1083
+ children: t("modelsAll")
1084
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1085
+ disabled: disabled || selectedIds.length === 0,
1086
+ onClick: () => update([]),
1087
+ children: t("modelsNone")
1088
+ })]
1089
+ }),
1090
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("fieldset", {
1091
+ className: "pkc-models",
1092
+ "aria-label": t("modelsTitle"),
1093
+ disabled,
1094
+ children: models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1095
+ className: "pkc-model",
1096
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1097
+ type: "checkbox",
1098
+ checked: model.selected,
1099
+ onChange: (event) => update(event.target.checked ? [...selectedIds, model.id] : selectedIds.filter((id) => id !== model.id))
1100
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: model.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1101
+ className: "pkc-meta pkc-mono",
1102
+ children: model.id
1103
+ })] })]
1104
+ }, model.id))
1105
+ }),
1106
+ selectedIds.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1107
+ className: "pkc-note",
1108
+ children: t("modelsEmpty")
1109
+ }),
1110
+ state.writable !== true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1111
+ className: "pkc-note",
1112
+ children: t("searchNotWritable")
1113
+ })
1114
+ ] }),
1115
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1116
+ className: "pkc-error",
1117
+ role: "alert",
1118
+ children: `${t("modelsFailed")}: ${error}`
1119
+ })
1120
+ ]
1121
+ });
1122
+ }
1009
1123
  /** Web search routing and backend, written through the host. */
1010
1124
  function SearchCard({ call, t }) {
1011
1125
  const [state, setState] = react.useState();
@@ -1469,6 +1583,10 @@ window.__ModuleLoader__.load({
1469
1583
  call,
1470
1584
  t
1471
1585
  }),
1586
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelsCard, {
1587
+ call,
1588
+ t
1589
+ }),
1472
1590
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchCard, {
1473
1591
  call,
1474
1592
  t
package/lib/index.js CHANGED
@@ -544,7 +544,8 @@ function createBalanceReader({ listKeys, getHosts, fetchImpl = ambientFetch, now
544
544
  * model does not support is refused before the request is sent: Claude Opus
545
545
  * 5.5 (platform.claude.com effort docs), GPT-6.1 Sol and GPT-6 Astra
546
546
  * `reasoning.effort` (developers.openai.com model pages), DeepSeek thinking
547
- * mode (`thinking` toggle plus `low|high|max` effort).
547
+ * mode (`thinking` toggle plus `low|high|max` effort), and Grok 4.7
548
+ * (docs.x.ai/developers/grok-4-7).
548
549
  *
549
550
  * @module dsh-packycode-api/catalog
550
551
  */
@@ -586,6 +587,11 @@ const ALWAYS_THINKING_LEVELS = Object.freeze({
586
587
  xhigh: "xhigh",
587
588
  max: "max"
588
589
  });
590
+ /** Grok 4.7 supports low | medium | high | xhigh, with no off or max. */
591
+ const GROK_LEVELS = Object.freeze({
592
+ ...ALWAYS_THINKING_LEVELS,
593
+ max: null
594
+ });
589
595
  const PACKYCODE_MODELS = Object.freeze([
590
596
  Object.freeze({
591
597
  id: "deepseek-flash",
@@ -632,6 +638,20 @@ const PACKYCODE_MODELS = Object.freeze([
632
638
  maxTokens: 128e3,
633
639
  thinkingLevelMap: ALWAYS_THINKING_LEVELS
634
640
  }),
641
+ Object.freeze({
642
+ id: "grok-4.7",
643
+ name: "Grok 4.7",
644
+ api: "openai-responses",
645
+ provider: PROVIDER,
646
+ baseUrl: RESPONSES_BASE,
647
+ reasoning: true,
648
+ input: Object.freeze(["text", "image"]),
649
+ cost: NO_COST,
650
+ contextWindow: 5e5,
651
+ maxTokens: 5e5,
652
+ thinkingLevelMap: GROK_LEVELS,
653
+ compat: Object.freeze({ supportsLongCacheRetention: false })
654
+ }),
635
655
  Object.freeze({
636
656
  id: "claude-opus-5-5",
637
657
  name: "Claude Opus 5.5",
@@ -4896,6 +4916,134 @@ var PackyCodeKeyRing = class {
4896
4916
  }
4897
4917
  };
4898
4918
  //#endregion
4919
+ //#region src/preferences.js
4920
+ /**
4921
+ * Where the plugin's preferences are read from and written to, on both
4922
+ * settings generations DSH has shipped.
4923
+ *
4924
+ * - DSH 0.1.5 installs a settings *section*: the section hands back a live
4925
+ * source and writes go through `settings.update(namespace, patch)`.
4926
+ * - DSH 0.2 has no sections: a preference is a *volatile* Config field of the
4927
+ * plugin's own row, read through a live reference, written through
4928
+ * `settings.update(rowId, patch)`, and announced by `loader/volatile-update`.
4929
+ * Only volatile fields are writable there, so the host overrides stay
4930
+ * read-only while web search and model visibility are editable.
4931
+ *
4932
+ * @module dsh-packycode-api/preferences
4933
+ */
4934
+ /**
4935
+ * Mark a preference editable without restarting the plugin. DSH 0.2 stores
4936
+ * plugin preferences as volatile Config fields and writes only those. The
4937
+ * peer dependency requires the schema version that implements `volatile()`.
4938
+ */
4939
+ const live = (schema) => schema.volatile();
4940
+ /** Read a Config field that may arrive as a volatile reference. */
4941
+ const fieldValue = (value) => value !== null && typeof value === "object" && typeof value.get === "function" ? value.get() : value;
4942
+ /** A preference target nothing can write to yet. */
4943
+ function unwritable(message) {
4944
+ return {
4945
+ writable: false,
4946
+ set: async () => {
4947
+ throw new Error(message);
4948
+ }
4949
+ };
4950
+ }
4951
+ /**
4952
+ * Connect the preferences to the settings service the host provides.
4953
+ * @param settingsCtx - the scope the `settings` inject handed over.
4954
+ * @param options - the plugin context and Config, the section namespace, the
4955
+ * current source and how to replace it, what to do when the section changes,
4956
+ * and the preference targets this fills in (host overrides, search, models).
4957
+ */
4958
+ function connectSettings(settingsCtx, { ctx, Config, namespace, source, setSource, onChange, hostPreference, searchPreference, modelPreference }) {
4959
+ const settings = settingsCtx.settings;
4960
+ if (typeof settings?.installSection === "function") {
4961
+ try {
4962
+ settings.installSection(ctx, namespace, Config, source(), {
4963
+ setSource: (current) => setSource(typeof current === "function" ? () => current() ?? {} : () => current ?? {}),
4964
+ onChange
4965
+ });
4966
+ if (typeof settings.update === "function") {
4967
+ const write = (patch) => settings.update(namespace, patch);
4968
+ const target = {
4969
+ writable: settings.writable !== false,
4970
+ set: write
4971
+ };
4972
+ Object.assign(hostPreference, target);
4973
+ Object.assign(searchPreference, target);
4974
+ Object.assign(modelPreference, target);
4975
+ }
4976
+ } catch (error) {
4977
+ ctx.logger?.warn?.("packycode-api: host overrides unavailable, defaults stand: %s", error.message);
4978
+ }
4979
+ return;
4980
+ }
4981
+ if (typeof settings?.update !== "function") return;
4982
+ const rowId = ctx.fiber?.entry?.options?.id ?? namespace;
4983
+ const target = {
4984
+ writable: settings.writable !== false,
4985
+ set: (patch) => settings.update(rowId, patch)
4986
+ };
4987
+ Object.assign(searchPreference, target);
4988
+ Object.assign(modelPreference, target);
4989
+ if (typeof settings.configure === "function") {
4990
+ const scope = typeof settingsCtx.effect === "function" ? settingsCtx : ctx;
4991
+ try {
4992
+ scope.effect(() => settings.configure({ auto: false }, ctx.fiber), "packycode-api: settings page policy");
4993
+ } catch (error) {
4994
+ ctx.logger?.warn?.("packycode-api: could not hide the generated settings page: %s", error.message);
4995
+ }
4996
+ }
4997
+ }
4998
+ //#endregion
4999
+ //#region src/model-selection.js
5000
+ /** Profile preferences for the models advertised in PackyCode's picker. */
5001
+ /** Store exclusions so new catalog models are selected by default as well. */
5002
+ function readHiddenModels(preference) {
5003
+ const value = fieldValue(preference?.hiddenModels);
5004
+ if (!Array.isArray(value)) return [];
5005
+ const hidden = new Set(value);
5006
+ return PACKYCODE_MODEL_IDS.filter((id) => hidden.has(id));
5007
+ }
5008
+ function createModelSelectionController({ readPreference, writePreference, isWritable, onChange }) {
5009
+ const hidden = () => readHiddenModels(readPreference());
5010
+ let advertised = hidden().join(",");
5011
+ const reconcile = () => {
5012
+ const next = hidden().join(",");
5013
+ if (next === advertised) return;
5014
+ onChange?.();
5015
+ advertised = next;
5016
+ };
5017
+ const status = () => {
5018
+ const excluded = new Set(hidden());
5019
+ return {
5020
+ writable: isWritable() === true,
5021
+ models: PACKYCODE_MODELS.map(({ id, name }) => ({
5022
+ id,
5023
+ name,
5024
+ selected: !excluded.has(id)
5025
+ }))
5026
+ };
5027
+ };
5028
+ return Object.freeze({
5029
+ status,
5030
+ reconcile,
5031
+ isVisible: (id) => !hidden().includes(id),
5032
+ async update({ selectedIds } = {}) {
5033
+ if (!Array.isArray(selectedIds) || selectedIds.some((id) => !PACKYCODE_MODEL_IDS.includes(id))) throw new Error("That PackyCode model selection is not supported");
5034
+ if (isWritable() !== true) throw new Error("PackyCode settings are not writable in this profile");
5035
+ const selected = new Set(selectedIds);
5036
+ try {
5037
+ await writePreference({ hiddenModels: PACKYCODE_MODEL_IDS.filter((id) => !selected.has(id)) });
5038
+ } catch {
5039
+ throw new Error("PackyCode could not save the model selection");
5040
+ }
5041
+ reconcile();
5042
+ return status();
5043
+ }
5044
+ });
5045
+ }
5046
+ //#endregion
4899
5047
  //#region src/plugin-version.js
4900
5048
  /**
4901
5049
  * Version self-knowledge for the settings panel.
@@ -5218,85 +5366,6 @@ function createPackyCodePluginManager({ fetchImpl = ambientFetch, runCommand = s
5218
5366
  });
5219
5367
  }
5220
5368
  //#endregion
5221
- //#region src/preferences.js
5222
- /**
5223
- * Where the plugin's preferences are read from and written to, on both
5224
- * settings generations DSH has shipped.
5225
- *
5226
- * - DSH 0.1.5 installs a settings *section*: the section hands back a live
5227
- * source and writes go through `settings.update(namespace, patch)`.
5228
- * - DSH 0.2 has no sections: a preference is a *volatile* Config field of the
5229
- * plugin's own row, read through a live reference, written through
5230
- * `settings.update(rowId, patch)`, and announced by `loader/volatile-update`.
5231
- * Only volatile fields are writable there, so the host overrides stay
5232
- * read-only while the web search preference is editable.
5233
- *
5234
- * @module dsh-packycode-api/preferences
5235
- */
5236
- /**
5237
- * Mark a preference editable without restarting the plugin. DSH 0.2 stores
5238
- * plugin preferences as volatile Config fields and writes only those; an older
5239
- * schema library has no `volatile()` and keeps a plain field.
5240
- */
5241
- const live = (schema) => typeof schema.volatile === "function" ? schema.volatile() : schema;
5242
- /** Read a Config field that may arrive as a volatile reference. */
5243
- const fieldValue = (value) => value !== null && typeof value === "object" && typeof value.get === "function" ? value.get() : value;
5244
- /** A preference target nothing can write to yet. */
5245
- function unwritable(message) {
5246
- return {
5247
- writable: false,
5248
- set: async () => {
5249
- throw new Error(message);
5250
- }
5251
- };
5252
- }
5253
- /**
5254
- * Connect the preferences to the settings service the host provides.
5255
- * @param settingsCtx - the scope the `settings` inject handed over.
5256
- * @param options - the plugin context and Config, the section namespace, the
5257
- * current source and how to replace it, what to do when the section changes,
5258
- * and the two preference targets this fills in (host overrides, search).
5259
- */
5260
- function connectSettings(settingsCtx, { ctx, Config, namespace, source, setSource, onChange, hostPreference, searchPreference }) {
5261
- const settings = settingsCtx.settings;
5262
- if (typeof settings?.installSection === "function") {
5263
- try {
5264
- settings.installSection(ctx, namespace, Config, source(), {
5265
- setSource: (current) => setSource(typeof current === "function" ? () => current() ?? {} : () => current ?? {}),
5266
- onChange
5267
- });
5268
- if (typeof settings.update === "function") {
5269
- const write = (patch) => settings.update(namespace, patch);
5270
- Object.assign(hostPreference, {
5271
- writable: true,
5272
- set: write
5273
- });
5274
- Object.assign(searchPreference, {
5275
- writable: true,
5276
- set: write
5277
- });
5278
- }
5279
- } catch (error) {
5280
- ctx.logger?.warn?.("packycode-api: host overrides unavailable, defaults stand: %s", error.message);
5281
- }
5282
- return;
5283
- }
5284
- if (typeof settings?.update !== "function") return;
5285
- const rowId = ctx.fiber?.entry?.options?.id ?? namespace;
5286
- Object.assign(searchPreference, {
5287
- writable: settings.writable !== false,
5288
- set: (patch) => settings.update(rowId, patch)
5289
- });
5290
- if (typeof settings.configure === "function") {
5291
- const scope = typeof settingsCtx.effect === "function" ? settingsCtx : ctx;
5292
- try {
5293
- scope.effect(() => settings.configure({ auto: false }, ctx.fiber), "packycode-api: settings page policy");
5294
- } catch (error) {
5295
- ctx.logger?.warn?.("packycode-api: could not hide the generated settings page: %s", error.message);
5296
- }
5297
- }
5298
- }
5299
- //#endregion
5300
5369
  //#region src/provider.js
5301
5370
  /**
5302
5371
  * The PackyCode pi-ai provider, built in code so the user configures no route.
@@ -5326,7 +5395,7 @@ function keyRingAuth() {
5326
5395
  }
5327
5396
  /** Build the route's pi-ai provider (unguarded; the plugin wraps its streams). */
5328
5397
  function createPackyCodeProvider() {
5329
- return createProvider({
5398
+ const provider = createProvider({
5330
5399
  id: PROVIDER,
5331
5400
  name: DISPLAY_NAME,
5332
5401
  baseUrl: DEFAULT_API_HOST,
@@ -5338,6 +5407,15 @@ function createPackyCodeProvider() {
5338
5407
  "anthropic-messages": anthropicMessagesApi()
5339
5408
  }
5340
5409
  });
5410
+ const requestOptions = (model, options) => model.api === "openai-responses" && !model.id.startsWith("gpt-") ? {
5411
+ ...options,
5412
+ cacheRetention: "none"
5413
+ } : options;
5414
+ return Object.freeze({
5415
+ ...provider,
5416
+ stream: (model, context, options) => provider.stream(model, context, requestOptions(model, options)),
5417
+ streamSimple: (model, context, options) => provider.streamSimple(model, context, requestOptions(model, options))
5418
+ });
5341
5419
  }
5342
5420
  /**
5343
5421
  * Observe a pi-ai event stream and hand a key-level failure to the plugin.
@@ -5418,7 +5496,7 @@ function guardKeyRotation(stream, { onKeyFailure, key } = {}) {
5418
5496
  //#region src/route.js
5419
5497
  /**
5420
5498
  * The HTTP model route: the pi-ai provider profile and the adapter that
5421
- * serves the catalog's HTTP models (DeepSeek and GPT) with the ring's keys.
5499
+ * serves the catalog's HTTP models (DeepSeek, GPT and Grok) with the ring's keys.
5422
5500
  *
5423
5501
  * @module dsh-packycode-api/route
5424
5502
  */
@@ -5508,7 +5586,7 @@ function createPackyCodeProfile(provider) {
5508
5586
  * supplies none, and the attachment store image input is read from.
5509
5587
  * @returns a `PiAiAdapter` serving the `packycode` route.
5510
5588
  */
5511
- function createRouteAdapter({ ring, keys, fallbackSessionId, resolveAttachments }) {
5589
+ function createRouteAdapter({ ring, keys, fallbackSessionId, resolveAttachments, isModelVisible = () => true }) {
5512
5590
  const raw = createPackyCodeProvider();
5513
5591
  /**
5514
5592
  * The gateway's Codex-group check refuses a Responses request that carries
@@ -5541,7 +5619,11 @@ function createRouteAdapter({ ring, keys, fallbackSessionId, resolveAttachments
5541
5619
  streamSimple: guarded("streamSimple")
5542
5620
  });
5543
5621
  const profiles = /* @__PURE__ */ new Map([[PROVIDER, createPackyCodeProfile(provider)]]);
5544
- return new PiAiAdapter({
5622
+ return new class extends PiAiAdapter {
5623
+ async listModels(provider) {
5624
+ return (await super.listModels(provider)).filter((model) => isModelVisible(model.id));
5625
+ }
5626
+ }({
5545
5627
  profiles: () => profiles,
5546
5628
  resolveApiKey: async () => {
5547
5629
  const active = await keys.active();
@@ -5566,7 +5648,7 @@ function createRouteAdapter({ ring, keys, fallbackSessionId, resolveAttachments
5566
5648
  * Every reply carries only what this plugin owns: key labels and state, the
5567
5649
  * balance and group projections the host built, host overrides, whether this
5568
5650
  * device has the Claude Code CLI, the plugin version, and the web search
5569
- * preference. Key material never crosses this boundary.
5651
+ * preference and model visibility. Key material never crosses this boundary.
5570
5652
  *
5571
5653
  * @module dsh-packycode-api/rpc
5572
5654
  */
@@ -5576,7 +5658,11 @@ const ok = (value) => ({
5576
5658
  });
5577
5659
  const failed = (message) => ({
5578
5660
  ok: false,
5579
- error: { message }
5661
+ error: {
5662
+ code: "packycode/request-failed",
5663
+ message,
5664
+ details: {}
5665
+ }
5580
5666
  });
5581
5667
  /** Only sentences this plugin authored may reach the browser. */
5582
5668
  const SAFE_MESSAGE = /^(?:PackyCode|That |Unknown |PackyCode's |add |the )[\s\S]{0,180}$/u;
@@ -5588,7 +5674,7 @@ const keyId = (payload) => String(payload?.id ?? "");
5588
5674
  * web search controller (without one, its endpoints refuse).
5589
5675
  * @returns a handler for `connection.rpc.handle(CHANNEL, handler)`.
5590
5676
  */
5591
- function createPackyCodeRpc({ ring, balance, groups, hosts, preference, claudeCli, pluginManager, search }) {
5677
+ function createPackyCodeRpc({ ring, balance, groups, hosts, preference, claudeCli, pluginManager, search, modelSelection }) {
5592
5678
  const need = (service, message) => {
5593
5679
  if (service === void 0) throw new Error(message);
5594
5680
  return service;
@@ -5597,6 +5683,7 @@ function createPackyCodeRpc({ ring, balance, groups, hosts, preference, claudeCl
5597
5683
  const manager = () => need(pluginManager, "PackyCode plugin version is unavailable");
5598
5684
  const webSearch = () => need(search, "PackyCode web search is unavailable in this runtime");
5599
5685
  const groupReader = () => need(groups, "PackyCode key groups are unavailable in this runtime");
5686
+ const models = () => need(modelSelection, "PackyCode model selection is unavailable in this runtime");
5600
5687
  const status = async () => ({
5601
5688
  ...await ring.list(),
5602
5689
  hosts: hosts(),
@@ -5661,7 +5748,9 @@ function createPackyCodeRpc({ ring, balance, groups, hosts, preference, claudeCl
5661
5748
  "search/update": (payload) => webSearch().update({
5662
5749
  searchProvider: payload?.searchProvider,
5663
5750
  searchBackend: payload?.searchBackend
5664
- })
5751
+ }),
5752
+ "models/status": () => models().status(),
5753
+ "models/update": (payload) => models().update({ selectedIds: payload?.selectedIds })
5665
5754
  };
5666
5755
  return async (endpoint, payload, signal) => {
5667
5756
  try {
@@ -6406,9 +6495,11 @@ const FOREIGN_ROUTERS = Object.freeze({
6406
6495
  });
6407
6496
  /** Normalize a stored preference; anything unknown reads as the default. */
6408
6497
  function readSearchChoice(value) {
6498
+ const provider = fieldValue(value?.searchProvider);
6499
+ const selectedBackend = fieldValue(value?.searchBackend);
6409
6500
  return {
6410
- mode: SEARCH_MODES.includes(value?.searchProvider) ? value.searchProvider : SEARCH_MODE_DEFAULT,
6411
- backend: SEARCH_BACKENDS.includes(value?.searchBackend) ? value.searchBackend : DEFAULT_SEARCH_BACKEND
6501
+ mode: SEARCH_MODES.includes(provider) ? provider : SEARCH_MODE_DEFAULT,
6502
+ backend: SEARCH_BACKENDS.includes(selectedBackend) ? selectedBackend : DEFAULT_SEARCH_BACKEND
6412
6503
  };
6413
6504
  }
6414
6505
  /** Only sentences this plugin wrote reach the browser. */
@@ -6592,7 +6683,9 @@ const Config = z.object({
6592
6683
  */
6593
6684
  searchProvider: live(z.union([...SEARCH_MODES]).default(SEARCH_MODE_DEFAULT)),
6594
6685
  /** Which PackyCode model runs a search: `deepseek` or `gpt`. */
6595
- searchBackend: live(z.union([...SEARCH_BACKENDS]).default(DEFAULT_SEARCH_BACKEND))
6686
+ searchBackend: live(z.union([...SEARCH_BACKENDS]).default(DEFAULT_SEARCH_BACKEND)),
6687
+ /** Only the picker is filtered; an existing session can keep its model. */
6688
+ hiddenModels: live(z.array(z.string()).default([]))
6596
6689
  });
6597
6690
  function apply(ctx, config) {
6598
6691
  const ring = new PackyCodeKeyRing(ctx.credentials);
@@ -6600,7 +6693,8 @@ function apply(ctx, config) {
6600
6693
  apiHost: normalizeHost(config?.apiHost, DEFAULT_API_HOST),
6601
6694
  statusHost: normalizeHost(config?.statusHost, DEFAULT_STATUS_HOST),
6602
6695
  searchProvider: fieldValue(config?.searchProvider),
6603
- searchBackend: fieldValue(config?.searchBackend)
6696
+ searchBackend: fieldValue(config?.searchBackend),
6697
+ hiddenModels: fieldValue(config?.hiddenModels)
6604
6698
  });
6605
6699
  const hosts = () => {
6606
6700
  const current = source() ?? {};
@@ -6646,6 +6740,17 @@ function apply(ctx, config) {
6646
6740
  };
6647
6741
  const fallbackSessionId = `${PLUGIN_ID}-${randomUUID()}`;
6648
6742
  const attachments = () => ctx.get?.("attachments") ?? ctx.attachments;
6743
+ const modelPreference = {
6744
+ writable: false,
6745
+ set: void 0
6746
+ };
6747
+ let refreshModels = () => {};
6748
+ const modelSelection = createModelSelectionController({
6749
+ readPreference: () => source() ?? {},
6750
+ writePreference: (patch) => modelPreference.set(patch),
6751
+ isWritable: () => modelPreference.writable === true && typeof modelPreference.set === "function",
6752
+ onChange: () => refreshModels()
6753
+ });
6649
6754
  /**
6650
6755
  * The Claude Code CLI runner. PackyCode serves its Claude models only to the
6651
6756
  * official CLI, so CLI-backed models are run by that CLI itself — with this
@@ -6704,12 +6809,13 @@ function apply(ctx, config) {
6704
6809
  const configured = config?.claudeCliMode;
6705
6810
  return configured === void 0 || configured === "auto" ? claudeModeForSession(ctx, session) : configured;
6706
6811
  };
6707
- ctx.llm.registerAdapter([PROVIDER], createClaudeCliAdapter({
6812
+ const registration = ctx.llm.registerAdapter([PROVIDER], createClaudeCliAdapter({
6708
6813
  inner: createRouteAdapter({
6709
6814
  ring,
6710
6815
  keys,
6711
6816
  fallbackSessionId,
6712
- resolveAttachments: attachments
6817
+ resolveAttachments: attachments,
6818
+ isModelVisible: modelSelection.isVisible
6713
6819
  }),
6714
6820
  runner: claudeRunner,
6715
6821
  resolveMode: () => {
@@ -6720,6 +6826,10 @@ function apply(ctx, config) {
6720
6826
  resolveAttachments: attachments,
6721
6827
  explainKey: (runKey) => keys.describe(runKey)
6722
6828
  }));
6829
+ refreshModels = () => {
6830
+ if (typeof registration?.replace === "function") registration.replace([PROVIDER]);
6831
+ else ctx.emit?.("llm/adapters-updated");
6832
+ };
6723
6833
  ctx.llm.registerConfigurableProviders([{
6724
6834
  provider: PROVIDER,
6725
6835
  displayName: DISPLAY_NAME,
@@ -6771,12 +6881,15 @@ function apply(ctx, config) {
6771
6881
  onChange: () => {
6772
6882
  balance.invalidate();
6773
6883
  groups.invalidate();
6884
+ modelSelection.reconcile();
6774
6885
  search.reconcile();
6775
6886
  },
6776
6887
  hostPreference,
6777
- searchPreference
6888
+ searchPreference,
6889
+ modelPreference
6778
6890
  }));
6779
6891
  ctx.on?.("loader/volatile-update", () => {
6892
+ modelSelection.reconcile();
6780
6893
  search.reconcile();
6781
6894
  });
6782
6895
  /**
@@ -6798,7 +6911,8 @@ function apply(ctx, config) {
6798
6911
  preference: hostPreference,
6799
6912
  claudeCli,
6800
6913
  pluginManager: createPackyCodePluginManager(),
6801
- search
6914
+ search,
6915
+ modelSelection
6802
6916
  });
6803
6917
  /**
6804
6918
  * Connection registers a channel through `owner.webServer`, read on its own
@@ -6820,4 +6934,4 @@ function apply(ctx, config) {
6820
6934
  });
6821
6935
  }
6822
6936
  //#endregion
6823
- export { AUTO_CLAUDE_MODE, CHANNEL, CLAUDE_CLI_MODES, CLAUDE_INSTALL_COMMAND, CLAUDE_MISSING_MESSAGE, CLAUDE_NPM_PACKAGE, CLAUDE_TOOL_INSTRUCTIONS, CLI_BACKED_MODEL_IDS, CLI_IMAGE_LIMITS, Config, DEFAULT_API_HOST, DEFAULT_APPEND_SYSTEM_PROMPT, DEFAULT_SEARCH_BACKEND, DEFAULT_STATUS_HOST, DISPLAY_NAME, LEGACY_STATUS_HOSTS, PACKYCODE_AUTO_SEARCH_PROVIDER_ID, PACKYCODE_MODELS, PACKYCODE_MODEL_IDS, PACKYCODE_SEARCH_PROVIDER_ID, PLUGIN_ID, PROVIDER, PackyCodeKeyRing, SEARCH_BACKENDS, SEARCH_BACKEND_MODELS, SEARCH_MODES, SETTINGS_NAMESPACE, TITLE_MODEL_ID, TITLE_MODEL_ROUTES, accountHostOrder, apply, assertApiKey, buildClaudeArgs, buildClaudeEnvironment, buildClaudeInput, buildDelegatedContent, buildSearchRequest, capClaudeMode, catalogCoverage, classifyClientPolicy, classifyGatewayFailure, claudeBinaryCandidates, claudeModeFor, claudeModeForSession, cliSearchInstructions, createBalanceReader, createClaudeCliAdapter, createClaudeCliManager, createClaudeCodeTool, createClaudeRunner, createClaudeSearchBridge, createGroupReader, createKeyChooser, createPackyCodeAutoSearchProvider, createPackyCodeProfile, createPackyCodeProvider, createPackyCodeRpc, createPackyCodeSearchProvider, createProfileSearchComposition, createRouteAdapter, createSearchComposition, createSearchController, delegationInstructions, describeRunKey, explainCliClientPolicyFailure, explainCliGroupFailure, explainClientPolicyFailure, explainNpmFailure, findClaudeBinary, guardKeyRotation, inject, keyNote, locateClaudeBinary, locateNpm, name, normalizeFailureMessage, normalizeHost, npmCandidates, parseBillingSubscription, parseBillingUsage, parseClaudeResult, parseClaudeVersion, parseMessagesSearchResponse, parsePricing, parseResponsesSearchResponse, parseSelectedGroups, parseTokenUsage, pickKeyForModel, planModeForSession, planModeForToolExecution, readClaudeStreamEvents, readSearchChoice, renderAuxiliaryPrompt, renderDelegatedPrompt, resolveSpawnCommand, statusHostOrder, summarizeToolUse };
6937
+ export { AUTO_CLAUDE_MODE, CHANNEL, CLAUDE_CLI_MODES, CLAUDE_INSTALL_COMMAND, CLAUDE_MISSING_MESSAGE, CLAUDE_NPM_PACKAGE, CLAUDE_TOOL_INSTRUCTIONS, CLI_BACKED_MODEL_IDS, CLI_IMAGE_LIMITS, Config, DEFAULT_API_HOST, DEFAULT_APPEND_SYSTEM_PROMPT, DEFAULT_SEARCH_BACKEND, DEFAULT_STATUS_HOST, DISPLAY_NAME, LEGACY_STATUS_HOSTS, PACKYCODE_AUTO_SEARCH_PROVIDER_ID, PACKYCODE_MODELS, PACKYCODE_MODEL_IDS, PACKYCODE_SEARCH_PROVIDER_ID, PLUGIN_ID, PROVIDER, PackyCodeKeyRing, SEARCH_BACKENDS, SEARCH_BACKEND_MODELS, SEARCH_MODES, SETTINGS_NAMESPACE, TITLE_MODEL_ID, TITLE_MODEL_ROUTES, accountHostOrder, apply, assertApiKey, buildClaudeArgs, buildClaudeEnvironment, buildClaudeInput, buildDelegatedContent, buildSearchRequest, capClaudeMode, catalogCoverage, classifyClientPolicy, classifyGatewayFailure, claudeBinaryCandidates, claudeModeFor, claudeModeForSession, cliSearchInstructions, createBalanceReader, createClaudeCliAdapter, createClaudeCliManager, createClaudeCodeTool, createClaudeRunner, createClaudeSearchBridge, createGroupReader, createKeyChooser, createModelSelectionController, createPackyCodeAutoSearchProvider, createPackyCodeProfile, createPackyCodeProvider, createPackyCodeRpc, createPackyCodeSearchProvider, createProfileSearchComposition, createRouteAdapter, createSearchComposition, createSearchController, delegationInstructions, describeRunKey, explainCliClientPolicyFailure, explainCliGroupFailure, explainClientPolicyFailure, explainNpmFailure, findClaudeBinary, guardKeyRotation, inject, keyNote, locateClaudeBinary, locateNpm, name, normalizeFailureMessage, normalizeHost, npmCandidates, parseBillingSubscription, parseBillingUsage, parseClaudeResult, parseClaudeVersion, parseMessagesSearchResponse, parsePricing, parseResponsesSearchResponse, parseSelectedGroups, parseTokenUsage, pickKeyForModel, planModeForSession, planModeForToolExecution, readClaudeStreamEvents, readHiddenModels, readSearchChoice, renderAuxiliaryPrompt, renderDelegatedPrompt, resolveSpawnCommand, statusHostOrder, summarizeToolUse };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-packycode-api",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Use a PackyCode (PackyAPI) API key in DeepSeek Harness through a built-in multi-protocol model route with key rotation and balance display",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -76,7 +76,7 @@
76
76
  "@deepseek-ai/dsh-llm-pi-ai": ">=0.1.5-rc.1 <0.3.0-0",
77
77
  "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.3.0-0",
78
78
  "@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.3.0-0",
79
- "@deepseek-ai/schemastery": "^3.18.2",
79
+ "@deepseek-ai/schemastery": "^3.18.4",
80
80
  "@earendil-works/pi-ai": "0.85.1 || 0.86.0 || 0.86.1 || 0.87.0 || 0.87.1",
81
81
  "react": "^18.2.0"
82
82
  },
@@ -87,10 +87,11 @@
87
87
  "@deepseek-ai/dsh-llm-pi-ai": "0.1.5-rc.2",
88
88
  "@deepseek-ai/dsh-settings": "0.1.5-rc.2",
89
89
  "@deepseek-ai/dsh-tools": "0.1.5-rc.2",
90
- "@deepseek-ai/schemastery": "3.18.2",
90
+ "@deepseek-ai/schemastery": "3.18.4",
91
91
  "@earendil-works/pi-ai": "0.85.1",
92
92
  "react": "18.3.1",
93
- "tsdown": "0.22.2"
93
+ "tsdown": "0.22.2",
94
+ "yaml": "2.9.1"
94
95
  },
95
96
  "scripts": {
96
97
  "build": "tsdown --config tsdown.config.mjs",