@shawnstack/quickforge 1.0.0 → 1.1.0
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 +21 -15
- package/bin/quickforge.mjs +11 -1
- package/dist/assets/{anthropic-u1nbNXhV.js → anthropic-By-wpU1w.js} +1 -1
- package/dist/assets/{azure-openai-responses-DQ6xSOmb.js → azure-openai-responses-C8spS__i.js} +1 -1
- package/dist/assets/{confirm-dialog-DSmrqQ60.js → confirm-dialog-4mZt9XEq.js} +1 -1
- package/dist/assets/{google-OeyKMN12.js → google-DiIcyajo.js} +1 -1
- package/dist/assets/{google-gemini-cli-SnPixyBu.js → google-gemini-cli-BXZFGMXD.js} +1 -1
- package/dist/assets/{google-vertex-y0o2eCZV.js → google-vertex-D93MV5Cx.js} +1 -1
- package/dist/assets/{index-CK_34smc.js → index-Bq6VHkyY.js} +473 -473
- package/dist/assets/index-D7uXa1RT.css +3 -0
- package/dist/assets/{mistral-DzE_jn-B.js → mistral-BAJNGYqd.js} +1 -1
- package/dist/assets/{openai-codex-responses-MtFRvp_b.js → openai-codex-responses-BHHCy65K.js} +1 -1
- package/dist/assets/{openai-completions-C2dhwzO8.js → openai-completions-BtZAvOiJ.js} +1 -1
- package/dist/assets/{openai-responses-C4n0VhzY.js → openai-responses-CP9-AyAD.js} +1 -1
- package/dist/assets/{openai-responses-shared-D2RkRvTj.js → openai-responses-shared-_z7sua8J.js} +1 -1
- package/dist/assets/{prompt-dialog-B4BD09Oc.js → prompt-dialog-BGMKszUz.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/index.mjs +8 -6
- package/server/project-config.mjs +11 -30
- package/server/routes/project.mjs +6 -12
- package/server/routes/storage.mjs +9 -3
- package/server/storage.mjs +343 -139
- package/server/utils/platform.mjs +1 -1
- package/server/utils/response.mjs +1 -1
- package/dist/assets/index-BQJ8qi1U.css +0 -3
package/server/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'node:path'
|
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
import { sendJson, sendError } from './utils/response.mjs'
|
|
7
7
|
import { openBrowser } from './utils/platform.mjs'
|
|
8
|
-
import {
|
|
8
|
+
import { ensureStorage, dataDir, configDir, storageDir, cacheDir, logsDir } from './storage.mjs'
|
|
9
9
|
import { setDefaultWorkspaceRoot, initializeActiveProject, readProjectConfig, getActiveProject } from './project-config.mjs'
|
|
10
10
|
import { getWorkspaceRoot } from './utils/workspace.mjs'
|
|
11
11
|
import { handleStorageApi } from './routes/storage.mjs'
|
|
@@ -21,11 +21,11 @@ const __dirname = path.dirname(__filename)
|
|
|
21
21
|
const projectRoot = path.resolve(__dirname, '..')
|
|
22
22
|
|
|
23
23
|
const isDev = process.argv.includes('--dev')
|
|
24
|
-
const host = process.env.QUICKFORGE_HOST ||
|
|
25
|
-
const port = Number(process.env.QUICKFORGE_PORT ||
|
|
26
|
-
const vitePort = Number(process.env.QUICKFORGE_VITE_PORT ||
|
|
24
|
+
const host = process.env.QUICKFORGE_HOST || '127.0.0.1'
|
|
25
|
+
const port = Number(process.env.QUICKFORGE_PORT || (isDev ? 32176 : 5176))
|
|
26
|
+
const vitePort = Number(process.env.QUICKFORGE_VITE_PORT || 5176)
|
|
27
27
|
|
|
28
|
-
setDefaultWorkspaceRoot(process.env.QUICKFORGE_WORKSPACE_DIR ||
|
|
28
|
+
setDefaultWorkspaceRoot(process.env.QUICKFORGE_WORKSPACE_DIR || projectRoot)
|
|
29
29
|
|
|
30
30
|
// --- Route dispatching ---
|
|
31
31
|
async function handleApi(req, res, url) {
|
|
@@ -39,7 +39,10 @@ async function handleApi(req, res, url) {
|
|
|
39
39
|
ok: true,
|
|
40
40
|
mode: isDev ? 'development' : 'production',
|
|
41
41
|
dataDir,
|
|
42
|
+
configDir,
|
|
42
43
|
storageDir,
|
|
44
|
+
cacheDir,
|
|
45
|
+
logsDir,
|
|
43
46
|
workspaceRoot: getWorkspaceRoot(),
|
|
44
47
|
project: getActiveProject(config),
|
|
45
48
|
})
|
|
@@ -126,7 +129,6 @@ const server = createServer(async (req, res) => {
|
|
|
126
129
|
}
|
|
127
130
|
})
|
|
128
131
|
|
|
129
|
-
await migrateLegacyDataDirs()
|
|
130
132
|
await ensureStorage()
|
|
131
133
|
await initializeActiveProject()
|
|
132
134
|
setActiveWorkspaceRootForFilesystem(getWorkspaceRoot())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { randomUUID } from 'node:crypto'
|
|
3
|
-
import {
|
|
3
|
+
import { ensureProjectCache, readProjectConfigData, writeProjectConfigData } from './storage.mjs'
|
|
4
4
|
import { promises as fs } from 'node:fs'
|
|
5
5
|
import { setWorkspaceRoot, getWorkspaceRoot, assertDirectory } from './utils/workspace.mjs'
|
|
6
6
|
|
|
@@ -15,41 +15,20 @@ function projectNameFromPath(dir) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function defaultProjectConfig() {
|
|
18
|
-
const now = new Date().toISOString()
|
|
19
|
-
const id = 'default'
|
|
20
18
|
return {
|
|
21
|
-
activeProjectId:
|
|
22
|
-
projects: [
|
|
23
|
-
{
|
|
24
|
-
id,
|
|
25
|
-
name: projectNameFromPath(defaultWorkspaceRoot),
|
|
26
|
-
path: defaultWorkspaceRoot,
|
|
27
|
-
lastOpenedAt: now,
|
|
28
|
-
},
|
|
29
|
-
],
|
|
19
|
+
activeProjectId: null,
|
|
20
|
+
projects: [],
|
|
30
21
|
}
|
|
31
22
|
}
|
|
32
23
|
|
|
33
24
|
export async function readProjectConfig() {
|
|
34
|
-
await
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const text = await fs.readFile(file, 'utf8')
|
|
38
|
-
const parsed = text.trim() ? JSON.parse(text) : defaultProjectConfig()
|
|
39
|
-
if (!Array.isArray(parsed.projects) || parsed.projects.length === 0) return defaultProjectConfig()
|
|
40
|
-
return parsed
|
|
41
|
-
} catch (error) {
|
|
42
|
-
if (error?.code === 'ENOENT') return defaultProjectConfig()
|
|
43
|
-
throw error
|
|
44
|
-
}
|
|
25
|
+
const parsed = await readProjectConfigData()
|
|
26
|
+
if (!Array.isArray(parsed.projects) || parsed.projects.length === 0) return defaultProjectConfig()
|
|
27
|
+
return parsed
|
|
45
28
|
}
|
|
46
29
|
|
|
47
30
|
export async function writeProjectConfig(config) {
|
|
48
|
-
await
|
|
49
|
-
const file = projectConfigFile()
|
|
50
|
-
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`
|
|
51
|
-
await fs.writeFile(tmp, `${JSON.stringify(config, null, 2)}\n`, 'utf8')
|
|
52
|
-
await fs.rename(tmp, file)
|
|
31
|
+
await writeProjectConfigData(config)
|
|
53
32
|
}
|
|
54
33
|
|
|
55
34
|
export function getActiveProject(config) {
|
|
@@ -80,6 +59,7 @@ export async function setActiveProjectPath(inputPath) {
|
|
|
80
59
|
config.activeProjectId = project.id
|
|
81
60
|
config.projects = [project, ...config.projects.filter((item) => item.id !== project.id)].slice(0, 20)
|
|
82
61
|
await writeProjectConfig(config)
|
|
62
|
+
await ensureProjectCache(project.id)
|
|
83
63
|
setWorkspaceRoot(resolved)
|
|
84
64
|
return { project, projects: config.projects }
|
|
85
65
|
}
|
|
@@ -90,6 +70,7 @@ export async function initializeActiveProject() {
|
|
|
90
70
|
if (activeProject?.path) {
|
|
91
71
|
try {
|
|
92
72
|
await assertDirectory(activeProject.path)
|
|
73
|
+
await ensureProjectCache(activeProject.id)
|
|
93
74
|
setWorkspaceRoot(path.resolve(activeProject.path))
|
|
94
75
|
return
|
|
95
76
|
} catch {
|
|
@@ -97,8 +78,7 @@ export async function initializeActiveProject() {
|
|
|
97
78
|
}
|
|
98
79
|
}
|
|
99
80
|
|
|
100
|
-
|
|
101
|
-
setWorkspaceRoot(path.resolve(fallback.project.path))
|
|
81
|
+
// No project configured — leave workspace unset, user will be prompted to add one.
|
|
102
82
|
}
|
|
103
83
|
|
|
104
84
|
export async function projectContextFromId(projectId) {
|
|
@@ -111,6 +91,7 @@ export async function projectContextFromId(projectId) {
|
|
|
111
91
|
}
|
|
112
92
|
|
|
113
93
|
await assertDirectory(project.path)
|
|
94
|
+
await ensureProjectCache(project.id)
|
|
114
95
|
return { project, workspaceRoot: path.resolve(project.path) }
|
|
115
96
|
}
|
|
116
97
|
|
|
@@ -53,12 +53,14 @@ export async function handleProjectApi(req, res, url) {
|
|
|
53
53
|
error.statusCode = 404
|
|
54
54
|
throw error
|
|
55
55
|
}
|
|
56
|
-
config.projects = nextProjects
|
|
57
|
-
if (config.activeProjectId === id) config.activeProjectId = config.projects[0]
|
|
56
|
+
config.projects = nextProjects
|
|
57
|
+
if (config.activeProjectId === id) config.activeProjectId = config.projects[0]?.id ?? null
|
|
58
58
|
await writeProjectConfig(config)
|
|
59
59
|
const active = getActiveProject(config)
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
if (active?.path) {
|
|
61
|
+
setWorkspaceRoot(path.resolve(active.path))
|
|
62
|
+
}
|
|
63
|
+
sendJson(res, 200, { project: active ?? null, projects: config.projects, workspaceRoot: getWorkspaceRoot() })
|
|
62
64
|
return
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -66,11 +68,3 @@ export async function handleProjectApi(req, res, url) {
|
|
|
66
68
|
error.statusCode = 404
|
|
67
69
|
throw error
|
|
68
70
|
}
|
|
69
|
-
|
|
70
|
-
function defaultProjectConfigFallback() {
|
|
71
|
-
const fallbackPath = getWorkspaceRoot()
|
|
72
|
-
return {
|
|
73
|
-
activeProjectId: 'default',
|
|
74
|
-
projects: [{ id: 'default', name: path.basename(fallbackPath) || 'QuickForge', path: fallbackPath, lastOpenedAt: new Date().toISOString() }],
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
|
|
3
|
-
import { readStore, writeStore, getComparable, storageDir } from '../storage.mjs'
|
|
3
|
+
import { readStore, writeStore, getComparable, dataDir, configDir, storageDir, cacheDir, logsDir } from '../storage.mjs'
|
|
4
4
|
import { directorySize } from '../utils/workspace.mjs'
|
|
5
5
|
|
|
6
6
|
export async function handleStorageApi(req, res, url) {
|
|
7
7
|
const parts = url.pathname.split('/').filter(Boolean)
|
|
8
8
|
|
|
9
9
|
if (req.method === 'GET' && url.pathname === '/api/storage/quota') {
|
|
10
|
-
const usage = await
|
|
11
|
-
|
|
10
|
+
const [usage, configUsage, storageUsage, cacheUsage, logsUsage] = await Promise.all([
|
|
11
|
+
directorySize(dataDir),
|
|
12
|
+
directorySize(configDir),
|
|
13
|
+
directorySize(storageDir),
|
|
14
|
+
directorySize(cacheDir),
|
|
15
|
+
directorySize(logsDir),
|
|
16
|
+
])
|
|
17
|
+
sendJson(res, 200, { usage, configUsage, storageUsage, cacheUsage, logsUsage, quota: 0, percent: 0 })
|
|
12
18
|
return
|
|
13
19
|
}
|
|
14
20
|
|