@kolisachint/hoocode-agent 0.5.13 → 0.5.15

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 (66) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/dist/config.d.ts +9 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +16 -0
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/context-files.d.ts +16 -3
  7. package/dist/core/context-files.d.ts.map +1 -1
  8. package/dist/core/context-files.js +77 -6
  9. package/dist/core/context-files.js.map +1 -1
  10. package/dist/core/extensions/loader.d.ts +2 -5
  11. package/dist/core/extensions/loader.d.ts.map +1 -1
  12. package/dist/core/extensions/loader.js +5 -0
  13. package/dist/core/extensions/loader.js.map +1 -1
  14. package/dist/core/extensions/types.d.ts +15 -4
  15. package/dist/core/extensions/types.d.ts.map +1 -1
  16. package/dist/core/extensions/types.js.map +1 -1
  17. package/dist/core/learn/digest.d.ts +17 -0
  18. package/dist/core/learn/digest.d.ts.map +1 -0
  19. package/dist/core/learn/digest.js +131 -0
  20. package/dist/core/learn/digest.js.map +1 -0
  21. package/dist/core/learn/extract.d.ts +178 -0
  22. package/dist/core/learn/extract.d.ts.map +1 -0
  23. package/dist/core/learn/extract.js +705 -0
  24. package/dist/core/learn/extract.js.map +1 -0
  25. package/dist/core/learn/normalize.d.ts +65 -0
  26. package/dist/core/learn/normalize.d.ts.map +1 -0
  27. package/dist/core/learn/normalize.js +245 -0
  28. package/dist/core/learn/normalize.js.map +1 -0
  29. package/dist/core/learn/state.d.ts +115 -0
  30. package/dist/core/learn/state.d.ts.map +1 -0
  31. package/dist/core/learn/state.js +151 -0
  32. package/dist/core/learn/state.js.map +1 -0
  33. package/dist/core/settings-defaults.d.ts +5 -0
  34. package/dist/core/settings-defaults.d.ts.map +1 -1
  35. package/dist/core/settings-defaults.js +5 -0
  36. package/dist/core/settings-defaults.js.map +1 -1
  37. package/dist/core/settings-manager.d.ts +14 -0
  38. package/dist/core/settings-manager.d.ts.map +1 -1
  39. package/dist/core/settings-manager.js +17 -0
  40. package/dist/core/settings-manager.js.map +1 -1
  41. package/dist/core/settings-types.d.ts +5 -0
  42. package/dist/core/settings-types.d.ts.map +1 -1
  43. package/dist/core/settings-types.js.map +1 -1
  44. package/dist/extensions/core/hoo-core.d.ts.map +1 -1
  45. package/dist/extensions/core/hoo-core.js +2 -0
  46. package/dist/extensions/core/hoo-core.js.map +1 -1
  47. package/dist/extensions/core/learn.d.ts +22 -0
  48. package/dist/extensions/core/learn.d.ts.map +1 -0
  49. package/dist/extensions/core/learn.js +167 -0
  50. package/dist/extensions/core/learn.js.map +1 -0
  51. package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
  52. package/dist/extensions/core/mcp-loader.js +38 -2
  53. package/dist/extensions/core/mcp-loader.js.map +1 -1
  54. package/dist/main.d.ts.map +1 -1
  55. package/dist/main.js +8 -4
  56. package/dist/main.js.map +1 -1
  57. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  58. package/dist/modes/interactive/resource-display.js +11 -2
  59. package/dist/modes/interactive/resource-display.js.map +1 -1
  60. package/docs/settings.md +31 -0
  61. package/docs/usage.md +64 -2
  62. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  63. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  64. package/examples/extensions/sandbox/package.json +1 -1
  65. package/examples/extensions/with-deps/package.json +1 -1
  66. package/package.json +4 -4
@@ -1,14 +1,21 @@
1
1
  /**
2
2
  * Context-file and prompt-input loading for the resource loader.
3
3
  *
4
- * Reads AGENTS.md / CLAUDE.md context files from the agent dir and the cwd
4
+ * Reads AGENTS.md / CLAUDE.md context files from the user scopes and the cwd
5
5
  * ancestor chain (warning/truncating oversized ones, since they are injected
6
6
  * into the system prompt every turn), and resolves a system-prompt input that
7
7
  * may be either an inline string or a file path. Extracted from resource-loader.ts.
8
+ *
9
+ * Two user scopes are read, least specific first: `~/.agents/AGENTS.md` (the
10
+ * cross-vendor convention, so rules written for one tool are seen by hoocode)
11
+ * and `~/.hoocode/AGENTS.md` (the native home, which therefore wins on
12
+ * conflict). Both are additive — neither shadows the other, and no migration
13
+ * is needed for users who already have the native file.
8
14
  */
9
15
  import { existsSync, readFileSync } from "node:fs";
10
16
  import { join, resolve } from "node:path";
11
17
  import chalk from "chalk";
