@lazyingart/agintiflow 0.20.21 → 0.20.23
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/package.json +1 -1
- package/scripts/smoke-capabilities.js +12 -0
- package/scripts/smoke-cli-chat.js +6 -6
- package/skills/android/SKILL.md +12 -2
- package/src/capabilities.js +1 -0
- package/src/command-policy.js +25 -10
- package/src/engineering-guidance.js +7 -0
- package/src/interactive-cli.js +2 -1
- package/src/task-profiles.js +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a web-first coding agent and CLI with DeepSeek routing, sandboxed tools, model providers, canvas artifacts, and optional wrappers.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -77,6 +77,14 @@ try {
|
|
|
77
77
|
capabilities.maintenancePolicy.some((check) => check.command.startsWith("sudo") && !check.allowed),
|
|
78
78
|
"sudo maintenance command was not blocked"
|
|
79
79
|
);
|
|
80
|
+
assert(
|
|
81
|
+
capabilities.maintenancePolicy.some((check) => check.command.startsWith("apt-get install") && !check.allowed),
|
|
82
|
+
"host OS package install was not blocked"
|
|
83
|
+
);
|
|
84
|
+
assert(
|
|
85
|
+
capabilities.tools?.taskProfiles?.some((profile) => profile.id === "android"),
|
|
86
|
+
"capabilities did not report Android task profile"
|
|
87
|
+
);
|
|
80
88
|
assert(
|
|
81
89
|
capabilities.trustedDockerPolicy.some((check) => check.command.startsWith("apt-get install") && check.allowed),
|
|
82
90
|
"trusted Docker policy did not allow apt-get install"
|
|
@@ -97,6 +105,10 @@ try {
|
|
|
97
105
|
capabilities.tools?.skills?.some((skill) => skill.id === "latex-manuscript"),
|
|
98
106
|
"capabilities did not report built-in LaTeX skill"
|
|
99
107
|
);
|
|
108
|
+
assert(
|
|
109
|
+
capabilities.tools?.skills?.some((skill) => skill.id === "android"),
|
|
110
|
+
"capabilities did not report built-in Android skill"
|
|
111
|
+
);
|
|
100
112
|
|
|
101
113
|
const doctor = JSON.parse(await runCli(["doctor", "--capabilities", "--json"]));
|
|
102
114
|
assert(doctor.project.root === tempRoot, "doctor --capabilities used the wrong project root");
|
|
@@ -141,8 +141,8 @@ try {
|
|
|
141
141
|
if (!promptText.includes("user>")) {
|
|
142
142
|
throw new Error("terminal prompt layout did not render the user> label");
|
|
143
143
|
}
|
|
144
|
-
if (!promptText.includes("user> ")) {
|
|
145
|
-
throw new Error("terminal prompt layout did not
|
|
144
|
+
if (!promptText.includes(" user> ") || promptText.includes("user> ")) {
|
|
145
|
+
throw new Error("terminal prompt layout did not right-align user> to the aginti> label width");
|
|
146
146
|
}
|
|
147
147
|
const visibleLengths = promptLayout.renderedRows.map((line) =>
|
|
148
148
|
line.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "").length
|
|
@@ -168,7 +168,7 @@ try {
|
|
|
168
168
|
if (
|
|
169
169
|
paddedPromptLayout.cursorRow !== 1 ||
|
|
170
170
|
paddedRows[0].trim() !== "" ||
|
|
171
|
-
!paddedRows[1].includes("user>
|
|
171
|
+
!paddedRows[1].includes(" user> hello") ||
|
|
172
172
|
paddedRows[2].trim() !== "" ||
|
|
173
173
|
!paddedRows[3].includes("cwd /tmp/aginti-project")
|
|
174
174
|
) {
|
|
@@ -177,7 +177,7 @@ try {
|
|
|
177
177
|
const committedUserText = formatCommittedUserPromptLines("list files", 90)
|
|
178
178
|
.map((line) => line.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, ""))
|
|
179
179
|
.join("\n");
|
|
180
|
-
if (!committedUserText.includes("user>
|
|
180
|
+
if (!committedUserText.includes(" user> list files") || committedUserText.includes("cwd")) {
|
|
181
181
|
throw new Error("committed user history should not include the live cwd footer");
|
|
182
182
|
}
|
|
183
183
|
const zhPromptLayout = buildPromptLayout("", 0, 90, 24, { language: "zh-Hans", commandCwd: "/tmp/aginti-project" });
|
|
@@ -214,7 +214,7 @@ try {
|
|
|
214
214
|
const hintText = hintPromptLayout.renderedRows
|
|
215
215
|
.map((line) => line.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, ""))
|
|
216
216
|
.join("\n");
|
|
217
|
-
if (!hintText.includes("user>
|
|
217
|
+
if (!hintText.includes(" user> /mo") || !hintText.includes("hint /models >/model")) {
|
|
218
218
|
throw new Error("terminal prompt layout did not align user and hint text columns");
|
|
219
219
|
}
|
|
220
220
|
const exactHintLayout = buildPromptLayout("/model", 6, 90, 24);
|
|
@@ -306,7 +306,7 @@ try {
|
|
|
306
306
|
if (!latest.stdout.includes("resume history") || !latest.stdout.includes("chat=") || !latest.stdout.includes("Mock run complete")) {
|
|
307
307
|
throw new Error("bare aginti resume did not preview saved chat history");
|
|
308
308
|
}
|
|
309
|
-
if (!latest.stdout.includes("user>") || !latest.stdout.includes("aginti>")) {
|
|
309
|
+
if (!latest.stdout.includes(" user>") || !latest.stdout.includes("aginti>") || latest.stdout.includes("user> ")) {
|
|
310
310
|
throw new Error("resume history should use prompt-style user>/aginti> labels");
|
|
311
311
|
}
|
|
312
312
|
if (!latest.stdout.includes("resume note=showing chat transcript only")) {
|
package/skills/android/SKILL.md
CHANGED
|
@@ -18,6 +18,16 @@ tools:
|
|
|
18
18
|
---
|
|
19
19
|
# Android Development
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
## Operating Loop
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
1. Inspect before editing: `git status --short`, project tree, Gradle/settings files, AndroidManifest, package names, modules, Java/Kotlin versions, `ANDROID_HOME`/`ANDROID_SDK_ROOT`, likely SDK folders, `adb devices`, and emulator/AVD availability.
|
|
24
|
+
2. Do not use host `sudo`, `apt`, `dnf`, `yum`, `brew`, `winget`, or global host installs for Android app work. These can hang on password prompts or mutate the user's machine. Prefer existing Android SDK tools, project-local Gradle wrapper setup, user-writable caches, or a clear setup report with the exact manual command.
|
|
25
|
+
3. If a Gradle wrapper is needed, create `gradle/wrapper/` before downloading files. Prefer a valid project-local wrapper or an already-installed Gradle. Do not loop on the same failed install/download.
|
|
26
|
+
4. Patch source-set-aware files only: manifests, Gradle scripts, Kotlin/Java sources, XML resources, and project docs. Keep generated build outputs out of patches and commits.
|
|
27
|
+
5. Build with the narrowest useful task first, usually `./gradlew :app:assembleDebug` or `./gradlew assembleDebug`. Repair build failures from the actual error text.
|
|
28
|
+
6. Install and launch on an available device/emulator with `adb install` and `adb shell am start`. Verify with `adb shell pidof`, `adb logcat -d`, `adb shell screencap`, or similar evidence when available.
|
|
29
|
+
7. Commit only after build/install/launch verification, with a clear message. If no device/emulator exists, finish with a concrete external blocker and the generated APK path.
|
|
30
|
+
|
|
31
|
+
## Missing Tooling
|
|
32
|
+
|
|
33
|
+
If SDK/emulator tooling is missing, produce a setup report or project-local script rather than guessing. On host mode, never ask for or send a sudo password.
|
package/src/capabilities.js
CHANGED
package/src/command-policy.js
CHANGED
|
@@ -276,6 +276,7 @@ export function classifyCommand(command) {
|
|
|
276
276
|
|
|
277
277
|
export function evaluateCommandPolicy(command, config) {
|
|
278
278
|
const classification = classifyCommand(command);
|
|
279
|
+
const normalizedCommand = String(command || "").trim();
|
|
279
280
|
const sandboxMode = normalizeSandboxMode(config.sandboxMode);
|
|
280
281
|
const packageInstallPolicy = normalizePackageInstallPolicy(config.packageInstallPolicy);
|
|
281
282
|
const dockerWorkspace = sandboxMode === "docker-workspace";
|
|
@@ -307,6 +308,30 @@ export function evaluateCommandPolicy(command, config) {
|
|
|
307
308
|
};
|
|
308
309
|
}
|
|
309
310
|
|
|
311
|
+
if (sandboxMode === "host" && /^sudo\b/.test(normalizedCommand)) {
|
|
312
|
+
return {
|
|
313
|
+
allowed: false,
|
|
314
|
+
category: "host-sudo",
|
|
315
|
+
needsApproval: true,
|
|
316
|
+
reason:
|
|
317
|
+
"Interactive host sudo is not run by AgInTiFlow because it can hang on password prompts or change the machine globally. Prefer project-local setup, Docker workspace mode, or return the exact manual install command for the user.",
|
|
318
|
+
sandboxMode,
|
|
319
|
+
packageInstallPolicy,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (classification.category === "system-package-install" && sandboxMode === "host") {
|
|
324
|
+
return {
|
|
325
|
+
allowed: false,
|
|
326
|
+
category: classification.category,
|
|
327
|
+
needsApproval: true,
|
|
328
|
+
reason:
|
|
329
|
+
"Host OS package installs are not run automatically. Prefer an existing toolchain, project-local setup, Docker workspace mode, or report the exact manual command the user can run.",
|
|
330
|
+
sandboxMode,
|
|
331
|
+
packageInstallPolicy,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
310
335
|
if (
|
|
311
336
|
classification.category === "package-install" ||
|
|
312
337
|
classification.category === "env-setup" ||
|
|
@@ -325,16 +350,6 @@ export function evaluateCommandPolicy(command, config) {
|
|
|
325
350
|
packageInstallPolicy,
|
|
326
351
|
};
|
|
327
352
|
}
|
|
328
|
-
|
|
329
|
-
if (classification.category === "system-package-install" && sandboxMode === "host" && !config.allowDestructive) {
|
|
330
|
-
return {
|
|
331
|
-
allowed: false,
|
|
332
|
-
category: classification.category,
|
|
333
|
-
reason: "Host system package installs require Allow destructive actions. Prefer Docker workspace mode.",
|
|
334
|
-
sandboxMode,
|
|
335
|
-
packageInstallPolicy,
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
353
|
}
|
|
339
354
|
|
|
340
355
|
if (classification.category === "general-shell" && !trustedDockerShell && !trustedHostShell) {
|
|
@@ -25,6 +25,12 @@ const LANGUAGE_HINTS = [
|
|
|
25
25
|
text:
|
|
26
26
|
"Go: inspect go.mod, use go test ./pkg-or-target first, run gofmt on touched files, avoid changing module paths unless required.",
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
id: "android",
|
|
30
|
+
pattern: /\b(android|apk|adb|avd|emulator|gradle wrapper|gradlew|android sdk|kotlin android|jetpack|compose)\b/i,
|
|
31
|
+
text:
|
|
32
|
+
"Android: inspect git status, Gradle/settings/manifests, ANDROID_HOME/SDK paths, Java/Kotlin versions, adb devices, and emulator/AVD list first. Never start host sudo or host OS package installs; use the existing SDK, a project-local Gradle wrapper, user-writable caches, or return a precise setup report. Build, install with adb, launch with am, verify with logcat/screencap when possible, then commit.",
|
|
33
|
+
},
|
|
28
34
|
{
|
|
29
35
|
id: "java-jvm",
|
|
30
36
|
pattern: /\b(java|kotlin|gradle|maven|spring|junit|jvm)\b/i,
|
|
@@ -85,6 +91,7 @@ export function engineeringGuidanceForTask(goal = "", taskProfile = "auto") {
|
|
|
85
91
|
"For large repositories, preserve context by reading fewer but more relevant files; prefer deterministic tools and diffs over long model memory.",
|
|
86
92
|
"Build a compact context pack before major edits: project instructions, manifests/scripts, git status/diff, relevant symbols/search hits, target files, and the narrowest checks. Do not paste whole trees or huge files into model context.",
|
|
87
93
|
"For system repair, act like a doctor: gather evidence first, avoid silent destructive host changes, prefer Docker or project-local scripts for installs, and make every stronger action explicit in logs.",
|
|
94
|
+
"Never send sudo passwords or wait at interactive password prompts. If host-level permission is truly required, stop that path, explain the blocker, and provide a manual command instead of hanging.",
|
|
88
95
|
];
|
|
89
96
|
|
|
90
97
|
if (matched.length > 0) {
|
package/src/interactive-cli.js
CHANGED
|
@@ -113,7 +113,8 @@ const PROMPT_LABEL_WIDTH = "aginti>".length;
|
|
|
113
113
|
function labelText(name, { prompt = false } = {}) {
|
|
114
114
|
const raw = String(name || "");
|
|
115
115
|
const width = prompt || raw.endsWith(">") ? PROMPT_LABEL_WIDTH : ROLE_LABEL_WIDTH;
|
|
116
|
-
|
|
116
|
+
const aligned = raw.endsWith(">") ? raw.padStart(width, " ") : raw.padEnd(width, " ");
|
|
117
|
+
return ` ${aligned} `;
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
function label(name, bgCode) {
|
package/src/task-profiles.js
CHANGED
|
@@ -55,6 +55,13 @@ export const TASK_PROFILES = {
|
|
|
55
55
|
"Bias toward Node/JavaScript/TypeScript workflows without excluding frontend, backend, docs, or deployment work. Inspect package.json/lockfiles, respect the package manager, add tests when useful, and run safe npm/node checks when available.",
|
|
56
56
|
tools: ["files", "shell", "sandbox"],
|
|
57
57
|
},
|
|
58
|
+
android: {
|
|
59
|
+
id: "android",
|
|
60
|
+
label: "Android",
|
|
61
|
+
prompt:
|
|
62
|
+
"Bias toward end-to-end Android app delivery while still handling normal project work. Inspect git status, existing Gradle files, AndroidManifest, SDK paths, Java/Kotlin versions, adb devices, and emulator/AVD availability before editing. Do not use host sudo, apt, dnf, yum, brew, winget, or global host installs during Android tasks; prefer the existing Android SDK, project-local Gradle wrapper, user-writable caches, or a clear setup report. Create missing wrapper directories before downloads, avoid repeated failing install attempts, build with focused Gradle tasks, install and launch with adb when a device/emulator exists, verify with am/logcat/screencap when possible, and commit the finished app only after checks.",
|
|
63
|
+
tools: ["inspect_project", "search_files", "read_file", "apply_patch", "shell", "sandbox", "canvas"],
|
|
64
|
+
},
|
|
58
65
|
website: {
|
|
59
66
|
id: "website",
|
|
60
67
|
label: "Website testing",
|
|
@@ -99,6 +106,11 @@ const PROFILE_ALIASES = {
|
|
|
99
106
|
repository: "large-codebase",
|
|
100
107
|
engineering: "large-codebase",
|
|
101
108
|
engineer: "large-codebase",
|
|
109
|
+
mobile: "android",
|
|
110
|
+
apk: "android",
|
|
111
|
+
gradle: "android",
|
|
112
|
+
kotlin: "android",
|
|
113
|
+
java: "android",
|
|
102
114
|
};
|
|
103
115
|
|
|
104
116
|
export function listTaskProfiles() {
|
|
@@ -118,6 +130,7 @@ export function getTaskProfile(value = "auto") {
|
|
|
118
130
|
export function defaultMaxStepsForProfile(value = "auto") {
|
|
119
131
|
const profile = normalizeTaskProfile(value);
|
|
120
132
|
if (profile === "large-codebase") return 36;
|
|
133
|
+
if (profile === "android") return 42;
|
|
121
134
|
if (profile === "latex") return 30;
|
|
122
135
|
return 24;
|
|
123
136
|
}
|