@codex-infinity/pi-infinity 0.64.1 → 0.64.3

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 (79) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +10 -4
  3. package/dist/core/agent-session-runtime.d.ts +136 -0
  4. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  5. package/dist/core/agent-session-runtime.js +265 -0
  6. package/dist/core/agent-session-runtime.js.map +1 -0
  7. package/dist/core/agent-session.d.ts +5 -42
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +13 -207
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/export-html/tool-renderer.d.ts +2 -0
  12. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  13. package/dist/core/export-html/tool-renderer.js +2 -2
  14. package/dist/core/export-html/tool-renderer.js.map +1 -1
  15. package/dist/core/extensions/index.d.ts +2 -2
  16. package/dist/core/extensions/index.d.ts.map +1 -1
  17. package/dist/core/extensions/index.js +1 -1
  18. package/dist/core/extensions/index.js.map +1 -1
  19. package/dist/core/extensions/types.d.ts +16 -16
  20. package/dist/core/extensions/types.d.ts.map +1 -1
  21. package/dist/core/extensions/types.js +10 -0
  22. package/dist/core/extensions/types.js.map +1 -1
  23. package/dist/core/footer-data-provider.d.ts +5 -1
  24. package/dist/core/footer-data-provider.d.ts.map +1 -1
  25. package/dist/core/footer-data-provider.js +69 -8
  26. package/dist/core/footer-data-provider.js.map +1 -1
  27. package/dist/core/index.d.ts +2 -1
  28. package/dist/core/index.d.ts.map +1 -1
  29. package/dist/core/index.js +2 -1
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/sdk.d.ts +4 -1
  32. package/dist/core/sdk.d.ts.map +1 -1
  33. package/dist/core/sdk.js +3 -0
  34. package/dist/core/sdk.js.map +1 -1
  35. package/dist/index.d.ts +3 -3
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +3 -3
  38. package/dist/index.js.map +1 -1
  39. package/dist/main.d.ts.map +1 -1
  40. package/dist/main.js +42 -9
  41. package/dist/main.js.map +1 -1
  42. package/dist/modes/interactive/components/footer.d.ts +1 -0
  43. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  44. package/dist/modes/interactive/components/footer.js +4 -1
  45. package/dist/modes/interactive/components/footer.js.map +1 -1
  46. package/dist/modes/interactive/interactive-mode.d.ts +8 -4
  47. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  48. package/dist/modes/interactive/interactive-mode.js +89 -86
  49. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  50. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  51. package/dist/modes/interactive/theme/theme.js +6 -11
  52. package/dist/modes/interactive/theme/theme.js.map +1 -1
  53. package/dist/modes/print-mode.d.ts +2 -2
  54. package/dist/modes/print-mode.d.ts.map +1 -1
  55. package/dist/modes/print-mode.js +37 -36
  56. package/dist/modes/print-mode.js.map +1 -1
  57. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  58. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  59. package/dist/modes/rpc/rpc-mode.js +69 -49
  60. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  61. package/docs/extensions.md +75 -19
  62. package/docs/sdk.md +160 -72
  63. package/docs/tree.md +1 -1
  64. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  65. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  66. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  67. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  68. package/examples/extensions/hello.ts +18 -17
  69. package/examples/extensions/hidden-thinking-label.ts +0 -4
  70. package/examples/extensions/rpc-demo.ts +3 -9
  71. package/examples/extensions/status-line.ts +0 -8
  72. package/examples/extensions/todo.ts +0 -2
  73. package/examples/extensions/tools.ts +0 -5
  74. package/examples/extensions/widget-placement.ts +4 -12
  75. package/examples/extensions/with-deps/package-lock.json +2 -2
  76. package/examples/extensions/with-deps/package.json +1 -1
  77. package/examples/sdk/13-session-runtime.ts +49 -0
  78. package/examples/sdk/README.md +2 -1
  79. package/package.json +4 -4