18
+ import { getUserAgentsDir } from "../config.js";
12
19
  /**
13
20
  * Resolve a prompt input that is either an inline string or a path to a file.
14
21
  * If the input names an existing file, its contents are returned; otherwise the
@@ -35,6 +42,17 @@ export function resolvePromptInput(input, description) {
35
42
  // so a pasted spec can't silently bloat every request forever.
36
43
  const CONTEXT_FILE_WARN_BYTES = 8 * 1024;
37
44
  const CONTEXT_FILE_MAX_BYTES = 40 * 1024;
45
+ // The per-file limits above cap one file; they say nothing about the total,
46
+ // and the set can now stack two user scopes on top of a whole ancestor chain.
47
+ // So the aggregate gets its own budget, deliberately warn-first: past the soft
48
+ // cap (~6k tokens) the user is told what it costs, and only past the hard cap
49
+ // (~16k tokens) is anything trimmed. Trimming should be the branch that never
50
+ // runs in practice.
51
+ const CONTEXT_TOTAL_WARN_BYTES = 24 * 1024;
52
+ const CONTEXT_TOTAL_MAX_BYTES = 64 * 1024;
53
+ // Below this, a trimmed file has no room left to say anything useful, so it is
54
+ // replaced by the notice alone rather than a few words of severed prose.
55
+ const CONTEXT_TRIM_MIN_BYTES = 512;
38
56
  function loadContextFileFromDir(dir) {
39
57
  const warnings = [];
40
58
  const candidates = ["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
@@ -68,15 +86,21 @@ function loadContextFileFromDir(dir) {
68
86
  export function loadProjectContextFiles(options) {
69
87
  const resolvedCwd = options.cwd;
70
88
  const resolvedAgentDir = options.agentDir;
89
+ const resolvedUserAgentsDir = options.userAgentsDir ?? getUserAgentsDir();
71
90
  const contextFiles = [];
72
91
  const warnings = [];
73
92
  const seenPaths = new Set();
74
- const globalResult = loadContextFileFromDir(resolvedAgentDir);
75
- if (globalResult.file) {
76
- contextFiles.push(globalResult.file);
77
- seenPaths.add(globalResult.file.path);
93
+ // Least specific first: the cross-vendor scope, then the native home. A file
94
+ // already seen is never added twice, so pointing both at one directory is a
95
+ // no-op rather than a doubled prompt.
96
+ for (const dir of [resolvedUserAgentsDir, resolvedAgentDir]) {
97
+ const result = loadContextFileFromDir(dir);
98
+ if (result.file && !seenPaths.has(result.file.path)) {
99
+ contextFiles.push(result.file);
100
+ seenPaths.add(result.file.path);
101
+ }
102
+ warnings.push(...result.warnings);
78
103
  }
79
- warnings.push(...globalResult.warnings);
80
104
  const ancestorContextFiles = [];
81
105
  let currentDir = resolvedCwd;
82
106
  const root = resolve("/");
@@ -95,6 +119,53 @@ export function loadProjectContextFiles(options) {
95
119
  currentDir = parentDir;
96
120
  }
97
121
  contextFiles.push(...ancestorContextFiles);
122
+ warnings.push(...enforceTotalBudget(contextFiles));
98
123
  return { agentsFiles: contextFiles, warnings };
99
124
  }
125
+ /**
126
+ * Apply the aggregate budget to an already-ordered context-file list.
127
+ *
128
+ * Mutates entries in place and returns any warnings. The list is ordered least
129
+ * specific first, and specificity is what decides who pays: the walk runs from
130
+ * the end so the file nearest the work keeps its budget, and a user-scope file
131
+ * is trimmed before a repo one. Files are trimmed rather than dropped, so a
132
+ * file that stops fitting still says so in the prompt instead of vanishing.
133
+ */
134
+ function enforceTotalBudget(files) {
135
+ const warnings = [];
136
+ const total = files.reduce((sum, file) => sum + Buffer.byteLength(file.content, "utf-8"), 0);
137
+ if (total <= CONTEXT_TOTAL_WARN_BYTES) {
138
+ return warnings;
139
+ }
140
+ if (total <= CONTEXT_TOTAL_MAX_BYTES) {
141
+ // A single oversized file is already priced by the per-file rule, which
142
+ // flags it `large` and annotates it where it is listed. Repeating that as
143
+ // an aggregate warning says nothing new. The aggregate exists to catch
144
+ // what per-file checks structurally cannot see: the sum across scopes.
145
+ if (files.length < 2)
146
+ return warnings;
147
+ warnings.push(`Context files total ~${Math.round(total / 4 / 100) / 10}k tokens across ${files.length} file(s), ` +
148
+ `re-sent on every request. Keep rules to one line each, and move long or conditional guidance into a skill ` +
149
+ `(loaded on demand) rather than a context file (loaded always).`);
150
+ return warnings;
151
+ }
152
+ let remaining = CONTEXT_TOTAL_MAX_BYTES;
153
+ for (let i = files.length - 1; i >= 0; i--) {
154
+ const file = files[i];
155
+ const bytes = Buffer.byteLength(file.content, "utf-8");
156
+ if (bytes <= remaining) {
157
+ remaining -= bytes;
158
+ continue;
159
+ }
160
+ const notice = `\n\n[trimmed: context files exceeded ${CONTEXT_TOTAL_MAX_BYTES} bytes (~16k tokens) in total; ` +
161
+ `least-specific scopes are trimmed first — move long guidance into a skill]`;
162
+ file.content =
163
+ remaining >= CONTEXT_TRIM_MIN_BYTES ? file.content.slice(0, remaining) + notice : notice.trimStart();
164
+ file.size = "truncated";
165
+ file.tokens = Math.round(Buffer.byteLength(file.content, "utf-8") / 4);
166
+ remaining = 0;
167
+ warnings.push(`Trimmed ${file.path} — context files exceeded the total budget.`);
168
+ }
169
+ return warnings;
170
+ }
100
171
  //# sourceMappingURL=context-files.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-files.js","sourceRoot":"","sources":["../../src/core/context-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context-file and prompt-input loading for the resource loader.\n *\n * Reads AGENTS.md / CLAUDE.md context files from the agent dir and the cwd\n * ancestor chain (warning/truncating oversized ones, since they are injected\n * into the system prompt every turn), and resolves a system-prompt input that\n * may be either an inline string or a file path. Extracted from resource-loader.ts.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\n\n/**\n * A loaded context file plus the recurring-cost metadata the UI surfaces.\n * `tokens`/`size` are optional so callers that synthesize context files (SDK\n * overrides, tests) can keep passing plain `{ path, content }`.\n */\nexport interface ContextFile {\n\tpath: string;\n\tcontent: string;\n\t/** Rough token estimate (bytes / 4) of the content as loaded. */\n\ttokens?: number;\n\t/** Set only past the soft limit; \"truncated\" means the hard limit clipped it. */\n\tsize?: \"large\" | \"truncated\";\n}\n\n/**\n * Resolve a prompt input that is either an inline string or a path to a file.\n * If the input names an existing file, its contents are returned; otherwise the\n * input is treated as the prompt text itself.\n */\nexport function resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n// Context files (AGENTS.md / CLAUDE.md) are injected into the system prompt on\n// every turn, so their size has a recurring cost on every provider. Warn the\n// user past a soft limit (~2k tokens) and truncate at a hard limit (~10k tokens)\n// so a pasted spec can't silently bloat every request forever.\nconst CONTEXT_FILE_WARN_BYTES = 8 * 1024;\nconst CONTEXT_FILE_MAX_BYTES = 40 * 1024;\n\nfunction loadContextFileFromDir(dir: string): { file: ContextFile | null; warnings: string[] } {\n\tconst warnings: string[] = [];\n\tconst candidates = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\tlet content = readFileSync(filePath, \"utf-8\");\n\t\t\t\tconst bytes = Buffer.byteLength(content, \"utf-8\");\n\t\t\t\t// Size is reported structurally (not as a warning string) so the UI can\n\t\t\t\t// annotate the file where it is already listed instead of repeating it.\n\t\t\t\tlet size: ContextFile[\"size\"];\n\t\t\t\tif (bytes > CONTEXT_FILE_MAX_BYTES) {\n\t\t\t\t\tcontent =\n\t\t\t\t\t\tcontent.slice(0, CONTEXT_FILE_MAX_BYTES) +\n\t\t\t\t\t\t`\\n\\n[truncated: file exceeded ${CONTEXT_FILE_MAX_BYTES} bytes (~10k tokens); keep context files brief — large specs belong in linked files, not in the system prompt]`;\n\t\t\t\t\tsize = \"truncated\";\n\t\t\t\t} else if (bytes > CONTEXT_FILE_WARN_BYTES) {\n\t\t\t\t\tsize = \"large\";\n\t\t\t\t}\n\t\t\t\treturn { file: { path: filePath, content, tokens: Math.round(bytes / 4), size }, warnings };\n\t\t\t} catch (error) {\n\t\t\t\twarnings.push(`Could not read ${filePath}: ${error}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn { file: null, warnings };\n}\n\nexport function loadProjectContextFiles(options: { cwd: string; agentDir: string }): {\n\tagentsFiles: ContextFile[];\n\twarnings: string[];\n} {\n\tconst resolvedCwd = options.cwd;\n\tconst resolvedAgentDir = options.agentDir;\n\n\tconst contextFiles: ContextFile[] = [];\n\tconst warnings: string[] = [];\n\tconst seenPaths = new Set<string>();\n\n\tconst globalResult = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalResult.file) {\n\t\tcontextFiles.push(globalResult.file);\n\t\tseenPaths.add(globalResult.file.path);\n\t}\n\twarnings.push(...globalResult.warnings);\n\n\tconst ancestorContextFiles: ContextFile[] = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst result = loadContextFileFromDir(currentDir);\n\t\tif (result.file && !seenPaths.has(result.file.path)) {\n\t\t\tancestorContextFiles.unshift(result.file);\n\t\t\tseenPaths.add(result.file.path);\n\t\t}\n\t\twarnings.push(...result.warnings);\n\n\t\tif (currentDir === root) break;\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break;\n\t\tcurrentDir = parentDir;\n\t}\n\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn { agentsFiles: contextFiles, warnings };\n}\n"]}
