@oh-my-pi/pi-coding-agent 9.3.1 → 9.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/examples/hooks/snake.ts +5 -5
  3. package/package.json +9 -8
  4. package/src/capability/index.ts +7 -9
  5. package/src/cli/config-cli.ts +86 -73
  6. package/src/cli/update-cli.ts +45 -3
  7. package/src/commit/agentic/agent.ts +4 -4
  8. package/src/commit/agentic/index.ts +6 -5
  9. package/src/commit/agentic/tools/analyze-file.ts +5 -7
  10. package/src/commit/agentic/tools/index.ts +3 -3
  11. package/src/commit/model-selection.ts +13 -17
  12. package/src/commit/pipeline.ts +5 -5
  13. package/src/config/model-registry.ts +7 -0
  14. package/src/config/settings-schema.ts +836 -0
  15. package/src/config/settings.ts +702 -0
  16. package/src/discovery/helpers.ts +55 -11
  17. package/src/exa/index.ts +1 -1
  18. package/src/exec/bash-executor.ts +13 -13
  19. package/src/exec/shell-session.ts +15 -3
  20. package/src/export/ttsr.ts +1 -1
  21. package/src/extensibility/skills.ts +40 -9
  22. package/src/index.ts +2 -10
  23. package/src/ipy/gateway-coordinator.ts +5 -159
  24. package/src/ipy/kernel.ts +6 -171
  25. package/src/ipy/runtime.ts +198 -0
  26. package/src/lsp/client.ts +14 -1
  27. package/src/lsp/defaults.json +0 -6
  28. package/src/lsp/index.ts +1 -1
  29. package/src/lsp/types.ts +2 -0
  30. package/src/main.ts +26 -48
  31. package/src/modes/components/armin.ts +7 -7
  32. package/src/modes/components/extensions/extension-dashboard.ts +33 -13
  33. package/src/modes/components/extensions/extension-list.ts +2 -2
  34. package/src/modes/components/footer.ts +5 -5
  35. package/src/modes/components/history-search.ts +2 -1
  36. package/src/modes/components/hook-selector.ts +2 -2
  37. package/src/modes/components/index.ts +1 -1
  38. package/src/modes/components/model-selector.ts +7 -7
  39. package/src/modes/components/session-selector.ts +2 -1
  40. package/src/modes/components/settings-defs.ts +210 -915
  41. package/src/modes/components/settings-selector.ts +80 -106
  42. package/src/modes/components/status-line/types.ts +2 -8
  43. package/src/modes/components/status-line-segment-editor.ts +4 -4
  44. package/src/modes/components/status-line.ts +28 -5
  45. package/src/modes/components/welcome.ts +3 -3
  46. package/src/modes/controllers/command-controller.ts +2 -2
  47. package/src/modes/controllers/event-controller.ts +9 -8
  48. package/src/modes/controllers/input-controller.ts +19 -15
  49. package/src/modes/controllers/selector-controller.ts +30 -14
  50. package/src/modes/interactive-mode.ts +10 -10
  51. package/src/modes/rpc/rpc-mode.ts +10 -0
  52. package/src/modes/rpc/rpc-types.ts +3 -0
  53. package/src/modes/types.ts +2 -2
  54. package/src/modes/utils/ui-helpers.ts +4 -3
  55. package/src/patch/index.ts +7 -7
  56. package/src/patch/normalize.ts +3 -1
  57. package/src/prompts/system/plan-mode-active.md +5 -4
  58. package/src/prompts/system/system-prompt.md +0 -1
  59. package/src/prompts/tools/bash.md +12 -2
  60. package/src/prompts/tools/task.md +180 -73
  61. package/src/sdk.ts +38 -61
  62. package/src/session/agent-session.ts +66 -55
  63. package/src/session/agent-storage.ts +1 -1
  64. package/src/session/session-manager.ts +10 -10
  65. package/src/system-prompt.ts +2 -2
  66. package/src/task/executor.ts +9 -9
  67. package/src/task/index.ts +2 -2
  68. package/src/tools/ask.ts +5 -6
  69. package/src/tools/bash-interceptor.ts +39 -1
  70. package/src/tools/bash-normalize.ts +126 -0
  71. package/src/tools/bash.ts +31 -5
  72. package/src/tools/find.ts +51 -33
  73. package/src/tools/gemini-image.ts +7 -8
  74. package/src/tools/index.ts +5 -23
  75. package/src/tools/plan-mode-guard.ts +1 -6
  76. package/src/tools/python.ts +29 -4
  77. package/src/tools/read.ts +2 -2
  78. package/src/tools/write.ts +2 -2
  79. package/src/tui/output-block.ts +2 -2
  80. package/src/tui/utils.ts +2 -2
  81. package/src/utils/ignore-files.ts +119 -0
  82. package/src/web/search/auth.ts +6 -58
  83. package/src/web/search/index.ts +2 -6
  84. package/src/web/search/providers/anthropic.ts +6 -6
  85. package/src/web/search/providers/exa.ts +2 -62
  86. package/src/web/search/providers/perplexity.ts +7 -53
  87. package/examples/sdk/10-settings.ts +0 -37
  88. package/src/config/settings-manager.ts +0 -2015
