@wei840222/qmd 2026.8.23
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/CHANGELOG.md +1373 -0
- package/LICENSE +45 -0
- package/README.md +1439 -0
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/bin/qmd +192 -0
- package/dist/ast.d.ts +65 -0
- package/dist/ast.js +334 -0
- package/dist/bench/bench.d.ts +35 -0
- package/dist/bench/bench.js +338 -0
- package/dist/bench/cjk-baseline.d.ts +36 -0
- package/dist/bench/cjk-baseline.js +111 -0
- package/dist/bench/fixture.d.ts +2 -0
- package/dist/bench/fixture.js +84 -0
- package/dist/bench/score.d.ts +38 -0
- package/dist/bench/score.js +107 -0
- package/dist/bench/types.d.ts +110 -0
- package/dist/bench/types.js +8 -0
- package/dist/cli/build-info.json +4 -0
- package/dist/cli/embed-lock.d.ts +24 -0
- package/dist/cli/embed-lock.js +94 -0
- package/dist/cli/embedding-owner.d.ts +10 -0
- package/dist/cli/embedding-owner.js +20 -0
- package/dist/cli/formatter.d.ts +120 -0
- package/dist/cli/formatter.js +355 -0
- package/dist/cli/mcp-pid.d.ts +25 -0
- package/dist/cli/mcp-pid.js +86 -0
- package/dist/cli/qmd.d.ts +72 -0
- package/dist/cli/qmd.js +4806 -0
- package/dist/cli/version.d.ts +42 -0
- package/dist/cli/version.js +80 -0
- package/dist/collections.d.ts +200 -0
- package/dist/collections.js +433 -0
- package/dist/db.d.ts +65 -0
- package/dist/db.js +143 -0
- package/dist/diagnostics.d.ts +62 -0
- package/dist/diagnostics.js +260 -0
- package/dist/embedding/config.d.ts +52 -0
- package/dist/embedding/config.js +229 -0
- package/dist/embedding/identity.d.ts +58 -0
- package/dist/embedding/identity.js +321 -0
- package/dist/embedding/local-identity.d.ts +1 -0
- package/dist/embedding/local-identity.js +15 -0
- package/dist/embedding/local.d.ts +34 -0
- package/dist/embedding/local.js +290 -0
- package/dist/embedding/openai.d.ts +79 -0
- package/dist/embedding/openai.js +477 -0
- package/dist/embedding/owner.d.ts +13 -0
- package/dist/embedding/owner.js +36 -0
- package/dist/embedding/provider.d.ts +68 -0
- package/dist/embedding/provider.js +16 -0
- package/dist/embedding/remote-chunking.d.ts +22 -0
- package/dist/embedding/remote-chunking.js +83 -0
- package/dist/embedding/remote-embedding.d.ts +15 -0
- package/dist/embedding/remote-embedding.js +77 -0
- package/dist/hybrid-llm.d.ts +18 -0
- package/dist/hybrid-llm.js +53 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +418 -0
- package/dist/llm.d.ts +566 -0
- package/dist/llm.js +1847 -0
- package/dist/maintenance.d.ts +33 -0
- package/dist/maintenance.js +52 -0
- package/dist/mcp/origin-guard.d.ts +67 -0
- package/dist/mcp/origin-guard.js +137 -0
- package/dist/mcp/server.d.ts +116 -0
- package/dist/mcp/server.js +919 -0
- package/dist/paths.d.ts +1 -0
- package/dist/paths.js +4 -0
- package/dist/remote-llm.d.ts +52 -0
- package/dist/remote-llm.js +464 -0
- package/dist/search/cjk-analyzer.d.ts +33 -0
- package/dist/search/cjk-analyzer.js +158 -0
- package/dist/search/cjk-index.d.ts +104 -0
- package/dist/search/cjk-index.js +1031 -0
- package/dist/search/jieba-loader.d.ts +23 -0
- package/dist/search/jieba-loader.js +79 -0
- package/dist/search/query-expansion.d.ts +23 -0
- package/dist/search/query-expansion.js +43 -0
- package/dist/search/zh-dict.txt +624013 -0
- package/dist/store.d.ts +1218 -0
- package/dist/store.js +6076 -0
- package/dist/trust.d.ts +152 -0
- package/dist/trust.js +249 -0
- package/package.json +139 -0
- package/scripts/build.mjs +83 -0
- package/scripts/check-package-grammars.mjs +29 -0
- package/scripts/package-smoke.mjs +205 -0
- package/scripts/sync-zh-dict.mjs +187 -0
- package/scripts/test-all.mjs +45 -0
- package/skills/qmd/SKILL.md +324 -0
- package/skills/qmd/references/mcp-setup.md +119 -0
- package/skills/release/SKILL.md +141 -0
- package/skills/release/scripts/install-hooks.sh +38 -0
- package/skills/release/scripts/release-context.sh +129 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build/commit identification for `qmd --version`.
|
|
3
|
+
*
|
|
4
|
+
* The commit is *stamped at build time* (scripts/build.mjs writes
|
|
5
|
+
* build-info.json next to the compiled CLI) rather than discovered at runtime.
|
|
6
|
+
* A published tarball carries no git history of its own, so a runtime lookup
|
|
7
|
+
* can only ever find some *other* repository's HEAD: `git -C <dir> rev-parse`
|
|
8
|
+
* walks up the tree, and a global install under a git-managed prefix (e.g.
|
|
9
|
+
* Homebrew's /opt/homebrew) reported that prefix's commit as qmd's.
|
|
10
|
+
*
|
|
11
|
+
* Running from a source checkout has no stamp, so the git lookup remains as a
|
|
12
|
+
* fallback — but only after confirming the enclosing repository is the package
|
|
13
|
+
* we are actually running from.
|
|
14
|
+
*/
|
|
15
|
+
/** Written next to the compiled CLI (dist/cli/) by scripts/build.mjs. */
|
|
16
|
+
export declare const BUILD_INFO_FILENAME = "build-info.json";
|
|
17
|
+
export type BuildInfo = {
|
|
18
|
+
commit: string;
|
|
19
|
+
builtAt?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Read the commit stamped into this build, or "" when there is none.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately looks beside the running script rather than in the package's
|
|
25
|
+
* dist/ directory: a source run (src/cli/) must not pick up the stamp left by
|
|
26
|
+
* an earlier, possibly unrelated, build in dist/.
|
|
27
|
+
*/
|
|
28
|
+
export declare function readStampedCommit(scriptDir: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Short HEAD of the checkout we are running from, or "" when we are not
|
|
31
|
+
* running from one.
|
|
32
|
+
*
|
|
33
|
+
* The guard is the whole point: an enclosing repository is only qmd's if its
|
|
34
|
+
* top level *is* this package's root. Without that check, any install nested
|
|
35
|
+
* inside an unrelated repository reports that repository's HEAD.
|
|
36
|
+
*/
|
|
37
|
+
export declare function gitCommitForCheckout(scriptDir: string, packageRoot: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* The commit to report for this invocation: the build stamp when there is one,
|
|
40
|
+
* otherwise the verified checkout HEAD, otherwise nothing.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveCommit(scriptDir: string, packageRoot: string): string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build/commit identification for `qmd --version`.
|
|
3
|
+
*
|
|
4
|
+
* The commit is *stamped at build time* (scripts/build.mjs writes
|
|
5
|
+
* build-info.json next to the compiled CLI) rather than discovered at runtime.
|
|
6
|
+
* A published tarball carries no git history of its own, so a runtime lookup
|
|
7
|
+
* can only ever find some *other* repository's HEAD: `git -C <dir> rev-parse`
|
|
8
|
+
* walks up the tree, and a global install under a git-managed prefix (e.g.
|
|
9
|
+
* Homebrew's /opt/homebrew) reported that prefix's commit as qmd's.
|
|
10
|
+
*
|
|
11
|
+
* Running from a source checkout has no stamp, so the git lookup remains as a
|
|
12
|
+
* fallback — but only after confirming the enclosing repository is the package
|
|
13
|
+
* we are actually running from.
|
|
14
|
+
*/
|
|
15
|
+
import { execFileSync } from "node:child_process";
|
|
16
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
/** Written next to the compiled CLI (dist/cli/) by scripts/build.mjs. */
|
|
19
|
+
export const BUILD_INFO_FILENAME = "build-info.json";
|
|
20
|
+
/**
|
|
21
|
+
* Read the commit stamped into this build, or "" when there is none.
|
|
22
|
+
*
|
|
23
|
+
* Deliberately looks beside the running script rather than in the package's
|
|
24
|
+
* dist/ directory: a source run (src/cli/) must not pick up the stamp left by
|
|
25
|
+
* an earlier, possibly unrelated, build in dist/.
|
|
26
|
+
*/
|
|
27
|
+
export function readStampedCommit(scriptDir) {
|
|
28
|
+
try {
|
|
29
|
+
const raw = readFileSync(join(scriptDir, BUILD_INFO_FILENAME), "utf-8");
|
|
30
|
+
const info = JSON.parse(raw);
|
|
31
|
+
return typeof info.commit === "string" ? info.commit : "";
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// No stamp (source run), unreadable, or malformed — fall through.
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function git(args, cwd) {
|
|
39
|
+
// execFileSync, not execSync: no shell, so a path containing spaces or shell
|
|
40
|
+
// metacharacters is passed through intact instead of silently failing.
|
|
41
|
+
return execFileSync("git", args, {
|
|
42
|
+
cwd,
|
|
43
|
+
encoding: "utf-8",
|
|
44
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
45
|
+
}).trim();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Short HEAD of the checkout we are running from, or "" when we are not
|
|
49
|
+
* running from one.
|
|
50
|
+
*
|
|
51
|
+
* The guard is the whole point: an enclosing repository is only qmd's if its
|
|
52
|
+
* top level *is* this package's root. Without that check, any install nested
|
|
53
|
+
* inside an unrelated repository reports that repository's HEAD.
|
|
54
|
+
*/
|
|
55
|
+
export function gitCommitForCheckout(scriptDir, packageRoot) {
|
|
56
|
+
try {
|
|
57
|
+
const top = git(["rev-parse", "--show-toplevel"], scriptDir);
|
|
58
|
+
if (realpathSync(top) !== realpathSync(packageRoot))
|
|
59
|
+
return "";
|
|
60
|
+
const commit = git(["rev-parse", "--short", "HEAD"], top);
|
|
61
|
+
if (!commit)
|
|
62
|
+
return "";
|
|
63
|
+
// Same "-dirty" marker scripts/build.mjs stamps: running edited sources is
|
|
64
|
+
// not the commit it names, and that distinction is the whole point of
|
|
65
|
+
// printing a commit at all.
|
|
66
|
+
const dirty = git(["status", "--porcelain"], top);
|
|
67
|
+
return dirty ? `${commit}-dirty` : commit;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Not a git repo, git not installed, or an unborn branch.
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The commit to report for this invocation: the build stamp when there is one,
|
|
76
|
+
* otherwise the verified checkout HEAD, otherwise nothing.
|
|
77
|
+
*/
|
|
78
|
+
export function resolveCommit(scriptDir, packageRoot) {
|
|
79
|
+
return readStampedCommit(scriptDir) || gitCommitForCheckout(scriptDir, packageRoot);
|
|
80
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections configuration management
|
|
3
|
+
*
|
|
4
|
+
* This module manages the YAML-based collection configuration at ~/.config/qmd/index.yml.
|
|
5
|
+
* Collections define which directories to index and their associated contexts.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Context definitions for a collection
|
|
9
|
+
* Key is path prefix (e.g., "/", "/2024", "/Board of Directors")
|
|
10
|
+
* Value is the context description
|
|
11
|
+
*/
|
|
12
|
+
export type ContextMap = Record<string, string>;
|
|
13
|
+
/**
|
|
14
|
+
* A single collection configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface Collection {
|
|
17
|
+
path: string;
|
|
18
|
+
pattern: string;
|
|
19
|
+
ignore?: string[];
|
|
20
|
+
context?: ContextMap;
|
|
21
|
+
update?: string;
|
|
22
|
+
includeByDefault?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Model configuration for embedding, reranking, and generation
|
|
26
|
+
*/
|
|
27
|
+
export interface ModelsConfig {
|
|
28
|
+
embed?: string;
|
|
29
|
+
embed_url?: string;
|
|
30
|
+
embed_base_url?: string;
|
|
31
|
+
embed_api_url?: string;
|
|
32
|
+
embed_api_model?: string;
|
|
33
|
+
embed_api_key?: string;
|
|
34
|
+
embed_dimension?: number;
|
|
35
|
+
rerank?: string;
|
|
36
|
+
generate?: string;
|
|
37
|
+
generate_url?: string;
|
|
38
|
+
generate_base_url?: string;
|
|
39
|
+
generate_api_url?: string;
|
|
40
|
+
generate_api_model?: string;
|
|
41
|
+
generate_api_key?: string;
|
|
42
|
+
rerank_url?: string;
|
|
43
|
+
rerank_base_url?: string;
|
|
44
|
+
rerank_api_url?: string;
|
|
45
|
+
rerank_api_model?: string;
|
|
46
|
+
rerank_api_key?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The complete configuration file structure
|
|
50
|
+
*/
|
|
51
|
+
export interface CollectionConfig {
|
|
52
|
+
global_context?: string;
|
|
53
|
+
editor_uri?: string;
|
|
54
|
+
editor_uri_template?: string;
|
|
55
|
+
editorUri?: string;
|
|
56
|
+
"editor-uri"?: string;
|
|
57
|
+
collections: Record<string, Collection>;
|
|
58
|
+
models?: ModelsConfig;
|
|
59
|
+
dictionary?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Collection with its name (for return values)
|
|
63
|
+
*/
|
|
64
|
+
export interface NamedCollection extends Collection {
|
|
65
|
+
name: string;
|
|
66
|
+
}
|
|
67
|
+
export type CollectionConfigSource = {
|
|
68
|
+
type: "file";
|
|
69
|
+
path?: string;
|
|
70
|
+
} | {
|
|
71
|
+
type: "inline";
|
|
72
|
+
config: CollectionConfig;
|
|
73
|
+
};
|
|
74
|
+
export declare function createCollectionConfigSource(source?: {
|
|
75
|
+
configPath?: string;
|
|
76
|
+
config?: CollectionConfig;
|
|
77
|
+
}): CollectionConfigSource;
|
|
78
|
+
export type ConfigWriteStage = "before-temp-write" | "before-rename";
|
|
79
|
+
/** @internal Test-only fault injection for crash-safety verification. */
|
|
80
|
+
export declare function setConfigWriteFaultInjectorForTests(injector?: (stage: ConfigWriteStage) => void): void;
|
|
81
|
+
/**
|
|
82
|
+
* Set the config source for SDK mode.
|
|
83
|
+
* - File path: load/save from a specific YAML file
|
|
84
|
+
* - Inline config: use an in-memory CollectionConfig (saveConfig updates in place, no file I/O)
|
|
85
|
+
* - undefined: reset to default file-based config
|
|
86
|
+
*/
|
|
87
|
+
export declare function setConfigSource(source?: {
|
|
88
|
+
configPath?: string;
|
|
89
|
+
config?: CollectionConfig;
|
|
90
|
+
}): void;
|
|
91
|
+
/**
|
|
92
|
+
* Set the current index name for config file lookup
|
|
93
|
+
* Config file will be ~/.config/qmd/{indexName}.yml
|
|
94
|
+
*/
|
|
95
|
+
export declare function setConfigIndexName(name: string): void;
|
|
96
|
+
export declare function getConfigDir(): string;
|
|
97
|
+
/**
|
|
98
|
+
* Find a project-local QMD config by walking upward from startDir.
|
|
99
|
+
* The local config lives at .qmd/index.yaml or .qmd/index.yml and,
|
|
100
|
+
* when used by the CLI, keeps both config and index DB writes inside
|
|
101
|
+
* the project instead of the global ~/.config / ~/.cache locations.
|
|
102
|
+
*/
|
|
103
|
+
export declare function findLocalConfigPath(startDir?: string): string | undefined;
|
|
104
|
+
/** Return the local SQLite index path paired with a local .qmd/index.yaml file. */
|
|
105
|
+
export declare function getLocalDbPath(configPath: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* Load configuration from the configured source.
|
|
108
|
+
* - Inline config: returns the in-memory object directly
|
|
109
|
+
* - File-based: reads from YAML file (default ~/.config/qmd/index.yml)
|
|
110
|
+
* Returns empty config if file doesn't exist
|
|
111
|
+
*/
|
|
112
|
+
export declare function loadConfig(source?: CollectionConfigSource): CollectionConfig;
|
|
113
|
+
/**
|
|
114
|
+
* Save configuration to the configured source.
|
|
115
|
+
* - Inline config: updates the in-memory object (no file I/O)
|
|
116
|
+
* - File-based: writes to YAML file (default ~/.config/qmd/index.yml)
|
|
117
|
+
*/
|
|
118
|
+
export declare function saveConfig(config: CollectionConfig, source?: CollectionConfigSource): void;
|
|
119
|
+
/**
|
|
120
|
+
* Get a specific collection by name
|
|
121
|
+
* Returns null if not found
|
|
122
|
+
*/
|
|
123
|
+
export declare function getCollection(name: string): NamedCollection | null;
|
|
124
|
+
/**
|
|
125
|
+
* List all collections
|
|
126
|
+
*/
|
|
127
|
+
export declare function listCollections(): NamedCollection[];
|
|
128
|
+
/**
|
|
129
|
+
* Get collections that are included by default in queries
|
|
130
|
+
*/
|
|
131
|
+
export declare function getDefaultCollections(): NamedCollection[];
|
|
132
|
+
/**
|
|
133
|
+
* Get collection names that are included by default
|
|
134
|
+
*/
|
|
135
|
+
export declare function getDefaultCollectionNames(): string[];
|
|
136
|
+
/**
|
|
137
|
+
* Update a collection's settings
|
|
138
|
+
*/
|
|
139
|
+
export declare function updateCollectionSettings(name: string, settings: {
|
|
140
|
+
update?: string | null;
|
|
141
|
+
includeByDefault?: boolean;
|
|
142
|
+
}): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Add or update a collection
|
|
145
|
+
*/
|
|
146
|
+
export declare function addCollection(name: string, path: string, pattern?: string, ignore?: string[], source?: CollectionConfigSource): void;
|
|
147
|
+
/**
|
|
148
|
+
* Remove a collection
|
|
149
|
+
*/
|
|
150
|
+
export declare function removeCollection(name: string, source?: CollectionConfigSource): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Rename a collection
|
|
153
|
+
*/
|
|
154
|
+
export declare function renameCollection(oldName: string, newName: string, source?: CollectionConfigSource): boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Get global context
|
|
157
|
+
*/
|
|
158
|
+
export declare function getGlobalContext(): string | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Set global context
|
|
161
|
+
*/
|
|
162
|
+
export declare function setGlobalContext(context: string | undefined, source?: CollectionConfigSource): void;
|
|
163
|
+
/**
|
|
164
|
+
* Get all contexts for a collection
|
|
165
|
+
*/
|
|
166
|
+
export declare function getContexts(collectionName: string): ContextMap | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Add or update a context for a specific path in a collection
|
|
169
|
+
*/
|
|
170
|
+
export declare function addContext(collectionName: string, pathPrefix: string, contextText: string, source?: CollectionConfigSource): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Remove a context from a collection
|
|
173
|
+
*/
|
|
174
|
+
export declare function removeContext(collectionName: string, pathPrefix: string, source?: CollectionConfigSource): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* List all contexts across all collections
|
|
177
|
+
*/
|
|
178
|
+
export declare function listAllContexts(): Array<{
|
|
179
|
+
collection: string;
|
|
180
|
+
path: string;
|
|
181
|
+
context: string;
|
|
182
|
+
}>;
|
|
183
|
+
/**
|
|
184
|
+
* Find best matching context for a given collection and path
|
|
185
|
+
* Returns the most specific matching context (longest path prefix match)
|
|
186
|
+
*/
|
|
187
|
+
export declare function findContextForPath(collectionName: string, filePath: string): string | undefined;
|
|
188
|
+
/**
|
|
189
|
+
* Get the config file path (useful for error messages)
|
|
190
|
+
*/
|
|
191
|
+
export declare function getConfigPath(): string;
|
|
192
|
+
/**
|
|
193
|
+
* Check if config file exists
|
|
194
|
+
*/
|
|
195
|
+
export declare function configExists(): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Validate a collection name
|
|
198
|
+
* Collection names must be valid and not contain special characters
|
|
199
|
+
*/
|
|
200
|
+
export declare function isValidCollectionName(name: string): boolean;
|