@mjasnikovs/pi-task 0.40.29 → 0.40.31
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/dist/workers/docs-core.js +2 -26
- package/dist/workers/docs-ecosystems.d.ts +1 -1
- package/dist/workers/docs-ecosystems.js +2 -2
- package/dist/workers/docs-index.d.ts +13 -0
- package/dist/workers/docs-index.js +10 -2
- package/dist/workers/eco-go.d.ts +34 -0
- package/dist/workers/eco-go.js +112 -1
- package/package.json +1 -1
|
@@ -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,7 +549,7 @@ 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 =
|
|
552
|
+
const surfaceFiles = collectFiles(pkg, profile).surface;
|
|
553
553
|
const entryFirst = pkg.entry ? [pkg.entry, ...surfaceFiles.filter(f => f !== pkg.entry)] : surfaceFiles;
|
|
554
554
|
for (const abs of entryFirst) {
|
|
555
555
|
let raw;
|
|
@@ -596,30 +596,6 @@ function docsRawUncached(pkg, profile, cacheError, autoInstalled) {
|
|
|
596
596
|
autoInstalled: autoInstalled ? true : undefined
|
|
597
597
|
};
|
|
598
598
|
}
|
|
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
599
|
function truncateHeadTail(s) {
|
|
624
600
|
if (s.length <= NO_CACHE_TOTAL)
|
|
625
601
|
return s;
|
|
@@ -140,7 +140,7 @@ export interface EcosystemProfile {
|
|
|
140
140
|
* retrieval budget for text the reader already has, and neither is
|
|
141
141
|
* separable downstream — same identifiers, same package, same version.
|
|
142
142
|
*/
|
|
143
|
-
selectFiles?: (files: readonly string[]) => string[];
|
|
143
|
+
selectFiles?: (files: readonly string[], pkg: ResolvedPackage) => string[];
|
|
144
144
|
/** What this ecosystem's packages ship, for a "there is nothing to read" answer. */
|
|
145
145
|
surfaceLabel: string;
|
|
146
146
|
/**
|
|
@@ -24,7 +24,7 @@ import { dropParallelDeclarations } from './docs-index.js';
|
|
|
24
24
|
import { npmVersionLookup } from './npm-version.js';
|
|
25
25
|
import { resolveCrate, cratesLatest, crateTarballUrl, crateOf, isValidCrateName, isRustFile, lockedVersion, rustSurface, cargoProjectName, childDirs, lockedDeps, manifestCrates, cargoExportGap, cargoContentFingerprint, cargoSupplementCandidates, CARGO_DECL_SPLIT_RE, CARGO_MEMBER_SPLIT_RE } from './eco-cargo.js';
|
|
26
26
|
import { resolveHackage, hackageLatest, hackageVersion, hackageTarballUrl, hackageExtractDir, hackageProjectName, supplementCandidates, hackageExportGap, hackageContentFingerprint, findCabalTarball, cachedVersions, resolvedVersions, manifestPackages, isValidHackageName, isHaskellFile, haskellSurface, HACKAGE_DECL_SPLIT_RE, HACKAGE_SKIP_DIRS, HACKAGE_MEMBER_SPLIT_RE } from './eco-hackage.js';
|
|
27
|
-
import { detectGo, isValidImportPath, resolveGoPackage, acquireGoModule, goDeclaredVersion, goLatest, goProjectName, goDeclaredDeps, goManifestDeps, isGoFile, selectBuildVariants, defaultGoModCache, goContentFingerprintParts } from './eco-go.js';
|
|
27
|
+
import { detectGo, isValidImportPath, resolveGoPackage, acquireGoModule, goDeclaredVersion, goLatest, goProjectName, goDeclaredDeps, goManifestDeps, isGoFile, selectBuildVariants, selectOwnPackage, defaultGoModCache, goContentFingerprintParts } from './eco-go.js';
|
|
28
28
|
import { goSurface, goContentFingerprint, GO_DECL_SPLIT_RE, GO_MEMBER_SPLIT_RE } from './go-surface.js';
|
|
29
29
|
import { runChild } from '../shared/child-process.js';
|
|
30
30
|
/**
|
|
@@ -503,7 +503,7 @@ const goProfile = {
|
|
|
503
503
|
typeKeywords: ['type', 'struct', 'interface', 'func'],
|
|
504
504
|
commentPrefix: '//',
|
|
505
505
|
skipDirs: ['testdata', 'examples', 'vendor', 'internal', '.git'],
|
|
506
|
-
selectFiles: selectBuildVariants,
|
|
506
|
+
selectFiles: (files, pkg) => selectBuildVariants(selectOwnPackage(files, pkg.root, pkg.name, pkg.version)),
|
|
507
507
|
surfaceLabel: '.go source or README',
|
|
508
508
|
packageSubject: 'a Go package',
|
|
509
509
|
projectGlobs: ['*.go'],
|
|
@@ -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;
|
|
@@ -177,11 +177,19 @@ function dropDeadMajors(files, root, version) {
|
|
|
177
177
|
// own version is not shipping a dead major — it is shipping its API there.
|
|
178
178
|
return kept.length > 0 ? kept : files;
|
|
179
179
|
}
|
|
180
|
-
|
|
180
|
+
/**
|
|
181
|
+
* The files that make up a package's surface, after every selection rule.
|
|
182
|
+
*
|
|
183
|
+
* Exported because the uncached fallback assembles the same package by hand: a
|
|
184
|
+
* walk that skipped these rules put a Go module's whole subtree, and both halves
|
|
185
|
+
* of every parallel `.d.cts`, into the one degraded path where the budget is a
|
|
186
|
+
* single truncated blob.
|
|
187
|
+
*/
|
|
188
|
+
export function collectFiles(pkg, profile) {
|
|
181
189
|
const walked = walkSurface(pkg.root, profile);
|
|
182
190
|
const surface = dropDeadMajors(walked, pkg.root, pkg.version);
|
|
183
191
|
return {
|
|
184
|
-
surface: profile.selectFiles ? profile.selectFiles(surface) : surface,
|
|
192
|
+
surface: profile.selectFiles ? profile.selectFiles(surface, pkg) : surface,
|
|
185
193
|
readme: pkg.readme
|
|
186
194
|
};
|
|
187
195
|
}
|
package/dist/workers/eco-go.d.ts
CHANGED
|
@@ -174,6 +174,40 @@ export declare function acquireGoModule(importPath: string, pinned: string | nul
|
|
|
174
174
|
* with no tags: a bare negation holds, a bare tag does not.
|
|
175
175
|
*/
|
|
176
176
|
export declare function selectBuildVariants(files: readonly string[]): string[];
|
|
177
|
+
/**
|
|
178
|
+
* Keep the package the caller asked for, and only the subpackages it can reach.
|
|
179
|
+
*
|
|
180
|
+
* A Go subdirectory is a DIFFERENT importable package — `zapcore` is not reachable
|
|
181
|
+
* as `zap.X` and `ginS` is not `gin` — so walking a module's whole tree files every
|
|
182
|
+
* one of them under the parent's name and its version banner. Measured on re-run 9's
|
|
183
|
+
* cache: 71% of `encoding/json`'s chunks, 54% of zap's and 34% of gin's belonged to
|
|
184
|
+
* a package nobody asked about, and it reached retrieval — a question about
|
|
185
|
+
* registering a gin route came back with 10 `ginS` chunks of 51, in a corpus already
|
|
186
|
+
* spending 19,941 of its 24,000 bytes.
|
|
187
|
+
*
|
|
188
|
+
* The gate is the ROOT'S OWN IMPORTS, closed over: zap's `Field` is
|
|
189
|
+
* `= zapcore.Field`, so dropping `zapcore` would break the alias hop that defect 3
|
|
190
|
+
* exists to serve, and zapcore in turn reaches `buffer`. What that keeps is what a
|
|
191
|
+
* caller of this package can actually be handed; `zapgrpc`, `zaptest`, `ginS`,
|
|
192
|
+
* `httputil` and `net/http/pprof` are reachable only by importing them directly,
|
|
193
|
+
* which the tool already resolves on its own — `github.com/gin-gonic/gin/binding`
|
|
194
|
+
* asked for by path reads 0% foreign.
|
|
195
|
+
*
|
|
196
|
+
* A mismatching top-level `vN/` goes whatever the imports say. `encoding/json` is
|
|
197
|
+
* built ON `encoding/json/v2` and imports it, but v2 is a different major of the
|
|
198
|
+
* same API with the same identifiers — `Marshal`, `Unmarshal` — and half the
|
|
199
|
+
* retrieval for the commonest decode question came back from it under a
|
|
200
|
+
* `Per encoding/json@go1.25.14` header. That is `dropDeadMajors`' case, which
|
|
201
|
+
* cannot fire here because it reads the major with `/^(\d+)\./` and Go spells its
|
|
202
|
+
* versions `v1.12.0` and `go1.25.14`.
|
|
203
|
+
*
|
|
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/`.
|
|
209
|
+
*/
|
|
210
|
+
export declare function selectOwnPackage(files: readonly string[], root: string, name: string, version: string): string[];
|
|
177
211
|
/**
|
|
178
212
|
* Everything below `goSurface` and the file-selection rule that feeds it, by
|
|
179
213
|
* source, so a fix to either re-indexes rather than being masked by a cache hit.
|
package/dist/workers/eco-go.js
CHANGED
|
@@ -650,10 +650,121 @@ function holdsByDefault(src) {
|
|
|
650
650
|
return true;
|
|
651
651
|
return expr.split(/\s*&&\s*/).every(term => term.startsWith('!'));
|
|
652
652
|
}
|
|
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. An `ImportPath` is a `string_lit`, so the backtick form is legal Go and
|
|
660
|
+
* dropping it silently drops everything reachable only through it.
|
|
661
|
+
*/
|
|
662
|
+
function importsOf(src) {
|
|
663
|
+
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
|
+
out.push(m[1] ?? m[2]);
|
|
668
|
+
}
|
|
669
|
+
return out;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* The package's own major, as Go spells it.
|
|
673
|
+
*
|
|
674
|
+
* v2 and up put the major in the module PATH, and the version agrees with it, so
|
|
675
|
+
* either reads the same answer. The standard library has neither and is 1: it is
|
|
676
|
+
* `go1.25.14`, and `encoding/json/v2` is a separate experimental package rather
|
|
677
|
+
* than a newer major of this one.
|
|
678
|
+
*/
|
|
679
|
+
function goMajor(name, version) {
|
|
680
|
+
const inPath = /\/v(\d+)$/.exec(name);
|
|
681
|
+
if (inPath)
|
|
682
|
+
return Number(inPath[1]);
|
|
683
|
+
const inVersion = /^(?:v|go)?(\d+)\./.exec(version);
|
|
684
|
+
return inVersion ? Number(inVersion[1]) : 1;
|
|
685
|
+
}
|
|
686
|
+
/** Does this file declare anything a caller of the package could be handed? */
|
|
687
|
+
function declaresApi(src) {
|
|
688
|
+
return /^(?:func|type|var|const)\b/m.test(src);
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Keep the package the caller asked for, and only the subpackages it can reach.
|
|
692
|
+
*
|
|
693
|
+
* A Go subdirectory is a DIFFERENT importable package — `zapcore` is not reachable
|
|
694
|
+
* as `zap.X` and `ginS` is not `gin` — so walking a module's whole tree files every
|
|
695
|
+
* one of them under the parent's name and its version banner. Measured on re-run 9's
|
|
696
|
+
* cache: 71% of `encoding/json`'s chunks, 54% of zap's and 34% of gin's belonged to
|
|
697
|
+
* a package nobody asked about, and it reached retrieval — a question about
|
|
698
|
+
* registering a gin route came back with 10 `ginS` chunks of 51, in a corpus already
|
|
699
|
+
* spending 19,941 of its 24,000 bytes.
|
|
700
|
+
*
|
|
701
|
+
* The gate is the ROOT'S OWN IMPORTS, closed over: zap's `Field` is
|
|
702
|
+
* `= zapcore.Field`, so dropping `zapcore` would break the alias hop that defect 3
|
|
703
|
+
* exists to serve, and zapcore in turn reaches `buffer`. What that keeps is what a
|
|
704
|
+
* caller of this package can actually be handed; `zapgrpc`, `zaptest`, `ginS`,
|
|
705
|
+
* `httputil` and `net/http/pprof` are reachable only by importing them directly,
|
|
706
|
+
* which the tool already resolves on its own — `github.com/gin-gonic/gin/binding`
|
|
707
|
+
* asked for by path reads 0% foreign.
|
|
708
|
+
*
|
|
709
|
+
* A mismatching top-level `vN/` goes whatever the imports say. `encoding/json` is
|
|
710
|
+
* built ON `encoding/json/v2` and imports it, but v2 is a different major of the
|
|
711
|
+
* same API with the same identifiers — `Marshal`, `Unmarshal` — and half the
|
|
712
|
+
* retrieval for the commonest decode question came back from it under a
|
|
713
|
+
* `Per encoding/json@go1.25.14` header. That is `dropDeadMajors`' case, which
|
|
714
|
+
* cannot fire here because it reads the major with `/^(\d+)\./` and Go spells its
|
|
715
|
+
* versions `v1.12.0` and `go1.25.14`.
|
|
716
|
+
*
|
|
717
|
+
* A root that declares nothing is not the API — the aws-sdk shape holds no Go files
|
|
718
|
+
* at all, and `cloud.google.com/go` holds a `doc.go` with a package clause and no
|
|
719
|
+
* imports while its whole surface lives in subdirectories. Either keeps everything,
|
|
720
|
+
* for the same reason `dropDeadMajors` keeps a package whose whole surface lives
|
|
721
|
+
* under one `vN/`.
|
|
722
|
+
*/
|
|
723
|
+
export function selectOwnPackage(files, root, name, version) {
|
|
724
|
+
const rel = (f) => path.relative(root, f).replace(/\\/g, '/');
|
|
725
|
+
const dirOf = (f) => {
|
|
726
|
+
const parts = rel(f).split('/');
|
|
727
|
+
return parts.slice(0, -1).join('/');
|
|
728
|
+
};
|
|
729
|
+
const byDir = new Map();
|
|
730
|
+
for (const f of files)
|
|
731
|
+
byDir.set(dirOf(f), [...(byDir.get(dirOf(f)) ?? []), f]);
|
|
732
|
+
if (!(byDir.get('') ?? []).some(f => declaresApi(safeRead(f) ?? '')))
|
|
733
|
+
return [...files];
|
|
734
|
+
const major = goMajor(name, version);
|
|
735
|
+
const reachable = new Set(['']);
|
|
736
|
+
const queue = [''];
|
|
737
|
+
while (queue.length > 0) {
|
|
738
|
+
const dir = queue.shift();
|
|
739
|
+
for (const f of byDir.get(dir) ?? []) {
|
|
740
|
+
for (const imp of importsOf(safeRead(f) ?? '')) {
|
|
741
|
+
if (!imp.startsWith(`${name}/`))
|
|
742
|
+
continue;
|
|
743
|
+
const sub = imp.slice(name.length + 1);
|
|
744
|
+
const top = /^v(\d+)$/.exec(sub.split('/')[0]);
|
|
745
|
+
if (top && Number(top[1]) !== major)
|
|
746
|
+
continue;
|
|
747
|
+
if (reachable.has(sub) || !byDir.has(sub))
|
|
748
|
+
continue;
|
|
749
|
+
reachable.add(sub);
|
|
750
|
+
queue.push(sub);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return files.filter(f => reachable.has(dirOf(f)));
|
|
755
|
+
}
|
|
653
756
|
/**
|
|
654
757
|
* Everything below `goSurface` and the file-selection rule that feeds it, by
|
|
655
758
|
* source, so a fix to either re-indexes rather than being masked by a cache hit.
|
|
656
759
|
*/
|
|
657
760
|
export function goContentFingerprintParts() {
|
|
658
|
-
return [
|
|
761
|
+
return [
|
|
762
|
+
String(selectBuildVariants),
|
|
763
|
+
String(holdsByDefault),
|
|
764
|
+
String(isWantedEntry),
|
|
765
|
+
String(selectOwnPackage),
|
|
766
|
+
String(declaresApi),
|
|
767
|
+
String(goMajor),
|
|
768
|
+
String(importsOf)
|
|
769
|
+
];
|
|
659
770
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.31",
|
|
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",
|