@mjasnikovs/pi-task 0.39.4 → 0.40.0
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/README.md +20 -5
- package/dist/task/auto-orchestrator.d.ts +36 -0
- package/dist/task/auto-orchestrator.js +43 -6
- package/dist/task/cancel-points.d.ts +34 -6
- package/dist/task/cancel-points.js +62 -10
- package/dist/task/child-status.js +13 -1
- package/dist/task/context-attribution.js +18 -6
- package/dist/task/external-context.d.ts +8 -1
- package/dist/task/external-context.js +52 -4
- package/dist/task/orchestrator.js +47 -5
- package/dist/task/phases.js +2 -1
- package/dist/task/plan-orchestrator.js +10 -1
- package/dist/task/prompts.d.ts +7 -1
- package/dist/task/prompts.js +14 -4
- package/dist/task/research-worker.js +11 -0
- package/dist/task/run-bracket.js +13 -1
- package/dist/task/task-gates.js +34 -0
- package/dist/workers/docs-cache.js +50 -3
- package/dist/workers/docs-chunk.d.ts +6 -3
- package/dist/workers/docs-chunk.js +8 -5
- package/dist/workers/docs-core.d.ts +27 -3
- package/dist/workers/docs-core.js +104 -41
- package/dist/workers/docs-ecosystems.d.ts +173 -0
- package/dist/workers/docs-ecosystems.js +449 -0
- package/dist/workers/docs-index.d.ts +2 -1
- package/dist/workers/docs-index.js +55 -27
- package/dist/workers/docs-project.d.ts +10 -0
- package/dist/workers/docs-project.js +86 -24
- package/dist/workers/docs-resolve.d.ts +6 -1
- package/dist/workers/docs-resolve.js +4 -3
- package/dist/workers/docs-retrieve.d.ts +2 -0
- package/dist/workers/docs-retrieve.js +11 -11
- package/dist/workers/eco-cargo.d.ts +115 -0
- package/dist/workers/eco-cargo.js +793 -0
- package/dist/workers/eco-hackage.d.ts +93 -0
- package/dist/workers/eco-hackage.js +508 -0
- package/dist/workers/npm-version.d.ts +5 -3
- package/dist/workers/npm-version.js +6 -4
- package/dist/workers/pi-worker-docs.d.ts +18 -4
- package/dist/workers/pi-worker-docs.js +57 -19
- package/dist/workers/research-cache.d.ts +2 -13
- package/dist/workers/research-cache.js +22 -46
- package/dist/workers/shared.d.ts +16 -5
- package/dist/workers/shared.js +0 -0
- package/package.json +1 -1
|
@@ -5,17 +5,49 @@ import * as path from 'node:path';
|
|
|
5
5
|
import { retrieveChunks as defaultRetrieveChunks, PROJECT_RETRIEVE_LIMIT, RETRIEVE_CONTENT_BUDGET } from './docs-retrieve.js';
|
|
6
6
|
import { buildExtractionPrompt } from './abstention.js';
|
|
7
7
|
import { chunkDeclarations } from './docs-chunk.js';
|
|
8
|
+
import { ECOSYSTEMS, detectEcosystems } from './docs-ecosystems.js';
|
|
8
9
|
const DEFAULT_LIMIT = PROJECT_RETRIEVE_LIMIT;
|
|
9
10
|
const DEFAULT_BUDGET = RETRIEVE_CONTENT_BUDGET;
|
|
11
|
+
/**
|
|
12
|
+
* Scope value for project-source rows. It sits in the same column as a registry
|
|
13
|
+
* id because these rows share the tables, but it is NOT one: a project is keyed
|
|
14
|
+
* by a hash of its cwd, so no registry could name it.
|
|
15
|
+
*/
|
|
16
|
+
export const PROJECT_SCOPE = 'project';
|
|
17
|
+
/**
|
|
18
|
+
* The rows whose manifest is present, or npm alone when none is. The npm
|
|
19
|
+
* fallback is what keeps a bare directory indexing its `.ts` exactly as before.
|
|
20
|
+
*/
|
|
21
|
+
function projectProfiles(cwd) {
|
|
22
|
+
const detected = detectEcosystems(cwd);
|
|
23
|
+
return detected.length ? detected.map(id => ECOSYSTEMS[id]) : [ECOSYSTEMS.npm];
|
|
24
|
+
}
|
|
10
25
|
export function getProjectName(cwd) {
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
26
|
+
for (const profile of projectProfiles(cwd)) {
|
|
27
|
+
const name = profile.projectName(cwd);
|
|
28
|
+
if (name)
|
|
29
|
+
return name;
|
|
15
30
|
}
|
|
16
|
-
catch { }
|
|
17
31
|
return path.basename(cwd);
|
|
18
32
|
}
|
|
33
|
+
/** The file extension a glob like `*.rs` selects. */
|
|
34
|
+
function extensionOf(glob) {
|
|
35
|
+
return glob.replace(/^\*/, '');
|
|
36
|
+
}
|
|
37
|
+
/** The extensions a given project is indexed for — `.ts/.tsx`, `.rs`, `.hs`. */
|
|
38
|
+
export function projectSourceLabel(cwd) {
|
|
39
|
+
return [...new Set(projectProfiles(cwd).flatMap(p => p.projectGlobs))]
|
|
40
|
+
.map(extensionOf)
|
|
41
|
+
.join('/');
|
|
42
|
+
}
|
|
43
|
+
/** Which row chunks a given project file, by its extension. */
|
|
44
|
+
function profileForFile(file, profiles) {
|
|
45
|
+
for (const profile of profiles) {
|
|
46
|
+
if (profile.projectGlobs.some(g => file.endsWith(extensionOf(g))))
|
|
47
|
+
return profile;
|
|
48
|
+
}
|
|
49
|
+
return profiles[0];
|
|
50
|
+
}
|
|
19
51
|
export function cwdKey(cwd) {
|
|
20
52
|
return createHash('sha256').update(cwd).digest('hex').slice(0, 8);
|
|
21
53
|
}
|
|
@@ -38,8 +70,9 @@ export function cwdKey(cwd) {
|
|
|
38
70
|
* and a temp dir that is not itself inside a repo.
|
|
39
71
|
*/
|
|
40
72
|
export function getProjectFiles(cwd) {
|
|
73
|
+
const globs = [...new Set(projectProfiles(cwd).flatMap(p => p.projectGlobs))];
|
|
41
74
|
try {
|
|
42
|
-
const result = spawnSync('git', ['ls-files', '--cached', '--others', '--exclude-standard',
|
|
75
|
+
const result = spawnSync('git', ['ls-files', '--cached', '--others', '--exclude-standard', ...globs], { cwd, encoding: 'utf8', timeout: 5000 });
|
|
43
76
|
if (result.status === 0 && result.stdout?.trim()) {
|
|
44
77
|
return result.stdout
|
|
45
78
|
.trim()
|
|
@@ -49,10 +82,25 @@ export function getProjectFiles(cwd) {
|
|
|
49
82
|
}
|
|
50
83
|
}
|
|
51
84
|
catch { }
|
|
52
|
-
return
|
|
85
|
+
return walkSourceFiles(cwd, globs.map(extensionOf));
|
|
53
86
|
}
|
|
54
|
-
|
|
55
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Build output, per ecosystem. NOT `profile.skipDirs` — that list says which
|
|
89
|
+
* directories of a DOWNLOADED package are not its published API, and `tests/`
|
|
90
|
+
* and `examples/` of the project's OWN repo are exactly what a question about
|
|
91
|
+
* the project may be asking. `git ls-files` filters none of them either.
|
|
92
|
+
*/
|
|
93
|
+
const BUILD_OUTPUT_DIRS = [
|
|
94
|
+
'node_modules',
|
|
95
|
+
'.git',
|
|
96
|
+
'dist',
|
|
97
|
+
'build',
|
|
98
|
+
'coverage',
|
|
99
|
+
'target',
|
|
100
|
+
'dist-newstyle'
|
|
101
|
+
];
|
|
102
|
+
function walkSourceFiles(root, extensions) {
|
|
103
|
+
const SKIP = new Set(BUILD_OUTPUT_DIRS);
|
|
56
104
|
const out = [];
|
|
57
105
|
const stack = [root];
|
|
58
106
|
while (stack.length) {
|
|
@@ -70,8 +118,7 @@ function walkTsFiles(root) {
|
|
|
70
118
|
const full = path.join(dir, entry.name);
|
|
71
119
|
if (entry.isDirectory())
|
|
72
120
|
stack.push(full);
|
|
73
|
-
else if (entry.isFile()
|
|
74
|
-
&& (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx'))) {
|
|
121
|
+
else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) {
|
|
75
122
|
out.push(full);
|
|
76
123
|
}
|
|
77
124
|
}
|
|
@@ -91,9 +138,10 @@ export function getMaxMtime(files) {
|
|
|
91
138
|
return String(Math.floor(max));
|
|
92
139
|
}
|
|
93
140
|
export function ensureProjectIndexed(cache, name, version, files, cwd) {
|
|
141
|
+
const profiles = projectProfiles(cwd);
|
|
94
142
|
const existing = cache.db
|
|
95
|
-
.prepare('SELECT content_hash FROM packages WHERE name = ? AND version = ?')
|
|
96
|
-
.get(name, version);
|
|
143
|
+
.prepare('SELECT content_hash FROM packages WHERE ecosystem = ? AND name = ? AND version = ?')
|
|
144
|
+
.get(PROJECT_SCOPE, name, version);
|
|
97
145
|
if (existing)
|
|
98
146
|
return { hitCache: true, filesIngested: 0, chunksWritten: 0 };
|
|
99
147
|
const t0 = Date.now();
|
|
@@ -101,9 +149,13 @@ export function ensureProjectIndexed(cache, name, version, files, cwd) {
|
|
|
101
149
|
try {
|
|
102
150
|
// Delete by NAME with no version: unlike the package index, a project
|
|
103
151
|
// keeps only its newest max-mtime version, so every older one goes.
|
|
104
|
-
cache.db
|
|
105
|
-
|
|
106
|
-
|
|
152
|
+
cache.db
|
|
153
|
+
.prepare('DELETE FROM chunks WHERE ecosystem = ? AND name = ?')
|
|
154
|
+
.run(PROJECT_SCOPE, name);
|
|
155
|
+
cache.db
|
|
156
|
+
.prepare('DELETE FROM packages WHERE ecosystem = ? AND name = ?')
|
|
157
|
+
.run(PROJECT_SCOPE, name);
|
|
158
|
+
const insertChunk = cache.db.prepare('INSERT INTO chunks (ecosystem, name, version, file_path, kind, content) VALUES (?, ?, ?, ?, ?, ?)');
|
|
107
159
|
let filesIngested = 0;
|
|
108
160
|
let chunksWritten = 0;
|
|
109
161
|
for (const abs of files) {
|
|
@@ -115,18 +167,25 @@ export function ensureProjectIndexed(cache, name, version, files, cwd) {
|
|
|
115
167
|
continue;
|
|
116
168
|
}
|
|
117
169
|
const rel = path.relative(cwd, abs);
|
|
118
|
-
|
|
170
|
+
// The project's own source goes in WHOLE. `profile.surface` strips a
|
|
171
|
+
// dependency's implementation down to its published API, which is the
|
|
172
|
+
// opposite of what is wanted here: a binary crate's `main.rs` has no
|
|
173
|
+
// `pub` item in it at all, so surfacing it indexes to nothing and
|
|
174
|
+
// `pi-worker-docs(".", …)` answers "no chunks" for the whole project.
|
|
175
|
+
// Only the CHUNK BOUNDARY is language-specific.
|
|
176
|
+
const profile = profileForFile(abs, profiles);
|
|
177
|
+
const chunks = chunkDeclarations(raw, rel, profile.declSplitRe, profile.commentPrefix);
|
|
119
178
|
if (!chunks.length)
|
|
120
179
|
continue;
|
|
121
180
|
filesIngested++;
|
|
122
181
|
for (const c of chunks) {
|
|
123
|
-
insertChunk.run(name, version, rel, 'dts', c);
|
|
182
|
+
insertChunk.run(PROJECT_SCOPE, name, version, rel, 'dts', c);
|
|
124
183
|
chunksWritten++;
|
|
125
184
|
}
|
|
126
185
|
}
|
|
127
186
|
cache.db
|
|
128
|
-
.prepare('INSERT OR REPLACE INTO packages (name, version, content_hash, indexed_at) VALUES (?, ?, ?, ?)')
|
|
129
|
-
.run(name, version, version, Date.now());
|
|
187
|
+
.prepare('INSERT OR REPLACE INTO packages (ecosystem, name, version, content_hash, indexed_at) VALUES (?, ?, ?, ?, ?)')
|
|
188
|
+
.run(PROJECT_SCOPE, name, version, version, Date.now());
|
|
130
189
|
cache.db.exec('COMMIT');
|
|
131
190
|
return { hitCache: false, filesIngested, chunksWritten, indexingMs: Date.now() - t0 };
|
|
132
191
|
}
|
|
@@ -154,8 +213,8 @@ listFiles = getProjectFiles) {
|
|
|
154
213
|
};
|
|
155
214
|
}
|
|
156
215
|
const chunkCount = cache.db
|
|
157
|
-
.prepare('SELECT count(*) AS c FROM chunks WHERE name = ? AND version = ?')
|
|
158
|
-
.get(cacheKey, version)?.c ?? 0;
|
|
216
|
+
.prepare('SELECT count(*) AS c FROM chunks WHERE ecosystem = ? AND name = ? AND version = ?')
|
|
217
|
+
.get(PROJECT_SCOPE, cacheKey, version)?.c ?? 0;
|
|
159
218
|
if (chunkCount === 0) {
|
|
160
219
|
return {
|
|
161
220
|
kind: 'no_chunks',
|
|
@@ -163,12 +222,14 @@ listFiles = getProjectFiles) {
|
|
|
163
222
|
cacheKey,
|
|
164
223
|
version,
|
|
165
224
|
hitCache: indexResult.hitCache,
|
|
166
|
-
filesIngested: indexResult.filesIngested
|
|
225
|
+
filesIngested: indexResult.filesIngested,
|
|
226
|
+
sourceLabel: projectSourceLabel(cwd)
|
|
167
227
|
};
|
|
168
228
|
}
|
|
169
229
|
let chunks;
|
|
170
230
|
try {
|
|
171
231
|
chunks = retrieveChunksFn(cache, {
|
|
232
|
+
ecosystem: PROJECT_SCOPE,
|
|
172
233
|
name: cacheKey,
|
|
173
234
|
version,
|
|
174
235
|
query,
|
|
@@ -190,7 +251,8 @@ listFiles = getProjectFiles) {
|
|
|
190
251
|
cacheKey,
|
|
191
252
|
version,
|
|
192
253
|
hitCache: indexResult.hitCache,
|
|
193
|
-
filesIngested: indexResult.filesIngested
|
|
254
|
+
filesIngested: indexResult.filesIngested,
|
|
255
|
+
sourceLabel: projectSourceLabel(cwd)
|
|
194
256
|
};
|
|
195
257
|
}
|
|
196
258
|
return {
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import type { EcosystemId } from './docs-ecosystems.js';
|
|
1
2
|
/** True for TypeScript declaration files: .d.ts, .d.mts, .d.cts. */
|
|
2
3
|
export declare function isDtsFile(name: string): boolean;
|
|
3
4
|
export interface ResolvedPackage {
|
|
5
|
+
/** Which registry this package came from. Scopes it in the docs cache. */
|
|
6
|
+
ecosystem: EcosystemId;
|
|
4
7
|
name: string;
|
|
5
8
|
version: string;
|
|
6
9
|
root: string;
|
|
7
|
-
|
|
10
|
+
/** The file holding the package's public API surface, if it has one. */
|
|
11
|
+
entry: string | null;
|
|
8
12
|
readme: string | null;
|
|
9
13
|
}
|
|
10
14
|
export declare class ResolveError extends Error {
|
|
11
15
|
readonly kind: 'not_installed' | 'invalid_name';
|
|
12
16
|
constructor(kind: 'not_installed' | 'invalid_name', message: string);
|
|
13
17
|
}
|
|
18
|
+
export declare function isValidModuleName(name: string): boolean;
|
|
14
19
|
/**
|
|
15
20
|
* Split a runtime builtin specifier (`bun:sql`, `node:fs/promises`) into its
|
|
16
21
|
* runtime and submodule. Returns null for ordinary specifiers (including scoped
|
|
@@ -15,7 +15,7 @@ export class ResolveError extends Error {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
const MODULE_NAME_RE = /^(?:@[a-z0-9-_.]+\/)?[a-z0-9-_.]+(?:\/[a-z0-9-_./]+)?$/i;
|
|
18
|
-
function isValidModuleName(name) {
|
|
18
|
+
export function isValidModuleName(name) {
|
|
19
19
|
if (!name || name.includes('..') || name.startsWith('/'))
|
|
20
20
|
return false;
|
|
21
21
|
return MODULE_NAME_RE.test(name);
|
|
@@ -147,10 +147,11 @@ export function resolvePackage(moduleName, cwd) {
|
|
|
147
147
|
const root = path.dirname(pkgJsonPath);
|
|
148
148
|
const pkg = readPackageJson(pkgJsonPath);
|
|
149
149
|
return {
|
|
150
|
+
ecosystem: 'npm',
|
|
150
151
|
name: pkg.name ?? parent,
|
|
151
152
|
version: pkg.version ?? '0.0.0',
|
|
152
153
|
root,
|
|
153
|
-
|
|
154
|
+
entry: resolveEntryDts(moduleName, parent, root, pkg),
|
|
154
155
|
readme: findReadme(root)
|
|
155
156
|
};
|
|
156
157
|
}
|
|
@@ -282,7 +283,7 @@ export function detectTypesRedirect(pkg) {
|
|
|
282
283
|
// redirect stub — use its own types.
|
|
283
284
|
if (countTypeFiles(pkg.root, 2) > 1)
|
|
284
285
|
return null;
|
|
285
|
-
const entry = pkg.
|
|
286
|
+
const entry = pkg.entry ?? findIndexDts(pkg.root);
|
|
286
287
|
if (!entry)
|
|
287
288
|
return null;
|
|
288
289
|
let content;
|
|
@@ -37,13 +37,13 @@ function tokenize(query) {
|
|
|
37
37
|
function buildFtsQuery(tokens) {
|
|
38
38
|
return tokens.map(t => `"${t}"`).join(' OR ');
|
|
39
39
|
}
|
|
40
|
-
function fallbackChunks(cache, name, version) {
|
|
40
|
+
function fallbackChunks(cache, ecosystem, name, version) {
|
|
41
41
|
const dts = cache.db
|
|
42
|
-
.prepare("SELECT file_path, kind, content, 0 AS rank FROM chunks WHERE name = ? AND version = ? AND kind = 'dts' ORDER BY file_path, id LIMIT 1")
|
|
43
|
-
.all(name, version);
|
|
42
|
+
.prepare("SELECT file_path, kind, content, 0 AS rank FROM chunks WHERE ecosystem = ? AND name = ? AND version = ? AND kind = 'dts' ORDER BY file_path, id LIMIT 1")
|
|
43
|
+
.all(ecosystem, name, version);
|
|
44
44
|
const readme = cache.db
|
|
45
|
-
.prepare("SELECT file_path, kind, content, 0 AS rank FROM chunks WHERE name = ? AND version = ? AND kind = 'readme' ORDER BY id LIMIT 1")
|
|
46
|
-
.all(name, version);
|
|
45
|
+
.prepare("SELECT file_path, kind, content, 0 AS rank FROM chunks WHERE ecosystem = ? AND name = ? AND version = ? AND kind = 'readme' ORDER BY id LIMIT 1")
|
|
46
|
+
.all(ecosystem, name, version);
|
|
47
47
|
const out = [];
|
|
48
48
|
for (const r of dts) {
|
|
49
49
|
out.push({
|
|
@@ -91,7 +91,7 @@ export function retrieveChunks(cache, opts) {
|
|
|
91
91
|
const budget = opts.contentBudget ?? DEFAULT_BUDGET;
|
|
92
92
|
const tokens = tokenize(opts.query);
|
|
93
93
|
if (tokens.length === 0) {
|
|
94
|
-
return enforceBudget(fallbackChunks(cache, opts.name, opts.version), budget);
|
|
94
|
+
return enforceBudget(fallbackChunks(cache, opts.ecosystem, opts.name, opts.version), budget);
|
|
95
95
|
}
|
|
96
96
|
const ftsQuery = buildFtsQuery(tokens);
|
|
97
97
|
let rows;
|
|
@@ -100,16 +100,16 @@ export function retrieveChunks(cache, opts) {
|
|
|
100
100
|
.prepare(`SELECT c.file_path, c.kind, c.content, bm25(chunks_fts) AS rank
|
|
101
101
|
FROM chunks_fts
|
|
102
102
|
JOIN chunks c ON c.id = chunks_fts.rowid
|
|
103
|
-
WHERE c.
|
|
103
|
+
WHERE c.ecosystem = ?1 AND c.name = ?2 AND c.version = ?3 AND chunks_fts MATCH ?4
|
|
104
104
|
ORDER BY rank
|
|
105
|
-
LIMIT ?
|
|
106
|
-
.all(opts.name, opts.version, ftsQuery, limit);
|
|
105
|
+
LIMIT ?5`)
|
|
106
|
+
.all(opts.ecosystem, opts.name, opts.version, ftsQuery, limit);
|
|
107
107
|
}
|
|
108
108
|
catch {
|
|
109
|
-
return enforceBudget(fallbackChunks(cache, opts.name, opts.version), budget);
|
|
109
|
+
return enforceBudget(fallbackChunks(cache, opts.ecosystem, opts.name, opts.version), budget);
|
|
110
110
|
}
|
|
111
111
|
if (rows.length === 0) {
|
|
112
|
-
return enforceBudget(fallbackChunks(cache, opts.name, opts.version), budget);
|
|
112
|
+
return enforceBudget(fallbackChunks(cache, opts.ecosystem, opts.name, opts.version), budget);
|
|
113
113
|
}
|
|
114
114
|
const mapped = rows.map(r => ({
|
|
115
115
|
filePath: r.file_path,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* eco-cargo — reading Rust crates for the docs Worker tool.
|
|
3
|
+
*
|
|
4
|
+
* Rust ships no declarations file, so the documented surface has to be cut out
|
|
5
|
+
* of `.rs` source: doc comments, attributes and public item heads kept, function
|
|
6
|
+
* bodies and private items dropped. That is what `surface` below does, and it is
|
|
7
|
+
* why this row needs code where the npm row needed none.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here parses TOML. `Cargo.lock` is a generated file with a fixed
|
|
10
|
+
* `[[package]]` shape, and a line reader over it costs one small function where
|
|
11
|
+
* a TOML dependency would cost a dependency.
|
|
12
|
+
*/
|
|
13
|
+
import { type ResolvedPackage } from './docs-resolve.js';
|
|
14
|
+
import type { NpmVersionInfo } from './npm-version.js';
|
|
15
|
+
export declare function isValidCrateName(name: string): boolean;
|
|
16
|
+
/** `serde_json::Value` is a path into `serde_json`; the crate is what installs. */
|
|
17
|
+
export declare function crateOf(name: string): string;
|
|
18
|
+
/** Every version of `name` recorded in a `Cargo.lock`, oldest first. */
|
|
19
|
+
export declare function lockVersions(lockText: string, name: string): string[];
|
|
20
|
+
/** Directories that never hold a project's own manifest. */
|
|
21
|
+
export declare const SKIP_DIRS: Set<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Immediate child directories of `cwd`, for the one-level-down manifest scan —
|
|
24
|
+
* and EMPTY unless `cwd` is itself a project root.
|
|
25
|
+
*
|
|
26
|
+
* Without that guard the scan reaches into any directory that merely happens to
|
|
27
|
+
* contain projects. `/tmp` is the case that bites: a single unrelated checkout
|
|
28
|
+
* under it would make every lookup run from `/tmp` believe it was in that
|
|
29
|
+
* ecosystem.
|
|
30
|
+
*/
|
|
31
|
+
export declare function childDirs(cwd: string): string[];
|
|
32
|
+
/**
|
|
33
|
+
* The `Cargo.lock` governing `cwd`: cargo's own upward walk first, then ONE level
|
|
34
|
+
* down. The step down is the Tauri shape — `package.json` at the repo root and
|
|
35
|
+
* the crate under `src-tauri/` — where the upward walk from the root finds
|
|
36
|
+
* nothing at all.
|
|
37
|
+
*/
|
|
38
|
+
export declare function findLock(cwd: string): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The first `<dir>/<name>` at or above `cwd`, checking each ancestor's immediate
|
|
41
|
+
* children too.
|
|
42
|
+
*
|
|
43
|
+
* The sideways step is the Tauri shape: `package.json` at the repo root and the
|
|
44
|
+
* crate under `src-tauri/`. Checking children of `cwd` alone is not enough —
|
|
45
|
+
* from the frontend directory `src/`, the crate is in a SIBLING, so the scan has
|
|
46
|
+
* to happen at every level on the way up or the whole project reads as npm-only.
|
|
47
|
+
*/
|
|
48
|
+
export declare function findAtOrAbove(cwd: string, ...rel: string[]): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* The version the project pins `name` to. Several is not an error — a workspace
|
|
51
|
+
* legitimately holds two majors of one crate — and the NEWEST is taken, which
|
|
52
|
+
* the answer then states in its `Per <name>@<version>:` header.
|
|
53
|
+
*/
|
|
54
|
+
export declare function lockedVersion(name: string, cwd: string): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Every crate the lock pins, name to version. Cargo has already resolved these,
|
|
57
|
+
* so unlike an npm range these are exact — and a `cargo update` that moves one
|
|
58
|
+
* is what a cached answer about it has to be dropped on.
|
|
59
|
+
*/
|
|
60
|
+
export declare function lockedDeps(cwd: string): Record<string, string> | undefined;
|
|
61
|
+
export interface CargoResolveDirs {
|
|
62
|
+
cargoHome: string;
|
|
63
|
+
/** Where a crate fetched by this tool was extracted. */
|
|
64
|
+
modulesDir: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find a crate's source on disk.
|
|
68
|
+
*
|
|
69
|
+
* The lock is consulted first, so a project reading `tokio` gets the `tokio` it
|
|
70
|
+
* builds against rather than the newest copy the machine happens to hold. With
|
|
71
|
+
* no lock in sight — which is where the post-fetch re-resolve arrives, since it
|
|
72
|
+
* is handed the download directory — the newest extracted copy wins.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveCrate(name: string, cwd: string, dirs: CargoResolveDirs): ResolvedPackage;
|
|
75
|
+
/** The newest published version of a crate, or null on any failure. */
|
|
76
|
+
export declare function cratesLatest(name: string, fetchFn: typeof fetch, signal?: AbortSignal): Promise<NpmVersionInfo | null>;
|
|
77
|
+
export declare function crateTarballUrl(name: string, version: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Where a Rust declaration begins, so a chunk never splits a signature. Column 0
|
|
80
|
+
* only: `rustSurface` INDENTS the members of an impl or a trait, so an `^\s*`
|
|
81
|
+
* anchor cut every method into its own chunk — an orphan signature with no
|
|
82
|
+
* receiver type, carrying the next method's doc comment.
|
|
83
|
+
*/
|
|
84
|
+
export declare const CARGO_DECL_SPLIT_RE: RegExp;
|
|
85
|
+
interface Item {
|
|
86
|
+
/** Doc comments and attributes immediately above the item. */
|
|
87
|
+
pending: string;
|
|
88
|
+
/** The item text up to its `{` or `;`. */
|
|
89
|
+
head: string;
|
|
90
|
+
/** The brace body, without the braces. Null for a `;`-terminated item. */
|
|
91
|
+
body: string | null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Split one nesting level of Rust source into items.
|
|
95
|
+
*
|
|
96
|
+
* Braces are counted with strings, chars, comments and lifetimes skipped: `"{"`
|
|
97
|
+
* and `'{'` both appear in real source, and a scanner that counts them never
|
|
98
|
+
* finds the end of the item it is in.
|
|
99
|
+
*/
|
|
100
|
+
export declare function splitRustItems(src: string): Item[];
|
|
101
|
+
/**
|
|
102
|
+
* Reduce Rust source to its public API surface.
|
|
103
|
+
*
|
|
104
|
+
* Function bodies go — they are the bulk of the file and answer no question the
|
|
105
|
+
* docs tool is asked. Everything a caller can name stays: the item head, its doc
|
|
106
|
+
* comment, its attributes, and for a struct or enum its fields and variants.
|
|
107
|
+
*
|
|
108
|
+
* Inside a `trait` every member is public by definition, so the `pub` test is
|
|
109
|
+
* suspended there; anywhere else a bare or `pub(crate)` item is dropped.
|
|
110
|
+
*/
|
|
111
|
+
export declare function rustSurface(src: string, insideTrait?: boolean, topLevel?: boolean): string;
|
|
112
|
+
export declare function isRustFile(name: string): boolean;
|
|
113
|
+
/** The `[package] name` of a cargo project, for labelling its own source. */
|
|
114
|
+
export declare function cargoProjectName(cwd: string): string | null;
|
|
115
|
+
export {};
|