@unbrained/pm-cli 2026.5.11 → 2026.5.14

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 (171) hide show
  1. package/AGENTS.md +3 -116
  2. package/CHANGELOG.md +18 -0
  3. package/PRD.md +18 -39
  4. package/README.md +8 -5
  5. package/dist/cli/commander-usage.js +27 -0
  6. package/dist/cli/commander-usage.js.map +1 -1
  7. package/dist/cli/commands/activity.js +19 -4
  8. package/dist/cli/commands/activity.js.map +1 -1
  9. package/dist/cli/commands/calendar.js +5 -2
  10. package/dist/cli/commands/calendar.js.map +1 -1
  11. package/dist/cli/commands/contracts.js +63 -19
  12. package/dist/cli/commands/contracts.js.map +1 -1
  13. package/dist/cli/commands/create.js +58 -3
  14. package/dist/cli/commands/create.js.map +1 -1
  15. package/dist/cli/commands/extension.d.ts +14 -3
  16. package/dist/cli/commands/extension.js +481 -95
  17. package/dist/cli/commands/extension.js.map +1 -1
  18. package/dist/cli/commands/index.d.ts +1 -8
  19. package/dist/cli/commands/index.js +1 -8
  20. package/dist/cli/commands/index.js.map +1 -1
  21. package/dist/cli/commands/reindex.d.ts +8 -0
  22. package/dist/cli/commands/reindex.js +96 -23
  23. package/dist/cli/commands/reindex.js.map +1 -1
  24. package/dist/cli/commands/search.js +51 -25
  25. package/dist/cli/commands/search.js.map +1 -1
  26. package/dist/cli/commands/test.js +14 -6
  27. package/dist/cli/commands/test.js.map +1 -1
  28. package/dist/cli/commands/upgrade.d.ts +63 -0
  29. package/dist/cli/commands/upgrade.js +260 -0
  30. package/dist/cli/commands/upgrade.js.map +1 -0
  31. package/dist/cli/guide-topics.js +18 -16
  32. package/dist/cli/guide-topics.js.map +1 -1
  33. package/dist/cli/help-content.js +57 -18
  34. package/dist/cli/help-content.js.map +1 -1
  35. package/dist/cli/main.js +73 -7
  36. package/dist/cli/main.js.map +1 -1
  37. package/dist/cli/register-list-query.js +24 -142
  38. package/dist/cli/register-list-query.js.map +1 -1
  39. package/dist/cli/register-mutation.js +49 -257
  40. package/dist/cli/register-mutation.js.map +1 -1
  41. package/dist/cli/register-operations.js +29 -198
  42. package/dist/cli/register-operations.js.map +1 -1
  43. package/dist/cli/register-setup.js +181 -204
  44. package/dist/cli/register-setup.js.map +1 -1
  45. package/dist/cli/registration-helpers.d.ts +2 -2
  46. package/dist/cli/registration-helpers.js +1 -19
  47. package/dist/cli/registration-helpers.js.map +1 -1
  48. package/dist/core/extensions/loader.js +7 -1
  49. package/dist/core/extensions/loader.js.map +1 -1
  50. package/dist/core/packages/manifest.d.ts +38 -0
  51. package/dist/core/packages/manifest.js +221 -0
  52. package/dist/core/packages/manifest.js.map +1 -0
  53. package/dist/core/search/embedding-batches.d.ts +13 -1
  54. package/dist/core/search/embedding-batches.js +19 -1
  55. package/dist/core/search/embedding-batches.js.map +1 -1
  56. package/dist/core/store/front-matter-cache.d.ts +8 -1
  57. package/dist/core/store/front-matter-cache.js +20 -11
  58. package/dist/core/store/front-matter-cache.js.map +1 -1
  59. package/dist/mcp/server.d.ts +8 -0
  60. package/dist/mcp/server.js +100 -43
  61. package/dist/mcp/server.js.map +1 -1
  62. package/dist/sdk/cli-contracts/commander-mutation-options.d.ts +7 -0
  63. package/dist/sdk/cli-contracts/commander-mutation-options.js +477 -0
  64. package/dist/sdk/cli-contracts/commander-mutation-options.js.map +1 -0
  65. package/dist/sdk/cli-contracts/commander-types.d.ts +21 -0
  66. package/dist/sdk/cli-contracts/commander-types.js +92 -0
  67. package/dist/sdk/cli-contracts/commander-types.js.map +1 -0
  68. package/dist/sdk/cli-contracts.d.ts +22 -32
  69. package/dist/sdk/cli-contracts.js +155 -296
  70. package/dist/sdk/cli-contracts.js.map +1 -1
  71. package/dist/sdk/index.d.ts +2 -0
  72. package/dist/sdk/index.js +2 -0
  73. package/dist/sdk/index.js.map +1 -1
  74. package/dist/sdk/runtime.d.ts +29 -0
  75. package/dist/sdk/runtime.js +28 -0
  76. package/dist/sdk/runtime.js.map +1 -0
  77. package/docs/ARCHITECTURE.md +1 -1
  78. package/docs/COMMANDS.md +17 -1
  79. package/docs/EXTENSIONS.md +169 -61
  80. package/docs/QUICKSTART.md +11 -2
  81. package/docs/README.md +4 -6
  82. package/docs/RELEASING.md +4 -2
  83. package/docs/SDK.md +79 -438
  84. package/package.json +6 -23
  85. package/packages/pm-beads/README.md +10 -0
  86. package/packages/pm-beads/extensions/beads/index.js +113 -0
  87. package/{.agents/pm/extensions/beads/index.js → packages/pm-beads/extensions/beads/index.ts} +42 -20
  88. package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.js +2 -17
  89. package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.ts +41 -18
  90. package/packages/pm-beads/package.json +50 -0
  91. package/packages/pm-calendar/README.md +13 -0
  92. package/packages/pm-calendar/extensions/calendar/index.js +56 -0
  93. package/packages/pm-calendar/extensions/calendar/index.ts +62 -0
  94. package/packages/pm-calendar/extensions/calendar/manifest.json +7 -0
  95. package/packages/pm-calendar/extensions/calendar/runtime.js +95 -0
  96. package/packages/pm-calendar/extensions/calendar/runtime.ts +104 -0
  97. package/packages/pm-calendar/package.json +51 -0
  98. package/packages/pm-governance-audit/README.md +23 -0
  99. package/packages/pm-governance-audit/extensions/governance-audit/index.js +117 -0
  100. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +118 -0
  101. package/packages/pm-governance-audit/extensions/governance-audit/manifest.json +7 -0
  102. package/packages/pm-governance-audit/extensions/governance-audit/runtime.js +159 -0
  103. package/packages/pm-governance-audit/extensions/governance-audit/runtime.ts +176 -0
  104. package/packages/pm-governance-audit/package.json +52 -0
  105. package/packages/pm-guide-shell/README.md +23 -0
  106. package/packages/pm-guide-shell/extensions/guide-shell/index.js +76 -0
  107. package/packages/pm-guide-shell/extensions/guide-shell/index.ts +81 -0
  108. package/packages/pm-guide-shell/extensions/guide-shell/manifest.json +7 -0
  109. package/packages/pm-guide-shell/extensions/guide-shell/runtime.js +263 -0
  110. package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +327 -0
  111. package/packages/pm-guide-shell/package.json +52 -0
  112. package/packages/pm-linked-test-adapters/README.md +24 -0
  113. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.js +101 -0
  114. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +102 -0
  115. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/manifest.json +7 -0
  116. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.js +142 -0
  117. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.ts +173 -0
  118. package/packages/pm-linked-test-adapters/package.json +53 -0
  119. package/packages/pm-search-advanced/README.md +27 -0
  120. package/packages/pm-search-advanced/extensions/search-advanced/index.js +93 -0
  121. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +94 -0
  122. package/packages/pm-search-advanced/extensions/search-advanced/manifest.json +7 -0
  123. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +120 -0
  124. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +144 -0
  125. package/packages/pm-search-advanced/package.json +54 -0
  126. package/packages/pm-templates/README.md +20 -0
  127. package/packages/pm-templates/extensions/templates/index.js +101 -0
  128. package/packages/pm-templates/extensions/templates/index.ts +109 -0
  129. package/packages/pm-templates/extensions/templates/manifest.json +7 -0
  130. package/packages/pm-templates/extensions/templates/runtime.js +226 -0
  131. package/packages/pm-templates/extensions/templates/runtime.ts +283 -0
  132. package/packages/pm-templates/package.json +50 -0
  133. package/packages/pm-todos/README.md +11 -0
  134. package/packages/pm-todos/extensions/todos/index.js +130 -0
  135. package/{.agents/pm/extensions/todos/index.js → packages/pm-todos/extensions/todos/index.ts} +47 -23
  136. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.js +3 -18
  137. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.ts +42 -20
  138. package/packages/pm-todos/package.json +51 -0
  139. package/plugins/pm-cli-claude/README.md +1 -2
  140. package/plugins/pm-cli-claude/hooks/session-start.mjs +4 -55
  141. package/plugins/pm-cli-claude/scripts/pm-mcp-server.mjs +4 -2
  142. package/plugins/pm-cli-codex/scripts/pm-mcp-server.mjs +4 -2
  143. package/.agents/pm/extensions/.managed-extensions.json +0 -42
  144. package/.agents/skills/HARNESS_COMPATIBILITY.md +0 -45
  145. package/.agents/skills/README.md +0 -21
  146. package/.agents/skills/pm-developer/SKILL.md +0 -73
  147. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +0 -48
  148. package/.agents/skills/pm-developer/references/PROMPTS.md +0 -17
  149. package/.agents/skills/pm-extensions/SKILL.md +0 -57
  150. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +0 -40
  151. package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +0 -25
  152. package/.agents/skills/pm-sdk/SKILL.md +0 -50
  153. package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +0 -31
  154. package/.agents/skills/pm-sdk/references/PROMPTS.md +0 -13
  155. package/.agents/skills/pm-user/SKILL.md +0 -59
  156. package/.agents/skills/pm-user/references/PROMPTS.md +0 -17
  157. package/.agents/skills/pm-user/references/WORKFLOWS.md +0 -35
  158. package/.pi/README.md +0 -35
  159. package/.pi/agents/pm-triage-agent.md +0 -19
  160. package/.pi/agents/pm-verification-agent.md +0 -21
  161. package/.pi/chains/pm-native-delivery.chain.md +0 -11
  162. package/.pi/extensions/pm-cli/index.js +0 -387
  163. package/.pi/prompts/pm-workflow.md +0 -5
  164. package/.pi/skills/pm-native/SKILL.md +0 -44
  165. package/.pi/skills/pm-release/SKILL.md +0 -35
  166. package/dist/pi/native.d.ts +0 -5
  167. package/dist/pi/native.js +0 -236
  168. package/dist/pi/native.js.map +0 -1
  169. package/docs/PI_PACKAGE.md +0 -141
  170. /package/{.agents/pm → packages/pm-beads}/extensions/beads/manifest.json +0 -0
  171. /package/{.agents/pm → packages/pm-todos}/extensions/todos/manifest.json +0 -0
