@kolisachint/hoocode-agent 0.4.155 → 0.4.157

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 (65) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/core/context-files.d.ts +14 -4
  3. package/dist/core/context-files.d.ts.map +1 -1
  4. package/dist/core/context-files.js +7 -4
  5. package/dist/core/context-files.js.map +1 -1
  6. package/dist/core/format-tokens.d.ts +9 -0
  7. package/dist/core/format-tokens.d.ts.map +1 -0
  8. package/dist/core/format-tokens.js +19 -0
  9. package/dist/core/format-tokens.js.map +1 -0
  10. package/dist/core/mcp-status.d.ts +32 -0
  11. package/dist/core/mcp-status.d.ts.map +1 -0
  12. package/dist/core/mcp-status.js +27 -0
  13. package/dist/core/mcp-status.js.map +1 -0
  14. package/dist/core/mode-prompts.d.ts.map +1 -1
  15. package/dist/core/mode-prompts.js +3 -1
  16. package/dist/core/mode-prompts.js.map +1 -1
  17. package/dist/core/resource-loader.d.ts +6 -16
  18. package/dist/core/resource-loader.d.ts.map +1 -1
  19. package/dist/core/resource-loader.js.map +1 -1
  20. package/dist/core/wordmark.d.ts +2 -2
  21. package/dist/core/wordmark.d.ts.map +1 -1
  22. package/dist/core/wordmark.js +4 -4
  23. package/dist/core/wordmark.js.map +1 -1
  24. package/dist/extensions/core/hoo-core.d.ts +3 -0
  25. package/dist/extensions/core/hoo-core.d.ts.map +1 -1
  26. package/dist/extensions/core/hoo-core.js +3 -0
  27. package/dist/extensions/core/hoo-core.js.map +1 -1
  28. package/dist/extensions/core/loop.d.ts +22 -0
  29. package/dist/extensions/core/loop.d.ts.map +1 -1
  30. package/dist/extensions/core/loop.js +36 -6
  31. package/dist/extensions/core/loop.js.map +1 -1
  32. package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
  33. package/dist/extensions/core/mcp-loader.js +27 -3
  34. package/dist/extensions/core/mcp-loader.js.map +1 -1
  35. package/dist/extensions/core/modes.d.ts +52 -1
  36. package/dist/extensions/core/modes.d.ts.map +1 -1
  37. package/dist/extensions/core/modes.js +221 -18
  38. package/dist/extensions/core/modes.js.map +1 -1
  39. package/dist/init-templates.generated.d.ts.map +1 -1
  40. package/dist/init-templates.generated.js +1 -1
  41. package/dist/init-templates.generated.js.map +1 -1
  42. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  43. package/dist/modes/interactive/components/footer.js +1 -11
  44. package/dist/modes/interactive/components/footer.js.map +1 -1
  45. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  46. package/dist/modes/interactive/components/task-panel.js +1 -9
  47. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  48. package/dist/modes/interactive/interactive-mode.d.ts +14 -0
  49. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  50. package/dist/modes/interactive/interactive-mode.js +50 -1
  51. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  52. package/dist/modes/interactive/model-controller.d.ts +6 -0
  53. package/dist/modes/interactive/model-controller.d.ts.map +1 -1
  54. package/dist/modes/interactive/model-controller.js +33 -14
  55. package/dist/modes/interactive/model-controller.js.map +1 -1
  56. package/dist/modes/interactive/resource-display.d.ts +22 -0
  57. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  58. package/dist/modes/interactive/resource-display.js +73 -16
  59. package/dist/modes/interactive/resource-display.js.map +1 -1
  60. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  61. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  62. package/examples/extensions/sandbox/package.json +1 -1
  63. package/examples/extensions/with-deps/package.json +1 -1
  64. package/package.json +4 -4
  65. package/templates/modes/plan/system.md +4 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.157] - 2026-08-07
