@lazyingart/agintiflow 0.20.45 → 0.20.46
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-cli-chat.js +20 -0
- package/src/docker-sandbox.js +25 -3
- package/src/interactive-cli.js +29 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.46",
|
|
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",
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
11
11
|
buildPromptRenderSequence,
|
|
12
12
|
canonicalSlashPromptBuffer,
|
|
13
13
|
classifyEscapeAction,
|
|
14
|
+
formatElapsedDuration,
|
|
14
15
|
formatWorkspaceChange,
|
|
15
16
|
stripMarkdown,
|
|
16
17
|
} from "../src/interactive-cli.js";
|
|
18
|
+
import { dockerPolicyTimeoutMs, dockerUserCommand } from "../src/docker-sandbox.js";
|
|
17
19
|
|
|
18
20
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
19
21
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-cli-chat-"));
|
|
@@ -135,6 +137,24 @@ try {
|
|
|
135
137
|
if (!launchHeader.includes("█████") || !launchHeader.includes("v0.0.0") || launchHeader.split("\n").length < 9) {
|
|
136
138
|
throw new Error("large launch header did not render a centered multi-line title");
|
|
137
139
|
}
|
|
140
|
+
if (
|
|
141
|
+
formatElapsedDuration(0) !== "00:00" ||
|
|
142
|
+
formatElapsedDuration(65_000) !== "01:05" ||
|
|
143
|
+
formatElapsedDuration(3_665_000) !== "1:01:05"
|
|
144
|
+
) {
|
|
145
|
+
throw new Error("elapsed duration formatter returned an unexpected value");
|
|
146
|
+
}
|
|
147
|
+
const wrappedDockerCommand = dockerUserCommand("node --test 2>&1 | tail -30", {
|
|
148
|
+
category: "general-shell",
|
|
149
|
+
needsNetwork: false,
|
|
150
|
+
});
|
|
151
|
+
if (
|
|
152
|
+
dockerPolicyTimeoutMs({ needsNetwork: true }) !== 120000 ||
|
|
153
|
+
!wrappedDockerCommand.includes("timeout -k 5s 15s bash -lc") ||
|
|
154
|
+
!wrappedDockerCommand.includes("'node --test 2>&1 | tail -30'")
|
|
155
|
+
) {
|
|
156
|
+
throw new Error("docker sandbox command wrapper did not add a bounded inner timeout");
|
|
157
|
+
}
|
|
138
158
|
|
|
139
159
|
const promptLayout = buildPromptLayout(`${"x".repeat(180)}\nsecond line`, 95, 80, 24);
|
|
140
160
|
const promptText = promptLayout.renderedRows
|
package/src/docker-sandbox.js
CHANGED
|
@@ -29,6 +29,28 @@ function shellEscape(value) {
|
|
|
29
29
|
return `'${String(value).replace(/'/g, `'\"'\"'`)}'`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export function dockerPolicyTimeoutMs(policy = {}) {
|
|
33
|
+
if (policy.needsNetwork) return 120000;
|
|
34
|
+
if (policy.category === "toolchain") return 90000;
|
|
35
|
+
return 15000;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function dockerExecTimeoutMs(policy = {}) {
|
|
39
|
+
return dockerPolicyTimeoutMs(policy) + 5000;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function dockerUserCommand(command, policy = {}) {
|
|
43
|
+
const seconds = Math.max(1, Math.ceil(dockerPolicyTimeoutMs(policy) / 1000));
|
|
44
|
+
const escapedCommand = shellEscape(String(command || ""));
|
|
45
|
+
return [
|
|
46
|
+
`if command -v timeout >/dev/null 2>&1; then`,
|
|
47
|
+
` timeout -k 5s ${seconds}s bash -lc ${escapedCommand}`,
|
|
48
|
+
`else`,
|
|
49
|
+
` bash -lc ${escapedCommand}`,
|
|
50
|
+
`fi`,
|
|
51
|
+
].join("\n");
|
|
52
|
+
}
|
|
53
|
+
|
|
32
54
|
function buildDockerInvocation(args) {
|
|
33
55
|
return ["docker", ...args].map(shellEscape).join(" ");
|
|
34
56
|
}
|
|
@@ -232,7 +254,7 @@ function dockerCommand(command, policy) {
|
|
|
232
254
|
);
|
|
233
255
|
}
|
|
234
256
|
|
|
235
|
-
return [...envLines,
|
|
257
|
+
return [...envLines, dockerUserCommand(command, policy)].join("\n");
|
|
236
258
|
}
|
|
237
259
|
|
|
238
260
|
function dockerRunArgs(command, config, policy = evaluateCommandPolicy(command, config), persistentDirs = persistentDockerDirs(config)) {
|
|
@@ -289,7 +311,7 @@ function dockerRunArgs(command, config, policy = evaluateCommandPolicy(command,
|
|
|
289
311
|
export async function runDockerSandboxCommand(command, config, policy = evaluateCommandPolicy(command, config), options = {}) {
|
|
290
312
|
const persistentDirs = await ensurePersistentDockerDirs(config);
|
|
291
313
|
const result = await execDocker(dockerRunArgs(command, config, policy, persistentDirs), {
|
|
292
|
-
timeout: policy
|
|
314
|
+
timeout: dockerExecTimeoutMs(policy),
|
|
293
315
|
maxBuffer: 300 * 1024,
|
|
294
316
|
signal: options.signal,
|
|
295
317
|
});
|
|
@@ -366,7 +388,7 @@ export async function runDockerPreflight(config, options = {}) {
|
|
|
366
388
|
]) {
|
|
367
389
|
try {
|
|
368
390
|
const result = await execDocker(dockerRunArgs(command, config, { needsNetwork: false, category: "preflight" }, persistentDirs), {
|
|
369
|
-
timeout:
|
|
391
|
+
timeout: dockerExecTimeoutMs({ needsNetwork: false, category: "preflight" }),
|
|
370
392
|
maxBuffer: 100 * 1024,
|
|
371
393
|
});
|
|
372
394
|
results.push({ command, ok: true, stdout: result.stdout.trim(), stderr: result.stderr.trim() });
|
package/src/interactive-cli.js
CHANGED
|
@@ -236,6 +236,15 @@ function compactLine(value = "", limit = 96) {
|
|
|
236
236
|
return text.length <= limit ? text : `${text.slice(0, Math.max(limit - 1, 1))}…`;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
export function formatElapsedDuration(ms = 0) {
|
|
240
|
+
const totalSeconds = Math.max(0, Math.floor((Number(ms) || 0) / 1000));
|
|
241
|
+
const seconds = totalSeconds % 60;
|
|
242
|
+
const minutes = Math.floor(totalSeconds / 60) % 60;
|
|
243
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
244
|
+
const two = (value) => String(value).padStart(2, "0");
|
|
245
|
+
return hours > 0 ? `${hours}:${two(minutes)}:${two(seconds)}` : `${two(minutes)}:${two(seconds)}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
239
248
|
function wrapTextLine(value = "", width = 72) {
|
|
240
249
|
const text = stripAnsi(String(value || ""));
|
|
241
250
|
if (text.length <= width) return [text];
|
|
@@ -1254,6 +1263,8 @@ class LiveRunInput {
|
|
|
1254
1263
|
this.pendingAsap = [];
|
|
1255
1264
|
this.pendingQueued = [];
|
|
1256
1265
|
this.statusLine = "";
|
|
1266
|
+
this.statusStartedAt = 0;
|
|
1267
|
+
this.statusTimer = null;
|
|
1257
1268
|
this.wasRaw = Boolean(input.isRaw);
|
|
1258
1269
|
this.started = false;
|
|
1259
1270
|
this.handler = this.handleKey.bind(this);
|
|
@@ -1270,6 +1281,11 @@ class LiveRunInput {
|
|
|
1270
1281
|
input.setRawMode(true);
|
|
1271
1282
|
input.on("keypress", this.handler);
|
|
1272
1283
|
activeRunInput = this;
|
|
1284
|
+
this.statusStartedAt = Date.now();
|
|
1285
|
+
this.statusTimer = setInterval(() => {
|
|
1286
|
+
if (this.started && this.statusLine) this.renderNow();
|
|
1287
|
+
}, 1000);
|
|
1288
|
+
this.statusTimer.unref?.();
|
|
1273
1289
|
this.started = true;
|
|
1274
1290
|
this.renderNow();
|
|
1275
1291
|
return true;
|
|
@@ -1281,6 +1297,10 @@ class LiveRunInput {
|
|
|
1281
1297
|
clearImmediate(this.redrawHandle);
|
|
1282
1298
|
this.redrawHandle = null;
|
|
1283
1299
|
}
|
|
1300
|
+
if (this.statusTimer) {
|
|
1301
|
+
clearInterval(this.statusTimer);
|
|
1302
|
+
this.statusTimer = null;
|
|
1303
|
+
}
|
|
1284
1304
|
input.off("keypress", this.handler);
|
|
1285
1305
|
if (typeof input.setRawMode === "function") input.setRawMode(this.wasRaw);
|
|
1286
1306
|
this.clearForExternalOutput();
|
|
@@ -1312,6 +1332,12 @@ class LiveRunInput {
|
|
|
1312
1332
|
output.write(ansi.cursorShow);
|
|
1313
1333
|
}
|
|
1314
1334
|
|
|
1335
|
+
currentStatusLine() {
|
|
1336
|
+
if (!this.statusLine) return "";
|
|
1337
|
+
const elapsed = formatElapsedDuration(Date.now() - (this.statusStartedAt || Date.now()));
|
|
1338
|
+
return compactLine(`${elapsed} · ${this.statusLine}`, Math.max(terminalWidth() - 16, 36));
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1315
1341
|
renderNow() {
|
|
1316
1342
|
if (this.redrawHandle) {
|
|
1317
1343
|
clearImmediate(this.redrawHandle);
|
|
@@ -1320,7 +1346,7 @@ class LiveRunInput {
|
|
|
1320
1346
|
this.rendered = renderPromptBuffer(this.buffer, this.cursor, this.rendered, {
|
|
1321
1347
|
commandCwd: this.commandCwd,
|
|
1322
1348
|
language: this.state.language || cliLanguage,
|
|
1323
|
-
statusLine: this.
|
|
1349
|
+
statusLine: this.currentStatusLine(),
|
|
1324
1350
|
pendingAsap: this.pendingAsap,
|
|
1325
1351
|
pendingQueued: this.pendingQueued,
|
|
1326
1352
|
});
|
|
@@ -1352,7 +1378,7 @@ class LiveRunInput {
|
|
|
1352
1378
|
const layout = buildPromptLayout(this.buffer, this.cursor, terminalWidth(), terminalHeight(), {
|
|
1353
1379
|
commandCwd: this.commandCwd,
|
|
1354
1380
|
language: this.state.language || cliLanguage,
|
|
1355
|
-
statusLine: this.
|
|
1381
|
+
statusLine: this.currentStatusLine(),
|
|
1356
1382
|
pendingAsap: this.pendingAsap,
|
|
1357
1383
|
pendingQueued: this.pendingQueued,
|
|
1358
1384
|
});
|
|
@@ -2469,7 +2495,7 @@ function buildReviewPrompt(focus = "") {
|
|
|
2469
2495
|
"3. Use `inspect_project`, `search_files`, and targeted `read_file`; avoid full-tree dumps. Prefer precise symbol/error searches over opening many files.",
|
|
2470
2496
|
"4. Exclude generated, vendored, binary, cache, and large artifact paths: .git, node_modules, vendor, dist, build, out, target, coverage, .next, .turbo, .venv, __pycache__, .pytest_cache, .aginti-sessions, .sessions, artifacts, images/videos/PDFs unless directly relevant.",
|
|
2471
2497
|
"5. Context budget: at most two discovery passes; at most 12 primary files read initially; expand only when a concrete risk requires neighboring code.",
|
|
2472
|
-
"6. Check likely validation commands from manifests, but run only focused non-destructive checks when useful.
|
|
2498
|
+
"6. Check likely validation commands from manifests, but run only focused non-destructive checks when useful. Bound shell checks with `timeout 30s ...` when available, avoid broad watch/dev commands, and do not install packages or run long broad suites unless clearly justified.",
|
|
2473
2499
|
"7. Stop when you have enough evidence. Do not keep scanning just because more files exist.",
|
|
2474
2500
|
"",
|
|
2475
2501
|
"Final answer format:",
|