@@ -0,0 +1,38 @@
1
+ export declare const PM_PACKAGE_RESOURCE_KINDS: readonly ["extensions", "docs", "examples"];
2
+ export type PmPackageResourceKind = (typeof PM_PACKAGE_RESOURCE_KINDS)[number];
3
+ export type PmPackageResourceMap = Partial<Record<PmPackageResourceKind, string[]>>;
4
+ export interface PmPackageCatalogLinkMap {
5
+ docs?: string;
6
+ npm?: string;
7
+ repository?: string;
8
+ report?: string;
9
+ }
10
+ export interface PmPackageCatalogMediaMap {
11
+ image?: string;
12
+ video?: string;
13
+ }
14
+ export interface PmPackageCatalogMetadata {
15
+ display_name?: string;
16
+ category?: string;
17
+ summary?: string;
18
+ links?: PmPackageCatalogLinkMap;
19
+ media?: PmPackageCatalogMediaMap;
20
+ tags?: string[];
21
+ }
22
+ export interface PmPackageManifest {
23
+ source: "pm" | "convention";
24
+ package_json_path?: string;
25
+ package_name?: string;
26
+ package_version?: string;
27
+ package_description?: string;
28
+ package_keywords?: string[];
29
+ package_homepage?: string;
30
+ package_repository_url?: string;
31
+ package_bugs_url?: string;
32
+ aliases?: string[];
33
+ resources: PmPackageResourceMap;
34
+ catalog?: PmPackageCatalogMetadata;
35
+ }
36
+ export declare const PM_PACKAGE_CONVENTIONAL_RESOURCE_ROOTS: Readonly<Record<PmPackageResourceKind, readonly string[]>>;
37
+ export declare function readPmPackageManifest(packageRoot: string): Promise<PmPackageManifest>;
38
+ export declare function collectPackageExtensionDirectories(packageRoot: string): Promise<string[]>;
@@ -0,0 +1,221 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { pathExists } from "../fs/fs-utils.js";
4
+ import { EXIT_CODE } from "../shared/constants.js";
5
+ import { PmCliError } from "../shared/errors.js";
6
+ export const PM_PACKAGE_RESOURCE_KINDS = [
7
+ "extensions",
8
+ "docs",
9
+ "examples",
10
+ ];
11
+ export const PM_PACKAGE_CONVENTIONAL_RESOURCE_ROOTS = Object.freeze({
12
+ extensions: Object.freeze([
13
+ ".agents/pm/extensions",
14
+ "extensions",
15
+ ".custom/pm-extensions",
16
+ ".custom/pm-extension",
17
+ ]),
18
+ docs: Object.freeze([
19
+ "docs",
20
+ "documentation",
21
+ ]),
22
+ examples: Object.freeze([
23
+ "examples",
24
+ "docs/examples",
25
+ ]),
26
+ });
27
+ function isKnownPackageResourceKind(value) {
28
+ return PM_PACKAGE_RESOURCE_KINDS.includes(value);
29
+ }
30
+ function normalizePackageResourceEntries(kind, raw) {
31
+ if (raw === undefined || raw === null) {
32
+ return [];
33
+ }
34
+ const entries = Array.isArray(raw) ? raw : [raw];
35
+ const normalized = [];
36
+ for (const entry of entries) {
37
+ if (typeof entry !== "string" || entry.trim().length === 0) {
38
+ throw new PmCliError(`Package manifest field pm.${kind} must contain string paths.`, EXIT_CODE.USAGE);
39
+ }
40
+ normalized.push(entry.trim());
41
+ }
42
+ return [...new Set(normalized)].sort((left, right) => left.localeCompare(right));
43
+ }
44
+ function normalizePackageResourceMap(raw) {
45
+ if (raw === undefined || raw === null) {
46
+ return {};
47
+ }
48
+ if (typeof raw !== "object" || Array.isArray(raw)) {
49
+ throw new PmCliError("Package manifest field pm must be an object.", EXIT_CODE.USAGE);
50
+ }
51
+ const resources = {};
52
+ const candidate = raw;
53
+ for (const [key, value] of Object.entries(candidate)) {
54
+ if (!isKnownPackageResourceKind(key)) {
55
+ continue;
56
+ }
57
+ const entries = normalizePackageResourceEntries(key, value);
58
+ if (entries.length > 0) {
59
+ resources[key] = entries;
60
+ }
61
+ }
62
+ return resources;
63
+ }
64
+ function readStringField(source, key) {
65
+ const value = source[key];
66
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
67
+ }
68
+ function normalizeStringArray(raw) {
69
+ if (!Array.isArray(raw)) {
70
+ return undefined;
71
+ }
72
+ const values = raw
73
+ .map((value) => typeof value === "string" ? value.trim() : "")
74
+ .filter((value) => value.length > 0);
75
+ return values.length > 0 ? [...new Set(values)].sort((left, right) => left.localeCompare(right)) : undefined;
76
+ }
77
+ function readUrlLikeField(raw) {
78
+ if (typeof raw === "string" && raw.trim().length > 0) {
79
+ return raw.trim();
80
+ }
81
+ if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
82
+ const value = raw.url;
83
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
84
+ }
85
+ return undefined;
86
+ }
87
+ function normalizeCatalogLinks(raw) {
88
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
89
+ return undefined;
90
+ }
91
+ const source = raw;
92
+ const links = {
93
+ docs: readStringField(source, "docs"),
94
+ npm: readStringField(source, "npm"),
95
+ repository: readStringField(source, "repository"),
96
+ report: readStringField(source, "report"),
97
+ };
98
+ return Object.values(links).some((value) => typeof value === "string") ? links : undefined;
99
+ }
100
+ function normalizeCatalogMedia(raw) {
101
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
102
+ return undefined;
103
+ }
104
+ const source = raw;
105
+ const media = {
106
+ image: readStringField(source, "image"),
107
+ video: readStringField(source, "video"),
108
+ };
109
+ return Object.values(media).some((value) => typeof value === "string") ? media : undefined;
110
+ }
111
+ function normalizePackageCatalogMetadata(raw) {
112
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
113
+ return undefined;
114
+ }
115
+ const source = raw;
116
+ const catalog = {
117
+ display_name: readStringField(source, "display_name") ?? readStringField(source, "displayName"),
118
+ category: readStringField(source, "category"),
119
+ summary: readStringField(source, "summary"),
120
+ links: normalizeCatalogLinks(source.links),
121
+ media: normalizeCatalogMedia(source.media),
122
+ tags: normalizeStringArray(source.tags),
123
+ };
124
+ return Object.values(catalog).some((value) => value !== undefined) ? catalog : undefined;
125
+ }
126
+ export async function readPmPackageManifest(packageRoot) {
127
+ const packageJsonPath = path.join(packageRoot, "package.json");
128
+ if (!(await pathExists(packageJsonPath))) {
129
+ return {
130
+ source: "convention",
131
+ resources: {},
132
+ };
133
+ }
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
137
+ }
138
+ catch (error) {
139
+ throw new PmCliError(`Failed to parse package manifest at "${packageJsonPath}": ${String(error)}`, EXIT_CODE.USAGE);
140
+ }
141
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
142
+ throw new PmCliError(`Package manifest at "${packageJsonPath}" must be a JSON object.`, EXIT_CODE.USAGE);
143
+ }
144
+ const packageJson = parsed;
145
+ const pmManifest = packageJson.pm;
146
+ const hasPmManifest = pmManifest !== undefined && pmManifest !== null;
147
+ const pmManifestRecord = typeof pmManifest === "object" && pmManifest !== null && !Array.isArray(pmManifest)
148
+ ? pmManifest
149
+ : {};
150
+ return {
151
+ source: hasPmManifest ? "pm" : "convention",
152
+ package_json_path: packageJsonPath,
153
+ package_name: typeof packageJson.name === "string" ? packageJson.name : undefined,
154
+ package_version: typeof packageJson.version === "string" ? packageJson.version : undefined,
155
+ package_description: typeof packageJson.description === "string" ? packageJson.description : undefined,
156
+ package_keywords: normalizeStringArray(packageJson.keywords),
157
+ package_homepage: typeof packageJson.homepage === "string" ? packageJson.homepage : undefined,
158
+ package_repository_url: readUrlLikeField(packageJson.repository),
159
+ package_bugs_url: readUrlLikeField(packageJson.bugs),
160
+ aliases: normalizeStringArray(pmManifestRecord.aliases),
161
+ resources: normalizePackageResourceMap(pmManifest),
162
+ catalog: normalizePackageCatalogMetadata(pmManifestRecord.catalog),
163
+ };
164
+ }
165
+ function isPathWithinDirectory(directory, targetPath) {
166
+ const relative = path.relative(directory, targetPath);
167
+ if (relative.length === 0) {
168
+ return true;
169
+ }
170
+ return !relative.startsWith("..") && !path.isAbsolute(relative);
171
+ }
172
+ async function listExtensionManifestDirectories(parentDirectory) {
173
+ if (!(await pathExists(parentDirectory))) {
174
+ return [];
175
+ }
176
+ const entries = await fs.readdir(parentDirectory, { withFileTypes: true });
177
+ const candidates = [];
178
+ for (const entry of entries) {
179
+ if (!entry.isDirectory()) {
180
+ continue;
181
+ }
182
+ const directory = path.join(parentDirectory, entry.name);
183
+ if (await pathExists(path.join(directory, "manifest.json"))) {
184
+ candidates.push(directory);
185
+ }
186
+ }
187
+ return candidates.sort((left, right) => left.localeCompare(right));
188
+ }
189
+ export async function collectPackageExtensionDirectories(packageRoot) {
190
+ if (await pathExists(path.join(packageRoot, "manifest.json"))) {
191
+ return [packageRoot];
192
+ }
193
+ const manifest = await readPmPackageManifest(packageRoot);
194
+ const manifestEntries = manifest.resources.extensions ?? [];
195
+ const discovered = new Set();
196
+ for (const entry of manifestEntries) {
197
+ if (entry.includes("*") || entry.startsWith("!")) {
198
+ throw new PmCliError(`Package extension entry "${entry}" uses a glob/exclusion pattern. pm package installs currently require concrete extension paths or directories.`, EXIT_CODE.USAGE);
199
+ }
200
+ const absolute = path.resolve(packageRoot, entry);
201
+ if (!isPathWithinDirectory(packageRoot, absolute)) {
202
+ throw new PmCliError(`Package extension entry "${entry}" resolves outside package root.`, EXIT_CODE.USAGE);
203
+ }
204
+ if (await pathExists(path.join(absolute, "manifest.json"))) {
205
+ discovered.add(absolute);
206
+ continue;
207
+ }
208
+ for (const child of await listExtensionManifestDirectories(absolute)) {
209
+ discovered.add(child);
210
+ }
211
+ }
212
+ if (manifestEntries.length === 0) {
213
+ for (const root of PM_PACKAGE_CONVENTIONAL_RESOURCE_ROOTS.extensions) {
214
+ for (const child of await listExtensionManifestDirectories(path.join(packageRoot, root))) {
215
+ discovered.add(child);
216
+ }
217
+ }
218
+ }
219
+ return [...discovered].sort((left, right) => left.localeCompare(right));
220
+ }
221
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"/","sources":["core/packages/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathExists } from \"../fs/fs-utils.js\";\nimport { EXIT_CODE } from \"../shared/constants.js\";\nimport { PmCliError } from \"../shared/errors.js\";\n\nexport const PM_PACKAGE_RESOURCE_KINDS = [\n \"extensions\",\n \"docs\",\n \"examples\",\n] as const;\n\nexport type PmPackageResourceKind = (typeof PM_PACKAGE_RESOURCE_KINDS)[number];\n\nexport type PmPackageResourceMap = Partial<Record<PmPackageResourceKind, string[]>>;\n\nexport interface PmPackageCatalogLinkMap {\n docs?: string;\n npm?: string;\n repository?: string;\n report?: string;\n}\n\nexport interface PmPackageCatalogMediaMap {\n image?: string;\n video?: string;\n}\n\nexport interface PmPackageCatalogMetadata {\n display_name?: string;\n category?: string;\n summary?: string;\n links?: PmPackageCatalogLinkMap;\n media?: PmPackageCatalogMediaMap;\n tags?: string[];\n}\n\nexport interface PmPackageManifest {\n source: \"pm\" | \"convention\";\n package_json_path?: string;\n package_name?: string;\n package_version?: string;\n package_description?: string;\n package_keywords?: string[];\n package_homepage?: string;\n package_repository_url?: string;\n package_bugs_url?: string;\n aliases?: string[];\n resources: PmPackageResourceMap;\n catalog?: PmPackageCatalogMetadata;\n}\n\nexport const PM_PACKAGE_CONVENTIONAL_RESOURCE_ROOTS: Readonly<Record<PmPackageResourceKind, readonly string[]>> =\n Object.freeze({\n extensions: Object.freeze([\n \".agents/pm/extensions\",\n \"extensions\",\n \".custom/pm-extensions\",\n \".custom/pm-extension\",\n ]),\n docs: Object.freeze([\n \"docs\",\n \"documentation\",\n ]),\n examples: Object.freeze([\n \"examples\",\n \"docs/examples\",\n ]),\n });\n\nfunction isKnownPackageResourceKind(value: string): value is PmPackageResourceKind {\n return (PM_PACKAGE_RESOURCE_KINDS as readonly string[]).includes(value);\n}\n\nfunction normalizePackageResourceEntries(kind: PmPackageResourceKind, raw: unknown): string[] {\n if (raw === undefined || raw === null) {\n return [];\n }\n const entries = Array.isArray(raw) ? raw : [raw];\n const normalized: string[] = [];\n for (const entry of entries) {\n if (typeof entry !== \"string\" || entry.trim().length === 0) {\n throw new PmCliError(`Package manifest field pm.${kind} must contain string paths.`, EXIT_CODE.USAGE);\n }\n normalized.push(entry.trim());\n }\n return [...new Set(normalized)].sort((left, right) => left.localeCompare(right));\n}\n\nfunction normalizePackageResourceMap(raw: unknown): PmPackageResourceMap {\n if (raw === undefined || raw === null) {\n return {};\n }\n if (typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new PmCliError(\"Package manifest field pm must be an object.\", EXIT_CODE.USAGE);\n }\n const resources: PmPackageResourceMap = {};\n const candidate = raw as Record<string, unknown>;\n for (const [key, value] of Object.entries(candidate)) {\n if (!isKnownPackageResourceKind(key)) {\n continue;\n }\n const entries = normalizePackageResourceEntries(key, value);\n if (entries.length > 0) {\n resources[key] = entries;\n }\n }\n return resources;\n}\n\nfunction readStringField(source: Record<string, unknown>, key: string): string | undefined {\n const value = source[key];\n return typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction normalizeStringArray(raw: unknown): string[] | undefined {\n if (!Array.isArray(raw)) {\n return undefined;\n }\n const values = raw\n .map((value) => typeof value === \"string\" ? value.trim() : \"\")\n .filter((value) => value.length > 0);\n return values.length > 0 ? [...new Set(values)].sort((left, right) => left.localeCompare(right)) : undefined;\n}\n\nfunction readUrlLikeField(raw: unknown): string | undefined {\n if (typeof raw === \"string\" && raw.trim().length > 0) {\n return raw.trim();\n }\n if (typeof raw === \"object\" && raw !== null && !Array.isArray(raw)) {\n const value = (raw as Record<string, unknown>).url;\n return typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n }\n return undefined;\n}\n\nfunction normalizeCatalogLinks(raw: unknown): PmPackageCatalogLinkMap | undefined {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return undefined;\n }\n const source = raw as Record<string, unknown>;\n const links: PmPackageCatalogLinkMap = {\n docs: readStringField(source, \"docs\"),\n npm: readStringField(source, \"npm\"),\n repository: readStringField(source, \"repository\"),\n report: readStringField(source, \"report\"),\n };\n return Object.values(links).some((value) => typeof value === \"string\") ? links : undefined;\n}\n\nfunction normalizeCatalogMedia(raw: unknown): PmPackageCatalogMediaMap | undefined {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return undefined;\n }\n const source = raw as Record<string, unknown>;\n const media: PmPackageCatalogMediaMap = {\n image: readStringField(source, \"image\"),\n video: readStringField(source, \"video\"),\n };\n return Object.values(media).some((value) => typeof value === \"string\") ? media : undefined;\n}\n\nfunction normalizePackageCatalogMetadata(raw: unknown): PmPackageCatalogMetadata | undefined {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return undefined;\n }\n const source = raw as Record<string, unknown>;\n const catalog: PmPackageCatalogMetadata = {\n display_name: readStringField(source, \"display_name\") ?? readStringField(source, \"displayName\"),\n category: readStringField(source, \"category\"),\n summary: readStringField(source, \"summary\"),\n links: normalizeCatalogLinks(source.links),\n media: normalizeCatalogMedia(source.media),\n tags: normalizeStringArray(source.tags),\n };\n return Object.values(catalog).some((value) => value !== undefined) ? catalog : undefined;\n}\n\nexport async function readPmPackageManifest(packageRoot: string): Promise<PmPackageManifest> {\n const packageJsonPath = path.join(packageRoot, \"package.json\");\n if (!(await pathExists(packageJsonPath))) {\n return {\n source: \"convention\",\n resources: {},\n };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(await fs.readFile(packageJsonPath, \"utf8\")) as unknown;\n } catch (error: unknown) {\n throw new PmCliError(\n `Failed to parse package manifest at \"${packageJsonPath}\": ${String(error)}`,\n EXIT_CODE.USAGE,\n );\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new PmCliError(`Package manifest at \"${packageJsonPath}\" must be a JSON object.`, EXIT_CODE.USAGE);\n }\n\n const packageJson = parsed as Record<string, unknown>;\n const pmManifest = packageJson.pm;\n const hasPmManifest = pmManifest !== undefined && pmManifest !== null;\n const pmManifestRecord = typeof pmManifest === \"object\" && pmManifest !== null && !Array.isArray(pmManifest)\n ? pmManifest as Record<string, unknown>\n : {};\n return {\n source: hasPmManifest ? \"pm\" : \"convention\",\n package_json_path: packageJsonPath,\n package_name: typeof packageJson.name === \"string\" ? packageJson.name : undefined,\n package_version: typeof packageJson.version === \"string\" ? packageJson.version : undefined,\n package_description: typeof packageJson.description === \"string\" ? packageJson.description : undefined,\n package_keywords: normalizeStringArray(packageJson.keywords),\n package_homepage: typeof packageJson.homepage === \"string\" ? packageJson.homepage : undefined,\n package_repository_url: readUrlLikeField(packageJson.repository),\n package_bugs_url: readUrlLikeField(packageJson.bugs),\n aliases: normalizeStringArray(pmManifestRecord.aliases),\n resources: normalizePackageResourceMap(pmManifest),\n catalog: normalizePackageCatalogMetadata(pmManifestRecord.catalog),\n };\n}\n\nfunction isPathWithinDirectory(directory: string, targetPath: string): boolean {\n const relative = path.relative(directory, targetPath);\n if (relative.length === 0) {\n return true;\n }\n return !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n}\n\nasync function listExtensionManifestDirectories(parentDirectory: string): Promise<string[]> {\n if (!(await pathExists(parentDirectory))) {\n return [];\n }\n const entries = await fs.readdir(parentDirectory, { withFileTypes: true });\n const candidates: string[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n const directory = path.join(parentDirectory, entry.name);\n if (await pathExists(path.join(directory, \"manifest.json\"))) {\n candidates.push(directory);\n }\n }\n return candidates.sort((left, right) => left.localeCompare(right));\n}\n\nexport async function collectPackageExtensionDirectories(packageRoot: string): Promise<string[]> {\n if (await pathExists(path.join(packageRoot, \"manifest.json\"))) {\n return [packageRoot];\n }\n\n const manifest = await readPmPackageManifest(packageRoot);\n const manifestEntries = manifest.resources.extensions ?? [];\n const discovered = new Set<string>();\n\n for (const entry of manifestEntries) {\n if (entry.includes(\"*\") || entry.startsWith(\"!\")) {\n throw new PmCliError(\n `Package extension entry \"${entry}\" uses a glob/exclusion pattern. pm package installs currently require concrete extension paths or directories.`,\n EXIT_CODE.USAGE,\n );\n }\n const absolute = path.resolve(packageRoot, entry);\n if (!isPathWithinDirectory(packageRoot, absolute)) {\n throw new PmCliError(`Package extension entry \"${entry}\" resolves outside package root.`, EXIT_CODE.USAGE);\n }\n if (await pathExists(path.join(absolute, \"manifest.json\"))) {\n discovered.add(absolute);\n continue;\n }\n for (const child of await listExtensionManifestDirectories(absolute)) {\n discovered.add(child);\n }\n }\n\n if (manifestEntries.length === 0) {\n for (const root of PM_PACKAGE_CONVENTIONAL_RESOURCE_ROOTS.extensions) {\n for (const child of await listExtensionManifestDirectories(path.join(packageRoot, root))) {\n discovered.add(child);\n }\n }\n }\n\n return [...discovered].sort((left, right) => left.localeCompare(right));\n}\n"]}
@@ -4,4 +4,16 @@ export interface EmbeddingBatchExecutionResult {
4
4
  vectors: number[][];
5
5
  warnings: string[];
6
6
  }
