@mariozechner/pi-coding-agent 0.64.0 → 0.65.1

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 (137) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +12 -6
  3. package/dist/cli/args.d.ts +7 -4
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +37 -15
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session-runtime.d.ts +83 -0
  8. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  9. package/dist/core/agent-session-runtime.js +236 -0
  10. package/dist/core/agent-session-runtime.js.map +1 -0
  11. package/dist/core/agent-session-services.d.ts +86 -0
  12. package/dist/core/agent-session-services.d.ts.map +1 -0
  13. package/dist/core/agent-session-services.js +116 -0
  14. package/dist/core/agent-session-services.js.map +1 -0
  15. package/dist/core/agent-session.d.ts +5 -42
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +46 -237
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/bash-executor.d.ts.map +1 -1
  20. package/dist/core/bash-executor.js +19 -7
  21. package/dist/core/bash-executor.js.map +1 -1
  22. package/dist/core/export-html/tool-renderer.d.ts +2 -0
  23. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  24. package/dist/core/export-html/tool-renderer.js +2 -2
  25. package/dist/core/export-html/tool-renderer.js.map +1 -1
  26. package/dist/core/extensions/index.d.ts +2 -2
  27. package/dist/core/extensions/index.d.ts.map +1 -1
  28. package/dist/core/extensions/index.js +1 -1
  29. package/dist/core/extensions/index.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +16 -28
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js +10 -0
  33. package/dist/core/extensions/types.js.map +1 -1
  34. package/dist/core/footer-data-provider.d.ts +5 -1
  35. package/dist/core/footer-data-provider.d.ts.map +1 -1
  36. package/dist/core/footer-data-provider.js +70 -8
  37. package/dist/core/footer-data-provider.js.map +1 -1
  38. package/dist/core/index.d.ts +3 -1
  39. package/dist/core/index.d.ts.map +1 -1
  40. package/dist/core/index.js +3 -1
  41. package/dist/core/index.js.map +1 -1
  42. package/dist/core/keybindings.d.ts +14 -1
  43. package/dist/core/keybindings.d.ts.map +1 -1
  44. package/dist/core/keybindings.js +13 -14
  45. package/dist/core/keybindings.js.map +1 -1
  46. package/dist/core/package-manager.d.ts +20 -0
  47. package/dist/core/package-manager.d.ts.map +1 -1
  48. package/dist/core/package-manager.js +55 -9
  49. package/dist/core/package-manager.js.map +1 -1
  50. package/dist/core/resource-loader.d.ts.map +1 -1
  51. package/dist/core/resource-loader.js +25 -3
  52. package/dist/core/resource-loader.js.map +1 -1
  53. package/dist/core/sdk.d.ts +4 -1
  54. package/dist/core/sdk.d.ts.map +1 -1
  55. package/dist/core/sdk.js +4 -1
  56. package/dist/core/sdk.js.map +1 -1
  57. package/dist/core/session-cwd.d.ts +19 -0
  58. package/dist/core/session-cwd.d.ts.map +1 -0
  59. package/dist/core/session-cwd.js +38 -0
  60. package/dist/core/session-cwd.js.map +1 -0
  61. package/dist/core/session-manager.d.ts +5 -1
  62. package/dist/core/session-manager.d.ts.map +1 -1
  63. package/dist/core/session-manager.js +16 -8
  64. package/dist/core/session-manager.js.map +1 -1
  65. package/dist/core/settings-manager.d.ts +1 -1
  66. package/dist/core/settings-manager.d.ts.map +1 -1
  67. package/dist/core/settings-manager.js +2 -1
  68. package/dist/core/settings-manager.js.map +1 -1
  69. package/dist/core/tools/bash.d.ts.map +1 -1
  70. package/dist/core/tools/bash.js +19 -9
  71. package/dist/core/tools/bash.js.map +1 -1
  72. package/dist/index.d.ts +3 -3
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +3 -3
  75. package/dist/index.js.map +1 -1
  76. package/dist/main.d.ts.map +1 -1
  77. package/dist/main.js +245 -426
  78. package/dist/main.js.map +1 -1
  79. package/dist/migrations.d.ts.map +1 -1
  80. package/dist/migrations.js +20 -0
  81. package/dist/migrations.js.map +1 -1
  82. package/dist/modes/interactive/components/footer.d.ts +1 -0
  83. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  84. package/dist/modes/interactive/components/footer.js +4 -1
  85. package/dist/modes/interactive/components/footer.js.map +1 -1
  86. package/dist/modes/interactive/components/tree-selector.d.ts +4 -2
  87. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  88. package/dist/modes/interactive/components/tree-selector.js +48 -15
  89. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  90. package/dist/modes/interactive/interactive-mode.d.ts +10 -4
  91. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  92. package/dist/modes/interactive/interactive-mode.js +160 -94
  93. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  94. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  95. package/dist/modes/interactive/theme/theme.js +15 -11
  96. package/dist/modes/interactive/theme/theme.js.map +1 -1
  97. package/dist/modes/print-mode.d.ts +2 -2
  98. package/dist/modes/print-mode.d.ts.map +1 -1
  99. package/dist/modes/print-mode.js +41 -36
  100. package/dist/modes/print-mode.js.map +1 -1
  101. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  102. package/dist/modes/rpc/rpc-client.js +1 -0
  103. package/dist/modes/rpc/rpc-client.js.map +1 -1
  104. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  105. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  106. package/dist/modes/rpc/rpc-mode.js +92 -64
  107. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  108. package/dist/package-manager-cli.d.ts +4 -0
  109. package/dist/package-manager-cli.d.ts.map +1 -0
  110. package/dist/package-manager-cli.js +234 -0
  111. package/dist/package-manager-cli.js.map +1 -0
  112. package/dist/utils/paths.d.ts +7 -0
  113. package/dist/utils/paths.d.ts.map +1 -0
  114. package/dist/utils/paths.js +19 -0
  115. package/dist/utils/paths.js.map +1 -0
  116. package/docs/extensions.md +72 -40
  117. package/docs/keybindings.md +2 -0
  118. package/docs/sdk.md +227 -74
  119. package/docs/settings.md +1 -1
  120. package/docs/tree.md +6 -3
  121. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  122. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  123. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  124. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  125. package/examples/extensions/doom-overlay/doom/build.sh +2 -2
  126. package/examples/extensions/hello.ts +18 -17
  127. package/examples/extensions/hidden-thinking-label.ts +0 -4
  128. package/examples/extensions/rpc-demo.ts +3 -9
  129. package/examples/extensions/status-line.ts +0 -8
  130. package/examples/extensions/todo.ts +0 -2
  131. package/examples/extensions/tools.ts +0 -5
  132. package/examples/extensions/widget-placement.ts +4 -12
  133. package/examples/extensions/with-deps/package-lock.json +2 -2
  134. package/examples/extensions/with-deps/package.json +1 -1
  135. package/examples/sdk/13-session-runtime.ts +67 -0
  136. package/examples/sdk/README.md +4 -1
  137. package/package.json +4 -4
