@causyne/agent 1.10.21 → 1.11.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/native-skills/media/professional-document-publishing/SKILL.md +44 -0
- package/native-skills/media/screenplay-and-shotlist-forge/SKILL.md +42 -0
- package/package.json +1 -1
- package/src/acp/client.js +235 -0
- package/src/acp/client.ts +282 -0
- package/src/acp/peerProfiles.js +122 -0
- package/src/acp/peerProfiles.ts +128 -0
- package/src/acp/protocol.js +54 -0
- package/src/acp/protocol.ts +434 -0
- package/src/acp/server.js +609 -0
- package/src/acp/server.ts +676 -0
- package/src/agentLoop.d.ts +43 -0
- package/src/agentLoop.js +142 -8
- package/src/commands.js +203 -0
- package/src/compiledSkills.js +10 -0
- package/src/documentEngine/antiSlopAuditor.js +156 -0
- package/src/documentEngine/antiSlopAuditor.ts +221 -0
- package/src/documentEngine/documentForge.js +443 -0
- package/src/documentEngine/documentForge.ts +519 -0
- package/src/documentEngine/screenplayFormatter.js +336 -0
- package/src/documentEngine/screenplayFormatter.ts +407 -0
- package/src/entrypoint.js +13 -0
- package/src/execSafe.js +10 -13
- package/src/execSafe.ts +25 -0
- package/src/modelRouter.js +56 -123
- package/src/modelRouter.ts +134 -0
- package/src/observer/advisory.js +164 -0
- package/src/observer/advisory.ts +171 -0
- package/src/observer/coldObserver.js +462 -0
- package/src/observer/coldObserver.ts +540 -0
- package/src/observer/evidence.js +435 -0
- package/src/observer/evidence.ts +499 -0
- package/src/perception.js +303 -118
- package/src/perception.ts +387 -0
- package/src/procSignal.js +15 -16
- package/src/procSignal.ts +31 -0
- package/src/promptMentions.js +170 -0
- package/src/promptMentions.ts +212 -0
- package/src/sandbox.js +1 -1
- package/src/textDiff.js +117 -109
- package/src/textDiff.ts +169 -0
- package/src/toolPacks.js +5 -2
- package/src/tools/documentForge.js +215 -0
- package/src/tools/documentForge.ts +265 -0
- package/src/tools/peerAgent.js +102 -0
- package/src/tools/peerAgent.ts +116 -0
- package/src/tools/registry.js +3 -1
- package/src/tui/completion.js +97 -41
- package/src/tui/prompt.js +17 -17
- package/src/uncertainty.js +93 -205
- package/src/uncertainty.ts +255 -0
- package/src/utils/paths.js +15 -18
- package/src/utils/paths.ts +36 -0
- package/src/vfeTracker.js +122 -181
- package/src/vfeTracker.ts +242 -0
package/src/perception.js
CHANGED
|
@@ -1,124 +1,309 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
const SKIP_DIRECTORIES = new Set([
|
|
5
|
+
'node_modules', '.git', 'dist', 'build', 'out', 'target',
|
|
6
|
+
'.next', '.nuxt', '.venv', 'venv', '__pycache__', '.gradle',
|
|
7
|
+
'.idea', '.cache', 'coverage', 'vendor', 'Pods', '.causyne'
|
|
8
|
+
]);
|
|
5
9
|
export class WorkspacePerception {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
context.structure = await this.getDirectoryTree(resolvedPath, 2);
|
|
12
|
-
|
|
13
|
-
// 2. Framework detection
|
|
14
|
-
context.framework = await this.detectFramework(resolvedPath);
|
|
15
|
-
|
|
16
|
-
// 2b. Design system detection (Anti-Slop: tells the brain what's already installed)
|
|
17
|
-
context.designSystem = await this.detectDesignContext(resolvedPath);
|
|
18
|
-
|
|
19
|
-
// 3. Package/dependency context
|
|
20
|
-
try {
|
|
21
|
-
const pkgPath = path.join(resolvedPath, 'package.json');
|
|
22
|
-
const pkgStats = await fs.stat(pkgPath);
|
|
23
|
-
if (pkgStats.isFile()) {
|
|
24
|
-
const pkgData = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
25
|
-
context.packageJson = {
|
|
26
|
-
name: pkgData.name,
|
|
27
|
-
dependencies: pkgData.dependencies || {},
|
|
28
|
-
devDependencies: pkgData.devDependencies || {},
|
|
29
|
-
scripts: pkgData.scripts || {}
|
|
10
|
+
async buildContext(workspacePath) {
|
|
11
|
+
const resolvedPath = workspacePath.replace(/^~\//, os.homedir() + '/');
|
|
12
|
+
const context = {
|
|
13
|
+
cwd: resolvedPath,
|
|
14
|
+
projectName: path.basename(resolvedPath)
|
|
30
15
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
16
|
+
// 1. Directory structure (tree, max depth 2 to keep context size manageable)
|
|
17
|
+
context.structure = await this.getDirectoryTree(resolvedPath, 2);
|
|
18
|
+
// 2. Framework detection
|
|
19
|
+
const fw = await this.detectFramework(resolvedPath);
|
|
20
|
+
if (fw && fw.type !== 'unknown') {
|
|
21
|
+
const fwStr = `${fw.type} (${fw.language})`;
|
|
22
|
+
context.framework = Object.assign(new String(fwStr), {
|
|
23
|
+
type: fw.type,
|
|
24
|
+
language: fw.language,
|
|
25
|
+
toString: () => fwStr
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
context.framework = null;
|
|
30
|
+
}
|
|
31
|
+
// 2b. Design system detection (Anti-Slop: tells the brain what's already installed)
|
|
32
|
+
context.designSystem = await this.detectDesignContext(resolvedPath);
|
|
33
|
+
// 2c. Subprojects detection (find subfolders like 'pixel2d games', 'causyne-agent', etc.)
|
|
34
|
+
context.subprojects = await this.detectSubprojects(resolvedPath);
|
|
35
|
+
// 2d. Key files discovery
|
|
36
|
+
context.keyFiles = await this.detectKeyFiles(resolvedPath);
|
|
37
|
+
// 2e. Package manager detection
|
|
38
|
+
context.packageManager = await this.detectPackageManager(resolvedPath);
|
|
39
|
+
// 2f. Git branch and status
|
|
40
|
+
const gitInfo = await this.detectGitInfo(resolvedPath);
|
|
41
|
+
if (gitInfo.branch)
|
|
42
|
+
context.gitBranch = gitInfo.branch;
|
|
43
|
+
if (gitInfo.status)
|
|
44
|
+
context.gitStatus = gitInfo.status;
|
|
45
|
+
// 3. Package/dependency context
|
|
46
|
+
try {
|
|
47
|
+
const pkgPath = path.join(resolvedPath, 'package.json');
|
|
48
|
+
const pkgStats = await fs.stat(pkgPath);
|
|
49
|
+
if (pkgStats.isFile()) {
|
|
50
|
+
const raw = await fs.readFile(pkgPath, 'utf8');
|
|
51
|
+
const pkgData = JSON.parse(raw);
|
|
52
|
+
context.packageJson = {
|
|
53
|
+
name: pkgData.name,
|
|
54
|
+
dependencies: pkgData.dependencies || {},
|
|
55
|
+
devDependencies: pkgData.devDependencies || {},
|
|
56
|
+
scripts: pkgData.scripts || {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// ignore missing or invalid package.json
|
|
62
|
+
}
|
|
63
|
+
// 3b. Project type classification
|
|
64
|
+
context.projectType = await this.detectProjectType(resolvedPath, context);
|
|
65
|
+
// 4. README (first 1000 chars)
|
|
66
|
+
try {
|
|
67
|
+
const readmePath = path.join(resolvedPath, 'README.md');
|
|
68
|
+
const readmeContent = await fs.readFile(readmePath, 'utf8');
|
|
69
|
+
context.readme = readmeContent.slice(0, 1000) + (readmeContent.length > 1000 ? '...' : '');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// ignore
|
|
73
|
+
}
|
|
74
|
+
// 5. OS & environment
|
|
75
|
+
const osStr = `${os.platform()} (${os.arch()})`;
|
|
76
|
+
context.os = Object.assign(new String(osStr), {
|
|
77
|
+
platform: os.platform(),
|
|
78
|
+
arch: os.arch(),
|
|
79
|
+
toString: () => osStr
|
|
80
|
+
});
|
|
81
|
+
return context;
|
|
82
|
+
}
|
|
83
|
+
async getDirectoryTree(dir, maxDepth, currentDepth = 0) {
|
|
84
|
+
if (currentDepth > maxDepth)
|
|
85
|
+
return '... (max depth reached)';
|
|
86
|
+
try {
|
|
87
|
+
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
88
|
+
const tree = {};
|
|
89
|
+
let count = 0;
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
if (item.name.startsWith('.') || item.name === 'node_modules')
|
|
92
|
+
continue;
|
|
93
|
+
if (count >= 30) {
|
|
94
|
+
tree['...'] = `(${items.length - count} more items hidden)`;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
count++;
|
|
98
|
+
if (item.isDirectory()) {
|
|
99
|
+
tree[item.name] = await this.getDirectoryTree(path.join(dir, item.name), maxDepth, currentDepth + 1);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
tree[item.name] = 'file';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return tree;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
109
|
+
return `Error: ${msg}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async detectFramework(dir) {
|
|
113
|
+
const detectors = [
|
|
114
|
+
{ file: 'next.config.js', type: 'nextjs', lang: 'javascript' },
|
|
115
|
+
{ file: 'next.config.ts', type: 'nextjs', lang: 'typescript' },
|
|
116
|
+
{ file: 'next.config.mjs', type: 'nextjs', lang: 'javascript' },
|
|
117
|
+
{ file: 'vite.config.ts', type: 'vite', lang: 'typescript' },
|
|
118
|
+
{ file: 'vite.config.js', type: 'vite', lang: 'javascript' },
|
|
119
|
+
{ file: 'nuxt.config.ts', type: 'nuxt', lang: 'typescript' },
|
|
120
|
+
{ file: 'astro.config.mjs', type: 'astro', lang: 'javascript' },
|
|
121
|
+
{ file: 'svelte.config.js', type: 'svelte', lang: 'javascript' },
|
|
122
|
+
{ file: 'tsconfig.json', type: 'node', lang: 'typescript' },
|
|
123
|
+
{ file: 'package.json', type: 'node', lang: 'javascript' },
|
|
124
|
+
{ file: 'manage.py', type: 'django', lang: 'python' },
|
|
125
|
+
{ file: 'pyproject.toml', type: 'python', lang: 'python' },
|
|
126
|
+
{ file: 'requirements.txt', type: 'python', lang: 'python' },
|
|
127
|
+
{ file: 'Cargo.toml', type: 'rust', lang: 'rust' },
|
|
128
|
+
{ file: 'go.mod', type: 'go', lang: 'go' },
|
|
129
|
+
{ file: 'project.godot', type: 'godot', lang: 'gdscript' },
|
|
130
|
+
{ file: 'build.gradle.kts', type: 'android', lang: 'kotlin' },
|
|
131
|
+
{ file: 'docker-compose.yml', type: 'docker', lang: 'various' },
|
|
132
|
+
];
|
|
133
|
+
for (const d of detectors) {
|
|
134
|
+
try {
|
|
135
|
+
await fs.access(path.join(dir, d.file));
|
|
136
|
+
return { type: d.type, language: d.lang };
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// ignore
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { type: 'unknown', language: 'unknown' };
|
|
143
|
+
}
|
|
144
|
+
async detectDesignContext(dir) {
|
|
145
|
+
const designDetectors = [
|
|
146
|
+
{ dep: 'tailwindcss', system: 'Tailwind CSS' },
|
|
147
|
+
{ dep: '@astryxdesign/core', system: 'Astryx Design System' },
|
|
148
|
+
{ dep: '@mui/material', system: 'Material-UI (MUI)' },
|
|
149
|
+
{ dep: '@chakra-ui/react', system: 'Chakra UI' },
|
|
150
|
+
{ dep: 'bootstrap', system: 'Bootstrap' },
|
|
151
|
+
{ dep: 'styled-components', system: 'Styled Components' },
|
|
152
|
+
{ dep: '@emotion/react', system: 'Emotion CSS-in-JS' },
|
|
153
|
+
];
|
|
154
|
+
try {
|
|
155
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
156
|
+
const raw = await fs.readFile(pkgPath, 'utf8');
|
|
157
|
+
const pkgData = JSON.parse(raw);
|
|
158
|
+
const allDeps = { ...pkgData.dependencies, ...pkgData.devDependencies };
|
|
159
|
+
const detected = designDetectors
|
|
160
|
+
.filter(d => Boolean(allDeps[d.dep]))
|
|
161
|
+
.map(d => d.system);
|
|
162
|
+
return detected.length > 0 ? detected : null;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async detectSubprojects(dir) {
|
|
169
|
+
const subprojects = [];
|
|
170
|
+
try {
|
|
171
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
172
|
+
for (const entry of entries) {
|
|
173
|
+
if (!entry.isDirectory())
|
|
174
|
+
continue;
|
|
175
|
+
if (entry.name.startsWith('.') || SKIP_DIRECTORIES.has(entry.name))
|
|
176
|
+
continue;
|
|
177
|
+
const subDir = path.join(dir, entry.name);
|
|
178
|
+
const markers = [
|
|
179
|
+
'package.json', 'index.html', 'project.godot', 'main.py',
|
|
180
|
+
'Cargo.toml', 'requirements.txt', 'go.mod', 'Makefile', 'CMakeLists.txt'
|
|
181
|
+
];
|
|
182
|
+
for (const marker of markers) {
|
|
183
|
+
try {
|
|
184
|
+
await fs.access(path.join(subDir, marker));
|
|
185
|
+
subprojects.push(entry.name);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// ignore
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// ignore
|
|
196
|
+
}
|
|
197
|
+
return subprojects;
|
|
198
|
+
}
|
|
199
|
+
async detectKeyFiles(dir) {
|
|
200
|
+
const candidateFiles = [
|
|
201
|
+
'package.json', 'tsconfig.json', 'index.html', 'main.js',
|
|
202
|
+
'src/index.js', 'src/index.ts', 'src/main.js', 'src/main.ts',
|
|
203
|
+
'src/App.tsx', 'src/App.jsx', 'README.md', 'project.godot',
|
|
204
|
+
'Makefile', 'docker-compose.yml', 'Dockerfile'
|
|
205
|
+
];
|
|
206
|
+
const found = [];
|
|
207
|
+
for (const rel of candidateFiles) {
|
|
208
|
+
try {
|
|
209
|
+
await fs.access(path.join(dir, rel));
|
|
210
|
+
found.push(rel);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// ignore
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return found;
|
|
217
|
+
}
|
|
218
|
+
async detectPackageManager(dir) {
|
|
219
|
+
const managers = [
|
|
220
|
+
{ file: 'pnpm-lock.yaml', name: 'pnpm' },
|
|
221
|
+
{ file: 'bun.lockb', name: 'bun' },
|
|
222
|
+
{ file: 'bun.lock', name: 'bun' },
|
|
223
|
+
{ file: 'yarn.lock', name: 'yarn' },
|
|
224
|
+
{ file: 'package-lock.json', name: 'npm' },
|
|
225
|
+
{ file: 'Cargo.lock', name: 'cargo' },
|
|
226
|
+
{ file: 'Pipfile.lock', name: 'pipenv' },
|
|
227
|
+
{ file: 'poetry.lock', name: 'poetry' }
|
|
228
|
+
];
|
|
229
|
+
for (const m of managers) {
|
|
230
|
+
try {
|
|
231
|
+
await fs.access(path.join(dir, m.file));
|
|
232
|
+
return m.name;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// ignore
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
await fs.access(path.join(dir, 'package.json'));
|
|
240
|
+
return 'npm';
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// ignore
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
73
246
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
247
|
+
async detectGitInfo(dir) {
|
|
248
|
+
let current = dir;
|
|
249
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
250
|
+
const gitDir = path.join(current, '.git');
|
|
251
|
+
try {
|
|
252
|
+
const stat = await fs.stat(gitDir);
|
|
253
|
+
if (stat.isDirectory()) {
|
|
254
|
+
const headFile = path.join(gitDir, 'HEAD');
|
|
255
|
+
const headContent = await fs.readFile(headFile, 'utf8');
|
|
256
|
+
const match = headContent.trim().match(/^ref:\s+refs\/heads\/(.+)$/);
|
|
257
|
+
const branch = match ? (match[1] ?? null) : headContent.trim().slice(0, 8);
|
|
258
|
+
return { branch, gitDir };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// ignore
|
|
263
|
+
}
|
|
264
|
+
const parent = path.dirname(current);
|
|
265
|
+
if (parent === current)
|
|
266
|
+
break;
|
|
267
|
+
current = parent;
|
|
268
|
+
}
|
|
269
|
+
return { branch: null, gitDir: null };
|
|
94
270
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
271
|
+
async detectProjectType(dir, context) {
|
|
272
|
+
const deps = context.packageJson ? {
|
|
273
|
+
...context.packageJson.dependencies,
|
|
274
|
+
...context.packageJson.devDependencies
|
|
275
|
+
} : {};
|
|
276
|
+
// 1. Game Development (2D Canvas, WebGL, Pixi, Phaser, Godot, Kaplay)
|
|
277
|
+
const gameLibs = ['phaser', 'pixi.js', 'kaboom', 'kaplay', 'three', 'howler', 'matter-js', 'planck'];
|
|
278
|
+
if (gameLibs.some(lib => Boolean(deps[lib]))) {
|
|
279
|
+
return '2D / Canvas Game Project';
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
await fs.access(path.join(dir, 'project.godot'));
|
|
283
|
+
return 'Godot Game Project';
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// ignore
|
|
287
|
+
}
|
|
288
|
+
// Check directory name or key files for game patterns
|
|
289
|
+
const baseName = path.basename(dir).toLowerCase();
|
|
290
|
+
if (baseName.includes('game') || baseName.includes('pixel') || baseName.includes('arcade')) {
|
|
291
|
+
return '2D Game Project';
|
|
292
|
+
}
|
|
293
|
+
// 2. Web Application
|
|
294
|
+
if (deps['next'] || deps['react'] || deps['vue'] || deps['svelte'] || deps['vite']) {
|
|
295
|
+
return 'Frontend Web Application';
|
|
296
|
+
}
|
|
297
|
+
// 3. Backend / Server / Service
|
|
298
|
+
if (deps['express'] || deps['fastify'] || deps['koa'] || deps['@nestjs/core']) {
|
|
299
|
+
return 'Backend Web Service';
|
|
300
|
+
}
|
|
301
|
+
if (context.framework && context.framework.type === 'android') {
|
|
302
|
+
return 'Android Application';
|
|
303
|
+
}
|
|
304
|
+
if (context.framework && context.framework.type === 'rust') {
|
|
305
|
+
return 'Rust Application / Library';
|
|
306
|
+
}
|
|
307
|
+
return 'Software Application';
|
|
122
308
|
}
|
|
123
|
-
}
|
|
124
309
|
}
|