@lazyingart/agintiflow 0.20.66 → 0.20.68

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.66",
3
+ "version": "0.20.68",
4
4
  "type": "module",
5
5
  "description": "Low-cost, project-aware Web and CLI agents with DeepSeek/Venice/OpenAI routing, visible tool calls, durable sessions, scouts, AAPS, SCS, and guarded local execution.",
6
6
  "license": "Apache-2.0",
@@ -24,6 +24,7 @@ async function exists(file) {
24
24
  const init = await runAapsAction("init", ["Smoke AAPS Project"], { cwd: tempRoot, packageDir: repoRoot });
25
25
  assert(init.ok, "AAPS init failed");
26
26
  assert(await exists(path.join(tempRoot, "aaps.project.json")), "AAPS init did not write manifest");
27
+ assert(await exists(path.join(tempRoot, "agents", "agent_registry.json")), "AAPS init did not write starter agent registry");
27
28
  assert(await exists(path.join(tempRoot, "workflows", "main.aaps")), "AAPS init did not write starter workflow");
28
29
 
29
30
  const files = await runAapsAction("files", [], { cwd: tempRoot, packageDir: repoRoot });
@@ -43,10 +44,7 @@ if (discovery.found) {
43
44
 
44
45
  const compile = await runAapsAction("compile", ["check"], { cwd: tempRoot, packageDir: repoRoot });
45
46
  assert(compile.json?.phase?.parse === "ok", `AAPS compile check did not return a structured parse-ok report\n${formatAapsResult(compile)}`);
46
- assert(
47
- compile.json?.status === "missing_components" || compile.json?.ok === true,
48
- `AAPS compile check returned an unexpected status\n${formatAapsResult(compile)}`
49
- );
47
+ assert(compile.ok && compile.json?.ok === true, `AAPS starter should compile cleanly after init\n${formatAapsResult(compile)}`);
50
48
  } else {
51
49
  const validate = await runAapsAction("validate", [], { cwd: tempRoot, packageDir: repoRoot });
52
50
  assert(validate.ok === false && validate.error, "AAPS missing path should return a structured error");
@@ -246,6 +246,20 @@ try {
246
246
  failedNetworkAdvice.instruction.includes("Stop and present this blocker"),
247
247
  "network failure advice did not tell the model to stop and ask"
248
248
  );
249
+ const failedOutsidePathAdvice = buildFailedCommandAdvice({
250
+ args: { command: 'echo "outside permission test" > /home/lachlan/ProjectsLFS/outside.txt' },
251
+ commandPolicy: evaluateCommandPolicy('echo "outside permission test" > /home/lachlan/ProjectsLFS/outside.txt', dockerWorkspacePolicy),
252
+ commandResult: {
253
+ ok: false,
254
+ stdout: "EXIT: 1",
255
+ stderr: "bash: line 1: /home/lachlan/ProjectsLFS/outside.txt: No such file or directory",
256
+ },
257
+ config: dockerWorkspacePolicy,
258
+ state: { sessionId: "coding-outside-path-smoke" },
259
+ });
260
+ assert(failedOutsidePathAdvice?.failureKind === "workspace-path", "outside host path failure advice was not generated");
261
+ assert(failedOutsidePathAdvice.suggestedCommand.includes("--sandbox-mode host"), "outside path advice did not suggest host mode");
262
+ assert(!failedOutsidePathAdvice.suggestedCommand.includes("aginti run --sandbox host"), "outside path advice used legacy sandbox syntax");
249
263
  assert(
250
264
  shouldRunParallelScouts(
251
265
  {
@@ -478,13 +478,21 @@ async function createAapsStarterProject({ cwd = process.cwd(), name = "" } = {})
478
478
  const projectDir = path.resolve(cwd || process.cwd());
479
479
  const projectName = String(name || path.basename(projectDir) || "AgInTiFlow AAPS Project").trim();
480
480
  const workflowDir = path.join(projectDir, "workflows");
481
+ const agentsDir = path.join(projectDir, "agents");
481
482
  const reportsDir = path.join(projectDir, "reports");
482
483
  const runsDir = path.join(projectDir, "runs");
483
484
  const artifactsDir = path.join(projectDir, "artifacts");
484
- await Promise.all([fs.mkdir(workflowDir, { recursive: true }), fs.mkdir(reportsDir, { recursive: true }), fs.mkdir(runsDir, { recursive: true }), fs.mkdir(artifactsDir, { recursive: true })]);
485
+ await Promise.all([
486
+ fs.mkdir(workflowDir, { recursive: true }),
487
+ fs.mkdir(agentsDir, { recursive: true }),
488
+ fs.mkdir(reportsDir, { recursive: true }),
489
+ fs.mkdir(runsDir, { recursive: true }),
490
+ fs.mkdir(artifactsDir, { recursive: true }),
491
+ ]);
485
492
 
486
493
  const manifestPath = path.join(projectDir, "aaps.project.json");
487
494
  const workflowPath = path.join(workflowDir, "main.aaps");
495
+ const agentRegistryPath = path.join(agentsDir, "agent_registry.json");
488
496
  const created = [];
489
497
  if (!fsSync.existsSync(manifestPath)) {
490
498
  const now = new Date().toISOString();
@@ -501,6 +509,7 @@ async function createAapsStarterProject({ cwd = process.cwd(), name = "" } = {})
501
509
  updated: now,
502
510
  paths: {
503
511
  workflows: "workflows",
512
+ agents: "agents",
504
513
  blocks: "blocks",
505
514
  skills: "skills",
506
515
  modules: "modules",
@@ -515,6 +524,7 @@ async function createAapsStarterProject({ cwd = process.cwd(), name = "" } = {})
515
524
  runDatabase: "runs/aaps-runs.jsonl",
516
525
  tools: ["node", "python3", "git", "aginti"],
517
526
  models: ["deepseek-v4-flash", "deepseek-v4-pro"],
527
+ agents: ["planner"],
518
528
  files: {
519
529
  workflows: ["workflows/main.aaps"],
520
530
  blocks: [],
@@ -530,6 +540,22 @@ async function createAapsStarterProject({ cwd = process.cwd(), name = "" } = {})
530
540
  await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
531
541
  created.push("aaps.project.json");
532
542
  }
543
+ if (!fsSync.existsSync(agentRegistryPath)) {
544
+ const registry = {
545
+ agents: [
546
+ {
547
+ name: "planner",
548
+ purpose: "Plan large project work in small, verifiable phases for the starter AAPS workflow.",
549
+ invocation: "prompt",
550
+ supportedTasks: ["planning", "workflow_planning", "compile_prompt"],
551
+ safety: ["project-local edits only", "ask before risky shell commands", "no secrets in logs"],
552
+ fallback: "prepare prompt-only handoff",
553
+ },
554
+ ],
555
+ };
556
+ await fs.writeFile(agentRegistryPath, `${JSON.stringify(registry, null, 2)}\n`, "utf8");
557
+ created.push("agents/agent_registry.json");
558
+ }
533
559
  if (!fsSync.existsSync(workflowPath)) {
534
560
  const source = `pipeline "${projectName} Starter" {
535
561
  subtitle "A project-local AAPS workflow for AgInTiFlow"
@@ -361,7 +361,7 @@ async function createInitialState(config, sessionId) {
361
361
  ? `A shell command tool is available inside Docker sandbox mode ${config.sandboxMode}. Docker workspace mode with approved package installs supports broader setup and network commands. The project is mounted at /workspace and the persistent agent toolchain is mounted at /aginti-env with caches under /aginti-cache.`
362
362
  : `A host shell command tool is available under the configured trust policy on ${platformLabel(platform)}. On native Windows, prefer PowerShell/cmd-compatible commands or switch to WSL/Docker for bash-like toolchains.`
363
363
  : "No shell command tool is available.",
364
- "Permission contract: current-workspace file writes are allowed through workspace file tools when enabled. Outside-workspace paths, host sudo, host OS package installs, destructive git/shell actions, and blocked network/setup must not be bypassed by retrying variants. If a tool result includes permissionAdvice or suggestedCommand, stop, explain the blocker, and ask the user to approve/rerun that mode or choose a safer workspace-relative path.",
364
+ "Permission contract: current-workspace file writes are allowed through workspace file tools when enabled. Outside-workspace paths, host sudo, host OS package installs, destructive git/shell actions, and blocked network/setup must not be bypassed by retrying variants. If a tool result includes permissionAdvice or suggestedCommand, stop, explain the blocker, copy the exact suggestedCommand when giving a rerun path, and ask the user to approve/rerun that mode or choose a safer workspace-relative path. Never invent legacy AgInTi syntax such as `aginti run --sandbox host`; use the exact flags from permissionAdvice.",
365
365
  "If an operation fails but a directory, artifact, or file already exists, treat it as pre-existing unless you have evidence this run created or updated it. Verify expected outputs before claiming success.",
366
366
  config.allowShellTool
367
367
  ? "Host tmux tools are available for long-running terminals: list sessions, capture panes, send safe keys/text, and start detached sessions. Prefer these tools for monitoring long installs/tests/dev servers without blocking; capture before sending input and never send secrets or sudo passwords. Do not start or install tmux inside Docker run_command containers because those containers are short-lived."
@@ -68,7 +68,7 @@ export function formatBehaviorContractForPrompt({ mode = "runtime" } = {}) {
68
68
  "Prefer the smallest coherent change that satisfies the request; do not add speculative features or abstractions.",
69
69
  "Make surgical edits: no drive-by refactors, unrelated formatting churn, or deletion of code you did not need to touch.",
70
70
  "Define or infer concrete success criteria for non-trivial work, then run focused checks or state why checks are unavailable.",
71
- "Respect the permission contract: if a tool is blocked, stop and present the safe rerun/approval path instead of retrying variants.",
71
+ "Respect the permission contract: if a tool is blocked or returns permissionAdvice, stop and present the exact suggestedCommand/approval path instead of retrying variants or inventing CLI flags.",
72
72
  "Keep artifacts durable and discoverable with descriptive non-conflicting names; never overwrite unless the user clearly asked.",
73
73
  "When reporting shell, language, runtime, build, or test results, name the actual environment used (host vs Docker, relevant interpreter/tool path/version when it matters). Do not claim compatibility across untested runtimes, hosts, containers, or language versions; state the caveat or run an explicit check.",
74
74
  ].join(" ");
@@ -10,6 +10,13 @@ const NETWORK_FAILURE_PATTERNS = [
10
10
  /unable to access ['"].*?:/i,
11
11
  ];
12
12
 
13
+ const DOCKER_WORKSPACE_PATH_FAILURE_PATTERNS = [
14
+ /\/home\/[^:\n]+:\s+No such file or directory/i,
15
+ /\/Users\/[^:\n]+:\s+No such file or directory/i,
16
+ /[A-Z]:\\[^:\n]+:\s+No such file or directory/i,
17
+ /cannot statx? ['"][^'"]+['"]:\s+No such file or directory/i,
18
+ ];
19
+
13
20
  function quoteShell(value = "") {
14
21
  const text = String(value || "");
15
22
  return `'${text.replace(/'/g, `'\\''`)}'`;
@@ -183,7 +190,26 @@ export function looksLikeNetworkFailure(result = {}) {
183
190
  return NETWORK_FAILURE_PATTERNS.some((pattern) => pattern.test(text));
184
191
  }
185
192
 
193
+ export function looksLikeDockerWorkspacePathFailure(result = {}, config = {}) {
194
+ if ((config.sandboxMode || "") !== "docker-workspace") return false;
195
+ const text = `${result.stdout || ""}\n${result.stderr || ""}`;
196
+ return DOCKER_WORKSPACE_PATH_FAILURE_PATTERNS.some((pattern) => pattern.test(text));
197
+ }
198
+
186
199
  export function buildFailedCommandAdvice({ args = {}, commandPolicy = {}, commandResult = {}, config = {}, state = {} } = {}) {
200
+ if (looksLikeDockerWorkspacePathFailure(commandResult, config)) {
201
+ return {
202
+ ...adviceForCategory("workspace-path", {
203
+ toolName: "run_command",
204
+ args,
205
+ config,
206
+ state,
207
+ reason:
208
+ "The command referenced a host absolute path that is not mounted inside the Docker workspace. Do not retry shell variants; keep output in the workspace or ask for explicit host-mode approval.",
209
+ }),
210
+ failureKind: "workspace-path",
211
+ };
212
+ }
187
213
  if (!looksLikeNetworkFailure(commandResult)) return null;
188
214
  return {
189
215
  ...adviceForCategory(commandPolicy.needsNetwork ? "network-fetch" : "general-shell", {