@shawnstack/quickforge 1.6.3 → 1.6.7
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-XJdWmkQb.js +1 -0
- package/dist/assets/{ChatPanelHost-DBCQpcp1.js → ChatPanelHost-BrUHIzBw.js} +68 -68
- package/dist/assets/{PluginsPage-DRbQLXc6.js → PluginsPage-DDxjlhiK.js} +1 -1
- package/dist/assets/ScheduledTasksPage-Bw-pSpbv.js +2 -0
- package/dist/assets/{SettingsWorkspacePage-B3KByRv9.js → SettingsWorkspacePage-B_7o3noo.js} +334 -334
- package/dist/assets/SharedConversationPage-B5DPQla3.js +1 -0
- package/dist/assets/TerminalDock-CVObjSM6.js +2 -0
- package/dist/assets/WorkspaceInspector-Dk5887WR.js +3 -0
- package/dist/assets/WorkspaceReaderDialog-D-_BBvud.js +1 -0
- package/dist/assets/diff-line-counts-DagL0jQr.js +10 -0
- package/dist/assets/icons-DHoaB5uq.js +1 -0
- package/dist/assets/index-C77QCHE9.css +3 -0
- package/dist/assets/index-DeUvsbzW.js +63 -0
- package/dist/assets/{mcp-servers-dialog-1Y9X80tB.js → mcp-servers-dialog-CJ4HKWVZ.js} +2 -2
- package/dist/assets/{monaco-BKEc9mhB.js → monaco-FCb94ino.js} +1 -1
- package/dist/assets/{react-vendor-EwqQ8x7m.js → react-vendor-BR9MG2D-.js} +1 -1
- package/dist/assets/skills-dialog-CmCLl7K_.js +1 -0
- package/dist/assets/{useAppTheme-CG1_MfzA.js → useAppTheme-BwZ5OEf3.js} +1 -1
- package/dist/assets/vscode-C_7wk1WI.svg +41 -0
- package/dist/index.html +6 -6
- package/package.json +1 -1
- package/server/index.mjs +1 -1
- package/server/routes/project.mjs +27 -1
- package/server/routes/workspace.mjs +351 -0
- package/server/utils/platform.mjs +108 -0
- package/dist/assets/AgentProfilesPage-BTWTENpJ.js +0 -1
- package/dist/assets/ScheduledTasksPage-_Te96TTL.js +0 -2
- package/dist/assets/SharedConversationPage-CJr-rzR4.js +0 -1
- package/dist/assets/TerminalDock-DSsVoL0f.js +0 -2
- package/dist/assets/WorkspaceInspector-HuIqe-Y6.js +0 -3
- package/dist/assets/WorkspaceReaderDialog-au2UL_Ti.js +0 -1
- package/dist/assets/diff-line-counts-CnZu37tM.js +0 -10
- package/dist/assets/icons-B0ihJZtt.js +0 -1
- package/dist/assets/index-CTo6RkZO.js +0 -63
- package/dist/assets/index-hb3vYF5_.css +0 -3
- package/dist/assets/skills-dialog-vMwLkH49.js +0 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { spawn } from 'node:child_process'
|
|
4
|
+
import { streamSimple } from '@earendil-works/pi-ai'
|
|
4
5
|
import { sendJson, readJsonBody } from '../utils/response.mjs'
|
|
5
6
|
import { projectContextFromId } from '../project-config.mjs'
|
|
7
|
+
import { readStore } from '../storage.mjs'
|
|
8
|
+
import { logger } from '../utils/logger.mjs'
|
|
6
9
|
import {
|
|
7
10
|
assertSafeWorkspacePath,
|
|
8
11
|
resolveWorkspacePath,
|
|
@@ -145,6 +148,97 @@ async function currentGitBranch(workspaceRoot) {
|
|
|
145
148
|
return commit ? `HEAD ${commit}` : undefined
|
|
146
149
|
}
|
|
147
150
|
|
|
151
|
+
async function assertValidBranchName(workspaceRoot, branch) {
|
|
152
|
+
const value = typeof branch === 'string' ? branch.trim() : ''
|
|
153
|
+
if (!value || value.length > 240 || /[\0\r\n]/.test(value)) {
|
|
154
|
+
const error = new Error('Invalid branch name')
|
|
155
|
+
error.statusCode = 400
|
|
156
|
+
throw error
|
|
157
|
+
}
|
|
158
|
+
const result = await git(['check-ref-format', '--branch', value], workspaceRoot, { allowFailure: true })
|
|
159
|
+
if (result.code !== 0) {
|
|
160
|
+
const error = new Error('Invalid branch name')
|
|
161
|
+
error.statusCode = 400
|
|
162
|
+
throw error
|
|
163
|
+
}
|
|
164
|
+
return value
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function branchSortKey(branch, current) {
|
|
168
|
+
return [branch.name === current ? '0' : '1', branch.remote ? '1' : '0', branch.name.toLowerCase()].join(':')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function listGitBranches(context) {
|
|
172
|
+
if (!(await isGitRepository(context.workspaceRoot))) return { isGitRepository: false, branches: [] }
|
|
173
|
+
const current = await currentGitBranch(context.workspaceRoot)
|
|
174
|
+
const result = await git([
|
|
175
|
+
'for-each-ref',
|
|
176
|
+
'--format=%(refname)%1f%(refname:short)%1f%(objectname:short)%1f%(committerdate:iso8601-strict)%1f%(upstream:short)',
|
|
177
|
+
'refs/heads',
|
|
178
|
+
'refs/remotes',
|
|
179
|
+
], context.workspaceRoot)
|
|
180
|
+
const branches = result.stdout.toString('utf8').split('\n')
|
|
181
|
+
.map((line) => line.trim())
|
|
182
|
+
.filter(Boolean)
|
|
183
|
+
.map((line) => {
|
|
184
|
+
const [refname = '', name = '', commit = '', lastCommitAt = '', upstream = ''] = line.split('\x1f')
|
|
185
|
+
const remote = refname.startsWith('refs/remotes/')
|
|
186
|
+
return {
|
|
187
|
+
name,
|
|
188
|
+
current: name === current,
|
|
189
|
+
remote,
|
|
190
|
+
upstream: upstream || undefined,
|
|
191
|
+
commit: commit || undefined,
|
|
192
|
+
lastCommitAt: lastCommitAt || undefined,
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
.filter((branch) => branch.name && !branch.name.endsWith('/HEAD'))
|
|
196
|
+
.sort((left, right) => branchSortKey(left, current).localeCompare(branchSortKey(right, current)))
|
|
197
|
+
return { isGitRepository: true, current, branches }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function parseGitDecorations(raw) {
|
|
201
|
+
if (!raw) return []
|
|
202
|
+
return raw.split(', ')
|
|
203
|
+
.map((entry) => entry.trim())
|
|
204
|
+
.filter(Boolean)
|
|
205
|
+
.map((entry) => {
|
|
206
|
+
if (entry === 'HEAD') return { name: 'HEAD', type: 'head' }
|
|
207
|
+
if (entry.startsWith('HEAD -> ')) return { name: entry.slice('HEAD -> '.length), type: 'branch' }
|
|
208
|
+
if (entry.startsWith('tag: ')) return { name: entry.slice('tag: '.length), type: 'tag' }
|
|
209
|
+
if (entry.includes('/')) return { name: entry, type: 'remote' }
|
|
210
|
+
return { name: entry, type: 'branch' }
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function listGitLog(context) {
|
|
215
|
+
if (!(await isGitRepository(context.workspaceRoot))) return { isGitRepository: false, commits: [] }
|
|
216
|
+
const result = await git([
|
|
217
|
+
'log',
|
|
218
|
+
'--all',
|
|
219
|
+
'--date=iso-strict',
|
|
220
|
+
'--max-count=200',
|
|
221
|
+
'--format=%H%x1f%h%x1f%P%x1f%an%x1f%aI%x1f%D%x1f%s%x1e',
|
|
222
|
+
], context.workspaceRoot, { allowFailure: true })
|
|
223
|
+
if (result.code !== 0) return { isGitRepository: true, commits: [] }
|
|
224
|
+
const commits = result.stdout.toString('utf8').split('\x1e')
|
|
225
|
+
.map((record) => record.trim())
|
|
226
|
+
.filter(Boolean)
|
|
227
|
+
.map((record) => {
|
|
228
|
+
const [hash = '', shortHash = '', parents = '', author = '', date = '', decorations = '', subject = ''] = record.split('\x1f')
|
|
229
|
+
return {
|
|
230
|
+
hash,
|
|
231
|
+
shortHash,
|
|
232
|
+
parents: parents ? parents.split(' ').filter(Boolean) : [],
|
|
233
|
+
author,
|
|
234
|
+
date,
|
|
235
|
+
subject,
|
|
236
|
+
decorations: parseGitDecorations(decorations),
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
return { isGitRepository: true, commits }
|
|
240
|
+
}
|
|
241
|
+
|
|
148
242
|
function countGitStatus(files) {
|
|
149
243
|
return files.reduce((counts, file) => {
|
|
150
244
|
if (file.conflict) counts.conflicts += 1
|
|
@@ -231,6 +325,150 @@ async function listGitStatus(context) {
|
|
|
231
325
|
}
|
|
232
326
|
}
|
|
233
327
|
|
|
328
|
+
async function assertGitRepository(context) {
|
|
329
|
+
if (await isGitRepository(context.workspaceRoot)) return
|
|
330
|
+
const error = new Error('Not a Git repository')
|
|
331
|
+
error.statusCode = 400
|
|
332
|
+
throw error
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function normalizeCommitMessage(value) {
|
|
336
|
+
const raw = String(value || '').trim()
|
|
337
|
+
if (!raw) {
|
|
338
|
+
const error = new Error('Commit message is required')
|
|
339
|
+
error.statusCode = 400
|
|
340
|
+
throw error
|
|
341
|
+
}
|
|
342
|
+
return raw.replace(/\r\n/g, '\n').replace(/\r/g, '\n').slice(0, 4000)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function hasStagedChanges(context) {
|
|
346
|
+
const result = await git(['diff', '--cached', '--quiet'], context.workspaceRoot, { allowFailure: true })
|
|
347
|
+
return result.code === 1
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async function commitGitChanges(context, message, includeUnstaged) {
|
|
351
|
+
await assertGitRepository(context)
|
|
352
|
+
const commitMessage = normalizeCommitMessage(message)
|
|
353
|
+
if (includeUnstaged) await git(['add', '-A'], context.workspaceRoot)
|
|
354
|
+
if (!(await hasStagedChanges(context))) {
|
|
355
|
+
const error = new Error('No staged changes to commit')
|
|
356
|
+
error.statusCode = 400
|
|
357
|
+
throw error
|
|
358
|
+
}
|
|
359
|
+
await git(['commit', '-m', commitMessage], context.workspaceRoot)
|
|
360
|
+
return listGitStatus(context)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function pushGitBranch(context) {
|
|
364
|
+
await assertGitRepository(context)
|
|
365
|
+
await git(['push'], context.workspaceRoot)
|
|
366
|
+
return listGitStatus(context)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function getApiKey(provider) {
|
|
370
|
+
try {
|
|
371
|
+
const keys = await readStore('provider-keys')
|
|
372
|
+
return keys?.[provider] || undefined
|
|
373
|
+
} catch {
|
|
374
|
+
return undefined
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function trimForPrompt(text, max = 14000) {
|
|
379
|
+
const raw = String(text || '').trim()
|
|
380
|
+
if (raw.length <= max) return raw
|
|
381
|
+
return `${raw.slice(0, max)}\n\n[Diff truncated]`
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function normalizeAiCommitMessage(text) {
|
|
385
|
+
const raw = String(text || '').trim()
|
|
386
|
+
.replace(/^```(?:text)?/i, '')
|
|
387
|
+
.replace(/```$/i, '')
|
|
388
|
+
.trim()
|
|
389
|
+
const lines = raw.split('\n').map((line) => line.trimEnd())
|
|
390
|
+
while (lines.length && !lines[0].trim()) lines.shift()
|
|
391
|
+
while (lines.length && !lines[lines.length - 1].trim()) lines.pop()
|
|
392
|
+
const message = lines.join('\n').trim().slice(0, 2000)
|
|
393
|
+
if (!message) {
|
|
394
|
+
const error = new Error('AI did not generate a commit message')
|
|
395
|
+
error.statusCode = 502
|
|
396
|
+
throw error
|
|
397
|
+
}
|
|
398
|
+
return message
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
async function generateGitCommitMessage(context, model, thinkingLevel = 'off') {
|
|
402
|
+
await assertGitRepository(context)
|
|
403
|
+
if (!model) {
|
|
404
|
+
const error = new Error('Please configure a default model first')
|
|
405
|
+
error.statusCode = 400
|
|
406
|
+
throw error
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const status = await listGitStatus(context)
|
|
410
|
+
if (!status.counts?.total) {
|
|
411
|
+
const error = new Error('No Git changes to summarize')
|
|
412
|
+
error.statusCode = 400
|
|
413
|
+
throw error
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const cachedStat = (await git(['diff', '--cached', '--stat'], context.workspaceRoot, { allowFailure: true })).stdout.toString('utf8')
|
|
417
|
+
const cachedDiff = (await git(['diff', '--cached'], context.workspaceRoot, { allowFailure: true })).stdout.toString('utf8')
|
|
418
|
+
const worktreeStat = (await git(['diff', '--stat'], context.workspaceRoot, { allowFailure: true })).stdout.toString('utf8')
|
|
419
|
+
const worktreeDiff = (await git(['diff'], context.workspaceRoot, { allowFailure: true })).stdout.toString('utf8')
|
|
420
|
+
const files = status.files.map((file) => `- ${file.status}${file.staged ? ' staged' : ''}${file.unstaged ? ' unstaged' : ''}: ${file.oldPath ? `${file.oldPath} -> ` : ''}${file.path}`).join('\n')
|
|
421
|
+
const systemPrompt = `You generate Git commit messages.
|
|
422
|
+
Return only the commit message, no Markdown, no explanation.
|
|
423
|
+
Use Conventional Commit style when possible, for example: feat: add git tools summary.
|
|
424
|
+
Keep the subject under 72 characters. Add a short body only if it is useful.`
|
|
425
|
+
const userPrompt = `Current branch: ${status.branch || 'unknown'}
|
|
426
|
+
|
|
427
|
+
Changed files:
|
|
428
|
+
${files}
|
|
429
|
+
|
|
430
|
+
Staged diff stat:
|
|
431
|
+
${cachedStat || '(none)'}
|
|
432
|
+
|
|
433
|
+
Staged diff:
|
|
434
|
+
${trimForPrompt(cachedDiff)}
|
|
435
|
+
|
|
436
|
+
Unstaged diff stat:
|
|
437
|
+
${worktreeStat || '(none)'}
|
|
438
|
+
|
|
439
|
+
Unstaged diff:
|
|
440
|
+
${trimForPrompt(worktreeDiff)}`
|
|
441
|
+
|
|
442
|
+
try {
|
|
443
|
+
const stream = streamSimple(
|
|
444
|
+
model,
|
|
445
|
+
{
|
|
446
|
+
systemPrompt,
|
|
447
|
+
messages: [{ role: 'user', content: userPrompt, timestamp: Date.now() }],
|
|
448
|
+
tools: [],
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
apiKey: await getApiKey(model.provider),
|
|
452
|
+
maxTokens: 500,
|
|
453
|
+
temperature: 0,
|
|
454
|
+
reasoning: thinkingLevel === 'off' ? undefined : thinkingLevel,
|
|
455
|
+
maxRetryDelayMs: 60000,
|
|
456
|
+
},
|
|
457
|
+
)
|
|
458
|
+
const message = await stream.result()
|
|
459
|
+
const content = Array.isArray(message.content)
|
|
460
|
+
? message.content.filter((block) => block.type === 'text').map((block) => block.text ?? '').join('\n')
|
|
461
|
+
: ''
|
|
462
|
+
return normalizeAiCommitMessage(content)
|
|
463
|
+
} catch (error) {
|
|
464
|
+
if (error?.statusCode) throw error
|
|
465
|
+
logger.warn('AI commit message generation failed:', error?.message || error)
|
|
466
|
+
const wrapped = new Error(`AI generation failed: ${error?.message || 'check model configuration and API key'}`)
|
|
467
|
+
wrapped.statusCode = 502
|
|
468
|
+
throw wrapped
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
234
472
|
async function readGitFile(workspaceRoot, ref, relativePath) {
|
|
235
473
|
const result = await git(['show', `${ref}:${relativePath}`], workspaceRoot, { allowFailure: true })
|
|
236
474
|
return result.code === 0 ? result.stdout.toString('utf8') : ''
|
|
@@ -407,6 +645,54 @@ async function handleGitStatus(req, res, url) {
|
|
|
407
645
|
sendJson(res, 200, await listGitStatus(context))
|
|
408
646
|
}
|
|
409
647
|
|
|
648
|
+
async function handleGitBranches(req, res, url) {
|
|
649
|
+
const context = await projectContextFromUrl(url)
|
|
650
|
+
sendJson(res, 200, await listGitBranches(context))
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
async function handleGitLog(req, res, url) {
|
|
654
|
+
const context = await projectContextFromUrl(url)
|
|
655
|
+
sendJson(res, 200, await listGitLog(context))
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
async function handleGitCheckout(req, res) {
|
|
659
|
+
const body = await readJsonBody(req, 16 * 1024)
|
|
660
|
+
const projectId = typeof body?.projectId === 'string' ? body.projectId : ''
|
|
661
|
+
if (!projectId) {
|
|
662
|
+
const error = new Error('projectId is required')
|
|
663
|
+
error.statusCode = 400
|
|
664
|
+
throw error
|
|
665
|
+
}
|
|
666
|
+
const context = await projectContextFromId(projectId)
|
|
667
|
+
if (!(await isGitRepository(context.workspaceRoot))) {
|
|
668
|
+
const error = new Error('This project is not a Git repository')
|
|
669
|
+
error.statusCode = 400
|
|
670
|
+
throw error
|
|
671
|
+
}
|
|
672
|
+
const branch = await assertValidBranchName(context.workspaceRoot, body?.branch)
|
|
673
|
+
await git(['checkout', branch], context.workspaceRoot)
|
|
674
|
+
sendJson(res, 200, await listGitStatus(context))
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
async function handleGitCreateBranch(req, res) {
|
|
678
|
+
const body = await readJsonBody(req, 16 * 1024)
|
|
679
|
+
const projectId = typeof body?.projectId === 'string' ? body.projectId : ''
|
|
680
|
+
if (!projectId) {
|
|
681
|
+
const error = new Error('projectId is required')
|
|
682
|
+
error.statusCode = 400
|
|
683
|
+
throw error
|
|
684
|
+
}
|
|
685
|
+
const context = await projectContextFromId(projectId)
|
|
686
|
+
if (!(await isGitRepository(context.workspaceRoot))) {
|
|
687
|
+
const error = new Error('This project is not a Git repository')
|
|
688
|
+
error.statusCode = 400
|
|
689
|
+
throw error
|
|
690
|
+
}
|
|
691
|
+
const branch = await assertValidBranchName(context.workspaceRoot, body?.branch)
|
|
692
|
+
await git(['checkout', '-b', branch], context.workspaceRoot)
|
|
693
|
+
sendJson(res, 200, await listGitStatus(context))
|
|
694
|
+
}
|
|
695
|
+
|
|
410
696
|
async function handleGitFileDiff(req, res, url) {
|
|
411
697
|
const context = await projectContextFromUrl(url)
|
|
412
698
|
const relativePath = url.searchParams.get('path') || ''
|
|
@@ -453,6 +739,39 @@ async function handleGitFileDiff(req, res, url) {
|
|
|
453
739
|
})
|
|
454
740
|
}
|
|
455
741
|
|
|
742
|
+
async function contextFromGitBody(req) {
|
|
743
|
+
const body = await readJsonBody(req, 1024 * 1024)
|
|
744
|
+
const projectId = typeof body?.projectId === 'string' ? body.projectId : ''
|
|
745
|
+
if (!projectId) {
|
|
746
|
+
const error = new Error('projectId is required')
|
|
747
|
+
error.statusCode = 400
|
|
748
|
+
throw error
|
|
749
|
+
}
|
|
750
|
+
return { context: await projectContextFromId(projectId), body }
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
async function handleGitGenerateCommitMessage(req, res) {
|
|
754
|
+
const { context, body } = await contextFromGitBody(req)
|
|
755
|
+
const message = await generateGitCommitMessage(context, body?.model, body?.thinkingLevel)
|
|
756
|
+
sendJson(res, 200, { message })
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
async function handleGitCommit(req, res) {
|
|
760
|
+
const { context, body } = await contextFromGitBody(req)
|
|
761
|
+
sendJson(res, 200, await commitGitChanges(context, body?.message, Boolean(body?.includeUnstaged)))
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
async function handleGitPush(req, res) {
|
|
765
|
+
const { context } = await contextFromGitBody(req)
|
|
766
|
+
sendJson(res, 200, await pushGitBranch(context))
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
async function handleGitCommitAndPush(req, res) {
|
|
770
|
+
const { context, body } = await contextFromGitBody(req)
|
|
771
|
+
await commitGitChanges(context, body?.message, Boolean(body?.includeUnstaged))
|
|
772
|
+
sendJson(res, 200, await pushGitBranch(context))
|
|
773
|
+
}
|
|
774
|
+
|
|
456
775
|
export async function handleWorkspaceApi(req, res, url) {
|
|
457
776
|
if (req.method === 'GET' && url.pathname === '/api/workspace/tree') {
|
|
458
777
|
await handleWorkspaceTree(req, res, url)
|
|
@@ -481,10 +800,42 @@ export async function handleGitApi(req, res, url) {
|
|
|
481
800
|
await handleGitStatus(req, res, url)
|
|
482
801
|
return
|
|
483
802
|
}
|
|
803
|
+
if (req.method === 'GET' && url.pathname === '/api/git/branches') {
|
|
804
|
+
await handleGitBranches(req, res, url)
|
|
805
|
+
return
|
|
806
|
+
}
|
|
807
|
+
if (req.method === 'GET' && url.pathname === '/api/git/log') {
|
|
808
|
+
await handleGitLog(req, res, url)
|
|
809
|
+
return
|
|
810
|
+
}
|
|
811
|
+
if (req.method === 'POST' && url.pathname === '/api/git/checkout') {
|
|
812
|
+
await handleGitCheckout(req, res)
|
|
813
|
+
return
|
|
814
|
+
}
|
|
815
|
+
if (req.method === 'POST' && url.pathname === '/api/git/create-branch') {
|
|
816
|
+
await handleGitCreateBranch(req, res)
|
|
817
|
+
return
|
|
818
|
+
}
|
|
484
819
|
if (req.method === 'GET' && url.pathname === '/api/git/file-diff') {
|
|
485
820
|
await handleGitFileDiff(req, res, url)
|
|
486
821
|
return
|
|
487
822
|
}
|
|
823
|
+
if (req.method === 'POST' && url.pathname === '/api/git/generate-commit-message') {
|
|
824
|
+
await handleGitGenerateCommitMessage(req, res)
|
|
825
|
+
return
|
|
826
|
+
}
|
|
827
|
+
if (req.method === 'POST' && url.pathname === '/api/git/commit') {
|
|
828
|
+
await handleGitCommit(req, res)
|
|
829
|
+
return
|
|
830
|
+
}
|
|
831
|
+
if (req.method === 'POST' && url.pathname === '/api/git/push') {
|
|
832
|
+
await handleGitPush(req, res)
|
|
833
|
+
return
|
|
834
|
+
}
|
|
835
|
+
if (req.method === 'POST' && url.pathname === '/api/git/commit-and-push') {
|
|
836
|
+
await handleGitCommitAndPush(req, res)
|
|
837
|
+
return
|
|
838
|
+
}
|
|
488
839
|
|
|
489
840
|
const error = new Error('Not found')
|
|
490
841
|
error.statusCode = 404
|
|
@@ -122,6 +122,15 @@ try {
|
|
|
122
122
|
throw error
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
async function findExistingFile(candidates) {
|
|
126
|
+
for (const candidate of candidates) {
|
|
127
|
+
if (!candidate) continue
|
|
128
|
+
const stat = await fs.stat(candidate).catch(() => null)
|
|
129
|
+
if (stat?.isFile()) return candidate
|
|
130
|
+
}
|
|
131
|
+
return undefined
|
|
132
|
+
}
|
|
133
|
+
|
|
125
134
|
export async function openPathInFileManager(targetPath) {
|
|
126
135
|
const resolved = path.resolve(String(targetPath || ''))
|
|
127
136
|
const stat = await fs.stat(resolved).catch(() => null)
|
|
@@ -151,6 +160,105 @@ export async function openPathInFileManager(targetPath) {
|
|
|
151
160
|
})
|
|
152
161
|
}
|
|
153
162
|
|
|
163
|
+
export async function openPathInVSCode(targetPath) {
|
|
164
|
+
const resolved = path.resolve(String(targetPath || ''))
|
|
165
|
+
const stat = await fs.stat(resolved).catch(() => null)
|
|
166
|
+
if (!stat || !stat.isDirectory()) {
|
|
167
|
+
const error = new Error(`Directory does not exist: ${resolved}`)
|
|
168
|
+
error.statusCode = 400
|
|
169
|
+
throw error
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let command = 'code'
|
|
173
|
+
let args = [resolved]
|
|
174
|
+
if (process.platform === 'darwin') {
|
|
175
|
+
command = 'open'
|
|
176
|
+
args = ['-a', 'Visual Studio Code', resolved]
|
|
177
|
+
} else if (process.platform === 'win32') {
|
|
178
|
+
const candidates = [
|
|
179
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, 'Programs', 'Microsoft VS Code', 'Code.exe') : undefined,
|
|
180
|
+
process.env.PROGRAMFILES ? path.join(process.env.PROGRAMFILES, 'Microsoft VS Code', 'Code.exe') : undefined,
|
|
181
|
+
process.env['PROGRAMFILES(X86)'] ? path.join(process.env['PROGRAMFILES(X86)'], 'Microsoft VS Code', 'Code.exe') : undefined,
|
|
182
|
+
].filter(Boolean)
|
|
183
|
+
const codeExecutable = await findExistingFile(candidates)
|
|
184
|
+
if (codeExecutable) {
|
|
185
|
+
command = codeExecutable
|
|
186
|
+
args = [resolved]
|
|
187
|
+
} else {
|
|
188
|
+
command = 'cmd.exe'
|
|
189
|
+
args = ['/d', '/s', '/c', 'start', '""', '/b', 'code', resolved]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await new Promise((resolve, reject) => {
|
|
194
|
+
const child = spawn(command, args, {
|
|
195
|
+
detached: true,
|
|
196
|
+
stdio: 'ignore',
|
|
197
|
+
windowsHide: true,
|
|
198
|
+
shell: false,
|
|
199
|
+
})
|
|
200
|
+
child.once('error', (error) => {
|
|
201
|
+
error.statusCode = 500
|
|
202
|
+
reject(error)
|
|
203
|
+
})
|
|
204
|
+
child.once('spawn', () => {
|
|
205
|
+
child.unref()
|
|
206
|
+
resolve()
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function openPathInIDEA(targetPath) {
|
|
212
|
+
const resolved = path.resolve(String(targetPath || ''))
|
|
213
|
+
const stat = await fs.stat(resolved).catch(() => null)
|
|
214
|
+
if (!stat || !stat.isDirectory()) {
|
|
215
|
+
const error = new Error(`Directory does not exist: ${resolved}`)
|
|
216
|
+
error.statusCode = 400
|
|
217
|
+
throw error
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
let command = 'idea'
|
|
221
|
+
let args = [resolved]
|
|
222
|
+
if (process.platform === 'darwin') {
|
|
223
|
+
command = 'open'
|
|
224
|
+
args = ['-a', 'IntelliJ IDEA', resolved]
|
|
225
|
+
} else if (process.platform === 'win32') {
|
|
226
|
+
const candidates = [
|
|
227
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, 'Programs', 'IntelliJ IDEA', 'bin', 'idea64.exe') : undefined,
|
|
228
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, 'Programs', 'IntelliJ IDEA', 'bin', 'idea.exe') : undefined,
|
|
229
|
+
process.env.PROGRAMFILES ? path.join(process.env.PROGRAMFILES, 'JetBrains', 'IntelliJ IDEA', 'bin', 'idea64.exe') : undefined,
|
|
230
|
+
process.env.PROGRAMFILES ? path.join(process.env.PROGRAMFILES, 'JetBrains', 'IntelliJ IDEA', 'bin', 'idea.exe') : undefined,
|
|
231
|
+
process.env['PROGRAMFILES(X86)'] ? path.join(process.env['PROGRAMFILES(X86)'], 'JetBrains', 'IntelliJ IDEA', 'bin', 'idea64.exe') : undefined,
|
|
232
|
+
process.env['PROGRAMFILES(X86)'] ? path.join(process.env['PROGRAMFILES(X86)'], 'JetBrains', 'IntelliJ IDEA', 'bin', 'idea.exe') : undefined,
|
|
233
|
+
].filter(Boolean)
|
|
234
|
+
const ideaExecutable = await findExistingFile(candidates)
|
|
235
|
+
if (ideaExecutable) {
|
|
236
|
+
command = ideaExecutable
|
|
237
|
+
args = [resolved]
|
|
238
|
+
} else {
|
|
239
|
+
command = 'cmd.exe'
|
|
240
|
+
args = ['/d', '/s', '/c', 'start', '""', '/b', 'idea', resolved]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
await new Promise((resolve, reject) => {
|
|
245
|
+
const child = spawn(command, args, {
|
|
246
|
+
detached: true,
|
|
247
|
+
stdio: 'ignore',
|
|
248
|
+
windowsHide: true,
|
|
249
|
+
shell: false,
|
|
250
|
+
})
|
|
251
|
+
child.once('error', (error) => {
|
|
252
|
+
error.statusCode = 500
|
|
253
|
+
reject(error)
|
|
254
|
+
})
|
|
255
|
+
child.once('spawn', () => {
|
|
256
|
+
child.unref()
|
|
257
|
+
resolve()
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
154
262
|
export function openBrowser(url) {
|
|
155
263
|
if (process.env.QUICKFORGE_NO_OPEN === '1') return
|
|
156
264
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{Et as t,Ot as n,T as r,a as i,c as a,it as o,jt as s}from"./icons-B0ihJZtt.js";import{n as c}from"./react-vendor-EwqQ8x7m.js";import{$ as l,G as u,H as d,K as f,M as p,Q as m,U as h,W as g,et as _,it as v}from"./index-CTo6RkZO.js";var y=e(s(),1),b=c();function x(){return{name:``,label:``,description:``,systemPrompt:``,allowedTools:[`read_file`,`grep_files`],maxRuntimeMs:`1800000`,maxToolCalls:`300`,enabledAsSubagent:!0}}function S(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 C(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 w(e){return!!(e.name.trim()&&e.label.trim()&&e.allowedTools.length>0)}async function T(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 E(){let[e,s]=(0,y.useState)([]),[c,E]=(0,y.useState)([]),[D,O]=(0,y.useState)(!1),[k,A]=(0,y.useState)(null),[j,M]=(0,y.useState)(()=>x()),[N,P]=(0,y.useState)(!1),[F,I]=(0,y.useState)(``),[L,R]=(0,y.useState)(!1),[z,B]=(0,y.useState)(),[V,H]=(0,y.useState)(`off`),[U,W]=(0,y.useState)(``),[G,K]=(0,y.useState)(null);async function q(){let[e,t]=await Promise.all([T(`/api/agent-profiles`),T(`/api/agent-profiles/available-tools`)]);s(e.agents),E(t.tools)}(0,y.useEffect)(()=>{let e=!1;async function t(){try{let[t,n]=await Promise.all([T(`/api/agent-profiles`),T(`/api/agent-profiles/available-tools`)]);if(e)return;s(t.agents),E(n.tools)}catch(t){e||W(t instanceof Error?t.message:v(`requestFailed`))}}return t(),()=>{e=!0}},[]),(0,y.useEffect)(()=>{let e=!1;async function t(){try{let t=await g(),n=await h(t),r=await u(t),i=r.model??await f(t)??n[0];if(e)return;B(i),H(r.thinkingLevel??d(i))}catch{}}return t(),()=>{e=!0}},[]),(0,y.useEffect)(()=>{if(!G)return;let e=()=>K(null);return window.addEventListener(`click`,e),window.addEventListener(`blur`,e),()=>{window.removeEventListener(`click`,e),window.removeEventListener(`blur`,e)}},[G]);let J=(0,y.useMemo)(()=>e.find(e=>e.id===k)??null,[e,k]);function Y(e,t){M(n=>({...n,[e]:t}))}function X(e){M(t=>({...t,allowedTools:t.allowedTools.includes(e)?t.allowedTools.filter(t=>t!==e):[...t.allowedTools,e]}))}function Z(){A(null),M(x()),I(``),W(``),O(!0)}function Q(e){A(e.id),M(S(e)),I(``),W(``),O(!0)}function $(){N||L||(O(!1),A(null),M(x()),I(``))}async function ee(){let e=F.trim();if(!e){W(v(`aiFillAgentInputRequired`));return}if(!z){W(v(`aiFillAgentNoModel`));return}R(!0),W(``);try{let t=await T(`/api/agent-profiles/ai-fill`,{method:`POST`,body:JSON.stringify({instruction:e,model:z,thinkingLevel:V})});M(e=>({...e,name:t.agent.name,label:t.agent.label,description:t.agent.description,systemPrompt:t.agent.systemPrompt}))}catch(e){W(e instanceof Error?e.message:v(`aiFillAgentFailed`))}finally{R(!1)}}async function te(){if(w(j)){P(!0),W(``);try{let e=C(j);k?await T(`/api/agent-profiles/${encodeURIComponent(k)}`,{method:`PATCH`,body:JSON.stringify(e)}):await T(`/api/agent-profiles`,{method:`POST`,body:JSON.stringify(e)}),$(),await q()}catch(e){W(e instanceof Error?e.message:v(`requestFailed`))}finally{P(!1)}}}async function ne(e){if(e.builtin||e.readonly)return;let t=!e.enabledAsSubagent,n=e.enabledAsSubagent;s(n=>n.map(n=>n.id===e.id?{...n,enabledAsSubagent:t}:n)),K(null);try{await T(`/api/agent-profiles/${encodeURIComponent(e.id)}`,{method:`PATCH`,body:JSON.stringify({enabledAsSubagent:t})})}catch(t){s(t=>t.map(t=>t.id===e.id?{...t,enabledAsSubagent:n}:t)),W(t instanceof Error?t.message:v(`requestFailed`))}}async function re(e){if(!(e.builtin||e.readonly)&&await p({description:v(`confirmDeleteAgent`),confirmLabel:v(`confirmDelete`),cancelLabel:v(`cancel`),variant:`destructive`})){W(``);try{await T(`/api/agent-profiles/${encodeURIComponent(e.id)}`,{method:`DELETE`}),await q()}catch(e){W(e instanceof Error?e.message:v(`requestFailed`))}}}return D?(0,b.jsxs)(`div`,{className:`quickforge-settings-stack`,children:[(0,b.jsx)(`div`,{className:`quickforge-settings-heading`,children:(0,b.jsxs)(`h3`,{className:`quickforge-settings-title`,children:[v(J?`editAgent`:`createAgent`),(0,b.jsx)(m,{label:J?.readonly?v(`builtinAgentReadonly`):v(`agentsDescription`)})]})}),(0,b.jsxs)(`section`,{className:`quickforge-settings-section`,"aria-label":v(J?`editAgent`:`createAgent`),children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-toolbar`,children:[(0,b.jsxs)(`button`,{className:`quickforge-settings-button quickforge-settings-button-secondary`,type:`button`,onClick:$,disabled:N||L,children:[(0,b.jsx)(n,{className:`mr-2 size-4`}),v(`back`)]}),(0,b.jsxs)(`div`,{className:`quickforge-settings-row-main`,children:[(0,b.jsx)(`div`,{className:`quickforge-settings-row-title`,children:v(J?`editAgent`:`createAgent`)}),J?.readonly?(0,b.jsx)(`div`,{className:`quickforge-settings-row-description`,children:v(`builtinAgentReadonly`)}):null]})]}),(0,b.jsx)(`div`,{className:`px-5 py-4`,children:(0,b.jsxs)(`div`,{className:`space-y-4`,children:[(0,b.jsxs)(`div`,{className:`rounded-2xl border border-border bg-muted/20 p-3`,children:[(0,b.jsxs)(`div`,{className:`mb-2 flex items-center gap-2 text-sm font-medium text-foreground`,children:[(0,b.jsx)(a,{className:`size-4 text-primary`}),v(`aiFillAgent`),(0,b.jsx)(m,{label:v(`aiFillAgentDescription`)})]}),(0,b.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:F,disabled:!!J?.readonly||L,onChange:e=>I(e.target.value),placeholder:v(`aiFillAgentPlaceholder`)}),(0,b.jsx)(`div`,{className:`mt-2 flex justify-end`,children:(0,b.jsxs)(l,{variant:`outline`,size:`sm`,onClick:()=>void ee(),disabled:!!J?.readonly||L||!F.trim(),children:[(0,b.jsx)(a,{className:`mr-1 size-3.5`}),v(L?`aiFillAgentLoading`:`aiFillAgent`)]})})]}),(0,b.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`agentName`),(0,b.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:j.name,disabled:!!J?.readonly,onChange:e=>Y(`name`,e.target.value),placeholder:`reviewer`})]}),(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`agentLabel`),(0,b.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:j.label,disabled:!!J?.readonly,onChange:e=>Y(`label`,e.target.value),placeholder:v(`agentLabelPlaceholder`)})]})]}),(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`agentDescription`),(0,b.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:j.description,disabled:!!J?.readonly,onChange:e=>Y(`description`,e.target.value)})]}),(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`agentSystemPrompt`),(0,b.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:j.systemPrompt,disabled:!!J?.readonly,onChange:e=>Y(`systemPrompt`,e.target.value)})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`div`,{className:`mb-2 text-sm font-medium text-foreground`,children:v(`allowedTools`)}),(0,b.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2`,children:c.map(e=>(0,b.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,b.jsx)(`input`,{type:`checkbox`,className:`mt-1`,disabled:!!J?.readonly,checked:j.allowedTools.includes(e.name),onChange:()=>X(e.name)}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`span`,{className:`font-medium text-foreground`,children:e.label}),(0,b.jsx)(`span`,{className:`ml-2 font-mono text-xs text-muted-foreground`,children:e.name}),e.riskLevel===`dangerous`?(0,b.jsx)(`span`,{className:`ml-2 rounded-full bg-amber-500/10 px-2 py-0.5 text-xs text-amber-700`,children:v(`highRiskTool`)}):null,(0,b.jsx)(`span`,{className:`mt-1 block text-xs text-muted-foreground`,children:e.description})]})]},e.name))})]}),(0,b.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`maxRuntimeMs`),(0,b.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:j.maxRuntimeMs,disabled:!!J?.readonly,onChange:e=>Y(`maxRuntimeMs`,e.target.value)})]}),(0,b.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[v(`maxToolCalls`),(0,b.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:j.maxToolCalls,disabled:!!J?.readonly,onChange:e=>Y(`maxToolCalls`,e.target.value)})]})]}),(0,b.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-foreground`,children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:j.enabledAsSubagent,disabled:!!J?.readonly,onChange:e=>Y(`enabledAsSubagent`,e.target.checked)}),v(`enabledAsSubagent`)]}),U?(0,b.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:U}):null]})}),(0,b.jsxs)(`div`,{className:`quickforge-settings-divider flex justify-end gap-2 px-5 py-4`,children:[(0,b.jsx)(l,{variant:`outline`,onClick:$,disabled:N||L,children:v(`cancel`)}),(0,b.jsx)(l,{onClick:te,disabled:N||L||!!J?.readonly||!w(j),children:v(`save`)})]})]})]}):(0,b.jsx)(`div`,{className:`quickforge-settings-stack`,children:(0,b.jsxs)(`section`,{className:`quickforge-settings-section`,"aria-label":v(`agentsTab`),children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-toolbar`,children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-row-main`,children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-row-title`,children:[(0,b.jsx)(t,{className:`size-4 text-primary`}),v(`agentsTab`)]}),(0,b.jsx)(`div`,{className:`quickforge-settings-row-description`,children:v(`agentsDescription`)})]}),(0,b.jsx)(`button`,{className:`quickforge-settings-button quickforge-settings-button-primary`,type:`button`,onClick:Z,children:v(`createAgent`)})]}),U?(0,b.jsx)(`div`,{className:`quickforge-settings-alert quickforge-settings-warning-attached`,children:U}):null,e.length===0?(0,b.jsx)(`div`,{className:`quickforge-settings-empty-row`,children:v(`loading`)}):e.map(e=>(0,b.jsxs)(`div`,{className:`quickforge-settings-list-item`,children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-list-item-main`,children:[(0,b.jsxs)(`div`,{className:`quickforge-settings-row-title`,children:[e.label,e.builtin?(0,b.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-info`,children:v(`builtinAgent`)}):null,(0,b.jsx)(`span`,{className:_(`quickforge-settings-badge`,e.enabledAsSubagent?`quickforge-settings-badge-success`:`quickforge-settings-badge-muted`),children:e.enabledAsSubagent?v(`enabled`):v(`disabled`)})]}),(0,b.jsx)(`div`,{className:`quickforge-settings-row-description quickforge-settings-mono`,children:e.name}),e.source&&!e.builtin?(0,b.jsxs)(`div`,{className:`quickforge-settings-row-description`,children:[e.source,e.relativePath?` · ${e.relativePath}`:``]}):null,(0,b.jsx)(`div`,{className:`quickforge-settings-row-description`,children:e.description||v(`noDescription`)}),(0,b.jsx)(`div`,{className:`quickforge-settings-meta`,children:e.allowedTools.map(e=>(0,b.jsx)(`code`,{className:`quickforge-settings-command-name`,children:e},e))}),(0,b.jsxs)(`div`,{className:`quickforge-settings-meta`,children:[(0,b.jsxs)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:[v(`maxRuntimeMs`),e.maxRuntimeMs??`-`]}),(0,b.jsxs)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:[v(`maxToolCalls`),e.maxToolCalls??`-`]})]})]}),(0,b.jsxs)(`div`,{className:`quickforge-settings-list-item-actions`,onClick:e=>e.stopPropagation(),children:[(0,b.jsxs)(`label`,{className:`quickforge-settings-switch`,"aria-disabled":e.builtin||e.readonly?`true`:`false`,title:e.enabledAsSubagent?v(`disableAsSubagent`):v(`enableAsSubagent`),children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:e.enabledAsSubagent,disabled:e.builtin||e.readonly,onChange:()=>void ne(e)}),(0,b.jsx)(`span`,{"aria-hidden":`true`})]}),(0,b.jsxs)(`div`,{className:`relative`,children:[(0,b.jsx)(`button`,{className:`quickforge-settings-icon-action`,type:`button`,onClick:()=>K(G===e.id?null:e.id),title:v(`moreActions`),children:(0,b.jsx)(o,{className:`size-4`})}),G===e.id?(0,b.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-36 overflow-hidden rounded-xl border border-border bg-popover py-1 text-sm shadow-quickforge`,children:[(0,b.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50`,disabled:e.builtin||e.readonly,onClick:()=>{K(null),Q(e)},children:[(0,b.jsx)(r,{className:`size-3.5`}),v(`editTask`)]}),(0,b.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left text-destructive hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50`,disabled:e.builtin||e.readonly,onClick:()=>{K(null),re(e)},children:[(0,b.jsx)(i,{className:`size-3.5`}),v(`delete`)]})]}):null]})]})]},e.id))]})})}export{E as AgentProfilesPage};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{Et as t,Ot as n,T as r,Tt as i,U as a,a as ee,c as te,ft as ne,g as re,it as ie,jt as o,mt as ae,nt as oe,t as se}from"./icons-B0ihJZtt.js";import{n as s}from"./react-vendor-EwqQ8x7m.js";import{$ as c,G as ce,H as le,K as ue,M as de,Q as fe,U as pe,W as me,et as l,it as u}from"./index-CTo6RkZO.js";var d=e(o(),1),f=s(),he=[{value:`off`,label:()=>u(`thinkingOff`)},{value:`low`,label:()=>u(`thinkingLow`)},{value:`medium`,label:()=>u(`thinkingMedium`)},{value:`high`,label:()=>u(`thinkingHigh`)},{value:`xhigh`,label:()=>u(`thinkingXHigh`)}];function ge(e){return`${e.provider} / ${e.id}`}function _e(e,t){return!!(e&&t&&e.api===t.api&&e.provider===t.provider&&e.id===t.id)}function p(e){return String(e).padStart(2,`0`)}function m(e){if(!e)return`-`;let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${p(t.getMonth()+1)}-${p(t.getDate())} ${p(t.getHours())}:${p(t.getMinutes())}`}function ve(e,t=20){let n=String(e||``).trim();return n.length>t?`${n.slice(0,t)}...`:n}function ye(){return{scheduleText:``,title:``,instruction:``,cronExpression:``,scheduleRule:``,nextRunAt:``,enabled:!0,agentId:``,executionMode:`serial`}}function h(){return{taskId:``,status:``,trigger:``,keyword:``,startedFrom:``,startedTo:``,page:1,pageSize:10}}function be(e){return{scheduleText:[e.scheduleRule,e.instruction].filter(Boolean).join(`
|
|
2
|
-
`),title:e.title,instruction:e.instruction,cronExpression:e.cronExpression??``,scheduleRule:e.scheduleRule,nextRunAt:e.nextRunAt,enabled:e.status!==`paused`,agentId:e.agentId??``,executionMode:e.executionMode??`serial`}}function xe(e,t){return{...t,title:e.title,instruction:e.instruction,cronExpression:e.cronExpression??``,scheduleRule:e.scheduleRule,nextRunAt:e.nextRunAt,enabled:t.enabled}}function Se(e){return{title:e.title.trim(),instruction:e.instruction.trim(),scheduleType:`cron`,scheduleRule:e.scheduleRule.trim()||e.cronExpression.trim(),cronExpression:e.cronExpression.trim(),nextRunAt:e.nextRunAt,enabled:e.enabled,agentId:e.agentId||null,executionMode:e.executionMode}}function g(e){return!!(e.currentRunId||e.currentRunIds?.length)}function Ce(e){return(e.executionMode??`serial`)===`parallel`||!g(e)}function we(e){return u(e===`parallel`?`taskExecutionModeParallel`:`taskExecutionModeSerial`)}function Te(e){return!!(e.title.trim()&&e.instruction.trim()&&e.cronExpression.trim())}function Ee(e){return u(e===`enabled`?`taskEnabled`:e===`running`?`taskRunning`:e===`paused`?`taskPaused`:e===`completed`?`taskFinished`:e===`success`?`executionSuccess`:`taskFailed`)}function De(e){return e===`enabled`||e===`success`?`bg-emerald-500/10 text-emerald-700`:e===`running`?`bg-blue-500/10 text-blue-700`:e===`paused`?`bg-amber-500/10 text-amber-700`:`bg-muted text-muted-foreground`}async function _(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 v({onOpenSession:e}){let[o,s]=(0,d.useState)([]),[p,v]=(0,d.useState)(`tasks`),[y,b]=(0,d.useState)(()=>ye()),[x,Oe]=(0,d.useState)(null),[S,C]=(0,d.useState)(null),[w,T]=(0,d.useState)(null),[E,D]=(0,d.useState)(!1),[O,k]=(0,d.useState)(null),[ke,A]=(0,d.useState)(``),[j,M]=(0,d.useState)(!1),[N,P]=(0,d.useState)(``),[F,Ae]=(0,d.useState)([]),[I,L]=(0,d.useState)(),[R,z]=(0,d.useState)(`off`),[B,je]=(0,d.useState)([]),[Me,V]=(0,d.useState)(``),[H,U]=(0,d.useState)(()=>h()),[W,G]=(0,d.useState)(()=>h()),[K,Ne]=(0,d.useState)({runs:[],total:0,page:1,pageSize:10}),[Pe,Fe]=(0,d.useState)(!1),[Ie,Le]=(0,d.useState)(null),[Re,ze]=(0,d.useState)([]),Be=B[0]?.id??``;(0,d.useEffect)(()=>{if(!w)return;let e=()=>T(null);return window.addEventListener(`click`,e),window.addEventListener(`blur`,e),()=>{window.removeEventListener(`click`,e),window.removeEventListener(`blur`,e)}},[w]);async function Ve(){s((await _(`/api/scheduled-tasks`)).tasks)}async function q(e=W){Fe(!0),P(``);try{let t=new URLSearchParams;t.set(`page`,String(e.page)),t.set(`pageSize`,String(e.pageSize)),e.taskId&&t.set(`taskId`,e.taskId),e.status&&t.set(`status`,e.status),e.trigger&&t.set(`trigger`,e.trigger),e.keyword.trim()&&t.set(`keyword`,e.keyword.trim()),e.startedFrom&&t.set(`startedFrom`,e.startedFrom),e.startedTo&&t.set(`startedTo`,e.startedTo),Ne(await _(`/api/scheduled-tasks/runs?${t.toString()}`))}catch(e){P(e instanceof Error?e.message:u(`requestFailed`))}finally{Fe(!1)}}(0,d.useEffect)(()=>{let e=!1;async function t(){try{let t=await _(`/api/project`);if(e)return;je(t.projects??[])}catch{}}return t(),()=>{e=!0}},[]),(0,d.useEffect)(()=>{let e=!1;async function t(){try{let t=await me(),n=await pe(t),r=await ce(t),i=r.model??await ue(t)??n[0];if(e)return;Ae(n),L(i),z(r.thinkingLevel??le(i))}catch(t){e||P(t instanceof Error?t.message:u(`requestFailed`))}}return t(),()=>{e=!0}},[]),(0,d.useEffect)(()=>{let e=!1,t=async()=>{try{let t=await _(`/api/scheduled-tasks`);e||s(t.tasks)}catch(t){e||P(t instanceof Error?t.message:u(`requestFailed`))}};t();let n=window.setInterval(t,10*1e3);return()=>{e=!0,window.clearInterval(n)}},[]),(0,d.useEffect)(()=>{let e=!1;async function t(){try{let t=await _(`/api/agent-profiles`);if(e)return;ze(t.agents)}catch(t){e||P(t instanceof Error?t.message:u(`requestFailed`))}}return t(),()=>{e=!0}},[]);let He=(0,d.useMemo)(()=>o.find(e=>e.id===x),[x,o]),J=(0,d.useMemo)(()=>o.find(e=>e.id===S)??null,[S,o]),Ue=(0,d.useMemo)(()=>o.filter(e=>e.status===`enabled`).length,[o]),Y=Math.max(1,Math.ceil(K.total/K.pageSize));function We(e){return e?Re.find(t=>t.id===e||t.name===e)?.label??e:u(`defaultAgent`)}function X(e,t){b(n=>({...n,[e]:t}))}function Z(e,t){U(n=>({...n,[e]:t}))}function Ge(){Oe(null),V(Be),b(ye()),k(null),A(``),P(``)}function Ke(){Ge(),D(!0)}function Q(){j||(D(!1),Ge())}function qe(){let e={...H,page:1};U(e),G(e),q(e)}function Je(){let e=h();U(e),G(e),q(e)}function Ye(e){let t=Math.min(Math.max(1,e),Y),n={...W,page:t};U(n),G(n),q(n)}function Xe(e){let t={...W,page:1,pageSize:e};U(t),G(t),q(t)}async function Ze(){let e=y.scheduleText.trim();if(e){M(!0),P(``);try{let t=await _(`/api/scheduled-tasks/parse`,{method:`POST`,body:JSON.stringify({instruction:e,model:I,thinkingLevel:R})});if(t.needMoreInfo||!t.task){A(t.question||`请补充任务信息。`),k(null);return}let n=t.task;A(``),k(n),b(e=>xe(n,e))}catch(e){P(e instanceof Error?e.message:u(`requestFailed`))}finally{M(!1)}}}async function Qe(){if(Te(y)){M(!0),P(``);try{let e=B.find(e=>e.id===Me),t={task:Se(y),model:I,thinkingLevel:R,projectId:e?.id,projectName:e?.name};x?await _(`/api/scheduled-tasks/${encodeURIComponent(x)}`,{method:`PUT`,body:JSON.stringify(t)}):await _(`/api/scheduled-tasks`,{method:`POST`,body:JSON.stringify(t)}),Q(),await Ve(),p===`history`&&await q(W)}catch(e){P(e instanceof Error?e.message:u(`requestFailed`))}finally{M(!1)}}}function $e(e){T(null),Oe(e.id),b(be(e)),k(null),A(``),P(``),V(e.projectId??``),e.model&&L(e.model),e.thinkingLevel&&z(e.thinkingLevel),D(!0)}async function $(e,t){if(P(``),T(null),!(t===`delete`&&!await de({description:u(`confirmDeleteTask`),confirmLabel:u(`confirmDelete`),cancelLabel:u(`cancel`),variant:`destructive`})))try{t===`delete`?(await _(`/api/scheduled-tasks/${encodeURIComponent(e)}`,{method:`DELETE`}),x===e&&Q(),S===e&&C(null)):await _(`/api/scheduled-tasks/${encodeURIComponent(e)}/${t}`,{method:`POST`}),await Ve(),p===`history`&&await q(W)}catch(e){P(e instanceof Error?e.message:u(`requestFailed`))}}function et(t){return(0,f.jsxs)(`div`,{className:`mt-2 space-y-2 text-xs text-muted-foreground`,children:[t.sessionId?(0,f.jsx)(c,{variant:`outline`,size:`sm`,onClick:()=>e?.(t.sessionId),children:u(`viewConversation`)}):null,(0,f.jsxs)(`div`,{children:[u(`executionAgent`),t.agentLabel||We(t.agentId)]}),t.warning?(0,f.jsx)(`div`,{className:`text-amber-600`,children:t.warning}):null,t.inputContent?(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`font-medium text-foreground`,children:u(`runInputContent`)}),(0,f.jsx)(`pre`,{className:`mt-1 max-h-32 overflow-auto whitespace-pre-wrap`,children:t.inputContent})]}):null,t.aiResult||t.result?(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`font-medium text-foreground`,children:u(`runAiResult`)}),(0,f.jsx)(`pre`,{className:`mt-1 max-h-48 overflow-auto whitespace-pre-wrap`,children:t.aiResult||t.result})]}):null,t.errorMessage?(0,f.jsx)(`div`,{className:`text-destructive`,children:t.errorMessage}):null,t.durationMs?(0,f.jsxs)(`div`,{children:[u(`runDuration`),t.durationMs,`ms`]}):null]})}return(0,f.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-hidden bg-background`,children:[(0,f.jsxs)(`div`,{className:`border-b border-border px-6 py-5`,children:[(0,f.jsx)(`div`,{className:`flex flex-wrap items-center justify-end gap-3`,children:E||J?(0,f.jsxs)(c,{variant:`outline`,onClick:()=>{E?Q():C(null)},children:[(0,f.jsx)(n,{className:`mr-1 size-4`}),u(`back`)]}):(0,f.jsx)(c,{onClick:Ke,children:u(`createTask`)})}),!E&&!J?(0,f.jsxs)(`div`,{className:`mt-4 flex flex-wrap gap-2`,children:[(0,f.jsxs)(`button`,{type:`button`,className:l(`rounded-full px-4 py-2 text-sm font-medium transition-colors`,p===`tasks`?`bg-primary text-primary-foreground`:`bg-muted text-muted-foreground hover:text-foreground`),onClick:()=>v(`tasks`),children:[u(`taskListTab`),` `,(0,f.jsx)(`span`,{className:`opacity-80`,children:o.length})]}),(0,f.jsx)(`button`,{type:`button`,className:l(`rounded-full px-4 py-2 text-sm font-medium transition-colors`,p===`history`?`bg-primary text-primary-foreground`:`bg-muted text-muted-foreground hover:text-foreground`),onClick:()=>{v(`history`),q(W)},children:u(`executionHistoryTab`)})]}):null]}),(0,f.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto p-6`,children:(0,f.jsx)(`div`,{className:`mx-auto max-w-5xl space-y-5`,children:E?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`div`,{className:`rounded-xl border border-border bg-card p-5 space-y-4`,children:[(0,f.jsxs)(`h2`,{className:`inline-flex items-center gap-1.5 text-base font-semibold text-foreground`,children:[u(He?`editTask`:`createTask`),(0,f.jsx)(fe,{label:u(`quickAiParseTask`)})]}),(0,f.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[u(`taskScheduleDescriptionLabel`),(0,f.jsx)(`textarea`,{className:`mt-1 min-h-24 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`,value:y.scheduleText,onChange:e=>X(`scheduleText`,e.target.value),placeholder:u(`taskScheduleDescriptionPlaceholder`)})]}),(0,f.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,f.jsxs)(c,{onClick:Ze,disabled:j||!I||!y.scheduleText.trim(),children:[(0,f.jsx)(te,{className:`mr-1 size-3.5`}),u(`aiParseTask`)]}),ke?(0,f.jsx)(`span`,{className:`text-sm text-amber-600`,children:ke}):null]}),(0,f.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,f.jsxs)(`label`,{className:`block text-sm font-medium text-foreground`,children:[u(`taskTitleLabel`),(0,f.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`,value:y.title,onChange:e=>X(`title`,e.target.value),placeholder:u(`taskTitlePlaceholder`)})]}),(0,f.jsxs)(`div`,{className:`block text-sm font-medium text-foreground`,children:[u(`executionRule`),(0,f.jsx)(`div`,{className:`mt-1 flex h-10 items-center rounded-md border border-input bg-muted/20 px-3 text-sm text-muted-foreground`,children:y.scheduleRule||`-`})]}),(0,f.jsxs)(`div`,{className:`block text-sm font-medium text-foreground`,children:[`cron`,(0,f.jsx)(`div`,{className:`mt-1 flex h-10 items-center rounded-md border border-input bg-muted/20 px-3 font-mono text-sm text-muted-foreground`,children:y.cronExpression||`-`})]}),(0,f.jsxs)(`div`,{className:`block text-sm font-medium text-foreground`,children:[u(`nextExecutionTime`),(0,f.jsx)(`div`,{className:`mt-1 flex h-10 items-center rounded-md border border-input bg-muted/20 px-3 text-sm text-muted-foreground`,children:m(y.nextRunAt)})]}),(0,f.jsxs)(`label`,{className:`block text-sm font-medium text-foreground sm:col-span-2`,children:[(0,f.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[u(`taskExecutionMode`),(0,f.jsx)(fe,{label:u(`taskExecutionModeHelp`)})]}),(0,f.jsxs)(`select`,{className:`mt-1 h-10 w-full rounded-md border border-input bg-background px-3 text-sm text-foreground outline-none focus:border-ring`,value:y.executionMode,onChange:e=>X(`executionMode`,e.target.value),children:[(0,f.jsx)(`option`,{value:`serial`,children:u(`taskExecutionModeSerial`)}),(0,f.jsx)(`option`,{value:`parallel`,children:u(`taskExecutionModeParallel`)})]})]}),(0,f.jsxs)(`label`,{className:`block text-sm font-medium text-foreground sm:col-span-2`,children:[u(`promptContentLabel`),(0,f.jsx)(`textarea`,{className:`mt-1 min-h-28 w-full resize-y rounded-xl border border-input bg-background px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground/65 focus:border-ring`,value:y.instruction,onChange:e=>X(`instruction`,e.target.value),placeholder:u(`promptContentPlaceholder`)})]})]}),(0,f.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-foreground`,children:[(0,f.jsx)(`input`,{type:`checkbox`,checked:y.enabled,onChange:e=>X(`enabled`,e.target.checked)}),u(`taskEnabledSwitch`)]}),(0,f.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 rounded-xl border border-border bg-muted/20 px-2 py-2`,children:[(0,f.jsxs)(`span`,{className:`relative inline-flex items-center`,children:[(0,f.jsx)(te,{className:`pointer-events-none absolute left-2 size-3.5 text-muted-foreground/70`}),(0,f.jsxs)(`select`,{className:`h-8 max-w-[240px] rounded-md border border-transparent bg-transparent pl-7 pr-2 text-xs text-muted-foreground outline-none hover:bg-background focus:border-ring`,value:I?`${I.provider}\u0000${I.id}`:``,onChange:e=>{let t=F.find(t=>`${t.provider}\u0000${t.id}`===e.target.value);L(t),z(le(t))},title:u(`taskModel`),children:[F.length===0?(0,f.jsx)(`option`,{value:``,children:u(`noModelAvailable`)}):null,F.map(e=>(0,f.jsxs)(`option`,{value:`${e.provider}\u0000${e.id}`,children:[ge(e),_e(e,I)?` ✓`:``]},`${e.provider}:${e.id}`))]})]}),(0,f.jsxs)(`span`,{className:`relative inline-flex items-center`,children:[(0,f.jsx)(i,{className:`pointer-events-none absolute left-2 size-3.5 text-muted-foreground/70`}),(0,f.jsx)(`select`,{className:`h-8 rounded-md border border-transparent bg-transparent pl-7 pr-2 text-xs text-muted-foreground outline-none hover:bg-background focus:border-ring`,value:R,onChange:e=>z(e.target.value),title:u(`taskThinking`),children:he.map(e=>(0,f.jsx)(`option`,{value:e.value,children:e.label()},e.value))})]}),(0,f.jsxs)(`span`,{className:`relative inline-flex items-center`,children:[(0,f.jsx)(a,{className:`pointer-events-none absolute left-2 size-3.5 text-muted-foreground/70`}),(0,f.jsxs)(`select`,{className:`h-8 max-w-[220px] rounded-md border border-transparent bg-transparent pl-7 pr-2 text-xs text-muted-foreground outline-none hover:bg-background focus:border-ring`,value:Me,onChange:e=>V(e.target.value),title:u(`taskProjectLabel`),children:[(0,f.jsx)(`option`,{value:``,children:u(`noProjectBound`)}),B.map(e=>(0,f.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]}),(0,f.jsxs)(`span`,{className:`relative inline-flex items-center`,children:[(0,f.jsx)(t,{className:`pointer-events-none absolute left-2 size-3.5 text-muted-foreground/70`}),(0,f.jsxs)(`select`,{className:`h-8 max-w-[220px] rounded-md border border-transparent bg-transparent pl-7 pr-2 text-xs text-muted-foreground outline-none hover:bg-background focus:border-ring`,value:y.agentId,onChange:e=>X(`agentId`,e.target.value),title:u(`executionAgent`),children:[(0,f.jsx)(`option`,{value:``,children:u(`defaultAgent`)}),Re.map(e=>(0,f.jsx)(`option`,{value:e.id,children:e.label},e.id))]})]})]}),O?(0,f.jsxs)(`div`,{className:`rounded-xl border border-border bg-muted/30 p-3 text-sm`,children:[(0,f.jsxs)(`div`,{className:`mb-2 flex items-center gap-2 font-medium text-foreground`,children:[(0,f.jsx)(ae,{className:`size-4 text-emerald-600`}),u(`aiParsed`)]}),(0,f.jsxs)(`div`,{className:`grid gap-2 text-muted-foreground sm:grid-cols-2`,children:[(0,f.jsxs)(`div`,{children:[u(`taskName`),(0,f.jsx)(`span`,{className:`text-foreground`,children:O.title})]}),(0,f.jsxs)(`div`,{children:[u(`executionRule`),(0,f.jsx)(`span`,{className:`text-foreground`,children:O.scheduleRule})]}),(0,f.jsxs)(`div`,{children:[`cron:`,(0,f.jsx)(`span`,{className:`font-mono text-foreground`,children:O.cronExpression??`-`})]}),(0,f.jsxs)(`div`,{children:[u(`nextExecutionTime`),(0,f.jsx)(`span`,{className:`text-foreground`,children:m(O.nextRunAt)})]}),(0,f.jsxs)(`div`,{className:`sm:col-span-2`,children:[u(`aiInstruction`),(0,f.jsx)(`span`,{className:`text-foreground`,children:O.instruction})]})]})]}):null,N?(0,f.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:N}):null]}),(0,f.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,f.jsx)(c,{variant:`outline`,onClick:Q,disabled:j,children:u(`cancel`)}),(0,f.jsx)(c,{onClick:Qe,disabled:j||!I||!Te(y),children:u(He?`saveTask`:`confirmCreate`)})]})]}):J?(0,f.jsxs)(`div`,{className:`rounded-xl border border-border bg-card`,children:[(0,f.jsx)(`div`,{className:`flex flex-wrap items-start justify-between gap-3 border-b border-border px-5 py-4`,children:(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:J.title}),(0,f.jsx)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:J.scheduleRule})]})}),(0,f.jsx)(`div`,{className:`px-5 py-4`,children:(0,f.jsxs)(`div`,{className:`space-y-4 text-sm`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`mb-1 font-medium text-foreground`,children:u(`taskContent`)}),(0,f.jsx)(`pre`,{className:`max-h-48 overflow-auto whitespace-pre-wrap rounded-xl border border-border bg-muted/20 p-3 text-muted-foreground`,children:J.instruction})]}),(0,f.jsxs)(`div`,{className:`grid gap-3 text-muted-foreground sm:grid-cols-2`,children:[(0,f.jsxs)(`div`,{children:[u(`executionRule`),(0,f.jsx)(`span`,{className:`text-foreground`,children:J.scheduleRule})]}),(0,f.jsxs)(`div`,{children:[u(`taskExecutionMode`),`:`,(0,f.jsx)(`span`,{className:`text-foreground`,children:we(J.executionMode)})]}),(0,f.jsxs)(`div`,{children:[`cron:`,(0,f.jsx)(`span`,{className:`font-mono text-foreground`,children:J.cronExpression??`-`})]}),(0,f.jsxs)(`div`,{children:[u(`lastExecution`),(0,f.jsx)(`span`,{className:`text-foreground`,children:m(J.lastRunAt)})]}),(0,f.jsxs)(`div`,{children:[u(`nextExecution`),(0,f.jsx)(`span`,{className:`text-foreground`,children:m(J.nextRunAt)})]}),(0,f.jsxs)(`div`,{children:[u(`executionAgent`),(0,f.jsx)(`span`,{className:`text-foreground`,children:We(J.agentId)})]}),J.projectName?(0,f.jsxs)(`div`,{children:[u(`taskProject`),(0,f.jsx)(`span`,{className:`text-foreground`,children:J.projectName})]}):null,J.model?(0,f.jsxs)(`div`,{children:[u(`taskModel`),`:`,(0,f.jsx)(`span`,{className:`text-foreground`,children:ge(J.model)})]}):null,J.thinkingLevel?(0,f.jsxs)(`div`,{children:[u(`taskThinkingLevel`),(0,f.jsx)(`span`,{className:`text-foreground`,children:he.find(e=>e.value===J.thinkingLevel)?.label()??J.thinkingLevel})]}):null,(0,f.jsxs)(`div`,{children:[u(`createdAt`),`:`,(0,f.jsx)(`span`,{className:`text-foreground`,children:m(J.createdAt)})]})]}),J.runs?.length>0?(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`mb-2 font-medium text-foreground`,children:u(`recentExecutions`)}),(0,f.jsx)(`div`,{className:`space-y-2`,children:J.runs.slice(0,5).map(e=>(0,f.jsxs)(`details`,{className:`rounded-lg border border-border bg-muted/20 p-2 text-xs text-muted-foreground`,children:[(0,f.jsxs)(`summary`,{className:`cursor-pointer text-foreground`,children:[m(e.startedAt),` · `,e.trigger===`manual`?u(`manualRun`):u(`autoRun`),` · `,Ee(e.status)]}),et(e)]},e.id))})]}):null]})}),(0,f.jsx)(`div`,{className:`border-t border-border px-5 py-4`,children:(0,f.jsxs)(`div`,{className:`flex flex-wrap justify-end gap-2`,children:[J.lastSessionId?(0,f.jsx)(c,{variant:`outline`,onClick:()=>e?.(J.lastSessionId),children:u(`viewConversation`)}):null,(0,f.jsxs)(c,{variant:`outline`,disabled:!Ce(J),onClick:()=>void $(J.id,`run`),children:[(0,f.jsx)(se,{className:`mr-1 size-3.5`}),u(`executeNow`)]}),(0,f.jsxs)(c,{variant:`outline`,disabled:g(J),onClick:()=>$e(J),children:[(0,f.jsx)(r,{className:`mr-1 size-3.5`}),u(`editTask`)]}),(0,f.jsxs)(c,{variant:`destructive`,disabled:g(J),onClick:()=>void $(J.id,`delete`),children:[(0,f.jsx)(ee,{className:`mr-1 size-3.5`}),u(`deleteTask`)]})]})})]}):(0,f.jsxs)(f.Fragment,{children:[N?(0,f.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:N}):null,p===`tasks`?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(`div`,{className:`rounded-xl border border-border bg-card p-4`,children:(0,f.jsx)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:u(`taskList`)}),(0,f.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:u(`tasksCount`,{total:o.length,enabled:Ue})})]})})}),(0,f.jsx)(`div`,{className:`grid gap-4 md:grid-cols-2`,children:o.length===0?(0,f.jsx)(`div`,{className:`rounded-lg px-3 py-3 text-center text-xs text-muted-foreground/55 md:col-span-2`,children:u(`noScheduledTasks`)}):o.map(e=>{let n=e.status===`enabled`,i=e.status===`completed`,a=g(e);return(0,f.jsxs)(`div`,{className:`relative cursor-pointer rounded-xl border border-border bg-card p-4 transition-colors hover:bg-muted/15`,onClick:()=>C(e.id),children:[(0,f.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,f.jsxs)(`div`,{className:`min-w-0`,children:[(0,f.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,f.jsx)(`h3`,{className:`truncate text-sm font-medium text-foreground/90`,children:e.title})}),(0,f.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:ve(e.instruction,20)})]}),(0,f.jsxs)(`div`,{className:`flex shrink-0 items-center gap-2`,onClick:e=>e.stopPropagation(),children:[(0,f.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":n,disabled:i,className:l(`relative h-6 w-11 rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60`,n?`bg-emerald-500`:`bg-muted-foreground/30`),onClick:()=>void $(e.id,e.status===`paused`?`resume`:`pause`),title:e.status===`paused`?u(`enable`):u(`pauseTask`),children:(0,f.jsx)(`span`,{className:l(`absolute left-0.5 top-0.5 size-5 rounded-full bg-white shadow transition-transform`,n?`translate-x-5`:`translate-x-0`)})}),(0,f.jsxs)(`div`,{className:`relative`,children:[(0,f.jsx)(c,{variant:`ghost`,size:`icon`,onClick:()=>T(w===e.id?null:e.id),title:u(`moreActions`),children:(0,f.jsx)(ie,{className:`size-4`})}),w===e.id?(0,f.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-36 overflow-hidden rounded-xl border border-border bg-popover py-1 text-sm shadow-quickforge`,children:[(0,f.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50`,disabled:!Ce(e),onClick:()=>void $(e.id,`run`),children:[(0,f.jsx)(se,{className:`size-3.5`}),u(`executeNow`)]}),(0,f.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50`,disabled:a,onClick:()=>$e(e),children:[(0,f.jsx)(r,{className:`size-3.5`}),u(`editTask`)]}),(0,f.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted`,onClick:()=>{T(null),C(e.id)},children:[(0,f.jsx)(oe,{className:`size-3.5`}),u(`viewDetails`)]}),(0,f.jsxs)(`button`,{className:`flex w-full items-center gap-2 px-3 py-2 text-left text-destructive hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50`,disabled:a,onClick:()=>void $(e.id,`delete`),children:[(0,f.jsx)(ee,{className:`size-3.5`}),u(`deleteTask`)]})]}):null]})]})]}),(0,f.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground`,children:[(0,f.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,f.jsx)(ne,{className:`size-3`}),e.scheduleRule]}),(0,f.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,f.jsx)(t,{className:`size-3`}),We(e.agentId)]}),(0,f.jsxs)(`span`,{children:[u(`taskExecutionMode`),`:`,we(e.executionMode)]}),e.projectName?(0,f.jsxs)(`span`,{children:[u(`taskProject`),e.projectName]}):null]}),(0,f.jsxs)(`div`,{className:`mt-4 grid gap-2 border-t border-border pt-3 text-xs text-muted-foreground sm:grid-cols-2`,children:[(0,f.jsxs)(`span`,{children:[u(`lastExecution`),m(e.lastRunAt)]}),(0,f.jsxs)(`span`,{children:[u(`nextExecution`),m(e.nextRunAt)]})]})]},e.id)})})]}):(0,f.jsxs)(`div`,{className:`space-y-4`,children:[(0,f.jsxs)(`div`,{className:`rounded-xl border border-border bg-card p-4`,children:[(0,f.jsxs)(`div`,{className:`mb-3 flex items-center gap-2 text-sm font-medium text-foreground`,children:[(0,f.jsx)(re,{className:`size-4`}),u(`historyFilters`)]}),(0,f.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-3`,children:[(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`taskName`),(0,f.jsxs)(`select`,{className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.taskId,onChange:e=>Z(`taskId`,e.target.value),children:[(0,f.jsx)(`option`,{value:``,children:u(`allTasks`)}),o.map(e=>(0,f.jsx)(`option`,{value:e.id,children:e.title},e.id))]})]}),(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`status`),(0,f.jsxs)(`select`,{className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.status,onChange:e=>Z(`status`,e.target.value),children:[(0,f.jsx)(`option`,{value:``,children:u(`allStatuses`)}),(0,f.jsx)(`option`,{value:`running`,children:u(`executionRunning`)}),(0,f.jsx)(`option`,{value:`success`,children:u(`executionSuccess`)}),(0,f.jsx)(`option`,{value:`failed`,children:u(`taskFailed`)})]})]}),(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`triggerType`),(0,f.jsxs)(`select`,{className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.trigger,onChange:e=>Z(`trigger`,e.target.value),children:[(0,f.jsx)(`option`,{value:``,children:u(`allTriggers`)}),(0,f.jsx)(`option`,{value:`schedule`,children:u(`autoRun`)}),(0,f.jsx)(`option`,{value:`manual`,children:u(`manualRun`)})]})]}),(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`startTime`),(0,f.jsx)(`input`,{type:`datetime-local`,className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.startedFrom,onChange:e=>Z(`startedFrom`,e.target.value)})]}),(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`endTime`),(0,f.jsx)(`input`,{type:`datetime-local`,className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.startedTo,onChange:e=>Z(`startedTo`,e.target.value)})]}),(0,f.jsxs)(`label`,{className:`block text-xs font-medium text-muted-foreground`,children:[u(`keyword`),(0,f.jsx)(`input`,{className:`mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm text-foreground`,value:H.keyword,onChange:e=>Z(`keyword`,e.target.value),placeholder:u(`keywordPlaceholder`)})]})]}),(0,f.jsxs)(`div`,{className:`mt-3 flex justify-end gap-2`,children:[(0,f.jsx)(c,{variant:`outline`,onClick:Je,children:u(`reset`)}),(0,f.jsx)(c,{onClick:qe,children:u(`query`)})]})]}),(0,f.jsxs)(`div`,{className:`overflow-hidden rounded-xl border border-border bg-card`,children:[(0,f.jsxs)(`div`,{className:`grid grid-cols-[1.3fr_0.7fr_0.7fr_1fr_0.7fr] gap-3 border-b border-border px-4 py-3 text-xs font-medium text-muted-foreground`,children:[(0,f.jsx)(`span`,{children:u(`taskName`)}),(0,f.jsx)(`span`,{children:u(`status`)}),(0,f.jsx)(`span`,{children:u(`triggerType`)}),(0,f.jsx)(`span`,{children:u(`startTime`)}),(0,f.jsx)(`span`,{children:u(`runDuration`)})]}),Pe?(0,f.jsx)(`div`,{className:`p-8 text-center text-sm text-muted-foreground`,children:u(`loading`)}):K.runs.length===0?(0,f.jsx)(`div`,{className:`p-8 text-center text-sm text-muted-foreground`,children:u(`noExecutionHistory`)}):K.runs.map(e=>(0,f.jsxs)(`div`,{className:`border-b border-border last:border-b-0`,children:[(0,f.jsxs)(`button`,{type:`button`,className:`grid w-full grid-cols-[1.3fr_0.7fr_0.7fr_1fr_0.7fr] gap-3 px-4 py-3 text-left text-sm hover:bg-muted/40`,onClick:()=>Le(Ie===e.id?null:e.id),children:[(0,f.jsx)(`span`,{className:`min-w-0 truncate text-foreground`,children:e.taskTitle}),(0,f.jsx)(`span`,{children:(0,f.jsx)(`span`,{className:l(`rounded-full px-2 py-0.5 text-xs`,De(e.status)),children:Ee(e.status)})}),(0,f.jsx)(`span`,{className:`text-muted-foreground`,children:e.trigger===`manual`?u(`manualRun`):u(`autoRun`)}),(0,f.jsx)(`span`,{className:`text-muted-foreground`,children:m(e.startedAt)}),(0,f.jsx)(`span`,{className:`text-muted-foreground`,children:e.durationMs?`${e.durationMs}ms`:`-`})]}),Ie===e.id?(0,f.jsx)(`div`,{className:`border-t border-border bg-muted/20 px-4 py-3`,children:et(e)}):null]},`${e.taskId}:${e.id}`)),(0,f.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3 px-4 py-3 text-sm text-muted-foreground`,children:[(0,f.jsx)(`span`,{children:u(`paginationSummary`,{page:K.page,pages:Y,total:K.total})}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,f.jsx)(`select`,{className:`h-8 rounded-md border border-input bg-background px-2 text-sm`,value:K.pageSize,onChange:e=>Xe(Number(e.target.value)),children:[10,20,50,100].map(e=>(0,f.jsx)(`option`,{value:e,children:u(`pageSize`,{size:e})},e))}),(0,f.jsx)(c,{variant:`outline`,size:`sm`,disabled:K.page<=1,onClick:()=>Ye(K.page-1),children:u(`previousPage`)}),(0,f.jsx)(c,{variant:`outline`,size:`sm`,disabled:K.page>=Y,onClick:()=>Ye(K.page+1),children:u(`nextPage`)})]})]})]})]})]})})})]})}export{v as ScheduledTasksPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,jt as n,st as r}from"./icons-B0ihJZtt.js";import{n as i}from"./react-vendor-EwqQ8x7m.js";import{d as a,i as o,l as s,n as c,r as l,t as u}from"./pi-web-ui-DFNE2m5b.js";import{p as d}from"./pi-ai-Cx633yhb.js";import{t as f}from"./logger-B65Akg8A.js";import{$ as p,B as m,F as h,H as g,I as _,P as v,R as y,Z as b,d as x,et as S,f as C,h as w,it as T,j as E,p as D,z as O}from"./index-CTo6RkZO.js";import{ChatPanelHost as k}from"./ChatPanelHost-DBCQpcp1.js";var A=e(n(),1),j=`quickforgeClientMessageId`;function M(e){let t=e?.metadata;return t&&typeof t==`object`&&!Array.isArray(t)?t:void 0}function N(e){let t=M(e)?.[j];return typeof t==`string`&&t?t:void 0}function P(){return`qfcm_${typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`}function F(e){let t=N(e);if(t)return{message:e,clientMessageId:t};let n=P();return{message:{...e,metadata:{...M(e),[j]:n}},clientMessageId:n}}function I(e){return typeof e==`string`?e:Array.isArray(e)?e.filter(e=>e&&typeof e==`object`&&e.type===`text`).map(e=>e.text).filter(e=>typeof e==`string`).join(``):``}function L(e,t){if(!e||!t||e.role!==t.role)return!1;let n=N(e),r=N(t);return n&&r?n===r:I(e.content)===I(t.content)}async function R(e,t){let n=await fetch(e,{...t,cache:`no-store`,headers:{...t?.body?{"content-type":`application/json`}:void 0,...t?.headers}}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`Request failed: ${n.status}`);return r}var z=class e{state;streamFn=d;getApiKey;sessionId;shareId;permission;listeners=new Set;eventSource=null;disposed=!1;reconnectTimer=null;reconnectDelay=1e3;baseUrl=``;syncingThinkingLevel=!1;planMode=!1;onPlanModeConsumed;constructor(e,t){this.shareId=e,this.sessionId=t.sessionId||t.id||e,this.permission=t.permission??`read`;let n={systemPrompt:t.systemPrompt??``,model:t.model??{provider:`shared`,id:`shared`},thinkingLevel:t.thinkingLevel??`off`,messages:t.messages?.slice()??[],tools:t.tools??[],isStreaming:!!t.isStreaming,streamingMessage:void 0,pendingToolCalls:new Set,errorMessage:t.errorMessage,contextCompaction:t.contextCompaction??null,contextUsage:t.contextUsage??null};this.state=new Proxy(n,{set:(e,t,n)=>{let r=e[t];return e[t]=n,t===`thinkingLevel`&&!this.syncingThinkingLevel&&n!==r&&this.updateThinkingLevel(n).catch(e=>{f.error(`Failed to update shared thinking level:`,e)}),!0}}),this.connectEvents()}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}setNextPromptCapabilities(){}setPlanMode(e,t){this.planMode=e,this.onPlanModeConsumed=e?t:void 0}async prompt(e){if(this.disposed||this.permission!==`operate`)return;let{message:t,clientMessageId:n}=F(this.normalizeInput(e)),r=this.planMode?{type:`plan`}:void 0;if(this.planMode){this.planMode=!1;let e=this.onPlanModeConsumed;this.onPlanModeConsumed=void 0,e?.()}this.state.messages=[...this.state.messages,t],this.emit({type:`message_start`,message:t}),this.state.isStreaming||(this.state.isStreaming=!0,this.state.errorMessage=void 0,this.emit({type:`agent_start`}));try{await R(`/api/shared/${encodeURIComponent(this.shareId)}/message`,{method:`POST`,body:JSON.stringify({message:t,clientMessageId:n,command:r})})}catch(e){let t=e instanceof Error?e.message:String(e);throw this.state.errorMessage=t,this.state.isStreaming=!1,this.emit({type:`error`,error:t}),this.emit({type:`agent_end`,messages:this.state.messages}),e}}async updateModel(e){if(!(this.disposed||this.permission!==`operate`)){this.state.model=e;try{let t=await R(`/api/shared/${encodeURIComponent(this.shareId)}/model`,{method:`POST`,body:JSON.stringify({model:e})});t.model&&(this.state.model=t.model)}catch(e){let t=e instanceof Error?e.message:String(e);throw this.state.errorMessage=t,this.emit({type:`error`,error:t}),e}}}async updateThinkingLevel(e){if(!(this.disposed||this.permission!==`operate`)){!this.syncingThinkingLevel&&this.state.thinkingLevel!==e&&(this.state.thinkingLevel=e);try{let t=await R(`/api/shared/${encodeURIComponent(this.shareId)}/thinking-level`,{method:`POST`,body:JSON.stringify({thinkingLevel:e})});t.thinkingLevel&&(this.state.thinkingLevel=t.thinkingLevel)}catch(e){let t=e instanceof Error?e.message:String(e);throw this.state.errorMessage=t,this.emit({type:`error`,error:t}),e}}}abort(){this.permission===`operate`&&fetch(`/api/shared/${encodeURIComponent(this.shareId)}/abort`,{method:`POST`}).catch(e=>{f.error(`Failed to abort shared conversation:`,e)})}steer(){}followUp(){}reset(){this.state.messages=[],this.state.errorMessage=void 0,this.state.isStreaming=!1,this.state.streamingMessage=void 0,this.state.pendingToolCalls=new Set}async rollback(e){if(this.permission!==`operate`)return;let t=await R(`/api/shared/${encodeURIComponent(this.shareId)}/rollback`,{method:`POST`,body:JSON.stringify({messageIndex:e})});return this.applyState(t.session),this.emit({type:`messages_replaced`,messages:this.state.messages}),t}dispose(){this.disposed=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.eventSource?.close(),this.eventSource=null,this.listeners.clear()}static async loadState(e){return R(`/api/shared/${encodeURIComponent(e)}/session`)}static async create(t){return new e(t,await e.loadState(t))}normalizeInput(e){return typeof e==`string`?{role:`user`,content:e,timestamp:Date.now()}:Array.isArray(e)?[...e].reverse().find(e=>e.role===`user`||e.role===`user-with-attachments`)??e[e.length-1]:e}connectEvents(){this.disposed||(this.eventSource?.close(),this.baseUrl=``,this.openEventSource())}openEventSource(){if(this.disposed)return;let e=`${this.baseUrl}/api/shared/${encodeURIComponent(this.shareId)}/events`;this.eventSource=new EventSource(e,{withCredentials:!0}),this.eventSource.onopen=()=>{this.reconnectDelay=1e3};let t=[`state`,`agent_start`,`agent_end`,`message_start`,`message_end`,`turn_start`,`turn_end`,`message_update`,`tool_execution_start`,`tool_execution_update`,`tool_execution_end`,`error`,`title_updated`,`messages_replaced`,`auto_compact_completed`],n=e=>t=>{try{let n=JSON.parse(t.data);this.handleEvent(e?{type:e,...n}:n)}catch{}};this.eventSource.onmessage=n();for(let e of t)this.eventSource.addEventListener(e,n(e));this.eventSource.onerror=()=>{this.eventSource?.close(),this.eventSource=null,this.scheduleReconnect()}}scheduleReconnect(){this.disposed||this.reconnectTimer||(this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this.openEventSource()},this.reconnectDelay))}handleEvent(e){if(e.type){switch(e.type){case`state`:this.applyState(e);break;case`agent_start`:this.state.isStreaming=!0,this.state.errorMessage=void 0;break;case`agent_end`:this.state.isStreaming=!1,this.state.streamingMessage=void 0;break;case`message_start`:if(e.message){let t=this.state.messages.findIndex(t=>L(t,e.message));if(t>=0){let n=this.state.messages.slice();n[t]=e.message,this.state.messages=n}else this.state.messages=[...this.state.messages,e.message];this.state.contextUsage=null}break;case`message_update`:e.message&&(this.state.streamingMessage=e.message);break;case`message_end`:e.message&&(this.state.messages=O(this.state.messages,e.message)),this.state.contextUsage=`contextUsage`in e?e.contextUsage:null,this.state.streamingMessage=void 0;break;case`messages_replaced`:e.messages&&(this.state.messages=e.messages,this.state.streamingMessage=void 0),`contextCompaction`in e&&(this.state.contextCompaction=e.contextCompaction),`contextUsage`in e&&(this.state.contextUsage=e.contextUsage);break;case`auto_compact_completed`:`contextCompaction`in e&&(this.state.contextCompaction=e.contextCompaction),`contextUsage`in e&&(this.state.contextUsage=e.contextUsage);break;case`tool_execution_start`:{let t=e;t.toolCallId&&(this.state.messages=m(this.state.messages,y(t),!0),this.state.pendingToolCalls=new Set([...this.state.pendingToolCalls,t.toolCallId]));break}case`tool_execution_update`:{let t=e;this.state.messages=m(this.state.messages,t,!0),t.toolCallId&&(this.state.pendingToolCalls=new Set([...this.state.pendingToolCalls,t.toolCallId]));break}case`tool_execution_end`:{let t=e;if(this.state.messages=m(this.state.messages,t,!1),t.toolCallId){let e=new Set(this.state.pendingToolCalls);e.delete(t.toolCallId),this.state.pendingToolCalls=e}break}case`error`:this.state.errorMessage=typeof e.error==`string`?e.error:`Unknown error`,this.state.isStreaming=!1;break}this.emit(e)}}applyState(e){this.sessionId=e.sessionId||e.id||this.sessionId,e.messages&&(this.state.messages=e.messages,this.state.contextUsage=e.contextUsage===void 0?null:e.contextUsage),e.systemPrompt!==void 0&&(this.state.systemPrompt=e.systemPrompt),e.model&&(this.state.model=e.model),e.thinkingLevel&&(this.syncingThinkingLevel=!0,this.state.thinkingLevel=e.thinkingLevel,this.syncingThinkingLevel=!1),e.tools&&(this.state.tools=e.tools),e.isStreaming!==void 0&&(this.state.isStreaming=!!e.isStreaming),e.errorMessage!==void 0&&(this.state.errorMessage=e.errorMessage),e.contextCompaction!==void 0&&(this.state.contextCompaction=e.contextCompaction),e.contextUsage!==void 0&&(this.state.contextUsage=e.contextUsage)}emit(e){for(let t of this.listeners)try{t(e)}catch{}}},B=i();function V(e){return{id:`shared-${e.provider}`,name:e.provider,type:e.api,baseUrl:e.baseUrl??``,models:[e]}}async function H(e,t){try{let t=await C(e);if(t.providers?.length)return t.providers}catch{}return t?[V(t)]:[]}function U(e,t){let n=t.model??{provider:`shared`,id:`shared`};return new z(e,{...t,model:n,thinkingLevel:t.thinkingLevel??g(n)})}function W(e,t){let n={settings:new u,providerKeys:new l,sessions:new c,customProviders:new o},r=new b(``,{blockedStores:[`sessions`,`provider-keys`],fakeProviderKeys:t?[t.provider]:void 0,storeOverrides:t?{"custom-providers":{keys:async()=>(await H(e,t)).map(e=>e.name),get:async n=>(await H(e,t)).find(e=>e.name===n)??null,has:async n=>(await H(e,t)).some(e=>e.name===n)}}:void 0});n.settings.setBackend(r),n.providerKeys.setBackend(r),n.sessions.setBackend(r),n.customProviders.setBackend(r),a(new s(n.settings,n.providerKeys,n.sessions,n.customProviders,r))}function G({shareId:e}){let[n,i]=(0,A.useState)(``),[a,o]=(0,A.useState)(null),[s,c]=(0,A.useState)(`read`),[l,u]=(0,A.useState)(`QuickForge 分享对话`),[d,m]=(0,A.useState)(),[g,y]=(0,A.useState)(!1),[b,C]=(0,A.useState)(),O=(0,A.useRef)(!1),j=s===`operate`,M=!!a,N=!!a?.state.tools?.length;(0,A.useEffect)(()=>{W(e,a?.state.model)},[a?.state.model,e]),(0,A.useEffect)(()=>()=>a?.dispose(),[a]);let P=(0,A.useCallback)(async(t=n.trim())=>{m(void 0),y(!0);try{let n=await D(e,t);c(n.permission),u(n.title||n.share.titleSnapshot||`QuickForge 分享对话`);let r=await z.loadState(e);W(e,r.model),o(U(e,r))}catch(e){m(e instanceof Error?e.message:`Failed to unlock shared conversation`)}finally{y(!1)}},[n,e]);(0,A.useEffect)(()=>{if(M||g||O.current)return;O.current=!0;let t=window.setTimeout(()=>{(async()=>{try{(await x(e)).share.hasPassword||await P(``)}catch(e){m(e instanceof Error?e.message:`Failed to load shared conversation`)}})()},0);return()=>window.clearTimeout(t)},[g,e,P,M]);let F=(0,A.useCallback)(async e=>{await v(e)},[]),I=(0,A.useCallback)(async()=>{if(!(!a||a.permission!==`operate`))try{let t=(await H(e,a.state.model)).flatMap(e=>e.models??[]);if(!t.length)return;w(a.state.model,t,t=>{!t.reasoning&&a.state.thinkingLevel!==`off`&&a.updateThinkingLevel(`off`).catch(e=>{f.error(`Failed to update shared thinking level:`,e)}),W(e,t),a.updateModel(t).catch(e=>{m(e instanceof Error?e.message:`Failed to update model`)})},void 0,{thinkingLevel:a.state.thinkingLevel,onThinkingLevelSelect:e=>{a.updateThinkingLevel(e).catch(e=>{f.error(`Failed to update shared thinking level:`,e),m(e instanceof Error?e.message:`Failed to update thinking level`)})}})}catch(e){m(e instanceof Error?e.message:`Failed to load models`)}},[a,e]),L=(0,A.useCallback)(async e=>{if(!a||a.permission!==`operate`)return;if(m(void 0),a.state.isStreaming){E(T(`generationStillRunning`));return}let t=_(a.state.messages,e),n=t>=0?a.state.messages[t]:void 0;if(!n){E(T(`noConversationTurnToRollback`));return}try{await a.rollback(e),C({id:Date.now(),sessionId:a.sessionId,text:h(n),attachments:n.role===`user-with-attachments`?n.attachments:void 0})}catch(e){m(e instanceof Error?e.message:`Failed to roll back`)}},[a]);return M?(0,B.jsxs)(`div`,{className:`flex h-screen min-h-0 flex-col bg-background text-foreground`,children:[(0,B.jsx)(`header`,{className:S(`shrink-0 border-b px-4 py-3`,j?`border-red-300 bg-red-50 text-red-950`:`border-border bg-background`),children:(0,B.jsxs)(`div`,{className:`mx-auto flex max-w-4xl items-start gap-3`,children:[(0,B.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,B.jsx)(`div`,{className:`truncate text-sm font-semibold`,children:l}),(0,B.jsxs)(`div`,{className:`mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs`,children:[(0,B.jsxs)(`span`,{className:S(`inline-flex items-center gap-1 rounded-full px-2 py-0.5 font-medium`,j?`bg-red-100 text-red-700`:`bg-muted text-muted-foreground`),children:[j?(0,B.jsx)(t,{className:`size-3.5`}):null,j?`高危可操作`:`只读分享`]}),(0,B.jsx)(`span`,{className:S(j?`text-red-800`:`text-muted-foreground`),children:j?`正在操作分享者的原始对话`:`只能查看,不能发送或修改`})]}),j?null:(0,B.jsx)(`div`,{className:`mt-1 text-xs leading-5 text-muted-foreground`,children:`界面与正常对话保持一致`})]}),(0,B.jsxs)(p,{variant:`ghost`,size:`sm`,className:S(`shrink-0`,j?`text-red-700 hover:bg-red-100 hover:text-red-800`:void 0),onClick:()=>void v(window.location.href),"aria-label":j?`复制高危分享链接`:`复制分享链接`,title:j?`复制高危分享链接`:`复制分享链接`,children:[(0,B.jsx)(r,{className:`size-4`}),(0,B.jsx)(`span`,{className:`hidden sm:inline`,children:j?`复制高危链接`:`复制链接`})]})]})}),d?(0,B.jsx)(`div`,{className:`mx-auto w-full max-w-4xl px-4 py-2 text-sm text-destructive`,children:d}):null,(0,B.jsx)(k,{agent:a,revision:0,agentAccessMode:N?`full-access`:`default`,workspaceToolsEnabled:N,onModelSelect:I,onAccessModeChange:()=>void 0,onRollbackFromMessage:L,onRetryFromMessage:()=>void 0,onCopyAnswer:F,onForkFromMessage:()=>void 0,onApproveToolCall:()=>void 0,onRejectToolCall:()=>void 0,disableFork:!0,rollbackConfirmTitle:T(`sharedRollbackConfirmTitle`),rollbackConfirmDescription:T(`sharedRollbackConfirm`),readOnly:!j,restoredDraft:b,bypassClientApiKeyCheck:!0})]}):(0,B.jsx)(`div`,{className:`flex min-h-screen items-center justify-center bg-background p-6 text-foreground`,children:(0,B.jsxs)(`div`,{className:`w-full max-w-md rounded-2xl border border-border bg-background p-6 shadow-quickforge`,children:[(0,B.jsxs)(`div`,{className:`flex items-center gap-2 text-base font-semibold`,children:[(0,B.jsx)(t,{className:`size-5 text-amber-500`}),`QuickForge 局域网对话分享`]}),(0,B.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`如果分享者设置了密码,请输入密码。未设置密码的链接会自动打开。`}),(0,B.jsx)(`input`,{type:`password`,value:n,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&P()},className:`mt-5 h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-primary`,placeholder:`密码`,autoFocus:!0}),d?(0,B.jsx)(`div`,{className:`mt-3 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:d}):null,(0,B.jsx)(p,{className:`mt-5 w-full`,onClick:()=>void P(),disabled:g||!n.trim(),children:g?T(`loading`):`用密码打开分享对话`})]})})}export{G as SharedConversationPage};
|