1
+ {"version":3,"file":"context-files.js","sourceRoot":"","sources":["../../src/core/context-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context-file and prompt-input loading for the resource loader.\n *\n * Reads AGENTS.md / CLAUDE.md context files from the user scopes and the cwd\n * ancestor chain (warning/truncating oversized ones, since they are injected\n * into the system prompt every turn), and resolves a system-prompt input that\n * may be either an inline string or a file path. Extracted from resource-loader.ts.\n *\n * Two user scopes are read, least specific first: `~/.agents/AGENTS.md` (the\n * cross-vendor convention, so rules written for one tool are seen by hoocode)\n * and `~/.hoocode/AGENTS.md` (the native home, which therefore wins on\n * conflict). Both are additive — neither shadows the other, and no migration\n * is needed for users who already have the native file.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport { getUserAgentsDir } from \"../config.js\";\n\n/**\n * A loaded context file plus the recurring-cost metadata the UI surfaces.\n * `tokens`/`size` are optional so callers that synthesize context files (SDK\n * overrides, tests) can keep passing plain `{ path, content }`.\n */\nexport interface ContextFile {\n\tpath: string;\n\tcontent: string;\n\t/** Rough token estimate (bytes / 4) of the content as loaded. */\n\ttokens?: number;\n\t/** Set only past the soft limit; \"truncated\" means the hard limit clipped it. */\n\tsize?: \"large\" | \"truncated\";\n}\n\n/**\n * Resolve a prompt input that is either an inline string or a path to a file.\n * If the input names an existing file, its contents are returned; otherwise the\n * input is treated as the prompt text itself.\n */\nexport function resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n// Context files (AGENTS.md / CLAUDE.md) are injected into the system prompt on\n// every turn, so their size has a recurring cost on every provider. Warn the\n// user past a soft limit (~2k tokens) and truncate at a hard limit (~10k tokens)\n// so a pasted spec can't silently bloat every request forever.\nconst CONTEXT_FILE_WARN_BYTES = 8 * 1024;\nconst CONTEXT_FILE_MAX_BYTES = 40 * 1024;\n\n// The per-file limits above cap one file; they say nothing about the total,\n// and the set can now stack two user scopes on top of a whole ancestor chain.\n// So the aggregate gets its own budget, deliberately warn-first: past the soft\n// cap (~6k tokens) the user is told what it costs, and only past the hard cap\n// (~16k tokens) is anything trimmed. Trimming should be the branch that never\n// runs in practice.\nconst CONTEXT_TOTAL_WARN_BYTES = 24 * 1024;\nconst CONTEXT_TOTAL_MAX_BYTES = 64 * 1024;\n// Below this, a trimmed file has no room left to say anything useful, so it is\n// replaced by the notice alone rather than a few words of severed prose.\nconst CONTEXT_TRIM_MIN_BYTES = 512;\n\nfunction loadContextFileFromDir(dir: string): { file: ContextFile | null; warnings: string[] } {\n\tconst warnings: string[] = [];\n\tconst candidates = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\tlet content = readFileSync(filePath, \"utf-8\");\n\t\t\t\tconst bytes = Buffer.byteLength(content, \"utf-8\");\n\t\t\t\t// Size is reported structurally (not as a warning string) so the UI can\n\t\t\t\t// annotate the file where it is already listed instead of repeating it.\n\t\t\t\tlet size: ContextFile[\"size\"];\n\t\t\t\tif (bytes > CONTEXT_FILE_MAX_BYTES) {\n\t\t\t\t\tcontent =\n\t\t\t\t\t\tcontent.slice(0, CONTEXT_FILE_MAX_BYTES) +\n\t\t\t\t\t\t`\\n\\n[truncated: file exceeded ${CONTEXT_FILE_MAX_BYTES} bytes (~10k tokens); keep context files brief — large specs belong in linked files, not in the system prompt]`;\n\t\t\t\t\tsize = \"truncated\";\n\t\t\t\t} else if (bytes > CONTEXT_FILE_WARN_BYTES) {\n\t\t\t\t\tsize = \"large\";\n\t\t\t\t}\n\t\t\t\treturn { file: { path: filePath, content, tokens: Math.round(bytes / 4), size }, warnings };\n\t\t\t} catch (error) {\n\t\t\t\twarnings.push(`Could not read ${filePath}: ${error}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn { file: null, warnings };\n}\n\nexport interface LoadProjectContextFilesOptions {\n\tcwd: string;\n\t/** hoocode's native home, e.g. `~/.hoocode`. */\n\tagentDir: string;\n\t/**\n\t * The cross-vendor user scope, e.g. `~/.agents`. Defaults to `~/.agents`;\n\t * injectable so tests do not read the real home directory.\n\t */\n\tuserAgentsDir?: string;\n}\n\nexport function loadProjectContextFiles(options: LoadProjectContextFilesOptions): {\n\tagentsFiles: ContextFile[];\n\twarnings: string[];\n} {\n\tconst resolvedCwd = options.cwd;\n\tconst resolvedAgentDir = options.agentDir;\n\tconst resolvedUserAgentsDir = options.userAgentsDir ?? getUserAgentsDir();\n\n\tconst contextFiles: ContextFile[] = [];\n\tconst warnings: string[] = [];\n\tconst seenPaths = new Set<string>();\n\n\t// Least specific first: the cross-vendor scope, then the native home. A file\n\t// already seen is never added twice, so pointing both at one directory is a\n\t// no-op rather than a doubled prompt.\n\tfor (const dir of [resolvedUserAgentsDir, resolvedAgentDir]) {\n\t\tconst result = loadContextFileFromDir(dir);\n\t\tif (result.file && !seenPaths.has(result.file.path)) {\n\t\t\tcontextFiles.push(result.file);\n\t\t\tseenPaths.add(result.file.path);\n\t\t}\n\t\twarnings.push(...result.warnings);\n\t}\n\n\tconst ancestorContextFiles: ContextFile[] = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst result = loadContextFileFromDir(currentDir);\n\t\tif (result.file && !seenPaths.has(result.file.path)) {\n\t\t\tancestorContextFiles.unshift(result.file);\n\t\t\tseenPaths.add(result.file.path);\n\t\t}\n\t\twarnings.push(...result.warnings);\n\n\t\tif (currentDir === root) break;\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break;\n\t\tcurrentDir = parentDir;\n\t}\n\n\tcontextFiles.push(...ancestorContextFiles);\n\n\twarnings.push(...enforceTotalBudget(contextFiles));\n\n\treturn { agentsFiles: contextFiles, warnings };\n}\n\n/**\n * Apply the aggregate budget to an already-ordered context-file list.\n *\n * Mutates entries in place and returns any warnings. The list is ordered least\n * specific first, and specificity is what decides who pays: the walk runs from\n * the end so the file nearest the work keeps its budget, and a user-scope file\n * is trimmed before a repo one. Files are trimmed rather than dropped, so a\n * file that stops fitting still says so in the prompt instead of vanishing.\n */\nfunction enforceTotalBudget(files: ContextFile[]): string[] {\n\tconst warnings: string[] = [];\n\tconst total = files.reduce((sum, file) => sum + Buffer.byteLength(file.content, \"utf-8\"), 0);\n\tif (total <= CONTEXT_TOTAL_WARN_BYTES) {\n\t\treturn warnings;\n\t}\n\n\tif (total <= CONTEXT_TOTAL_MAX_BYTES) {\n\t\t// A single oversized file is already priced by the per-file rule, which\n\t\t// flags it `large` and annotates it where it is listed. Repeating that as\n\t\t// an aggregate warning says nothing new. The aggregate exists to catch\n\t\t// what per-file checks structurally cannot see: the sum across scopes.\n\t\tif (files.length < 2) return warnings;\n\t\twarnings.push(\n\t\t\t`Context files total ~${Math.round(total / 4 / 100) / 10}k tokens across ${files.length} file(s), ` +\n\t\t\t\t`re-sent on every request. Keep rules to one line each, and move long or conditional guidance into a skill ` +\n\t\t\t\t`(loaded on demand) rather than a context file (loaded always).`,\n\t\t);\n\t\treturn warnings;\n\t}\n\n\tlet remaining = CONTEXT_TOTAL_MAX_BYTES;\n\tfor (let i = files.length - 1; i >= 0; i--) {\n\t\tconst file = files[i]!;\n\t\tconst bytes = Buffer.byteLength(file.content, \"utf-8\");\n\t\tif (bytes <= remaining) {\n\t\t\tremaining -= bytes;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst notice =\n\t\t\t`\\n\\n[trimmed: context files exceeded ${CONTEXT_TOTAL_MAX_BYTES} bytes (~16k tokens) in total; ` +\n\t\t\t`least-specific scopes are trimmed first — move long guidance into a skill]`;\n\t\tfile.content =\n\t\t\tremaining >= CONTEXT_TRIM_MIN_BYTES ? file.content.slice(0, remaining) + notice : notice.trimStart();\n\t\tfile.size = \"truncated\";\n\t\tfile.tokens = Math.round(Buffer.byteLength(file.content, \"utf-8\") / 4);\n\t\tremaining = 0;\n\t\twarnings.push(`Trimmed ${file.path} — context files exceeded the total budget.`);\n\t}\n\n\treturn warnings;\n}\n"]}
@@ -3,7 +3,7 @@
3
3
  *