7
- export declare function executeEmbeddingBatchesWithRetry(provider: EmbeddingProviderConfig, settings: PmSettings, inputs: string[]): Promise<EmbeddingBatchExecutionResult>;
7
+ export interface EmbeddingBatchProgressEvent {
8
+ batch_index: number;
9
+ batch_total: number;
10
+ batch_size: number;
11
+ completed_inputs: number;
12
+ total_inputs: number;
13
+ attempt?: number;
14
+ phase: "start" | "complete";
15
+ }
16
+ export interface EmbeddingBatchExecutionOptions {
17
+ onProgress?: (event: EmbeddingBatchProgressEvent) => void;
18
+ }
19
+ export declare function executeEmbeddingBatchesWithRetry(provider: EmbeddingProviderConfig, settings: PmSettings, inputs: string[], options?: EmbeddingBatchExecutionOptions): Promise<EmbeddingBatchExecutionResult>;
@@ -84,7 +84,7 @@ async function executeBatchWithAdaptiveSplit(provider, batch, batchLabel, maxRet
84
84
  }
85
85
  throw new Error(`Embedding batch ${batchLabel} failed after ${maxRetries + 1} attempt(s): ${toErrorMessage(lastError)}`);
86
86
  }
87
- export async function executeEmbeddingBatchesWithRetry(provider, settings, inputs) {
87
+ export async function executeEmbeddingBatchesWithRetry(provider, settings, inputs, options = {}) {
88
88
  if (inputs.length === 0) {
89
89
  return {
90
90
  vectors: [],
@@ -106,9 +106,27 @@ export async function executeEmbeddingBatchesWithRetry(provider, settings, input
106
106
  }
107
107
  const batches = createBatches(normalizedInputs, runtime.batchSize, runtime.maxBatchInputCharacters);
108
108
  const vectors = [];
109
+ let completedInputs = 0;
109
110
  for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {
110
111
  const batch = batches[batchIndex];
112
+ options.onProgress?.({
113
+ batch_index: batchIndex + 1,
114
+ batch_total: batches.length,
115
+ batch_size: batch.length,
116
+ completed_inputs: completedInputs,
117
+ total_inputs: normalizedInputs.length,
118
+ phase: "start",
119
+ });
111
120
  vectors.push(...(await executeBatchWithAdaptiveSplit(provider, batch, String(batchIndex + 1), runtime.maxRetries, warnings)));
121
+ completedInputs += batch.length;
122
+ options.onProgress?.({
123
+ batch_index: batchIndex + 1,
124
+ batch_total: batches.length,
125
+ batch_size: batch.length,
126
+ completed_inputs: completedInputs,
127
+ total_inputs: normalizedInputs.length,
128
+ phase: "complete",
129
+ });
112
130
  }
113
131
  return {
114
132
  vectors,
@@ -1 +1 @@
1
- {"version":3,"file":"embedding-batches.js","sourceRoot":"/","sources":["core/search/embedding-batches.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PmSettings } from \"../../types/index.js\";\nimport { executeEmbeddingRequest } from \"./providers.js\";\nimport type { EmbeddingProviderConfig } from \"./providers.js\";\nimport { toErrorMessage } from \"../shared/primitives.js\";\nimport {\n DEFAULT_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n SEMANTIC_CORPUS_TRUNCATION_SUFFIX,\n} from \"./corpus.js\";\n\nexport interface EmbeddingBatchExecutionResult {\n vectors: number[][];\n warnings: string[];\n}\n\ninterface EmbeddingBatchRuntime {\n batchSize: number;\n maxRetries: number;\n maxBatchInputCharacters: number;\n maxInputCharacters: number;\n}\n\nfunction resolveBatchRuntime(settings: PmSettings): EmbeddingBatchRuntime {\n const batchSizeCandidate = settings.search.embedding_batch_size;\n const maxRetriesCandidate = settings.search.scanner_max_batch_retries;\n const batchSize = Number.isFinite(batchSizeCandidate) && batchSizeCandidate > 0 ? Math.floor(batchSizeCandidate) : 1;\n const maxRetries = Number.isFinite(maxRetriesCandidate) && maxRetriesCandidate >= 0 ? Math.floor(maxRetriesCandidate) : 0;\n return {\n batchSize,\n maxRetries,\n maxBatchInputCharacters: Number.POSITIVE_INFINITY,\n maxInputCharacters: DEFAULT_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n };\n}\n\nfunction createBatches(inputs: string[], batchSize: number, maxBatchInputCharacters: number): string[][] {\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentCharacters = 0;\n for (const input of inputs) {\n const wouldExceedCount = currentBatch.length >= batchSize;\n const wouldExceedCharacters =\n currentBatch.length > 0 &&\n Number.isFinite(maxBatchInputCharacters) &&\n currentCharacters + input.length > maxBatchInputCharacters;\n if (wouldExceedCount || wouldExceedCharacters) {\n batches.push(currentBatch);\n currentBatch = [];\n currentCharacters = 0;\n }\n currentBatch.push(input);\n currentCharacters += input.length;\n }\n batches.push(currentBatch);\n return batches;\n}\n\nfunction resolveProviderBatchRuntime(provider: EmbeddingProviderConfig, runtime: EmbeddingBatchRuntime): EmbeddingBatchRuntime {\n if (provider.name !== \"ollama\") {\n return runtime;\n }\n return {\n ...runtime,\n maxBatchInputCharacters: OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n maxInputCharacters: OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n };\n}\n\nfunction truncateInputForRuntime(input: string, maxInputCharacters: number): string {\n if (!Number.isFinite(maxInputCharacters) || maxInputCharacters <= 0 || input.length <= maxInputCharacters) {\n return input;\n }\n const keepLength = Math.max(0, maxInputCharacters - SEMANTIC_CORPUS_TRUNCATION_SUFFIX.length);\n return `${input.slice(0, keepLength)}${SEMANTIC_CORPUS_TRUNCATION_SUFFIX}`.slice(0, maxInputCharacters);\n}\n\nfunction isEmbeddingTimeoutError(error: unknown): boolean {\n const message = toErrorMessage(error).toLowerCase();\n return message.includes(\"timed out\") || message.includes(\"timeout\");\n}\n\nasync function executeBatchWithAdaptiveSplit(\n provider: EmbeddingProviderConfig,\n batch: string[],\n batchLabel: string,\n maxRetries: number,\n warnings: string[],\n): Promise<number[][]> {\n let lastError: unknown = null;\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n try {\n const batchVectors = await executeEmbeddingRequest(provider, batch);\n if (attempt > 0) {\n warnings.push(\n `search_embedding_batch_retry_succeeded:batch=${batchLabel}:attempt=${attempt + 1}:size=${batch.length}`,\n );\n }\n return batchVectors;\n } catch (error: unknown) {\n lastError = error;\n if (isEmbeddingTimeoutError(error) && batch.length > 1) {\n const midpoint = Math.ceil(batch.length / 2);\n const left = batch.slice(0, midpoint);\n const right = batch.slice(midpoint);\n warnings.push(\n `search_embedding_batch_split_after_timeout:batch=${batchLabel}:size=${batch.length}:parts=${left.length}|${right.length}`,\n );\n return [\n ...(await executeBatchWithAdaptiveSplit(provider, left, `${batchLabel}.1`, maxRetries, warnings)),\n ...(await executeBatchWithAdaptiveSplit(provider, right, `${batchLabel}.2`, maxRetries, warnings)),\n ];\n }\n if (attempt < maxRetries) {\n const delayMs = Math.min(1000 * 2 ** attempt, 8000);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n }\n throw new Error(`Embedding batch ${batchLabel} failed after ${maxRetries + 1} attempt(s): ${toErrorMessage(lastError)}`);\n}\n\nexport async function executeEmbeddingBatchesWithRetry(\n provider: EmbeddingProviderConfig,\n settings: PmSettings,\n inputs: string[],\n): Promise<EmbeddingBatchExecutionResult> {\n if (inputs.length === 0) {\n return {\n vectors: [],\n warnings: [],\n };\n }\n const runtime = resolveProviderBatchRuntime(provider, resolveBatchRuntime(settings));\n const warnings: string[] = [];\n let truncatedInputCount = 0;\n const normalizedInputs = inputs.map((input) => {\n const normalized = truncateInputForRuntime(input, runtime.maxInputCharacters);\n if (normalized.length < input.length) {\n truncatedInputCount += 1;\n }\n return normalized;\n });\n if (truncatedInputCount > 0) {\n warnings.push(`search_embedding_input_truncated:count=${truncatedInputCount}:max_characters=${runtime.maxInputCharacters}`);\n }\n const batches = createBatches(normalizedInputs, runtime.batchSize, runtime.maxBatchInputCharacters);\n const vectors: number[][] = [];\n for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {\n const batch = batches[batchIndex];\n vectors.push(...(await executeBatchWithAdaptiveSplit(provider, batch, String(batchIndex + 1), runtime.maxRetries, warnings)));\n }\n return {\n vectors,\n warnings,\n };\n}\n"]}
1
+ {"version":3,"file":"embedding-batches.js","sourceRoot":"/","sources":["core/search/embedding-batches.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PmSettings } from \"../../types/index.js\";\nimport { executeEmbeddingRequest } from \"./providers.js\";\nimport type { EmbeddingProviderConfig } from \"./providers.js\";\nimport { toErrorMessage } from \"../shared/primitives.js\";\nimport {\n DEFAULT_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n SEMANTIC_CORPUS_TRUNCATION_SUFFIX,\n} from \"./corpus.js\";\n\nexport interface EmbeddingBatchExecutionResult {\n vectors: number[][];\n warnings: string[];\n}\n\nexport interface EmbeddingBatchProgressEvent {\n batch_index: number;\n batch_total: number;\n batch_size: number;\n completed_inputs: number;\n total_inputs: number;\n attempt?: number;\n phase: \"start\" | \"complete\";\n}\n\nexport interface EmbeddingBatchExecutionOptions {\n onProgress?: (event: EmbeddingBatchProgressEvent) => void;\n}\n\ninterface EmbeddingBatchRuntime {\n batchSize: number;\n maxRetries: number;\n maxBatchInputCharacters: number;\n maxInputCharacters: number;\n}\n\nfunction resolveBatchRuntime(settings: PmSettings): EmbeddingBatchRuntime {\n const batchSizeCandidate = settings.search.embedding_batch_size;\n const maxRetriesCandidate = settings.search.scanner_max_batch_retries;\n const batchSize = Number.isFinite(batchSizeCandidate) && batchSizeCandidate > 0 ? Math.floor(batchSizeCandidate) : 1;\n const maxRetries = Number.isFinite(maxRetriesCandidate) && maxRetriesCandidate >= 0 ? Math.floor(maxRetriesCandidate) : 0;\n return {\n batchSize,\n maxRetries,\n maxBatchInputCharacters: Number.POSITIVE_INFINITY,\n maxInputCharacters: DEFAULT_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n };\n}\n\nfunction createBatches(inputs: string[], batchSize: number, maxBatchInputCharacters: number): string[][] {\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentCharacters = 0;\n for (const input of inputs) {\n const wouldExceedCount = currentBatch.length >= batchSize;\n const wouldExceedCharacters =\n currentBatch.length > 0 &&\n Number.isFinite(maxBatchInputCharacters) &&\n currentCharacters + input.length > maxBatchInputCharacters;\n if (wouldExceedCount || wouldExceedCharacters) {\n batches.push(currentBatch);\n currentBatch = [];\n currentCharacters = 0;\n }\n currentBatch.push(input);\n currentCharacters += input.length;\n }\n batches.push(currentBatch);\n return batches;\n}\n\nfunction resolveProviderBatchRuntime(provider: EmbeddingProviderConfig, runtime: EmbeddingBatchRuntime): EmbeddingBatchRuntime {\n if (provider.name !== \"ollama\") {\n return runtime;\n }\n return {\n ...runtime,\n maxBatchInputCharacters: OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n maxInputCharacters: OLLAMA_SEMANTIC_CORPUS_INPUT_MAX_CHARACTERS,\n };\n}\n\nfunction truncateInputForRuntime(input: string, maxInputCharacters: number): string {\n if (!Number.isFinite(maxInputCharacters) || maxInputCharacters <= 0 || input.length <= maxInputCharacters) {\n return input;\n }\n const keepLength = Math.max(0, maxInputCharacters - SEMANTIC_CORPUS_TRUNCATION_SUFFIX.length);\n return `${input.slice(0, keepLength)}${SEMANTIC_CORPUS_TRUNCATION_SUFFIX}`.slice(0, maxInputCharacters);\n}\n\nfunction isEmbeddingTimeoutError(error: unknown): boolean {\n const message = toErrorMessage(error).toLowerCase();\n return message.includes(\"timed out\") || message.includes(\"timeout\");\n}\n\nasync function executeBatchWithAdaptiveSplit(\n provider: EmbeddingProviderConfig,\n batch: string[],\n batchLabel: string,\n maxRetries: number,\n warnings: string[],\n): Promise<number[][]> {\n let lastError: unknown = null;\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n try {\n const batchVectors = await executeEmbeddingRequest(provider, batch);\n if (attempt > 0) {\n warnings.push(\n `search_embedding_batch_retry_succeeded:batch=${batchLabel}:attempt=${attempt + 1}:size=${batch.length}`,\n );\n }\n return batchVectors;\n } catch (error: unknown) {\n lastError = error;\n if (isEmbeddingTimeoutError(error) && batch.length > 1) {\n const midpoint = Math.ceil(batch.length / 2);\n const left = batch.slice(0, midpoint);\n const right = batch.slice(midpoint);\n warnings.push(\n `search_embedding_batch_split_after_timeout:batch=${batchLabel}:size=${batch.length}:parts=${left.length}|${right.length}`,\n );\n return [\n ...(await executeBatchWithAdaptiveSplit(provider, left, `${batchLabel}.1`, maxRetries, warnings)),\n ...(await executeBatchWithAdaptiveSplit(provider, right, `${batchLabel}.2`, maxRetries, warnings)),\n ];\n }\n if (attempt < maxRetries) {\n const delayMs = Math.min(1000 * 2 ** attempt, 8000);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n }\n throw new Error(`Embedding batch ${batchLabel} failed after ${maxRetries + 1} attempt(s): ${toErrorMessage(lastError)}`);\n}\n\nexport async function executeEmbeddingBatchesWithRetry(\n provider: EmbeddingProviderConfig,\n settings: PmSettings,\n inputs: string[],\n options: EmbeddingBatchExecutionOptions = {},\n): Promise<EmbeddingBatchExecutionResult> {\n if (inputs.length === 0) {\n return {\n vectors: [],\n warnings: [],\n };\n }\n const runtime = resolveProviderBatchRuntime(provider, resolveBatchRuntime(settings));\n const warnings: string[] = [];\n let truncatedInputCount = 0;\n const normalizedInputs = inputs.map((input) => {\n const normalized = truncateInputForRuntime(input, runtime.maxInputCharacters);\n if (normalized.length < input.length) {\n truncatedInputCount += 1;\n }\n return normalized;\n });\n if (truncatedInputCount > 0) {\n warnings.push(`search_embedding_input_truncated:count=${truncatedInputCount}:max_characters=${runtime.maxInputCharacters}`);\n }\n const batches = createBatches(normalizedInputs, runtime.batchSize, runtime.maxBatchInputCharacters);\n const vectors: number[][] = [];\n let completedInputs = 0;\n for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {\n const batch = batches[batchIndex];\n options.onProgress?.({\n batch_index: batchIndex + 1,\n batch_total: batches.length,\n batch_size: batch.length,\n completed_inputs: completedInputs,\n total_inputs: normalizedInputs.length,\n phase: \"start\",\n });\n vectors.push(...(await executeBatchWithAdaptiveSplit(provider, batch, String(batchIndex + 1), runtime.maxRetries, warnings)));\n completedInputs += batch.length;\n options.onProgress?.({\n batch_index: batchIndex + 1,\n batch_total: batches.length,\n batch_size: batch.length,\n completed_inputs: completedInputs,\n total_inputs: normalizedInputs.length,\n phase: \"complete\",\n });\n }\n return {\n vectors,\n warnings,\n };\n}\n"]}
@@ -1,6 +1,13 @@
1
- import type { ItemDocument, ItemFormat, RuntimeSchemaSettings } from "../../types/index.js";
1
+ import type { ItemDocument, ItemFormat, ItemMetadata, RuntimeSchemaSettings } from "../../types/index.js";
2
+ export interface CachedDocumentCandidate {
3
+ metadata: ItemMetadata;
4
+ body?: string;
5
+ item_format: ItemFormat;
6
+ item_path: string;
7
+ }
2
8
  /**
3
9
  * List all item documents using a persistent on-disk metadata cache.
4
10
  * Only parses files whose mtime/size have changed since the last cached run.
5
11
  */
12
+ export declare function listAllDocumentCandidatesCached(pmRoot: string, preferredFormat: ItemFormat | undefined, typeToFolder: Record<string, string>, warnings: string[] | undefined, schema: RuntimeSchemaSettings | undefined): Promise<CachedDocumentCandidate[]>;
6
13
  export declare function listAllDocumentsCached(pmRoot: string, preferredFormat: ItemFormat | undefined, typeToFolder: Record<string, string>, warnings: string[] | undefined, schema: RuntimeSchemaSettings | undefined): Promise<ItemDocument[]>;
@@ -49,7 +49,7 @@ function appendWarning(warnings, warning) {
49
49
  * List all item documents using a persistent on-disk metadata cache.
50
50
  * Only parses files whose mtime/size have changed since the last cached run.
51
51
  */
52
- export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFolder, warnings, schema) {
52
+ export async function listAllDocumentCandidatesCached(pmRoot, preferredFormat, typeToFolder, warnings, schema) {
53
53
  const contextFingerprint = computeContextFingerprint(preferredFormat, typeToFolder, schema);
54
54
  const existingCache = await loadCache(pmRoot);
55
55
  const previousEntries = existingCache && existingCache.context_fingerprint === contextFingerprint
@@ -88,6 +88,7 @@ export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFold
88
88
  const cached = previousEntries[relativePath];
89
89
  let metadata;
90
90
  let bodyLength;
91
+ let body;
91
92
  const itemFormat = getItemFormatFromPath(filePath);
92
93
  // Preserve onRead hook semantics even when metadata is served from cache.
93
94
  await runActiveOnReadHooks({ path: filePath, scope: "project" });
@@ -104,6 +105,7 @@ export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFold
104
105
  });
105
106
  metadata = parsed.metadata;
106
107
  bodyLength = parsed.body.length;
108
+ body = parsed.body;
107
109
  }
108
110
  newEntries[relativePath] = {
109
111
  mtime_ms: mtimeMs,
@@ -113,21 +115,21 @@ export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFold
113
115
  body_length: bodyLength,
114
116
  };
115
117
  const existing = documentsById.get(metadata.id);
118
+ const candidate = {
119
+ metadata,
120
+ body,
121
+ item_format: itemFormat,
122
+ item_path: filePath,
123
+ };
116
124
  if (!existing) {
117
- documentsById.set(metadata.id, {
118
- document: { metadata, body: "" },
119
- itemFormat,
120
- });
125
+ documentsById.set(metadata.id, { candidate, itemFormat });
121
126
  }
122
127
  else {
123
128
  const shouldReplace = preferredFormat
124
129
  ? itemFormat === preferredFormat && existing.itemFormat !== preferredFormat
125
130
  : itemFormat === "toon" && existing.itemFormat !== "toon";
126
131
  if (shouldReplace) {
127
- documentsById.set(metadata.id, {
128
- document: { metadata, body: "" },
129
- itemFormat,
130
- });
132
+ documentsById.set(metadata.id, { candidate, itemFormat });
131
133
  }
132
134
  }
133
135
  }
@@ -144,7 +146,14 @@ export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFold
144
146
  entries: newEntries,
145
147
  }).catch(() => { });
146
148
  return [...documentsById.values()]
147
- .sort((left, right) => left.document.metadata.id.localeCompare(right.document.metadata.id))
148
- .map((entry) => entry.document);
149
+ .sort((left, right) => left.candidate.metadata.id.localeCompare(right.candidate.metadata.id))
150
+ .map((entry) => entry.candidate);
151
+ }
152
+ export async function listAllDocumentsCached(pmRoot, preferredFormat, typeToFolder, warnings, schema) {
153
+ const candidates = await listAllDocumentCandidatesCached(pmRoot, preferredFormat, typeToFolder, warnings, schema);
154
+ return candidates.map((candidate) => ({
155
+ metadata: candidate.metadata,
156
+ body: candidate.body ?? "",
157
+ }));
149
158
  }
