codemini-cli 0.6.5 → 0.6.6
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/codemini-web/dist/assets/{AboutDialog-BUp8EzDg.js → AboutDialog-dFkTshay.js} +1 -1
- package/codemini-web/dist/assets/{CodeWikiPanel-Fp0VKdzo.js → CodeWikiPanel-Dqup5Sen.js} +1 -1
- package/codemini-web/dist/assets/{ConfigDialog-DIpj779O.js → ConfigDialog-DTehAh2r.js} +1 -1
- package/codemini-web/dist/assets/{GitDiffDialog-ZLEuX8Qm.js → GitDiffDialog-D4uMixee.js} +1 -1
- package/codemini-web/dist/assets/{MemoryDialog-D2YbENVd.js → MemoryDialog-DJqtWamU.js} +1 -1
- package/codemini-web/dist/assets/{MessageBubble-BIgpZsLn.js → MessageBubble-BGnFIxcq.js} +1 -1
- package/codemini-web/dist/assets/{PatchDiff-CvKNaHsw.js → PatchDiff-CpHAbmv3.js} +1 -1
- package/codemini-web/dist/assets/{ProjectSelector-DXIep3lE.js → ProjectSelector-CgJDcTNL.js} +1 -1
- package/codemini-web/dist/assets/SkillDialog-D1J46nMC.js +8 -0
- package/codemini-web/dist/assets/{SoulDialog-BfIoKETs.js → SoulDialog-DIqK4utD.js} +1 -1
- package/codemini-web/dist/assets/chevron-right-BBG4s6Zh.js +1 -0
- package/codemini-web/dist/assets/{chunk-BO2N2NFS-DMUdjM9q.js → chunk-BO2N2NFS-fRXUeu1b.js} +4 -4
- package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-8ch0jz7Z.js → highlighted-body-OFNGDK62-CKKvx7S1.js} +1 -1
- package/codemini-web/dist/assets/{index-DRXwJ-n_.css → index-DF9s7Tuc.css} +1 -1
- package/codemini-web/dist/assets/{index-BhMtCC8_.js → index-DyIUhlc8.js} +3 -3
- package/codemini-web/dist/assets/{input-CYpdNDlR.js → input-BKNu4DOt.js} +1 -1
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-BM8yuNk5.js +1 -0
- package/codemini-web/dist/assets/{pencil-BdA2cEeE.js → pencil-C0uznNC_.js} +1 -1
- package/codemini-web/dist/assets/{refresh-cw-CJGgUGiS.js → refresh-cw-DUgU5bEu.js} +1 -1
- package/codemini-web/dist/assets/{select-BLOccU1M.js → select-J6668k2a.js} +1 -1
- package/codemini-web/dist/assets/{trash-2-CQzNOch5.js → trash-2-H0DiWqiE.js} +1 -1
- package/codemini-web/dist/index.html +2 -2
- package/codemini-web/server.js +90 -73
- package/package.json +1 -1
- package/src/commands/skill.js +188 -48
- package/src/core/agent-loop.js +67 -25
- package/src/core/chat-runtime.js +16 -13
- package/src/core/shell-profile.js +3 -2
- package/src/core/tools.js +42 -27
- package/codemini-web/dist/assets/SkillDialog-DjPF-XBx.js +0 -8
- package/codemini-web/dist/assets/chevron-right-CfNZHlyU.js +0 -1
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-KBEtMEB9.js +0 -1
package/src/commands/skill.js
CHANGED
|
@@ -6,13 +6,15 @@ import { copyRecursive } from '../core/fs-utils.js';
|
|
|
6
6
|
import { loadConfig, saveConfig } from '../core/config-store.js';
|
|
7
7
|
import { loadCommandsAndSkills } from '../core/command-loader.js';
|
|
8
8
|
import { getProjectSkillsDir, getSkillsDir } from '../core/paths.js';
|
|
9
|
-
import {
|
|
10
|
-
computeFileSha256,
|
|
11
|
-
readSkillRegistry,
|
|
12
|
-
upsertSkillRegistryEntry,
|
|
13
|
-
writeSkillRegistry
|
|
14
|
-
} from '../core/skill-registry.js';
|
|
15
|
-
|
|
9
|
+
import {
|
|
10
|
+
computeFileSha256,
|
|
11
|
+
readSkillRegistry,
|
|
12
|
+
upsertSkillRegistryEntry,
|
|
13
|
+
writeSkillRegistry
|
|
14
|
+
} from '../core/skill-registry.js';
|
|
15
|
+
|
|
16
|
+
const SKILL_CATALOG_FILE = 'codemini.skills.json';
|
|
17
|
+
|
|
16
18
|
function parseScopeArgs(args = [], { defaultScope = 'project', allowAll = false } = {}) {
|
|
17
19
|
let scope = defaultScope;
|
|
18
20
|
const rest = [];
|
|
@@ -195,16 +197,132 @@ async function runTarExtract(tgzPath, destDir) {
|
|
|
195
197
|
});
|
|
196
198
|
}
|
|
197
199
|
|
|
198
|
-
async function readManifestSafe(skillRoot) {
|
|
199
|
-
const p = path.join(skillRoot, 'manifest.json');
|
|
200
|
-
try {
|
|
201
|
-
const raw = await fs.readFile(p, 'utf8');
|
|
202
|
-
return JSON.parse(raw);
|
|
200
|
+
async function readManifestSafe(skillRoot) {
|
|
201
|
+
const p = path.join(skillRoot, 'manifest.json');
|
|
202
|
+
try {
|
|
203
|
+
const raw = await fs.readFile(p, 'utf8');
|
|
204
|
+
return JSON.parse(raw);
|
|
203
205
|
} catch {
|
|
204
206
|
return null;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function parseArrayText(value) {
|
|
211
|
+
const inner = value.slice(1, -1).trim();
|
|
212
|
+
if (!inner) return [];
|
|
213
|
+
return inner.split(',').map((item) => item.trim().replace(/^["']|["']$/g, ''));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function parseSkillFrontmatter(raw) {
|
|
217
|
+
const normalized = String(raw || '').replace(/\r\n/g, '\n');
|
|
218
|
+
if (!normalized.startsWith('---\n')) {
|
|
219
|
+
return { metadata: {}, content: normalized };
|
|
220
|
+
}
|
|
221
|
+
const end = normalized.indexOf('\n---\n', 4);
|
|
222
|
+
if (end === -1) {
|
|
223
|
+
return { metadata: {}, content: normalized };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const metadata = {};
|
|
227
|
+
const metaRaw = normalized.slice(4, end).trim();
|
|
228
|
+
for (const line of metaRaw.split('\n')) {
|
|
229
|
+
const idx = line.indexOf(':');
|
|
230
|
+
if (idx <= 0) continue;
|
|
231
|
+
const key = line.slice(0, idx).trim();
|
|
232
|
+
const value = line.slice(idx + 1).trim();
|
|
233
|
+
metadata[key] = value.startsWith('[') && value.endsWith(']')
|
|
234
|
+
? parseArrayText(value)
|
|
235
|
+
: value.replace(/^["']|["']$/g, '');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
metadata,
|
|
240
|
+
content: normalized.slice(end + 5).trim()
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function cleanDescriptionText(value) {
|
|
245
|
+
return String(value || '')
|
|
246
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
247
|
+
.replace(/[`*_~]/g, '')
|
|
248
|
+
.replace(/\s+/g, ' ')
|
|
249
|
+
.trim()
|
|
250
|
+
.slice(0, 240);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function inferDescriptionFromSkillMarkdown(content) {
|
|
254
|
+
const lines = String(content || '').replace(/\r\n/g, '\n').split('\n');
|
|
255
|
+
let inFence = false;
|
|
256
|
+
const paragraph = [];
|
|
257
|
+
|
|
258
|
+
for (const rawLine of lines) {
|
|
259
|
+
const trimmed = rawLine.trim();
|
|
260
|
+
if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
|
|
261
|
+
inFence = !inFence;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (inFence) continue;
|
|
265
|
+
|
|
266
|
+
if (!trimmed) {
|
|
267
|
+
if (paragraph.length > 0) break;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (/^#{1,6}\s+/.test(trimmed)) continue;
|
|
271
|
+
if (/^<!--/.test(trimmed)) continue;
|
|
272
|
+
if (/^[-*_]{3,}$/.test(trimmed)) continue;
|
|
273
|
+
|
|
274
|
+
const withoutListMarker = trimmed.replace(/^([-*+]|\d+[.)])\s+/, '');
|
|
275
|
+
if (/^(name|version|author|license|entry)\s*:/i.test(withoutListMarker)) continue;
|
|
276
|
+
paragraph.push(withoutListMarker);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return cleanDescriptionText(paragraph.join(' '));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function readSkillDocumentMeta(skillRoot, entryFile = 'SKILL.md') {
|
|
283
|
+
const entryPath = path.join(skillRoot, entryFile || 'SKILL.md');
|
|
284
|
+
try {
|
|
285
|
+
const raw = await fs.readFile(entryPath, 'utf8');
|
|
286
|
+
const parsed = parseSkillFrontmatter(raw);
|
|
287
|
+
return {
|
|
288
|
+
version: parsed.metadata.version ? String(parsed.metadata.version) : '',
|
|
289
|
+
description: parsed.metadata.description
|
|
290
|
+
? cleanDescriptionText(parsed.metadata.description)
|
|
291
|
+
: inferDescriptionFromSkillMarkdown(parsed.content)
|
|
292
|
+
};
|
|
293
|
+
} catch {
|
|
294
|
+
return { version: '', description: '' };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async function readSkillCatalogSafe(baseDir) {
|
|
299
|
+
const catalogPath = path.join(baseDir, SKILL_CATALOG_FILE);
|
|
300
|
+
try {
|
|
301
|
+
const parsed = JSON.parse(await fs.readFile(catalogPath, 'utf8'));
|
|
302
|
+
return parsed && typeof parsed === 'object' && parsed.skills && typeof parsed.skills === 'object'
|
|
303
|
+
? parsed
|
|
304
|
+
: { version: 1, skills: {} };
|
|
305
|
+
} catch {
|
|
306
|
+
return { version: 1, skills: {} };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function writeSkillCatalog(baseDir, catalog) {
|
|
311
|
+
await fs.mkdir(baseDir, { recursive: true });
|
|
312
|
+
await fs.writeFile(path.join(baseDir, SKILL_CATALOG_FILE), `${JSON.stringify(catalog, null, 2)}\n`, 'utf8');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function upsertSkillCatalogEntry(baseDir, name, entry) {
|
|
316
|
+
const catalog = await readSkillCatalogSafe(baseDir);
|
|
317
|
+
catalog.version = catalog.version || 1;
|
|
318
|
+
catalog.skills = catalog.skills || {};
|
|
319
|
+
catalog.skills[name] = {
|
|
320
|
+
...(catalog.skills[name] || {}),
|
|
321
|
+
...entry
|
|
322
|
+
};
|
|
323
|
+
await writeSkillCatalog(baseDir, catalog);
|
|
324
|
+
}
|
|
325
|
+
|
|
208
326
|
async function resolveSkillSourceDir(sourcePath) {
|
|
209
327
|
const absSrc = path.resolve(sourcePath);
|
|
210
328
|
const srcStat = await fs.stat(absSrc);
|
|
@@ -277,22 +395,30 @@ export async function installSkill(sourcePath, { scope = 'project', cwd = proces
|
|
|
277
395
|
|
|
278
396
|
const entryFile = manifest?.entry || 'SKILL.md';
|
|
279
397
|
const entryPath = path.join(targetDir, entryFile);
|
|
280
|
-
await fs.access(entryPath);
|
|
281
|
-
|
|
282
|
-
const hash = await computeFileSha256(entryPath);
|
|
283
|
-
|
|
284
|
-
|
|
398
|
+
await fs.access(entryPath);
|
|
399
|
+
|
|
400
|
+
const hash = await computeFileSha256(entryPath);
|
|
401
|
+
const documentMeta = await readSkillDocumentMeta(targetDir, entryFile);
|
|
402
|
+
const description = manifest?.description || documentMeta.description || '';
|
|
403
|
+
const version = manifest?.version || documentMeta.version || '0.0.0';
|
|
404
|
+
if (scope === 'global') {
|
|
405
|
+
await upsertSkillRegistryEntry(undefined, {
|
|
285
406
|
name: folderName,
|
|
286
|
-
version
|
|
287
|
-
description
|
|
407
|
+
version,
|
|
408
|
+
description,
|
|
288
409
|
enabled: true,
|
|
289
410
|
source: sourceLabel,
|
|
290
411
|
entryFile,
|
|
291
412
|
sha256: hash,
|
|
292
413
|
installedAt: new Date().toISOString()
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
414
|
+
});
|
|
415
|
+
} else {
|
|
416
|
+
await upsertSkillCatalogEntry(baseDirForScope(scope, cwd), folderName, {
|
|
417
|
+
description,
|
|
418
|
+
enabled: true
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
await setSkillEnabledConfig(folderName, true);
|
|
296
422
|
|
|
297
423
|
if (resolved.cleanupDir) {
|
|
298
424
|
await fs.rm(resolved.cleanupDir, { recursive: true, force: true });
|
|
@@ -387,37 +513,51 @@ async function reindexSkills({ scope = 'global', cwd = process.cwd() } = {}) {
|
|
|
387
513
|
if (!entry.isDirectory()) continue;
|
|
388
514
|
const name = entry.name;
|
|
389
515
|
const dir = path.join(baseDir, name);
|
|
390
|
-
const manifest = await readManifestSafe(dir);
|
|
391
|
-
const entryFile = manifest?.entry || 'SKILL.md';
|
|
392
|
-
const entryPath = path.join(dir, entryFile);
|
|
393
|
-
try {
|
|
394
|
-
await fs.access(entryPath);
|
|
516
|
+
const manifest = await readManifestSafe(dir);
|
|
517
|
+
const entryFile = manifest?.entry || 'SKILL.md';
|
|
518
|
+
const entryPath = path.join(dir, entryFile);
|
|
519
|
+
try {
|
|
520
|
+
await fs.access(entryPath);
|
|
395
521
|
} catch {
|
|
396
522
|
continue;
|
|
397
|
-
}
|
|
398
|
-
const hash = await computeFileSha256(entryPath);
|
|
399
|
-
const prior = byName.get(name);
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
523
|
+
}
|
|
524
|
+
const hash = await computeFileSha256(entryPath);
|
|
525
|
+
const prior = byName.get(name);
|
|
526
|
+
const documentMeta = await readSkillDocumentMeta(dir, entryFile);
|
|
527
|
+
rebuilt.push({
|
|
528
|
+
name: manifest?.name || name,
|
|
529
|
+
version: manifest?.version || documentMeta.version || prior?.version || '0.0.0',
|
|
530
|
+
description: manifest?.description || documentMeta.description || prior?.description || '',
|
|
531
|
+
enabled: prior?.enabled !== false,
|
|
532
|
+
source: prior?.source || 'reindex',
|
|
533
|
+
entryFile,
|
|
534
|
+
sha256: hash,
|
|
535
|
+
installedAt: prior?.installedAt || new Date().toISOString()
|
|
409
536
|
});
|
|
410
537
|
}
|
|
411
538
|
|
|
412
539
|
if (scope === 'global') {
|
|
413
540
|
await writeSkillRegistry(undefined, {
|
|
414
541
|
version: 1,
|
|
415
|
-
skills: rebuilt
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
542
|
+
skills: rebuilt
|
|
543
|
+
});
|
|
544
|
+
} else if (scope === 'project') {
|
|
545
|
+
const catalog = await readSkillCatalogSafe(baseDir);
|
|
546
|
+
catalog.version = catalog.version || 1;
|
|
547
|
+
catalog.skills = catalog.skills || {};
|
|
548
|
+
for (const item of rebuilt) {
|
|
549
|
+
catalog.skills[item.name] = {
|
|
550
|
+
...(catalog.skills[item.name] || {}),
|
|
551
|
+
description: item.description,
|
|
552
|
+
enabled: item.enabled !== false,
|
|
553
|
+
triggers: Array.isArray(catalog.skills[item.name]?.triggers) ? catalog.skills[item.name].triggers : []
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
await writeSkillCatalog(baseDir, catalog);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return rebuilt.length;
|
|
560
|
+
}
|
|
421
561
|
|
|
422
562
|
function usage() {
|
|
423
563
|
console.log(`Usage:
|
package/src/core/agent-loop.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { trimInline as _trimInline, normalizePath } from './string-utils.js';
|
|
3
3
|
import { captureToInbox, listInbox } from './memory-store.js';
|
|
4
|
-
import { requiresApprovalEvaluation } from './command-risk.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { requiresApprovalEvaluation } from './command-risk.js';
|
|
5
|
+
import { evaluateCommandPolicy } from './command-policy.js';
|
|
6
|
+
import { getToolOutputSanitizeOptions, sanitizeTextForModel } from './tool-output.js';
|
|
7
|
+
import { normalizeToolArguments } from './tool-args.js';
|
|
8
|
+
import { storeResultIfNeeded, summarizeToolResult } from './tool-result-store.js';
|
|
9
|
+
import { markRunCommandSafeModeApproved } from './tools.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* 安全解析 JSON 字符串。
|
|
@@ -336,8 +338,12 @@ function extractToolResultMeta(toolName, result) {
|
|
|
336
338
|
}
|
|
337
339
|
|
|
338
340
|
export const trimInline = _trimInline;
|
|
339
|
-
|
|
340
|
-
function
|
|
341
|
+
|
|
342
|
+
export function shouldDenyHighRiskRunEvaluation(config = {}, evaluation = {}) {
|
|
343
|
+
return config?.policy?.allow_dangerous_commands !== true && String(evaluation?.risk || '').toLowerCase() === 'high';
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function normalizeAssistantText(value) {
|
|
341
347
|
return String(value || '').trim();
|
|
342
348
|
}
|
|
343
349
|
|
|
@@ -759,9 +765,16 @@ export async function runAgentLoop({
|
|
|
759
765
|
let approved = true;
|
|
760
766
|
let approvalArgs = args;
|
|
761
767
|
let preflightErrorContent = '';
|
|
768
|
+
const runPolicyCheck = toolName === 'run'
|
|
769
|
+
? evaluateCommandPolicy(args?.command || '', config, config?.workspaceRoot || process.cwd())
|
|
770
|
+
: { allowed: true };
|
|
771
|
+
const isSafeModePolicyBlocked = toolName === 'run'
|
|
772
|
+
&& config?.policy?.safe_mode !== false
|
|
773
|
+
&& !runPolicyCheck.allowed
|
|
774
|
+
&& runPolicyCheck.reason !== 'blocked by dangerous command pattern';
|
|
762
775
|
const isSafeModeRun = toolName === 'run'
|
|
763
776
|
&& config?.policy?.safe_mode !== false
|
|
764
|
-
&& requiresApprovalEvaluation(args?.command || '', config?.shell?.default);
|
|
777
|
+
&& (isSafeModePolicyBlocked || requiresApprovalEvaluation(args?.command || '', config?.shell?.default));
|
|
765
778
|
const isFileWriteTool = toolName === 'edit' || toolName === 'write' || toolName === 'delete';
|
|
766
779
|
const needsApproval = normalizedApprovalMode === 'full_access'
|
|
767
780
|
? false
|
|
@@ -787,20 +800,46 @@ export async function runAgentLoop({
|
|
|
787
800
|
if (toolName === 'run' && isSafeModeRun && !preflightErrorContent) {
|
|
788
801
|
try {
|
|
789
802
|
const { evaluateCommandWithLLM } = await import('./command-evaluator.js');
|
|
790
|
-
const evaluation = await evaluateCommandWithLLM({
|
|
791
|
-
command: args?.command || '',
|
|
792
|
-
config,
|
|
793
|
-
workspaceRoot: config?.workspaceRoot || process.cwd()
|
|
794
|
-
});
|
|
795
|
-
approvalArgs = {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
803
|
+
const evaluation = await evaluateCommandWithLLM({
|
|
804
|
+
command: args?.command || '',
|
|
805
|
+
config,
|
|
806
|
+
workspaceRoot: config?.workspaceRoot || process.cwd()
|
|
807
|
+
});
|
|
808
|
+
approvalArgs = {
|
|
809
|
+
...args,
|
|
810
|
+
_risk: isSafeModePolicyBlocked && evaluation.risk === 'low' ? 'medium' : evaluation.risk,
|
|
811
|
+
_evaluation: evaluation,
|
|
812
|
+
_policyBlock: isSafeModePolicyBlocked
|
|
813
|
+
? { reason: runPolicyCheck.reason, suggestion: runPolicyCheck.suggestion || '' }
|
|
814
|
+
: null
|
|
815
|
+
};
|
|
816
|
+
if (shouldDenyHighRiskRunEvaluation(config, evaluation)) {
|
|
817
|
+
preflightErrorContent = clipToolResult({
|
|
818
|
+
error: 'Command blocked by safe mode: high-risk command denied because dangerous commands are disabled',
|
|
819
|
+
evaluation
|
|
820
|
+
}, toolResultMaxChars);
|
|
821
|
+
approvalResults.set(call.id, {
|
|
822
|
+
approved: false,
|
|
823
|
+
args: approvalArgs,
|
|
824
|
+
errorContent: preflightErrorContent
|
|
825
|
+
});
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
/* LLM says low-risk + allow → auto-approve, skip confirmation panel */
|
|
829
|
+
if (!isSafeModePolicyBlocked && normalizedApprovalMode !== 'review' && evaluation.risk === 'low' && evaluation.recommendation === 'allow') {
|
|
830
|
+
approvalResults.set(call.id, { approved: true, args: approvalArgs });
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
} catch (_) {
|
|
834
|
+
approvalArgs = {
|
|
835
|
+
...args,
|
|
836
|
+
_risk: isSafeModePolicyBlocked ? 'medium' : 'high',
|
|
837
|
+
_evaluation: null,
|
|
838
|
+
_policyBlock: isSafeModePolicyBlocked
|
|
839
|
+
? { reason: runPolicyCheck.reason, suggestion: runPolicyCheck.suggestion || '' }
|
|
840
|
+
: null
|
|
841
|
+
};
|
|
842
|
+
}
|
|
804
843
|
if (typeof handler?.prepareApproval === 'function') {
|
|
805
844
|
try {
|
|
806
845
|
const approval = await handler.prepareApproval(approvalArgs);
|
|
@@ -824,10 +863,13 @@ export async function runAgentLoop({
|
|
|
824
863
|
arguments: approvalArgs,
|
|
825
864
|
approvalDetails: toolName === 'delete' ? approvalArgs.approval
|
|
826
865
|
: (toolName === 'run' ? approvalArgs.approval : undefined)
|
|
827
|
-
});
|
|
828
|
-
approved = Boolean(decision?.approved);
|
|
829
|
-
|
|
830
|
-
|
|
866
|
+
});
|
|
867
|
+
approved = Boolean(decision?.approved);
|
|
868
|
+
if (approved && toolName === 'run' && isSafeModePolicyBlocked) {
|
|
869
|
+
approvalArgs = markRunCommandSafeModeApproved(approvalArgs);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
831
873
|
approvalResults.set(call.id, { approved, args: approvalArgs });
|
|
832
874
|
}
|
|
833
875
|
|
package/src/core/chat-runtime.js
CHANGED
|
@@ -3104,18 +3104,21 @@ async function askModel({
|
|
|
3104
3104
|
projectContextGuidance
|
|
3105
3105
|
});
|
|
3106
3106
|
|
|
3107
|
-
const
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
policy
|
|
3112
|
-
|
|
3113
|
-
allowed_paths: [
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3107
|
+
const toolConfig = {
|
|
3108
|
+
...config,
|
|
3109
|
+
workspaceRoot: process.cwd(),
|
|
3110
|
+
policy: {
|
|
3111
|
+
...(config.policy || {}),
|
|
3112
|
+
allowed_paths: [
|
|
3113
|
+
...(Array.isArray(config.policy?.allowed_paths) ? config.policy.allowed_paths : []),
|
|
3114
|
+
path.join(getSessionsDir(), String(session.id))
|
|
3115
|
+
]
|
|
3116
|
+
}
|
|
3117
|
+
};
|
|
3118
|
+
|
|
3119
|
+
const { definitions, handlers, formatters, deferredDefinitions, dispose: disposeTools } = getBuiltinTools({
|
|
3120
|
+
workspaceRoot: process.cwd(),
|
|
3121
|
+
config: toolConfig,
|
|
3119
3122
|
sessionId: session.id,
|
|
3120
3123
|
onSystemEvent: onAgentEvent,
|
|
3121
3124
|
getTodos: () => normalizeTodos(session.todos),
|
|
@@ -3387,7 +3390,7 @@ async function askModel({
|
|
|
3387
3390
|
requestToolApproval,
|
|
3388
3391
|
signal,
|
|
3389
3392
|
skipAnalysisNudge,
|
|
3390
|
-
config,
|
|
3393
|
+
config: toolConfig,
|
|
3391
3394
|
changeTracker: changeTracker?.enabled
|
|
3392
3395
|
? {
|
|
3393
3396
|
begin: (meta) => beginGitOplogCapture(changeTracker, meta),
|
package/src/core/tools.js
CHANGED
|
@@ -30,8 +30,8 @@ import {
|
|
|
30
30
|
sanitizeTextForModel,
|
|
31
31
|
summarizeRunOutput
|
|
32
32
|
} from './tool-output.js';
|
|
33
|
-
import {
|
|
34
|
-
normalizeFilePathValue,
|
|
33
|
+
import {
|
|
34
|
+
normalizeFilePathValue,
|
|
35
35
|
normalizePathArgs,
|
|
36
36
|
parseInlineRangePath,
|
|
37
37
|
normalizePatternArgs,
|
|
@@ -39,14 +39,28 @@ import {
|
|
|
39
39
|
normalizeWebFetchArgs,
|
|
40
40
|
normalizeWebSearchArgs,
|
|
41
41
|
normalizeWriteArgs
|
|
42
|
-
} from './tool-args.js';
|
|
43
|
-
const BACKGROUND_TASK_RECENT_OUTPUT_LIMIT = 80;
|
|
44
|
-
const BACKGROUND_TASK_POLL_MS = 150;
|
|
45
|
-
const MAX_AST_ENCLOSING_BYTES = 300_000;
|
|
46
|
-
const MAX_AST_ENCLOSING_LINES = 5_000;
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
let
|
|
42
|
+
} from './tool-args.js';
|
|
43
|
+
const BACKGROUND_TASK_RECENT_OUTPUT_LIMIT = 80;
|
|
44
|
+
const BACKGROUND_TASK_POLL_MS = 150;
|
|
45
|
+
const MAX_AST_ENCLOSING_BYTES = 300_000;
|
|
46
|
+
const MAX_AST_ENCLOSING_LINES = 5_000;
|
|
47
|
+
const RUN_COMMAND_SAFE_MODE_APPROVED = Symbol('runCommandSafeModeApproved');
|
|
48
|
+
const backgroundTaskRegistry = new Map();
|
|
49
|
+
let backgroundTaskCounter = 0;
|
|
50
|
+
let backgroundTaskLogCursorCounter = 0;
|
|
51
|
+
|
|
52
|
+
export function markRunCommandSafeModeApproved(args = {}) {
|
|
53
|
+
const next = { ...(args && typeof args === 'object' ? args : {}) };
|
|
54
|
+
Object.defineProperty(next, RUN_COMMAND_SAFE_MODE_APPROVED, {
|
|
55
|
+
value: true,
|
|
56
|
+
enumerable: false
|
|
57
|
+
});
|
|
58
|
+
return next;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function hasRunCommandSafeModeApproval(args = {}) {
|
|
62
|
+
return Boolean(args?.[RUN_COMMAND_SAFE_MODE_APPROVED]);
|
|
63
|
+
}
|
|
50
64
|
|
|
51
65
|
async function realpathIfExists(targetPath) {
|
|
52
66
|
try {
|
|
@@ -1125,11 +1139,11 @@ async function runCommand(root, config, args) {
|
|
|
1125
1139
|
throw new Error('Command blocked by policy');
|
|
1126
1140
|
}
|
|
1127
1141
|
|
|
1128
|
-
const check = evaluateCommandPolicy(command, config, root);
|
|
1129
|
-
if (!check.allowed) {
|
|
1130
|
-
throw new Error(
|
|
1131
|
-
`Command blocked by safe mode: ${check.reason}${check.suggestion ? ` | ${check.suggestion}` : ''}`
|
|
1132
|
-
);
|
|
1142
|
+
const check = evaluateCommandPolicy(command, config, root);
|
|
1143
|
+
if (!check.allowed && !hasRunCommandSafeModeApproval(args)) {
|
|
1144
|
+
throw new Error(
|
|
1145
|
+
`Command blocked by safe mode: ${check.reason}${check.suggestion ? ` | ${check.suggestion}` : ''}`
|
|
1146
|
+
);
|
|
1133
1147
|
}
|
|
1134
1148
|
|
|
1135
1149
|
const shouldBackground =
|
|
@@ -1296,11 +1310,11 @@ async function startBackgroundTask(root, config, args) {
|
|
|
1296
1310
|
) {
|
|
1297
1311
|
throw new Error('Command blocked by policy');
|
|
1298
1312
|
}
|
|
1299
|
-
const check = evaluateCommandPolicy(command, config, root);
|
|
1300
|
-
if (!check.allowed) {
|
|
1301
|
-
throw new Error(
|
|
1302
|
-
`Command blocked by safe mode: ${check.reason}${check.suggestion ? ` | ${check.suggestion}` : ''}`
|
|
1303
|
-
);
|
|
1313
|
+
const check = evaluateCommandPolicy(command, config, root);
|
|
1314
|
+
if (!check.allowed && !hasRunCommandSafeModeApproval(args)) {
|
|
1315
|
+
throw new Error(
|
|
1316
|
+
`Command blocked by safe mode: ${check.reason}${check.suggestion ? ` | ${check.suggestion}` : ''}`
|
|
1317
|
+
);
|
|
1304
1318
|
}
|
|
1305
1319
|
|
|
1306
1320
|
const shellSpec = resolveShell(config.shell.default);
|
|
@@ -2920,13 +2934,14 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2920
2934
|
run: Object.assign(
|
|
2921
2935
|
(args) => runCommand(workspaceRoot, config, args),
|
|
2922
2936
|
{
|
|
2923
|
-
prepareApproval: async (args) => ({
|
|
2924
|
-
command: args?.command || '',
|
|
2925
|
-
risk: args?._risk || 'high',
|
|
2926
|
-
evaluation: args?._evaluation || null
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2937
|
+
prepareApproval: async (args) => ({
|
|
2938
|
+
command: args?.command || '',
|
|
2939
|
+
risk: args?._risk || 'high',
|
|
2940
|
+
evaluation: args?._evaluation || null,
|
|
2941
|
+
policyBlock: args?._policyBlock || null
|
|
2942
|
+
})
|
|
2943
|
+
}
|
|
2944
|
+
),
|
|
2930
2945
|
save_memory: async (args = {}) => {
|
|
2931
2946
|
const rawScope = String(args.scope || 'global').toLowerCase();
|
|
2932
2947
|
const memoryScope = rawScope === 'repo' || rawScope === 'project' ? 'project'
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{a as t,r as n}from"./bundle-mjs-C44PrJ2C.js";import{a as r,i,n as a,r as o,t as s}from"./select-BLOccU1M.js";import{t as c}from"./chevron-right-CfNZHlyU.js";import{n as l,t as u}from"./pencil-BdA2cEeE.js";import{n as d,t as f}from"./trash-2-CQzNOch5.js";import{B as p,J as m,L as h,P as g,Y as _,b as v,c as y,d as b,et as x,f as S,g as C,k as w,l as T,lt as E,n as D,ot as O,pt as k,r as A,rt as j,s as M,st as N,u as P,w as F}from"./index-BhMtCC8_.js";import{t as I}from"./input-CYpdNDlR.js";var ee=g(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]),te=g(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),L=g(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),R=e(t(),1),z=n(),ne=[`all`,`enabled`,`builtin`,`custom`],B=[`always`,`auto_attach`,`agent_requested`,`manual`];function V({checked:e,onClick:t,title:n}){return(0,z.jsx)(`button`,{type:`button`,onClick:t,title:n,"aria-pressed":e,className:k(`relative h-5 w-9 rounded-full border shadow-inner transition-colors`,e?`border-(--text-primary) bg-(--text-primary)`:`border-(--border-strong) bg-(--bg-hover)`),children:(0,z.jsx)(`span`,{className:k(`absolute left-0.5 top-0.5 size-3.5 rounded-full transition-transform`,e?`bg-(--bg-primary)`:`bg-(--text-muted)`,e?`translate-x-4`:`translate-x-0`)})})}function H(e){return E(e===`builtin`?`builtin`:e===`global`?`globalScope`:`projectScope`)}function U(e){return`${e?.scope||`unknown`}:${e?.projectDir||``}:${e?.name||``}`}function W(e){return e===`__codemini_general__`?E(`generalChat`):e}function re(e=[]){return Array.isArray(e)?e.map(e=>String(e||``).trim()).filter(Boolean).join(`
|
|
2
|
-
`):``}function G(e){return e?.scope===`builtin`}function K(e){return e?.enabled!==!1}function q({skill:e,onSave:t,onCancel:n}){let[c,l]=(0,R.useState)(e?.name||``),[u,d]=(0,R.useState)(e?.description||``),[f,p]=(0,R.useState)(e?.scope||`project`),[g,_]=(0,R.useState)(e?.mode||`agent_requested`),[v,y]=(0,R.useState)((e?.triggers||[]).join(`, `)),[b,x]=(0,R.useState)(e?.priority??50),[C,w]=(0,R.useState)(K(e)),[T,k]=(0,R.useState)(``),[j,M]=(0,R.useState)(!1),P=!e,F=G(e);return(0,R.useEffect)(()=>{if(l(e?.name||``),d(e?.description||``),p(e?.scope||`project`),_(e?.mode||`agent_requested`),y((e?.triggers||[]).join(`, `)),x(e?.priority??50),w(K(e)),!e){k(``);return}M(!0),m(e.name,e.projectDir).then(e=>k(e.content||``)).catch(()=>{}).finally(()=>M(!1))},[e]),(0,z.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col`,children:[(0,z.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto pr-1`,children:[(0,z.jsxs)(`div`,{className:`mb-3 flex items-start justify-between gap-3`,children:[(0,z.jsxs)(`div`,{children:[(0,z.jsx)(`div`,{className:`text-[13px] font-medium text-(--text-primary)`,children:E(P?`newSkill`:`editSkill`)}),(0,z.jsx)(`div`,{className:`mt-0.5 text-[11px] text-(--text-muted)`,children:E(`skillEditorHint`)})]}),(0,z.jsx)(A,{variant:`outline`,className:`rounded-md px-1.5 py-0 text-[10px]`,children:H(f)})]}),(0,z.jsxs)(`div`,{className:`grid gap-3`,children:[(P||!G(e))&&(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`skillScope`)}),(0,z.jsxs)(s,{value:f,onValueChange:p,children:[(0,z.jsx)(i,{className:`h-8 w-full bg-(--bg-primary) text-[13px]`,children:(0,z.jsx)(r,{})}),(0,z.jsxs)(a,{align:`start`,children:[(0,z.jsx)(o,{value:`project`,children:E(`projectScope`)}),(0,z.jsx)(o,{value:`global`,children:E(`globalScope`)})]})]})]}),(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`name`)}),(0,z.jsx)(I,{value:c,onChange:e=>l(e.target.value),disabled:!P,placeholder:`my-skill`,className:`h-8 text-[13px]`})]}),(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`description`)}),(0,z.jsx)(I,{value:u,onChange:e=>d(e.target.value),placeholder:E(`skillDescriptionPlaceholder`),className:`h-8 text-[13px]`})]}),(0,z.jsxs)(`div`,{className:`rounded-md border border-(--border-default) bg-(--bg-secondary) p-3`,children:[(0,z.jsxs)(`div`,{className:`mb-2 flex items-center gap-2 text-[12px] font-medium text-(--text-primary)`,children:[(0,z.jsx)(L,{size:13}),E(`skillRoutingSettings`)]}),(0,z.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`skillMode`)}),(0,z.jsxs)(s,{value:g,onValueChange:_,children:[(0,z.jsx)(i,{className:`h-8 w-full bg-(--bg-primary) text-[13px]`,children:(0,z.jsx)(r,{})}),(0,z.jsx)(a,{align:`start`,children:B.map(e=>(0,z.jsx)(o,{value:e,children:E(`skillMode_${e}`)},e))})]})]}),(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`skillPriority`)}),(0,z.jsx)(I,{type:`number`,min:`0`,max:`100`,value:b,onChange:e=>x(e.target.value),className:`h-8 text-[13px]`})]}),(0,z.jsxs)(`div`,{className:`grid gap-1.5 sm:col-span-2`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`skillTriggers`)}),(0,z.jsx)(I,{value:v,onChange:e=>y(e.target.value),placeholder:`after_edit, before_final`,className:`h-8 text-[13px]`})]}),(0,z.jsxs)(`div`,{className:`flex items-center justify-between rounded-md border border-(--border-default) bg-(--bg-primary) px-2 py-1.5 sm:col-span-2`,children:[(0,z.jsx)(`span`,{className:`text-[12px] text-(--text-muted)`,children:E(C?`enabled`:`disabled`)}),(0,z.jsx)(V,{checked:C,onClick:()=>w(e=>!e),title:E(C?`disable`:`enable`)})]})]})]}),(0,z.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,z.jsx)(`label`,{className:`text-[12px] text-(--text-muted)`,children:E(`skillContent`)}),j?(0,z.jsxs)(`div`,{className:`rounded-md border border-(--border-default) py-8 text-center text-[12px] text-(--text-muted)`,children:[E(`loading`),`...`]}):(0,z.jsx)(D,{value:T,onChange:e=>k(e.target.value),disabled:F,className:`min-h-[360px] resize-y text-[13px] font-mono leading-5`,placeholder:`---
|
|
3
|
-
name: my-skill
|
|
4
|
-
description: ...
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Skill instructions...`})]})]})]}),(0,z.jsxs)(`div`,{className:`mt-3 flex shrink-0 justify-end gap-2 border-t border-(--border-default) bg-(--bg-primary) pt-3`,children:[(0,z.jsx)(S,{variant:`outline`,onClick:n,size:`sm`,children:E(`cancel`)}),(0,z.jsx)(S,{onClick:async()=>{let n={description:u,scope:f,mode:g,triggers:v.split(`,`).map(e=>e.trim()).filter(Boolean),enabled:C,priority:Number(b)||0};P?(await h({name:c,description:u,content:T,scope:f}),await N(c,n)):(await N(e.name,n,e.projectDir),F||await O(e.name,T,e.projectDir)),t()},disabled:j||!F&&!T.trim()||P&&!c.trim(),size:`sm`,children:E(P?`create`:`save`)})]})]})}function ie({skill:e,open:t,onSave:n,onOpenChange:r}){return(0,z.jsx)(M,{open:t,onOpenChange:r,children:(0,z.jsxs)(y,{className:`sm:max-w-[760px] h-[86vh] max-h-[86vh] flex flex-col overflow-hidden`,children:[(0,z.jsx)(P,{className:`shrink-0`,children:(0,z.jsx)(b,{children:E(e?`editSkill`:`newSkill`)})}),(0,z.jsx)(q,{skill:e,onSave:n,onCancel:()=>r(!1)})]})})}function ae({skill:e,open:t,onOpenChange:n}){let[r,i]=(0,R.useState)(``),[a,o]=(0,R.useState)(!1);return(0,R.useEffect)(()=>{!t||!e||(o(!0),m(e.name,e.projectDir).then(e=>i(e.content||``)).catch(()=>{}).finally(()=>o(!1)))},[t,e]),(0,z.jsx)(M,{open:t,onOpenChange:n,children:(0,z.jsxs)(y,{className:`sm:max-w-[720px] max-h-[82vh] flex flex-col overflow-hidden`,children:[(0,z.jsx)(P,{className:`shrink-0`,children:(0,z.jsxs)(b,{children:[e?.name,` `,E(`contentPreview`)]})}),(0,z.jsx)(`div`,{className:`flex-1 overflow-y-auto min-h-0 pr-1`,children:a?(0,z.jsxs)(`div`,{className:`py-8 text-center text-[12px] text-(--text-muted)`,children:[E(`loading`),`...`]}):(0,z.jsx)(`pre`,{className:`rounded-lg bg-(--bg-secondary) p-3 text-[13px] whitespace-pre-wrap break-words font-mono leading-5`,children:r})}),(0,z.jsx)(T,{className:`shrink-0`,children:(0,z.jsx)(S,{variant:`outline`,onClick:()=>n(!1),size:`sm`,children:E(`close`)})})]})})}function J({skill:e,onView:t,onToggle:n,onEdit:r,onDelete:i}){let a=K(e);return(0,z.jsx)(`div`,{className:k(`rounded-lg border p-3 transition-colors`,a?`border-(--border-default) bg-(--bg-primary) hover:bg-(--bg-hover)`:`border-(--border-default) bg-(--bg-secondary) opacity-75`),children:(0,z.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,z.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,z.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[(0,z.jsx)(`span`,{className:`truncate text-[13px] font-medium text-(--text-primary)`,children:e.name}),(0,z.jsx)(A,{variant:G(e)?`secondary`:`outline`,className:`h-4 rounded-md px-1.5 py-0 text-[10px]`,children:H(e.scope)}),(0,z.jsx)(A,{variant:a?`outline`:`secondary`,className:`h-4 rounded-md px-1.5 py-0 text-[10px]`,children:E(a?`enabled`:`disabled`)}),e.version&&e.version!==`0.0.0`&&(0,z.jsxs)(`span`,{className:`text-[10px] text-(--text-muted)`,children:[`v`,e.version]}),e.mode&&(0,z.jsx)(A,{variant:`outline`,className:`h-4 rounded-md px-1.5 py-0 text-[10px]`,children:E(`skillMode_${e.mode}`)})]}),(0,z.jsx)(`div`,{className:`mt-1 line-clamp-2 text-[11px] leading-4 text-(--text-muted)`,children:e.description||E(`noDescription`)}),e.triggers?.length>0&&(0,z.jsxs)(`div`,{className:`mt-1 truncate text-[10px] text-(--text-muted)`,children:[E(`skillTriggers`),`: `,e.triggers.join(`, `)]})]}),(0,z.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1`,children:[(0,z.jsx)(S,{variant:`ghost`,size:`icon-xs`,onClick:()=>t(e),title:E(`view`),children:(0,z.jsx)(l,{size:13})}),(0,z.jsx)(V,{checked:a,onClick:()=>n(e,!a),title:E(a?`disable`:`enable`)}),(0,z.jsx)(S,{variant:`ghost`,size:`icon-xs`,onClick:()=>r(e),title:G(e)?E(`skillRoutingSettings`):E(`edit`),children:G(e)?(0,z.jsx)(L,{size:13}):(0,z.jsx)(u,{size:13})}),!G(e)&&(0,z.jsx)(S,{variant:`ghost`,size:`icon-xs`,onClick:()=>{confirm(E(`confirmDeleteSkill`).replace(`{{name}}`,e.name))&&i(e)},title:E(`delete`),className:`text-(--accent-red) hover:text-(--accent-red)`,children:(0,z.jsx)(f,{size:13})})]})]})})}function Y({projectDirs:e=[]}){let[t,n]=(0,R.useState)([]),[l,u]=(0,R.useState)(!0),[f,m]=(0,R.useState)(null),[h,g]=(0,R.useState)(null),[y,b]=(0,R.useState)(()=>new Set),[T,D]=(0,R.useState)(``),[O,k]=(0,R.useState)(`all`),[A,M]=(0,R.useState)(``),[N,P]=(0,R.useState)(`project`),[L,B]=(0,R.useState)(!1),[V,H]=(0,R.useState)(``),q=re(e),Y=(0,R.useMemo)(()=>q?q.split(`
|
|
8
|
-
`):[],[q]),X=(0,R.useCallback)(async()=>{u(!0);try{let e=await _(Y);n(Array.isArray(e)?e:[])}catch{}u(!1)},[Y]);(0,R.useEffect)(()=>{X()},[X]);let Z=async(e,t)=>{n(n=>n.map(n=>n.name===e.name&&n.projectDir===e.projectDir?{...n,enabled:t}:n));try{await j(e.name,t,e.projectDir)}catch{n(n=>n.map(n=>n.name===e.name&&n.projectDir===e.projectDir?{...n,enabled:!t}:n))}try{let e=await _(Y);n(Array.isArray(e)?e:[])}catch{}},Q=async e=>{await p(e.name,e.projectDir),X()},oe=()=>{m(null),X()},se=async()=>{let e=A.trim();if(e){B(!0),H(``);try{let t=await x({source:e,scope:N});if(t?.error)throw Error(t.message||`Install failed`);M(``),await X()}catch(e){H(e.message||`Install failed`)}finally{B(!1)}}};t.filter(K).length,t.filter(e=>!G(e)).length;let $=(0,R.useMemo)(()=>{let e=T.trim().toLowerCase();return t.filter(t=>O===`enabled`&&!K(t)||O===`builtin`&&t.scope!==`builtin`||O===`custom`&&t.scope===`builtin`?!1:e?t.name.toLowerCase().includes(e)||String(W(t.projectName||``)).toLowerCase().includes(e):!0)},[t,T,O]),ce=(0,R.useMemo)(()=>{let e=[],t=[],n=new Map;for(let r of $){if(r.scope!==`project`){e.push(r);continue}let i=r.projectDir||`__current_project__`;if(!n.has(i)){let e={key:i,name:W(r.projectName||E(`projectScope`)),items:[]};n.set(i,e),t.push(e)}n.get(i).items.push(r)}return{regular:e,projectGroups:t}},[$]),le=(0,R.useCallback)(e=>{b(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]);return l?(0,z.jsxs)(`div`,{className:`py-8 text-center text-[12px] text-(--text-muted)`,children:[E(`loading`),`...`]}):(0,z.jsxs)(`div`,{className:`space-y-3`,children:[(0,z.jsx)(`div`,{className:`rounded-lg border border-(--border-default) bg-(--bg-secondary) p-3`,children:(0,z.jsxs)(`div`,{className:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[(0,z.jsxs)(`div`,{className:`min-w-0`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsx)(te,{size:14,className:`text-(--text-muted)`}),(0,z.jsx)(`span`,{className:`text-[13px] font-medium text-(--text-primary)`,children:E(`skillLibrary`)})]}),(0,z.jsx)(`div`,{className:`mt-1 text-[11px] text-(--text-muted)`,children:E(`skillPanelHint`)})]}),(0,z.jsx)(`div`,{className:`flex flex-wrap items-center gap-2`,children:(0,z.jsxs)(S,{onClick:()=>m(`new`),size:`sm`,children:[(0,z.jsx)(v,{size:13}),E(`addSkill`)]})})]})}),(0,z.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-[1fr_auto_auto] sm:items-center`,children:[(0,z.jsx)(I,{value:A,onChange:e=>M(e.target.value),placeholder:E(`skillInstallPlaceholder`),className:`h-8 text-[13px]`}),(0,z.jsxs)(s,{value:N,onValueChange:P,children:[(0,z.jsx)(i,{className:`h-8 w-full bg-(--bg-primary) text-[13px] sm:w-[104px]`,children:(0,z.jsx)(r,{})}),(0,z.jsxs)(a,{align:`start`,children:[(0,z.jsx)(o,{value:`project`,children:E(`projectScope`)}),(0,z.jsx)(o,{value:`global`,children:E(`globalScope`)})]})]}),(0,z.jsxs)(S,{onClick:se,disabled:L||!A.trim(),size:`sm`,children:[(0,z.jsx)(ee,{size:13}),E(L?`installing`:`installSkill`)]})]}),V&&(0,z.jsx)(`div`,{className:`mt-2 text-[11px] text-(--accent-red)`,children:V}),(0,z.jsxs)(`div`,{className:`flex flex-col gap-2 sm:flex-row sm:items-center`,children:[(0,z.jsxs)(`div`,{className:`relative flex-1`,children:[(0,z.jsx)(d,{size:13,className:`pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-(--text-muted)`}),(0,z.jsx)(I,{value:T,onChange:e=>D(e.target.value),placeholder:E(`searchSkills`),className:`h-8 pl-8 text-[13px]`})]}),(0,z.jsx)(`div`,{className:`flex shrink-0 rounded-md border border-(--border-default) p-0.5 gap-0.5`,children:ne.map(e=>(0,z.jsx)(S,{type:`button`,variant:O===e?`secondary`:`ghost`,size:`xs`,onClick:()=>k(e),className:`px-2`,children:E(`filter_${e}`)},e))})]}),(0,z.jsx)(C,{className:`bg-(--border-default)`}),t.length===0&&!f&&(0,z.jsxs)(`div`,{className:`rounded-lg border border-dashed border-(--border-default) py-8 text-center`,children:[(0,z.jsx)(`div`,{className:`text-[13px] text-(--text-primary)`,children:E(`noSkills`)}),(0,z.jsx)(`div`,{className:`mt-1 text-[11px] text-(--text-muted)`,children:E(`noSkillsHint`)})]}),t.length>0&&$.length===0&&(0,z.jsx)(`div`,{className:`py-8 text-center text-[12px] text-(--text-muted)`,children:E(`noMatches`)}),(0,z.jsxs)(`div`,{className:`grid max-h-[420px] gap-2 overflow-y-auto pr-1`,children:[ce.regular.map(e=>(0,z.jsx)(J,{skill:e,onView:g,onToggle:Z,onEdit:m,onDelete:Q},U(e))),ce.projectGroups.map(e=>{let t=y.has(e.key);return(0,z.jsxs)(`div`,{className:`grid gap-1`,children:[(0,z.jsxs)(`button`,{type:`button`,onClick:()=>le(e.key),className:`flex h-8 w-full items-center gap-2 rounded-md border-0 bg-transparent px-2 text-left text-[12px] font-medium text-(--text-primary) hover:bg-(--bg-hover)`,title:e.key,children:[(0,z.jsx)(F,{size:14,className:`shrink-0 text-(--text-muted)`}),(0,z.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:e.name}),(0,z.jsx)(`span`,{className:`shrink-0 text-[12px] font-medium text-(--text-accent)`,children:e.items.length}),t?(0,z.jsx)(c,{size:13,className:`shrink-0 text-(--text-muted)`}):(0,z.jsx)(w,{size:13,className:`shrink-0 text-(--text-muted)`})]}),!t&&(0,z.jsx)(`div`,{className:`grid gap-2 pl-6`,children:e.items.map(e=>(0,z.jsx)(J,{skill:e,onView:g,onToggle:Z,onEdit:m,onDelete:Q},U(e)))})]},e.key)})]}),(0,z.jsx)(ae,{skill:h,open:!!h,onOpenChange:e=>{e||g(null)}}),(0,z.jsx)(ie,{skill:f===`new`?null:f,open:!!f,onSave:oe,onOpenChange:e=>{e||m(null)}})]})}function X({open:e,onOpenChange:t,projectDirs:n=[]}){return(0,z.jsx)(M,{open:e,onOpenChange:t,children:(0,z.jsxs)(y,{className:`sm:max-w-[800px] max-h-[86vh] overflow-hidden flex flex-col`,children:[(0,z.jsx)(P,{children:(0,z.jsx)(b,{children:E(`skills`)})}),(0,z.jsx)(`div`,{className:`flex-1 overflow-y-auto min-h-0 pr-1`,children:(0,z.jsx)(Y,{projectDirs:n})})]})})}export{X as SkillDialog};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{P as e}from"./index-BhMtCC8_.js";var t=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]);export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./chunk-BO2N2NFS-DMUdjM9q.js";export{e as Mermaid};
|