@lazyingart/agintiflow 0.20.44 → 0.20.45

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 CHANGED
@@ -146,6 +146,8 @@ aginti resume --all-sessions
146
146
  aginti resume latest
147
147
  aginti resume <session-id> "continue with a short follow-up"
148
148
  aginti queue <session-id> "extra instruction for the running agent"
149
+ aginti chat
150
+ # then in chat: /review [focus]
149
151
  aginti --profile code "write a small Python CLI app with tests"
150
152
  aginti --latex "draw a figure, write a short LaTeX report, and compile the PDF"
151
153
  aginti "set up this project and run the tests"
@@ -153,7 +155,9 @@ aginti "set up this project and run the tests"
153
155
 
154
156
  Bare `aginti resume` lists sessions for the current cwd by default. Use `--all-sessions` to browse the global session index; in the interactive selector, type a number to resume, `q` to quit, `/text` to filter the visible list, or `/` to clear the filter.
155
157
 
156
- Session cleanup is cwd-scoped by default. `aginti --remove-empty-sessions` shows only empty sessions and preselects them; `aginti --remove-sessions` shows all cwd sessions with nothing preselected. The cleanup selector uses Space to select, Up/Down to move, Tab to switch to OK/Cancel, and a second Yes/Cancel confirmation before deleting the project pointer and central `~/.agintiflow/sessions/<session-id>` data.
158
+ Session cleanup is cwd-scoped by default. `aginti --remove-empty-sessions` shows only empty sessions and preselects them; `aginti --remove-sessions` shows all cwd sessions with nothing preselected. The cleanup selector uses Space to select or activate the focused button, Up/Down to move, Tab to switch to Delete/Cancel, and a second Delete/Cancel confirmation before deleting the project pointer and central `~/.agintiflow/sessions/<session-id>` data.
159
+
160
+ In interactive chat, `/review [focus]` starts a bounded repository review. It begins from git status/diff and project instructions, reads manifests/entry points/tests/changed files first, avoids generated or binary folders, limits discovery passes, and reports findings before any summary.
157
161
 
158
162
  Run from a source checkout:
159
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.44",
3
+ "version": "0.20.45",
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",
@@ -260,7 +260,7 @@ try {
260
260
  }
261
261
  const helpResult = await runChat("/help\n/exit\n");
262
262
  const misspelledAuxiliary = "/auxil" + "liary";
