@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.
Files changed (94) hide show
  1. package/CHANGELOG.md +1373 -0
  2. package/LICENSE +45 -0
  3. package/README.md +1439 -0
  4. package/THIRD_PARTY_NOTICES.md +31 -0
  5. package/bin/qmd +192 -0
  6. package/dist/ast.d.ts +65 -0
  7. package/dist/ast.js +334 -0
  8. package/dist/bench/bench.d.ts +35 -0
  9. package/dist/bench/bench.js +338 -0
  10. package/dist/bench/cjk-baseline.d.ts +36 -0
  11. package/dist/bench/cjk-baseline.js +111 -0
  12. package/dist/bench/fixture.d.ts +2 -0
  13. package/dist/bench/fixture.js +84 -0
  14. package/dist/bench/score.d.ts +38 -0
  15. package/dist/bench/score.js +107 -0
  16. package/dist/bench/types.d.ts +110 -0
  17. package/dist/bench/types.js +8 -0
  18. package/dist/cli/build-info.json +4 -0
  19. package/dist/cli/embed-lock.d.ts +24 -0
  20. package/dist/cli/embed-lock.js +94 -0
  21. package/dist/cli/embedding-owner.d.ts +10 -0
  22. package/dist/cli/embedding-owner.js +20 -0
  23. package/dist/cli/formatter.d.ts +120 -0
  24. package/dist/cli/formatter.js +355 -0
  25. package/dist/cli/mcp-pid.d.ts +25 -0
  26. package/dist/cli/mcp-pid.js +86 -0
  27. package/dist/cli/qmd.d.ts +72 -0
  28. package/dist/cli/qmd.js +4806 -0
  29. package/dist/cli/version.d.ts +42 -0
  30. package/dist/cli/version.js +80 -0
  31. package/dist/collections.d.ts +200 -0
  32. package/dist/collections.js +433 -0
  33. package/dist/db.d.ts +65 -0
  34. package/dist/db.js +143 -0
  35. package/dist/diagnostics.d.ts +62 -0
  36. package/dist/diagnostics.js +260 -0
  37. package/dist/embedding/config.d.ts +52 -0
  38. package/dist/embedding/config.js +229 -0
  39. package/dist/embedding/identity.d.ts +58 -0
  40. package/dist/embedding/identity.js +321 -0
  41. package/dist/embedding/local-identity.d.ts +1 -0
  42. package/dist/embedding/local-identity.js +15 -0
  43. package/dist/embedding/local.d.ts +34 -0
  44. package/dist/embedding/local.js +290 -0
  45. package/dist/embedding/openai.d.ts +79 -0
  46. package/dist/embedding/openai.js +477 -0
  47. package/dist/embedding/owner.d.ts +13 -0
  48. package/dist/embedding/owner.js +36 -0
  49. package/dist/embedding/provider.d.ts +68 -0
  50. package/dist/embedding/provider.js +16 -0
  51. package/dist/embedding/remote-chunking.d.ts +22 -0
  52. package/dist/embedding/remote-chunking.js +83 -0
  53. package/dist/embedding/remote-embedding.d.ts +15 -0
  54. package/dist/embedding/remote-embedding.js +77 -0
  55. package/dist/hybrid-llm.d.ts +18 -0
  56. package/dist/hybrid-llm.js +53 -0
  57. package/dist/index.d.ts +244 -0
  58. package/dist/index.js +418 -0
  59. package/dist/llm.d.ts +566 -0
  60. package/dist/llm.js +1847 -0
  61. package/dist/maintenance.d.ts +33 -0
  62. package/dist/maintenance.js +52 -0
  63. package/dist/mcp/origin-guard.d.ts +67 -0
  64. package/dist/mcp/origin-guard.js +137 -0
  65. package/dist/mcp/server.d.ts +116 -0
  66. package/dist/mcp/server.js +919 -0
  67. package/dist/paths.d.ts +1 -0
  68. package/dist/paths.js +4 -0
  69. package/dist/remote-llm.d.ts +52 -0
  70. package/dist/remote-llm.js +464 -0
  71. package/dist/search/cjk-analyzer.d.ts +33 -0
  72. package/dist/search/cjk-analyzer.js +158 -0
  73. package/dist/search/cjk-index.d.ts +104 -0
  74. package/dist/search/cjk-index.js +1031 -0
  75. package/dist/search/jieba-loader.d.ts +23 -0
  76. package/dist/search/jieba-loader.js +79 -0
  77. package/dist/search/query-expansion.d.ts +23 -0
  78. package/dist/search/query-expansion.js +43 -0
  79. package/dist/search/zh-dict.txt +624013 -0
  80. package/dist/store.d.ts +1218 -0
  81. package/dist/store.js +6076 -0
  82. package/dist/trust.d.ts +152 -0
  83. package/dist/trust.js +249 -0
  84. package/package.json +139 -0
  85. package/scripts/build.mjs +83 -0
  86. package/scripts/check-package-grammars.mjs +29 -0
  87. package/scripts/package-smoke.mjs +205 -0
  88. package/scripts/sync-zh-dict.mjs +187 -0
  89. package/scripts/test-all.mjs +45 -0
  90. package/skills/qmd/SKILL.md +324 -0
  91. package/skills/qmd/references/mcp-setup.md +119 -0
  92. package/skills/release/SKILL.md +141 -0
  93. package/skills/release/scripts/install-hooks.sh +38 -0
  94. 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;