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.
Files changed (32) hide show
  1. package/codemini-web/dist/assets/{AboutDialog-BUp8EzDg.js → AboutDialog-dFkTshay.js} +1 -1
  2. package/codemini-web/dist/assets/{CodeWikiPanel-Fp0VKdzo.js → CodeWikiPanel-Dqup5Sen.js} +1 -1
  3. package/codemini-web/dist/assets/{ConfigDialog-DIpj779O.js → ConfigDialog-DTehAh2r.js} +1 -1
  4. package/codemini-web/dist/assets/{GitDiffDialog-ZLEuX8Qm.js → GitDiffDialog-D4uMixee.js} +1 -1
  5. package/codemini-web/dist/assets/{MemoryDialog-D2YbENVd.js → MemoryDialog-DJqtWamU.js} +1 -1
  6. package/codemini-web/dist/assets/{MessageBubble-BIgpZsLn.js → MessageBubble-BGnFIxcq.js} +1 -1
  7. package/codemini-web/dist/assets/{PatchDiff-CvKNaHsw.js → PatchDiff-CpHAbmv3.js} +1 -1
  8. package/codemini-web/dist/assets/{ProjectSelector-DXIep3lE.js → ProjectSelector-CgJDcTNL.js} +1 -1
  9. package/codemini-web/dist/assets/SkillDialog-D1J46nMC.js +8 -0
  10. package/codemini-web/dist/assets/{SoulDialog-BfIoKETs.js → SoulDialog-DIqK4utD.js} +1 -1
  11. package/codemini-web/dist/assets/chevron-right-BBG4s6Zh.js +1 -0
  12. package/codemini-web/dist/assets/{chunk-BO2N2NFS-DMUdjM9q.js → chunk-BO2N2NFS-fRXUeu1b.js} +4 -4
  13. package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-8ch0jz7Z.js → highlighted-body-OFNGDK62-CKKvx7S1.js} +1 -1
  14. package/codemini-web/dist/assets/{index-DRXwJ-n_.css → index-DF9s7Tuc.css} +1 -1
  15. package/codemini-web/dist/assets/{index-BhMtCC8_.js → index-DyIUhlc8.js} +3 -3
  16. package/codemini-web/dist/assets/{input-CYpdNDlR.js → input-BKNu4DOt.js} +1 -1
  17. package/codemini-web/dist/assets/mermaid-GHXKKRXX-BM8yuNk5.js +1 -0
  18. package/codemini-web/dist/assets/{pencil-BdA2cEeE.js → pencil-C0uznNC_.js} +1 -1
  19. package/codemini-web/dist/assets/{refresh-cw-CJGgUGiS.js → refresh-cw-DUgU5bEu.js} +1 -1
  20. package/codemini-web/dist/assets/{select-BLOccU1M.js → select-J6668k2a.js} +1 -1
  21. package/codemini-web/dist/assets/{trash-2-CQzNOch5.js → trash-2-H0DiWqiE.js} +1 -1
  22. package/codemini-web/dist/index.html +2 -2
  23. package/codemini-web/server.js +90 -73
  24. package/package.json +1 -1
  25. package/src/commands/skill.js +188 -48
  26. package/src/core/agent-loop.js +67 -25
  27. package/src/core/chat-runtime.js +16 -13
  28. package/src/core/shell-profile.js +3 -2
  29. package/src/core/tools.js +42 -27
  30. package/codemini-web/dist/assets/SkillDialog-DjPF-XBx.js +0 -8
  31. package/codemini-web/dist/assets/chevron-right-CfNZHlyU.js +0 -1
  32. package/codemini-web/dist/assets/mermaid-GHXKKRXX-KBEtMEB9.js +0 -1
@@ -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
- if (scope === 'global') {
284
- await upsertSkillRegistryEntry(undefined, {
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: manifest?.version || '0.0.0',
287
- description: manifest?.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
- await setSkillEnabledConfig(folderName, true);
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
- rebuilt.push({
401
- name: manifest?.name || name,
402
- version: manifest?.version || prior?.version || '0.0.0',
403
- description: manifest?.description || prior?.description || '',
404
- enabled: prior?.enabled !== false,
405
- source: prior?.source || 'reindex',
406
- entryFile,
407
- sha256: hash,
408
- installedAt: prior?.installedAt || new Date().toISOString()
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
- return rebuilt.length;
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:
@@ -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 { getToolOutputSanitizeOptions, sanitizeTextForModel } from './tool-output.js';
6
- import { normalizeToolArguments } from './tool-args.js';
7
- import { storeResultIfNeeded, summarizeToolResult } from './tool-result-store.js';
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 normalizeAssistantText(value) {
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 = { ...args, _risk: evaluation.risk, _evaluation: evaluation };
796
- /* LLM says low-risk + allow → auto-approve, skip confirmation panel */
797
- if (normalizedApprovalMode !== 'review' && evaluation.risk === 'low' && evaluation.recommendation === 'allow') {
798
- approvalResults.set(call.id, { approved: true, args: approvalArgs });
799
- continue;
800
- }
801
- } catch (_) {
802
- approvalArgs = { ...args, _risk: 'high', _evaluation: null };
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
 
@@ -3104,18 +3104,21 @@ async function askModel({
3104
3104
  projectContextGuidance
3105
3105
  });
3106
3106
 
3107
- const { definitions, handlers, formatters, deferredDefinitions, dispose: disposeTools } = getBuiltinTools({
3108
- workspaceRoot: process.cwd(),
3109
- config: {
3110
- ...config,
3111
- policy: {
3112
- ...(config.policy || {}),
3113
- allowed_paths: [
3114
- ...(Array.isArray(config.policy?.allowed_paths) ? config.policy.allowed_paths : []),
3115
- path.join(getSessionsDir(), String(session.id))
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),
@@ -17,8 +17,9 @@ const SHELL_PROFILES = {
17
17
  shell: 'powershell',
18
18
  label: 'PowerShell',
19
19
  command_allowlist: [
20
- 'rg',
21
- 'git',
20
+ 'rg',
21
+ 'cd',
22
+ 'git',
22
23
  'node',
23
24
  'npm',
24
25
  'npx',
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 backgroundTaskRegistry = new Map();
48
- let backgroundTaskCounter = 0;
49
- let backgroundTaskLogCursorCounter = 0;
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};