150
159
  //# sourceMappingURL=front-matter-cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"front-matter-cache.js","sourceRoot":"/","sources":["core/store/front-matter-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { runActiveOnReadHooks } from \"../extensions/index.js\";\nimport { parseItemDocument } from \"../item/item-format.js\";\nimport { ITEM_FILE_EXTENSIONS, getItemFormatFromPath } from \"./paths.js\";\nimport type { ItemDocument, ItemFormat, ItemMetadata, ItemType, RuntimeSchemaSettings } from \"../../types/index.js\";\n\nconst CACHE_VERSION = 3;\nconst CACHE_FILENAME = \"metadata-cache.json\";\n\ninterface CachedEntry {\n mtime_ms: number;\n ctime_ms: number;\n size: number;\n metadata: ItemMetadata;\n body_length: number;\n}\n\ninterface CacheEnvelope {\n version: number;\n context_fingerprint: string;\n entries: Record<string, CachedEntry>;\n}\n\nfunction computeContextFingerprint(\n preferredFormat: ItemFormat | undefined,\n typeToFolder: Record<string, string>,\n schema: RuntimeSchemaSettings | undefined,\n): string {\n const hash = createHash(\"sha256\");\n hash.update(`format:${preferredFormat ?? \"default\"}`);\n const sortedTypes = Object.entries(typeToFolder)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([type, folder]) => `${type}=${folder}`)\n .join(\",\");\n hash.update(`|types:${sortedTypes}`);\n if (schema) {\n hash.update(`|schema:${JSON.stringify(schema)}`);\n }\n return hash.digest(\"hex\").slice(0, 16);\n}\n\nfunction getCachePath(pmRoot: string): string {\n return path.join(pmRoot, \"runtime\", CACHE_FILENAME);\n}\n\nasync function loadCache(pmRoot: string): Promise<CacheEnvelope | null> {\n try {\n const raw = await fs.readFile(getCachePath(pmRoot), \"utf8\");\n const parsed = JSON.parse(raw) as CacheEnvelope;\n if (parsed.version !== CACHE_VERSION || typeof parsed.entries !== \"object\") {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nasync function persistCache(pmRoot: string, envelope: CacheEnvelope): Promise<void> {\n const cachePath = getCachePath(pmRoot);\n await fs.mkdir(path.dirname(cachePath), { recursive: true });\n await fs.writeFile(cachePath, JSON.stringify(envelope), \"utf8\");\n}\n\nfunction appendWarning(warnings: string[] | undefined, warning: string): void {\n if (warnings && !warnings.includes(warning)) {\n warnings.push(warning);\n }\n}\n\n/**\n * List all item documents using a persistent on-disk metadata cache.\n * Only parses files whose mtime/size have changed since the last cached run.\n */\nexport async function listAllDocumentsCached(\n pmRoot: string,\n preferredFormat: ItemFormat | undefined,\n typeToFolder: Record<string, string>,\n warnings: string[] | undefined,\n schema: RuntimeSchemaSettings | undefined,\n): Promise<ItemDocument[]> {\n const contextFingerprint = computeContextFingerprint(preferredFormat, typeToFolder, schema);\n const existingCache = await loadCache(pmRoot);\n\n const previousEntries: Record<string, CachedEntry> =\n existingCache && existingCache.context_fingerprint === contextFingerprint\n ? existingCache.entries\n : {};\n\n const entries = Object.entries(typeToFolder) as Array<[ItemType, string]>;\n\n const dirResults = await Promise.all(\n entries.map(async ([, folder]) => {\n const dirPath = path.join(pmRoot, folder);\n try {\n const files = await fs.readdir(dirPath);\n return { folder, dirPath, files };\n } catch (error: unknown) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: string }).code !== \"ENOENT\") {\n appendWarning(warnings, `item_list_directory_read_failed:${folder}`);\n }\n return { folder, dirPath, files: [] as string[] };\n }\n }),\n );\n\n const newEntries: Record<string, CachedEntry> = {};\n const documentsById = new Map<string, { document: ItemDocument; itemFormat: ItemFormat }>();\n\n const parseTasks: Array<Promise<void>> = [];\n\n for (const { folder, dirPath, files } of dirResults) {\n for (const file of files) {\n if (!ITEM_FILE_EXTENSIONS.some((ext) => file.toLowerCase().endsWith(ext))) {\n continue;\n }\n const filePath = path.join(dirPath, file);\n const relativePath = path.relative(pmRoot, filePath);\n\n parseTasks.push(\n (async () => {\n try {\n const stat = await fs.stat(filePath);\n const mtimeMs = stat.mtimeMs;\n const ctimeMs = stat.ctimeMs;\n const { size } = stat;\n const cached = previousEntries[relativePath];\n\n let metadata: ItemMetadata;\n let bodyLength: number;\n const itemFormat = getItemFormatFromPath(filePath) as ItemFormat;\n\n // Preserve onRead hook semantics even when metadata is served from cache.\n await runActiveOnReadHooks({ path: filePath, scope: \"project\" });\n\n if (cached && cached.mtime_ms === mtimeMs && cached.ctime_ms === ctimeMs && cached.size === size) {\n metadata = cached.metadata;\n bodyLength = cached.body_length;\n } else {\n const raw = await fs.readFile(filePath, \"utf8\");\n const parsed = parseItemDocument(raw, {\n format: itemFormat,\n schema,\n onWarning: (w) => appendWarning(warnings, w),\n });\n metadata = parsed.metadata;\n bodyLength = parsed.body.length;\n }\n\n newEntries[relativePath] = {\n mtime_ms: mtimeMs,\n ctime_ms: ctimeMs,\n size,\n metadata,\n body_length: bodyLength,\n };\n\n const existing = documentsById.get(metadata.id);\n if (!existing) {\n documentsById.set(metadata.id, {\n document: { metadata, body: \"\" },\n itemFormat,\n });\n } else {\n const shouldReplace = preferredFormat\n ? itemFormat === preferredFormat && existing.itemFormat !== preferredFormat\n : itemFormat === \"toon\" && existing.itemFormat !== \"toon\";\n if (shouldReplace) {\n documentsById.set(metadata.id, {\n document: { metadata, body: \"\" },\n itemFormat,\n });\n }\n }\n } catch {\n appendWarning(warnings, `item_list_item_read_failed:${folder}/${file}`);\n }\n })(),\n );\n }\n }\n\n await Promise.all(parseTasks);\n\n persistCache(pmRoot, {\n version: CACHE_VERSION,\n context_fingerprint: contextFingerprint,\n entries: newEntries,\n }).catch(() => {});\n\n return [...documentsById.values()]\n .sort((left, right) => left.document.metadata.id.localeCompare(right.document.metadata.id))\n .map((entry) => entry.document);\n}\n"]}