@@ -8,7 +8,7 @@ import { formatCommitMessage } from "../../commit/message";
8
8
  import { resolvePrimaryModel, resolveSmolModel } from "../../commit/model-selection";
9
9
  import type { CommitCommandArgs, ConventionalAnalysis } from "../../commit/types";
10
10
  import { renderPromptTemplate } from "../../config/prompt-templates";
11
- import { SettingsManager } from "../../config/settings-manager";
11
+ import { Settings } from "../../config/settings";
12
12
  import { discoverAuthStorage, discoverContextFiles, discoverModels } from "../../sdk";
13
13
  import { type ExistingChangelogEntries, runCommitAgentSession } from "./agent";
14
14
  import { generateFallbackProposal } from "./fallback";
@@ -26,7 +26,8 @@ interface CommitExecutionContext {
26
26
  export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
27
27
  const cwd = process.cwd();
28
28
  const git = new ControlledGit(cwd);
29
- const [settingsManager, authStorage] = await Promise.all([SettingsManager.create(cwd), discoverAuthStorage()]);
29
+ const [settingsInstance, authStorage] = await Promise.all([Settings.init({ cwd }), discoverAuthStorage()]);
30
+ const settings = settingsInstance;
30
31
 
31
32
  writeStdout("● Resolving model...");
32
33
  const modelRegistry = discoverModels(authStorage);
@@ -40,12 +41,12 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
40
41
  return stagedFiles;
41
42
  })();
42
43
 
43
- const primaryModelPromise = resolvePrimaryModel(args.model, settingsManager, modelRegistry);
44
+ const primaryModelPromise = resolvePrimaryModel(args.model, settings, modelRegistry);
44
45
  const [primaryModelResult, stagedFiles] = await Promise.all([primaryModelPromise, stagedFilesPromise]);
45
46
  const { model: primaryModel, apiKey: primaryApiKey } = primaryModelResult;
46
47
  writeStdout(` └─ ${primaryModel.name}`);
47
48
 
48
- const { model: agentModel } = await resolveSmolModel(settingsManager, modelRegistry, primaryModel, primaryApiKey);
49
+ const { model: agentModel } = await resolveSmolModel(settings, modelRegistry, primaryModel, primaryApiKey);
49
50
 