4
4
  */
5
5
  import { type EventBus } from "../event-bus.js";
6
- import type { Extension, ExtensionFactory, ExtensionRuntime, LoadExtensionsResult } from "./types.js";
6
+ import type { Extension, ExtensionFactory, ExtensionLoadIssue, ExtensionRuntime, LoadExtensionsResult } from "./types.js";
7
7
  /**
8
8
  * Create a runtime with throwing stubs for action methods.
9
9
  * Runner.bindCore() replaces these with real implementations.
@@ -75,9 +75,6 @@ export declare function defaultPluginDirs(cwd: string, agentDir?: string): strin
75
75
  */
76
76
  export declare function loadPlugins(pluginDirs: string[], cwd: string, eventBus: EventBus, runtime: ExtensionRuntime): Promise<{
77
77
  extensions: Extension[];
78
- errors: Array<{
79
- path: string;
80
- error: string;
81
- }>;
78
+ errors: ExtensionLoadIssue[];
82
79
  }>;
83
80
  //# sourceMappingURL=loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAOhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA8FpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CA+CzD;AA4OD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAepB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAwBrH;AAkHD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAkD/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAEpH;AASD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,EAAE,CAWzF;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAChC,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC;IAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAyCtF","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins, pluginExtensionPath, withheldCapabilities } from \"./plugins/index.js\";\nimport { isWorkspaceTrusted } from \"./plugins/trust.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Whether a discovered plugin sits in the working tree, and therefore came with\n * the repository as far as anyone but its installer can tell.\n *\n * All three project paths count: `<cwd>/.claude/skills` (the vendor convention\n * for repo-committed plugins) and `<cwd>/.agents/plugins` + `<cwd>/.hoocode/plugins`\n * (hoocode's own project-scope install homes). An earlier version listed only the\n * first, reasoning that the hoocode homes held plugins \"the user installed\n * deliberately\" — true of the person who ran the install, and false for every\n * collaborator who clones the result. Location cannot tell those two apart, so it\n * is the wrong thing to ask; {@link isWorkspaceTrusted} asks the right one.\n */\nexport function isProjectSuppliedPlugin(pluginRoot: string, cwd: string): boolean {\n\treturn [\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t].some((root) => isUnderDir(pluginRoot, root));\n}\n\n/**\n * Whether a plugin's **executable** capabilities (hooks, MCP servers) should be\n * withheld: it lives in the working tree and this machine has not trusted the\n * workspace.\n *\n * Passive capabilities always load. Reading a repository's skill text is what\n * opening the repository already implies; starting its processes is not.\n */\nexport function shouldWithholdExecutables(pluginRoot: string, cwd: string, agentDir: string = getAgentDir()): boolean {\n\treturn isProjectSuppliedPlugin(pluginRoot, cwd) && !isWorkspaceTrusted(cwd, agentDir);\n}\n\n/** True when `target` is `root` or sits inside it. */\nfunction isUnderDir(target: string, root: string): boolean {\n\tconst normalized = path.resolve(root);\n\tif (path.resolve(target) === normalized) return true;\n\treturn path.resolve(target).startsWith(normalized.endsWith(path.sep) ? normalized : `${normalized}${path.sep}`);\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global surfaces live next to the agent dir\n * (`~/.agents`, `~/.claude` alongside `~/.hoocode`), so they stay parameterized\n * on `agentDir` rather than hardcoding the home directory.\n *\n * Two of these are *production homes* for plugins hoocode authored, and two are\n * skills directories:\n *\n * - `<cwd>/.agents/plugins` is the legacy project-local install home. Nothing\n * writes there any more; it is read so plugins installed by older versions\n * keep working.\n * - `.claude/skills` (project and personal) implements Claude Code's\n * skills-directory plugins: a folder there carrying `.claude-plugin/plugin.json`\n * is a plugin, and a folder with only a `SKILL.md` stays a plain skill —\n * `parsePluginDir` returns null for the latter, which is exactly the vendor's\n * own rule, so no special-casing is needed here.\n *\n * See docs/plugin-system-architecture.md §5.3 and §5.7.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst home = path.dirname(agentDir);\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(home, \".agents\", \"plugins\"),\n\t\tpath.join(home, \".agents\", \"publish\", \"github\"),\n\t\tpath.join(home, \".claude\", \"skills\"),\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: Array<{ path: string; error: string }> }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\t// Withhold the executable half of a plugin that lives in the working tree\n\t\t\t// until this machine has trusted the workspace. Skills, commands and\n\t\t\t// subagents still load — reading a repository's text is what opening it\n\t\t\t// already implies. See PluginFactoryOptions.passiveOnly.\n\t\t\tconst passiveOnly = shouldWithholdExecutables(plugin.root, cwd);\n\t\t\tconst withheld = passiveOnly ? withheldCapabilities(plugin) : [];\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin, { passiveOnly }),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\tpluginExtensionPath(plugin.id),\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t\tif (withheld.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Plugin \"${plugin.id}\" is in the working tree: ${withheld.join(\" and \")} not loaded. ` +\n\t\t\t\t\t\t\"Code committed to a repository runs for whoever clones it, so hoocode does not start it \" +\n\t\t\t\t\t\t\"until you say this directory is yours to run code from. Run `/plugin trust` to allow it here, \" +\n\t\t\t\t\t\t\"or install the plugin at user scope instead.\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAOhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA8FpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CA+CzD;AA4OD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,EAC1B,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAepB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAwBrH;AAkHD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAkD/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAEpH;AASD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAsB,GAAG,MAAM,EAAE,CAWzF;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAChC,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC;IAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAC,CA8CpE","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins, pluginExtensionPath, withheldCapabilities } from \"./plugins/index.js\";\nimport { isWorkspaceTrusted } from \"./plugins/trust.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionLoadIssue,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Whether a discovered plugin sits in the working tree, and therefore came with\n * the repository as far as anyone but its installer can tell.\n *\n * All three project paths count: `<cwd>/.claude/skills` (the vendor convention\n * for repo-committed plugins) and `<cwd>/.agents/plugins` + `<cwd>/.hoocode/plugins`\n * (hoocode's own project-scope install homes). An earlier version listed only the\n * first, reasoning that the hoocode homes held plugins \"the user installed\n * deliberately\" — true of the person who ran the install, and false for every\n * collaborator who clones the result. Location cannot tell those two apart, so it\n * is the wrong thing to ask; {@link isWorkspaceTrusted} asks the right one.\n */\nexport function isProjectSuppliedPlugin(pluginRoot: string, cwd: string): boolean {\n\treturn [\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t].some((root) => isUnderDir(pluginRoot, root));\n}\n\n/**\n * Whether a plugin's **executable** capabilities (hooks, MCP servers) should be\n * withheld: it lives in the working tree and this machine has not trusted the\n * workspace.\n *\n * Passive capabilities always load. Reading a repository's skill text is what\n * opening the repository already implies; starting its processes is not.\n */\nexport function shouldWithholdExecutables(pluginRoot: string, cwd: string, agentDir: string = getAgentDir()): boolean {\n\treturn isProjectSuppliedPlugin(pluginRoot, cwd) && !isWorkspaceTrusted(cwd, agentDir);\n}\n\n/** True when `target` is `root` or sits inside it. */\nfunction isUnderDir(target: string, root: string): boolean {\n\tconst normalized = path.resolve(root);\n\tif (path.resolve(target) === normalized) return true;\n\treturn path.resolve(target).startsWith(normalized.endsWith(path.sep) ? normalized : `${normalized}${path.sep}`);\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global surfaces live next to the agent dir\n * (`~/.agents`, `~/.claude` alongside `~/.hoocode`), so they stay parameterized\n * on `agentDir` rather than hardcoding the home directory.\n *\n * Two of these are *production homes* for plugins hoocode authored, and two are\n * skills directories:\n *\n * - `<cwd>/.agents/plugins` is the legacy project-local install home. Nothing\n * writes there any more; it is read so plugins installed by older versions\n * keep working.\n * - `.claude/skills` (project and personal) implements Claude Code's\n * skills-directory plugins: a folder there carrying `.claude-plugin/plugin.json`\n * is a plugin, and a folder with only a `SKILL.md` stays a plain skill —\n * `parsePluginDir` returns null for the latter, which is exactly the vendor's\n * own rule, so no special-casing is needed here.\n *\n * See docs/plugin-system-architecture.md §5.3 and §5.7.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst home = path.dirname(agentDir);\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(home, \".agents\", \"plugins\"),\n\t\tpath.join(home, \".agents\", \"publish\", \"github\"),\n\t\tpath.join(home, \".claude\", \"skills\"),\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: ExtensionLoadIssue[] }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: ExtensionLoadIssue[] = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\t// Withhold the executable half of a plugin that lives in the working tree\n\t\t\t// until this machine has trusted the workspace. Skills, commands and\n\t\t\t// subagents still load — reading a repository's text is what opening it\n\t\t\t// already implies. See PluginFactoryOptions.passiveOnly.\n\t\t\tconst passiveOnly = shouldWithholdExecutables(plugin.root, cwd);\n\t\t\tconst withheld = passiveOnly ? withheldCapabilities(plugin) : [];\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin, { passiveOnly }),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\tpluginExtensionPath(plugin.id),\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t\tif (withheld.length > 0) {\n\t\t\t\t// A warning, not an error: the plugin *did* load, minus its executable\n\t\t\t\t// half, and the session must reach the prompt for `/plugin trust` to be\n\t\t\t\t// runnable at all. Reporting this as an error aborted startup, which\n\t\t\t\t// left the only remedy behind a door it had just locked.\n\t\t\t\terrors.push({\n\t\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\t\tseverity: \"warning\",\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Plugin \"${plugin.id}\" is in the working tree: ${withheld.join(\" and \")} not loaded. ` +\n\t\t\t\t\t\t\"Code committed to a repository runs for whoever clones it, so hoocode does not start it \" +\n\t\t\t\t\t\t\"until you say this directory is yours to run code from. Run `/plugin trust` to allow it here, \" +\n\t\t\t\t\t\t\"or install the plugin at user scope instead.\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}