1
+ {"version":3,"file":"front-matter-cache.js","sourceRoot":"/","sources":["core/store/front-matter-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { runActiveOnReadHooks } from \"../extensions/index.js\";\nimport { parseItemDocument } from \"../item/item-format.js\";\nimport { ITEM_FILE_EXTENSIONS, getItemFormatFromPath } from \"./paths.js\";\nimport type { ItemDocument, ItemFormat, ItemMetadata, ItemType, RuntimeSchemaSettings } from \"../../types/index.js\";\n\nconst CACHE_VERSION = 3;\nconst CACHE_FILENAME = \"metadata-cache.json\";\n\ninterface CachedEntry {\n mtime_ms: number;\n ctime_ms: number;\n size: number;\n metadata: ItemMetadata;\n body_length: number;\n}\n\ninterface CacheEnvelope {\n version: number;\n context_fingerprint: string;\n entries: Record<string, CachedEntry>;\n}\n\nexport interface CachedDocumentCandidate {\n metadata: ItemMetadata;\n body?: string;\n item_format: ItemFormat;\n item_path: string;\n}\n\nfunction computeContextFingerprint(\n preferredFormat: ItemFormat | undefined,\n typeToFolder: Record<string, string>,\n schema: RuntimeSchemaSettings | undefined,\n): string {\n const hash = createHash(\"sha256\");\n hash.update(`format:${preferredFormat ?? \"default\"}`);\n const sortedTypes = Object.entries(typeToFolder)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([type, folder]) => `${type}=${folder}`)\n .join(\",\");\n hash.update(`|types:${sortedTypes}`);\n if (schema) {\n hash.update(`|schema:${JSON.stringify(schema)}`);\n }\n return hash.digest(\"hex\").slice(0, 16);\n}\n\nfunction getCachePath(pmRoot: string): string {\n return path.join(pmRoot, \"runtime\", CACHE_FILENAME);\n}\n\nasync function loadCache(pmRoot: string): Promise<CacheEnvelope | null> {\n try {\n const raw = await fs.readFile(getCachePath(pmRoot), \"utf8\");\n const parsed = JSON.parse(raw) as CacheEnvelope;\n if (parsed.version !== CACHE_VERSION || typeof parsed.entries !== \"object\") {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nasync function persistCache(pmRoot: string, envelope: CacheEnvelope): Promise<void> {\n const cachePath = getCachePath(pmRoot);\n await fs.mkdir(path.dirname(cachePath), { recursive: true });\n await fs.writeFile(cachePath, JSON.stringify(envelope), \"utf8\");\n}\n\nfunction appendWarning(warnings: string[] | undefined, warning: string): void {\n if (warnings && !warnings.includes(warning)) {\n warnings.push(warning);\n }\n}\n\n/**\n * List all item documents using a persistent on-disk metadata cache.\n * Only parses files whose mtime/size have changed since the last cached run.\n */\nexport async function listAllDocumentCandidatesCached(\n pmRoot: string,\n preferredFormat: ItemFormat | undefined,\n typeToFolder: Record<string, string>,\n warnings: string[] | undefined,\n schema: RuntimeSchemaSettings | undefined,\n): Promise<CachedDocumentCandidate[]> {\n const contextFingerprint = computeContextFingerprint(preferredFormat, typeToFolder, schema);\n const existingCache = await loadCache(pmRoot);\n\n const previousEntries: Record<string, CachedEntry> =\n existingCache && existingCache.context_fingerprint === contextFingerprint\n ? existingCache.entries\n : {};\n\n const entries = Object.entries(typeToFolder) as Array<[ItemType, string]>;\n\n const dirResults = await Promise.all(\n entries.map(async ([, folder]) => {\n const dirPath = path.join(pmRoot, folder);\n try {\n const files = await fs.readdir(dirPath);\n return { folder, dirPath, files };\n } catch (error: unknown) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: string }).code !== \"ENOENT\") {\n appendWarning(warnings, `item_list_directory_read_failed:${folder}`);\n }\n return { folder, dirPath, files: [] as string[] };\n }\n }),\n );\n\n const newEntries: Record<string, CachedEntry> = {};\n const documentsById = new Map<string, { candidate: CachedDocumentCandidate; itemFormat: ItemFormat }>();\n\n const parseTasks: Array<Promise<void>> = [];\n\n for (const { folder, dirPath, files } of dirResults) {\n for (const file of files) {\n if (!ITEM_FILE_EXTENSIONS.some((ext) => file.toLowerCase().endsWith(ext))) {\n continue;\n }\n const filePath = path.join(dirPath, file);\n const relativePath = path.relative(pmRoot, filePath);\n\n parseTasks.push(\n (async () => {\n try {\n const stat = await fs.stat(filePath);\n const mtimeMs = stat.mtimeMs;\n const ctimeMs = stat.ctimeMs;\n const { size } = stat;\n const cached = previousEntries[relativePath];\n\n let metadata: ItemMetadata;\n let bodyLength: number;\n let body: string | undefined;\n const itemFormat = getItemFormatFromPath(filePath) as ItemFormat;\n\n // Preserve onRead hook semantics even when metadata is served from cache.\n await runActiveOnReadHooks({ path: filePath, scope: \"project\" });\n\n if (cached && cached.mtime_ms === mtimeMs && cached.ctime_ms === ctimeMs && cached.size === size) {\n metadata = cached.metadata;\n bodyLength = cached.body_length;\n } else {\n const raw = await fs.readFile(filePath, \"utf8\");\n const parsed = parseItemDocument(raw, {\n format: itemFormat,\n schema,\n onWarning: (w) => appendWarning(warnings, w),\n });\n metadata = parsed.metadata;\n bodyLength = parsed.body.length;\n body = parsed.body;\n }\n\n newEntries[relativePath] = {\n mtime_ms: mtimeMs,\n ctime_ms: ctimeMs,\n size,\n metadata,\n body_length: bodyLength,\n };\n\n const existing = documentsById.get(metadata.id);\n const candidate: CachedDocumentCandidate = {\n metadata,\n body,\n item_format: itemFormat,\n item_path: filePath,\n };\n if (!existing) {\n documentsById.set(metadata.id, { candidate, itemFormat });\n } else {\n const shouldReplace = preferredFormat\n ? itemFormat === preferredFormat && existing.itemFormat !== preferredFormat\n : itemFormat === \"toon\" && existing.itemFormat !== \"toon\";\n if (shouldReplace) {\n documentsById.set(metadata.id, { candidate, itemFormat });\n }\n }\n } catch {\n appendWarning(warnings, `item_list_item_read_failed:${folder}/${file}`);\n }\n })(),\n );\n }\n }\n\n await Promise.all(parseTasks);\n\n persistCache(pmRoot, {\n version: CACHE_VERSION,\n context_fingerprint: contextFingerprint,\n entries: newEntries,\n }).catch(() => {});\n\n return [...documentsById.values()]\n .sort((left, right) => left.candidate.metadata.id.localeCompare(right.candidate.metadata.id))\n .map((entry) => entry.candidate);\n}\n\nexport async function listAllDocumentsCached(\n pmRoot: string,\n preferredFormat: ItemFormat | undefined,\n typeToFolder: Record<string, string>,\n warnings: string[] | undefined,\n schema: RuntimeSchemaSettings | undefined,\n): Promise<ItemDocument[]> {\n const candidates = await listAllDocumentCandidatesCached(pmRoot, preferredFormat, typeToFolder, warnings, schema);\n return candidates.map((candidate) => ({\n metadata: candidate.metadata,\n body: candidate.body ?? \"\",\n }));\n}\n"]}
@@ -1,2 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ interface JsonRpcRequest {
3
+ jsonrpc?: string;
4
+ id?: string | number | null;
5
+ method?: string;
6
+ params?: Record<string, unknown>;
7
+ }
8
+ export declare function handleRequest(request: JsonRpcRequest): Promise<Record<string, unknown> | undefined>;
2
9
  export declare function startMcpServer(): void;
10
+ export {};