@code-yeongyu/senpi 0.74.0 → 2026.5.13

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 (112) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +4 -0
  3. package/dist/core/agent-session-services.d.ts.map +1 -1
  4. package/dist/core/agent-session-services.js +3 -1
  5. package/dist/core/agent-session-services.js.map +1 -1
  6. package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
  7. package/dist/core/extensions/builtin/anthropic-web-search/index.js +25 -14
  8. package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
  9. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.d.ts.map +1 -1
  10. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js +56 -7
  11. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js.map +1 -1
  12. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts +7 -3
  13. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  14. package/dist/core/extensions/builtin/prompt-preset/presets.js +12 -4
  15. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  16. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -0
  17. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  18. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -1
  19. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  20. package/dist/core/extensions/builtin/todotools/continuation/runtime.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/todotools/continuation/runtime.js +7 -10
  22. package/dist/core/extensions/builtin/todotools/continuation/runtime.js.map +1 -1
  23. package/dist/core/extensions/builtin/todotools/index.d.ts +2 -2
  24. package/dist/core/extensions/builtin/todotools/index.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/todotools/index.js +2 -2
  26. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  27. package/dist/core/extensions/builtin/todotools/settings.d.ts +6 -0
  28. package/dist/core/extensions/builtin/todotools/settings.d.ts.map +1 -0
  29. package/dist/core/extensions/builtin/todotools/settings.js +58 -0
  30. package/dist/core/extensions/builtin/todotools/settings.js.map +1 -0
  31. package/dist/core/extensions/builtin/todotools/system-messages.d.ts +34 -0
  32. package/dist/core/extensions/builtin/todotools/system-messages.d.ts.map +1 -0
  33. package/dist/core/extensions/builtin/todotools/system-messages.js +82 -0
  34. package/dist/core/extensions/builtin/todotools/system-messages.js.map +1 -0
  35. package/dist/core/extensions/builtin/todotools/tools/todoread.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/todotools/tools/todoread.js +3 -1
  37. package/dist/core/extensions/builtin/todotools/tools/todoread.js.map +1 -1
  38. package/dist/core/extensions/builtin/todotools/tools/todowrite.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/todotools/tools/todowrite.js +3 -1
  40. package/dist/core/extensions/builtin/todotools/tools/todowrite.js.map +1 -1
  41. package/dist/core/keybindings.d.ts +5 -0
  42. package/dist/core/keybindings.d.ts.map +1 -1
  43. package/dist/core/keybindings.js +10 -3
  44. package/dist/core/keybindings.js.map +1 -1
  45. package/dist/core/model-registry.d.ts.map +1 -1
  46. package/dist/core/model-registry.js +8 -3
  47. package/dist/core/model-registry.js.map +1 -1
  48. package/dist/core/resource-loader.d.ts +8 -0
  49. package/dist/core/resource-loader.d.ts.map +1 -1
  50. package/dist/core/resource-loader.js +168 -17
  51. package/dist/core/resource-loader.js.map +1 -1
  52. package/dist/core/tools/bash.d.ts.map +1 -1
  53. package/dist/core/tools/bash.js +11 -4
  54. package/dist/core/tools/bash.js.map +1 -1
  55. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  56. package/dist/modes/interactive/components/bash-execution.js +11 -3
  57. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  58. package/dist/modes/interactive/components/favorite-models-selector.d.ts +10 -4
  59. package/dist/modes/interactive/components/favorite-models-selector.d.ts.map +1 -1
  60. package/dist/modes/interactive/components/favorite-models-selector.js +56 -78
  61. package/dist/modes/interactive/components/favorite-models-selector.js.map +1 -1
  62. package/dist/modes/interactive/components/model-favorites.d.ts +10 -0
  63. package/dist/modes/interactive/components/model-favorites.d.ts.map +1 -0
  64. package/dist/modes/interactive/components/model-favorites.js +53 -0
  65. package/dist/modes/interactive/components/model-favorites.js.map +1 -0
  66. package/dist/modes/interactive/components/model-selector.d.ts +9 -1
  67. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  68. package/dist/modes/interactive/components/model-selector.js +52 -10
  69. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  70. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  71. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  72. package/dist/modes/interactive/interactive-mode.js +83 -94
  73. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  74. package/docs/models.md +26 -1
  75. package/docs/settings.md +14 -0
  76. package/package.json +5 -8
  77. package/dist/core/extensions/builtin/agent-system/agent-types.d.ts +0 -25
  78. package/dist/core/extensions/builtin/agent-system/agent-types.d.ts.map +0 -1
  79. package/dist/core/extensions/builtin/agent-system/agent-types.js +0 -38
  80. package/dist/core/extensions/builtin/agent-system/agent-types.js.map +0 -1
  81. package/dist/core/extensions/builtin/agent-system/builtin-agents.d.ts +0 -3
  82. package/dist/core/extensions/builtin/agent-system/builtin-agents.d.ts.map +0 -1
  83. package/dist/core/extensions/builtin/agent-system/builtin-agents.js +0 -32
  84. package/dist/core/extensions/builtin/agent-system/builtin-agents.js.map +0 -1
  85. package/dist/core/extensions/builtin/agent-system/index.d.ts +0 -3
  86. package/dist/core/extensions/builtin/agent-system/index.d.ts.map +0 -1
  87. package/dist/core/extensions/builtin/agent-system/index.js +0 -42
  88. package/dist/core/extensions/builtin/agent-system/index.js.map +0 -1
  89. package/dist/core/extensions/builtin/agent-system/loader.d.ts +0 -4
  90. package/dist/core/extensions/builtin/agent-system/loader.d.ts.map +0 -1
  91. package/dist/core/extensions/builtin/agent-system/loader.js +0 -59
  92. package/dist/core/extensions/builtin/agent-system/loader.js.map +0 -1
  93. package/dist/core/extensions/builtin/agent-system/permission.d.ts +0 -11
  94. package/dist/core/extensions/builtin/agent-system/permission.d.ts.map +0 -1
  95. package/dist/core/extensions/builtin/agent-system/permission.js +0 -24
  96. package/dist/core/extensions/builtin/agent-system/permission.js.map +0 -1
  97. package/dist/core/extensions/builtin/agent-system/registry.d.ts +0 -10
  98. package/dist/core/extensions/builtin/agent-system/registry.d.ts.map +0 -1
  99. package/dist/core/extensions/builtin/agent-system/registry.js +0 -50
  100. package/dist/core/extensions/builtin/agent-system/registry.js.map +0 -1
  101. package/dist/core/extensions/builtin/agent-system/types.d.ts +0 -9
  102. package/dist/core/extensions/builtin/agent-system/types.d.ts.map +0 -1
  103. package/dist/core/extensions/builtin/agent-system/types.js +0 -2
  104. package/dist/core/extensions/builtin/agent-system/types.js.map +0 -1
  105. package/dist/core/extensions/builtin/agent-system/wildcard.d.ts +0 -4
  106. package/dist/core/extensions/builtin/agent-system/wildcard.d.ts.map +0 -1
  107. package/dist/core/extensions/builtin/agent-system/wildcard.js +0 -58
  108. package/dist/core/extensions/builtin/agent-system/wildcard.js.map +0 -1
  109. package/dist/core/extensions/builtin/anthropic-web-fetch/index.d.ts +0 -7
  110. package/dist/core/extensions/builtin/anthropic-web-fetch/index.d.ts.map +0 -1
  111. package/dist/core/extensions/builtin/anthropic-web-fetch/index.js +0 -112
  112. package/dist/core/extensions/builtin/anthropic-web-fetch/index.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [2026.05.13] - 2026-05-13
4
4
 
5
5
  ### Added
6
6
 
package/README.md CHANGED
@@ -70,6 +70,8 @@ I regularly publish my own `pi-mono` work sessions here:
70
70
  npm install -g @code-yeongyu/senpi
71
71
  ```
72
72
 
73
+ `@code-yeongyu/senpi` is the npm package name. The installed executable is still `senpi`.
74
+
73
75
  Authenticate with an API key:
74
76
 
75
77
  ```bash