@@ -613,8 +613,13 @@ export async function loadPlugins(pluginDirs, cwd, eventBus, runtime) {
613
613
  const extension = await loadExtensionFromFactory(buildPluginFactory(plugin, { passiveOnly }), cwd, eventBus, runtime, pluginExtensionPath(plugin.id), `plugin:${plugin.id}`);
614
614
  extensions.push(extension);
615
615
  if (withheld.length > 0) {
616
+ // A warning, not an error: the plugin *did* load, minus its executable
617
+ // half, and the session must reach the prompt for `/plugin trust` to be
618
+ // runnable at all. Reporting this as an error aborted startup, which
619
+ // left the only remedy behind a door it had just locked.
616
620
  errors.push({
617
621
  path: plugin.manifestPath,
622
+ severity: "warning",
618
623
  error: `Plugin "${plugin.id}" is in the working tree: ${withheld.join(" and ")} not loaded. ` +
619
624
  "Code committed to a repository runs for whoever clones it, so hoocode does not start it " +
620
625
  "until you say this directory is yours to run code from. Run `/plugin trust` to allow it here, " +
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins, pluginExtensionPath, withheldCapabilities } from \"./plugins/index.js\";\nimport { isWorkspaceTrusted } from \"./plugins/trust.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Whether a discovered plugin sits in the working tree, and therefore came with\n * the repository as far as anyone but its installer can tell.\n *\n * All three project paths count: `<cwd>/.claude/skills` (the vendor convention\n * for repo-committed plugins) and `<cwd>/.agents/plugins` + `<cwd>/.hoocode/plugins`\n * (hoocode's own project-scope install homes). An earlier version listed only the\n * first, reasoning that the hoocode homes held plugins \"the user installed\n * deliberately\" — true of the person who ran the install, and false for every\n * collaborator who clones the result. Location cannot tell those two apart, so it\n * is the wrong thing to ask; {@link isWorkspaceTrusted} asks the right one.\n */\nexport function isProjectSuppliedPlugin(pluginRoot: string, cwd: string): boolean {\n\treturn [\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t].some((root) => isUnderDir(pluginRoot, root));\n}\n\n/**\n * Whether a plugin's **executable** capabilities (hooks, MCP servers) should be\n * withheld: it lives in the working tree and this machine has not trusted the\n * workspace.\n *\n * Passive capabilities always load. Reading a repository's skill text is what\n * opening the repository already implies; starting its processes is not.\n */\nexport function shouldWithholdExecutables(pluginRoot: string, cwd: string, agentDir: string = getAgentDir()): boolean {\n\treturn isProjectSuppliedPlugin(pluginRoot, cwd) && !isWorkspaceTrusted(cwd, agentDir);\n}\n\n/** True when `target` is `root` or sits inside it. */\nfunction isUnderDir(target: string, root: string): boolean {\n\tconst normalized = path.resolve(root);\n\tif (path.resolve(target) === normalized) return true;\n\treturn path.resolve(target).startsWith(normalized.endsWith(path.sep) ? normalized : `${normalized}${path.sep}`);\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global surfaces live next to the agent dir\n * (`~/.agents`, `~/.claude` alongside `~/.hoocode`), so they stay parameterized\n * on `agentDir` rather than hardcoding the home directory.\n *\n * Two of these are *production homes* for plugins hoocode authored, and two are\n * skills directories:\n *\n * - `<cwd>/.agents/plugins` is the legacy project-local install home. Nothing\n * writes there any more; it is read so plugins installed by older versions\n * keep working.\n * - `.claude/skills` (project and personal) implements Claude Code's\n * skills-directory plugins: a folder there carrying `.claude-plugin/plugin.json`\n * is a plugin, and a folder with only a `SKILL.md` stays a plain skill —\n * `parsePluginDir` returns null for the latter, which is exactly the vendor's\n * own rule, so no special-casing is needed here.\n *\n * See docs/plugin-system-architecture.md §5.3 and §5.7.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst home = path.dirname(agentDir);\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(home, \".agents\", \"plugins\"),\n\t\tpath.join(home, \".agents\", \"publish\", \"github\"),\n\t\tpath.join(home, \".claude\", \"skills\"),\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: Array<{ path: string; error: string }> }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\t// Withhold the executable half of a plugin that lives in the working tree\n\t\t\t// until this machine has trusted the workspace. Skills, commands and\n\t\t\t// subagents still load — reading a repository's text is what opening it\n\t\t\t// already implies. See PluginFactoryOptions.passiveOnly.\n\t\t\tconst passiveOnly = shouldWithholdExecutables(plugin.root, cwd);\n\t\t\tconst withheld = passiveOnly ? withheldCapabilities(plugin) : [];\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin, { passiveOnly }),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\tpluginExtensionPath(plugin.id),\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t\tif (withheld.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Plugin \"${plugin.id}\" is in the working tree: ${withheld.join(\" and \")} not loaded. ` +\n\t\t\t\t\t\t\"Code committed to a repository runs for whoever clones it, so hoocode does not start it \" +\n\t\t\t\t\t\t\"until you say this directory is yours to run code from. Run `/plugin trust` to allow it here, \" +\n\t\t\t\t\t\t\"or install the plugin at user scope instead.\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins, pluginExtensionPath, withheldCapabilities } from \"./plugins/index.js\";\nimport { isWorkspaceTrusted } from \"./plugins/trust.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionLoadIssue,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Whether a discovered plugin sits in the working tree, and therefore came with\n * the repository as far as anyone but its installer can tell.\n *\n * All three project paths count: `<cwd>/.claude/skills` (the vendor convention\n * for repo-committed plugins) and `<cwd>/.agents/plugins` + `<cwd>/.hoocode/plugins`\n * (hoocode's own project-scope install homes). An earlier version listed only the\n * first, reasoning that the hoocode homes held plugins \"the user installed\n * deliberately\" — true of the person who ran the install, and false for every\n * collaborator who clones the result. Location cannot tell those two apart, so it\n * is the wrong thing to ask; {@link isWorkspaceTrusted} asks the right one.\n */\nexport function isProjectSuppliedPlugin(pluginRoot: string, cwd: string): boolean {\n\treturn [\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t].some((root) => isUnderDir(pluginRoot, root));\n}\n\n/**\n * Whether a plugin's **executable** capabilities (hooks, MCP servers) should be\n * withheld: it lives in the working tree and this machine has not trusted the\n * workspace.\n *\n * Passive capabilities always load. Reading a repository's skill text is what\n * opening the repository already implies; starting its processes is not.\n */\nexport function shouldWithholdExecutables(pluginRoot: string, cwd: string, agentDir: string = getAgentDir()): boolean {\n\treturn isProjectSuppliedPlugin(pluginRoot, cwd) && !isWorkspaceTrusted(cwd, agentDir);\n}\n\n/** True when `target` is `root` or sits inside it. */\nfunction isUnderDir(target: string, root: string): boolean {\n\tconst normalized = path.resolve(root);\n\tif (path.resolve(target) === normalized) return true;\n\treturn path.resolve(target).startsWith(normalized.endsWith(path.sep) ? normalized : `${normalized}${path.sep}`);\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global surfaces live next to the agent dir\n * (`~/.agents`, `~/.claude` alongside `~/.hoocode`), so they stay parameterized\n * on `agentDir` rather than hardcoding the home directory.\n *\n * Two of these are *production homes* for plugins hoocode authored, and two are\n * skills directories:\n *\n * - `<cwd>/.agents/plugins` is the legacy project-local install home. Nothing\n * writes there any more; it is read so plugins installed by older versions\n * keep working.\n * - `.claude/skills` (project and personal) implements Claude Code's\n * skills-directory plugins: a folder there carrying `.claude-plugin/plugin.json`\n * is a plugin, and a folder with only a `SKILL.md` stays a plain skill —\n * `parsePluginDir` returns null for the latter, which is exactly the vendor's\n * own rule, so no special-casing is needed here.\n *\n * See docs/plugin-system-architecture.md §5.3 and §5.7.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst home = path.dirname(agentDir);\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(home, \".agents\", \"plugins\"),\n\t\tpath.join(home, \".agents\", \"publish\", \"github\"),\n\t\tpath.join(home, \".claude\", \"skills\"),\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: ExtensionLoadIssue[] }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: ExtensionLoadIssue[] = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\t// Withhold the executable half of a plugin that lives in the working tree\n\t\t\t// until this machine has trusted the workspace. Skills, commands and\n\t\t\t// subagents still load — reading a repository's text is what opening it\n\t\t\t// already implies. See PluginFactoryOptions.passiveOnly.\n\t\t\tconst passiveOnly = shouldWithholdExecutables(plugin.root, cwd);\n\t\t\tconst withheld = passiveOnly ? withheldCapabilities(plugin) : [];\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin, { passiveOnly }),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\tpluginExtensionPath(plugin.id),\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t\tif (withheld.length > 0) {\n\t\t\t\t// A warning, not an error: the plugin *did* load, minus its executable\n\t\t\t\t// half, and the session must reach the prompt for `/plugin trust` to be\n\t\t\t\t// runnable at all. Reporting this as an error aborted startup, which\n\t\t\t\t// left the only remedy behind a door it had just locked.\n\t\t\t\terrors.push({\n\t\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\t\tseverity: \"warning\",\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Plugin \"${plugin.id}\" is in the working tree: ${withheld.join(\" and \")} not loaded. ` +\n\t\t\t\t\t\t\"Code committed to a repository runs for whoever clones it, so hoocode does not start it \" +\n\t\t\t\t\t\t\"until you say this directory is yours to run code from. Run `/plugin trust` to allow it here, \" +\n\t\t\t\t\t\t\"or install the plugin at user scope instead.\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}