@kairyou/agent-tools 0.5.0 → 0.5.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/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/scripts/install.mjs +32 -68
package/README.md
CHANGED
|
@@ -101,8 +101,8 @@ Here `5h` and `w` are Claude's rolling usage windows; `⟳` is the reset countdo
|
|
|
101
101
|
When a compatible API relay is active, the statusline also appends provider usage.
|
|
102
102
|
|
|
103
103
|
To choose what appears, edit `statusline.fields` in
|
|
104
|
-
`~/.agent-tools/config.jsonc`.
|
|
105
|
-
|
|
104
|
+
`~/.agent-tools/config.jsonc`. Installer updates only add missing default keys
|
|
105
|
+
and never touch your edits or comments.
|
|
106
106
|
|
|
107
107
|
### Provider usage
|
|
108
108
|
|
package/README.zh-CN.md
CHANGED
|
@@ -96,7 +96,7 @@ npx -y @kairyou/agent-tools@latest statusline -a claude
|
|
|
96
96
|
使用兼容的 API 中转时, statusline 还会追加 provider usage.
|
|
97
97
|
|
|
98
98
|
如需控制显示项, 修改 `~/.agent-tools/config.jsonc` 里的
|
|
99
|
-
`statusline.fields`.
|
|
99
|
+
`statusline.fields`. 安装器更新时只会补充缺失的默认键, 不会动你的修改和注释.
|
|
100
100
|
|
|
101
101
|
### Provider usage
|
|
102
102
|
|
package/package.json
CHANGED
package/scripts/install.mjs
CHANGED
|
@@ -102,40 +102,6 @@ function nodeCmd(absScript) {
|
|
|
102
102
|
return `node "${fwd(absScript)}"`;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
function stripJsonComments(input) {
|
|
106
|
-
let out = "";
|
|
107
|
-
let inString = false;
|
|
108
|
-
let escaped = false;
|
|
109
|
-
for (let i = 0; i < input.length; i++) {
|
|
110
|
-
const ch = input[i];
|
|
111
|
-
const next = input[i + 1];
|
|
112
|
-
if (inString) {
|
|
113
|
-
out += ch;
|
|
114
|
-
escaped = ch === "\\" ? !escaped : false;
|
|
115
|
-
if (ch === "\"" && !escaped) inString = false;
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (ch === "\"") {
|
|
119
|
-
inString = true;
|
|
120
|
-
out += ch;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (ch === "/" && next === "/") {
|
|
124
|
-
while (i < input.length && input[i] !== "\n") i++;
|
|
125
|
-
out += "\n";
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (ch === "/" && next === "*") {
|
|
129
|
-
i += 2;
|
|
130
|
-
while (i < input.length && !(input[i] === "*" && input[i + 1] === "/")) i++;
|
|
131
|
-
i++;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
out += ch;
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
105
|
function readJsonc(file) {
|
|
140
106
|
if (!fs.existsSync(file)) return {};
|
|
141
107
|
const raw = fs.readFileSync(file, "utf8").replace(/^\uFEFF/, "");
|
|
@@ -146,31 +112,6 @@ function readJsonc(file) {
|
|
|
146
112
|
return parsed ?? {};
|
|
147
113
|
}
|
|
148
114
|
|
|
149
|
-
function headerComments(text) {
|
|
150
|
-
const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
|
|
151
|
-
const header = [];
|
|
152
|
-
for (const line of lines) {
|
|
153
|
-
if (/^\s*(?:\/\/.*)?$/.test(line)) {
|
|
154
|
-
header.push(line);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
return header.length ? header.join("\n").replace(/\s+$/, "") + "\n" : "";
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function mergeDefaults(target, defaults) {
|
|
163
|
-
if (Array.isArray(defaults)) return target === undefined ? defaults : target;
|
|
164
|
-
if (!defaults || typeof defaults !== "object") {
|
|
165
|
-
return target === undefined ? defaults : target;
|
|
166
|
-
}
|
|
167
|
-
const out = target && typeof target === "object" && !Array.isArray(target) ? { ...target } : {};
|
|
168
|
-
for (const [key, value] of Object.entries(defaults)) {
|
|
169
|
-
out[key] = mergeDefaults(out[key], value);
|
|
170
|
-
}
|
|
171
|
-
return out;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
115
|
function writeText(file, text, dryRun) {
|
|
175
116
|
if (dryRun) {
|
|
176
117
|
console.log(` [dry-run] would write ${file}:`);
|
|
@@ -215,23 +156,46 @@ function updateOpenCodeTuiConfig(file, { remove, dryRun }) {
|
|
|
215
156
|
writeText(file, updated, dryRun);
|
|
216
157
|
}
|
|
217
158
|
|
|
159
|
+
// Keys present in defaults but absent in current, as jsonc-parser edit paths.
|
|
160
|
+
function missingDefaultPaths(current, defaults, basePath = []) {
|
|
161
|
+
const out = [];
|
|
162
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
163
|
+
const existing = current?.[key];
|
|
164
|
+
if (existing === undefined) {
|
|
165
|
+
out.push({ path: [...basePath, key], value });
|
|
166
|
+
} else if (
|
|
167
|
+
value && typeof value === "object" && !Array.isArray(value) &&
|
|
168
|
+
existing && typeof existing === "object" && !Array.isArray(existing)
|
|
169
|
+
) {
|
|
170
|
+
out.push(...missingDefaultPaths(existing, value, [...basePath, key]));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Updates only add missing default keys via surgical jsonc-parser edits, so
|
|
177
|
+
// the user's comments, formatting, and key order survive installer updates.
|
|
218
178
|
function mergeJsoncFile(src, dest, dryRun) {
|
|
219
|
-
|
|
220
|
-
const defaultHeader = headerComments(fs.readFileSync(src, "utf8"));
|
|
221
|
-
if (!fs.existsSync(dest)) {
|
|
179
|
+
if (!fs.existsSync(dest) || !fs.readFileSync(dest, "utf8").trim()) {
|
|
222
180
|
writeText(dest, fs.readFileSync(src, "utf8"), dryRun);
|
|
223
181
|
return;
|
|
224
182
|
}
|
|
183
|
+
const defaults = readJsonc(src);
|
|
225
184
|
const currentText = fs.readFileSync(dest, "utf8");
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
const currentHeader = headerComments(currentText) || defaultHeader;
|
|
229
|
-
const mergedText = currentHeader + JSON.stringify(merged, null, 2) + "\n";
|
|
230
|
-
if (stripJsonComments(currentText).trim() === JSON.stringify(merged, null, 2)) {
|
|
185
|
+
const additions = missingDefaultPaths(readJsonc(dest), defaults);
|
|
186
|
+
if (additions.length === 0) {
|
|
231
187
|
console.log(` kept existing ${dest}`);
|
|
232
188
|
return;
|
|
233
189
|
}
|
|
234
|
-
|
|
190
|
+
const eol = currentText.includes("\r\n") ? "\r\n" : "\n";
|
|
191
|
+
let updated = currentText;
|
|
192
|
+
for (const { path: keyPath, value } of additions) {
|
|
193
|
+
const edits = modify(updated, keyPath, value, {
|
|
194
|
+
formattingOptions: { insertSpaces: true, tabSize: 2, eol },
|
|
195
|
+
});
|
|
196
|
+
updated = applyEdits(updated, edits);
|
|
197
|
+
}
|
|
198
|
+
writeText(dest, updated, dryRun);
|
|
235
199
|
}
|
|
236
200
|
|
|
237
201
|
function copyRuntimeFile(src, dest, dryRun, options = {}) {
|