@vandeepunk/pi-coding-agent 0.0.3 → 0.0.4

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 (83) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +1 -0
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +7 -0
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/auth-storage.d.ts.map +1 -1
  11. package/dist/core/auth-storage.js +16 -0
  12. package/dist/core/auth-storage.js.map +1 -1
  13. package/dist/core/export-html/template.css +3 -0
  14. package/dist/core/export-html/template.js +32 -15
  15. package/dist/core/extensions/loader.d.ts.map +1 -1
  16. package/dist/core/extensions/loader.js.map +1 -1
  17. package/dist/core/extensions/runner.d.ts +17 -2
  18. package/dist/core/extensions/runner.d.ts.map +1 -1
  19. package/dist/core/extensions/runner.js +53 -9
  20. package/dist/core/extensions/runner.js.map +1 -1
  21. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  22. package/dist/core/extensions/wrapper.js +3 -3
  23. package/dist/core/extensions/wrapper.js.map +1 -1
  24. package/dist/core/model-registry.d.ts +3 -1
  25. package/dist/core/model-registry.d.ts.map +1 -1
  26. package/dist/core/model-registry.js +133 -37
  27. package/dist/core/model-registry.js.map +1 -1
  28. package/dist/core/model-resolver.d.ts.map +1 -1
  29. package/dist/core/model-resolver.js +5 -5
  30. package/dist/core/model-resolver.js.map +1 -1
  31. package/dist/core/package-manager.d.ts +20 -0
  32. package/dist/core/package-manager.d.ts.map +1 -1
  33. package/dist/core/package-manager.js +122 -21
  34. package/dist/core/package-manager.js.map +1 -1
  35. package/dist/core/prompt-templates.d.ts.map +1 -1
  36. package/dist/core/prompt-templates.js.map +1 -1
  37. package/dist/core/settings-manager.d.ts.map +1 -1
  38. package/dist/core/settings-manager.js.map +1 -1
  39. package/dist/core/skills.d.ts.map +1 -1
  40. package/dist/core/skills.js +57 -3
  41. package/dist/core/skills.js.map +1 -1
  42. package/dist/core/slash-commands.d.ts.map +1 -1
  43. package/dist/core/slash-commands.js +2 -1
  44. package/dist/core/slash-commands.js.map +1 -1
  45. package/dist/main.d.ts.map +1 -1
  46. package/dist/main.js +172 -177
  47. package/dist/main.js.map +1 -1
  48. package/dist/migrations.d.ts.map +1 -1
  49. package/dist/migrations.js.map +1 -1
  50. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  51. package/dist/modes/interactive/components/assistant-message.js +9 -4
  52. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  53. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  54. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  55. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  56. package/dist/modes/interactive/components/model-selector.js +5 -0
  57. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  58. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  59. package/dist/modes/interactive/components/scoped-models-selector.js +5 -0
  60. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  61. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  62. package/dist/modes/interactive/components/tool-execution.js +49 -34
  63. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  64. package/dist/modes/interactive/interactive-mode.d.ts +0 -1
  65. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  66. package/dist/modes/interactive/interactive-mode.js +115 -102
  67. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  68. package/dist/utils/git.d.ts +21 -1
  69. package/dist/utils/git.d.ts.map +1 -1
  70. package/dist/utils/git.js +150 -4
  71. package/dist/utils/git.js.map +1 -1
  72. package/docs/extensions.md +5 -0
  73. package/docs/models.md +40 -1
  74. package/docs/packages.md +20 -0
  75. package/docs/providers.md +13 -0
  76. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  77. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  78. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  79. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  80. package/examples/extensions/hello.ts +1 -1
  81. package/examples/extensions/with-deps/package-lock.json +2 -2
  82. package/examples/extensions/with-deps/package.json +1 -1
  83. package/package.json +7 -8
package/dist/main.js CHANGED
@@ -4,8 +4,6 @@
4
4
  * This file handles CLI argument parsing and translates them into
5
5
  * createAgentSession() options. The SDK does the heavy lifting.
6
6
  */
7
- import { homedir } from "node:os";
8
- import { isAbsolute, join, relative, resolve } from "node:path";
9
7
  import { modelsAreEqual, supportsXhigh } from "@mariozechner/pi-ai";
10
8
  import chalk from "chalk";