263
- if (!helpResult.stdout.includes("/auxiliary") || helpResult.stdout.includes(misspelledAuxiliary)) {
263
+ if (!helpResult.stdout.includes("/auxiliary") || !helpResult.stdout.includes("/review") || helpResult.stdout.includes(misspelledAuxiliary)) {
264
264
  throw new Error("interactive help did not expose only the correctly spelled /auxiliary command");
265
265
  }
266
266
  const zhHelpResult = await runCli(["chat", "--language", "zh-Hans"], "/help\n/exit\n");
@@ -271,6 +271,10 @@ try {
271
271
  if (!skillsResult.stdout.includes("website-app") || !skillsResult.stdout.includes("Website And App Builder")) {
272
272
  throw new Error("interactive /skills did not show matching built-in skills");
273
273
  }
274
+ const reviewResult = await runChat("/review changed files only\n/exit\n");
275
+ if (!reviewResult.stdout.includes("Review focus: changed files only") || !reviewResult.stdout.includes("Mock run complete")) {
276
+ throw new Error("interactive /review did not launch the bounded review workflow");
277
+ }
274
278
  const abbreviatedSkillsResult = await runChat("/sk website\n/ex\n");
275
279
  if (abbreviatedSkillsResult.stdout.includes("Unknown command") || !abbreviatedSkillsResult.stdout.includes("website-app")) {
276
280
  throw new Error("interactive slash command prefix did not auto-select the first matching command");
@@ -347,6 +351,7 @@ try {
347
351
  "instructions-command",
348
352
  "auxiliary-command-spelling",
349
353
  "skills-command",
354
+ "review-command",
350
355
  "slash-prefix-autoselect",
351
356
  "slash-prefix-canonical-history",
352
357
  "instructions-chat-edit",
@@ -20,5 +20,12 @@ tools:
20
20
 
21
21
  Prioritize findings over summary. Inspect changed files, neighboring code, tests, and runtime assumptions. Report concrete risks with file paths, reproduction evidence, and suggested fixes.
22
22
 
23
- If no findings are found, say that clearly and name residual risk or missing test coverage. Do not rewrite code during a review unless the user asks for fixes.
23
+ Use a bounded review loop:
24
+
25
+ 1. Start with git status/diff and project instructions or manifests.
26
+ 2. Read high-signal files first: changed files, entry points, tests, package/build configs, and nearby code needed to prove a risk.
27
+ 3. Avoid full-tree reads and generated/vendor/cache/binary folders such as `.git`, `node_modules`, `dist`, `build`, `target`, `coverage`, `.venv`, `__pycache__`, `.aginti-sessions`, `.sessions`, and artifacts.
28
+ 4. Cap discovery at two passes unless a concrete finding needs one more neighboring file.
29
+ 5. Run focused non-destructive checks when useful; do not install dependencies or run long broad suites for a review unless clearly justified.
24
30
 
31
+ If no findings are found, say that clearly and name residual risk or missing test coverage. Do not rewrite code during a review unless the user asks for fixes.
package/src/cli.js CHANGED
@@ -607,6 +607,7 @@ const removeSessionAnsi = {
607
607
  reset: "\x1b[0m",
608
608
  bold: "\x1b[1m",
609
609
  dim: "\x1b[2m",
610
+ red: "\x1b[31m",
610
611
  inverse: "\x1b[7m",
611
612
  };
612
613
 
@@ -624,10 +625,13 @@ function ellipsize(text, width) {
624
625
  return `${value.slice(0, Math.max(0, width - 1))}…`;
625
626
  }
626
627
 
627
- function buttonLabel(label, focused, disabled = false) {
628
+ function buttonLabel(label, focused, disabled = false, danger = false) {
628
629
  const text = ` ${label} `;
629
630
  if (disabled) return removeSessionColor(text, removeSessionAnsi.dim);
630
- return focused ? removeSessionColor(text, removeSessionAnsi.inverse, removeSessionAnsi.bold) : text;
631
+ const codes = [];
632
+ if (danger) codes.push(removeSessionAnsi.red, removeSessionAnsi.bold);
633
+ if (focused) codes.push(removeSessionAnsi.inverse, removeSessionAnsi.bold);
634
+ return codes.length > 0 ? removeSessionColor(text, ...codes) : text;
631
635
  }
632
636
 
633
637
  function renderSessionRemovalWizard(state) {
@@ -658,12 +662,12 @@ function renderSessionRemovalWizard(state) {
658
662
  });
659
663
  const footer =
660
664
  state.phase === "confirm"
661
- ? `Confirm deletion: ${buttonLabel("Yes, delete", state.confirmFocus === "yes")} ${buttonLabel("Cancel", state.confirmFocus === "cancel")}`
662
- : `Actions: ${buttonLabel(`OK delete ${selectedCount}`, state.focus === "ok", selectedCount === 0)} ${buttonLabel("Cancel", state.focus === "cancel")}`;
665
+ ? `Confirm deletion: ${buttonLabel("Delete", state.confirmFocus === "yes", false, true)} ${buttonLabel("Cancel", state.confirmFocus === "cancel")}`
666
+ : `Actions: ${buttonLabel(`Delete ${selectedCount}`, state.focus === "ok", selectedCount === 0, true)} ${buttonLabel("Cancel", state.focus === "cancel")}`;
663
667
  const guidance =
664
668
  state.phase === "confirm"
665
- ? "Left/Right switches choice. Enter confirms. Esc/q cancels."
666
- : "Space toggles. Up/Down moves. Tab changes focus. Enter opens confirm. Esc/q cancels.";
669
+ ? "Left/Right switches choice. Enter/Space confirms. Esc/q cancels."
670
+ : "Space toggles or activates focused button. Up/Down moves. Tab changes focus. Esc/q cancels.";
667
671
  const lines = [
668
672
  `╭${border}╮`,
669
673
  line(state.title),
@@ -733,7 +737,7 @@ async function promptRemoveSessions(candidates, { defaultSelectedIds = [], title
733
737
  if (name === "escape" || name === "q") return cleanup(null);
734
738
  if (state.phase === "confirm") {
735
739
  if (name === "left" || name === "right" || name === "tab") state.confirmFocus = state.confirmFocus === "yes" ? "cancel" : "yes";
736
- else if (name === "return" || name === "enter") return cleanup(state.confirmFocus === "yes" ? [...state.selected] : null);
740
+ else if (name === "return" || name === "enter" || name === "space") return cleanup(state.confirmFocus === "yes" ? [...state.selected] : null);
737
741
  renderSessionRemovalWizard(state);
738
742
  return;
739
743
  }
@@ -741,7 +745,11 @@ async function promptRemoveSessions(candidates, { defaultSelectedIds = [], title
741
745
  else if (name === "down") moveCursor(1);
742
746
  else if (name === "pageup") moveCursor(-8);
743
747
  else if (name === "pagedown") moveCursor(8);
744
- else if (name === "space") toggleCurrent();
748
+ else if (name === "space") {
749
+ if (state.focus === "list") toggleCurrent();
750
+ else if (state.focus === "cancel") return cleanup(null);
751
+ else openConfirm();
752
+ }
745
753
  else if (name === "tab") state.focus = state.focus === "list" ? "ok" : state.focus === "ok" ? "cancel" : "list";
746
754
  else if (name === "left" || name === "right") state.focus = state.focus === "cancel" ? "ok" : "cancel";
747
755
  else if (name === "return" || name === "enter") {
@@ -69,6 +69,7 @@ const SLASH_COMMANDS = [
69
69
  "/new",
70
70
  "/resume",
71
71
  "/sessions",
72
+ "/review",
72
73
  "/rename",
73
74
  "/skills",
74
75
  "/skill",
@@ -635,6 +636,7 @@ function printHelp() {
635
636
  ` ${command("/auxiliary [status|grsai|venice|model [provider/model]|on|off|image]", "Manage optional auxiliary skills, including image generation.", "helpAuxiliary")}`,
636
637
  ` ${command("/new", "Start a fresh session on the next message.", "helpNew")}`,
637
638
  ` ${command("/resume <session-id>", "Continue a saved session.", "helpResume")}`,
639
+ ` ${command("/review [focus]", "Run a bounded repo/diff review with controlled context gathering.", "helpReview")}`,
638
640
  ` ${command("/rename [title|auto]", "Rename the current session.", "helpRename")}`,
639
641
  ` ${command("/sessions", "List recent sessions in this project.", "helpSessions")}`,
640
642
  ` ${command("/skills [query]", "List Markdown skills selected for a topic.", "helpSkills")}`,
@@ -2454,6 +2456,29 @@ async function promptAndSaveProviderKey(provider = "", state = null) {
2454
2456
  applyAuthWizardResult(result, state);
2455
2457
  }
2456
2458
 
2459
+ function buildReviewPrompt(focus = "") {
2460
+ const target = String(focus || "").trim();
2461
+ return [
2462
+ target ? `Review focus: ${target}` : "Review focus: current repository state, especially local changes if any.",
2463
+ "",
2464
+ "Run a bounded, evidence-based code review of this workspace. Default to read-only review; do not edit files unless the review focus explicitly asks for fixes.",
2465
+ "",
2466
+ "Review operating loop:",
2467
+ "1. Start with `git status --short`, `git diff --stat`, and project metadata. If git is unavailable, say so and continue from manifests.",
2468
+ "2. Read only the highest-signal context first: AGINTI.md/AGENTS.md/README, package/build manifests, entry points, tests, and files changed in git diff.",
2469
+ "3. Use `inspect_project`, `search_files`, and targeted `read_file`; avoid full-tree dumps. Prefer precise symbol/error searches over opening many files.",
2470
+ "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
+ "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. Do not install packages or run long broad suites unless clearly justified.",
2473
+ "7. Stop when you have enough evidence. Do not keep scanning just because more files exist.",
2474
+ "",
2475
+ "Final answer format:",
2476
+ "- Findings first, ordered by severity, with file/line references or exact evidence. Focus on bugs, regressions, security issues, data loss, broken UX/API behavior, and missing tests.",
2477
+ "- If no findings, state that clearly and list residual risks or unrun checks.",
2478
+ "- Then include a short `Files inspected` and `Checks run` section. Keep summary secondary and concise.",
2479
+ ].join("\n");
2480
+ }
2481
+
2457
2482
  async function handleCommand(line, state, packageDir) {
2458
2483
  const [rawCommand, ...rest] = line.slice(1).trim().split(/\s+/);
2459
2484
  const command = resolveSlashCommand(rawCommand);
@@ -2605,6 +2630,19 @@ async function handleCommand(line, state, packageDir) {
2605
2630
  }
2606
2631
  return true;
2607
2632
  }
2633
+ if (command === "review") {
2634
+ const previousProfile = state.taskProfile;
2635
+ const previousMaxSteps = state.maxSteps;
2636
+ try {
2637
+ state.taskProfile = "review";
2638
+ state.maxSteps = Math.max(state.maxSteps, 32);
2639
+ await runPrompt(buildReviewPrompt(value), state, packageDir);
2640
+ } finally {
2641
+ state.taskProfile = previousProfile;
2642
+ state.maxSteps = previousMaxSteps;
2643
+ }
2644
+ return true;
2645
+ }
2608
2646
  if (command === "rename") {
2609
2647
  if (!state.sessionId) {
2610
2648
  printAgentMessage("No active session to rename. Start or resume a session first.");
@@ -20,6 +20,13 @@ export const TASK_PROFILES = {
20
20
  "Bias toward senior large-repo engineering while still answering ordinary side questions. Inspect_project first unless context is already known, read AGINTI/AGENTS/README/manifests, locate entry points and tests, make a small explicit change plan, patch in coherent batches, run the narrowest relevant checks first, escalate to broader checks when stable, and summarize files changed, checks, tradeoffs, and remaining risks.",
21
21
  tools: ["inspect_project", "search_files", "read_file", "apply_patch", "shell", "sandbox", "canvas"],
22
22
  },
23
+ review: {
24
+ id: "review",
25
+ label: "Code review",
26
+ prompt:
27
+ "Bias toward bounded code review rather than implementation. Start with git status/diff and project instructions, then inspect manifests, entry points, tests, changed files, and only the neighboring code needed to prove or disprove concrete risks. Avoid full-tree scans, generated/vendor/cache/binary folders, and infinite context gathering. Do not edit files unless explicitly asked for fixes. Findings must come first, ordered by severity with file/line evidence; if no findings are found, say so and name residual risks and checks not run.",
28
+ tools: ["inspect_project", "search_files", "read_file", "shell", "web_search"],
29
+ },
23
30
  writing: {
24
31
  id: "writing",
25
32
  label: "Book/script writing",
@@ -331,6 +338,12 @@ const PROFILE_ALIASES = {
331
338
  etl: "data",
332
339
  dataframe: "data",
333
340
  qa: "qa",
341
+ review: "review",
342
+ reviews: "review",
343
+ "code-review": "review",
344
+ "code-audit": "review",
345
+ codereview: "review",
346
+ codeaudit: "review",
334
347
  test: "qa",
335
348
  testing: "qa",
336
349
  ci: "qa",
@@ -412,6 +425,7 @@ export function getTaskProfile(value = "auto") {
412
425
  export function defaultMaxStepsForProfile(value = "auto") {
413
426
  const profile = normalizeTaskProfile(value);
414
427
  if (profile === "code") return 36;
428
+ if (profile === "review") return 32;
415
429
  if (profile === "large-codebase") return 36;
416
430
  if (profile === "qa") return 40;
417
431
  if (profile === "app") return 40;