@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.
Files changed (26) hide show
  1. package/README.md +21 -15
  2. package/bin/quickforge.mjs +11 -1
  3. package/dist/assets/{anthropic-u1nbNXhV.js → anthropic-By-wpU1w.js} +1 -1
  4. package/dist/assets/{azure-openai-responses-DQ6xSOmb.js → azure-openai-responses-C8spS__i.js} +1 -1
  5. package/dist/assets/{confirm-dialog-DSmrqQ60.js → confirm-dialog-4mZt9XEq.js} +1 -1
  6. package/dist/assets/{google-OeyKMN12.js → google-DiIcyajo.js} +1 -1
  7. package/dist/assets/{google-gemini-cli-SnPixyBu.js → google-gemini-cli-BXZFGMXD.js} +1 -1
  8. package/dist/assets/{google-vertex-y0o2eCZV.js → google-vertex-D93MV5Cx.js} +1 -1
  9. package/dist/assets/{index-CK_34smc.js → index-Bq6VHkyY.js} +473 -473
  10. package/dist/assets/index-D7uXa1RT.css +3 -0
  11. package/dist/assets/{mistral-DzE_jn-B.js → mistral-BAJNGYqd.js} +1 -1
  12. package/dist/assets/{openai-codex-responses-MtFRvp_b.js → openai-codex-responses-BHHCy65K.js} +1 -1
  13. package/dist/assets/{openai-completions-C2dhwzO8.js → openai-completions-BtZAvOiJ.js} +1 -1
  14. package/dist/assets/{openai-responses-C4n0VhzY.js → openai-responses-CP9-AyAD.js} +1 -1
  15. package/dist/assets/{openai-responses-shared-D2RkRvTj.js → openai-responses-shared-_z7sua8J.js} +1 -1
  16. package/dist/assets/{prompt-dialog-B4BD09Oc.js → prompt-dialog-BGMKszUz.js} +1 -1
  17. package/dist/index.html +2 -2
  18. package/package.json +1 -1
  19. package/server/index.mjs +8 -6
  20. package/server/project-config.mjs +11 -30
  21. package/server/routes/project.mjs +6 -12
  22. package/server/routes/storage.mjs +9 -3
  23. package/server/storage.mjs +343 -139
  24. package/server/utils/platform.mjs +1 -1
  25. package/server/utils/response.mjs +1 -1
  26. 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 { migrateLegacyDataDirs, ensureStorage, dataDir, storageDir } from './storage.mjs'
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 || process.env.FASTCODE_HOST || '127.0.0.1'
25
- const port = Number(process.env.QUICKFORGE_PORT || process.env.FASTCODE_PORT || (isDev ? 32176 : 5176))
26
- const vitePort = Number(process.env.QUICKFORGE_VITE_PORT || process.env.FASTCODE_VITE_PORT || 5176)
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 || process.env.FASTCODE_WORKSPACE_DIR || projectRoot)
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 { ensureStorage, projectConfigFile, dataDir } from './storage.mjs'
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: id,
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 ensureStorage()
35
- const file = projectConfigFile()
36
- try {
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 ensureStorage()
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
- const fallback = await setActiveProjectPath(defaultWorkspaceRoot)
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.length ? nextProjects : defaultProjectConfigFallback().projects
57
- if (config.activeProjectId === id) config.activeProjectId = config.projects[0].id
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
- setWorkspaceRoot(path.resolve(active.path))
61
- sendJson(res, 200, { project: active, projects: config.projects, workspaceRoot: getWorkspaceRoot() })
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 directorySize(storageDir)
11
- sendJson(res, 200, { usage, quota: 0, percent: 0 })
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