@shawnstack/quickforge 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/assets/AgentProfilesPage-DKyIh3dE.js +1 -0
- package/dist/assets/ChatPanelHost-BUZ6scv9.js +242 -0
- package/dist/assets/{PluginsPage-kiBq0gOT.js → PluginsPage-CN-SFQ_s.js} +1 -1
- package/dist/assets/ScheduledTasksPage-C0htXZk2.js +2 -0
- package/dist/assets/SharedConversationPage-CxbAx1fN.js +1 -0
- package/dist/assets/TerminalDock-_voUf7d-.js +2 -0
- package/dist/assets/WorkspaceInspector-Ci4FuaZH.js +3 -0
- package/dist/assets/{WorkspaceReaderDialog-BJo_KEWi.js → WorkspaceReaderDialog-D75__GFg.js} +1 -1
- package/dist/assets/diff-line-counts-DHyWKEXk.js +10 -0
- package/dist/assets/icons-DzxBk7tb.js +1 -0
- package/dist/assets/index-BI7xZuj-.css +3 -0
- package/dist/assets/index-BzOV50wA.js +1442 -0
- package/dist/assets/{monaco-CGq6uVF1.js → monaco-dMY7_GLO.js} +1 -1
- package/dist/assets/{react-vendor-DunfCFfp.js → react-vendor-DsAeMFcm.js} +1 -1
- package/dist/index.html +4 -4
- package/package.json +1 -1
- package/server/acp/server.mjs +1 -0
- package/server/agent-manager.mjs +8 -8
- package/server/agent-profile-files.mjs +2 -1
- package/server/channels/process-channel.mjs +1 -0
- package/server/channels/providers/wechat.mjs +1 -0
- package/server/custom-commands.mjs +4 -3
- package/server/plugins/registry.mjs +1 -1
- package/server/project-config.mjs +2 -2
- package/server/routes/agent.mjs +0 -1
- package/server/routes/project.mjs +3 -2
- package/server/routes/scheduled-tasks.mjs +13 -121
- package/server/routes/static.mjs +1 -1
- package/server/routes/storage.mjs +13 -7
- package/server/routes/workspace.mjs +8 -24
- package/server/session-utils.mjs +2 -1
- package/server/skills.mjs +3 -2
- package/server/storage.mjs +0 -1
- package/server/tools/index.mjs +5 -2
- package/server/utils/logger.mjs +0 -1
- package/server/utils/package-update.mjs +2 -2
- package/server/utils/scheduled-tasks.mjs +127 -0
- package/server/utils/workspace.mjs +1 -1
- package/dist/assets/AgentProfilesPage-DUmXUxjA.js +0 -1
- package/dist/assets/ChatPanelHost-Syx0SSLe.js +0 -242
- package/dist/assets/ScheduledTasksPage-Dw4-tgp9.js +0 -2
- package/dist/assets/SharedConversationPage-CaE9bNb9.js +0 -1
- package/dist/assets/TerminalDock-BYJcp8Ts.js +0 -2
- package/dist/assets/WorkspaceInspector-Bzmv8Cvi.js +0 -3
- package/dist/assets/diff-line-counts-BZoYp5ai.js +0 -10
- package/dist/assets/icons-47L5YLKz.js +0 -1
- package/dist/assets/index-CqfScETb.js +0 -1200
- package/dist/assets/index-DzkBgHZf.css +0 -3
package/server/skills.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { dataDir } from './storage.mjs'
|
|
5
5
|
import { getEnabledPluginSkillSources } from './plugins/registry.mjs'
|
|
6
|
+
import { logger } from './utils/logger.mjs'
|
|
6
7
|
|
|
7
8
|
const userSkillsDir = path.join(dataDir, 'skills')
|
|
8
9
|
const sharedUserSkillsDir = path.join(os.homedir(), '.agents', 'skills')
|
|
@@ -347,7 +348,7 @@ async function loadSkillsFromSources(sources) {
|
|
|
347
348
|
if (skillsByName.has(skill.name)) skillsByName.delete(skill.name)
|
|
348
349
|
skillsByName.set(skill.name, skill)
|
|
349
350
|
} catch (error) {
|
|
350
|
-
|
|
351
|
+
logger.warn(`Failed to load skill from ${skillDir}:`, error.message || error)
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
}
|
|
@@ -371,7 +372,7 @@ async function loadSkillsFromExplicitSources(sources) {
|
|
|
371
372
|
if (skillsByName.has(skill.name)) skillsByName.delete(skill.name)
|
|
372
373
|
skillsByName.set(skill.name, skill)
|
|
373
374
|
} catch (error) {
|
|
374
|
-
|
|
375
|
+
logger.warn(`Failed to load skill from ${skillDir}:`, error.message || error)
|
|
375
376
|
}
|
|
376
377
|
}
|
|
377
378
|
}
|
package/server/storage.mjs
CHANGED
|
@@ -75,7 +75,6 @@ export function getStoreRevision(storeName) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const configStores = new Set(['settings', 'provider-keys', 'custom-providers', 'plugins'])
|
|
78
|
-
const sessionStores = new Set(['sessions', 'sessions-metadata'])
|
|
79
78
|
|
|
80
79
|
const configStoreSections = {
|
|
81
80
|
settings: ['app', 'settings'],
|
package/server/tools/index.mjs
CHANGED
|
@@ -671,12 +671,15 @@ export async function toolPresentFiles(params, context) {
|
|
|
671
671
|
seen.add(key)
|
|
672
672
|
const kind = entry.kind || inferPresentedFileKind(relativePath)
|
|
673
673
|
const isDefaultPreview = defaultPreviewInput ? relativePath === defaultPreviewInput.replace(/\\/g, '/') : false
|
|
674
|
+
// 所有已知 kind 均自动预览(与前端 isPreviewablePath 语义一致):调用 present_files 即自动打开 tab。
|
|
675
|
+
// 渲染路径由前端按 kind 决定:html/image → browser iframe;markdown/code → 侧栏渲染。
|
|
676
|
+
const autoPreviewable = kind !== 'unknown'
|
|
674
677
|
files.push({
|
|
675
678
|
path: relativePath,
|
|
676
679
|
title: entry.title,
|
|
677
680
|
description: entry.description,
|
|
678
681
|
kind,
|
|
679
|
-
preview: entry.preview ?? (isDefaultPreview ||
|
|
682
|
+
preview: entry.preview ?? (isDefaultPreview || autoPreviewable),
|
|
680
683
|
defaultPreview: isDefaultPreview,
|
|
681
684
|
bytes: stat.size,
|
|
682
685
|
})
|
|
@@ -688,7 +691,7 @@ export async function toolPresentFiles(params, context) {
|
|
|
688
691
|
throw error
|
|
689
692
|
}
|
|
690
693
|
|
|
691
|
-
const previewed = files.filter((file) => file.preview
|
|
694
|
+
const previewed = files.filter((file) => file.preview).map((file) => file.path)
|
|
692
695
|
return {
|
|
693
696
|
content: `Presented ${files.length} file(s)${previewed.length ? ` and opened ${previewed.length} preview(s)` : ''}: ${files.map((file) => file.path).join(', ')}`,
|
|
694
697
|
details: {
|
package/server/utils/logger.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import { logsDir } from '../storage.mjs'
|
|
|
4
4
|
|
|
5
5
|
// --- Level control ---
|
|
6
6
|
const LEVELS = { ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3 }
|
|
7
|
-
const levelNames = Object.keys(LEVELS)
|
|
8
7
|
|
|
9
8
|
const envLevel = (process.env.QUICKFORGE_LOG_LEVEL || '').toUpperCase()
|
|
10
9
|
const minLevel = LEVELS[envLevel] ?? LEVELS.INFO
|
|
@@ -27,7 +27,7 @@ export async function getPackageInfo(projectRoot) {
|
|
|
27
27
|
bugsUrl: typeof pkg.bugs === 'string' ? pkg.bugs : pkg.bugs?.url || '',
|
|
28
28
|
}
|
|
29
29
|
} catch (error) {
|
|
30
|
-
throw new Error(`Unable to read package metadata: ${error.message}
|
|
30
|
+
throw new Error(`Unable to read package metadata: ${error.message}`, { cause: error })
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -109,7 +109,7 @@ export async function fetchLatestVersion(packageName) {
|
|
|
109
109
|
if (!latest || typeof latest !== 'string') throw new Error('latest version not found in registry response')
|
|
110
110
|
return latest
|
|
111
111
|
} catch (error) {
|
|
112
|
-
if (error.name === 'AbortError') throw new Error('request timeout')
|
|
112
|
+
if (error.name === 'AbortError') throw new Error('request timeout', { cause: error })
|
|
113
113
|
throw error
|
|
114
114
|
} finally {
|
|
115
115
|
clearTimeout(timeout)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export const minuteMs = 60 * 1000
|
|
2
|
+
export const hourMs = 60 * minuteMs
|
|
3
|
+
export const dayMs = 24 * hourMs
|
|
4
|
+
|
|
5
|
+
function requestError(message, statusCode = 400) {
|
|
6
|
+
const error = new Error(message)
|
|
7
|
+
error.statusCode = statusCode
|
|
8
|
+
return error
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function pad(value) {
|
|
12
|
+
return String(value).padStart(2, '0')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatLocalDateTime(date) {
|
|
16
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function timeFromDate(value) {
|
|
20
|
+
const date = value ? new Date(value) : null
|
|
21
|
+
if (!date || Number.isNaN(date.getTime())) return undefined
|
|
22
|
+
return `${pad(date.getHours())}:${pad(date.getMinutes())}`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function normalizeExecutionMode(value) {
|
|
26
|
+
if (value === undefined || value === null || value === '') return 'serial'
|
|
27
|
+
const mode = String(value)
|
|
28
|
+
if (mode === 'serial' || mode === 'parallel') return mode
|
|
29
|
+
throw requestError('executionMode must be serial or parallel')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function parseExecuteTime(value) {
|
|
33
|
+
const text = String(value ?? '').trim()
|
|
34
|
+
const match = text.match(/^(\d{1,2}):(\d{2})$/)
|
|
35
|
+
if (!match) throw requestError('executeTime must use HH:mm format')
|
|
36
|
+
const hours = Number(match[1])
|
|
37
|
+
const minutes = Number(match[2])
|
|
38
|
+
if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
|
|
39
|
+
throw requestError('executeTime is out of range')
|
|
40
|
+
}
|
|
41
|
+
return `${pad(hours)}:${pad(minutes)}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function dateWithTime(base, executeTime) {
|
|
45
|
+
const [hours, minutes] = parseExecuteTime(executeTime).split(':').map(Number)
|
|
46
|
+
const date = new Date(base)
|
|
47
|
+
date.setHours(hours, minutes, 0, 0)
|
|
48
|
+
return date
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function nextDailyRun(executeTime, base = new Date()) {
|
|
52
|
+
const next = dateWithTime(base, executeTime)
|
|
53
|
+
if (next.getTime() <= base.getTime()) next.setDate(next.getDate() + 1)
|
|
54
|
+
return next
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function nextWeeklyRun(weekDay, executeTime, base = new Date()) {
|
|
58
|
+
const targetDay = Number(weekDay)
|
|
59
|
+
if (!Number.isInteger(targetDay) || targetDay < 0 || targetDay > 6) {
|
|
60
|
+
throw requestError('weekDay must be between 0 and 6')
|
|
61
|
+
}
|
|
62
|
+
const next = dateWithTime(base, executeTime)
|
|
63
|
+
let daysToAdd = (targetDay - next.getDay() + 7) % 7
|
|
64
|
+
if (daysToAdd === 0 && next.getTime() <= base.getTime()) daysToAdd = 7
|
|
65
|
+
next.setDate(next.getDate() + daysToAdd)
|
|
66
|
+
return next
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function monthlyCandidate(year, month, monthDay, executeTime) {
|
|
70
|
+
const targetDay = Number(monthDay)
|
|
71
|
+
if (!Number.isInteger(targetDay) || targetDay < 1 || targetDay > 31) {
|
|
72
|
+
throw requestError('monthDay must be between 1 and 31')
|
|
73
|
+
}
|
|
74
|
+
const [hours, minutes] = parseExecuteTime(executeTime).split(':').map(Number)
|
|
75
|
+
const lastDay = new Date(year, month + 1, 0).getDate()
|
|
76
|
+
return new Date(year, month, Math.min(targetDay, lastDay), hours, minutes, 0, 0)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function nextMonthlyRun(monthDay, executeTime, base = new Date()) {
|
|
80
|
+
let next = monthlyCandidate(base.getFullYear(), base.getMonth(), monthDay, executeTime)
|
|
81
|
+
if (next.getTime() <= base.getTime()) {
|
|
82
|
+
next = monthlyCandidate(base.getFullYear(), base.getMonth() + 1, monthDay, executeTime)
|
|
83
|
+
}
|
|
84
|
+
return next
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseCronField(field, min, max) {
|
|
88
|
+
if (field === '*') return { any: true, values: [] }
|
|
89
|
+
const values = new Set()
|
|
90
|
+
for (const part of field.split(',')) {
|
|
91
|
+
if (/^\*\/\d+$/.test(part)) {
|
|
92
|
+
const step = Number(part.slice(2))
|
|
93
|
+
for (let value = min; value <= max; value += step) values.add(value)
|
|
94
|
+
} else if (/^\d+-\d+$/.test(part)) {
|
|
95
|
+
const [start, end] = part.split('-').map(Number)
|
|
96
|
+
for (let value = Math.max(start, min); value <= Math.min(end, max); value += 1) values.add(value)
|
|
97
|
+
} else if (/^\d+$/.test(part)) {
|
|
98
|
+
const value = Number(part)
|
|
99
|
+
if (value >= min && value <= max) values.add(value)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { any: false, values: [...values] }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function cronMatches(date, cronExpression) {
|
|
106
|
+
const fields = String(cronExpression || '').trim().split(/\s+/)
|
|
107
|
+
if (fields.length !== 5) return false
|
|
108
|
+
const checks = [
|
|
109
|
+
[date.getMinutes(), parseCronField(fields[0], 0, 59)],
|
|
110
|
+
[date.getHours(), parseCronField(fields[1], 0, 23)],
|
|
111
|
+
[date.getDate(), parseCronField(fields[2], 1, 31)],
|
|
112
|
+
[date.getMonth() + 1, parseCronField(fields[3], 1, 12)],
|
|
113
|
+
[date.getDay(), parseCronField(fields[4], 0, 6)],
|
|
114
|
+
]
|
|
115
|
+
return checks.every(([value, rule]) => rule.any || rule.values.includes(value))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function nextCronRun(cronExpression, base = new Date()) {
|
|
119
|
+
const cursor = new Date(base.getTime() + minuteMs)
|
|
120
|
+
cursor.setSeconds(0, 0)
|
|
121
|
+
const maxChecks = 366 * 24 * 60
|
|
122
|
+
for (let index = 0; index < maxChecks; index += 1) {
|
|
123
|
+
if (cronMatches(cursor, cronExpression)) return cursor
|
|
124
|
+
cursor.setMinutes(cursor.getMinutes() + 1)
|
|
125
|
+
}
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
@@ -76,7 +76,7 @@ async function realpathNearestExistingParent(inputPath) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export async function assertSafeWorkspacePath(fullPath, context, options = {}) {
|
|
79
|
-
if (isSensitiveWorkspacePath(fullPath, context)) {
|
|
79
|
+
if (!options.allowSensitive && isSensitiveWorkspacePath(fullPath, context)) {
|
|
80
80
|
const error = new Error(`Access to sensitive path is blocked: ${toWorkspaceRelative(fullPath, context)}`)
|
|
81
81
|
error.statusCode = 403
|
|
82
82
|
throw error
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{St as t,bt as n,c as r}from"./icons-47L5YLKz.js";import{n as i}from"./react-vendor-DunfCFfp.js";import{A as a,C as o,E as s,N as c,S as l,T as u,j as d,k as f,w as p}from"./index-CqfScETb.js";var m=e(t(),1),h=i();function g(){return{name:``,label:``,description:``,systemPrompt:``,allowedTools:[`read_file`,`grep_files`],maxRuntimeMs:`1800000`,maxToolCalls:`300`,enabledAsSubagent:!0}}function _(e){return{name:e.name,label:e.label,description:e.description??``,systemPrompt:e.systemPrompt??``,allowedTools:e.allowedTools??[],maxRuntimeMs:String(e.maxRuntimeMs??18e5),maxToolCalls:String(e.maxToolCalls??300),enabledAsSubagent:e.enabledAsSubagent}}function v(e){return{name:e.name.trim().toLowerCase(),label:e.label.trim(),description:e.description.trim(),systemPrompt:e.systemPrompt.trim(),allowedTools:e.allowedTools,maxRuntimeMs:Number(e.maxRuntimeMs||18e5),maxToolCalls:Number(e.maxToolCalls||300),enabledAsSubagent:e.enabledAsSubagent}}function y(e){return!!(e.name.trim()&&e.label.trim()&&e.allowedTools.length>0)}async function b(e,t){let n=await fetch(e,{...t,headers:{"content-type":`application/json`,...t?.headers}}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`请求失败`);return r}function x(){let[e,t]=(0,m.useState)([]),[i,x]=(0,m.useState)([]),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(null),[E,D]=(0,m.useState)(()=>g()),[O,k]=(0,m.useState)(!1),[A,j]=(0,m.useState)(``),[M,N]=(0,m.useState)(!1),[P,F]=(0,m.useState)(),[I,L]=(0,m.useState)(`off`),[R,z]=(0,m.useState)(``);async function B(){let[e,n]=await Promise.all([b(`/api/agent-profiles`),b(`/api/agent-profiles/available-tools`)]);t(e.agents),x(n.tools)}(0,m.useEffect)(()=>{let e=!1;async function n(){try{let[n,r]=await Promise.all([b(`/api/agent-profiles`),b(`/api/agent-profiles/available-tools`)]);if(e)return;t(n.agents),x(r.tools)}catch(t){e||z(t instanceof Error?t.message:c(`requestFailed`))}}return n(),()=>{e=!0}},[]),(0,m.useEffect)(()=>{let e=!1;async function t(){try{let t=await p(),n=await o(t),r=await u(t),i=r.model??await s(t)??n[0];if(e)return;F(i),L(r.thinkingLevel??l(i))}catch{}}return t(),()=>{e=!0}},[]);let V=(0,m.useMemo)(()=>e.find(e=>e.id===w)??null,[e,w]);function H(e,t){D(n=>({...n,[e]:t}))}function U(e){D(t=>({...t,allowedTools:t.allowedTools.includes(e)?t.allowedTools.filter(t=>t!==e):[...t.allowedTools,e]}))}function W(){T(null),D(g()),j(``),z(``),C(!0)}function G(e){T(e.id),D(_(e)),j(``),z(``),C(!0)}function K(){O||M||(C(!1),T(null),D(g()),j(``))}async function q(){let e=A.trim();if(!e){z(c(`aiFillAgentInputRequired`));return}if(!P){z(c(`aiFillAgentNoModel`));return}N(!0),z(``);try{let t=await b(`/api/agent-profiles/ai-fill`,{method:`POST`,body:JSON.stringify({instruction:e,model:P,thinkingLevel:I})});D(e=>({...e,name:t.agent.name,label:t.agent.label,description:t.agent.description,systemPrompt:t.agent.systemPrompt}))}catch(e){z(e instanceof Error?e.message:c(`aiFillAgentFailed`))}finally{N(!1)}}async function J(){if(y(E)){k(!0),z(``);try{let e=v(E);w?await b(`/api/agent-profiles/${encodeURIComponent(w)}`,{method:`PATCH`,body:JSON.stringify(e)}):await b(`/api/agent-profiles`,{method:`POST`,body:JSON.stringify(e)}),K(),await B()}catch(e){z(e instanceof Error?e.message:c(`requestFailed`))}finally{k(!1)}}}async function Y(e){if(!(e.builtin||e.readonly)&&await f({description:c(`confirmDeleteAgent`),confirmLabel:c(`confirmDelete`),cancelLabel:c(`cancel`),variant:`destructive`})){z(``);try{await b(`/api/agent-profiles/${encodeURIComponent(e.id)}`,{method:`DELETE`}),await B()}catch(e){z(e instanceof Error?e.message:c(`requestFailed`))}}}return(0,h.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-hidden bg-background`,children:[(0,h.jsx)(`div`,{className:`border-b border-border px-6 py-5`,children:(0,h.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,h.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,h.jsx)(`div`,{className:`flex size-10 items-center justify-center rounded-2xl bg-primary/10 text-primary`,children:(0,h.jsx)(n,{className:`size-5`})}),(0,h.jsx)(`div`,{children:(0,h.jsxs)(`h1`,{className:`inline-flex items-center gap-1.5 text-lg font-semibold text-foreground`,children:[c(`agentsTab`),(0,h.jsx)(a,{label:c(`agentsDescription`)})]})})]}),(0,h.jsx)(d,{onClick:W,children:c(`createAgent`)})]})}),(0,h.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto p-6`,children:(0,h.jsxs)(`div`,{className:`mx-auto max-w-5xl space-y-5`,children:[R&&!S?(0,h.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:R}):null,(0,h.jsx)(`div`,{className:`grid gap-4 md:grid-cols-2`,children:e.map(e=>(0,h.jsxs)(`div`,{className:`rounded-xl border border-border bg-card p-4`,children:[(0,h.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,h.jsxs)(`div`,{className:`min-w-0`,children:[(0,h.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,h.jsx)(`h3`,{className:`truncate text-sm font-medium text-foreground/90`,children:e.label}),e.builtin?(0,h.jsx)(`span`,{className:`rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary`,children:c(`builtinAgent`)}):null,e.enabledAsSubagent?(0,h.jsx)(`span`,{className:`rounded-full bg-emerald-500/10 px-2 py-0.5 text-xs text-emerald-700`,children:c(`enabledAsSubagent`)}):null]}),(0,h.jsx)(`p`,{className:`mt-1 font-mono text-xs text-muted-foreground`,children:e.name}),e.source&&!e.builtin?(0,h.jsxs)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:[e.source,e.relativePath?` · ${e.relativePath}`:``]}):null,(0,h.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:e.description||c(`noDescription`)})]}),(0,h.jsxs)(`div`,{className:`flex shrink-0 gap-1`,children:[(0,h.jsx)(d,{variant:`outline`,size:`sm`,disabled:e.builtin||e.readonly,onClick:()=>G(e),children:c(`editTask`)}),(0,h.jsx)(d,{variant:`destructive`,size:`sm`,disabled:e.builtin||e.readonly,onClick:()=>void Y(e),children:c(`delete`)})]})]}),(0,h.jsx)(`div`,{className:`mt-3 flex flex-wrap gap-1`,children:e.allowedTools.map(e=>(0,h.jsx)(`span`,{className:`rounded-full bg-muted px-2 py-0.5 font-mono text-xs text-muted-foreground`,children:e},e))}),(0,h.jsxs)(`div`,{className:`mt-3 grid gap-2 border-t border-border pt-3 text-xs text-muted-foreground sm:grid-cols-2`,children:[(0,h.jsxs)(`span`,{children:[c(`maxRuntimeMs`),e.maxRuntimeMs??`-`]}),(0,h.jsxs)(`span`,{children:[c(`maxToolCalls`),e.maxToolCalls??`-`]})]})]},e.id))})]})}),S?(0,h.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4`,onMouseDown:e=>{e.target===e.currentTarget&&K()},children:(0,h.jsxs)(`div`,{className:`flex max-h-[90vh] w-full max-w-3xl flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-quickforge`,onMouseDown:e=>e.stopPropagation(),children:[(0,h.jsxs)(`div`,{className:`shrink-0 border-b border-border px-5 py-4`,children:[(0,h.jsx)(`h2`,{className:`text-base font-medium text-foreground`,children:c(V?`editAgent`:`createAgent`)}),V?.readonly?(0,h.jsx)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:c(`builtinAgentReadonly`)}):null]}),(0,h.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-4`,children:(0,h.jsxs)(`div`,{className:`space-y-4`,children:[(0,h.jsxs)(`div`,{className:`rounded-2xl border border-border bg-muted/20 p-3`,children:[(0,h.jsxs)(`div`,{className:`mb-2 flex items-center gap-2 text-sm font-medium text-foreground`,children:[(0,h.jsx)(r,{className:`size-4 text-primary`}),c(`aiFillAgent`),(0,h.jsx)(a,{label:c(`aiFillAgentDescription`)})]}),(0,h.jsx)(`textarea`,{className:`min-h-20 w-full resize-y rounded-xl border border-input bg-background px-3 py-2 text-sm outline-none transition-colors placeholder:text-muted-foreground/65 focus:border-ring disabled:opacity-60`,value:A,disabled:!!V?.readonly||M,onChange:e=>j(e.target.value),placeholder:c(`aiFillAgentPlaceholder`)}),(0,h.jsx)(`div`,{className:`mt-2 flex justify-end`,children:(0,h.jsxs)(d,{variant:`outline`,size:`sm`,onClick:()=>void q(),disabled:!!V?.readonly||M||!A.trim(),children:[(0,h.jsx)(r,{className:`mr-1 size-3.5`}),c(M?`aiFillAgentLoading`:`aiFillAgent`)]})})]}),(0,h.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`agentName`),(0,h.jsx)(`input`,{className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.name,disabled:!!V?.readonly,onChange:e=>H(`name`,e.target.value),placeholder:`reviewer`})]}),(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`agentLabel`),(0,h.jsx)(`input`,{className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.label,disabled:!!V?.readonly,onChange:e=>H(`label`,e.target.value),placeholder:c(`agentLabelPlaceholder`)})]})]}),(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`agentDescription`),(0,h.jsx)(`input`,{className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.description,disabled:!!V?.readonly,onChange:e=>H(`description`,e.target.value)})]}),(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`agentSystemPrompt`),(0,h.jsx)(`textarea`,{className:`mt-1 min-h-36 w-full resize-y rounded-xl border border-input bg-background px-3 py-2 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.systemPrompt,disabled:!!V?.readonly,onChange:e=>H(`systemPrompt`,e.target.value)})]}),(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`div`,{className:`mb-2 text-sm font-medium text-foreground`,children:c(`allowedTools`)}),(0,h.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2`,children:i.map(e=>(0,h.jsxs)(`label`,{className:`flex items-start gap-2 rounded-xl border border-border bg-muted/20 p-3 text-sm disabled:opacity-60`,children:[(0,h.jsx)(`input`,{type:`checkbox`,className:`mt-1`,disabled:!!V?.readonly,checked:E.allowedTools.includes(e.name),onChange:()=>U(e.name)}),(0,h.jsxs)(`span`,{children:[(0,h.jsx)(`span`,{className:`font-medium text-foreground`,children:e.label}),(0,h.jsx)(`span`,{className:`ml-2 font-mono text-xs text-muted-foreground`,children:e.name}),e.riskLevel===`dangerous`?(0,h.jsx)(`span`,{className:`ml-2 rounded-full bg-amber-500/10 px-2 py-0.5 text-xs text-amber-700`,children:c(`highRiskTool`)}):null,(0,h.jsx)(`span`,{className:`mt-1 block text-xs text-muted-foreground`,children:e.description})]})]},e.name))})]}),(0,h.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`maxRuntimeMs`),(0,h.jsx)(`input`,{type:`number`,className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.maxRuntimeMs,disabled:!!V?.readonly,onChange:e=>H(`maxRuntimeMs`,e.target.value)})]}),(0,h.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[c(`maxToolCalls`),(0,h.jsx)(`input`,{type:`number`,className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring disabled:opacity-60`,value:E.maxToolCalls,disabled:!!V?.readonly,onChange:e=>H(`maxToolCalls`,e.target.value)})]})]}),(0,h.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-foreground`,children:[(0,h.jsx)(`input`,{type:`checkbox`,checked:E.enabledAsSubagent,disabled:!!V?.readonly,onChange:e=>H(`enabledAsSubagent`,e.target.checked)}),c(`enabledAsSubagent`)]}),R?(0,h.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:R}):null]})}),(0,h.jsx)(`div`,{className:`shrink-0 border-t border-border px-5 py-4`,children:(0,h.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,h.jsx)(d,{variant:`outline`,onClick:K,disabled:O||M,children:c(`cancel`)}),(0,h.jsx)(d,{onClick:J,disabled:O||M||!!V?.readonly||!y(E),children:c(`save`)})]})})]})}):null]})}export{x as AgentProfilesPage};
|