@agentbean/daemon 0.1.8 → 0.1.9

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.
@@ -1,10 +1,23 @@
1
- import { readdirSync, statSync, existsSync } from 'node:fs';
1
+ import { readdirSync, realpathSync, statSync, existsSync } from 'node:fs';
2
2
  import { isAbsolute, join, resolve } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { logger } from './log.js';
5
5
  const CODE_BLOCK_RE = /```python\n([\s\S]*?)```/g;
6
6
  const CODEX_IMG_DIR = join(homedir(), '.codex', 'generated_images');
7
7
  const OUTPUT_FILE_EXT_RE = /\.(png|jpe?g|gif|webp|svg|pdf|txt|csv|json|md|mp4|mov|zip)$/i;
8
+ const IGNORED_OUTPUT_DIRS = new Set([
9
+ '.git',
10
+ '.hg',
11
+ '.svn',
12
+ '.cache',
13
+ '.next',
14
+ '.nuxt',
15
+ '.turbo',
16
+ 'node_modules',
17
+ 'vendor',
18
+ ]);
19
+ const MAX_OUTPUT_FILES_PER_ROOT = 2000;
20
+ const OUTPUT_DIR_ENV = 'AGENT_BEAN_OUTPUT_DIRS';
8
21
  export function listAllFiles(dir, maxDepth = 10, depth = 0) {
9
22
  if (!existsSync(dir) || depth > maxDepth)
10
23
  return [];
@@ -13,10 +26,15 @@ export function listAllFiles(dir, maxDepth = 10, depth = 0) {
13
26
  const full = join(dir, entry.name);
14
27
  if (entry.isSymbolicLink())
15
28
  continue;
16
- if (entry.isDirectory())
29
+ if (entry.isDirectory()) {
30
+ if (IGNORED_OUTPUT_DIRS.has(entry.name))
31
+ continue;
17
32
  results.push(...listAllFiles(full, maxDepth, depth + 1));
33
+ }
18
34
  else
19
35
  results.push(full);
36
+ if (results.length >= MAX_OUTPUT_FILES_PER_ROOT)
37
+ break;
20
38
  }
21
39
  return results;
22
40
  }
@@ -59,41 +77,85 @@ function extractMentionedFiles(reply, workspace, dispatchStart) {
59
77
  }
60
78
  return files;
61
79
  }
62
- export async function postProcess(reply, workspace, kind, dispatchStart) {
63
- const outputFiles = new Set();
64
- // Codex native image detection
65
- if (kind === 'codex') {
66
- const allCodexFiles = listAllFiles(CODEX_IMG_DIR);
67
- for (const f of allCodexFiles) {
80
+ function outputDirsFromEnv() {
81
+ const raw = process.env[OUTPUT_DIR_ENV];
82
+ if (!raw?.trim())
83
+ return [];
84
+ return raw
85
+ .split(/[,:;]/)
86
+ .map((item) => item.trim())
87
+ .filter(Boolean);
88
+ }
89
+ function canonicalPath(path) {
90
+ try {
91
+ return realpathSync(path);
92
+ }
93
+ catch {
94
+ return path;
95
+ }
96
+ }
97
+ function resolveOutputRoots(workspace, outputDirs = []) {
98
+ const roots = new Set();
99
+ if (workspace)
100
+ roots.add(resolve(workspace));
101
+ for (const raw of [...outputDirs, ...outputDirsFromEnv()]) {
102
+ const expanded = raw.replace(/^~(?=$|\/)/, homedir());
103
+ const root = isAbsolute(expanded)
104
+ ? expanded
105
+ : workspace
106
+ ? resolve(workspace, expanded)
107
+ : resolve(expanded);
108
+ roots.add(root);
109
+ }
110
+ return [...roots].filter((root) => {
111
+ try {
112
+ return statSync(root).isDirectory();
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ });
118
+ }
119
+ function collectRecentOutputFiles(roots, dispatchStart) {
120
+ const files = new Set();
121
+ for (const root of roots) {
122
+ for (const filePath of listAllFiles(root, 8)) {
123
+ if (!OUTPUT_FILE_EXT_RE.test(filePath))
124
+ continue;
68
125
  try {
69
- const st = statSync(f);
70
- if (st.mtimeMs > dispatchStart) {
71
- outputFiles.add(f);
126
+ const st = statSync(filePath);
127
+ if (st.isFile() && st.mtimeMs > dispatchStart) {
128
+ files.add(canonicalPath(filePath));
72
129
  }
73
130
  }
74
131
  catch { }
75
132
  }
76
133
  }
77
- for (const filePath of extractMentionedFiles(reply, workspace, dispatchStart)) {
78
- outputFiles.add(filePath);
79
- }
80
- // Detect files created during this dispatch
81
- if (workspace) {
82
- for (const entry of readdirSync(workspace, { withFileTypes: true })) {
83
- if (entry.isDirectory())
84
- continue;
85
- const f = join(workspace, entry.name);
86
- if (entry.name.startsWith('.agentbean-exec-'))
134
+ return [...files];
135
+ }
136
+ export async function postProcess(reply, workspace, kind, dispatchStart, options = {}) {
137
+ const outputFiles = new Set();
138
+ // Codex native image detection
139
+ if (kind === 'codex') {
140
+ const allCodexFiles = listAllFiles(CODEX_IMG_DIR, 4);
141
+ for (const f of allCodexFiles) {
142
+ if (!OUTPUT_FILE_EXT_RE.test(f))
87
143
  continue;
88
144
  try {
89
145
  const st = statSync(f);
90
146
  if (st.mtimeMs > dispatchStart) {
91
- outputFiles.add(f);
147
+ outputFiles.add(canonicalPath(f));
92
148
  }
93
149
  }
94
150
  catch { }
95
151
  }
96
152
  }
153
+ for (const filePath of extractMentionedFiles(reply, workspace, dispatchStart)) {
154
+ outputFiles.add(canonicalPath(filePath));
155
+ }
156
+ for (const filePath of collectRecentOutputFiles(resolveOutputRoots(workspace, options.outputDirs), dispatchStart)) {
157
+ outputFiles.add(filePath);
158
+ }
97
159
  // Extract code blocks for logging but do NOT auto-execute (security)
98
160
  if (workspace) {
99
161
  const codeBlocks = [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agentbean/daemon",
3
3
  "private": false,
4
- "version": "0.1.8",
4
+ "version": "0.1.9",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {