@saluzi/saluzi-edu 0.2.47 → 0.2.49

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.
@@ -3100,7 +3100,7 @@
3100
3100
  "模型槽位"
3101
3101
  ]
3102
3102
  },
3103
- "content": "\n## 什么是 /keys\n\n`/keys` 命令管理 Saluzi 的 API Key 绑定。它采用**双栏 TUI 界面**(左栏为模型槽位,右栏为 Key 列表),支持:\n\n- 绑定多个 provider 的 Key(Anthropic、OpenAI、Gemini、Grok、Foundry、自定义等)\n- 将 Key 绑定到不同的**模型槽位**(default / max / pro / std / subagent)\n- 为每个 Key 设置名称、指定 Base URL(transit 代理场景)\n- 编辑、删除、解绑已有配置\n\n## 使用方法\n\n```\n> /keys\n```\n\n打开双栏管理面板。通过键盘快捷键操作:\n\n| 快捷键 | 操作 |\n|--------|------|\n| `a` | 添加新 Key |\n| `e` | 编辑已有 Key(名称/provider/URL/key 值) |\n| `d` | 删除 Key |\n| `b` | 绑定到模型槽位 |\n| `u` | 解绑槽位 |\n| `Esc` | 关闭面板 |\n\n添加 Key 时需要输入:\n- Key 名称(如 `anthropic-work`)\n- Provider(Anthropic Direct / Transit / OpenAI / Gemini / Grok / Foundry / Custom)\n- API Key 值\n- Base URL(Transit、Foundry、Custom 等场景需要)\n\nKey 保存在本地配置中,不会提交到 VCS。\n\n## 模型槽位\n\n`/keys` 的核心概念是**模型槽位**。每个槽位对应一个模型级别:\n\n| 槽位 | 说明 |\n|------|------|\n| `default` | 默认 Key,所有模型共用 |\n| `max` | Max 级别模型专用 Key |\n| `pro` | Pro 级别模型专用 Key |\n| `std` | Std 级别模型专用 Key |\n| `subagent` | 子 agent 专用 Key |\n\n当 `/model max` 执行时,Saluzi 优先使用 `max` 槽位的 Key;未配置时回退到 `default`。\n\n## 环境变量\n\n可通过环境变量预设 Key 配置(CI/CD 场景常用):\n\n```bash\nKEYS_DEFAULT_KEY=sk-xxx slz\nKEYS_MAX_KEY=sk-xxx KEYS_MAX_MODEL=claude-opus-4-7 slz\n```\n\n格式为 `KEYS_{SLOT}_{FIELD}`,其中 SLOT 为 `DEFAULT`/`MAX`/`PRO`/`STD`/`SUBAGENT`,FIELD 为 `KEY`/`PROVIDER`/`MODEL`/`URL`。\n\n## Provider 选择\n\nSaluzi 自动选择最优 Provider。如需指定:\n- 通过环境变量(如 `ANTHROPIC_API_KEY`)指定\n- 通过 `/keys` 绑定特定 provider 的 Key 到对应槽位\n- 通过 `/model` 切换当前会话模型\n\n## 安全建议\n\n- 不要把 Key 写进代码或 commit\n- 用 `/keys` 管理而非环境变量(更安全、可切换)\n- 定期轮换 Key\n"
3103
+ "content": "\n## 什么是 /keys\n\n`/keys` 命令管理 Saluzi 的 API Key 绑定。它采用**双栏 TUI 界面**(左栏为模型槽位,右栏为 Key 列表),支持:\n\n- 绑定多个 provider 的 Key(Anthropic、OpenAI、Gemini、Grok、Foundry、自定义等)\n- 将 Key 绑定到不同的**模型槽位**(default / max / pro / std / subagent)\n- 为每个 Key 设置名称、指定 Base URL(transit 代理场景)\n- 编辑、删除、解绑已有配置\n\n## 使用方法\n\n```\n> /keys\n```\n\n打开双栏管理面板。通过键盘快捷键操作:\n\n| 快捷键 | 操作 |\n|--------|------|\n| `a` | 添加新 Key |\n| `e` | 编辑已有 Key(名称/provider/URL/key 值) |\n| `d` | 删除 Key |\n| `b` | 绑定到模型槽位 |\n| `u` | 解绑槽位 |\n| `Esc` | 关闭面板 |\n\n添加 Key 时需要输入:\n- Key 名称(如 `anthropic-work`)\n- Provider(Anthropic Direct / Transit / OpenAI / Gemini / Grok / Foundry / Custom)\n- API Key 值\n- Base URL(Transit、Foundry、Custom 等场景需要)\n\nKey 保存在本地配置中,不会提交到 VCS。\n\n## 模型槽位\n\n`/keys` 的核心概念是**模型槽位**。每个槽位对应一个模型级别:\n\n| 槽位 | 说明 |\n|------|------|\n| `default` | 默认 Key,所有模型共用 |\n| `max` | Max 级别模型专用 Key |\n| `pro` | Pro 级别模型专用 Key |\n| `std` | Std 级别模型专用 Key |\n| `subagent` | 子 agent 专用 Key |\n\n当 `/model max` 执行时,Saluzi 优先使用 `max` 槽位的 Key;未配置时回退到 `default`。\n\n## 槽位上下文长度\n\n不同 provider 的模型上下文窗口可能不一致(例如 Anthropic 200K、Gemini 1M、某些 OpenAI 兼容端点 128K)。默认情况下,所有槽位共用全局配置的上下文上限(`SALUZI_MAX_CONTEXT_TOKENS` 或 `/login` 配置)。\n\n`/keys` 支持为每个槽位单独配置上下文长度:\n\n1. 在 Model Slots 区域选中目标槽位,按 `b` 开始绑定\n2. 选择 Key 后输入 model name(可留空使用 provider 默认)\n3. 在 **Context Limit** 步骤输入该槽位的上下文 token 数(如 `200000`、`1000000`),留空则使用全局配置\n\n配置后,切换到该槽位的模型时,状态栏与 auto-compact 阈值都会使用槽位专属的上下文长度。槽位列表会显示 `[ctx: 500k]` 标记。\n\n槽位上下文长度的解析优先级:\n\n1. `SALUZI_MAX_CONTEXT_TOKENS`(管理员全局强制覆盖,最高优先)\n2. `KEYS_{SLOT}_CONTEXT_LIMIT`(本槽位配置)\n3. `SALUZI_AUTO_COMPACT_WINDOW`(全局 auto-compact 阈值)\n4. `[1m]` 后缀 / 模型能力缓存 / 200K 默认\n\n## 环境变量\n\n可通过环境变量预设 Key 配置(CI/CD 场景常用):\n\n```bash\nKEYS_DEFAULT_KEY=sk-xxx slz\nKEYS_MAX_KEY=sk-xxx KEYS_MAX_MODEL=claude-opus-4-7 KEYS_MAX_CONTEXT_LIMIT=1000000 slz\n```\n\n格式为 `KEYS_{SLOT}_{FIELD}`,其中 SLOT 为 `DEFAULT`/`MAX`/`PRO`/`STD`/`SUBAGENT`,FIELD 为 `KEY`/`PROVIDER`/`MODEL`/`URL`/`CONTEXT_LIMIT`。\n\n## Provider 选择\n\nSaluzi 自动选择最优 Provider。如需指定:\n- 通过环境变量(如 `ANTHROPIC_API_KEY`)指定\n- 通过 `/keys` 绑定特定 provider 的 Key 到对应槽位\n- 通过 `/model` 切换当前会话模型\n\n## 安全建议\n\n- 不要把 Key 写进代码或 commit\n- 用 `/keys` 管理而非环境变量(更安全、可切换)\n- 定期轮换 Key\n"
3104
3104
  },
