@oh-my-pi/pi-coding-agent 1.337.0

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 (224) hide show
  1. package/CHANGELOG.md +1228 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/custom-tools.md +541 -0
  5. package/docs/extension-loading.md +1004 -0
  6. package/docs/hooks.md +867 -0
  7. package/docs/rpc.md +1040 -0
  8. package/docs/sdk.md +994 -0
  9. package/docs/session-tree-plan.md +441 -0
  10. package/docs/session.md +240 -0
  11. package/docs/skills.md +290 -0
  12. package/docs/theme.md +637 -0
  13. package/docs/tree.md +197 -0
  14. package/docs/tui.md +341 -0
  15. package/examples/README.md +21 -0
  16. package/examples/custom-tools/README.md +124 -0
  17. package/examples/custom-tools/hello/index.ts +20 -0
  18. package/examples/custom-tools/question/index.ts +84 -0
  19. package/examples/custom-tools/subagent/README.md +172 -0
  20. package/examples/custom-tools/subagent/agents/planner.md +37 -0
  21. package/examples/custom-tools/subagent/agents/reviewer.md +35 -0
  22. package/examples/custom-tools/subagent/agents/scout.md +50 -0
  23. package/examples/custom-tools/subagent/agents/worker.md +24 -0
  24. package/examples/custom-tools/subagent/agents.ts +156 -0
  25. package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
  26. package/examples/custom-tools/subagent/commands/implement.md +10 -0
  27. package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
  28. package/examples/custom-tools/subagent/index.ts +1002 -0
  29. package/examples/custom-tools/todo/index.ts +212 -0
  30. package/examples/hooks/README.md +56 -0
  31. package/examples/hooks/auto-commit-on-exit.ts +49 -0
  32. package/examples/hooks/confirm-destructive.ts +59 -0
  33. package/examples/hooks/custom-compaction.ts +116 -0
  34. package/examples/hooks/dirty-repo-guard.ts +52 -0
  35. package/examples/hooks/file-trigger.ts +41 -0
  36. package/examples/hooks/git-checkpoint.ts +53 -0
  37. package/examples/hooks/handoff.ts +150 -0
  38. package/examples/hooks/permission-gate.ts +34 -0
  39. package/examples/hooks/protected-paths.ts +30 -0
  40. package/examples/hooks/qna.ts +119 -0
  41. package/examples/hooks/snake.ts +343 -0
  42. package/examples/hooks/status-line.ts +40 -0
  43. package/examples/sdk/01-minimal.ts +22 -0
  44. package/examples/sdk/02-custom-model.ts +49 -0
  45. package/examples/sdk/03-custom-prompt.ts +44 -0
  46. package/examples/sdk/04-skills.ts +44 -0
  47. package/examples/sdk/05-tools.ts +90 -0
  48. package/examples/sdk/06-hooks.ts +61 -0
  49. package/examples/sdk/07-context-files.ts +36 -0
  50. package/examples/sdk/08-slash-commands.ts +42 -0
  51. package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
  52. package/examples/sdk/10-settings.ts +38 -0
  53. package/examples/sdk/11-sessions.ts +48 -0
  54. package/examples/sdk/12-full-control.ts +95 -0
  55. package/examples/sdk/README.md +154 -0
  56. package/package.json +81 -0
  57. package/src/cli/args.ts +246 -0
  58. package/src/cli/file-processor.ts +72 -0
  59. package/src/cli/list-models.ts +104 -0
  60. package/src/cli/plugin-cli.ts +650 -0
  61. package/src/cli/session-picker.ts +41 -0
  62. package/src/cli.ts +10 -0
  63. package/src/commands/init.md +20 -0
  64. package/src/config.ts +159 -0
  65. package/src/core/agent-session.ts +1900 -0
  66. package/src/core/auth-storage.ts +236 -0
  67. package/src/core/bash-executor.ts +196 -0
  68. package/src/core/compaction/branch-summarization.ts +343 -0
  69. package/src/core/compaction/compaction.ts +742 -0
  70. package/src/core/compaction/index.ts +7 -0
  71. package/src/core/compaction/utils.ts +154 -0
  72. package/src/core/custom-tools/index.ts +21 -0
  73. package/src/core/custom-tools/loader.ts +248 -0
  74. package/src/core/custom-tools/types.ts +169 -0
  75. package/src/core/custom-tools/wrapper.ts +28 -0
  76. package/src/core/exec.ts +129 -0
  77. package/src/core/export-html/index.ts +211 -0
  78. package/src/core/export-html/template.css +781 -0
  79. package/src/core/export-html/template.html +54 -0
  80. package/src/core/export-html/template.js +1185 -0
  81. package/src/core/export-html/vendor/highlight.min.js +1213 -0
  82. package/src/core/export-html/vendor/marked.min.js +6 -0
  83. package/src/core/hooks/index.ts +16 -0
  84. package/src/core/hooks/loader.ts +312 -0
  85. package/src/core/hooks/runner.ts +434 -0
  86. package/src/core/hooks/tool-wrapper.ts +99 -0
  87. package/src/core/hooks/types.ts +773 -0
  88. package/src/core/index.ts +52 -0
  89. package/src/core/mcp/client.ts +158 -0
  90. package/src/core/mcp/config.ts +154 -0
  91. package/src/core/mcp/index.ts +45 -0
  92. package/src/core/mcp/loader.ts +68 -0
  93. package/src/core/mcp/manager.ts +181 -0
  94. package/src/core/mcp/tool-bridge.ts +148 -0
  95. package/src/core/mcp/transports/http.ts +316 -0
  96. package/src/core/mcp/transports/index.ts +6 -0
  97. package/src/core/mcp/transports/stdio.ts +252 -0
  98. package/src/core/mcp/types.ts +220 -0
  99. package/src/core/messages.ts +189 -0
  100. package/src/core/model-registry.ts +317 -0
  101. package/src/core/model-resolver.ts +393 -0
  102. package/src/core/plugins/doctor.ts +59 -0
  103. package/src/core/plugins/index.ts +38 -0
  104. package/src/core/plugins/installer.ts +189 -0
  105. package/src/core/plugins/loader.ts +338 -0
  106. package/src/core/plugins/manager.ts +672 -0
  107. package/src/core/plugins/parser.ts +105 -0
  108. package/src/core/plugins/paths.ts +32 -0
  109. package/src/core/plugins/types.ts +190 -0
  110. package/src/core/sdk.ts +760 -0
  111. package/src/core/session-manager.ts +1128 -0
  112. package/src/core/settings-manager.ts +443 -0
  113. package/src/core/skills.ts +437 -0
  114. package/src/core/slash-commands.ts +248 -0
  115. package/src/core/system-prompt.ts +439 -0
  116. package/src/core/timings.ts +25 -0
  117. package/src/core/tools/ask.ts +211 -0
  118. package/src/core/tools/bash-interceptor.ts +120 -0
  119. package/src/core/tools/bash.ts +250 -0
  120. package/src/core/tools/context.ts +32 -0
  121. package/src/core/tools/edit-diff.ts +475 -0
  122. package/src/core/tools/edit.ts +208 -0
  123. package/src/core/tools/exa/company.ts +59 -0
  124. package/src/core/tools/exa/index.ts +64 -0
  125. package/src/core/tools/exa/linkedin.ts +59 -0
  126. package/src/core/tools/exa/logger.ts +56 -0
  127. package/src/core/tools/exa/mcp-client.ts +368 -0
  128. package/src/core/tools/exa/render.ts +196 -0
  129. package/src/core/tools/exa/researcher.ts +90 -0
  130. package/src/core/tools/exa/search.ts +337 -0
  131. package/src/core/tools/exa/types.ts +168 -0
  132. package/src/core/tools/exa/websets.ts +248 -0
  133. package/src/core/tools/find.ts +261 -0
  134. package/src/core/tools/grep.ts +555 -0
  135. package/src/core/tools/index.ts +202 -0
  136. package/src/core/tools/ls.ts +140 -0
  137. package/src/core/tools/lsp/client.ts +605 -0
  138. package/src/core/tools/lsp/config.ts +147 -0
  139. package/src/core/tools/lsp/edits.ts +101 -0
  140. package/src/core/tools/lsp/index.ts +804 -0
  141. package/src/core/tools/lsp/render.ts +447 -0
  142. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  143. package/src/core/tools/lsp/types.ts +463 -0
  144. package/src/core/tools/lsp/utils.ts +486 -0
  145. package/src/core/tools/notebook.ts +229 -0
  146. package/src/core/tools/path-utils.ts +61 -0
  147. package/src/core/tools/read.ts +240 -0
  148. package/src/core/tools/renderers.ts +540 -0
  149. package/src/core/tools/task/agents.ts +153 -0
  150. package/src/core/tools/task/artifacts.ts +114 -0
  151. package/src/core/tools/task/bundled-agents/browser.md +71 -0
  152. package/src/core/tools/task/bundled-agents/explore.md +82 -0
  153. package/src/core/tools/task/bundled-agents/plan.md +54 -0
  154. package/src/core/tools/task/bundled-agents/reviewer.md +59 -0
  155. package/src/core/tools/task/bundled-agents/task.md +53 -0
  156. package/src/core/tools/task/bundled-commands/architect-plan.md +10 -0
  157. package/src/core/tools/task/bundled-commands/implement-with-critic.md +11 -0
  158. package/src/core/tools/task/bundled-commands/implement.md +11 -0
  159. package/src/core/tools/task/commands.ts +213 -0
  160. package/src/core/tools/task/discovery.ts +208 -0
  161. package/src/core/tools/task/executor.ts +367 -0
  162. package/src/core/tools/task/index.ts +388 -0
  163. package/src/core/tools/task/model-resolver.ts +115 -0
  164. package/src/core/tools/task/parallel.ts +38 -0
  165. package/src/core/tools/task/render.ts +232 -0
  166. package/src/core/tools/task/types.ts +99 -0
  167. package/src/core/tools/truncate.ts +265 -0
  168. package/src/core/tools/web-fetch.ts +2370 -0
  169. package/src/core/tools/web-search/auth.ts +193 -0
  170. package/src/core/tools/web-search/index.ts +537 -0
  171. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  172. package/src/core/tools/web-search/providers/exa.ts +302 -0
  173. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  174. package/src/core/tools/web-search/render.ts +182 -0
  175. package/src/core/tools/web-search/types.ts +180 -0
  176. package/src/core/tools/write.ts +99 -0
  177. package/src/index.ts +176 -0
  178. package/src/main.ts +464 -0
  179. package/src/migrations.ts +135 -0
  180. package/src/modes/index.ts +43 -0
  181. package/src/modes/interactive/components/armin.ts +382 -0
  182. package/src/modes/interactive/components/assistant-message.ts +86 -0
  183. package/src/modes/interactive/components/bash-execution.ts +196 -0
  184. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  185. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  186. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  187. package/src/modes/interactive/components/custom-editor.ts +122 -0
  188. package/src/modes/interactive/components/diff.ts +147 -0
  189. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  190. package/src/modes/interactive/components/footer.ts +381 -0
  191. package/src/modes/interactive/components/hook-editor.ts +117 -0
  192. package/src/modes/interactive/components/hook-input.ts +64 -0
  193. package/src/modes/interactive/components/hook-message.ts +96 -0
  194. package/src/modes/interactive/components/hook-selector.ts +91 -0
  195. package/src/modes/interactive/components/model-selector.ts +247 -0
  196. package/src/modes/interactive/components/oauth-selector.ts +120 -0
  197. package/src/modes/interactive/components/plugin-settings.ts +479 -0
  198. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  199. package/src/modes/interactive/components/session-selector.ts +204 -0
  200. package/src/modes/interactive/components/settings-selector.ts +453 -0
  201. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  202. package/src/modes/interactive/components/theme-selector.ts +62 -0
  203. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  204. package/src/modes/interactive/components/tool-execution.ts +675 -0
  205. package/src/modes/interactive/components/tree-selector.ts +866 -0
  206. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  207. package/src/modes/interactive/components/user-message.ts +18 -0
  208. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  209. package/src/modes/interactive/components/welcome.ts +183 -0
  210. package/src/modes/interactive/interactive-mode.ts +2516 -0
  211. package/src/modes/interactive/theme/dark.json +101 -0
  212. package/src/modes/interactive/theme/light.json +98 -0
  213. package/src/modes/interactive/theme/theme-schema.json +308 -0
  214. package/src/modes/interactive/theme/theme.ts +998 -0
  215. package/src/modes/print-mode.ts +128 -0
  216. package/src/modes/rpc/rpc-client.ts +527 -0
  217. package/src/modes/rpc/rpc-mode.ts +483 -0
  218. package/src/modes/rpc/rpc-types.ts +203 -0
  219. package/src/utils/changelog.ts +99 -0
  220. package/src/utils/clipboard.ts +265 -0
  221. package/src/utils/fuzzy.ts +108 -0
  222. package/src/utils/mime.ts +30 -0
  223. package/src/utils/shell.ts +276 -0
  224. package/src/utils/tools-manager.ts +274 -0
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Status Line Hook
3
+ *
4
+ * Demonstrates ctx.ui.setStatus() for displaying persistent status text in the footer.
5
+ * Shows turn progress with themed colors.
6
+ */
7
+
8
+ import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
9
+
10
+ export default function (pi: HookAPI) {
11
+ let turnCount = 0;
12
+
13
+ pi.on("session_start", async (_event, ctx) => {
14
+ const theme = ctx.ui.theme;
15
+ ctx.ui.setStatus("status-demo", theme.fg("dim", "Ready"));
16
+ });
17
+
18
+ pi.on("turn_start", async (_event, ctx) => {
19
+ turnCount++;
20
+ const theme = ctx.ui.theme;
21
+ const spinner = theme.fg("accent", "●");
22
+ const text = theme.fg("dim", ` Turn ${turnCount}...`);
23
+ ctx.ui.setStatus("status-demo", spinner + text);
24
+ });
25
+
26
+ pi.on("turn_end", async (_event, ctx) => {
27
+ const theme = ctx.ui.theme;
28
+ const check = theme.fg("success", "✓");
29
+ const text = theme.fg("dim", ` Turn ${turnCount} complete`);
30
+ ctx.ui.setStatus("status-demo", check + text);
31
+ });
32
+
33
+ pi.on("session_switch", async (event, ctx) => {
34
+ if (event.reason === "new") {
35
+ turnCount = 0;
36
+ const theme = ctx.ui.theme;
37
+ ctx.ui.setStatus("status-demo", theme.fg("dim", "Ready"));
38
+ }
39
+ });
40
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Minimal SDK Usage
3
+ *
4
+ * Uses all defaults: discovers skills, hooks, tools, context files
5
+ * from cwd and ~/.pi/agent. Model chosen from settings or first available.
6
+ */
7
+
8
+ import { createAgentSession } from "@oh-my-pi/pi-coding-agent";
9
+
10
+ const { session } = await createAgentSession();
11
+
12
+ session.subscribe((event) => {
13
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
14
+ process.stdout.write(event.assistantMessageEvent.delta);
15
+ }
16
+ });
17
+
18
+ await session.prompt("What files are in the current directory?");
19
+ session.state.messages.forEach((msg) => {
20
+ console.log(msg);
21
+ });
22
+ console.log();
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Custom Model Selection
3
+ *
4
+ * Shows how to select a specific model and thinking level.
5
+ */
6
+
7
+ import { getModel } from "@oh-my-pi/pi-ai";
8
+ import { createAgentSession, discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
9
+
10
+ // Set up auth storage and model registry
11
+ const authStorage = discoverAuthStorage();
12
+ const modelRegistry = discoverModels(authStorage);
13
+
14
+ // Option 1: Find a specific built-in model by provider/id
15
+ const opus = getModel("anthropic", "claude-opus-4-5");
16
+ if (opus) {
17
+ console.log(`Found model: ${opus.provider}/${opus.id}`);
18
+ }
19
+
20
+ // Option 2: Find model via registry (includes custom models from models.json)
21
+ const customModel = modelRegistry.find("my-provider", "my-model");
22
+ if (customModel) {
23
+ console.log(`Found custom model: ${customModel.provider}/${customModel.id}`);
24
+ }
25
+
26
+ // Option 3: Pick from available models (have valid API keys)
27
+ const available = await modelRegistry.getAvailable();
28
+ console.log(
29
+ "Available models:",
30
+ available.map((m) => `${m.provider}/${m.id}`),
31
+ );
32
+
33
+ if (available.length > 0) {
34
+ const { session } = await createAgentSession({
35
+ model: available[0],
36
+ thinkingLevel: "medium", // off, low, medium, high
37
+ authStorage,
38
+ modelRegistry,
39
+ });
40
+
41
+ session.subscribe((event) => {
42
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
43
+ process.stdout.write(event.assistantMessageEvent.delta);
44
+ }
45
+ });
46
+
47
+ await session.prompt("Say hello in one sentence.");
48
+ console.log();
49
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Custom System Prompt
3
+ *
4
+ * Shows how to replace or modify the default system prompt.
5
+ */
6
+
7
+ import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
8
+
9
+ // Option 1: Replace prompt entirely
10
+ const { session: session1 } = await createAgentSession({
11
+ systemPrompt: `You are a helpful assistant that speaks like a pirate.
12
+ Always end responses with "Arrr!"`,
13
+ sessionManager: SessionManager.inMemory(),
14
+ });
15
+
16
+ session1.subscribe((event) => {
17
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
18
+ process.stdout.write(event.assistantMessageEvent.delta);
19
+ }
20
+ });
21
+
22
+ console.log("=== Replace prompt ===");
23
+ await session1.prompt("What is 2 + 2?");
24
+ console.log("\n");
25
+
26
+ // Option 2: Modify default prompt (receives default, returns modified)
27
+ const { session: session2 } = await createAgentSession({
28
+ systemPrompt: (defaultPrompt) => `${defaultPrompt}
29
+
30
+ ## Additional Instructions
31
+ - Always be concise
32
+ - Use bullet points when listing things`,
33
+ sessionManager: SessionManager.inMemory(),
34
+ });
35
+
36
+ session2.subscribe((event) => {
37
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
38
+ process.stdout.write(event.assistantMessageEvent.delta);
39
+ }
40
+ });
41
+
42
+ console.log("=== Modify prompt ===");
43
+ await session2.prompt("List 3 benefits of TypeScript.");
44
+ console.log();
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Skills Configuration
3
+ *
4
+ * Skills provide specialized instructions loaded into the system prompt.
5
+ * Discover, filter, merge, or replace them.
6
+ */
7
+
8
+ import { createAgentSession, discoverSkills, SessionManager, type Skill } from "@oh-my-pi/pi-coding-agent";
9
+
10
+ // Discover all skills from cwd/.pi/skills, ~/.pi/agent/skills, etc.
11
+ const allSkills = discoverSkills();
12
+ console.log(
13
+ "Discovered skills:",
14
+ allSkills.map((s) => s.name),
15
+ );
16
+
17
+ // Filter to specific skills
18
+ const filteredSkills = allSkills.filter((s) => s.name.includes("browser") || s.name.includes("search"));
19
+
20
+ // Or define custom skills inline
21
+ const customSkill: Skill = {
22
+ name: "my-skill",
23
+ description: "Custom project instructions",
24
+ filePath: "/virtual/SKILL.md",
25
+ baseDir: "/virtual",
26
+ source: "custom",
27
+ };
28
+
29
+ // Use filtered + custom skills
30
+ await createAgentSession({
31
+ skills: [...filteredSkills, customSkill],
32
+ sessionManager: SessionManager.inMemory(),
33
+ });
34
+
35
+ console.log(`Session created with ${filteredSkills.length + 1} skills`);
36
+
37
+ // To disable all skills:
38
+ // skills: []
39
+
40
+ // To use discovery with filtering via settings:
41
+ // discoverSkills(process.cwd(), undefined, {
42
+ // ignoredSkills: ["browser-tools"], // glob patterns to exclude
43
+ // includeSkills: ["brave-*"], // glob patterns to include (empty = all)
44
+ // })
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Tools Configuration
3
+ *
4
+ * Use built-in tool sets, individual tools, or add custom tools.
5
+ *
6
+ * IMPORTANT: When using a custom `cwd`, you must use the tool factory functions
7
+ * (createCodingTools, createReadOnlyTools, createReadTool, etc.) to ensure
8
+ * tools resolve paths relative to your cwd, not process.cwd().
9
+ */
10
+
11
+ import {
12
+ bashTool, // read, bash, edit, write - uses process.cwd()
13
+ type CustomTool,
14
+ createAgentSession,
15
+ createBashTool,
16
+ createCodingTools, // Factory: creates tools for specific cwd
17
+ createGrepTool,
18
+ createReadTool,
19
+ grepTool,
20
+ readOnlyTools, // read, grep, find, ls - uses process.cwd()
21
+ readTool,
22
+ SessionManager,
23
+ } from "@oh-my-pi/pi-coding-agent";
24
+ import { Type } from "@sinclair/typebox";
25
+
26
+ // Read-only mode (no edit/write) - uses process.cwd()
27
+ await createAgentSession({
28
+ tools: readOnlyTools,
29
+ sessionManager: SessionManager.inMemory(),
30
+ });
31
+ console.log("Read-only session created");
32
+
33
+ // Custom tool selection - uses process.cwd()
34
+ await createAgentSession({
35
+ tools: [readTool, bashTool, grepTool],
36
+ sessionManager: SessionManager.inMemory(),
37
+ });
38
+ console.log("Custom tools session created");
39
+
40
+ // With custom cwd - MUST use factory functions!
41
+ const customCwd = "/path/to/project";
42
+ await createAgentSession({
43
+ cwd: customCwd,
44
+ tools: createCodingTools(customCwd), // Tools resolve paths relative to customCwd
45
+ sessionManager: SessionManager.inMemory(),
46
+ });
47
+ console.log("Custom cwd session created");
48
+
49
+ // Or pick specific tools for custom cwd
50
+ await createAgentSession({
51
+ cwd: customCwd,
52
+ tools: [createReadTool(customCwd), createBashTool(customCwd), createGrepTool(customCwd)],
53
+ sessionManager: SessionManager.inMemory(),
54
+ });
55
+ console.log("Specific tools with custom cwd session created");
56
+
57
+ // Inline custom tool (needs TypeBox schema)
58
+ const weatherTool: CustomTool = {
59
+ name: "get_weather",
60
+ label: "Get Weather",
61
+ description: "Get current weather for a city",
62
+ parameters: Type.Object({
63
+ city: Type.String({ description: "City name" }),
64
+ }),
65
+ execute: async (_toolCallId, params) => ({
66
+ content: [{ type: "text", text: `Weather in ${(params as { city: string }).city}: 22°C, sunny` }],
67
+ details: {},
68
+ }),
69
+ };
70
+
71
+ const { session } = await createAgentSession({
72
+ customTools: [{ tool: weatherTool }],
73
+ sessionManager: SessionManager.inMemory(),
74
+ });
75
+
76
+ session.subscribe((event) => {
77
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
78
+ process.stdout.write(event.assistantMessageEvent.delta);
79
+ }
80
+ });
81
+
82
+ await session.prompt("What's the weather in Tokyo?");
83
+ console.log();
84
+
85
+ // Merge with discovered tools from cwd/.pi/tools and ~/.pi/agent/tools:
86
+ // const discovered = await discoverCustomTools();
87
+ // customTools: [...discovered, { tool: myTool }]
88
+
89
+ // Or add paths without replacing discovery:
90
+ // additionalCustomToolPaths: ["/extra/tools"]
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Hooks Configuration
3
+ *
4
+ * Hooks intercept agent events for logging, blocking, or modification.
5
+ */
6
+
7
+ import { createAgentSession, type HookFactory, SessionManager } from "@oh-my-pi/pi-coding-agent";
8
+
9
+ // Logging hook
10
+ const loggingHook: HookFactory = (api) => {
11
+ api.on("agent_start", async () => {
12
+ console.log("[Hook] Agent starting");
13
+ });
14
+
15
+ api.on("tool_call", async (event) => {
16
+ console.log(`[Hook] Tool: ${event.toolName}`);
17
+ return undefined; // Don't block
18
+ });
19
+
20
+ api.on("agent_end", async (event) => {
21
+ console.log(`[Hook] Done, ${event.messages.length} messages`);
22
+ });
23
+ };
24
+
25
+ // Blocking hook (returns { block: true, reason: "..." })
26
+ const safetyHook: HookFactory = (api) => {
27
+ api.on("tool_call", async (event) => {
28
+ if (event.toolName === "bash") {
29
+ const cmd = (event.input as { command?: string }).command ?? "";
30
+ if (cmd.includes("rm -rf")) {
31
+ return { block: true, reason: "Dangerous command blocked" };
32
+ }
33
+ }
34
+ return undefined;
35
+ });
36
+ };
37
+
38
+ // Use inline hooks
39
+ const { session } = await createAgentSession({
40
+ hooks: [{ factory: loggingHook }, { factory: safetyHook }],
41
+ sessionManager: SessionManager.inMemory(),
42
+ });
43
+
44
+ session.subscribe((event) => {
45
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
46
+ process.stdout.write(event.assistantMessageEvent.delta);
47
+ }
48
+ });
49
+
50
+ await session.prompt("List files in the current directory.");
51
+ console.log();
52
+
53
+ // Disable all hooks:
54
+ // hooks: []
55
+
56
+ // Merge with discovered hooks:
57
+ // const discovered = await discoverHooks();
58
+ // hooks: [...discovered, { factory: myHook }]
59
+
60
+ // Add paths without replacing discovery:
61
+ // additionalHookPaths: ["/extra/hooks"]
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Context Files (AGENTS.md)
3
+ *
4
+ * Context files provide project-specific instructions loaded into the system prompt.
5
+ */
6
+
7
+ import { createAgentSession, discoverContextFiles, SessionManager } from "@oh-my-pi/pi-coding-agent";
8
+
9
+ // Discover AGENTS.md files walking up from cwd
10
+ const discovered = discoverContextFiles();
11
+ console.log("Discovered context files:");
12
+ for (const file of discovered) {
13
+ console.log(` - ${file.path} (${file.content.length} chars)`);
14
+ }
15
+
16
+ // Use custom context files
17
+ await createAgentSession({
18
+ contextFiles: [
19
+ ...discovered,
20
+ {
21
+ path: "/virtual/AGENTS.md",
22
+ content: `# Project Guidelines
23
+
24
+ ## Code Style
25
+ - Use TypeScript strict mode
26
+ - No any types
27
+ - Prefer const over let`,
28
+ },
29
+ ],
30
+ sessionManager: SessionManager.inMemory(),
31
+ });
32
+
33
+ console.log(`Session created with ${discovered.length + 1} context files`);
34
+
35
+ // Disable context files:
36
+ // contextFiles: []
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Slash Commands
3
+ *
4
+ * File-based commands that inject content when invoked with /commandname.
5
+ */
6
+
7
+ import {
8
+ createAgentSession,
9
+ discoverSlashCommands,
10
+ type FileSlashCommand,
11
+ SessionManager,
12
+ } from "@oh-my-pi/pi-coding-agent";
13
+
14
+ // Discover commands from cwd/.pi/commands/ and ~/.pi/agent/commands/
15
+ const discovered = discoverSlashCommands();
16
+ console.log("Discovered slash commands:");
17
+ for (const cmd of discovered) {
18
+ console.log(` /${cmd.name}: ${cmd.description}`);
19
+ }
20
+
21
+ // Define custom commands
22
+ const deployCommand: FileSlashCommand = {
23
+ name: "deploy",
24
+ description: "Deploy the application",
25
+ source: "(custom)",
26
+ content: `# Deploy Instructions
27
+
28
+ 1. Build: npm run build
29
+ 2. Test: npm test
30
+ 3. Deploy: npm run deploy`,
31
+ };
32
+
33
+ // Use discovered + custom commands
34
+ await createAgentSession({
35
+ slashCommands: [...discovered, deployCommand],
36
+ sessionManager: SessionManager.inMemory(),
37
+ });
38
+
39
+ console.log(`Session created with ${discovered.length + 1} slash commands`);
40
+
41
+ // Disable slash commands:
42
+ // slashCommands: []
@@ -0,0 +1,55 @@
1
+ /**
2
+ * API Keys and OAuth
3
+ *
4
+ * Configure API key resolution via AuthStorage and ModelRegistry.
5
+ */
6
+
7
+ import {
8
+ AuthStorage,
9
+ createAgentSession,
10
+ discoverAuthStorage,
11
+ discoverModels,
12
+ ModelRegistry,
13
+ SessionManager,
14
+ } from "@oh-my-pi/pi-coding-agent";
15
+
16
+ // Default: discoverAuthStorage() uses ~/.pi/agent/auth.json
17
+ // discoverModels() loads built-in + custom models from ~/.pi/agent/models.json
18
+ const authStorage = discoverAuthStorage();
19
+ const modelRegistry = discoverModels(authStorage);
20
+
21
+ await createAgentSession({
22
+ sessionManager: SessionManager.inMemory(),
23
+ authStorage,
24
+ modelRegistry,
25
+ });
26
+ console.log("Session with default auth storage and model registry");
27
+
28
+ // Custom auth storage location
29
+ const customAuthStorage = new AuthStorage("/tmp/my-app/auth.json");
30
+ const customModelRegistry = new ModelRegistry(customAuthStorage, "/tmp/my-app/models.json");
31
+
32
+ await createAgentSession({
33
+ sessionManager: SessionManager.inMemory(),
34
+ authStorage: customAuthStorage,
35
+ modelRegistry: customModelRegistry,
36
+ });
37
+ console.log("Session with custom auth storage location");
38
+
39
+ // Runtime API key override (not persisted to disk)
40
+ authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");
41
+ await createAgentSession({
42
+ sessionManager: SessionManager.inMemory(),
43
+ authStorage,
44
+ modelRegistry,
45
+ });
46
+ console.log("Session with runtime API key override");
47
+
48
+ // No models.json - only built-in models
49
+ const simpleRegistry = new ModelRegistry(authStorage); // null = no models.json
50
+ await createAgentSession({
51
+ sessionManager: SessionManager.inMemory(),
52
+ authStorage,
53
+ modelRegistry: simpleRegistry,
54
+ });
55
+ console.log("Session with only built-in models");
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Settings Configuration
3
+ *
4
+ * Override settings using SettingsManager.
5
+ */
6
+
7
+ import { createAgentSession, loadSettings, SessionManager, SettingsManager } from "@oh-my-pi/pi-coding-agent";
8
+
9
+ // Load current settings (merged global + project)
10
+ const settings = loadSettings();
11
+ console.log("Current settings:", JSON.stringify(settings, null, 2));
12
+
13
+ // Override specific settings
14
+ const settingsManager = SettingsManager.create();
15
+ settingsManager.applyOverrides({
16
+ compaction: { enabled: false },
17
+ retry: { enabled: true, maxRetries: 5, baseDelayMs: 1000 },
18
+ });
19
+
20
+ await createAgentSession({
21
+ settingsManager,
22
+ sessionManager: SessionManager.inMemory(),
23
+ });
24
+
25
+ console.log("Session created with custom settings");
26
+
27
+ // For testing without file I/O:
28
+ const inMemorySettings = SettingsManager.inMemory({
29
+ compaction: { enabled: false },
30
+ retry: { enabled: false },
31
+ });
32
+
33
+ await createAgentSession({
34
+ settingsManager: inMemorySettings,
35
+ sessionManager: SessionManager.inMemory(),
36
+ });
37
+
38
+ console.log("Test session created with in-memory settings");
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Session Management
3
+ *
4
+ * Control session persistence: in-memory, new file, continue, or open specific.
5
+ */
6
+
7
+ import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
8
+
9
+ // In-memory (no persistence)
10
+ const { session: inMemory } = await createAgentSession({
11
+ sessionManager: SessionManager.inMemory(),
12
+ });
13
+ console.log("In-memory session:", inMemory.sessionFile ?? "(none)");
14
+
15
+ // New persistent session
16
+ const { session: newSession } = await createAgentSession({
17
+ sessionManager: SessionManager.create(process.cwd()),
18
+ });
19
+ console.log("New session file:", newSession.sessionFile);
20
+
21
+ // Continue most recent session (or create new if none)
22
+ const { session: continued, modelFallbackMessage } = await createAgentSession({
23
+ sessionManager: SessionManager.continueRecent(process.cwd()),
24
+ });
25
+ if (modelFallbackMessage) console.log("Note:", modelFallbackMessage);
26
+ console.log("Continued session:", continued.sessionFile);
27
+
28
+ // List and open specific session
29
+ const sessions = SessionManager.list(process.cwd());
30
+ console.log(`\nFound ${sessions.length} sessions:`);
31
+ for (const info of sessions.slice(0, 3)) {
32
+ console.log(` ${info.id.slice(0, 8)}... - "${info.firstMessage.slice(0, 30)}..."`);
33
+ }
34
+
35
+ if (sessions.length > 0) {
36
+ const { session: opened } = await createAgentSession({
37
+ sessionManager: SessionManager.open(sessions[0].path),
38
+ });
39
+ console.log(`\nOpened: ${opened.sessionId}`);
40
+ }
41
+
42
+ // Custom session directory (no cwd encoding)
43
+ // const customDir = "/path/to/my-sessions";
44
+ // const { session } = await createAgentSession({
45
+ // sessionManager: SessionManager.create(process.cwd(), customDir),
46
+ // });
47
+ // SessionManager.list(process.cwd(), customDir);
48
+ // SessionManager.continueRecent(process.cwd(), customDir);
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Full Control
3
+ *
4
+ * Replace everything - no discovery, explicit configuration.
5
+ *
6
+ * IMPORTANT: When providing `tools` with a custom `cwd`, use the tool factory
7
+ * functions (createReadTool, createBashTool, etc.) to ensure tools resolve
8
+ * paths relative to your cwd.
9
+ */
10
+
11
+ import { getModel } from "@oh-my-pi/pi-ai";
12
+ import {
13
+ AuthStorage,
14
+ type CustomTool,
15
+ createAgentSession,
16
+ createBashTool,
17
+ createReadTool,
18
+ type HookFactory,
19
+ ModelRegistry,
20
+ SessionManager,
21
+ SettingsManager,
22
+ } from "@oh-my-pi/pi-coding-agent";
23
+ import { Type } from "@sinclair/typebox";
24
+
25
+ // Custom auth storage location
26
+ const authStorage = new AuthStorage("/tmp/my-agent/auth.json");
27
+
28
+ // Runtime API key override (not persisted)
29
+ if (process.env.MY_ANTHROPIC_KEY) {
30
+ authStorage.setRuntimeApiKey("anthropic", process.env.MY_ANTHROPIC_KEY);
31
+ }
32
+
33
+ // Model registry with no custom models.json
34
+ const modelRegistry = new ModelRegistry(authStorage);
35
+
36
+ // Inline hook
37
+ const auditHook: HookFactory = (api) => {
38
+ api.on("tool_call", async (event) => {
39
+ console.log(`[Audit] ${event.toolName}`);
40
+ return undefined;
41
+ });
42
+ };
43
+
44
+ // Inline custom tool
45
+ const statusTool: CustomTool = {
46
+ name: "status",
47
+ label: "Status",
48
+ description: "Get system status",
49
+ parameters: Type.Object({}),
50
+ execute: async () => ({
51
+ content: [{ type: "text", text: `Uptime: ${process.uptime()}s, Node: ${process.version}` }],
52
+ details: {},
53
+ }),
54
+ };
55
+
56
+ const model = getModel("anthropic", "claude-opus-4-5");
57
+ if (!model) throw new Error("Model not found");
58
+
59
+ // In-memory settings with overrides
60
+ const settingsManager = SettingsManager.inMemory({
61
+ compaction: { enabled: false },
62
+ retry: { enabled: true, maxRetries: 2 },
63
+ });
64
+
65
+ // When using a custom cwd with explicit tools, use the factory functions
66
+ const cwd = process.cwd();
67
+
68
+ const { session } = await createAgentSession({
69
+ cwd,
70
+ agentDir: "/tmp/my-agent",
71
+ model,
72
+ thinkingLevel: "off",
73
+ authStorage,
74
+ modelRegistry,
75
+ systemPrompt: `You are a minimal assistant.
76
+ Available: read, bash, status. Be concise.`,
77
+ // Use factory functions with the same cwd to ensure path resolution works correctly
78
+ tools: [createReadTool(cwd), createBashTool(cwd)],
79
+ customTools: [{ tool: statusTool }],
80
+ hooks: [{ factory: auditHook }],
81
+ skills: [],
82
+ contextFiles: [],
83
+ slashCommands: [],
84
+ sessionManager: SessionManager.inMemory(),
85
+ settingsManager,
86
+ });
87
+
88
+ session.subscribe((event) => {
89
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
90
+ process.stdout.write(event.assistantMessageEvent.delta);
91
+ }
92
+ });
93
+
94
+ await session.prompt("Get status and list files.");
95
+ console.log();