@serviceme/devtools-core 2.0.0 → 2.0.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/dist/auth-Bzss8zOv.mjs +995 -0
- package/dist/auth-Bzss8zOv.mjs.map +1 -0
- package/dist/auth-DXam3c4S.js +1078 -0
- package/dist/auth-DXam3c4S.js.map +1 -0
- package/dist/auth.d.mts +2 -2
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +14 -1029
- package/dist/auth.mjs +2 -991
- package/dist/device-CDDcwDY6.mjs +758 -0
- package/dist/device-CDDcwDY6.mjs.map +1 -0
- package/dist/device-DuAYH8bk.js +839 -0
- package/dist/device-DuAYH8bk.js.map +1 -0
- package/dist/device.d.mts +2 -455
- package/dist/device.d.ts +2 -455
- package/dist/device.js +15 -728
- package/dist/device.mjs +2 -679
- package/dist/index-2rX86yMq.d.mts +331 -0
- package/dist/index-BI11AfMH.d.mts +377 -0
- package/dist/index-BI11AfMH.d.ts +377 -0
- package/dist/index-CoA6y0MP.d.mts +498 -0
- package/dist/index-CoA6y0MP.d.ts +498 -0
- package/dist/index-DaW7IYA-.d.mts +185 -0
- package/dist/index-DaW7IYA-.d.ts +185 -0
- package/dist/index-Dp6FwWKh.d.ts +331 -0
- package/dist/index.d.mts +2340 -2101
- package/dist/index.d.ts +2340 -2101
- package/dist/index.js +8117 -10538
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7895 -10318
- package/dist/index.mjs.map +1 -1
- package/dist/rolldown-runtime-VH7oDXx4.js +28 -0
- package/dist/skill-linker.d.mts +82 -81
- package/dist/skill-linker.d.ts +82 -81
- package/dist/skill-linker.js +359 -402
- package/dist/skill-linker.js.map +1 -1
- package/dist/skill-linker.mjs +345 -357
- package/dist/skill-linker.mjs.map +1 -1
- package/dist/skill-store-Bym2yinU.mjs +388 -0
- package/dist/skill-store-Bym2yinU.mjs.map +1 -0
- package/dist/skill-store-CJdYyyxu.js +408 -0
- package/dist/skill-store-CJdYyyxu.js.map +1 -0
- package/dist/skill-store.d.mts +41 -42
- package/dist/skill-store.d.ts +41 -42
- package/dist/skill-store.js +5 -338
- package/dist/skill-store.mjs +2 -301
- package/dist/submit-Cg7wSa3x.mjs +84 -0
- package/dist/submit-Cg7wSa3x.mjs.map +1 -0
- package/dist/submit-CltE6YOZ.js +98 -0
- package/dist/submit-CltE6YOZ.js.map +1 -0
- package/dist/submit.d.mts +2 -3
- package/dist/submit.d.ts +2 -3
- package/dist/submit.js +4 -166
- package/dist/submit.mjs +2 -130
- package/dist/toolbox-CbfxpNg-.mjs +540 -0
- package/dist/toolbox-CbfxpNg-.mjs.map +1 -0
- package/dist/toolbox-CxnOr-FY.js +614 -0
- package/dist/toolbox-CxnOr-FY.js.map +1 -0
- package/dist/toolbox.d.mts +2 -244
- package/dist/toolbox.d.ts +2 -244
- package/dist/toolbox.js +14 -584
- package/dist/toolbox.mjs +2 -536
- package/dist/{types-B9gk3dXH.d.ts → types-BCV3IedE.d.mts} +25 -23
- package/dist/{types-B9gk3dXH.d.mts → types-BCV3IedE.d.ts} +25 -23
- package/dist/userHome-BquDeFVE.js +526 -0
- package/dist/userHome-BquDeFVE.js.map +1 -0
- package/dist/userHome-CcnAQPG1.mjs +212 -0
- package/dist/userHome-CcnAQPG1.mjs.map +1 -0
- package/package.json +10 -10
- package/dist/auth.js.map +0 -1
- package/dist/auth.mjs.map +0 -1
- package/dist/device.js.map +0 -1
- package/dist/device.mjs.map +0 -1
- package/dist/index-BMk4tqIT.d.mts +0 -328
- package/dist/index-CymN0x9Z.d.ts +0 -328
- package/dist/index-PD135hlB.d.mts +0 -626
- package/dist/index-PD135hlB.d.ts +0 -626
- package/dist/skill-store.js.map +0 -1
- package/dist/skill-store.mjs.map +0 -1
- package/dist/submit.js.map +0 -1
- package/dist/submit.mjs.map +0 -1
- package/dist/toolbox.js.map +0 -1
- package/dist/toolbox.mjs.map +0 -1
package/dist/toolbox.js
CHANGED
|
@@ -1,584 +1,14 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/toolbox/index.ts
|
|
31
|
-
var toolbox_exports = {};
|
|
32
|
-
__export(toolbox_exports, {
|
|
33
|
-
BUILTIN_DEFAULT_TOOLS: () => BUILTIN_DEFAULT_TOOLS,
|
|
34
|
-
DefaultToolImmutableError: () => DefaultToolImmutableError,
|
|
35
|
-
FsToolboxFileBackend: () => FsToolboxFileBackend,
|
|
36
|
-
TOOLBOX_JSON_SCHEMA_VERSION: () => TOOLBOX_JSON_SCHEMA_VERSION,
|
|
37
|
-
ToolboxCore: () => ToolboxCore,
|
|
38
|
-
ToolboxStore: () => ToolboxStore,
|
|
39
|
-
WORKSPACE_TOOLBOX_RELATIVE_PATH: () => WORKSPACE_TOOLBOX_RELATIVE_PATH,
|
|
40
|
-
mergeWithDefaults: () => mergeWithDefaults,
|
|
41
|
-
reindexOrder: () => reindexOrder,
|
|
42
|
-
sortByRecentFirst: () => sortByRecentFirst,
|
|
43
|
-
sortByUserOrder: () => sortByUserOrder,
|
|
44
|
-
touchLastUsedAt: () => touchLastUsedAt
|
|
45
|
-
});
|
|
46
|
-
module.exports = __toCommonJS(toolbox_exports);
|
|
47
|
-
|
|
48
|
-
// src/toolbox/sort.ts
|
|
49
|
-
function lastUsedTimestamp(tool) {
|
|
50
|
-
if (!tool.lastUsedAt) return 0;
|
|
51
|
-
const ms = Date.parse(tool.lastUsedAt);
|
|
52
|
-
return Number.isFinite(ms) ? ms : 0;
|
|
53
|
-
}
|
|
54
|
-
function sortByRecentFirst(tools) {
|
|
55
|
-
return [...tools].sort((a, b) => {
|
|
56
|
-
const tsA = lastUsedTimestamp(a);
|
|
57
|
-
const tsB = lastUsedTimestamp(b);
|
|
58
|
-
if (tsA !== tsB) return tsB - tsA;
|
|
59
|
-
const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
|
|
60
|
-
const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
|
|
61
|
-
if (orderA !== orderB) return orderA - orderB;
|
|
62
|
-
return a.id.localeCompare(b.id);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
function sortByUserOrder(tools) {
|
|
66
|
-
return [...tools].sort((a, b) => {
|
|
67
|
-
const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
|
|
68
|
-
const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
|
|
69
|
-
if (orderA !== orderB) return orderA - orderB;
|
|
70
|
-
return a.id.localeCompare(b.id);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function mergeWithDefaults(defaults, userTools) {
|
|
74
|
-
const defaultIds = new Set(defaults.map((d) => d.id));
|
|
75
|
-
const uniqueUserTools = userTools.filter((t) => !defaultIds.has(t.id));
|
|
76
|
-
return sortByUserOrder([...defaults, ...uniqueUserTools]);
|
|
77
|
-
}
|
|
78
|
-
function reindexOrder(tools, newOrderIds) {
|
|
79
|
-
const orderMap = /* @__PURE__ */ new Map();
|
|
80
|
-
for (const [index, id] of newOrderIds.entries()) {
|
|
81
|
-
orderMap.set(id, index);
|
|
82
|
-
}
|
|
83
|
-
for (const tool of tools) {
|
|
84
|
-
const next = orderMap.get(tool.id);
|
|
85
|
-
if (next !== void 0) tool.order = next;
|
|
86
|
-
}
|
|
87
|
-
return tools;
|
|
88
|
-
}
|
|
89
|
-
function touchLastUsedAt(tools, id, when = /* @__PURE__ */ new Date()) {
|
|
90
|
-
return tools.map((tool) => tool.id === id ? { ...tool, lastUsedAt: when.toISOString() } : tool);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// src/toolbox/ToolboxStore.ts
|
|
94
|
-
var fsp = __toESM(require("fs/promises"));
|
|
95
|
-
var path2 = __toESM(require("path"));
|
|
96
|
-
var import_promises = require("timers/promises");
|
|
97
|
-
|
|
98
|
-
// src/paths/userHome.ts
|
|
99
|
-
var os = __toESM(require("os"));
|
|
100
|
-
var path = __toESM(require("path"));
|
|
101
|
-
var SERVICEME_DIR_NAME = ".serviceme";
|
|
102
|
-
var SERVICEME_HOME_ENV = "SERVICEME_HOME";
|
|
103
|
-
var activeOverrides = {};
|
|
104
|
-
function resolveHomeDir() {
|
|
105
|
-
const injected = activeOverrides.homeDir;
|
|
106
|
-
if (injected !== void 0) {
|
|
107
|
-
return injected;
|
|
108
|
-
}
|
|
109
|
-
return os.homedir();
|
|
110
|
-
}
|
|
111
|
-
function resolveServicemeHomeEnv() {
|
|
112
|
-
const injected = activeOverrides.servicemeHomeEnv;
|
|
113
|
-
if (injected !== void 0) {
|
|
114
|
-
return injected.length > 0 ? injected : void 0;
|
|
115
|
-
}
|
|
116
|
-
const envValue = process.env[SERVICEME_HOME_ENV];
|
|
117
|
-
return envValue && envValue.length > 0 ? envValue : void 0;
|
|
118
|
-
}
|
|
119
|
-
function getServicemeHome() {
|
|
120
|
-
const override = resolveServicemeHomeEnv();
|
|
121
|
-
if (override !== void 0) {
|
|
122
|
-
return path.resolve(override);
|
|
123
|
-
}
|
|
124
|
-
return path.join(resolveHomeDir(), SERVICEME_DIR_NAME);
|
|
125
|
-
}
|
|
126
|
-
var TOOLBOX_JSON_FILENAME = "toolbox.json";
|
|
127
|
-
function getToolboxJsonPath() {
|
|
128
|
-
return path.join(getServicemeHome(), TOOLBOX_JSON_FILENAME);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/toolbox/types.ts
|
|
132
|
-
var TOOLBOX_JSON_SCHEMA_VERSION = 1;
|
|
133
|
-
var BUILTIN_DEFAULT_TOOLS = [
|
|
134
|
-
{
|
|
135
|
-
id: "builtin-docs",
|
|
136
|
-
name: "SERVICEME Docs",
|
|
137
|
-
description: "Official documentation portal",
|
|
138
|
-
icon: "book",
|
|
139
|
-
url: "https://docs.medalsoft.com/serviceme"
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
id: "builtin-issues",
|
|
143
|
-
name: "Issue Tracker",
|
|
144
|
-
description: "Report bugs and feature requests",
|
|
145
|
-
icon: "bug",
|
|
146
|
-
url: "https://github.com/medalsoftchina/ms-devtools-vscode/issues"
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
id: "builtin-changelog",
|
|
150
|
-
name: "Changelog",
|
|
151
|
-
description: "Release notes for every published version",
|
|
152
|
-
icon: "history",
|
|
153
|
-
url: "https://github.com/medalsoftchina/ms-devtools-vscode/releases"
|
|
154
|
-
}
|
|
155
|
-
];
|
|
156
|
-
|
|
157
|
-
// src/toolbox/ToolboxStore.ts
|
|
158
|
-
var FILE_MODE = 384;
|
|
159
|
-
var LOCK_DIR_MODE = 448;
|
|
160
|
-
var DEFAULT_LOCK_TIMEOUT_MS = 5e3;
|
|
161
|
-
var DEFAULT_LOCK_RETRY_MS = 25;
|
|
162
|
-
var LOCK_STALE_GRACE_MS = 200;
|
|
163
|
-
var TMP_SUFFIX = ".tmp";
|
|
164
|
-
var WORKSPACE_TOOLBOX_RELATIVE_PATH = path2.join(".github", ".serviceme-toolbox.json");
|
|
165
|
-
var LEGACY_WORKSPACE_TOOLBOX_FILENAME = ".ms-devtools-toolbox.json";
|
|
166
|
-
async function migrateLegacyWorkspaceToolboxFile(filePath) {
|
|
167
|
-
if (!filePath) return;
|
|
168
|
-
const legacyPath = path2.join(path2.dirname(filePath), LEGACY_WORKSPACE_TOOLBOX_FILENAME);
|
|
169
|
-
if (legacyPath === filePath) return;
|
|
170
|
-
try {
|
|
171
|
-
await fsp.access(filePath);
|
|
172
|
-
return;
|
|
173
|
-
} catch {
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
await fsp.rename(legacyPath, filePath);
|
|
177
|
-
} catch {
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
var FsToolboxFileBackend = class {
|
|
181
|
-
constructor() {
|
|
182
|
-
this.maxBackupCount = 5;
|
|
183
|
-
}
|
|
184
|
-
async exists(filePath) {
|
|
185
|
-
try {
|
|
186
|
-
await fsp.access(filePath);
|
|
187
|
-
return true;
|
|
188
|
-
} catch {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
async read(filePath) {
|
|
193
|
-
let buf;
|
|
194
|
-
try {
|
|
195
|
-
buf = await fsp.readFile(filePath, "utf8");
|
|
196
|
-
} catch (err) {
|
|
197
|
-
if (isNodeError(err) && err.code === "ENOENT") return null;
|
|
198
|
-
throw err;
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
const parsed = JSON.parse(buf);
|
|
202
|
-
return coercePersistedToolbox(parsed);
|
|
203
|
-
} catch {
|
|
204
|
-
await this.backupCorruptedFile(filePath);
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
async backupCorruptedFile(filePath) {
|
|
209
|
-
try {
|
|
210
|
-
const backupPath = `${filePath}.corrupted.${Date.now()}.bak`;
|
|
211
|
-
await fsp.copyFile(filePath, backupPath);
|
|
212
|
-
await this.purgeExcessBackups(filePath);
|
|
213
|
-
} catch {
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
async purgeExcessBackups(filePath) {
|
|
217
|
-
const dir = path2.dirname(filePath);
|
|
218
|
-
const base = path2.basename(filePath);
|
|
219
|
-
let entries;
|
|
220
|
-
try {
|
|
221
|
-
entries = await fsp.readdir(dir);
|
|
222
|
-
} catch {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const backups = entries.filter((n) => n.startsWith(base) && n.endsWith(".bak")).map((n) => ({ name: n, filePath: path2.join(dir, n) })).sort((a, b) => {
|
|
226
|
-
return a.name.localeCompare(b.name);
|
|
227
|
-
});
|
|
228
|
-
const excess = backups.length - this.maxBackupCount;
|
|
229
|
-
if (excess <= 0) return;
|
|
230
|
-
await Promise.all(
|
|
231
|
-
backups.slice(0, excess).map((b) => fsp.rm(b.filePath).catch(() => void 0))
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
async write(filePath, payload) {
|
|
235
|
-
await fsp.mkdir(path2.dirname(filePath), { recursive: true });
|
|
236
|
-
const tmpPath = `${filePath}${TMP_SUFFIX}`;
|
|
237
|
-
const bytes = Buffer.from(JSON.stringify(payload, null, " "), "utf8");
|
|
238
|
-
await fsp.rm(tmpPath, { force: true });
|
|
239
|
-
const handle = await fsp.open(tmpPath, "w", FILE_MODE);
|
|
240
|
-
try {
|
|
241
|
-
await handle.writeFile(bytes);
|
|
242
|
-
await handle.sync();
|
|
243
|
-
} finally {
|
|
244
|
-
await handle.close();
|
|
245
|
-
}
|
|
246
|
-
await fsp.rename(tmpPath, filePath);
|
|
247
|
-
await fsp.chmod(filePath, FILE_MODE).catch(() => void 0);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
function coercePersistedToolbox(parsed) {
|
|
251
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
252
|
-
throw new Error("toolbox.json: top-level must be an object");
|
|
253
|
-
}
|
|
254
|
-
const obj = parsed;
|
|
255
|
-
const version = obj.version;
|
|
256
|
-
if (version !== TOOLBOX_JSON_SCHEMA_VERSION) {
|
|
257
|
-
throw new Error(`toolbox.json: unsupported schema version ${String(version)}`);
|
|
258
|
-
}
|
|
259
|
-
if (!Array.isArray(obj.tools)) {
|
|
260
|
-
throw new Error("toolbox.json: 'tools' must be an array");
|
|
261
|
-
}
|
|
262
|
-
return { version, tools: obj.tools };
|
|
263
|
-
}
|
|
264
|
-
function isNodeError(value) {
|
|
265
|
-
return value instanceof Error && typeof value.code === "string";
|
|
266
|
-
}
|
|
267
|
-
function isProcessAlive(pid) {
|
|
268
|
-
try {
|
|
269
|
-
process.kill(pid, 0);
|
|
270
|
-
return true;
|
|
271
|
-
} catch {
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
var ToolboxFileLock = class {
|
|
276
|
-
constructor(filePath, timeoutMs, retryMs) {
|
|
277
|
-
this.acquired = false;
|
|
278
|
-
this.dirPath = `${filePath}.lock`;
|
|
279
|
-
this.pidFilePath = path2.join(this.dirPath, "pid");
|
|
280
|
-
this.timeoutMs = timeoutMs;
|
|
281
|
-
this.retryMs = retryMs;
|
|
282
|
-
}
|
|
283
|
-
async acquire() {
|
|
284
|
-
const start = Date.now();
|
|
285
|
-
while (true) {
|
|
286
|
-
try {
|
|
287
|
-
await fsp.mkdir(this.dirPath, { mode: LOCK_DIR_MODE });
|
|
288
|
-
await fsp.writeFile(this.pidFilePath, String(process.pid), "utf8").catch(() => void 0);
|
|
289
|
-
this.acquired = true;
|
|
290
|
-
return;
|
|
291
|
-
} catch (err) {
|
|
292
|
-
if (!isNodeError(err) || err.code !== "EEXIST") throw err;
|
|
293
|
-
const stale = await this.isStaleLock();
|
|
294
|
-
if (stale) {
|
|
295
|
-
await fsp.rm(this.dirPath, { recursive: true, force: true });
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (Date.now() - start >= this.timeoutMs) {
|
|
299
|
-
throw new Error(`ToolboxStore lock acquisition timed out for ${this.dirPath}`);
|
|
300
|
-
}
|
|
301
|
-
await (0, import_promises.setTimeout)(this.retryMs);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
async isStaleLock() {
|
|
306
|
-
let pidStr;
|
|
307
|
-
try {
|
|
308
|
-
pidStr = await fsp.readFile(this.pidFilePath, "utf8");
|
|
309
|
-
} catch {
|
|
310
|
-
try {
|
|
311
|
-
const stat2 = await fsp.stat(this.dirPath);
|
|
312
|
-
return Date.now() - stat2.mtimeMs > LOCK_STALE_GRACE_MS;
|
|
313
|
-
} catch {
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
const pid = Number.parseInt(pidStr.trim(), 10);
|
|
318
|
-
if (!Number.isFinite(pid) || pid <= 0) return true;
|
|
319
|
-
return !isProcessAlive(pid);
|
|
320
|
-
}
|
|
321
|
-
async release() {
|
|
322
|
-
if (!this.acquired) return;
|
|
323
|
-
this.acquired = false;
|
|
324
|
-
await fsp.rm(this.dirPath, { recursive: true, force: true });
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
function defaultWorkspacePath() {
|
|
328
|
-
if (process.env.SERVICEME_NO_WORKSPACE_TOOLBOX === "1") return null;
|
|
329
|
-
return path2.join(process.cwd(), WORKSPACE_TOOLBOX_RELATIVE_PATH);
|
|
330
|
-
}
|
|
331
|
-
var ToolboxStore = class {
|
|
332
|
-
constructor(opts = {}) {
|
|
333
|
-
this.userFilePath = opts.userFilePath ?? getToolboxJsonPath();
|
|
334
|
-
this.resolveWorkspacePath = opts.resolveWorkspacePath ?? defaultWorkspacePath;
|
|
335
|
-
this.defaults = opts.defaultTools ?? BUILTIN_DEFAULT_TOOLS;
|
|
336
|
-
this.hooks = opts.hooks ?? {};
|
|
337
|
-
this.backend = opts.backend ?? new FsToolboxFileBackend();
|
|
338
|
-
this.lockTimeoutMs = opts.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS;
|
|
339
|
-
this.lockRetryMs = opts.lockRetryMs ?? DEFAULT_LOCK_RETRY_MS;
|
|
340
|
-
}
|
|
341
|
-
/** Read a scope; returns the resolved toolbox (with defaults merged when empty). */
|
|
342
|
-
async read(scope) {
|
|
343
|
-
const filePath = this.filePathFor(scope);
|
|
344
|
-
if (scope === "workspace") {
|
|
345
|
-
await migrateLegacyWorkspaceToolboxFile(filePath);
|
|
346
|
-
}
|
|
347
|
-
const stored = filePath ? await this.backend.read(filePath) : null;
|
|
348
|
-
const storedTools = stored?.tools ?? [];
|
|
349
|
-
const defaults = this.defaults.map((seed, index) => toDefaultTool(seed, index));
|
|
350
|
-
const merged = mergeWithDefaults(defaults, storedTools);
|
|
351
|
-
const userOnly = storedTools.filter((t) => !this.defaults.some((d) => d.id === t.id));
|
|
352
|
-
void userOnly;
|
|
353
|
-
return { scope, tools: merged };
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Atomic write under a file lock. Replaces the entire `tools` array
|
|
357
|
-
* with the provided snapshot.
|
|
358
|
-
*/
|
|
359
|
-
async write(scope, tools) {
|
|
360
|
-
const filePath = this.filePathFor(scope);
|
|
361
|
-
if (!filePath) {
|
|
362
|
-
throw new Error(`Cannot write toolbox scope '${scope}': file path is unavailable`);
|
|
363
|
-
}
|
|
364
|
-
if (scope === "workspace") {
|
|
365
|
-
await migrateLegacyWorkspaceToolboxFile(filePath);
|
|
366
|
-
}
|
|
367
|
-
const payload = {
|
|
368
|
-
version: TOOLBOX_JSON_SCHEMA_VERSION,
|
|
369
|
-
tools: sortByUserOrder([...tools])
|
|
370
|
-
};
|
|
371
|
-
await this.hooks.beforeWrite?.(scope, payload);
|
|
372
|
-
const lock = new ToolboxFileLock(filePath, this.lockTimeoutMs, this.lockRetryMs);
|
|
373
|
-
await lock.acquire();
|
|
374
|
-
try {
|
|
375
|
-
await this.backend.write(filePath, payload);
|
|
376
|
-
} finally {
|
|
377
|
-
await lock.release();
|
|
378
|
-
}
|
|
379
|
-
await this.hooks.afterWrite?.(scope, payload);
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Read-modify-write under the file lock. The mutator receives the
|
|
383
|
-
* current user-only list (defaults not included) and returns the
|
|
384
|
-
* replacement list. Throwing inside the mutator aborts the write.
|
|
385
|
-
*/
|
|
386
|
-
async mutate(scope, mutator) {
|
|
387
|
-
const filePath = this.filePathFor(scope);
|
|
388
|
-
if (!filePath) {
|
|
389
|
-
throw new Error(`Cannot mutate toolbox scope '${scope}': file path is unavailable`);
|
|
390
|
-
}
|
|
391
|
-
if (scope === "workspace") {
|
|
392
|
-
await migrateLegacyWorkspaceToolboxFile(filePath);
|
|
393
|
-
}
|
|
394
|
-
const lock = new ToolboxFileLock(filePath, this.lockTimeoutMs, this.lockRetryMs);
|
|
395
|
-
await lock.acquire();
|
|
396
|
-
try {
|
|
397
|
-
const stored = await this.backend.read(filePath);
|
|
398
|
-
const storedTools = stored?.tools ?? [];
|
|
399
|
-
const defaultIds = new Set(this.defaults.map((d) => d.id));
|
|
400
|
-
const userTools = storedTools.filter((t) => !defaultIds.has(t.id));
|
|
401
|
-
const next = await mutator(userTools);
|
|
402
|
-
const payload = {
|
|
403
|
-
version: TOOLBOX_JSON_SCHEMA_VERSION,
|
|
404
|
-
tools: sortByUserOrder([...next])
|
|
405
|
-
};
|
|
406
|
-
await this.hooks.beforeWrite?.(scope, payload);
|
|
407
|
-
await this.backend.write(filePath, payload);
|
|
408
|
-
await this.hooks.afterWrite?.(scope, payload);
|
|
409
|
-
return next;
|
|
410
|
-
} finally {
|
|
411
|
-
await lock.release();
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
/** Wipe a scope entirely (used by `toolbox.remove --all` extensions). */
|
|
415
|
-
async clear(scope) {
|
|
416
|
-
const filePath = this.filePathFor(scope);
|
|
417
|
-
if (!filePath) return;
|
|
418
|
-
await fsp.rm(filePath, { force: true });
|
|
419
|
-
}
|
|
420
|
-
/** Test seam — resolve the user-scope file path. */
|
|
421
|
-
getUserFilePath() {
|
|
422
|
-
return this.userFilePath;
|
|
423
|
-
}
|
|
424
|
-
/** Test seam — resolve the workspace-scope file path (or null when disabled). */
|
|
425
|
-
getWorkspaceFilePath() {
|
|
426
|
-
return this.resolveWorkspacePath();
|
|
427
|
-
}
|
|
428
|
-
filePathFor(scope) {
|
|
429
|
-
return scope === "user" ? this.userFilePath : this.resolveWorkspacePath();
|
|
430
|
-
}
|
|
431
|
-
};
|
|
432
|
-
function toDefaultTool(seed, order) {
|
|
433
|
-
return {
|
|
434
|
-
id: seed.id,
|
|
435
|
-
name: seed.name,
|
|
436
|
-
description: seed.description,
|
|
437
|
-
icon: seed.icon,
|
|
438
|
-
url: seed.url,
|
|
439
|
-
isDefault: true,
|
|
440
|
-
order,
|
|
441
|
-
scope: "user"
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// src/toolbox/ToolboxCore.ts
|
|
446
|
-
var DefaultToolImmutableError = class extends Error {
|
|
447
|
-
constructor(toolId) {
|
|
448
|
-
super(`Cannot remove default toolbox entry: ${toolId}`);
|
|
449
|
-
this.toolId = toolId;
|
|
450
|
-
this.name = "DefaultToolImmutableError";
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
var ToolboxCore = class {
|
|
454
|
-
constructor(opts = {}) {
|
|
455
|
-
this.store = opts.store ?? new ToolboxStore();
|
|
456
|
-
this.defaults = opts.defaultTools ?? BUILTIN_DEFAULT_TOOLS;
|
|
457
|
-
this.listSort = opts.listSort ?? sortByUserOrder;
|
|
458
|
-
}
|
|
459
|
-
/** List all tools in a scope. Built-in defaults are merged in. */
|
|
460
|
-
async list(scope = "user") {
|
|
461
|
-
const resolved = await this.store.read(scope);
|
|
462
|
-
return {
|
|
463
|
-
scope,
|
|
464
|
-
tools: this.listSort(resolved.tools)
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Append a new tool to the requested scope. Default tools are
|
|
469
|
-
* rejected (they are seeds, not user entries).
|
|
470
|
-
*/
|
|
471
|
-
async add(tool, scope = "user") {
|
|
472
|
-
if (this.isDefaultId(tool.id)) {
|
|
473
|
-
throw new DefaultToolImmutableError(tool.id);
|
|
474
|
-
}
|
|
475
|
-
const next = await this.store.mutate(scope, async (current) => {
|
|
476
|
-
const filtered = current.filter((t) => t.id !== tool.id);
|
|
477
|
-
return [
|
|
478
|
-
...filtered,
|
|
479
|
-
{
|
|
480
|
-
...tool,
|
|
481
|
-
scope,
|
|
482
|
-
isDefault: false,
|
|
483
|
-
order: tool.order ?? filtered.length
|
|
484
|
-
}
|
|
485
|
-
];
|
|
486
|
-
});
|
|
487
|
-
return { scope, tools: next };
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Remove a tool by id. Returns `success: false` when the id is a
|
|
491
|
-
* built-in default (idempotent, never throws on missing entries).
|
|
492
|
-
*/
|
|
493
|
-
async remove(id, scope = "user") {
|
|
494
|
-
if (this.isDefaultId(id)) {
|
|
495
|
-
throw new DefaultToolImmutableError(id);
|
|
496
|
-
}
|
|
497
|
-
const removed = await this.store.mutate(
|
|
498
|
-
scope,
|
|
499
|
-
async (current) => current.filter((t) => t.id !== id)
|
|
500
|
-
);
|
|
501
|
-
return { scope, toolId: id, success: !removed.some((t) => t.id === id) };
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Patch a tool by id. Default tools can only have their `order`
|
|
505
|
-
* updated; other patches are silently ignored for default entries
|
|
506
|
-
* (callers can compare before/after to detect the ignore).
|
|
507
|
-
*/
|
|
508
|
-
async update(id, patch, scope = "user") {
|
|
509
|
-
const isDefault = this.isDefaultId(id);
|
|
510
|
-
const next = await this.store.mutate(scope, async (current) => {
|
|
511
|
-
if (isDefault) {
|
|
512
|
-
return current;
|
|
513
|
-
}
|
|
514
|
-
return current.map(
|
|
515
|
-
(tool) => tool.id === id ? { ...tool, ...patch, scope, isDefault: false } : tool
|
|
516
|
-
);
|
|
517
|
-
});
|
|
518
|
-
return { scope, tools: next };
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Stamp `lastUsedAt` on the targeted tool. This is the "recently
|
|
522
|
-
* used" hook the Extension's webview uses when a user clicks a
|
|
523
|
-
* toolbox entry.
|
|
524
|
-
*/
|
|
525
|
-
async recordUsage(id, scope = "user", when = /* @__PURE__ */ new Date()) {
|
|
526
|
-
if (this.isDefaultId(id)) {
|
|
527
|
-
const seed = this.defaults.find((d) => d.id === id);
|
|
528
|
-
if (!seed) return null;
|
|
529
|
-
return { ...seed, scope, isDefault: true, order: 0, lastUsedAt: when.toISOString() };
|
|
530
|
-
}
|
|
531
|
-
let updated = null;
|
|
532
|
-
await this.store.mutate(scope, async (current) => {
|
|
533
|
-
const next = touchLastUsedAt(current, id, when);
|
|
534
|
-
updated = next.find((t) => t.id === id) ?? null;
|
|
535
|
-
return next;
|
|
536
|
-
});
|
|
537
|
-
return updated;
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* Combined view: user + workspace scopes merged, sorted by recent
|
|
541
|
-
* usage. Workspace tools overlay user tools (workspace entries win
|
|
542
|
-
* on `id` collision).
|
|
543
|
-
*/
|
|
544
|
-
async listMerged() {
|
|
545
|
-
const [user, workspace] = await Promise.all([
|
|
546
|
-
this.store.read("user"),
|
|
547
|
-
this.store.read("workspace")
|
|
548
|
-
]);
|
|
549
|
-
const seen = /* @__PURE__ */ new Set();
|
|
550
|
-
const merged = [];
|
|
551
|
-
for (const tool of workspace.tools) {
|
|
552
|
-
seen.add(tool.id);
|
|
553
|
-
merged.push({ ...tool, scope: "workspace" });
|
|
554
|
-
}
|
|
555
|
-
for (const tool of user.tools) {
|
|
556
|
-
if (seen.has(tool.id)) continue;
|
|
557
|
-
merged.push({ ...tool, scope: "user" });
|
|
558
|
-
}
|
|
559
|
-
return { scope: "user", tools: sortByRecentFirst(merged) };
|
|
560
|
-
}
|
|
561
|
-
/** Expose the underlying store (CLI / Bridge use it for path-level access). */
|
|
562
|
-
getStore() {
|
|
563
|
-
return this.store;
|
|
564
|
-
}
|
|
565
|
-
isDefaultId(id) {
|
|
566
|
-
return this.defaults.some((d) => d.id === id);
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
570
|
-
0 && (module.exports = {
|
|
571
|
-
BUILTIN_DEFAULT_TOOLS,
|
|
572
|
-
DefaultToolImmutableError,
|
|
573
|
-
FsToolboxFileBackend,
|
|
574
|
-
TOOLBOX_JSON_SCHEMA_VERSION,
|
|
575
|
-
ToolboxCore,
|
|
576
|
-
ToolboxStore,
|
|
577
|
-
WORKSPACE_TOOLBOX_RELATIVE_PATH,
|
|
578
|
-
mergeWithDefaults,
|
|
579
|
-
reindexOrder,
|
|
580
|
-
sortByRecentFirst,
|
|
581
|
-
sortByUserOrder,
|
|
582
|
-
touchLastUsedAt
|
|
583
|
-
});
|
|
584
|
-
//# sourceMappingURL=toolbox.js.map
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_toolbox = require("./toolbox-CxnOr-FY.js");
|
|
3
|
+
exports.BUILTIN_DEFAULT_TOOLS = require_toolbox.BUILTIN_DEFAULT_TOOLS;
|
|
4
|
+
exports.DefaultToolImmutableError = require_toolbox.DefaultToolImmutableError;
|
|
5
|
+
exports.FsToolboxFileBackend = require_toolbox.FsToolboxFileBackend;
|
|
6
|
+
exports.TOOLBOX_JSON_SCHEMA_VERSION = require_toolbox.TOOLBOX_JSON_SCHEMA_VERSION;
|
|
7
|
+
exports.ToolboxCore = require_toolbox.ToolboxCore;
|
|
8
|
+
exports.ToolboxStore = require_toolbox.ToolboxStore;
|
|
9
|
+
exports.WORKSPACE_TOOLBOX_RELATIVE_PATH = require_toolbox.WORKSPACE_TOOLBOX_RELATIVE_PATH;
|
|
10
|
+
exports.mergeWithDefaults = require_toolbox.mergeWithDefaults;
|
|
11
|
+
exports.reindexOrder = require_toolbox.reindexOrder;
|
|
12
|
+
exports.sortByRecentFirst = require_toolbox.sortByRecentFirst;
|
|
13
|
+
exports.sortByUserOrder = require_toolbox.sortByUserOrder;
|
|
14
|
+
exports.touchLastUsedAt = require_toolbox.touchLastUsedAt;
|