@mjasnikovs/pi-task 0.40.30 → 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.
|
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as os from 'node:os';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { openCache as defaultOpenCache } from './docs-cache.js';
|
|
6
|
-
import { ensureIndexed as defaultEnsureIndexed } from './docs-index.js';
|
|
6
|
+
import { collectFiles, ensureIndexed as defaultEnsureIndexed } from './docs-index.js';
|
|
7
7
|
import { npmProfile, chooseEcosystem, defaultEcosystemIo, ECOSYSTEMS } from './docs-ecosystems.js';
|
|
8
8
|
import { resolvePackage as defaultResolvePackage, ResolveError, resolveTypeSource, typesPackageName, splitRuntimeNamespace } from './docs-resolve.js';
|
|
9
9
|
import { retrieveChunks as defaultRetrieveChunks, PACKAGE_RETRIEVE_LIMIT, RETRIEVE_CONTENT_BUDGET } from './docs-retrieve.js';
|
|
@@ -549,8 +549,12 @@ function docsRawCached(cache, pkg, profile, query, ensureIndexed, retrieveChunks
|
|
|
549
549
|
}
|
|
550
550
|
function docsRawUncached(pkg, profile, cacheError, autoInstalled) {
|
|
551
551
|
const parts = [];
|
|
552
|
-
const surfaceFiles =
|
|
553
|
-
|
|
552
|
+
const surfaceFiles = collectFiles(pkg, profile).surface;
|
|
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 {
|
|
@@ -596,30 +600,6 @@ function docsRawUncached(pkg, profile, cacheError, autoInstalled) {
|
|
|
596
600
|
autoInstalled: autoInstalled ? true : undefined
|
|
597
601
|
};
|
|
598
602
|
}
|
|
599
|
-
function walkSurfaceAlpha(root, profile) {
|
|
600
|
-
const out = [];
|
|
601
|
-
const stack = [root];
|
|
602
|
-
while (stack.length) {
|
|
603
|
-
const dir = stack.pop();
|
|
604
|
-
let entries;
|
|
605
|
-
try {
|
|
606
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
607
|
-
}
|
|
608
|
-
catch {
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
for (const entry of entries) {
|
|
612
|
-
if (profile.skipDirs.includes(entry.name))
|
|
613
|
-
continue;
|
|
614
|
-
const full = path.join(dir, entry.name);
|
|
615
|
-
if (entry.isDirectory())
|
|
616
|
-
stack.push(full);
|
|
617
|
-
else if (entry.isFile() && profile.isSurfaceFile(entry.name))
|
|
618
|
-
out.push(full);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
return out.sort();
|
|
622
|
-
}
|
|
623
603
|
function truncateHeadTail(s) {
|
|
624
604
|
if (s.length <= NO_CACHE_TOTAL)
|
|
625
605
|
return s;
|
|
@@ -7,6 +7,10 @@ export interface IndexResult {
|
|
|
7
7
|
chunksWritten: number;
|
|
8
8
|
contentHash: string;
|
|
9
9
|
}
|
|
10
|
+
export interface CollectedFiles {
|
|
11
|
+
surface: string[];
|
|
12
|
+
readme: string | null;
|
|
13
|
+
}
|
|
10
14
|
/**
|
|
11
15
|
* The gate that decides whether a package needs re-indexing.
|
|
12
16
|
*
|
|
@@ -48,4 +52,13 @@ export declare function chunkerFingerprint(): string;
|
|
|
48
52
|
* `.d.cts` still has to be readable, and all 123 of zod's had a `.d.ts` twin.
|
|
49
53
|
*/
|
|
50
54
|
export declare function dropParallelDeclarations(files: readonly string[]): string[];
|
|
55
|
+
/**
|
|
56
|
+
* The files that make up a package's surface, after every selection rule.
|
|
57
|
+
*
|
|
58
|
+
* Exported because the uncached fallback assembles the same package by hand: a
|
|
59
|
+
* walk that skipped these rules put a Go module's whole subtree, and both halves
|
|
60
|
+
* of every parallel `.d.cts`, into the one degraded path where the budget is a
|
|
61
|
+
* single truncated blob.
|
|
62
|
+
*/
|
|
63
|
+
export declare function collectFiles(pkg: ResolvedPackage, profile: EcosystemProfile): CollectedFiles;
|
|
51
64
|
export declare function ensureIndexed(cache: CacheHandle, pkg: ResolvedPackage, profile?: EcosystemProfile, supplements?: readonly ResolvedPackage[]): IndexResult;
|
|
@@ -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
|
-
|
|
121
|
-
|
|
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
|
}
|
|
@@ -177,7 +189,15 @@ function dropDeadMajors(files, root, version) {
|
|
|
177
189
|
// own version is not shipping a dead major — it is shipping its API there.
|
|
178
190
|
return kept.length > 0 ? kept : files;
|
|
179
191
|
}
|
|
180
|
-
|
|
192
|
+
/**
|
|
193
|
+
* The files that make up a package's surface, after every selection rule.
|
|
194
|
+
*
|
|
195
|
+
* Exported because the uncached fallback assembles the same package by hand: a
|
|
196
|
+
* walk that skipped these rules put a Go module's whole subtree, and both halves
|
|
197
|
+
* of every parallel `.d.cts`, into the one degraded path where the budget is a
|
|
198
|
+
* single truncated blob.
|
|
199
|
+
*/
|
|
200
|
+
export function collectFiles(pkg, profile) {
|
|
181
201
|
const walked = walkSurface(pkg.root, profile);
|
|
182
202
|
const surface = dropDeadMajors(walked, pkg.root, pkg.version);
|
|
183
203
|
return {
|
package/dist/workers/eco-go.d.ts
CHANGED
|
@@ -201,9 +201,11 @@ export declare function selectBuildVariants(files: readonly string[]): string[];
|
|
|
201
201
|
* cannot fire here because it reads the major with `/^(\d+)\./` and Go spells its
|
|
202
202
|
* versions `v1.12.0` and `go1.25.14`.
|
|
203
203
|
*
|
|
204
|
-
* A
|
|
205
|
-
*
|
|
206
|
-
* whole surface lives
|
|
204
|
+
* A root that declares nothing is not the API — the aws-sdk shape holds no Go files
|
|
205
|
+
* at all, and `cloud.google.com/go` holds a `doc.go` with a package clause and no
|
|
206
|
+
* imports while its whole surface lives in subdirectories. Either keeps everything,
|
|
207
|
+
* for the same reason `dropDeadMajors` keeps a package whose whole surface lives
|
|
208
|
+
* under one `vN/`.
|
|
207
209
|
*/
|
|
208
210
|
export declare function selectOwnPackage(files: readonly string[], root: string, name: string, version: string): string[];
|
|
209
211
|
/**
|
package/dist/workers/eco-go.js
CHANGED
|
@@ -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';
|
|
@@ -650,12 +650,25 @@ function holdsByDefault(src) {
|
|
|
650
650
|
return true;
|
|
651
651
|
return expr.split(/\s*&&\s*/).every(term => term.startsWith('!'));
|
|
652
652
|
}
|
|
653
|
-
/**
|
|
653
|
+
/**
|
|
654
|
+
* The import paths a Go file's import block names.
|
|
655
|
+
*
|
|
656
|
+
* Scoped to the import DECLARATION, not the file: a sibling's import path also
|
|
657
|
+
* occurs as a plain string constant, in an error message and in a `go:generate`
|
|
658
|
+
* line, and reading those keeps the very subpackage `selectOwnPackage` exists to
|
|
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
|
|
663
|
+
* dropping it silently drops everything reachable only through it.
|
|
664
|
+
*/
|
|
654
665
|
function importsOf(src) {
|
|
655
666
|
const out = [];
|
|
656
|
-
for (const
|
|
657
|
-
if (
|
|
658
|
-
|
|
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))
|
|
671
|
+
out.push(m[1] ?? m[2]);
|
|
659
672
|
}
|
|
660
673
|
return out;
|
|
661
674
|
}
|
|
@@ -674,6 +687,17 @@ function goMajor(name, version) {
|
|
|
674
687
|
const inVersion = /^(?:v|go)?(\d+)\./.exec(version);
|
|
675
688
|
return inVersion ? Number(inVersion[1]) : 1;
|
|
676
689
|
}
|
|
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
|
+
*/
|
|
698
|
+
function declaresApi(src) {
|
|
699
|
+
return splitGoItems(src).some(item => /^(?:func|type|var|const)\b/.test(item.text));
|
|
700
|
+
}
|
|
677
701
|
/**
|
|
678
702
|
* Keep the package the caller asked for, and only the subpackages it can reach.
|
|
679
703
|
*
|
|
@@ -701,9 +725,11 @@ function goMajor(name, version) {
|
|
|
701
725
|
* cannot fire here because it reads the major with `/^(\d+)\./` and Go spells its
|
|
702
726
|
* versions `v1.12.0` and `go1.25.14`.
|
|
703
727
|
*
|
|
704
|
-
* A
|
|
705
|
-
*
|
|
706
|
-
* whole surface lives
|
|
728
|
+
* A root that declares nothing is not the API — the aws-sdk shape holds no Go files
|
|
729
|
+
* at all, and `cloud.google.com/go` holds a `doc.go` with a package clause and no
|
|
730
|
+
* imports while its whole surface lives in subdirectories. Either keeps everything,
|
|
731
|
+
* for the same reason `dropDeadMajors` keeps a package whose whole surface lives
|
|
732
|
+
* under one `vN/`.
|
|
707
733
|
*/
|
|
708
734
|
export function selectOwnPackage(files, root, name, version) {
|
|
709
735
|
const rel = (f) => path.relative(root, f).replace(/\\/g, '/');
|
|
@@ -714,7 +740,16 @@ export function selectOwnPackage(files, root, name, version) {
|
|
|
714
740
|
const byDir = new Map();
|
|
715
741
|
for (const f of files)
|
|
716
742
|
byDir.set(dirOf(f), [...(byDir.get(dirOf(f)) ?? []), f]);
|
|
717
|
-
|
|
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))))
|
|
718
753
|
return [...files];
|
|
719
754
|
const major = goMajor(name, version);
|
|
720
755
|
const reachable = new Set(['']);
|
|
@@ -722,7 +757,7 @@ export function selectOwnPackage(files, root, name, version) {
|
|
|
722
757
|
while (queue.length > 0) {
|
|
723
758
|
const dir = queue.shift();
|
|
724
759
|
for (const f of byDir.get(dir) ?? []) {
|
|
725
|
-
for (const imp of importsOf(
|
|
760
|
+
for (const imp of importsOf(sourceOf(f))) {
|
|
726
761
|
if (!imp.startsWith(`${name}/`))
|
|
727
762
|
continue;
|
|
728
763
|
const sub = imp.slice(name.length + 1);
|
|
@@ -748,6 +783,7 @@ export function goContentFingerprintParts() {
|
|
|
748
783
|
String(holdsByDefault),
|
|
749
784
|
String(isWantedEntry),
|
|
750
785
|
String(selectOwnPackage),
|
|
786
|
+
String(declaresApi),
|
|
751
787
|
String(goMajor),
|
|
752
788
|
String(importsOf)
|
|
753
789
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.40.
|
|
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",
|