11
9
  import { createInterface } from "readline";
@@ -14,7 +12,7 @@ import { selectConfig } from "./cli/config-selector.js";
14
12
  import { processFileArguments } from "./cli/file-processor.js";
15
13
  import { listModels } from "./cli/list-models.js";
16
14
  import { selectSession } from "./cli/session-picker.js";
17
- import { CONFIG_DIR_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
15
+ import { APP_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
18
16
  import { AuthStorage } from "./core/auth-storage.js";
19
17
  import { DEFAULT_THINKING_LEVEL } from "./core/defaults.js";
20
18
  import { exportFromFile } from "./core/export-html/index.js";
@@ -52,205 +50,201 @@ async function readPipedStdin() {
52
50
  process.stdin.resume();
53
51
  });
54
52
  }
53
+ function getPackageCommandUsage(command) {
54
+ switch (command) {
55
+ case "install":
56
+ return `${APP_NAME} install <source> [-l]`;
57
+ case "remove":
58
+ return `${APP_NAME} remove <source> [-l]`;
59
+ case "update":
60
+ return `${APP_NAME} update [source]`;
61
+ case "list":
62
+ return `${APP_NAME} list`;
63
+ }
64
+ }
65
+ function printPackageCommandHelp(command) {
66
+ switch (command) {
67
+ case "install":
68
+ console.log(`${chalk.bold("Usage:")}
69
+ ${getPackageCommandUsage("install")}
70
+
71
+ Install a package and add it to settings.
72
+
73
+ Options:
74
+ -l, --local Install project-locally (.pi/settings.json)
75
+
76
+ Examples:
77
+ ${APP_NAME} install npm:@foo/bar
78
+ ${APP_NAME} install git:github.com/user/repo
79
+ ${APP_NAME} install https://github.com/user/repo
80
+ ${APP_NAME} install git@github.com:user/repo
81
+ ${APP_NAME} install ./local/path
82
+ `);
83
+ return;
84
+ case "remove":
85
+ console.log(`${chalk.bold("Usage:")}
86
+ ${getPackageCommandUsage("remove")}
87
+
88
+ Remove a package and its source from settings.
89
+
90
+ Options:
91
+ -l, --local Remove from project settings (.pi/settings.json)
92
+
93
+ Example:
94
+ ${APP_NAME} remove npm:@foo/bar
95
+ `);
96
+ return;
97
+ case "update":
98
+ console.log(`${chalk.bold("Usage:")}
99
+ ${getPackageCommandUsage("update")}
100
+
101
+ Update installed packages.
102
+ If <source> is provided, only that package is updated.
103
+ `);
104
+ return;
105
+ case "list":
106
+ console.log(`${chalk.bold("Usage:")}
107
+ ${getPackageCommandUsage("list")}
108
+
109
+ List installed packages from user and project settings.
110
+ `);
111
+ return;
112
+ }
113
+ }
55
114
  function parsePackageCommand(args) {
56
115
  const [command, ...rest] = args;
57
116
  if (command !== "install" && command !== "remove" && command !== "update" && command !== "list") {
58
117
  return undefined;
59
118
  }
60
119
  let local = false;
61
- const sources = [];
120
+ let help = false;
121
+ let invalidOption;
122
+ let source;
62
123
  for (const arg of rest) {
124
+ if (arg === "-h" || arg === "--help") {
125
+ help = true;
126
+ continue;
127
+ }
63
128
  if (arg === "-l" || arg === "--local") {
64
- local = true;
129
+ if (command === "install" || command === "remove") {
130
+ local = true;
131
+ }
132
+ else {
133
+ invalidOption = invalidOption ?? arg;
134
+ }
65
135
  continue;
66
136
  }
67
- sources.push(arg);
68
- }
69
- return { command, source: sources[0], local };
70
- }
71
- function expandTildePath(input) {
72
- const trimmed = input.trim();
73
- if (trimmed === "~")
74
- return homedir();
75
- if (trimmed.startsWith("~/"))
76
- return resolve(homedir(), trimmed.slice(2));
77
- if (trimmed.startsWith("~"))
78
- return resolve(homedir(), trimmed.slice(1));
79
- return trimmed;
80
- }
81
- function resolveLocalSourceFromInput(source, cwd) {
82
- const expanded = expandTildePath(source);
83
- return isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
84
- }
85
- function resolveLocalSourceFromSettings(source, baseDir) {
86
- const expanded = expandTildePath(source);
87
- return isAbsolute(expanded) ? expanded : resolve(baseDir, expanded);
88
- }
89
- function normalizeLocalSourceForSettings(source, baseDir, cwd) {
90
- const resolved = resolveLocalSourceFromInput(source, cwd);
91
- const rel = relative(baseDir, resolved);
92
- return rel || ".";
93
- }
94
- function normalizePackageSourceForSettings(source, baseDir, cwd) {
95
- const normalized = normalizeExtensionSource(source);
96
- if (normalized.type !== "local") {
97
- return source;
98
- }
99
- return normalizeLocalSourceForSettings(source, baseDir, cwd);
100
- }
101
- function normalizeExtensionSource(source) {
102
- if (source.startsWith("npm:")) {
103
- const spec = source.slice("npm:".length).trim();
104
- const match = spec.match(/^(@?[^@]+(?:\/[^@]+)?)(?:@.+)?$/);
105
- return { type: "npm", key: match?.[1] ?? spec };
106
- }
107
- if (source.startsWith("git:")) {
108
- const repo = source.slice("git:".length).trim().split("@")[0] ?? "";
109
- return { type: "git", key: repo.replace(/^https?:\/\//, "").replace(/\.git$/, "") };
110
- }
111
- // Raw git URLs
112
- if (source.startsWith("https://") || source.startsWith("http://")) {
113
- const repo = source.split("@")[0] ?? "";
114
- return { type: "git", key: repo.replace(/^https?:\/\//, "").replace(/\.git$/, "") };
115
- }
116
- return { type: "local", key: source };
117
- }
118
- function normalizeSourceForInput(source, cwd) {
119
- const normalized = normalizeExtensionSource(source);
120
- if (normalized.type !== "local") {
121
- return normalized;
122
- }
123
- return { type: "local", key: resolveLocalSourceFromInput(source, cwd) };
124
- }
125
- function normalizeSourceForSettings(source, baseDir) {
126
- const normalized = normalizeExtensionSource(source);
127
- if (normalized.type !== "local") {
128
- return normalized;
129
- }
130
- return { type: "local", key: resolveLocalSourceFromSettings(source, baseDir) };
131
- }
132
- function sourcesMatch(a, b, baseDir, cwd) {
133
- const left = normalizeSourceForSettings(a, baseDir);
134
- const right = normalizeSourceForInput(b, cwd);
135
- return left.type === right.type && left.key === right.key;
136
- }
137
- function getPackageSourceString(pkg) {
138
- return typeof pkg === "string" ? pkg : pkg.source;
139
- }
140
- function packageSourcesMatch(a, b, baseDir, cwd) {
141
- const aSource = getPackageSourceString(a);
142
- return sourcesMatch(aSource, b, baseDir, cwd);
143
- }
144
- function updatePackageSources(settingsManager, source, local, cwd, agentDir, action) {
145
- const currentSettings = local ? settingsManager.getProjectSettings() : settingsManager.getGlobalSettings();
146
- const currentPackages = currentSettings.packages ?? [];
147
- const baseDir = local ? join(cwd, CONFIG_DIR_NAME) : agentDir;
148
- const normalizedSource = normalizePackageSourceForSettings(source, baseDir, cwd);
149
- let nextPackages;
150
- let changed = false;
151
- if (action === "add") {
152
- const exists = currentPackages.some((existing) => packageSourcesMatch(existing, source, baseDir, cwd));
153
- nextPackages = exists ? currentPackages : [...currentPackages, normalizedSource];
154
- changed = !exists;
155
- }
156
- else {
157
- nextPackages = currentPackages.filter((existing) => !packageSourcesMatch(existing, source, baseDir, cwd));
158
- changed = nextPackages.length !== currentPackages.length;
159
- }
160
- if (local) {
161
- settingsManager.setProjectPackages(nextPackages);
162
- }
163
- else {
164
- settingsManager.setPackages(nextPackages);
137
+ if (arg.startsWith("-")) {
138
+ invalidOption = invalidOption ?? arg;
139
+ continue;
140
+ }
141
+ if (!source) {
142
+ source = arg;
143
+ }
165
144
  }
166
- return changed;
145
+ return { command, source, local, help, invalidOption };
167
146
  }
168
147
  async function handlePackageCommand(args) {
169
148
  const options = parsePackageCommand(args);
170
149
  if (!options) {
171
150
  return false;
172
151
  }
152
+ if (options.help) {
153
+ printPackageCommandHelp(options.command);
154
+ return true;
155
+ }
156
+ if (options.invalidOption) {
157
+ console.error(chalk.red(`Unknown option ${options.invalidOption} for "${options.command}".`));
158
+ console.error(chalk.dim(`Use "${APP_NAME} --help" or "${getPackageCommandUsage(options.command)}".`));
159
+ process.exitCode = 1;
160
+ return true;
161
+ }
162
+ const source = options.source;
163
+ if ((options.command === "install" || options.command === "remove") && !source) {
164
+ console.error(chalk.red(`Missing ${options.command} source.`));
165
+ console.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));
166
+ process.exitCode = 1;
167
+ return true;
168
+ }
173
169
  const cwd = process.cwd();
174
170
  const agentDir = getAgentDir();
175
171
  const settingsManager = SettingsManager.create(cwd, agentDir);
176
172
  const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
177
- // Set up progress callback for CLI feedback
178
173
  packageManager.setProgressCallback((event) => {
179
174
  if (event.type === "start") {
180
175
  process.stdout.write(chalk.dim(`${event.message}\n`));
181
176
  }
182
- else if (event.type === "error") {
183
- console.error(chalk.red(`Error: ${event.message}`));
184
- }
185
177
  });
186
- if (options.command === "install") {
187
- if (!options.source) {
188
- console.error(chalk.red("Missing install source."));
189
- process.exit(1);
190
- }
191
- await packageManager.install(options.source, { local: options.local });
192
- updatePackageSources(settingsManager, options.source, options.local, cwd, agentDir, "add");
193
- console.log(chalk.green(`Installed ${options.source}`));
194
- return true;
195
- }
196
- if (options.command === "remove") {
197
- if (!options.source) {
198
- console.error(chalk.red("Missing remove source."));
199
- process.exit(1);
200
- }
201
- await packageManager.remove(options.source, { local: options.local });
202
- const removed = updatePackageSources(settingsManager, options.source, options.local, cwd, agentDir, "remove");
203
- if (!removed) {
204
- console.error(chalk.red(`No matching package found for ${options.source}`));
205
- process.exit(1);
206
- }
207
- console.log(chalk.green(`Removed ${options.source}`));
208
- return true;
209
- }
210
- if (options.command === "list") {
211
- const globalSettings = settingsManager.getGlobalSettings();
212
- const projectSettings = settingsManager.getProjectSettings();
213
- const globalPackages = globalSettings.packages ?? [];
214
- const projectPackages = projectSettings.packages ?? [];
215
- if (globalPackages.length === 0 && projectPackages.length === 0) {
216
- console.log(chalk.dim("No packages installed."));
217
- return true;
218
- }
219
- const formatPackage = (pkg, scope) => {
220
- const source = typeof pkg === "string" ? pkg : pkg.source;
221
- const filtered = typeof pkg === "object";
222
- const display = filtered ? `${source} (filtered)` : source;
223
- console.log(` ${display}`);
224
- // Show resolved path
225
- const path = packageManager.getInstalledPath(source, scope);
226
- if (path) {
227
- console.log(chalk.dim(` ${path}`));
228
- }
229
- };
230
- if (globalPackages.length > 0) {
231
- console.log(chalk.bold("User packages:"));
232
- for (const pkg of globalPackages) {
233
- formatPackage(pkg, "user");
178
+ try {
179
+ switch (options.command) {
180
+ case "install":
181
+ await packageManager.install(source, { local: options.local });
182
+ packageManager.addSourceToSettings(source, { local: options.local });
183
+ console.log(chalk.green(`Installed ${source}`));
184
+ return true;
185
+ case "remove": {
186
+ await packageManager.remove(source, { local: options.local });
187
+ const removed = packageManager.removeSourceFromSettings(source, { local: options.local });
188
+ if (!removed) {
189
+ console.error(chalk.red(`No matching package found for ${source}`));
190
+ process.exitCode = 1;
191
+ return true;
192
+ }
193
+ console.log(chalk.green(`Removed ${source}`));
194
+ return true;
234
195
  }
235
- }
236
- if (projectPackages.length > 0) {
237
- if (globalPackages.length > 0)
238
- console.log();
239
- console.log(chalk.bold("Project packages:"));
240
- for (const pkg of projectPackages) {
241
- formatPackage(pkg, "project");
196
+ case "list": {
197
+ const globalSettings = settingsManager.getGlobalSettings();
198
+ const projectSettings = settingsManager.getProjectSettings();
199
+ const globalPackages = globalSettings.packages ?? [];
200
+ const projectPackages = projectSettings.packages ?? [];
201
+ if (globalPackages.length === 0 && projectPackages.length === 0) {
202
+ console.log(chalk.dim("No packages installed."));
203
+ return true;
204
+ }
205
+ const formatPackage = (pkg, scope) => {
206
+ const source = typeof pkg === "string" ? pkg : pkg.source;
207
+ const filtered = typeof pkg === "object";
208
+ const display = filtered ? `${source} (filtered)` : source;
209
+ console.log(` ${display}`);
210
+ const path = packageManager.getInstalledPath(source, scope);
211
+ if (path) {
212
+ console.log(chalk.dim(` ${path}`));
213
+ }
214
+ };
215
+ if (globalPackages.length > 0) {
216
+ console.log(chalk.bold("User packages:"));
217
+ for (const pkg of globalPackages) {
218
+ formatPackage(pkg, "user");
219
+ }
220
+ }
221
+ if (projectPackages.length > 0) {
222
+ if (globalPackages.length > 0)
223
+ console.log();
224
+ console.log(chalk.bold("Project packages:"));
225
+ for (const pkg of projectPackages) {
226
+ formatPackage(pkg, "project");
227
+ }
228
+ }
229
+ return true;
242
230
  }
231
+ case "update":
232
+ await packageManager.update(source);
233
+ if (source) {
234
+ console.log(chalk.green(`Updated ${source}`));
235
+ }
236
+ else {
237
+ console.log(chalk.green("Updated packages"));
238
+ }
239
+ return true;
243
240
  }
244
- return true;
245
241
  }
246
- await packageManager.update(options.source);
247
- if (options.source) {
248
- console.log(chalk.green(`Updated ${options.source}`));
249
- }
250
- else {
251
- console.log(chalk.green("Updated packages"));
242
+ catch (error) {
243
+ const message = error instanceof Error ? error.message : "Unknown package command error";
244
+ console.error(chalk.red(`Error: ${message}`));
245
+ process.exitCode = 1;
246
+ return true;
252
247
  }
253
- return true;
254
248
  }
255
249
  async function prepareInitialMessage(parsed, autoResizeImages) {
256
250
  if (parsed.fileArgs.length === 0) {
@@ -484,16 +478,16 @@ export async function main(args) {
484
478
  }
485
479
  if (parsed.version) {
486
480
  console.log(VERSION);
487
- return;
481
+ process.exit(0);
488
482
  }
489
483
  if (parsed.help) {
490
484
  printHelp();
491
- return;
485
+ process.exit(0);
492
486
  }
493
487
  if (parsed.listModels !== undefined) {
494
488
  const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
495
489
  await listModels(modelRegistry, searchPattern);
496
- return;
490
+ process.exit(0);
497
491
  }
498
492
  // Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC
499
493
  if (parsed.mode !== "rpc") {
@@ -506,17 +500,18 @@ export async function main(args) {
506
500
  }
507
501
  }
508
502
  if (parsed.export) {
503
+ let result;
509
504
  try {
510
505
  const outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;
511
- const result = await exportFromFile(parsed.export, outputPath);
512
- console.log(`Exported to: ${result}`);
513
- return;
506
+ result = await exportFromFile(parsed.export, outputPath);
514
507
  }
515
508
  catch (error) {
516
509
  const message = error instanceof Error ? error.message : "Failed to export session";
517
510
  console.error(chalk.red(`Error: ${message}`));
518
511
  process.exit(1);
519
512
  }
513
+ console.log(`Exported to: ${result}`);
514
+ process.exit(0);
520
515
  }
521
516
  if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) {
522
517
  console.error(chalk.red("Error: @file arguments are not supported in RPC mode"));