@lazyingart/agintiflow 0.4.1 → 0.6.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 +32 -6
- package/docs/real-deepseek-capabilities.md +51 -0
- package/package.json +7 -3
- package/scripts/real-deepseek-capabilities.js +389 -0
- package/scripts/smoke-capabilities.js +82 -0
- package/scripts/smoke-web-api.js +11 -0
- package/src/agent-runner.js +33 -20
- package/src/capabilities.js +231 -0
- package/src/cli.js +38 -3
- package/src/command-policy.js +157 -15
- package/src/config.js +1 -1
- package/src/docker-sandbox.js +1 -1
- package/src/model-client.js +5 -3
- package/src/task-profiles.js +11 -4
- package/web.js +14 -0
package/src/command-policy.js
CHANGED
|
@@ -27,12 +27,24 @@ const READ_ONLY_PATTERNS = [
|
|
|
27
27
|
|
|
28
28
|
const TEST_PATTERNS = [
|
|
29
29
|
/^npm\s+(run\s+)?(check|test|build|lint)(?:\s+--\s+[-\w./:=]+)*$/,
|
|
30
|
+
/^npm\s+--prefix\s+[-\w./]+\s+(run\s+)?(check|test|build|lint)(?:\s+--\s+[-\w./:=]+)*$/,
|
|
30
31
|
/^npm\s+test$/,
|
|
31
32
|
/^node\s+--check\s+[-\w./]+$/,
|
|
33
|
+
/^node\s+--test(?:\s+[-\w./]+)*$/,
|
|
34
|
+
/^bash\s+-n\s+[-\w./]+\.sh$/,
|
|
35
|
+
/^sh\s+-n\s+[-\w./]+\.sh$/,
|
|
36
|
+
/^python(?:3)?\s+-m\s+py_compile\s+[-\w./]+\.py$/,
|
|
32
37
|
/^python(?:3)?\s+-m\s+pytest(?:\s+[-\w./:=]+)*$/,
|
|
33
38
|
/^pytest(?:\s+[-\w./:=]+)*$/,
|
|
34
39
|
];
|
|
35
40
|
|
|
41
|
+
const SAFE_WORKSPACE_WRITE_PATTERNS = [/^mkdir\s+-p\s+[-\w./]+$/];
|
|
42
|
+
|
|
43
|
+
const NETWORK_FETCH_PATTERNS = [
|
|
44
|
+
/^curl\s+(?:-[A-Za-z0-9]*\s+)*https?:\/\/\S+(?:\s+-o\s+[-\w./]+)?$/,
|
|
45
|
+
/^wget\s+(?:-[A-Za-z0-9]*\s+)*(?:-O\s+[-\w./]+\s+)?https?:\/\/\S+$/,
|
|
46
|
+
];
|
|
47
|
+
|
|
36
48
|
const TOOLCHAIN_PATTERNS = [
|
|
37
49
|
/^python(?:3)?\s+[-\w./]+\.py(?:\s+[-\w./:=]+)*$/,
|
|
38
50
|
/^latexmk\s+(?=[-\w./=\s]*-pdf\b)(?:(?:-cd|-pdf|-interaction=nonstopmode|-halt-on-error|-output-directory=[-\w./]+)\s+)+[-\w./]+\.tex$/,
|
|
@@ -41,12 +53,24 @@ const TOOLCHAIN_PATTERNS = [
|
|
|
41
53
|
|
|
42
54
|
const PACKAGE_INSTALL_PATTERNS = [
|
|
43
55
|
/^npm\s+ci$/,
|
|
44
|
-
/^npm\s+install
|
|
56
|
+
/^npm\s+install(?:\s+[-@\w./:=]+)*$/,
|
|
45
57
|
/^pnpm\s+install$/,
|
|
58
|
+
/^pnpm\s+add(?:\s+[-@\w./:=]+)+$/,
|
|
46
59
|
/^yarn\s+install$/,
|
|
60
|
+
/^yarn\s+add(?:\s+[-@\w./:=]+)+$/,
|
|
47
61
|
/^python(?:3)?\s+-m\s+pip\s+install\s+-r\s+[-\w./]+$/,
|
|
62
|
+
/^python(?:3)?\s+-m\s+pip\s+install(?:\s+[-@\w./:=]+)+$/,
|
|
48
63
|
/^pip(?:3)?\s+install\s+-r\s+[-\w./]+$/,
|
|
64
|
+
/^pip(?:3)?\s+install(?:\s+[-@\w./:=]+)+$/,
|
|
65
|
+
/^uv\s+(sync|pip\s+install)(?:\s+[-@\w./:=]+)*$/,
|
|
49
66
|
/^conda\s+env\s+(create|update)\s+-f\s+[-\w./]+$/,
|
|
67
|
+
/^conda\s+install(?:\s+[-@\w./:=]+)+$/,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const SYSTEM_PACKAGE_INSTALL_PATTERNS = [
|
|
71
|
+
/^(?:sudo\s+)?apt(?:-get)?\s+update$/,
|
|
72
|
+
/^(?:sudo\s+)?apt(?:-get)?\s+install(?:\s+-y)?(?:\s+[-@\w.+:=]+)+$/,
|
|
73
|
+
/^apk\s+add(?:\s+--no-cache)?(?:\s+[-@\w.+:=]+)+$/,
|
|
50
74
|
];
|
|
51
75
|
|
|
52
76
|
const ENV_SETUP_PATTERNS = [
|
|
@@ -57,13 +81,10 @@ const ENV_SETUP_PATTERNS = [
|
|
|
57
81
|
|
|
58
82
|
const BLOCKED_SHELL_TOKENS = ["&&", "||", ";", "|", ">", "<", "$(", "`"];
|
|
59
83
|
const BLOCKED_WRITE_TOKENS = [
|
|
60
|
-
"sudo ",
|
|
61
84
|
" rm",
|
|
62
85
|
" mv",
|
|
63
|
-
" cp",
|
|
64
86
|
" chmod",
|
|
65
87
|
" chown",
|
|
66
|
-
" mkdir",
|
|
67
88
|
" rmdir",
|
|
68
89
|
" touch",
|
|
69
90
|
" tee",
|
|
@@ -76,8 +97,6 @@ const BLOCKED_WRITE_TOKENS = [
|
|
|
76
97
|
"git switch",
|
|
77
98
|
"git reset",
|
|
78
99
|
"git clean",
|
|
79
|
-
"curl ",
|
|
80
|
-
"wget ",
|
|
81
100
|
];
|
|
82
101
|
|
|
83
102
|
const ALWAYS_BLOCKED_PATTERNS = [
|
|
@@ -91,6 +110,13 @@ const ALWAYS_BLOCKED_PATTERNS = [
|
|
|
91
110
|
/DEEPSEEK_API_KEY\s*=/i,
|
|
92
111
|
];
|
|
93
112
|
|
|
113
|
+
const SENSITIVE_COMMAND_PATTERNS = [
|
|
114
|
+
/(^|[\s./])\.env(\s|$|[./])/i,
|
|
115
|
+
/(^|[\s./])\.npmrc(\s|$|[./])/i,
|
|
116
|
+
/^(env|printenv)(\s|$)/i,
|
|
117
|
+
/(api[_-]?key|auth[_-]?token|npm[_-]?token|_authToken|bearer\s+[A-Za-z0-9._-]+)/i,
|
|
118
|
+
];
|
|
119
|
+
|
|
94
120
|
function normalizePolicy(value, allowed, fallback) {
|
|
95
121
|
return allowed.includes(value) ? value : fallback;
|
|
96
122
|
}
|
|
@@ -107,20 +133,50 @@ function matchAny(patterns, command) {
|
|
|
107
133
|
return patterns.some((pattern) => pattern.test(command));
|
|
108
134
|
}
|
|
109
135
|
|
|
110
|
-
|
|
111
|
-
const normalized = String(
|
|
112
|
-
if (!normalized
|
|
136
|
+
function isSafeRelativeDir(value) {
|
|
137
|
+
const normalized = String(value || "").trim();
|
|
138
|
+
if (!normalized || normalized.startsWith("/") || normalized.startsWith("~")) return false;
|
|
139
|
+
return normalized.split("/").every((part) => part && part !== "." && part !== "..");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isSafeVirtualWorkspaceDir(value) {
|
|
143
|
+
const normalized = String(value || "").trim();
|
|
144
|
+
if (!normalized.startsWith("/workspace/")) return false;
|
|
145
|
+
return isSafeRelativeDir(normalized.replace(/^\/workspace\//, ""));
|
|
146
|
+
}
|
|
113
147
|
|
|
148
|
+
function classifySimpleCommand(normalized) {
|
|
114
149
|
if (ALWAYS_BLOCKED_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
115
150
|
return { category: "blocked", reason: "Command is blocked because it may expose secrets or publish packages." };
|
|
116
151
|
}
|
|
152
|
+
if (SENSITIVE_COMMAND_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
153
|
+
return { category: "blocked", reason: "Command is blocked because it references secrets or credential files." };
|
|
154
|
+
}
|
|
117
155
|
|
|
118
156
|
const lowered = ` ${normalized.toLowerCase()} `;
|
|
119
157
|
if (BLOCKED_SHELL_TOKENS.some((part) => normalized.includes(part))) {
|
|
120
|
-
return {
|
|
158
|
+
return {
|
|
159
|
+
category: "general-shell",
|
|
160
|
+
needsNetwork: true,
|
|
161
|
+
writesWorkspace: true,
|
|
162
|
+
reason: `Command uses general shell syntax: ${normalized}`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (matchAny(SAFE_WORKSPACE_WRITE_PATTERNS, normalized)) {
|
|
166
|
+
const target = normalized.replace(/^mkdir\s+-p\s+/, "");
|
|
167
|
+
const virtualWorkspacePath = isSafeVirtualWorkspaceDir(target);
|
|
168
|
+
if (!isSafeRelativeDir(target) && !virtualWorkspacePath) {
|
|
169
|
+
return { category: "blocked", reason: `mkdir target must be a safe workspace-relative directory: ${target}` };
|
|
170
|
+
}
|
|
171
|
+
return { category: "workspace-write", needsNetwork: false, writesWorkspace: true, virtualWorkspacePath };
|
|
121
172
|
}
|
|
122
173
|
if (BLOCKED_WRITE_TOKENS.some((part) => lowered.includes(part))) {
|
|
123
|
-
return {
|
|
174
|
+
return {
|
|
175
|
+
category: "destructive",
|
|
176
|
+
needsNetwork: false,
|
|
177
|
+
writesWorkspace: true,
|
|
178
|
+
reason: `Command contains a write-capable or destructive token: ${normalized}`,
|
|
179
|
+
};
|
|
124
180
|
}
|
|
125
181
|
|
|
126
182
|
if (matchAny(READ_ONLY_PATTERNS, normalized)) {
|
|
@@ -132,6 +188,12 @@ export function classifyCommand(command) {
|
|
|
132
188
|
if (matchAny(TOOLCHAIN_PATTERNS, normalized)) {
|
|
133
189
|
return { category: "toolchain", needsNetwork: false, writesWorkspace: true };
|
|
134
190
|
}
|
|
191
|
+
if (matchAny(NETWORK_FETCH_PATTERNS, normalized)) {
|
|
192
|
+
return { category: "network-fetch", needsNetwork: true, writesWorkspace: /(\s-o\s|\s-O\s)/.test(normalized) };
|
|
193
|
+
}
|
|
194
|
+
if (matchAny(SYSTEM_PACKAGE_INSTALL_PATTERNS, normalized)) {
|
|
195
|
+
return { category: "system-package-install", needsNetwork: true, writesWorkspace: false, requiresDockerRoot: true };
|
|
196
|
+
}
|
|
135
197
|
if (matchAny(PACKAGE_INSTALL_PATTERNS, normalized)) {
|
|
136
198
|
return { category: "package-install", needsNetwork: true, writesWorkspace: true };
|
|
137
199
|
}
|
|
@@ -139,18 +201,57 @@ export function classifyCommand(command) {
|
|
|
139
201
|
return { category: "env-setup", needsNetwork: false, writesWorkspace: true };
|
|
140
202
|
}
|
|
141
203
|
|
|
142
|
-
return {
|
|
204
|
+
return {
|
|
205
|
+
category: "general-shell",
|
|
206
|
+
needsNetwork: false,
|
|
207
|
+
writesWorkspace: false,
|
|
208
|
+
reason: `Command is outside the narrow allowlist and requires a trusted shell policy: ${normalized}`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function classifyCdCommand(normalized) {
|
|
213
|
+
const match = normalized.match(/^cd\s+([-\w./]+)\s+&&\s+(.+)$/);
|
|
214
|
+
if (!match) return null;
|
|
215
|
+
const [, dir, inner] = match;
|
|
216
|
+
const virtualWorkspacePath = isSafeVirtualWorkspaceDir(dir);
|
|
217
|
+
if (!isSafeRelativeDir(dir) && !virtualWorkspacePath) {
|
|
218
|
+
return { category: "blocked", reason: `cd target must be a safe workspace-relative directory: ${dir}` };
|
|
219
|
+
}
|
|
220
|
+
const innerClassification = classifySimpleCommand(inner.trim());
|
|
221
|
+
if (innerClassification.category === "blocked") return innerClassification;
|
|
222
|
+
return { ...innerClassification, cdDir: dir, virtualWorkspacePath };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function classifyCommand(command) {
|
|
226
|
+
const normalized = String(command || "").trim();
|
|
227
|
+
if (!normalized) return { category: "blocked", reason: "Command is empty." };
|
|
228
|
+
|
|
229
|
+
return classifyCdCommand(normalized) || classifySimpleCommand(normalized);
|
|
143
230
|
}
|
|
144
231
|
|
|
145
232
|
export function evaluateCommandPolicy(command, config) {
|
|
146
233
|
const classification = classifyCommand(command);
|
|
147
234
|
const sandboxMode = normalizeSandboxMode(config.sandboxMode);
|
|
148
235
|
const packageInstallPolicy = normalizePackageInstallPolicy(config.packageInstallPolicy);
|
|
236
|
+
const dockerWorkspace = sandboxMode === "docker-workspace";
|
|
237
|
+
const packageInstallsAllowed = packageInstallPolicy === "allow";
|
|
238
|
+
const trustedDockerShell = dockerWorkspace && packageInstallsAllowed;
|
|
239
|
+
const trustedHostShell = sandboxMode === "host" && Boolean(config.allowDestructive);
|
|
149
240
|
|
|
150
241
|
if (classification.category === "blocked") {
|
|
151
242
|
return { allowed: false, ...classification, sandboxMode, packageInstallPolicy };
|
|
152
243
|
}
|
|
153
244
|
|
|
245
|
+
if (classification.virtualWorkspacePath && !config.useDockerSandbox) {
|
|
246
|
+
return {
|
|
247
|
+
allowed: false,
|
|
248
|
+
...classification,
|
|
249
|
+
reason: "Virtual /workspace shell paths are allowed only inside Docker sandbox mode.",
|
|
250
|
+
sandboxMode,
|
|
251
|
+
packageInstallPolicy,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
154
255
|
if (!config.allowShellTool) {
|
|
155
256
|
return {
|
|
156
257
|
allowed: false,
|
|
@@ -161,7 +262,11 @@ export function evaluateCommandPolicy(command, config) {
|
|
|
161
262
|
};
|
|
162
263
|
}
|
|
163
264
|
|
|
164
|
-
if (
|
|
265
|
+
if (
|
|
266
|
+
classification.category === "package-install" ||
|
|
267
|
+
classification.category === "env-setup" ||
|
|
268
|
+
classification.category === "system-package-install"
|
|
269
|
+
) {
|
|
165
270
|
if (packageInstallPolicy !== "allow") {
|
|
166
271
|
return {
|
|
167
272
|
allowed: false,
|
|
@@ -176,17 +281,53 @@ export function evaluateCommandPolicy(command, config) {
|
|
|
176
281
|
};
|
|
177
282
|
}
|
|
178
283
|
|
|
179
|
-
if (
|
|
284
|
+
if (classification.category === "system-package-install" && sandboxMode === "host" && !config.allowDestructive) {
|
|
180
285
|
return {
|
|
181
286
|
allowed: false,
|
|
182
287
|
category: classification.category,
|
|
183
|
-
reason: "
|
|
288
|
+
reason: "Host system package installs require Allow destructive actions. Prefer Docker workspace mode.",
|
|
184
289
|
sandboxMode,
|
|
185
290
|
packageInstallPolicy,
|
|
186
291
|
};
|
|
187
292
|
}
|
|
188
293
|
}
|
|
189
294
|
|
|
295
|
+
if (classification.category === "general-shell" && !trustedDockerShell && !trustedHostShell) {
|
|
296
|
+
return {
|
|
297
|
+
allowed: false,
|
|
298
|
+
...classification,
|
|
299
|
+
needsApproval: true,
|
|
300
|
+
reason:
|
|
301
|
+
sandboxMode === "host"
|
|
302
|
+
? "General shell commands on the host require Allow destructive actions. Prefer Docker workspace mode for broad shell access."
|
|
303
|
+
: "General Docker shell commands require Package installs = allow in docker-workspace mode.",
|
|
304
|
+
sandboxMode,
|
|
305
|
+
packageInstallPolicy,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (classification.category === "destructive" && !config.allowDestructive) {
|
|
310
|
+
return {
|
|
311
|
+
allowed: false,
|
|
312
|
+
...classification,
|
|
313
|
+
needsApproval: true,
|
|
314
|
+
reason: "Destructive shell commands require Allow destructive actions.",
|
|
315
|
+
sandboxMode,
|
|
316
|
+
packageInstallPolicy,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (classification.category === "network-fetch" && config.useDockerSandbox && !trustedDockerShell) {
|
|
321
|
+
return {
|
|
322
|
+
allowed: false,
|
|
323
|
+
...classification,
|
|
324
|
+
needsApproval: true,
|
|
325
|
+
reason: "Docker network commands require docker-workspace mode with Package installs = allow.",
|
|
326
|
+
sandboxMode,
|
|
327
|
+
packageInstallPolicy,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
190
331
|
if (classification.writesWorkspace && config.useDockerSandbox && sandboxMode !== "docker-workspace") {
|
|
191
332
|
return {
|
|
192
333
|
allowed: false,
|
|
@@ -200,6 +341,7 @@ export function evaluateCommandPolicy(command, config) {
|
|
|
200
341
|
return {
|
|
201
342
|
allowed: true,
|
|
202
343
|
...classification,
|
|
344
|
+
requiresDockerRoot: Boolean(classification.requiresDockerRoot && config.useDockerSandbox),
|
|
203
345
|
sandboxMode,
|
|
204
346
|
packageInstallPolicy,
|
|
205
347
|
};
|
package/src/config.js
CHANGED
|
@@ -71,7 +71,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
71
71
|
? overrides.allowedDomains
|
|
72
72
|
: parseList(process.env.ALLOWED_DOMAINS),
|
|
73
73
|
allowPasswords: parseBoolean(overrides.allowPasswords ?? process.env.ALLOW_PASSWORDS, false),
|
|
74
|
-
allowDestructive: parseBoolean(overrides.allowDestructive ?? process.env.ALLOW_DESTRUCTIVE, false),
|
|
74
|
+
allowDestructive: parseBoolean(overrides.allowDestructive ?? args.allowDestructive ?? process.env.ALLOW_DESTRUCTIVE, false),
|
|
75
75
|
allowShellTool: parseBoolean(overrides.allowShellTool ?? args.allowShellTool ?? process.env.ALLOW_SHELL_TOOL, false),
|
|
76
76
|
allowFileTools: parseBoolean(overrides.allowFileTools ?? args.allowFileTools ?? process.env.ALLOW_FILE_TOOLS, true),
|
|
77
77
|
allowWrapperTools: parseBoolean(
|
package/src/docker-sandbox.js
CHANGED
|
@@ -168,7 +168,7 @@ export async function ensureDockerSandboxReady(config, observers, options = {})
|
|
|
168
168
|
function dockerRunArgs(command, config, policy = evaluateCommandPolicy(command, config)) {
|
|
169
169
|
const uid = typeof process.getuid === "function" ? String(process.getuid()) : "";
|
|
170
170
|
const gid = typeof process.getgid === "function" ? String(process.getgid()) : "";
|
|
171
|
-
const userArgs = uid && gid ? ["--user", `${uid}:${gid}`] : [];
|
|
171
|
+
const userArgs = uid && gid && !policy.requiresDockerRoot ? ["--user", `${uid}:${gid}`] : [];
|
|
172
172
|
const sandboxMode = normalizeSandboxMode(config.sandboxMode);
|
|
173
173
|
const mountMode = sandboxMode === "docker-workspace" ? "rw" : "ro";
|
|
174
174
|
const networkMode = policy.needsNetwork ? "bridge" : "none";
|
package/src/model-client.js
CHANGED
|
@@ -156,8 +156,10 @@ export async function createPlan(client, config, state) {
|
|
|
156
156
|
: "",
|
|
157
157
|
`Task profile: ${taskProfile.label}. ${taskProfile.prompt}`,
|
|
158
158
|
"A canvas/artifacts tunnel is available through send_to_canvas. Use it when an output should be highlighted visually, such as screenshots, image files, important markdown, diffs, or generated artifact paths. It is optional for ordinary text answers.",
|
|
159
|
-
"
|
|
160
|
-
"
|
|
159
|
+
"Work like a practical coding agent: inspect when useful, edit with file tools, run safe checks when they add confidence, and keep outputs inside the workspace.",
|
|
160
|
+
"Use the canvas tunnel for outputs the user would likely want to inspect visually, such as figures, PDFs, screenshots, images, important markdown, or generated files.",
|
|
161
|
+
"For environment or system-maintenance work, prefer project-local dry-run plans/scripts unless the configured policy explicitly allows stronger actions.",
|
|
162
|
+
"Plan for a complete result, not endless exploration; finish once the request is satisfied and checks have passed or been honestly skipped.",
|
|
161
163
|
"Return a numbered plan only.",
|
|
162
164
|
]
|
|
163
165
|
.filter(Boolean)
|
|
@@ -298,7 +300,7 @@ export async function requestNextStep(client, config, messages) {
|
|
|
298
300
|
function: {
|
|
299
301
|
name: "run_command",
|
|
300
302
|
description:
|
|
301
|
-
"Run
|
|
303
|
+
"Run a terminal command in the configured working directory under the active shell policy. Secrets and npm publishing are always blocked; Docker workspace mode with approved package installs supports broader network/setup commands, while host destructive or privileged work requires explicit trust.",
|
|
302
304
|
parameters: {
|
|
303
305
|
type: "object",
|
|
304
306
|
properties: {
|
package/src/task-profiles.js
CHANGED
|
@@ -10,7 +10,7 @@ export const TASK_PROFILES = {
|
|
|
10
10
|
id: "code",
|
|
11
11
|
label: "Code writing",
|
|
12
12
|
prompt:
|
|
13
|
-
"Act like a coding agent:
|
|
13
|
+
"Act like a coding agent: understand the request, edit workspace files, run useful safe checks, and report changed files and residual risks.",
|
|
14
14
|
tools: ["files", "shell", "sandbox"],
|
|
15
15
|
},
|
|
16
16
|
writing: {
|
|
@@ -45,14 +45,21 @@ export const TASK_PROFILES = {
|
|
|
45
45
|
id: "node",
|
|
46
46
|
label: "Node",
|
|
47
47
|
prompt:
|
|
48
|
-
"For Node.js tasks,
|
|
48
|
+
"For Node.js tasks, use the local project structure, add tests when useful, and run safe npm/node checks when available.",
|
|
49
49
|
tools: ["files", "shell", "sandbox"],
|
|
50
50
|
},
|
|
51
|
+
website: {
|
|
52
|
+
id: "website",
|
|
53
|
+
label: "Website testing",
|
|
54
|
+
prompt:
|
|
55
|
+
"For website-testing tasks, create or inspect the site, add a local check when useful, and use the configured sandbox/package policy for dependencies.",
|
|
56
|
+
tools: ["files", "shell", "canvas", "sandbox"],
|
|
57
|
+
},
|
|
51
58
|
aaps: {
|
|
52
59
|
id: "aaps",
|
|
53
60
|
label: "AAPS",
|
|
54
61
|
prompt:
|
|
55
|
-
"For AAPS tasks, recognize .aaps folders and @lazyingart/aaps
|
|
62
|
+
"For AAPS tasks, recognize .aaps folders and @lazyingart/aaps workflows, keep work project-local, and avoid secrets or publishing.",
|
|
56
63
|
tools: ["files", "shell", "sandbox"],
|
|
57
64
|
},
|
|
58
65
|
latex: {
|
|
@@ -66,7 +73,7 @@ export const TASK_PROFILES = {
|
|
|
66
73
|
id: "maintenance",
|
|
67
74
|
label: "System maintenance",
|
|
68
75
|
prompt:
|
|
69
|
-
"For system maintenance, diagnose first,
|
|
76
|
+
"For system maintenance, diagnose first, use Docker for broad installs when available, and follow the configured trust/package policy for host-level changes.",
|
|
70
77
|
tools: ["shell", "sandbox", "files"],
|
|
71
78
|
},
|
|
72
79
|
};
|
package/web.js
CHANGED
|
@@ -13,6 +13,7 @@ import { normalizePackageInstallPolicy, normalizeSandboxMode } from "./src/comma
|
|
|
13
13
|
import { summarizeWorkspaceTools, WORKSPACE_TOOL_NAMES } from "./src/workspace-tools.js";
|
|
14
14
|
import { listTaskProfiles, normalizeTaskProfile } from "./src/task-profiles.js";
|
|
15
15
|
import { loadProjectEnv, projectPaths, providerKeyStatus, setProviderKey } from "./src/project.js";
|
|
16
|
+
import { buildCapabilityReport } from "./src/capabilities.js";
|
|
16
17
|
import {
|
|
17
18
|
buildArtifacts,
|
|
18
19
|
countUnreadArtifacts,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
26
|
const __dirname = path.dirname(__filename);
|
|
26
27
|
const packageDir = __dirname;
|
|
28
|
+
const packageJson = JSON.parse(await fs.readFile(path.join(packageDir, "package.json"), "utf8"));
|
|
27
29
|
const baseDir = path.resolve(process.env.AGINTIFLOW_RUNTIME_DIR || process.cwd());
|
|
28
30
|
const sessionsDir = path.join(baseDir, ".sessions");
|
|
29
31
|
loadProjectEnv(baseDir);
|
|
@@ -539,6 +541,18 @@ app.get("/api/keys/status", (_req, res) => {
|
|
|
539
541
|
res.json({ ok: true, keyStatus: publicKeyStatus(baseDir) });
|
|
540
542
|
});
|
|
541
543
|
|
|
544
|
+
app.get("/api/capabilities", async (_req, res) => {
|
|
545
|
+
const preferences = normalizePreferencePayload({}, db.getPreferences());
|
|
546
|
+
const config = buildRunConfig({
|
|
547
|
+
...preferences,
|
|
548
|
+
goal: "capabilities",
|
|
549
|
+
allowShellTool: true,
|
|
550
|
+
allowFileTools: true,
|
|
551
|
+
});
|
|
552
|
+
const report = await buildCapabilityReport(baseDir, packageJson.version, config);
|
|
553
|
+
res.json(report);
|
|
554
|
+
});
|
|
555
|
+
|
|
542
556
|
app.post("/api/keys/:provider", async (req, res) => {
|
|
543
557
|
try {
|
|
544
558
|
const result = await setProviderKey(baseDir, req.params.provider, req.body?.apiKey || req.body?.key || "");
|