farming-code 2.2.11 → 2.2.12

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 (34) hide show
  1. package/README.md +8 -7
  2. package/README.zh_cn.md +8 -7
  3. package/backend/agent-manager.js +104 -5
  4. package/backend/codex-session-archive.js +13 -4
  5. package/backend/config-manager.js +5 -0
  6. package/backend/executable-discovery.js +2 -0
  7. package/backend/server.js +62 -0
  8. package/backend/usage-monitor.js +97 -15
  9. package/backend/workspace-directory.js +80 -0
  10. package/dist/assets/App-DWsa7DXG.js +206 -0
  11. package/dist/assets/{FileEditorMarkdownPreview--Cri80nQ.js → FileEditorMarkdownPreview-UlVd0O4D.js} +1 -1
  12. package/dist/assets/FileEditorPane-Dxx4rKOg.js +2 -0
  13. package/dist/assets/IconGlyphs-AU22gPDY.js +1 -0
  14. package/dist/assets/{ProjectFilesSection-Cz1wG4NT.js → ProjectFilesSection-DE7Nb9Jk.js} +3 -3
  15. package/dist/assets/ReviewPage-CeDKDyZh.js +3 -0
  16. package/dist/assets/code-dark-DPiuyeSp.css +1 -0
  17. package/dist/assets/{index-miO2r9IZ.js → index-CUFPJoa5.js} +2 -2
  18. package/dist/assets/main-Bqtb5kuz.css +1 -0
  19. package/dist/assets/{monaco.contribution-CyLosfZI.js → monaco.contribution-BXz-lfFB.js} +2 -2
  20. package/dist/assets/{tsMode-DGZTlTj8.js → tsMode-B0oUTcXQ.js} +1 -1
  21. package/dist/assets/workspace-editor-monaco-BICJESG0.js +4 -0
  22. package/dist/assets/workspace-editor-monaco-DRJ7IaXk.js +1 -0
  23. package/dist/farming-2/site.webmanifest +2 -0
  24. package/dist/index.html +1 -1
  25. package/frontend/skins/crt/app.js +2 -0
  26. package/package.json +1 -1
  27. package/dist/assets/App-CHYpgECZ.js +0 -208
  28. package/dist/assets/FileEditorPane-DGJlEKdf.js +0 -2
  29. package/dist/assets/IconGlyphs-Cc14sepw.js +0 -1
  30. package/dist/assets/ReviewPage-LonRc6Fz.js +0 -3
  31. package/dist/assets/code-dark-B1pAtO_P.css +0 -1
  32. package/dist/assets/main-DNe0jPw-.css +0 -1
  33. package/dist/assets/workspace-editor-monaco-5gFbeDPF.js +0 -1
  34. package/dist/assets/workspace-editor-monaco-xPv8JzHH.js +0 -4
@@ -5,6 +5,7 @@ const path = require('path');
5
5
 
6
6
  const CREATE_FORBIDDEN_CODES = new Set(['EACCES', 'EPERM', 'EROFS']);
7
7
  const INVALID_PATH_CODES = new Set(['EINVAL', 'ENAMETOOLONG']);
8
+ const DEFAULT_BROWSE_LIMIT = 500;
8
9
 
9
10
  function resolveWorkspaceDirectory(value, homeDir = process.env.HOME || os.homedir()) {
10
11
  const input = typeof value === 'string' ? value.trim() : '';
@@ -131,9 +132,87 @@ async function prepareWorkspaceDirectory(value, options = {}) {
131
132
  }
132
133
  }
133
134
 
135
+ async function browseWorkspaceDirectory(value, options = {}) {
136
+ const workspace = resolveWorkspaceDirectory(value || '~', options.homeDir);
137
+ const fileSystem = options.fileSystem || fs.promises;
138
+ let entries;
139
+ try {
140
+ const stat = await fileSystem.stat(workspace);
141
+ if (!stat.isDirectory()) {
142
+ return {
143
+ status: 409,
144
+ body: {
145
+ status: 'rejected',
146
+ code: 'workspace-not-directory',
147
+ workspace,
148
+ message: `Workspace path is not a directory: ${workspace}`,
149
+ },
150
+ };
151
+ }
152
+ entries = await fileSystem.readdir(workspace, { withFileTypes: true });
153
+ } catch (error) {
154
+ const forbidden = CREATE_FORBIDDEN_CODES.has(error?.code);
155
+ const missing = error?.code === 'ENOENT';
156
+ return {
157
+ status: forbidden ? 403 : missing ? 404 : 500,
158
+ body: {
159
+ status: 'rejected',
160
+ code: forbidden
161
+ ? 'workspace-browse-forbidden'
162
+ : missing
163
+ ? 'workspace-not-found'
164
+ : 'workspace-browse-failed',
165
+ workspace,
166
+ message: forbidden
167
+ ? `Farming does not have permission to read this directory: ${workspace}`
168
+ : missing
169
+ ? `Workspace directory does not exist: ${workspace}`
170
+ : `Failed to read workspace directory: ${workspace}`,
171
+ },
172
+ };
173
+ }
174
+
175
+ const directories = (await Promise.all(entries.map(async (entry) => {
176
+ if (!entry.isDirectory() && !entry.isSymbolicLink()) return null;
177
+ const childPath = path.join(workspace, entry.name);
178
+ if (entry.isSymbolicLink()) {
179
+ try {
180
+ const stat = await fileSystem.stat(childPath);
181
+ if (!stat.isDirectory()) return null;
182
+ } catch {
183
+ return null;
184
+ }
185
+ }
186
+ return { name: entry.name, path: childPath };
187
+ })))
188
+ .filter(Boolean)
189
+ .sort((left, right) => left.name.localeCompare(right.name));
190
+ const limit = Math.max(1, Math.min(Number(options.limit) || DEFAULT_BROWSE_LIMIT, DEFAULT_BROWSE_LIMIT));
191
+ const parentPath = path.dirname(workspace);
192
+
193
+ return {
194
+ status: 200,
195
+ body: {
196
+ status: 'ready',
197
+ workspace,
198
+ parent: parentPath === workspace ? null : parentPath,
199
+ directories: directories.slice(0, limit),
200
+ truncated: directories.length > limit,
201
+ },
202
+ };
203
+ }
204
+
134
205
  function createWorkspaceDirectoryRouter(options = {}) {
135
206
  const router = express.Router();
136
207
  router.use(express.json({ limit: '8kb' }));
208
+ router.get('/browse', async (req, res) => {
209
+ const result = await browseWorkspaceDirectory(req.query?.path, {
210
+ fileSystem: options.fileSystem,
211
+ homeDir: options.homeDir,
212
+ limit: req.query?.limit,
213
+ });
214
+ res.status(result.status).json(result.body);
215
+ });
137
216
  router.post('/prepare', async (req, res) => {
138
217
  const result = await prepareWorkspaceDirectory(req.body?.workspace, {
139
218
  create: req.body?.create === true,
@@ -146,6 +225,7 @@ function createWorkspaceDirectoryRouter(options = {}) {
146
225
  }
147
226
 
148
227
  module.exports = {
228
+ browseWorkspaceDirectory,
149
229
  createWorkspaceDirectoryRouter,
150
230
  prepareWorkspaceDirectory,
151
231
  resolveWorkspaceDirectory,