@@ -0,0 +1,234 @@
1
+ import chalk from "chalk";
2
+ import { selectConfig } from "./cli/config-selector.js";
3
+ import { APP_NAME, getAgentDir } from "./config.js";
4
+ import { DefaultPackageManager } from "./core/package-manager.js";
5
+ import { SettingsManager } from "./core/settings-manager.js";
6
+ function reportSettingsErrors(settingsManager, context) {
7
+ const errors = settingsManager.drainErrors();
8
+ for (const { scope, error } of errors) {
9
+ console.error(chalk.yellow(`Warning (${context}, ${scope} settings): ${error.message}`));
10
+ if (error.stack) {
11
+ console.error(chalk.dim(error.stack));
12
+ }
13
+ }
14
+ }
15
+ function getPackageCommandUsage(command) {
16
+ switch (command) {
17
+ case "install":
18
+ return `${APP_NAME} install <source> [-l]`;
19
+ case "remove":
20
+ return `${APP_NAME} remove <source> [-l]`;
21
+ case "update":
22
+ return `${APP_NAME} update [source]`;
23
+ case "list":
24
+ return `${APP_NAME} list`;
25
+ }
26
+ }
27
+ function printPackageCommandHelp(command) {
28
+ switch (command) {
29
+ case "install":
30
+ console.log(`${chalk.bold("Usage:")}
31
+ ${getPackageCommandUsage("install")}
32
+
33
+ Install a package and add it to settings.
34
+
35
+ Options:
36
+ -l, --local Install project-locally (.pi/settings.json)
37
+
38
+ Examples:
39
+ ${APP_NAME} install npm:@foo/bar
40
+ ${APP_NAME} install git:github.com/user/repo
41
+ ${APP_NAME} install git:git@github.com:user/repo
42
+ ${APP_NAME} install https://github.com/user/repo
43
+ ${APP_NAME} install ssh://git@github.com/user/repo
44
+ ${APP_NAME} install ./local/path
45
+ `);
46
+ return;
47
+ case "remove":
48
+ console.log(`${chalk.bold("Usage:")}
49
+ ${getPackageCommandUsage("remove")}
50
+
51
+ Remove a package and its source from settings.
52
+ Alias: ${APP_NAME} uninstall <source> [-l]
53
+
54
+ Options:
55
+ -l, --local Remove from project settings (.pi/settings.json)
56
+
57
+ Examples:
58
+ ${APP_NAME} remove npm:@foo/bar
59
+ ${APP_NAME} uninstall npm:@foo/bar
60
+ `);
61
+ return;
62
+ case "update":
63
+ console.log(`${chalk.bold("Usage:")}
64
+ ${getPackageCommandUsage("update")}
65
+
66
+ Update installed packages.
67
+ If <source> is provided, only that package is updated.
68
+ `);
69
+ return;
70
+ case "list":
71
+ console.log(`${chalk.bold("Usage:")}
72
+ ${getPackageCommandUsage("list")}
73
+
74
+ List installed packages from user and project settings.
75
+ `);
76
+ return;
77
+ }
78
+ }
79
+ function parsePackageCommand(args) {
80
+ const [rawCommand, ...rest] = args;
81
+ let command;
82
+ if (rawCommand === "uninstall") {
83
+ command = "remove";
84
+ }
85
+ else if (rawCommand === "install" || rawCommand === "remove" || rawCommand === "update" || rawCommand === "list") {
86
+ command = rawCommand;
87
+ }
88
+ if (!command) {
89
+ return undefined;
90
+ }
91
+ let local = false;
92
+ let help = false;
93
+ let invalidOption;
94
+ let source;
95
+ for (const arg of rest) {
96
+ if (arg === "-h" || arg === "--help") {
97
+ help = true;
98
+ continue;
99
+ }
100
+ if (arg === "-l" || arg === "--local") {
101
+ if (command === "install" || command === "remove") {
102
+ local = true;
103
+ }
104
+ else {
105
+ invalidOption = invalidOption ?? arg;
106
+ }
107
+ continue;
108
+ }
109
+ if (arg.startsWith("-")) {
110
+ invalidOption = invalidOption ?? arg;
111
+ continue;
112
+ }
113
+ if (!source) {
114
+ source = arg;
115
+ }
116
+ }
117
+ return { command, source, local, help, invalidOption };
118
+ }
119
+ export async function handleConfigCommand(args) {
120
+ if (args[0] !== "config") {
121
+ return false;
122
+ }
123
+ const cwd = process.cwd();
124
+ const agentDir = getAgentDir();
125
+ const settingsManager = SettingsManager.create(cwd, agentDir);
126
+ reportSettingsErrors(settingsManager, "config command");
127
+ const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
128
+ const resolvedPaths = await packageManager.resolve();
129
+ await selectConfig({
130
+ resolvedPaths,
131
+ settingsManager,
132
+ cwd,
133
+ agentDir,
134
+ });
135
+ process.exit(0);
136
+ }
137
+ export async function handlePackageCommand(args) {
138
+ const options = parsePackageCommand(args);
139
+ if (!options) {
140
+ return false;
141
+ }
142
+ if (options.help) {
143
+ printPackageCommandHelp(options.command);
144
+ return true;
145
+ }
146
+ if (options.invalidOption) {
147
+ console.error(chalk.red(`Unknown option ${options.invalidOption} for "${options.command}".`));
148
+ console.error(chalk.dim(`Use "${APP_NAME} --help" or "${getPackageCommandUsage(options.command)}".`));
149
+ process.exitCode = 1;
150
+ return true;
151
+ }
152
+ const source = options.source;
153
+ if ((options.command === "install" || options.command === "remove") && !source) {
154
+ console.error(chalk.red(`Missing ${options.command} source.`));
155
+ console.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));
156
+ process.exitCode = 1;
157
+ return true;
158
+ }
159
+ const cwd = process.cwd();
160
+ const agentDir = getAgentDir();
161
+ const settingsManager = SettingsManager.create(cwd, agentDir);
162
+ reportSettingsErrors(settingsManager, "package command");
163
+ const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
164
+ packageManager.setProgressCallback((event) => {
165
+ if (event.type === "start") {
166
+ process.stdout.write(chalk.dim(`${event.message}\n`));
167
+ }
168
+ });
169
+ try {
170
+ switch (options.command) {
171
+ case "install":
172
+ await packageManager.installAndPersist(source, { local: options.local });
173
+ console.log(chalk.green(`Installed ${source}`));
174
+ return true;
175
+ case "remove": {
176
+ const removed = await packageManager.removeAndPersist(source, { local: options.local });
177
+ if (!removed) {
178
+ console.error(chalk.red(`No matching package found for ${source}`));
179
+ process.exitCode = 1;
180
+ return true;
181
+ }
182
+ console.log(chalk.green(`Removed ${source}`));
183
+ return true;
184
+ }
185
+ case "list": {
186
+ const configuredPackages = packageManager.listConfiguredPackages();
187
+ const userPackages = configuredPackages.filter((pkg) => pkg.scope === "user");
188
+ const projectPackages = configuredPackages.filter((pkg) => pkg.scope === "project");
189
+ if (configuredPackages.length === 0) {
190
+ console.log(chalk.dim("No packages installed."));
191
+ return true;
192
+ }
193
+ const formatPackage = (pkg) => {
194
+ const display = pkg.filtered ? `${pkg.source} (filtered)` : pkg.source;
195
+ console.log(` ${display}`);
196
+ if (pkg.installedPath) {
197
+ console.log(chalk.dim(` ${pkg.installedPath}`));
198
+ }
199
+ };
200
+ if (userPackages.length > 0) {
201
+ console.log(chalk.bold("User packages:"));
202
+ for (const pkg of userPackages) {
203
+ formatPackage(pkg);
204
+ }
205
+ }
206
+ if (projectPackages.length > 0) {
207
+ if (userPackages.length > 0)
208
+ console.log();
209
+ console.log(chalk.bold("Project packages:"));
210
+ for (const pkg of projectPackages) {
211
+ formatPackage(pkg);
212
+ }
213
+ }
214
+ return true;
215
+ }
216
+ case "update":
217
+ await packageManager.update(source);
218
+ if (source) {
219
+ console.log(chalk.green(`Updated ${source}`));
220
+ }
221
+ else {
222
+ console.log(chalk.green("Updated packages"));
223
+ }
224
+ return true;
225
+ }
226
+ }
227
+ catch (error) {
228
+ const message = error instanceof Error ? error.message : "Unknown package command error";
229
+ console.error(chalk.red(`Error: ${message}`));
230
+ process.exitCode = 1;
231
+ return true;
232
+ }
233
+ }
234
+ //# sourceMappingURL=package-manager-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager-cli.js","sourceRoot":"","sources":["../src/package-manager-cli.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\nimport { selectConfig } from \"./cli/config-selector.js\";\nimport { APP_NAME, getAgentDir } from \"./config.js\";\nimport { DefaultPackageManager } from \"./core/package-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\n\nexport type PackageCommand = \"install\" | \"remove\" | \"update\" | \"list\";\n\ninterface PackageCommandOptions {\n\tcommand: PackageCommand;\n\tsource?: string;\n\tlocal: boolean;\n\thelp: boolean;\n\tinvalidOption?: string;\n}\n\nfunction reportSettingsErrors(settingsManager: SettingsManager, context: string): void {\n\tconst errors = settingsManager.drainErrors();\n\tfor (const { scope, error } of errors) {\n\t\tconsole.error(chalk.yellow(`Warning (${context}, ${scope} settings): ${error.message}`));\n\t\tif (error.stack) {\n\t\t\tconsole.error(chalk.dim(error.stack));\n\t\t}\n\t}\n}\n\nfunction getPackageCommandUsage(command: PackageCommand): string {\n\tswitch (command) {\n\t\tcase \"install\":\n\t\t\treturn `${APP_NAME} install <source> [-l]`;\n\t\tcase \"remove\":\n\t\t\treturn `${APP_NAME} remove <source> [-l]`;\n\t\tcase \"update\":\n\t\t\treturn `${APP_NAME} update [source]`;\n\t\tcase \"list\":\n\t\t\treturn `${APP_NAME} list`;\n\t}\n}\n\nfunction printPackageCommandHelp(command: PackageCommand): void {\n\tswitch (command) {\n\t\tcase \"install\":\n\t\t\tconsole.log(`${chalk.bold(\"Usage:\")}\n ${getPackageCommandUsage(\"install\")}\n\nInstall a package and add it to settings.\n\nOptions:\n -l, --local Install project-locally (.pi/settings.json)\n\nExamples:\n ${APP_NAME} install npm:@foo/bar\n ${APP_NAME} install git:github.com/user/repo\n ${APP_NAME} install git:git@github.com:user/repo\n ${APP_NAME} install https://github.com/user/repo\n ${APP_NAME} install ssh://git@github.com/user/repo\n ${APP_NAME} install ./local/path\n`);\n\t\t\treturn;\n\n\t\tcase \"remove\":\n\t\t\tconsole.log(`${chalk.bold(\"Usage:\")}\n ${getPackageCommandUsage(\"remove\")}\n\nRemove a package and its source from settings.\nAlias: ${APP_NAME} uninstall <source> [-l]\n\nOptions:\n -l, --local Remove from project settings (.pi/settings.json)\n\nExamples:\n ${APP_NAME} remove npm:@foo/bar\n ${APP_NAME} uninstall npm:@foo/bar\n`);\n\t\t\treturn;\n\n\t\tcase \"update\":\n\t\t\tconsole.log(`${chalk.bold(\"Usage:\")}\n ${getPackageCommandUsage(\"update\")}\n\nUpdate installed packages.\nIf <source> is provided, only that package is updated.\n`);\n\t\t\treturn;\n\n\t\tcase \"list\":\n\t\t\tconsole.log(`${chalk.bold(\"Usage:\")}\n ${getPackageCommandUsage(\"list\")}\n\nList installed packages from user and project settings.\n`);\n\t\t\treturn;\n\t}\n}\n\nfunction parsePackageCommand(args: string[]): PackageCommandOptions | undefined {\n\tconst [rawCommand, ...rest] = args;\n\tlet command: PackageCommand | undefined;\n\tif (rawCommand === \"uninstall\") {\n\t\tcommand = \"remove\";\n\t} else if (rawCommand === \"install\" || rawCommand === \"remove\" || rawCommand === \"update\" || rawCommand === \"list\") {\n\t\tcommand = rawCommand;\n\t}\n\tif (!command) {\n\t\treturn undefined;\n\t}\n\n\tlet local = false;\n\tlet help = false;\n\tlet invalidOption: string | undefined;\n\tlet source: string | undefined;\n\n\tfor (const arg of rest) {\n\t\tif (arg === \"-h\" || arg === \"--help\") {\n\t\t\thelp = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (arg === \"-l\" || arg === \"--local\") {\n\t\t\tif (command === \"install\" || command === \"remove\") {\n\t\t\t\tlocal = true;\n\t\t\t} else {\n\t\t\t\tinvalidOption = invalidOption ?? arg;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (arg.startsWith(\"-\")) {\n\t\t\tinvalidOption = invalidOption ?? arg;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!source) {\n\t\t\tsource = arg;\n\t\t}\n\t}\n\n\treturn { command, source, local, help, invalidOption };\n}\n\nexport async function handleConfigCommand(args: string[]): Promise<boolean> {\n\tif (args[0] !== \"config\") {\n\t\treturn false;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst settingsManager = SettingsManager.create(cwd, agentDir);\n\treportSettingsErrors(settingsManager, \"config command\");\n\tconst packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });\n\tconst resolvedPaths = await packageManager.resolve();\n\n\tawait selectConfig({\n\t\tresolvedPaths,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tagentDir,\n\t});\n\n\tprocess.exit(0);\n}\n\nexport async function handlePackageCommand(args: string[]): Promise<boolean> {\n\tconst options = parsePackageCommand(args);\n\tif (!options) {\n\t\treturn false;\n\t}\n\n\tif (options.help) {\n\t\tprintPackageCommandHelp(options.command);\n\t\treturn true;\n\t}\n\n\tif (options.invalidOption) {\n\t\tconsole.error(chalk.red(`Unknown option ${options.invalidOption} for \"${options.command}\".`));\n\t\tconsole.error(chalk.dim(`Use \"${APP_NAME} --help\" or \"${getPackageCommandUsage(options.command)}\".`));\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\n\tconst source = options.source;\n\tif ((options.command === \"install\" || options.command === \"remove\") && !source) {\n\t\tconsole.error(chalk.red(`Missing ${options.command} source.`));\n\t\tconsole.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst settingsManager = SettingsManager.create(cwd, agentDir);\n\treportSettingsErrors(settingsManager, \"package command\");\n\tconst packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });\n\n\tpackageManager.setProgressCallback((event) => {\n\t\tif (event.type === \"start\") {\n\t\t\tprocess.stdout.write(chalk.dim(`${event.message}\\n`));\n\t\t}\n\t});\n\n\ttry {\n\t\tswitch (options.command) {\n\t\t\tcase \"install\":\n\t\t\t\tawait packageManager.installAndPersist(source!, { local: options.local });\n\t\t\t\tconsole.log(chalk.green(`Installed ${source}`));\n\t\t\t\treturn true;\n\n\t\t\tcase \"remove\": {\n\t\t\t\tconst removed = await packageManager.removeAndPersist(source!, { local: options.local });\n\t\t\t\tif (!removed) {\n\t\t\t\t\tconsole.error(chalk.red(`No matching package found for ${source}`));\n\t\t\t\t\tprocess.exitCode = 1;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconsole.log(chalk.green(`Removed ${source}`));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst configuredPackages = packageManager.listConfiguredPackages();\n\t\t\t\tconst userPackages = configuredPackages.filter((pkg) => pkg.scope === \"user\");\n\t\t\t\tconst projectPackages = configuredPackages.filter((pkg) => pkg.scope === \"project\");\n\n\t\t\t\tif (configuredPackages.length === 0) {\n\t\t\t\t\tconsole.log(chalk.dim(\"No packages installed.\"));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tconst formatPackage = (pkg: (typeof configuredPackages)[number]) => {\n\t\t\t\t\tconst display = pkg.filtered ? `${pkg.source} (filtered)` : pkg.source;\n\t\t\t\t\tconsole.log(` ${display}`);\n\t\t\t\t\tif (pkg.installedPath) {\n\t\t\t\t\t\tconsole.log(chalk.dim(` ${pkg.installedPath}`));\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tif (userPackages.length > 0) {\n\t\t\t\t\tconsole.log(chalk.bold(\"User packages:\"));\n\t\t\t\t\tfor (const pkg of userPackages) {\n\t\t\t\t\t\tformatPackage(pkg);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (projectPackages.length > 0) {\n\t\t\t\t\tif (userPackages.length > 0) console.log();\n\t\t\t\t\tconsole.log(chalk.bold(\"Project packages:\"));\n\t\t\t\t\tfor (const pkg of projectPackages) {\n\t\t\t\t\t\tformatPackage(pkg);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tcase \"update\":\n\t\t\t\tawait packageManager.update(source);\n\t\t\t\tif (source) {\n\t\t\t\t\tconsole.log(chalk.green(`Updated ${source}`));\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(chalk.green(\"Updated packages\"));\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t}\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown package command error\";\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns true if the value is NOT a package source (npm:, git:, etc.)
3
+ * or a URL protocol. Bare names and relative paths without ./ prefix
4
+ * are considered local.
5
+ */
6
+ export declare function isLocalPath(value: string): boolean;
7
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAclD","sourcesContent":["/**\n * Returns true if the value is NOT a package source (npm:, git:, etc.)\n * or a URL protocol. Bare names and relative paths without ./ prefix\n * are considered local.\n */\nexport function isLocalPath(value: string): boolean {\n\tconst trimmed = value.trim();\n\t// Known non-local prefixes\n\tif (\n\t\ttrimmed.startsWith(\"npm:\") ||\n\t\ttrimmed.startsWith(\"git:\") ||\n\t\ttrimmed.startsWith(\"github:\") ||\n\t\ttrimmed.startsWith(\"http:\") ||\n\t\ttrimmed.startsWith(\"https:\") ||\n\t\ttrimmed.startsWith(\"ssh:\")\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Returns true if the value is NOT a package source (npm:, git:, etc.)
3
+ * or a URL protocol. Bare names and relative paths without ./ prefix
4
+ * are considered local.
5
+ */
6
+ export function isLocalPath(value) {
7
+ const trimmed = value.trim();
8
+ // Known non-local prefixes
9
+ if (trimmed.startsWith("npm:") ||
10
+ trimmed.startsWith("git:") ||
11
+ trimmed.startsWith("github:") ||
12
+ trimmed.startsWith("http:") ||
13
+ trimmed.startsWith("https:") ||
14
+ trimmed.startsWith("ssh:")) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAW;IACnD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,2BAA2B;IAC3B,IACC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;QAC1B,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;QAC1B,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;QAC7B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;QAC3B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC5B,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EACzB,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ","sourcesContent":["/**\n * Returns true if the value is NOT a package source (npm:, git:, etc.)\n * or a URL protocol. Bare names and relative paths without ./ prefix\n * are considered local.\n */\nexport function isLocalPath(value: string): boolean {\n\tconst trimmed = value.trim();\n\t// Known non-local prefixes\n\tif (\n\t\ttrimmed.startsWith(\"npm:\") ||\n\t\ttrimmed.startsWith(\"git:\") ||\n\t\ttrimmed.startsWith(\"github:\") ||\n\t\ttrimmed.startsWith(\"http:\") ||\n\t\ttrimmed.startsWith(\"https:\") ||\n\t\ttrimmed.startsWith(\"ssh:\")\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n"]}
@@ -37,6 +37,7 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
37
37
  - [Extension Styles](#extension-styles)
38
38
  - [Events](#events)
39
39
  - [Lifecycle Overview](#lifecycle-overview)
40
+ - [Resource Events](#resource-events)
40
41
  - [Session Events](#session-events)
41
42
  - [Agent Events](#agent-events)
42
43
  - [Tool Events](#tool-events)
@@ -225,10 +226,10 @@ Run `npm install` in the extension directory, then imports from `node_modules/`
225
226
  ### Lifecycle Overview
226
227
 
227
228
  ```
228
- pi starts (CLI only)
229
+ pi starts
229
230
 
230
- ├─► session_directory (CLI startup only, no ctx)
231
- └─► session_start
231
+ ├─► session_start { reason: "startup" }
232
+ └─► resources_discover { reason: "startup" }
232
233
 
233
234
 
234
235
  user sends prompt ─────────────────────────────────────────┐
@@ -261,11 +262,15 @@ user sends another prompt ◄─────────────────
261
262
 
262
263
  /new (new session) or /resume (switch session)
263
264
  ├─► session_before_switch (can cancel)
264
- └─► session_switch
265
+ ├─► session_shutdown
266
+ ├─► session_start { reason: "new" | "resume", previousSessionFile? }
267
+ └─► resources_discover { reason: "startup" }
265
268
 
266
269
  /fork
267
270
  ├─► session_before_fork (can cancel)
268
- └─► session_fork
271
+ ├─► session_shutdown
272
+ ├─► session_start { reason: "fork", previousSessionFile }
273
+ └─► resources_discover { reason: "startup" }
269
274
 
270
275
  /compact or auto-compaction
271
276
  ├─► session_before_compact (can cancel or customize)
@@ -282,44 +287,44 @@ exit (Ctrl+C, Ctrl+D)
282
287
  └─► session_shutdown
283
288
  ```
284
289
 
285
- ### Session Events
286
-
287
- See [session.md](session.md) for session storage internals and the SessionManager API.
288
-
289
- #### session_directory
290
-
291
- Fired by the `pi` CLI during startup session resolution, before the initial session manager is created.
290
+ ### Resource Events
292
291
 
293
- This event is:
294
- - CLI-only. It is not emitted in SDK mode.
295
- - Startup-only. It is not emitted for later interactive `/new` or `/resume` actions.
296
- - Lower priority than `--session-dir` and `sessionDir` in `settings.json`.
297
- - Special-cased to receive no `ctx` argument.
292
+ #### resources_discover
298
293
 
299
- If multiple extensions return `sessionDir`, the last one wins.
300
- Combined precedence is: `--session-dir` CLI flag, then `sessionDir` in settings, then extension `session_directory` hooks.
294
+ Fired after `session_start` so extensions can contribute additional skill, prompt, and theme paths.
295
+ The startup path uses `reason: "startup"`. Reload uses `reason: "reload"`.
301
296
 
302
297
  ```typescript
303
- pi.on("session_directory", async (event) => {
298
+ pi.on("resources_discover", async (event, _ctx) => {
299
+ // event.cwd - current working directory
300
+ // event.reason - "startup" | "reload"
304
301
  return {
305
- sessionDir: `/tmp/pi-sessions/${encodeURIComponent(event.cwd)}`,
302
+ skillPaths: ["/path/to/skills"],
303
+ promptPaths: ["/path/to/prompts"],
304
+ themePaths: ["/path/to/themes"],
306
305
  };
307
306
  });
308
307
  ```
309
308
 
309
+ ### Session Events
310
+
311
+ See [session.md](session.md) for session storage internals and the SessionManager API.
312
+
310
313
  #### session_start
311
314
 
312
- Fired on initial session load.
315
+ Fired when a session is started, loaded, or reloaded.
313
316
 
314
317
  ```typescript
315
- pi.on("session_start", async (_event, ctx) => {
318
+ pi.on("session_start", async (event, ctx) => {
319
+ // event.reason - "startup" | "reload" | "new" | "resume" | "fork"
320
+ // event.previousSessionFile - present for "new", "resume", and "fork"
316
321
  ctx.ui.notify(`Session: ${ctx.sessionManager.getSessionFile() ?? "ephemeral"}`, "info");
317
322
  });
318
323
  ```
319
324
 
320
- #### session_before_switch / session_switch
325
+ #### session_before_switch
321
326
 
322
- Fired when starting a new session (`/new`) or switching sessions (`/resume`).
327
+ Fired before starting a new session (`/new`) or switching sessions (`/resume`).
323
328
 
324
329
  ```typescript
325
330
  pi.on("session_before_switch", async (event, ctx) => {
@@ -331,14 +336,12 @@ pi.on("session_before_switch", async (event, ctx) => {
331
336
  if (!ok) return { cancel: true };
332
337
  }
333
338
  });
334
-
335
- pi.on("session_switch", async (event, ctx) => {
336
- // event.reason - "new" or "resume"
337
- // event.previousSessionFile - session we came from
338
- });
339
339
  ```
340
340
 
341
- #### session_before_fork / session_fork
341
+ After a successful switch or new-session action, pi emits `session_shutdown` for the old extension instance, reloads and rebinds extensions for the new session, then emits `session_start` with `reason: "new" | "resume"` and `previousSessionFile`.
342
+ Do cleanup work in `session_shutdown`, then reestablish any in-memory state in `session_start`.
343
+
344
+ #### session_before_fork
342
345
 
343
346
  Fired when forking via `/fork`.
344
347
 
@@ -349,12 +352,11 @@ pi.on("session_before_fork", async (event, ctx) => {
349
352
  // OR
350
353
  return { skipConversationRestore: true }; // Fork but don't rewind messages
351
354
  });
352
-
353
- pi.on("session_fork", async (event, ctx) => {
354
- // event.previousSessionFile - previous session file
355
- });
356
355
  ```
357
356
 
357
+ After a successful fork, pi emits `session_shutdown` for the old extension instance, reloads and rebinds extensions for the new session, then emits `session_start` with `reason: "fork"` and `previousSessionFile`.
358
+ Do cleanup work in `session_shutdown`, then reestablish any in-memory state in `session_start`.
359
+
358
360
  #### session_before_compact / session_compact
359
361
 
360
362
  Fired on compaction. See [compaction.md](compaction.md) for details.
@@ -735,9 +737,7 @@ Transforms chain across handlers. See [input-transform.ts](../examples/extension
735
737
 
736
738
  ## ExtensionContext
737
739
 
738
- All handlers except `session_directory` receive `ctx: ExtensionContext`.
739
-
740
- `session_directory` is a CLI startup hook and receives only the event.
740
+ All handlers receive `ctx: ExtensionContext`.
741
741
 
742
742
  ### ctx.ui
743
743
 
@@ -920,6 +920,38 @@ Options:
920
920
  - `replaceInstructions`: If true, `customInstructions` replaces the default prompt instead of being appended
921
921
  - `label`: Label to attach to the branch summary entry (or target entry if not summarizing)
922
922
 
923
+ ### ctx.switchSession(sessionPath)
924
+
925
+ Switch to a different session file:
926
+
927
+ ```typescript
928
+ const result = await ctx.switchSession("/path/to/session.jsonl");
929
+ if (result.cancelled) {
930
+ // An extension cancelled the switch via session_before_switch
931
+ }
932
+ ```
933
+
934
+ To discover available sessions, use the static `SessionManager.list()` or `SessionManager.listAll()` methods:
935
+
936
+ ```typescript
937
+ import { SessionManager } from "@mariozechner/pi-coding-agent";
938
+
939
+ pi.registerCommand("switch", {
940
+ description: "Switch to another session",
941
+ handler: async (args, ctx) => {
942
+ const sessions = await SessionManager.list(ctx.cwd);
943
+ if (sessions.length === 0) return;
944
+ const choice = await ctx.ui.select(
945
+ "Pick session:",
946
+ sessions.map(s => s.file),
947
+ );
948
+ if (choice) {
949
+ await ctx.switchSession(choice);
950
+ }
951
+ },
952
+ });
953
+ ```
954
+
923
955
  ### ctx.reload()
924
956
 
925
957
  Run the same reload flow as `/reload`.
@@ -936,7 +968,7 @@ pi.registerCommand("reload-runtime", {
936
968
 
937
969
  Important behavior:
938
970
  - `await ctx.reload()` emits `session_shutdown` for the current extension runtime
939
- - It then reloads resources and emits `session_start` (and `resources_discover` with reason `"reload"`) for the new runtime
971
+ - It then reloads resources and emits `session_start` with `reason: "reload"` and `resources_discover` with reason `"reload"`
940
972
  - The currently running command handler still continues in the old call frame
941
973
  - Code after `await ctx.reload()` still runs from the pre-reload version
942
974
  - Code after `await ctx.reload()` must not assume old in-memory extension state is still valid
@@ -2187,7 +2219,7 @@ All examples in [examples/extensions/](../examples/extensions/).
2187
2219
  | **Compaction & Sessions** |||
2188
2220
  | `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
2189
2221
  | `trigger-compact.ts` | Trigger compaction manually | `compact()` |
2190
- | `git-checkpoint.ts` | Git stash on turns | `on("turn_end")`, `on("session_fork")`, `exec` |
2222
+ | `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
2191
2223
  | `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
2192
2224
  | **UI Components** |||
2193
2225
  | `status-line.ts` | Footer status indicator | `setStatus`, session events |
@@ -128,6 +128,8 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
128
128
  |--------|---------|-------------|
129
129
  | `app.tree.foldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
130
130
  | `app.tree.unfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
131
+ | `app.tree.editLabel` | `shift+l` | Edit the label on the selected tree node |
132
+ | `app.tree.toggleLabelTimestamp` | `shift+t` | Toggle label timestamps in the tree |
131
133
 
132
134
  ## Custom Configuration
133
135