@steerable/agent-shell 0.6.53 → 0.6.55
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/dist/brand.js +1 -1
- package/dist/host/pack-assembly.d.ts +6 -16
- package/dist/host/pack-assembly.js +3 -4
- package/dist/i18n.d.ts +23 -0
- package/dist/i18n.js +87 -0
- package/dist/image-attachment.d.ts +31 -4
- package/dist/image-attachment.js +13 -18
- package/dist/json-store.js +3 -6
- package/dist/local-backend/portable-bundle.js +8 -7
- package/dist/local-backend/router.js +2 -2
- package/dist/local-backend/skills/10-goal/SKILL.md +1 -1
- package/dist/local-backend/skills/11-loop/SKILL.md +1 -1
- package/dist/local-backend/skills/12-create-skill/SKILL.md +2 -2
- package/dist/local-script-registry.js +2 -2
- package/dist/mcp-server-registry.d.ts +3 -3
- package/dist/mcp-server-registry.js +2 -2
- package/dist/product-config.d.ts +10 -14
- package/dist/project-registry.d.ts +3 -3
- package/dist/project-registry.js +2 -2
- package/dist/runtime.d.ts +8 -54
- package/dist/runtime.js +15 -129
- package/dist/scenario/pack.d.ts +1 -1
- package/dist/scenario/registry.d.ts +4 -5
- package/dist/scenario/registry.js +2 -10
- package/dist/server/start.js +1 -2
- package/dist/sidecar/reverse-spawn.js +6 -15
- package/dist/sidecar/supervisor.d.ts +0 -2
- package/dist/sidecar/supervisor.js +7 -30
- package/dist/storage/index.js +1 -1
- package/dist/storage/write-lease-error.d.ts +2 -11
- package/dist/storage/write-lease-error.js +3 -8
- package/package.json +6 -13
- package/dist/app-update-electron.d.ts +0 -5
- package/dist/app-update-electron.js +0 -66
- package/dist/app-update.d.ts +0 -92
- package/dist/app-update.js +0 -213
- package/dist/host/ipc.d.ts +0 -11
- package/dist/host/ipc.js +0 -20
- package/dist/main.d.ts +0 -1
- package/dist/main.js +0 -967
- package/dist/preload-default.d.ts +0 -1
- package/dist/preload-default.js +0 -9
- package/dist/preload.cjs +0 -425
- package/dist/preload.d.ts +0 -20
- package/dist/preload.js +0 -442
- package/dist/single-instance.d.ts +0 -11
- package/dist/single-instance.js +0 -21
package/dist/brand.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 包装配注册表(阶段 2.3)——纯构建期组合的宿主侧机制。
|
|
3
3
|
*
|
|
4
|
-
* 宿主(host/runtime.ts、
|
|
4
|
+
* 宿主(host/runtime.ts、server/index.ts)不再静态 import 任何
|
|
5
5
|
* 包代码:产品组装根(products/<id>/active.ts)把包的装配函数注册进本
|
|
6
6
|
* 注册表,宿主在装配期逐个调用。产品的 tsc 编译单元只 include 自己的包,
|
|
7
7
|
* 他包代码物理上不进产品 dist。
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
* - import 期(active.ts 顶层):迁移/种子/品牌等无宿主依赖的注册;
|
|
11
11
|
* - 装配期(createHostRuntime 内):服务/工具/路由等需要宿主能力的部分,
|
|
12
12
|
* 经 {@link PackAssemblyDeps} 注入。
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 不出现任何包名。
|
|
13
|
+
* server/index.ts 消费 handle.httpRoutes——包的入口面贡献由宿主循环驱动,
|
|
14
|
+
* 宿主代码里不出现任何包名。
|
|
16
15
|
*/
|
|
17
|
-
import type { HttpRouteContribution,
|
|
16
|
+
import type { HttpRouteContribution, ToolContribution } from '../scenario/pack.js';
|
|
18
17
|
import type { PackDbAccess } from '../storage/driver.js';
|
|
19
18
|
/** 宿主注入包的装配能力面。包不 import 宿主装配模块,全部经回调注入。 */
|
|
20
19
|
export interface PackAssemblyDeps {
|
|
@@ -31,7 +30,7 @@ export interface PackAssemblyDeps {
|
|
|
31
30
|
name: string;
|
|
32
31
|
folderPath: string;
|
|
33
32
|
} | null>;
|
|
34
|
-
/** 面向全部用户面的事件广播(
|
|
33
|
+
/** 面向全部用户面的事件广播(SSE 总线)。 */
|
|
35
34
|
readonly broadcast: (channel: string, payload: unknown) => void;
|
|
36
35
|
/** 工具贡献注册口(toolRouter.registerToolContributions 的收窄面)。 */
|
|
37
36
|
readonly registerTools: (tools: readonly ToolContribution[]) => void;
|
|
@@ -61,20 +60,11 @@ export interface PackAssemblyDeps {
|
|
|
61
60
|
/** 装配期日志行(进宿主日志)。 */
|
|
62
61
|
readonly onLog: (line: string) => void;
|
|
63
62
|
}
|
|
64
|
-
/** CS 宿主的窗口能力:打开一个加载应用内路由的独立窗口。 */
|
|
65
|
-
export interface PackHostWindowCapabilities {
|
|
66
|
-
/** route 如 '/<pack>-debug-log';title 为窗口副标题(宿主拼品牌名)。 */
|
|
67
|
-
openRouteWindow(route: string, options: {
|
|
68
|
-
title: string;
|
|
69
|
-
}): Promise<void>;
|
|
70
|
-
}
|
|
71
63
|
/** 装配产物:宿主按入口面消费。全部槽位可选。 */
|
|
72
64
|
export interface PackAssemblyHandle {
|
|
73
65
|
/** 宿主关停钩子(进程退出时按装配逆序调用)。 */
|
|
74
66
|
readonly dispose?: () => void | Promise<void>;
|
|
75
|
-
/**
|
|
76
|
-
readonly ipc?: (caps: PackHostWindowCapabilities) => readonly IpcContribution[];
|
|
77
|
-
/** BS:/host/<packId>/* 路由贡献。 */
|
|
67
|
+
/** /host/<packId>/* 路由贡献。 */
|
|
78
68
|
readonly httpRoutes?: () => readonly HttpRouteContribution[];
|
|
79
69
|
}
|
|
80
70
|
export type PackAssembly = (deps: PackAssemblyDeps) => PackAssemblyHandle | void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 包装配注册表(阶段 2.3)——纯构建期组合的宿主侧机制。
|
|
3
3
|
*
|
|
4
|
-
* 宿主(host/runtime.ts、
|
|
4
|
+
* 宿主(host/runtime.ts、server/index.ts)不再静态 import 任何
|
|
5
5
|
* 包代码:产品组装根(products/<id>/active.ts)把包的装配函数注册进本
|
|
6
6
|
* 注册表,宿主在装配期逐个调用。产品的 tsc 编译单元只 include 自己的包,
|
|
7
7
|
* 他包代码物理上不进产品 dist。
|
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
* - import 期(active.ts 顶层):迁移/种子/品牌等无宿主依赖的注册;
|
|
11
11
|
* - 装配期(createHostRuntime 内):服务/工具/路由等需要宿主能力的部分,
|
|
12
12
|
* 经 {@link PackAssemblyDeps} 注入。
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 不出现任何包名。
|
|
13
|
+
* server/index.ts 消费 handle.httpRoutes——包的入口面贡献由宿主循环驱动,
|
|
14
|
+
* 宿主代码里不出现任何包名。
|
|
16
15
|
*/
|
|
17
16
|
const assemblies = new Map();
|
|
18
17
|
/** 注册包的装配函数(产品组装根在 import 期调用;重复注册同包抛错)。 */
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主进程界面文案。与渲染层同一规则:英文是源句,应用层 registerLocale 注入译文。
|
|
3
|
+
* 本模块不依赖 Electron,菜单在 app ready 时读取。
|
|
4
|
+
*/
|
|
5
|
+
export declare const SOURCE_LOCALE = "en";
|
|
6
|
+
export declare function normalizeLocale(raw: string | null | undefined): string | null;
|
|
7
|
+
export declare function resolveLocale(options: {
|
|
8
|
+
supported: readonly string[];
|
|
9
|
+
defaultLocale: string;
|
|
10
|
+
saved: string | null;
|
|
11
|
+
system: string | null;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function registerLocale(locale: string, messages: Record<string, string>): void;
|
|
14
|
+
export declare function configureI18n(options: {
|
|
15
|
+
locales: readonly string[];
|
|
16
|
+
defaultLocale: string;
|
|
17
|
+
systemLocale?: string | null;
|
|
18
|
+
savedLocale?: string | null;
|
|
19
|
+
}): void;
|
|
20
|
+
export declare function getLocale(): string;
|
|
21
|
+
export declare function setLocale(locale: string): boolean;
|
|
22
|
+
export declare function t(message: string, params?: Record<string, string | number>): string;
|
|
23
|
+
export declare function resetI18nForTests(): void;
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主进程界面文案。与渲染层同一规则:英文是源句,应用层 registerLocale 注入译文。
|
|
3
|
+
* 本模块不依赖 Electron,菜单在 app ready 时读取。
|
|
4
|
+
*/
|
|
5
|
+
export const SOURCE_LOCALE = 'en';
|
|
6
|
+
export function normalizeLocale(raw) {
|
|
7
|
+
if (!raw)
|
|
8
|
+
return null;
|
|
9
|
+
const lower = raw.trim().toLowerCase().replace(/_/g, '-');
|
|
10
|
+
if (!lower)
|
|
11
|
+
return null;
|
|
12
|
+
if (lower.startsWith('zh'))
|
|
13
|
+
return 'zh';
|
|
14
|
+
if (lower.startsWith('en'))
|
|
15
|
+
return 'en';
|
|
16
|
+
const primary = lower.split('-')[0];
|
|
17
|
+
return primary || null;
|
|
18
|
+
}
|
|
19
|
+
export function resolveLocale(options) {
|
|
20
|
+
const supported = options.supported.filter((locale) => locale.length > 0);
|
|
21
|
+
const list = supported.length > 0 ? supported : [SOURCE_LOCALE];
|
|
22
|
+
const pick = (value) => {
|
|
23
|
+
if (!value)
|
|
24
|
+
return null;
|
|
25
|
+
if (list.includes(value))
|
|
26
|
+
return value;
|
|
27
|
+
const normalized = normalizeLocale(value);
|
|
28
|
+
if (normalized && list.includes(normalized))
|
|
29
|
+
return normalized;
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
return (pick(options.saved) ??
|
|
33
|
+
pick(options.system) ??
|
|
34
|
+
pick(options.defaultLocale) ??
|
|
35
|
+
list[0] ??
|
|
36
|
+
SOURCE_LOCALE);
|
|
37
|
+
}
|
|
38
|
+
function formatMessage(template, params) {
|
|
39
|
+
if (!params)
|
|
40
|
+
return template;
|
|
41
|
+
return template.replace(/\{(\w+)\}/g, (whole, name) => {
|
|
42
|
+
const value = params[name];
|
|
43
|
+
return value === undefined ? whole : String(value);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const catalogs = {};
|
|
47
|
+
let locales = [SOURCE_LOCALE];
|
|
48
|
+
let defaultLocale = SOURCE_LOCALE;
|
|
49
|
+
let current = SOURCE_LOCALE;
|
|
50
|
+
export function registerLocale(locale, messages) {
|
|
51
|
+
const normalized = locale.trim();
|
|
52
|
+
if (!normalized || normalized === SOURCE_LOCALE)
|
|
53
|
+
return;
|
|
54
|
+
catalogs[normalized] = { ...catalogs[normalized], ...messages };
|
|
55
|
+
}
|
|
56
|
+
export function configureI18n(options) {
|
|
57
|
+
const next = [...new Set(options.locales.filter((locale) => locale.length > 0))];
|
|
58
|
+
locales = next.length > 0 ? next : [SOURCE_LOCALE];
|
|
59
|
+
defaultLocale = options.defaultLocale || SOURCE_LOCALE;
|
|
60
|
+
current = resolveLocale({
|
|
61
|
+
supported: locales,
|
|
62
|
+
defaultLocale,
|
|
63
|
+
saved: options.savedLocale ?? null,
|
|
64
|
+
system: options.systemLocale ?? null,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function getLocale() {
|
|
68
|
+
return current;
|
|
69
|
+
}
|
|
70
|
+
export function setLocale(locale) {
|
|
71
|
+
if (!locales.includes(locale))
|
|
72
|
+
return false;
|
|
73
|
+
current = locale;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
export function t(message, params) {
|
|
77
|
+
const table = current === SOURCE_LOCALE ? undefined : catalogs[current];
|
|
78
|
+
const template = table?.[message] ?? message;
|
|
79
|
+
return formatMessage(template, params);
|
|
80
|
+
}
|
|
81
|
+
export function resetI18nForTests() {
|
|
82
|
+
for (const key of Object.keys(catalogs))
|
|
83
|
+
delete catalogs[key];
|
|
84
|
+
locales = [SOURCE_LOCALE];
|
|
85
|
+
defaultLocale = SOURCE_LOCALE;
|
|
86
|
+
current = SOURCE_LOCALE;
|
|
87
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { NativeImageLike } from './runtime.js';
|
|
2
1
|
import type { LlmImage } from './llm/types.js';
|
|
3
2
|
/** Refuse to read source files larger than this (10 MB). */
|
|
4
3
|
export declare const IMAGE_MAX_SOURCE_BYTES: number;
|
|
@@ -6,6 +5,34 @@ export declare const IMAGE_MAX_SOURCE_BYTES: number;
|
|
|
6
5
|
export declare const IMAGE_MAX_DIMENSION = 1568;
|
|
7
6
|
/** Refuse the encoded payload if it still exceeds this after re-encode (5 MB). */
|
|
8
7
|
export declare const IMAGE_MAX_ENCODED_BYTES: number;
|
|
8
|
+
/** A decoded raster that can be cropped, resized, and re-encoded synchronously. */
|
|
9
|
+
export interface DecodedImage {
|
|
10
|
+
isEmpty(): boolean;
|
|
11
|
+
getSize(): {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
crop(rect: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}): DecodedImage;
|
|
21
|
+
resize(o: {
|
|
22
|
+
width?: number;
|
|
23
|
+
height?: number;
|
|
24
|
+
quality?: string;
|
|
25
|
+
}): DecodedImage;
|
|
26
|
+
toPNG(): Buffer;
|
|
27
|
+
toJPEG(quality: number): Buffer;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Optional image decoder. Without one, images pass through as the original
|
|
31
|
+
* bytes and crop / resize / transcode requests are refused.
|
|
32
|
+
*/
|
|
33
|
+
export interface ImageDecoder {
|
|
34
|
+
createFromPath(p: string): DecodedImage;
|
|
35
|
+
}
|
|
9
36
|
export interface ImageAttachmentInput {
|
|
10
37
|
path: string;
|
|
11
38
|
name?: string;
|
|
@@ -65,9 +92,9 @@ export declare function computeTargetSize(width: number, height: number, maxDime
|
|
|
65
92
|
* tool result. `_image` is consumed by the CoreLoop as an image content part;
|
|
66
93
|
* it is not a path or model-visible base64 string.
|
|
67
94
|
*/
|
|
68
|
-
export declare function processViewImage(input: ViewImageInput,
|
|
95
|
+
export declare function processViewImage(input: ViewImageInput, decoder?: ImageDecoder | null): ViewImageResult;
|
|
69
96
|
/**
|
|
70
|
-
* Process a batch of image attachments. Synchronous:
|
|
97
|
+
* Process a batch of image attachments. Synchronous: decoder decode /
|
|
71
98
|
* resize / encode are all synchronous, and the byte check uses `statSync`.
|
|
72
99
|
*/
|
|
73
|
-
export declare function processImageAttachments(files: ImageAttachmentInput[]): ProcessedImageAttachments;
|
|
100
|
+
export declare function processImageAttachments(files: ImageAttachmentInput[], decoder?: ImageDecoder | null): ProcessedImageAttachments;
|
package/dist/image-attachment.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* actually see, replacing the old behavior of dropping only the file *path*
|
|
4
4
|
* into the prompt text.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* enforced before the image ever reaches the model:
|
|
6
|
+
* Decoding / downscaling runs only when an {@link ImageDecoder} is supplied;
|
|
7
|
+
* otherwise the original bytes pass through under the encoded cap. These caps
|
|
8
|
+
* are enforced before the image ever reaches the model:
|
|
9
9
|
*
|
|
10
10
|
* - source bytes (`IMAGE_MAX_SOURCE_BYTES`) — refuse to read huge files;
|
|
11
11
|
* - long-edge px (`IMAGE_MAX_DIMENSION`) — downscale so the provider's
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
* line so the caller can inject it into the model-visible context — the model
|
|
18
18
|
* should know an image was attached even when it was too large to send.
|
|
19
19
|
*/
|
|
20
|
-
import { getNativeImage } from './runtime.js';
|
|
21
20
|
import { readFileSync, statSync } from 'fs';
|
|
22
21
|
import { basename, extname } from 'path';
|
|
23
22
|
/** Refuse to read source files larger than this (10 MB). */
|
|
@@ -74,7 +73,7 @@ export function computeTargetSize(width, height, maxDimension = IMAGE_MAX_DIMENS
|
|
|
74
73
|
* tool result. `_image` is consumed by the CoreLoop as an image content part;
|
|
75
74
|
* it is not a path or model-visible base64 string.
|
|
76
75
|
*/
|
|
77
|
-
export function processViewImage(input,
|
|
76
|
+
export function processViewImage(input, decoder = null) {
|
|
78
77
|
if (!isImagePath(input.path)) {
|
|
79
78
|
return {
|
|
80
79
|
success: false,
|
|
@@ -104,10 +103,10 @@ export function processViewImage(input, nativeImage = getNativeImage()) {
|
|
|
104
103
|
needsFollowup: true,
|
|
105
104
|
};
|
|
106
105
|
}
|
|
107
|
-
if (!
|
|
106
|
+
if (!decoder) {
|
|
108
107
|
return viewImageWithoutDecoder(input, sourceBytes, maxEdge);
|
|
109
108
|
}
|
|
110
|
-
let rendered =
|
|
109
|
+
let rendered = decoder.createFromPath(input.path);
|
|
111
110
|
if (rendered.isEmpty()) {
|
|
112
111
|
return { success: false, error: '不是可识别的图片', needsFollowup: true };
|
|
113
112
|
}
|
|
@@ -262,16 +261,15 @@ function formatMb(bytes) {
|
|
|
262
261
|
return (bytes / (1024 * 1024)).toFixed(1).replace(/\.0$/, '');
|
|
263
262
|
}
|
|
264
263
|
/**
|
|
265
|
-
* Process a batch of image attachments. Synchronous:
|
|
264
|
+
* Process a batch of image attachments. Synchronous: decoder decode /
|
|
266
265
|
* resize / encode are all synchronous, and the byte check uses `statSync`.
|
|
267
266
|
*/
|
|
268
|
-
export function processImageAttachments(files) {
|
|
267
|
+
export function processImageAttachments(files, decoder = null) {
|
|
269
268
|
const images = [];
|
|
270
269
|
const notes = [];
|
|
271
270
|
for (const file of files) {
|
|
272
271
|
const label = file.name || basename(file.path);
|
|
273
|
-
// Existence + source-size guards run before the decoder
|
|
274
|
-
// exercisable in a non-Electron (test) host too.
|
|
272
|
+
// Existence + source-size guards run before the decoder.
|
|
275
273
|
let sourceBytes = 0;
|
|
276
274
|
try {
|
|
277
275
|
sourceBytes = statSync(file.path).size;
|
|
@@ -284,12 +282,9 @@ export function processImageAttachments(files) {
|
|
|
284
282
|
notes.push(`- ${label}:源文件 ${formatMb(sourceBytes)}MB 超过 ${formatMb(IMAGE_MAX_SOURCE_BYTES)}MB 上限,未附加`);
|
|
285
283
|
continue;
|
|
286
284
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
// nativeImage. The bytes are already a PNG/JPEG the provider can read;
|
|
291
|
-
// pass them through when they fit the encoded cap. Resize stays on the
|
|
292
|
-
// Electron path.
|
|
285
|
+
if (!decoder) {
|
|
286
|
+
// The bytes are already an image the provider can read; pass them
|
|
287
|
+
// through when they fit the encoded cap.
|
|
293
288
|
if (sourceBytes > IMAGE_MAX_ENCODED_BYTES) {
|
|
294
289
|
notes.push(`- ${label}:源文件 ${formatMb(sourceBytes)}MB 超过 ${formatMb(IMAGE_MAX_ENCODED_BYTES)}MB,当前环境不能缩放,未附加`);
|
|
295
290
|
continue;
|
|
@@ -307,7 +302,7 @@ export function processImageAttachments(files) {
|
|
|
307
302
|
notes.push(`- ${label}(原图)`);
|
|
308
303
|
continue;
|
|
309
304
|
}
|
|
310
|
-
const image =
|
|
305
|
+
const image = decoder.createFromPath(file.path);
|
|
311
306
|
if (image.isEmpty()) {
|
|
312
307
|
notes.push(`- ${label}:不是可识别的图片,未附加`);
|
|
313
308
|
continue;
|
package/dist/json-store.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JSON 键值存储工厂(agent-mcp-servers.json / agent-projects.json /
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* 而 conf(electron-store 的底层,已是本项目直接依赖)API 完全覆盖用到的
|
|
6
|
-
* get/set + name + defaults 子集。统一走 conf + getUserDataDir(),Electron
|
|
7
|
-
* 与 BS server 得到同一个文件路径,两种模式共享同一份数据。
|
|
2
|
+
* JSON 键值存储工厂(agent-mcp-servers.json / agent-projects.json /
|
|
3
|
+
* agent-local-scripts.json)。文件在 getUserDataDir() 下,由 conf 读写;
|
|
4
|
+
* 桌面与 BS server 得到同一个文件路径。
|
|
8
5
|
*
|
|
9
6
|
* conf@10 的 d.ts 是 ESM 风格但包本身没有 `type: module`,NodeNext 下类型
|
|
10
7
|
* 解析会塌成 namespace——所以这里声明用到的最小接口并做一次强转,不依赖
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* 钥匙(模型 Key、搜索 Key、MCP 环境变量)默认不进包;`includeSecrets`
|
|
6
6
|
* 为 true 时原样写入,导入方要自己确认。
|
|
7
7
|
*/
|
|
8
|
+
import { t } from '../i18n.js';
|
|
8
9
|
export const PORTABLE_SCHEMA_VERSION = 1;
|
|
9
10
|
export const PORTABLE_MESSAGE_LIMIT = 1000;
|
|
10
11
|
export const PORTABLE_CONFIG_KIND = 'steerable-config';
|
|
@@ -64,19 +65,19 @@ export function readPortableProject(raw) {
|
|
|
64
65
|
}
|
|
65
66
|
function thinkingLabel(mode) {
|
|
66
67
|
if (mode === 'hidden')
|
|
67
|
-
return '
|
|
68
|
+
return t('Hide');
|
|
68
69
|
if (mode === 'full')
|
|
69
|
-
return '
|
|
70
|
+
return t('Show all');
|
|
70
71
|
if (mode === 'peek')
|
|
71
|
-
return '
|
|
72
|
-
return '
|
|
72
|
+
return t('Show 5 lines');
|
|
73
|
+
return t('Unrecognized display mode');
|
|
73
74
|
}
|
|
74
75
|
function execLabel(policy) {
|
|
75
76
|
if (policy === 'full')
|
|
76
|
-
return '
|
|
77
|
+
return t('Full access');
|
|
77
78
|
if (policy === 'workspace')
|
|
78
|
-
return '
|
|
79
|
-
return '
|
|
79
|
+
return t('Workspace');
|
|
80
|
+
return t('Unrecognized permission');
|
|
80
81
|
}
|
|
81
82
|
export function llmSectionFromSettings(settings, includeSecrets) {
|
|
82
83
|
const apiKey = asString(settings.apiKey);
|
|
@@ -163,7 +163,7 @@ function buildLocalAgent() {
|
|
|
163
163
|
platform: process.platform,
|
|
164
164
|
hostname: 'localhost',
|
|
165
165
|
shell: process.platform === 'win32' ? 'powershell' : 'zsh',
|
|
166
|
-
osVersion:
|
|
166
|
+
osVersion: null,
|
|
167
167
|
osArch: process.arch,
|
|
168
168
|
isOnline: true,
|
|
169
169
|
lastHeartbeat: now,
|
|
@@ -461,7 +461,7 @@ export class LocalBackendRouter {
|
|
|
461
461
|
return { status: 200, data: { deletedChatIds } };
|
|
462
462
|
}
|
|
463
463
|
// ───── 项目模式:projects CRUD ─────
|
|
464
|
-
// 项目记录存
|
|
464
|
+
// 项目记录存 json-store(agent-projects.json),chat.project_id 存
|
|
465
465
|
// SQLite。删除项目不删会话——会话降级为无项目对话。
|
|
466
466
|
if ((pathname === '/api/v2/projects' || pathname.startsWith('/api/v2/projects/')) &&
|
|
467
467
|
!getResolvedHostTools().projects.capability) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-skill
|
|
3
|
-
displayName:
|
|
3
|
+
displayName: Create a skill
|
|
4
4
|
description: 按本产品的 SKILL.md 规范创建一个新的本地技能,含目录结构、frontmatter 字段、写作要求。写到项目 skills/ 目录后自动出现在 Skill 设置与 / 菜单。用户说「做个技能 / 写个 skill / 把这套流程固化下来」时使用。
|
|
5
5
|
priority: 500
|
|
6
6
|
tags: [skill, authoring, meta]
|
|
@@ -40,7 +40,7 @@ disable-model-invocation: true
|
|
|
40
40
|
```markdown
|
|
41
41
|
---
|
|
42
42
|
name: my-skill
|
|
43
|
-
displayName:
|
|
43
|
+
displayName: My skill
|
|
44
44
|
description: 做什么 + 什么时候用,一句话说清。
|
|
45
45
|
priority: 500
|
|
46
46
|
tags: [workflow]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import Store from 'electron-store';
|
|
2
1
|
import { randomUUID } from 'crypto';
|
|
2
|
+
import { createJsonStore } from './json-store.js';
|
|
3
3
|
export class LocalScriptRegistry {
|
|
4
4
|
store;
|
|
5
5
|
constructor() {
|
|
6
|
-
this.store =
|
|
6
|
+
this.store = createJsonStore({
|
|
7
7
|
name: 'agent-local-scripts',
|
|
8
8
|
defaults: {
|
|
9
9
|
localScripts: [],
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* 持久化在 userData/agent-mcp-servers.json。已启用服务的工具会经
|
|
6
6
|
* ToolRouter 以 `mcp__<serverKey>__<toolName>` 一等工具身份暴露给模型。
|
|
7
7
|
*
|
|
8
|
-
* 存储通过 {@link McpServerKvStore}
|
|
9
|
-
*
|
|
8
|
+
* 存储通过 {@link McpServerKvStore} 接口注入:宿主用 json-store 实现,
|
|
9
|
+
* 单测用内存实现。
|
|
10
10
|
*/
|
|
11
11
|
import { type McpExecutorLike, type McpServerConfig } from './mcp-executor.js';
|
|
12
12
|
interface McpServerCommon {
|
|
@@ -74,7 +74,7 @@ export interface UpdateMcpServerInput {
|
|
|
74
74
|
reconnect?: StreamableHttpMcpServerEntry['reconnect'];
|
|
75
75
|
enabled?: boolean;
|
|
76
76
|
}
|
|
77
|
-
/** 最小 KV
|
|
77
|
+
/** 最小 KV 存储接口,避免本模块直接依赖具体存储实现。 */
|
|
78
78
|
export interface McpServerKvStore {
|
|
79
79
|
get(key: 'mcpServers'): McpServerEntry[] | undefined;
|
|
80
80
|
set(key: 'mcpServers', value: McpServerEntry[]): void;
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* 持久化在 userData/agent-mcp-servers.json。已启用服务的工具会经
|
|
6
6
|
* ToolRouter 以 `mcp__<serverKey>__<toolName>` 一等工具身份暴露给模型。
|
|
7
7
|
*
|
|
8
|
-
* 存储通过 {@link McpServerKvStore}
|
|
9
|
-
*
|
|
8
|
+
* 存储通过 {@link McpServerKvStore} 接口注入:宿主用 json-store 实现,
|
|
9
|
+
* 单测用内存实现。
|
|
10
10
|
*/
|
|
11
11
|
import { randomUUID } from 'node:crypto';
|
|
12
12
|
import { MAX_MCP_SERVER_TOOLS, mcpExecutor, } from './mcp-executor.js';
|
package/dist/product-config.d.ts
CHANGED
|
@@ -15,13 +15,6 @@ export interface ProductLinks {
|
|
|
15
15
|
/** 帮助菜单「访问官网」URL。 */
|
|
16
16
|
website?: string;
|
|
17
17
|
}
|
|
18
|
-
export interface ProductUpdates {
|
|
19
|
-
/**
|
|
20
|
-
* electron-updater generic 通道根地址(目录,不含 latest*.yml)。
|
|
21
|
-
* 打包配置里的 publishUrl 由产品组装根注入到这里。空则不检查更新。
|
|
22
|
-
*/
|
|
23
|
-
feedUrl?: string;
|
|
24
|
-
}
|
|
25
18
|
export interface ProductConfig {
|
|
26
19
|
/**
|
|
27
20
|
* 云端遥测端点(insights flush 的 API base)。空 = 不上报(中性默认);
|
|
@@ -31,13 +24,8 @@ export interface ProductConfig {
|
|
|
31
24
|
/** 帮助菜单链接;缺省的项不渲染。 */
|
|
32
25
|
links?: ProductLinks;
|
|
33
26
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*/
|
|
37
|
-
updates?: ProductUpdates;
|
|
38
|
-
/**
|
|
39
|
-
* BS 模式的 userData 目录名(~/ 下)。CS 模式由 Electron 按
|
|
40
|
-
* productName 分目录,不经此字段。
|
|
27
|
+
* 未设置 `DEEPPATH_USER_DATA_DIR` 时的 userData 目录名(~/ 下)。
|
|
28
|
+
* Tauri 宿主总是注入该环境变量,不经此字段。
|
|
41
29
|
*/
|
|
42
30
|
dataDirName?: string;
|
|
43
31
|
/**
|
|
@@ -130,6 +118,14 @@ export interface ProductConfig {
|
|
|
130
118
|
maxDepth?: number;
|
|
131
119
|
maxParallel?: number;
|
|
132
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* 界面语言。缺省只有 `en`。译文在应用层语言包,不在本包。
|
|
123
|
+
* `locales` 是这个产品装进包里的语言;多于一种时设置页才出现切换。
|
|
124
|
+
*/
|
|
125
|
+
i18n?: {
|
|
126
|
+
locales: string[];
|
|
127
|
+
defaultLocale: string;
|
|
128
|
+
};
|
|
133
129
|
}
|
|
134
130
|
/** shell 内置智能体:只有产品显式 `true` 才开。 */
|
|
135
131
|
export declare function isShellBuiltinAgentEnabled(id: 'local-assistant' | 'all-round-assistant', config?: ProductConfig): boolean;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* 源文件夹及其子目录同样可写。
|
|
9
9
|
*
|
|
10
10
|
* 持久化在 userData/agent-projects.json。存储通过 {@link ProjectKvStore}
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* 接口注入:宿主用 json-store 实现,单测用内存实现(与
|
|
12
|
+
* mcp-server-registry.ts 同一模式)。
|
|
13
13
|
*/
|
|
14
14
|
export interface ProjectRecord {
|
|
15
15
|
id: string;
|
|
@@ -38,7 +38,7 @@ export interface CreateProjectInput {
|
|
|
38
38
|
folderPath: string;
|
|
39
39
|
sourceFolders?: string[];
|
|
40
40
|
}
|
|
41
|
-
/** 最小 KV
|
|
41
|
+
/** 最小 KV 存储接口,避免本模块直接依赖具体存储实现。 */
|
|
42
42
|
export interface ProjectKvStore {
|
|
43
43
|
get(key: 'projects'): ProjectRecord[] | undefined;
|
|
44
44
|
set(key: 'projects', value: ProjectRecord[]): void;
|
package/dist/project-registry.js
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* 源文件夹及其子目录同样可写。
|
|
9
9
|
*
|
|
10
10
|
* 持久化在 userData/agent-projects.json。存储通过 {@link ProjectKvStore}
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* 接口注入:宿主用 json-store 实现,单测用内存实现(与
|
|
12
|
+
* mcp-server-registry.ts 同一模式)。
|
|
13
13
|
*/
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
15
|
const STORE_KEY = 'projects';
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/** Electron 主进程里 `process.versions.electron` 有值;普通 Node(BS server、vitest)没有。 */
|
|
2
|
-
export declare function isElectronRuntime(): boolean;
|
|
3
1
|
/** 应用数据目录(SQLite、JSON store、用户技能目录的根)。 */
|
|
4
2
|
export declare function getUserDataDir(): string;
|
|
5
3
|
/**
|
|
@@ -15,59 +13,15 @@ export declare function getDocumentsDir(): string;
|
|
|
15
13
|
export declare function setAppRootDir(dir: string): void;
|
|
16
14
|
export declare function getAppRootDir(): string;
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* (shellDir 一般为 shell main.js 所在目录)。
|
|
25
|
-
*/
|
|
26
|
-
export declare function getPreloadPath(shellDir: string): string;
|
|
27
|
-
/**
|
|
28
|
-
* 产品 web 产物目录(2.3):产品入口(products/<id>/{main,server}.ts)
|
|
29
|
-
* 用本函数把 DEEPPATH_WEB_DIST 注入环境,shell 的 main/server 据此定位
|
|
30
|
-
* web dist。双平面探测:源码平面入口在 products/<id>/(web dist 在同级
|
|
31
|
-
* web/dist);编译平面入口在 products/<id>/dist/products/<id>/(web dist
|
|
32
|
-
* 在仓库根的 products/<id>/web/dist)。两处都没有返回 null(打包后的
|
|
33
|
-
* CS 走 app.getAppPath()/web-dist 约定,不经本函数)。
|
|
16
|
+
* 产品 web 产物目录(2.3):产品入口(products/<id>/server.ts)用本函数
|
|
17
|
+
* 把 DEEPPATH_WEB_DIST 注入环境,shell server 据此定位 web dist。双平面
|
|
18
|
+
* 探测:源码平面入口在 products/<id>/(web dist 在同级 web/dist);编译
|
|
19
|
+
* 平面入口在 products/<id>/dist/products/<id>/(web dist 在仓库根的
|
|
20
|
+
* products/<id>/web/dist)。两处都没有返回 null(打包后的 Tauri 宿主直接
|
|
21
|
+
* 注入 DEEPPATH_WEB_DIST,不经本函数)。
|
|
34
22
|
*/
|
|
35
23
|
export declare function resolveProductWebDist(entryUrl: string): string | null;
|
|
36
|
-
/**
|
|
24
|
+
/** 用系统默认应用打开本地路径。返回空串表示成功,否则是错误消息。 */
|
|
37
25
|
export declare function shellOpenPath(target: string): Promise<string>;
|
|
38
|
-
/** 用系统浏览器打开 URL
|
|
26
|
+
/** 用系统浏览器打开 URL。 */
|
|
39
27
|
export declare function shellOpenExternal(url: string): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* 注册应用退出钩子(sidecar 的兜底清理)。BS 下没有 app 生命周期——
|
|
42
|
-
* 宿主退出由 server 的 SIGINT/SIGTERM 钩子统一负责,这里 no-op。
|
|
43
|
-
*/
|
|
44
|
-
export declare function onAppWillQuit(listener: () => void): void;
|
|
45
|
-
export declare function offAppWillQuit(listener: () => void): void;
|
|
46
|
-
export interface NativeImageInstance {
|
|
47
|
-
isEmpty(): boolean;
|
|
48
|
-
getSize(): {
|
|
49
|
-
width: number;
|
|
50
|
-
height: number;
|
|
51
|
-
};
|
|
52
|
-
crop(rect: {
|
|
53
|
-
x: number;
|
|
54
|
-
y: number;
|
|
55
|
-
width: number;
|
|
56
|
-
height: number;
|
|
57
|
-
}): NativeImageInstance;
|
|
58
|
-
resize(o: {
|
|
59
|
-
width?: number;
|
|
60
|
-
height?: number;
|
|
61
|
-
quality?: string;
|
|
62
|
-
}): NativeImageInstance;
|
|
63
|
-
toPNG(): Buffer;
|
|
64
|
-
toJPEG(quality: number): Buffer;
|
|
65
|
-
}
|
|
66
|
-
export interface NativeImageLike {
|
|
67
|
-
createFromPath(p: string): NativeImageInstance;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Electron `nativeImage`(图片解码/缩放)。BS / 单测等无 Electron 环境返回
|
|
71
|
-
* null——调用方按"不支持图片解码"降级(image-attachment 已有该分支)。
|
|
72
|
-
*/
|
|
73
|
-
export declare function getNativeImage(): NativeImageLike | null;
|