@@ -442,6 +444,8 @@ const { session } = await createAgentSession({
442
444
  await session.prompt("What files are in the current directory?");
443
445
  ```
444
446
 
447
+ The package name is scoped, but runtime branding, config paths, and the CLI command stay `senpi`.
448
+
445
449
  For advanced multi-session runtime replacement, use `createAgentSessionRuntime()` and `AgentSessionRuntime`.
446
450
 
447
451
  See [docs/sdk.md](docs/sdk.md) and [examples/sdk/](examples/sdk/).
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-services.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport type { ServiceTier } from \"./extensions/builtin/service-tier.js\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.js\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\tfavoriteModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = options.cwd;\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\tfavoriteModels: options.favoriteModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agent-session-services.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport type { ServiceTier } from \"./extensions/builtin/service-tier.js\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.js\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\tfavoriteModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tif (!registeredFlags.has(name)) {\n\t\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = options.cwd;\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\tfavoriteModels: options.favoriteModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
@@ -14,7 +14,9 @@ function applyExtensionFlagValues(resourceLoader, extensionFlagValues) {
14
14
  const registeredFlags = new Map();
15
15
  for (const extension of extensionsResult.extensions) {
16
16
  for (const [name, flag] of extension.flags) {
17
- registeredFlags.set(name, { type: flag.type });
17
+ if (!registeredFlags.has(name)) {
18
+ registeredFlags.set(name, { type: flag.type });
19
+ }
18
20
  }
19
21
  }
20
22
  const unknownFlags = [];
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-services.js","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport type { ServiceTier } from \"./extensions/builtin/service-tier.js\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.js\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\tfavoriteModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = options.cwd;\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\tfavoriteModels: options.favoriteModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agent-session-services.js","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAA0D,MAAM,sBAAsB,CAAC;AACrH,OAAO,EAAiE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE7G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAkExD,SAAS,wBAAwB,CAChC,cAA8B,EAC9B,mBAA8D,EAC5B;IAClC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,WAAW,GAAoC,EAAE,CAAC;IACxD,MAAM,gBAAgB,GAAG,cAAc,CAAC,aAAa,EAAE,CAAC;IACxD,MAAM,eAAe,GAAG,IAAI,GAAG,EAA0C,CAAC;IAC1E,KAAK,MAAM,SAAS,IAAI,gBAAgB,CAAC,UAAU,EAAE,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YAC5C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAChD,CAAC;QACF,CAAC;IACF,CAAC;IAED,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,mBAAmB,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,SAAS;QACV,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACpD,SAAS;QACV,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACrD,SAAS;QACV,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YAChB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,qBAAqB,IAAI,oBAAoB;SACtD,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC;YAChB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,iBAAiB,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SACvH,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,WAAW,CAAC;AAAA,CACnB;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC/C,OAA0C,EACV;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3F,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzF,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IAChH,MAAM,cAAc,GAAG,IAAI,qBAAqB,CAAC;QAChD,GAAG,CAAC,OAAO,CAAC,qBAAqB,IAAI,EAAE,CAAC;QACxC,GAAG;QACH,QAAQ;QACR,eAAe;KACf,CAAC,CAAC;IACH,MAAM,cAAc,CAAC,MAAM,EAAE,CAAC;IAE9B,MAAM,WAAW,GAAoC,EAAE,CAAC;IACxD,MAAM,gBAAgB,GAAG,cAAc,CAAC,aAAa,EAAE,CAAC;IACxD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC,4BAA4B,EAAE,CAAC;QACrG,IAAI,CAAC;YACJ,aAAa,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,WAAW,CAAC,IAAI,CAAC;gBAChB,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,cAAc,aAAa,YAAY,OAAO,EAAE;aACzD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IACD,gBAAgB,CAAC,OAAO,CAAC,4BAA4B,GAAG,EAAE,CAAC;IAC3D,WAAW,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,cAAc,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAE3F,OAAO;QACN,GAAG;QACH,QAAQ;QACR,WAAW;QACX,eAAe;QACf,aAAa;QACb,cAAc;QACd,WAAW;KACX,CAAC;AAAA,CACF;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CACnD,OAA8C,EACV;IACpC,OAAO,kBAAkB,CAAC;QACzB,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG;QACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;QACnC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW;QACzC,eAAe,EAAE,OAAO,CAAC,QAAQ,CAAC,eAAe;QACjD,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,aAAa;QAC7C,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,cAAc;QAC/C,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;KAC5C,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport type { ServiceTier } from \"./extensions/builtin/service-tier.js\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.js\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.js\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\tfavoriteModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel; serviceTier?: ServiceTier }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tif (!registeredFlags.has(name)) {\n\t\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = options.cwd;\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\tfavoriteModels: options.favoriteModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-web-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAkEnD,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CA4B9F;AAED,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,4BAA4B,iNAMxC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAkB1E","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst DEFAULT_MAX_USES = 5;\nconst ENABLE_ENV = \"PI_ANTHROPIC_WEB_SEARCH\";\nconst MAX_USES_ENV = \"PI_ANTHROPIC_WEB_SEARCH_MAX_USES\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isWebSearchType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"web_search_\");\n}\n\nfunction getMaxUses(): number {\n\tconst envValue = process.env[MAX_USES_ENV];\n\tif (!envValue) {\n\t\treturn DEFAULT_MAX_USES;\n\t}\n\n\tconst parsed = Number.parseInt(envValue, 10);\n\tif (Number.isNaN(parsed) || parsed <= 0) {\n\t\treturn DEFAULT_MAX_USES;\n\t}\n\n\treturn parsed;\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitized: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = tool.name;\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant = name === \"web_search\" && !isWebSearchType(type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nexport function addAnthropicWebSearchToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isAnthropicWebSearchEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isWebSearchType(tool.type));\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push({\n\t\t\ttype: \"web_search_20250305\",\n\t\t\tname: \"web_search\",\n\t\t\tmax_uses: getMaxUses(),\n\t\t});\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport function isAnthropicWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nexport const ANTHROPIC_WEB_SEARCH_SECTION = `\n## Web Search\n\nThe native web_search tool is available in this session.\nUse web_search when the user asks for current or online information.\nPrefer web_search over guessing when freshness matters.\n`;\n\nexport default function anthropicWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicWebSearchToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isAnthropicWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-web-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAoFnD,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAwB9F;AAED,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,4BAA4B,iNAMxC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAkB1E","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst WEB_SEARCH_MAX_USES = 8;\nconst ENABLE_ENV = \"PI_ANTHROPIC_WEB_SEARCH\";\nconst ALLOWED_DOMAINS_ENV = \"PI_ANTHROPIC_WEB_SEARCH_ALLOWED_DOMAINS\";\nconst BLOCKED_DOMAINS_ENV = \"PI_ANTHROPIC_WEB_SEARCH_BLOCKED_DOMAINS\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isWebSearchType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"web_search_\");\n}\n\nfunction parseDomainListEnv(envVar: string): string[] | undefined {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn undefined;\n\t}\n\n\tconst domains = envValue\n\t\t.split(\",\")\n\t\t.map((domain) => domain.trim())\n\t\t.filter((domain) => domain.length > 0);\n\n\tif (domains.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn domains;\n}\n\nfunction makeWebSearchTool(): ToolDefinition {\n\tconst allowedDomains = parseDomainListEnv(ALLOWED_DOMAINS_ENV);\n\tconst blockedDomains = parseDomainListEnv(BLOCKED_DOMAINS_ENV);\n\n\treturn {\n\t\ttype: \"web_search_20250305\",\n\t\tname: \"web_search\",\n\t\t...(allowedDomains ? { allowed_domains: allowedDomains } : {}),\n\t\t...(blockedDomains ? { blocked_domains: blockedDomains } : {}),\n\t\tmax_uses: WEB_SEARCH_MAX_USES,\n\t};\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitized: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = tool.name;\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant = name === \"web_search\" && !isWebSearchType(type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nexport function addAnthropicWebSearchToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isAnthropicWebSearchEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isWebSearchType(tool.type));\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push(makeWebSearchTool());\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport function isAnthropicWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nexport const ANTHROPIC_WEB_SEARCH_SECTION = `\n## Web Search\n\nThe native web_search tool is available in this session.\nUse web_search when the user asks for current or online information.\nPrefer web_search over guessing when freshness matters.\n`;\n\nexport default function anthropicWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicWebSearchToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isAnthropicWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
@@ -1,6 +1,7 @@
1
- const DEFAULT_MAX_USES = 5;
1
+ const WEB_SEARCH_MAX_USES = 8;
2
2
  const ENABLE_ENV = "PI_ANTHROPIC_WEB_SEARCH";
3
- const MAX_USES_ENV = "PI_ANTHROPIC_WEB_SEARCH_MAX_USES";
3
+ const ALLOWED_DOMAINS_ENV = "PI_ANTHROPIC_WEB_SEARCH_ALLOWED_DOMAINS";
4
+ const BLOCKED_DOMAINS_ENV = "PI_ANTHROPIC_WEB_SEARCH_BLOCKED_DOMAINS";
4
5
  function parseEnableEnv(envVar) {
5
6
  const envValue = process.env[envVar];
6
7
  if (!envValue) {
@@ -22,16 +23,30 @@ function isRecord(value) {
22
23
  function isWebSearchType(value) {
23
24
  return typeof value === "string" && value.startsWith("web_search_");
24
25
  }
25
- function getMaxUses() {
26
- const envValue = process.env[MAX_USES_ENV];
26
+ function parseDomainListEnv(envVar) {
27
+ const envValue = process.env[envVar];
27
28
  if (!envValue) {
28
- return DEFAULT_MAX_USES;
29
+ return undefined;
29
30
  }
30
- const parsed = Number.parseInt(envValue, 10);
31
- if (Number.isNaN(parsed) || parsed <= 0) {
32
- return DEFAULT_MAX_USES;
31
+ const domains = envValue
32
+ .split(",")
33
+ .map((domain) => domain.trim())
34
+ .filter((domain) => domain.length > 0);
35
+ if (domains.length === 0) {
36
+ return undefined;
33
37
  }
34
- return parsed;
38
+ return domains;
39
+ }
40
+ function makeWebSearchTool() {
41
+ const allowedDomains = parseDomainListEnv(ALLOWED_DOMAINS_ENV);
42
+ const blockedDomains = parseDomainListEnv(BLOCKED_DOMAINS_ENV);
43
+ return {
44
+ type: "web_search_20250305",
45
+ name: "web_search",
46
+ ...(allowedDomains ? { allowed_domains: allowedDomains } : {}),
47
+ ...(blockedDomains ? { blocked_domains: blockedDomains } : {}),
48
+ max_uses: WEB_SEARCH_MAX_USES,
49
+ };
35
50
  }
36
51
  function sanitizeTools(tools) {
37
52
  const sanitized = [];
@@ -62,11 +77,7 @@ export function addAnthropicWebSearchToPayload(api, payload) {
62
77
  const sanitizedTools = sanitizeTools(tools);
63
78
  const hasNativeWebSearch = sanitizedTools.some((tool) => isWebSearchType(tool.type));
64
79
  if (!hasNativeWebSearch) {
65
- sanitizedTools.push({
66
- type: "web_search_20250305",
67
- name: "web_search",
68
- max_uses: getMaxUses(),
69
- });
80
+ sanitizedTools.push(makeWebSearchTool());
70
81
  }
71
82
  return {
72
83
  ...payload,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-web-search/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst DEFAULT_MAX_USES = 5;\nconst ENABLE_ENV = \"PI_ANTHROPIC_WEB_SEARCH\";\nconst MAX_USES_ENV = \"PI_ANTHROPIC_WEB_SEARCH_MAX_USES\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isWebSearchType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"web_search_\");\n}\n\nfunction getMaxUses(): number {\n\tconst envValue = process.env[MAX_USES_ENV];\n\tif (!envValue) {\n\t\treturn DEFAULT_MAX_USES;\n\t}\n\n\tconst parsed = Number.parseInt(envValue, 10);\n\tif (Number.isNaN(parsed) || parsed <= 0) {\n\t\treturn DEFAULT_MAX_USES;\n\t}\n\n\treturn parsed;\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitized: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = tool.name;\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant = name === \"web_search\" && !isWebSearchType(type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nexport function addAnthropicWebSearchToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isAnthropicWebSearchEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isWebSearchType(tool.type));\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push({\n\t\t\ttype: \"web_search_20250305\",\n\t\t\tname: \"web_search\",\n\t\t\tmax_uses: getMaxUses(),\n\t\t});\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport function isAnthropicWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nexport const ANTHROPIC_WEB_SEARCH_SECTION = `\n## Web Search\n\nThe native web_search tool is available in this session.\nUse web_search when the user asks for current or online information.\nPrefer web_search over guessing when freshness matters.\n`;\n\nexport default function anthropicWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicWebSearchToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isAnthropicWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-web-search/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst WEB_SEARCH_MAX_USES = 8;\nconst ENABLE_ENV = \"PI_ANTHROPIC_WEB_SEARCH\";\nconst ALLOWED_DOMAINS_ENV = \"PI_ANTHROPIC_WEB_SEARCH_ALLOWED_DOMAINS\";\nconst BLOCKED_DOMAINS_ENV = \"PI_ANTHROPIC_WEB_SEARCH_BLOCKED_DOMAINS\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isWebSearchType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"web_search_\");\n}\n\nfunction parseDomainListEnv(envVar: string): string[] | undefined {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn undefined;\n\t}\n\n\tconst domains = envValue\n\t\t.split(\",\")\n\t\t.map((domain) => domain.trim())\n\t\t.filter((domain) => domain.length > 0);\n\n\tif (domains.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn domains;\n}\n\nfunction makeWebSearchTool(): ToolDefinition {\n\tconst allowedDomains = parseDomainListEnv(ALLOWED_DOMAINS_ENV);\n\tconst blockedDomains = parseDomainListEnv(BLOCKED_DOMAINS_ENV);\n\n\treturn {\n\t\ttype: \"web_search_20250305\",\n\t\tname: \"web_search\",\n\t\t...(allowedDomains ? { allowed_domains: allowedDomains } : {}),\n\t\t...(blockedDomains ? { blocked_domains: blockedDomains } : {}),\n\t\tmax_uses: WEB_SEARCH_MAX_USES,\n\t};\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitized: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = tool.name;\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant = name === \"web_search\" && !isWebSearchType(type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nexport function addAnthropicWebSearchToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isAnthropicWebSearchEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isWebSearchType(tool.type));\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push(makeWebSearchTool());\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport function isAnthropicWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nexport const ANTHROPIC_WEB_SEARCH_SECTION = `\n## Web Search\n\nThe native web_search tool is available in this session.\nUse web_search when the user asks for current or online information.\nPrefer web_search over guessing when freshness matters.\n`;\n\nexport default function anthropicWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicWebSearchToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isAnthropicWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"preview-format.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/gpt-apply-patch/preview-format.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEX,iBAAiB,EAEjB,qBAAqB,EACrB,eAAe,EACf,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAkB5C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAWjE;AAcD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,GAAE,MAAsB,EAC3B,QAAQ,GAAE,OAAc,GACtB,MAAM,CA8BR;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhE;AA4JD,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,qBAAqB,CA6BlH;AAED,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,OAAO,GACf,MAAM,CA6CR;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CAO5E","sourcesContent":["import path from \"node:path\";\nimport * as Diff from \"diff\";\nimport { getLanguageFromPath, highlightCode } from \"../../../../modes/interactive/theme/theme.js\";\nimport { parsePatch } from \"./parser.js\";\nimport { extractPatchedPaths } from \"./text.js\";\nimport type {\n\tApplyPatchOperation,\n\tApplyPatchPreview,\n\tApplyPatchPreviewFile,\n\tApplyPatchRenderState,\n\tApplyPatchTheme,\n} from \"./types.js\";\n\nexport const PATCH_PREVIEW_MAX_LINES = 16;\nexport const PATCH_PREVIEW_MAX_CHARS = 4000;\nconst PATCH_PREVIEW_HEAD_LINES = 8;\nconst PATCH_PREVIEW_TAIL_LINES = 8;\nconst applyPatchRenderStates = new Map<string, ApplyPatchRenderState>();\n\nfunction formatLineCountSummary(added: number, removed: number): string {\n\treturn `(+${added} -${removed})`;\n}\n\nfunction countLines(text: string): number {\n\tif (text.length === 0) return 0;\n\tlet lines = 1;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text.charCodeAt(index) === 10) lines += 1;\n\t}\n\treturn lines;\n}\n\nexport function truncatePreview(text: string): string {\n\tif (text.length <= PATCH_PREVIEW_MAX_CHARS && countLines(text) <= PATCH_PREVIEW_MAX_LINES) return text;\n\tconst lines = text.split(\"\\n\");\n\tconst head = lines.slice(0, PATCH_PREVIEW_HEAD_LINES);\n\tconst tail = lines.slice(-PATCH_PREVIEW_TAIL_LINES);\n\tlet preview = [...head, \"…\", ...tail].join(\"\\n\");\n\tif (preview.length > PATCH_PREVIEW_MAX_CHARS) preview = `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS).trimEnd()}\\n…`;\n\treturn preview;\n}\n\nexport function displayPath(filePath: string, cwd: string): string {\n\tif (!path.isAbsolute(filePath)) return filePath;\n\tconst absoluteCwd = path.resolve(cwd);\n\tconst relativePath = path.relative(absoluteCwd, filePath);\n\tif (\n\t\trelativePath === \"\" ||\n\t\t(!relativePath.startsWith(`..${path.sep}`) && relativePath !== \"..\" && !path.isAbsolute(relativePath))\n\t) {\n\t\treturn relativePath || \".\";\n\t}\n\treturn filePath;\n}\n\nfunction formatPatchFilePath(file: ApplyPatchPreviewFile, cwd: string = process.cwd()): string {\n\tconst filePath = displayPath(file.filePath, cwd);\n\tif (!file.movePath) return filePath;\n\treturn `${filePath} → ${displayPath(file.movePath, cwd)}`;\n}\n\nfunction formatPatchOperation(operation: ApplyPatchOperation): string {\n\tif (operation === \"add\") return \"Added\";\n\tif (operation === \"delete\") return \"Deleted\";\n\treturn \"Edited\";\n}\n\nexport function formatPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string = process.cwd(),\n\texpanded: boolean = true,\n): string {\n\tconst lines: string[] = [];\n\tif (preview.files.length === 1) {\n\t\tconst file = preview.files[0];\n\t\tif (file) {\n\t\t\tlines.push(\n\t\t\t\t`• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`,\n\t\t\t);\n\t\t\tif (expanded && file.diff)\n\t\t\t\tlines.push(\n\t\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t\t);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\tlines.push(`• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}`);\n\tfor (const file of preview.files) {\n\t\tlines.push(` └ ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`);\n\t\tif (expanded && file.diff)\n\t\t\tlines.push(\n\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatInFlightCallText(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Patching\";\n\tconst noun = paths.length === 1 ? \"file\" : \"files\";\n\tconst count = paths.length > 1 ? ` (${paths.length} ${noun})` : \"\";\n\treturn `Patching${count}: ${paths.join(\", \")}`;\n}\n\ntype RenderableAddedDiffLine = { content: string; kind: \"added\"; lineNumber: string; sign: \"+\" };\ntype RenderableRemovedDiffLine = { content: string; kind: \"removed\"; lineNumber: string; sign: \"-\" };\ntype RenderableContextDiffLine = { content: string; kind: \"context\"; lineNumber: string; sign: \" \" };\ntype RenderableContentDiffLine = RenderableAddedDiffLine | RenderableContextDiffLine | RenderableRemovedDiffLine;\ntype RenderableDiffLine = RenderableContentDiffLine | { kind: \"meta\"; text: string };\n\nfunction parseRenderableDiffLine(line: string): RenderableDiffLine {\n\tconst match = line.match(/^([+\\- ])(\\s*\\d+)\\s(.*)$/);\n\tif (!match) return { kind: \"meta\", text: line };\n\n\tconst sign = match[1];\n\tconst lineNumber = match[2];\n\tif ((sign !== \"+\" && sign !== \"-\" && sign !== \" \") || lineNumber === undefined) return { kind: \"meta\", text: line };\n\n\tconst content = match[3] ?? \"\";\n\tif (sign === \"+\") return { content, kind: \"added\", lineNumber, sign };\n\tif (sign === \"-\") return { content, kind: \"removed\", lineNumber, sign };\n\treturn { content, kind: \"context\", lineNumber, sign };\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction highlightDiffContent(content: string, filePath: string): string {\n\tconst plainContent = replaceTabs(content);\n\tconst language = getLanguageFromPath(filePath);\n\ttry {\n\t\treturn highlightCode(plainContent, language)[0] ?? plainContent;\n\t} catch {\n\t\treturn plainContent;\n\t}\n}\n\nfunction renderInlineDiff(\n\toldContent: string,\n\tnewContent: string,\n\ttheme: ApplyPatchTheme,\n): { added: string; removed: string } {\n\tconst parts = Diff.diffWords(replaceTabs(oldContent), replaceTabs(newContent));\n\tlet added = \"\";\n\tlet removed = \"\";\n\tlet firstAdded = true;\n\tlet firstRemoved = true;\n\n\tfor (const part of parts) {\n\t\tif (part.added) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstAdded) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tadded += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstAdded = false;\n\t\t\t}\n\t\t\tif (value) added += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (part.removed) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstRemoved) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tremoved += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstRemoved = false;\n\t\t\t}\n\t\t\tif (value) removed += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tadded += part.value;\n\t\tremoved += part.value;\n\t}\n\n\treturn { added, removed };\n}\n\nfunction renderOpenCodeLikeDiffLine(\n\tline: RenderableContentDiffLine,\n\tfilePath: string,\n\ttheme: ApplyPatchTheme,\n\tcontentOverride?: string,\n): string {\n\tconst lineNumber = theme.fg(\"muted\", line.lineNumber);\n\tif (line.kind === \"context\") {\n\t\treturn `${theme.fg(\"toolDiffContext\", line.sign)}${lineNumber} ${highlightDiffContent(line.content, filePath)}`;\n\t}\n\n\tconst diffColor = line.kind === \"added\" ? \"toolDiffAdded\" : \"toolDiffRemoved\";\n\tconst background = line.kind === \"added\" ? \"toolSuccessBg\" : \"toolErrorBg\";\n\tconst content =\n\t\tcontentOverride === undefined\n\t\t\t? highlightDiffContent(line.content, filePath)\n\t\t\t: theme.fg(diffColor, replaceTabs(contentOverride));\n\tconst rendered = `${theme.fg(diffColor, line.sign)}${lineNumber} ${content}`;\n\treturn theme.bg(background, rendered);\n}\n\nfunction renderOpenCodeLikeDiff(diffText: string, filePath: string, theme: ApplyPatchTheme): string {\n\tconst parsedLines = diffText.split(\"\\n\").map(parseRenderableDiffLine);\n\tconst rendered: string[] = [];\n\tlet index = 0;\n\n\twhile (index < parsedLines.length) {\n\t\tconst line = parsedLines[index];\n\t\tif (!line) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.kind !== \"removed\") {\n\t\t\trendered.push(\n\t\t\t\tline.kind === \"meta\"\n\t\t\t\t\t? theme.fg(\"toolDiffContext\", line.text)\n\t\t\t\t\t: renderOpenCodeLikeDiffLine(line, filePath, theme),\n\t\t\t);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst removedLines: RenderableRemovedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"removed\") {\n\t\t\tconst removedLine = parsedLines[index];\n\t\t\tif (removedLine?.kind === \"removed\") removedLines.push(removedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst addedLines: RenderableAddedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"added\") {\n\t\t\tconst addedLine = parsedLines[index];\n\t\t\tif (addedLine?.kind === \"added\") addedLines.push(addedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst pairedCount = Math.min(removedLines.length, addedLines.length);\n\t\tfor (let pairIndex = 0; pairIndex < pairedCount; pairIndex++) {\n\t\t\tconst removedLine = removedLines[pairIndex];\n\t\t\tconst addedLine = addedLines[pairIndex];\n\t\t\tif (!removedLine || !addedLine) continue;\n\n\t\t\tconst inline = renderInlineDiff(removedLine.content, addedLine.content, theme);\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme, inline.removed));\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme, inline.added));\n\t\t}\n\n\t\tfor (const removedLine of removedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme));\n\t\tfor (const addedLine of addedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme));\n\t}\n\n\treturn rendered.join(\"\\n\");\n}\n\nexport function getApplyPatchRenderState(toolCallId: string, cwd: string, patchText: string): ApplyPatchRenderState {\n\tconst existing = applyPatchRenderStates.get(toolCallId);\n\tif (existing && existing.cwd === cwd && existing.patchText === patchText) return existing;\n\n\tconst callText = formatInFlightCallText(patchText);\n\tlet collapsed = \"\";\n\tlet expanded = \"\";\n\ttry {\n\t\tconst hunks = parsePatch(patchText);\n\t\tif (hunks.length > 0) {\n\t\t\tconst files = hunks.map((hunk) => ({\n\t\t\t\tfilePath: hunk.filePath,\n\t\t\t\tmovePath: hunk.type === \"update\" ? hunk.movePath : undefined,\n\t\t\t\toperation: hunk.type,\n\t\t\t\tdiff: \"\",\n\t\t\t\tadded: 0,\n\t\t\t\tremoved: 0,\n\t\t\t})) satisfies ApplyPatchPreviewFile[];\n\t\t\tconst preview: ApplyPatchPreview = { files, added: 0, removed: 0 };\n\t\t\tcollapsed = formatPatchPreview(preview, cwd, false);\n\t\t\texpanded = formatPatchPreview(preview, cwd, true);\n\t\t}\n\t} catch {\n\t\t// ignore incomplete patch text\n\t}\n\n\tconst nextState: ApplyPatchRenderState = { ...existing, cwd, patchText, callText, collapsed, expanded };\n\tapplyPatchRenderStates.set(toolCallId, nextState);\n\treturn nextState;\n}\n\nexport function clearApplyPatchRenderState(): void {\n\tapplyPatchRenderStates.clear();\n}\n\nexport function renderPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string,\n\ttheme: ApplyPatchTheme,\n\texpanded: boolean,\n): string {\n\tif (expanded) {\n\t\ttry {\n\t\t\tconst renderFile = (file: ApplyPatchPreviewFile, headerPrefix: string): string => {\n\t\t\t\tconst header = `• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\tif (!file.diff) {\n\t\t\t\t\treturn headerPrefix.length > 0\n\t\t\t\t\t\t? `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`\n\t\t\t\t\t\t: header;\n\t\t\t\t}\n\n\t\t\t\tconst renderedDiff = renderOpenCodeLikeDiff(\n\t\t\t\t\ttruncatePreview(file.diff),\n\t\t\t\t\tfile.movePath ?? file.filePath,\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\tif (headerPrefix.length > 0) {\n\t\t\t\t\tconst nestedHeader = `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\t\treturn `${nestedHeader}\\n${renderedDiff\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`)\n\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\t\t}\n\t\t\t\treturn `${header}\\n${renderedDiff}`;\n\t\t\t};\n\n\t\t\tif (preview.files.length === 1) {\n\t\t\t\tconst file = preview.files[0];\n\t\t\t\treturn file ? renderFile(file, \"\") : \"\";\n\t\t\t}\n\n\t\t\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\t\t\tconst renderedFiles = preview.files.map((file) => renderFile(file, \" └ \")).join(\"\\n\");\n\t\t\tif (renderedFiles.length > 0) {\n\t\t\t\treturn `• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}\\n${renderedFiles}`;\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall back to manual themed line rendering\n\t\t}\n\t}\n\n\treturn formatPatchPreview(preview, cwd, expanded)\n\t\t.split(\"\\n\")\n\t\t.map((line) => renderPatchLine(line, theme))\n\t\t.join(\"\\n\");\n}\n\nexport function formatPendingPatchPaths(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Applying patch...\";\n\treturn `Applying patch...\\n${paths.map((filePath) => `• ${filePath}`).join(\"\\n\")}`;\n}\n\nexport function renderPatchLine(line: string, theme: ApplyPatchTheme): string {\n\tconst trimmed = line.trimStart();\n\tif (trimmed.startsWith(\"+\")) return theme.fg(\"toolDiffAdded\", line);\n\tif (trimmed.startsWith(\"-\")) return theme.fg(\"toolDiffRemoved\", line);\n\tif (trimmed.startsWith(\"•\")) return theme.fg(\"toolTitle\", theme.bold(line));\n\tif (trimmed.startsWith(\"└\")) return theme.fg(\"accent\", line);\n\treturn theme.fg(\"toolDiffContext\", line);\n}\n"]}
1
+ {"version":3,"file":"preview-format.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/gpt-apply-patch/preview-format.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEX,iBAAiB,EAEjB,qBAAqB,EACrB,eAAe,EACf,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAuE5C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAWjE;AAcD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,GAAE,MAAsB,EAC3B,QAAQ,GAAE,OAAc,GACtB,MAAM,CA8BR;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhE;AA4JD,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,qBAAqB,CA6BlH;AAED,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,OAAO,GACf,MAAM,CA6CR;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CAO5E","sourcesContent":["import path from \"node:path\";\nimport * as Diff from \"diff\";\nimport { getLanguageFromPath, highlightCode } from \"../../../../modes/interactive/theme/theme.js\";\nimport { parsePatch } from \"./parser.js\";\nimport { extractPatchedPaths } from \"./text.js\";\nimport type {\n\tApplyPatchOperation,\n\tApplyPatchPreview,\n\tApplyPatchPreviewFile,\n\tApplyPatchRenderState,\n\tApplyPatchTheme,\n} from \"./types.js\";\n\nexport const PATCH_PREVIEW_MAX_LINES = 16;\nexport const PATCH_PREVIEW_MAX_CHARS = 4000;\nconst PATCH_PREVIEW_HEAD_LINES = 8;\nconst PATCH_PREVIEW_TAIL_LINES = PATCH_PREVIEW_MAX_LINES - PATCH_PREVIEW_HEAD_LINES - 1;\nconst PATCH_PREVIEW_TRUNCATION_MARKER = \"…\";\nconst applyPatchRenderStates = new Map<string, ApplyPatchRenderState>();\n\nfunction isChangedPreviewLine(line: string): boolean {\n\treturn /^[+-]\\s*\\d+\\s/.test(line);\n}\n\nfunction countWindowLines(lines: string[], start: number, end: number): number {\n\treturn end - start + (start > 0 ? 1 : 0) + (end < lines.length ? 1 : 0);\n}\n\nfunction formatPreviewWindow(lines: string[], start: number, end: number): string {\n\tconst previewLines = lines.slice(start, end);\n\tif (start > 0) previewLines.unshift(\"…\");\n\tif (end < lines.length) previewLines.push(\"…\");\n\treturn previewLines.join(\"\\n\");\n}\n\nfunction createChangedHunkPreview(lines: string[]): string | undefined {\n\tconst firstChangedLine = lines.findIndex(isChangedPreviewLine);\n\tif (firstChangedLine === -1) return undefined;\n\n\tlet start = firstChangedLine;\n\tlet end = firstChangedLine + 1;\n\twhile (end < lines.length) {\n\t\tconst line = lines[end];\n\t\tif (line === undefined || !isChangedPreviewLine(line)) break;\n\t\tend++;\n\t}\n\n\tconst changedHunkEnd = end;\n\twhile (end > start && countWindowLines(lines, start, end) > PATCH_PREVIEW_MAX_LINES) end--;\n\n\twhile (countWindowLines(lines, start, end) < PATCH_PREVIEW_MAX_LINES) {\n\t\tconst canAddBefore = start > 0;\n\t\tconst canAddAfter = end < lines.length;\n\t\tif (!canAddBefore && !canAddAfter) break;\n\n\t\tconst beforeContextLines = firstChangedLine - start;\n\t\tconst afterContextLines = end - changedHunkEnd;\n\t\tif (canAddBefore && (!canAddAfter || beforeContextLines <= afterContextLines)) {\n\t\t\tstart--;\n\t\t} else {\n\t\t\tend++;\n\t\t}\n\t}\n\n\treturn formatPreviewWindow(lines, start, end);\n}\n\nfunction formatLineCountSummary(added: number, removed: number): string {\n\treturn `(+${added} -${removed})`;\n}\n\nfunction countLines(text: string): number {\n\tif (text.length === 0) return 0;\n\tlet lines = 1;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text.charCodeAt(index) === 10) lines += 1;\n\t}\n\treturn lines;\n}\n\nfunction enforcePreviewCharLimit(preview: string): string {\n\tif (preview.length <= PATCH_PREVIEW_MAX_CHARS) return preview;\n\treturn `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS - PATCH_PREVIEW_TRUNCATION_MARKER.length).trimEnd()}${PATCH_PREVIEW_TRUNCATION_MARKER}`;\n}\n\nexport function truncatePreview(text: string): string {\n\tif (text.length <= PATCH_PREVIEW_MAX_CHARS && countLines(text) <= PATCH_PREVIEW_MAX_LINES) return text;\n\tconst lines = text.split(\"\\n\");\n\tconst changedHunkPreview = createChangedHunkPreview(lines);\n\tconst preview =\n\t\tchangedHunkPreview ??\n\t\t[...lines.slice(0, PATCH_PREVIEW_HEAD_LINES), \"…\", ...lines.slice(-PATCH_PREVIEW_TAIL_LINES)].join(\"\\n\");\n\treturn enforcePreviewCharLimit(preview);\n}\n\nexport function displayPath(filePath: string, cwd: string): string {\n\tif (!path.isAbsolute(filePath)) return filePath;\n\tconst absoluteCwd = path.resolve(cwd);\n\tconst relativePath = path.relative(absoluteCwd, filePath);\n\tif (\n\t\trelativePath === \"\" ||\n\t\t(!relativePath.startsWith(`..${path.sep}`) && relativePath !== \"..\" && !path.isAbsolute(relativePath))\n\t) {\n\t\treturn relativePath || \".\";\n\t}\n\treturn filePath;\n}\n\nfunction formatPatchFilePath(file: ApplyPatchPreviewFile, cwd: string = process.cwd()): string {\n\tconst filePath = displayPath(file.filePath, cwd);\n\tif (!file.movePath) return filePath;\n\treturn `${filePath} → ${displayPath(file.movePath, cwd)}`;\n}\n\nfunction formatPatchOperation(operation: ApplyPatchOperation): string {\n\tif (operation === \"add\") return \"Added\";\n\tif (operation === \"delete\") return \"Deleted\";\n\treturn \"Edited\";\n}\n\nexport function formatPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string = process.cwd(),\n\texpanded: boolean = true,\n): string {\n\tconst lines: string[] = [];\n\tif (preview.files.length === 1) {\n\t\tconst file = preview.files[0];\n\t\tif (file) {\n\t\t\tlines.push(\n\t\t\t\t`• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`,\n\t\t\t);\n\t\t\tif (expanded && file.diff)\n\t\t\t\tlines.push(\n\t\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t\t);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\tlines.push(`• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}`);\n\tfor (const file of preview.files) {\n\t\tlines.push(` └ ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`);\n\t\tif (expanded && file.diff)\n\t\t\tlines.push(\n\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatInFlightCallText(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Patching\";\n\tconst noun = paths.length === 1 ? \"file\" : \"files\";\n\tconst count = paths.length > 1 ? ` (${paths.length} ${noun})` : \"\";\n\treturn `Patching${count}: ${paths.join(\", \")}`;\n}\n\ntype RenderableAddedDiffLine = { content: string; kind: \"added\"; lineNumber: string; sign: \"+\" };\ntype RenderableRemovedDiffLine = { content: string; kind: \"removed\"; lineNumber: string; sign: \"-\" };\ntype RenderableContextDiffLine = { content: string; kind: \"context\"; lineNumber: string; sign: \" \" };\ntype RenderableContentDiffLine = RenderableAddedDiffLine | RenderableContextDiffLine | RenderableRemovedDiffLine;\ntype RenderableDiffLine = RenderableContentDiffLine | { kind: \"meta\"; text: string };\n\nfunction parseRenderableDiffLine(line: string): RenderableDiffLine {\n\tconst match = line.match(/^([+\\- ])(\\s*\\d+)\\s(.*)$/);\n\tif (!match) return { kind: \"meta\", text: line };\n\n\tconst sign = match[1];\n\tconst lineNumber = match[2];\n\tif ((sign !== \"+\" && sign !== \"-\" && sign !== \" \") || lineNumber === undefined) return { kind: \"meta\", text: line };\n\n\tconst content = match[3] ?? \"\";\n\tif (sign === \"+\") return { content, kind: \"added\", lineNumber, sign };\n\tif (sign === \"-\") return { content, kind: \"removed\", lineNumber, sign };\n\treturn { content, kind: \"context\", lineNumber, sign };\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction highlightDiffContent(content: string, filePath: string): string {\n\tconst plainContent = replaceTabs(content);\n\tconst language = getLanguageFromPath(filePath);\n\ttry {\n\t\treturn highlightCode(plainContent, language)[0] ?? plainContent;\n\t} catch {\n\t\treturn plainContent;\n\t}\n}\n\nfunction renderInlineDiff(\n\toldContent: string,\n\tnewContent: string,\n\ttheme: ApplyPatchTheme,\n): { added: string; removed: string } {\n\tconst parts = Diff.diffWords(replaceTabs(oldContent), replaceTabs(newContent));\n\tlet added = \"\";\n\tlet removed = \"\";\n\tlet firstAdded = true;\n\tlet firstRemoved = true;\n\n\tfor (const part of parts) {\n\t\tif (part.added) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstAdded) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tadded += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstAdded = false;\n\t\t\t}\n\t\t\tif (value) added += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (part.removed) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstRemoved) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tremoved += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstRemoved = false;\n\t\t\t}\n\t\t\tif (value) removed += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tadded += part.value;\n\t\tremoved += part.value;\n\t}\n\n\treturn { added, removed };\n}\n\nfunction renderOpenCodeLikeDiffLine(\n\tline: RenderableContentDiffLine,\n\tfilePath: string,\n\ttheme: ApplyPatchTheme,\n\tcontentOverride?: string,\n): string {\n\tconst lineNumber = theme.fg(\"muted\", line.lineNumber);\n\tif (line.kind === \"context\") {\n\t\treturn `${theme.fg(\"toolDiffContext\", line.sign)}${lineNumber} ${highlightDiffContent(line.content, filePath)}`;\n\t}\n\n\tconst diffColor = line.kind === \"added\" ? \"toolDiffAdded\" : \"toolDiffRemoved\";\n\tconst background = line.kind === \"added\" ? \"toolSuccessBg\" : \"toolErrorBg\";\n\tconst content =\n\t\tcontentOverride === undefined\n\t\t\t? highlightDiffContent(line.content, filePath)\n\t\t\t: theme.fg(diffColor, replaceTabs(contentOverride));\n\tconst rendered = `${theme.fg(diffColor, line.sign)}${lineNumber} ${content}`;\n\treturn theme.bg(background, rendered);\n}\n\nfunction renderOpenCodeLikeDiff(diffText: string, filePath: string, theme: ApplyPatchTheme): string {\n\tconst parsedLines = diffText.split(\"\\n\").map(parseRenderableDiffLine);\n\tconst rendered: string[] = [];\n\tlet index = 0;\n\n\twhile (index < parsedLines.length) {\n\t\tconst line = parsedLines[index];\n\t\tif (!line) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.kind !== \"removed\") {\n\t\t\trendered.push(\n\t\t\t\tline.kind === \"meta\"\n\t\t\t\t\t? theme.fg(\"toolDiffContext\", line.text)\n\t\t\t\t\t: renderOpenCodeLikeDiffLine(line, filePath, theme),\n\t\t\t);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst removedLines: RenderableRemovedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"removed\") {\n\t\t\tconst removedLine = parsedLines[index];\n\t\t\tif (removedLine?.kind === \"removed\") removedLines.push(removedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst addedLines: RenderableAddedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"added\") {\n\t\t\tconst addedLine = parsedLines[index];\n\t\t\tif (addedLine?.kind === \"added\") addedLines.push(addedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst pairedCount = Math.min(removedLines.length, addedLines.length);\n\t\tfor (let pairIndex = 0; pairIndex < pairedCount; pairIndex++) {\n\t\t\tconst removedLine = removedLines[pairIndex];\n\t\t\tconst addedLine = addedLines[pairIndex];\n\t\t\tif (!removedLine || !addedLine) continue;\n\n\t\t\tconst inline = renderInlineDiff(removedLine.content, addedLine.content, theme);\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme, inline.removed));\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme, inline.added));\n\t\t}\n\n\t\tfor (const removedLine of removedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme));\n\t\tfor (const addedLine of addedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme));\n\t}\n\n\treturn rendered.join(\"\\n\");\n}\n\nexport function getApplyPatchRenderState(toolCallId: string, cwd: string, patchText: string): ApplyPatchRenderState {\n\tconst existing = applyPatchRenderStates.get(toolCallId);\n\tif (existing && existing.cwd === cwd && existing.patchText === patchText) return existing;\n\n\tconst callText = formatInFlightCallText(patchText);\n\tlet collapsed = \"\";\n\tlet expanded = \"\";\n\ttry {\n\t\tconst hunks = parsePatch(patchText);\n\t\tif (hunks.length > 0) {\n\t\t\tconst files = hunks.map((hunk) => ({\n\t\t\t\tfilePath: hunk.filePath,\n\t\t\t\tmovePath: hunk.type === \"update\" ? hunk.movePath : undefined,\n\t\t\t\toperation: hunk.type,\n\t\t\t\tdiff: \"\",\n\t\t\t\tadded: 0,\n\t\t\t\tremoved: 0,\n\t\t\t})) satisfies ApplyPatchPreviewFile[];\n\t\t\tconst preview: ApplyPatchPreview = { files, added: 0, removed: 0 };\n\t\t\tcollapsed = formatPatchPreview(preview, cwd, false);\n\t\t\texpanded = formatPatchPreview(preview, cwd, true);\n\t\t}\n\t} catch {\n\t\t// ignore incomplete patch text\n\t}\n\n\tconst nextState: ApplyPatchRenderState = { ...existing, cwd, patchText, callText, collapsed, expanded };\n\tapplyPatchRenderStates.set(toolCallId, nextState);\n\treturn nextState;\n}\n\nexport function clearApplyPatchRenderState(): void {\n\tapplyPatchRenderStates.clear();\n}\n\nexport function renderPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string,\n\ttheme: ApplyPatchTheme,\n\texpanded: boolean,\n): string {\n\tif (expanded) {\n\t\ttry {\n\t\t\tconst renderFile = (file: ApplyPatchPreviewFile, headerPrefix: string): string => {\n\t\t\t\tconst header = `• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\tif (!file.diff) {\n\t\t\t\t\treturn headerPrefix.length > 0\n\t\t\t\t\t\t? `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`\n\t\t\t\t\t\t: header;\n\t\t\t\t}\n\n\t\t\t\tconst renderedDiff = renderOpenCodeLikeDiff(\n\t\t\t\t\ttruncatePreview(file.diff),\n\t\t\t\t\tfile.movePath ?? file.filePath,\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\tif (headerPrefix.length > 0) {\n\t\t\t\t\tconst nestedHeader = `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\t\treturn `${nestedHeader}\\n${renderedDiff\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`)\n\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\t\t}\n\t\t\t\treturn `${header}\\n${renderedDiff}`;\n\t\t\t};\n\n\t\t\tif (preview.files.length === 1) {\n\t\t\t\tconst file = preview.files[0];\n\t\t\t\treturn file ? renderFile(file, \"\") : \"\";\n\t\t\t}\n\n\t\t\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\t\t\tconst renderedFiles = preview.files.map((file) => renderFile(file, \" └ \")).join(\"\\n\");\n\t\t\tif (renderedFiles.length > 0) {\n\t\t\t\treturn `• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}\\n${renderedFiles}`;\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall back to manual themed line rendering\n\t\t}\n\t}\n\n\treturn formatPatchPreview(preview, cwd, expanded)\n\t\t.split(\"\\n\")\n\t\t.map((line) => renderPatchLine(line, theme))\n\t\t.join(\"\\n\");\n}\n\nexport function formatPendingPatchPaths(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Applying patch...\";\n\treturn `Applying patch...\\n${paths.map((filePath) => `• ${filePath}`).join(\"\\n\")}`;\n}\n\nexport function renderPatchLine(line: string, theme: ApplyPatchTheme): string {\n\tconst trimmed = line.trimStart();\n\tif (trimmed.startsWith(\"+\")) return theme.fg(\"toolDiffAdded\", line);\n\tif (trimmed.startsWith(\"-\")) return theme.fg(\"toolDiffRemoved\", line);\n\tif (trimmed.startsWith(\"•\")) return theme.fg(\"toolTitle\", theme.bold(line));\n\tif (trimmed.startsWith(\"└\")) return theme.fg(\"accent\", line);\n\treturn theme.fg(\"toolDiffContext\", line);\n}\n"]}
@@ -6,8 +6,54 @@ import { extractPatchedPaths } from "./text.js";
6
6
  export const PATCH_PREVIEW_MAX_LINES = 16;
7
7
  export const PATCH_PREVIEW_MAX_CHARS = 4000;
8
8
  const PATCH_PREVIEW_HEAD_LINES = 8;
9
- const PATCH_PREVIEW_TAIL_LINES = 8;
9
+ const PATCH_PREVIEW_TAIL_LINES = PATCH_PREVIEW_MAX_LINES - PATCH_PREVIEW_HEAD_LINES - 1;
10
+ const PATCH_PREVIEW_TRUNCATION_MARKER = "…";
10
11
  const applyPatchRenderStates = new Map();
12
+ function isChangedPreviewLine(line) {
13
+ return /^[+-]\s*\d+\s/.test(line);
14
+ }
15
+ function countWindowLines(lines, start, end) {
16
+ return end - start + (start > 0 ? 1 : 0) + (end < lines.length ? 1 : 0);
17
+ }
18
+ function formatPreviewWindow(lines, start, end) {
19
+ const previewLines = lines.slice(start, end);
20
+ if (start > 0)
21
+ previewLines.unshift("…");
22
+ if (end < lines.length)
23
+ previewLines.push("…");
24
+ return previewLines.join("\n");
25
+ }
26
+ function createChangedHunkPreview(lines) {
27
+ const firstChangedLine = lines.findIndex(isChangedPreviewLine);
28
+ if (firstChangedLine === -1)
29
+ return undefined;
30
+ let start = firstChangedLine;
31
+ let end = firstChangedLine + 1;
32
+ while (end < lines.length) {
33
+ const line = lines[end];
34
+ if (line === undefined || !isChangedPreviewLine(line))
35
+ break;
36
+ end++;
37
+ }
38
+ const changedHunkEnd = end;
39
+ while (end > start && countWindowLines(lines, start, end) > PATCH_PREVIEW_MAX_LINES)
40
+ end--;
41
+ while (countWindowLines(lines, start, end) < PATCH_PREVIEW_MAX_LINES) {
42
+ const canAddBefore = start > 0;
43
+ const canAddAfter = end < lines.length;
44
+ if (!canAddBefore && !canAddAfter)
45
+ break;
46
+ const beforeContextLines = firstChangedLine - start;
47
+ const afterContextLines = end - changedHunkEnd;
48
+ if (canAddBefore && (!canAddAfter || beforeContextLines <= afterContextLines)) {
49
+ start--;
50
+ }
51
+ else {
52
+ end++;
53
+ }
54
+ }
55
+ return formatPreviewWindow(lines, start, end);
56
+ }
11
57
  function formatLineCountSummary(added, removed) {
12
58
  return `(+${added} -${removed})`;
13
59
  }
@@ -21,16 +67,19 @@ function countLines(text) {
21
67
  }
22
68
  return lines;
23
69
  }
70
+ function enforcePreviewCharLimit(preview) {
71
+ if (preview.length <= PATCH_PREVIEW_MAX_CHARS)
72
+ return preview;
73
+ return `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS - PATCH_PREVIEW_TRUNCATION_MARKER.length).trimEnd()}${PATCH_PREVIEW_TRUNCATION_MARKER}`;
74
+ }
24
75
  export function truncatePreview(text) {
25
76
  if (text.length <= PATCH_PREVIEW_MAX_CHARS && countLines(text) <= PATCH_PREVIEW_MAX_LINES)
26
77
  return text;
27
78
  const lines = text.split("\n");
28
- const head = lines.slice(0, PATCH_PREVIEW_HEAD_LINES);
29
- const tail = lines.slice(-PATCH_PREVIEW_TAIL_LINES);
30
- let preview = [...head, "…", ...tail].join("\n");
31
- if (preview.length > PATCH_PREVIEW_MAX_CHARS)
32
- preview = `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS).trimEnd()}\n…`;
33
- return preview;
79
+ const changedHunkPreview = createChangedHunkPreview(lines);
80
+ const preview = changedHunkPreview ??
81
+ [...lines.slice(0, PATCH_PREVIEW_HEAD_LINES), "…", ...lines.slice(-PATCH_PREVIEW_TAIL_LINES)].join("\n");
82
+ return enforcePreviewCharLimit(preview);
34
83
  }
35
84
  export function displayPath(filePath, cwd) {
36
85
  if (!path.isAbsolute(filePath))
@@ -1 +1 @@
1
- {"version":3,"file":"preview-format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/gpt-apply-patch/preview-format.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport * as Diff from \"diff\";\nimport { getLanguageFromPath, highlightCode } from \"../../../../modes/interactive/theme/theme.js\";\nimport { parsePatch } from \"./parser.js\";\nimport { extractPatchedPaths } from \"./text.js\";\nimport type {\n\tApplyPatchOperation,\n\tApplyPatchPreview,\n\tApplyPatchPreviewFile,\n\tApplyPatchRenderState,\n\tApplyPatchTheme,\n} from \"./types.js\";\n\nexport const PATCH_PREVIEW_MAX_LINES = 16;\nexport const PATCH_PREVIEW_MAX_CHARS = 4000;\nconst PATCH_PREVIEW_HEAD_LINES = 8;\nconst PATCH_PREVIEW_TAIL_LINES = 8;\nconst applyPatchRenderStates = new Map<string, ApplyPatchRenderState>();\n\nfunction formatLineCountSummary(added: number, removed: number): string {\n\treturn `(+${added} -${removed})`;\n}\n\nfunction countLines(text: string): number {\n\tif (text.length === 0) return 0;\n\tlet lines = 1;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text.charCodeAt(index) === 10) lines += 1;\n\t}\n\treturn lines;\n}\n\nexport function truncatePreview(text: string): string {\n\tif (text.length <= PATCH_PREVIEW_MAX_CHARS && countLines(text) <= PATCH_PREVIEW_MAX_LINES) return text;\n\tconst lines = text.split(\"\\n\");\n\tconst head = lines.slice(0, PATCH_PREVIEW_HEAD_LINES);\n\tconst tail = lines.slice(-PATCH_PREVIEW_TAIL_LINES);\n\tlet preview = [...head, \"…\", ...tail].join(\"\\n\");\n\tif (preview.length > PATCH_PREVIEW_MAX_CHARS) preview = `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS).trimEnd()}\\n…`;\n\treturn preview;\n}\n\nexport function displayPath(filePath: string, cwd: string): string {\n\tif (!path.isAbsolute(filePath)) return filePath;\n\tconst absoluteCwd = path.resolve(cwd);\n\tconst relativePath = path.relative(absoluteCwd, filePath);\n\tif (\n\t\trelativePath === \"\" ||\n\t\t(!relativePath.startsWith(`..${path.sep}`) && relativePath !== \"..\" && !path.isAbsolute(relativePath))\n\t) {\n\t\treturn relativePath || \".\";\n\t}\n\treturn filePath;\n}\n\nfunction formatPatchFilePath(file: ApplyPatchPreviewFile, cwd: string = process.cwd()): string {\n\tconst filePath = displayPath(file.filePath, cwd);\n\tif (!file.movePath) return filePath;\n\treturn `${filePath} → ${displayPath(file.movePath, cwd)}`;\n}\n\nfunction formatPatchOperation(operation: ApplyPatchOperation): string {\n\tif (operation === \"add\") return \"Added\";\n\tif (operation === \"delete\") return \"Deleted\";\n\treturn \"Edited\";\n}\n\nexport function formatPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string = process.cwd(),\n\texpanded: boolean = true,\n): string {\n\tconst lines: string[] = [];\n\tif (preview.files.length === 1) {\n\t\tconst file = preview.files[0];\n\t\tif (file) {\n\t\t\tlines.push(\n\t\t\t\t`• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`,\n\t\t\t);\n\t\t\tif (expanded && file.diff)\n\t\t\t\tlines.push(\n\t\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t\t);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\tlines.push(`• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}`);\n\tfor (const file of preview.files) {\n\t\tlines.push(` └ ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`);\n\t\tif (expanded && file.diff)\n\t\t\tlines.push(\n\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatInFlightCallText(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Patching\";\n\tconst noun = paths.length === 1 ? \"file\" : \"files\";\n\tconst count = paths.length > 1 ? ` (${paths.length} ${noun})` : \"\";\n\treturn `Patching${count}: ${paths.join(\", \")}`;\n}\n\ntype RenderableAddedDiffLine = { content: string; kind: \"added\"; lineNumber: string; sign: \"+\" };\ntype RenderableRemovedDiffLine = { content: string; kind: \"removed\"; lineNumber: string; sign: \"-\" };\ntype RenderableContextDiffLine = { content: string; kind: \"context\"; lineNumber: string; sign: \" \" };\ntype RenderableContentDiffLine = RenderableAddedDiffLine | RenderableContextDiffLine | RenderableRemovedDiffLine;\ntype RenderableDiffLine = RenderableContentDiffLine | { kind: \"meta\"; text: string };\n\nfunction parseRenderableDiffLine(line: string): RenderableDiffLine {\n\tconst match = line.match(/^([+\\- ])(\\s*\\d+)\\s(.*)$/);\n\tif (!match) return { kind: \"meta\", text: line };\n\n\tconst sign = match[1];\n\tconst lineNumber = match[2];\n\tif ((sign !== \"+\" && sign !== \"-\" && sign !== \" \") || lineNumber === undefined) return { kind: \"meta\", text: line };\n\n\tconst content = match[3] ?? \"\";\n\tif (sign === \"+\") return { content, kind: \"added\", lineNumber, sign };\n\tif (sign === \"-\") return { content, kind: \"removed\", lineNumber, sign };\n\treturn { content, kind: \"context\", lineNumber, sign };\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction highlightDiffContent(content: string, filePath: string): string {\n\tconst plainContent = replaceTabs(content);\n\tconst language = getLanguageFromPath(filePath);\n\ttry {\n\t\treturn highlightCode(plainContent, language)[0] ?? plainContent;\n\t} catch {\n\t\treturn plainContent;\n\t}\n}\n\nfunction renderInlineDiff(\n\toldContent: string,\n\tnewContent: string,\n\ttheme: ApplyPatchTheme,\n): { added: string; removed: string } {\n\tconst parts = Diff.diffWords(replaceTabs(oldContent), replaceTabs(newContent));\n\tlet added = \"\";\n\tlet removed = \"\";\n\tlet firstAdded = true;\n\tlet firstRemoved = true;\n\n\tfor (const part of parts) {\n\t\tif (part.added) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstAdded) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tadded += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstAdded = false;\n\t\t\t}\n\t\t\tif (value) added += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (part.removed) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstRemoved) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tremoved += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstRemoved = false;\n\t\t\t}\n\t\t\tif (value) removed += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tadded += part.value;\n\t\tremoved += part.value;\n\t}\n\n\treturn { added, removed };\n}\n\nfunction renderOpenCodeLikeDiffLine(\n\tline: RenderableContentDiffLine,\n\tfilePath: string,\n\ttheme: ApplyPatchTheme,\n\tcontentOverride?: string,\n): string {\n\tconst lineNumber = theme.fg(\"muted\", line.lineNumber);\n\tif (line.kind === \"context\") {\n\t\treturn `${theme.fg(\"toolDiffContext\", line.sign)}${lineNumber} ${highlightDiffContent(line.content, filePath)}`;\n\t}\n\n\tconst diffColor = line.kind === \"added\" ? \"toolDiffAdded\" : \"toolDiffRemoved\";\n\tconst background = line.kind === \"added\" ? \"toolSuccessBg\" : \"toolErrorBg\";\n\tconst content =\n\t\tcontentOverride === undefined\n\t\t\t? highlightDiffContent(line.content, filePath)\n\t\t\t: theme.fg(diffColor, replaceTabs(contentOverride));\n\tconst rendered = `${theme.fg(diffColor, line.sign)}${lineNumber} ${content}`;\n\treturn theme.bg(background, rendered);\n}\n\nfunction renderOpenCodeLikeDiff(diffText: string, filePath: string, theme: ApplyPatchTheme): string {\n\tconst parsedLines = diffText.split(\"\\n\").map(parseRenderableDiffLine);\n\tconst rendered: string[] = [];\n\tlet index = 0;\n\n\twhile (index < parsedLines.length) {\n\t\tconst line = parsedLines[index];\n\t\tif (!line) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.kind !== \"removed\") {\n\t\t\trendered.push(\n\t\t\t\tline.kind === \"meta\"\n\t\t\t\t\t? theme.fg(\"toolDiffContext\", line.text)\n\t\t\t\t\t: renderOpenCodeLikeDiffLine(line, filePath, theme),\n\t\t\t);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst removedLines: RenderableRemovedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"removed\") {\n\t\t\tconst removedLine = parsedLines[index];\n\t\t\tif (removedLine?.kind === \"removed\") removedLines.push(removedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst addedLines: RenderableAddedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"added\") {\n\t\t\tconst addedLine = parsedLines[index];\n\t\t\tif (addedLine?.kind === \"added\") addedLines.push(addedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst pairedCount = Math.min(removedLines.length, addedLines.length);\n\t\tfor (let pairIndex = 0; pairIndex < pairedCount; pairIndex++) {\n\t\t\tconst removedLine = removedLines[pairIndex];\n\t\t\tconst addedLine = addedLines[pairIndex];\n\t\t\tif (!removedLine || !addedLine) continue;\n\n\t\t\tconst inline = renderInlineDiff(removedLine.content, addedLine.content, theme);\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme, inline.removed));\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme, inline.added));\n\t\t}\n\n\t\tfor (const removedLine of removedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme));\n\t\tfor (const addedLine of addedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme));\n\t}\n\n\treturn rendered.join(\"\\n\");\n}\n\nexport function getApplyPatchRenderState(toolCallId: string, cwd: string, patchText: string): ApplyPatchRenderState {\n\tconst existing = applyPatchRenderStates.get(toolCallId);\n\tif (existing && existing.cwd === cwd && existing.patchText === patchText) return existing;\n\n\tconst callText = formatInFlightCallText(patchText);\n\tlet collapsed = \"\";\n\tlet expanded = \"\";\n\ttry {\n\t\tconst hunks = parsePatch(patchText);\n\t\tif (hunks.length > 0) {\n\t\t\tconst files = hunks.map((hunk) => ({\n\t\t\t\tfilePath: hunk.filePath,\n\t\t\t\tmovePath: hunk.type === \"update\" ? hunk.movePath : undefined,\n\t\t\t\toperation: hunk.type,\n\t\t\t\tdiff: \"\",\n\t\t\t\tadded: 0,\n\t\t\t\tremoved: 0,\n\t\t\t})) satisfies ApplyPatchPreviewFile[];\n\t\t\tconst preview: ApplyPatchPreview = { files, added: 0, removed: 0 };\n\t\t\tcollapsed = formatPatchPreview(preview, cwd, false);\n\t\t\texpanded = formatPatchPreview(preview, cwd, true);\n\t\t}\n\t} catch {\n\t\t// ignore incomplete patch text\n\t}\n\n\tconst nextState: ApplyPatchRenderState = { ...existing, cwd, patchText, callText, collapsed, expanded };\n\tapplyPatchRenderStates.set(toolCallId, nextState);\n\treturn nextState;\n}\n\nexport function clearApplyPatchRenderState(): void {\n\tapplyPatchRenderStates.clear();\n}\n\nexport function renderPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string,\n\ttheme: ApplyPatchTheme,\n\texpanded: boolean,\n): string {\n\tif (expanded) {\n\t\ttry {\n\t\t\tconst renderFile = (file: ApplyPatchPreviewFile, headerPrefix: string): string => {\n\t\t\t\tconst header = `• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\tif (!file.diff) {\n\t\t\t\t\treturn headerPrefix.length > 0\n\t\t\t\t\t\t? `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`\n\t\t\t\t\t\t: header;\n\t\t\t\t}\n\n\t\t\t\tconst renderedDiff = renderOpenCodeLikeDiff(\n\t\t\t\t\ttruncatePreview(file.diff),\n\t\t\t\t\tfile.movePath ?? file.filePath,\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\tif (headerPrefix.length > 0) {\n\t\t\t\t\tconst nestedHeader = `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\t\treturn `${nestedHeader}\\n${renderedDiff\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`)\n\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\t\t}\n\t\t\t\treturn `${header}\\n${renderedDiff}`;\n\t\t\t};\n\n\t\t\tif (preview.files.length === 1) {\n\t\t\t\tconst file = preview.files[0];\n\t\t\t\treturn file ? renderFile(file, \"\") : \"\";\n\t\t\t}\n\n\t\t\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\t\t\tconst renderedFiles = preview.files.map((file) => renderFile(file, \" └ \")).join(\"\\n\");\n\t\t\tif (renderedFiles.length > 0) {\n\t\t\t\treturn `• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}\\n${renderedFiles}`;\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall back to manual themed line rendering\n\t\t}\n\t}\n\n\treturn formatPatchPreview(preview, cwd, expanded)\n\t\t.split(\"\\n\")\n\t\t.map((line) => renderPatchLine(line, theme))\n\t\t.join(\"\\n\");\n}\n\nexport function formatPendingPatchPaths(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Applying patch...\";\n\treturn `Applying patch...\\n${paths.map((filePath) => `• ${filePath}`).join(\"\\n\")}`;\n}\n\nexport function renderPatchLine(line: string, theme: ApplyPatchTheme): string {\n\tconst trimmed = line.trimStart();\n\tif (trimmed.startsWith(\"+\")) return theme.fg(\"toolDiffAdded\", line);\n\tif (trimmed.startsWith(\"-\")) return theme.fg(\"toolDiffRemoved\", line);\n\tif (trimmed.startsWith(\"•\")) return theme.fg(\"toolTitle\", theme.bold(line));\n\tif (trimmed.startsWith(\"└\")) return theme.fg(\"accent\", line);\n\treturn theme.fg(\"toolDiffContext\", line);\n}\n"]}
1
+ {"version":3,"file":"preview-format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/gpt-apply-patch/preview-format.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport * as Diff from \"diff\";\nimport { getLanguageFromPath, highlightCode } from \"../../../../modes/interactive/theme/theme.js\";\nimport { parsePatch } from \"./parser.js\";\nimport { extractPatchedPaths } from \"./text.js\";\nimport type {\n\tApplyPatchOperation,\n\tApplyPatchPreview,\n\tApplyPatchPreviewFile,\n\tApplyPatchRenderState,\n\tApplyPatchTheme,\n} from \"./types.js\";\n\nexport const PATCH_PREVIEW_MAX_LINES = 16;\nexport const PATCH_PREVIEW_MAX_CHARS = 4000;\nconst PATCH_PREVIEW_HEAD_LINES = 8;\nconst PATCH_PREVIEW_TAIL_LINES = PATCH_PREVIEW_MAX_LINES - PATCH_PREVIEW_HEAD_LINES - 1;\nconst PATCH_PREVIEW_TRUNCATION_MARKER = \"…\";\nconst applyPatchRenderStates = new Map<string, ApplyPatchRenderState>();\n\nfunction isChangedPreviewLine(line: string): boolean {\n\treturn /^[+-]\\s*\\d+\\s/.test(line);\n}\n\nfunction countWindowLines(lines: string[], start: number, end: number): number {\n\treturn end - start + (start > 0 ? 1 : 0) + (end < lines.length ? 1 : 0);\n}\n\nfunction formatPreviewWindow(lines: string[], start: number, end: number): string {\n\tconst previewLines = lines.slice(start, end);\n\tif (start > 0) previewLines.unshift(\"…\");\n\tif (end < lines.length) previewLines.push(\"…\");\n\treturn previewLines.join(\"\\n\");\n}\n\nfunction createChangedHunkPreview(lines: string[]): string | undefined {\n\tconst firstChangedLine = lines.findIndex(isChangedPreviewLine);\n\tif (firstChangedLine === -1) return undefined;\n\n\tlet start = firstChangedLine;\n\tlet end = firstChangedLine + 1;\n\twhile (end < lines.length) {\n\t\tconst line = lines[end];\n\t\tif (line === undefined || !isChangedPreviewLine(line)) break;\n\t\tend++;\n\t}\n\n\tconst changedHunkEnd = end;\n\twhile (end > start && countWindowLines(lines, start, end) > PATCH_PREVIEW_MAX_LINES) end--;\n\n\twhile (countWindowLines(lines, start, end) < PATCH_PREVIEW_MAX_LINES) {\n\t\tconst canAddBefore = start > 0;\n\t\tconst canAddAfter = end < lines.length;\n\t\tif (!canAddBefore && !canAddAfter) break;\n\n\t\tconst beforeContextLines = firstChangedLine - start;\n\t\tconst afterContextLines = end - changedHunkEnd;\n\t\tif (canAddBefore && (!canAddAfter || beforeContextLines <= afterContextLines)) {\n\t\t\tstart--;\n\t\t} else {\n\t\t\tend++;\n\t\t}\n\t}\n\n\treturn formatPreviewWindow(lines, start, end);\n}\n\nfunction formatLineCountSummary(added: number, removed: number): string {\n\treturn `(+${added} -${removed})`;\n}\n\nfunction countLines(text: string): number {\n\tif (text.length === 0) return 0;\n\tlet lines = 1;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text.charCodeAt(index) === 10) lines += 1;\n\t}\n\treturn lines;\n}\n\nfunction enforcePreviewCharLimit(preview: string): string {\n\tif (preview.length <= PATCH_PREVIEW_MAX_CHARS) return preview;\n\treturn `${preview.slice(0, PATCH_PREVIEW_MAX_CHARS - PATCH_PREVIEW_TRUNCATION_MARKER.length).trimEnd()}${PATCH_PREVIEW_TRUNCATION_MARKER}`;\n}\n\nexport function truncatePreview(text: string): string {\n\tif (text.length <= PATCH_PREVIEW_MAX_CHARS && countLines(text) <= PATCH_PREVIEW_MAX_LINES) return text;\n\tconst lines = text.split(\"\\n\");\n\tconst changedHunkPreview = createChangedHunkPreview(lines);\n\tconst preview =\n\t\tchangedHunkPreview ??\n\t\t[...lines.slice(0, PATCH_PREVIEW_HEAD_LINES), \"…\", ...lines.slice(-PATCH_PREVIEW_TAIL_LINES)].join(\"\\n\");\n\treturn enforcePreviewCharLimit(preview);\n}\n\nexport function displayPath(filePath: string, cwd: string): string {\n\tif (!path.isAbsolute(filePath)) return filePath;\n\tconst absoluteCwd = path.resolve(cwd);\n\tconst relativePath = path.relative(absoluteCwd, filePath);\n\tif (\n\t\trelativePath === \"\" ||\n\t\t(!relativePath.startsWith(`..${path.sep}`) && relativePath !== \"..\" && !path.isAbsolute(relativePath))\n\t) {\n\t\treturn relativePath || \".\";\n\t}\n\treturn filePath;\n}\n\nfunction formatPatchFilePath(file: ApplyPatchPreviewFile, cwd: string = process.cwd()): string {\n\tconst filePath = displayPath(file.filePath, cwd);\n\tif (!file.movePath) return filePath;\n\treturn `${filePath} → ${displayPath(file.movePath, cwd)}`;\n}\n\nfunction formatPatchOperation(operation: ApplyPatchOperation): string {\n\tif (operation === \"add\") return \"Added\";\n\tif (operation === \"delete\") return \"Deleted\";\n\treturn \"Edited\";\n}\n\nexport function formatPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string = process.cwd(),\n\texpanded: boolean = true,\n): string {\n\tconst lines: string[] = [];\n\tif (preview.files.length === 1) {\n\t\tconst file = preview.files[0];\n\t\tif (file) {\n\t\t\tlines.push(\n\t\t\t\t`• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`,\n\t\t\t);\n\t\t\tif (expanded && file.diff)\n\t\t\t\tlines.push(\n\t\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t\t);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\tlines.push(`• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}`);\n\tfor (const file of preview.files) {\n\t\tlines.push(` └ ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`);\n\t\tif (expanded && file.diff)\n\t\t\tlines.push(\n\t\t\t\t...truncatePreview(file.diff)\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => ` ${line}`),\n\t\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatInFlightCallText(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Patching\";\n\tconst noun = paths.length === 1 ? \"file\" : \"files\";\n\tconst count = paths.length > 1 ? ` (${paths.length} ${noun})` : \"\";\n\treturn `Patching${count}: ${paths.join(\", \")}`;\n}\n\ntype RenderableAddedDiffLine = { content: string; kind: \"added\"; lineNumber: string; sign: \"+\" };\ntype RenderableRemovedDiffLine = { content: string; kind: \"removed\"; lineNumber: string; sign: \"-\" };\ntype RenderableContextDiffLine = { content: string; kind: \"context\"; lineNumber: string; sign: \" \" };\ntype RenderableContentDiffLine = RenderableAddedDiffLine | RenderableContextDiffLine | RenderableRemovedDiffLine;\ntype RenderableDiffLine = RenderableContentDiffLine | { kind: \"meta\"; text: string };\n\nfunction parseRenderableDiffLine(line: string): RenderableDiffLine {\n\tconst match = line.match(/^([+\\- ])(\\s*\\d+)\\s(.*)$/);\n\tif (!match) return { kind: \"meta\", text: line };\n\n\tconst sign = match[1];\n\tconst lineNumber = match[2];\n\tif ((sign !== \"+\" && sign !== \"-\" && sign !== \" \") || lineNumber === undefined) return { kind: \"meta\", text: line };\n\n\tconst content = match[3] ?? \"\";\n\tif (sign === \"+\") return { content, kind: \"added\", lineNumber, sign };\n\tif (sign === \"-\") return { content, kind: \"removed\", lineNumber, sign };\n\treturn { content, kind: \"context\", lineNumber, sign };\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction highlightDiffContent(content: string, filePath: string): string {\n\tconst plainContent = replaceTabs(content);\n\tconst language = getLanguageFromPath(filePath);\n\ttry {\n\t\treturn highlightCode(plainContent, language)[0] ?? plainContent;\n\t} catch {\n\t\treturn plainContent;\n\t}\n}\n\nfunction renderInlineDiff(\n\toldContent: string,\n\tnewContent: string,\n\ttheme: ApplyPatchTheme,\n): { added: string; removed: string } {\n\tconst parts = Diff.diffWords(replaceTabs(oldContent), replaceTabs(newContent));\n\tlet added = \"\";\n\tlet removed = \"\";\n\tlet firstAdded = true;\n\tlet firstRemoved = true;\n\n\tfor (const part of parts) {\n\t\tif (part.added) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstAdded) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tadded += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstAdded = false;\n\t\t\t}\n\t\t\tif (value) added += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (part.removed) {\n\t\t\tlet value = part.value;\n\t\t\tif (firstRemoved) {\n\t\t\t\tconst leadingWhitespace = value.match(/^(\\s*)/)?.[1] ?? \"\";\n\t\t\t\tremoved += leadingWhitespace;\n\t\t\t\tvalue = value.slice(leadingWhitespace.length);\n\t\t\t\tfirstRemoved = false;\n\t\t\t}\n\t\t\tif (value) removed += theme.inverse(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\tadded += part.value;\n\t\tremoved += part.value;\n\t}\n\n\treturn { added, removed };\n}\n\nfunction renderOpenCodeLikeDiffLine(\n\tline: RenderableContentDiffLine,\n\tfilePath: string,\n\ttheme: ApplyPatchTheme,\n\tcontentOverride?: string,\n): string {\n\tconst lineNumber = theme.fg(\"muted\", line.lineNumber);\n\tif (line.kind === \"context\") {\n\t\treturn `${theme.fg(\"toolDiffContext\", line.sign)}${lineNumber} ${highlightDiffContent(line.content, filePath)}`;\n\t}\n\n\tconst diffColor = line.kind === \"added\" ? \"toolDiffAdded\" : \"toolDiffRemoved\";\n\tconst background = line.kind === \"added\" ? \"toolSuccessBg\" : \"toolErrorBg\";\n\tconst content =\n\t\tcontentOverride === undefined\n\t\t\t? highlightDiffContent(line.content, filePath)\n\t\t\t: theme.fg(diffColor, replaceTabs(contentOverride));\n\tconst rendered = `${theme.fg(diffColor, line.sign)}${lineNumber} ${content}`;\n\treturn theme.bg(background, rendered);\n}\n\nfunction renderOpenCodeLikeDiff(diffText: string, filePath: string, theme: ApplyPatchTheme): string {\n\tconst parsedLines = diffText.split(\"\\n\").map(parseRenderableDiffLine);\n\tconst rendered: string[] = [];\n\tlet index = 0;\n\n\twhile (index < parsedLines.length) {\n\t\tconst line = parsedLines[index];\n\t\tif (!line) {\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.kind !== \"removed\") {\n\t\t\trendered.push(\n\t\t\t\tline.kind === \"meta\"\n\t\t\t\t\t? theme.fg(\"toolDiffContext\", line.text)\n\t\t\t\t\t: renderOpenCodeLikeDiffLine(line, filePath, theme),\n\t\t\t);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst removedLines: RenderableRemovedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"removed\") {\n\t\t\tconst removedLine = parsedLines[index];\n\t\t\tif (removedLine?.kind === \"removed\") removedLines.push(removedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst addedLines: RenderableAddedDiffLine[] = [];\n\t\twhile (parsedLines[index]?.kind === \"added\") {\n\t\t\tconst addedLine = parsedLines[index];\n\t\t\tif (addedLine?.kind === \"added\") addedLines.push(addedLine);\n\t\t\tindex++;\n\t\t}\n\n\t\tconst pairedCount = Math.min(removedLines.length, addedLines.length);\n\t\tfor (let pairIndex = 0; pairIndex < pairedCount; pairIndex++) {\n\t\t\tconst removedLine = removedLines[pairIndex];\n\t\t\tconst addedLine = addedLines[pairIndex];\n\t\t\tif (!removedLine || !addedLine) continue;\n\n\t\t\tconst inline = renderInlineDiff(removedLine.content, addedLine.content, theme);\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme, inline.removed));\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme, inline.added));\n\t\t}\n\n\t\tfor (const removedLine of removedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(removedLine, filePath, theme));\n\t\tfor (const addedLine of addedLines.slice(pairedCount))\n\t\t\trendered.push(renderOpenCodeLikeDiffLine(addedLine, filePath, theme));\n\t}\n\n\treturn rendered.join(\"\\n\");\n}\n\nexport function getApplyPatchRenderState(toolCallId: string, cwd: string, patchText: string): ApplyPatchRenderState {\n\tconst existing = applyPatchRenderStates.get(toolCallId);\n\tif (existing && existing.cwd === cwd && existing.patchText === patchText) return existing;\n\n\tconst callText = formatInFlightCallText(patchText);\n\tlet collapsed = \"\";\n\tlet expanded = \"\";\n\ttry {\n\t\tconst hunks = parsePatch(patchText);\n\t\tif (hunks.length > 0) {\n\t\t\tconst files = hunks.map((hunk) => ({\n\t\t\t\tfilePath: hunk.filePath,\n\t\t\t\tmovePath: hunk.type === \"update\" ? hunk.movePath : undefined,\n\t\t\t\toperation: hunk.type,\n\t\t\t\tdiff: \"\",\n\t\t\t\tadded: 0,\n\t\t\t\tremoved: 0,\n\t\t\t})) satisfies ApplyPatchPreviewFile[];\n\t\t\tconst preview: ApplyPatchPreview = { files, added: 0, removed: 0 };\n\t\t\tcollapsed = formatPatchPreview(preview, cwd, false);\n\t\t\texpanded = formatPatchPreview(preview, cwd, true);\n\t\t}\n\t} catch {\n\t\t// ignore incomplete patch text\n\t}\n\n\tconst nextState: ApplyPatchRenderState = { ...existing, cwd, patchText, callText, collapsed, expanded };\n\tapplyPatchRenderStates.set(toolCallId, nextState);\n\treturn nextState;\n}\n\nexport function clearApplyPatchRenderState(): void {\n\tapplyPatchRenderStates.clear();\n}\n\nexport function renderPatchPreview(\n\tpreview: ApplyPatchPreview,\n\tcwd: string,\n\ttheme: ApplyPatchTheme,\n\texpanded: boolean,\n): string {\n\tif (expanded) {\n\t\ttry {\n\t\t\tconst renderFile = (file: ApplyPatchPreviewFile, headerPrefix: string): string => {\n\t\t\t\tconst header = `• ${formatPatchOperation(file.operation)} ${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\tif (!file.diff) {\n\t\t\t\t\treturn headerPrefix.length > 0\n\t\t\t\t\t\t? `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`\n\t\t\t\t\t\t: header;\n\t\t\t\t}\n\n\t\t\t\tconst renderedDiff = renderOpenCodeLikeDiff(\n\t\t\t\t\ttruncatePreview(file.diff),\n\t\t\t\t\tfile.movePath ?? file.filePath,\n\t\t\t\t\ttheme,\n\t\t\t\t);\n\t\t\t\tif (headerPrefix.length > 0) {\n\t\t\t\t\tconst nestedHeader = `${headerPrefix}${formatPatchFilePath(file, cwd)} ${formatLineCountSummary(file.added, file.removed)}`;\n\t\t\t\t\treturn `${nestedHeader}\\n${renderedDiff\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((line) => ` ${line}`)\n\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\t\t}\n\t\t\t\treturn `${header}\\n${renderedDiff}`;\n\t\t\t};\n\n\t\t\tif (preview.files.length === 1) {\n\t\t\t\tconst file = preview.files[0];\n\t\t\t\treturn file ? renderFile(file, \"\") : \"\";\n\t\t\t}\n\n\t\t\tconst noun = preview.files.length === 1 ? \"file\" : \"files\";\n\t\t\tconst renderedFiles = preview.files.map((file) => renderFile(file, \" └ \")).join(\"\\n\");\n\t\t\tif (renderedFiles.length > 0) {\n\t\t\t\treturn `• Edited ${preview.files.length} ${noun} ${formatLineCountSummary(preview.added, preview.removed)}\\n${renderedFiles}`;\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall back to manual themed line rendering\n\t\t}\n\t}\n\n\treturn formatPatchPreview(preview, cwd, expanded)\n\t\t.split(\"\\n\")\n\t\t.map((line) => renderPatchLine(line, theme))\n\t\t.join(\"\\n\");\n}\n\nexport function formatPendingPatchPaths(patchText: string): string {\n\tconst paths = extractPatchedPaths(patchText);\n\tif (paths.length === 0) return \"Applying patch...\";\n\treturn `Applying patch...\\n${paths.map((filePath) => `• ${filePath}`).join(\"\\n\")}`;\n}\n\nexport function renderPatchLine(line: string, theme: ApplyPatchTheme): string {\n\tconst trimmed = line.trimStart();\n\tif (trimmed.startsWith(\"+\")) return theme.fg(\"toolDiffAdded\", line);\n\tif (trimmed.startsWith(\"-\")) return theme.fg(\"toolDiffRemoved\", line);\n\tif (trimmed.startsWith(\"•\")) return theme.fg(\"toolTitle\", theme.bold(line));\n\tif (trimmed.startsWith(\"└\")) return theme.fg(\"accent\", line);\n\treturn theme.fg(\"toolDiffContext\", line);\n}\n"]}
@@ -1,12 +1,16 @@
1
1
  import type { Api, Model } from "@earendil-works/pi-ai";
2
2
  import type { BuildDynamicSystemPromptOptions } from "../../../dynamic-prompt/build.js";
3
- import type { PromptPresetName, PromptPresetSettings } from "./settings.js";
3
+ import { type PromptPresetName, type PromptPresetSettings } from "./settings.js";
4
4
  export type { PromptPresetSettings } from "./settings.js";
5
5
  type ResolvedPresetName = Exclude<PromptPresetName, "auto">;
6
+ type ModelWithPromptPresetMetadata = Pick<Model<Api>, "id" | "provider"> & {
7
+ name?: string;
8
+ promptPreset?: string;
9
+ };
6
10
  export interface ResolvedPromptPreset {
7
11
  name: ResolvedPresetName;
8
12
  prompt: string;
9
13
  }
10
- export declare function resolvePresetName(model: Pick<Model<Api>, "id" | "provider">, settings: PromptPresetSettings): ResolvedPresetName | undefined;
11
- export declare function resolvePreset(model: Pick<Model<Api>, "id" | "provider">, settings: PromptPresetSettings, options?: Partial<BuildDynamicSystemPromptOptions>): ResolvedPromptPreset | undefined;
14
+ export declare function resolvePresetName(model: ModelWithPromptPresetMetadata, settings: PromptPresetSettings): ResolvedPresetName | undefined;
15
+ export declare function resolvePreset(model: ModelWithPromptPresetMetadata, settings: PromptPresetSettings, options?: Partial<BuildDynamicSystemPromptOptions>): ResolvedPromptPreset | undefined;
12
16
  //# sourceMappingURL=presets.d.ts.map