4
+
5
+ ### Changed
6
+
7
+ - The startup page is one column and states the session instead of narrating it.
8
+ Everything on it now sits on a single left rail under the banner, and the model,
9
+ thinking level, and Anthropic subscription-billing caveat collapse into one
10
+ state line (`claude-sonnet-4-5 · thinking high · anthropic sub — billed as extra
11
+ usage`) rather than three separate status/warning lines that the footer already
12
+ carries for the rest of the session.
13
+ - MCP servers are reported as a capability, not as boot chatter. A successful
14
+ connect no longer prints a line above the summary; live servers get an `⧉` cell
15
+ in the counted grid and a `[MCP]` details row with tool count, background mode,
16
+ and schema deferral. Failures and authorization prompts still surface inline,
17
+ since those need action. The count now covers every source (`mcp.json`,
18
+ per-server files, plugins) instead of only plugin-contributed servers.
19
+ - The agents cell counts dispatchable subagents from the agent registry (and is
20
+ hidden when the Task tool is off). It previously counted only agents contributed
21
+ by package manifests, so a session with five usable agents could show none.
22
+ - Context files are priced where they are listed: an oversized `AGENTS.md` is
23
+ annotated inline (`~3.6k tokens · consider trimming`) instead of repeating the
24
+ file on a separate warning line. Size is now structural data on the loaded file
25
+ (`tokens`, `size`), and `warnings` carries only real failures.
26
+ - The banner tagline is `coding agent`.
27
+
28
+ ### Removed
29
+
30
+ - `hoo-core` no longer appears in the loaded-resources summary or details. It is
31
+ built-in plumbing that is always present, so listing it as "1 extension" said
32
+ nothing about the session.
33
+
34
+ ## [0.4.156] - 2026-08-07
35
+
36
+ ### Added
37
+
38
+ - `/goal` — works autonomously toward a completion condition. `/goal <objective>`
39
+ takes the objective directly; bare `/goal` reads it from the plan's Goal
40
+ section, and the plan's Verification section becomes the completion condition
41
+ either way, which is the difference between a run that stops when it feels
42
+ finished and one that stops when something it can execute says so. Accepts
43
+ `--max-turns N` for the turn budget. Deliberately linear: a single thread of
44
+ execution that iterates until it reports done or exhausts its budget, with no
45
+ task graph and no subtask fan-out. The run inherits whatever the active mode
46
+ already permits (`enabled_tools`, `allowed_bash_commands`,
47
+ `allowed_write_paths`, `auto_allow`), so how much rope an unattended goal gets
48
+ stays a mode-config decision.
49
+ - `/grill` — stress-tests the current plan before `/approve` executes it. Two
50
+ phases: `/grill me` surfaces the request's unconfirmed assumptions as
51
+ `ask_options` questions, and `/grill plan` attacks the plan file itself,
52
+ verifying its claims against the codebase and revising it where it is weak.
53
+ Bare `/grill` runs both, in that order: underspecification sits upstream of
54
+ plan weakness, so critiquing a plan built on a misread request only produces a
55
+ well-reviewed plan for the wrong job — the user's answers are folded into the
56
+ critique instead. Unlike `/approve` the command only injects a follow-up
57
+ message, so there is no session switch, no mode change, and no config write.
58
+ While a `/loop auto` run is active nobody is present to answer a question, so
59
+ the interrogation phase is dropped and the plan critique runs on its own.
60
+
61
+ ### Changed
62
+
63
+ - Plan mode now points at the whole path out of a plan rather than only
64
+ `/approve`: it offers `/grill` to stress-test first, then `/approve` to execute
65
+ step by step or `/goal` to work toward the plan autonomously, and recommends
66
+ grilling whenever the plan carries real risk. Previously the two new commands
67
+ were reachable only if you already knew to type them.
68
+ - The autonomous loop can now be started over the event bus. `LOOP_AUTO_START`
69
+ mirrors the existing `LOOP_HALT` channel in the opposite direction, letting an
70
+ extension drive a run without reaching into state private to `/loop`, and its
71
+ payload carries an optional `continuePrompt` so a caller with a concrete
72
+ completion condition can restate it on every continuation instead of relying
73
+ on the generic nudge. `/loop auto` now shares that same starter; its behaviour
74
+ is unchanged.
75
+
3
76
  ## [0.4.155] - 2026-07-29
4
77
 
5
78
  ## [0.4.154] - 2026-07-23
@@ -6,6 +6,19 @@
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
8
  */
