@lazyingart/agintiflow 0.20.320 → 0.20.321

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.320",
3
+ "version": "0.20.321",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -167,6 +167,53 @@ assert.equal(
167
167
  );
168
168
  fs.rmSync(educationWorkspace, { recursive: true, force: true });
169
169
 
170
+ const crowdedWorkspace = fs.mkdtempSync(
171
+ path.join(os.tmpdir(), "aginti-crowded-scoped-artifact-")
172
+ );
173
+ const crowdedArtifactRoot = path.join(crowdedWorkspace, "output", "task-artifacts");
174
+ const crowdedReportDir = path.join(crowdedArtifactRoot, "reports", "final");
175
+ fs.mkdirSync(crowdedReportDir, { recursive: true });
176
+ for (let index = 0; index < 3005; index += 1) {
177
+ fs.writeFileSync(
178
+ path.join(crowdedWorkspace, `unrelated-${String(index).padStart(4, "0")}.txt`),
179
+ "noise\n",
180
+ "utf8"
181
+ );
182
+ }
183
+ fs.writeFileSync(
184
+ path.join(crowdedReportDir, "wecom-external-group-ai-bot-capabilities.md"),
185
+ "# Source-grounded report\n",
186
+ "utf8"
187
+ );
188
+ const crowdedScopedContract = deriveScsTaskContract({
189
+ goal: [
190
+ "Save one concise source-grounded Markdown report under the task artifact directory.",
191
+ `AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
192
+ mode: "task",
193
+ request:
194
+ "Save one concise source-grounded Markdown report under the task artifact directory.",
195
+ artifact_root: crowdedArtifactRoot,
196
+ })}`,
197
+ ].join("\n"),
198
+ taskProfile: "research",
199
+ });
200
+ const crowdedScopedArtifacts = evaluateRequestedArtifactRequirements(
201
+ crowdedScopedContract,
202
+ { commandCwd: crowdedWorkspace, state: {} }
203
+ );
204
+ assert.equal(
205
+ crowdedScopedArtifacts.ok,
206
+ true,
207
+ `a valid scoped Markdown report was hidden by unrelated workspace files: ${crowdedScopedArtifacts.reason}`
208
+ );
209
+ assert(
210
+ crowdedScopedArtifacts.candidates.some((item) =>
211
+ item.path.endsWith("wecom-external-group-ai-bot-capabilities.md")
212
+ ),
213
+ "the host-declared task artifact root was not inspected before the bounded workspace scan"
214
+ );
215
+ fs.rmSync(crowdedWorkspace, { recursive: true, force: true });
216
+
170
217
  function fakeStudentClient(json) {
171
218
  return {
172
219
  chat: {
@@ -2654,58 +2654,86 @@ function taskArtifactMutationPaths(state = {}) {
2654
2654
  return paths;
2655
2655
  }
2656
2656
 
2657
- function collectRequestedArtifactCandidates(commandCwd = process.cwd(), state = {}) {
2657
+ function collectRequestedArtifactCandidates(
2658
+ commandCwd = process.cwd(),
2659
+ state = {},
2660
+ artifactRoot = ""
2661
+ ) {
2658
2662
  const root = path.resolve(commandCwd || process.cwd());
2659
2663
  const freshnessBoundary = taskArtifactFreshnessBoundary(state);
2660
2664
  const mutationPaths = taskArtifactMutationPaths(state);
2661
2665
  const candidates = [];
2662
- const queue = [{ absolutePath: root, depth: 0 }];
2663
- let visited = 0;
2664
- while (queue.length && candidates.length < 3000 && visited < 6000) {
2665
- const current = queue.shift();
2666
- visited += 1;
2667
- let entries = [];
2666
+ const seenFiles = new Set();
2667
+ const scanRoots = [];
2668
+ const appendScanRoot = (rawPath = "") => {
2669
+ const absolutePath = rawPath
2670
+ ? resolveContractPath(root, rawPath)
2671
+ : root;
2672
+ if (!absolutePath || scanRoots.includes(absolutePath)) return;
2668
2673
  try {
2669
- entries = fs.readdirSync(current.absolutePath, { withFileTypes: true });
2674
+ if (!fs.statSync(absolutePath).isDirectory()) return;
2670
2675
  } catch {
2671
- continue;
2676
+ return;
2672
2677
  }
2673
- for (const entry of entries) {
2674
- if (entry.isSymbolicLink()) continue;
2675
- const absolutePath = path.join(current.absolutePath, entry.name);
2676
- if (entry.isDirectory()) {
2677
- if (
2678
- current.depth < 7 &&
2679
- !ARTIFACT_SCAN_IGNORED_DIRECTORIES.has(entry.name) &&
2680
- !entry.name.startsWith(".cache")
2681
- ) {
2682
- queue.push({ absolutePath, depth: current.depth + 1 });
2683
- }
2684
- continue;
2685
- }
2686
- if (!entry.isFile()) continue;
2687
- let stat;
2678
+ scanRoots.push(absolutePath);
2679
+ };
2680
+ // A host-declared task artifact root is authoritative and usually sits deep
2681
+ // inside a large application workspace. Inspect it before the bounded broad
2682
+ // workspace scan so unrelated files cannot exhaust the candidate limit and
2683
+ // hide a valid task deliverable.
2684
+ appendScanRoot(artifactRoot);
2685
+ appendScanRoot();
2686
+ let visited = 0;
2687
+ for (const scanRoot of scanRoots) {
2688
+ const queue = [{ absolutePath: scanRoot, depth: 0 }];
2689
+ while (queue.length && candidates.length < 3000 && visited < 6000) {
2690
+ const current = queue.shift();
2691
+ visited += 1;
2692
+ let entries = [];
2688
2693
  try {
2689
- stat = fs.statSync(absolutePath);
2694
+ entries = fs.readdirSync(current.absolutePath, { withFileTypes: true });
2690
2695
  } catch {
2691
2696
  continue;
2692
2697
  }
2693
- if (!stat.size) continue;
2694
- const relativePath = path.relative(root, absolutePath).replace(/\\/g, "/");
2695
- const normalized = normalizedContractPath(relativePath).toLocaleLowerCase("en-US");
2696
- const fresh = Boolean(
2697
- mutationPaths.has(normalized) ||
2698
- freshnessBoundary === 0 ||
2699
- Number(stat.mtimeMs || 0) >= freshnessBoundary
2700
- );
2701
- candidates.push({
2702
- path: relativePath,
2703
- extension: path.extname(entry.name).toLocaleLowerCase("en-US"),
2704
- basename: entry.name.toLocaleLowerCase("en-US"),
2705
- bytes: stat.size,
2706
- mtimeMs: Number(stat.mtimeMs || 0),
2707
- fresh,
2708
- });
2698
+ for (const entry of entries) {
2699
+ if (entry.isSymbolicLink()) continue;
2700
+ const absolutePath = path.join(current.absolutePath, entry.name);
2701
+ if (entry.isDirectory()) {
2702
+ if (
2703
+ current.depth < 7 &&
2704
+ !ARTIFACT_SCAN_IGNORED_DIRECTORIES.has(entry.name) &&
2705
+ !entry.name.startsWith(".cache")
2706
+ ) {
2707
+ queue.push({ absolutePath, depth: current.depth + 1 });
2708
+ }
2709
+ continue;
2710
+ }
2711
+ if (!entry.isFile()) continue;
2712
+ if (seenFiles.has(absolutePath)) continue;
2713
+ seenFiles.add(absolutePath);
2714
+ let stat;
2715
+ try {
2716
+ stat = fs.statSync(absolutePath);
2717
+ } catch {
2718
+ continue;
2719
+ }
2720
+ if (!stat.size) continue;
2721
+ const relativePath = path.relative(root, absolutePath).replace(/\\/g, "/");
2722
+ const normalized = normalizedContractPath(relativePath).toLocaleLowerCase("en-US");
2723
+ const fresh = Boolean(
2724
+ mutationPaths.has(normalized) ||
2725
+ freshnessBoundary === 0 ||
2726
+ Number(stat.mtimeMs || 0) >= freshnessBoundary
2727
+ );
2728
+ candidates.push({
2729
+ path: relativePath,
2730
+ extension: path.extname(entry.name).toLocaleLowerCase("en-US"),
2731
+ basename: entry.name.toLocaleLowerCase("en-US"),
2732
+ bytes: stat.size,
2733
+ mtimeMs: Number(stat.mtimeMs || 0),
2734
+ fresh,
2735
+ });
2736
+ }
2709
2737
  }
2710
2738
  }
2711
2739
  return candidates;
@@ -2763,7 +2791,11 @@ export function evaluateRequestedArtifactRequirements(
2763
2791
  reason: "No semantic artifact-set contract was inferred.",
2764
2792
  };
2765
2793
  }
2766
- const candidates = collectRequestedArtifactCandidates(commandCwd, state);
2794
+ const candidates = collectRequestedArtifactCandidates(
2795
+ commandCwd,
2796
+ state,
2797
+ String(contract.artifactRoot || "")
2798
+ );
2767
2799
  const requireFresh = contract.requiresFileMutation === true;
2768
2800
  const usableCandidates = requireFresh
2769
2801
  ? candidates.filter((candidate) => candidate.fresh)