package/docs/sdk.md CHANGED
@@ -49,7 +49,7 @@ The SDK is included in the main package. No separate installation needed.
49
49
 
50
50
  ### createAgentSession()
51
51
 
52
- The main factory function. Creates an `AgentSession` with configurable options.
52
+ The main factory function for a single `AgentSession`.
53
53
 
54
54
  `createAgentSession()` uses a `ResourceLoader` to supply extensions, skills, prompt templates, themes, and context files. If you do not provide one, it uses `DefaultResourceLoader` with standard discovery.
55
55
 
@@ -69,61 +69,102 @@ const { session } = await createAgentSession({
69
69
 
70
70
  ### AgentSession
71
71
 
72
- The session manages the agent lifecycle, message history, and event streaming.
72
+ The session manages agent lifecycle, message history, model state, compaction, and event streaming.
73
73
 
74
74
  ```typescript
75
75
  interface AgentSession {
76
76
  // Send a prompt and wait for completion
77
- // If streaming, requires streamingBehavior option to queue the message
78
77
  prompt(text: string, options?: PromptOptions): Promise<void>;
79
-
78
+
80
79
  // Queue messages during streaming
81
- steer(text: string): Promise<void>; // Queue for delivery after the current assistant turn finishes its tool calls
82
- followUp(text: string): Promise<void>; // Wait: delivered only when agent finishes
83
-
80
+ steer(text: string): Promise<void>;
81
+ followUp(text: string): Promise<void>;
82
+
84
83
  // Subscribe to events (returns unsubscribe function)
85
84
  subscribe(listener: (event: AgentSessionEvent) => void): () => void;
86
-
85
+
87
86
  // Session info
88
- sessionFile: string | undefined; // undefined for in-memory
87
+ sessionFile: string | undefined;
89
88
  sessionId: string;
90
-
89
+
91
90
  // Model control
92
91
  setModel(model: Model): Promise<void>;
93
92
  setThinkingLevel(level: ThinkingLevel): void;
94
93
  cycleModel(): Promise<ModelCycleResult | undefined>;
95
94
  cycleThinkingLevel(): ThinkingLevel | undefined;
96
-
95
+
97
96
  // State access
98
97
  agent: Agent;
99
98
  model: Model | undefined;
100
99
  thinkingLevel: ThinkingLevel;
101
100
  messages: AgentMessage[];
102
101
  isStreaming: boolean;
103
-
104
- // Session management
105
- newSession(options?: { parentSession?: string }): Promise<boolean>; // Returns false if cancelled by hook
106
- switchSession(sessionPath: string): Promise<boolean>;
107
-
108
- // Forking
109
- fork(entryId: string): Promise<{ selectedText: string; cancelled: boolean }>; // Creates new session file
110
- navigateTree(targetId: string, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }): Promise<{ editorText?: string; cancelled: boolean }>; // In-place navigation
111
-
112
- // Hook message injection
113
- sendHookMessage(message: HookMessage, triggerTurn?: boolean): Promise<void>;
114
-
102
+
103
+ // In-place tree navigation within the current session file
104
+ navigateTree(targetId: string, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }): Promise<{ editorText?: string; cancelled: boolean }>;
105
+
115
106
  // Compaction
116
107
  compact(customInstructions?: string): Promise<CompactionResult>;
117
108
  abortCompaction(): void;
118
-
109
+
119
110
  // Abort current operation
120
111
  abort(): Promise<void>;
121
-
112
+
122
113
  // Cleanup
123
114
  dispose(): void;
124
115
  }
125
116
  ```
126
117
 
118
+ Session replacement APIs such as new-session, resume, fork, and import live on `AgentSessionRuntimeHost`, not on `AgentSession`.
119
+
120
+ ### createAgentSessionRuntime() and AgentSessionRuntimeHost
121
+
122
+ Use the runtime API when you need to replace the active session and rebuild cwd-bound runtime state.
123
+ This is the same layer used by the built-in interactive, print, and RPC modes.
124
+
125
+ ```typescript
126
+ import {
127
+ AgentSessionRuntimeHost,
128
+ createAgentSessionRuntime,
129
+ SessionManager,
130
+ } from "@mariozechner/pi-coding-agent";
131
+
132
+ const bootstrap = {
133
+ // Optional: authStorage, model, thinkingLevel, tools, customTools, resourceLoader
134
+ };
135
+
136
+ const runtime = await createAgentSessionRuntime(bootstrap, {
137
+ cwd: process.cwd(),
138
+ sessionManager: SessionManager.create(process.cwd()),
139
+ });
140
+
141
+ const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
142
+ ```
143
+
144
+ `createAgentSessionRuntime()` returns an internal runtime bundle. `AgentSessionRuntimeHost` owns replacement of that bundle across:
145
+
146
+ - `newSession()`
147
+ - `switchSession()`
148
+ - `fork()`
149
+ - `importFromJsonl()`
150
+
151
+ Important behavior:
152
+
153
+ - `runtimeHost.session` changes after those operations
154
+ - event subscriptions are attached to a specific `AgentSession`, so re-subscribe after replacement
155
+ - if you use extensions, call `runtimeHost.session.bindExtensions(...)` again for the new session
156
+
157
+ ```typescript
158
+ let session = runtimeHost.session;
159
+ let unsubscribe = session.subscribe(() => {});
160
+
161
+ await runtimeHost.newSession();
162
+
163
+ unsubscribe();
164
+ session = runtimeHost.session;
165
+ unsubscribe = session.subscribe(() => {});
166
+ ```
167
+
127
168
  ### Prompting and Message Queueing
128
169
 
129
170
  The `prompt()` method handles prompt templates, extension commands, and message sending:
@@ -452,21 +493,21 @@ const { session } = await createAgentSession({
452
493
 
453
494
  ```typescript
454
495
  import { Type } from "@sinclair/typebox";
455
- import { createAgentSession, type ToolDefinition } from "@mariozechner/pi-coding-agent";
496
+ import { createAgentSession, defineTool } from "@mariozechner/pi-coding-agent";
456
497
 
457
498
  // Inline custom tool
458
- const myTool: ToolDefinition = {
499
+ const myTool = defineTool({
459
500
  name: "my_tool",
460
501
  label: "My Tool",
461
502
  description: "Does something useful",
462
503
  parameters: Type.Object({
463
504
  input: Type.String({ description: "Input value" }),
464
505
  }),
465
- execute: async (toolCallId, params, onUpdate, ctx, signal) => ({
506
+ execute: async (_toolCallId, params) => ({
466
507
  content: [{ type: "text", text: `Result: ${params.input}` }],
467
508
  details: {},
468
509
  }),
469
- };
510
+ });
470
511
 
471
512
  // Pass custom tools directly
472
513
  const { session } = await createAgentSession({
@@ -474,6 +515,8 @@ const { session } = await createAgentSession({
474
515
  });
475
516
  ```
476
517
 
518
+ Use `defineTool()` for standalone definitions and arrays like `customTools: [myTool]`. Inline `pi.registerTool({ ... })` already infers parameter types correctly.
519
+
477
520
  Custom tools passed via `customTools` are combined with extension-registered tools. Extensions loaded by the ResourceLoader can also register tools via `pi.registerTool()`.
478
521
 
479
522
  > See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
@@ -602,7 +645,12 @@ const { session } = await createAgentSession({ resourceLoader: loader });
602
645
  Sessions use a tree structure with `id`/`parentId` linking, enabling in-place branching.
603
646
 
604
647
  ```typescript
605
- import { createAgentSession, SessionManager } from "@mariozechner/pi-coding-agent";
648
+ import {
649
+ AgentSessionRuntimeHost,
650
+ createAgentSession,
651
+ createAgentSessionRuntime,
652
+ SessionManager,
653
+ } from "@mariozechner/pi-coding-agent";
606
654
 
607
655
  // In-memory (no persistence)
608
656
  const { session } = await createAgentSession({
@@ -610,12 +658,12 @@ const { session } = await createAgentSession({
610
658
  });
611
659
 
612
660
  // New persistent session
613
- const { session } = await createAgentSession({
661
+ const { session: persisted } = await createAgentSession({
614
662
  sessionManager: SessionManager.create(process.cwd()),
615
663
  });
616
664
 
617
665
  // Continue most recent
618
- const { session, modelFallbackMessage } = await createAgentSession({
666
+ const { session: continued, modelFallbackMessage } = await createAgentSession({
619
667
  sessionManager: SessionManager.continueRecent(process.cwd()),
620
668
  });
621
669
  if (modelFallbackMessage) {
@@ -623,26 +671,30 @@ if (modelFallbackMessage) {
623
671
  }
624
672
 
625
673
  // Open specific file
626
- const { session } = await createAgentSession({
674
+ const { session: opened } = await createAgentSession({
627
675
  sessionManager: SessionManager.open("/path/to/session.jsonl"),
628
676
  });
629
677
 
630
- // List available sessions (async with optional progress callback)
631
- const sessions = await SessionManager.list(process.cwd());
632
- for (const info of sessions) {
633
- console.log(`${info.id}: ${info.firstMessage} (${info.messageCount} messages, cwd: ${info.cwd})`);
634
- }
678
+ // List sessions
679
+ const currentProjectSessions = await SessionManager.list(process.cwd());
680
+ const allSessions = await SessionManager.listAll(process.cwd());
635
681
 
636
- // List all sessions across all projects
637
- const allSessions = await SessionManager.listAll((loaded, total) => {
638
- console.log(`Loading ${loaded}/${total}...`);
682
+ // Session replacement API for /new, /resume, /fork, and import flows.
683
+ const bootstrap = {};
684
+ const runtime = await createAgentSessionRuntime(bootstrap, {
685
+ cwd: process.cwd(),
686
+ sessionManager: SessionManager.create(process.cwd()),
639
687
  });
688
+ const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
640
689
 
641
- // Custom session directory (no cwd encoding)
642
- const customDir = "/path/to/my-sessions";
643
- const { session } = await createAgentSession({
644
- sessionManager: SessionManager.create(process.cwd(), customDir),
645
- });
690
+ // Replace the active session with a fresh one
691
+ await runtimeHost.newSession();
692
+
693
+ // Replace the active session with another saved session
694
+ await runtimeHost.switchSession("/path/to/session.jsonl");
695
+
696
+ // Replace the active session with a fork from a specific entry
697
+ await runtimeHost.fork("entry-id");
646
698
  ```
647
699
 
648
700
  **SessionManager tree API:**
@@ -650,6 +702,10 @@ const { session } = await createAgentSession({
650
702
  ```typescript
651
703
  const sm = SessionManager.open("/path/to/session.jsonl");
652
704
 
705
+ // Session listing
706
+ const currentProjectSessions = await SessionManager.list(process.cwd());
707
+ const allSessions = await SessionManager.listAll(process.cwd());
708
+
653
709
  // Tree traversal
654
710
  const entries = sm.getEntries(); // All entries (excludes header)
655
711
  const tree = sm.getTree(); // Full tree structure
@@ -774,14 +830,14 @@ import { getModel } from "@mariozechner/pi-ai";
774
830
  import { Type } from "@sinclair/typebox";
775
831
  import {
776
832
  AuthStorage,
833
+ bashTool,
777
834
  createAgentSession,
778
835
  DefaultResourceLoader,
836
+ defineTool,
779
837
  ModelRegistry,
838
+ readTool,
780
839
  SessionManager,
781
840
  SettingsManager,
782
- readTool,
783
- bashTool,
784
- type ToolDefinition,
785
841
  } from "@mariozechner/pi-coding-agent";
786
842
 
787
843
  // Set up auth storage (custom location)
@@ -796,7 +852,7 @@ if (process.env.MY_KEY) {
796
852
  const modelRegistry = ModelRegistry.create(authStorage);
797
853
 
798
854
  // Inline tool
799
- const statusTool: ToolDefinition = {
855
+ const statusTool = defineTool({
800
856
  name: "status",
801
857
  label: "Status",
802
858
  description: "Get system status",
@@ -805,7 +861,7 @@ const statusTool: ToolDefinition = {
805
861
  content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }],
806
862
  details: {},
807
863
  }),
808
- };
864
+ });
809
865
 
810
866
  const model = getModel("anthropic", "claude-opus-4-5");
811
867
  if (!model) throw new Error("Model not found");
@@ -859,20 +915,29 @@ The SDK exports run mode utilities for building custom interfaces on top of `cre
859
915
  Full TUI interactive mode with editor, chat history, and all built-in commands:
860
916
 
861
917
  ```typescript
862
- import { createAgentSession, InteractiveMode } from "@mariozechner/pi-coding-agent";
863
-
864
- const { session } = await createAgentSession({ /* ... */ });
918
+ import {
919
+ AgentSessionRuntimeHost,
920
+ createAgentSessionRuntime,
921
+ InteractiveMode,
922
+ SessionManager,
923
+ } from "@mariozechner/pi-coding-agent";
865
924
 
866
- const mode = new InteractiveMode(session, {
867
- // All optional
868
- migratedProviders: [], // Show migration warnings
869
- modelFallbackMessage: undefined, // Show model restore warning
870
- initialMessage: "Hello", // Send on startup
871
- initialImages: [], // Images with initial message
872
- initialMessages: [], // Additional startup prompts
925
+ const bootstrap = {};
926
+ const runtime = await createAgentSessionRuntime(bootstrap, {
927
+ cwd: process.cwd(),
928
+ sessionManager: SessionManager.create(process.cwd()),
929
+ });
930
+ const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
931
+
932
+ const mode = new InteractiveMode(runtimeHost, {
933
+ migratedProviders: [],
934
+ modelFallbackMessage: undefined,
935
+ initialMessage: "Hello",
936
+ initialImages: [],
937
+ initialMessages: [],
873
938
  });
874
939
 
875
- await mode.run(); // Blocks until exit
940
+ await mode.run();
876
941
  ```
877
942
 
878
943
  ### runPrintMode
@@ -880,15 +945,25 @@ await mode.run(); // Blocks until exit
880
945
  Single-shot mode: send prompts, output result, exit:
881
946
 
882
947
  ```typescript
883
- import { createAgentSession, runPrintMode } from "@mariozechner/pi-coding-agent";
948
+ import {
949
+ AgentSessionRuntimeHost,
950
+ createAgentSessionRuntime,
951
+ runPrintMode,
952
+ SessionManager,
953
+ } from "@mariozechner/pi-coding-agent";
884
954
 
885
- const { session } = await createAgentSession({ /* ... */ });
955
+ const bootstrap = {};
956
+ const runtime = await createAgentSessionRuntime(bootstrap, {
957
+ cwd: process.cwd(),
958
+ sessionManager: SessionManager.create(process.cwd()),
959
+ });
960
+ const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
886
961
 
887
- await runPrintMode(session, {
888
- mode: "text", // "text" for final response, "json" for all events
889
- initialMessage: "Hello", // First message (can include @file content)
890
- initialImages: [], // Images with initial message
891
- messages: ["Follow up"], // Additional prompts
962
+ await runPrintMode(runtimeHost, {
963
+ mode: "text",
964
+ initialMessage: "Hello",
965
+ initialImages: [],
966
+ messages: ["Follow up"],
892
967
  });
893
968
  ```
894
969
 
@@ -897,11 +972,21 @@ await runPrintMode(session, {
897
972
  JSON-RPC mode for subprocess integration:
898
973
 
899
974
  ```typescript
900
- import { createAgentSession, runRpcMode } from "@mariozechner/pi-coding-agent";
975
+ import {
976
+ AgentSessionRuntimeHost,
977
+ createAgentSessionRuntime,
978
+ runRpcMode,
979
+ SessionManager,
980
+ } from "@mariozechner/pi-coding-agent";
901
981
 
902
- const { session } = await createAgentSession({ /* ... */ });
982
+ const bootstrap = {};
983
+ const runtime = await createAgentSessionRuntime(bootstrap, {
984
+ cwd: process.cwd(),
985
+ sessionManager: SessionManager.create(process.cwd()),
986
+ });
987
+ const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
903
988
 
904
- await runRpcMode(session); // Reads JSON commands from stdin, writes to stdout
989
+ await runRpcMode(runtimeHost);
905
990
  ```
906
991
 
907
992
  See [RPC documentation](rpc.md) for the JSON protocol.
@@ -934,6 +1019,8 @@ The main entry point exports:
934
1019
  ```typescript
935
1020
  // Factory
936
1021
  createAgentSession
1022
+ createAgentSessionRuntime
1023
+ AgentSessionRuntimeHost
937
1024
 
938
1025
  // Auth and Models
939
1026
  AuthStorage
@@ -945,6 +1032,7 @@ type ResourceLoader
945
1032
  createEventBus
946
1033
 
947
1034
  // Helpers
1035
+ defineTool
948
1036
 
949
1037
  // Session management
950
1038
  SessionManager
package/docs/tree.md CHANGED
@@ -13,7 +13,7 @@ Sessions are stored as trees where each entry has an `id` and `parentId`. The "l
13
13
  | View | Flat list of user messages | Full tree structure |
14
14
  | Action | Extracts path to **new session file** | Changes leaf in **same session** |
15
15
  | Summary | Never | Optional (user prompted) |
16
- | Events | `session_before_fork` / `session_fork` | `session_before_tree` / `session_tree` |
16
+ | Events | `session_before_fork` / `session_start` (`reason: "fork"`) | `session_before_tree` / `session_tree` |
17
17
 
18
18
  ## Tree UI
19
19
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "1.15.1",
3
+ "version": "1.15.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "1.15.1",
9
+ "version": "1.15.2",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "1.15.1",
4
+ "version": "1.15.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "1.15.1",
4
+ "version": "1.15.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-qwen-cli",
3
3
  "private": true,
4
- "version": "1.14.1",
4
+ "version": "1.14.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -3,23 +3,24 @@
3
3
  */
4
4
 
5
5
  import { Type } from "@mariozechner/pi-ai";
6
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
6
+ import { defineTool, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
7
7
 
8
- export default function (pi: ExtensionAPI) {
9
- pi.registerTool({
10
- name: "hello",
11
- label: "Hello",
12
- description: "A simple greeting tool",
13
- parameters: Type.Object({
14
- name: Type.String({ description: "Name to greet" }),
15
- }),
8
+ const helloTool = defineTool({
9
+ name: "hello",
10
+ label: "Hello",
11
+ description: "A simple greeting tool",
12
+ parameters: Type.Object({
13
+ name: Type.String({ description: "Name to greet" }),
14
+ }),
15
+
16
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
17
+ return {
18
+ content: [{ type: "text", text: `Hello, ${params.name}!` }],
19
+ details: { greeted: params.name },
20
+ };
21
+ },
22
+ });
16
23
 
17
- async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
18
- const { name } = params as { name: string };
19
- return {
20
- content: [{ type: "text", text: `Hello, ${name}!` }],
21
- details: { greeted: name },
22
- };
23
- },
24
- });
24
+ export default function (pi: ExtensionAPI) {
25
+ pi.registerTool(helloTool);
25
26
  }
@@ -33,10 +33,6 @@ export default function (pi: ExtensionAPI) {
33
33
  applyLabel(ctx);
34
34
  });
35
35
 
36
- pi.on("session_switch", async (_event, ctx) => {
37
- applyLabel(ctx);
38
- });
39
-
40
36
  pi.registerCommand("thinking-label", {
41
37
  description: "Set the hidden thinking label. Use without args to reset.",
42
38
  handler: async (args, ctx) => {
@@ -13,7 +13,7 @@
13
13
  * - notify() - after each dialog completes
14
14
  * - setStatus() - on turn_start/turn_end
15
15
  * - setWidget() - on session_start
16
- * - setTitle() - on session_start and session_switch
16
+ * - setTitle() - on session_start
17
17
  * - setEditorText() - via /rpc-prefill command
18
18
  */
19
19
 
@@ -24,18 +24,12 @@ export default function (pi: ExtensionAPI) {
24
24
 
25
25
  // -- setTitle, setWidget, setStatus on session lifecycle --
26
26
 
27
- pi.on("session_start", async (_event, ctx) => {
28
- ctx.ui.setTitle("pi RPC Demo");
27
+ pi.on("session_start", async (event, ctx) => {
28
+ ctx.ui.setTitle(event.reason === "new" ? "pi RPC Demo (new session)" : "pi RPC Demo");
29
29
  ctx.ui.setWidget("rpc-demo", ["--- RPC Extension UI Demo ---", "Loaded and ready."]);
30
30
  ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
31
31
  });
32
32
 
33
- pi.on("session_switch", async (_event, ctx) => {
34
- turnCount = 0;
35
- ctx.ui.setTitle("pi RPC Demo (new session)");
36
- ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
37
- });
38
-
39
33
  // -- setStatus on turn lifecycle --
40
34
 
41
35
  pi.on("turn_start", async (_event, ctx) => {
@@ -29,12 +29,4 @@ export default function (pi: ExtensionAPI) {
29
29
  const text = theme.fg("dim", ` Turn ${turnCount} complete`);
30
30
  ctx.ui.setStatus("status-demo", check + text);
31
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
32
  }
@@ -130,8 +130,6 @@ export default function (pi: ExtensionAPI) {
130
130
 
131
131
  // Reconstruct state on session events
132
132
  pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
133
- pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
134
- pi.on("session_fork", async (_event, ctx) => reconstructState(ctx));
135
133
  pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
136
134
 
137
135
  // Register the todo tool for the LLM
@@ -138,9 +138,4 @@ export default function toolsExtension(pi: ExtensionAPI) {
138
138
  pi.on("session_tree", async (_event, ctx) => {
139
139
  restoreFromBranch(ctx);
140
140
  });
141
-
142
- // Restore state after forking
143
- pi.on("session_fork", async (_event, ctx) => {
144
- restoreFromBranch(ctx);
145
- });
146
141
  }
@@ -1,17 +1,9 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
2
-
3
- const applyWidgets = (ctx: ExtensionContext) => {
4
- if (!ctx.hasUI) return;
5
- ctx.ui.setWidget("widget-above", ["Above editor widget"]);
6
- ctx.ui.setWidget("widget-below", ["Below editor widget"], { placement: "belowEditor" });
7
- };
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
8
2
 
9
3
  export default function widgetPlacementExtension(pi: ExtensionAPI) {
10
4
  pi.on("session_start", (_event, ctx) => {
11
- applyWidgets(ctx);
12
- });
13
-
14
- pi.on("session_switch", (_event, ctx) => {
15
- applyWidgets(ctx);
5
+ if (!ctx.hasUI) return;
6
+ ctx.ui.setWidget("widget-above", ["Above editor widget"]);
7
+ ctx.ui.setWidget("widget-below", ["Below editor widget"], { placement: "belowEditor" });
16
8
  });
17
9
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "1.28.1",
3
+ "version": "1.28.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "1.28.1",
9
+ "version": "1.28.2",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "1.28.1",
4
+ "version": "1.28.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",