@mjasnikovs/pi-task 0.40.31 → 0.40.32

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.
@@ -550,7 +550,11 @@ function docsRawCached(cache, pkg, profile, query, ensureIndexed, retrieveChunks
550
550
  function docsRawUncached(pkg, profile, cacheError, autoInstalled) {
551
551
  const parts = [];
552
552
  const surfaceFiles = collectFiles(pkg, profile).surface;
553
- const entryFirst = pkg.entry ? [pkg.entry, ...surfaceFiles.filter(f => f !== pkg.entry)] : surfaceFiles;
553
+ // Only an entry the rules KEPT goes first. A CJS-first package names its
554
+ // `.d.cts` in `types`, so the entry is exactly the twin `collectFiles` drops,
555
+ // and prepending it blind put it back at the head of the truncated blob.
556
+ const entry = pkg.entry !== null && surfaceFiles.includes(pkg.entry) ? pkg.entry : null;
557
+ const entryFirst = entry === null ? surfaceFiles : [entry, ...surfaceFiles.filter(f => f !== entry)];
554
558
  for (const abs of entryFirst) {
555
559
  let raw;
556
560
  try {
@@ -93,6 +93,9 @@ function computeContentHash(pkg, profile, supplements = []) {
93
93
  function walkSurface(root, profile) {
94
94
  const out = [];
95
95
  const stack = [root];
96
+ // A directory symlink is followed by its resolved target, so one pointing at
97
+ // an ancestor inside `root` walks the same subtree forever without this.
98
+ const walked = new Set([root]);
96
99
  while (stack.length) {
97
100
  const dir = stack.pop();
98
101
  let entries;
@@ -107,9 +110,11 @@ function walkSurface(root, profile) {
107
110
  continue;
108
111
  const full = path.join(dir, entry.name);
109
112
  if (entry.isSymbolicLink()) {
113
+ let stat;
110
114
  let realPath;
111
115
  try {
112
116
  realPath = fs.realpathSync(full);
117
+ stat = fs.statSync(realPath);
113
118
  }
114
119
  catch {
115
120
  continue;
@@ -117,15 +122,22 @@ function walkSurface(root, profile) {
117
122
  const relReal = path.relative(root, realPath);
118
123
  if (relReal.startsWith('..'))
119
124
  continue;
120
- const stat = fs.statSync(realPath);
121
- if (stat.isDirectory())
125
+ if (stat.isDirectory()) {
126
+ if (walked.has(realPath))
127
+ continue;
128
+ walked.add(realPath);
122
129
  stack.push(realPath);
130
+ }
123
131
  else if (stat.isFile() && profile.isSurfaceFile(realPath))
124
132
  out.push(realPath);
125
133
  continue;
126
134
  }
127
- if (entry.isDirectory())
135
+ if (entry.isDirectory()) {
136
+ if (walked.has(full))
137
+ continue;
138
+ walked.add(full);
128
139
  stack.push(full);
140
+ }
129
141
  else if (entry.isFile() && profile.isSurfaceFile(entry.name))
130
142
  out.push(full);
131
143
  }
@@ -25,7 +25,7 @@ import * as os from 'node:os';
25
25
  import * as path from 'node:path';
26
26
  import { ResolveError } from './docs-resolve.js';
27
27
  import { findAtOrAbove } from './eco-cargo.js';
28
- import { buildConstraint } from './go-surface.js';
28
+ import { buildConstraint, splitGoItems } from './go-surface.js';
29
29
  import { readZip, readEntry, isUnsafeEntryName } from '../shared/zip.js';
30
30
  import { acquireStdlibPackage, findInGoroot, findSliced } from './go-stdlib.js';
31
31
  const PROXY = 'https://proxy.golang.org';
@@ -653,17 +653,21 @@ function holdsByDefault(src) {
653
653
  /**
654
654
  * The import paths a Go file's import block names.
655
655
  *
656
- * Scoped to the import declaration, not the file: a sibling's import path also
656
+ * Scoped to the import DECLARATION, not the file: a sibling's import path also
657
657
  * occurs as a plain string constant, in an error message and in a `go:generate`
658
658
  * line, and reading those keeps the very subpackage `selectOwnPackage` exists to
659
- * drop. An `ImportPath` is a `string_lit`, so the backtick form is legal Go and
659
+ * drop. A regex cannot draw that line a column-0 `import (` also sits inside a
660
+ * generator template's raw string and inside a doc comment's example — so the
661
+ * split is the surface scanner's, which already skips comments and literals.
662
+ * An `ImportPath` is a `string_lit`, so the backtick form is legal Go and
660
663
  * dropping it silently drops everything reachable only through it.
661
664
  */
662
665
  function importsOf(src) {
663
666
  const out = [];
664
- for (const decl of src.matchAll(/^import\s*(?:\(([\s\S]*?)^\)|(.*))$/gm)) {
665
- const body = decl[1] ?? decl[2] ?? '';
666
- for (const m of body.matchAll(/"([^"\n]+)"|`([^`]+)`/g))
667
+ for (const item of splitGoItems(src)) {
668
+ if (!/^import\b/.test(item.text))
669
+ continue;
670
+ for (const m of item.text.matchAll(/"([^"\n]+)"|`([^`]+)`/g))
667
671
  out.push(m[1] ?? m[2]);
668
672
  }
669
673
  return out;
@@ -683,9 +687,16 @@ function goMajor(name, version) {
683
687
  const inVersion = /^(?:v|go)?(\d+)\./.exec(version);
684
688
  return inVersion ? Number(inVersion[1]) : 1;
685
689
  }
686
- /** Does this file declare anything a caller of the package could be handed? */
690
+ /**
691
+ * Does this file declare anything a caller of the package could be handed?
692
+ *
693
+ * Read from the scanned declarations, not the raw text. `cloud.google.com/go`'s
694
+ * doc.go is one block comment, and a wrapped sentence beginning `type ` sits at
695
+ * column 0 — enough for a multiline regex to call the root the API and drop the
696
+ * subdirectories that hold all of it.
697
+ */
687
698
  function declaresApi(src) {
688
- return /^(?:func|type|var|const)\b/m.test(src);
699
+ return splitGoItems(src).some(item => /^(?:func|type|var|const)\b/.test(item.text));
689
700
  }
690
701
  /**
691
702
  * Keep the package the caller asked for, and only the subpackages it can reach.
@@ -729,7 +740,16 @@ export function selectOwnPackage(files, root, name, version) {
729
740
  const byDir = new Map();
730
741
  for (const f of files)
731
742
  byDir.set(dirOf(f), [...(byDir.get(dirOf(f)) ?? []), f]);
732
- if (!(byDir.get('') ?? []).some(f => declaresApi(safeRead(f) ?? '')))
743
+ const sources = new Map();
744
+ const sourceOf = (f) => {
745
+ const seen = sources.get(f);
746
+ if (seen !== undefined)
747
+ return seen;
748
+ const text = safeRead(f) ?? '';
749
+ sources.set(f, text);
750
+ return text;
751
+ };
752
+ if (!(byDir.get('') ?? []).some(f => declaresApi(sourceOf(f))))
733
753
  return [...files];
734
754
  const major = goMajor(name, version);
735
755
  const reachable = new Set(['']);
@@ -737,7 +757,7 @@ export function selectOwnPackage(files, root, name, version) {
737
757
  while (queue.length > 0) {
738
758
  const dir = queue.shift();
739
759
  for (const f of byDir.get(dir) ?? []) {
740
- for (const imp of importsOf(safeRead(f) ?? '')) {
760
+ for (const imp of importsOf(sourceOf(f))) {
741
761
  if (!imp.startsWith(`${name}/`))
742
762
  continue;
743
763
  const sub = imp.slice(name.length + 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.40.31",
3
+ "version": "0.40.32",
4
4
  "description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",