@vandeepunk/pi-coding-agent 0.0.2 → 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 (105) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +6 -6
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/config.d.ts +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +2 -2
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +7 -0
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/auth-storage.d.ts.map +1 -1
  14. package/dist/core/auth-storage.js +16 -0
  15. package/dist/core/auth-storage.js.map +1 -1
  16. package/dist/core/export-html/template.css +3 -0
  17. package/dist/core/export-html/template.js +32 -15
  18. package/dist/core/extensions/loader.d.ts.map +1 -1
  19. package/dist/core/extensions/loader.js.map +1 -1
  20. package/dist/core/extensions/runner.d.ts +17 -2
  21. package/dist/core/extensions/runner.d.ts.map +1 -1
  22. package/dist/core/extensions/runner.js +53 -9
  23. package/dist/core/extensions/runner.js.map +1 -1
  24. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  25. package/dist/core/extensions/wrapper.js +3 -3
  26. package/dist/core/extensions/wrapper.js.map +1 -1
  27. package/dist/core/model-registry.d.ts +3 -1
  28. package/dist/core/model-registry.d.ts.map +1 -1
  29. package/dist/core/model-registry.js +133 -37
  30. package/dist/core/model-registry.js.map +1 -1
  31. package/dist/core/model-resolver.d.ts.map +1 -1
  32. package/dist/core/model-resolver.js +5 -5
  33. package/dist/core/model-resolver.js.map +1 -1
  34. package/dist/core/package-manager.d.ts +21 -1
  35. package/dist/core/package-manager.d.ts.map +1 -1
  36. package/dist/core/package-manager.js +134 -33
  37. package/dist/core/package-manager.js.map +1 -1
  38. package/dist/core/prompt-templates.d.ts +3 -3
  39. package/dist/core/prompt-templates.d.ts.map +1 -1
  40. package/dist/core/prompt-templates.js +15 -15
  41. package/dist/core/prompt-templates.js.map +1 -1
  42. package/dist/core/resource-loader.d.ts.map +1 -1
  43. package/dist/core/resource-loader.js +6 -6
  44. package/dist/core/resource-loader.js.map +1 -1
  45. package/dist/core/settings-manager.d.ts +2 -2
  46. package/dist/core/settings-manager.d.ts.map +1 -1
  47. package/dist/core/settings-manager.js +4 -4
  48. package/dist/core/settings-manager.js.map +1 -1
  49. package/dist/core/skills.d.ts.map +1 -1
  50. package/dist/core/skills.js +57 -3
  51. package/dist/core/skills.js.map +1 -1
  52. package/dist/core/slash-commands.d.ts.map +1 -1
  53. package/dist/core/slash-commands.js +1 -0
  54. package/dist/core/slash-commands.js.map +1 -1
  55. package/dist/main.d.ts.map +1 -1
  56. package/dist/main.js +172 -177
  57. package/dist/main.js.map +1 -1
  58. package/dist/migrations.d.ts.map +1 -1
  59. package/dist/migrations.js +11 -11
  60. package/dist/migrations.js.map +1 -1
  61. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  62. package/dist/modes/interactive/components/assistant-message.js +9 -4
  63. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  64. package/dist/modes/interactive/components/config-selector.d.ts +1 -1
  65. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  66. package/dist/modes/interactive/components/config-selector.js +6 -6
  67. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  68. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  69. package/dist/modes/interactive/components/model-selector.js +5 -0
  70. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  71. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  72. package/dist/modes/interactive/components/scoped-models-selector.js +5 -0
  73. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  74. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  75. package/dist/modes/interactive/components/tool-execution.js +49 -34
  76. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  77. package/dist/modes/interactive/interactive-mode.d.ts +0 -1
  78. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  79. package/dist/modes/interactive/interactive-mode.js +117 -104
  80. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  81. package/dist/utils/git.d.ts +21 -1
  82. package/dist/utils/git.d.ts.map +1 -1
  83. package/dist/utils/git.js +150 -4
  84. package/dist/utils/git.js.map +1 -1
  85. package/docs/extensions.md +5 -0
  86. package/docs/models.md +40 -1
  87. package/docs/packages.md +23 -3
  88. package/docs/prompt-templates.md +6 -6
  89. package/docs/providers.md +13 -0
  90. package/docs/rpc.md +1 -1
  91. package/docs/sdk.md +5 -3
  92. package/docs/settings.md +2 -2
  93. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  94. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  95. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  96. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  97. package/examples/extensions/hello.ts +1 -1
  98. package/examples/extensions/subagent/README.md +4 -4
  99. package/examples/extensions/with-deps/package-lock.json +2 -2
  100. package/examples/extensions/with-deps/package.json +1 -1
  101. package/examples/sdk/08-prompt-templates.ts +2 -2
  102. package/package.json +7 -8
  103. /package/examples/extensions/subagent/{prompts → commands}/implement-and-review.md +0 -0
  104. /package/examples/extensions/subagent/{prompts → commands}/implement.md +0 -0
  105. /package/examples/extensions/subagent/{prompts → commands}/scout-and-plan.md +0 -0
