dsh-composer-ux 0.5.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +229 -0
- package/README.md +31 -7
- package/lib/client.js +581 -291
- package/lib/client.js.map +4 -4
- package/lib/index.js +992 -204
- package/lib/index.js.map +4 -4
- package/package.json +3 -4
package/lib/index.js
CHANGED
|
@@ -17,6 +17,32 @@ function pick(source, keys, forced) {
|
|
|
17
17
|
for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
|
|
18
18
|
return result;
|
|
19
19
|
}
|
|
20
|
+
var write = Symbol.for("cosmokit.volatile.write");
|
|
21
|
+
function snapshot(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
22
|
+
if (typeof value === "function") throw new TypeError("volatile config cannot contain functions");
|
|
23
|
+
if (value === null || typeof value !== "object") return value;
|
|
24
|
+
if (ancestors.has(value)) throw new TypeError("volatile config cannot contain cycles");
|
|
25
|
+
ancestors.add(value);
|
|
26
|
+
try {
|
|
27
|
+
if (Array.isArray(value)) return Object.freeze(value.map((item) => snapshot(item, ancestors)));
|
|
28
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new TypeError("volatile config objects must be plain objects or arrays");
|
|
29
|
+
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])));
|
|
30
|
+
} finally {
|
|
31
|
+
ancestors.delete(value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createVolatile(value) {
|
|
35
|
+
let current = snapshot(value);
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
get: () => current,
|
|
38
|
+
[write]: (value2) => {
|
|
39
|
+
current = value2;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function isVolatile(value) {
|
|
44
|
+
return typeof value === "object" && value !== null && write in value;
|
|
45
|
+
}
|
|
20
46
|
function is(type, value) {
|
|
21
47
|
if (arguments.length === 1) return (value2) => is(type, value2);
|
|
22
48
|
return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
|
|
@@ -95,24 +121,37 @@ function clone(source, refs = /* @__PURE__ */ new Map()) {
|
|
|
95
121
|
return result;
|
|
96
122
|
}
|
|
97
123
|
function deepEqual(a, b, strict) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
125
|
+
function compare(a2, b2) {
|
|
126
|
+
if (a2 === b2) return true;
|
|
127
|
+
if (isVolatile(a2) || isVolatile(b2)) return isVolatile(a2) && isVolatile(b2);
|
|
128
|
+
if (!strict && isNullable(a2) && isNullable(b2)) return true;
|
|
129
|
+
if (typeof a2 !== typeof b2 || typeof a2 !== "object" || !a2 || !b2) return false;
|
|
130
|
+
if (ancestors.has(a2)) return false;
|
|
131
|
+
function check(test, then) {
|
|
132
|
+
return test(a2) ? test(b2) ? then(a2, b2) : false : test(b2) ? false : void 0;
|
|
133
|
+
}
|
|
134
|
+
ancestors.add(a2);
|
|
135
|
+
try {
|
|
136
|
+
return check(Array.isArray, (a3, b3) => {
|
|
137
|
+
if (a3.length !== b3.length) return false;
|
|
138
|
+
for (let index = 0; index < a3.length; index++) if (!compare(a3[index], b3[index])) return false;
|
|
139
|
+
return true;
|
|
140
|
+
}) ?? check(is("Date"), (a3, b3) => a3.valueOf() === b3.valueOf()) ?? check(is("URL"), (a3, b3) => a3.href === b3.href) ?? check(is("RegExp"), (a3, b3) => a3.source === b3.source && a3.flags === b3.flags) ?? check(isArrayBufferLike, (a3, b3) => {
|
|
141
|
+
if (a3.byteLength !== b3.byteLength) return false;
|
|
142
|
+
const viewA = new Uint8Array(a3);
|
|
143
|
+
const viewB = new Uint8Array(b3);
|
|
144
|
+
for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
|
|
145
|
+
return true;
|
|
146
|
+
}) ?? ((!strict || [a2, b2].every((value) => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) && Object.keys({
|
|
147
|
+
...a2,
|
|
148
|
+
...b2
|
|
149
|
+
}).every((key) => compare(a2[key], b2[key])));
|
|
150
|
+
} finally {
|
|
151
|
+
ancestors.delete(a2);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return compare(a, b);
|
|
116
155
|
}
|
|
117
156
|
var Time;
|
|
118
157
|
(function(Time2) {
|
|
@@ -361,6 +400,7 @@ Schema.prototype.pattern = function pattern(regexp) {
|
|
|
361
400
|
return schema;
|
|
362
401
|
};
|
|
363
402
|
Schema.prototype.simplify = function simplify(value) {
|
|
403
|
+
if (isVolatile(value)) value = value.get();
|
|
364
404
|
if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
|
|
365
405
|
if (isNullable(value)) return value;
|
|
366
406
|
if (this.type === "object" || this.type === "dict") {
|
|
@@ -418,12 +458,49 @@ for (const key of [
|
|
|
418
458
|
};
|
|
419
459
|
return schema;
|
|
420
460
|
} });
|
|
461
|
+
Schema.prototype.volatile = function volatile() {
|
|
462
|
+
if (this.meta.volatile) throw new TypeError("volatile schema is already wrapped");
|
|
463
|
+
return this.extra("volatile", true);
|
|
464
|
+
};
|
|
421
465
|
var resolvers = {};
|
|
466
|
+
var checkedVolatile = Symbol("checked-volatile-schema");
|
|
467
|
+
function validateVolatileSchema(schema, path = [], blocked = false, seen = /* @__PURE__ */ new Map()) {
|
|
468
|
+
const states = seen.get(schema) ?? /* @__PURE__ */ new Set();
|
|
469
|
+
if (states.has(blocked)) return;
|
|
470
|
+
states.add(blocked);
|
|
471
|
+
seen.set(schema, states);
|
|
472
|
+
if (schema.meta?.volatile && blocked) throw new ValidationError("volatile fields require a fixed object path without an enclosing volatile field", { path });
|
|
473
|
+
const nested = blocked || !!schema.meta?.volatile;
|
|
474
|
+
if (schema.dict) for (const [key, child] of Object.entries(schema.dict)) validateVolatileSchema(child, [...path, key], nested, seen);
|
|
475
|
+
if (schema.sKey) validateVolatileSchema(schema.sKey, [...path, "<key>"], true, seen);
|
|
476
|
+
if (schema.inner && (schema.type !== "lazy" || schema.inner[kSchema])) validateVolatileSchema(schema.inner, [...path, "*"], true, seen);
|
|
477
|
+
if (schema.list) for (let index = 0; index < schema.list.length; index++) validateVolatileSchema(schema.list[index], [...path, String(index)], true, seen);
|
|
478
|
+
}
|
|
422
479
|
Schema.extend = function extend(type, resolve3) {
|
|
423
480
|
resolvers[type] = resolve3;
|
|
424
481
|
};
|
|
425
482
|
Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
|
|
426
483
|
if (!schema) return [data];
|
|
484
|
+
if (!options[checkedVolatile]) {
|
|
485
|
+
validateVolatileSchema(schema, options.path);
|
|
486
|
+
options = {
|
|
487
|
+
...options,
|
|
488
|
+
[checkedVolatile]: true
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (schema.meta?.volatile) {
|
|
492
|
+
const inner = Schema(schema);
|
|
493
|
+
inner.meta = {
|
|
494
|
+
...schema.meta,
|
|
495
|
+
volatile: false
|
|
496
|
+
};
|
|
497
|
+
const [value, adapted] = Schema.resolve(data, inner, options, strict);
|
|
498
|
+
try {
|
|
499
|
+
return [createVolatile(value), adapted];
|
|
500
|
+
} catch (error) {
|
|
501
|
+
throw new ValidationError(error instanceof Error ? error.message : String(error), options);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
427
504
|
if (options.ignore?.(data, schema)) return [data];
|
|
428
505
|
if (isNullable(data) && schema.type !== "lazy") {
|
|
429
506
|
if (schema.meta.required) throw new ValidationError(`missing required value`, options);
|
|
@@ -531,6 +608,7 @@ Schema.extend("lazy", (data, schema, options, strict) => {
|
|
|
531
608
|
...schema.meta,
|
|
532
609
|
...schema.inner.meta
|
|
533
610
|
};
|
|
611
|
+
validateVolatileSchema(schema.inner, options.path, true);
|
|
534
612
|
}
|
|
535
613
|
return Schema.resolve(data, schema.inner, options, strict);
|
|
536
614
|
});
|
|
@@ -630,7 +708,7 @@ function property(data, key, schema, options) {
|
|
|
630
708
|
} catch (e) {
|
|
631
709
|
if (!options?.autofix) throw e;
|
|
632
710
|
delete data[key];
|
|
633
|
-
return schema.meta.default;
|
|
711
|
+
return schema.meta.volatile ? createVolatile(schema.meta.default) : schema.meta.default;
|
|
634
712
|
}
|
|
635
713
|
}
|
|
636
714
|
Schema.extend("array", (data, { inner, meta }, options) => {
|
|
@@ -790,7 +868,7 @@ defineMethod("transform", [
|
|
|
790
868
|
import { spawn } from "node:child_process";
|
|
791
869
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
792
870
|
import { tmpdir } from "node:os";
|
|
793
|
-
import { dirname as
|
|
871
|
+
import { dirname as dirname3, join as join3, resolve as resolve2 } from "node:path";
|
|
794
872
|
import inspector from "node:inspector";
|
|
795
873
|
|
|
796
874
|
// src/terminal/discover.ts
|
|
@@ -1008,6 +1086,9 @@ function terminalStatusText(input) {
|
|
|
1008
1086
|
if (input.mode === "pwsh") {
|
|
1009
1087
|
return "\u4FDD\u6301 DSH \u9ED8\u8BA4\uFF08PowerShell\uFF09\u2014\u2014\u672C\u63D2\u4EF6\u4E0D\u4ECB\u5165\u7EC8\u7AEF\u5DE5\u5177\u9762";
|
|
1010
1088
|
}
|
|
1089
|
+
if (input.probeFailed !== void 0 && input.probeFailed !== "") {
|
|
1090
|
+
return `\u5DF2\u542F\u7528\uFF0C\u4F46\u81EA\u68C0\u672A\u901A\u8FC7\uFF1A${input.probeFailed} \u2014\u2014 \u4E3A\u907F\u514D\u628A\u4F1A\u8BDD\u7684 shell \u6253\u6B7B\uFF0C\u6682\u4E0D\u63A5\u7BA1\uFF08\u4FDD\u6301 PowerShell\uFF09`;
|
|
1091
|
+
}
|
|
1011
1092
|
if (input.effective === "bash") {
|
|
1012
1093
|
const path = input.effectivePath ?? "";
|
|
1013
1094
|
const candidate = input.candidates.find((item) => item.path === path);
|
|
@@ -1018,6 +1099,9 @@ function terminalStatusText(input) {
|
|
|
1018
1099
|
const excluded = input.excludedCount > 0 ? `\uFF08\u5DF2\u6392\u9664 ${input.excludedCount} \u4E2A WSL \u7684 bash.exe\uFF09` : "";
|
|
1019
1100
|
return `\u6CA1\u627E\u5230\u53EF\u7528\u7684 bash${excluded}\uFF0C\u6682\u65F6\u4FDD\u6301 PowerShell`;
|
|
1020
1101
|
}
|
|
1102
|
+
if (input.deliveryFailed === true) {
|
|
1103
|
+
return "\u627E\u5230\u4E86 bash \u4F46\u6CA1\u80FD\u6362\u4E0A\uFF08\u5DF2\u56DE\u6EDA\uFF0Cpwsh \u7167\u65E7\u53EF\u7528\uFF09\uFF0C\u6682\u65F6\u4FDD\u6301 PowerShell";
|
|
1104
|
+
}
|
|
1021
1105
|
return `\u5019\u9009\u4E0D\u53EF\u7528\uFF0C\u6682\u65F6\u4FDD\u6301 PowerShell`;
|
|
1022
1106
|
})();
|
|
1023
1107
|
const failure = input.failure === void 0 || input.failure === "" ? "" : `\uFF1B\u4E0B\u53D1\u5931\u8D25\uFF1A${input.failure}`;
|
|
@@ -1035,7 +1119,6 @@ var PANEL_ENABLED_FIELD = "panelEnabled";
|
|
|
1035
1119
|
var TERMINAL_ENABLED_FIELD = "terminalEnabled";
|
|
1036
1120
|
var SEND_KEY_FIELD = "sendKey";
|
|
1037
1121
|
var NEWLINE_KEY_FIELD = "newlineKey";
|
|
1038
|
-
var PANEL_SCROLL_FIELD = "panelScroll";
|
|
1039
1122
|
var PANEL_RESIZE_FIELD = "panelResize";
|
|
1040
1123
|
var PANEL_WIDTH_FIELD = "panelWidth";
|
|
1041
1124
|
var PANEL_HEIGHT_FIELD = "panelHeight";
|
|
@@ -1069,7 +1152,21 @@ var QUICK_BOOK_VERSION = 2;
|
|
|
1069
1152
|
var DEFAULT_CATEGORY_NAME = "\u9ED8\u8BA4";
|
|
1070
1153
|
var OPTIMIZE_OUTPUT_MAX = 12e3;
|
|
1071
1154
|
var OPTIMIZER_API_PATH = "/composer-ux/optimize";
|
|
1155
|
+
var OPTIMIZER_TIERS = [
|
|
1156
|
+
{ id: "basic", label: "\u666E\u901A", hint: "\u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\uFF1A\u75C5\u53E5\u3001\u9519\u522B\u5B57\u3001\u6307\u4EE3\u4E0E\u542B\u7CCA\u8BCD\uFF0C\u4E0D\u65B0\u589E\u4EFB\u4F55\u9700\u6C42\uFF0C\u7BC7\u5E45\u7EA6\u4E3A\u539F\u6587 1.4 \u500D\u3002" },
|
|
1157
|
+
{ id: "advanced", label: "\u9AD8\u7EA7", hint: "\u5728\u4E0D\u52A8\u76EE\u6807\u7684\u524D\u63D0\u4E0B\uFF0C\u628A\u300C\u4F60\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3\u300D\u7684\u5FC5\u8981\u8981\u6C42\u8865\u6210\u5BF9 AI \u7684\u8981\u6C42\uFF0C\u6BCF\u6761\u90FD\u8981\u6307\u56DE\u4F60\u539F\u8BDD\u91CC\u7684\u67D0\u4E00\u53E5\u3002" },
|
|
1158
|
+
{ id: "extreme", label: "\u6781\u7AEF", hint: "\u6309\u590D\u6742\u4EFB\u52A1\u5904\u7406\uFF1A\u5728\u4E0A\u9762\u57FA\u7840\u4E0A\u518D\u52A0\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\u4E0E 2~4 \u79CD\u60C5\u51B5\u7684\u9884\u6848\u3002" }
|
|
1159
|
+
];
|
|
1072
1160
|
var DEFAULT_OPTIMIZER_TIER = "advanced";
|
|
1161
|
+
var OPTIMIZER_PROMPT_FIELDS = {
|
|
1162
|
+
basic: "optimizerPromptBasic",
|
|
1163
|
+
advanced: "optimizerPromptAdvanced",
|
|
1164
|
+
extreme: "optimizerPromptExtreme"
|
|
1165
|
+
};
|
|
1166
|
+
var OPTIMIZER_PROMPT_FIELD_LIST = OPTIMIZER_TIERS.map((item) => OPTIMIZER_PROMPT_FIELDS[item.id]);
|
|
1167
|
+
function optimizerPromptFieldOf(tier) {
|
|
1168
|
+
return OPTIMIZER_PROMPT_FIELDS[tier] ?? OPTIMIZER_PROMPT_FIELDS[DEFAULT_OPTIMIZER_TIER];
|
|
1169
|
+
}
|
|
1073
1170
|
var DEFAULT_QUICK_PROMPTS = [
|
|
1074
1171
|
{ id: "builtin-1", label: "\u4E00\u95EE\u4E00\u7B54", prompt: "\u4F60\u4E0D\u61C2\u7684\u5C31\u95EE\u6211\uFF0C\u4E00\u95EE\u4E00\u7B54\uFF1B\u540C\u65F6\u8BF4\u6E05\u695A\u4F60\u4E3A\u4EC0\u4E48\u8981\u95EE\u8BE5\u95EE\u9898\uFF1B\u76F4\u5230\u4F60\u5BF9\u6211\u7684\u76EE\u6807\u6709\u660E\u786E\u8BA4\u77E5\u540E\u518D\u5F00\u59CB\u5E72\u6D3B\u3002", always: false, firstOnly: false },
|
|
1075
1172
|
{ id: "builtin-2", label: "\u4EA4\u63A5\u6587\u6863", prompt: "\u628A\u8FD9\u6B21\u4EFB\u52A1\u3001\u5DF2\u5B8C\u6210\u5185\u5BB9\u3001\u5F53\u524D\u5361\u70B9\u3001\u4E0B\u4E00\u6B65\u8BA1\u5212\u3001\u8E29\u8FC7\u7684\u5751\uFF0C\u6574\u7406\u6210\u4E00\u4EFD\u4EA4\u63A5\u6587\u6863\uFF0C\u5199\u7ED9\u65B0\u4F1A\u8BDD\u770B\u3002", always: false, firstOnly: false },
|
|
@@ -1214,7 +1311,6 @@ var DEFAULT_SETTINGS = {
|
|
|
1214
1311
|
menuDelete: true,
|
|
1215
1312
|
menuSelectAll: true,
|
|
1216
1313
|
menuMode: "official",
|
|
1217
|
-
panelScroll: true,
|
|
1218
1314
|
panelResize: true,
|
|
1219
1315
|
headerEnabled: false,
|
|
1220
1316
|
headerName: DEFAULT_HEADER_NAME,
|
|
@@ -1225,6 +1321,10 @@ var DEFAULT_SETTINGS = {
|
|
|
1225
1321
|
headerStatus: "",
|
|
1226
1322
|
quickPrompts: DEFAULT_QUICK_PROMPTS,
|
|
1227
1323
|
optimizerTier: DEFAULT_OPTIMIZER_TIER,
|
|
1324
|
+
// 空串 = 用内置提示词。默认必须是空串:它同时就是「恢复内置」要写回去的值。
|
|
1325
|
+
optimizerPromptBasic: "",
|
|
1326
|
+
optimizerPromptAdvanced: "",
|
|
1327
|
+
optimizerPromptExtreme: "",
|
|
1228
1328
|
terminalMode: DEFAULT_TERMINAL_MODE,
|
|
1229
1329
|
terminalBashPath: "",
|
|
1230
1330
|
terminalCandidates: [],
|
|
@@ -1250,7 +1350,7 @@ var SECTION_SIGNALS = {
|
|
|
1250
1350
|
// (`menuModeFrom` 对"两个键都没有"给的就是 'official',天然满足"缺省 = 默认"。)
|
|
1251
1351
|
[MENU_ENABLED_FIELD]: (source) => menuModeFrom(source[MENU_MODE_FIELD], source[MENU_NATIVE_FIELD]) !== "official",
|
|
1252
1352
|
[QUICK_ENABLED_FIELD]: (source) => Array.isArray(source[QUICK_PROMPTS_FIELD]) && source[QUICK_PROMPTS_FIELD].length !== DEFAULT_QUICK_PROMPTS.length || touched(source, OPTIMIZER_TIER_FIELD, DEFAULT_OPTIMIZER_TIER),
|
|
1253
|
-
[PANEL_ENABLED_FIELD]: (source) => touched(source,
|
|
1353
|
+
[PANEL_ENABLED_FIELD]: (source) => touched(source, PANEL_RESIZE_FIELD, true) || source[PANEL_WIDTH_FIELD] !== void 0 || source[PANEL_HEIGHT_FIELD] !== void 0,
|
|
1254
1354
|
[TERMINAL_ENABLED_FIELD]: (source) => touched(source, TERMINAL_MODE_FIELD, DEFAULT_TERMINAL_MODE) || touched(source, TERMINAL_BASH_PATH_FIELD, "")
|
|
1255
1355
|
};
|
|
1256
1356
|
function touched(source, field, untouched) {
|
|
@@ -1506,6 +1606,7 @@ function createBashTool(deps, options) {
|
|
|
1506
1606
|
const escalationModes = escalationModesOf(deps);
|
|
1507
1607
|
const sep2 = options.sep ?? "\\";
|
|
1508
1608
|
const isAbsolute2 = options.isAbsolute ?? ((path) => /^([a-zA-Z]:[\\/]|[\\/])/.test(path));
|
|
1609
|
+
const electron = options.electron ?? process.versions.electron !== void 0;
|
|
1509
1610
|
const minTimeout = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1510
1611
|
const maxTimeout = options.maxTimeoutMs ?? MAX_TIMEOUT_MS;
|
|
1511
1612
|
const spawnSpec = (argv, cwd, dshEnv, signal) => ({
|
|
@@ -1519,7 +1620,17 @@ function createBashTool(deps, options) {
|
|
|
1519
1620
|
graceMs: GRACE_MS,
|
|
1520
1621
|
...signal === void 0 ? {} : { signal },
|
|
1521
1622
|
// dshEnv 必须显式带上:subprocess 会先按凭据形状清洗父环境(含清掉所有 DSH_*)。
|
|
1522
|
-
env: {
|
|
1623
|
+
env: {
|
|
1624
|
+
...ENV_OVERRIDES,
|
|
1625
|
+
...dshEnv,
|
|
1626
|
+
// ⚠️ 打包形态(Electron 桌面版)下必须补这一项。Windows 上受限模式的沙箱 runner
|
|
1627
|
+
// 的 argv[0] 是 `process.execPath`(`dsh-sandbox-local/lib/index.js:539`),桌面版里
|
|
1628
|
+
// 那就是 `DeepSeek Harness.exe`;而用 Electron 跑 JS 脚本**必须**带
|
|
1629
|
+
// `ELECTRON_RUN_AS_NODE=1`,否则它按 App 形态启动、原生初始化就失败
|
|
1630
|
+
// (2026-09-25 实测:零输出 / 0xC0000142)。官方 `sandbox-local` 只返回 argv、不带 env,
|
|
1631
|
+
// 所以这一项只能由 **spawn 方**补齐。对 `bash.exe` 本身无副作用(它不认这个变量)。
|
|
1632
|
+
...electron ? { ELECTRON_RUN_AS_NODE: "1" } : {}
|
|
1633
|
+
}
|
|
1523
1634
|
});
|
|
1524
1635
|
const readFrame = (handle, offsets) => {
|
|
1525
1636
|
const outRead = handle.collected.stdout?.readFrom(offsets.stdout);
|
|
@@ -1713,6 +1824,52 @@ ${raw.replace(/\n+$/, "")}
|
|
|
1713
1824
|
}
|
|
1714
1825
|
};
|
|
1715
1826
|
}
|
|
1827
|
+
var PROBE_COMMAND = "printf %s dsh-composer-ux-probe-ok";
|
|
1828
|
+
var PROBE_MARKER = "dsh-composer-ux-probe-ok";
|
|
1829
|
+
var PROBE_TIMEOUT_MS = 8e3;
|
|
1830
|
+
function formatProbeExit(exitCode) {
|
|
1831
|
+
if (exitCode === null) return "null\uFF08\u88AB\u4FE1\u53F7\u7ED3\u675F\uFF09";
|
|
1832
|
+
if (exitCode < 0 || exitCode >= 2147483648) {
|
|
1833
|
+
const unsigned = exitCode < 0 ? exitCode + 4294967296 : exitCode;
|
|
1834
|
+
return `0x${unsigned.toString(16).toUpperCase()}\uFF08${unsigned}\uFF09`;
|
|
1835
|
+
}
|
|
1836
|
+
return String(exitCode);
|
|
1837
|
+
}
|
|
1838
|
+
async function probeBashExecution(deps, options, exec) {
|
|
1839
|
+
const probeDeps = deps.shellEnv === void 0 ? deps : {
|
|
1840
|
+
...deps,
|
|
1841
|
+
shellEnv: {
|
|
1842
|
+
collect: (ctx) => {
|
|
1843
|
+
try {
|
|
1844
|
+
return deps.shellEnv?.collect(ctx) ?? {};
|
|
1845
|
+
} catch {
|
|
1846
|
+
return {};
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
try {
|
|
1852
|
+
const tool = createBashTool(probeDeps, { ...options, timeoutMs: PROBE_TIMEOUT_MS, maxTimeoutMs: PROBE_TIMEOUT_MS });
|
|
1853
|
+
const result = await tool.execute(
|
|
1854
|
+
{ command: PROBE_COMMAND, description: "composer-ux terminal self-check", timeoutMs: PROBE_TIMEOUT_MS },
|
|
1855
|
+
exec
|
|
1856
|
+
);
|
|
1857
|
+
if (result?.kind !== "foreground") return { ok: false, detail: "\u81EA\u68C0\u6CA1\u6709\u8D70\u524D\u53F0\u6267\u884C\u8DEF\u5F84" };
|
|
1858
|
+
if (result.timedOut === true) return { ok: false, detail: `\u81EA\u68C0\u8D85\u65F6\uFF08${PROBE_TIMEOUT_MS}ms\uFF09` };
|
|
1859
|
+
const text = result.stdout?.text ?? "";
|
|
1860
|
+
const exit = result.exitCode ?? 0;
|
|
1861
|
+
if (exit !== 0) {
|
|
1862
|
+
return {
|
|
1863
|
+
ok: false,
|
|
1864
|
+
detail: `\u81EA\u68C0\u547D\u4EE4\u9000\u51FA\u7801 ${formatProbeExit(exit)}${text.trim() === "" ? "\uFF08\u96F6\u8F93\u51FA\uFF09" : ""}`
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
if (!text.includes(PROBE_MARKER)) return { ok: false, detail: "\u81EA\u68C0\u6CA1\u62FF\u5230\u9884\u671F\u8F93\u51FA\uFF08\u547D\u4EE4\u6CA1\u771F\u6B63\u8DD1\u8D77\u6765\uFF09" };
|
|
1868
|
+
return { ok: true, detail: "" };
|
|
1869
|
+
} catch (error) {
|
|
1870
|
+
return { ok: false, detail: error instanceof Error ? error.message : String(error) };
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1716
1873
|
|
|
1717
1874
|
// src/terminal/host.ts
|
|
1718
1875
|
var TERMINAL_OFF_TEXT = "\u672A\u542F\u7528\uFF1A\u6253\u5F00\u8FD9\u4E00\u680F\u7684\u5F00\u5173\u540E\u624D\u4F1A\u63A5\u7BA1\uFF08\u73B0\u5728\u4FDD\u6301 PowerShell\uFF09";
|
|
@@ -1734,8 +1891,11 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1734
1891
|
let lastEffective = "";
|
|
1735
1892
|
let lastCandidates = "";
|
|
1736
1893
|
let failure = "";
|
|
1894
|
+
let lastDeliveryFailure = "";
|
|
1737
1895
|
let busy = false;
|
|
1738
1896
|
let again = false;
|
|
1897
|
+
let probeKey = "";
|
|
1898
|
+
let probeOutcome;
|
|
1739
1899
|
const discover = options.discover ?? ((explicitPath) => probeBash(
|
|
1740
1900
|
explicitPath,
|
|
1741
1901
|
process.env.PATH ?? "",
|
|
@@ -1755,12 +1915,14 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1755
1915
|
const scoped = agent.ctx;
|
|
1756
1916
|
const cleanups = [];
|
|
1757
1917
|
const notes = [];
|
|
1918
|
+
const skips = [];
|
|
1758
1919
|
try {
|
|
1759
1920
|
const lift = scoped.tools?.restrict({ deny: ["pwsh"] });
|
|
1760
1921
|
if (typeof lift === "function") cleanups.push(lift);
|
|
1761
1922
|
} catch (error) {
|
|
1762
|
-
|
|
1923
|
+
skips.push(`restrict(pwsh) \u8DF3\u8FC7\uFF1A${errorText(error)}`);
|
|
1763
1924
|
}
|
|
1925
|
+
let registered = false;
|
|
1764
1926
|
try {
|
|
1765
1927
|
const deps = readToolDeps();
|
|
1766
1928
|
if (deps === void 0) {
|
|
@@ -1768,7 +1930,12 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1768
1930
|
} else {
|
|
1769
1931
|
const definition = createBashTool(deps, { bashPath, sep, isAbsolute });
|
|
1770
1932
|
const unregister = scoped.tools?.register(definition);
|
|
1771
|
-
if (typeof unregister === "function")
|
|
1933
|
+
if (typeof unregister === "function") {
|
|
1934
|
+
cleanups.push(unregister);
|
|
1935
|
+
registered = true;
|
|
1936
|
+
} else {
|
|
1937
|
+
notes.push("tools.register \u6CA1\u6709\u8FD4\u56DE disposer\uFF08\u8FD9\u4E00\u7248\u7684\u6CE8\u518C\u9762\u4E0D\u53EF\u7528\uFF09");
|
|
1938
|
+
}
|
|
1772
1939
|
}
|
|
1773
1940
|
} catch (error) {
|
|
1774
1941
|
notes.push(`\u6CE8\u518C bash \u5931\u8D25\uFF1A${errorText(error)}`);
|
|
@@ -1788,6 +1955,16 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1788
1955
|
} catch (error) {
|
|
1789
1956
|
notes.push(`\u63D0\u793A\u8BCD\u6BB5\u5931\u8D25\uFF1A${errorText(error)}`);
|
|
1790
1957
|
}
|
|
1958
|
+
if (!registered) {
|
|
1959
|
+
for (const cleanup of [...cleanups].reverse()) {
|
|
1960
|
+
try {
|
|
1961
|
+
cleanup();
|
|
1962
|
+
} catch {
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
lastDeliveryFailure = notes.length === 0 ? "bash \u5DE5\u5177\u6CA1\u6709\u6CE8\u518C\u4E0A" : notes.join("\uFF1B");
|
|
1966
|
+
return void 0;
|
|
1967
|
+
}
|
|
1791
1968
|
return {
|
|
1792
1969
|
path: bashPath,
|
|
1793
1970
|
dispose: () => {
|
|
@@ -1798,9 +1975,45 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1798
1975
|
}
|
|
1799
1976
|
}
|
|
1800
1977
|
},
|
|
1801
|
-
...notes.length === 0 ? {} : { failure: notes.join("\uFF1B") }
|
|
1978
|
+
...notes.length === 0 ? {} : { failure: notes.join("\uFF1B") },
|
|
1979
|
+
...skips.length === 0 ? {} : { skipped: skips.join("\uFF1B") }
|
|
1802
1980
|
};
|
|
1803
1981
|
};
|
|
1982
|
+
const confinedModeOf = (deps, agent) => {
|
|
1983
|
+
if (deps?.sandbox === void 0 || deps.sandboxPolicy === void 0) return "";
|
|
1984
|
+
try {
|
|
1985
|
+
const session = agent?.session;
|
|
1986
|
+
const mode = deps.sandboxPolicy.resolve(session === void 0 ? {} : { session }).mode;
|
|
1987
|
+
return mode === "read-only" || mode === "workspace-write" ? mode : "";
|
|
1988
|
+
} catch {
|
|
1989
|
+
return "";
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1992
|
+
const runProbe = async (deps, bashPath, mode, agent) => {
|
|
1993
|
+
const key = `${bashPath}|${mode}`;
|
|
1994
|
+
if (probeOutcome !== void 0 && probeKey === key) return probeOutcome;
|
|
1995
|
+
const controller = new AbortController();
|
|
1996
|
+
const timer = setTimeout(() => {
|
|
1997
|
+
controller.abort();
|
|
1998
|
+
}, PROBE_TIMEOUT_MS * 2);
|
|
1999
|
+
try {
|
|
2000
|
+
probeOutcome = await (options.probe ?? probeBashExecution)(
|
|
2001
|
+
deps,
|
|
2002
|
+
{ bashPath, sep, isAbsolute },
|
|
2003
|
+
{
|
|
2004
|
+
callId: "composer-ux-self-check",
|
|
2005
|
+
signal: controller.signal,
|
|
2006
|
+
...agent === void 0 ? {} : { agent }
|
|
2007
|
+
}
|
|
2008
|
+
);
|
|
2009
|
+
} catch (error) {
|
|
2010
|
+
probeOutcome = { ok: false, detail: error instanceof Error ? error.message : String(error) };
|
|
2011
|
+
} finally {
|
|
2012
|
+
clearTimeout(timer);
|
|
2013
|
+
}
|
|
2014
|
+
probeKey = key;
|
|
2015
|
+
return probeOutcome;
|
|
2016
|
+
};
|
|
1804
2017
|
const reconcile = () => {
|
|
1805
2018
|
if (busy) {
|
|
1806
2019
|
again = true;
|
|
@@ -1838,8 +2051,24 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1838
2051
|
const candidates = candidatesToStored(found.candidates);
|
|
1839
2052
|
const bashPath = activeBashPath(mode, explicit, candidates, found.explicit);
|
|
1840
2053
|
const usable = bashPath !== "" && existsFn(bashPath);
|
|
2054
|
+
let probeFailure = "";
|
|
1841
2055
|
if (usable) {
|
|
2056
|
+
const probeDeps = readToolDeps();
|
|
2057
|
+
lastDeliveryFailure = "";
|
|
1842
2058
|
for (const agent of agents?.list() ?? []) {
|
|
2059
|
+
const confinedMode = probeDeps === void 0 ? "" : confinedModeOf(probeDeps, agent);
|
|
2060
|
+
if (confinedMode !== "") {
|
|
2061
|
+
const probe = await runProbe(probeDeps, bashPath, confinedMode, agent);
|
|
2062
|
+
if (!probe.ok) {
|
|
2063
|
+
probeFailure = `${probe.detail}\uFF1B\u53D7\u9650\u6A21\u5F0F ${confinedMode}`;
|
|
2064
|
+
const current2 = installed.get(agent);
|
|
2065
|
+
if (current2 !== void 0) {
|
|
2066
|
+
current2.dispose();
|
|
2067
|
+
installed.delete(agent);
|
|
2068
|
+
}
|
|
2069
|
+
continue;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
1843
2072
|
const current = installed.get(agent);
|
|
1844
2073
|
if (current !== void 0 && current.path === bashPath) continue;
|
|
1845
2074
|
if (current !== void 0) {
|
|
@@ -1849,12 +2078,15 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1849
2078
|
const record = install(agent, bashPath);
|
|
1850
2079
|
if (record !== void 0) installed.set(agent, record);
|
|
1851
2080
|
}
|
|
2081
|
+
if (probeFailure !== "") lastDeliveryFailure = probeFailure;
|
|
1852
2082
|
} else {
|
|
1853
2083
|
for (const entry of installed.values()) entry.dispose();
|
|
1854
2084
|
installed.clear();
|
|
1855
2085
|
failure = "";
|
|
1856
2086
|
}
|
|
1857
2087
|
const firstFailure = [...installed.values()].find((entry) => entry.failure !== void 0)?.failure;
|
|
2088
|
+
const delivered = usable && firstFailure === void 0 && lastDeliveryFailure === "";
|
|
2089
|
+
const failureText = firstFailure ?? (lastDeliveryFailure === "" ? failure : lastDeliveryFailure);
|
|
1858
2090
|
writeState(ops, {
|
|
1859
2091
|
status: terminalStatusText({
|
|
1860
2092
|
platform,
|
|
@@ -1862,11 +2094,14 @@ function installTerminalPolicy(ctx, namespace, settings, readToolDeps, options =
|
|
|
1862
2094
|
candidates,
|
|
1863
2095
|
excludedCount: found.excluded.length,
|
|
1864
2096
|
...found.explicit === void 0 ? {} : { explicit: found.explicit },
|
|
1865
|
-
effective:
|
|
1866
|
-
...
|
|
1867
|
-
|
|
2097
|
+
effective: delivered ? "bash" : "pwsh",
|
|
2098
|
+
...delivered ? { effectivePath: bashPath } : {},
|
|
2099
|
+
// 自检没过时优先用那条更准确的说法("预检就没过、根本没试"),
|
|
2100
|
+
// 而不是泛泛的"找到了 bash 但没能换上"。
|
|
2101
|
+
...delivered ? {} : probeFailure === "" ? { deliveryFailed: true } : { probeFailed: probeFailure },
|
|
2102
|
+
...failureText === "" ? {} : { failure: failureText }
|
|
1868
2103
|
}),
|
|
1869
|
-
effective:
|
|
2104
|
+
effective: delivered ? "bash" : "pwsh",
|
|
1870
2105
|
candidates
|
|
1871
2106
|
});
|
|
1872
2107
|
await flush(ops);
|
|
@@ -1983,10 +2218,10 @@ function isAbsolutePath(value) {
|
|
|
1983
2218
|
return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
1984
2219
|
}
|
|
1985
2220
|
function launchCommand(facts) {
|
|
1986
|
-
const { argv1, execArgv, rest, cwd, platform, resolve: resolve3, dirname:
|
|
2221
|
+
const { argv1, execArgv, rest, cwd, platform, resolve: resolve3, dirname: dirname4 } = facts;
|
|
1987
2222
|
if (argv1 !== void 0 && /[\\/](?:bin\.(?:js|ts)|dsh)$/.test(argv1)) {
|
|
1988
2223
|
const absolute = resolve3(argv1);
|
|
1989
|
-
return { file: facts.node, args: [...execArgv, absolute, ...rest], cwd:
|
|
2224
|
+
return { file: facts.node, args: [...execArgv, absolute, ...rest], cwd: dirname4(absolute), viaShell: false };
|
|
1990
2225
|
}
|
|
1991
2226
|
return { file: "dsh", args: [...rest], cwd, viaShell: platform === "win32" };
|
|
1992
2227
|
}
|
|
@@ -2191,96 +2426,479 @@ function bootId(pid, now) {
|
|
|
2191
2426
|
|
|
2192
2427
|
// src/optimizer-prompt.ts
|
|
2193
2428
|
var RELAY_ROLE = [
|
|
2194
|
-
'\u3010\u4F60\u662F\u8C01\u3011\u4F60\u662F\u4E00\u4E2A**\u4F20\u8BDD\u5668/\
|
|
2195
|
-
" \u7528\u6237 \u2192\uFF08\u4F60\uFF1A\u628A\u7528\u6237\u7684\u610F\u601D\u6574\u7406\u6210\u4E00\u6761\u547D\u4EE4\uFF09\u2192 \u5DE5\u4F5C AI\
|
|
2196
|
-
"\u4F60\u7684\
|
|
2429
|
+
'\u3010\u4F60\u662F\u8C01\u3011\u4F60\u662F\u4E00\u4E2A**\u4F20\u8BDD\u5668/\u610F\u56FE\u8865\u5168\u5668**\uFF0C\u7AD9\u5728\u7528\u6237\u4E0E"\u5DE5\u4F5C AI"\u4E4B\u95F4\uFF1A',
|
|
2430
|
+
" \u7528\u6237 \u2192\uFF08\u4F60\uFF1A\u628A\u7528\u6237\u7684\u610F\u601D\u6574\u7406\u6210\u6761\u76EE\u5E76\u7ED9\u51FA\u9010\u5B57\u4F9D\u636E\uFF09\u2192 \u5BBF\u4E3B\uFF08\u88C5\u914D\u6210\u4E00\u6761\u547D\u4EE4\uFF09\u2192 \u5DE5\u4F5C AI\u3002",
|
|
2431
|
+
"\u4F60\u7684\u4EA7\u51FA**\u4E0D\u4F1A**\u88AB\u76F4\u63A5\u5C55\u793A\u7ED9\u7528\u6237\uFF0C\u4E5F\u4E0D\u4F1A\u88AB\u539F\u6837\u53D1\u51FA\uFF1A\u5BBF\u4E3B\u4F1A\u7528\u4F60\u7ED9\u7684**\u9010\u5B57\u5F15\u6587**",
|
|
2432
|
+
"\u5728\u539F\u8BDD\u91CC\u5B9A\u4F4D\u3001\u53EA\u91C7\u7EB3\u80FD\u6838\u5BF9\u7684\u6761\u76EE\uFF0C\u518D\u88C5\u914D\u6210\u4E00\u6761\u547D\u4EE4\u4EA4\u7ED9\u5DE5\u4F5C AI\u3002",
|
|
2197
2433
|
"\u3010\u4F60\u4E0D\u662F\u8C01\u3011\u4F60\u4E0D\u662F\u5728\u548C\u7528\u6237\u804A\u5929\uFF0C\u4E5F\u4E0D\u662F\u5728\u56DE\u7B54\u7528\u6237\uFF1A",
|
|
2198
2434
|
"- \u4E0D\u8981\u56DE\u5E94\u3001\u4E0D\u8981\u56DE\u7B54\u7528\u6237\u7684\u8981\u6C42\uFF0C\u4E5F\u4E0D\u8981\u66FF\u7528\u6237\u5B8C\u6210\u4EFB\u52A1\uFF08\u4E0D\u8981\u76F4\u63A5\u7ED9\u51FA\u4EE3\u7801/\u7B54\u6848/\u7ED3\u679C\uFF09\u3002",
|
|
2199
2435
|
'- \u4E0D\u8981\u4EE5\u52A9\u624B\u53E3\u543B\u5BF9\u7528\u6237\u8BF4\u8BDD\uFF08"\u597D\u7684""\u6536\u5230""\u6211\u53EF\u4EE5\u5E2E\u4F60""\u5EFA\u8BAE\u4F60\u2026""\u9700\u8981\u6211\u2026\u5417"\uFF09\u3002',
|
|
2200
2436
|
'- \u4E0D\u8981\u628A\u7528\u6237\u53D1\u6765\u7684\u6587\u5B57\u5F53\u6210"\u5BF9\u4F60\u8BF4\u7684\u8BDD"\u6765\u56DE\u5E94\uFF1B\u5B83\u53EA\u662F\u4F60\u8981\u8F6C\u8FBE\u7684\u5185\u5BB9\u3002',
|
|
2201
|
-
|
|
2202
|
-
' "\u82E5 X \u4E0D\u660E\u786E\uFF0C\u5148\u8BFB Y \u6216\u5148\u5411\u6211\u786E\u8BA4\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE"\u3002'
|
|
2203
|
-
'\u3010\u4F60\u7684\u4EA7\u54C1\u3011\u4E00\u6761"\u50CF\u7528\u6237\u672C\u4EBA\u5728\u4E0B\u547D\u4EE4"\u7684\u6D88\u606F\uFF1A\u8BFB\u8005\u53EA\u6709\u5DE5\u4F5C AI \u4E00\u4E2A\u3002'
|
|
2437
|
+
"- \u4E0D\u8981\u5411\u7528\u6237\u63D0\u95EE\u3002\u8981\u6F84\u6E05\u65F6\uFF0C\u5199\u6210**\u7ED9\u5DE5\u4F5C AI \u7684\u6307\u4EE4**\uFF1A",
|
|
2438
|
+
' "\u82E5 X \u4E0D\u660E\u786E\uFF0C\u5148\u8BFB Y \u6216\u5148\u5411\u6211\u786E\u8BA4\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE"\u3002'
|
|
2204
2439
|
].join("\n");
|
|
2205
|
-
var
|
|
2206
|
-
"\u3010\
|
|
2207
|
-
|
|
2208
|
-
"\
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
'
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
'
|
|
2215
|
-
|
|
2216
|
-
'\
|
|
2217
|
-
|
|
2218
|
-
'\u3010\u81EA\u68C0\u3011\u843D\u7B14\u524D\u95EE\u81EA\u5DF1\u4E24\u53E5\uFF1A\u2460 \u8FD9\u6BB5\u8BDD\u662F\u4E0D\u662F"\u7528\u6237\u5728\u547D\u4EE4\u5DE5\u4F5C AI"\uFF1F\u2461 \u5DE5\u4F5C AI \u62FF\u5230\u5B83\u80FD\u4E0D\u80FD\u76F4\u63A5\u5F00\u59CB\u5E72\uFF1F',
|
|
2219
|
-
'\u4E24\u4E2A\u7B54\u6848\u90FD\u4E3A"\u662F"\u624D\u8F93\u51FA\u3002\u73B0\u5728\u76F4\u63A5\u8F93\u51FA\u8FD9\u6761\u6D88\u606F\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5F00\u573A\u767D\u4E0E\u6536\u5C3E\u8BED\u3002'
|
|
2440
|
+
var EVIDENCE_RULES = [
|
|
2441
|
+
"\u3010\u4F9D\u636E\u7EAA\u5F8B\uFF08\u5BBF\u4E3B\u4F1A\u9010\u6761\u673A\u68B0\u6838\u5BF9\uFF0C\u5199\u9519\u5C31\u4E22\u8FD9\u4E00\u6761\uFF09\u3011",
|
|
2442
|
+
"1. `rewrite` / `requirement` / `quality` **\u5FC5\u987B**\u5E26 `quote`\uFF1A\u4E00\u6BB5\u5728\u3010\u7528\u6237\u539F\u8BDD\u3011\u91CC",
|
|
2443
|
+
" **\u9010\u5B57\u5B58\u5728**\u7684\u5B50\u4E32 \u2014\u2014 \u7167\u6284\uFF0C\u4E0D\u8981\u6539\u5199\u3001\u4E0D\u8981\u8865\u6807\u70B9\u3001\u4E0D\u8981\u7FFB\u8BD1\u3002\u5BBF\u4E3B\u505A\u5B57\u9762\u5B50\u4E32\u6BD4\u5BF9\uFF0C",
|
|
2444
|
+
" \u5BF9\u4E0D\u4E0A\u5C31\u4E22\u6389\u90A3\u4E00\u6761\uFF08\u4E0D\u4F1A\u62A5\u9519\u7ED9\u4F60\uFF0C\u4E5F\u4E0D\u4F1A\u6709\u4EBA\u63D0\u9192\u4F60\uFF09\u3002",
|
|
2445
|
+
'2. **\u4E0D\u8BB8\u51ED\u7A7A\u65B0\u589E**\uFF1A\u4EA7\u54C1\u76EE\u6807\u3001\u529F\u80FD\u3001\u786C\u7EA6\u675F\uFF08"\u5FC5\u987B\u79BB\u7EBF""\u7981\u6B62\u8054\u7F51""\u53EA\u80FD\u7528\u67D0\u4E2A\u5E93"',
|
|
2446
|
+
' "\u5FC5\u987B\u652F\u6301\u79FB\u52A8\u7AEF"\uFF09\u4E00\u5F8B\u4E0D\u8BB8\u7531\u4F60\u51B3\u5B9A\u3002\u4F60\u53EA\u80FD\u8865**\u80FD\u4ECE\u539F\u8BDD\u67D0\u4E00\u53E5\u76F4\u63A5\u63A8\u51FA**\u7684\u6700\u4F4E\u8981\u6C42\uFF0C',
|
|
2447
|
+
" \u5E76\u4E14\u5FC5\u987B\u5F15\u7528\u90A3\u4E00\u53E5\u3002",
|
|
2448
|
+
"3. \u4E0D\u786E\u5B9A\u3001\u4F1A\u5F71\u54CD\u7ED3\u679C\u3001\u4E14\u53EA\u6709\u7528\u6237\u80FD\u5B9A\u7684\u53D6\u820D \u2192 \u5199 `unknown`\uFF08`unknownClass` =",
|
|
2449
|
+
' "user_preference"\uFF09\uFF0C**\u4E0D\u8981\u66FF\u7528\u6237\u731C**\uFF0C\u4E5F\u4E0D\u8981\u5199"\u6309\u6700\u4FDD\u5B88\u7406\u89E3\u6267\u884C"\u3002',
|
|
2450
|
+
' \u5728\u8BB8\u53EF\u8303\u56F4\u5185\u8BFB\u4EE3\u7801\u5C31\u80FD\u786E\u5B9A\u7684\u4E8B\u5B9E\u5199 "lookupable_fact"\uFF1B\u53EF\u9006\u7684\u5B9E\u73B0\u7EC6\u8282',
|
|
2451
|
+
' \uFF08\u95F4\u8DDD\u3001\u547D\u540D\u3001\u5E93\u7684\u5185\u90E8\u7528\u6CD5\uFF09\u5199 "implementation_detail"\u3002',
|
|
2452
|
+
"4. \u4E0D\u5F97\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\uFF08\u6587\u4EF6\u5185\u5BB9\u3001\u76EE\u5F55\u7ED3\u6784\u3001\u4F9D\u8D56\u7248\u672C\uFF09\u3002\u4F60\u6CA1\u8BFB\u5230\u7684\u4E1C\u897F\u4E0D\u5B58\u5728\u3002"
|
|
2220
2453
|
].join("\n");
|
|
2454
|
+
var STYLE_RULES = [
|
|
2455
|
+
'\u3010\u5199 text \u7684\u7EAA\u5F8B\u3011\u4F60\u7684 text \u4F1A\u88AB\u5BBF\u4E3B\u62FC\u8FDB\u6700\u7EC8\u547D\u4EE4\uFF0C\u8BFB\u8005\u53EA\u6709"\u5DE5\u4F5C AI"\u4E00\u4E2A\uFF1A',
|
|
2456
|
+
"- \u7948\u4F7F\u53E5\u3001\u76F4\u7ED9\u8981\u6C42\u3001\u53EF\u6267\u884C\uFF1B\u4E2D\u6587\u8FDB\u4E2D\u6587\u51FA\u3002",
|
|
2457
|
+
'- \u4E0D\u8981\u5143\u8BDD\u8BED\u4E0E\u5143\u6807\u9898\uFF08"\u4F18\u5316\u540E\u7684\u63D0\u793A\u8BCD""\u6539\u5199\u540E""\u8BF4\u660E""\u4EE5\u4E0B\u662F\u2026"\uFF09\u3002',
|
|
2458
|
+
'- \u4E0D\u8981\u63D0\u5230"\u7528\u6237/\u539F\u6587/\u4E0A\u9762\u7684\u8BDD"\uFF0C\u4E5F\u4E0D\u8981\u5199"\u6211\u6765\u5E2E\u4F60\u2026"\u3002',
|
|
2459
|
+
'- \u4E0D\u8981\u5199\u6D41\u7A0B\u4EEA\u5F0F\u3001\u901A\u7528\u6559\u5B66\u3001\u9A8C\u6536\u5957\u8BDD\uFF08"\u8BF7\u786E\u4FDD\u4EE3\u7801\u8D28\u91CF"\u8FD9\u79CD\u6CA1\u6709\u6307\u5411\u7684\u8BDD\uFF09\u3002',
|
|
2460
|
+
"- `rewrite` \u7684 text \u662F**\u66FF\u6362\u6389\u90A3\u6BB5\u5F15\u6587**\u7684\u6B63\u6587\uFF0C\u6240\u4EE5\u53EA\u5199\u90A3\u6BB5\u8BDD\u672C\u8EAB\uFF0C\u4E0D\u8981\u5E26\u524D\u7F00\u540E\u7F00\u3002"
|
|
2461
|
+
].join("\n");
|
|
2462
|
+
var OPTIMIZER_OUTPUT_CONTRACT = [
|
|
2463
|
+
"\u3010\u8F93\u51FA\u5951\u7EA6\uFF08\u56FA\u5B9A\uFF0C\u4E0D\u53EF\u66F4\u6539\uFF09\u3011",
|
|
2464
|
+
"\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981 Markdown \u4EE3\u7801\u5757\u3001\u4E0D\u8981\u5728 JSON \u524D\u540E\u5199\u4EFB\u4F55\u5B57\uFF1A",
|
|
2465
|
+
'{"items":[{"kind":"rewrite","quote":"\u539F\u8BDD\u91CC\u9010\u5B57\u5B58\u5728\u7684\u7247\u6BB5","text":"\u66FF\u6362\u6389\u8BE5\u7247\u6BB5\u7684\u6B63\u6587"}]}',
|
|
2466
|
+
"\u5B57\u6BB5\u4E0E\u53D6\u503C\uFF08`kind` \u53EA\u80FD\u662F\u8FD9\u516D\u79CD\uFF09\uFF1A",
|
|
2467
|
+
"- rewrite\uFF1A\u8BED\u8A00\u5C42\u4FEE\u590D\u3002`quote` \u5FC5\u586B\uFF1B\u540C\u4E00\u6BB5\u539F\u8BDD\u6700\u591A\u4E00\u6761 rewrite\uFF0C\u4E0D\u8981\u91CD\u53E0\u3002",
|
|
2468
|
+
"- requirement\uFF1A\u4ECE `quote` \u76F4\u63A5\u63A8\u51FA\u7684\u8865\u5168\u8981\u6C42\uFF08\u9A8C\u6536\u6807\u51C6/\u786C\u7EA6\u675F\uFF09\u3002`quote` \u5FC5\u586B\u3002",
|
|
2469
|
+
"- quality\uFF1A\u5BF9\u539F\u8BDD\u91CC\u8D28\u91CF\u8BCD\u7684\u89E3\u91CA\u3002`quote` \u5FC5\u586B\uFF08\u5C31\u586B\u90A3\u51E0\u4E2A\u8D28\u91CF\u5B57\uFF09\u3002",
|
|
2470
|
+
"- unknown\uFF1A\u672A\u51B3\u9879\u3002\u5FC5\u987B\u5E26 `unknownClass`\uFF08user_preference / lookupable_fact /",
|
|
2471
|
+
" implementation_detail\uFF09\uFF0C\u53EF\u9009 `blocking`\uFF08true/false\uFF0C\u662F\u5426\u6321\u4F4F\u4E0B\u4E00\u6B65\uFF09\u3002",
|
|
2472
|
+
'- plan\uFF1A\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\uFF08\u4EC5"\u6781\u7AEF"\u6863\u7528\uFF09\u3002',
|
|
2473
|
+
'- risk\uFF1A\u591A\u60C5\u51B5\u9884\u6848\uFF08\u4EC5"\u6781\u7AEF"\u6863\u7528\uFF09\uFF0C\u6BCF\u6761\u6309"\u89E6\u53D1\u4FE1\u53F7 \u2192 \u5E94\u5BF9 \u2192 \u7981\u6B62\u52A8\u4F5C"\u5199\u3002',
|
|
2474
|
+
"\u9650\u5236\uFF1A`text` \u6BCF\u6761\u4E0D\u8D85\u8FC7 300 \u5B57\uFF1B`items` \u603B\u5171\u4E0D\u8D85\u8FC7 12 \u6761\uFF1Bid \u4E0D\u9700\u8981\u7ED9\u3002",
|
|
2475
|
+
'\u6CA1\u6709\u53EF\u8865\u7684\u5185\u5BB9\u65F6\uFF0C\u8F93\u51FA {"items":[]} \u2014\u2014 \u4F46**\u5148\u60F3\u6E05\u695A**\uFF1A\u7528\u6237\u8FD9\u4E00\u8F6E\u7684\u539F\u8BDD\u91CC',
|
|
2476
|
+
"\u771F\u7684\u6CA1\u6709\u4EFB\u4F55\u53EF\u6838\u5BF9\u7684\u8865\u5168\u5417\uFF1F"
|
|
2477
|
+
].join("\n");
|
|
2478
|
+
var OPTIMIZE_ITEM_KINDS = ["rewrite", "requirement", "quality", "unknown", "plan", "risk"];
|
|
2479
|
+
var OPTIMIZE_UNKNOWN_CLASSES = ["user_preference", "lookupable_fact", "implementation_detail"];
|
|
2480
|
+
var OPTIMIZE_MAX_ITEMS = 12;
|
|
2481
|
+
var OPTIMIZE_ITEM_MAX_CHARS = 300;
|
|
2482
|
+
var TIER_TASKS = {
|
|
2483
|
+
basic: [
|
|
2484
|
+
"\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\u3011",
|
|
2485
|
+
"\u7528\u6237\u539F\u8BDD\u53EF\u80FD\u6709\u75C5\u53E5\u3001\u6307\u4EE3\u4E0D\u660E\u3001\u7528\u8BCD\u542B\u7CCA\u3002\u628A\u5B83\u6539\u5199\u6210\u901A\u987A\u3001\u7CBE\u786E\u3001\u65E0\u6B67\u4E49\u7684**\u540C\u4E00\u6BB5\u8BDD**\u3002",
|
|
2486
|
+
"\u53EA\u4EA7\u51FA `rewrite`\uFF08\u53EF\u4EE5\u6309\u53E5\u5B50\u62C6\u6210\u591A\u6761\uFF0C\u6BCF\u6761\u5F15\u7528\u539F\u8BDD\u91CC\u5BF9\u5E94\u90A3\u4E00\u53E5\uFF09\u3002",
|
|
2487
|
+
"\u4E25\u7981\u4EA7\u51FA requirement / plan / risk\uFF1A\u8FD9\u4E00\u6863**\u4E0D\u65B0\u589E\u4EFB\u4F55\u8981\u6C42**\uFF0C\u53EA\u628A\u8BDD\u8BF4\u660E\u767D\u3002",
|
|
2488
|
+
"\u539F\u8BDD\u786E\u6709\u6B67\u4E49\u3001\u4E14\u6B67\u4E49\u4F1A\u5BFC\u81F4\u505A\u9519\u65F6\uFF0C\u624D\u8865\u4E00\u6761 `unknown`\uFF08unknownClass \u53D6",
|
|
2489
|
+
"user_preference \u6216 lookupable_fact\uFF09\uFF1B\u786E\u5B9E\u6CA1\u6709\u53EF\u8865\u7684\u5C31\u8F93\u51FA\u7A7A\u6570\u7EC4\u3002",
|
|
2490
|
+
"\u957F\u5EA6\u7EAA\u5F8B\uFF1A\u6210\u54C1\u4E0D\u8D85\u8FC7\u539F\u8BDD\u7684 1.4 \u500D\uFF1B\u539F\u8BDD 30 \u5B57\u4EE5\u5185\u65F6\u4E0D\u8D85\u8FC7 60 \u5B57\u3002"
|
|
2491
|
+
],
|
|
2492
|
+
advanced: [
|
|
2493
|
+
"\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u5728\u4E0D\u52A8\u76EE\u6807\u7684\u524D\u63D0\u4E0B\u628A\u547D\u4EE4\u8BF4\u6E05\u695A\u3011",
|
|
2494
|
+
'\u7528\u6237\u539F\u8BDD\u542B\u7CCA\u3001\u7F3A\u5173\u952E\u7EA6\u675F\u3002\u4F60\u8981\u8865\u7684\u662F"\u7528\u6237\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3"\u7684\u5FC5\u8981\u4FE1\u606F\uFF0C',
|
|
2495
|
+
"\u8BA9\u5B83\u4E00\u6B21\u505A\u5BF9 \u2014\u2014 \u4F46\u6BCF\u4E00\u6761\u90FD\u5FC5\u987B\u662F**\u4ECE\u539F\u8BDD\u67D0\u4E00\u53E5\u76F4\u63A5\u63A8\u51FA**\u7684\uFF0C\u5E76\u5F15\u7528\u90A3\u4E00\u53E5\u3002",
|
|
2496
|
+
"\u5141\u8BB8\u4EA7\u51FA\uFF1A",
|
|
2497
|
+
"- `rewrite`\uFF1A\u628A\u542B\u7CCA\u3001\u6709\u75C5\u53E5\u7684\u5730\u65B9\u8BF4\u6E05\u695A\uFF08\u540C\u4E00\u6BB5\u539F\u8BDD\u6700\u591A\u4E00\u6761\uFF09\u3002",
|
|
2498
|
+
'- `requirement`\uFF1A\u4ECE\u539F\u8BDD\u76F4\u63A5\u63A8\u51FA\u7684\u6700\u4F4E\u4EA4\u4ED8\u8981\u6C42\u4E0E\u9A8C\u6536\u6807\u51C6\uFF08"\u6539\u5B8C\u80FD\u8DD1\u8D77\u6765""\u9875\u9762\u80FD\u6253\u5F00"',
|
|
2499
|
+
" \u8FD9\u7C7B\u53EF\u89C2\u6D4B\u7684\u8BDD\uFF09\uFF0C\u5199\u6210\u5BF9\u5DE5\u4F5C AI \u7684\u8981\u6C42\u800C\u4E0D\u662F\u8BC4\u8BBA\u3002\u6BCF\u6761\u90FD\u8981\u80FD\u6307\u56DE\u539F\u8BDD\u91CC\u7684\u67D0\u4E00\u53E5\u3002",
|
|
2500
|
+
'- `quality`\uFF1A\u7528\u6237\u8BF4\u7684\u8D28\u91CF\u8BCD\uFF08"\u597D\u770B\u70B9""\u9AD8\u7EA7\u611F""\u6D41\u7545"\uFF09\u2192 \u89E3\u91CA\u6210\u53EF\u89C2\u5BDF\u7684\u8981\u6C42\u3002',
|
|
2501
|
+
" \u5B83\u662F**\u89E3\u91CA**\uFF0C\u4E0D\u662F\u65B0\u589E\u76EE\u6807\uFF1A\u4E00\u6761\u8D28\u91CF\u8BCD\u6700\u591A\u4E00\u6761 quality\u3002",
|
|
2502
|
+
"- `unknown`\uFF1A\u53EA\u6709\u7528\u6237\u80FD\u5B9A\u7684\u53D6\u820D\uFF08user_preference\uFF09/ \u8BE5\u53BB\u67E5\u8BC1\u7684\u4E8B\u5B9E\uFF08lookupable_fact\uFF09\u3002",
|
|
2503
|
+
"\u7981\u6B62\uFF1A\u65B0\u589E\u529F\u80FD\u3001\u65B0\u76EE\u6807\u3001\u65B0\u4F9D\u8D56\uFF1B\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\uFF1B\u5199\u7528\u6237\u6CA1\u6388\u6743\u7684\u6280\u672F\u9009\u578B\u3002",
|
|
2504
|
+
"\u6570\u91CF\u7EAA\u5F8B\uFF1Arequirement \u6700\u591A 3 \u6761\uFF0Cquality \u6700\u591A 2 \u6761\uFF0Cunknown \u6700\u591A 2 \u6761\u3002"
|
|
2505
|
+
],
|
|
2506
|
+
extreme: [
|
|
2507
|
+
"\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u628A\u8BC9\u6C42\u56FA\u5316\u6210\u4E00\u6761\u53EF\u76F4\u63A5\u6267\u884C\u7684\u547D\u4EE4\u3011",
|
|
2508
|
+
"\u8FD9\u6B21\u662F\u591A\u6B65\u6267\u884C\u7684\u590D\u6742\u4EFB\u52A1\uFF0C\u5DE5\u4F5C AI \u4F1A\u7167\u8FD9\u6761\u547D\u4EE4\u5E72\uFF0C\u7528\u6237\u4E0D\u4F1A\u518D\u8865\u5145\u3002",
|
|
2509
|
+
'\u5728"\u9AD8\u7EA7"\u6863\u5141\u8BB8\u7684\u5168\u90E8\u6761\u76EE\u7684\u57FA\u7840\u4E0A\uFF0C\u518D\u52A0\u4E24\u7C7B\uFF08\u90FD\u8981\u4EE5\u7528\u6237\u5728\u7ED9\u5DE5\u4F5C AI \u4E0B\u547D\u4EE4\u7684\u53E3\u543B\u5199\uFF09\uFF1A',
|
|
2510
|
+
"- `plan`\uFF1A\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\u3002\u6BCF\u9636\u6BB5\u5199\u6E05\u52A8\u4F5C\u4E0E\u4EA7\u51FA\uFF0C\u5E76\u5199\u660E\u7EAA\u5F8B\uFF08\u5148\u9A8C\u8BC1\u518D\u6539\u3001\u5931\u8D25\u5373\u56DE\u9000\u3001",
|
|
2511
|
+
" \u4E0D\u64C5\u81EA\u6269\u5927\u8303\u56F4\u3001\u6539\u5B8C\u7ED9\u51FA\u8BC1\u636E\uFF09\u3002",
|
|
2512
|
+
'- `risk`\uFF1A\u591A\u60C5\u51B5\u9884\u6848 2~4 \u6761\uFF0C\u6BCF\u6761\u5199\u6210"\u5982\u679C\u51FA\u73B0 <\u89E6\u53D1\u4FE1\u53F7>\uFF0C\u5C31\u5148 <\u5E94\u5BF9\u52A8\u4F5C>\uFF0C',
|
|
2513
|
+
' \u4E0D\u8981 <\u7981\u6B62\u52A8\u4F5C>"\u3002',
|
|
2514
|
+
"\u8FD8\u8981\u5224\u65AD\u8FD9\u6B21\u4EFB\u52A1\u662F\u5426\u503C\u5F97\u8BA9\u5DE5\u4F5C AI \u7528 goal / todo / \u8BA1\u5212\u6A21\u5F0F\u8DDF\u8E2A\uFF0C\u5E76\u628A\u7ED3\u8BBA\u5199\u6210",
|
|
2515
|
+
'`requirement` \u7684\u4E00\u90E8\u5206\uFF08\u4F8B\u5982"\u8BF7\u5148\u5EFA\u7ACB goal\uFF1A\u2026\uFF0C\u518D\u6309\u4E0B\u5217\u9636\u6BB5\u63A8\u8FDB"\uFF09\uFF1B\u4E0D\u9700\u8981\u5C31\u5B8C\u5168\u4E0D\u63D0\u3002',
|
|
2516
|
+
'\u94C1\u5F8B\uFF1A\u4E0D\u5F97\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\u3002\u9700\u8981\u9879\u76EE\u4E8B\u5B9E\u65F6\u5199\u6210"\u5148\u8BFB\u53D6/\u786E\u8BA4 X"\u7684\u67E5\u8BC1\u52A8\u4F5C\u3002',
|
|
2517
|
+
"\u6570\u91CF\u7EAA\u5F8B\uFF1Aplan \u6700\u591A 1 \u6761\uFF0Crisk \u6700\u591A 4 \u6761\uFF0Crequirement \u6700\u591A 3 \u6761\u3002"
|
|
2518
|
+
]
|
|
2519
|
+
};
|
|
2221
2520
|
var OPTIMIZER_SPECS = {
|
|
2222
2521
|
basic: {
|
|
2223
2522
|
temperature: 0.2,
|
|
2224
|
-
system: [
|
|
2225
|
-
RELAY_ROLE,
|
|
2226
|
-
"\u4E0B\u9762\u8FD9\u6BB5\u662F\u7528\u6237\u8981\u53D1\u7ED9\u5DE5\u4F5C AI \u7684\u6307\u4EE4\uFF0C\u53EF\u80FD\u6709\u75C5\u53E5\u3001\u6307\u4EE3\u4E0D\u660E\u3001\u7528\u8BCD\u542B\u7CCA\u3002",
|
|
2227
|
-
"\u4F60\u7684\u552F\u4E00\u4EFB\u52A1\uFF1A\u628A\u5B83\u6539\u5199\u6210\u901A\u987A\u3001\u7CBE\u786E\u3001\u65E0\u6B67\u4E49\u7684**\u540C\u4E00\u6761\u6307\u4EE4**\uFF0C\u6539\u5B8C\u5C31\u80FD\u76F4\u63A5\u53D1\u51FA\u53BB\u3002",
|
|
2228
|
-
"\u94C1\u5F8B\uFF1A",
|
|
2229
|
-
'- \u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\uFF1A\u75C5\u53E5\u3001\u9519\u522B\u5B57\u3001\u6807\u70B9\u3001\u6307\u4EE3\u6D88\u89E3\uFF08"\u90A3\u4E2A\u9875\u9762"\u2192\u4FDD\u7559\u4F46\u660E\u786E\u6307\u5411\u540C\u4E00\u5BF9\u8C61\uFF09\u3001\u542B\u7CCA\u8BCD\u6536\u655B\u5230"\u53EF\u6267\u884C\u4F46\u4E0D\u65B0\u589E\u9700\u6C42"\u3002',
|
|
2230
|
-
"- \u4E25\u7981\u65B0\u589E\u539F\u6587\u6CA1\u6709\u7684\u9700\u6C42\u3001\u529F\u80FD\u3001\u7EA6\u675F\u3001\u6280\u672F\u9009\u578B\u3001\u4EA4\u4ED8\u7269\uFF1B\u4E25\u7981\u6269\u5927\u6216\u7F29\u5C0F\u8303\u56F4\u3002",
|
|
2231
|
-
'- \u539F\u6587\u6CA1\u8BF4\u7684\u5C31\u4E0D\u8981\u66FF\u7528\u6237\u51B3\u5B9A\uFF1A\u65E0\u6CD5\u786E\u5B9A\u5904\u5199\u6210\u7ED9\u5DE5\u4F5C AI \u7684\u67E5\u8BC1\u6307\u4EE4\uFF08\u4F8B\u5982"\u5148\u786E\u8BA4\u6307\u7684\u662F\u54EA\u4E2A\u9875\u9762\uFF0C\u518D\u52A8\u624B"\uFF09\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u62CD\u677F\u3002',
|
|
2232
|
-
"- \u7BC7\u5E45\u4E0E\u539F\u6587\u76F8\u5F53\uFF0C\u4E0D\u8981\u81A8\u80C0\u3002",
|
|
2233
|
-
NO_META_RULES
|
|
2234
|
-
].join("\n")
|
|
2523
|
+
system: [RELAY_ROLE, TIER_TASKS.basic.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
|
|
2235
2524
|
},
|
|
2236
2525
|
advanced: {
|
|
2237
2526
|
temperature: 0.3,
|
|
2238
|
-
system: [
|
|
2239
|
-
RELAY_ROLE,
|
|
2240
|
-
"\u7528\u6237\u7684\u539F\u8BDD\u542B\u7CCA\u3001\u7F3A\u5173\u952E\u7EA6\u675F\uFF1B\u4F60\u8981**\u4EE5\u7528\u6237\u7684\u540D\u4E49**\u628A\u8FD9\u6761\u547D\u4EE4\u8BF4\u6E05\u695A\uFF0C\u8F6C\u8FBE\u7ED9\u5DE5\u4F5C AI\u3002",
|
|
2241
|
-
'\u4F60\u7684\u4EFB\u52A1\uFF1A\u5728\u5B8C\u5168\u4E0D\u6539\u53D8\u7528\u6237\u76EE\u6807\u7684\u524D\u63D0\u4E0B\uFF0C\u7528\u4F60\u81EA\u5DF1\u7684\u63A8\u7406\uFF0C\u628A"\u7528\u6237\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3"\u7684\u5FC5\u8981\u4FE1\u606F**\u5199\u6210\u5BF9\u5DE5\u4F5C AI \u7684\u8981\u6C42**\uFF0C\u8BA9\u5B83\u4E00\u6B21\u505A\u5BF9\u3002',
|
|
2242
|
-
"\u5141\u8BB8\u4F60\u505A\uFF08\u4E14\u4EC5\u9650\u8FD9\u4E9B\uFF09\uFF1A",
|
|
2243
|
-
'- \u8865\u5168\u4ECE\u76EE\u6807\u53EF\u76F4\u63A5\u63A8\u51FA\u7684\u6700\u4F4E\u4EA4\u4ED8\u8981\u6C42\u4E0E\u9A8C\u6536\u6807\u51C6\uFF08\u4F8B\u5982"\u80FD\u8DD1\u8D77\u6765""\u754C\u9762\u80FD\u7528"\uFF09\uFF0C\u5F62\u5F0F\u662F\u8981\u6C42\u800C\u975E\u8BC4\u8BBA\u3002',
|
|
2244
|
-
"- \u628A\u542B\u7CCA\u8BCD\u6536\u655B\u4E3A\u53EF\u89C2\u5BDF\u3001\u53EF\u6267\u884C\u7684\u8981\u6C42\u3002",
|
|
2245
|
-
'- \u5B58\u5728\u4E24\u79CD\u5408\u7406\u89E3\u8BFB\u65F6\uFF1A\u6309\u66F4\u5E38\u89C1\u7684\u4E00\u79CD\u5199\u6210\u4E3B\u8981\u6C42\uFF0C\u53E6\u4E00\u79CD\u5199\u6210"\u5982\u679C\u5B9E\u9645\u662F X\uFF0C\u5219\u2026"\u7684\u6307\u4EE4\u3002',
|
|
2246
|
-
"\u94C1\u5F8B\uFF1A\u4E0D\u5F97\u589E\u52A0\u65B0\u529F\u80FD/\u65B0\u76EE\u6807/\u65B0\u4F9D\u8D56\uFF1B\u4E0D\u5F97\u865A\u6784\u7528\u6237\u6CA1\u63D0\u7684\u73AF\u5883\u3001\u6570\u636E\u3001\u6280\u672F\u6808\uFF1B\u6BCF\u6761\u8865\u5145\u90FD\u5FC5\u987B\u80FD\u56DE\u6EAF\u5230\u539F\u8BDD\u91CC\u7684\u67D0\u53E5\u3002",
|
|
2247
|
-
NO_META_RULES
|
|
2248
|
-
].join("\n")
|
|
2527
|
+
system: [RELAY_ROLE, TIER_TASKS.advanced.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
|
|
2249
2528
|
},
|
|
2250
2529
|
extreme: {
|
|
2251
2530
|
temperature: 0.3,
|
|
2252
|
-
system: [
|
|
2253
|
-
RELAY_ROLE,
|
|
2254
|
-
"\u8FD9\u6B21\u662F\u4E00\u4E2A\u9700\u8981\u591A\u6B65\u6267\u884C\u7684\u590D\u6742\u4EFB\u52A1\u3002\u4F60\u8981\u8F6C\u8FBE\u7684\u662F**\u4E00\u6761\u53EF\u76F4\u63A5\u53D1\u9001\u7684\u547D\u4EE4**\uFF1A\u7528\u6237\u4E0D\u4F1A\u518D\u7F16\u8F91\u6216\u8F6C\u8FF0\uFF0C\u5DE5\u4F5C AI \u4F1A\u7167\u5B83\u6267\u884C\u3002",
|
|
2255
|
-
'\u8981\u6C42\uFF08\u5168\u90E8\u4EE5"\u7528\u6237\u5728\u7ED9\u5DE5\u4F5C AI \u4E0B\u547D\u4EE4"\u7684\u53E3\u543B\u5199\uFF09\uFF1A',
|
|
2256
|
-
"- \u5148\u628A\u8BC9\u6C42\u56FA\u5316\u4E3A\u547D\u4EE4\u7ED3\u6784\uFF1A\u8981\u505A\u4EC0\u4E48 / \u505A\u5B8C\u7684\u6807\u5FD7\uFF08\u53EF\u89C2\u6D4B\u9A8C\u6536\u6807\u51C6\uFF09/ \u786C\u7EA6\u675F / \u4E0D\u8BB8\u505A\u4EC0\u4E48\u3002",
|
|
2257
|
-
"- \u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\uFF1A\u6BCF\u9636\u6BB5\u5199\u6E05\u52A8\u4F5C\u4E0E\u4EA7\u51FA\uFF0C\u5E76\u5199\u660E\u7EAA\u5F8B\u8981\u6C42\uFF08\u5148\u9A8C\u8BC1\u518D\u6539\u3001\u5931\u8D25\u5373\u56DE\u9000\u3001\u4E0D\u64C5\u81EA\u6269\u5927\u8303\u56F4\u3001\u6539\u5B8C\u7ED9\u51FA\u8BC1\u636E\uFF09\u3002",
|
|
2258
|
-
'- \u591A\u60C5\u51B5\u9884\u6848\uFF1A\u7ED9\u51FA\u6700\u53EF\u80FD\u51FA\u5C94\u5B50\u7684 2\u20134 \u79CD\u60C5\u51B5\uFF0C\u6BCF\u79CD\u5199\u6210"\u5982\u679C\u51FA\u73B0 <\u89E6\u53D1\u4FE1\u53F7>\uFF0C\u5C31\u5148 <\u5E94\u5BF9\u52A8\u4F5C>\uFF0C\u4E0D\u8981 <\u7981\u6B62\u52A8\u4F5C>"\u3002',
|
|
2259
|
-
'- \u662F\u5426\u9700\u8981\u529F\u80FD\u6027\u6307\u4EE4\uFF1A\u5224\u65AD\u8FD9\u6B21\u4EFB\u52A1\u662F\u5426\u503C\u5F97\u8BA9\u5DE5\u4F5C AI \u7528 goal / todo / \u8BA1\u5212\u6A21\u5F0F \u8DDF\u8E2A\uFF0C\u5E76\u628A\u7ED3\u8BBA**\u5199\u6210\u547D\u4EE4\u672C\u8EAB\u7684\u4E00\u90E8\u5206**\uFF08\u4F8B\u5982"\u8BF7\u5148\u5EFA\u7ACB goal\uFF1A\u2026\uFF0C\u518D\u6309\u4E0B\u5217\u9636\u6BB5\u63A8\u8FDB"\uFF09\uFF1B\u4E0D\u9700\u8981\u5C31\u5B8C\u5168\u4E0D\u63D0\u3002',
|
|
2260
|
-
'\u94C1\u5F8B\uFF1A\u4E0D\u5F97\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\uFF1B\u9700\u8981\u9879\u76EE\u4E8B\u5B9E\u65F6\u5199\u6210"\u5148\u8BFB\u53D6/\u786E\u8BA4 X"\u7684\u67E5\u8BC1\u52A8\u4F5C\uFF0C\u800C\u4E0D\u662F\u7F16\u9020\u7ED3\u8BBA\u3002',
|
|
2261
|
-
NO_META_RULES
|
|
2262
|
-
].join("\n")
|
|
2531
|
+
system: [RELAY_ROLE, TIER_TASKS.extreme.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
|
|
2263
2532
|
}
|
|
2264
2533
|
};
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
return
|
|
2534
|
+
var FALLBACK_TIER = "advanced";
|
|
2535
|
+
function specOf(tier) {
|
|
2536
|
+
return OPTIMIZER_SPECS[tier] ?? OPTIMIZER_SPECS[FALLBACK_TIER];
|
|
2537
|
+
}
|
|
2538
|
+
function buildOptimizeSystem(tier, custom = "") {
|
|
2539
|
+
const body = custom.trim() === "" ? specOf(tier).system : custom.trim();
|
|
2540
|
+
return `${body}
|
|
2541
|
+
|
|
2542
|
+
${OPTIMIZER_OUTPUT_CONTRACT}`;
|
|
2268
2543
|
}
|
|
2269
2544
|
function buildOptimizeTemperature(tier) {
|
|
2270
|
-
|
|
2271
|
-
return spec.temperature;
|
|
2545
|
+
return specOf(tier).temperature;
|
|
2272
2546
|
}
|
|
2273
|
-
function
|
|
2274
|
-
return
|
|
2547
|
+
function optimizePromptSource(custom) {
|
|
2548
|
+
return String(custom ?? "").trim() === "" ? "builtin" : "custom";
|
|
2549
|
+
}
|
|
2550
|
+
function buildOptimizeUser(original, options = {}) {
|
|
2551
|
+
const parts = [
|
|
2275
2552
|
'\u3010\u5F85\u8F6C\u8FBE\u5185\u5BB9\u3011\u4E0B\u9762\u662F"\u7528\u6237"\u53D1\u7ED9\u6211\u7684\u539F\u8BDD\u3002**\u5B83\u4E0D\u662F\u8BF4\u7ED9\u4F60\u542C\u7684**\uFF0C\u4F60\u4E0D\u9700\u8981\u56DE\u5E94\u5B83\u3001\u4E5F\u4E0D\u9700\u8981\u66FF\u7528\u6237\u53BB\u505A\u8FD9\u4EF6\u4E8B\u3002',
|
|
2276
2553
|
"<\u539F\u6587>",
|
|
2277
2554
|
String(original ?? ""),
|
|
2278
2555
|
"</\u539F\u6587>",
|
|
2279
2556
|
"",
|
|
2280
|
-
|
|
2281
|
-
"- \u53EA\u8F93\u51FA\
|
|
2282
|
-
'- \u8BFB\
|
|
2283
|
-
]
|
|
2557
|
+
"\u3010\u4F60\u7684\u4EFB\u52A1\u3011\u6309\u7CFB\u7EDF\u63D0\u793A\u8BCD\u7684\u89C4\u5219\uFF0C\u628A\u4E0A\u9762\u7684\u539F\u8BDD\u62C6\u6210**\u6761\u76EE**\u5E76\u7ED9\u6BCF\u6761\u9644\u4E0A**\u9010\u5B57\u5F15\u6587**\u3002",
|
|
2558
|
+
"- \u53EA\u8F93\u51FA\u90A3\u4EFD JSON \u5951\u7EA6\u8981\u6C42\u7684\u4E1C\u897F\uFF1B\u4E0D\u8981\u56DE\u5E94\u6211\u3001\u4E0D\u8981\u56DE\u7B54\u95EE\u9898\u3001\u4E0D\u8981\u8C22\u5E55\u3001\u4E0D\u8981\u89E3\u91CA\u4F60\u505A\u4E86\u4EC0\u4E48\u3002",
|
|
2559
|
+
'- \u8BFB\u8005\u53EA\u6709"\u5DE5\u4F5C AI"\u4E00\u4E2A\uFF0C\u800C\u4F60\u7684\u4EA7\u51FA\u4F1A\u5148\u7ECF\u5BBF\u4E3B\u9010\u6761\u6838\u5BF9\u5F15\u6587\u3002'
|
|
2560
|
+
];
|
|
2561
|
+
if (options.retry === true) {
|
|
2562
|
+
parts.push(
|
|
2563
|
+
"",
|
|
2564
|
+
`\u3010\u91CD\u8981\uFF1A\u4F60\u4E0A\u4E00\u6B21\u7684\u8F93\u51FA\u662F\u7A7A\u7684${options.reason ? `\uFF08${options.reason}\uFF09` : ""}\u3011`,
|
|
2565
|
+
"\u4E0A\u4E00\u6B21\u4F60\u6CA1\u6709\u7ED9\u51FA\u4EFB\u4F55\u6761\u76EE\uFF0C\u8FD9\u4E00\u8F6E\u56E0\u6B64**\u6CA1\u6709\u4EFB\u4F55\u8865\u5168**\u53EF\u4EE5\u4EA4\u7ED9\u5DE5\u4F5C AI\u3002",
|
|
2566
|
+
"\u8BF7\u6309\u7CFB\u7EDF\u63D0\u793A\u8BCD\u7684\u786C\u89C4\u5219\u91CD\u505A\uFF1A**\u54EA\u6015\u7528\u6237\u53EA\u5199\u4E86\u4E00\u4E24\u4E2A\u5B57\uFF0C\u4E5F\u8981\u5C3D\u91CF\u628A\u5B83\u62C6\u6210\u53EF\u5F15\u7528\u7684\u6761\u76EE**",
|
|
2567
|
+
'\uFF08\u81F3\u5C11\u4E00\u6761 `rewrite`\uFF0C\u6216\u4E00\u6761 `quality` / `unknown`\uFF09\uFF1B\u786E\u5B9E\u6CA1\u6709\u53EF\u8865\u7684\u5185\u5BB9\u65F6\u624D\u8F93\u51FA {"items":[]}\u3002',
|
|
2568
|
+
"\u53EA\u8F93\u51FA JSON\u3002"
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
return parts.join("\n");
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
// src/optimizer-assemble.ts
|
|
2575
|
+
var TIER_BUDGET = {
|
|
2576
|
+
basic: { factor: 1.4, floor: 400 },
|
|
2577
|
+
advanced: { factor: 2.6, floor: 700 },
|
|
2578
|
+
extreme: { factor: 4, floor: 1400 }
|
|
2579
|
+
};
|
|
2580
|
+
var TIER_KINDS = {
|
|
2581
|
+
basic: ["rewrite", "unknown"],
|
|
2582
|
+
advanced: ["rewrite", "requirement", "quality", "unknown"],
|
|
2583
|
+
extreme: ["rewrite", "requirement", "quality", "unknown", "plan", "risk"]
|
|
2584
|
+
};
|
|
2585
|
+
function allowedKindsFor(tier) {
|
|
2586
|
+
return TIER_KINDS[tier] ?? TIER_KINDS.advanced;
|
|
2587
|
+
}
|
|
2588
|
+
function optimizeBudgetFor(tier, originalChars) {
|
|
2589
|
+
const spec = TIER_BUDGET[tier] ?? TIER_BUDGET.advanced;
|
|
2590
|
+
const scaled = Math.ceil(Math.max(0, originalChars) * spec.factor);
|
|
2591
|
+
return Math.min(OPTIMIZE_OUTPUT_MAX, Math.max(spec.floor, scaled));
|
|
2592
|
+
}
|
|
2593
|
+
function looksLikeEnvelope(raw) {
|
|
2594
|
+
const text = String(raw ?? "").trim();
|
|
2595
|
+
if (text.startsWith("{") || text.startsWith("```")) return true;
|
|
2596
|
+
return /"(items|ops)"\s*:/.test(text);
|
|
2597
|
+
}
|
|
2598
|
+
function extractJson(raw) {
|
|
2599
|
+
const text = String(raw ?? "");
|
|
2600
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
2601
|
+
const candidate = fenced ? fenced[1] : text;
|
|
2602
|
+
const start = candidate.indexOf("{");
|
|
2603
|
+
const end = candidate.lastIndexOf("}");
|
|
2604
|
+
const envelope = looksLikeEnvelope(text);
|
|
2605
|
+
if (start < 0 || end <= start) {
|
|
2606
|
+
return envelope ? { ok: false, code: "BAD_JSON", reason: "\u8F93\u51FA\u770B\u8D77\u6765\u662F\u672C\u63D2\u4EF6\u7684\u6761\u76EE JSON\uFF0C\u4F46\u62EC\u53F7\u4E0D\u5B8C\u6574\uFF08\u53EF\u80FD\u88AB\u622A\u65AD\uFF09" } : { ok: false, code: "NO_JSON", reason: "\u8F93\u51FA\u91CC\u6CA1\u6709 JSON \u5BF9\u8C61" };
|
|
2607
|
+
}
|
|
2608
|
+
try {
|
|
2609
|
+
return { ok: true, value: JSON.parse(candidate.slice(start, end + 1)) };
|
|
2610
|
+
} catch (error) {
|
|
2611
|
+
return {
|
|
2612
|
+
ok: false,
|
|
2613
|
+
code: envelope ? "BAD_JSON" : "NO_JSON",
|
|
2614
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
function findQuoteSpan(original, quote) {
|
|
2619
|
+
const q = String(quote ?? "").trim();
|
|
2620
|
+
if (q === "") return void 0;
|
|
2621
|
+
const exact = original.indexOf(q);
|
|
2622
|
+
if (exact >= 0) return { start: exact, end: exact + q.length };
|
|
2623
|
+
const target = q.replace(/\s+/g, " ");
|
|
2624
|
+
let acc = "";
|
|
2625
|
+
const map = [];
|
|
2626
|
+
for (let i = 0; i < original.length; i += 1) {
|
|
2627
|
+
const ch = original[i];
|
|
2628
|
+
if (/\s/.test(ch)) {
|
|
2629
|
+
if (acc === "" || acc.endsWith(" ")) continue;
|
|
2630
|
+
acc += " ";
|
|
2631
|
+
map.push(i);
|
|
2632
|
+
continue;
|
|
2633
|
+
}
|
|
2634
|
+
acc += ch;
|
|
2635
|
+
map.push(i);
|
|
2636
|
+
}
|
|
2637
|
+
const at = acc.indexOf(target);
|
|
2638
|
+
if (at < 0) return void 0;
|
|
2639
|
+
const start = map[at];
|
|
2640
|
+
const last = map[at + target.length - 1] ?? start;
|
|
2641
|
+
return { start, end: last + 1 };
|
|
2642
|
+
}
|
|
2643
|
+
function itemsOf(value, warnings) {
|
|
2644
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
2645
|
+
const row = value;
|
|
2646
|
+
if (Array.isArray(row.items)) return row.items;
|
|
2647
|
+
if (Array.isArray(row.ops)) {
|
|
2648
|
+
const out = [];
|
|
2649
|
+
for (const op of row.ops) {
|
|
2650
|
+
if (typeof op !== "object" || op === null) continue;
|
|
2651
|
+
const entry = op;
|
|
2652
|
+
if (entry.op === "add_item" && typeof entry.item === "object" && entry.item !== null) {
|
|
2653
|
+
out.push(entry.item);
|
|
2654
|
+
continue;
|
|
2655
|
+
}
|
|
2656
|
+
warnings.push(`\u5FFD\u7565\u4E86\u4E0D\u652F\u6301\u7684 op\u300C${String(entry.op ?? "(\u7A7A)")}\u300D\uFF1A\u672C\u63D2\u4EF6\u4E0D\u505A\u8DE8\u8F6E\u72B6\u6001\uFF0C\u53EA\u8BA4 add_item`);
|
|
2657
|
+
}
|
|
2658
|
+
return out;
|
|
2659
|
+
}
|
|
2660
|
+
return void 0;
|
|
2661
|
+
}
|
|
2662
|
+
function hasEnvelopeKey(value) {
|
|
2663
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
2664
|
+
const row = value;
|
|
2665
|
+
return "items" in row || "ops" in row;
|
|
2666
|
+
}
|
|
2667
|
+
function unknownClassOf(value) {
|
|
2668
|
+
return OPTIMIZE_UNKNOWN_CLASSES.includes(value) ? value : "user_preference";
|
|
2669
|
+
}
|
|
2670
|
+
function parseOptimizeOutput(raw, original) {
|
|
2671
|
+
const extracted = extractJson(raw);
|
|
2672
|
+
if (!extracted.ok) return { ok: false, code: extracted.code, reason: extracted.reason };
|
|
2673
|
+
const warnings = [];
|
|
2674
|
+
const raw_items = itemsOf(extracted.value, warnings);
|
|
2675
|
+
if (raw_items === void 0) {
|
|
2676
|
+
return hasEnvelopeKey(extracted.value) ? { ok: false, code: "BAD_SHAPE", reason: '\u671F\u671B {"items":[...]} \u6216 {"ops":[{"op":"add_item","item":{...}}]}' } : { ok: false, code: "NOT_ENVELOPE", reason: "\u8FD9\u662F\u4E00\u6BB5 JSON\uFF0C\u4F46\u4E0D\u662F\u672C\u63D2\u4EF6\u7684\u6761\u76EE\u4FE1\u5C01" };
|
|
2677
|
+
}
|
|
2678
|
+
const items = [];
|
|
2679
|
+
const dropped = [];
|
|
2680
|
+
const seenRewrite = /* @__PURE__ */ new Set();
|
|
2681
|
+
for (let index = 0; index < raw_items.length; index += 1) {
|
|
2682
|
+
const id = `item#${index + 1}`;
|
|
2683
|
+
const entry = raw_items[index];
|
|
2684
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
2685
|
+
dropped.push({ id, kind: "(\u975E\u5BF9\u8C61)", reason: "\u6761\u76EE\u4E0D\u662F\u5BF9\u8C61" });
|
|
2686
|
+
continue;
|
|
2687
|
+
}
|
|
2688
|
+
const row = entry;
|
|
2689
|
+
const kind = String(row.kind ?? "");
|
|
2690
|
+
if (!OPTIMIZE_ITEM_KINDS.includes(kind)) {
|
|
2691
|
+
dropped.push({ id, kind: kind === "" ? "(\u7A7A)" : kind, reason: `kind \u4E0D\u5728\u5141\u8BB8\u5217\u8868\u91CC\uFF08${OPTIMIZE_ITEM_KINDS.join(" / ")}\uFF09` });
|
|
2692
|
+
continue;
|
|
2693
|
+
}
|
|
2694
|
+
let text = typeof row.text === "string" ? row.text.trim() : "";
|
|
2695
|
+
if (text === "") {
|
|
2696
|
+
dropped.push({ id, kind, reason: "text \u662F\u7A7A\u7684" });
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
if (text.length > OPTIMIZE_ITEM_MAX_CHARS) {
|
|
2700
|
+
warnings.push(`${id}\uFF1Atext \u8D85 ${OPTIMIZE_ITEM_MAX_CHARS} \u5B57\uFF0C\u5DF2\u622A\u65AD`);
|
|
2701
|
+
text = text.slice(0, OPTIMIZE_ITEM_MAX_CHARS);
|
|
2702
|
+
}
|
|
2703
|
+
if (items.length >= OPTIMIZE_MAX_ITEMS) {
|
|
2704
|
+
dropped.push({ id, kind, reason: `\u8D85\u8FC7\u5355\u8F6E\u4E0A\u9650 ${OPTIMIZE_MAX_ITEMS} \u6761 \u21D2 \u622A\u65AD\u4E22\u5F03\uFF08\u6574\u8F6E\u7167\u5E38\u51FA\u6210\u54C1\uFF09` });
|
|
2705
|
+
continue;
|
|
2706
|
+
}
|
|
2707
|
+
const needsQuote = kind === "rewrite" || kind === "requirement" || kind === "quality";
|
|
2708
|
+
const quote = typeof row.quote === "string" ? row.quote.trim() : "";
|
|
2709
|
+
if (needsQuote) {
|
|
2710
|
+
if (quote === "") {
|
|
2711
|
+
dropped.push({ id, kind, reason: "\u7F3A\u5C11 quote\uFF08\u8FD9\u4E00\u7C7B\u6761\u76EE\u5FC5\u987B\u6709\u9010\u5B57\u5F15\u6587\uFF09" });
|
|
2712
|
+
continue;
|
|
2713
|
+
}
|
|
2714
|
+
const span2 = findQuoteSpan(original, quote);
|
|
2715
|
+
if (span2 === void 0) {
|
|
2716
|
+
dropped.push({ id, kind, reason: `\u5F15\u6587\u4E0D\u662F\u539F\u8BDD\u91CC\u7684\u9010\u5B57\u7247\u6BB5\uFF1A\u300C${quote.slice(0, 40)}\u300D` });
|
|
2717
|
+
continue;
|
|
2718
|
+
}
|
|
2719
|
+
if (kind === "rewrite") {
|
|
2720
|
+
const key = `${String(span2.start)}-${String(span2.end)}`;
|
|
2721
|
+
if (seenRewrite.has(key)) {
|
|
2722
|
+
dropped.push({ id, kind, reason: "\u4E0E\u53E6\u4E00\u6761 rewrite \u5F15\u7528\u4E86\u540C\u4E00\u6BB5\u539F\u8BDD\uFF08\u91CD\u590D\uFF09" });
|
|
2723
|
+
continue;
|
|
2724
|
+
}
|
|
2725
|
+
seenRewrite.add(key);
|
|
2726
|
+
}
|
|
2727
|
+
items.push({ id, kind, text, quote, span: span2, quoteSource: "user" });
|
|
2728
|
+
continue;
|
|
2729
|
+
}
|
|
2730
|
+
const span = quote === "" ? void 0 : findQuoteSpan(original, quote);
|
|
2731
|
+
if (quote !== "" && span === void 0) {
|
|
2732
|
+
warnings.push(`${id}\uFF1A\u5F15\u6587\u5BF9\u4E0D\u4E0A\u539F\u8BDD\uFF0C\u5DF2\u6309"\u6A21\u578B\u81EA\u5DF1\u8865\u7684"\u8BB0\u8D26\uFF08\u4E0D\u5192\u5145\u4F60\u8BF4\u8FC7\u7684\u8BDD\uFF09`);
|
|
2733
|
+
}
|
|
2734
|
+
items.push({
|
|
2735
|
+
id,
|
|
2736
|
+
kind,
|
|
2737
|
+
text,
|
|
2738
|
+
quoteSource: span === void 0 ? "none" : "user",
|
|
2739
|
+
...span === void 0 ? {} : { span, quote },
|
|
2740
|
+
...kind === "unknown" ? { unknownClass: unknownClassOf(row.unknownClass), blocking: row.blocking === true } : {}
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
if (items.length === 0 && dropped.length === 0 && raw_items.length === 0) warnings.push("\u6A21\u578B\u4EA4\u56DE\u7A7A\u6570\u7EC4\uFF1A\u8FD9\u4E00\u8F6E\u6CA1\u6709\u53EF\u6838\u5B9E\u7684\u8865\u5168");
|
|
2744
|
+
return { ok: true, items, dropped, warnings };
|
|
2745
|
+
}
|
|
2746
|
+
var SECTIONS = [
|
|
2747
|
+
{ key: "requirement", label: "\u8865\u5168\u8981\u6C42\uFF08\u6BCF\u6761\u90FD\u6307\u56DE\u4F60\u539F\u8BDD\u91CC\u7684\u67D0\u53E5\uFF09", required: true },
|
|
2748
|
+
{ key: "quality", label: "\u5BF9\u8D28\u91CF\u8BCD\u7684\u7406\u89E3", required: false },
|
|
2749
|
+
{ key: "plan", label: "\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212", required: false },
|
|
2750
|
+
{ key: "risk", label: "\u591A\u60C5\u51B5\u9884\u6848", required: false },
|
|
2751
|
+
{ key: "unknown", label: "\u4E0D\u660E\u786E\u5904", required: false }
|
|
2752
|
+
];
|
|
2753
|
+
var DROP_ORDER = ["risk", "plan", "quality", "unknown"];
|
|
2754
|
+
var UNKNOWN_SUFFIX = {
|
|
2755
|
+
user_preference: "\uFF08\u53EA\u6709\u6211\u80FD\u5B9A\uFF1A\u5148\u95EE\u6211\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE\uFF09",
|
|
2756
|
+
lookupable_fact: "\uFF08\u53EF\u67E5\u8BC1\u7684\u4E8B\u5B9E\uFF1A\u5148\u8BFB\u4EE3\u7801/\u6587\u6863\u786E\u8BA4\uFF0C\u4E0D\u8981\u731C\uFF09",
|
|
2757
|
+
implementation_detail: "\uFF08\u5B9E\u73B0\u7EC6\u8282\uFF1A\u4F60\u81EA\u5DF1\u5B9A\uFF09"
|
|
2758
|
+
};
|
|
2759
|
+
function lineFor(item) {
|
|
2760
|
+
if (item.kind === "unknown") {
|
|
2761
|
+
const cls = item.unknownClass ?? "user_preference";
|
|
2762
|
+
const blocking = item.blocking === true ? "[\u6321\u4F4F\u4E0B\u4E00\u6B65] " : "";
|
|
2763
|
+
return `- ${blocking}${item.text}${UNKNOWN_SUFFIX[cls]}`;
|
|
2764
|
+
}
|
|
2765
|
+
const evidence = item.quote === void 0 ? "" : `\uFF08\u4F9D\u636E\uFF1A"${item.quote}"\uFF09`;
|
|
2766
|
+
return `- ${item.text}${evidence}`;
|
|
2767
|
+
}
|
|
2768
|
+
function assembleCommand(original, items, options) {
|
|
2769
|
+
const body0 = String(original ?? "");
|
|
2770
|
+
const warnings = [];
|
|
2771
|
+
const dropped = [];
|
|
2772
|
+
const allowed = allowedKindsFor(options.tier);
|
|
2773
|
+
const usable = [];
|
|
2774
|
+
for (const item of items) {
|
|
2775
|
+
if (allowed.includes(item.kind)) {
|
|
2776
|
+
usable.push(item);
|
|
2777
|
+
continue;
|
|
2778
|
+
}
|
|
2779
|
+
dropped.push({ id: item.id, kind: item.kind, reason: `\u5F53\u524D\u6863\u4F4D\uFF08${options.tier}\uFF09\u4E0D\u4EA7\u51FA\u300C${item.kind}\u300D\u8FD9\u4E00\u7C7B\u6761\u76EE` });
|
|
2780
|
+
}
|
|
2781
|
+
const rewrites = usable.filter((item) => item.kind === "rewrite" && item.span !== void 0).slice().sort((a, b) => a.span.start - b.span.start || a.span.end - b.span.end);
|
|
2782
|
+
const keptRewrites = [];
|
|
2783
|
+
let cursor = -1;
|
|
2784
|
+
for (const item of rewrites) {
|
|
2785
|
+
if (item.span.start < cursor) {
|
|
2786
|
+
dropped.push({ id: item.id, kind: item.kind, reason: "\u6539\u5199\u533A\u95F4\u4E0E\u53E6\u4E00\u6761 rewrite \u91CD\u53E0\uFF0C\u53EA\u4FDD\u7559\u9760\u524D\u7684\u90A3\u6761" });
|
|
2787
|
+
continue;
|
|
2788
|
+
}
|
|
2789
|
+
cursor = item.span.end;
|
|
2790
|
+
keptRewrites.push(item);
|
|
2791
|
+
}
|
|
2792
|
+
let body = body0;
|
|
2793
|
+
let rewrittenChars = 0;
|
|
2794
|
+
for (let i = keptRewrites.length - 1; i >= 0; i -= 1) {
|
|
2795
|
+
const span = keptRewrites[i].span;
|
|
2796
|
+
body = body.slice(0, span.start) + keptRewrites[i].text + body.slice(span.end);
|
|
2797
|
+
rewrittenChars += span.end - span.start;
|
|
2798
|
+
}
|
|
2799
|
+
const included = {};
|
|
2800
|
+
for (const section of SECTIONS) included[section.key] = [];
|
|
2801
|
+
for (const item of usable) {
|
|
2802
|
+
if (item.kind === "rewrite") continue;
|
|
2803
|
+
if (included[item.kind] === void 0) continue;
|
|
2804
|
+
included[item.kind].push(item);
|
|
2805
|
+
}
|
|
2806
|
+
const renderBlocks = () => {
|
|
2807
|
+
const blocks2 = [];
|
|
2808
|
+
for (const section of SECTIONS) {
|
|
2809
|
+
const bucket = included[section.key] ?? [];
|
|
2810
|
+
if (bucket.length === 0) continue;
|
|
2811
|
+
blocks2.push(`\u3010${section.label}\u3011
|
|
2812
|
+
${bucket.map(lineFor).join("\n")}`);
|
|
2813
|
+
}
|
|
2814
|
+
return blocks2;
|
|
2815
|
+
};
|
|
2816
|
+
const compose = (blocks2, removed2, overBy2) => {
|
|
2817
|
+
const tail = [];
|
|
2818
|
+
if (removed2.length > 0) {
|
|
2819
|
+
tail.push(`\u3010\u8BF4\u660E\u3011\u56E0\u7BC7\u5E45\u9884\u7B97\u7701\u7565 ${removed2.length} \u6761\u8865\u5168\uFF08${removed2.map((d) => d.kind).join("\u3001")}\uFF09\uFF1B\u5982\u679C\u5176\u4E2D\u6709\u7528\u4FE1\u606F\u5F71\u54CD\u5224\u65AD\uFF0C\u8BF7\u5148\u5411\u6211\u786E\u8BA4\u3002`);
|
|
2820
|
+
}
|
|
2821
|
+
if (overBy2 > 0) {
|
|
2822
|
+
tail.push(`\u3010\u9884\u7B97\u4E0D\u8DB3\u3011\u5DF2\u7701\u7565\u5168\u90E8\u53EF\u7701\u7565\u9879\uFF0C\u4ECD\u8D85\u51FA\u7EA6 ${overBy2} \u5B57\u7B26\uFF1B\u672C\u8F6E\u5148\u6309\u4E0B\u8FBE\u7684\u8FD9\u4E9B\u505A\uFF0C\u9700\u8981\u4FDD\u7559\u88AB\u7701\u7565\u7684\u5185\u5BB9\u8BF7\u7F29\u5C0F\u8303\u56F4\u3002`);
|
|
2823
|
+
}
|
|
2824
|
+
const head = blocks2.length === 0 ? "" : `${body}
|
|
2825
|
+
|
|
2826
|
+
${blocks2.join("\n\n")}`;
|
|
2827
|
+
if (tail.length === 0) return blocks2.length === 0 ? body : head;
|
|
2828
|
+
return head === "" ? tail.join("\n\n") : `${head}
|
|
2829
|
+
|
|
2830
|
+
${tail.join("\n\n")}`;
|
|
2831
|
+
};
|
|
2832
|
+
const budget = optimizeBudgetFor(options.tier, body0.length);
|
|
2833
|
+
const removed = [];
|
|
2834
|
+
let blocks = renderBlocks();
|
|
2835
|
+
let overBy = 0;
|
|
2836
|
+
let text = compose(blocks, removed, 0);
|
|
2837
|
+
for (let guard = 0; guard < 200; guard += 1) {
|
|
2838
|
+
const bare = compose(blocks, [], 0);
|
|
2839
|
+
overBy = bare.length > budget ? bare.length - budget : 0;
|
|
2840
|
+
text = compose(blocks, removed, overBy);
|
|
2841
|
+
if (bare.length <= budget) break;
|
|
2842
|
+
const victim = DROP_ORDER.find((key) => (included[key] ?? []).length > 0);
|
|
2843
|
+
if (victim === void 0) break;
|
|
2844
|
+
const taken = included[victim].pop();
|
|
2845
|
+
removed.push({ id: taken.id, kind: taken.kind, reason: "budget\uFF08\u7BC7\u5E45\u9884\u7B97\uFF09" });
|
|
2846
|
+
blocks = renderBlocks();
|
|
2847
|
+
}
|
|
2848
|
+
if (removed.length > 0) {
|
|
2849
|
+
warnings.push(`\u7BC7\u5E45\u9884\u7B97 ${budget} \u5B57\u7B26\uFF1A\u7701\u7565\u4E86 ${removed.length} \u6761\uFF08${removed.map((d) => d.id).join("\u3001")}\uFF09`);
|
|
2850
|
+
}
|
|
2851
|
+
if (overBy > 0) warnings.push(`\u88C5\u4E86\u5FC5\u4FDD\u8282\u540E\u4ECD\u8D85\u51FA\u9884\u7B97\u7EA6 ${overBy} \u5B57\u7B26\uFF0C\u5DF2\u5728\u6210\u54C1\u91CC\u5982\u5B9E\u8BF4\u660E`);
|
|
2852
|
+
const itemCount = keptRewrites.length + SECTIONS.reduce((sum, section) => sum + (included[section.key] ?? []).length, 0);
|
|
2853
|
+
return {
|
|
2854
|
+
text,
|
|
2855
|
+
sections: SECTIONS.filter((section) => (included[section.key] ?? []).length > 0).map((section) => section.label),
|
|
2856
|
+
dropped: [...dropped, ...removed],
|
|
2857
|
+
warnings,
|
|
2858
|
+
chars: text.length,
|
|
2859
|
+
budget,
|
|
2860
|
+
overBudget: overBy > 0,
|
|
2861
|
+
overBy,
|
|
2862
|
+
rewrittenChars,
|
|
2863
|
+
itemCount
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
function runOptimizePipeline(raw, original, options) {
|
|
2867
|
+
const parsed = parseOptimizeOutput(raw, original);
|
|
2868
|
+
if (!parsed.ok) {
|
|
2869
|
+
if (parsed.code === "NO_JSON" || parsed.code === "NOT_ENVELOPE") {
|
|
2870
|
+
return {
|
|
2871
|
+
ok: true,
|
|
2872
|
+
text: raw.trim(),
|
|
2873
|
+
fallback: true,
|
|
2874
|
+
itemCount: 0,
|
|
2875
|
+
dropped: [],
|
|
2876
|
+
warnings: ["\u6A21\u578B\u6CA1\u6709\u6309 JSON \u5951\u7EA6\u8F93\u51FA\uFF1A\u5DF2\u6309\u539F\u6837\u5199\u56DE\uFF08\u8FD9\u4E00\u8F6E\u6CA1\u6709\u505A\u4F9D\u636E\u6821\u9A8C\uFF09"],
|
|
2877
|
+
sections: [],
|
|
2878
|
+
chars: raw.trim().length,
|
|
2879
|
+
budget: optimizeBudgetFor(options.tier, original.length),
|
|
2880
|
+
overBudget: false,
|
|
2881
|
+
rewrittenChars: 0
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2884
|
+
return { ok: false, code: parsed.code, reason: parsed.reason };
|
|
2885
|
+
}
|
|
2886
|
+
const assembled = assembleCommand(original, parsed.items, options);
|
|
2887
|
+
const warnings = [...parsed.warnings, ...assembled.warnings];
|
|
2888
|
+
if (parsed.items.length === 0 && parsed.dropped.length === 0) warnings.push("\u8FD9\u4E00\u8F6E\u6CA1\u6709\u53EF\u6838\u5B9E\u7684\u8865\u5168\uFF0C\u539F\u8BDD\u539F\u6837\u5199\u56DE");
|
|
2889
|
+
return {
|
|
2890
|
+
ok: true,
|
|
2891
|
+
text: assembled.text,
|
|
2892
|
+
fallback: false,
|
|
2893
|
+
itemCount: assembled.itemCount,
|
|
2894
|
+
dropped: [...parsed.dropped, ...assembled.dropped],
|
|
2895
|
+
warnings,
|
|
2896
|
+
sections: assembled.sections,
|
|
2897
|
+
chars: assembled.chars,
|
|
2898
|
+
budget: assembled.budget,
|
|
2899
|
+
overBudget: assembled.overBudget,
|
|
2900
|
+
rewrittenChars: assembled.rewrittenChars
|
|
2901
|
+
};
|
|
2284
2902
|
}
|
|
2285
2903
|
|
|
2286
2904
|
// src/quick-store.ts
|
|
@@ -2418,16 +3036,103 @@ async function ensureQuickBook(seed, file = quickStorePath()) {
|
|
|
2418
3036
|
}
|
|
2419
3037
|
}
|
|
2420
3038
|
|
|
3039
|
+
// src/settings-lock.ts
|
|
3040
|
+
import { readFile as readFile2, rm } from "node:fs/promises";
|
|
3041
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
3042
|
+
var SETTINGS_LOCK_FILENAME = "package.json.lock";
|
|
3043
|
+
function staleLockDecision(content, alive) {
|
|
3044
|
+
const text = content.trim();
|
|
3045
|
+
if (!/^[1-9][0-9]{0,9}$/.test(text)) return { action: "ignore", reason: "unreadable-holder" };
|
|
3046
|
+
const pid = Number(text);
|
|
3047
|
+
return alive(pid) ? { action: "keep", pid } : { action: "remove", pid };
|
|
3048
|
+
}
|
|
3049
|
+
function isProcessAlive(pid) {
|
|
3050
|
+
try {
|
|
3051
|
+
process.kill(pid, 0);
|
|
3052
|
+
return true;
|
|
3053
|
+
} catch (error) {
|
|
3054
|
+
return error?.code === "EPERM";
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
function profileDirOfPatchPath(patchPath) {
|
|
3058
|
+
return dirname2(patchPath);
|
|
3059
|
+
}
|
|
3060
|
+
async function recoverStaleSettingsLock(profileDir, log) {
|
|
3061
|
+
const path = join2(profileDir, SETTINGS_LOCK_FILENAME);
|
|
3062
|
+
let content;
|
|
3063
|
+
try {
|
|
3064
|
+
content = await readFile2(path, "utf8");
|
|
3065
|
+
} catch (error) {
|
|
3066
|
+
if (error?.code === "ENOENT") return "absent";
|
|
3067
|
+
log(`\u8BFB\u53D6\u5199\u5165\u9501\u5931\u8D25\uFF08${path}\uFF09\uFF1A${String(error)}`);
|
|
3068
|
+
return "ignored";
|
|
3069
|
+
}
|
|
3070
|
+
const decision = staleLockDecision(content, isProcessAlive);
|
|
3071
|
+
if (decision.action === "keep") {
|
|
3072
|
+
log(`\u5199\u5165\u9501\u7531 PID ${decision.pid} \u6301\u6709\u4E14\u8BE5\u8FDB\u7A0B\u4ECD\u5728\uFF0C\u4FDD\u6301\u4E0D\u52A8\uFF08${path}\uFF09\u3002`);
|
|
3073
|
+
return "kept";
|
|
3074
|
+
}
|
|
3075
|
+
if (decision.action === "ignore") {
|
|
3076
|
+
log(`\u5199\u5165\u9501\u5185\u5BB9\u4E0D\u662F PID\uFF0C\u4FDD\u6301\u4E0D\u52A8\uFF08${path}\uFF09\u3002`);
|
|
3077
|
+
return "ignored";
|
|
3078
|
+
}
|
|
3079
|
+
try {
|
|
3080
|
+
await rm(path, { force: true });
|
|
3081
|
+
} catch (error) {
|
|
3082
|
+
log(`\u56DE\u6536\u5B64\u513F\u5199\u5165\u9501\u5931\u8D25\uFF08${path}\uFF09\uFF1A${String(error)}`);
|
|
3083
|
+
return "ignored";
|
|
3084
|
+
}
|
|
3085
|
+
log(
|
|
3086
|
+
`\u5DF2\u56DE\u6536\u5B64\u513F\u5199\u5165\u9501\uFF08\u6301\u6709\u8005 PID ${decision.pid} \u4E0D\u5B58\u5728\uFF09\uFF1A${path}\u3002\u5728\u6B64\u4E4B\u524D\u8BE5 profile \u7684\u6BCF\u4E00\u6B21\u8BBE\u7F6E\u5199\u5165\u90FD\u4F1A\u8D85\u65F6\u5931\u8D25\uFF08\u754C\u9762\u8868\u73B0\u4E3A"\u70B9\u4E86\u6CA1\u53CD\u5E94"\uFF09\u3002`
|
|
3087
|
+
);
|
|
3088
|
+
return "removed";
|
|
3089
|
+
}
|
|
3090
|
+
|
|
2421
3091
|
// src/host.ts
|
|
2422
3092
|
var name = "composer-ux";
|
|
2423
3093
|
var PANEL_MIN = 560;
|
|
2424
3094
|
var PANEL_MAX = 4e3;
|
|
3095
|
+
function plainConfig(value) {
|
|
3096
|
+
if (typeof value === "object" && value !== null && typeof value.get === "function") {
|
|
3097
|
+
return plainConfig(value.get());
|
|
3098
|
+
}
|
|
3099
|
+
if (Array.isArray(value)) return value.map(plainConfig);
|
|
3100
|
+
if (typeof value === "object" && value !== null) {
|
|
3101
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plainConfig(child)]));
|
|
3102
|
+
}
|
|
3103
|
+
return value;
|
|
3104
|
+
}
|
|
3105
|
+
function makeReader(settings, config) {
|
|
3106
|
+
return (ns) => {
|
|
3107
|
+
try {
|
|
3108
|
+
if (typeof settings?.get === "function") return objectOf2(settings.get(ns));
|
|
3109
|
+
if (ns === NAMESPACE) {
|
|
3110
|
+
const own = objectOf2(plainConfig(config));
|
|
3111
|
+
if (own !== void 0) return own;
|
|
3112
|
+
}
|
|
3113
|
+
const row = (settings?.describe?.() ?? []).find((candidate) => candidate?.ns === ns);
|
|
3114
|
+
return objectOf2(row?.value);
|
|
3115
|
+
} catch {
|
|
3116
|
+
return void 0;
|
|
3117
|
+
}
|
|
3118
|
+
};
|
|
3119
|
+
}
|
|
2425
3120
|
function objectOf2(value) {
|
|
2426
3121
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
2427
3122
|
}
|
|
2428
3123
|
function textOf2(value) {
|
|
2429
3124
|
return typeof value === "string" ? value : "";
|
|
2430
3125
|
}
|
|
3126
|
+
function readOwnSetting(scope, config, field) {
|
|
3127
|
+
try {
|
|
3128
|
+
const get = scope?.get;
|
|
3129
|
+
if (typeof get !== "function") return "";
|
|
3130
|
+
const service = get.call(scope, "settings");
|
|
3131
|
+
return textOf2(makeReader(service, config)(NAMESPACE)?.[field]);
|
|
3132
|
+
} catch {
|
|
3133
|
+
return "";
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
2431
3136
|
function firstHeaderValue(value) {
|
|
2432
3137
|
if (value === void 0) return void 0;
|
|
2433
3138
|
return typeof value === "string" ? value : value[0];
|
|
@@ -2475,8 +3180,8 @@ function errorText3(error) {
|
|
|
2475
3180
|
if (error instanceof Error && error.message !== "") return error.message;
|
|
2476
3181
|
return String(error);
|
|
2477
3182
|
}
|
|
2478
|
-
async function mirrorHeader(settings) {
|
|
2479
|
-
const own =
|
|
3183
|
+
async function mirrorHeader(settings, read) {
|
|
3184
|
+
const own = read(NAMESPACE);
|
|
2480
3185
|
if (own === void 0) return;
|
|
2481
3186
|
const enabled = own[ENABLED_FIELD] === true && own[HEADER_ENABLED_FIELD] === true;
|
|
2482
3187
|
const name2 = textOf2(own[HEADER_NAME_FIELD]);
|
|
@@ -2487,7 +3192,7 @@ async function mirrorHeader(settings) {
|
|
|
2487
3192
|
value = newSessionId();
|
|
2488
3193
|
await settings.mutate(NAMESPACE, [{ op: "set", path: [HEADER_VALUE_FIELD], value }]);
|
|
2489
3194
|
}
|
|
2490
|
-
const llm =
|
|
3195
|
+
const llm = read(LLM_NAMESPACE);
|
|
2491
3196
|
const providers = llm === void 0 ? void 0 : objectOf2(llm.providers);
|
|
2492
3197
|
const writes = [];
|
|
2493
3198
|
const applied = [];
|
|
@@ -2553,70 +3258,109 @@ async function mirrorHeader(settings) {
|
|
|
2553
3258
|
}
|
|
2554
3259
|
if (ownOps.length > 0) await settings.mutate(NAMESPACE, ownOps);
|
|
2555
3260
|
}
|
|
2556
|
-
function
|
|
3261
|
+
function ownSchema() {
|
|
3262
|
+
return Schema.object({
|
|
3263
|
+
[ENABLED_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.enabled),
|
|
3264
|
+
// 五栏开关。**故意不给默认值、声明成可选**:迁移要用的信息就是"文档里有没有这个键"
|
|
3265
|
+
// —— 没有 ⇒ 从没碰过这一栏 ⇒ 关闭;有 ⇒ 用户碰过 ⇒ 保持他写下的值。
|
|
3266
|
+
// 给了静态默认值就再也分不出这两种情况了(净化的 sectionEnabledOf 靠它)。
|
|
3267
|
+
[KEYS_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
3268
|
+
[MENU_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
3269
|
+
[QUICK_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
3270
|
+
[PANEL_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
3271
|
+
[TERMINAL_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
3272
|
+
[SEND_KEY_FIELD]: Schema.string().default(DEFAULT_SETTINGS.sendKey),
|
|
3273
|
+
[NEWLINE_KEY_FIELD]: Schema.string().default(DEFAULT_SETTINGS.newlineKey),
|
|
3274
|
+
...Object.fromEntries(MENU_FIELDS.map((field) => [
|
|
3275
|
+
field,
|
|
3276
|
+
Schema.boolean().default(DEFAULT_SETTINGS[field])
|
|
3277
|
+
])),
|
|
3278
|
+
// 右键菜单模式(0.5.0 起三档)。**故意不给默认值、且声明成可选**:
|
|
3279
|
+
// 「文档里没有这个键」本身就是迁移要用的信息——净化据此按旧布尔 menuNative
|
|
3280
|
+
// 推断(见 menuModeFrom)。给了默认值就再也分不出「从没设置过」与「明确设成了它」。
|
|
3281
|
+
[MENU_MODE_FIELD]: Schema.string().required(false),
|
|
3282
|
+
// 旧的布尔字段:只作迁移线索,故同样不给默认值——旧文档里的 true / false
|
|
3283
|
+
// 都要保住原意(true = 浏览器菜单、false = 明确选过自定义菜单)。
|
|
3284
|
+
[MENU_NATIVE_FIELD]: Schema.boolean().required(false),
|
|
3285
|
+
// 「导航滚动」在 0.6.0 随功能一起删掉了(DSH 0.1.7 的官方设置页自带导航列滚动)。
|
|
3286
|
+
// 旧文档里可能仍留着 panelScroll:schemastery 对未声明键是**原样放行**(已实测),
|
|
3287
|
+
// 所以不需要为它保留一个宽容字段,升级时也不会因此判非法。
|
|
3288
|
+
[PANEL_RESIZE_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.panelResize),
|
|
3289
|
+
// schemastery 无 .optional():可选键用 .required(false)。
|
|
3290
|
+
[PANEL_WIDTH_FIELD]: Schema.number().min(PANEL_MIN).max(PANEL_MAX).required(false),
|
|
3291
|
+
[PANEL_HEIGHT_FIELD]: Schema.number().min(320).max(PANEL_MAX).required(false),
|
|
3292
|
+
// OpenCode 请求头栏目(值由宿主半按 llm-pi-ai 的 Fetch 规则自校验后再写入)。
|
|
3293
|
+
[HEADER_ENABLED_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.headerEnabled),
|
|
3294
|
+
[HEADER_NAME_FIELD]: Schema.string().default(DEFAULT_HEADER_NAME),
|
|
3295
|
+
[HEADER_VALUE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerValue),
|
|
3296
|
+
[HEADER_ROUTES_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerRoutes),
|
|
3297
|
+
[HEADER_APPLIED_NAME_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerAppliedName),
|
|
3298
|
+
[HEADER_APPLIED_VALUE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerAppliedValue),
|
|
3299
|
+
[HEADER_STATUS_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerStatus),
|
|
3300
|
+
// 快捷指令列表:结构固定为 {id,label,prompt,always},逐条自带默认值,
|
|
3301
|
+
// 让旧设置文档(没有这个键)在读取时直接得到内置 9 条。
|
|
3302
|
+
[QUICK_PROMPTS_FIELD]: Schema.array(Schema.object({
|
|
3303
|
+
id: Schema.string().default(""),
|
|
3304
|
+
label: Schema.string().default(""),
|
|
3305
|
+
prompt: Schema.string().default(""),
|
|
3306
|
+
always: Schema.boolean().default(false)
|
|
3307
|
+
})).default(DEFAULT_QUICK_PROMPTS.map((item) => ({ ...item }))),
|
|
3308
|
+
[OPTIMIZER_TIER_FIELD]: Schema.string().default(DEFAULT_SETTINGS.optimizerTier),
|
|
3309
|
+
// 三档的自定义系统提示词:默认空串 = 用内置那份(空串同时就是「恢复内置」写回的值)。
|
|
3310
|
+
[OPTIMIZER_PROMPT_FIELDS.basic]: Schema.string().default(DEFAULT_SETTINGS.optimizerPromptBasic),
|
|
3311
|
+
[OPTIMIZER_PROMPT_FIELDS.advanced]: Schema.string().default(DEFAULT_SETTINGS.optimizerPromptAdvanced),
|
|
3312
|
+
[OPTIMIZER_PROMPT_FIELDS.extreme]: Schema.string().default(DEFAULT_SETTINGS.optimizerPromptExtreme),
|
|
3313
|
+
// 「默认终端」(0.5.0 起):用户档位与可选路径。
|
|
3314
|
+
[TERMINAL_MODE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalMode),
|
|
3315
|
+
[TERMINAL_BASH_PATH_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalBashPath),
|
|
3316
|
+
// 宿主半自持的三项:探测候选、状态行、当前生效 shell(见 HOST_OWNED_FIELDS)。
|
|
3317
|
+
[TERMINAL_CANDIDATES_FIELD]: Schema.array(Schema.object({
|
|
3318
|
+
path: Schema.string().default(""),
|
|
3319
|
+
label: Schema.string().default(""),
|
|
3320
|
+
kind: Schema.string().default("path"),
|
|
3321
|
+
explicit: Schema.boolean().default(false)
|
|
3322
|
+
})).default([]),
|
|
3323
|
+
[TERMINAL_STATUS_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalStatus),
|
|
3324
|
+
[TERMINAL_EFFECTIVE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalEffective)
|
|
3325
|
+
});
|
|
3326
|
+
}
|
|
3327
|
+
function markVolatileField(node) {
|
|
3328
|
+
const withMethod = node;
|
|
3329
|
+
if (typeof withMethod.volatile === "function") return withMethod.volatile();
|
|
3330
|
+
const target = node;
|
|
3331
|
+
if (target.meta !== void 0) target.meta.volatile = true;
|
|
3332
|
+
return node;
|
|
3333
|
+
}
|
|
3334
|
+
function markVolatile(schema) {
|
|
3335
|
+
const dict = schema.dict;
|
|
3336
|
+
if (dict === void 0) return schema;
|
|
3337
|
+
for (const key of Object.keys(dict)) dict[key] = markVolatileField(dict[key]);
|
|
3338
|
+
return schema;
|
|
3339
|
+
}
|
|
3340
|
+
var Config = markVolatile(ownSchema());
|
|
3341
|
+
function apply(ctx, config) {
|
|
3342
|
+
const readView = (service) => {
|
|
3343
|
+
if (service === null || service === void 0) return void 0;
|
|
3344
|
+
const real = service;
|
|
3345
|
+
return { get: makeReader(real, config), mutate: (ns, ops) => real.mutate(ns, ops) };
|
|
3346
|
+
};
|
|
3347
|
+
ctx.inject(["configEditor"], (lockCtx) => {
|
|
3348
|
+
try {
|
|
3349
|
+
const documentPath = lockCtx.configEditor.documentPath;
|
|
3350
|
+
if (typeof documentPath !== "string" || documentPath === "") return;
|
|
3351
|
+
void recoverStaleSettingsLock(profileDirOfPatchPath(documentPath), (message) => {
|
|
3352
|
+
console.warn(`[composer-ux] ${message}`);
|
|
3353
|
+
}).catch((error) => {
|
|
3354
|
+
console.error("[composer-ux] \u5B64\u513F\u5199\u5165\u9501\u68C0\u67E5\u5931\u8D25", error);
|
|
3355
|
+
});
|
|
3356
|
+
} catch (error) {
|
|
3357
|
+
console.error("[composer-ux] \u5B64\u513F\u5199\u5165\u9501\u68C0\u67E5\u5931\u8D25", error);
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
2557
3360
|
ctx.inject(["settings"], (settingsCtx) => {
|
|
2558
|
-
settingsCtx.settings.register(
|
|
2559
|
-
NAMESPACE,
|
|
2560
|
-
Schema.object({
|
|
2561
|
-
[ENABLED_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.enabled),
|
|
2562
|
-
// 五栏开关。**故意不给默认值、声明成可选**:迁移要用的信息就是"文档里有没有这个键"
|
|
2563
|
-
// —— 没有 ⇒ 从没碰过这一栏 ⇒ 关闭;有 ⇒ 用户碰过 ⇒ 保持他写下的值。
|
|
2564
|
-
// 给了静态默认值就再也分不出这两种情况了(净化的 sectionEnabledOf 靠它)。
|
|
2565
|
-
[KEYS_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
2566
|
-
[MENU_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
2567
|
-
[QUICK_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
2568
|
-
[PANEL_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
2569
|
-
[TERMINAL_ENABLED_FIELD]: Schema.boolean().required(false),
|
|
2570
|
-
[SEND_KEY_FIELD]: Schema.string().default(DEFAULT_SETTINGS.sendKey),
|
|
2571
|
-
[NEWLINE_KEY_FIELD]: Schema.string().default(DEFAULT_SETTINGS.newlineKey),
|
|
2572
|
-
...Object.fromEntries(MENU_FIELDS.map((field) => [
|
|
2573
|
-
field,
|
|
2574
|
-
Schema.boolean().default(DEFAULT_SETTINGS[field])
|
|
2575
|
-
])),
|
|
2576
|
-
// 右键菜单模式(0.5.0 起三档)。**故意不给默认值、且声明成可选**:
|
|
2577
|
-
// 「文档里没有这个键」本身就是迁移要用的信息——净化据此按旧布尔 menuNative
|
|
2578
|
-
// 推断(见 menuModeFrom)。给了默认值就再也分不出「从没设置过」与「明确设成了它」。
|
|
2579
|
-
[MENU_MODE_FIELD]: Schema.string().required(false),
|
|
2580
|
-
// 旧的布尔字段:只作迁移线索,故同样不给默认值——旧文档里的 true / false
|
|
2581
|
-
// 都要保住原意(true = 浏览器菜单、false = 明确选过自定义菜单)。
|
|
2582
|
-
[MENU_NATIVE_FIELD]: Schema.boolean().required(false),
|
|
2583
|
-
[PANEL_SCROLL_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.panelScroll),
|
|
2584
|
-
[PANEL_RESIZE_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.panelResize),
|
|
2585
|
-
// schemastery 无 .optional():可选键用 .required(false)。
|
|
2586
|
-
[PANEL_WIDTH_FIELD]: Schema.number().min(PANEL_MIN).max(PANEL_MAX).required(false),
|
|
2587
|
-
[PANEL_HEIGHT_FIELD]: Schema.number().min(320).max(PANEL_MAX).required(false),
|
|
2588
|
-
// OpenCode 请求头栏目(值由宿主半按 llm-pi-ai 的 Fetch 规则自校验后再写入)。
|
|
2589
|
-
[HEADER_ENABLED_FIELD]: Schema.boolean().default(DEFAULT_SETTINGS.headerEnabled),
|
|
2590
|
-
[HEADER_NAME_FIELD]: Schema.string().default(DEFAULT_HEADER_NAME),
|
|
2591
|
-
[HEADER_VALUE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerValue),
|
|
2592
|
-
[HEADER_ROUTES_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerRoutes),
|
|
2593
|
-
[HEADER_APPLIED_NAME_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerAppliedName),
|
|
2594
|
-
[HEADER_APPLIED_VALUE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerAppliedValue),
|
|
2595
|
-
[HEADER_STATUS_FIELD]: Schema.string().default(DEFAULT_SETTINGS.headerStatus),
|
|
2596
|
-
// 快捷指令列表:结构固定为 {id,label,prompt,always},逐条自带默认值,
|
|
2597
|
-
// 让旧设置文档(没有这个键)在读取时直接得到内置 9 条。
|
|
2598
|
-
[QUICK_PROMPTS_FIELD]: Schema.array(Schema.object({
|
|
2599
|
-
id: Schema.string().default(""),
|
|
2600
|
-
label: Schema.string().default(""),
|
|
2601
|
-
prompt: Schema.string().default(""),
|
|
2602
|
-
always: Schema.boolean().default(false)
|
|
2603
|
-
})).default(DEFAULT_QUICK_PROMPTS.map((item) => ({ ...item }))),
|
|
2604
|
-
[OPTIMIZER_TIER_FIELD]: Schema.string().default(DEFAULT_SETTINGS.optimizerTier),
|
|
2605
|
-
// 「默认终端」(0.5.0 起):用户档位与可选路径。
|
|
2606
|
-
[TERMINAL_MODE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalMode),
|
|
2607
|
-
[TERMINAL_BASH_PATH_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalBashPath),
|
|
2608
|
-
// 宿主半自持的三项:探测候选、状态行、当前生效 shell(见 HOST_OWNED_FIELDS)。
|
|
2609
|
-
[TERMINAL_CANDIDATES_FIELD]: Schema.array(Schema.object({
|
|
2610
|
-
path: Schema.string().default(""),
|
|
2611
|
-
label: Schema.string().default(""),
|
|
2612
|
-
kind: Schema.string().default("path"),
|
|
2613
|
-
explicit: Schema.boolean().default(false)
|
|
2614
|
-
})).default([]),
|
|
2615
|
-
[TERMINAL_STATUS_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalStatus),
|
|
2616
|
-
[TERMINAL_EFFECTIVE_FIELD]: Schema.string().default(DEFAULT_SETTINGS.terminalEffective)
|
|
2617
|
-
})
|
|
2618
|
-
);
|
|
2619
3361
|
const settings = settingsCtx.settings;
|
|
3362
|
+
if (typeof settings.register === "function") settings.register(NAMESPACE, Config);
|
|
3363
|
+
const read = makeReader(settings, config);
|
|
2620
3364
|
let busy = false;
|
|
2621
3365
|
let again = false;
|
|
2622
3366
|
const sync = () => {
|
|
@@ -2625,7 +3369,7 @@ function apply(ctx) {
|
|
|
2625
3369
|
return;
|
|
2626
3370
|
}
|
|
2627
3371
|
busy = true;
|
|
2628
|
-
void mirrorHeader(settings).catch((error) => {
|
|
3372
|
+
void mirrorHeader(settings, read).catch((error) => {
|
|
2629
3373
|
console.error("[composer-ux] \u8BF7\u6C42\u5934\u955C\u50CF\u5931\u8D25", error);
|
|
2630
3374
|
}).finally(() => {
|
|
2631
3375
|
busy = false;
|
|
@@ -2638,7 +3382,9 @@ function apply(ctx) {
|
|
|
2638
3382
|
const onSettingsUpdated = (ns) => {
|
|
2639
3383
|
if (ns === NAMESPACE || ns === LLM_NAMESPACE) sync();
|
|
2640
3384
|
};
|
|
2641
|
-
|
|
3385
|
+
for (const event of ["settings/updated", "settings/document-updated"]) {
|
|
3386
|
+
ctx.on(event, onSettingsUpdated);
|
|
3387
|
+
}
|
|
2642
3388
|
sync();
|
|
2643
3389
|
});
|
|
2644
3390
|
ctx.inject(["webServer", "llm"], (optCtx) => {
|
|
@@ -2699,57 +3445,98 @@ function apply(ctx) {
|
|
|
2699
3445
|
sendJson(res, 200, { ok: false, error: "\u62FF\u4E0D\u5230\u5F53\u524D\u7684\u6A21\u578B\u8DEF\u7531\uFF0C\u65E0\u6CD5\u4F18\u5316\uFF08\u8BF7\u5148\u5728\u8F93\u5165\u6846\u65C1\u7684\u6A21\u578B\u9009\u62E9\u5668\u91CC\u9009\u4E00\u4E2A\u6A21\u578B\uFF09" });
|
|
2700
3446
|
return;
|
|
2701
3447
|
}
|
|
3448
|
+
const customPrompt = readOwnSetting(optCtx, config, optimizerPromptFieldOf(tier));
|
|
3449
|
+
const system = buildOptimizeSystem(tier, customPrompt);
|
|
2702
3450
|
const controller = new AbortController();
|
|
2703
3451
|
const timer = setTimeout(() => {
|
|
2704
3452
|
controller.abort();
|
|
2705
3453
|
}, LLM_TIMEOUT_MS);
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
3454
|
+
const runOnce = async (userText) => {
|
|
3455
|
+
let out = "";
|
|
3456
|
+
let failure = "";
|
|
3457
|
+
try {
|
|
3458
|
+
const stream = optCtx.llm.stream({
|
|
3459
|
+
provider: route.provider,
|
|
3460
|
+
model: route.model,
|
|
3461
|
+
system,
|
|
3462
|
+
temperature: buildOptimizeTemperature(tier),
|
|
3463
|
+
signal: controller.signal,
|
|
3464
|
+
messages: [{
|
|
3465
|
+
id: `optimize-${Date.now().toString(36)}`,
|
|
3466
|
+
role: "user",
|
|
3467
|
+
content: [{ type: "text", text: userText }],
|
|
3468
|
+
source: { kind: "user" }
|
|
3469
|
+
}]
|
|
3470
|
+
});
|
|
3471
|
+
for await (const chunk of stream) {
|
|
3472
|
+
if (chunk.type === "text-delta") {
|
|
3473
|
+
out += String(chunk.text ?? "");
|
|
3474
|
+
if (out.length > OPTIMIZE_OUTPUT_MAX * 4) break;
|
|
3475
|
+
} else if (chunk.type === "finish") {
|
|
3476
|
+
const reason = objectOf2(chunk.reason);
|
|
3477
|
+
if (reason?.kind === "error" || reason?.kind === "aborted") {
|
|
3478
|
+
const detail = objectOf2(reason.failure);
|
|
3479
|
+
failure = textOf2(detail?.message) || (reason.kind === "aborted" ? "\u4F18\u5316\u88AB\u4E2D\u65AD" : "\u6A21\u578B\u8FD4\u56DE\u9519\u8BEF");
|
|
3480
|
+
}
|
|
2731
3481
|
}
|
|
2732
3482
|
}
|
|
3483
|
+
} catch (error) {
|
|
3484
|
+
failure = errorText3(error);
|
|
3485
|
+
}
|
|
3486
|
+
return { out, failure };
|
|
3487
|
+
};
|
|
3488
|
+
let retried = false;
|
|
3489
|
+
let result;
|
|
3490
|
+
try {
|
|
3491
|
+
result = await runOnce(buildOptimizeUser(text));
|
|
3492
|
+
if (result.out.trim() === "" && result.failure === "") {
|
|
3493
|
+
retried = true;
|
|
3494
|
+
const second = await runOnce(buildOptimizeUser(text, { retry: true, reason: "\u5BBF\u4E3B\u6CA1\u6709\u6536\u5230\u4EFB\u4F55\u6761\u76EE" }));
|
|
3495
|
+
if (second.out.trim() !== "") result = second;
|
|
3496
|
+
else if (result.failure === "") result = second;
|
|
2733
3497
|
}
|
|
2734
|
-
} catch (error) {
|
|
2735
|
-
failure = errorText3(error);
|
|
2736
3498
|
} finally {
|
|
2737
3499
|
clearTimeout(timer);
|
|
2738
3500
|
}
|
|
2739
|
-
|
|
2740
|
-
|
|
3501
|
+
if (result.out.trim() === "") {
|
|
3502
|
+
sendJson(res, 200, {
|
|
3503
|
+
ok: false,
|
|
3504
|
+
error: result.failure === "" ? "\u6A21\u578B\u6CA1\u6709\u4EA7\u51FA\u4EFB\u4F55\u5185\u5BB9" : `\u4F18\u5316\u5931\u8D25\uFF1A${result.failure}`,
|
|
3505
|
+
retried
|
|
3506
|
+
});
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
const assembled = runOptimizePipeline(result.out, text, { tier });
|
|
3510
|
+
if (!assembled.ok) {
|
|
2741
3511
|
sendJson(res, 200, {
|
|
2742
3512
|
ok: false,
|
|
2743
|
-
error:
|
|
3513
|
+
error: `\u6A21\u578B\u8F93\u51FA\u4E0D\u662F\u53EF\u7528\u7684\u6761\u76EE JSON\uFF08${assembled.code}\uFF09\uFF1A${assembled.reason}`,
|
|
3514
|
+
retried
|
|
2744
3515
|
});
|
|
2745
3516
|
return;
|
|
2746
3517
|
}
|
|
3518
|
+
const optimized = assembled.text.trim();
|
|
3519
|
+
if (optimized === "") {
|
|
3520
|
+
sendJson(res, 200, { ok: false, error: "\u88C5\u914D\u540E\u662F\u7A7A\u7684\uFF08\u6A21\u578B\u6CA1\u6709\u7ED9\u51FA\u53EF\u6838\u5B9E\u7684\u6761\u76EE\uFF09", retried });
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
2747
3523
|
sendJson(res, 200, {
|
|
2748
3524
|
ok: true,
|
|
2749
|
-
text: optimized
|
|
2750
|
-
truncated
|
|
3525
|
+
text: optimized,
|
|
3526
|
+
// 语义收窄:`truncated` 现在专指"篇幅闸门真的动过手"(装了必保节仍超预算)。
|
|
3527
|
+
truncated: assembled.overBudget,
|
|
2751
3528
|
provider: route.provider,
|
|
2752
|
-
model: route.model
|
|
3529
|
+
model: route.model,
|
|
3530
|
+
// ── 以下为 0.6.0 新增的**附加**字段:老客户端不读它们也不会坏。
|
|
3531
|
+
promptSource: optimizePromptSource(customPrompt),
|
|
3532
|
+
retried,
|
|
3533
|
+
fallback: assembled.fallback,
|
|
3534
|
+
itemCount: assembled.itemCount,
|
|
3535
|
+
rewrittenChars: assembled.rewrittenChars,
|
|
3536
|
+
dropped: assembled.dropped,
|
|
3537
|
+
warnings: assembled.warnings,
|
|
3538
|
+
budget: assembled.budget,
|
|
3539
|
+
chars: assembled.chars
|
|
2753
3540
|
});
|
|
2754
3541
|
};
|
|
2755
3542
|
optCtx.effect(() => optCtx.webServer.register({
|
|
@@ -2778,7 +3565,7 @@ function apply(ctx) {
|
|
|
2778
3565
|
const legacyPrompts = () => {
|
|
2779
3566
|
try {
|
|
2780
3567
|
const settings = storeCtx.get("settings");
|
|
2781
|
-
const row =
|
|
3568
|
+
const row = makeReader(settings, config)(NAMESPACE);
|
|
2782
3569
|
const list = row?.[QUICK_PROMPTS_FIELD];
|
|
2783
3570
|
return Array.isArray(list) ? list : void 0;
|
|
2784
3571
|
} catch {
|
|
@@ -2858,7 +3645,7 @@ function apply(ctx) {
|
|
|
2858
3645
|
installTerminalPolicy(
|
|
2859
3646
|
termCtx,
|
|
2860
3647
|
NAMESPACE,
|
|
2861
|
-
termCtx.get("settings"),
|
|
3648
|
+
readView(termCtx.get("settings")),
|
|
2862
3649
|
readToolDeps
|
|
2863
3650
|
);
|
|
2864
3651
|
});
|
|
@@ -2866,7 +3653,7 @@ function apply(ctx) {
|
|
|
2866
3653
|
void (async () => {
|
|
2867
3654
|
const service = migrateCtx.get("settings");
|
|
2868
3655
|
if (service === void 0) return;
|
|
2869
|
-
const row =
|
|
3656
|
+
const row = makeReader(service, config)(NAMESPACE);
|
|
2870
3657
|
if (row === void 0 || row[QUICK_ENABLED_FIELD] !== void 0) return;
|
|
2871
3658
|
try {
|
|
2872
3659
|
const outcome = await readQuickBook(quickStorePath());
|
|
@@ -2916,8 +3703,8 @@ function apply(ctx) {
|
|
|
2916
3703
|
stamp: (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19),
|
|
2917
3704
|
exists: (path) => existsSync2(path),
|
|
2918
3705
|
resolve: (path) => resolve2(path),
|
|
2919
|
-
dirname: (path) =>
|
|
2920
|
-
join: (...parts) =>
|
|
3706
|
+
dirname: (path) => dirname3(path),
|
|
3707
|
+
join: (...parts) => join3(...parts),
|
|
2921
3708
|
spawn: (command, args, options) => spawn(command, [...args], {
|
|
2922
3709
|
detached: options.detached,
|
|
2923
3710
|
stdio: options.stdio,
|
|
@@ -2948,7 +3735,7 @@ function apply(ctx) {
|
|
|
2948
3735
|
return {
|
|
2949
3736
|
command: [plan.respawn.file, ...plan.respawn.args].join(" "),
|
|
2950
3737
|
execPath: plan.node,
|
|
2951
|
-
logHint:
|
|
3738
|
+
logHint: join3(io.tmpdir, `${RESTART_LOG_PREFIX}*.err.log`)
|
|
2952
3739
|
};
|
|
2953
3740
|
};
|
|
2954
3741
|
restartCtx.effect(() => restartCtx.webServer.register({
|
|
@@ -3008,6 +3795,7 @@ function apply(ctx) {
|
|
|
3008
3795
|
});
|
|
3009
3796
|
}
|
|
3010
3797
|
export {
|
|
3798
|
+
Config,
|
|
3011
3799
|
apply,
|
|
3012
3800
|
name
|
|
3013
3801
|
};
|