50
51
  if (stagedFiles.length === 0) {
51
52
  writeStderr("No changes to commit.");
@@ -123,7 +124,7 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
123
124
  cwd,
124
125
  git,
125
126
  model: agentModel,
126
- settingsManager,
127
+ settings,
127
128
  modelRegistry,
128
129
  authStorage,
129
130
  userContext: args.context,
@@ -4,7 +4,7 @@ import type { CommitAgentState } from "../../../commit/agentic/state";
4
4
  import type { NumstatEntry } from "../../../commit/types";
5
5
  import type { ModelRegistry } from "../../../config/model-registry";
6
6
  import { renderPromptTemplate } from "../../../config/prompt-templates";
7
- import type { SettingsManager } from "../../../config/settings-manager";
7
+ import type { Settings } from "../../../config/settings";
8
8
  import type { CustomTool, CustomToolContext } from "../../../extensibility/custom-tools/types";
9
9
  import type { AuthStorage } from "../../../session/auth-storage";
10
10
  import { TaskTool } from "../../../task";
@@ -31,18 +31,16 @@ function buildToolSession(
31
31
  cwd: string;
32
32
  authStorage: AuthStorage;
33
33
  modelRegistry: ModelRegistry;
34
- settingsManager: SettingsManager;
34
+ settings: Settings;
35
35
  spawns: string;
36
36
  },
37
37
  ): ToolSession {
38
- const sessionFile = () => ctx.sessionManager.getSessionFile() ?? null;
39
38
  return {
40
39
  cwd: options.cwd,
41
40
  hasUI: false,
42
- getSessionFile: sessionFile,
41
+ getSessionFile: () => ctx.sessionManager.getSessionFile() ?? null,
43
42
  getSessionSpawns: () => options.spawns,
44
- settings: options.settingsManager,
45
- settingsManager: options.settingsManager,
43
+ settings: options.settings,
46
44
  authStorage: options.authStorage,
47
45
  modelRegistry: options.modelRegistry,
48
46
  };
@@ -52,7 +50,7 @@ export function createAnalyzeFileTool(options: {
52
50
  cwd: string;
53
51
  authStorage: AuthStorage;
54
52
  modelRegistry: ModelRegistry;
55
- settingsManager: SettingsManager;
53
+ settings: Settings;
56
54
  spawns: string;
57
55
  state: CommitAgentState;
58
56
  }): CustomTool<typeof analyzeFileSchema> {
@@ -1,7 +1,7 @@
1
1
  import type { CommitAgentState } from "../../../commit/agentic/state";
2
2
  import type { ControlledGit } from "../../../commit/git";
3
3
  import type { ModelRegistry } from "../../../config/model-registry";
4
- import type { SettingsManager } from "../../../config/settings-manager";
4
+ import type { Settings } from "../../../config/settings";
5
5
  import type { CustomTool } from "../../../extensibility/custom-tools/types";
6
6
  import type { AuthStorage } from "../../../session/auth-storage";
7
7
  import { createAnalyzeFileTool } from "./analyze-file";
@@ -18,7 +18,7 @@ export interface CommitToolOptions {
18
18
  git: ControlledGit;
19
19
  authStorage: AuthStorage;
20
20
  modelRegistry: ModelRegistry;
21
- settingsManager: SettingsManager;
21
+ settings: Settings;
22
22
  spawns: string;
23
23
  state: CommitAgentState;
24
24
  changelogTargets: string[];
@@ -39,7 +39,7 @@ export function createCommitTools(options: CommitToolOptions): Array<CustomTool<
39
39
  cwd: options.cwd,
40
40
  authStorage: options.authStorage,
41
41
  modelRegistry: options.modelRegistry,
42
- settingsManager: options.settingsManager,
42
+ settings: options.settings,
43
43
  spawns: options.spawns,
44
44
  state: options.state,
45
45
  }),
@@ -1,20 +1,20 @@
1
1
  import type { Api, Model } from "@oh-my-pi/pi-ai";
2
2
  import { parseModelPattern, parseModelString, SMOL_MODEL_PRIORITY } from "../config/model-resolver";
3
- import type { SettingsManager } from "../config/settings-manager";
3
+ import type { Settings } from "../config/settings";
4
4
 
5
5
  export async function resolvePrimaryModel(
6
6
  override: string | undefined,
7
- settingsManager: SettingsManager,
7
+ settings: Settings,
8
8
  modelRegistry: {
9
9
  getAvailable: () => Model<Api>[];
10
10
  getApiKey: (model: Model<Api>) => Promise<string | undefined>;
11
11
  },
12
12
  ): Promise<{ model: Model<Api>; apiKey: string }> {
13
13
  const available = modelRegistry.getAvailable();
14
- const matchPreferences = { usageOrder: settingsManager.getStorage()?.getModelUsageOrder() };
14
+ const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
15
15
  const model = override
16
- ? resolveModelFromString(expandRoleAlias(override, settingsManager), available, matchPreferences)
17
- : resolveModelFromSettings(settingsManager, available, matchPreferences);
16
+ ? resolveModelFromString(expandRoleAlias(override, settings), available, matchPreferences)
17
+ : resolveModelFromSettings(settings, available, matchPreferences);
18
18
  if (!model) {
19
19
  throw new Error("No model available for commit generation");
20
20
  }
@@ -26,7 +26,7 @@ export async function resolvePrimaryModel(
26
26
  }
27
27
 
28
28
  export async function resolveSmolModel(
29
- settingsManager: SettingsManager,
29
+ settings: Settings,
30
30
  modelRegistry: {
31
31
  getAvailable: () => Model<Api>[];
32
32
  getApiKey: (model: Model<Api>) => Promise<string | undefined>;
@@ -35,8 +35,8 @@ export async function resolveSmolModel(
35
35
  fallbackApiKey: string,
36
36
  ): Promise<{ model: Model<Api>; apiKey: string }> {
37
37
  const available = modelRegistry.getAvailable();
38
- const matchPreferences = { usageOrder: settingsManager.getStorage()?.getModelUsageOrder() };
39
- const role = settingsManager.getModelRole("smol");
38
+ const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
39
+ const role = settings.getModelRole("smol");
40
40
  const roleModel = role ? resolveModelFromString(role, available, matchPreferences) : undefined;
41
41
  if (roleModel) {
42
42
  const apiKey = await modelRegistry.getApiKey(roleModel);
@@ -54,19 +54,15 @@ export async function resolveSmolModel(
54
54
  }
55
55
 
56
56
  function resolveModelFromSettings(
57
- settingsManager: SettingsManager,
57
+ settings: Settings,
58
58
  available: Model<Api>[],
59
59
  matchPreferences: { usageOrder?: string[] },
60
60
  ): Model<Api> | undefined {
61
61
  const roles = ["commit", "smol", "default"];
62
62
  for (const role of roles) {
63
- const configured = settingsManager.getModelRole(role);
63
+ const configured = settings.getModelRole(role);
64
64
  if (!configured) continue;
65
- const resolved = resolveModelFromString(
66
- expandRoleAlias(configured, settingsManager),
67
- available,
68
- matchPreferences,
69
- );
65
+ const resolved = resolveModelFromString(expandRoleAlias(configured, settings), available, matchPreferences);
70
66
  if (resolved) return resolved;
71
67
  }
72
68
  return available[0];
@@ -84,11 +80,11 @@ function resolveModelFromString(
84
80
  return parseModelPattern(value, available, matchPreferences).model;
85
81
  }
86
82
 
87
- function expandRoleAlias(value: string, settingsManager: SettingsManager): string {
83
+ function expandRoleAlias(value: string, settings: Settings): string {
88
84
  const lower = value.toLowerCase();
89
85
  if (lower.startsWith("pi/") || lower.startsWith("omp/")) {
90
86
  const role = lower.startsWith("pi/") ? value.slice(3) : value.slice(4);
91
- return settingsManager.getModelRole(role) ?? value;
87
+ return settings.getModelRole(role) ?? value;
92
88
  }
93
89
  return value;
94
90
  }
@@ -2,7 +2,7 @@ import * as path from "node:path";
2
2
  import type { Api, Model } from "@oh-my-pi/pi-ai";
3
3
  import { logger } from "@oh-my-pi/pi-utils";
4
4
  import { renderPromptTemplate } from "../config/prompt-templates";
5
- import { SettingsManager } from "../config/settings-manager";
5
+ import { Settings } from "../config/settings";
6
6
  import { discoverAuthStorage, discoverModels } from "../sdk";
7
7
  import { loadProjectContextFiles } from "../system-prompt";
8
8
  import { runAgenticCommit } from "./agentic";
@@ -38,18 +38,18 @@ export async function runCommitCommand(args: CommitCommandArgs): Promise<void> {
38
38
 
39
39
  async function runLegacyCommitCommand(args: CommitCommandArgs): Promise<void> {
40
40
  const cwd = process.cwd();
41
- const settingsManager = await SettingsManager.create(cwd);
42
- const commitSettings = settingsManager.getCommitSettings();
41
+ const settingsInstance = await Settings.init();
42
+ const commitSettings = settingsInstance.getGroup("commit");
43
43
  const authStorage = await discoverAuthStorage();
44
44
  const modelRegistry = discoverModels(authStorage);
45
45
 
46
46
  const { model: primaryModel, apiKey: primaryApiKey } = await resolvePrimaryModel(
47
47
  args.model,
48
- settingsManager,
48
+ settingsInstance,
49
49
  modelRegistry,
50
50
  );
51
51
  const { model: smolModel, apiKey: smolApiKey } = await resolveSmolModel(
52
- settingsManager,
52
+ settingsInstance,
53
53
  modelRegistry,
54
54
  primaryModel,
55
55
  primaryApiKey,
@@ -24,6 +24,12 @@ const OpenRouterRoutingSchema = Type.Object({
24
24
  order: Type.Optional(Type.Array(Type.String())),
25
25
  });
26
26
 
27
+ // Schema for Vercel AI Gateway routing preferences
28
+ const VercelGatewayRoutingSchema = Type.Object({
29
+ only: Type.Optional(Type.Array(Type.String())),
30
+ order: Type.Optional(Type.Array(Type.String())),
31
+ });
32
+
27
33
  // Schema for OpenAI compatibility settings
28
34
  const OpenAICompatSchema = Type.Object({
29
35
  supportsStore: Type.Optional(Type.Boolean()),
@@ -31,6 +37,7 @@ const OpenAICompatSchema = Type.Object({
31
37
  supportsReasoningEffort: Type.Optional(Type.Boolean()),
32
38
  maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
33
39
  openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
40
+ vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
34
41
  });
35
42
 
36
43
  // Schema for custom model definition