9
+ /**
10
+ * A loaded context file plus the recurring-cost metadata the UI surfaces.
11
+ * `tokens`/`size` are optional so callers that synthesize context files (SDK
12
+ * overrides, tests) can keep passing plain `{ path, content }`.
13
+ */
14
+ export interface ContextFile {
15
+ path: string;
16
+ content: string;
17
+ /** Rough token estimate (bytes / 4) of the content as loaded. */
18
+ tokens?: number;
19
+ /** Set only past the soft limit; "truncated" means the hard limit clipped it. */
20
+ size?: "large" | "truncated";
21
+ }
9
22
  /**
10
23
  * Resolve a prompt input that is either an inline string or a path to a file.
11
24
  * If the input names an existing file, its contents are returned; otherwise the
@@ -16,10 +29,7 @@ export declare function loadProjectContextFiles(options: {
16
29
  cwd: string;
17
30
  agentDir: string;
18
31
  }): {
19
- agentsFiles: Array<{
20
- path: string;
21
- content: string;
22
- }>;
32
+ agentsFiles: ContextFile[];
23
33
  warnings: string[];
24
34
  };
25
35
  //# sourceMappingURL=context-files.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-files.d.ts","sourceRoot":"","sources":["../../src/core/context-files.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAerG;AAqCD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB,CAsCA","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 { basename, join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\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: { path: string; content: string } | 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\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\twarnings.push(`${basename(filePath)} ${bytes} bytes, truncated.`);\n\t\t\t\t} else if (bytes > CONTEXT_FILE_WARN_BYTES) {\n\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t`${basename(filePath)} ~${Math.round(bytes / 4)} tokens, injected every turn — consider trimming.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { file: { path: filePath, content }, 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: Array<{ path: string; content: string }>;\n\twarnings: string[];\n} {\n\tconst resolvedCwd = options.cwd;\n\tconst resolvedAgentDir = options.agentDir;\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\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: Array<{ path: string; content: string }> = [];\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.d.ts","sourceRoot":"","sources":["../../src/core/context-files.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAerG;AAsCD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB,CAsCA","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"]}
@@ -7,7 +7,7 @@
7
7
  * may be either an inline string or a file path. Extracted from resource-loader.ts.
8
8
  */
9
9
  import { existsSync, readFileSync } from "node:fs";
10
- import { basename, join, resolve } from "node:path";
10
+ import { join, resolve } from "node:path";
11
11
  import chalk from "chalk";
