@co0ontty/wand 4.93.0 → 4.94.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 +25 -30
- package/dist/ai-text-runner.d.ts +2 -10
- package/dist/ai-text-runner.js +13 -74
- package/dist/build-info.json +3 -3
- package/dist/cli.js +47 -9
- package/dist/config.d.ts +2 -3
- package/dist/config.js +26 -5
- package/dist/core-status-cli.d.ts +1 -1
- package/dist/core-status-cli.js +3 -1
- package/dist/daemon-connection.d.ts +10 -0
- package/dist/daemon-connection.js +28 -0
- package/dist/diagnostic-logs.d.ts +10 -0
- package/dist/diagnostic-logs.js +121 -0
- package/dist/employee-text.js +1 -3
- package/dist/git-quick-commit.d.ts +1 -1
- package/dist/git-quick-commit.js +2 -9
- package/dist/layout-tree.d.ts +3 -1
- package/dist/layout-tree.js +8 -0
- package/dist/local-model-process.js +20 -0
- package/dist/local-model-setup.js +5 -3
- package/dist/managed-temp.d.ts +32 -0
- package/dist/managed-temp.js +176 -0
- package/dist/middleware/api-scope.js +1 -0
- package/dist/models/shared.d.ts +0 -6
- package/dist/models/shared.js +0 -12
- package/dist/models/thinking.d.ts +0 -2
- package/dist/models/thinking.js +0 -2
- package/dist/models.d.ts +0 -1
- package/dist/models.js +3 -11
- package/dist/native-session-title.d.ts +1 -1
- package/dist/native-session-title.js +1 -1
- package/dist/pi-model-discovery.js +5 -17
- package/dist/pi-resource-recommendation.d.ts +1 -1
- package/dist/pi-resource-recommendation.js +129 -42
- package/dist/process-manager-native-history.js +1 -6
- package/dist/process-manager.d.ts +0 -1
- package/dist/process-manager.js +5 -18
- package/dist/provider-catalog.d.ts +1 -2
- package/dist/provider-catalog.js +1 -6
- package/dist/provider-cli-updater.js +1 -9
- package/dist/provider-history-scanner.d.ts +0 -3
- package/dist/provider-history-scanner.js +0 -26
- package/dist/render-daemon-client.js +6 -29
- package/dist/render-structured-client.js +2 -7
- package/dist/retention.js +1 -6
- package/dist/run-command.d.ts +5 -0
- package/dist/run-command.js +14 -1
- package/dist/server-session-lifecycle-routes.js +1 -1
- package/dist/server-storage-cleanup-routes.d.ts +3 -0
- package/dist/server-storage-cleanup-routes.js +19 -0
- package/dist/server-workspace-routes.d.ts +4 -1
- package/dist/server-workspace-routes.js +75 -9
- package/dist/server.js +21 -16
- package/dist/service-command-privilege.d.ts +17 -0
- package/dist/service-command-privilege.js +55 -0
- package/dist/service-manager/index.d.ts +3 -0
- package/dist/service-manager/index.js +3 -0
- package/dist/service-manager/launchd.d.ts +1 -0
- package/dist/service-manager/launchd.js +15 -0
- package/dist/service-manager/systemd.d.ts +1 -0
- package/dist/service-manager/systemd.js +11 -0
- package/dist/session-ai-context.js +17 -6
- package/dist/session-completion-state.d.ts +2 -0
- package/dist/session-completion-state.js +6 -2
- package/dist/session-logger.js +7 -1
- package/dist/session-model.d.ts +4 -0
- package/dist/session-model.js +13 -4
- package/dist/session-registry.d.ts +1 -1
- package/dist/session-registry.js +0 -3
- package/dist/silicon-employee-draft.js +0 -1
- package/dist/speech-service.js +18 -8
- package/dist/storage/mappers.js +6 -10
- package/dist/storage/migrations.js +14 -0
- package/dist/storage/uploads-repository.d.ts +36 -0
- package/dist/storage/uploads-repository.js +98 -0
- package/dist/storage-cleanup.d.ts +50 -0
- package/dist/storage-cleanup.js +344 -0
- package/dist/storage.d.ts +3 -1
- package/dist/storage.js +4 -0
- package/dist/structured-failure.d.ts +2 -0
- package/dist/structured-failure.js +9 -0
- package/dist/structured-grok-adapter.js +4 -4
- package/dist/structured-opencode-adapter.js +4 -9
- package/dist/structured-provider-common.d.ts +1 -2
- package/dist/structured-provider-common.js +3 -6
- package/dist/structured-session-manager-replay.js +2 -6
- package/dist/structured-session-manager.d.ts +1 -2
- package/dist/structured-session-manager.js +32 -25
- package/dist/task-organize-contract.d.ts +41 -0
- package/dist/task-organize-contract.js +4 -0
- package/dist/task-title-organize-service.d.ts +21 -0
- package/dist/task-title-organize-service.js +168 -0
- package/dist/task-title-organize.d.ts +77 -0
- package/dist/task-title-organize.js +346 -0
- package/dist/terminal-daemon-client.js +10 -48
- package/dist/time-utils.d.ts +2 -0
- package/dist/time-utils.js +7 -0
- package/dist/tui/attach.js +6 -5
- package/dist/tui/commands.d.ts +4 -1
- package/dist/tui/commands.js +36 -25
- package/dist/tui/index.js +2 -2
- package/dist/tui/service-actions.js +5 -4
- package/dist/tui/service-command.d.ts +6 -0
- package/dist/tui/service-command.js +40 -0
- package/dist/tui/service-panel.js +9 -8
- package/dist/types.d.ts +4 -4
- package/dist/upload-reference-guard.d.ts +4 -0
- package/dist/upload-reference-guard.js +29 -0
- package/dist/upload-routes.d.ts +4 -0
- package/dist/upload-routes.js +121 -21
- package/dist/user-profile.d.ts +1 -1
- package/dist/user-profile.js +8 -3
- package/dist/web-ui/content/ai-teams.js +9 -9
- package/dist/web-ui/content/module-manifest.json +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chat-render-EODYMQF6.js → 0051bd3d55f10ab7/chat-render-RY2I2CF3.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-ZTEQSXPA.js → 0051bd3d55f10ab7/chunk-2F6J2MKX.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-A33YPCY6.js → 0051bd3d55f10ab7/chunk-7AFM245W.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-QNUWUMKW.js → 0051bd3d55f10ab7/chunk-MHX2QXIS.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-WGADUEIT.js → 0051bd3d55f10ab7/chunk-RAAPETNH.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-I3UYDQLS.js → 0051bd3d55f10ab7/chunk-RXKBHYUR.js} +2 -2
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-3TCUG766.js → 0051bd3d55f10ab7/chunk-U4EDP4TI.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-HK7RBU3M.js → 0051bd3d55f10ab7/chunk-WHXQR7JT.js} +1 -1
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/employee-card-NV34TZIH.js +1 -0
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-2PU6TV2I.js → 0051bd3d55f10ab7/host-2IVIZ2YC.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-BPYNMKFC.js → 0051bd3d55f10ab7/host-AZXNFCRW.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-HZIKPWYY.js → 0051bd3d55f10ab7/host-EPEQX22R.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-YELXZID4.js → 0051bd3d55f10ab7/host-FZYIMOLC.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-OGD6AWHL.js → 0051bd3d55f10ab7/host-G6GL4SNL.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-E3SCPOIU.js → 0051bd3d55f10ab7/host-PEILC5NU.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-OWD32FZ3.js → 0051bd3d55f10ab7/host-PHHNGVNL.js} +2 -2
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-CXDAFMXX.js → 0051bd3d55f10ab7/host-Q524TMSR.js} +1 -1
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/host-RO5MB6RB.js +69 -0
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-J5XRAQFP.js → 0051bd3d55f10ab7/host-WOQRK6NG.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-HKXE2DOT.js → 0051bd3d55f10ab7/host-XNIR3NTJ.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/host-4E4H4JZJ.js → 0051bd3d55f10ab7/host-XRVOIEP6.js} +1 -1
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/host-ZDKOQEMS.js +1 -0
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/host-bridge-PMQZRG5G.js +1 -0
- package/dist/web-ui/content/modules/{2548dbe0d0783577/library-bridge-Y3Y24CPQ.js → 0051bd3d55f10ab7/library-bridge-DTMQIHVJ.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/page-GQBUU7T7.js → 0051bd3d55f10ab7/page-PY4JUL4W.js} +1 -1
- package/dist/web-ui/content/modules/{2548dbe0d0783577/panel-PG662OC5.js → 0051bd3d55f10ab7/panel-BBQFC55Q.js} +1 -1
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/runtime.js +974 -0
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/task-board-host-PXZSWBBG.js +2 -0
- package/dist/web-ui/content/modules/0051bd3d55f10ab7/workspace-agent-picker-DJSECSY6.js +1 -0
- package/dist/web-ui/content/modules/{2548dbe0d0783577/workspace-window-HV4T3WKR.js → 0051bd3d55f10ab7/workspace-window-MNMKSOBG.js} +1 -1
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +27 -27
- package/dist/web-ui/embedded-assets.js +4 -4
- package/dist/web-ui/provider-identity.d.ts +4 -5
- package/dist/web-ui/provider-identity.js +4 -10
- package/dist/web-ui/react/workspaces/sidebar-manage.d.ts +39 -0
- package/dist/web-ui/react/workspaces/sidebar-manage.js +149 -0
- package/dist/web-ui/react/workspaces/types.d.ts +408 -0
- package/dist/web-ui/react/workspaces/types.js +16 -0
- package/dist/web-ui/session-activity.js +1 -1
- package/package.json +2 -2
- package/dist/structured-gemini-adapter.d.ts +0 -40
- package/dist/structured-gemini-adapter.js +0 -208
- package/dist/web-ui/content/modules/2548dbe0d0783577/chunk-XGVT4ZWT.js +0 -1
- package/dist/web-ui/content/modules/2548dbe0d0783577/employee-card-LJ3TX72B.js +0 -1
- package/dist/web-ui/content/modules/2548dbe0d0783577/host-ITV2QZ4A.js +0 -1
- package/dist/web-ui/content/modules/2548dbe0d0783577/host-XNWC7KPR.js +0 -69
- package/dist/web-ui/content/modules/2548dbe0d0783577/host-bridge-G5HEVADT.js +0 -1
- package/dist/web-ui/content/modules/2548dbe0d0783577/runtime.js +0 -946
- package/dist/web-ui/content/modules/2548dbe0d0783577/task-board-host-RAN2Z2KR.js +0 -2
- package/dist/web-ui/content/modules/2548dbe0d0783577/workspace-agent-picker-FXLH6N5K.js +0 -1
- /package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-YX475LXO.js → 0051bd3d55f10ab7/chunk-6C6A2RHG.js} +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-NP35GDQ3.js → 0051bd3d55f10ab7/chunk-ECWYA3U5.js} +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-47EVOSJS.js → 0051bd3d55f10ab7/chunk-T35D57FW.js} +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577 → 0051bd3d55f10ab7}/chunk-YOXXNXOX.js +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577/chunk-C3K34WJD.js → 0051bd3d55f10ab7/chunk-YQJ6XYV7.js} +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577/host-J6HBDK4A.js → 0051bd3d55f10ab7/host-2AQAIUNO.js} +0 -0
- /package/dist/web-ui/content/modules/{2548dbe0d0783577 → 0051bd3d55f10ab7}/sha256-ANXV72UC.js +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { constants, closeSync, fstatSync, lstatSync, openSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertPlainTempPath } from "./managed-temp.js";
|
|
4
|
+
export const DIAGNOSTIC_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
5
|
+
export const DIAGNOSTIC_LOG_ROTATIONS = 3;
|
|
6
|
+
export const DIAGNOSTIC_LOG_RETENTION_DAYS = 14;
|
|
7
|
+
const FILES = new Set(["web.log", "web-error.log", "terminald.log", "terminald-error.log", "structured-stdout.log", "structured-stderr.log", "structured-spawns.jsonl"]);
|
|
8
|
+
export const DIAGNOSTIC_RECEIPT_SUFFIX = ".wand-log-receipt.json";
|
|
9
|
+
function checkFile(file) {
|
|
10
|
+
assertPlainTempPath(file);
|
|
11
|
+
try {
|
|
12
|
+
const stat = lstatSync(file);
|
|
13
|
+
if (!stat.isFile() || (process.getuid && stat.uid !== process.getuid()))
|
|
14
|
+
throw new Error("Diagnostic log is not an owned file.");
|
|
15
|
+
return stat;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === "ENOENT")
|
|
19
|
+
return null;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function receipt(file) {
|
|
24
|
+
const stat = checkFile(file);
|
|
25
|
+
const target = file + DIAGNOSTIC_RECEIPT_SUFFIX;
|
|
26
|
+
checkFile(target);
|
|
27
|
+
writeFileSync(target, JSON.stringify({ app: "wand-diagnostic-log", version: 1, device: stat.dev, inode: stat.ino,
|
|
28
|
+
size: stat.size, mtimeMs: stat.mtimeMs, ctimeMs: stat.ctimeMs }), { mode: 0o600 });
|
|
29
|
+
}
|
|
30
|
+
export function diagnosticReceiptMatches(file) {
|
|
31
|
+
const stat = checkFile(file), marker = checkFile(file + DIAGNOSTIC_RECEIPT_SUFFIX);
|
|
32
|
+
if (!stat || !marker || marker.size > 4096)
|
|
33
|
+
return false;
|
|
34
|
+
const fd = openSync(file + DIAGNOSTIC_RECEIPT_SUFFIX, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
35
|
+
try {
|
|
36
|
+
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
37
|
+
return value.app === "wand-diagnostic-log" && value.version === 1 && value.device === stat.dev
|
|
38
|
+
&& value.inode === stat.ino && value.size === stat.size && value.mtimeMs === stat.mtimeMs && value.ctimeMs === stat.ctimeMs;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
closeSync(fd);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Only redundant diagnostics: PTY history and native protocol sources never enter this writer. */
|
|
45
|
+
export function appendBoundedDiagnostic(file, data, maxBytes = DIAGNOSTIC_LOG_MAX_BYTES, rotations = DIAGNOSTIC_LOG_ROTATIONS) {
|
|
46
|
+
if (!FILES.has(path.basename(file)) || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || !Number.isSafeInteger(rotations) || rotations < 1 || rotations > 3) {
|
|
47
|
+
throw new Error("Unknown diagnostic log or invalid limits.");
|
|
48
|
+
}
|
|
49
|
+
const target = path.join(realpathSync(path.dirname(file)), path.basename(file));
|
|
50
|
+
let bytes = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
51
|
+
if (bytes.length > maxBytes)
|
|
52
|
+
bytes = bytes.subarray(bytes.length - maxBytes);
|
|
53
|
+
const stat = checkFile(target);
|
|
54
|
+
if (stat && stat.size + bytes.length > maxBytes) {
|
|
55
|
+
// Preflight all slots before renaming: unknown/replaced files are never overwritten.
|
|
56
|
+
for (let i = 1; i <= rotations; i++) {
|
|
57
|
+
const old = `${target}.${i}`;
|
|
58
|
+
const archive = checkFile(old), marker = checkFile(old + DIAGNOSTIC_RECEIPT_SUFFIX);
|
|
59
|
+
if (archive ? !diagnosticReceiptMatches(old) : marker)
|
|
60
|
+
throw new Error("Diagnostic archive ownership changed.");
|
|
61
|
+
}
|
|
62
|
+
const oldest = `${target}.${rotations}`;
|
|
63
|
+
if (checkFile(oldest)) {
|
|
64
|
+
unlinkSync(oldest);
|
|
65
|
+
unlinkSync(oldest + DIAGNOSTIC_RECEIPT_SUFFIX);
|
|
66
|
+
}
|
|
67
|
+
for (let i = rotations - 1; i >= 1; i--) {
|
|
68
|
+
const from = `${target}.${i}`, to = `${target}.${i + 1}`;
|
|
69
|
+
if (checkFile(from)) {
|
|
70
|
+
renameSync(from, to);
|
|
71
|
+
unlinkSync(from + DIAGNOSTIC_RECEIPT_SUFFIX);
|
|
72
|
+
receipt(to);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
renameSync(target, `${target}.1`);
|
|
76
|
+
receipt(`${target}.1`);
|
|
77
|
+
}
|
|
78
|
+
const fd = openSync(target, constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND | (constants.O_NOFOLLOW ?? 0), 0o600);
|
|
79
|
+
try {
|
|
80
|
+
const current = fstatSync(fd);
|
|
81
|
+
if (!current.isFile() || (process.getuid && current.uid !== process.getuid()))
|
|
82
|
+
throw new Error("Diagnostic output changed.");
|
|
83
|
+
let offset = 0;
|
|
84
|
+
while (offset < bytes.length)
|
|
85
|
+
offset += writeSync(fd, bytes, offset, bytes.length - offset);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
closeSync(fd);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Attach only to launchd/file redirections matching this instance; keep TTYs and journald untouched. */
|
|
92
|
+
export function installServiceDiagnosticRotation(configDir, kind) {
|
|
93
|
+
const restore = [];
|
|
94
|
+
for (const [stream, file, fd] of [[process.stdout, `${kind}.log`, 1], [process.stderr, `${kind}-error.log`, 2]]) {
|
|
95
|
+
try {
|
|
96
|
+
const target = path.join(realpathSync(configDir), file), stat = checkFile(target), output = fstatSync(fd);
|
|
97
|
+
if (!stat || stat.dev !== output.dev || stat.ino !== output.ino)
|
|
98
|
+
continue;
|
|
99
|
+
const original = stream.write;
|
|
100
|
+
stream.write = function (chunk, encoding, callback) {
|
|
101
|
+
const cb = typeof encoding === "function" ? encoding : callback;
|
|
102
|
+
try {
|
|
103
|
+
appendBoundedDiagnostic(target, typeof chunk === "string" ? Buffer.from(chunk, typeof encoding === "string" ? encoding : "utf8") : Buffer.from(chunk));
|
|
104
|
+
if (cb)
|
|
105
|
+
queueMicrotask(() => cb(null));
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return original.apply(stream, arguments);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
restore.push(() => { stream.write = original; });
|
|
113
|
+
}
|
|
114
|
+
catch { /* Never prevent startup or redirect unrelated output. */ }
|
|
115
|
+
}
|
|
116
|
+
return () => { for (const undo of restore)
|
|
117
|
+
undo(); };
|
|
118
|
+
}
|
|
119
|
+
export function isDiagnosticArchive(name) {
|
|
120
|
+
return [...FILES].some(file => [1, 2, 3].some(index => name === `${file}.${index}`));
|
|
121
|
+
}
|
package/dist/employee-text.js
CHANGED
|
@@ -74,9 +74,7 @@ export async function prepareEmployeeTextCandidate(deps, agent, request, signal)
|
|
|
74
74
|
if (agent.engine !== "sdk") {
|
|
75
75
|
if (!providerCliInstalled(agent.provider) || isOpenRouterFreeSelector(agent.model))
|
|
76
76
|
throw new Error("CLI候选不可用。");
|
|
77
|
-
const { callCliAiText
|
|
78
|
-
if (agent.provider === "gemini")
|
|
79
|
-
assertGeminiTextCapability();
|
|
77
|
+
const { callCliAiText } = await import("./ai-text-runner.js");
|
|
80
78
|
// One adapter call, never re-enter the candidate chain.
|
|
81
79
|
return async () => {
|
|
82
80
|
signal.throwIfAborted();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { GitStatusResult, PushResult, QuickCommitResult, SessionProvider, SessionSnapshot, TagHeadResult } from "./types.js";
|
|
2
2
|
/** provider 缺省值:无法识别时回落到 Claude。 */
|
|
3
3
|
import { type QuickCommitAiOptions } from "./ai-text-runner.js";
|
|
4
|
-
export {
|
|
4
|
+
export { callCliAiText, callConfiguredAiText, withOpsPersona } from "./ai-text-runner.js";
|
|
5
5
|
export type { QuickCommitAiOptions } from "./ai-text-runner.js";
|
|
6
6
|
export { QuickCommitError, type QuickCommitErrorCode } from "./command-error.js";
|
|
7
7
|
/** Non-blocking status implementation used by HTTP routes. */
|
package/dist/git-quick-commit.js
CHANGED
|
@@ -2,9 +2,9 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { getGitErrorMessage, runGitAsync as runGitAsyncBase, runGitRawAsync as runGitRawAsyncBase, } from "./git-utils.js";
|
|
3
3
|
import { thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToOpenCodeVariant } from "./structured-provider-common.js";
|
|
4
4
|
/** provider 缺省值:无法识别时回落到 Claude。 */
|
|
5
|
-
import {
|
|
5
|
+
import { buildGrokTextArgs, buildPiTextArgs, buildQoderTextArgs, callConfiguredAiText, contentWithSystemPrompt, defaultProvider, normalizeAiText, runCliText, systemPromptArgsFrom, withOpsPersona } from "./ai-text-runner.js";
|
|
6
6
|
import { QuickCommitError } from "./command-error.js";
|
|
7
|
-
export {
|
|
7
|
+
export { callCliAiText, callConfiguredAiText, withOpsPersona } from "./ai-text-runner.js";
|
|
8
8
|
export { QuickCommitError } from "./command-error.js";
|
|
9
9
|
const GIT_TIMEOUT_MS = 1500;
|
|
10
10
|
const GIT_PUSH_TIMEOUT_MS = 30_000;
|
|
@@ -929,13 +929,6 @@ async function runQuickCommitFallbackCli(opts, priorError) {
|
|
|
929
929
|
inheritEnv: opts.inheritEnv,
|
|
930
930
|
});
|
|
931
931
|
}
|
|
932
|
-
else if (provider === "gemini") {
|
|
933
|
-
await runCliText("gemini", buildGeminiTextArgs(opts, true), contentWithSystemPrompt("gemini", request), {
|
|
934
|
-
cwd: opts.cwd,
|
|
935
|
-
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
936
|
-
inheritEnv: opts.inheritEnv,
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
932
|
else {
|
|
940
933
|
const args = [
|
|
941
934
|
"-p",
|
package/dist/layout-tree.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { LayoutNode } from "./types.js";
|
|
1
|
+
import type { LayoutNode, TaskWindowLayout } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* 取布局树中最左上角可用的 tab id:pane 优先用它记住的 active,
|
|
4
4
|
* 否则取第一个 tab;split 递归左侧再右侧。
|
|
5
5
|
*/
|
|
6
6
|
export declare function firstLayoutTabId(node: LayoutNode): string | undefined;
|
|
7
|
+
/** Wrap a legacy tree after each caller applies its own write/read acceptance policy. */
|
|
8
|
+
export declare function wrapLegacyTaskLayout(layout: LayoutNode): TaskWindowLayout;
|
package/dist/layout-tree.js
CHANGED
|
@@ -7,3 +7,11 @@ export function firstLayoutTabId(node) {
|
|
|
7
7
|
return node.tabs[node.active]?.id ?? node.tabs[0]?.id;
|
|
8
8
|
return firstLayoutTabId(node.children[0]) ?? firstLayoutTabId(node.children[1]);
|
|
9
9
|
}
|
|
10
|
+
/** Wrap a legacy tree after each caller applies its own write/read acceptance policy. */
|
|
11
|
+
export function wrapLegacyTaskLayout(layout) {
|
|
12
|
+
return {
|
|
13
|
+
type: "windows",
|
|
14
|
+
windows: [{ id: "window-legacy", layout, activeTabId: firstLayoutTabId(layout) }],
|
|
15
|
+
activeWindowId: "window-legacy",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { buildChildEnv, systemEnvValue } from "./env-utils.js";
|
|
3
|
+
import { registerTemporaryChild } from "./managed-temp.js";
|
|
3
4
|
/** Runs one fixed deployment command. Only whitelisted server code constructs executable/args. */
|
|
4
5
|
export function runModelSetup(executable, args, cwd, signal, progress, timeoutMs = 20 * 60_000) {
|
|
5
6
|
return new Promise((resolve, reject) => {
|
|
@@ -13,6 +14,25 @@ export function runModelSetup(executable, args, cwd, signal, progress, timeoutMs
|
|
|
13
14
|
HTTPS_PROXY: systemEnvValue("HTTPS_PROXY"), HTTP_PROXY: systemEnvValue("HTTP_PROXY"), NO_PROXY: systemEnvValue("NO_PROXY"),
|
|
14
15
|
WAND_LAYA_PYTHON_BIN: systemEnvValue("WAND_LAYA_PYTHON_BIN"),
|
|
15
16
|
}) });
|
|
17
|
+
const workIndex = args.indexOf("--work-dir");
|
|
18
|
+
if (workIndex !== -1) {
|
|
19
|
+
try {
|
|
20
|
+
registerTemporaryChild(args[workIndex + 1], child.pid, grouped);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
child.on("error", () => { });
|
|
24
|
+
child.once("close", () => { reject(new Error("Model setup temporary lease unavailable")); });
|
|
25
|
+
if (grouped && child.pid) {
|
|
26
|
+
try {
|
|
27
|
+
process.kill(-child.pid, "SIGKILL");
|
|
28
|
+
}
|
|
29
|
+
catch { }
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
child.kill("SIGKILL");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
16
36
|
let failed = false, buffer = "", kill;
|
|
17
37
|
const terminate = () => {
|
|
18
38
|
failed = true;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir,
|
|
2
|
+
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { DecisionError } from "./decision-types.js";
|
|
@@ -11,6 +11,7 @@ import { speechSupport } from "./speech-support.js";
|
|
|
11
11
|
import { systemEnvValue } from "./env-utils.js";
|
|
12
12
|
import { decisionHardware } from "./decision-hardware.js";
|
|
13
13
|
import { DECISION_EXPERT_ID } from "./decision-expert-identity.js";
|
|
14
|
+
import { configTemporaryRoot, createManagedTemporary } from "./managed-temp.js";
|
|
14
15
|
/** Deployment jobs only; existing inference owners retain their protocols, rate limits and capabilities. */
|
|
15
16
|
export class LocalModelSetupService {
|
|
16
17
|
deps;
|
|
@@ -244,12 +245,13 @@ export class LocalModelSetupService {
|
|
|
244
245
|
throw new Error("服务器使用自定义语音运行时,请由管理员核对环境配置;不会覆盖它。");
|
|
245
246
|
phase("runtime", "安装固定 whisper.cpp 运行时(需 Git、CMake、C++工具链;CUDA需已安装Toolkit)");
|
|
246
247
|
await mkdir(path.join(this.deps.configDir, "speech"), { recursive: true, mode: 0o700 });
|
|
247
|
-
const
|
|
248
|
+
const temporary = createManagedTemporary("speech-setup", configTemporaryRoot(this.deps.configDir));
|
|
249
|
+
const work = temporary.directory;
|
|
248
250
|
try {
|
|
249
251
|
await (this.deps.run ?? runModelSetup)(process.execPath, [this.installer("install-speech-runtime.js"), "--dir", path.join(this.deps.configDir, "speech"), "--backend", backend, "--work-dir", work, "--events"], this.deps.configDir, signal, (name, message) => phase(name === "verifying" ? "verifying" : "runtime", message));
|
|
250
252
|
}
|
|
251
253
|
finally {
|
|
252
|
-
await
|
|
254
|
+
await temporary.closeAsync();
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
phase("initializing", action === "activate" ? "正在检查语音模型,完成后自动启用。" : "加载所选语音模型并用合成静音检查,未启用识别或重启服务");
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const TEMP_ROOT_MARKER = ".wand-temporary-root.json";
|
|
2
|
+
export declare const TEMP_LEASE = ".wand-temporary-lease.json";
|
|
3
|
+
export declare const TEMP_KINDS: readonly ["speech-check", "speech-voice", "speech-setup", "test-run", "upload-stage"];
|
|
4
|
+
export type TempKind = typeof TEMP_KINDS[number];
|
|
5
|
+
export declare function systemTemporaryRoot(): string;
|
|
6
|
+
/** Keep test fixture Unix sockets below the platform path length limit. */
|
|
7
|
+
export declare function testTemporaryRoot(): string;
|
|
8
|
+
export declare function configTemporaryRoot(configDir: string): string;
|
|
9
|
+
/** Never follow a redirect beneath the trusted, canonical deployment/temp path. */
|
|
10
|
+
export declare function assertPlainTempPath(target: string): void;
|
|
11
|
+
export declare function validateTemporaryRoot(root: string): void;
|
|
12
|
+
export interface TempLease {
|
|
13
|
+
app: "wand-temporary";
|
|
14
|
+
version: 1;
|
|
15
|
+
kind: TempKind;
|
|
16
|
+
id: string;
|
|
17
|
+
ownerPid: number;
|
|
18
|
+
children: {
|
|
19
|
+
pid: number;
|
|
20
|
+
group: boolean;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
export declare function readTemporaryLease(directory: string): TempLease;
|
|
24
|
+
/** ESRCH alone establishes absence; permissions and unexpected errors fail closed. */
|
|
25
|
+
export declare function temporaryPidAlive(pid: number, group?: boolean): boolean;
|
|
26
|
+
export declare function temporaryChildrenAlive(lease: TempLease): boolean;
|
|
27
|
+
export declare function registerTemporaryChild(directory: string, pid: number | undefined, group?: boolean): void;
|
|
28
|
+
export declare function createManagedTemporary(kind: TempKind, root?: string): {
|
|
29
|
+
directory: string;
|
|
30
|
+
close(): boolean;
|
|
31
|
+
closeAsync(): Promise<boolean>;
|
|
32
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { constants, chownSync, closeSync, fstatSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { rm } from "node:fs/promises";
|
|
6
|
+
export const TEMP_ROOT_MARKER = ".wand-temporary-root.json";
|
|
7
|
+
export const TEMP_LEASE = ".wand-temporary-lease.json";
|
|
8
|
+
export const TEMP_KINDS = ["speech-check", "speech-voice", "speech-setup", "test-run", "upload-stage"];
|
|
9
|
+
const uid = () => process.getuid?.() ?? null;
|
|
10
|
+
export function systemTemporaryRoot() {
|
|
11
|
+
return path.join(realpathSync(os.tmpdir()), `wand-transient-${uid() ?? "user"}`);
|
|
12
|
+
}
|
|
13
|
+
/** Keep test fixture Unix sockets below the platform path length limit. */
|
|
14
|
+
export function testTemporaryRoot() {
|
|
15
|
+
return process.platform === "win32" ? systemTemporaryRoot()
|
|
16
|
+
: path.join(realpathSync("/tmp"), `wand-transient-${uid() ?? "user"}`);
|
|
17
|
+
}
|
|
18
|
+
export function configTemporaryRoot(configDir) {
|
|
19
|
+
let base = path.resolve(configDir);
|
|
20
|
+
const missing = [];
|
|
21
|
+
for (;;) {
|
|
22
|
+
try {
|
|
23
|
+
base = realpathSync(base);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.code !== "ENOENT" || base === path.dirname(base))
|
|
28
|
+
throw error;
|
|
29
|
+
missing.unshift(path.basename(base));
|
|
30
|
+
base = path.dirname(base);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return path.join(base, ...missing, "cache", "temporary");
|
|
34
|
+
}
|
|
35
|
+
/** Never follow a redirect beneath the trusted, canonical deployment/temp path. */
|
|
36
|
+
export function assertPlainTempPath(target) {
|
|
37
|
+
for (let current = path.resolve(target);; current = path.dirname(current)) {
|
|
38
|
+
try {
|
|
39
|
+
if (lstatSync(current).isSymbolicLink())
|
|
40
|
+
throw new Error("Temporary path contains a symbolic link.");
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.code !== "ENOENT")
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
if (current === path.dirname(current))
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function readMarker(file) {
|
|
51
|
+
const fd = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
52
|
+
try {
|
|
53
|
+
const stat = fstatSync(fd);
|
|
54
|
+
if (!stat.isFile() || stat.size > 4096 || (uid() !== null && stat.uid !== uid()))
|
|
55
|
+
throw new Error("Invalid temporary marker.");
|
|
56
|
+
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
57
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
58
|
+
throw new Error("Invalid temporary marker.");
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
closeSync(fd);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function validateTemporaryRoot(root) {
|
|
66
|
+
assertPlainTempPath(root);
|
|
67
|
+
const stat = lstatSync(root);
|
|
68
|
+
if (!stat.isDirectory() || (uid() !== null && (stat.uid !== uid() || (stat.mode & 0o077) !== 0))) {
|
|
69
|
+
throw new Error("Temporary root is not private to this user.");
|
|
70
|
+
}
|
|
71
|
+
const marker = readMarker(path.join(root, TEMP_ROOT_MARKER));
|
|
72
|
+
if (marker.app !== "wand-temporary" || marker.version !== 1 || marker.uid !== uid())
|
|
73
|
+
throw new Error("Unmanaged temporary root.");
|
|
74
|
+
}
|
|
75
|
+
export function readTemporaryLease(directory) {
|
|
76
|
+
assertPlainTempPath(directory);
|
|
77
|
+
const value = readMarker(path.join(directory, TEMP_LEASE));
|
|
78
|
+
if (value.app !== "wand-temporary" || value.version !== 1 || !TEMP_KINDS.includes(value.kind)
|
|
79
|
+
|| !path.basename(directory).startsWith(`${value.kind}-`) || typeof value.id !== "string"
|
|
80
|
+
|| !/^[a-f0-9-]{36}$/.test(value.id) || !Number.isSafeInteger(value.ownerPid) || value.ownerPid <= 0
|
|
81
|
+
|| !Array.isArray(value.children) || value.children.length > 16
|
|
82
|
+
|| value.children.some(child => !child || !Number.isSafeInteger(child.pid) || child.pid <= 0 || typeof child.group !== "boolean")) {
|
|
83
|
+
throw new Error("Invalid temporary lease.");
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
/** ESRCH alone establishes absence; permissions and unexpected errors fail closed. */
|
|
88
|
+
export function temporaryPidAlive(pid, group = false) {
|
|
89
|
+
try {
|
|
90
|
+
process.kill(group && process.platform !== "win32" ? -pid : pid, 0);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return error.code !== "ESRCH";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function temporaryChildrenAlive(lease) {
|
|
98
|
+
return lease.children.some(child => temporaryPidAlive(child.pid, child.group));
|
|
99
|
+
}
|
|
100
|
+
export function registerTemporaryChild(directory, pid, group = false) {
|
|
101
|
+
if (!pid)
|
|
102
|
+
return;
|
|
103
|
+
validateTemporaryRoot(path.dirname(directory));
|
|
104
|
+
const lease = readTemporaryLease(directory);
|
|
105
|
+
if (lease.ownerPid !== process.pid)
|
|
106
|
+
throw new Error("Temporary lease belongs to another process.");
|
|
107
|
+
lease.children = lease.children.filter(child => temporaryPidAlive(child.pid, child.group));
|
|
108
|
+
if (!lease.children.some(child => child.pid === pid))
|
|
109
|
+
lease.children.push({ pid, group });
|
|
110
|
+
const file = path.join(directory, TEMP_LEASE);
|
|
111
|
+
const pending = path.join(directory, `${TEMP_LEASE}.${randomUUID()}.tmp`);
|
|
112
|
+
writeFileSync(pending, JSON.stringify(lease), { mode: 0o600, flag: "wx" });
|
|
113
|
+
renameSync(pending, file);
|
|
114
|
+
}
|
|
115
|
+
export function createManagedTemporary(kind, root = systemTemporaryRoot()) {
|
|
116
|
+
if (!TEMP_KINDS.includes(kind))
|
|
117
|
+
throw new Error("Unknown temporary purpose.");
|
|
118
|
+
assertPlainTempPath(root);
|
|
119
|
+
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
120
|
+
const marker = path.join(root, TEMP_ROOT_MARKER);
|
|
121
|
+
try {
|
|
122
|
+
writeFileSync(marker, JSON.stringify({ app: "wand-temporary", version: 1, uid: uid() }), { mode: 0o600, flag: "wx" });
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (error.code !== "EEXIST")
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
validateTemporaryRoot(root);
|
|
129
|
+
// macOS inherits /private/tmp's wheel group; fixtures should retain the caller's group semantics.
|
|
130
|
+
if (process.getgid && uid() !== null && lstatSync(root).gid !== process.getgid())
|
|
131
|
+
chownSync(root, uid(), process.getgid());
|
|
132
|
+
const directory = mkdtempSync(path.join(root, `${kind}-`));
|
|
133
|
+
const lease = { app: "wand-temporary", version: 1, kind, id: randomUUID(), ownerPid: process.pid, children: [] };
|
|
134
|
+
try {
|
|
135
|
+
writeFileSync(path.join(directory, TEMP_LEASE), JSON.stringify(lease), { mode: 0o600, flag: "wx" });
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
rmSync(directory, { recursive: true, force: true });
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
const removable = () => {
|
|
142
|
+
validateTemporaryRoot(root);
|
|
143
|
+
const current = readTemporaryLease(directory);
|
|
144
|
+
return current.id === lease.id && current.ownerPid === process.pid && !temporaryChildrenAlive(current);
|
|
145
|
+
};
|
|
146
|
+
const absent = () => {
|
|
147
|
+
try {
|
|
148
|
+
lstatSync(directory);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return error.code === "ENOENT";
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
return { directory, close() {
|
|
156
|
+
try {
|
|
157
|
+
if (!removable())
|
|
158
|
+
return false;
|
|
159
|
+
rmSync(directory, { recursive: true, force: true });
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return absent();
|
|
164
|
+
}
|
|
165
|
+
}, async closeAsync() {
|
|
166
|
+
try {
|
|
167
|
+
if (!removable())
|
|
168
|
+
return false;
|
|
169
|
+
await rm(directory, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return absent();
|
|
174
|
+
}
|
|
175
|
+
} };
|
|
176
|
+
}
|
|
@@ -23,6 +23,7 @@ export const API_ROUTE_RULES = [
|
|
|
23
23
|
{ prefix: "/api/check-update", scope: "admin" },
|
|
24
24
|
{ prefix: "/api/auto-update", scope: "admin" },
|
|
25
25
|
{ prefix: "/api/provider-cli-updates", scope: "admin" },
|
|
26
|
+
{ prefix: "/api/storage-cleanup", scope: "admin" },
|
|
26
27
|
{ prefix: "/api/android-apk", scope: "admin" },
|
|
27
28
|
{ prefix: "/api/macos-dmg", scope: "admin" },
|
|
28
29
|
{ prefix: "/api/ios-ipa", scope: "admin" },
|
package/dist/models/shared.d.ts
CHANGED
|
@@ -8,11 +8,5 @@ export declare const OPENCODE_FALLBACK_MODELS: ClaudeModelInfo[];
|
|
|
8
8
|
export declare const GROK_FALLBACK_MODELS: ClaudeModelInfo[];
|
|
9
9
|
export declare const QODER_FALLBACK_MODELS: ClaudeModelInfo[];
|
|
10
10
|
export declare const PI_FALLBACK_MODELS: ClaudeModelInfo[];
|
|
11
|
-
/**
|
|
12
|
-
* Gemini CLI 没有列模型的子命令,只能给出稳定别名(`packages/core/src/config/models.ts`
|
|
13
|
-
* 里的 GEMINI_MODEL_ALIAS_*)。具体版本名随发布滚动,不适合写死在这里;
|
|
14
|
-
* 设置页的模型输入框是自由文本,用户可以自己填完整模型名。
|
|
15
|
-
*/
|
|
16
|
-
export declare const GEMINI_FALLBACK_MODELS: ClaudeModelInfo[];
|
|
17
11
|
export declare function cloneModels(models: readonly ClaudeModelInfo[]): ClaudeModelInfo[];
|
|
18
12
|
export { isRecord } from "../object-utils.js";
|
package/dist/models/shared.js
CHANGED
|
@@ -38,18 +38,6 @@ export const QODER_FALLBACK_MODELS = [
|
|
|
38
38
|
export const PI_FALLBACK_MODELS = [
|
|
39
39
|
{ id: "default", label: "跟随 Pi 默认", alias: true },
|
|
40
40
|
];
|
|
41
|
-
/**
|
|
42
|
-
* Gemini CLI 没有列模型的子命令,只能给出稳定别名(`packages/core/src/config/models.ts`
|
|
43
|
-
* 里的 GEMINI_MODEL_ALIAS_*)。具体版本名随发布滚动,不适合写死在这里;
|
|
44
|
-
* 设置页的模型输入框是自由文本,用户可以自己填完整模型名。
|
|
45
|
-
*/
|
|
46
|
-
export const GEMINI_FALLBACK_MODELS = [
|
|
47
|
-
{ id: "default", label: "跟随 Gemini 默认", alias: true },
|
|
48
|
-
{ id: "auto", label: "Auto(按任务自动选模型)" },
|
|
49
|
-
{ id: "pro", label: "Pro" },
|
|
50
|
-
{ id: "flash", label: "Flash" },
|
|
51
|
-
{ id: "flash-lite", label: "Flash Lite" },
|
|
52
|
-
];
|
|
53
41
|
export function cloneModels(models) {
|
|
54
42
|
return models.map((model) => ({
|
|
55
43
|
...model,
|
|
@@ -11,8 +11,6 @@ export interface ProviderThinkingEfforts {
|
|
|
11
11
|
grok: ThinkingEffortLevel[];
|
|
12
12
|
qoder: ThinkingEffortLevel[];
|
|
13
13
|
pi: ThinkingEffortLevel[];
|
|
14
|
-
/** Gemini CLI 没有思考档位开关,只保留「不覆盖」一项,不假装能调。 */
|
|
15
|
-
gemini: ThinkingEffortLevel[];
|
|
16
14
|
}
|
|
17
15
|
/** 探针失败时的已知档位。下一次 CLI 成功应答会把它换掉。 */
|
|
18
16
|
export declare const FALLBACK_PROVIDER_THINKING: ProviderThinkingEfforts;
|
package/dist/models/thinking.js
CHANGED
|
@@ -7,7 +7,6 @@ export const FALLBACK_PROVIDER_THINKING = {
|
|
|
7
7
|
grok: effortLevelsFromIds(["low", "medium", "high", "xhigh"]),
|
|
8
8
|
qoder: effortLevelsFromIds(["auto", "none", "low", "medium", "high", "xhigh", "max", "ultracode"]),
|
|
9
9
|
pi: effortLevelsFromIds(["minimal", "low", "medium", "high", "xhigh", "max"]),
|
|
10
|
-
gemini: effortLevelsFromIds(["off"]),
|
|
11
10
|
};
|
|
12
11
|
export function cloneThinkingEfforts(efforts) {
|
|
13
12
|
const copy = (levels) => levels.map((level) => ({ ...level }));
|
|
@@ -17,7 +16,6 @@ export function cloneThinkingEfforts(efforts) {
|
|
|
17
16
|
grok: copy(efforts.grok),
|
|
18
17
|
qoder: copy(efforts.qoder),
|
|
19
18
|
pi: copy(efforts.pi),
|
|
20
|
-
gemini: copy(efforts.gemini),
|
|
21
19
|
};
|
|
22
20
|
}
|
|
23
21
|
export function effortLevelsFromIds(ids) {
|
package/dist/models.d.ts
CHANGED
|
@@ -64,7 +64,6 @@ export interface ModelCache {
|
|
|
64
64
|
grokModels: ClaudeModelInfo[];
|
|
65
65
|
qoderModels: ClaudeModelInfo[];
|
|
66
66
|
piModels: ClaudeModelInfo[];
|
|
67
|
-
geminiModels: ClaudeModelInfo[];
|
|
68
67
|
thinkingEfforts: ProviderThinkingEfforts;
|
|
69
68
|
claudeVersion: string | null;
|
|
70
69
|
opencodeVersion: string | null;
|
package/dist/models.js
CHANGED
|
@@ -9,7 +9,7 @@ import { resolveChildEnv } from "./env-utils.js";
|
|
|
9
9
|
import { discoverPiEndpointModels } from "./pi-model-discovery.js";
|
|
10
10
|
import { extractSemver } from "./version-utils.js";
|
|
11
11
|
import { AUTO_ASSIGN_LABEL, AUTO_ASSIGN_SELECTOR, FREE_MODEL_GROUP_ID, isAutoAssignSelector, isModelGroupSelector, modelGroupSelector, orderModelIds } from "./model-groups.js";
|
|
12
|
-
import { MODEL_ID_PATTERN, QODER_MODEL_ID_PATTERN, CLAUDE_BUILTIN_MODELS, CODEX_FALLBACK_MODELS, OPENCODE_FALLBACK_MODELS, GROK_FALLBACK_MODELS, QODER_FALLBACK_MODELS, PI_FALLBACK_MODELS,
|
|
12
|
+
import { MODEL_ID_PATTERN, QODER_MODEL_ID_PATTERN, CLAUDE_BUILTIN_MODELS, CODEX_FALLBACK_MODELS, OPENCODE_FALLBACK_MODELS, GROK_FALLBACK_MODELS, QODER_FALLBACK_MODELS, PI_FALLBACK_MODELS, cloneModels, isRecord } from "./models/shared.js";
|
|
13
13
|
import { EFFORT_ID_PATTERN, FALLBACK_PROVIDER_THINKING, cloneThinkingEfforts, effortLevelsFromIds, unionModelEfforts, parseCliEffortList } from "./models/thinking.js";
|
|
14
14
|
import { parseOpenCodeModelCatalog } from "./models/parsers/opencode.js";
|
|
15
15
|
import { parseGrokModels } from "./models/parsers/grok.js";
|
|
@@ -45,7 +45,6 @@ const PROVIDER_MODEL_LIST_FIELDS = {
|
|
|
45
45
|
grok: "grokModels",
|
|
46
46
|
qoder: "qoderModels",
|
|
47
47
|
pi: "piModels",
|
|
48
|
-
gemini: "geminiModels",
|
|
49
48
|
};
|
|
50
49
|
/**
|
|
51
50
|
* 目录里 `default` 项(「不传 --model」那一项)的标签补上服务端配置的默认模型名:
|
|
@@ -84,7 +83,6 @@ function cloneCache(cache) {
|
|
|
84
83
|
grokModels: cloneModels(cache.grokModels),
|
|
85
84
|
qoderModels: cloneModels(cache.qoderModels),
|
|
86
85
|
piModels: cloneModels(cache.piModels),
|
|
87
|
-
geminiModels: cloneModels(cache.geminiModels),
|
|
88
86
|
thinkingEfforts: cloneThinkingEfforts(cache.thinkingEfforts),
|
|
89
87
|
claudeVersion: cache.claudeVersion,
|
|
90
88
|
opencodeVersion: cache.opencodeVersion,
|
|
@@ -253,7 +251,6 @@ function createInitialCache(options) {
|
|
|
253
251
|
grokModels: cloneModels(GROK_FALLBACK_MODELS),
|
|
254
252
|
qoderModels: cloneModels(QODER_FALLBACK_MODELS),
|
|
255
253
|
piModels: cloneModels(PI_FALLBACK_MODELS),
|
|
256
|
-
geminiModels: cloneModels(GEMINI_FALLBACK_MODELS),
|
|
257
254
|
thinkingEfforts: cloneThinkingEfforts(FALLBACK_PROVIDER_THINKING),
|
|
258
255
|
claudeVersion: null,
|
|
259
256
|
opencodeVersion: null,
|
|
@@ -485,7 +482,6 @@ function catalogRevision(cache) {
|
|
|
485
482
|
grokModels: cache.grokModels,
|
|
486
483
|
qoderModels: cache.qoderModels,
|
|
487
484
|
piModels: cache.piModels,
|
|
488
|
-
geminiModels: cache.geminiModels,
|
|
489
485
|
thinkingEfforts: cache.thinkingEfforts,
|
|
490
486
|
claudeVersion: cache.claudeVersion,
|
|
491
487
|
opencodeVersion: cache.opencodeVersion,
|
|
@@ -560,7 +556,7 @@ function parsePersistedThinkingEfforts(value) {
|
|
|
560
556
|
const fallback = cloneThinkingEfforts(FALLBACK_PROVIDER_THINKING);
|
|
561
557
|
if (!isRecord(value))
|
|
562
558
|
return fallback;
|
|
563
|
-
const providers = ["claude", "opencode", "grok", "qoder", "pi"
|
|
559
|
+
const providers = ["claude", "opencode", "grok", "qoder", "pi"];
|
|
564
560
|
for (const provider of providers) {
|
|
565
561
|
const levels = parsePersistedEffortLevels(value[provider]);
|
|
566
562
|
if (levels)
|
|
@@ -595,9 +591,8 @@ function parsePersistedModelCatalog(value) {
|
|
|
595
591
|
const grokModels = parsePersistedModelList(catalog.grokModels);
|
|
596
592
|
const qoderModels = parsePersistedModelList(catalog.qoderModels);
|
|
597
593
|
const piModels = parsePersistedModelList(catalog.piModels);
|
|
598
|
-
const geminiModels = parsePersistedModelList(catalog.geminiModels);
|
|
599
594
|
const refreshedAt = safePersistedString(catalog.refreshedAt, 64);
|
|
600
|
-
if (!models || !codexModels || !opencodeModels || !grokModels || !qoderModels || !piModels
|
|
595
|
+
if (!models || !codexModels || !opencodeModels || !grokModels || !qoderModels || !piModels
|
|
601
596
|
|| !refreshedAt || Number.isNaN(Date.parse(refreshedAt))) {
|
|
602
597
|
return null;
|
|
603
598
|
}
|
|
@@ -613,7 +608,6 @@ function parsePersistedModelCatalog(value) {
|
|
|
613
608
|
grokModels,
|
|
614
609
|
qoderModels,
|
|
615
610
|
piModels,
|
|
616
|
-
geminiModels,
|
|
617
611
|
thinkingEfforts: parsePersistedThinkingEfforts(catalog.thinkingEfforts),
|
|
618
612
|
claudeVersion,
|
|
619
613
|
opencodeVersion,
|
|
@@ -704,7 +698,6 @@ async function discoverModelCache(options, previous) {
|
|
|
704
698
|
grokModels: grokProbe.ok ? grokProbe.value : cloneModels(previous.grokModels),
|
|
705
699
|
qoderModels: qoderProbe.ok ? qoderProbe.value : cloneModels(previous.qoderModels),
|
|
706
700
|
piModels: piProbe.ok ? piProbe.value : cloneModels(previous.piModels),
|
|
707
|
-
geminiModels: cloneModels(previous.geminiModels),
|
|
708
701
|
thinkingEfforts: {
|
|
709
702
|
claude: claudeEffortProbe.ok ? claudeEffortProbe.value : cloneThinkingEfforts(previous.thinkingEfforts).claude,
|
|
710
703
|
opencode: opencodeProbe.models.ok && unionModelEfforts(opencodeProbe.models.value).length
|
|
@@ -717,7 +710,6 @@ async function discoverModelCache(options, previous) {
|
|
|
717
710
|
: piEffortProbe.ok
|
|
718
711
|
? piEffortProbe.value
|
|
719
712
|
: cloneThinkingEfforts(previous.thinkingEfforts).pi,
|
|
720
|
-
gemini: cloneThinkingEfforts(previous.thinkingEfforts).gemini,
|
|
721
713
|
},
|
|
722
714
|
claudeVersion,
|
|
723
715
|
opencodeVersion: opencodeProbe.version.ok ? opencodeProbe.version.value : previous.opencodeVersion,
|
|
@@ -10,7 +10,7 @@ export interface NativeTitleHomes {
|
|
|
10
10
|
* provider 自己在运行期写下的会话标题:
|
|
11
11
|
* codex `session_index.jsonl` 的 thread_name、qoder 转录里的 ai-title、
|
|
12
12
|
* OpenCode SQLite 的 session.title、grok `summary.json` 的 generated_title。
|
|
13
|
-
* Claude / Pi
|
|
13
|
+
* Claude / Pi 没有这个入口,返回空串让调用方回退系统硅基员工。
|
|
14
14
|
*/
|
|
15
15
|
export declare function readNativeSessionTitle(provider: SessionProvider, providerSessionId: string | null | undefined, cwd: string, homes?: NativeTitleHomes): Promise<string>;
|
|
16
16
|
/** 只用于测试与降级:清掉按文件指纹缓存的原生标题。 */
|
|
@@ -11,7 +11,7 @@ const GROK_WALK_LIMIT = 4_000;
|
|
|
11
11
|
* provider 自己在运行期写下的会话标题:
|
|
12
12
|
* codex `session_index.jsonl` 的 thread_name、qoder 转录里的 ai-title、
|
|
13
13
|
* OpenCode SQLite 的 session.title、grok `summary.json` 的 generated_title。
|
|
14
|
-
* Claude / Pi
|
|
14
|
+
* Claude / Pi 没有这个入口,返回空串让调用方回退系统硅基员工。
|
|
15
15
|
*/
|
|
16
16
|
export async function readNativeSessionTitle(provider, providerSessionId, cwd, homes = {}) {
|
|
17
17
|
const id = providerSessionId?.trim() ?? "";
|