@lazyingart/agintiflow 0.20.41 → 0.20.43

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
@@ -140,6 +140,7 @@ aginti sessions show <session-id>
140
140
  aginti sessions rename <session-id> "friendly title"
141
141
  aginti storage migrate
142
142
  aginti resume
143
+ aginti resume --all-sessions
143
144
  aginti resume latest
144
145
  aginti resume <session-id> "continue with a short follow-up"
145
146
  aginti queue <session-id> "extra instruction for the running agent"
@@ -148,6 +149,8 @@ aginti --latex "draw a figure, write a short LaTeX report, and compile the PDF"
148
149
  aginti "set up this project and run the tests"
149
150
  ```
150
151
 
152
+ 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.
153
+
151
154
  Run from a source checkout:
152
155
 
153
156
  ```bash
package/demos/README.md CHANGED
@@ -4,3 +4,4 @@ This folder stores shareable screenshots and visual demos used by the repository
4
4
 
5
5
  - `agintiflow-cli-launch.png`: interactive CLI launch screen with the AgInTi Flow terminal banner, Docker workspace status, and input panel.
6
6
  - `agintiflow-cli-launch.jpg`: optimized README/web preview derived from the same screenshot.
7
+ - `archive/`: previous CLI launch screenshots kept before replacing the active README preview.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.41",
3
+ "version": "0.20.43",
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",
@@ -235,6 +235,11 @@ try {
235
235
  if (classifyEscapeAction({ active: true, pendingAsap: [] }) !== "abort") {
236
236
  throw new Error("active Esc should abort when no ASAP pipe messages are pending");
237
237
  }
238
+ await runChat("/exit\n");
239
+ const idleSessionEntries = await fs.readdir(path.join(agintiflowHome, "sessions"), { withFileTypes: true }).catch(() => []);
240
+ if (idleSessionEntries.some((entry) => entry.isDirectory())) {
241
+ throw new Error("idle interactive chat created a session before any user task");
242
+ }
238
243
  if (
239
244
  canonicalSlashPromptBuffer("/ve") !== "/venice" ||
240
245
  canonicalSlashPromptBuffer("/v") !== "/venice" ||
@@ -2,7 +2,7 @@
2
2
  import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
- import { ensureProjectSessionStorage, listProjectSessions } from "../src/project.js";
5
+ import { ensureProjectSessionStorage, listProjectSessions, sessionStoreOptions } from "../src/project.js";
6
6
  import { SessionStore } from "../src/session-store.js";
7
7
 
8
8
  const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-inbox-"));
@@ -58,6 +58,25 @@ try {
58
58
  "project session pointer was not created"
59
59
  );
60
60
 
61
+ const nestedCwd = path.join(legacyProject, "nested");
62
+ await fs.mkdir(nestedCwd, { recursive: true });
63
+ const otherCwdStore = new SessionStore(paths.globalSessionsDir, "other-cwd-smoke", sessionStoreOptions(legacyProject, "other-cwd-smoke"));
64
+ await otherCwdStore.saveState({
65
+ sessionId: "other-cwd-smoke",
66
+ createdAt: "2026-01-01T00:02:00.000Z",
67
+ updatedAt: "2026-01-01T00:03:00.000Z",
68
+ provider: "mock",
69
+ model: "mock-agent",
70
+ goal: "nested cwd smoke",
71
+ projectRoot: legacyProject,
72
+ commandCwd: nestedCwd,
73
+ chat: [],
74
+ });
75
+ const cwdFiltered = await listProjectSessions(legacyProject, { limit: 10, commandCwd: legacyProject });
76
+ assert(!cwdFiltered.some((session) => session.sessionId === "other-cwd-smoke"), "default cwd filtering included a different cwd session");
77
+ const allSessions = await listProjectSessions(legacyProject, { limit: 10, allSessions: true });
78
+ assert(allSessions.some((session) => session.sessionId === "other-cwd-smoke"), "--all-sessions mode did not include a different cwd session");
79
+
61
80
  console.log(
62
81
  JSON.stringify(
63
82
  {
@@ -68,6 +87,8 @@ try {
68
87
  "session-inbox-asap-priority",
69
88
  "legacy-session-migration",
70
89
  "global-session-store",
90
+ "cwd-session-filter",
91
+ "all-sessions-list",
71
92
  ],
72
93
  },
73
94
  null,
package/src/cli.js CHANGED
@@ -378,7 +378,7 @@ export function parseArgs(argv) {
378
378
 
379
379
  function printUsage() {
380
380
  console.log(
381
- 'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti skills [query] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [latest|<session-id>] ["prompt"] OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
381
+ 'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti skills [query] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [--all-sessions] [latest|<session-id>] ["prompt"] OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
382
382
  );
383
383
  console.log(`Languages: ${["en", "ja", "zh-Hans", "zh-Hant", "ko", "fr", "es", "ar", "vi", "de", "ru"].map((code) => `${code}=${languageLabel(code)}`).join(", ")}`);
384
384
  }
@@ -601,11 +601,13 @@ function printAuthWizardResult(result) {
601
601
  }
602
602
 
603
603
  async function handleSessionsCommand(argv) {
604
- const [verb = "list", sessionId = "", ...rest] = argv;
604
+ const normalizedArgv = argv[0] === "--all-sessions" ? ["list", ...argv] : argv;
605
+ const [verb = "list", sessionId = "", ...rest] = normalizedArgv;
605
606
  if (verb === "list") {
606
- const sessions = await listProjectSessions(process.cwd(), 80);
607
+ const allSessions = normalizedArgv.includes("--all-sessions");
608
+ const sessions = await listProjectSessions(process.cwd(), { limit: 80, allSessions });
607
609
  if (sessions.length === 0) {
608
- console.log("No project-local sessions found.");
610
+ console.log(allSessions ? "No sessions found." : "No sessions found for this cwd.");
609
611
  return;
610
612
  }
611
613
  for (const session of sessions) {
@@ -640,35 +642,82 @@ async function handleSessionsCommand(argv) {
640
642
  process.exit(1);
641
643
  }
642
644
 
643
- async function promptSelectSession(sessions) {
644
- if (!process.stdin.isTTY || !process.stdout.isTTY) return sessions[0]?.sessionId || "";
645
- console.log("Select a session to resume:");
646
- sessions.slice(0, 20).forEach((session, index) => {
645
+ function sessionSearchText(session) {
646
+ return [
647
+ session.sessionId,
648
+ session.provider,
649
+ session.model,
650
+ session.updatedAt,
651
+ session.title,
652
+ session.goal,
653
+ session.projectRoot,
654
+ session.commandCwd,
655
+ ]
656
+ .filter(Boolean)
657
+ .join(" ")
658
+ .toLowerCase();
659
+ }
660
+
661
+ function filterSessions(sessions, filterText = "") {
662
+ const needle = String(filterText || "").trim().toLowerCase();
663
+ if (!needle) return sessions;
664
+ return sessions.filter((session) => sessionSearchText(session).includes(needle));
665
+ }
666
+
667
+ function printSessionChoices(sessions, { filterText = "", allSessions = false, maxShown = 20 } = {}) {
668
+ const scope = allSessions ? "all sessions" : `cwd ${process.cwd()}`;
669
+ const shown = sessions.slice(0, maxShown);
670
+ console.log(`Select a session to resume (${scope}${filterText ? `, filter="${filterText}"` : ""}):`);
671
+ if (shown.length === 0) {
672
+ console.log("No matching sessions. Type /text to change the filter, / to clear it, or q to quit.");
673
+ return;
674
+ }
675
+ shown.forEach((session, index) => {
647
676
  const title = session.title || session.goal || "(untitled)";
648
677
  console.log(
649
678
  `${index + 1}. ${session.sessionId} ${session.provider || "unknown"}/${session.model || "unknown"} ${session.updatedAt || ""} ${title.slice(0, 90)}`
650
679
  );
651
680
  });
681
+ if (sessions.length > shown.length) console.log(`... ${sessions.length - shown.length} more hidden by display limit; type /text to narrow.`);
682
+ console.log("Type a number to select, /text to filter, / to clear, or q to quit.");
683
+ }
684
+
685
+ async function promptSelectSession(sessions, { allSessions = false } = {}) {
686
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return sessions[0]?.sessionId || "";
652
687
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
688
+ let filterText = "";
653
689
  try {
654
- const answer = await rl.question("Session number: ");
655
- const index = Number(answer.trim()) - 1;
656
- return sessions[index]?.sessionId || "";
690
+ while (true) {
691
+ const filtered = filterSessions(sessions, filterText);
692
+ printSessionChoices(filtered, { filterText, allSessions });
693
+ const answer = (await rl.question("Session number/filter: ")).trim();
694
+ if (!answer || answer.toLowerCase() === "q" || answer.toLowerCase() === "quit") return "";
695
+ if (answer.startsWith("/")) {
696
+ filterText = answer.slice(1).trim();
697
+ continue;
698
+ }
699
+ const index = Number(answer) - 1;
700
+ if (Number.isInteger(index) && index >= 0 && index < Math.min(filtered.length, 20)) {
701
+ return filtered[index]?.sessionId || "";
702
+ }
703
+ console.log("Invalid selection. Type a shown number, /text to filter, or q to quit.");
704
+ }
657
705
  } finally {
658
706
  rl.close();
659
707
  }
660
708
  }
661
709
 
662
- async function resolveResumeSessionId(sessionId) {
710
+ async function resolveResumeSessionId(sessionId, { allSessions = false } = {}) {
663
711
  if (sessionId && sessionId !== "latest") return sessionId;
664
- const sessions = await listProjectSessions(process.cwd(), 50);
712
+ const sessions = await listProjectSessions(process.cwd(), { limit: 1000, allSessions });
665
713
  if (sessionId === "latest" || sessions.length <= 1 || !process.stdin.isTTY || !process.stdout.isTTY) {
666
714
  if (sessions[0]?.sessionId) return sessions[0].sessionId;
667
715
  } else {
668
- const selected = await promptSelectSession(sessions);
716
+ const selected = await promptSelectSession(sessions, { allSessions });
669
717
  if (selected) return selected;
718
+ return "";
670
719
  }
671
- throw new Error("No project-local sessions found. Run `aginti sessions list` to check this folder.");
720
+ throw new Error(allSessions ? "No sessions found." : "No sessions found for this cwd. Use `aginti resume --all-sessions` to browse all sessions.");
672
721
  }
673
722
 
674
723
  async function handleQueueCommand(argv) {
@@ -837,14 +886,18 @@ export async function main(argv = process.argv.slice(2)) {
837
886
  }
838
887
 
839
888
  if (argv[0] === "resume") {
840
- let sessionId = argv[1] || "";
841
- const prompt = argv.slice(2).join(" ").trim();
889
+ const resumeArgv = argv.slice(1);
890
+ const allSessions = resumeArgv.includes("--all-sessions");
891
+ const positional = resumeArgv.filter((arg) => arg !== "--all-sessions");
892
+ let sessionId = positional[0] || "";
893
+ const prompt = positional.slice(1).join(" ").trim();
842
894
  try {
843
- sessionId = await resolveResumeSessionId(sessionId);
895
+ sessionId = await resolveResumeSessionId(sessionId, { allSessions });
844
896
  } catch (error) {
845
897
  console.error(error instanceof Error ? error.message : String(error));
846
898
  process.exit(1);
847
899
  }
900
+ if (!sessionId) return;
848
901
  if (!prompt) {
849
902
  await startInteractiveCli(agentDefaults({ ...parseArgs([]), resume: sessionId }), {
850
903
  packageDir,
package/src/project.js CHANGED
@@ -484,11 +484,34 @@ export async function setProviderKey(projectRoot, provider, value) {
484
484
  };
485
485
  }
486
486
 
487
- export async function listProjectSessions(projectRoot = process.cwd(), limit = 50) {
487
+ function normalizeSessionListOptions(projectRoot, limitOrOptions = 50) {
488
+ const options = typeof limitOrOptions === "object" && limitOrOptions !== null ? limitOrOptions : { limit: limitOrOptions };
489
+ const root = resolveProjectRoot(projectRoot);
490
+ const commandCwd = options.commandCwd === false ? "" : path.resolve(options.commandCwd || root);
491
+ return {
492
+ limit: Math.min(Math.max(Number(options.limit) || 50, 1), 1000),
493
+ commandCwd,
494
+ allSessions: Boolean(options.allSessions),
495
+ };
496
+ }
497
+
498
+ function sessionMatchesCommandCwd(session, commandCwd = "") {
499
+ if (!commandCwd) return true;
500
+ const value = session.commandCwd || session.projectRoot || "";
501
+ if (!value) return false;
502
+ return path.resolve(value) === path.resolve(commandCwd);
503
+ }
504
+
505
+ export async function listProjectSessions(projectRoot = process.cwd(), limitOrOptions = 50) {
506
+ const options = normalizeSessionListOptions(projectRoot, limitOrOptions);
488
507
  const paths = await ensureProjectSessionStorage(projectRoot);
489
508
  const indexed = (() => {
490
509
  try {
491
- return listSessionIndex({ projectRoot: paths.root, limit: Math.max(limit, 100) });
510
+ return listSessionIndex({
511
+ projectRoot: options.allSessions ? "" : paths.root,
512
+ commandCwd: options.allSessions ? "" : options.commandCwd,
513
+ limit: Math.max(options.limit, 100),
514
+ });
492
515
  } catch {
493
516
  return [];
494
517
  }
@@ -521,6 +544,7 @@ export async function listProjectSessions(projectRoot = process.cwd(), limit = 5
521
544
  updatedAt: state?.updatedAt || pointer.updatedAt || byId.get(sessionId)?.updatedAt || state?.createdAt || "",
522
545
  stepsCompleted: state?.stepsCompleted || 0,
523
546
  };
547
+ if (!options.allSessions && !sessionMatchesCommandCwd(record, options.commandCwd)) continue;
524
548
  byId.set(sessionId, record);
525
549
  try {
526
550
  upsertSessionIndex({
@@ -534,7 +558,7 @@ export async function listProjectSessions(projectRoot = process.cwd(), limit = 5
534
558
  }
535
559
 
536
560
  const sessions = [...byId.values()];
537
- return sessions.sort((a, b) => String(b.updatedAt).localeCompare(String(a.updatedAt))).slice(0, limit);
561
+ return sessions.sort((a, b) => String(b.updatedAt).localeCompare(String(a.updatedAt))).slice(0, options.limit);
538
562
  }
539
563
 
540
564
  export async function showProjectSession(projectRoot, sessionId) {
@@ -120,16 +120,26 @@ export function deleteSessionIndex(sessionId) {
120
120
  return result.changes > 0;
121
121
  }
122
122
 
123
- export function listSessionIndex({ projectRoot = "", limit = 100 } = {}) {
123
+ export function listSessionIndex({ projectRoot = "", commandCwd = "", limit = 100 } = {}) {
124
124
  const db = ensureIndexDb();
125
125
  const maxRows = Math.min(Math.max(Number(limit) || 100, 1), 1000);
126
126
  const columns = `session_id AS sessionId, project_root AS projectRoot, command_cwd AS commandCwd, project_sessions_dir AS projectSessionsDir,
127
127
  session_dir AS sessionDir, provider, model, goal, title, status,
128
128
  created_at AS createdAt, updated_at AS updatedAt, ended_at AS endedAt, result, error`;
129
+ const clauses = [];
130
+ const params = [];
129
131
  if (projectRoot) {
132
+ clauses.push("project_root = ?");
133
+ params.push(path.resolve(projectRoot));
134
+ }
135
+ if (commandCwd) {
136
+ clauses.push("command_cwd = ?");
137
+ params.push(path.resolve(commandCwd));
138
+ }
139
+ if (clauses.length > 0) {
130
140
  return db
131
- .prepare(`SELECT ${columns} FROM sessions WHERE project_root = ? ORDER BY updated_at DESC LIMIT ?`)
132
- .all(path.resolve(projectRoot), maxRows);
141
+ .prepare(`SELECT ${columns} FROM sessions WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC LIMIT ?`)
142
+ .all(...params, maxRows);
133
143
  }
134
144
  return db.prepare(`SELECT ${columns} FROM sessions ORDER BY updated_at DESC LIMIT ?`).all(maxRows);
135
145
  }