3105
3105
  "docs/guide/token-saving-modes": {
3106
3106
  "frontmatter": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saluzi/saluzi-edu",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "description": "Saluzi CLI - interactive AI coding assistant in the terminal",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -292,6 +292,24 @@ export function resolveOwnedWebSessionId(
292
292
  ): string | null {
293
293
  try {
294
294
  const db = getDb()
295
+
296
+ // Admin bypass — admin sees all sessions in list views (listSessions),
297
+ // so detail/delete/control resolution must also bypass the visibility
298
+ // check. Otherwise admin sees sessions they cannot open or delete
299
+ // (orphan ACP sessions, other users' sessions). canManageSession still
300
+ // gates destructive actions; control.ts gates on session status.
301
+ const userRow = db
302
+ .query('SELECT role FROM users WHERE id = $userId')
303
+ .get({ $userId: uuid }) as { role: string } | null
304
+ if (userRow?.role === 'admin') {
305
+ if (storeGetSession(sessionId)) return sessionId
306
+ const compatibleCodeSessionId = toCompatibleCodeSessionId(sessionId)
307
+ if (compatibleCodeSessionId && storeGetSession(compatibleCodeSessionId)) {
308
+ return compatibleCodeSessionId
309
+ }
310
+ return sessionId
311
+ }
312
+
295
313
  const visibility = isSessionVisibleToUser(sessionId, uuid, db)
296
314
  if (visibility) {
297
315
  if (!requireWrite || visibility === 'owner' || visibility === 'write') {