12
12
  /**
13
13
  * Resolve a prompt input that is either an inline string or a path to a file.
@@ -44,16 +44,19 @@ function loadContextFileFromDir(dir) {
44
44
  try {
45
45
  let content = readFileSync(filePath, "utf-8");
46
46
  const bytes = Buffer.byteLength(content, "utf-8");
47
+ // Size is reported structurally (not as a warning string) so the UI can
48
+ // annotate the file where it is already listed instead of repeating it.
49
+ let size;
47
50
  if (bytes > CONTEXT_FILE_MAX_BYTES) {
48
51
  content =
49
52
  content.slice(0, CONTEXT_FILE_MAX_BYTES) +
50
53
  `\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]`;
51
- warnings.push(`${basename(filePath)} ${bytes} bytes, truncated.`);
54
+ size = "truncated";
52
55
  }
53
56
  else if (bytes > CONTEXT_FILE_WARN_BYTES) {
54
- warnings.push(`${basename(filePath)} ~${Math.round(bytes / 4)} tokens, injected every turn — consider trimming.`);
57
+ size = "large";
55
58
  }
56
- return { file: { path: filePath, content }, warnings };
59
+ return { file: { path: filePath, content, tokens: Math.round(bytes / 4), size }, warnings };
57
60
  }
58
61
  catch (error) {
59
62
  warnings.push(`Could not read ${filePath}: ${error}`);
@@ -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 { basename, join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\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: { path: string; content: string } | 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\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\twarnings.push(`${basename(filePath)} ${bytes} bytes, truncated.`);\n\t\t\t\t} else if (bytes > CONTEXT_FILE_WARN_BYTES) {\n\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t`${basename(filePath)} ~${Math.round(bytes / 4)} tokens, injected every turn — consider trimming.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { file: { path: filePath, content }, 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: Array<{ path: string; content: string }>;\n\twarnings: string[];\n} {\n\tconst resolvedCwd = options.cwd;\n\tconst resolvedAgentDir = options.agentDir;\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\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: Array<{ path: string; content: string }> = [];\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 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"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Compact token/count formatting shared by the surfaces that report numbers
3
+ * (footer, task panel, startup resource summary).
4
+ *
5
+ * Numbers stay exact where they fit and degrade to one decimal of `k`/`M` so a
6
+ * count never grows the fixed-width chrome it sits in.
7
+ */
8
+ export declare function formatTokens(count: number): string;
9
+ //# sourceMappingURL=format-tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-tokens.d.ts","sourceRoot":"","sources":["../../src/core/format-tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD","sourcesContent":["/**\n * Compact token/count formatting shared by the surfaces that report numbers\n * (footer, task panel, startup resource summary).\n *\n * Numbers stay exact where they fit and degrade to one decimal of `k`/`M` so a\n * count never grows the fixed-width chrome it sits in.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Compact token/count formatting shared by the surfaces that report numbers
3
+ * (footer, task panel, startup resource summary).
4
+ *
5
+ * Numbers stay exact where they fit and degrade to one decimal of `k`/`M` so a
6
+ * count never grows the fixed-width chrome it sits in.
7
+ */
8
+ export function formatTokens(count) {
9
+ if (count < 1000)
10
+ return count.toString();
11
+ if (count < 10000)
12
+ return `${(count / 1000).toFixed(1)}k`;
13
+ if (count < 1000000)
14
+ return `${Math.round(count / 1000)}k`;
15
+ if (count < 10000000)
16
+ return `${(count / 1000000).toFixed(1)}M`;
17
+ return `${Math.round(count / 1000000)}M`;
18
+ }
19
+ //# sourceMappingURL=format-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-tokens.js","sourceRoot":"","sources":["../../src/core/format-tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAU;IACnD,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1C,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,IAAI,KAAK,GAAG,OAAO;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC;IAC3D,IAAI,KAAK,GAAG,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC;AAAA,CACzC","sourcesContent":["/**\n * Compact token/count formatting shared by the surfaces that report numbers\n * (footer, task panel, startup resource summary).\n *\n * Numbers stay exact where they fit and degrade to one decimal of `k`/`M` so a\n * count never grows the fixed-width chrome it sits in.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Process-global registry of MCP servers that actually connected this session.
3
+ *
4
+ * MCP discovery and connection happen inside the hoo-core `mcp-loader` module on
5
+ * `session_start`, from several sources (standard `mcp.json` files, hoocode's
6
+ * per-server JSON files, plugin registrations). The startup resource summary
7
+ * needs a single answer to "which servers are live and how many tools do they
8
+ * bring", so the loader records each outcome here and the UI reads it.
9
+ *
10
+ * Mirrors the module-global approach of `extension-mcp-servers.ts`. The registry
11
+ * is cleared at the start of each connect pass so a session switch or reload
12
+ * rebuilds it instead of accumulating.
13
+ */
14
+ export interface McpServerStatus {
15
+ /** Server name, as used in the `mcp_<server>_<tool>` prefix. */
16
+ name: string;
17
+ /** Tools the server exposed on connect. */
18
+ toolCount: number;
19
+ /** Tools default to background execution (task-panel rows) rather than inline. */
20
+ background: boolean;
21
+ /** Tool names are injected but schemas are materialized on demand. */
22
+ deferred: boolean;
23
+ /** `authorizing` means a browser OAuth flow is in flight; tools register when it completes. */
24
+ state: "connected" | "authorizing";
25
+ }
26
+ /** Record (or replace) the connection outcome for one server. */
27
+ export declare function setMcpServerStatus(status: McpServerStatus): void;
28
+ /** All servers that connected (or are awaiting authorization) this session. */
29
+ export declare function getMcpServerStatuses(): McpServerStatus[];
30
+ /** Clear the registry. Called before each connect pass so reloads rebuild it. */
31
+ export declare function clearMcpServerStatuses(): void;
32
+ //# sourceMappingURL=mcp-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-status.d.ts","sourceRoot":"","sources":["../../src/core/mcp-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,eAAe;IAC/B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAC;IACpB,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,+FAA+F;IAC/F,KAAK,EAAE,WAAW,GAAG,aAAa,CAAC;CACnC;AAID,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAEhE;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAExD;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C","sourcesContent":["/**\n * Process-global registry of MCP servers that actually connected this session.\n *\n * MCP discovery and connection happen inside the hoo-core `mcp-loader` module on\n * `session_start`, from several sources (standard `mcp.json` files, hoocode's\n * per-server JSON files, plugin registrations). The startup resource summary\n * needs a single answer to \"which servers are live and how many tools do they\n * bring\", so the loader records each outcome here and the UI reads it.\n *\n * Mirrors the module-global approach of `extension-mcp-servers.ts`. The registry\n * is cleared at the start of each connect pass so a session switch or reload\n * rebuilds it instead of accumulating.\n */\n\nexport interface McpServerStatus {\n\t/** Server name, as used in the `mcp_<server>_<tool>` prefix. */\n\tname: string;\n\t/** Tools the server exposed on connect. */\n\ttoolCount: number;\n\t/** Tools default to background execution (task-panel rows) rather than inline. */\n\tbackground: boolean;\n\t/** Tool names are injected but schemas are materialized on demand. */\n\tdeferred: boolean;\n\t/** `authorizing` means a browser OAuth flow is in flight; tools register when it completes. */\n\tstate: \"connected\" | \"authorizing\";\n}\n\nconst statuses = new Map<string, McpServerStatus>();\n\n/** Record (or replace) the connection outcome for one server. */\nexport function setMcpServerStatus(status: McpServerStatus): void {\n\tstatuses.set(status.name, status);\n}\n\n/** All servers that connected (or are awaiting authorization) this session. */\nexport function getMcpServerStatuses(): McpServerStatus[] {\n\treturn [...statuses.values()];\n}\n\n/** Clear the registry. Called before each connect pass so reloads rebuild it. */\nexport function clearMcpServerStatuses(): void {\n\tstatuses.clear();\n}\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Process-global registry of MCP servers that actually connected this session.
3
+ *
4
+ * MCP discovery and connection happen inside the hoo-core `mcp-loader` module on
5
+ * `session_start`, from several sources (standard `mcp.json` files, hoocode's
6
+ * per-server JSON files, plugin registrations). The startup resource summary
7
+ * needs a single answer to "which servers are live and how many tools do they
8
+ * bring", so the loader records each outcome here and the UI reads it.
9
+ *
10
+ * Mirrors the module-global approach of `extension-mcp-servers.ts`. The registry
11
+ * is cleared at the start of each connect pass so a session switch or reload
12
+ * rebuilds it instead of accumulating.
13
+ */
14
+ const statuses = new Map();
15
+ /** Record (or replace) the connection outcome for one server. */
16
+ export function setMcpServerStatus(status) {
17
+ statuses.set(status.name, status);
18
+ }
19
+ /** All servers that connected (or are awaiting authorization) this session. */
20
+ export function getMcpServerStatuses() {
21
+ return [...statuses.values()];
22
+ }
23
+ /** Clear the registry. Called before each connect pass so reloads rebuild it. */
24
+ export function clearMcpServerStatuses() {
25
+ statuses.clear();
26
+ }
27
+ //# sourceMappingURL=mcp-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-status.js","sourceRoot":"","sources":["../../src/core/mcp-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEpD,iEAAiE;AACjE,MAAM,UAAU,kBAAkB,CAAC,MAAuB,EAAQ;IACjE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,CAClC;AAED,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,GAAsB;IACzD,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAAA,CAC9B;AAED,iFAAiF;AACjF,MAAM,UAAU,sBAAsB,GAAS;IAC9C,QAAQ,CAAC,KAAK,EAAE,CAAC;AAAA,CACjB","sourcesContent":["/**\n * Process-global registry of MCP servers that actually connected this session.\n *\n * MCP discovery and connection happen inside the hoo-core `mcp-loader` module on\n * `session_start`, from several sources (standard `mcp.json` files, hoocode's\n * per-server JSON files, plugin registrations). The startup resource summary\n * needs a single answer to \"which servers are live and how many tools do they\n * bring\", so the loader records each outcome here and the UI reads it.\n *\n * Mirrors the module-global approach of `extension-mcp-servers.ts`. The registry\n * is cleared at the start of each connect pass so a session switch or reload\n * rebuilds it instead of accumulating.\n */\n\nexport interface McpServerStatus {\n\t/** Server name, as used in the `mcp_<server>_<tool>` prefix. */\n\tname: string;\n\t/** Tools the server exposed on connect. */\n\ttoolCount: number;\n\t/** Tools default to background execution (task-panel rows) rather than inline. */\n\tbackground: boolean;\n\t/** Tool names are injected but schemas are materialized on demand. */\n\tdeferred: boolean;\n\t/** `authorizing` means a browser OAuth flow is in flight; tools register when it completes. */\n\tstate: \"connected\" | \"authorizing\";\n}\n\nconst statuses = new Map<string, McpServerStatus>();\n\n/** Record (or replace) the connection outcome for one server. */\nexport function setMcpServerStatus(status: McpServerStatus): void {\n\tstatuses.set(status.name, status);\n}\n\n/** All servers that connected (or are awaiting authorization) this session. */\nexport function getMcpServerStatuses(): McpServerStatus[] {\n\treturn [...statuses.values()];\n}\n\n/** Clear the registry. Called before each connect pass so reloads rebuild it. */\nexport function clearMcpServerStatuses(): void {\n\tstatuses.clear();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mode-prompts.d.ts","sourceRoot":"","sources":["../../src/core/mode-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qDAAqD;AACrD,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,2DAA2D;AAC3D,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0BvD,CAAC","sourcesContent":["/**\n * Canonical built-in mode prompts and the default active mode.\n *\n * These are the fallback system prompts hoocode ships for its four built-in\n * modes (ask / plan / build / debug). They are resolved only when a project or\n * user has not supplied a `modes/{name}/system.md` override.\n *\n * Extracted into a standalone module (instead of living inside the internal\n * `hoo-core` extension's `modes` module) so downstream apps embedding hoocode can import,\n * inspect, and extend the shipped prompts without copy-pasting them.\n */\n\n/** Mode used when no `active_mode` is configured. */\nexport const DEFAULT_MODE = \"build\";\n\n/** Built-in fallback system prompts keyed by mode name. */\nexport const DEFAULT_MODE_PROMPTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user to run /approve to execute it.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n"]}
1
+ {"version":3,"file":"mode-prompts.d.ts","sourceRoot":"","sources":["../../src/core/mode-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qDAAqD;AACrD,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,2DAA2D;AAC3D,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA4BvD,CAAC","sourcesContent":["/**\n * Canonical built-in mode prompts and the default active mode.\n *\n * These are the fallback system prompts hoocode ships for its four built-in\n * modes (ask / plan / build / debug). They are resolved only when a project or\n * user has not supplied a `modes/{name}/system.md` override.\n *\n * Extracted into a standalone module (instead of living inside the internal\n * `hoo-core` extension's `modes` module) so downstream apps embedding hoocode can import,\n * inspect, and extend the shipped prompts without copy-pasting them.\n */\n\n/** Mode used when no `active_mode` is configured. */\nexport const DEFAULT_MODE = \"build\";\n\n/** Built-in fallback system prompts keyed by mode name. */\nexport const DEFAULT_MODE_PROMPTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user their options: /grill to stress-test it\nfirst, then /approve to execute it step by step or /goal to work toward it\nautonomously. Recommend /grill when the plan carries real risk.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n"]}
@@ -22,7 +22,9 @@ Cite specific file paths and line numbers in your answers.`,
22
22
  Explore the codebase thoroughly. Understand the current structure.
23
23
  Draft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.
24
24
  Write the plan to {{PLAN_PATH}}.
25
- When the plan is complete, tell the user to run /approve to execute it.`,
25
+ When the plan is complete, tell the user their options: /grill to stress-test it
26
+ first, then /approve to execute it step by step or /goal to work toward it
27
+ autonomously. Recommend /grill when the plan carries real risk.`,
26
28
  build: `You are in BUILD mode — careful implementation.
27
29
  Read files before editing them. Show diffs before non-trivial changes.
28
30
  Ask for confirmation before destructive operations (delete, reformat).
@@ -1 +1 @@
1
- {"version":3,"file":"mode-prompts.js","sourceRoot":"","sources":["../../src/core/mode-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAEpC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC3D,GAAG,EAAE;;;;2DAIqD;IAE1D,IAAI,EAAE;;;;wEAIiE;IAEvE,KAAK,EAAE;;;;;+CAKuC;IAE9C,KAAK,EAAE;;;;;+BAKuB;CAC9B,CAAC","sourcesContent":["/**\n * Canonical built-in mode prompts and the default active mode.\n *\n * These are the fallback system prompts hoocode ships for its four built-in\n * modes (ask / plan / build / debug). They are resolved only when a project or\n * user has not supplied a `modes/{name}/system.md` override.\n *\n * Extracted into a standalone module (instead of living inside the internal\n * `hoo-core` extension's `modes` module) so downstream apps embedding hoocode can import,\n * inspect, and extend the shipped prompts without copy-pasting them.\n */\n\n/** Mode used when no `active_mode` is configured. */\nexport const DEFAULT_MODE = \"build\";\n\n/** Built-in fallback system prompts keyed by mode name. */\nexport const DEFAULT_MODE_PROMPTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user to run /approve to execute it.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n"]}
1
+ {"version":3,"file":"mode-prompts.js","sourceRoot":"","sources":["../../src/core/mode-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAEpC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC3D,GAAG,EAAE;;;;2DAIqD;IAE1D,IAAI,EAAE;;;;;;gEAMyD;IAE/D,KAAK,EAAE;;;;;+CAKuC;IAE9C,KAAK,EAAE;;;;;+BAKuB;CAC9B,CAAC","sourcesContent":["/**\n * Canonical built-in mode prompts and the default active mode.\n *\n * These are the fallback system prompts hoocode ships for its four built-in\n * modes (ask / plan / build / debug). They are resolved only when a project or\n * user has not supplied a `modes/{name}/system.md` override.\n *\n * Extracted into a standalone module (instead of living inside the internal\n * `hoo-core` extension's `modes` module) so downstream apps embedding hoocode can import,\n * inspect, and extend the shipped prompts without copy-pasting them.\n */\n\n/** Mode used when no `active_mode` is configured. */\nexport const DEFAULT_MODE = \"build\";\n\n/** Built-in fallback system prompts keyed by mode name. */\nexport const DEFAULT_MODE_PROMPTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user their options: /grill to stress-test it\nfirst, then /approve to execute it step by step or /goal to work toward it\nautonomously. Recommend /grill when the plan carries real risk.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n"]}
@@ -1,7 +1,9 @@
1
1
  import { type Theme } from "../modes/interactive/theme/theme.js";
2
2
  import type { ResourceDiagnostic } from "./diagnostics.js";
3
+ export type { ContextFile } from "./context-files.js";
3
4
  export { loadProjectContextFiles } from "./context-files.js";
4
5
  export type { ResourceCollision, ResourceDiagnostic } from "./diagnostics.js";
6
+ import { type ContextFile } from "./context-files.js";
5
7
  import { type EventBus } from "./event-bus.js";
6
8
  import type { ExtensionFactory, LoadExtensionsResult } from "./extensions/types.js";
7
9
  import { type PathMetadata } from "./package-manager.js";
@@ -56,10 +58,7 @@ export interface ResourceLoader {
56
58
  diagnostics: ResourceDiagnostic[];
57
59
  };
58
60
  getAgentsFiles(): {
59
- agentsFiles: Array<{
60
- path: string;
61
- content: string;
62
- }>;
61
+ agentsFiles: ContextFile[];
63
62
  warnings: string[];
64
63
  };
65
64
  getSystemPrompt(): string | undefined;
@@ -110,16 +109,10 @@ export interface DefaultResourceLoaderOptions {
110
109
  diagnostics: ResourceDiagnostic[];
111
110
  };
112
111
  agentsFilesOverride?: (base: {
113
- agentsFiles: Array<{
114
- path: string;
115
- content: string;
116
- }>;
112
+ agentsFiles: ContextFile[];
117
113
  warnings: string[];
118
114
  }) => {
119
- agentsFiles: Array<{
120
- path: string;
121
- content: string;
122
- }>;
115
+ agentsFiles: ContextFile[];
123
116
  warnings?: string[];
124
117
  };
125
118
  systemPromptOverride?: (base: string | undefined) => string | undefined;
@@ -188,10 +181,7 @@ export declare class DefaultResourceLoader implements ResourceLoader {
188
181
  diagnostics: ResourceDiagnostic[];
189
182
  };
190
183
  getAgentsFiles(): {
191
- agentsFiles: Array<{
192
- path: string;
193
- content: string;
194
- }>;
184
+ agentsFiles: ContextFile[];
195
185
  warnings: string[];
196
186
  };
197
187
  getSystemPrompt(): string | undefined;