@@ -6,12 +6,12 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
6
6
  import ignore from "ignore";
7
7
  import { minimatch } from "minimatch";
8
8
  import { CONFIG_DIR_NAME } from "../config.js";
9
- import { looksLikeGitUrl } from "../utils/git.js";
10
- const RESOURCE_TYPES = ["extensions", "skills", "prompts", "themes"];
9
+ import { parseGitUrl } from "../utils/git.js";
10
+ const RESOURCE_TYPES = ["extensions", "skills", "commands", "themes"];
11
11
  const FILE_PATTERNS = {
12
12
  extensions: /\.(ts|js)$/,
13
13
  skills: /\.md$/,
14
- prompts: /\.md$/,
14
+ commands: /\.md$/,
15
15
  themes: /\.json$/,
16
16
  };
17
17
  const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
@@ -283,6 +283,12 @@ function collectAutoExtensionEntries(dir) {
283
283
  const entries = [];
284
284
  if (!existsSync(dir))
285
285
  return entries;
286
+ // First check if this directory itself has explicit extension entries (package.json or index)
287
+ const rootEntries = resolveExtensionEntries(dir);
288
+ if (rootEntries) {
289
+ return rootEntries;
290
+ }
291
+ // Otherwise, discover extensions from directory contents
286
292
  const ig = ignore();
287
293
  addIgnoreRules(ig, dir, dir);
288
294
  try {
@@ -465,6 +471,41 @@ export class DefaultPackageManager {
465
471
  setProgressCallback(callback) {
466
472
  this.progressCallback = callback;
467
473
  }
474
+ addSourceToSettings(source, options) {
475
+ const scope = options?.local ? "project" : "user";
476
+ const currentSettings = scope === "project" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();
477
+ const currentPackages = currentSettings.packages ?? [];
478
+ const normalizedSource = this.normalizePackageSourceForSettings(source, scope);
479
+ const exists = currentPackages.some((existing) => this.packageSourcesMatch(existing, source, scope));
480
+ if (exists) {
481
+ return false;
482
+ }
483
+ const nextPackages = [...currentPackages, normalizedSource];
484
+ if (scope === "project") {
485
+ this.settingsManager.setProjectPackages(nextPackages);
486
+ }
487
+ else {
488
+ this.settingsManager.setPackages(nextPackages);
489
+ }
490
+ return true;
491
+ }
492
+ removeSourceFromSettings(source, options) {
493
+ const scope = options?.local ? "project" : "user";
494
+ const currentSettings = scope === "project" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();
495
+ const currentPackages = currentSettings.packages ?? [];
496
+ const nextPackages = currentPackages.filter((existing) => !this.packageSourcesMatch(existing, source, scope));
497
+ const changed = nextPackages.length !== currentPackages.length;
498
+ if (!changed) {
499
+ return false;
500
+ }
501
+ if (scope === "project") {
502
+ this.settingsManager.setProjectPackages(nextPackages);
503
+ }
504
+ else {
505
+ this.settingsManager.setPackages(nextPackages);
506
+ }
507
+ return true;
508
+ }
468
509
  getInstalledPath(source, scope) {
469
510
  const parsed = this.parseSource(source);
470
511
  if (parsed.type === "npm") {
@@ -658,6 +699,9 @@ export class DefaultPackageManager {
658
699
  if (!installed)
659
700
  continue;
660
701
  }
702
+ else if (scope === "temporary" && !parsed.pinned) {
703
+ await this.refreshTemporaryGitSource(parsed, sourceStr);
704
+ }
661
705
  metadata.baseDir = installedPath;
662
706
  this.collectPackageResources(installedPath, accumulator, filter, metadata);
663
707
  }
@@ -697,6 +741,45 @@ export class DefaultPackageManager {
697
741
  return;
698
742
  }
699
743
  }
744
+ getPackageSourceString(pkg) {
745
+ return typeof pkg === "string" ? pkg : pkg.source;
746
+ }
747
+ getSourceMatchKeyForInput(source) {
748
+ const parsed = this.parseSource(source);
749
+ if (parsed.type === "npm") {
750
+ return `npm:${parsed.name}`;
751
+ }
752
+ if (parsed.type === "git") {
753
+ return `git:${parsed.host}/${parsed.path}`;
754
+ }
755
+ return `local:${this.resolvePath(parsed.path)}`;
756
+ }
757
+ getSourceMatchKeyForSettings(source, scope) {
758
+ const parsed = this.parseSource(source);
759
+ if (parsed.type === "npm") {
760
+ return `npm:${parsed.name}`;
761
+ }
762
+ if (parsed.type === "git") {
763
+ return `git:${parsed.host}/${parsed.path}`;
764
+ }
765
+ const baseDir = this.getBaseDirForScope(scope);
766
+ return `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;
767
+ }
768
+ packageSourcesMatch(existing, inputSource, scope) {
769
+ const left = this.getSourceMatchKeyForSettings(this.getPackageSourceString(existing), scope);
770
+ const right = this.getSourceMatchKeyForInput(inputSource);
771
+ return left === right;
772
+ }
773
+ normalizePackageSourceForSettings(source, scope) {
774
+ const parsed = this.parseSource(source);
775
+ if (parsed.type !== "local") {
776
+ return source;
777
+ }
778
+ const baseDir = this.getBaseDirForScope(scope);
779
+ const resolved = this.resolvePath(parsed.path);
780
+ const rel = relative(baseDir, resolved);
781
+ return rel || ".";
782
+ }
700
783
  parseSource(source) {
701
784
  if (source.startsWith("npm:")) {
702
785
  const spec = source.slice("npm:".length).trim();
@@ -708,21 +791,21 @@ export class DefaultPackageManager {
708
791
  pinned: Boolean(version),
709
792
  };
710
793
  }
711
- if (source.startsWith("git:") || looksLikeGitUrl(source)) {
712
- const repoSpec = source.startsWith("git:") ? source.slice("git:".length).trim() : source;
713
- const [repo, ref] = repoSpec.split("@");
714
- const normalized = repo.replace(/^https?:\/\//, "").replace(/\.git$/, "");
715
- const parts = normalized.split("/");
716
- const host = parts.shift() ?? "";
717
- const repoPath = parts.join("/");
718
- return {
719
- type: "git",
720
- repo: normalized,
721
- host,
722
- path: repoPath,
723
- ref,
724
- pinned: Boolean(ref),
725
- };
794
+ const trimmed = source.trim();
795
+ const isWindowsAbsolutePath = /^[A-Za-z]:[\\/]|^\\\\/.test(trimmed);
796
+ const isLocalPathLike = trimmed.startsWith("./") ||
797
+ trimmed.startsWith("../") ||
798
+ trimmed.startsWith("/") ||
799
+ trimmed === "~" ||
800
+ trimmed.startsWith("~/") ||
801
+ isWindowsAbsolutePath;
802
+ if (isLocalPathLike) {
803
+ return { type: "local", path: source };
804
+ }
805
+ // Try parsing as git URL
806
+ const gitParsed = parseGitUrl(source);
807
+ if (gitParsed) {
808
+ return gitParsed;
726
809
  }
727
810
  return { type: "local", path: source };
728
811
  }
@@ -773,6 +856,8 @@ export class DefaultPackageManager {
773
856
  /**
774
857
  * Get a unique identity for a package, ignoring version/ref.
775
858
  * Used to detect when the same package is in both global and project settings.
859
+ * For git packages, uses normalized host/path to ensure SSH and HTTPS URLs
860
+ * for the same repository are treated as identical.
776
861
  */
777
862
  getPackageIdentity(source, scope) {
778
863
  const parsed = this.parseSource(source);
@@ -780,7 +865,8 @@ export class DefaultPackageManager {
780
865
  return `npm:${parsed.name}`;
781
866
  }
782
867
  if (parsed.type === "git") {
783
- return `git:${parsed.repo}`;
868
+ // Use host/path for identity to normalize SSH and HTTPS
869
+ return `git:${parsed.host}/${parsed.path}`;
784
870
  }
785
871
  if (scope) {
786
872
  const baseDir = this.getBaseDirForScope(scope);
@@ -849,8 +935,7 @@ export class DefaultPackageManager {
849
935
  this.ensureGitIgnore(gitRoot);
850
936
  }
851
937
  mkdirSync(dirname(targetDir), { recursive: true });
852
- const cloneUrl = source.repo.startsWith("http") ? source.repo : `https://${source.repo}`;
853
- await this.runCommand("git", ["clone", cloneUrl, targetDir]);
938
+ await this.runCommand("git", ["clone", source.repo, targetDir]);
854
939
  if (source.ref) {
855
940
  await this.runCommand("git", ["checkout", source.ref], { cwd: targetDir });
856
941
  }
@@ -867,8 +952,14 @@ export class DefaultPackageManager {
867
952
  }
868
953
  // Fetch latest from remote (handles force-push by getting new history)
869
954
  await this.runCommand("git", ["fetch", "--prune", "origin"], { cwd: targetDir });
870
- // Reset to upstream tracking branch (handles force-push gracefully)
871
- await this.runCommand("git", ["reset", "--hard", "@{upstream}"], { cwd: targetDir });
955
+ // Reset to tracking branch. Fall back to origin/HEAD when no upstream is configured.
956
+ try {
957
+ await this.runCommand("git", ["reset", "--hard", "@{upstream}"], { cwd: targetDir });
958
+ }
959
+ catch {
960
+ await this.runCommand("git", ["remote", "set-head", "origin", "-a"], { cwd: targetDir }).catch(() => { });
961
+ await this.runCommand("git", ["reset", "--hard", "origin/HEAD"], { cwd: targetDir });
962
+ }
872
963
  // Clean untracked files (extensions should be pristine)
873
964
  await this.runCommand("git", ["clean", "-fdx"], { cwd: targetDir });
874
965
  const packageJsonPath = join(targetDir, "package.json");
@@ -876,6 +967,16 @@ export class DefaultPackageManager {
876
967
  await this.runCommand("npm", ["install"], { cwd: targetDir });
877
968
  }
878
969
  }
970
+ async refreshTemporaryGitSource(source, sourceStr) {
971
+ try {
972
+ await this.withProgress("pull", sourceStr, `Refreshing ${sourceStr}...`, async () => {
973
+ await this.updateGit(source, "temporary");
974
+ });
975
+ }
976
+ catch {
977
+ // Keep cached temporary checkout if refresh fails.
978
+ }
979
+ }
879
980
  async removeGit(source, scope) {
880
981
  const targetDir = this.getGitInstallPath(source, scope);
881
982
  if (!existsSync(targetDir))
@@ -1156,25 +1257,25 @@ export class DefaultPackageManager {
1156
1257
  const userOverrides = {
1157
1258
  extensions: (globalSettings.extensions ?? []),
1158
1259
  skills: (globalSettings.skills ?? []),
1159
- prompts: (globalSettings.prompts ?? []),
1260
+ commands: (globalSettings.commands ?? []),
1160
1261
  themes: (globalSettings.themes ?? []),
1161
1262
  };
1162
1263
  const projectOverrides = {
1163
1264
  extensions: (projectSettings.extensions ?? []),
1164
1265
  skills: (projectSettings.skills ?? []),
1165
- prompts: (projectSettings.prompts ?? []),
1266
+ commands: (projectSettings.commands ?? []),
1166
1267
  themes: (projectSettings.themes ?? []),
1167
1268
  };
1168
1269
  const userDirs = {
1169
1270
  extensions: join(globalBaseDir, "extensions"),
1170
1271
  skills: join(globalBaseDir, "skills"),
1171
- prompts: join(globalBaseDir, "prompts"),
1272
+ commands: join(globalBaseDir, "commands"),
1172
1273
  themes: join(globalBaseDir, "themes"),
1173
1274
  };
1174
1275
  const projectDirs = {
1175
1276
  extensions: join(projectBaseDir, "extensions"),
1176
1277
  skills: join(projectBaseDir, "skills"),
1177
- prompts: join(projectBaseDir, "prompts"),
1278
+ commands: join(projectBaseDir, "commands"),
1178
1279
  themes: join(projectBaseDir, "themes"),
1179
1280
  };
1180
1281
  const addResources = (resourceType, paths, metadata, overrides, baseDir) => {
@@ -1186,11 +1287,11 @@ export class DefaultPackageManager {
1186
1287
  };
1187
1288
  addResources("extensions", collectAutoExtensionEntries(userDirs.extensions), userMetadata, userOverrides.extensions, globalBaseDir);
1188
1289
  addResources("skills", collectAutoSkillEntries(userDirs.skills), userMetadata, userOverrides.skills, globalBaseDir);
1189
- addResources("prompts", collectAutoPromptEntries(userDirs.prompts), userMetadata, userOverrides.prompts, globalBaseDir);
1290
+ addResources("commands", collectAutoPromptEntries(userDirs.commands), userMetadata, userOverrides.commands, globalBaseDir);
1190
1291
  addResources("themes", collectAutoThemeEntries(userDirs.themes), userMetadata, userOverrides.themes, globalBaseDir);
1191
1292
  addResources("extensions", collectAutoExtensionEntries(projectDirs.extensions), projectMetadata, projectOverrides.extensions, projectBaseDir);
1192
1293
  addResources("skills", collectAutoSkillEntries(projectDirs.skills), projectMetadata, projectOverrides.skills, projectBaseDir);
1193
- addResources("prompts", collectAutoPromptEntries(projectDirs.prompts), projectMetadata, projectOverrides.prompts, projectBaseDir);
1294
+ addResources("commands", collectAutoPromptEntries(projectDirs.commands), projectMetadata, projectOverrides.commands, projectBaseDir);
1194
1295
  addResources("themes", collectAutoThemeEntries(projectDirs.themes), projectMetadata, projectOverrides.themes, projectBaseDir);
1195
1296
  }
1196
1297
  collectFilesFromPaths(paths, resourceType) {
@@ -1219,8 +1320,8 @@ export class DefaultPackageManager {
1219
1320
  return accumulator.extensions;
1220
1321
  case "skills":
1221
1322
  return accumulator.skills;
1222
- case "prompts":
1223
- return accumulator.prompts;
1323
+ case "commands":
1324
+ return accumulator.commands;
1224
1325
  case "themes":
1225
1326
  return accumulator.themes;
1226
1327
  default:
@@ -1238,7 +1339,7 @@ export class DefaultPackageManager {
1238
1339
  return {
1239
1340
  extensions: new Map(),
1240
1341
  skills: new Map(),
1241
- prompts: new Map(),
1342
+ commands: new Map(),
1242
1343
  themes: new Map(),
1243
1344
  };
1244
1345
  }
@@ -1253,7 +1354,7 @@ export class DefaultPackageManager {
1253
1354
  return {
1254
1355
  extensions: toResolved(accumulator.extensions),
1255
1356
  skills: toResolved(accumulator.skills),
1256
- prompts: toResolved(accumulator.prompts),
1357
+ commands: toResolved(accumulator.commands),
1257
1358
  themes: toResolved(accumulator.themes),
1258
1359
  };
1259
1360
  }