@co0ontty/wand 4.96.1-beta.365.1.g4847c70 → 4.97.0
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 +12 -2
- package/dist/ai-text-runner.d.ts +14 -2
- package/dist/ai-text-runner.js +71 -21
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +14 -0
- package/dist/build-info.json +4 -4
- package/dist/cli-api.d.ts +1 -1
- package/dist/cli-api.js +8 -7
- package/dist/cli.js +15 -1
- package/dist/config.js +2 -2
- package/dist/decision-skill.d.ts +2 -4
- package/dist/employee-knowledge.d.ts +4 -1
- package/dist/employee-knowledge.js +18 -7
- package/dist/employee-text.d.ts +1 -1
- package/dist/employee-text.js +4 -4
- package/dist/env-utils.js +1 -1
- package/dist/feedback-feature-map.d.ts +56 -0
- package/dist/feedback-feature-map.js +20 -0
- package/dist/feedback.d.ts +142 -0
- package/dist/feedback.js +444 -0
- package/dist/git-quick-commit.js +53 -17
- package/dist/managed-skill.d.ts +8 -3
- package/dist/managed-skill.js +10 -3
- package/dist/managed-skills-ensure.d.ts +12 -0
- package/dist/managed-skills-ensure.js +43 -0
- package/dist/middleware/api-scope.js +4 -0
- package/dist/model-group-runner.js +4 -1
- package/dist/model-groups.d.ts +3 -0
- package/dist/model-groups.js +22 -6
- package/dist/models/parsers/opencode.d.ts +5 -0
- package/dist/models/parsers/opencode.js +27 -12
- package/dist/models.js +1 -1
- package/dist/opencode-free-selection.d.ts +10 -0
- package/dist/opencode-free-selection.js +11 -0
- package/dist/opencode-system-fallback.d.ts +70 -0
- package/dist/opencode-system-fallback.js +313 -0
- package/dist/path-repair.js +1 -0
- package/dist/pi-auto-resources.js +3 -1
- package/dist/pi-tmux-host.js +1 -1
- package/dist/process-manager.d.ts +3 -0
- package/dist/process-manager.js +68 -3
- package/dist/provider-history-scanner.d.ts +2 -0
- package/dist/provider-history-scanner.js +62 -48
- package/dist/render-structured-client.js +1 -1
- package/dist/scheduled-task-calendar.js +2 -3
- package/dist/scheduled-task-time.d.ts +2 -1
- package/dist/scheduled-task-time.js +27 -2
- package/dist/scheduled-task-types.d.ts +5 -0
- package/dist/server-auth-routes.d.ts +5 -1
- package/dist/server-auth-routes.js +90 -0
- package/dist/server-feedback-routes.d.ts +9 -0
- package/dist/server-feedback-routes.js +99 -0
- package/dist/server-session-list-routes.js +10 -2
- package/dist/server-settings-routes.js +3 -2
- package/dist/server-task-routes.js +43 -8
- package/dist/server-update-routes.d.ts +3 -0
- package/dist/server-update-routes.js +10 -1
- package/dist/server-workspace-routes.js +31 -3
- package/dist/server.js +99 -5
- package/dist/session-ai-context.d.ts +3 -0
- package/dist/session-ai-context.js +7 -0
- package/dist/session-artifact-cleanup.d.ts +7 -0
- package/dist/session-artifact-cleanup.js +45 -0
- package/dist/session-registry.d.ts +9 -1
- package/dist/session-registry.js +59 -10
- package/dist/storage/employees-repository.js +2 -2
- package/dist/storage/feedback-repository.d.ts +14 -0
- package/dist/storage/feedback-repository.js +56 -0
- package/dist/storage/internal.d.ts +3 -2
- package/dist/storage/internal.js +1 -1
- package/dist/storage/migrations.js +37 -0
- package/dist/storage/tasks-repository.d.ts +2 -1
- package/dist/storage/tasks-repository.js +31 -4
- package/dist/storage-schema.js +3 -0
- package/dist/storage.d.ts +3 -1
- package/dist/storage.js +4 -0
- package/dist/structured-claude-protocol.d.ts +2 -0
- package/dist/structured-claude-protocol.js +67 -2
- package/dist/structured-exec-host.d.ts +2 -0
- package/dist/structured-exec-pump.js +11 -2
- package/dist/structured-opencode-adapter.js +1 -1
- package/dist/structured-pi-adapter.js +1 -0
- package/dist/structured-runner.d.ts +2 -0
- package/dist/structured-session-manager.d.ts +7 -1
- package/dist/structured-session-manager.js +60 -4
- package/dist/system-ai-redaction.d.ts +2 -0
- package/dist/system-ai-redaction.js +15 -0
- package/dist/system-ai-session-recorder.d.ts +1 -2
- package/dist/system-ai-session-recorder.js +4 -15
- package/dist/system-cli.js +19 -0
- package/dist/system-employee.d.ts +2 -0
- package/dist/system-employee.js +8 -1
- package/dist/system-skill.d.ts +1 -4
- package/dist/system-skill.js +1 -1
- package/dist/task-agent-parsing.d.ts +1 -1
- package/dist/task-agent-parsing.js +6 -11
- package/dist/task-dispatch-receipt.d.ts +4 -0
- package/dist/task-dispatch-receipt.js +59 -0
- package/dist/task-hierarchy.d.ts +15 -0
- package/dist/task-hierarchy.js +67 -0
- package/dist/task-read-model.d.ts +6 -0
- package/dist/task-read-model.js +12 -0
- package/dist/task-title-organize.js +23 -6
- package/dist/task-title-service.js +4 -0
- package/dist/task-types.d.ts +16 -0
- package/dist/terminal-daemon-client.js +2 -1
- package/dist/update-helper.d.ts +3 -0
- package/dist/update-helper.js +72 -18
- package/dist/web-login-tickets.d.ts +41 -0
- package/dist/web-login-tickets.js +102 -0
- package/dist/web-ui/client-feedback.d.ts +16 -0
- package/dist/web-ui/client-feedback.js +72 -0
- package/dist/web-ui/content/module-manifest.json +1 -1
- package/dist/web-ui/content/modules/{c4706f47c23f33e4 → 0c96341a022aa360}/host.js +1 -1
- package/dist/web-ui/content/modules/15e32e85e086f6b4/page.js +6 -0
- package/dist/web-ui/content/modules/1e43259bddbc6805/markdown.js +1 -0
- package/dist/web-ui/content/modules/271d488d262909c2/host.js +30 -0
- package/dist/web-ui/content/modules/{e4fd9906521b4aa3 → 2bce1137f402bd70}/chunk.js +1 -1
- package/dist/web-ui/content/modules/3086df78444998b3/host.js +1 -0
- package/dist/web-ui/content/modules/{bcecb0cc14b7d2bd → 3172fe0b46d51f8d}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{4f74d2517f29134c → 3338b55c7767bacb}/chunk.js +1 -1
- package/dist/web-ui/content/modules/349ee129eef5a182/chunk.js +8 -0
- package/dist/web-ui/content/modules/{9510efce6caaa9ec → 3ddcbd8505bfcdf4}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{1021ae40c5761e3f → 42ae495da5903b07}/sha256.js +1 -1
- package/dist/web-ui/content/modules/43746e7237d61da9/task-board-host.js +17 -0
- package/dist/web-ui/content/modules/4485e6c1f0459aa8/chunk.js +1 -0
- package/dist/web-ui/content/modules/{799b19da948bec8d → 5903104a2e0e3888}/host.js +2 -2
- package/dist/web-ui/content/modules/5b541e0f296a3592/employee-card.js +1 -0
- package/dist/web-ui/content/modules/5e5eabd9a9366a56/panel.js +1 -0
- package/dist/web-ui/content/modules/{1d518ae6ed66fe5a → 64c1b0217f5377aa}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{9a0e65188739957f → 66f36cd2c38cfb07}/chunk.js +1 -1
- package/dist/web-ui/content/modules/6ed52e6604661678/chat-render.js +75 -0
- package/dist/web-ui/content/modules/{db4e2dbc7aed6353 → 801e7f686ce7eb28}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{f33ed89d1ccd3a2d → 854b0f6dc887923b}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{a50ce28f45bfeb2e → 87379801875d1921}/host.js +1 -1
- package/dist/web-ui/content/modules/89888da0972e5033/host.js +50 -0
- package/dist/web-ui/content/modules/{c7de873095c061ab → 9984f6bb05ac55bb}/host.js +1 -1
- package/dist/web-ui/content/modules/{31ffc2f05f87652c → a9f15bd03bc590e7}/host.js +1 -1
- package/dist/web-ui/content/modules/{7ef73b6c20d2504f → b33c567946044d83}/host.js +2 -2
- package/dist/web-ui/content/modules/c11165f843d818f4/host-bridge.js +1 -0
- package/dist/web-ui/content/modules/c1829693f91fd25c/host.js +1 -0
- package/dist/web-ui/content/modules/{9eae1033f47e4526 → c41d8ffa27816766}/host.js +1 -1
- package/dist/web-ui/content/modules/cdb882ddab12e325/host.js +1 -0
- package/dist/web-ui/content/modules/{3cea480770cb184c → d30ac9af6dc7d555}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{f6502dab121f9d91 → de00ab5329b5e05a}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{ec68d93a95c1d5d6 → e01e1e25b7fe37e9}/host.js +1 -1
- package/dist/web-ui/content/modules/e8f0cda6b9ac8a70/chunk.js +1 -0
- package/dist/web-ui/content/modules/{09842858f9d34a4e → e9a01a25ec573294}/library-bridge.js +1 -1
- package/dist/web-ui/content/modules/{2ed8bafd5b4fecc5 → ea67fd4e96c9f45a}/workspace-window.js +1 -1
- package/dist/web-ui/content/modules/ee12d3c4421a5c12/host.js +1 -0
- package/dist/web-ui/content/modules/{35aaa85b9d0937af → f5b3fb6fedd9b05d}/chunk.js +1 -1
- package/dist/web-ui/content/modules/fd767282c29173b5/runtime.js +539 -0
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +173 -176
- package/dist/web-ui/embedded-assets.js +4 -4
- package/dist/web-ui/index.js +7 -1
- package/dist/web-ui/login-credential.d.ts +4 -0
- package/dist/web-ui/login-credential.js +15 -0
- package/dist/web-ui/react/workspaces/types.d.ts +2 -0
- package/dist/ws-broadcast.d.ts +1 -1
- package/package.json +3 -1
- package/skills/wand-system/SKILL.md +9 -1
- package/skills/wand-system/references/operations.md +36 -1
- package/skills/wand-system/scripts/wand.mjs +1 -0
- package/skills/wand-system/scripts/web-login.mjs +116 -0
- package/dist/web-ui/content/modules/134f6120c0acaf57/host.js +0 -1
- package/dist/web-ui/content/modules/1f93b5bd70381bb6/runtime.js +0 -539
- package/dist/web-ui/content/modules/26c68d4decdd18b4/markdown.js +0 -1
- package/dist/web-ui/content/modules/3664d0620f124292/chunk.js +0 -3
- package/dist/web-ui/content/modules/3d12adf54647c1e2/host-bridge.js +0 -1
- package/dist/web-ui/content/modules/459cca2482a9a4ba/host.js +0 -18
- package/dist/web-ui/content/modules/474c9647130ef3e9/task-board-host.js +0 -2
- package/dist/web-ui/content/modules/52a218d74002a011/host.js +0 -30
- package/dist/web-ui/content/modules/54f2b10659ef8475/employee-card.js +0 -1
- package/dist/web-ui/content/modules/703fb1c670f7b199/chunk.js +0 -1
- package/dist/web-ui/content/modules/75511da23f051718/host.js +0 -1
- package/dist/web-ui/content/modules/8f8f7a0a8874d29a/host.js +0 -1
- package/dist/web-ui/content/modules/90f2cd73cdf3a2cd/chat-render.js +0 -25
- package/dist/web-ui/content/modules/a2c5b246e57fa165/panel.js +0 -1
- package/dist/web-ui/content/modules/adfc53789d5bedb2/chunk.js +0 -1
- package/dist/web-ui/content/modules/d789f84a3f8765ae/page.js +0 -6
- package/dist/web-ui/content/modules/eb95c3ee0d42827a/chunk.js +0 -6
- package/dist/web-ui/content/modules/fac83e61c0a8c8a7/host.js +0 -1
package/README.md
CHANGED
|
@@ -183,7 +183,11 @@ npm uninstall -g opencode
|
|
|
183
183
|
npm install -g opencode-ai@latest
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
New system employees default to OpenCode's **Free group**, a saved Wand-managed group (`wand-model-group/opencode/opencode-free`), not an implicit fallback. Every six hours the server refreshes the native catalog and actually tests every native zero-priced `opencode/*` candidate (including models without a `-free` suffix), adds new usable models and removes retired, paid or failed models while preserving saved priority. Membership is server-owned; clients may reorder it. A one-time default migration prepends this group while retaining existing candidates; later manual edits are not overwritten on restart. If all four slots are already occupied, no candidate is discarded: the server asks for a free slot instead. If the CLI is missing, the server installs `opencode-ai` under the configuration directory's `tools/opencode/`, without sudo or changing global npm packages. Free system text calls use a separate anonymous profile under `tools/opencode-system/` (no user credentials, project configuration or authorized tools), and check native pricing before execution. An empty/unavailable group never selects a paid default. Original provider errors are shown in the system call log with credentials redacted. Local decision roles and ordinary interactive sessions do not acquire an implicit cloud fallback.
|
|
187
|
+
|
|
188
|
+
Set `WAND_DISABLE_OPENCODE_FALLBACK=1` on the server to disable automatic preparation and the free-group execution service. Free upstream models can be rate-limited, retired, or have different data-retention/training policies; system text sent to this fallback is processed by that provider. See [OpenCode model policies](https://opencode.ai/docs/zen).
|
|
189
|
+
|
|
190
|
+
Employee onboarding is available in the Web console: **Settings menu → 员工与通讯录 → 管理员工与团队模板 → 员工 → 招聘员工**. Use manual configuration or review HR's draft before confirming onboarding. See the [employee onboarding guide](docs/employee-onboarding.md); `employee:list` only lists definitions, it does not create employees.
|
|
187
191
|
|
|
188
192
|
## 中文
|
|
189
193
|
|
|
@@ -226,7 +230,13 @@ npm uninstall -g opencode
|
|
|
226
230
|
npm install -g opencode-ai@latest
|
|
227
231
|
```
|
|
228
232
|
|
|
229
|
-
|
|
233
|
+
新系统员工默认使用 OpenCode 的「免费分组」(`wand-model-group/opencode/opencode-free`),这是 Wand 保存并维护的真实分组,不是隐式追加的兜底。服务端每 6 小时刷新原生目录并实际验证全部原生零价格 `opencode/*` 候选(包括不带 `-free` 后缀的模型),加入新可用模型、移除下架/收费/验证失败模型,保留已有优先顺序;客户端只能排序,不能塞入未经验证的成员。首次迁移会把该组放在首位、原候选保留为后备;之后手动调整不被重启覆盖。若原有4格已满则不丢弃任何候选,服务日志提示先腾出一格。缺少 CLI 时自动安装到配置目录下的 `tools/opencode/`,不用 sudo、不覆盖全局 npm 包;系统文本调用使用 `tools/opencode-system/` 的匿名独立环境,不加载用户凭据、项目配置或授权工具,执行前仍检查原生价格。空组或不可用时明确失败,不改用付费默认模型。系统调用日志提供凭据脱敏后的上游原始错误;普通交互会话、显式本地决策不会隐式增加云端候选。
|
|
234
|
+
|
|
235
|
+
服务环境设置 `WAND_DISABLE_OPENCODE_FALLBACK=1` 可关闭自动准备和免费分组执行服务。免费上游可能限流、退役,数据保留/训练政策也各不相同;使用兜底时系统文本会发往对应提供商,详见 [OpenCode 模型政策](https://opencode.ai/docs/zen)。
|
|
236
|
+
|
|
237
|
+
### 创建硅基员工
|
|
238
|
+
|
|
239
|
+
正式入口:**左侧设置菜单 → 员工与通讯录 → 管理员工与团队模板 → 员工 → 招聘员工**。可手动填写资料,或请 HR 嘟嘟拟定后核对并确认入职;起草不会自动创建员工。详见[招聘与入职指南](docs/employee-onboarding.md)。CLI `employee:list` 仅查询定义,创建请使用控制台,无需绕过界面调用内部接口。
|
|
230
240
|
|
|
231
241
|
### 功能
|
|
232
242
|
|
package/dist/ai-text-runner.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type EmployeeTextDeps } from "./employee-text.js";
|
|
2
|
-
import { type AiCallTraceFactory, type SystemAiPurpose } from "./system-ai-call.js";
|
|
2
|
+
import { type AiCallTrace, type AiCallTraceFactory, type SystemAiPurpose } from "./system-ai-call.js";
|
|
3
|
+
import type { OpenCodeTextRuntime, OpenCodeFreePool } from "./opencode-system-fallback.js";
|
|
3
4
|
import type { AiTextRequest, SessionProvider, SessionSnapshot } from "./types.js";
|
|
4
5
|
export { QuickCommitError } from "./command-error.js";
|
|
5
|
-
/** Neutral one-shot text execution. Tool-running Git fallback
|
|
6
|
+
/** Neutral one-shot text execution. Tool-running Git fallback uses the same employee chain. */
|
|
6
7
|
export declare function defaultProvider(provider: SessionProvider | undefined): SessionProvider;
|
|
7
8
|
export interface QuickCommitAiOptions {
|
|
8
9
|
modelGroups?: import("./model-groups.js").ModelGroup[];
|
|
@@ -18,6 +19,10 @@ export interface QuickCommitAiOptions {
|
|
|
18
19
|
employeeText?: EmployeeTextDeps;
|
|
19
20
|
/** 系统应用必须经员工渠道;没有可用候选时直接失败,不退回默认 provider。 */
|
|
20
21
|
employeeChannelOnly?: boolean;
|
|
22
|
+
/** Server-owned proof/runtime for the saved OpenCode free group. */
|
|
23
|
+
opencodeFree?: OpenCodeFreePool;
|
|
24
|
+
/** Internal anonymous runtime for the final OpenCode-only stage. Never a client DTO. */
|
|
25
|
+
opencodeRuntime?: OpenCodeTextRuntime;
|
|
21
26
|
/** 整条候选链的时间上限;默认 CLI_CHAIN_BUDGET_MS。第一条消息里的调用要短得多。 */
|
|
22
27
|
budgetMs?: number;
|
|
23
28
|
signal?: AbortSignal;
|
|
@@ -48,6 +53,13 @@ export declare function runCliText(command: string, args: string[], prompt: stri
|
|
|
48
53
|
export declare function callCliAiText(request: AiTextRequest, cwd: string, language: string, opts: CliAiTextOptions): Promise<string>;
|
|
49
54
|
/** 角色设定走系统提示前缀;任务自己的输出格式与约束必须排在后面。 */
|
|
50
55
|
export declare function withOpsPersona(request: AiTextRequest, persona?: string): AiTextRequest;
|
|
56
|
+
export interface ExpandedAiCandidates {
|
|
57
|
+
chain: import("./types.js").AiCliCandidate[];
|
|
58
|
+
freeLeaves: Set<import("./types.js").AiCliCandidate>;
|
|
59
|
+
deadline: number;
|
|
60
|
+
}
|
|
61
|
+
/** Expand the system employee's chain once: groups, free leaves, and duplicates. */
|
|
62
|
+
export declare function expandEmployeeCandidates(opts: QuickCommitAiOptions, trace?: AiCallTrace): Promise<ExpandedAiCandidates>;
|
|
51
63
|
/**
|
|
52
64
|
* Run a lightweight AI request through the system employee's configured chain.
|
|
53
65
|
* provider 与引擎由候选决定;SDK 与 CLI 均保留各自适配和身份。
|
package/dist/ai-text-runner.js
CHANGED
|
@@ -11,11 +11,12 @@ import { buildLanguageDirective } from "./language-prompt.js";
|
|
|
11
11
|
import { candidateInstalled, isSessionProvider } from "./session-provider.js";
|
|
12
12
|
import { asRecord } from "./structured-content.js";
|
|
13
13
|
import { AiCallTraceError } from "./system-ai-call.js";
|
|
14
|
+
import { OPENCODE_FREE_GROUP_SELECTOR } from "./opencode-free-selection.js";
|
|
14
15
|
import { composeSystemFallback, systemPromptFlag, thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToGrokEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToPiLevel, thinkingEffortToQoderEffort } from "./structured-provider-common.js";
|
|
15
16
|
export { QuickCommitError } from "./command-error.js";
|
|
16
17
|
const CLAUDE_MESSAGE_TIMEOUT_MS = 60_000;
|
|
17
18
|
const CODEX_MESSAGE_TIMEOUT_MS = 60_000;
|
|
18
|
-
/** Neutral one-shot text execution. Tool-running Git fallback
|
|
19
|
+
/** Neutral one-shot text execution. Tool-running Git fallback uses the same employee chain. */
|
|
19
20
|
export function defaultProvider(provider) {
|
|
20
21
|
return isSessionProvider(provider) ? provider : "claude";
|
|
21
22
|
}
|
|
@@ -154,11 +155,16 @@ function extractOpenCodeText(stdout) {
|
|
|
154
155
|
continue;
|
|
155
156
|
try {
|
|
156
157
|
const parsed = JSON.parse(trimmed);
|
|
158
|
+
if (parsed.type === "tool_use") {
|
|
159
|
+
throw new QuickCommitError("OpenCode 纯文本调用尝试使用工具,结果未采用。", "CLAUDE_CLI_FAILED");
|
|
160
|
+
}
|
|
157
161
|
if (parsed.type === "text" && typeof parsed.part?.text === "string" && parsed.part.text.trim()) {
|
|
158
162
|
texts.push(parsed.part.text.trim());
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
|
-
catch {
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof QuickCommitError)
|
|
167
|
+
throw error;
|
|
162
168
|
// ignore diagnostics mixed into stdout
|
|
163
169
|
}
|
|
164
170
|
}
|
|
@@ -421,18 +427,26 @@ async function callOpenCodeText(request, cwd, opts) {
|
|
|
421
427
|
if (variant)
|
|
422
428
|
args.push("--variant", variant);
|
|
423
429
|
const stdout = await runCliText("opencode", args, contentWithSystemPrompt("opencode", request), {
|
|
424
|
-
cwd,
|
|
430
|
+
cwd: opts.opencodeRuntime?.cwd ?? cwd,
|
|
425
431
|
timeoutMs: cliTextTimeoutMs(CODEX_MESSAGE_TIMEOUT_MS, opts),
|
|
426
432
|
inheritEnv: opts.inheritEnv, signal: opts.signal,
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
|
|
433
|
+
// Keep the native tool schemas: Zen rejects tool-less free-tier requests.
|
|
434
|
+
// Scalar ask replaces inherited allow rules; non-interactive `run` WITHOUT
|
|
435
|
+
// --auto/--yolo rejects every permission request, so no tool is authorized.
|
|
436
|
+
// Tool attempts also invalidate the text result. Do not loosen this to allow.
|
|
437
|
+
// Disable the CLI's unrelated title call (which can use a paid default model).
|
|
438
|
+
env: inherited => {
|
|
439
|
+
const base = opts.opencodeRuntime ? opts.opencodeRuntime.env(inherited) : inherited;
|
|
430
440
|
const configured = base.OPENCODE_CONFIG_CONTENT ? JSON.parse(base.OPENCODE_CONFIG_CONTENT) : {};
|
|
431
441
|
if (!configured || typeof configured !== "object" || Array.isArray(configured))
|
|
432
442
|
throw new Error("OpenCode 内联配置无效。");
|
|
433
|
-
return { ...base, OPENCODE_PERMISSION: JSON.stringify("
|
|
434
|
-
...configured, permission: "
|
|
435
|
-
agent: {
|
|
443
|
+
return { ...base, OPENCODE_PERMISSION: JSON.stringify("ask"), OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
444
|
+
...configured, permission: "ask", autoupdate: false, share: "disabled",
|
|
445
|
+
agent: {
|
|
446
|
+
...configured.agent,
|
|
447
|
+
title: { ...configured.agent?.title, disable: true },
|
|
448
|
+
[agent]: { mode: "primary", permission: "ask", prompt: "Return only the requested text. Do not use tools." },
|
|
449
|
+
},
|
|
436
450
|
}) };
|
|
437
451
|
},
|
|
438
452
|
});
|
|
@@ -517,20 +531,42 @@ function singleCandidate(opts) {
|
|
|
517
531
|
thinkingEffort: opts.thinkingEffort ?? undefined,
|
|
518
532
|
};
|
|
519
533
|
}
|
|
520
|
-
/**
|
|
521
|
-
|
|
522
|
-
* 只有一条候选时保持原行为(错误原样抛出,不摘要)。
|
|
523
|
-
* 仅用于一次性文本生成;执行工具的任务不能使用这条无条件重试路径。
|
|
524
|
-
*/
|
|
525
|
-
async function callTextCandidates(request, cwd, language, opts, parseOutput, trace) {
|
|
534
|
+
/** Expand the system employee's chain once: groups, free leaves, and duplicates. */
|
|
535
|
+
export async function expandEmployeeCandidates(opts, trace) {
|
|
526
536
|
opts.signal?.throwIfAborted();
|
|
527
537
|
const { resolveModelGroupModels } = await import("./model-groups.js");
|
|
528
538
|
const modelGroups = opts.modelGroups ?? opts.employeeText?.config.modelGroups;
|
|
529
539
|
const seen = new Set();
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
540
|
+
const deadline = Date.now() + Math.max(1, opts.budgetMs ?? CLI_CHAIN_BUDGET_MS);
|
|
541
|
+
const sources = opts.cliCandidates?.length ? opts.cliCandidates : [singleCandidate(opts)];
|
|
542
|
+
const freeLeaves = new Set();
|
|
543
|
+
const expanded = [];
|
|
544
|
+
for (const candidate of sources) {
|
|
545
|
+
if (candidate.provider === "opencode" && candidate.model === OPENCODE_FREE_GROUP_SELECTOR) {
|
|
546
|
+
if (!opts.opencodeFree) {
|
|
547
|
+
trace?.candidateSkipped(candidate, "OpenCode 免费分组执行服务尚未就绪。");
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
const signal = AbortSignal.any([...(opts.signal ? [opts.signal] : []), AbortSignal.timeout(Math.max(1, deadline - Date.now()))]);
|
|
551
|
+
try {
|
|
552
|
+
const members = await abortableEmployeeText(opts.opencodeFree.candidates(signal), signal);
|
|
553
|
+
for (const member of members) {
|
|
554
|
+
const leaf = { ...candidate, ...member, thinkingEffort: "off" };
|
|
555
|
+
expanded.push(leaf);
|
|
556
|
+
freeLeaves.add(leaf);
|
|
557
|
+
}
|
|
558
|
+
if (!members.length)
|
|
559
|
+
trace?.candidateSkipped(candidate, "当前没有实测可用且仍免费的 OpenCode 模型。");
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
trace?.candidateFailed(candidate, error, "availability");
|
|
563
|
+
opts.signal?.throwIfAborted();
|
|
564
|
+
}
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
expanded.push(...resolveModelGroupModels(modelGroups, candidate.provider, candidate.model, { preferDefault: !candidate.model || candidate.model === "default" }).map(model => ({ ...candidate, model: model || undefined })));
|
|
568
|
+
}
|
|
569
|
+
const chain = expanded.filter(candidate => {
|
|
534
570
|
const key = JSON.stringify([candidate.provider, candidate.engine ?? "cli", candidate.model ?? "", candidate.thinkingEffort ?? opts.thinkingEffort]);
|
|
535
571
|
if (seen.has(key))
|
|
536
572
|
return false;
|
|
@@ -540,10 +576,24 @@ async function callTextCandidates(request, cwd, language, opts, parseOutput, tra
|
|
|
540
576
|
if (opts.employeeChannelOnly && !opts.cliCandidates?.length) {
|
|
541
577
|
throw new QuickCommitError("系统员工没有可用的执行候选。", "AI_FALLBACK_FAILED");
|
|
542
578
|
}
|
|
543
|
-
|
|
579
|
+
if (!chain.length)
|
|
580
|
+
throw new QuickCommitError("系统员工没有可用的执行候选;免费分组为空或尚未同步。", "AI_FALLBACK_FAILED");
|
|
581
|
+
return { chain, freeLeaves, deadline };
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* 按顺序尝试候选:跳过没安装的 CLI,协议与输出校验均成功才返回。
|
|
585
|
+
* 只有一条候选时保持原行为(错误原样抛出,不摘要)。
|
|
586
|
+
* 文本生成可以无条件换下一条;有副作用的执行要先确认没有产生结果再换。
|
|
587
|
+
*/
|
|
588
|
+
async function callTextCandidates(request, cwd, language, opts, parseOutput, trace) {
|
|
589
|
+
const modelGroups = opts.modelGroups ?? opts.employeeText?.config.modelGroups;
|
|
590
|
+
const { chain, freeLeaves, deadline } = await expandEmployeeCandidates(opts, trace);
|
|
544
591
|
const call = async (candidate) => {
|
|
592
|
+
const free = freeLeaves.has(candidate);
|
|
593
|
+
const candidateDeadline = free ? Math.min(deadline, Date.now() + 20_000) : deadline;
|
|
545
594
|
if (candidate.engine !== "sdk")
|
|
546
|
-
return callCliAiText(request, cwd, language, { ...candidateOptions(opts, candidate),
|
|
595
|
+
return callCliAiText(request, cwd, language, { ...candidateOptions(opts, candidate),
|
|
596
|
+
...(free ? { opencodeRuntime: opts.opencodeFree.execution } : {}), deadline: candidateDeadline });
|
|
547
597
|
const controller = new AbortController();
|
|
548
598
|
const timer = setTimeout(() => controller.abort(new QuickCommitError("Wand Agent 调用超时。", "CLAUDE_TIMEOUT")), Math.max(1, deadline - Date.now()));
|
|
549
599
|
const signal = opts.signal ? AbortSignal.any([opts.signal, controller.signal]) : controller.signal;
|
package/dist/auth.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export declare class AuthService {
|
|
|
27
27
|
private readonly sessions;
|
|
28
28
|
private readonly cleanupTimer;
|
|
29
29
|
private disposed;
|
|
30
|
+
private readonly revokeAllListeners;
|
|
31
|
+
onRevokeAll(listener: () => void): void;
|
|
30
32
|
constructor(storage: WandStorage, sessionTtlMs?: number, cleanupIntervalMs?: number);
|
|
31
33
|
createSession(principal?: AuthPrincipal): string;
|
|
32
34
|
authenticateSession(token: string | undefined): AuthPrincipal | null;
|
package/dist/auth.js
CHANGED
|
@@ -45,6 +45,8 @@ export class AuthService {
|
|
|
45
45
|
sessions = new Map();
|
|
46
46
|
cleanupTimer;
|
|
47
47
|
disposed = false;
|
|
48
|
+
revokeAllListeners = new Set();
|
|
49
|
+
onRevokeAll(listener) { this.revokeAllListeners.add(listener); }
|
|
48
50
|
constructor(storage, sessionTtlMs = SESSION_TTL_MS, cleanupIntervalMs = 1000 * 60 * 10) {
|
|
49
51
|
this.storage = storage;
|
|
50
52
|
this.sessionTtlMs = sessionTtlMs;
|
|
@@ -58,6 +60,7 @@ export class AuthService {
|
|
|
58
60
|
const expiresAt = Date.now() + this.sessionTtlMs;
|
|
59
61
|
const cached = { expiresAt, principal: clonePrincipal(principal) };
|
|
60
62
|
this.sessions.set(token, cached);
|
|
63
|
+
// 所有登录态(含票据登录)持久化,和密码登录一样跨服务重启有效。
|
|
61
64
|
this.storage.saveAuthSession(token, expiresAt, cached.principal);
|
|
62
65
|
return token;
|
|
63
66
|
}
|
|
@@ -79,6 +82,12 @@ export class AuthService {
|
|
|
79
82
|
}
|
|
80
83
|
return null;
|
|
81
84
|
}
|
|
85
|
+
// Retire cookies minted by the early ticket prototype. Native App sessions
|
|
86
|
+
// use the established multi-scope principal; a sessions-only connected-app
|
|
87
|
+
// cookie must never regain broad workbench access after upgrade.
|
|
88
|
+
if (cached.principal.kind === "connected-app" && cached.principal.scopes.length === 1
|
|
89
|
+
&& cached.principal.scopes[0] === "sessions")
|
|
90
|
+
return null;
|
|
82
91
|
return clonePrincipal(cached.principal);
|
|
83
92
|
}
|
|
84
93
|
validateSession(token) {
|
|
@@ -95,6 +104,8 @@ export class AuthService {
|
|
|
95
104
|
return;
|
|
96
105
|
this.sessions.clear();
|
|
97
106
|
this.storage.deleteAllAuthSessions();
|
|
107
|
+
for (const listener of this.revokeAllListeners)
|
|
108
|
+
listener();
|
|
98
109
|
}
|
|
99
110
|
dispose() {
|
|
100
111
|
if (this.disposed)
|
|
@@ -102,6 +113,9 @@ export class AuthService {
|
|
|
102
113
|
this.disposed = true;
|
|
103
114
|
clearInterval(this.cleanupTimer);
|
|
104
115
|
this.sessions.clear();
|
|
116
|
+
for (const listener of this.revokeAllListeners)
|
|
117
|
+
listener();
|
|
118
|
+
this.revokeAllListeners.clear();
|
|
105
119
|
}
|
|
106
120
|
cleanupExpiredSessions() {
|
|
107
121
|
if (this.disposed)
|
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-10-
|
|
4
|
-
"version": "4.
|
|
5
|
-
"channel": "
|
|
2
|
+
"commit": "a09542822526896c8dcc2c5af5862441fdb58282",
|
|
3
|
+
"builtAt": "2026-10-17T13:42:08.826Z",
|
|
4
|
+
"version": "4.97.0",
|
|
5
|
+
"channel": "stable"
|
|
6
6
|
}
|
package/dist/cli-api.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare class WandCliApi {
|
|
|
4
4
|
private cookie;
|
|
5
5
|
constructor(config: WandConfig);
|
|
6
6
|
get<T>(pathname: string): Promise<T>;
|
|
7
|
-
post<T>(pathname: string, body: unknown): Promise<T>;
|
|
7
|
+
post<T>(pathname: string, body: unknown, headers?: Record<string, string>): Promise<T>;
|
|
8
8
|
patch<T>(pathname: string, body: unknown): Promise<T>;
|
|
9
9
|
del<T>(pathname: string): Promise<T>;
|
|
10
10
|
private login;
|
package/dist/cli-api.js
CHANGED
|
@@ -9,8 +9,8 @@ export class WandCliApi {
|
|
|
9
9
|
async get(pathname) {
|
|
10
10
|
return this.request("GET", pathname);
|
|
11
11
|
}
|
|
12
|
-
async post(pathname, body) {
|
|
13
|
-
return this.request("POST", pathname, body);
|
|
12
|
+
async post(pathname, body, headers) {
|
|
13
|
+
return this.request("POST", pathname, body, headers);
|
|
14
14
|
}
|
|
15
15
|
async patch(pathname, body) {
|
|
16
16
|
return this.request("PATCH", pathname, body);
|
|
@@ -21,15 +21,15 @@ export class WandCliApi {
|
|
|
21
21
|
async login() {
|
|
22
22
|
const result = await this.rawRequest("POST", "/api/login", { password: this.config.password });
|
|
23
23
|
if (result.status < 200 || result.status >= 300)
|
|
24
|
-
throw new Error(`Wand 登录失败 (HTTP ${result.status})`);
|
|
24
|
+
throw Object.assign(new Error(`Wand 登录失败 (HTTP ${result.status})`), { status: result.status });
|
|
25
25
|
this.cookie = result.cookies.map((value) => value.split(";", 1)[0]).join("; ");
|
|
26
26
|
if (!this.cookie)
|
|
27
27
|
throw new Error("Wand 服务未返回登录会话。");
|
|
28
28
|
}
|
|
29
|
-
async request(method, pathname, body) {
|
|
29
|
+
async request(method, pathname, body, headers) {
|
|
30
30
|
if (!this.cookie)
|
|
31
31
|
await this.login();
|
|
32
|
-
const result = await this.rawRequest(method, pathname, body, this.cookie);
|
|
32
|
+
const result = await this.rawRequest(method, pathname, body, this.cookie, headers);
|
|
33
33
|
let parsed = {};
|
|
34
34
|
try {
|
|
35
35
|
parsed = result.body ? JSON.parse(result.body) : {};
|
|
@@ -41,11 +41,11 @@ export class WandCliApi {
|
|
|
41
41
|
? parsed.error
|
|
42
42
|
: null;
|
|
43
43
|
if (result.status < 200 || result.status >= 300 || error) {
|
|
44
|
-
throw new Error(`Wand 请求失败 (HTTP ${result.status})${error ? `:${error}` : ""}`);
|
|
44
|
+
throw Object.assign(new Error(`Wand 请求失败 (HTTP ${result.status})${error ? `:${error}` : ""}`), { status: result.status });
|
|
45
45
|
}
|
|
46
46
|
return parsed;
|
|
47
47
|
}
|
|
48
|
-
rawRequest(method, pathname, body, cookie) {
|
|
48
|
+
rawRequest(method, pathname, body, cookie, headers) {
|
|
49
49
|
return new Promise((resolve, reject) => {
|
|
50
50
|
const protocol = this.config.https ? "https:" : "http:";
|
|
51
51
|
const url = new URL(`${protocol}//127.0.0.1:${this.config.port}${pathname}`);
|
|
@@ -56,6 +56,7 @@ export class WandCliApi {
|
|
|
56
56
|
rejectUnauthorized: false,
|
|
57
57
|
timeout: 30_000,
|
|
58
58
|
headers: {
|
|
59
|
+
...headers,
|
|
59
60
|
Accept: "application/json",
|
|
60
61
|
...(payload ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload) } : {}),
|
|
61
62
|
...(cookie ? { Cookie: cookie } : {}),
|
package/dist/cli.js
CHANGED
|
@@ -197,6 +197,8 @@ async function main() {
|
|
|
197
197
|
}
|
|
198
198
|
break;
|
|
199
199
|
}
|
|
200
|
+
case "web-login:issue":
|
|
201
|
+
case "web-login:cancel":
|
|
200
202
|
case "employee:list":
|
|
201
203
|
case "workspace:list":
|
|
202
204
|
case "session:create":
|
|
@@ -205,6 +207,9 @@ async function main() {
|
|
|
205
207
|
case "schedule:read":
|
|
206
208
|
case "schedule:create":
|
|
207
209
|
case "schedule:update": {
|
|
210
|
+
if (command === "web-login:issue" && (process.stdout.isTTY || process.env.WAND_WEB_LOGIN_PIPE !== "1" || process.env.DEBUG || process.env.PWDEBUG || process.env.NODE_DEBUG)) {
|
|
211
|
+
throw new Error("票据只能通过 wand-system 的受控内存助手传递;禁止终端回显和调试录制。");
|
|
212
|
+
}
|
|
208
213
|
const { parseSystemCliCommand } = await import("./system-cli.js");
|
|
209
214
|
const operationArgs = args.slice(1);
|
|
210
215
|
for (const flag of ["-c", "--config"]) {
|
|
@@ -354,6 +359,8 @@ Agent runtime:
|
|
|
354
359
|
wand system:skills [--providers pi,claude,...] Install the managed wand-system skill
|
|
355
360
|
wand employee:list [--include-archived] List employee definitions (not private knowledge)
|
|
356
361
|
wand workspace:list List project directories
|
|
362
|
+
wand web-login:issue --stdin Mint a 60s, one-use Web admin ticket (employee execution proof + controlled pipe only)
|
|
363
|
+
wand web-login:cancel --stdin Cancel an unconsumed ticket by requestId
|
|
357
364
|
wand session:create --stdin Create an employee session from JSON
|
|
358
365
|
wand session:resume <id> --stdin Continue the exact structured session with JSON input
|
|
359
366
|
wand schedule:list [--include-cancelled]
|
|
@@ -1019,6 +1026,13 @@ function printServiceResult(result, verbose) {
|
|
|
1019
1026
|
}
|
|
1020
1027
|
}
|
|
1021
1028
|
main().catch((error) => {
|
|
1022
|
-
process.
|
|
1029
|
+
if (["web-login:issue", "web-login:cancel"].includes(process.argv[2] ?? "") && process.env.WAND_WEB_LOGIN_PIPE === "1" && !process.stdout.isTTY) {
|
|
1030
|
+
const status = typeof error?.status === "number" ? error.status : 0;
|
|
1031
|
+
const rejected = status >= 400 && status < 500 && ![408, 409].includes(status);
|
|
1032
|
+
// Only machine facts enter the pipe; never reflect a remote error, credential or stack.
|
|
1033
|
+
process.stdout.write(JSON.stringify({ error: { code: rejected ? "ISSUANCE_REJECTED" : "DELIVERY_UNKNOWN", status } }) + "\n");
|
|
1034
|
+
}
|
|
1035
|
+
else
|
|
1036
|
+
process.stderr.write(`[wand] ${getErrorMessage(error)}\n`);
|
|
1023
1037
|
process.exitCode = 1;
|
|
1024
1038
|
});
|
package/dist/config.js
CHANGED
|
@@ -201,8 +201,8 @@ export async function loadConfigWithStorage(configPath, storage) {
|
|
|
201
201
|
*/
|
|
202
202
|
export function bootstrapBuiltinEmployees(config, storage) {
|
|
203
203
|
// 内置「系统运维」员工负责 commit message / 标题 / 提示词优化;招聘由 HR 负责。
|
|
204
|
-
//
|
|
205
|
-
//
|
|
204
|
+
// 新系统员工默认用服务端维护的 OpenCode 免费分组;显式旧系统 AI 选择仍优先。
|
|
205
|
+
// 这里只幂等补齐;已有员工候选由用户维护,不在重启时改写。
|
|
206
206
|
storage.ensureSystemSiliconEmployee({
|
|
207
207
|
cli: config.systemAiCli,
|
|
208
208
|
model: config.systemAiModel,
|
package/dist/decision-skill.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
+
import { type ManagedSkillInstallResult } from "./managed-skill.js";
|
|
1
2
|
import { type SessionProvider } from "./provider-catalog.js";
|
|
2
|
-
export declare function installDecisionSkill(configDir: string, providers?: readonly SessionProvider[], home?: string): Promise<
|
|
3
|
-
installed: string[];
|
|
4
|
-
providers: readonly SessionProvider[];
|
|
5
|
-
}>;
|
|
3
|
+
export declare function installDecisionSkill(configDir: string, providers?: readonly SessionProvider[], home?: string): Promise<ManagedSkillInstallResult>;
|
|
@@ -3,4 +3,7 @@ import type { StructuredRunnerAdapter, StructuredRunnerContext, StructuredRunner
|
|
|
3
3
|
/** Strong-prefix requests are an explicit, local data operation, not an extra model invocation. */
|
|
4
4
|
export declare function rememberExplicitEmployeeRequest(storage: WandStorage, employeeId: string | undefined, prompt: string): string | null;
|
|
5
5
|
/** Central runner boundary shared by all CLI providers; credentials live only in the child env. */
|
|
6
|
-
export declare function startEmployeeKnowledgeRunner(storage: WandStorage, runner: StructuredRunnerAdapter, context: StructuredRunnerContext, observer: StructuredRunnerObserver
|
|
6
|
+
export declare function startEmployeeKnowledgeRunner(storage: WandStorage, runner: StructuredRunnerAdapter, context: StructuredRunnerContext, observer: StructuredRunnerObserver, webLoginGrant?: (sessionId: string, employeeId: string) => {
|
|
7
|
+
proof: string;
|
|
8
|
+
revoke(): void;
|
|
9
|
+
}): StructuredRunnerExecution;
|
|
@@ -48,13 +48,14 @@ export function rememberExplicitEmployeeRequest(storage, employeeId, prompt) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
/** Central runner boundary shared by all CLI providers; credentials live only in the child env. */
|
|
51
|
-
export function startEmployeeKnowledgeRunner(storage, runner, context, observer) {
|
|
51
|
+
export function startEmployeeKnowledgeRunner(storage, runner, context, observer, webLoginGrant) {
|
|
52
52
|
const employeeId = context.session.employeeId;
|
|
53
53
|
// Strip any inherited credentials from the parent environment (including nested Wand runs).
|
|
54
54
|
// Non-secret identity, overwritten for nested executions; never infer a current session by title/time.
|
|
55
55
|
const env = { ...context.env, WAND_SESSION_ID: context.session.id };
|
|
56
56
|
delete env.WAND_KNOWLEDGE_DB;
|
|
57
57
|
delete env.WAND_KNOWLEDGE_TOKEN;
|
|
58
|
+
delete env.WAND_WEB_LOGIN_PROOF;
|
|
58
59
|
if (!employeeId)
|
|
59
60
|
return runner.start({ ...context, env }, observer);
|
|
60
61
|
if (!storage.getSiliconEmployee(employeeId)) {
|
|
@@ -63,20 +64,30 @@ export function startEmployeeKnowledgeRunner(storage, runner, context, observer)
|
|
|
63
64
|
} }, observer);
|
|
64
65
|
}
|
|
65
66
|
const token = storage.issueEmployeeKnowledgeAccess(context.session.id, employeeId);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
let loginGrant;
|
|
68
|
+
const cleanup = () => {
|
|
69
|
+
loginGrant?.revoke();
|
|
70
|
+
try {
|
|
71
|
+
storage.revokeEmployeeKnowledgeAccess(token);
|
|
72
|
+
}
|
|
73
|
+
catch { /* storage may be closing */ }
|
|
74
|
+
};
|
|
70
75
|
try {
|
|
76
|
+
// Optional Web login must not prevent an otherwise valid employee execution.
|
|
77
|
+
try {
|
|
78
|
+
loginGrant = webLoginGrant?.(context.session.id, employeeId);
|
|
79
|
+
}
|
|
80
|
+
catch { /* CLI reports unavailable when explicitly used. */ }
|
|
71
81
|
const receipt = (!context.session.automationId || context.session.automationId.startsWith("wand-task:"))
|
|
72
82
|
? rememberExplicitEmployeeRequest(storage, employeeId, context.prompt) : null;
|
|
73
83
|
const runtimeSystemPrompt = [context.session.runtimeSystemPrompt, `当前 Wand 会话 ID:${context.session.id}(非凭据;创建后续检查计划时用作精确续接目标)。`, receipt, knowledgeContext(storage, employeeId, context.prompt)]
|
|
74
84
|
.filter(Boolean).join("\n\n");
|
|
75
85
|
const execution = runner.start({ ...context,
|
|
76
86
|
session: { ...context.session, runtimeSystemPrompt },
|
|
77
|
-
env: { ...env, WAND_KNOWLEDGE_DB: storage.databasePath(), WAND_KNOWLEDGE_TOKEN: token
|
|
87
|
+
env: { ...env, WAND_KNOWLEDGE_DB: storage.databasePath(), WAND_KNOWLEDGE_TOKEN: token,
|
|
88
|
+
...(loginGrant ? { WAND_WEB_LOGIN_PROOF: loginGrant.proof } : {}) },
|
|
78
89
|
}, observer);
|
|
79
|
-
return { ...execution, completion: execution.completion.finally(cleanup), interrupt: () => execution.interrupt() };
|
|
90
|
+
return { ...execution, completion: execution.completion.finally(cleanup), interrupt: () => { loginGrant?.revoke(); execution.interrupt(); } };
|
|
80
91
|
}
|
|
81
92
|
catch (error) {
|
|
82
93
|
cleanup();
|
package/dist/employee-text.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare function employeeTextCandidates(agents: readonly WandTaskAgent[],
|
|
|
23
23
|
export declare function abortableEmployeeText<T>(pending: Promise<T>, signal: AbortSignal): Promise<T>;
|
|
24
24
|
export declare class EmployeeCandidateRejected extends Error {
|
|
25
25
|
readonly failure: StructuredFailure;
|
|
26
|
-
constructor(failure: StructuredFailure);
|
|
26
|
+
constructor(failure: StructuredFailure, message?: string);
|
|
27
27
|
}
|
|
28
28
|
/** Prepare a configured, no-tool adapter before any user input is accepted. */
|
|
29
29
|
export declare function prepareEmployeeTextCandidate(deps: EmployeeTextDeps, agent: WandTaskAgent, request: AiTextRequest, signal: AbortSignal): Promise<() => Promise<string>>;
|
package/dist/employee-text.js
CHANGED
|
@@ -47,8 +47,8 @@ export async function abortableEmployeeText(pending, signal) {
|
|
|
47
47
|
}
|
|
48
48
|
export class EmployeeCandidateRejected extends Error {
|
|
49
49
|
failure;
|
|
50
|
-
constructor(failure) {
|
|
51
|
-
super(
|
|
50
|
+
constructor(failure, message = "SDK 候选在执行前被拒绝。") {
|
|
51
|
+
super(message);
|
|
52
52
|
this.failure = failure;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -62,8 +62,8 @@ function sdkText(message, status) {
|
|
|
62
62
|
signal: null, stderr: "", primaryError: "SDK 文字生成失败。", rejection,
|
|
63
63
|
inputAccepted: rejection && !progressed ? false : undefined }, { progress: progressed });
|
|
64
64
|
if (failure?.retryable)
|
|
65
|
-
throw new EmployeeCandidateRejected(failure);
|
|
66
|
-
throw new Error("SDK文字生成失败。");
|
|
65
|
+
throw new EmployeeCandidateRejected(failure, message.errorMessage || "SDK 候选在执行前被拒绝。");
|
|
66
|
+
throw new Error(message.errorMessage || "SDK文字生成失败。");
|
|
67
67
|
}
|
|
68
68
|
if (message.stopReason === "aborted" || message.content.some(part => part.type === "toolCall"))
|
|
69
69
|
throw new Error("SDK文字生成失败。");
|
package/dist/env-utils.js
CHANGED
|
@@ -73,7 +73,7 @@ export function buildChildEnv(inheritEnv, extras = {}) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
// Do not let nested Wand/PTY or one-shot automation inherit another run's decision capability.
|
|
76
|
-
for (const key of ["WAND_DECISION_URL", "WAND_DECISION_TOKEN", "WAND_DECISION_CA", "WAND_DECISION_NODE", "WAND_DECISION_CLI"])
|
|
76
|
+
for (const key of ["WAND_DECISION_URL", "WAND_DECISION_TOKEN", "WAND_DECISION_CA", "WAND_DECISION_NODE", "WAND_DECISION_CLI", "WAND_WEB_LOGIN_PROOF"])
|
|
77
77
|
delete base[key];
|
|
78
78
|
for (const [k, v] of Object.entries(extras)) {
|
|
79
79
|
if (typeof v === "string")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { FeedbackFeature } from "./feedback.js";
|
|
2
|
+
/** Canonical route-family ownership. Native clients mirror these explicit entries, not error text. */
|
|
3
|
+
export declare const FEEDBACK_API_FEATURES: {
|
|
4
|
+
readonly sessions: "sessions";
|
|
5
|
+
readonly "structured-sessions": "sessions";
|
|
6
|
+
readonly commands: "sessions";
|
|
7
|
+
readonly "session-list": "sessions";
|
|
8
|
+
readonly "session-directories": "sessions";
|
|
9
|
+
readonly conversations: "conversations";
|
|
10
|
+
readonly "wand-tasks": "tasks";
|
|
11
|
+
readonly "wand-task-agent-defaults": "tasks";
|
|
12
|
+
readonly tasks: "tasks";
|
|
13
|
+
readonly "workspace-tasks": "tasks";
|
|
14
|
+
readonly workspaces: "tasks";
|
|
15
|
+
readonly "wand-milestones": "tasks";
|
|
16
|
+
readonly missions: "tasks";
|
|
17
|
+
readonly "scheduled-tasks": "tasks";
|
|
18
|
+
readonly files: "files";
|
|
19
|
+
readonly upload: "files";
|
|
20
|
+
readonly directory: "files";
|
|
21
|
+
readonly "session-files": "files";
|
|
22
|
+
readonly "file-preview": "files";
|
|
23
|
+
readonly "file-read": "files";
|
|
24
|
+
readonly "file-write": "files";
|
|
25
|
+
readonly "recent-paths": "files";
|
|
26
|
+
readonly speech: "speech";
|
|
27
|
+
readonly settings: "settings";
|
|
28
|
+
readonly config: "settings";
|
|
29
|
+
readonly "user-profile": "settings";
|
|
30
|
+
readonly "auto-update": "settings";
|
|
31
|
+
readonly "update-channel": "settings";
|
|
32
|
+
readonly models: "models";
|
|
33
|
+
readonly "model-groups": "models";
|
|
34
|
+
readonly "local-models": "models";
|
|
35
|
+
readonly login: "authentication";
|
|
36
|
+
readonly logout: "authentication";
|
|
37
|
+
readonly "app-login": "authentication";
|
|
38
|
+
readonly "session-check": "authentication";
|
|
39
|
+
readonly "set-password": "authentication";
|
|
40
|
+
readonly update: "server_update";
|
|
41
|
+
readonly "update-status": "server_update";
|
|
42
|
+
readonly "check-update": "server_update";
|
|
43
|
+
readonly "android-apk-update": "app_update";
|
|
44
|
+
readonly "android-apk": "app_update";
|
|
45
|
+
readonly "macos-app-update": "app_update";
|
|
46
|
+
readonly "macos-dmg-update": "app_update";
|
|
47
|
+
readonly "macos-dmg": "app_update";
|
|
48
|
+
readonly "ios-ipa-update": "app_update";
|
|
49
|
+
readonly "ios-ipa": "app_update";
|
|
50
|
+
readonly "provider-cli-updates": "provider_update";
|
|
51
|
+
readonly "daemon-maintenance": "daemon_update";
|
|
52
|
+
readonly "storage-cleanup": "storage";
|
|
53
|
+
readonly git: "repository";
|
|
54
|
+
readonly github: "repository";
|
|
55
|
+
};
|
|
56
|
+
export declare function feedbackFeatureForApiPath(pathname: string): FeedbackFeature;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Canonical route-family ownership. Native clients mirror these explicit entries, not error text. */
|
|
2
|
+
export const FEEDBACK_API_FEATURES = {
|
|
3
|
+
sessions: "sessions", "structured-sessions": "sessions", commands: "sessions", "session-list": "sessions", "session-directories": "sessions",
|
|
4
|
+
conversations: "conversations",
|
|
5
|
+
"wand-tasks": "tasks", "wand-task-agent-defaults": "tasks", tasks: "tasks", "workspace-tasks": "tasks", workspaces: "tasks", "wand-milestones": "tasks", missions: "tasks", "scheduled-tasks": "tasks",
|
|
6
|
+
files: "files", upload: "files", directory: "files", "session-files": "files", "file-preview": "files", "file-read": "files", "file-write": "files", "recent-paths": "files",
|
|
7
|
+
speech: "speech",
|
|
8
|
+
settings: "settings", config: "settings", "user-profile": "settings", "auto-update": "settings", "update-channel": "settings",
|
|
9
|
+
models: "models", "model-groups": "models", "local-models": "models",
|
|
10
|
+
login: "authentication", logout: "authentication", "app-login": "authentication", "session-check": "authentication", "set-password": "authentication",
|
|
11
|
+
update: "server_update", "update-status": "server_update", "check-update": "server_update",
|
|
12
|
+
"android-apk-update": "app_update", "android-apk": "app_update", "macos-app-update": "app_update", "macos-dmg-update": "app_update", "macos-dmg": "app_update", "ios-ipa-update": "app_update", "ios-ipa": "app_update",
|
|
13
|
+
"provider-cli-updates": "provider_update", "daemon-maintenance": "daemon_update", "storage-cleanup": "storage",
|
|
14
|
+
git: "repository", github: "repository",
|
|
15
|
+
};
|
|
16
|
+
export function feedbackFeatureForApiPath(pathname) {
|
|
17
|
+
const family = pathname.split("?")[0].split("/")[2] ?? "";
|
|
18
|
+
return Object.prototype.hasOwnProperty.call(FEEDBACK_API_FEATURES, family)
|
|
19
|
+
? FEEDBACK_API_FEATURES[family] : "api";
|
|
20
|
+
}
|