@spikedpunch/mast 0.1.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/LICENSE +21 -0
- package/MAST_SPEC.md +2926 -0
- package/README.md +842 -0
- package/assets/skill.md +45 -0
- package/dist/ast/extract.d.ts +65 -0
- package/dist/ast/extract.d.ts.map +1 -0
- package/dist/ast/extract.js +147 -0
- package/dist/ast/extract.js.map +1 -0
- package/dist/ast/extractor.d.ts +85 -0
- package/dist/ast/extractor.d.ts.map +1 -0
- package/dist/ast/extractor.js +2 -0
- package/dist/ast/extractor.js.map +1 -0
- package/dist/ast/extractors/markdown.d.ts +40 -0
- package/dist/ast/extractors/markdown.d.ts.map +1 -0
- package/dist/ast/extractors/markdown.js +175 -0
- package/dist/ast/extractors/markdown.js.map +1 -0
- package/dist/ast/extractors/typescript.d.ts +179 -0
- package/dist/ast/extractors/typescript.d.ts.map +1 -0
- package/dist/ast/extractors/typescript.js +1439 -0
- package/dist/ast/extractors/typescript.js.map +1 -0
- package/dist/ast/parser.d.ts +5 -0
- package/dist/ast/parser.d.ts.map +1 -0
- package/dist/ast/parser.js +21 -0
- package/dist/ast/parser.js.map +1 -0
- package/dist/ast/types.d.ts +586 -0
- package/dist/ast/types.d.ts.map +1 -0
- package/dist/ast/types.js +3 -0
- package/dist/ast/types.js.map +1 -0
- package/dist/cli/docs-cmd.d.ts +22 -0
- package/dist/cli/docs-cmd.d.ts.map +1 -0
- package/dist/cli/docs-cmd.js +100 -0
- package/dist/cli/docs-cmd.js.map +1 -0
- package/dist/cli/index-cmd.d.ts +72 -0
- package/dist/cli/index-cmd.d.ts.map +1 -0
- package/dist/cli/index-cmd.js +263 -0
- package/dist/cli/index-cmd.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +14 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +64 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/install-hooks.d.ts +3 -0
- package/dist/cli/install-hooks.d.ts.map +1 -0
- package/dist/cli/install-hooks.js +34 -0
- package/dist/cli/install-hooks.js.map +1 -0
- package/dist/cli/metrics-cmd.d.ts +3 -0
- package/dist/cli/metrics-cmd.d.ts.map +1 -0
- package/dist/cli/metrics-cmd.js +164 -0
- package/dist/cli/metrics-cmd.js.map +1 -0
- package/dist/cli/program.d.ts +14 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +44 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/query.d.ts +46 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +153 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/search-cmd.d.ts +33 -0
- package/dist/cli/search-cmd.d.ts.map +1 -0
- package/dist/cli/search-cmd.js +114 -0
- package/dist/cli/search-cmd.js.map +1 -0
- package/dist/cli/serve.d.ts +3 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +19 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/skill-install.d.ts +39 -0
- package/dist/cli/skill-install.d.ts.map +1 -0
- package/dist/cli/skill-install.js +57 -0
- package/dist/cli/skill-install.js.map +1 -0
- package/dist/cli/status.d.ts +35 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +117 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/upgrade-cmd.d.ts +48 -0
- package/dist/cli/upgrade-cmd.d.ts.map +1 -0
- package/dist/cli/upgrade-cmd.js +129 -0
- package/dist/cli/upgrade-cmd.js.map +1 -0
- package/dist/cli/version.d.ts +3 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +19 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/env.d.ts +17 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +17 -0
- package/dist/env.js.map +1 -0
- package/dist/graph/checker-resolver.d.ts +156 -0
- package/dist/graph/checker-resolver.d.ts.map +1 -0
- package/dist/graph/checker-resolver.js +458 -0
- package/dist/graph/checker-resolver.js.map +1 -0
- package/dist/graph/db.d.ts +318 -0
- package/dist/graph/db.d.ts.map +1 -0
- package/dist/graph/db.js +266 -0
- package/dist/graph/db.js.map +1 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +5 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/local-type-env.d.ts +45 -0
- package/dist/graph/local-type-env.d.ts.map +1 -0
- package/dist/graph/local-type-env.js +59 -0
- package/dist/graph/local-type-env.js.map +1 -0
- package/dist/graph/path-range.d.ts +40 -0
- package/dist/graph/path-range.d.ts.map +1 -0
- package/dist/graph/path-range.js +42 -0
- package/dist/graph/path-range.js.map +1 -0
- package/dist/graph/populate.d.ts +263 -0
- package/dist/graph/populate.d.ts.map +1 -0
- package/dist/graph/populate.js +984 -0
- package/dist/graph/populate.js.map +1 -0
- package/dist/graph/queries.d.ts +114 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +415 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/sqliteBatch.d.ts +48 -0
- package/dist/graph/sqliteBatch.d.ts.map +1 -0
- package/dist/graph/sqliteBatch.js +93 -0
- package/dist/graph/sqliteBatch.js.map +1 -0
- package/dist/indexer/freshness.d.ts +48 -0
- package/dist/indexer/freshness.d.ts.map +1 -0
- package/dist/indexer/freshness.js +72 -0
- package/dist/indexer/freshness.js.map +1 -0
- package/dist/indexer/import-resolver.d.ts +50 -0
- package/dist/indexer/import-resolver.d.ts.map +1 -0
- package/dist/indexer/import-resolver.js +318 -0
- package/dist/indexer/import-resolver.js.map +1 -0
- package/dist/indexer/index.d.ts +249 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +560 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/walker.d.ts +60 -0
- package/dist/indexer/walker.d.ts.map +1 -0
- package/dist/indexer/walker.js +128 -0
- package/dist/indexer/walker.js.map +1 -0
- package/dist/indexer/watcher.d.ts +80 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +151 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/context.d.ts +23 -0
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +2 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/register-tools.d.ts +21 -0
- package/dist/mcp/register-tools.d.ts.map +1 -0
- package/dist/mcp/register-tools.js +42 -0
- package/dist/mcp/register-tools.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/staleness.d.ts +72 -0
- package/dist/mcp/staleness.d.ts.map +1 -0
- package/dist/mcp/staleness.js +213 -0
- package/dist/mcp/staleness.js.map +1 -0
- package/dist/mcp/startup.d.ts +40 -0
- package/dist/mcp/startup.d.ts.map +1 -0
- package/dist/mcp/startup.js +114 -0
- package/dist/mcp/startup.js.map +1 -0
- package/dist/mcp/tools/_helpers.d.ts +26 -0
- package/dist/mcp/tools/_helpers.d.ts.map +1 -0
- package/dist/mcp/tools/_helpers.js +54 -0
- package/dist/mcp/tools/_helpers.js.map +1 -0
- package/dist/mcp/tools/callers.d.ts +4 -0
- package/dist/mcp/tools/callers.d.ts.map +1 -0
- package/dist/mcp/tools/callers.js +112 -0
- package/dist/mcp/tools/callers.js.map +1 -0
- package/dist/mcp/tools/dependencies.d.ts +4 -0
- package/dist/mcp/tools/dependencies.d.ts.map +1 -0
- package/dist/mcp/tools/dependencies.js +36 -0
- package/dist/mcp/tools/dependencies.js.map +1 -0
- package/dist/mcp/tools/efficiency.d.ts +4 -0
- package/dist/mcp/tools/efficiency.d.ts.map +1 -0
- package/dist/mcp/tools/efficiency.js +39 -0
- package/dist/mcp/tools/efficiency.js.map +1 -0
- package/dist/mcp/tools/exports.d.ts +4 -0
- package/dist/mcp/tools/exports.d.ts.map +1 -0
- package/dist/mcp/tools/exports.js +56 -0
- package/dist/mcp/tools/exports.js.map +1 -0
- package/dist/mcp/tools/implementors.d.ts +4 -0
- package/dist/mcp/tools/implementors.d.ts.map +1 -0
- package/dist/mcp/tools/implementors.js +47 -0
- package/dist/mcp/tools/implementors.js.map +1 -0
- package/dist/mcp/tools/project-skeleton.d.ts +4 -0
- package/dist/mcp/tools/project-skeleton.d.ts.map +1 -0
- package/dist/mcp/tools/project-skeleton.js +61 -0
- package/dist/mcp/tools/project-skeleton.js.map +1 -0
- package/dist/mcp/tools/reindex.d.ts +14 -0
- package/dist/mcp/tools/reindex.d.ts.map +1 -0
- package/dist/mcp/tools/reindex.js +32 -0
- package/dist/mcp/tools/reindex.js.map +1 -0
- package/dist/mcp/tools/rename-impact.d.ts +4 -0
- package/dist/mcp/tools/rename-impact.d.ts.map +1 -0
- package/dist/mcp/tools/rename-impact.js +124 -0
- package/dist/mcp/tools/rename-impact.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +4 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +69 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/tools/signature.d.ts +4 -0
- package/dist/mcp/tools/signature.d.ts.map +1 -0
- package/dist/mcp/tools/signature.js +127 -0
- package/dist/mcp/tools/signature.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +4 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +30 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/search/declex.d.ts +109 -0
- package/dist/search/declex.d.ts.map +1 -0
- package/dist/search/declex.js +242 -0
- package/dist/search/declex.js.map +1 -0
- package/dist/search/fts.d.ts +77 -0
- package/dist/search/fts.d.ts.map +1 -0
- package/dist/search/fts.js +223 -0
- package/dist/search/fts.js.map +1 -0
- package/dist/search/fused.d.ts +110 -0
- package/dist/search/fused.d.ts.map +1 -0
- package/dist/search/fused.js +323 -0
- package/dist/search/fused.js.map +1 -0
- package/dist/search/potential-matches.d.ts +88 -0
- package/dist/search/potential-matches.d.ts.map +1 -0
- package/dist/search/potential-matches.js +83 -0
- package/dist/search/potential-matches.js.map +1 -0
- package/dist/search/scope.d.ts +66 -0
- package/dist/search/scope.d.ts.map +1 -0
- package/dist/search/scope.js +71 -0
- package/dist/search/scope.js.map +1 -0
- package/dist/store/config.d.ts +57 -0
- package/dist/store/config.d.ts.map +1 -0
- package/dist/store/config.js +208 -0
- package/dist/store/config.js.map +1 -0
- package/dist/store/lock.d.ts +101 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +182 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/lockMetrics.d.ts +52 -0
- package/dist/store/lockMetrics.d.ts.map +1 -0
- package/dist/store/lockMetrics.js +29 -0
- package/dist/store/lockMetrics.js.map +1 -0
- package/dist/store/sqliteChunkStore.d.ts +44 -0
- package/dist/store/sqliteChunkStore.d.ts.map +1 -0
- package/dist/store/sqliteChunkStore.js +135 -0
- package/dist/store/sqliteChunkStore.js.map +1 -0
- package/dist/telemetry/lockMetricsSummary.d.ts +42 -0
- package/dist/telemetry/lockMetricsSummary.d.ts.map +1 -0
- package/dist/telemetry/lockMetricsSummary.js +139 -0
- package/dist/telemetry/lockMetricsSummary.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +140 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +312 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/tokenizer.d.ts +125 -0
- package/dist/telemetry/tokenizer.d.ts.map +1 -0
- package/dist/telemetry/tokenizer.js +174 -0
- package/dist/telemetry/tokenizer.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { CLI_VERSION, PACKAGE_NAME } from './version.js';
|
|
5
|
+
import { detectSkillTargets, installSkillInto } from './skill-install.js';
|
|
6
|
+
import { resolveConfig } from '../store/config.js';
|
|
7
|
+
/**
|
|
8
|
+
* `mast docs` and `mast skill` — documentation that is version-matched by construction.
|
|
9
|
+
*
|
|
10
|
+
* Both read files shipped inside the installed package rather than pointing at a
|
|
11
|
+
* website, so what a user (or an agent) reads is what their binary does. Looking up
|
|
12
|
+
* "which release am I on, and which docs go with it" is exactly the step this removes,
|
|
13
|
+
* and it is the step where a reader silently ends up on docs for a different version.
|
|
14
|
+
*/
|
|
15
|
+
export class DocsError extends Error {
|
|
16
|
+
}
|
|
17
|
+
// `dist/cli/` and `src/cli/` both sit two levels below the package root, so this
|
|
18
|
+
// resolves identically under vitest and in the published tarball.
|
|
19
|
+
const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
20
|
+
export const DOC_TOPICS = [
|
|
21
|
+
{ name: 'readme', file: 'README.md', summary: 'Install, quick start, CLI and MCP tool reference' },
|
|
22
|
+
{ name: 'spec', file: 'MAST_SPEC.md', summary: 'Full behavioural specification — schemas, tool contracts, invariants' },
|
|
23
|
+
{ name: 'skill', file: 'assets/skill.md', summary: 'The instructions to paste into an agent prompt or skill file' },
|
|
24
|
+
];
|
|
25
|
+
export function readDoc(name) {
|
|
26
|
+
const topic = DOC_TOPICS.find((t) => t.name === name);
|
|
27
|
+
if (topic === undefined) {
|
|
28
|
+
throw new DocsError(`unknown docs topic "${name}"; available topics: ${DOC_TOPICS.map((t) => t.name).join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return readFileSync(join(PACKAGE_ROOT, topic.file), 'utf8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new DocsError(`${topic.file} is missing from this installation of ${PACKAGE_NAME}@${CLI_VERSION}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function listDocs() {
|
|
38
|
+
const width = Math.max(...DOC_TOPICS.map((t) => t.name.length));
|
|
39
|
+
return [
|
|
40
|
+
`${PACKAGE_NAME} ${CLI_VERSION} — documentation shipped with this build`,
|
|
41
|
+
'',
|
|
42
|
+
...DOC_TOPICS.map((t) => ` ${t.name.padEnd(width)} ${t.summary}`),
|
|
43
|
+
'',
|
|
44
|
+
'Read one with `mast docs <topic>`.',
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
export function registerDocsCommand(program) {
|
|
48
|
+
program
|
|
49
|
+
.command('docs [topic]')
|
|
50
|
+
.description('Print the documentation shipped with this build — no version lookup needed')
|
|
51
|
+
.action((topic) => {
|
|
52
|
+
try {
|
|
53
|
+
process.stdout.write((topic === undefined ? listDocs() : readDoc(topic)) + '\n');
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function registerSkillCommand(program) {
|
|
62
|
+
program
|
|
63
|
+
.command('skill [path]')
|
|
64
|
+
.description('Print the MAST instructions to copy into an agent prompt or skill file')
|
|
65
|
+
.option('--install', 'Splice the instructions into this project\'s existing agent config files')
|
|
66
|
+
.option('--dry-run', 'With --install, report what would change without writing')
|
|
67
|
+
.action((projectPath, opts) => {
|
|
68
|
+
try {
|
|
69
|
+
const skill = readDoc('skill');
|
|
70
|
+
if (opts.install !== true) {
|
|
71
|
+
process.stdout.write(skill + '\n');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const root = resolveConfig({ projectRoot: projectPath }).resolved_project_root;
|
|
75
|
+
const targets = detectSkillTargets(root);
|
|
76
|
+
if (targets.length === 0) {
|
|
77
|
+
// Not an error: a project with no agent config is a normal state, and the
|
|
78
|
+
// remedy is a decision for the user, not a file this command invents.
|
|
79
|
+
process.stdout.write([`No agent config files found in ${root}.`, '',
|
|
80
|
+
'Create one of these and re-run, or pipe the skill wherever you keep prompts:',
|
|
81
|
+
' CLAUDE.md AGENTS.md .cursorrules .windsurfrules .github/copilot-instructions.md', '',
|
|
82
|
+
' mast skill >> CLAUDE.md'].join('\n') + '\n');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const dryRun = opts.dryRun === true;
|
|
86
|
+
for (const { target, changed } of installSkillInto(targets, skill, { dryRun })) {
|
|
87
|
+
const verb = !changed ? 'unchanged' : dryRun ? 'would update' : 'updated';
|
|
88
|
+
process.stdout.write(` ${verb.padEnd(13)} ${target.file} (${target.agent})\n`);
|
|
89
|
+
}
|
|
90
|
+
process.stdout.write(dryRun
|
|
91
|
+
? '\nDry run — nothing written. Re-run without --dry-run to apply.\n'
|
|
92
|
+
: '\nThe block is marked; re-running after an upgrade replaces it rather than adding a second copy.\n');
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=docs-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-cmd.js","sourceRoot":"","sources":["../../src/cli/docs-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type OpenDatabaseOptions } from '../graph/db.js';
|
|
3
|
+
/**
|
|
4
|
+
* Whether to print the per-phase breakdown.
|
|
5
|
+
*
|
|
6
|
+
* Extracted rather than inlined in the action so the gate is testable without spawning the
|
|
7
|
+
* built CLI: a spawn-based test resolves against `dist/`, and a negative assertion
|
|
8
|
+
* ("stdout does not contain phases:") passes trivially when the spawn produces no output at
|
|
9
|
+
* all. That false green is the D8 failure mode in miniature.
|
|
10
|
+
*
|
|
11
|
+
* This is the first environment flag in the codebase and so sets the convention:
|
|
12
|
+
* `ENABLE_`-prefixed, and the value is the word `true` or `false`, never `1`/`0`. Compared
|
|
13
|
+
* case-insensitively after trimming, because env vars are typed by hand. Anything that is
|
|
14
|
+
* not `true` is off, so a typo fails closed rather than silently switching instrumentation
|
|
15
|
+
* on in an ordinary run.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isPhaseTimingEnabled(flag: boolean | undefined, env?: NodeJS.ProcessEnv): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Parse an operator-supplied MiB figure for the SQLite tuning flags.
|
|
20
|
+
*
|
|
21
|
+
* Commander yields raw strings, so this is a trust boundary (§3.2) — the value
|
|
22
|
+
* is validated here and the pragma layer downstream receives only numbers it
|
|
23
|
+
* can apply verbatim. Fractions are refused rather than truncated so that an
|
|
24
|
+
* arm's declared size and its applied size are always the same number; a silent
|
|
25
|
+
* truncation would put a measurement's own label out of step with what ran.
|
|
26
|
+
*
|
|
27
|
+
* Exported for direct testing: a spawn-based CLI test resolves against `dist/`
|
|
28
|
+
* and would grade a different binary than the one under review (the D8 failure
|
|
29
|
+
* mode), which is why `isPhaseTimingEnabled` above is exported for the same
|
|
30
|
+
* reason.
|
|
31
|
+
*
|
|
32
|
+
* @throws Error naming the flag and the rejected value, if it is not a
|
|
33
|
+
* non-negative whole number.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseMebibytes(flag: string, raw: string): number;
|
|
36
|
+
/**
|
|
37
|
+
* Whether to print the applied-pragma line.
|
|
38
|
+
*
|
|
39
|
+
* Emitted when the operator tuned something (they should see what actually took
|
|
40
|
+
* effect, not what they typed), and also under the phase-timing gate — which is
|
|
41
|
+
* what gives the A/B's *control* arm, which passes no tuning flag at all, a
|
|
42
|
+
* `pragmas:` line to be graded against. Without the second clause the one arm
|
|
43
|
+
* whose "un-pragma'd" claim carries the most weight would be the one arm with
|
|
44
|
+
* no evidence for it.
|
|
45
|
+
*
|
|
46
|
+
* Extracted for the same reason as {@link isPhaseTimingEnabled}: a spawn-based
|
|
47
|
+
* test resolves against `dist/`, where a negative assertion passes trivially on
|
|
48
|
+
* empty stdout.
|
|
49
|
+
*/
|
|
50
|
+
export declare function shouldPrintPragmas(phaseTimingEnabled: boolean, dbOptions: OpenDatabaseOptions): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether this run skips the per-file FTS5 deletes — E1-FTS's arm G.
|
|
53
|
+
*
|
|
54
|
+
* The skip is only sound on a **cold** build, where those deletes match zero
|
|
55
|
+
* rows and the finished database is therefore identical to the control's. On an
|
|
56
|
+
* incremental run they are load-bearing: skipping them leaves the previous
|
|
57
|
+
* version's rows in `chunk_fts` / `identifier_fts` alongside the new ones while
|
|
58
|
+
* the ordinary tables replace correctly, so the index goes silently wrong — no
|
|
59
|
+
* error, no missing rows, just stale search hits.
|
|
60
|
+
*
|
|
61
|
+
* Refused here, at the trust boundary, rather than documented and hoped for.
|
|
62
|
+
* It **throws** instead of falling back to the safe path, because an operator
|
|
63
|
+
* who asked for arm G and quietly received arm A would collect a null and have
|
|
64
|
+
* no way to tell.
|
|
65
|
+
*
|
|
66
|
+
* Exported for direct testing, same reason as {@link parseMebibytes}.
|
|
67
|
+
*
|
|
68
|
+
* @throws Error naming both flags, if the skip is combined with `--incremental`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveSkipFtsDeletes(flag: boolean | undefined, incremental: boolean): boolean;
|
|
71
|
+
export declare function registerIndexCommand(program: Command): void;
|
|
72
|
+
//# sourceMappingURL=index-cmd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/index-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAIxE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAGT;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAShE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,OAAO,EAC3B,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAET;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,WAAW,EAAE,OAAO,GACnB,OAAO,CAUT;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+M3D"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { resolveConfig } from '../store/config.js';
|
|
2
|
+
import { runIndex } from '../indexer/index.js';
|
|
3
|
+
import { newWriteSpans } from '../graph/populate.js';
|
|
4
|
+
import { openDatabase } from '../graph/db.js';
|
|
5
|
+
import { SqliteChunkStore } from '../store/sqliteChunkStore.js';
|
|
6
|
+
import { runCheckerPass } from '../graph/checker-resolver.js';
|
|
7
|
+
/**
|
|
8
|
+
* Whether to print the per-phase breakdown.
|
|
9
|
+
*
|
|
10
|
+
* Extracted rather than inlined in the action so the gate is testable without spawning the
|
|
11
|
+
* built CLI: a spawn-based test resolves against `dist/`, and a negative assertion
|
|
12
|
+
* ("stdout does not contain phases:") passes trivially when the spawn produces no output at
|
|
13
|
+
* all. That false green is the D8 failure mode in miniature.
|
|
14
|
+
*
|
|
15
|
+
* This is the first environment flag in the codebase and so sets the convention:
|
|
16
|
+
* `ENABLE_`-prefixed, and the value is the word `true` or `false`, never `1`/`0`. Compared
|
|
17
|
+
* case-insensitively after trimming, because env vars are typed by hand. Anything that is
|
|
18
|
+
* not `true` is off, so a typo fails closed rather than silently switching instrumentation
|
|
19
|
+
* on in an ordinary run.
|
|
20
|
+
*/
|
|
21
|
+
export function isPhaseTimingEnabled(flag, env = process.env) {
|
|
22
|
+
if (flag === true)
|
|
23
|
+
return true;
|
|
24
|
+
return env.ENABLE_MAST_PHASE_TIMING?.trim().toLowerCase() === 'true';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse an operator-supplied MiB figure for the SQLite tuning flags.
|
|
28
|
+
*
|
|
29
|
+
* Commander yields raw strings, so this is a trust boundary (§3.2) — the value
|
|
30
|
+
* is validated here and the pragma layer downstream receives only numbers it
|
|
31
|
+
* can apply verbatim. Fractions are refused rather than truncated so that an
|
|
32
|
+
* arm's declared size and its applied size are always the same number; a silent
|
|
33
|
+
* truncation would put a measurement's own label out of step with what ran.
|
|
34
|
+
*
|
|
35
|
+
* Exported for direct testing: a spawn-based CLI test resolves against `dist/`
|
|
36
|
+
* and would grade a different binary than the one under review (the D8 failure
|
|
37
|
+
* mode), which is why `isPhaseTimingEnabled` above is exported for the same
|
|
38
|
+
* reason.
|
|
39
|
+
*
|
|
40
|
+
* @throws Error naming the flag and the rejected value, if it is not a
|
|
41
|
+
* non-negative whole number.
|
|
42
|
+
*/
|
|
43
|
+
export function parseMebibytes(flag, raw) {
|
|
44
|
+
// Number('') is 0 — an empty value must be an error, not a silent zero.
|
|
45
|
+
const value = raw.trim() === '' ? Number.NaN : Number(raw);
|
|
46
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
47
|
+
throw new Error(`${flag} expects a non-negative whole number of MiB, received "${raw}"`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether to print the applied-pragma line.
|
|
53
|
+
*
|
|
54
|
+
* Emitted when the operator tuned something (they should see what actually took
|
|
55
|
+
* effect, not what they typed), and also under the phase-timing gate — which is
|
|
56
|
+
* what gives the A/B's *control* arm, which passes no tuning flag at all, a
|
|
57
|
+
* `pragmas:` line to be graded against. Without the second clause the one arm
|
|
58
|
+
* whose "un-pragma'd" claim carries the most weight would be the one arm with
|
|
59
|
+
* no evidence for it.
|
|
60
|
+
*
|
|
61
|
+
* Extracted for the same reason as {@link isPhaseTimingEnabled}: a spawn-based
|
|
62
|
+
* test resolves against `dist/`, where a negative assertion passes trivially on
|
|
63
|
+
* empty stdout.
|
|
64
|
+
*/
|
|
65
|
+
export function shouldPrintPragmas(phaseTimingEnabled, dbOptions) {
|
|
66
|
+
return phaseTimingEnabled || Object.keys(dbOptions).length > 0;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Whether this run skips the per-file FTS5 deletes — E1-FTS's arm G.
|
|
70
|
+
*
|
|
71
|
+
* The skip is only sound on a **cold** build, where those deletes match zero
|
|
72
|
+
* rows and the finished database is therefore identical to the control's. On an
|
|
73
|
+
* incremental run they are load-bearing: skipping them leaves the previous
|
|
74
|
+
* version's rows in `chunk_fts` / `identifier_fts` alongside the new ones while
|
|
75
|
+
* the ordinary tables replace correctly, so the index goes silently wrong — no
|
|
76
|
+
* error, no missing rows, just stale search hits.
|
|
77
|
+
*
|
|
78
|
+
* Refused here, at the trust boundary, rather than documented and hoped for.
|
|
79
|
+
* It **throws** instead of falling back to the safe path, because an operator
|
|
80
|
+
* who asked for arm G and quietly received arm A would collect a null and have
|
|
81
|
+
* no way to tell.
|
|
82
|
+
*
|
|
83
|
+
* Exported for direct testing, same reason as {@link parseMebibytes}.
|
|
84
|
+
*
|
|
85
|
+
* @throws Error naming both flags, if the skip is combined with `--incremental`.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveSkipFtsDeletes(flag, incremental) {
|
|
88
|
+
if (flag !== true)
|
|
89
|
+
return false;
|
|
90
|
+
if (incremental) {
|
|
91
|
+
throw new Error('--unsafe-skip-fts-deletes cannot be combined with --incremental: the FTS deletes are ' +
|
|
92
|
+
'only redundant on a cold build. On an incremental run they are what removes the ' +
|
|
93
|
+
'previous version\'s rows, and skipping them corrupts the index silently.');
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
export function registerIndexCommand(program) {
|
|
98
|
+
program
|
|
99
|
+
.command('index [path]')
|
|
100
|
+
.description('Build or update the index')
|
|
101
|
+
.option('--state-dir <dir>', 'State directory (resolved from config if omitted)')
|
|
102
|
+
.option('--incremental', 'Only reindex files changed since last index run')
|
|
103
|
+
.option('--show-progress', 'Print indexing progress to stderr')
|
|
104
|
+
.option('--checker', 'Opt-in TypeScript-checker pass (Stage 1.2): upgrade heuristic potential_matches into verified edges ' +
|
|
105
|
+
'or drop non-call-site/wrong-declaration noise. Holds one ts.Program at a time; can take tens of seconds ' +
|
|
106
|
+
'on a large monorepo — not part of the default index path (MAST_SPEC §10.3.2).')
|
|
107
|
+
.option('--phase-timing', 'Print a machine-readable per-phase breakdown of the index run (walk/parse/write/edges/finalise). ' +
|
|
108
|
+
'Also enabled by ENABLE_MAST_PHASE_TIMING=true. The timers themselves always run — this only ' +
|
|
109
|
+
'controls the output line — so enabling it costs nothing but a line of stdout.')
|
|
110
|
+
.option('--cache-size-mib <mib>', 'SQLite page-cache budget for this run, in MiB (PRAGMA cache_size). Diagnostic lever for the ' +
|
|
111
|
+
'E1-PHASE mechanism probe; omitted, SQLite\'s own default stands and nothing is set.')
|
|
112
|
+
.option('--mmap-size-mib <mib>', 'SQLite memory-map budget for this run, in MiB (PRAGMA mmap_size); 0 disables memory mapping. ' +
|
|
113
|
+
'Diagnostic lever for the E1-PHASE mechanism probe; omitted, SQLite\'s own default stands.')
|
|
114
|
+
.option('--unsafe-skip-fts-deletes', 'EVAL ONLY — skip the per-file FTS5 delete statements. Sound ONLY on a cold build, where they ' +
|
|
115
|
+
'match zero rows; on any other path this leaves stale FTS rows behind and corrupts the index ' +
|
|
116
|
+
'silently, so it is refused with --incremental. E1-FTS arm G.')
|
|
117
|
+
.action(async (projectPath, opts) => {
|
|
118
|
+
const config = resolveConfig({
|
|
119
|
+
projectRoot: projectPath,
|
|
120
|
+
stateDirOverride: opts.stateDir,
|
|
121
|
+
});
|
|
122
|
+
// Built with conditional spreads, not `{ cacheSizeKib: maybeUndefined }`:
|
|
123
|
+
// `exactOptionalPropertyTypes` distinguishes an absent property from one
|
|
124
|
+
// explicitly set to undefined, and the A/B's control arm depends on the
|
|
125
|
+
// property being genuinely absent.
|
|
126
|
+
const dbOptions = {
|
|
127
|
+
...(opts.cacheSizeMib !== undefined
|
|
128
|
+
? { cacheSizeKib: parseMebibytes('--cache-size-mib', opts.cacheSizeMib) * 1024 }
|
|
129
|
+
: {}),
|
|
130
|
+
...(opts.mmapSizeMib !== undefined
|
|
131
|
+
? { mmapSizeBytes: parseMebibytes('--mmap-size-mib', opts.mmapSizeMib) * 1024 * 1024 }
|
|
132
|
+
: {}),
|
|
133
|
+
};
|
|
134
|
+
const onProgress = opts.showProgress
|
|
135
|
+
? (processed, total) => {
|
|
136
|
+
if (total === 0)
|
|
137
|
+
return;
|
|
138
|
+
const pct = Math.round((processed / total) * 100);
|
|
139
|
+
const line = ` indexing ${processed}/${total} files (${pct}%)`;
|
|
140
|
+
// \r rewrites the line in place on a TTY; fall back to newlines otherwise.
|
|
141
|
+
process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
|
|
142
|
+
if (processed === total && process.stderr.isTTY)
|
|
143
|
+
process.stderr.write('\n');
|
|
144
|
+
}
|
|
145
|
+
: undefined;
|
|
146
|
+
const incremental = opts.incremental ?? false;
|
|
147
|
+
const skipFtsDeletes = resolveSkipFtsDeletes(opts.unsafeSkipFtsDeletes, incremental);
|
|
148
|
+
// Allocated only under the phase-timing gate, and passed only when
|
|
149
|
+
// allocated: `populateFile` reads no clock at all without an accumulator,
|
|
150
|
+
// so an ordinary `mast index` is untouched by this instrument.
|
|
151
|
+
const writeSpans = isPhaseTimingEnabled(opts.phaseTiming) ? newWriteSpans() : undefined;
|
|
152
|
+
if (skipFtsDeletes) {
|
|
153
|
+
// Loud on stderr as well as refused above: this run's database is a
|
|
154
|
+
// measurement artifact, and anyone reading the log later must be able
|
|
155
|
+
// to tell it apart from a production index.
|
|
156
|
+
process.stderr.write('[mast] WARN: --unsafe-skip-fts-deletes is set — FTS5 delete statements are being ' +
|
|
157
|
+
'skipped. This is an eval instrument (E1-FTS arm G) and is sound only because this ' +
|
|
158
|
+
'is a cold build. Do NOT reuse this index.\n');
|
|
159
|
+
}
|
|
160
|
+
const result = await runIndex(config, {
|
|
161
|
+
incremental,
|
|
162
|
+
onProgress,
|
|
163
|
+
dbOptions,
|
|
164
|
+
...(writeSpans !== undefined ? { writeSpans } : {}),
|
|
165
|
+
...(skipFtsDeletes ? { unsafeSkipFtsDeletes: true } : {}),
|
|
166
|
+
});
|
|
167
|
+
process.stdout.write(`files: ${result.filesIndexed} indexed, ${result.filesSkipped} skipped` +
|
|
168
|
+
` chunks: +${result.chunksAdded} -${result.chunksRemoved}` +
|
|
169
|
+
` duration: ${result.durationMs}ms` +
|
|
170
|
+
(result.parseErrors > 0 ? ` parse_errors: ${result.parseErrors}` : '') +
|
|
171
|
+
(result.writeErrors > 0 ? ` write_errors: ${result.writeErrors}` : '') +
|
|
172
|
+
(result.staleWriteRejections > 0 ? ` stale_write_rejections: ${result.staleWriteRejections}` : '') +
|
|
173
|
+
(result.miscasedImports.count > 0 ? ` miscased_imports: ${result.miscasedImports.count}` : '') +
|
|
174
|
+
'\n');
|
|
175
|
+
// A mis-cased import is a defect in the indexed repository, not in MAST:
|
|
176
|
+
// it compiles on APFS/NTFS and fails on a case-sensitive filesystem. MAST
|
|
177
|
+
// indexes it correctly regardless (the edge points at the on-disk file),
|
|
178
|
+
// so this is advisory and does not affect the exit code. stderr, because
|
|
179
|
+
// stdout carries the machine-readable summary above.
|
|
180
|
+
if (result.miscasedImports.count > 0) {
|
|
181
|
+
const { count, samples } = result.miscasedImports;
|
|
182
|
+
process.stderr.write(`warning: ${count} import${count === 1 ? '' : 's'} resolved only because this ` +
|
|
183
|
+
`filesystem ignores case; ${count === 1 ? 'it' : 'they'} will not resolve on a ` +
|
|
184
|
+
`case-sensitive one:\n` +
|
|
185
|
+
samples.map((m) => ` ${m.fromFile}: '${m.specifier}' -> ${m.onDiskPath}\n`).join('') +
|
|
186
|
+
(count > samples.length ? ` ... and ${count - samples.length} more\n` : ''));
|
|
187
|
+
}
|
|
188
|
+
// Machine-readable phase breakdown, opt-in. E1 measured a growth exponent of ~1.75
|
|
189
|
+
// from `duration` alone and could not say which phase carried it; the scaling harness
|
|
190
|
+
// parses this line to decompose the next ladder.
|
|
191
|
+
//
|
|
192
|
+
// Gated because it is instrumentation, not a user-facing summary, and an unconditional
|
|
193
|
+
// extra stdout line changes the CLI's output contract for everyone. The env var exists
|
|
194
|
+
// so a harness that spawns the shipped binary can enable it without every call site
|
|
195
|
+
// growing an argument — read HERE, at the CLI boundary, and never inside the indexer.
|
|
196
|
+
if (isPhaseTimingEnabled(opts.phaseTiming)) {
|
|
197
|
+
process.stdout.write(`phases: ${JSON.stringify(result.phaseMs)}\n`);
|
|
198
|
+
}
|
|
199
|
+
// The write phase's own decomposition (E1-FTS). A separate line from
|
|
200
|
+
// `phases:` on purpose — `phases:` is E1-PHASE's scored instrument and a
|
|
201
|
+
// finished record must not sit behind a moving definition, which is the
|
|
202
|
+
// same rule that gave E1-AB its own schedule module rather than an
|
|
203
|
+
// extension of E1's.
|
|
204
|
+
if (writeSpans !== undefined) {
|
|
205
|
+
process.stdout.write(`write_spans: ${JSON.stringify(writeSpans)}\n`);
|
|
206
|
+
}
|
|
207
|
+
// The pragmas SQLite reported for this run's own connection, not an echo
|
|
208
|
+
// of the flags. A flag that failed to reach the connection would make the
|
|
209
|
+
// A/B's two arms identical and produce a clean, credible-looking null —
|
|
210
|
+
// this line is what makes that failure visible instead.
|
|
211
|
+
if (shouldPrintPragmas(isPhaseTimingEnabled(opts.phaseTiming), dbOptions)) {
|
|
212
|
+
process.stdout.write(`pragmas: ${JSON.stringify(result.appliedPragmas)}\n`);
|
|
213
|
+
}
|
|
214
|
+
// Non-zero exit so CI/scripts catch a silently-amputated file — a
|
|
215
|
+
// chunk-store write failure must be impossible to miss, not just a
|
|
216
|
+
// console line a human happens to read (GITNEXUS_COMPARISON.md §16).
|
|
217
|
+
// `exitCode` (not `process.exit()`) lets stdout/stderr flush and any
|
|
218
|
+
// later steps in this action (Phase 2 embed, checker pass) still run.
|
|
219
|
+
if (result.writeErrors > 0)
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
// Opt-in Stage 1.2 checker pass — runs after Phase 1 (parse/chunk/graph/
|
|
222
|
+
// FTS is all there is post-Stage-7.1) so it classifies against the
|
|
223
|
+
// freshest graph.db this invocation just wrote. Opens its own db handle
|
|
224
|
+
// (chunkStore wraps it, §15.1) and destroys it itself (runIndex already
|
|
225
|
+
// closed its own), matching the one-shot-process pattern this command
|
|
226
|
+
// already used for the now-removed Phase 2 embed step.
|
|
227
|
+
if (opts.checker) {
|
|
228
|
+
// Same tuning as the index run above: a flag that applied to one half
|
|
229
|
+
// of `mast index` and silently not the other would be a trap.
|
|
230
|
+
const db = openDatabase(config.resolved_state_dir, dbOptions);
|
|
231
|
+
const chunkStore = new SqliteChunkStore(db);
|
|
232
|
+
try {
|
|
233
|
+
const checkerResult = await runCheckerPass(db, chunkStore, config, {
|
|
234
|
+
onProject: opts.showProgress
|
|
235
|
+
? (configDir, index, total) => {
|
|
236
|
+
const line = ` checker ${index}/${total}: ${configDir}`;
|
|
237
|
+
process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
|
|
238
|
+
}
|
|
239
|
+
: undefined,
|
|
240
|
+
});
|
|
241
|
+
if (opts.showProgress && process.stderr.isTTY)
|
|
242
|
+
process.stderr.write('\n');
|
|
243
|
+
// No silent caps: every project the pass skipped is named, not just counted.
|
|
244
|
+
for (const skip of checkerResult.projectsSkipped) {
|
|
245
|
+
process.stderr.write(`[mast] checker: skipped ${skip.configDir} (${skip.reason})\n`);
|
|
246
|
+
}
|
|
247
|
+
process.stdout.write(`checker: ${checkerResult.projectsChecked} project(s) checked, ${checkerResult.projectsSkipped.length} skipped` +
|
|
248
|
+
` symbols_checked: ${checkerResult.symbolsChecked}` +
|
|
249
|
+
` outside_ts_scope: ${checkerResult.potentialSitesOutsideScope}\n` +
|
|
250
|
+
` edges_upgraded: ${checkerResult.edgesUpgraded}` +
|
|
251
|
+
` non_call_site: ${checkerResult.classifiedNonCallSite}` +
|
|
252
|
+
` different_declaration: ${checkerResult.classifiedDifferentDeclaration}` +
|
|
253
|
+
` unresolved: ${checkerResult.unresolved}\n` +
|
|
254
|
+
` duration: ${checkerResult.durationMs}ms` +
|
|
255
|
+
` peak_rss_mb: ${Math.round(checkerResult.peakRssBytes / (1024 * 1024))}\n`);
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
await db.destroy();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=index-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-cmd.js","sourceRoot":"","sources":["../../src/cli/index-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,YAAY,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Parses `mast init --extensions <ext,...>` into `resolveConfig`'s `extensions` override.
|
|
4
|
+
* Returns `undefined` when the flag is absent, so flag absence keeps `resolveConfig`'s
|
|
5
|
+
* default-priority behavior byte-identical (F9, Stage 3.5).
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseExtensionsFlag(raw: string | undefined): readonly string[] | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Parses `mast init --exclude <pattern,...>` into `resolveConfig`'s `excludePatterns` override.
|
|
10
|
+
* Returns `undefined` when the flag is absent, same rationale as `parseExtensionsFlag`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseExcludeFlag(raw: string | undefined): readonly string[] | undefined;
|
|
13
|
+
export declare function registerInitCommand(program: Command): void;
|
|
14
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBzC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAG1F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAGvF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkC1D"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveConfig, writeStateConfig } from '../store/config.js';
|
|
2
|
+
import { initLockMarkers } from '../store/lock.js';
|
|
3
|
+
import { runIndex } from '../indexer/index.js';
|
|
4
|
+
/** Splits a comma-separated CLI flag value, trimming entries and dropping empties. */
|
|
5
|
+
function parseCommaSeparatedList(raw) {
|
|
6
|
+
return raw
|
|
7
|
+
.split(',')
|
|
8
|
+
.map((entry) => entry.trim())
|
|
9
|
+
.filter((entry) => entry.length > 0);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Normalizes a user-supplied extension to the leading-dot form `MastConfig.file_extensions`
|
|
13
|
+
* expects (`indexer/walker.ts`'s `walkProject` builds glob patterns as `**\/*${ext}`) — both
|
|
14
|
+
* '.py' and 'py' are accepted on the CLI so users don't have to remember the internal form.
|
|
15
|
+
*/
|
|
16
|
+
function normalizeExtension(ext) {
|
|
17
|
+
return ext.startsWith('.') ? ext : `.${ext}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parses `mast init --extensions <ext,...>` into `resolveConfig`'s `extensions` override.
|
|
21
|
+
* Returns `undefined` when the flag is absent, so flag absence keeps `resolveConfig`'s
|
|
22
|
+
* default-priority behavior byte-identical (F9, Stage 3.5).
|
|
23
|
+
*/
|
|
24
|
+
export function parseExtensionsFlag(raw) {
|
|
25
|
+
if (raw === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
return parseCommaSeparatedList(raw).map(normalizeExtension);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses `mast init --exclude <pattern,...>` into `resolveConfig`'s `excludePatterns` override.
|
|
31
|
+
* Returns `undefined` when the flag is absent, same rationale as `parseExtensionsFlag`.
|
|
32
|
+
*/
|
|
33
|
+
export function parseExcludeFlag(raw) {
|
|
34
|
+
if (raw === undefined)
|
|
35
|
+
return undefined;
|
|
36
|
+
return parseCommaSeparatedList(raw);
|
|
37
|
+
}
|
|
38
|
+
export function registerInitCommand(program) {
|
|
39
|
+
program
|
|
40
|
+
.command('init [path]')
|
|
41
|
+
.description('Initialise mast for a project and run the initial index')
|
|
42
|
+
.option('--state-dir <dir>', 'Where to write index state (default: <path>/.mast)')
|
|
43
|
+
.option('--extensions <ext,...>', 'Comma-separated file extensions to index (default: .ts,.tsx,.js,.jsx)')
|
|
44
|
+
.option('--exclude <pattern,...>', 'Comma-separated glob patterns to exclude')
|
|
45
|
+
.option('--no-index', 'Create config only; skip initial indexing')
|
|
46
|
+
.action(async (projectPath, opts) => {
|
|
47
|
+
const config = resolveConfig({
|
|
48
|
+
projectRoot: projectPath,
|
|
49
|
+
stateDirOverride: opts.stateDir,
|
|
50
|
+
extensions: parseExtensionsFlag(opts.extensions),
|
|
51
|
+
excludePatterns: parseExcludeFlag(opts.exclude),
|
|
52
|
+
});
|
|
53
|
+
initLockMarkers(config.resolved_state_dir);
|
|
54
|
+
writeStateConfig(config.resolved_state_dir, config);
|
|
55
|
+
process.stdout.write(`Initialised ${config.resolved_state_dir}\n`);
|
|
56
|
+
if (opts.index) {
|
|
57
|
+
const result = await runIndex(config, { incremental: false });
|
|
58
|
+
process.stdout.write(`Indexed ${result.filesIndexed} files, ${result.chunksAdded} chunks in ${result.durationMs}ms` +
|
|
59
|
+
(result.parseErrors > 0 ? ` (${result.parseErrors} parse errors — check stderr)` : '') +
|
|
60
|
+
'\n');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,sFAAsF;AACtF,SAAS,uBAAuB,CAAC,GAAW;IAC1C,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAuB;IACzD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,yDAAyD,CAAC;SACtE,MAAM,CAAC,mBAAmB,EAAE,oDAAoD,CAAC;SACjF,MAAM,CAAC,wBAAwB,EAAE,uEAAuE,CAAC;SACzG,MAAM,CAAC,yBAAyB,EAAE,0CAA0C,CAAC;SAC7E,MAAM,CAAC,YAAY,EAAE,2CAA2C,CAAC;SACjE,MAAM,CAAC,KAAK,EAAE,WAA+B,EAAE,IAK/C,EAAE,EAAE;QACH,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,WAAW,EAAE,WAAW;YACxB,gBAAgB,EAAE,IAAI,CAAC,QAAQ;YAC/B,UAAU,EAAE,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC;YAChD,eAAe,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC;SAChD,CAAC,CAAC;QAEH,eAAe,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC3C,gBAAgB,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;QACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,MAAM,CAAC,kBAAkB,IAAI,CAAC,CAAC;QAEnE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,MAAM,CAAC,YAAY,WAAW,MAAM,CAAC,WAAW,cAAc,MAAM,CAAC,UAAU,IAAI;gBAC9F,CAAC,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,WAAW,+BAA+B,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtF,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/cli/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuBlE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
const HOOKS = [
|
|
4
|
+
{
|
|
5
|
+
name: 'post-commit',
|
|
6
|
+
body: '#!/bin/sh\nmast index --incremental\n',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'post-checkout',
|
|
10
|
+
body: '#!/bin/sh\nmast index --incremental\n',
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
export function registerInstallHooksCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command('install-hooks [path]')
|
|
16
|
+
.description('Install git hooks that keep the index fresh after commits and checkouts')
|
|
17
|
+
.action((projectPath) => {
|
|
18
|
+
const root = resolve(projectPath ?? process.cwd());
|
|
19
|
+
const hooksDir = join(root, '.git', 'hooks');
|
|
20
|
+
if (!existsSync(join(root, '.git'))) {
|
|
21
|
+
process.stderr.write(`mast: no .git directory found at ${root}\n`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
25
|
+
for (const hook of HOOKS) {
|
|
26
|
+
const hookPath = join(hooksDir, hook.name);
|
|
27
|
+
writeFileSync(hookPath, hook.body, { encoding: 'utf-8' });
|
|
28
|
+
// Git requires hooks to be executable.
|
|
29
|
+
chmodSync(hookPath, 0o755);
|
|
30
|
+
process.stdout.write(`Installed ${hookPath}\n`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=install-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../src/cli/install-hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,KAAK,GAAkD;IAC3D;QACE,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,uCAAuC;KAC9C;IACD;QACE,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE,uCAAuC;KAC9C;CACF,CAAC;AAEF,MAAM,UAAU,2BAA2B,CAAC,OAAgB;IAC1D,OAAO;SACJ,OAAO,CAAC,sBAAsB,CAAC;SAC/B,WAAW,CAAC,yEAAyE,CAAC;SACtF,MAAM,CAAC,CAAC,WAA+B,EAAE,EAAE;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAE7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,IAAI,IAAI,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3C,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1D,uCAAuC;YACvC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,IAAI,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/metrics-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4IzC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgE7D"}
|