@f5-sales-demo/xcsh 20.13.0 → 20.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "20.
|
|
4
|
+
"version": "20.14.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -61,20 +61,21 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
64
|
+
"@f5-sales-demo/pi-agent-core": "20.14.0",
|
|
65
|
+
"@f5-sales-demo/pi-ai": "20.14.0",
|
|
66
|
+
"@f5-sales-demo/pi-natives": "20.14.0",
|
|
67
|
+
"@f5-sales-demo/pi-resource-management": "20.14.0",
|
|
68
|
+
"@f5-sales-demo/pi-tui": "20.14.0",
|
|
69
|
+
"@f5-sales-demo/pi-utils": "20.14.0",
|
|
70
|
+
"@f5-sales-demo/xcsh-stats": "20.14.0",
|
|
64
71
|
"@mozilla/readability": "^0.6",
|
|
65
|
-
"@f5-sales-demo/xcsh-stats": "20.13.0",
|
|
66
|
-
"@f5-sales-demo/pi-agent-core": "20.13.0",
|
|
67
|
-
"@f5-sales-demo/pi-ai": "20.13.0",
|
|
68
|
-
"@f5-sales-demo/pi-natives": "20.13.0",
|
|
69
|
-
"@f5-sales-demo/pi-resource-management": "20.13.0",
|
|
70
|
-
"@f5-sales-demo/pi-tui": "20.13.0",
|
|
71
|
-
"@f5-sales-demo/pi-utils": "20.13.0",
|
|
72
72
|
"@sinclair/typebox": "^0.34",
|
|
73
73
|
"@xterm/headless": "^6.0",
|
|
74
74
|
"ajv": "^8.20",
|
|
75
75
|
"chalk": "^5.6",
|
|
76
76
|
"diff": "^9.0",
|
|
77
77
|
"fflate": "0.8.3",
|
|
78
|
+
"google-auth-library": "10.9.1",
|
|
78
79
|
"linkedom": "^0.18",
|
|
79
80
|
"lru-cache": "11.5.2",
|
|
80
81
|
"markit-ai": "0.5.3",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "20.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "20.14.0",
|
|
21
|
+
"commit": "97c02a788b722cbc3aec14d92b37a4c721454687",
|
|
22
|
+
"shortCommit": "97c02a7",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v20.
|
|
25
|
-
"commitDate": "2026-08-
|
|
26
|
-
"buildDate": "2026-08-
|
|
24
|
+
"tag": "v20.14.0",
|
|
25
|
+
"commitDate": "2026-08-11T21:58:20Z",
|
|
26
|
+
"buildDate": "2026-08-12T08:05:53.700Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5-sales-demo/xcsh",
|
|
30
30
|
"repoSlug": "f5-sales-demo/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/97c02a788b722cbc3aec14d92b37a4c721454687",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.14.0"
|
|
33
33
|
};
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ConsoleCatalogData } from "./console-catalog-types";
|
|
4
4
|
|
|
5
|
-
export const CONSOLE_CATALOG_VERSION = "
|
|
5
|
+
export const CONSOLE_CATALOG_VERSION = "4450d0ec7d164aaee226271a6b4cd69aca408f28";
|
|
6
6
|
|
|
7
7
|
export const CONSOLE_CATALOG_DATA: ConsoleCatalogData = {
|
|
8
|
-
version: "
|
|
8
|
+
version: "4450d0ec7d164aaee226271a6b4cd69aca408f28",
|
|
9
9
|
workflows: {
|
|
10
10
|
"address-allocator/create":
|
|
11
11
|
'---\nschema: urn:xcsh:console:workflow:v1\nid: address-allocator-create\nlabel: Create IP Address Allocators\nresource: address-allocator\noperation: create\npreconditions:\n - user_logged_in\n - "role_minimum: admin"\nparams:\n name:\n required: true\n description: IP Address Allocators name (lowercase alphanumeric and hyphens)\n example: example-address-allocator\n address_allocator_mode:\n required: true\n description: Address Allocator Mode\n allocation_unit:\n required: false\n description: Allocation Unit\n default: 0\n address_pool:\n required: false\n description: Address Pool\n default: value\n address_allocation_scheme:\n required: false\n description: "Server-required: Field should be not nil"\n default: value\nsteps:\n - id: navigate-to-list\n action: navigate\n url: /web/workspaces/multi-cloud-network-connect/manage/networking/legacy_network_configuration/address_allocators\n wait_for: text(\'IP Address Allocators\')\n description: Navigate to IP Address Allocators list page\n - id: click-add-tab\n action: click\n selector: text(\'Add IP Address Allocator\')\n wait_for: textbox[name=\'Name\']\n description: Click Add IP Address Allocator to open the create form\n - id: fill-name\n action: fill\n selector: textbox[name=\'Name\']\n value: "{name}"\n description: Enter Name\n - id: select-address_allocator_mode\n action: select\n selector: listbox\n context: Address Allocator Mode section\n value: "{address_allocator_mode}"\n description: Select Address Allocator Mode\n - id: fill-allocation_unit\n action: fill\n selector: spinbutton[name=\'Allocation Unit\']\n value: "{allocation_unit}"\n description: Set Allocation Unit\n - id: fill-address_pool\n action: fill\n selector: ngx-datatable input.form-control\n context: Address Pool table\n value: "{address_pool}"\n description: Enter Address Pool in the existing table row (no Add Item needed — the table ships one empty row)\n - id: select-address_allocation_scheme\n action: select\n selector: listbox\n context: Address Allocation Scheme section\n value: "{address_allocation_scheme}"\n description: Select Address Allocation Scheme\n - id: save\n action: click\n selector: "[class*=\'save-bt\'],[class*=\'submit-button\']"\n context: footer\n wait_for: text(\'{name}\')\n wait_timeout_ms: 30000\n description: Save/submit the form (union selector matches save-bt OR submit-button)\npostconditions:\n - resource_list_page_visible\n - "resource_name_in_list: {name}"\nmetadata:\n confidence: inferred\n discovered_at: 2026-06-24\n console_version: "2025.06"\n notes: Auto-generated by scripts/generate-workflows.ts from api-specs-enriched field metadata.\n',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Auto-generated by scripts/generate-docs-index.ts - DO NOT EDIT
|
|
2
2
|
|
|
3
|
-
export const EMBEDDED_DOC_FILENAMES: readonly string[] = ["SYSTEM_PROMPT_GUIDE.md","ar/configuration/blob-artifact-architecture.md","ar/configuration/config-usage.md","ar/configuration/environment-variables.md","ar/configuration/fs-scan-cache-architecture.md","ar/configuration/hooks.md","ar/configuration/porting-from-pi-mono.md","ar/configuration/rpc.md","ar/configuration/sdk.md","ar/configuration/secrets.md","ar/extensions/extension-loading.md","ar/extensions/extensions.md","ar/extensions/gemini-manifest-extensions.md","ar/extensions/marketplace.md","ar/extensions/plugin-manager-installer-plumbing.md","ar/extensions/rulebook-matching-pipeline.md","ar/extensions/skills.md","ar/index.md","ar/mcp/mcp-config.md","ar/mcp/mcp-protocol-transports.md","ar/mcp/mcp-runtime-lifecycle.md","ar/mcp/mcp-server-tool-authoring.md","ar/natives/natives-addon-loader-runtime.md","ar/natives/natives-architecture.md","ar/natives/natives-binding-contract.md","ar/natives/natives-build-release-debugging.md","ar/natives/natives-media-system-utils.md","ar/natives/natives-rust-task-cancellation.md","ar/natives/natives-shell-pty-process.md","ar/natives/natives-text-search-pipeline.md","ar/natives/porting-to-natives.md","ar/providers/models.md","ar/providers/provider-streaming-internals.md","ar/providers/python-repl.md","ar/runtime-tools/bash-tool-runtime.md","ar/runtime-tools/context-command.md","ar/runtime-tools/custom-tools.md","ar/runtime-tools/notebook-tool-runtime.md","ar/runtime-tools/resolve-tool-runtime.md","ar/runtime-tools/slash-command-internals.md","ar/runtime-tools/task-agent-discovery.md","ar/sessions/compaction.md","ar/sessions/handoff-generation-pipeline.md","ar/sessions/memory.md","ar/sessions/non-compaction-retry-policy.md","ar/sessions/session-operations-export-share-fork-resume.md","ar/sessions/session-switching-and-recent-listing.md","ar/sessions/session-tree-plan.md","ar/sessions/session.md","ar/sessions/ttsr-injection-lifecycle.md","ar/tui/theme.md","ar/tui/tree.md","ar/tui/tui-runtime-internals.md","ar/tui/tui.md","de/configuration/blob-artifact-architecture.md","de/configuration/config-usage.md","de/configuration/environment-variables.md","de/configuration/fs-scan-cache-architecture.md","de/configuration/hooks.md","de/configuration/porting-from-pi-mono.md","de/configuration/rpc.md","de/configuration/sdk.md","de/configuration/secrets.md","de/extensions/extension-loading.md","de/extensions/extensions.md","de/extensions/gemini-manifest-extensions.md","de/extensions/marketplace.md","de/extensions/plugin-manager-installer-plumbing.md","de/extensions/rulebook-matching-pipeline.md","de/extensions/skills.md","de/index.md","de/mcp/mcp-config.md","de/mcp/mcp-protocol-transports.md","de/mcp/mcp-runtime-lifecycle.md","de/mcp/mcp-server-tool-authoring.md","de/natives/natives-addon-loader-runtime.md","de/natives/natives-architecture.md","de/natives/natives-binding-contract.md","de/natives/natives-build-release-debugging.md","de/natives/natives-media-system-utils.md","de/natives/natives-rust-task-cancellation.md","de/natives/natives-shell-pty-process.md","de/natives/natives-text-search-pipeline.md","de/natives/porting-to-natives.md","de/providers/models.md","de/providers/provider-streaming-internals.md","de/providers/python-repl.md","de/runtime-tools/bash-tool-runtime.md","de/runtime-tools/context-command.md","de/runtime-tools/custom-tools.md","de/runtime-tools/notebook-tool-runtime.md","de/runtime-tools/resolve-tool-runtime.md","de/runtime-tools/slash-command-internals.md","de/runtime-tools/task-agent-discovery.md","de/sessions/compaction.md","de/sessions/handoff-generation-pipeline.md","de/sessions/memory.md","de/sessions/non-compaction-retry-policy.md","de/sessions/session-operations-export-share-fork-resume.md","de/sessions/session-switching-and-recent-listing.md","de/sessions/session-tree-plan.md","de/sessions/session.md","de/sessions/ttsr-injection-lifecycle.md","de/tui/theme.md","de/tui/tree.md","de/tui/tui-runtime-internals.md","de/tui/tui.md","en/configuration/blob-artifact-architecture.md","en/configuration/config-usage.md","en/configuration/environment-variables.md","en/configuration/fs-scan-cache-architecture.md","en/configuration/hooks.md","en/configuration/porting-from-pi-mono.md","en/configuration/rpc.md","en/configuration/sdk.md","en/configuration/secrets.md","en/extensions/extension-loading.md","en/extensions/extensions.md","en/extensions/gemini-manifest-extensions.md","en/extensions/marketplace.md","en/extensions/plugin-manager-installer-plumbing.md","en/extensions/rulebook-matching-pipeline.md","en/extensions/skills.md","en/index.md","en/mcp/mcp-config.md","en/mcp/mcp-protocol-transports.md","en/mcp/mcp-runtime-lifecycle.md","en/mcp/mcp-server-tool-authoring.md","en/natives/natives-addon-loader-runtime.md","en/natives/natives-architecture.md","en/natives/natives-binding-contract.md","en/natives/natives-build-release-debugging.md","en/natives/natives-media-system-utils.md","en/natives/natives-rust-task-cancellation.md","en/natives/natives-shell-pty-process.md","en/natives/natives-text-search-pipeline.md","en/natives/porting-to-natives.md","en/providers/models.md","en/providers/provider-streaming-internals.md","en/providers/python-repl.md","en/runtime-tools/bash-tool-runtime.md","en/runtime-tools/context-command.md","en/runtime-tools/custom-tools.md","en/runtime-tools/notebook-tool-runtime.md","en/runtime-tools/resolve-tool-runtime.md","en/runtime-tools/slash-command-internals.md","en/runtime-tools/task-agent-discovery.md","en/sessions/compaction.md","en/sessions/handoff-generation-pipeline.md","en/sessions/memory.md","en/sessions/non-compaction-retry-policy.md","en/sessions/session-operations-export-share-fork-resume.md","en/sessions/session-switching-and-recent-listing.md","en/sessions/session-tree-plan.md","en/sessions/session.md","en/sessions/ttsr-injection-lifecycle.md","en/tui/theme.md","en/tui/tree.md","en/tui/tui-runtime-internals.md","en/tui/tui.md","es/configuration/blob-artifact-architecture.md","es/configuration/config-usage.md","es/configuration/environment-variables.md","es/configuration/fs-scan-cache-architecture.md","es/configuration/hooks.md","es/configuration/porting-from-pi-mono.md","es/configuration/rpc.md","es/configuration/sdk.md","es/configuration/secrets.md","es/extensions/extension-loading.md","es/extensions/extensions.md","es/extensions/gemini-manifest-extensions.md","es/extensions/marketplace.md","es/extensions/plugin-manager-installer-plumbing.md","es/extensions/rulebook-matching-pipeline.md","es/extensions/skills.md","es/index.md","es/mcp/mcp-config.md","es/mcp/mcp-protocol-transports.md","es/mcp/mcp-runtime-lifecycle.md","es/mcp/mcp-server-tool-authoring.md","es/natives/natives-addon-loader-runtime.md","es/natives/natives-architecture.md","es/natives/natives-binding-contract.md","es/natives/natives-build-release-debugging.md","es/natives/natives-media-system-utils.md","es/natives/natives-rust-task-cancellation.md","es/natives/natives-shell-pty-process.md","es/natives/natives-text-search-pipeline.md","es/natives/porting-to-natives.md","es/providers/models.md","es/providers/provider-streaming-internals.md","es/providers/python-repl.md","es/runtime-tools/bash-tool-runtime.md","es/runtime-tools/context-command.md","es/runtime-tools/custom-tools.md","es/runtime-tools/notebook-tool-runtime.md","es/runtime-tools/resolve-tool-runtime.md","es/runtime-tools/slash-command-internals.md","es/runtime-tools/task-agent-discovery.md","es/sessions/compaction.md","es/sessions/handoff-generation-pipeline.md","es/sessions/memory.md","es/sessions/non-compaction-retry-policy.md","es/sessions/session-operations-export-share-fork-resume.md","es/sessions/session-switching-and-recent-listing.md","es/sessions/session-tree-plan.md","es/sessions/session.md","es/sessions/ttsr-injection-lifecycle.md","es/tui/theme.md","es/tui/tree.md","es/tui/tui-runtime-internals.md","es/tui/tui.md","fr/configuration/blob-artifact-architecture.md","fr/configuration/config-usage.md","fr/configuration/environment-variables.md","fr/configuration/fs-scan-cache-architecture.md","fr/configuration/hooks.md","fr/configuration/porting-from-pi-mono.md","fr/configuration/rpc.md","fr/configuration/sdk.md","fr/configuration/secrets.md","fr/extensions/extension-loading.md","fr/extensions/extensions.md","fr/extensions/gemini-manifest-extensions.md","fr/extensions/marketplace.md","fr/extensions/plugin-manager-installer-plumbing.md","fr/extensions/rulebook-matching-pipeline.md","fr/extensions/skills.md","fr/index.md","fr/mcp/mcp-config.md","fr/mcp/mcp-protocol-transports.md","fr/mcp/mcp-runtime-lifecycle.md","fr/mcp/mcp-server-tool-authoring.md","fr/natives/natives-addon-loader-runtime.md","fr/natives/natives-architecture.md","fr/natives/natives-binding-contract.md","fr/natives/natives-build-release-debugging.md","fr/natives/natives-media-system-utils.md","fr/natives/natives-rust-task-cancellation.md","fr/natives/natives-shell-pty-process.md","fr/natives/natives-text-search-pipeline.md","fr/natives/porting-to-natives.md","fr/providers/models.md","fr/providers/provider-streaming-internals.md","fr/providers/python-repl.md","fr/runtime-tools/bash-tool-runtime.md","fr/runtime-tools/context-command.md","fr/runtime-tools/custom-tools.md","fr/runtime-tools/notebook-tool-runtime.md","fr/runtime-tools/resolve-tool-runtime.md","fr/runtime-tools/slash-command-internals.md","fr/runtime-tools/task-agent-discovery.md","fr/sessions/compaction.md","fr/sessions/handoff-generation-pipeline.md","fr/sessions/memory.md","fr/sessions/non-compaction-retry-policy.md","fr/sessions/session-operations-export-share-fork-resume.md","fr/sessions/session-switching-and-recent-listing.md","fr/sessions/session-tree-plan.md","fr/sessions/session.md","fr/sessions/ttsr-injection-lifecycle.md","fr/tui/theme.md","fr/tui/tree.md","fr/tui/tui-runtime-internals.md","fr/tui/tui.md","hi/configuration/blob-artifact-architecture.md","hi/configuration/config-usage.md","hi/configuration/environment-variables.md","hi/configuration/fs-scan-cache-architecture.md","hi/configuration/hooks.md","hi/configuration/porting-from-pi-mono.md","hi/configuration/rpc.md","hi/configuration/sdk.md","hi/configuration/secrets.md","hi/extensions/extension-loading.md","hi/extensions/extensions.md","hi/extensions/gemini-manifest-extensions.md","hi/extensions/marketplace.md","hi/extensions/plugin-manager-installer-plumbing.md","hi/extensions/rulebook-matching-pipeline.md","hi/extensions/skills.md","hi/index.md","hi/mcp/mcp-config.md","hi/mcp/mcp-protocol-transports.md","hi/mcp/mcp-runtime-lifecycle.md","hi/mcp/mcp-server-tool-authoring.md","hi/natives/natives-addon-loader-runtime.md","hi/natives/natives-architecture.md","hi/natives/natives-binding-contract.md","hi/natives/natives-build-release-debugging.md","hi/natives/natives-media-system-utils.md","hi/natives/natives-rust-task-cancellation.md","hi/natives/natives-shell-pty-process.md","hi/natives/natives-text-search-pipeline.md","hi/natives/porting-to-natives.md","hi/providers/models.md","hi/providers/provider-streaming-internals.md","hi/providers/python-repl.md","hi/runtime-tools/bash-tool-runtime.md","hi/runtime-tools/context-command.md","hi/runtime-tools/custom-tools.md","hi/runtime-tools/notebook-tool-runtime.md","hi/runtime-tools/resolve-tool-runtime.md","hi/runtime-tools/slash-command-internals.md","hi/runtime-tools/task-agent-discovery.md","hi/sessions/compaction.md","hi/sessions/handoff-generation-pipeline.md","hi/sessions/memory.md","hi/sessions/non-compaction-retry-policy.md","hi/sessions/session-operations-export-share-fork-resume.md","hi/sessions/session-switching-and-recent-listing.md","hi/sessions/session-tree-plan.md","hi/sessions/session.md","hi/sessions/ttsr-injection-lifecycle.md","hi/tui/theme.md","hi/tui/tree.md","hi/tui/tui-runtime-internals.md","hi/tui/tui.md","it/configuration/blob-artifact-architecture.md","it/configuration/config-usage.md","it/configuration/environment-variables.md","it/configuration/fs-scan-cache-architecture.md","it/configuration/hooks.md","it/configuration/porting-from-pi-mono.md","it/configuration/rpc.md","it/configuration/sdk.md","it/configuration/secrets.md","it/extensions/extension-loading.md","it/extensions/extensions.md","it/extensions/gemini-manifest-extensions.md","it/extensions/marketplace.md","it/extensions/plugin-manager-installer-plumbing.md","it/extensions/rulebook-matching-pipeline.md","it/extensions/skills.md","it/index.md","it/mcp/mcp-config.md","it/mcp/mcp-protocol-transports.md","it/mcp/mcp-runtime-lifecycle.md","it/mcp/mcp-server-tool-authoring.md","it/natives/natives-addon-loader-runtime.md","it/natives/natives-architecture.md","it/natives/natives-binding-contract.md","it/natives/natives-build-release-debugging.md","it/natives/natives-media-system-utils.md","it/natives/natives-rust-task-cancellation.md","it/natives/natives-shell-pty-process.md","it/natives/natives-text-search-pipeline.md","it/natives/porting-to-natives.md","it/providers/models.md","it/providers/provider-streaming-internals.md","it/providers/python-repl.md","it/runtime-tools/bash-tool-runtime.md","it/runtime-tools/context-command.md","it/runtime-tools/custom-tools.md","it/runtime-tools/notebook-tool-runtime.md","it/runtime-tools/resolve-tool-runtime.md","it/runtime-tools/slash-command-internals.md","it/runtime-tools/task-agent-discovery.md","it/sessions/compaction.md","it/sessions/handoff-generation-pipeline.md","it/sessions/memory.md","it/sessions/non-compaction-retry-policy.md","it/sessions/session-operations-export-share-fork-resume.md","it/sessions/session-switching-and-recent-listing.md","it/sessions/session-tree-plan.md","it/sessions/session.md","it/sessions/ttsr-injection-lifecycle.md","it/tui/theme.md","it/tui/tree.md","it/tui/tui-runtime-internals.md","it/tui/tui.md","ja/configuration/blob-artifact-architecture.md","ja/configuration/config-usage.md","ja/configuration/environment-variables.md","ja/configuration/fs-scan-cache-architecture.md","ja/configuration/hooks.md","ja/configuration/porting-from-pi-mono.md","ja/configuration/rpc.md","ja/configuration/sdk.md","ja/configuration/secrets.md","ja/extensions/extension-loading.md","ja/extensions/extensions.md","ja/extensions/gemini-manifest-extensions.md","ja/extensions/marketplace.md","ja/extensions/plugin-manager-installer-plumbing.md","ja/extensions/rulebook-matching-pipeline.md","ja/extensions/skills.md","ja/index.md","ja/mcp/mcp-config.md","ja/mcp/mcp-protocol-transports.md","ja/mcp/mcp-runtime-lifecycle.md","ja/mcp/mcp-server-tool-authoring.md","ja/natives/natives-addon-loader-runtime.md","ja/natives/natives-architecture.md","ja/natives/natives-binding-contract.md","ja/natives/natives-build-release-debugging.md","ja/natives/natives-media-system-utils.md","ja/natives/natives-rust-task-cancellation.md","ja/natives/natives-shell-pty-process.md","ja/natives/natives-text-search-pipeline.md","ja/natives/porting-to-natives.md","ja/providers/models.md","ja/providers/provider-streaming-internals.md","ja/providers/python-repl.md","ja/runtime-tools/bash-tool-runtime.md","ja/runtime-tools/context-command.md","ja/runtime-tools/custom-tools.md","ja/runtime-tools/notebook-tool-runtime.md","ja/runtime-tools/resolve-tool-runtime.md","ja/runtime-tools/slash-command-internals.md","ja/runtime-tools/task-agent-discovery.md","ja/sessions/compaction.md","ja/sessions/handoff-generation-pipeline.md","ja/sessions/memory.md","ja/sessions/non-compaction-retry-policy.md","ja/sessions/session-operations-export-share-fork-resume.md","ja/sessions/session-switching-and-recent-listing.md","ja/sessions/session-tree-plan.md","ja/sessions/session.md","ja/sessions/ttsr-injection-lifecycle.md","ja/tui/theme.md","ja/tui/tree.md","ja/tui/tui-runtime-internals.md","ja/tui/tui.md","ko/configuration/blob-artifact-architecture.md","ko/configuration/config-usage.md","ko/configuration/environment-variables.md","ko/configuration/fs-scan-cache-architecture.md","ko/configuration/hooks.md","ko/configuration/porting-from-pi-mono.md","ko/configuration/rpc.md","ko/configuration/sdk.md","ko/configuration/secrets.md","ko/extensions/extension-loading.md","ko/extensions/extensions.md","ko/extensions/gemini-manifest-extensions.md","ko/extensions/marketplace.md","ko/extensions/plugin-manager-installer-plumbing.md","ko/extensions/rulebook-matching-pipeline.md","ko/extensions/skills.md","ko/index.md","ko/mcp/mcp-config.md","ko/mcp/mcp-protocol-transports.md","ko/mcp/mcp-runtime-lifecycle.md","ko/mcp/mcp-server-tool-authoring.md","ko/natives/natives-addon-loader-runtime.md","ko/natives/natives-architecture.md","ko/natives/natives-binding-contract.md","ko/natives/natives-build-release-debugging.md","ko/natives/natives-media-system-utils.md","ko/natives/natives-rust-task-cancellation.md","ko/natives/natives-shell-pty-process.md","ko/natives/natives-text-search-pipeline.md","ko/natives/porting-to-natives.md","ko/providers/models.md","ko/providers/provider-streaming-internals.md","ko/providers/python-repl.md","ko/runtime-tools/bash-tool-runtime.md","ko/runtime-tools/context-command.md","ko/runtime-tools/custom-tools.md","ko/runtime-tools/notebook-tool-runtime.md","ko/runtime-tools/resolve-tool-runtime.md","ko/runtime-tools/slash-command-internals.md","ko/runtime-tools/task-agent-discovery.md","ko/sessions/compaction.md","ko/sessions/handoff-generation-pipeline.md","ko/sessions/memory.md","ko/sessions/non-compaction-retry-policy.md","ko/sessions/session-operations-export-share-fork-resume.md","ko/sessions/session-switching-and-recent-listing.md","ko/sessions/session-tree-plan.md","ko/sessions/session.md","ko/sessions/ttsr-injection-lifecycle.md","ko/tui/theme.md","ko/tui/tree.md","ko/tui/tui-runtime-internals.md","ko/tui/tui.md","plans/provider-agnostic-dynamic-model-routing.md","pt-br/configuration/blob-artifact-architecture.md","pt-br/configuration/config-usage.md","pt-br/configuration/environment-variables.md","pt-br/configuration/fs-scan-cache-architecture.md","pt-br/configuration/hooks.md","pt-br/configuration/porting-from-pi-mono.md","pt-br/configuration/rpc.md","pt-br/configuration/sdk.md","pt-br/configuration/secrets.md","pt-br/extensions/extension-loading.md","pt-br/extensions/extensions.md","pt-br/extensions/gemini-manifest-extensions.md","pt-br/extensions/marketplace.md","pt-br/extensions/plugin-manager-installer-plumbing.md","pt-br/extensions/rulebook-matching-pipeline.md","pt-br/extensions/skills.md","pt-br/index.md","pt-br/mcp/mcp-config.md","pt-br/mcp/mcp-protocol-transports.md","pt-br/mcp/mcp-runtime-lifecycle.md","pt-br/mcp/mcp-server-tool-authoring.md","pt-br/natives/natives-addon-loader-runtime.md","pt-br/natives/natives-architecture.md","pt-br/natives/natives-binding-contract.md","pt-br/natives/natives-build-release-debugging.md","pt-br/natives/natives-media-system-utils.md","pt-br/natives/natives-rust-task-cancellation.md","pt-br/natives/natives-shell-pty-process.md","pt-br/natives/natives-text-search-pipeline.md","pt-br/natives/porting-to-natives.md","pt-br/providers/models.md","pt-br/providers/provider-streaming-internals.md","pt-br/providers/python-repl.md","pt-br/runtime-tools/bash-tool-runtime.md","pt-br/runtime-tools/context-command.md","pt-br/runtime-tools/custom-tools.md","pt-br/runtime-tools/notebook-tool-runtime.md","pt-br/runtime-tools/resolve-tool-runtime.md","pt-br/runtime-tools/slash-command-internals.md","pt-br/runtime-tools/task-agent-discovery.md","pt-br/sessions/compaction.md","pt-br/sessions/handoff-generation-pipeline.md","pt-br/sessions/memory.md","pt-br/sessions/non-compaction-retry-policy.md","pt-br/sessions/session-operations-export-share-fork-resume.md","pt-br/sessions/session-switching-and-recent-listing.md","pt-br/sessions/session-tree-plan.md","pt-br/sessions/session.md","pt-br/sessions/ttsr-injection-lifecycle.md","pt-br/tui/theme.md","pt-br/tui/tree.md","pt-br/tui/tui-runtime-internals.md","pt-br/tui/tui.md","th/configuration/blob-artifact-architecture.md","th/configuration/config-usage.md","th/configuration/environment-variables.md","th/configuration/fs-scan-cache-architecture.md","th/configuration/hooks.md","th/configuration/porting-from-pi-mono.md","th/configuration/rpc.md","th/configuration/sdk.md","th/configuration/secrets.md","th/extensions/extension-loading.md","th/extensions/extensions.md","th/extensions/gemini-manifest-extensions.md","th/extensions/marketplace.md","th/extensions/plugin-manager-installer-plumbing.md","th/extensions/rulebook-matching-pipeline.md","th/extensions/skills.md","th/index.md","th/mcp/mcp-config.md","th/mcp/mcp-protocol-transports.md","th/mcp/mcp-runtime-lifecycle.md","th/mcp/mcp-server-tool-authoring.md","th/natives/natives-addon-loader-runtime.md","th/natives/natives-architecture.md","th/natives/natives-binding-contract.md","th/natives/natives-build-release-debugging.md","th/natives/natives-media-system-utils.md","th/natives/natives-rust-task-cancellation.md","th/natives/natives-shell-pty-process.md","th/natives/natives-text-search-pipeline.md","th/natives/porting-to-natives.md","th/providers/models.md","th/providers/provider-streaming-internals.md","th/providers/python-repl.md","th/runtime-tools/bash-tool-runtime.md","th/runtime-tools/context-command.md","th/runtime-tools/custom-tools.md","th/runtime-tools/notebook-tool-runtime.md","th/runtime-tools/resolve-tool-runtime.md","th/runtime-tools/slash-command-internals.md","th/runtime-tools/task-agent-discovery.md","th/sessions/compaction.md","th/sessions/handoff-generation-pipeline.md","th/sessions/memory.md","th/sessions/non-compaction-retry-policy.md","th/sessions/session-operations-export-share-fork-resume.md","th/sessions/session-switching-and-recent-listing.md","th/sessions/session-tree-plan.md","th/sessions/session.md","th/sessions/ttsr-injection-lifecycle.md","th/tui/theme.md","th/tui/tree.md","th/tui/tui-runtime-internals.md","th/tui/tui.md","zh-cn/configuration/blob-artifact-architecture.md","zh-cn/configuration/config-usage.md","zh-cn/configuration/environment-variables.md","zh-cn/configuration/fs-scan-cache-architecture.md","zh-cn/configuration/hooks.md","zh-cn/configuration/porting-from-pi-mono.md","zh-cn/configuration/rpc.md","zh-cn/configuration/sdk.md","zh-cn/configuration/secrets.md","zh-cn/extensions/extension-loading.md","zh-cn/extensions/extensions.md","zh-cn/extensions/gemini-manifest-extensions.md","zh-cn/extensions/marketplace.md","zh-cn/extensions/plugin-manager-installer-plumbing.md","zh-cn/extensions/rulebook-matching-pipeline.md","zh-cn/extensions/skills.md","zh-cn/index.md","zh-cn/mcp/mcp-config.md","zh-cn/mcp/mcp-protocol-transports.md","zh-cn/mcp/mcp-runtime-lifecycle.md","zh-cn/mcp/mcp-server-tool-authoring.md","zh-cn/natives/natives-addon-loader-runtime.md","zh-cn/natives/natives-architecture.md","zh-cn/natives/natives-binding-contract.md","zh-cn/natives/natives-build-release-debugging.md","zh-cn/natives/natives-media-system-utils.md","zh-cn/natives/natives-rust-task-cancellation.md","zh-cn/natives/natives-shell-pty-process.md","zh-cn/natives/natives-text-search-pipeline.md","zh-cn/natives/porting-to-natives.md","zh-cn/providers/models.md","zh-cn/providers/provider-streaming-internals.md","zh-cn/providers/python-repl.md","zh-cn/runtime-tools/bash-tool-runtime.md","zh-cn/runtime-tools/context-command.md","zh-cn/runtime-tools/custom-tools.md","zh-cn/runtime-tools/notebook-tool-runtime.md","zh-cn/runtime-tools/resolve-tool-runtime.md","zh-cn/runtime-tools/slash-command-internals.md","zh-cn/runtime-tools/task-agent-discovery.md","zh-cn/sessions/compaction.md","zh-cn/sessions/handoff-generation-pipeline.md","zh-cn/sessions/memory.md","zh-cn/sessions/non-compaction-retry-policy.md","zh-cn/sessions/session-operations-export-share-fork-resume.md","zh-cn/sessions/session-switching-and-recent-listing.md","zh-cn/sessions/session-tree-plan.md","zh-cn/sessions/session.md","zh-cn/sessions/ttsr-injection-lifecycle.md","zh-cn/tui/theme.md","zh-cn/tui/tree.md","zh-cn/tui/tui-runtime-internals.md","zh-cn/tui/tui.md","zh-tw/configuration/blob-artifact-architecture.md","zh-tw/configuration/config-usage.md","zh-tw/configuration/environment-variables.md","zh-tw/configuration/fs-scan-cache-architecture.md","zh-tw/configuration/hooks.md","zh-tw/configuration/porting-from-pi-mono.md","zh-tw/configuration/rpc.md","zh-tw/configuration/sdk.md","zh-tw/configuration/secrets.md","zh-tw/extensions/extension-loading.md","zh-tw/extensions/extensions.md","zh-tw/extensions/gemini-manifest-extensions.md","zh-tw/extensions/marketplace.md","zh-tw/extensions/plugin-manager-installer-plumbing.md","zh-tw/extensions/rulebook-matching-pipeline.md","zh-tw/extensions/skills.md","zh-tw/index.md","zh-tw/mcp/mcp-config.md","zh-tw/mcp/mcp-protocol-transports.md","zh-tw/mcp/mcp-runtime-lifecycle.md","zh-tw/mcp/mcp-server-tool-authoring.md","zh-tw/natives/natives-addon-loader-runtime.md","zh-tw/natives/natives-architecture.md","zh-tw/natives/natives-binding-contract.md","zh-tw/natives/natives-build-release-debugging.md","zh-tw/natives/natives-media-system-utils.md","zh-tw/natives/natives-rust-task-cancellation.md","zh-tw/natives/natives-shell-pty-process.md","zh-tw/natives/natives-text-search-pipeline.md","zh-tw/natives/porting-to-natives.md","zh-tw/providers/models.md","zh-tw/providers/provider-streaming-internals.md","zh-tw/providers/python-repl.md","zh-tw/runtime-tools/bash-tool-runtime.md","zh-tw/runtime-tools/context-command.md","zh-tw/runtime-tools/custom-tools.md","zh-tw/runtime-tools/notebook-tool-runtime.md","zh-tw/runtime-tools/resolve-tool-runtime.md","zh-tw/runtime-tools/slash-command-internals.md","zh-tw/runtime-tools/task-agent-discovery.md","zh-tw/sessions/compaction.md","zh-tw/sessions/handoff-generation-pipeline.md","zh-tw/sessions/memory.md","zh-tw/sessions/non-compaction-retry-policy.md","zh-tw/sessions/session-operations-export-share-fork-resume.md","zh-tw/sessions/session-switching-and-recent-listing.md","zh-tw/sessions/session-tree-plan.md","zh-tw/sessions/session.md","zh-tw/sessions/ttsr-injection-lifecycle.md","zh-tw/tui/theme.md","zh-tw/tui/tree.md","zh-tw/tui/tui-runtime-internals.md","zh-tw/tui/tui.md"];
|
|
3
|
+
export const EMBEDDED_DOC_FILENAMES: readonly string[] = ["SYSTEM_PROMPT_GUIDE.md","ar/configuration/blob-artifact-architecture.md","ar/configuration/config-usage.md","ar/configuration/environment-variables.md","ar/configuration/fs-scan-cache-architecture.md","ar/configuration/hooks.md","ar/configuration/porting-from-pi-mono.md","ar/configuration/rpc.md","ar/configuration/sdk.md","ar/configuration/secrets.md","ar/extensions/extension-loading.md","ar/extensions/extensions.md","ar/extensions/gemini-manifest-extensions.md","ar/extensions/marketplace.md","ar/extensions/plugin-manager-installer-plumbing.md","ar/extensions/rulebook-matching-pipeline.md","ar/extensions/skills.md","ar/index.md","ar/mcp/mcp-config.md","ar/mcp/mcp-protocol-transports.md","ar/mcp/mcp-runtime-lifecycle.md","ar/mcp/mcp-server-tool-authoring.md","ar/natives/natives-addon-loader-runtime.md","ar/natives/natives-architecture.md","ar/natives/natives-binding-contract.md","ar/natives/natives-build-release-debugging.md","ar/natives/natives-media-system-utils.md","ar/natives/natives-rust-task-cancellation.md","ar/natives/natives-shell-pty-process.md","ar/natives/natives-text-search-pipeline.md","ar/natives/porting-to-natives.md","ar/providers/models.md","ar/providers/provider-streaming-internals.md","ar/providers/python-repl.md","ar/runtime-tools/bash-tool-runtime.md","ar/runtime-tools/context-command.md","ar/runtime-tools/custom-tools.md","ar/runtime-tools/notebook-tool-runtime.md","ar/runtime-tools/resolve-tool-runtime.md","ar/runtime-tools/slash-command-internals.md","ar/runtime-tools/task-agent-discovery.md","ar/sessions/compaction.md","ar/sessions/handoff-generation-pipeline.md","ar/sessions/memory.md","ar/sessions/non-compaction-retry-policy.md","ar/sessions/session-operations-export-share-fork-resume.md","ar/sessions/session-switching-and-recent-listing.md","ar/sessions/session-tree-plan.md","ar/sessions/session.md","ar/sessions/ttsr-injection-lifecycle.md","ar/tui/theme.md","ar/tui/tree.md","ar/tui/tui-runtime-internals.md","ar/tui/tui.md","de/configuration/blob-artifact-architecture.md","de/configuration/config-usage.md","de/configuration/environment-variables.md","de/configuration/fs-scan-cache-architecture.md","de/configuration/hooks.md","de/configuration/porting-from-pi-mono.md","de/configuration/rpc.md","de/configuration/sdk.md","de/configuration/secrets.md","de/extensions/extension-loading.md","de/extensions/extensions.md","de/extensions/gemini-manifest-extensions.md","de/extensions/marketplace.md","de/extensions/plugin-manager-installer-plumbing.md","de/extensions/rulebook-matching-pipeline.md","de/extensions/skills.md","de/index.md","de/mcp/mcp-config.md","de/mcp/mcp-protocol-transports.md","de/mcp/mcp-runtime-lifecycle.md","de/mcp/mcp-server-tool-authoring.md","de/natives/natives-addon-loader-runtime.md","de/natives/natives-architecture.md","de/natives/natives-binding-contract.md","de/natives/natives-build-release-debugging.md","de/natives/natives-media-system-utils.md","de/natives/natives-rust-task-cancellation.md","de/natives/natives-shell-pty-process.md","de/natives/natives-text-search-pipeline.md","de/natives/porting-to-natives.md","de/providers/models.md","de/providers/provider-streaming-internals.md","de/providers/python-repl.md","de/runtime-tools/bash-tool-runtime.md","de/runtime-tools/context-command.md","de/runtime-tools/custom-tools.md","de/runtime-tools/notebook-tool-runtime.md","de/runtime-tools/resolve-tool-runtime.md","de/runtime-tools/slash-command-internals.md","de/runtime-tools/task-agent-discovery.md","de/sessions/compaction.md","de/sessions/handoff-generation-pipeline.md","de/sessions/memory.md","de/sessions/non-compaction-retry-policy.md","de/sessions/session-operations-export-share-fork-resume.md","de/sessions/session-switching-and-recent-listing.md","de/sessions/session-tree-plan.md","de/sessions/session.md","de/sessions/ttsr-injection-lifecycle.md","de/tui/theme.md","de/tui/tree.md","de/tui/tui-runtime-internals.md","de/tui/tui.md","en/configuration/blob-artifact-architecture.md","en/configuration/config-usage.md","en/configuration/environment-variables.md","en/configuration/fs-scan-cache-architecture.md","en/configuration/hooks.md","en/configuration/porting-from-pi-mono.md","en/configuration/rpc.md","en/configuration/sdk.md","en/configuration/secrets.md","en/container/alpine-deployment.md","en/extensions/extension-loading.md","en/extensions/extensions.md","en/extensions/gemini-manifest-extensions.md","en/extensions/marketplace.md","en/extensions/plugin-manager-installer-plumbing.md","en/extensions/rulebook-matching-pipeline.md","en/extensions/skills.md","en/index.md","en/mcp/mcp-config.md","en/mcp/mcp-protocol-transports.md","en/mcp/mcp-runtime-lifecycle.md","en/mcp/mcp-server-tool-authoring.md","en/natives/natives-addon-loader-runtime.md","en/natives/natives-architecture.md","en/natives/natives-binding-contract.md","en/natives/natives-build-release-debugging.md","en/natives/natives-media-system-utils.md","en/natives/natives-rust-task-cancellation.md","en/natives/natives-shell-pty-process.md","en/natives/natives-text-search-pipeline.md","en/natives/porting-to-natives.md","en/providers/models.md","en/providers/provider-streaming-internals.md","en/providers/python-repl.md","en/runtime-tools/bash-tool-runtime.md","en/runtime-tools/context-command.md","en/runtime-tools/custom-tools.md","en/runtime-tools/notebook-tool-runtime.md","en/runtime-tools/resolve-tool-runtime.md","en/runtime-tools/slash-command-internals.md","en/runtime-tools/task-agent-discovery.md","en/sessions/compaction.md","en/sessions/handoff-generation-pipeline.md","en/sessions/memory.md","en/sessions/non-compaction-retry-policy.md","en/sessions/session-operations-export-share-fork-resume.md","en/sessions/session-switching-and-recent-listing.md","en/sessions/session-tree-plan.md","en/sessions/session.md","en/sessions/ttsr-injection-lifecycle.md","en/tui/theme.md","en/tui/tree.md","en/tui/tui-runtime-internals.md","en/tui/tui.md","es/configuration/blob-artifact-architecture.md","es/configuration/config-usage.md","es/configuration/environment-variables.md","es/configuration/fs-scan-cache-architecture.md","es/configuration/hooks.md","es/configuration/porting-from-pi-mono.md","es/configuration/rpc.md","es/configuration/sdk.md","es/configuration/secrets.md","es/extensions/extension-loading.md","es/extensions/extensions.md","es/extensions/gemini-manifest-extensions.md","es/extensions/marketplace.md","es/extensions/plugin-manager-installer-plumbing.md","es/extensions/rulebook-matching-pipeline.md","es/extensions/skills.md","es/index.md","es/mcp/mcp-config.md","es/mcp/mcp-protocol-transports.md","es/mcp/mcp-runtime-lifecycle.md","es/mcp/mcp-server-tool-authoring.md","es/natives/natives-addon-loader-runtime.md","es/natives/natives-architecture.md","es/natives/natives-binding-contract.md","es/natives/natives-build-release-debugging.md","es/natives/natives-media-system-utils.md","es/natives/natives-rust-task-cancellation.md","es/natives/natives-shell-pty-process.md","es/natives/natives-text-search-pipeline.md","es/natives/porting-to-natives.md","es/providers/models.md","es/providers/provider-streaming-internals.md","es/providers/python-repl.md","es/runtime-tools/bash-tool-runtime.md","es/runtime-tools/context-command.md","es/runtime-tools/custom-tools.md","es/runtime-tools/notebook-tool-runtime.md","es/runtime-tools/resolve-tool-runtime.md","es/runtime-tools/slash-command-internals.md","es/runtime-tools/task-agent-discovery.md","es/sessions/compaction.md","es/sessions/handoff-generation-pipeline.md","es/sessions/memory.md","es/sessions/non-compaction-retry-policy.md","es/sessions/session-operations-export-share-fork-resume.md","es/sessions/session-switching-and-recent-listing.md","es/sessions/session-tree-plan.md","es/sessions/session.md","es/sessions/ttsr-injection-lifecycle.md","es/tui/theme.md","es/tui/tree.md","es/tui/tui-runtime-internals.md","es/tui/tui.md","fr/configuration/blob-artifact-architecture.md","fr/configuration/config-usage.md","fr/configuration/environment-variables.md","fr/configuration/fs-scan-cache-architecture.md","fr/configuration/hooks.md","fr/configuration/porting-from-pi-mono.md","fr/configuration/rpc.md","fr/configuration/sdk.md","fr/configuration/secrets.md","fr/extensions/extension-loading.md","fr/extensions/extensions.md","fr/extensions/gemini-manifest-extensions.md","fr/extensions/marketplace.md","fr/extensions/plugin-manager-installer-plumbing.md","fr/extensions/rulebook-matching-pipeline.md","fr/extensions/skills.md","fr/index.md","fr/mcp/mcp-config.md","fr/mcp/mcp-protocol-transports.md","fr/mcp/mcp-runtime-lifecycle.md","fr/mcp/mcp-server-tool-authoring.md","fr/natives/natives-addon-loader-runtime.md","fr/natives/natives-architecture.md","fr/natives/natives-binding-contract.md","fr/natives/natives-build-release-debugging.md","fr/natives/natives-media-system-utils.md","fr/natives/natives-rust-task-cancellation.md","fr/natives/natives-shell-pty-process.md","fr/natives/natives-text-search-pipeline.md","fr/natives/porting-to-natives.md","fr/providers/models.md","fr/providers/provider-streaming-internals.md","fr/providers/python-repl.md","fr/runtime-tools/bash-tool-runtime.md","fr/runtime-tools/context-command.md","fr/runtime-tools/custom-tools.md","fr/runtime-tools/notebook-tool-runtime.md","fr/runtime-tools/resolve-tool-runtime.md","fr/runtime-tools/slash-command-internals.md","fr/runtime-tools/task-agent-discovery.md","fr/sessions/compaction.md","fr/sessions/handoff-generation-pipeline.md","fr/sessions/memory.md","fr/sessions/non-compaction-retry-policy.md","fr/sessions/session-operations-export-share-fork-resume.md","fr/sessions/session-switching-and-recent-listing.md","fr/sessions/session-tree-plan.md","fr/sessions/session.md","fr/sessions/ttsr-injection-lifecycle.md","fr/tui/theme.md","fr/tui/tree.md","fr/tui/tui-runtime-internals.md","fr/tui/tui.md","hi/configuration/blob-artifact-architecture.md","hi/configuration/config-usage.md","hi/configuration/environment-variables.md","hi/configuration/fs-scan-cache-architecture.md","hi/configuration/hooks.md","hi/configuration/porting-from-pi-mono.md","hi/configuration/rpc.md","hi/configuration/sdk.md","hi/configuration/secrets.md","hi/extensions/extension-loading.md","hi/extensions/extensions.md","hi/extensions/gemini-manifest-extensions.md","hi/extensions/marketplace.md","hi/extensions/plugin-manager-installer-plumbing.md","hi/extensions/rulebook-matching-pipeline.md","hi/extensions/skills.md","hi/index.md","hi/mcp/mcp-config.md","hi/mcp/mcp-protocol-transports.md","hi/mcp/mcp-runtime-lifecycle.md","hi/mcp/mcp-server-tool-authoring.md","hi/natives/natives-addon-loader-runtime.md","hi/natives/natives-architecture.md","hi/natives/natives-binding-contract.md","hi/natives/natives-build-release-debugging.md","hi/natives/natives-media-system-utils.md","hi/natives/natives-rust-task-cancellation.md","hi/natives/natives-shell-pty-process.md","hi/natives/natives-text-search-pipeline.md","hi/natives/porting-to-natives.md","hi/providers/models.md","hi/providers/provider-streaming-internals.md","hi/providers/python-repl.md","hi/runtime-tools/bash-tool-runtime.md","hi/runtime-tools/context-command.md","hi/runtime-tools/custom-tools.md","hi/runtime-tools/notebook-tool-runtime.md","hi/runtime-tools/resolve-tool-runtime.md","hi/runtime-tools/slash-command-internals.md","hi/runtime-tools/task-agent-discovery.md","hi/sessions/compaction.md","hi/sessions/handoff-generation-pipeline.md","hi/sessions/memory.md","hi/sessions/non-compaction-retry-policy.md","hi/sessions/session-operations-export-share-fork-resume.md","hi/sessions/session-switching-and-recent-listing.md","hi/sessions/session-tree-plan.md","hi/sessions/session.md","hi/sessions/ttsr-injection-lifecycle.md","hi/tui/theme.md","hi/tui/tree.md","hi/tui/tui-runtime-internals.md","hi/tui/tui.md","it/configuration/blob-artifact-architecture.md","it/configuration/config-usage.md","it/configuration/environment-variables.md","it/configuration/fs-scan-cache-architecture.md","it/configuration/hooks.md","it/configuration/porting-from-pi-mono.md","it/configuration/rpc.md","it/configuration/sdk.md","it/configuration/secrets.md","it/extensions/extension-loading.md","it/extensions/extensions.md","it/extensions/gemini-manifest-extensions.md","it/extensions/marketplace.md","it/extensions/plugin-manager-installer-plumbing.md","it/extensions/rulebook-matching-pipeline.md","it/extensions/skills.md","it/index.md","it/mcp/mcp-config.md","it/mcp/mcp-protocol-transports.md","it/mcp/mcp-runtime-lifecycle.md","it/mcp/mcp-server-tool-authoring.md","it/natives/natives-addon-loader-runtime.md","it/natives/natives-architecture.md","it/natives/natives-binding-contract.md","it/natives/natives-build-release-debugging.md","it/natives/natives-media-system-utils.md","it/natives/natives-rust-task-cancellation.md","it/natives/natives-shell-pty-process.md","it/natives/natives-text-search-pipeline.md","it/natives/porting-to-natives.md","it/providers/models.md","it/providers/provider-streaming-internals.md","it/providers/python-repl.md","it/runtime-tools/bash-tool-runtime.md","it/runtime-tools/context-command.md","it/runtime-tools/custom-tools.md","it/runtime-tools/notebook-tool-runtime.md","it/runtime-tools/resolve-tool-runtime.md","it/runtime-tools/slash-command-internals.md","it/runtime-tools/task-agent-discovery.md","it/sessions/compaction.md","it/sessions/handoff-generation-pipeline.md","it/sessions/memory.md","it/sessions/non-compaction-retry-policy.md","it/sessions/session-operations-export-share-fork-resume.md","it/sessions/session-switching-and-recent-listing.md","it/sessions/session-tree-plan.md","it/sessions/session.md","it/sessions/ttsr-injection-lifecycle.md","it/tui/theme.md","it/tui/tree.md","it/tui/tui-runtime-internals.md","it/tui/tui.md","ja/configuration/blob-artifact-architecture.md","ja/configuration/config-usage.md","ja/configuration/environment-variables.md","ja/configuration/fs-scan-cache-architecture.md","ja/configuration/hooks.md","ja/configuration/porting-from-pi-mono.md","ja/configuration/rpc.md","ja/configuration/sdk.md","ja/configuration/secrets.md","ja/extensions/extension-loading.md","ja/extensions/extensions.md","ja/extensions/gemini-manifest-extensions.md","ja/extensions/marketplace.md","ja/extensions/plugin-manager-installer-plumbing.md","ja/extensions/rulebook-matching-pipeline.md","ja/extensions/skills.md","ja/index.md","ja/mcp/mcp-config.md","ja/mcp/mcp-protocol-transports.md","ja/mcp/mcp-runtime-lifecycle.md","ja/mcp/mcp-server-tool-authoring.md","ja/natives/natives-addon-loader-runtime.md","ja/natives/natives-architecture.md","ja/natives/natives-binding-contract.md","ja/natives/natives-build-release-debugging.md","ja/natives/natives-media-system-utils.md","ja/natives/natives-rust-task-cancellation.md","ja/natives/natives-shell-pty-process.md","ja/natives/natives-text-search-pipeline.md","ja/natives/porting-to-natives.md","ja/providers/models.md","ja/providers/provider-streaming-internals.md","ja/providers/python-repl.md","ja/runtime-tools/bash-tool-runtime.md","ja/runtime-tools/context-command.md","ja/runtime-tools/custom-tools.md","ja/runtime-tools/notebook-tool-runtime.md","ja/runtime-tools/resolve-tool-runtime.md","ja/runtime-tools/slash-command-internals.md","ja/runtime-tools/task-agent-discovery.md","ja/sessions/compaction.md","ja/sessions/handoff-generation-pipeline.md","ja/sessions/memory.md","ja/sessions/non-compaction-retry-policy.md","ja/sessions/session-operations-export-share-fork-resume.md","ja/sessions/session-switching-and-recent-listing.md","ja/sessions/session-tree-plan.md","ja/sessions/session.md","ja/sessions/ttsr-injection-lifecycle.md","ja/tui/theme.md","ja/tui/tree.md","ja/tui/tui-runtime-internals.md","ja/tui/tui.md","ko/configuration/blob-artifact-architecture.md","ko/configuration/config-usage.md","ko/configuration/environment-variables.md","ko/configuration/fs-scan-cache-architecture.md","ko/configuration/hooks.md","ko/configuration/porting-from-pi-mono.md","ko/configuration/rpc.md","ko/configuration/sdk.md","ko/configuration/secrets.md","ko/extensions/extension-loading.md","ko/extensions/extensions.md","ko/extensions/gemini-manifest-extensions.md","ko/extensions/marketplace.md","ko/extensions/plugin-manager-installer-plumbing.md","ko/extensions/rulebook-matching-pipeline.md","ko/extensions/skills.md","ko/index.md","ko/mcp/mcp-config.md","ko/mcp/mcp-protocol-transports.md","ko/mcp/mcp-runtime-lifecycle.md","ko/mcp/mcp-server-tool-authoring.md","ko/natives/natives-addon-loader-runtime.md","ko/natives/natives-architecture.md","ko/natives/natives-binding-contract.md","ko/natives/natives-build-release-debugging.md","ko/natives/natives-media-system-utils.md","ko/natives/natives-rust-task-cancellation.md","ko/natives/natives-shell-pty-process.md","ko/natives/natives-text-search-pipeline.md","ko/natives/porting-to-natives.md","ko/providers/models.md","ko/providers/provider-streaming-internals.md","ko/providers/python-repl.md","ko/runtime-tools/bash-tool-runtime.md","ko/runtime-tools/context-command.md","ko/runtime-tools/custom-tools.md","ko/runtime-tools/notebook-tool-runtime.md","ko/runtime-tools/resolve-tool-runtime.md","ko/runtime-tools/slash-command-internals.md","ko/runtime-tools/task-agent-discovery.md","ko/sessions/compaction.md","ko/sessions/handoff-generation-pipeline.md","ko/sessions/memory.md","ko/sessions/non-compaction-retry-policy.md","ko/sessions/session-operations-export-share-fork-resume.md","ko/sessions/session-switching-and-recent-listing.md","ko/sessions/session-tree-plan.md","ko/sessions/session.md","ko/sessions/ttsr-injection-lifecycle.md","ko/tui/theme.md","ko/tui/tree.md","ko/tui/tui-runtime-internals.md","ko/tui/tui.md","plans/provider-agnostic-dynamic-model-routing.md","pt-br/configuration/blob-artifact-architecture.md","pt-br/configuration/config-usage.md","pt-br/configuration/environment-variables.md","pt-br/configuration/fs-scan-cache-architecture.md","pt-br/configuration/hooks.md","pt-br/configuration/porting-from-pi-mono.md","pt-br/configuration/rpc.md","pt-br/configuration/sdk.md","pt-br/configuration/secrets.md","pt-br/extensions/extension-loading.md","pt-br/extensions/extensions.md","pt-br/extensions/gemini-manifest-extensions.md","pt-br/extensions/marketplace.md","pt-br/extensions/plugin-manager-installer-plumbing.md","pt-br/extensions/rulebook-matching-pipeline.md","pt-br/extensions/skills.md","pt-br/index.md","pt-br/mcp/mcp-config.md","pt-br/mcp/mcp-protocol-transports.md","pt-br/mcp/mcp-runtime-lifecycle.md","pt-br/mcp/mcp-server-tool-authoring.md","pt-br/natives/natives-addon-loader-runtime.md","pt-br/natives/natives-architecture.md","pt-br/natives/natives-binding-contract.md","pt-br/natives/natives-build-release-debugging.md","pt-br/natives/natives-media-system-utils.md","pt-br/natives/natives-rust-task-cancellation.md","pt-br/natives/natives-shell-pty-process.md","pt-br/natives/natives-text-search-pipeline.md","pt-br/natives/porting-to-natives.md","pt-br/providers/models.md","pt-br/providers/provider-streaming-internals.md","pt-br/providers/python-repl.md","pt-br/runtime-tools/bash-tool-runtime.md","pt-br/runtime-tools/context-command.md","pt-br/runtime-tools/custom-tools.md","pt-br/runtime-tools/notebook-tool-runtime.md","pt-br/runtime-tools/resolve-tool-runtime.md","pt-br/runtime-tools/slash-command-internals.md","pt-br/runtime-tools/task-agent-discovery.md","pt-br/sessions/compaction.md","pt-br/sessions/handoff-generation-pipeline.md","pt-br/sessions/memory.md","pt-br/sessions/non-compaction-retry-policy.md","pt-br/sessions/session-operations-export-share-fork-resume.md","pt-br/sessions/session-switching-and-recent-listing.md","pt-br/sessions/session-tree-plan.md","pt-br/sessions/session.md","pt-br/sessions/ttsr-injection-lifecycle.md","pt-br/tui/theme.md","pt-br/tui/tree.md","pt-br/tui/tui-runtime-internals.md","pt-br/tui/tui.md","th/configuration/blob-artifact-architecture.md","th/configuration/config-usage.md","th/configuration/environment-variables.md","th/configuration/fs-scan-cache-architecture.md","th/configuration/hooks.md","th/configuration/porting-from-pi-mono.md","th/configuration/rpc.md","th/configuration/sdk.md","th/configuration/secrets.md","th/extensions/extension-loading.md","th/extensions/extensions.md","th/extensions/gemini-manifest-extensions.md","th/extensions/marketplace.md","th/extensions/plugin-manager-installer-plumbing.md","th/extensions/rulebook-matching-pipeline.md","th/extensions/skills.md","th/index.md","th/mcp/mcp-config.md","th/mcp/mcp-protocol-transports.md","th/mcp/mcp-runtime-lifecycle.md","th/mcp/mcp-server-tool-authoring.md","th/natives/natives-addon-loader-runtime.md","th/natives/natives-architecture.md","th/natives/natives-binding-contract.md","th/natives/natives-build-release-debugging.md","th/natives/natives-media-system-utils.md","th/natives/natives-rust-task-cancellation.md","th/natives/natives-shell-pty-process.md","th/natives/natives-text-search-pipeline.md","th/natives/porting-to-natives.md","th/providers/models.md","th/providers/provider-streaming-internals.md","th/providers/python-repl.md","th/runtime-tools/bash-tool-runtime.md","th/runtime-tools/context-command.md","th/runtime-tools/custom-tools.md","th/runtime-tools/notebook-tool-runtime.md","th/runtime-tools/resolve-tool-runtime.md","th/runtime-tools/slash-command-internals.md","th/runtime-tools/task-agent-discovery.md","th/sessions/compaction.md","th/sessions/handoff-generation-pipeline.md","th/sessions/memory.md","th/sessions/non-compaction-retry-policy.md","th/sessions/session-operations-export-share-fork-resume.md","th/sessions/session-switching-and-recent-listing.md","th/sessions/session-tree-plan.md","th/sessions/session.md","th/sessions/ttsr-injection-lifecycle.md","th/tui/theme.md","th/tui/tree.md","th/tui/tui-runtime-internals.md","th/tui/tui.md","zh-cn/configuration/blob-artifact-architecture.md","zh-cn/configuration/config-usage.md","zh-cn/configuration/environment-variables.md","zh-cn/configuration/fs-scan-cache-architecture.md","zh-cn/configuration/hooks.md","zh-cn/configuration/porting-from-pi-mono.md","zh-cn/configuration/rpc.md","zh-cn/configuration/sdk.md","zh-cn/configuration/secrets.md","zh-cn/extensions/extension-loading.md","zh-cn/extensions/extensions.md","zh-cn/extensions/gemini-manifest-extensions.md","zh-cn/extensions/marketplace.md","zh-cn/extensions/plugin-manager-installer-plumbing.md","zh-cn/extensions/rulebook-matching-pipeline.md","zh-cn/extensions/skills.md","zh-cn/index.md","zh-cn/mcp/mcp-config.md","zh-cn/mcp/mcp-protocol-transports.md","zh-cn/mcp/mcp-runtime-lifecycle.md","zh-cn/mcp/mcp-server-tool-authoring.md","zh-cn/natives/natives-addon-loader-runtime.md","zh-cn/natives/natives-architecture.md","zh-cn/natives/natives-binding-contract.md","zh-cn/natives/natives-build-release-debugging.md","zh-cn/natives/natives-media-system-utils.md","zh-cn/natives/natives-rust-task-cancellation.md","zh-cn/natives/natives-shell-pty-process.md","zh-cn/natives/natives-text-search-pipeline.md","zh-cn/natives/porting-to-natives.md","zh-cn/providers/models.md","zh-cn/providers/provider-streaming-internals.md","zh-cn/providers/python-repl.md","zh-cn/runtime-tools/bash-tool-runtime.md","zh-cn/runtime-tools/context-command.md","zh-cn/runtime-tools/custom-tools.md","zh-cn/runtime-tools/notebook-tool-runtime.md","zh-cn/runtime-tools/resolve-tool-runtime.md","zh-cn/runtime-tools/slash-command-internals.md","zh-cn/runtime-tools/task-agent-discovery.md","zh-cn/sessions/compaction.md","zh-cn/sessions/handoff-generation-pipeline.md","zh-cn/sessions/memory.md","zh-cn/sessions/non-compaction-retry-policy.md","zh-cn/sessions/session-operations-export-share-fork-resume.md","zh-cn/sessions/session-switching-and-recent-listing.md","zh-cn/sessions/session-tree-plan.md","zh-cn/sessions/session.md","zh-cn/sessions/ttsr-injection-lifecycle.md","zh-cn/tui/theme.md","zh-cn/tui/tree.md","zh-cn/tui/tui-runtime-internals.md","zh-cn/tui/tui.md","zh-tw/configuration/blob-artifact-architecture.md","zh-tw/configuration/config-usage.md","zh-tw/configuration/environment-variables.md","zh-tw/configuration/fs-scan-cache-architecture.md","zh-tw/configuration/hooks.md","zh-tw/configuration/porting-from-pi-mono.md","zh-tw/configuration/rpc.md","zh-tw/configuration/sdk.md","zh-tw/configuration/secrets.md","zh-tw/extensions/extension-loading.md","zh-tw/extensions/extensions.md","zh-tw/extensions/gemini-manifest-extensions.md","zh-tw/extensions/marketplace.md","zh-tw/extensions/plugin-manager-installer-plumbing.md","zh-tw/extensions/rulebook-matching-pipeline.md","zh-tw/extensions/skills.md","zh-tw/index.md","zh-tw/mcp/mcp-config.md","zh-tw/mcp/mcp-protocol-transports.md","zh-tw/mcp/mcp-runtime-lifecycle.md","zh-tw/mcp/mcp-server-tool-authoring.md","zh-tw/natives/natives-addon-loader-runtime.md","zh-tw/natives/natives-architecture.md","zh-tw/natives/natives-binding-contract.md","zh-tw/natives/natives-build-release-debugging.md","zh-tw/natives/natives-media-system-utils.md","zh-tw/natives/natives-rust-task-cancellation.md","zh-tw/natives/natives-shell-pty-process.md","zh-tw/natives/natives-text-search-pipeline.md","zh-tw/natives/porting-to-natives.md","zh-tw/providers/models.md","zh-tw/providers/provider-streaming-internals.md","zh-tw/providers/python-repl.md","zh-tw/runtime-tools/bash-tool-runtime.md","zh-tw/runtime-tools/context-command.md","zh-tw/runtime-tools/custom-tools.md","zh-tw/runtime-tools/notebook-tool-runtime.md","zh-tw/runtime-tools/resolve-tool-runtime.md","zh-tw/runtime-tools/slash-command-internals.md","zh-tw/runtime-tools/task-agent-discovery.md","zh-tw/sessions/compaction.md","zh-tw/sessions/handoff-generation-pipeline.md","zh-tw/sessions/memory.md","zh-tw/sessions/non-compaction-retry-policy.md","zh-tw/sessions/session-operations-export-share-fork-resume.md","zh-tw/sessions/session-switching-and-recent-listing.md","zh-tw/sessions/session-tree-plan.md","zh-tw/sessions/session.md","zh-tw/sessions/ttsr-injection-lifecycle.md","zh-tw/tui/theme.md","zh-tw/tui/tree.md","zh-tw/tui/tui-runtime-internals.md","zh-tw/tui/tui.md"];
|
|
4
4
|
|
|
5
5
|
export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
|
|
6
6
|
"SYSTEM_PROMPT_GUIDE.md": "# Anthropic System Prompting Best Practices Standard\n\nThis document defines the authoritative engineering standard for authoring, refactoring, and maintaining system prompts, agent instructions, and skills across all f5-sales-demo repositories and xcsh AI assistant plugins.\n\nAll system prompts and agent instructions must strictly adhere to this 8-point checklist.\n\n---\n\n## The 8-Point System Prompt Checklist\n\n### 1. XML Tag Hierarchy & Semantic Framing\n- **Standard**: Wrap logical prompt sections in clean, explicit XML tags (`<role>`, `<defensive_scope>`, `<governance>`, `<operational_standards>`, `<execution_protocol>`, `<examples>`, `<structured_reporting>`).\n- **Rationale**: Claude models are optimized to recognize XML tags as deterministic structural boundaries. Using XML tags prevents context confusion, isolates directives, and ensures consistent rule adherence.\n\n### 2. Affirmative Guidance over Negative Prohibitions\n- **Standard**: Frame all operational boundaries, rules, and workflows using positive, action-oriented directives (*what TO do*). Eliminate negative panic keywords (`HALT immediately`, `STOP`, `DON'T`, `NEVER`, `PROHIBITED`).\n- **Rationale**: Negative prohibition language induces cognitive friction and model freezing, causing the assistant to become overly hesitant or refuse valid execution paths. Affirmative guidance provides a clear forward direction.\n\n### 3. Actionable Rationale (\"Why\" Explanations)\n- **Standard**: Pair every guideline, constraint, or workflow step with an explicit explanation of *why* the rule exists and what outcome it guarantees.\n- **Rationale**: Providing rationale equips the model with the underlying engineering intent. This allows Claude to reason safely and adapt flexibly in novel edge cases rather than failing when encountering unexpected inputs.\n\n### 4. Progressive Context Loading & Modular Hierarchy\n- **Standard**: Keep top-level system prompts concise and focused on core persona, scope, and high-level routing. Place granular tool schemas, raw API curl specs, and detailed multi-step SOPs into dynamically loaded skills or specialized subagents.\n- **Rationale**: Progressive context loading prevents prompt bloat, reduces token overhead, avoids recency bias degradation, and maximizes model attention on the immediate task.\n\n### 5. Expert Persona & Professional Confidence\n- **Standard**: Anchor the assistant or agent with an authoritative, expert persona (*\"You are the GitHub Operations Expert agent...\"*) that approaches tasks with professional confidence, precision, and mastery.\n- **Rationale**: An expert persona establishes domain authority, enhances task execution precision, and encourages autonomous problem-solving within safety boundaries.\n\n### 6. Constructive Fallback Paths (Forward Progress)\n- **Standard**: Provide constructive forward-progress actions for handling missing parameters, ambiguous inputs, or transient API errors instead of halting or throwing panic errors.\n- **Rationale**: Forward progress logic guarantees continuous execution, prompting the caller or retrieving missing context proactively.\n\n### 7. Canonical Few-Shot Examples\n- **Standard**: For complex output structures, status reports, or reasoning patterns, provide clean, canonical few-shot examples wrapped in `<examples>` tags, using `<thinking>` blocks when demonstrating multi-step reasoning.\n- **Rationale**: Few-shot examples ground the model's output formatting far more effectively than abstract rules alone.\n\n### 8. Security Guardrails as High-Rigor Engineering Standards\n- **Standard**: Frame security guardrails (credential protection, input sanitization, worktree isolation, commit history integrity) as standard software craftsmanship and high-rigor engineering practices.\n- **Rationale**: Framing safeguards as standard professional practices integrates security seamlessly without triggering timid refusal behavior.\n\n---\n\n## Verification & Audit Standard\n\nPrior to merging any new or updated prompt file (`*.md` agents, system prompts, or skills), verify compliance against the 8-point checklist above.\n",
|
|
@@ -119,6 +119,7 @@ export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
|
|
|
119
119
|
"en/configuration/rpc.md": "---\ntitle: RPC Protocol Reference\ndescription: JSON-RPC protocol reference for inter-process communication between xcsh components.\nsidebar:\n order: 5\n label: RPC protocol\n---\n\n# RPC Protocol Reference\n\nRPC mode runs the coding agent as a newline-delimited JSON protocol over stdio.\n\n- **stdin**: commands (`RpcCommand`) and extension UI responses\n- **stdout**: command responses (`RpcResponse`), session/agent events, extension UI requests\n\nPrimary implementation:\n\n- `src/modes/rpc/rpc-mode.ts`\n- `src/modes/rpc/rpc-types.ts`\n- `src/session/agent-session.ts`\n- `packages/agent/src/agent.ts`\n- `packages/agent/src/agent-loop.ts`\n\n## Startup\n\n```bash\nxcsh --mode rpc [regular CLI options]\n```\n\nBehavior notes:\n\n- `@file` CLI arguments are rejected in RPC mode.\n- RPC mode disables automatic session title generation by default to avoid an extra model call.\n- RPC mode resets workflow-altering `todo.*`, `task.*`, and `async.*` settings to their built-in defaults instead of inheriting user overrides.\n- The process reads stdin as JSONL (`readJsonl(Bun.stdin.stream())`).\n- When stdin closes, the process exits with code `0`.\n- Responses/events are written as one JSON object per line.\n\n## Transport and Framing\n\nEach frame is a single JSON object followed by `\\n`.\n\nThere is no envelope beyond the object shape itself.\n\n### Outbound frame categories (stdout)\n\n1. `RpcResponse` (`{ type: \"response\", ... }`)\n2. `AgentSessionEvent` objects (`agent_start`, `message_update`, etc.)\n3. `RpcExtensionUIRequest` (`{ type: \"extension_ui_request\", ... }`)\n4. Extension errors (`{ type: \"extension_error\", extensionPath, event, error }`)\n\n### Inbound frame categories (stdin)\n\n1. `RpcCommand`\n2. `RpcExtensionUIResponse` (`{ type: \"extension_ui_response\", ... }`)\n\n## Request/Response Correlation\n\nAll commands accept optional `id?: string`.\n\n- If provided, normal command responses echo the same `id`.\n- `RpcClient` relies on this for pending-request resolution.\n\nImportant edge behavior from runtime:\n\n- Unknown command responses are emitted with `id: undefined` (even if the request had an `id`).\n- Parse/handler exceptions in the input loop emit `command: \"parse\"` with `id: undefined`.\n- `prompt` and `abort_and_prompt` return immediate success, then may emit a later error response with the **same** id if async prompt scheduling fails.\n\n## Command Schema (canonical)\n\n`RpcCommand` is defined in `src/modes/rpc/rpc-types.ts`:\n\n### Prompting\n\n- `{ id?, type: \"prompt\", message: string, images?: ImageContent[], streamingBehavior?: \"steer\" | \"followUp\" }`\n- `{ id?, type: \"steer\", message: string, images?: ImageContent[] }`\n- `{ id?, type: \"follow_up\", message: string, images?: ImageContent[] }`\n- `{ id?, type: \"abort\" }`\n- `{ id?, type: \"abort_and_prompt\", message: string, images?: ImageContent[] }`\n- `{ id?, type: \"new_session\", parentSession?: string }`\n\n### State\n\n- `{ id?, type: \"get_state\" }`\n- `{ id?, type: \"set_todos\", phases: TodoPhase[] }`\n- `{ id?, type: \"set_host_tools\", tools: RpcHostToolDefinition[] }`\n\n### Model\n\n- `{ id?, type: \"set_model\", provider: string, modelId: string }`\n- `{ id?, type: \"cycle_model\" }`\n- `{ id?, type: \"get_available_models\" }`\n\n### Thinking\n\n- `{ id?, type: \"set_thinking_level\", level: ThinkingLevel }`\n- `{ id?, type: \"cycle_thinking_level\" }`\n\n### Queue modes\n\n- `{ id?, type: \"set_steering_mode\", mode: \"all\" | \"one-at-a-time\" }`\n- `{ id?, type: \"set_follow_up_mode\", mode: \"all\" | \"one-at-a-time\" }`\n- `{ id?, type: \"set_interrupt_mode\", mode: \"immediate\" | \"wait\" }`\n\n### Compaction\n\n- `{ id?, type: \"compact\", customInstructions?: string }`\n- `{ id?, type: \"set_auto_compaction\", enabled: boolean }`\n\n### Retry\n\n- `{ id?, type: \"set_auto_retry\", enabled: boolean }`\n- `{ id?, type: \"abort_retry\" }`\n\n### Bash\n\n- `{ id?, type: \"bash\", command: string }`\n- `{ id?, type: \"abort_bash\" }`\n\n### Session\n\n- `{ id?, type: \"get_session_stats\" }`\n- `{ id?, type: \"export_html\", outputPath?: string }`\n- `{ id?, type: \"switch_session\", sessionPath: string }`\n- `{ id?, type: \"branch\", entryId: string }`\n- `{ id?, type: \"get_branch_messages\" }`\n- `{ id?, type: \"get_last_assistant_text\" }`\n- `{ id?, type: \"set_session_name\", name: string }`\n\n### Messages\n\n- `{ id?, type: \"get_messages\" }`\n\n## Response Schema\n\nAll command results use `RpcResponse`:\n\n- Success: `{ id?, type: \"response\", command: <command>, success: true, data?: ... }`\n- Failure: `{ id?, type: \"response\", command: string, success: false, error: string }`\n\nData payloads are command-specific and defined in `rpc-types.ts`.\n\n### `get_state` payload\n\n```json\n{\n \"model\": { \"provider\": \"...\", \"id\": \"...\" },\n \"thinkingLevel\": \"off|minimal|low|medium|high|xhigh\",\n \"isStreaming\": false,\n \"isCompacting\": false,\n \"steeringMode\": \"all|one-at-a-time\",\n \"followUpMode\": \"all|one-at-a-time\",\n \"interruptMode\": \"immediate|wait\",\n \"sessionFile\": \"...\",\n \"sessionId\": \"...\",\n \"sessionName\": \"...\",\n \"autoCompactionEnabled\": true,\n \"messageCount\": 0,\n \"queuedMessageCount\": 0,\n \"todoPhases\": [\n {\n \"id\": \"phase-1\",\n \"name\": \"Todos\",\n \"tasks\": [\n {\n \"id\": \"task-1\",\n \"content\": \"Map the tool surface\",\n \"status\": \"in_progress\"\n }\n ]\n }\n ]\n}\n```\n\n### `set_todos` payload\n\nReplaces the in-memory todo state for the current session and returns the normalized phase list:\n\n```json\n{\n \"id\": \"req_2\",\n \"type\": \"set_todos\",\n \"phases\": [\n {\n \"id\": \"phase-1\",\n \"name\": \"Evaluation\",\n \"tasks\": [\n {\n \"id\": \"task-1\",\n \"content\": \"Map the read tool surface\",\n \"status\": \"in_progress\"\n },\n {\n \"id\": \"task-2\",\n \"content\": \"Exercise edit operations\",\n \"status\": \"pending\"\n }\n ]\n }\n ]\n}\n```\n\nThis is useful for hosts that want to pre-seed a plan before the first prompt.\n\n### `set_host_tools` payload\n\nReplaces the current set of host-owned tools that the RPC server may call back\ninto over stdio:\n\n```json\n{\n \"id\": \"req_3\",\n \"type\": \"set_host_tools\",\n \"tools\": [\n {\n \"name\": \"echo_host\",\n \"label\": \"Echo Host\",\n \"description\": \"Echo a value from the embedding host\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"message\": { \"type\": \"string\" }\n },\n \"required\": [\"message\"],\n \"additionalProperties\": false\n }\n }\n ]\n}\n```\n\nThe response payload is:\n\n```json\n{\n \"toolNames\": [\"echo_host\"]\n}\n```\n\nThese tools are added to the active session tool registry before the next model\ncall. Re-sending `set_host_tools` replaces the previous host-owned set.\n\n## Event Stream Schema\n\nRPC mode forwards `AgentSessionEvent` objects from `AgentSession.subscribe(...)`.\n\nCommon event types:\n\n- `agent_start`, `agent_end`\n- `turn_start`, `turn_end`\n- `message_start`, `message_update`, `message_end`\n- `tool_execution_start`, `tool_execution_update`, `tool_execution_end`\n- `auto_compaction_start`, `auto_compaction_end`\n- `auto_retry_start`, `auto_retry_end`\n- `ttsr_triggered`\n- `todo_reminder`\n- `todo_auto_clear`\n\nExtension runner errors are emitted separately as:\n\n```json\n{ \"type\": \"extension_error\", \"extensionPath\": \"...\", \"event\": \"...\", \"error\": \"...\" }\n```\n\n`message_update` includes streaming deltas in `assistantMessageEvent` (text/thinking/toolcall deltas).\n\n## Prompt/Queue Concurrency and Ordering\n\nThis is the most important operational behavior.\n\n### Immediate ack vs completion\n\n`prompt` and `abort_and_prompt` are **acknowledged immediately**:\n\n```json\n{ \"id\": \"req_1\", \"type\": \"response\", \"command\": \"prompt\", \"success\": true }\n```\n\nThat means:\n\n- command acceptance != run completion\n- final completion is observed via `agent_end`\n\n### While streaming\n\n`AgentSession.prompt()` requires `streamingBehavior` during active streaming:\n\n- `\"steer\"` => queued steering message (interrupt path)\n- `\"followUp\"` => queued follow-up message (post-turn path)\n\nIf omitted during streaming, prompt fails.\n\n### Queue defaults\n\nFrom the coding-agent settings schema (`packages/coding-agent/src/config/settings-schema.ts`):\n\n- `steeringMode`: `\"one-at-a-time\"`\n- `followUpMode`: `\"one-at-a-time\"`\n- `interruptMode`: `\"wait\"`\n\n### Mode semantics\n\n- `set_steering_mode` / `set_follow_up_mode`\n - `\"one-at-a-time\"`: dequeue one queued message per turn\n - `\"all\"`: dequeue entire queue at once\n- `set_interrupt_mode`\n - `\"immediate\"`: tool execution checks steering between tool calls; pending steering can abort remaining tool calls in the turn\n - `\"wait\"`: defer steering until turn completion\n\n## Extension UI Sub-Protocol\n\nExtensions in RPC mode use request/response UI frames.\n\n### Outbound request\n\n`RpcExtensionUIRequest` (`type: \"extension_ui_request\"`) methods:\n\n- `select`, `confirm`, `input`, `editor`\n- `notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`\n\nRuntime note:\n\n- Automatic session title generation is disabled in RPC mode, and `setTitle` UI\n requests are also suppressed by default because most hosts do not have a\n meaningful terminal-title surface. Set `PI_RPC_EMIT_TITLE=1` to opt back in to\n the UI event only.\n\nExample:\n\n```json\n{ \"type\": \"extension_ui_request\", \"id\": \"123\", \"method\": \"confirm\", \"title\": \"Confirm\", \"message\": \"Continue?\", \"timeout\": 30000 }\n```\n\n### Inbound response\n\n`RpcExtensionUIResponse` (`type: \"extension_ui_response\"`):\n\n- `{ type: \"extension_ui_response\", id: string, value: string }`\n- `{ type: \"extension_ui_response\", id: string, confirmed: boolean }`\n- `{ type: \"extension_ui_response\", id: string, cancelled: true }`\n\nIf a dialog has a timeout, RPC mode resolves to a default value when timeout/abort fires.\n\n## Host Tool Sub-Protocol\n\nRPC hosts can expose custom tools to the agent by sending `set_host_tools`, then\nserving execution requests over the same transport.\n\n### Outbound request\n\nWhen the agent wants the host to execute one of those tools, RPC mode emits:\n\n```json\n{\n \"type\": \"host_tool_call\",\n \"id\": \"host_1\",\n \"toolCallId\": \"toolu_123\",\n \"toolName\": \"echo_host\",\n \"arguments\": { \"message\": \"hello\" }\n}\n```\n\nIf the tool execution is later aborted, RPC mode emits:\n\n```json\n{\n \"type\": \"host_tool_cancel\",\n \"id\": \"host_cancel_1\",\n \"targetId\": \"host_1\"\n}\n```\n\n### Inbound updates and completion\n\nHosts can optionally stream progress:\n\n```json\n{\n \"type\": \"host_tool_update\",\n \"id\": \"host_1\",\n \"partialResult\": {\n \"content\": [{ \"type\": \"text\", \"text\": \"working\" }]\n }\n}\n```\n\nCompletion uses:\n\n```json\n{\n \"type\": \"host_tool_result\",\n \"id\": \"host_1\",\n \"result\": {\n \"content\": [{ \"type\": \"text\", \"text\": \"done\" }]\n }\n}\n```\n\nSet `isError: true` on `host_tool_result` to surface the returned content as a\ntool error.\n\n## Error Model and Recoverability\n\n### Command-level failures\n\nFailures are `success: false` with string `error`.\n\n```json\n{ \"id\": \"req_2\", \"type\": \"response\", \"command\": \"set_model\", \"success\": false, \"error\": \"Model not found: provider/model\" }\n```\n\n### Recoverability expectations\n\n- Most command failures are recoverable; process remains alive.\n- Malformed JSONL / parse-loop exceptions emit a `parse` error response and continue reading subsequent lines.\n- Empty `set_session_name` is rejected (`Session name cannot be empty`).\n- Extension UI responses with unknown `id` are ignored.\n- Process termination conditions are stdin close or explicit extension-triggered shutdown.\n\n## Compact Command Flows\n\n### 1) Prompt and stream\n\nstdin:\n\n```json\n{ \"id\": \"req_1\", \"type\": \"prompt\", \"message\": \"Summarize this repo\" }\n```\n\nstdout sequence (typical):\n\n```json\n{ \"id\": \"req_1\", \"type\": \"response\", \"command\": \"prompt\", \"success\": true }\n{ \"type\": \"agent_start\" }\n{ \"type\": \"message_update\", \"assistantMessageEvent\": { \"type\": \"text_delta\", \"delta\": \"...\" }, \"message\": { \"role\": \"assistant\", \"content\": [] } }\n{ \"type\": \"agent_end\", \"messages\": [] }\n```\n\n### 2) Prompt during streaming with explicit queue policy\n\nstdin:\n\n```json\n{ \"id\": \"req_2\", \"type\": \"prompt\", \"message\": \"Also include risks\", \"streamingBehavior\": \"followUp\" }\n```\n\n### 3) Inspect and tune queue behavior\n\nstdin:\n\n```json\n{ \"id\": \"q1\", \"type\": \"get_state\" }\n{ \"id\": \"q2\", \"type\": \"set_steering_mode\", \"mode\": \"all\" }\n{ \"id\": \"q3\", \"type\": \"set_interrupt_mode\", \"mode\": \"wait\" }\n```\n\n### 4) Extension UI round trip\n\nstdout:\n\n```json\n{ \"type\": \"extension_ui_request\", \"id\": \"ui_7\", \"method\": \"input\", \"title\": \"Branch name\", \"placeholder\": \"feature/...\" }\n```\n\nstdin:\n\n```json\n{ \"type\": \"extension_ui_response\", \"id\": \"ui_7\", \"value\": \"feature/rpc-host\" }\n```\n\n## Notes on `RpcClient` helper\n\n`src/modes/rpc/rpc-client.ts` is a convenience wrapper, not the protocol definition.\n\nCurrent helper characteristics:\n\n- Spawns `bun <cliPath> --mode rpc`\n- Correlates responses by generated `req_<n>` ids\n- Dispatches only recognized `AgentEvent` types to listeners\n- Supports host-owned custom tools via `setCustomTools()` and automatic handling of `host_tool_call` / `host_tool_cancel`\n- Does **not** expose helper methods for every protocol command (for example, `set_interrupt_mode` and `set_session_name` are in protocol types but not wrapped as dedicated methods)\n\nUse raw protocol frames if you need complete surface coverage.\n",
|
|
120
120
|
"en/configuration/sdk.md": "---\ntitle: SDK\ndescription: SDK for building custom agents and integrations on top of the xcsh coding agent runtime.\nsidebar:\n order: 6\n label: SDK\n---\n\n# SDK\n\nThe SDK is the in-process integration surface for `@f5-sales-demo/xcsh`.\nUse it when you want direct access to agent state, event streaming, tool wiring, and session control from your own Bun/Node process.\n\nIf you need cross-language/process isolation, use RPC mode instead.\n\n## Installation\n\n```bash\nbun add @f5-sales-demo/xcsh\n```\n\n## Entry points\n\n`@f5-sales-demo/xcsh` exports the SDK APIs from the package root.\n\nCore exports for embedders:\n\n- `createAgentSession`\n- `SessionManager`\n- `Settings`\n- `AuthStorage`\n- `ModelRegistry`\n- `discoverAuthStorage`\n- Discovery helpers (`discoverExtensions`, `discoverSkills`, `discoverContextFiles`, `discoverPromptTemplates`, `discoverSlashCommands`, `discoverCustomTSCommands`, `discoverMCPServers`)\n- Tool factory surface (`createTools`, `BUILTIN_TOOLS`, tool classes)\n\n## Quick start (auto-discovery defaults)\n\n```ts\nimport { createAgentSession } from \"@f5-sales-demo/xcsh\";\n\nconst { session, modelFallbackMessage } = await createAgentSession();\n\nif (modelFallbackMessage) {\n process.stderr.write(`${modelFallbackMessage}\\n`);\n}\n\nconst unsubscribe = session.subscribe(event => {\n if (event.type === \"message_update\" && event.assistantMessageEvent.type === \"text_delta\") {\n process.stdout.write(event.assistantMessageEvent.delta);\n }\n});\n\nawait session.prompt(\"Summarize this repository in 3 bullets.\");\nunsubscribe();\nawait session.dispose();\n```\n\n## What `createAgentSession()` discovers by default\n\n`createAgentSession()` follows “provide to override, omit to discover”.\n\nIf omitted, it resolves:\n\n- `cwd`: `getProjectDir()`\n- `agentDir`: `~/.xcsh/agent` (via `getAgentDir()`)\n- `authStorage`: `discoverAuthStorage(agentDir)`\n- `modelRegistry`: `new ModelRegistry(authStorage)` + `await refresh()`\n- `settings`: `await Settings.init({ cwd, agentDir })`\n- `sessionManager`: `SessionManager.create(cwd)` (file-backed)\n- skills/context files/prompt templates/slash commands/extensions/custom TS commands\n- built-in tools via `createTools(...)`\n- MCP tools (enabled by default)\n- LSP integration (enabled by default)\n\n### Required vs optional inputs\n\nTypically you must provide only what you want to control:\n\n- **Must provide**: nothing for a minimal session\n- **Usually provide explicitly** in embedders:\n - `sessionManager` (if you need in-memory or custom location)\n - `authStorage` + `modelRegistry` (if you own credential/model lifecycle)\n - `model` or `modelPattern` (if deterministic model selection matters)\n - `settings` (if you need isolated/test config)\n\n## Session manager behavior (persistent vs in-memory)\n\n`AgentSession` always uses a `SessionManager`; behavior depends on which factory you use.\n\n### File-backed (default)\n\n```ts\nimport { createAgentSession, SessionManager } from \"@f5-sales-demo/xcsh\";\n\nconst { session } = await createAgentSession({\n sessionManager: SessionManager.create(process.cwd()),\n});\n\nconsole.log(session.sessionFile); // absolute .jsonl path\n```\n\n- Persists conversation/messages/state deltas to session files.\n- Supports resume/open/list/fork workflows.\n- `session.sessionFile` is defined.\n\n### In-memory\n\n```ts\nimport { createAgentSession, SessionManager } from \"@f5-sales-demo/xcsh\";\n\nconst { session } = await createAgentSession({\n sessionManager: SessionManager.inMemory(),\n});\n\nconsole.log(session.sessionFile); // undefined\n```\n\n- No filesystem persistence.\n- Useful for tests, ephemeral workers, request-scoped agents.\n- Session methods still work, but persistence-specific behaviors (file resume/fork paths) are naturally limited.\n\n### Resume/open/list helpers\n\n```ts\nimport { SessionManager } from \"@f5-sales-demo/xcsh\";\n\nconst recent = await SessionManager.continueRecent(process.cwd());\nconst listed = await SessionManager.list(process.cwd());\nconst opened = listed[0] ? await SessionManager.open(listed[0].path) : null;\n```\n\n## Model and auth wiring\n\n`createAgentSession()` uses `ModelRegistry` + `AuthStorage` for model selection and API key resolution.\n\n### Explicit wiring\n\n```ts\nimport {\n createAgentSession,\n discoverAuthStorage,\n ModelRegistry,\n SessionManager,\n} from \"@f5-sales-demo/xcsh\";\n\nconst authStorage = await discoverAuthStorage();\nconst modelRegistry = new ModelRegistry(authStorage);\nawait modelRegistry.refresh();\n\nconst available = modelRegistry.getAvailable();\nif (available.length === 0) throw new Error(\"No authenticated models available\");\n\nconst { session } = await createAgentSession({\n authStorage,\n modelRegistry,\n model: available[0],\n thinkingLevel: \"medium\",\n sessionManager: SessionManager.inMemory(),\n});\n```\n\n### Selection order when `model` is omitted\n\nWhen no explicit `model`/`modelPattern` is provided:\n\n1. restore model from existing session (if restorable + key available)\n2. settings default model role (`default`)\n3. first available model with valid auth\n\nIf restore fails, `modelFallbackMessage` explains fallback.\n\n### Auth priority\n\n`AuthStorage.getApiKey(...)` resolves in this order:\n\n1. runtime override (`setRuntimeApiKey`)\n2. stored credentials in `agent.db`\n3. provider environment variables\n4. custom-provider resolver fallback (if configured)\n\n## Event subscription model\n\nSubscribe with `session.subscribe(listener)`; it returns an unsubscribe function.\n\n```ts\nconst unsubscribe = session.subscribe(event => {\n switch (event.type) {\n case \"agent_start\":\n case \"turn_start\":\n case \"tool_execution_start\":\n break;\n case \"message_update\":\n if (event.assistantMessageEvent.type === \"text_delta\") {\n process.stdout.write(event.assistantMessageEvent.delta);\n }\n break;\n }\n});\n```\n\n`AgentSessionEvent` includes core `AgentEvent` plus session-level events:\n\n- `auto_compaction_start` / `auto_compaction_end`\n- `auto_retry_start` / `auto_retry_end`\n- `ttsr_triggered`\n- `todo_reminder`\n\n## Prompt lifecycle\n\n`session.prompt(text, options?)` is the primary entry point.\n\nBehavior:\n\n1. optional command/template expansion (`/` commands, custom commands, file slash commands, prompt templates)\n2. if currently streaming:\n - requires `streamingBehavior: \"steer\" | \"followUp\"`\n - queues instead of throwing work away\n3. if idle:\n - validates model + API key\n - appends user message\n - starts agent turn\n\nRelated APIs:\n\n- `sendUserMessage(content, { deliverAs? })`\n- `steer(text, images?)`\n- `followUp(text, images?)`\n- `sendCustomMessage({ customType, content, ... }, { deliverAs?, triggerTurn? })`\n- `abort()`\n\n## Tools and extension integration\n\n### Built-ins and filtering\n\n- Built-ins come from `createTools(...)` and `BUILTIN_TOOLS`.\n- `toolNames` acts as an allowlist for built-ins.\n- `customTools` and extension-registered tools are still included.\n- Hidden tools (for example `submit_result`) are opt-in unless required by options.\n\n```ts\nconst { session } = await createAgentSession({\n toolNames: [\"read\", \"grep\", \"find\", \"write\"],\n requireSubmitResultTool: true,\n});\n```\n\n### Extensions\n\n- `extensions`: inline `ExtensionFactory[]`\n- `additionalExtensionPaths`: load extra extension files\n- `disableExtensionDiscovery`: disable automatic extension scanning\n- `preloadedExtensions`: reuse already loaded extension set\n\n### Runtime tool set changes\n\n`AgentSession` supports runtime activation updates:\n\n- `getActiveToolNames()`\n- `getAllToolNames()`\n- `setActiveToolsByName(names)`\n- `refreshMCPTools(mcpTools)`\n\nSystem prompt is rebuilt to reflect active tool changes.\n\n## Discovery helpers\n\nUse these when you want partial control without recreating internal discovery logic:\n\n- `discoverAuthStorage(agentDir?)`\n- `discoverExtensions(cwd?)`\n- `discoverSkills(cwd?, _agentDir?, settings?)`\n- `discoverContextFiles(cwd?, _agentDir?)`\n- `discoverPromptTemplates(cwd?, agentDir?)`\n- `discoverSlashCommands(cwd?)`\n- `discoverCustomTSCommands(cwd?, agentDir?)`\n- `discoverMCPServers(cwd?)`\n- `buildSystemPrompt(options?)`\n\n## Subagent-oriented options\n\nFor SDK consumers building orchestrators (similar to task executor flow):\n\n- `outputSchema`: passes structured output expectation into tool context\n- `requireSubmitResultTool`: forces `submit_result` tool inclusion\n- `taskDepth`: recursion-depth context for nested task sessions\n- `parentTaskPrefix`: artifact naming prefix for nested task outputs\n\nThese are optional for normal single-agent embedding.\n\n## `createAgentSession()` return value\n\n```ts\ntype CreateAgentSessionResult = {\n session: AgentSession;\n extensionsResult: LoadExtensionsResult;\n setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void;\n mcpManager?: MCPManager;\n modelFallbackMessage?: string;\n lspServers?: Array<{ name: string; status: \"ready\" | \"error\"; fileTypes: string[]; error?: string }>;\n};\n```\n\nUse `setToolUIContext(...)` only if your embedder provides UI capabilities that tools/extensions should call into.\n\n## Minimal controlled embed example\n\n```ts\nimport {\n createAgentSession,\n discoverAuthStorage,\n ModelRegistry,\n SessionManager,\n Settings,\n} from \"@f5-sales-demo/xcsh\";\n\nconst authStorage = await discoverAuthStorage();\nconst modelRegistry = new ModelRegistry(authStorage);\nawait modelRegistry.refresh();\n\nconst settings = Settings.isolated({\n \"compaction.enabled\": true,\n \"retry.enabled\": true,\n});\n\nconst { session } = await createAgentSession({\n authStorage,\n modelRegistry,\n settings,\n sessionManager: SessionManager.inMemory(),\n toolNames: [\"read\", \"grep\", \"find\", \"edit\", \"write\"],\n enableMCP: false,\n enableLsp: true,\n});\n\nsession.subscribe(event => {\n if (event.type === \"message_update\" && event.assistantMessageEvent.type === \"text_delta\") {\n process.stdout.write(event.assistantMessageEvent.delta);\n }\n});\n\nawait session.prompt(\"Find all TODO comments in this repo and propose fixes.\");\nawait session.dispose();\n```\n",
|
|
121
121
|
"en/configuration/secrets.md": "---\ntitle: Secret Obfuscation\ndescription: Secret obfuscation pipeline that redacts sensitive values from session logs and outputs.\nsidebar:\n order: 3\n label: Secrets\n---\n\n# Secret Obfuscation\n\nPrevents sensitive values (API keys, tokens, passwords) from being sent to LLM providers. When enabled, secrets are replaced with deterministic placeholders before leaving the process, and restored in tool call arguments returned by the model.\n\n## Enabling\n\nEnabled by default. Toggle via `/settings` UI or directly in `config.yml`:\n\n```yaml\nsecrets:\n enabled: false\n```\n\n## How it works\n\n1. On session startup, secrets are collected from two sources:\n - **Environment variables** matching common secret patterns (`*_KEY`, `*_SECRET`, `*_TOKEN`, `*_PASSWORD`, etc.) with values >= 8 characters\n - **`secrets.yml` files** (see below)\n\n2. Outbound messages to the LLM have all secret values replaced with placeholders like `<<$env:S0>>`, `<<$env:S1>>`, etc.\n\n3. Tool call arguments returned by the model are deep-walked and placeholders are restored to original values before execution.\n\nTwo modes control what happens to each secret:\n\n| Mode | Behavior | Reversible |\n|---|---|---|\n| `obfuscate` (default) | Replaced with indexed placeholder `<<$env:SN>>` | Yes (deobfuscated in tool args) |\n| `replace` | Replaced with deterministic same-length string | No (one-way) |\n\n## secrets.yml\n\nDefine custom secret entries in YAML. Two locations are checked:\n\n| Level | Path | Purpose |\n|---|---|---|\n| Global | `~/.xcsh/agent/secrets.yml` | Secrets across all projects |\n| Project | `<cwd>/.xcsh/secrets.yml` | Project-specific secrets |\n\nProject entries override global entries with matching `content`.\n\n### Schema\n\nEach entry in the array has these fields:\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `type` | `\"plain\"` or `\"regex\"` | Yes | Match strategy |\n| `content` | string | Yes | The secret value (plain) or regex pattern (regex) |\n| `mode` | `\"obfuscate\"` or `\"replace\"` | No | Default: `\"obfuscate\"` |\n| `replacement` | string | No | Custom replacement (replace mode only) |\n| `flags` | string | No | Regex flags (regex type only) |\n\n### Examples\n\n#### Plain secrets\n\n```yaml\n# Obfuscate a specific API key (default mode)\n- type: plain\n content: sk-proj-abc123def456\n\n# Replace a database password with a fixed string\n- type: plain\n content: hunter2\n mode: replace\n replacement: \"********\"\n```\n\n#### Regex secrets\n\n```yaml\n# Obfuscate any AWS-style key\n- type: regex\n content: \"AKIA[0-9A-Z]{16}\"\n\n# Case-insensitive match with explicit flags\n- type: regex\n content: \"api[_-]?key\\\\s*=\\\\s*\\\\w+\"\n flags: \"i\"\n\n# Regex literal syntax (pattern and flags in one string)\n- type: regex\n content: \"/bearer\\\\s+[a-zA-Z0-9._~+\\\\/=-]+/i\"\n```\n\nRegex entries always scan globally (the `g` flag is enforced automatically). The regex literal syntax `/pattern/flags` is supported as an alternative to separate `content` + `flags` fields. Escaped slashes within the pattern (`\\\\/`) are handled correctly.\n\n#### Replace mode with regex\n\n```yaml\n# One-way replace connection strings (not reversible)\n- type: regex\n content: \"postgres://[^\\\\s]+\"\n mode: replace\n replacement: \"postgres://***\"\n```\n\n## Interaction with env var detection\n\nEnvironment variables are always collected first. File-defined entries are appended after, so file entries can cover secrets that don't live in env vars (config files, hardcoded values, etc.). If the same value appears in both, the file entry's mode takes precedence.\n\n## Key files\n\n- `src/secrets/index.ts` -- loading, merging, env var collection\n- `src/secrets/obfuscator.ts` -- `SecretObfuscator` class, placeholder generation, message obfuscation\n- `src/secrets/regex.ts` -- regex literal parsing and compilation\n- `src/config/settings-schema.ts` -- `secrets.enabled` setting definition\n",
|
|
122
|
+
"en/container/alpine-deployment.md": "---\ntitle: Run xcsh in an Alpine container\ndescription: Build or run the non-root xcsh Alpine image and optionally verify mounted cloud CLI sessions.\n---\n\nTagged xcsh releases publish an image to GitHub Container Registry (GHCR) as\n`ghcr.io/f5-sales-demo/xcsh`. The first package becomes available when a `v*`\nrelease tag runs the container workflow from the default branch. The image runs\nas the unprivileged `xcsh` user and includes the xcsh, Google Cloud, Azure,\nAmazon Web Services (AWS), GitHub, Salesforce, Bun, and Zig command-line\ninterfaces (CLIs).\n\nThe image currently supports `linux/amd64` hosts.\n\n## Prerequisites\n\nBefore you begin, install Docker Engine with the Compose plugin. To run the\noptional live tests, authenticate the Google Cloud and Azure CLIs on your host.\nUse only F5-owned labs or customer demo environments covered by an engagement.\n\nAllow about 10 minutes for the first local build. The cloud CLIs make the image\nsubstantially larger than a minimal xcsh-only runtime.\n\n## Pull a release image\n\nAfter a tagged release finishes, pull the most recent stable image:\n\n```bash\ndocker pull ghcr.io/f5-sales-demo/xcsh:latest\n```\n\nReleases also publish immutable `vX.Y.Z` tags and moving `X.Y` tags. Prefer a\npublished immutable tag when reproducibility matters, for example\n`ghcr.io/f5-sales-demo/xcsh:vX.Y.Z` after replacing `X.Y.Z` with a release\nversion.\n\nRun a non-interactive command through the image entrypoint:\n\n```bash\ndocker run --rm ghcr.io/f5-sales-demo/xcsh:latest --version\ndocker run --rm ghcr.io/f5-sales-demo/xcsh:latest --help\n```\n\nOverride the entrypoint when you need a shell:\n\n```bash\ndocker run --rm -it \\\n --entrypoint /bin/bash \\\n ghcr.io/f5-sales-demo/xcsh:latest\n```\n\n## Build the development service\n\nFrom an xcsh repository checkout, build and start the hardened development\nservice:\n\n```bash\ndocker compose -f docker-compose.dev.yml up -d --build\n```\n\nThe service idles without invoking xcsh, mounts the checkout read-only at\n`/workspace`, and lets you run commands explicitly:\n\n```bash\ndocker compose -f docker-compose.dev.yml exec xcsh-dev xcsh --help\ndocker compose -f docker-compose.dev.yml exec xcsh-dev bash\n```\n\nThe Compose service applies these controls:\n\n- User and group IDs default to `1000`.\n- All Linux capabilities are dropped.\n- `no-new-privileges` blocks privilege escalation.\n- The image filesystem and source checkout are read-only. The `/tmp`, xcsh,\n and Salesforce state paths use writable, ephemeral temporary filesystems.\n The xcsh state mount permits executable mappings because xcsh extracts its\n embedded native module there.\n- The Docker socket and static service-account keys are not mounted.\n- Host CLI configuration directories are mounted read-only under `*-host` paths.\n\nRead-only credentials can still be read by processes in the container. Mount\nthem only into images and source trees you trust.\n\n## Configure the environment\n\nThe development and live user acceptance testing (UAT) scripts use these\nvariables:\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `UID` | `1000` | Runtime user ID used by Compose. |\n| `GID` | `1000` | Runtime group ID used by Compose. |\n| `GEMINI_MODEL` | `gemini-3.1-pro-preview` | Vertex AI model tested by live UAT. |\n| `VERTEX_AI_PROJECT` | Active gcloud project | Vertex AI project tested by live UAT. |\n| `VERTEX_AI_LOCATION` | `us-central1` | Vertex AI location tested by live UAT. |\n| `AZURE_CONFIG_DIR` | `/tmp/xcsh-azure` | Writable Azure CLI session directory inside Compose. |\n| `CLOUDSDK_CONFIG` | `/tmp/xcsh-gcloud` | Writable Google Cloud CLI session directory inside Compose. |\n\nCompose mounts host configuration into these read-only source paths:\n\n| CLI | Host path | Container source path |\n| --- | --- | --- |\n| Google Cloud | `~/.config/gcloud` | `/home/xcsh/.config/gcloud-host` |\n| Azure | `~/.azure` | `/home/xcsh/.azure-host` |\n| AWS | `~/.aws` | `/home/xcsh/.aws-host` |\n| GitHub | `~/.config/gh` | `/home/xcsh/.config/gh-host` |\n| Salesforce | `~/.sfdx` | `/home/xcsh/.sfdx-host` |\n\nThe live tests copy only the required Google Cloud and Azure configuration into\nprivate temporary directories. They delete those copies on exit and never write\nsession state into the host mounts.\n\n## Run verification\n\nRun the deterministic end-to-end test without cloud credentials:\n\n```bash\n./scripts/e2e-user-install-test.sh\n```\n\nThis path builds the image, verifies the non-root identity and hardening\nsettings, checks every bundled CLI, and tears down the service. It does not call\nAzure or Vertex AI.\n\nTo test already-authorized F5 lab credentials, opt in explicitly:\n\n```bash\n./scripts/e2e-user-install-test.sh --live\n```\n\nThe live path verifies Azure CLI and Vertex AI access. It reports only pass or\nfail status; it does not print tokens, account identities, tenant or subscription\nnames, project IDs, prompts, or model responses.\n\n## Verify\n\nInspect the running service directly when troubleshooting:\n\n```bash\ndocker compose -f docker-compose.dev.yml exec xcsh-dev id\ndocker compose -f docker-compose.dev.yml exec xcsh-dev xcsh --version\ndocker compose -f docker-compose.dev.yml exec xcsh-dev gcloud --version\ndocker compose -f docker-compose.dev.yml exec xcsh-dev az version\n```\n\nThe identity output must show user and group ID `1000`. The xcsh and cloud CLI\ncommands must exit successfully.\n\n## Clean up\n\nRemove the development service and network:\n\n```bash\ndocker compose -f docker-compose.dev.yml down --remove-orphans\n```\n\nThe test scripts perform the same teardown automatically on success, failure,\nor interruption.\n\n## Localized documentation\n\nAuthor container documentation in English under `docs/en/`. Localized files are\nmanaged automation output and are refreshed only for an eligible major release\nunless an exceptional translation run is explicitly requested. Expected locale\ndrift during ordinary English development is not a blocking failure.\n",
|
|
122
123
|
"en/extensions/extension-loading.md": "---\ntitle: Extension Loading (TypeScript/JavaScript Modules)\ndescription: TypeScript and JavaScript module loading pipeline for extensions with resolution, validation, and caching.\nsidebar:\n order: 2\n label: Extension loading\n---\n\n# Extension Loading (TypeScript/JavaScript Modules)\n\nThis document covers how the coding agent discovers and loads **extension modules** (`.ts`/`.js`) at startup.\n\nIt does **not** cover `gemini-extension.json` manifest extensions (documented separately).\n\n## What this subsystem does\n\nExtension loading builds a list of module entry files, imports each module with Bun, executes its factory, and returns:\n\n- loaded extension definitions\n- per-path load errors (without aborting the whole load)\n- a shared extension runtime object used later by `ExtensionRunner`\n\n## Primary implementation files\n\n- `src/extensibility/extensions/loader.ts` — path discovery + import/execution\n- `src/extensibility/extensions/index.ts` — public exports\n- `src/extensibility/extensions/runner.ts` — runtime/event execution after load\n- `src/discovery/builtin.ts` — native auto-discovery provider for extension modules\n- `src/config/settings.ts` — loads merged `extensions` / `disabledExtensions` settings\n\n---\n\n## Inputs to extension loading\n\n### 1) Auto-discovered native extension modules\n\n`discoverAndLoadExtensions()` first asks discovery providers for `extension-module` capability items, then keeps only provider `native` items.\n\nEffective native locations:\n\n- Project: `<cwd>/.xcsh/extensions`\n- User: `~/.xcsh/agent/extensions`\n\nPath roots come from the native provider (`SOURCE_PATHS.native`).\n\nNotes:\n\n- Native auto-discovery is currently `.xcsh` based.\n- Legacy `.pi` is still accepted in `package.json` manifest keys (`pi.extensions`), but not as a native root here.\n\n### 2) Explicitly configured paths\n\nAfter auto-discovery, configured paths are appended and resolved.\n\nConfigured path sources in the main session startup path (`sdk.ts`):\n\n1. CLI-provided paths (`--extension/-e`, and `--hook` is also treated as an extension path)\n2. Settings `extensions` array (merged global + project settings)\n\nGlobal settings file:\n\n- `~/.xcsh/agent/config.yml` (or custom agent dir via `PI_CODING_AGENT_DIR`)\n\nProject settings file:\n\n- `<cwd>/.xcsh/settings.json`\n\nExamples:\n\n```yaml\n# ~/.xcsh/agent/config.yml\nextensions:\n - ~/my-exts/safety.ts\n - ./local/ext-pack\n```\n\n```json\n{\n \"extensions\": [\"./.xcsh/extensions/my-extra\"]\n}\n```\n\n---\n\n## Enable/disable controls\n\n### Disable discovery\n\n- CLI: `--no-extensions`\n- SDK option: `disableExtensionDiscovery`\n\nBehavior split:\n\n- SDK: when `disableExtensionDiscovery=true`, it still loads `additionalExtensionPaths` via `loadExtensions()`.\n- CLI path building (`main.ts`) currently clears CLI extension paths when `--no-extensions` is set, so explicit `-e/--hook` are not forwarded in that mode.\n\n### Disable specific extension modules\n\n`disabledExtensions` setting filters by extension id format:\n\n- `extension-module:<derivedName>`\n\n`derivedName` is based on entry path (`getExtensionNameFromPath`), for example:\n\n- `/x/foo.ts` -> `foo`\n- `/x/bar/index.ts` -> `bar`\n\nExample:\n\n```yaml\ndisabledExtensions:\n - extension-module:foo\n```\n\n---\n\n## Path and entry resolution\n\n### Path normalization\n\nFor configured paths:\n\n1. Normalize unicode spaces\n2. Expand `~`\n3. If relative, resolve against current `cwd`\n\n### If configured path is a file\n\nIt is used directly as a module entry candidate.\n\n### If configured path is a directory\n\nResolution order:\n\n1. `package.json` in that directory with `xcsh.extensions` (or legacy `pi.extensions`) -> use declared entries\n2. `index.ts`\n3. `index.js`\n4. Otherwise scan one level for extension entries:\n - direct `*.ts` / `*.js`\n - subdir `index.ts` / `index.js`\n - subdir `package.json` with `xcsh.extensions` / `pi.extensions`\n\nRules and constraints:\n\n- no recursive discovery beyond one subdirectory level\n- declared `extensions` manifest entries are resolved relative to that package directory\n- declared entries are included only if file exists/access is allowed\n- in `*/index.{ts,js}` pairs, TypeScript is preferred over JavaScript\n- symlinks are treated as eligible files/directories\n\n### Ignore behavior differs by source\n\n- Native auto-discovery (`discoverExtensionModulePaths` in discovery helpers) uses native glob with `gitignore: true` and `hidden: false`.\n- Explicit configured directory scanning in `loader.ts` uses `readdir` rules and does **not** apply gitignore filtering.\n\n---\n\n## Load order and precedence\n\n`discoverAndLoadExtensions()` builds one ordered list and then calls `loadExtensions()`.\n\nOrder:\n\n1. Native auto-discovered modules\n2. Explicit configured paths (in provided order)\n\nIn `sdk.ts`, configured order is:\n\n1. CLI additional paths\n2. Settings `extensions`\n\nDe-duplication:\n\n- absolute path based\n- first seen path wins\n- later duplicates are ignored\n\nImplication: if the same module path is both auto-discovered and explicitly configured, it is loaded once at the first position (auto-discovered stage).\n\n---\n\n## Module import and factory contract\n\nEach candidate path is loaded with dynamic import:\n\n- `await import(resolvedPath)`\n- factory is `module.default ?? module`\n- factory must be a function (`ExtensionFactory`)\n\nIf export is not a function, that path fails with a structured error and loading continues.\n\n---\n\n## Failure handling and isolation\n\n### During loading\n\nPer extension path, failures are captured as `{ path, error }` and do not stop other paths from loading.\n\nCommon cases:\n\n- import failure / missing file\n- invalid factory export (non-function)\n- exception thrown while executing factory\n\n### Runtime isolation model\n\n- Extensions are **not sandboxed** (same process/runtime).\n- They share one `EventBus` and one `ExtensionRuntime` instance.\n- During load, runtime action methods intentionally throw `ExtensionRuntimeNotInitializedError`; action wiring happens later in `ExtensionRunner.initialize()`.\n\n### After loading\n\nWhen events run through `ExtensionRunner`, handler exceptions are caught and emitted as extension errors instead of crashing the runner loop.\n\n---\n\n## Minimal user/project layout examples\n\n### User-level\n\n```text\n~/.xcsh/agent/\n config.yml\n extensions/\n guardrails.ts\n audit/\n index.ts\n```\n\n### Project-level\n\n```text\n<repo>/\n .xcsh/\n settings.json\n extensions/\n checks/\n package.json\n lint-gates.ts\n```\n\n`checks/package.json`:\n\n```json\n{\n \"xcsh\": {\n \"extensions\": [\"./src/check-a.ts\", \"./src/check-b.js\"]\n }\n}\n```\n\nLegacy manifest key still accepted:\n\n```json\n{\n \"pi\": {\n \"extensions\": [\"./index.ts\"]\n }\n}\n```\n",
|
|
123
124
|
"en/extensions/extensions.md": "---\ntitle: Extensions\ndescription: Extension runtime overview covering types, runner lifecycle, registration, and discovery.\nsidebar:\n order: 1\n label: Overview\n---\n\n# Extensions\n\nPrimary guide for authoring runtime extensions in `packages/coding-agent`.\n\nThis document covers the current extension runtime in:\n\n- `src/extensibility/extensions/types.ts`\n- `src/extensibility/extensions/runner.ts`\n- `src/extensibility/extensions/wrapper.ts`\n- `src/extensibility/extensions/index.ts`\n- `src/modes/controllers/extension-ui-controller.ts`\n\nFor discovery paths and filesystem loading rules, see `docs/extension-loading.md`.\n\n## What an extension is\n\nAn extension is a TS/JS module exporting a default factory:\n\n```ts\nimport type { ExtensionAPI } from \"@f5-sales-demo/xcsh\";\n\nexport default function myExtension(pi: ExtensionAPI) {\n // register handlers/tools/commands/renderers\n}\n```\n\nExtensions can combine all of the following in one module:\n\n- event handlers (`pi.on(...)`)\n- LLM-callable tools (`pi.registerTool(...)`)\n- slash commands (`pi.registerCommand(...)`)\n- keyboard shortcuts and flags\n- custom message rendering\n- session/message injection APIs (`sendMessage`, `sendUserMessage`, `appendEntry`)\n\n## Runtime model\n\n1. Extensions are imported and their factory functions run.\n2. During that load phase, registration methods are valid; runtime action methods are not yet initialized.\n3. `ExtensionRunner.initialize(...)` wires live actions/contexts for the active mode.\n4. Session/agent/tool lifecycle events are emitted to handlers.\n5. Every tool execution is wrapped with extension interception (`tool_call` / `tool_result`).\n\n```text\nExtension lifecycle (simplified)\n\nload paths\n │\n ▼\nimport module + run factory (registration only)\n │\n ▼\nExtensionRunner.initialize(mode/session/tool registry)\n │\n ├─ emit session/agent events to handlers\n ├─ wrap tool execution (tool_call/tool_result)\n └─ expose runtime actions (sendMessage, setActiveTools, ...)\n```\n\nImportant constraint from `loader.ts`:\n\n- calling action methods like `pi.sendMessage()` during extension load throws `ExtensionRuntimeNotInitializedError`\n- register first; perform runtime behavior from events/commands/tools\n\n## Quick start\n\n```ts\nimport type { ExtensionAPI } from \"@f5-sales-demo/xcsh\";\nimport { Type } from \"@sinclair/typebox\";\n\nexport default function (pi: ExtensionAPI) {\n pi.setLabel(\"Safety + Utilities\");\n\n pi.on(\"session_start\", async (_event, ctx) => {\n ctx.ui.notify(`Extension loaded in ${ctx.cwd}`, \"info\");\n });\n\n pi.on(\"tool_call\", async (event) => {\n if (event.toolName === \"bash\" && event.input.command?.includes(\"rm -rf\")) {\n return { block: true, reason: \"Blocked by extension policy\" };\n }\n });\n\n pi.registerTool({\n name: \"hello_extension\",\n label: \"Hello Extension\",\n description: \"Return a greeting\",\n parameters: Type.Object({ name: Type.String() }),\n async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {\n return {\n content: [{ type: \"text\", text: `Hello, ${params.name}` }],\n details: { greeted: params.name },\n };\n },\n });\n\n pi.registerCommand(\"hello-ext\", {\n description: \"Show queue state\",\n handler: async (_args, ctx) => {\n ctx.ui.notify(`pending=${ctx.hasPendingMessages()}`, \"info\");\n },\n });\n}\n```\n\n## Extension API surfaces\n\n## 1) Registration and actions (`ExtensionAPI`)\n\nCore methods:\n\n- `on(event, handler)`\n- `registerTool`, `registerCommand`, `registerShortcut`, `registerFlag`\n- `registerMessageRenderer`\n- `sendMessage`, `sendUserMessage`, `appendEntry`\n- `getActiveTools`, `getAllTools`, `setActiveTools`\n- `getSessionName`, `setSessionName`\n- `setModel`, `getThinkingLevel`, `setThinkingLevel`\n- `registerProvider`\n- `events` (shared event bus)\n\nIn interactive mode, `input` handlers run before the built-in first-message auto-title check. Extensions that call `await pi.setSessionName(...)` from `input` can set the persisted session name and prevent the default auto-generated title from running for that session.\n\nAlso exposed:\n\n- `pi.logger`\n- `pi.typebox`\n- `pi.pi` (package exports)\n\n### Message delivery semantics\n\n`pi.sendMessage(message, options)` supports:\n\n- `deliverAs: \"steer\"` (default) — interrupts current run\n- `deliverAs: \"followUp\"` — queued to run after current run\n- `deliverAs: \"nextTurn\"` — stored and injected on the next user prompt\n- `triggerTurn: true` — starts a turn when idle (`nextTurn` ignores this)\n\n`pi.sendUserMessage(content, { deliverAs })` always goes through prompt flow; while streaming it queues as steer/follow-up.\n\n## 2) Handler context (`ExtensionContext`)\n\nHandlers and tool `execute` receive `ctx` with:\n\n- `ui`\n- `hasUI`\n- `cwd`\n- `sessionManager` (read-only)\n- `modelRegistry`, `model`\n- `getContextUsage()`\n- `compact(...)`\n- `isIdle()`, `hasPendingMessages()`, `abort()`\n- `shutdown()`\n- `getSystemPrompt()`\n\n## 3) Command context (`ExtensionCommandContext`)\n\nCommand handlers additionally get:\n\n- `waitForIdle()`\n- `newSession(...)`\n- `switchSession(...)`\n- `branch(entryId)`\n- `navigateTree(targetId, { summarize })`\n- `reload()`\n\nUse command context for session-control flows; these methods are intentionally separated from general event handlers.\n\n## Event surface (current names and behavior)\n\nCanonical event unions and payload types are in `types.ts`.\n\n### Session lifecycle\n\n- `session_start`\n- `session_before_switch` / `session_switch`\n- `session_before_branch` / `session_branch`\n- `session_before_compact` / `session.compacting` / `session_compact`\n- `session_before_tree` / `session_tree`\n- `session_shutdown`\n\nCancelable pre-events:\n\n- `session_before_switch` → `{ cancel?: boolean }`\n- `session_before_branch` → `{ cancel?: boolean; skipConversationRestore?: boolean }`\n- `session_before_compact` → `{ cancel?: boolean; compaction?: CompactionResult }`\n- `session_before_tree` → `{ cancel?: boolean; summary?: { summary: string; details?: unknown } }`\n\n### Prompt and turn lifecycle\n\n- `input`\n- `before_agent_start`\n- `context`\n- `agent_start` / `agent_end`\n- `turn_start` / `turn_end`\n- `message_start` / `message_update` / `message_end`\n\n### Tool lifecycle\n\n- `tool_call` (pre-exec, may block)\n- `tool_result` (post-exec, may patch content/details/isError)\n- `tool_execution_start` / `tool_execution_update` / `tool_execution_end` (observability)\n\n`tool_result` is middleware-style: handlers run in extension order and each sees prior modifications.\n\n### Reliability/runtime signals\n\n- `auto_compaction_start` / `auto_compaction_end`\n- `auto_retry_start` / `auto_retry_end`\n- `ttsr_triggered`\n- `todo_reminder`\n\n### User command interception\n\n- `user_bash` (override with `{ result }`)\n- `user_python` (override with `{ result }`)\n\n### `resources_discover`\n\n`resources_discover` exists in extension types and `ExtensionRunner`.\nCurrent runtime note: `ExtensionRunner.emitResourcesDiscover(...)` is implemented, but there are no `AgentSession` callsites invoking it in the current codebase.\n\n## Tool authoring details\n\n`registerTool` uses `ToolDefinition` from `types.ts`.\n\nCurrent `execute` signature:\n\n```ts\nexecute(\n toolCallId,\n params,\n signal,\n onUpdate,\n ctx,\n): Promise<AgentToolResult>\n```\n\nTemplate:\n\n```ts\npi.registerTool({\n name: \"my_tool\",\n label: \"My Tool\",\n description: \"...\",\n parameters: Type.Object({}),\n async execute(_id, _params, signal, onUpdate, ctx) {\n if (signal?.aborted) {\n return { content: [{ type: \"text\", text: \"Cancelled\" }] };\n }\n onUpdate?.({ content: [{ type: \"text\", text: \"Working...\" }] });\n return { content: [{ type: \"text\", text: \"Done\" }], details: {} };\n },\n onSession(event, ctx) {\n // reason: start|switch|branch|tree|shutdown\n },\n renderCall(args, theme) {\n // optional TUI render\n },\n renderResult(result, options, theme, args) {\n // optional TUI render\n },\n});\n```\n\n`tool_call`/`tool_result` intercept all tools once the registry is wrapped in `sdk.ts`, including built-ins and extension/custom tools.\n\n## UI integration points\n\n`ctx.ui` implements the `ExtensionUIContext` interface. Support differs by mode.\n\n### Interactive mode (`extension-ui-controller.ts`)\n\nSupported:\n\n- dialogs: `select`, `confirm`, `input`, `editor`\n- notifications/status/editor text/terminal input/custom overlays\n- theme listing/loading by name (`setTheme` supports string names)\n- tools expanded toggle\n\nCurrent no-op methods in this controller:\n\n- `setFooter`\n- `setHeader`\n- `setEditorComponent`\n\nAlso note: `setWidget` currently routes to status-line text via `setHookWidget(...)`.\n\n### RPC mode (`rpc-mode.ts`)\n\n`ctx.ui` is backed by RPC `extension_ui_request` events:\n\n- dialog methods (`select`, `confirm`, `input`, `editor`) round-trip to client responses\n- fire-and-forget methods emit requests (`notify`, `setStatus`, `setWidget` for string arrays, `setTitle`, `setEditorText`)\n\nUnsupported/no-op in RPC implementation:\n\n- `onTerminalInput`\n- `custom`\n- `setFooter`, `setHeader`, `setEditorComponent`\n- `setWorkingMessage`\n- theme switching/loading (`setTheme` returns failure)\n- tool expansion controls are inert\n\n### Print/headless/subagent paths\n\nWhen no UI context is supplied to runner init, `ctx.hasUI` is `false` and methods are no-op/default-returning.\n\n### Background interactive mode\n\nBackground mode installs a non-interactive UI context object. In current implementation, `ctx.hasUI` may still be `true` while interactive dialogs return defaults/no-op behavior.\n\n## Session and state patterns\n\nFor durable extension state:\n\n1. Persist with `pi.appendEntry(customType, data)`.\n2. Rebuild state from `ctx.sessionManager.getBranch()` on `session_start`, `session_branch`, `session_tree`.\n3. Keep tool result `details` structured when state should be visible/reconstructible from tool result history.\n\nExample reconstruction pattern:\n\n```ts\npi.on(\"session_start\", async (_event, ctx) => {\n let latest;\n for (const entry of ctx.sessionManager.getBranch()) {\n if (entry.type === \"custom\" && entry.customType === \"my-state\") {\n latest = entry.data;\n }\n }\n // restore from latest\n});\n```\n\n## Rendering extension points\n\n## Custom message renderer\n\n```ts\npi.registerMessageRenderer(\"my-type\", (message, { expanded }, theme) => {\n // return pi-tui Component\n});\n```\n\nUsed by interactive rendering when custom messages are displayed.\n\n## Tool call/result renderer\n\nProvide `renderCall` / `renderResult` on `registerTool` definitions for custom tool visualization in TUI.\n\n## Constraints and pitfalls\n\n- Runtime actions are unavailable during extension load.\n- `tool_call` errors block execution (fail-closed).\n- Command name conflicts with built-ins are skipped with diagnostics.\n- Reserved shortcuts are ignored (`ctrl+c`, `ctrl+d`, `ctrl+z`, `ctrl+k`, `ctrl+p`, `ctrl+l`, `ctrl+o`, `ctrl+t`, `ctrl+g`, `shift+tab`, `shift+ctrl+p`, `alt+enter`, `escape`, `enter`).\n- Treat `ctx.reload()` as terminal for the current command handler frame.\n\n## Extensions vs hooks vs custom-tools\n\nUse the right surface:\n\n- **Extensions** (`src/extensibility/extensions/*`): unified system (events + tools + commands + renderers + provider registration).\n- **Hooks** (`src/extensibility/hooks/*`): separate legacy event API.\n- **Custom-tools** (`src/extensibility/custom-tools/*`): tool-focused modules; when loaded alongside extensions they are adapted and still pass through extension interception wrappers.\n\nIf you need one package that owns policy, tools, command UX, and rendering together, use extensions.\n",
|
|
124
125
|
"en/extensions/gemini-manifest-extensions.md": "---\ntitle: Gemini Manifest Extensions\ndescription: Gemini manifest extension format for cross-platform skill and agent compatibility.\nsidebar:\n order: 7\n label: Gemini manifest\n---\n\n# Gemini Manifest Extensions (`gemini-extension.json`)\n\nThis document covers how the coding-agent discovers and parses Gemini-style manifest extensions (`gemini-extension.json`) into the `extensions` capability.\n\nIt does **not** cover TypeScript/JavaScript extension module loading (`extensions/*.ts`, `index.ts`, `package.json xcsh.extensions`), which is documented in `extension-loading.md`.\n\n## Implementation files\n\n- [`../src/discovery/gemini.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/gemini.ts)\n- [`../src/discovery/builtin.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/builtin.ts)\n- [`../src/discovery/helpers.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/helpers.ts)\n- [`../src/capability/extension.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/capability/extension.ts)\n- [`../src/capability/index.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/capability/index.ts)\n- [`../src/extensibility/extensions/loader.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/extensions/loader.ts)\n\n---\n\n## What gets discovered\n\nThe Gemini provider (`id: gemini`, priority `60`) registers an `extensions` loader that scans two fixed roots:\n\n- User: `~/.gemini/extensions`\n- Project: `<cwd>/.gemini/extensions`\n\nPath resolution is direct from `ctx.home` and `ctx.cwd` via `getUserPath()` / `getProjectPath()`.\n\nImportant scope rule: project lookup is **cwd-only**. It does not walk parent directories.\n\n---\n\n## Directory scan rules\n\nFor each root (`~/.gemini/extensions` and `<cwd>/.gemini/extensions`), discovery does:\n\n1. `readDirEntries(root)`\n2. keep only direct child directories (`entry.isDirectory()`)\n3. for each child `<name>`, attempt to read exactly:\n - `<root>/<name>/gemini-extension.json`\n\nThere is no recursive scan beyond one directory level.\n\n### Hidden directories\n\nGemini manifest discovery does **not** filter out dot-prefixed directory names. If a hidden child directory exists and contains `gemini-extension.json`, it is considered.\n\n### Missing/unreadable files\n\nIf `gemini-extension.json` is missing or unreadable, that directory is skipped silently (no warning).\n\n---\n\n## Manifest shape (as implemented)\n\nThe capability type defines this manifest shape:\n\n```ts\ninterface ExtensionManifest {\n name?: string;\n description?: string;\n mcpServers?: Record<string, Omit<MCPServer, \"name\" | \"_source\">>;\n tools?: unknown[];\n context?: unknown;\n}\n```\n\nDiscovery-time behavior is intentionally loose:\n\n- JSON parse success is required.\n- There is no runtime schema validation for field types/content beyond JSON syntax.\n- The parsed object is stored as `manifest` on the capability item.\n\n### Name normalization\n\n`Extension.name` is set to:\n\n1. `manifest.name` if it is not `null`/`undefined`\n2. otherwise the extension directory name\n\nNo string-type enforcement is applied here.\n\n---\n\n## Materialization into capability items\n\nA valid parsed manifest creates one `Extension` capability item:\n\n```ts\n{\n name: manifest.name ?? <directory-name>,\n path: <extension-directory>,\n manifest: <parsed-json>,\n level: \"user\" | \"project\",\n _source: {\n provider: \"gemini\",\n providerName: \"Gemini CLI\" // attached by capability registry\n path: <absolute-manifest-path>,\n level: \"user\" | \"project\"\n }\n}\n```\n\nNotes:\n\n- `_source.path` is normalized to an absolute path by `createSourceMeta()`.\n- Registry-level capability validation for `extensions` only checks presence of `name` and `path`.\n- Manifest internals (`mcpServers`, `tools`, `context`) are not validated during discovery.\n\n---\n\n## Error handling and warning semantics\n\n### Warned\n\n- Invalid JSON in a manifest file:\n - warning format: `Invalid JSON in <manifestPath>`\n\n### Not warned (silent skip)\n\n- `extensions` directory missing\n- child directory has no `gemini-extension.json`\n- unreadable manifest file\n- manifest JSON is syntactically valid but semantically odd/incomplete\n\nThis means partial validity is accepted: only syntactic JSON failure emits a warning.\n\n---\n\n## Precedence and deduplication with other sources\n\n`extensions` capability is aggregated across providers by the capability registry.\n\nCurrent providers for this capability:\n\n- `native` (`packages/coding-agent/src/discovery/builtin.ts`) priority `100`\n- `gemini` (`packages/coding-agent/src/discovery/gemini.ts`) priority `60`\n\nDedup key is `ext.name` (`extensionCapability.key = ext => ext.name`).\n\n### Cross-provider precedence\n\nHigher-priority provider wins on duplicate extension names.\n\n- If `native` and `gemini` both emit extension name `foo`, the native item is kept.\n- Lower-priority duplicate is retained only in `result.all` with `_shadowed = true`.\n\n### Intra-provider order effects\n\nBecause dedup is “first seen wins”, provider-local item order matters.\n\n- Gemini loader appends **user first**, then **project**.\n- Therefore, duplicate names between `~/.gemini/extensions` and `<cwd>/.gemini/extensions` keep the user entry and shadow the project entry.\n\nBy contrast, native provider builds config dir order differently (`project` then `user` in `getConfigDirs()`), so native intra-provider shadowing is the opposite direction.\n\n---\n\n## User vs project behavior summary\n\nFor Gemini manifests specifically:\n\n- Both user and project roots are scanned every load.\n- Project root is fixed to `<cwd>/.gemini/extensions` (no ancestor walk).\n- Duplicate names inside Gemini source resolve to user-first.\n- Duplicate names against higher-priority providers (notably native) lose by priority.\n\n---\n\n## Boundary: discovery metadata vs runtime extension loading\n\n`gemini-extension.json` discovery currently feeds capability metadata (`Extension` items). It does **not** directly load runnable TS/JS extension modules.\n\nRuntime module loading (`discoverAndLoadExtensions()` / `loadExtensions()`) uses `extension-modules` and explicit paths, and currently filters auto-discovered modules to provider `native` only.\n\nPractical implication:\n\n- Gemini manifest extensions are discoverable as capability records.\n- They are not, by themselves, executed as runtime extension modules by the extension loader pipeline.\n\nThis boundary is intentional in current implementation and explains why manifest discovery and executable module loading can diverge.\n",
|
|
@@ -126,7 +127,7 @@ export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
|
|
|
126
127
|
"en/extensions/plugin-manager-installer-plumbing.md": "---\ntitle: Plugin Manager and Installer Plumbing\ndescription: Plugin manager internals covering installation, validation, dependency resolution, and lifecycle management.\nsidebar:\n order: 5\n label: Plugin manager\n---\n\n# Plugin manager and installer plumbing\n\nThis document describes how `xcsh plugin` operations mutate plugin state on disk and how installed plugins become runtime capabilities (tools today, hooks/commands path resolution available).\n\n## Scope and architecture\n\nThere are two plugin-management implementations in the codebase:\n\n1. **Active path used by CLI commands**: `PluginManager` (`src/extensibility/plugins/manager.ts`)\n2. **Legacy helper module**: installer functions (`src/extensibility/plugins/installer.ts`)\n\n`xcsh plugin ...` command execution goes through `PluginManager`.\n\n`installer.ts` still documents important safety checks and filesystem behavior, but it is not the path used by `src/commands/plugin.ts` + `src/cli/plugin-cli.ts`.\n\n## Lifecycle: from CLI invocation to runtime availability\n\n```text\nxcsh plugin <action> ...\n -> src/commands/plugin.ts\n -> runPluginCommand(...) in src/cli/plugin-cli.ts\n -> PluginManager method (install/list/uninstall/link/...) \n -> mutate ~/.xcsh/plugins/{package.json,node_modules,xcsh-plugins.lock.json}\n -> runtime discovery: discoverAndLoadCustomTools(...)\n -> getAllPluginToolPaths(cwd)\n -> custom tool loader imports tool modules\n```\n\n### Command entrypoints\n\n- `src/commands/plugin.ts` defines command/flags and forwards to `runPluginCommand`.\n- `src/cli/plugin-cli.ts` maps subcommands to `PluginManager` methods:\n - `install`, `uninstall`, `list`, `link`, `doctor`, `features`, `config`, `enable`, `disable`\n- No explicit `update` action exists; update is done by re-running `install` with a new package/version spec.\n\n## On-disk model\n\nGlobal plugin state lives under `~/.xcsh/plugins`:\n\n- `package.json` — dependency manifest used by `bun install`/`bun uninstall`\n- `node_modules/` — installed plugin packages or symlinks\n- `xcsh-plugins.lock.json` — runtime state:\n - enabled/disabled per plugin\n - selected feature set per plugin\n - persisted plugin settings\n\nProject-local overrides live at:\n\n- `<cwd>/.xcsh/plugin-overrides.json`\n\nOverrides are read-only from manager/loader perspective (no write path here) and can disable plugins or override features/settings for this project.\n\n## Plugin spec parsing and metadata interpretation\n\n## Install spec grammar\n\n`parsePluginSpec` (`parser.ts`) supports:\n\n- `pkg` -> `features: null` (defaults behavior)\n- `pkg[*]` -> enable all manifest features\n- `pkg[]` -> enable no optional features\n- `pkg[a,b]` -> enable named features\n- `@scope/pkg@1.2.3[feat]` -> scoped + versioned package with explicit feature selection\n\n`extractPackageName` strips version suffix for on-disk path lookup after install.\n\n## Manifest source and required fields\n\nManifest is resolved as:\n\n1. `package.json.xcsh`\n2. fallback `package.json.pi`\n3. fallback `{ version: package.version }`\n\nImplications:\n\n- There is no strict schema validation in manager/loader.\n- A package missing `xcsh`/`pi` is still installable and listable.\n- Runtime plugin loading (`getEnabledPlugins`) skips packages without `xcsh`/`pi` manifest.\n- `manifest.version` is always overwritten from package `version`.\n\nMalformed `package.json` JSON is a hard failure at read time; malformed manifest shape may fail later only when specific fields are consumed.\n\n## Install/update flow (`PluginManager.install`)\n\n1. Parse feature bracket syntax from install spec.\n2. Validate package name against regex + shell-metacharacter denylist.\n3. Ensure plugin `package.json` exists (`xcsh-plugins`, private dependencies map).\n4. Run `bun install <packageSpec>` in `~/.xcsh/plugins`.\n5. Read installed package `node_modules/<name>/package.json`.\n6. Resolve manifest and compute `enabledFeatures`:\n - `[*]`: all declared features (or `null` if no feature map)\n - `[a,b]`: validates each feature exists in manifest features map\n - `[]`: empty feature list\n - bare spec: `null` (use defaults policy later in loader)\n7. Upsert lockfile runtime state: `{ version, enabledFeatures, enabled: true }`.\n\n### Update semantics\n\nBecause update is install-driven:\n\n- `xcsh plugin install pkg@newVersion` updates dependency and lockfile version.\n- Existing settings are preserved; state entry is overwritten for version/features/enabled.\n- No separate “check updates” or transactional migration logic exists.\n\n## Remove flow (`PluginManager.uninstall`)\n\n1. Validate package name.\n2. Run `bun uninstall <name>` in plugin dir.\n3. Remove plugin runtime state from lockfile:\n - `config.plugins[name]`\n - `config.settings[name]`\n\nIf uninstall command fails, runtime state is not changed.\n\n## List flow (`PluginManager.list`)\n\n1. Read plugin dependency map from `~/.xcsh/plugins/package.json`.\n2. Load lockfile runtime config (missing file -> empty defaults).\n3. Load project overrides (`<cwd>/.xcsh/plugin-overrides.json`, parse/read errors -> empty object with warning).\n4. For each dependency with a resolvable package.json:\n - build `InstalledPlugin` record\n - merge feature/enable state:\n - base from lockfile (or defaults)\n - project overrides can replace feature selection\n - project `disabled` list masks plugin as disabled\n\nThis is the effective state used by CLI status output and settings/features operations.\n\n## Link flow (`PluginManager.link`)\n\n`link` supports local plugin development by symlinking a local package into `~/.xcsh/plugins/node_modules/<pkg.name>`.\n\nBehavior:\n\n1. Resolve `localPath` against manager cwd.\n2. Require local `package.json` and `name` field.\n3. Ensure plugin dirs exist.\n4. For scoped names, create scope directory.\n5. Remove existing path at target link location.\n6. Create symlink.\n7. Add runtime lockfile entry enabled with default features (`null`).\n\nCaveat: current `PluginManager.link` does not enforce the `cwd` path-boundary check present in legacy `installer.ts` (`normalizedPath.startsWith(normalizedCwd)`), so trust is the caller’s responsibility.\n\n## Runtime loading: from installed plugin to callable capabilities\n\n## Discovery gate\n\n`getEnabledPlugins(cwd)` (`plugins/loader.ts`) reads:\n\n- plugin dependency manifest (`package.json`)\n- lockfile runtime state\n- project overrides via `getConfigDirPaths(\"plugin-overrides.json\", { user: false, cwd })`\n\nFiltering:\n\n- skip if no plugin package.json\n- skip if manifest (`xcsh`/`pi`) absent\n- skip if globally disabled in lockfile\n- skip if project-disabled\n\n## Capability path resolution\n\nFor each enabled plugin:\n\n- `resolvePluginToolPaths(plugin)`\n- `resolvePluginHookPaths(plugin)`\n- `resolvePluginCommandPaths(plugin)`\n\nEach resolver includes base entries plus feature entries:\n\n- explicit feature list -> only selected features\n- `enabledFeatures === null` -> enable features marked `default: true`\n\nMissing files are silently skipped (`existsSync` guard).\n\n## Current runtime wiring differences\n\n- **Tools are wired into runtime today** via `discoverAndLoadCustomTools` (`custom-tools/loader.ts`), which calls `getAllPluginToolPaths(cwd)`.\n- Paths are de-duplicated by resolved absolute path in custom tool discovery (`seen` set, first path wins).\n- **Hooks/commands resolvers exist** and are exported, but this code path does not currently wire them into a runtime registry in the same way tools are wired.\n\n## Lock/state management details\n\n`PluginManager` caches runtime config in memory per instance (`#runtimeConfig`) and lazily loads once.\n\nLoad behavior:\n\n- lockfile missing -> `{ plugins: {}, settings: {} }`\n- lockfile read/parse failure -> warning + same empty defaults\n\nSave behavior:\n\n- writes full lockfile JSON pretty-printed each mutation\n\nNo cross-process locking or merge strategy exists; concurrent writers can overwrite each other.\n\n## Safety checks and trust boundaries\n\n## Input/package validation\n\nActive manager path enforces package-name validation:\n\n- regex for scoped/unscoped package specs (optionally with version)\n- explicit shell metacharacter denylist (`[;&|`$(){}[]<>\\\\]`)\n\nThis limits command-injection risk when invoking `bun install/uninstall`.\n\n## Filesystem trust boundary\n\n- Plugin code executes in-process when custom tool modules are imported; no sandboxing.\n- Manifest relative paths are joined against plugin package directory and only existence-checked.\n- The plugin package itself is trusted code once installed.\n\n## Legacy installer-only checks\n\n`installer.ts` includes additional link-time checks not mirrored in `PluginManager.link`:\n\n- local path must resolve inside project cwd\n- extra package name/path traversal guards for symlink target naming\n\nBecause CLI uses `PluginManager`, these stricter link guards are not currently on the main path.\n\n## Failure, partial success, and rollback behavior\n\nThe plugin manager is not transactional.\n\n| Operation stage | Failure behavior | Rollback |\n| --- | --- | --- |\n| `bun install` fails | install aborts with stderr | N/A (no state writes yet) |\n| Install succeeds, then manifest/feature validation fails | command fails | No uninstall rollback; dependency may remain in `node_modules`/`package.json` |\n| Install succeeds, then lockfile write fails | command fails | No rollback of installed package |\n| `bun uninstall` succeeds, lockfile write fails | command fails | Package removed, stale runtime state may remain |\n| `link` removes old target then symlink creation fails | command fails | No restoration of previous link/dir |\n\nOperationally, `doctor --fix` can repair some drift (`bun install`, orphaned config cleanup, invalid-feature cleanup), but it is best-effort.\n\n## Malformed/missing manifest behavior summary\n\n- Missing `xcsh`/`pi` field:\n - install/list: tolerated (minimal manifest)\n - runtime enabled-plugin discovery: skipped as non-plugin\n- Missing feature referenced by install spec or `features --set/--enable`: hard error with available feature list\n- Invalid `plugin-overrides.json`: ignored with fallback to `{}` in both manager and loader paths\n- Missing tool/hook/command file paths referenced by manifest: silently ignored during resolver expansion; flagged as errors only by `doctor`\n\n## Mode differences and precedence\n\n- `--dry-run` (install): returns synthetic install result, no filesystem/network/state writes.\n- `--json`: output formatting only, no behavior change.\n- Project overrides always take precedence over global lockfile for feature/settings view.\n- Effective enablement is `runtimeEnabled && !projectDisabled`.\n\n## Implementation files\n\n- [`src/commands/plugin.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/commands/plugin.ts) — CLI command declaration and flag mapping\n- [`src/cli/plugin-cli.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/cli/plugin-cli.ts) — action dispatch, user-facing command handlers\n- [`src/extensibility/plugins/manager.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/plugins/manager.ts) — active install/remove/list/link/state/doctor implementation\n- [`src/extensibility/plugins/installer.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/plugins/installer.ts) — legacy installer helpers and additional link safety checks\n- [`src/extensibility/plugins/loader.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/plugins/loader.ts) — enabled-plugin discovery and tool/hook/command path resolution\n- [`src/extensibility/plugins/parser.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/plugins/parser.ts) — install spec and package-name parsing helpers\n- [`src/extensibility/plugins/types.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/plugins/types.ts) — manifest/runtime/override type contracts\n- [`src/extensibility/custom-tools/loader.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/extensibility/custom-tools/loader.ts) — runtime wiring for plugin-provided tool modules\n",
|
|
127
128
|
"en/extensions/rulebook-matching-pipeline.md": "---\ntitle: Rulebook Matching Pipeline\ndescription: Rulebook matching pipeline for selecting and applying context-specific instruction sets to agent sessions.\nsidebar:\n order: 6\n label: Rulebook matching\n---\n\n# Rulebook Matching Pipeline\n\nThis document describes how coding-agent discovers rules from supported config formats, normalizes them into a single `Rule` shape, resolves precedence conflicts, and splits the result into:\n\n- **Rulebook rules** (available to the model via system prompt + `rule://` URLs)\n- **TTSR rules** (time-travel stream interruption rules)\n\nIt reflects the current implementation, including partial semantics and metadata that is parsed but not enforced.\n\n## Implementation files\n\n- [`../src/capability/rule.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/capability/rule.ts)\n- [`../src/capability/index.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/capability/index.ts)\n- [`../src/discovery/index.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/index.ts)\n- [`../src/discovery/helpers.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/helpers.ts)\n- [`../src/discovery/builtin.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/builtin.ts)\n- [`../src/discovery/cursor.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/cursor.ts)\n- [`../src/discovery/windsurf.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/windsurf.ts)\n- [`../src/discovery/cline.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/discovery/cline.ts)\n- [`../src/sdk.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/sdk.ts)\n- [`../src/system-prompt.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/system-prompt.ts)\n- [`../src/internal-urls/rule-protocol.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/internal-urls/rule-protocol.ts)\n- [`../src/utils/frontmatter.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/utils/frontmatter.ts)\n\n## 1. Canonical rule shape\n\nAll providers normalize source files into `Rule`:\n\n```ts\ninterface Rule {\n name: string;\n path: string;\n content: string;\n globs?: string[];\n alwaysApply?: boolean;\n description?: string;\n ttsrTrigger?: string;\n _source: SourceMeta;\n}\n```\n\nCapability identity is `rule.name` (`ruleCapability.key = rule => rule.name`).\n\nConsequence: precedence and deduplication are **name-based only**. Two different files with the same `name` are considered the same logical rule.\n\n## 2. Discovery sources and normalization\n\n`src/discovery/index.ts` auto-registers providers. For `rules`, current providers are:\n\n- `native` (priority `100`)\n- `cursor` (priority `50`)\n- `windsurf` (priority `50`)\n- `cline` (priority `40`)\n\n### Native provider (`builtin.ts`)\n\nLoads `.xcsh` rules from:\n\n- project: `<cwd>/.xcsh/rules/*.{md,mdc}`\n- user: `~/.xcsh/agent/rules/*.{md,mdc}`\n\nNormalization:\n\n- `name` = filename without `.md`/`.mdc`\n- frontmatter parsed via `parseFrontmatter`\n- `content` = body (frontmatter stripped)\n- `globs`, `alwaysApply`, `description`, `ttsr_trigger` mapped directly\n\nImportant caveat: `globs` is cast as `string[] | undefined` with no element filtering in this provider.\n\n### Cursor provider (`cursor.ts`)\n\nLoads from:\n\n- user: `~/.cursor/rules/*.{mdc,md}`\n- project: `<cwd>/.cursor/rules/*.{mdc,md}`\n\nNormalization (`transformMDCRule`):\n\n- `description`: kept only if string\n- `alwaysApply`: only `true` is preserved (`false` becomes `undefined`)\n- `globs`: accepts array (string elements only) or single string\n- `ttsr_trigger`: string only\n- `name` from filename without extension\n\n### Windsurf provider (`windsurf.ts`)\n\nLoads from:\n\n- user: `~/.codeium/windsurf/memories/global_rules.md` (fixed rule name `global_rules`)\n- project: `<cwd>/.windsurf/rules/*.md`\n\nNormalization:\n\n- `globs`: array-of-string or single string\n- `alwaysApply`, `description` cast from frontmatter\n- `ttsr_trigger`: string only\n- `name` from filename for project rules\n\n### Cline provider (`cline.ts`)\n\nSearches upward from `cwd` for nearest `.clinerules`:\n\n- if directory: loads `*.md` inside it\n- if file: loads single file as rule named `clinerules`\n\nNormalization:\n\n- `globs`: array-of-string or single string\n- `alwaysApply`: only if boolean\n- `description`: string only\n- `ttsr_trigger`: string only\n\n## 3. Frontmatter parsing behavior and ambiguity\n\nAll providers use `parseFrontmatter` (`utils/frontmatter.ts`) with these semantics:\n\n1. Frontmatter is parsed only when content starts with `---` and has a closing `\\n---`.\n2. Body is trimmed after frontmatter extraction.\n3. If YAML parse fails:\n - warning is logged,\n - parser falls back to simple `key: value` line parsing (`^(\\w+):\\s*(.*)$`).\n\nAmbiguity consequences:\n\n- Fallback parser does not support arrays, nested objects, quoting rules, or hyphenated keys.\n- Fallback values become strings (for example `alwaysApply: true` becomes string `\"true\"`), so providers requiring boolean/string types may drop metadata.\n- `ttsr_trigger` works in fallback (underscore key); keys like `thinking-level` would not.\n- Files without valid frontmatter still load as rules with empty metadata and full content body.\n\n## 4. Provider precedence and deduplication\n\n`loadCapability(\"rules\")` (`capability/index.ts`) merges provider outputs and then deduplicates by `rule.name`.\n\n### Precedence model\n\n- Providers are ordered by priority descending.\n- Equal priority keeps registration order (`cursor` before `windsurf` from `discovery/index.ts`).\n- Dedup is first-wins: first encountered rule name is kept; later same-name items are marked `_shadowed` in `all` and excluded from `items`.\n\nEffective rule provider order is currently:\n\n1. `native` (100)\n2. `cursor` (50)\n3. `windsurf` (50)\n4. `cline` (40)\n\n### Intra-provider ordering caveat\n\nWithin a provider, item order comes from `loadFilesFromDir` glob result ordering plus explicit push order. This is deterministic enough for normal use but not explicitly sorted in code.\n\nNotable source-order differences:\n\n- `native` appends project then user config dirs.\n- `cursor` appends user then project results.\n- `windsurf` appends user `global_rules` first, then project rules.\n- `cline` loads only nearest `.clinerules` source.\n\n## 5. Split into Rulebook, Always-Apply, and TTSR buckets\n\nAfter rule discovery in `createAgentSession` (`sdk.ts`):\n\n1. All discovered rules are scanned.\n2. Rules with `condition` (frontmatter key; `ttsr_trigger` / `ttsrTrigger` accepted as fallback) are registered into `TtsrManager`.\n3. A separate `rulebookRules` list is built with this predicate:\n\n```ts\n!registeredTtsrRuleNames.has(rule.name) && !rule.alwaysApply && !!rule.description\n```\n\n4. An `alwaysApplyRules` list is built:\n\n```ts\n!registeredTtsrRuleNames.has(rule.name) && rule.alwaysApply === true\n```\n\n### Bucket behavior\n\n- **TTSR bucket**: any rule with `condition` (description not required). Takes priority over other buckets.\n- **Always-apply bucket**: `alwaysApply === true`, not TTSR. Full content injected into system prompt. Resolvable via `rule://`.\n- **Rulebook bucket**: must have description, must not be TTSR, must not be `alwaysApply`. Listed in system prompt by name+description; content read on demand via `rule://`.\n- A rule with both `condition` and `alwaysApply` goes to TTSR only (TTSR takes priority).\n- A rule with both `alwaysApply` and `description` goes to always-apply only (not rulebook).\n\n## 6. How metadata affects runtime surfaces\n\n### `description`\n\n- Required for inclusion in rulebook.\n- Rendered in system prompt `<rules>` block.\n- Missing description means rule is not available via `rule://` and not listed in system prompt rules.\n\n### `globs`\n\n- Carried through on `Rule`.\n- Rendered as `<glob>...</glob>` entries in the system prompt rules block.\n- Exposed in rules UI state (`extensions` mode list).\n- **Not enforced for automatic matching in this pipeline.** There is no runtime glob matcher selecting rules by current file/tool target.\n\n### `alwaysApply`\n\n- Parsed and preserved by providers.\n- Used in UI display (`\"always\"` trigger label in extensions state manager).\n- Used as an exclusion condition from `rulebookRules`.\n- **Full rule content is auto-injected into the system prompt** (before the rulebook rules section).\n- Rule is also addressable via `rule://<name>` for re-reading.\n\n### `ttsr_trigger`\n\n- Mapped to `rule.ttsrTrigger`.\n- If present, rule is routed to TTSR manager, not rulebook.\n\n## 7. System prompt inclusion path\n\n`buildSystemPromptInternal` receives both `rules` (rulebook) and `alwaysApplyRules`.\n\nAlways-apply rules are rendered first, injecting their raw content directly into the prompt.\n\nRulebook rules are rendered in a `# Rules` section with:\n\n- `Read rule://<name> when working in matching domain`\n- Each rule's `name`, `description`, and optional `<glob>` list\n\nThis is advisory/contextual: prompt text asks the model to read applicable rules, but code does not enforce glob applicability.\n\n## 8. `rule://` internal URL behavior\n\n`RuleProtocolHandler` is registered with:\n\n```ts\nnew RuleProtocolHandler({ getRules: () => [...rulebookRules, ...alwaysApplyRules] })\n```\n\nImplications:\n\n- `rule://<name>` resolves against both **rulebookRules** and **alwaysApplyRules**.\n- TTSR-only rules and rules with no description and no `alwaysApply` are not addressable via `rule://`.\n- Resolution is exact name match.\n- Unknown names return error listing available rule names.\n- Returned content is raw `rule.content` (frontmatter stripped), content type `text/markdown`.\n\n## 9. Known partial / non-enforced semantics\n\n1. Provider descriptions mention legacy files (`.cursorrules`, `.windsurfrules`), but current loader code paths do not actually read those files.\n2. `globs` metadata is surfaced to prompt/UI but not enforced by rule selection logic.\n3. Rule selection for `rule://` includes rulebook and always-apply rules, but not TTSR-only rules.\n4. Discovery warnings (`loadCapability(\"rules\").warnings`) are produced but `createAgentSession` does not currently surface/log them in this path.\n",
|
|
128
129
|
"en/extensions/skills.md": "---\ntitle: Skills\ndescription: Skills system for registering, discovering, and invoking specialized capabilities in the coding agent.\nsidebar:\n order: 3\n label: Skills\n---\n\n# Skills\n\nSkills are file-backed capability packs discovered at startup and exposed to the model as:\n\n- lightweight metadata in the system prompt (name + description)\n- on-demand content via `read skill://...`\n- optional interactive `/skill:<name>` commands\n\nThis document covers current runtime behavior in `src/extensibility/skills.ts`, `src/discovery/builtin.ts`, `src/internal-urls/skill-protocol.ts`, and `src/discovery/agents-md.ts`.\n\n## What a skill is in this codebase\n\nA discovered skill is represented as:\n\n- `name`\n- `description`\n- `filePath` (the `SKILL.md` path)\n- `baseDir` (skill directory)\n- source metadata (`provider`, `level`, path)\n\nThe runtime only requires `name` and `path` for validity. In practice, matching quality depends on `description` being meaningful.\n\n## Required layout and SKILL.md expectations\n\n### Directory layout\n\nFor provider-based discovery (native/Claude/Codex/Agents/plugin providers), skills are discovered as **one level under `skills/`**:\n\n- `<skills-root>/<skill-name>/SKILL.md`\n\nNested patterns like `<skills-root>/group/<skill>/SKILL.md` are not discovered by provider loaders.\n\nFor `skills.customDirectories`, scanning uses the same non-recursive layout (`*/SKILL.md`).\n\n```text\nProvider-discovered layout (non-recursive under skills/):\n\n<root>/skills/\n ├─ postgres/\n │ └─ SKILL.md ✅ discovered\n ├─ pdf/\n │ └─ SKILL.md ✅ discovered\n └─ team/\n └─ internal/\n └─ SKILL.md ❌ not discovered by provider loaders\n\nCustom-directory scanning is also non-recursive, so nested paths are ignored unless you point `customDirectories` at that nested parent.\n```\n\n### `SKILL.md` frontmatter\n\nSupported frontmatter fields on the skill type:\n\n- `name?: string`\n- `description?: string`\n- `globs?: string[]`\n- `alwaysApply?: boolean`\n- additional keys are preserved as unknown metadata\n\nCurrent runtime behavior:\n\n- `name` defaults to the skill directory name\n- `description` is required for:\n - native `.xcsh` provider skill discovery (`requireDescription: true`)\n - `skills.customDirectories` scans via `scanSkillsFromDir` in `src/discovery/helpers.ts` (non-recursive)\n- non-native providers can load skills without description\n\n## Discovery pipeline\n\n`discoverSkills()` in `src/extensibility/skills.ts` does two passes:\n\n1. **Capability providers** via `loadCapability(\"skills\")`\n2. **Custom directories** via `scanSkillsFromDir(..., { requireDescription: true })` (one-level directory enumeration)\n\nIf `skills.enabled` is `false`, discovery returns no skills.\n\n### Built-in skill providers and precedence\n\nProvider ordering is priority-first (higher wins), then registration order for ties.\n\nCurrent registered skill providers:\n\n1. `native` (priority 100) — `.xcsh` user/project skills via `src/discovery/builtin.ts`\n2. `claude` (priority 80)\n3. priority 70 group (in registration order):\n - `claude-plugins`\n - `agents`\n - `codex`\n\nDedup key is skill name. First item with a given name wins.\n\n### Source toggles and filtering\n\n`discoverSkills()` applies these controls:\n\n- source toggles: `enableCodexUser`, `enableClaudeUser`, `enableClaudeProject`, `enablePiUser`, `enablePiProject`\n- glob filters on skill name:\n - `ignoredSkills` (exclude)\n - `includeSkills` (include allowlist; empty means include all)\n\nFilter order is:\n\n1. source enabled\n2. not ignored\n3. included (if include list present)\n\nFor providers other than codex/claude/native (for example `agents`, `claude-plugins`), enablement currently falls back to: enabled if **any** built-in source toggle is enabled.\n\n### Collision and duplicate handling\n\n- Capability dedup already keeps first skill per name (highest-precedence provider)\n- `extensibility/skills.ts` additionally:\n - de-duplicates identical files by `realpath` (symlink-safe)\n - emits collision warnings when a later skill name conflicts\n - keeps the convenience `discoverSkillsFromDir({ dir, source })` API as a thin adapter over `scanSkillsFromDir`\n- Custom-directory skills are merged after provider skills and follow the same collision behavior\n\n## Runtime usage behavior\n\n### System prompt exposure\n\nSystem prompt construction (`src/system-prompt.ts`) uses discovered skills as follows:\n\n- if `read` tool is available:\n - include discovered skills list in prompt\n- otherwise:\n - omit discovered list\n\nTask tool subagents receive the session's discovered/provided skills list via normal session creation; there is no per-task skill pinning override.\n\n### Interactive `/skill:<name>` commands\n\nIf `skills.enableSkillCommands` is true, interactive mode registers one slash command per discovered skill.\n\n`/skill:<name> [args]` behavior:\n\n- reads the skill file directly from `filePath`\n- strips frontmatter\n- injects skill body as a follow-up custom message\n- appends metadata (`Skill: <path>`, optional `User: <args>`)\n\n## `skill://` URL behavior\n\n`src/internal-urls/skill-protocol.ts` supports:\n\n- `skill://<name>` → resolves to that skill's `SKILL.md`\n- `skill://<name>/<relative-path>` → resolves inside that skill directory\n\n```text\nskill:// URL resolution\n\nskill://pdf\n -> <pdf-base>/SKILL.md\n\nskill://pdf/references/tables.md\n -> <pdf-base>/references/tables.md\n\nGuards:\n- reject absolute paths\n- reject `..` traversal\n- reject any resolved path escaping <pdf-base>\n```\n\nResolution details:\n\n- skill name must match exactly\n- relative paths are URL-decoded\n- absolute paths are rejected\n- path traversal (`..`) is rejected\n- resolved path must remain within `baseDir`\n- missing files return an explicit `File not found` error\n\nContent type:\n\n- `.md` => `text/markdown`\n- everything else => `text/plain`\n\nNo fallback search is performed for missing assets.\n\n## Skills vs XCSH.md, commands, tools, hooks\n\n### Skills vs XCSH.md\n\n- **Skills**: named, optional capability packs selected by task context or explicitly requested\n- **XCSH.md/context files**: persistent instruction files loaded as context-file capability and merged by level/depth rules\n\n`src/discovery/agents-md.ts` specifically walks ancestor directories from `cwd` to discover standalone `XCSH.md` files (up to depth 20), excluding hidden-directory segments.\n\n### Skills vs slash commands\n\n- **Skills**: model-readable knowledge/workflow content\n- **Slash commands**: user-invoked command entry points\n- `/skill:<name>` is a convenience wrapper that injects skill text; it does not change skill discovery semantics\n\n### Skills vs custom tools\n\n- **Skills**: documentation/workflow content loaded through prompt context and `read`\n- **Custom tools**: executable tool APIs callable by the model with schemas and runtime side effects\n\n### Skills vs hooks\n\n- **Skills**: passive content\n- **Hooks**: event-driven runtime interceptors that can block/modify behavior during execution\n\n## Practical authoring guidance tied to discovery logic\n\n- Put each skill in its own directory: `<skills-root>/<skill-name>/SKILL.md`\n- Always include explicit `name` and `description` frontmatter\n- Keep referenced assets under the same skill directory and access with `skill://<name>/...`\n- For nested taxonomy (`team/domain/skill`), point `skills.customDirectories` to the nested parent directory; scanning itself remains non-recursive\n- Avoid duplicate skill names across sources; first match wins by provider precedence\n",
|
|
129
|
-
"en/index.md": "---\ntitle: xcsh Documentation\ndescription: AI-powered development CLI with TypeScript coding agent and Rust native layer for long-lived sessions, MCP support, and platform packaging.\nsidebar:\n order: 0\n label: Overview\n---\n\nxcsh is an AI-powered development CLI with a TypeScript coding agent and a\nRust native layer (`pi-natives`). It extends the open-source\n[`badlogic/pi-mono`](https://github.com/badlogic/pi-mono) line with a\nhardened runtime, long-lived sessions with tree navigation and compaction,\na Python IPython tool, full MCP support, a skills system, and platform\npackaging targeting Linux, macOS, and Windows.\n\n## Where to start\n\n- **[F5 XC Contexts](runtime-tools/context-command)** — connect to F5 Distributed Cloud\n tenants. Create contexts, switch between them, manage namespaces and credentials.\n- **Configuration** — how xcsh discovers, resolves, and layers configuration.\n- **Runtime & Tools** — the bash / notebook / resolve tool runtimes and the\n slash-command surface.\n- **Sessions** — append-only entry log, tree navigation, compaction, and the\n autonomous memory system.\n- **Natives (Rust)** — architecture of the `pi-natives` N-API addon that\n powers shell / PTY / media / search.\n- **MCP** — configuration, protocol internals, runtime lifecycle, and how to\n author servers and tools.\n- **Extensions, Skills & Plugins** — authoring, loading, matching rules, the\n marketplace, and the plugin installer.\n- **Providers & Models** — model configuration, streaming internals, and the\n Python / IPython runtime.\n- **TUI** — theming, the `/tree` command, and integration hooks for\n extensions and custom tools.\n\n## How this doc set is organized\n\nEach top-level group in the sidebar maps to a subsystem of the agent. Within\na group, pages run from \"overview\" to \"internals\" so you can stop reading\nwhen you have enough context for the task at hand.\n",
|
|
130
|
+
"en/index.md": "---\ntitle: xcsh Documentation\ndescription: AI-powered development CLI with TypeScript coding agent and Rust native layer for long-lived sessions, MCP support, and platform packaging.\nsidebar:\n order: 0\n label: Overview\n---\n\nxcsh is an AI-powered development CLI with a TypeScript coding agent and a\nRust native layer (`pi-natives`). It extends the open-source\n[`badlogic/pi-mono`](https://github.com/badlogic/pi-mono) line with a\nhardened runtime, long-lived sessions with tree navigation and compaction,\na Python IPython tool, full MCP support, a skills system, and platform\npackaging targeting Linux, macOS, and Windows.\n\n## Where to start\n\n- **[F5 XC Contexts](runtime-tools/context-command)** — connect to F5 Distributed Cloud\n tenants. Create contexts, switch between them, manage namespaces and credentials.\n- **[Alpine Container Deployment](container/alpine-deployment)** — run `xcsh` inside security-hardened Alpine containers with multi-cloud CLI tool integration.\n- **Configuration** — how xcsh discovers, resolves, and layers configuration.\n- **Runtime & Tools** — the bash / notebook / resolve tool runtimes and the\n slash-command surface.\n- **Sessions** — append-only entry log, tree navigation, compaction, and the\n autonomous memory system.\n- **Natives (Rust)** — architecture of the `pi-natives` N-API addon that\n powers shell / PTY / media / search.\n- **MCP** — configuration, protocol internals, runtime lifecycle, and how to\n author servers and tools.\n- **Extensions, Skills & Plugins** — authoring, loading, matching rules, the\n marketplace, and the plugin installer.\n- **Providers & Models** — model configuration, streaming internals, and the\n Python / IPython runtime.\n- **TUI** — theming, the `/tree` command, and integration hooks for\n extensions and custom tools.\n\n## How this doc set is organized\n\nEach top-level group in the sidebar maps to a subsystem of the agent. Within\na group, pages run from \"overview\" to \"internals\" so you can stop reading\nwhen you have enough context for the task at hand.\n",
|
|
130
131
|
"en/mcp/mcp-config.md": "---\ntitle: MCP Configuration\ndescription: MCP server configuration, validation, and management for the coding agent runtime.\nsidebar:\n order: 1\n label: Configuration\n---\n\n# MCP configuration in OMP\n\nThis guide explains how to add, edit, and validate MCP servers for the OMP coding agent.\n\nSource of truth in code:\n\n- Runtime config types: `packages/coding-agent/src/mcp/types.ts`\n- Config writer: `packages/coding-agent/src/mcp/config-writer.ts`\n- Loader + validation: `packages/coding-agent/src/mcp/config.ts`\n- Standalone `mcp.json` discovery: `packages/coding-agent/src/discovery/mcp-json.ts`\n- Schema: `packages/coding-agent/src/config/mcp-schema.json`\n\n## Preferred config locations\n\nOMP can discover MCP servers from multiple tools (`.claude/`, `.cursor/`, `.vscode/`, `opencode.json`, and more), but for OMP-native configuration you should usually use one of these files:\n\n- Project: `.xcsh/mcp.json`\n- User: `~/.xcsh/mcp.json`\n\nOMP also accepts fallback standalone files in the project root:\n\n- `mcp.json`\n- `.mcp.json`\n\nUse `.xcsh/mcp.json` when you want OMP to own the configuration. Use root `mcp.json` / `.mcp.json` only when you want a portable fallback file that other MCP clients may also read.\n\n## Add a schema reference\n\nAdd this line at the top of the file for editor autocomplete and validation:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {}\n}\n```\n\nOMP now writes this automatically when `/mcp add`, `/mcp enable`, `/mcp disable`, `/mcp reauth`, or other config-writing flows create or update an OMP-managed MCP file.\n\n## File shape\n\nOMP supports this top-level structure:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"server-name\": {\n \"type\": \"stdio\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"some-mcp-server\"]\n }\n },\n \"disabledServers\": [\"server-name\"]\n}\n```\n\nTop-level keys:\n\n- `$schema` — optional JSON Schema URL for tooling\n- `mcpServers` — map of server name to server config\n- `disabledServers` — user-level denylist used to turn off discovered servers by name\n\nServer names must match `^[a-zA-Z0-9_.-]{1,100}$`.\n\n## Supported server fields\n\nShared fields for every transport:\n\n- `enabled?: boolean` — skip this server when `false`\n- `timeout?: number` — connection timeout in milliseconds\n- `auth?: { ... }` — auth metadata used by OMP for OAuth/API-key flows\n- `oauth?: { ... }` — explicit OAuth client settings used during auth/reauth\n\n### `stdio` transport\n\n`stdio` is the default when `type` is omitted.\n\nRequired:\n\n- `command: string`\n\nOptional:\n\n- `type?: \"stdio\"`\n- `args?: string[]`\n- `env?: Record<string, string>`\n- `cwd?: string`\n\nExample:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"filesystem\": {\n \"command\": \"npx\",\n \"args\": [\n \"-y\",\n \"@modelcontextprotocol/server-filesystem\",\n \"/Users/alice/projects\",\n \"/Users/alice/Documents\"\n ]\n }\n }\n}\n```\n\nThis follows the official Filesystem MCP server package (`@modelcontextprotocol/server-filesystem`).\n\n### `http` transport\n\nRequired:\n\n- `type: \"http\"`\n- `url: string`\n\nOptional:\n\n- `headers?: Record<string, string>`\n\nExample:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"github\": {\n \"type\": \"http\",\n \"url\": \"https://api.githubcopilot.com/mcp/\"\n }\n }\n}\n```\n\nThis matches GitHub's hosted GitHub MCP server endpoint.\n\n### `sse` transport\n\nRequired:\n\n- `type: \"sse\"`\n- `url: string`\n\nOptional:\n\n- `headers?: Record<string, string>`\n\nExample:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"legacy-remote\": {\n \"type\": \"sse\",\n \"url\": \"https://example.com/mcp/sse\"\n }\n }\n}\n```\n\n`sse` is still supported for compatibility, but the MCP spec now prefers Streamable HTTP (`type: \"http\"`) for new servers.\n\n## Auth fields\n\nOMP understands two auth-related objects.\n\n### `auth`\n\n```json\n{\n \"type\": \"oauth\" | \"apikey\",\n \"credentialId\": \"optional-stored-credential-id\",\n \"tokenUrl\": \"optional-token-endpoint\",\n \"clientId\": \"optional-client-id\",\n \"clientSecret\": \"optional-client-secret\"\n}\n```\n\nUse this when OMP should remember how to rehydrate credentials for a server.\n\n### `oauth`\n\n```json\n{\n \"clientId\": \"...\",\n \"clientSecret\": \"...\",\n \"redirectUri\": \"...\",\n \"callbackPort\": 3334,\n \"callbackPath\": \"/oauth/callback\"\n}\n```\n\nUse this when the MCP server requires explicit OAuth client settings.\n\nSlack is the clearest current example. Slack's MCP server is hosted at `https://mcp.slack.com/mcp`, uses Streamable HTTP, and requires confidential OAuth with your Slack app's client credentials.\n\nExample:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"slack\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.slack.com/mcp\",\n \"oauth\": {\n \"clientId\": \"YOUR_SLACK_CLIENT_ID\",\n \"clientSecret\": \"YOUR_SLACK_CLIENT_SECRET\"\n },\n \"auth\": {\n \"type\": \"oauth\",\n \"tokenUrl\": \"https://slack.com/api/oauth.v2.user.access\",\n \"clientId\": \"YOUR_SLACK_CLIENT_ID\",\n \"clientSecret\": \"YOUR_SLACK_CLIENT_SECRET\"\n }\n }\n }\n}\n```\n\nRelevant Slack endpoints from Slack's docs:\n\n- MCP endpoint: `https://mcp.slack.com/mcp`\n- Authorization endpoint: `https://slack.com/oauth/v2_user/authorize`\n- Token endpoint: `https://slack.com/api/oauth.v2.user.access`\n\n## Common copy-paste examples\n\n### Filesystem server via stdio\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"filesystem\": {\n \"command\": \"npx\",\n \"args\": [\n \"-y\",\n \"@modelcontextprotocol/server-filesystem\",\n \"/absolute/path/one\",\n \"/absolute/path/two\"\n ]\n }\n }\n}\n```\n\n### GitHub hosted server via HTTP\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"github\": {\n \"type\": \"http\",\n \"url\": \"https://api.githubcopilot.com/mcp/\"\n }\n }\n}\n```\n\n### GitHub local server via Docker\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"github\": {\n \"command\": \"docker\",\n \"args\": [\n \"run\",\n \"-i\",\n \"--rm\",\n \"-e\",\n \"GITHUB_PERSONAL_ACCESS_TOKEN\",\n \"ghcr.io/github/github-mcp-server\"\n ],\n \"env\": {\n \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"GITHUB_PERSONAL_ACCESS_TOKEN\"\n }\n }\n }\n}\n```\n\nThis matches GitHub's official local Docker image `ghcr.io/github/github-mcp-server`.\n\n### Slack hosted server via OAuth\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"mcpServers\": {\n \"slack\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.slack.com/mcp\",\n \"oauth\": {\n \"clientId\": \"YOUR_SLACK_CLIENT_ID\",\n \"clientSecret\": \"YOUR_SLACK_CLIENT_SECRET\"\n },\n \"auth\": {\n \"type\": \"oauth\",\n \"tokenUrl\": \"https://slack.com/api/oauth.v2.user.access\",\n \"clientId\": \"YOUR_SLACK_CLIENT_ID\",\n \"clientSecret\": \"YOUR_SLACK_CLIENT_SECRET\"\n }\n }\n }\n}\n```\n\n## Secrets and variable resolution\n\nThis is the part that usually trips people up.\n\n### In `.xcsh/mcp.json` and `~/.xcsh/mcp.json`\n\nBefore OMP launches a server or makes an HTTP request, it resolves `env` and `headers` values like this:\n\n1. If a value starts with `!`, OMP runs it as a shell command and uses trimmed stdout.\n2. Otherwise OMP first checks whether the value matches an environment variable name.\n3. If that environment variable is not set, OMP uses the string literally.\n\nExamples:\n\n```json\n{\n \"env\": {\n \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"GITHUB_PERSONAL_ACCESS_TOKEN\"\n },\n \"headers\": {\n \"X-MCP-Insiders\": \"true\"\n }\n}\n```\n\nThat means this is valid and convenient for local secrets:\n\n- `\"GITHUB_PERSONAL_ACCESS_TOKEN\": \"GITHUB_PERSONAL_ACCESS_TOKEN\"` → copy from the current shell environment\n- `\"Authorization\": \"Bearer hardcoded-token\"` → use the literal value\n- `\"Authorization\": \"!printf 'Bearer %s' \\\"$GITHUB_TOKEN\\\"\"` → build the header from a command\n\n### In root `mcp.json` and `.mcp.json`\n\nThe standalone fallback loader also expands `${VAR}` and `${VAR:-default}` inside strings during discovery.\n\nExample:\n\n```json\n{\n \"mcpServers\": {\n \"github\": {\n \"type\": \"http\",\n \"url\": \"https://api.githubcopilot.com/mcp/\",\n \"headers\": {\n \"Authorization\": \"Bearer ${GITHUB_TOKEN}\"\n }\n }\n }\n}\n```\n\nIf you want the least surprising OMP behavior, prefer `.xcsh/mcp.json` and use explicit env/header values.\n\n## `disabledServers`\n\n`disabledServers` is mainly useful in the user config file (`~/.xcsh/mcp.json`) when a server is discovered from some other source and you want OMP to ignore it without editing that other tool's config.\n\nExample:\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/packages/coding-agent/src/config/mcp-schema.json\",\n \"disabledServers\": [\"github\", \"slack\"]\n}\n```\n\n## `/mcp add` vs editing JSON directly\n\nUse `/mcp add` when you want guided setup.\n\nUse direct JSON editing when:\n\n- you need a transport or auth option the wizard does not prompt for yet\n- you want to paste a server definition from another MCP client\n- you want schema-backed validation in your editor\n\nAfter editing, use:\n\n- `/mcp reload` to rediscover and reconnect servers in the current session\n- `/mcp list` to see which config file a server came from\n- `/mcp test <name>` to test a single server\n\n## Validation rules OMP enforces\n\nFrom `validateServerConfig()` in `packages/coding-agent/src/mcp/config.ts`:\n\n- `stdio` requires `command`\n- `http` and `sse` require `url`\n- a server cannot set both `command` and `url`\n- unknown `type` values are rejected\n\nPractical implications:\n\n- Omitting `type` means `stdio`\n- If you paste a remote server config and forget `\"type\": \"http\"`, OMP will treat it as `stdio` and complain that `command` is missing\n- `sse` remains valid for compatibility, but new hosted servers should usually be configured as `http`\n\n## Discovery and precedence\n\nOMP does not merge duplicate server definitions across files. Discovery providers are prioritized, and the higher-priority definition wins.\n\nIn practice:\n\n- prefer `.xcsh/mcp.json` or `~/.xcsh/mcp.json` when you want an OMP-specific override\n- keep server names unique across tools when possible\n- use `disabledServers` in the user config when a third-party config keeps reintroducing a server you do not want\n\n## Troubleshooting\n\n### `Server \"name\": stdio server requires \"command\" field`\n\nYou probably omitted `type: \"http\"` on a remote server.\n\n### `Server \"name\": both \"command\" and \"url\" are set`\n\nPick one transport. OMP treats `command` as stdio and `url` as http/sse.\n\n### `/mcp add` worked but the server still does not connect\n\nThe JSON is valid, but the server may still be unreachable. Use `/mcp test <name>` and check whether:\n\n- the binary or Docker image exists\n- required environment variables are set\n- the remote URL is reachable\n- the OAuth or API token is valid\n\n### The server exists in another tool's config but not in OMP\n\nRun `/mcp list`. OMP discovers many third-party MCP files, but project-level loading can also be disabled via the `mcp.enableProjectConfig` setting.\n\n## References\n\n- MCP transport spec: <https://modelcontextprotocol.io/specification/2025-03-26/basic/transports>\n- Filesystem server package: <https://www.npmjs.com/package/@modelcontextprotocol/server-filesystem>\n- GitHub MCP server: <https://github.com/github/github-mcp-server>\n- Slack MCP server docs: <https://docs.slack.dev/ai/slack-mcp-server/>\n",
|
|
131
132
|
"en/mcp/mcp-protocol-transports.md": "---\ntitle: MCP Protocol and Transport Internals\ndescription: MCP protocol implementation with stdio, SSE, and streamable HTTP transport layers.\nsidebar:\n order: 2\n label: Protocol & transports\n---\n\n# MCP Protocol and Transport Internals\n\nThis document describes how coding-agent implements MCP JSON-RPC messaging and how protocol concerns are split from transport concerns.\n\n## Scope\n\nCovers:\n\n- JSON-RPC request/response and notification flow\n- Request correlation and lifecycle for stdio and HTTP/SSE transports\n- Timeout and cancellation behavior\n- Error propagation and malformed payload handling\n- Transport selection boundaries (`stdio` vs `http`/`sse`)\n- Which reconnect/retry responsibilities are transport-level vs manager-level\n\nDoes not cover extension authoring UX or command UI.\n\n## Implementation files\n\n- [`src/mcp/types.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/types.ts)\n- [`src/mcp/transports/stdio.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/transports/stdio.ts)\n- [`src/mcp/transports/http.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/transports/http.ts)\n- [`src/mcp/transports/index.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/transports/index.ts)\n- [`src/mcp/json-rpc.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/json-rpc.ts)\n- [`src/mcp/client.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/client.ts)\n- [`src/mcp/manager.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/manager.ts)\n\n## Layer boundaries\n\n### Protocol layer (JSON-RPC + MCP methods)\n\n- Message shapes are defined in `types.ts` (`JsonRpcRequest`, `JsonRpcNotification`, `JsonRpcResponse`, `JsonRpcMessage`).\n- MCP client logic (`client.ts`) decides method order and session handshake:\n 1. `initialize` request\n 2. `notifications/initialized` notification\n 3. method calls like `tools/list`, `tools/call`\n\n### Transport layer (`MCPTransport`)\n\n`MCPTransport` abstracts delivery and lifecycle:\n\n- `request(method, params, options?) -> Promise<T>`\n- `notify(method, params?) -> Promise<void>`\n- `close()`\n- `connected`\n- optional callbacks: `onClose`, `onError`, `onNotification`\n\nTransport implementations own framing and I/O details:\n\n- `StdioTransport`: newline-delimited JSON over subprocess stdio\n- `HttpTransport`: JSON-RPC over HTTP POST, with optional SSE responses/listening\n\n### Important current caveat\n\nTransport callbacks (`onClose`, `onError`, `onNotification`) are implemented, but current `MCPClient`/`MCPManager` flows do not wire reconnection logic to these callbacks. Notifications are only consumed if caller registers handlers.\n\n## Transport selection\n\n`client.ts:createTransport()` chooses transport from config:\n\n- `type` omitted or `\"stdio\"` -> `createStdioTransport`\n- `\"http\"` or `\"sse\"` -> `createHttpTransport`\n\n`\"sse\"` is treated as an HTTP transport variant (same class), not a separate transport implementation.\n\n## JSON-RPC message flow and correlation\n\n## Request IDs\n\nEach transport generates per-request IDs (`Math.random` + timestamp string). IDs are transport-local correlation tokens.\n\n## Stdio correlation path\n\n- Outbound request is serialized as one JSON object + `\\n`.\n- `#pendingRequests: Map<id, {resolve,reject}>` stores in-flight requests.\n- Read loop parses JSONL from stdout and calls `#handleMessage`.\n- If inbound message has matching `id`, request resolves/rejects.\n- If inbound message has `method` and no `id`, treated as notification and sent to `onNotification`.\n\nUnknown IDs are ignored (no rejection, no error callback).\n\n## HTTP correlation path\n\n- Outbound request is HTTP `POST` with JSON body and generated `id`.\n- Non-SSE response path: parse one JSON-RPC response and return `result`/throw on `error`.\n- SSE response path (`Content-Type: text/event-stream`): stream events, return first message whose `id` matches expected request ID and has `result` or `error`.\n- SSE messages with `method` and no `id` are treated as notifications.\n\nIf SSE stream ends before matching response, request fails with `No response received for request ID ...`.\n\n## Notifications\n\nClient emits JSON-RPC notifications via `transport.notify(...)`.\n\n- Stdio: writes notification frame to stdin (`jsonrpc`, `method`, optional `params`) plus newline.\n- HTTP: sends POST body without `id`; success accepts `2xx` or `202 Accepted`.\n\nServer-initiated notifications are only surfaced through transport `onNotification`; there is no default global subscriber in manager/client.\n\n## Stdio transport internals\n\n## Lifecycle and state transitions\n\n- Initial: `connected=false`, `process=null`, pending map empty\n- `connect()`:\n - spawn subprocess with configured command/args/env/cwd\n - mark connected\n - start stdout read loop (`readJsonl`)\n - start stderr loop (read/discard; currently silent)\n- `close()`:\n - mark disconnected\n - reject all pending requests (`Transport closed`)\n - kill subprocess\n - await read loop shutdown\n - emit `onClose`\n\nIf read loop exits unexpectedly, `finally` triggers `#handleClose()` which performs the same pending-request rejection and close callback.\n\n## Timeout and cancellation\n\nPer request:\n\n- timeout defaults to `config.timeout ?? 30000`\n- optional `AbortSignal` from caller\n- abort and timeout both reject the pending promise and clean map entry\n\nCancellation is local only: transport does not send protocol-level cancellation notification to the server.\n\n## Malformed payload handling\n\nIn read loop:\n\n- each parsed JSONL line is passed to `#handleMessage` in `try/catch`\n- malformed/invalid message handling exceptions are dropped (`Skip malformed lines` comment)\n- loop continues, so one bad message does not kill the connection\n\nIf the underlying stream parser throws, `onError` is invoked (when still connected), then connection closes.\n\n## Disconnect/failure behavior\n\nWhen process exits or stream closes:\n\n- all in-flight requests are rejected with `Transport closed`\n- no automatic restart or reconnect\n- higher layers must reconnect by creating a new transport\n\n## Backpressure/streaming notes\n\n- Outbound writes use `stdin.write()` + `flush()` without awaiting drain semantics.\n- There is no explicit queue or high-watermark management in transport.\n- Inbound processing is stream-driven (`for await` over `readJsonl`), one parsed message at a time.\n\n## HTTP/SSE transport internals\n\n## Lifecycle and connection semantics\n\nHTTP transport has logical connection state, but request path is stateless per HTTP call:\n\n- `connect()` sets `connected=true` (no socket/session handshake)\n- optional server session tracking via `Mcp-Session-Id` header\n- `close()` optionally sends `DELETE` with `Mcp-Session-Id`, aborts SSE listener, emits `onClose`\n\nSo `connected` means \"transport usable\", not \"persistent stream established\".\n\n## Session header behavior\n\n- On POST response, if `Mcp-Session-Id` header is present, transport stores it.\n- Subsequent requests/notifications include `Mcp-Session-Id`.\n- `close()` tries to terminate server session with HTTP DELETE; termination failures are ignored.\n\n## Timeout and cancellation\n\nFor both `request()` and `notify()`:\n\n- timeout uses `AbortController` (`config.timeout ?? 30000`)\n- external signal, if provided, is merged via `AbortSignal.any([...])`\n- AbortError handling distinguishes caller abort vs timeout\n\nErrors thrown:\n\n- timeout: `Request timeout after ...ms` (or `SSE response timeout ...`, `Notify timeout ...`)\n- caller abort: original AbortError is rethrown when external signal is already aborted\n\n## HTTP error propagation\n\nOn non-OK response:\n\n- response text is included in thrown error (`HTTP <status>: <text>`)\n- if present, auth hints from `WWW-Authenticate` and `Mcp-Auth-Server` are appended\n\nOn JSON-RPC error object:\n\n- throws `MCP error <code>: <message>`\n\nMalformed JSON body (`response.json()` failure) propagates as parse exception.\n\n## SSE behavior and modes\n\nTwo SSE paths exist:\n\n1. **Per-request SSE response** (`#parseSSEResponse`)\n - used when POST response content type is `text/event-stream`\n - consumes stream until matching response id found\n - can process interleaved notifications during same stream\n\n2. **Background SSE listener** (`startSSEListener()`)\n - optional GET listener for server-initiated notifications\n - currently not automatically started by MCP manager/client\n - if GET returns `405`, listener silently disables itself (server does not support this mode)\n\n## Malformed payload and disconnect handling\n\nSSE JSON parsing errors bubble out of `readSseJson` and reject request/listener.\n\n- Request SSE parse errors reject the active request.\n- Background listener errors trigger `onError` (except AbortError).\n- No auto-reconnect for background listener.\n\n## `json-rpc.ts` utility vs transport abstraction\n\n`src/mcp/json-rpc.ts` provides `callMCP()` and `parseSSE()` helpers for direct HTTP MCP calls (used by Exa integration), not the `MCPTransport` abstraction used by `MCPClient`/`MCPManager`.\n\nNotable differences from `HttpTransport`:\n\n- parses entire response text first, then extracts first `data:` line (`parseSSE`), with JSON fallback\n- no request timeout management, no abort API, no session-id handling, no transport lifecycle\n- returns raw JSON-RPC envelope object\n\nThis path is lightweight but less robust than full transport implementation.\n\n## Retry/reconnect responsibilities\n\n## Transport-level\n\nCurrent transport implementations do **not**:\n\n- retry failed requests\n- reconnect after stdio process exit\n- reconnect SSE listeners\n- resend in-flight requests after disconnect\n\nThey fail fast and propagate errors.\n\n## Manager/client-level\n\n`MCPManager` handles discovery/initial connection orchestration and can reconnect only by running connect flows again (`connectToServer`/`discoverAndConnect` paths). It does not auto-heal an already connected transport on runtime failure callbacks.\n\n`MCPManager` does have startup fallback behavior for slow servers (deferred tools from cache), but that is tool availability fallback, not transport retry.\n\n## Failure scenarios summary\n\n- **Malformed stdio message line**: dropped; stream continues.\n- **Stdio stream/process ends**: transport closes; pending requests rejected as `Transport closed`.\n- **HTTP non-2xx**: request/notify throws HTTP error.\n- **Invalid JSON response**: parse exception propagated.\n- **SSE ends without matching id**: request fails with `No response received for request ID ...`.\n- **Timeout**: transport-specific timeout error.\n- **Caller abort**: AbortError/reason propagated from caller signal.\n\n## Practical boundary rule\n\nIf the concern is message shape, id correlation, or MCP method ordering, it belongs to protocol/client logic.\n\nIf the concern is framing (JSONL vs HTTP/SSE), stream parsing, fetch/spawn lifecycle, timeout clocks, or connection teardown, it belongs to transport implementation.\n",
|
|
132
133
|
"en/mcp/mcp-runtime-lifecycle.md": "---\ntitle: MCP Runtime Lifecycle\ndescription: MCP server process lifecycle from initialization through tool registration, health monitoring, and shutdown.\nsidebar:\n order: 3\n label: Runtime lifecycle\n---\n\n# MCP runtime lifecycle\n\nThis document describes how MCP servers are discovered, connected, exposed as tools, refreshed, and torn down in the coding-agent runtime.\n\n## Lifecycle at a glance\n\n1. **SDK startup** calls `discoverAndLoadMCPTools()` (unless MCP is disabled).\n2. **Discovery** (`loadAllMCPConfigs`) resolves MCP server configs from capability sources, filters disabled/project/Exa entries, and preserves source metadata.\n3. **Manager connect phase** (`MCPManager.connectServers`) starts per-server connect + `tools/list` in parallel.\n4. **Fast startup gate** waits up to 250ms, then may return:\n - fully loaded `MCPTool`s,\n - failures per server,\n - or cached `DeferredMCPTool`s for still-pending servers.\n5. **SDK wiring** merges MCP tools into runtime tool registry for the session.\n6. **Live session** can refresh MCP tools via `/mcp` flows (`disconnectAll` + rediscover + `session.refreshMCPTools`).\n7. **Teardown** happens when callers invoke `disconnectServer`/`disconnectAll`; manager also clears MCP tool registrations for disconnected servers.\n\n## Discovery and load phase\n\n### Entry path from SDK\n\n`createAgentSession()` in `src/sdk.ts` performs MCP startup when `enableMCP` is true (default):\n\n- calls `discoverAndLoadMCPTools(cwd, { ... })`,\n- passes `authStorage`, cache storage, and `mcp.enableProjectConfig` setting,\n- always sets `filterExa: true`,\n- logs per-server load/connect errors,\n- stores returned manager in `toolSession.mcpManager` and session result.\n\nIf `enableMCP` is false, MCP discovery is skipped entirely.\n\n### Config discovery and filtering\n\n`loadAllMCPConfigs()` (`src/mcp/config.ts`) loads canonical MCP server items through capability discovery, then converts to legacy `MCPServerConfig`.\n\nFiltering behavior:\n\n- `enableProjectConfig: false` removes project-level entries (`_source.level === \"project\"`).\n- `enabled: false` servers are skipped before connect attempts.\n- Exa servers are filtered out by default and API keys are extracted for native Exa tool integration.\n\nResult includes both `configs` and `sources` (metadata used later for provider labeling).\n\n### Discovery-level failure behavior\n\n`discoverAndLoadMCPTools()` distinguishes two failure classes:\n\n- **Discovery hard failure** (exception from `manager.discoverAndConnect`, typically from config discovery): returns an empty tool set and one synthetic error `{ path: \".mcp.json\", error }`.\n- **Per-server runtime/connect failure**: manager returns partial success with `errors` map; other servers continue.\n\nSo startup does not fail the whole agent session when individual MCP servers fail.\n\n## Manager state model\n\n`MCPManager` tracks runtime lifecycle with separate registries:\n\n- `#connections: Map<string, MCPServerConnection>` — fully connected servers.\n- `#pendingConnections: Map<string, Promise<MCPServerConnection>>` — handshake in progress.\n- `#pendingToolLoads: Map<string, Promise<{ connection, serverTools }>>` — connected but tools still loading.\n- `#tools: CustomTool[]` — current MCP tool view exposed to callers.\n- `#sources: Map<string, SourceMeta>` — provider/source metadata even before connect completes.\n\n`getConnectionStatus(name)` derives status from these maps:\n\n- `connected` if in `#connections`,\n- `connecting` if pending connect or pending tool load,\n- `disconnected` otherwise.\n\n## Connection establishment and startup timing\n\n## Per-server connect pipeline\n\nFor each discovered server in `connectServers()`:\n\n1. store/update source metadata,\n2. skip if already connected/pending,\n3. validate transport fields (`validateServerConfig`),\n4. resolve auth/shell substitutions (`#resolveAuthConfig`),\n5. call `connectToServer(name, resolvedConfig)`,\n6. call `listTools(connection)`,\n7. cache tool definitions (`MCPToolCache.set`) best-effort.\n\n`connectToServer()` behavior (`src/mcp/client.ts`):\n\n- creates stdio or HTTP/SSE transport,\n- performs MCP `initialize` + `notifications/initialized`,\n- uses timeout (`config.timeout` or 30s default),\n- closes transport on init failure.\n\n### Fast startup gate + deferred fallback\n\n`connectServers()` waits on a race between:\n\n- all connect/tool-load tasks settled, and\n- `STARTUP_TIMEOUT_MS = 250`.\n\nAfter 250ms:\n\n- fulfilled tasks become live `MCPTool`s,\n- rejected tasks produce per-server errors,\n- still-pending tasks:\n - use cached tool definitions if available (`MCPToolCache.get`) to create `DeferredMCPTool`s,\n - otherwise block until those pending tasks settle.\n\nThis is a hybrid startup model: fast return when cache is available, correctness wait when cache is not.\n\n### Background completion behavior\n\nEach pending `toolsPromise` also has a background continuation that eventually:\n\n- replaces that server’s tool slice in manager state via `#replaceServerTools`,\n- writes cache,\n- logs late failures only after startup (`allowBackgroundLogging`).\n\n## Tool exposure and live-session availability\n\n### Startup registration\n\n`discoverAndLoadMCPTools()` converts manager tools into `LoadedCustomTool[]` and decorates paths (`mcp:<server> via <providerName>` when known).\n\n`createAgentSession()` then pushes these tools into `customTools`, which are wrapped and added to the runtime tool registry with names like `mcp_<server>_<tool>`.\n\n### Tool calls\n\n- `MCPTool` calls tools through an already connected `MCPServerConnection`.\n- `DeferredMCPTool` waits for `waitForConnection(server)` before calling; this allows cached tools to exist before connection is ready.\n\nBoth return structured tool output and convert transport/tool errors into `MCP error: ...` tool content (abort remains abort).\n\n## Refresh/reload paths (startup vs live reload)\n\n### Initial startup path\n\n- one-time discovery/load in `sdk.ts`,\n- tools are registered in initial session tool registry.\n\n### Interactive reload path\n\n`/mcp reload` path (`src/modes/controllers/mcp-command-controller.ts`) does:\n\n1. `mcpManager.disconnectAll()`,\n2. `mcpManager.discoverAndConnect()`,\n3. `session.refreshMCPTools(mcpManager.getTools())`.\n\n`session.refreshMCPTools()` (`src/session/agent-session.ts`) removes all `mcp_` tools, re-wraps latest MCP tools, and re-activates tool set so MCP changes apply without restarting session.\n\nThere is also a follow-up path for late connections: after waiting for a specific server, if status becomes `connected`, it re-runs `session.refreshMCPTools(...)` so newly available tools are rebound in-session.\n\n## Health, reconnect, and partial failure behavior\n\nCurrent runtime behavior is intentionally minimal:\n\n- **No autonomous health monitor** in manager/client.\n- **No automatic reconnect loop** when a transport drops.\n- Manager does not subscribe to transport `onClose`/`onError`; status is registry-driven.\n- Reconnect is explicit: reload flow or direct `connectServers()` invocation.\n\nOperationally:\n\n- one server failing does not remove tools from healthy servers,\n- connect/list failures are isolated per server,\n- tool cache and background updates are best-effort (warnings/errors logged, no hard stop).\n\n## Teardown semantics\n\n### Server-level teardown\n\n`disconnectServer(name)`:\n\n- removes pending entries/source metadata,\n- closes transport if connected,\n- removes that server’s `mcp_` tools from manager state.\n\n### Global teardown\n\n`disconnectAll()`:\n\n- closes all active transports with `Promise.allSettled`,\n- clears pending maps, sources, connections, and manager tool list.\n\nIn current wiring, explicit teardown is used in MCP command flows (for reload/remove/disable). There is no separate automatic manager disposal hook in the startup path itself; callers are responsible for invoking manager disconnect methods when they need deterministic MCP shutdown.\n\n## Failure modes and guarantees\n\n| Scenario | Behavior | Hard fail vs best-effort |\n| --- | --- | --- |\n| Discovery throws (capability/config load path) | Loader returns empty tools + synthetic `.mcp.json` error | Best-effort session startup |\n| Invalid server config | Server skipped with validation error entry | Best-effort per server |\n| Connect timeout/init failure | Server error recorded; others continue | Best-effort per server |\n| `tools/list` still pending at startup with cache hit | Deferred tools returned immediately | Best-effort fast startup |\n| `tools/list` still pending at startup without cache | Startup waits for pending to settle | Hard wait for correctness |\n| Late background tool-load failure | Logged after startup gate | Best-effort logging |\n| Runtime dropped transport | No automatic reconnect; future calls fail until reconnect/reload | Best-effort recovery via manual action |\n\n## Public API surface\n\n`src/mcp/index.ts` re-exports loader/manager/client APIs for external callers. `src/sdk.ts` exposes `discoverMCPServers()` as a convenience wrapper returning the same loader result shape.\n\n## Implementation files\n\n- [`src/mcp/loader.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/loader.ts) — loader facade, discovery error normalization, `LoadedCustomTool` conversion.\n- [`src/mcp/manager.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/manager.ts) — lifecycle state registries, parallel connect/list flow, refresh/disconnect.\n- [`src/mcp/client.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/client.ts) — transport setup, initialize handshake, list/call/disconnect.\n- [`src/mcp/index.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/index.ts) — MCP module API exports.\n- [`src/sdk.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/sdk.ts) — startup wiring into session/tool registry.\n- [`src/mcp/config.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/config.ts) — config discovery/filtering/validation used by manager.\n- [`src/mcp/tool-bridge.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/mcp/tool-bridge.ts) — `MCPTool` and `DeferredMCPTool` runtime behavior.\n- [`src/session/agent-session.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/agent-session.ts) — `refreshMCPTools` live rebinding.\n- [`src/modes/controllers/mcp-command-controller.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/modes/controllers/mcp-command-controller.ts) — interactive reload/reconnect flows.\n- [`src/task/executor.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/task/executor.ts) — subagent MCP proxying via parent manager connections.\n",
|
|
@@ -481,7 +482,7 @@ export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
|
|
|
481
482
|
"ko/tui/tree.md": "---\ntitle: Tree 명령어 레퍼런스\ndescription: 세션 기록과 대화 분기를 시각화하기 위한 /tree 명령어 레퍼런스.\nsidebar:\n order: 4\n label: /tree 명령어\ni18n:\n sourceHash: ee0e412fe993\n translator: machine\n---\n\n# `/tree` 명령어 레퍼런스\n\n`/tree`는 대화형 **세션 트리** 탐색기를 엽니다. 현재 세션 파일의 모든 항목으로 이동하여 해당 지점부터 계속할 수 있습니다.\n\n이것은 파일 내 리프 이동이며, 새로운 세션 내보내기가 아닙니다.\n\n## `/tree`의 기능\n\n- 현재 세션 항목에서 트리를 구축합니다 (`SessionManager.getTree()`)\n- 키보드 탐색, 필터, 검색 기능이 포함된 `TreeSelectorComponent`를 엽니다\n- 선택 시 `AgentSession.navigateTree(targetId, { summarize, customInstructions })`를 호출합니다\n- 새로운 리프 경로에서 보이는 채팅을 재구축합니다\n- user/custom 메시지를 선택할 때 선택적으로 에디터 텍스트를 미리 채웁니다\n\n주요 구현:\n\n- `src/modes/controllers/input-controller.ts` (`/tree`, 키바인딩 연결, 이중 Escape 동작)\n- `src/modes/controllers/selector-controller.ts` (트리 UI 실행 + 요약 프롬프트 흐름)\n- `src/modes/components/tree-selector.ts` (탐색, 필터, 검색, 레이블, 렌더링)\n- `src/session/agent-session.ts` (`navigateTree` 리프 전환 + 선택적 요약)\n- `src/session/session-manager.ts` (`getTree`, `branch`, `branchWithSummary`, `resetLeaf`, 레이블 영속성)\n\n## 여는 방법\n\n다음 중 하나로 동일한 선택기를 열 수 있습니다:\n\n- `/tree`\n- 설정된 키바인딩 액션 `tree`\n- 빈 에디터에서 이중 Escape (`doubleEscapeAction = \"tree\"`인 경우, 기본값)\n- `/branch` (`doubleEscapeAction = \"tree\"`인 경우, 사용자 전용 분기 선택기 대신 트리 선택기로 라우팅)\n\n## 트리 UI 모델\n\n트리는 세션 항목의 부모 포인터(`id` / `parentId`)에서 렌더링됩니다.\n\n- 자식은 타임스탬프 오름차순으로 정렬됩니다 (오래된 것이 먼저, 새로운 것이 아래)\n- 활성 분기(루트에서 현재 리프까지의 경로)는 불릿으로 표시됩니다\n- 레이블(있는 경우)은 노드 텍스트 앞에 `[label]`로 렌더링됩니다\n- 여러 루트가 존재하는 경우(고아/끊어진 부모 체인), 가상 분기 루트 아래에 표시됩니다\n\n```text\n트리 뷰 예시 (활성 경로는 •로 표시):\n\n├─ user: \"작업 시작\"\n│ └─ assistant: \"계획\"\n│ ├─ • user: \"접근법 A 시도\"\n│ │ └─ • assistant: \"A 결과\"\n│ │ └─ • [milestone] user: \"A 계속\"\n│ └─ user: \"접근법 B 시도\"\n│ └─ assistant: \"B 결과\"\n```\n\n선택기는 현재 선택 항목을 중심으로 재배치되며 최대 다음만큼의 행을 표시합니다:\n\n- `max(5, floor(terminalHeight / 2))` 행\n\n## 트리 선택기 내 키바인딩\n\n- `Up` / `Down`: 선택 이동 (순환)\n- `Left` / `Right`: 페이지 위 / 페이지 아래\n- `Enter`: 노드 선택\n- `Esc`: 검색이 활성화된 경우 검색 지우기; 그렇지 않으면 선택기 닫기\n- `Ctrl+C`: 선택기 닫기\n- `Type`: 검색 쿼리에 추가\n- `Backspace`: 검색 문자 삭제\n- `Shift+L`: 선택된 항목의 레이블 편집/지우기\n- `Ctrl+O`: 필터를 앞으로 순환\n- `Shift+Ctrl+O`: 필터를 뒤로 순환\n- `Alt+D/T/U/L/A`: 특정 필터 모드로 직접 이동\n\n## 필터 및 검색 의미론\n\n필터 모드 (`TreeList`):\n\n1. `default`\n2. `no-tools`\n3. `user-only`\n4. `labeled-only`\n5. `all`\n\n### `default`\n\n대부분의 대화 노드를 표시하지만 관리용 항목 유형은 숨깁니다:\n\n- `label`\n- `custom`\n- `model_change`\n- `thinking_level_change`\n\n### `no-tools`\n\n`default`와 동일하며, 추가로 `toolResult` 메시지를 숨깁니다.\n\n### `user-only`\n\n역할이 `user`인 `message` 항목만 표시합니다.\n\n### `labeled-only`\n\n현재 레이블로 확인되는 항목만 표시합니다.\n\n### `all`\n\n관리용/custom 항목을 포함하여 세션 트리의 모든 것을 표시합니다.\n\n### 도구 전용 어시스턴트 노드 동작\n\n**도구 호출만** 포함하고 텍스트가 없는 어시스턴트 메시지는 다음의 경우를 제외하고 모든 필터 뷰에서 기본적으로 숨겨집니다:\n\n- 메시지가 오류/중단됨 (`stopReason`이 `stop`/`toolUse`가 아닌 경우), 또는\n- 현재 리프인 경우 (항상 표시 유지)\n\n### 검색 동작\n\n- 쿼리는 공백으로 토큰화됩니다\n- 매칭은 대소문자를 구분하지 않습니다\n- 모든 토큰이 일치해야 합니다 (AND 의미론)\n- 검색 가능한 텍스트에는 레이블, 역할, 유형별 콘텐츠(메시지 텍스트, 분기 요약 텍스트, custom 유형, 도구 명령어 스니펫 등)가 포함됩니다\n\n## 선택 결과 (중요)\n\n`navigateTree`는 선택된 항목 유형에 따라 새로운 리프 동작을 계산합니다:\n\n### `user` 메시지 선택\n\n- 새로운 리프는 선택된 항목의 `parentId`가 됩니다\n- 부모가 `null`인 경우(루트 사용자 메시지), 리프는 루트로 재설정됩니다 (`resetLeaf()`)\n- 선택된 메시지 텍스트가 편집/재제출을 위해 에디터에 복사됩니다\n\n### `custom_message` 선택\n\n- 사용자 메시지와 동일한 리프 규칙 (`parentId`)\n- 텍스트 콘텐츠가 추출되어 에디터에 복사됩니다\n\n### 비사용자 노드 선택 (assistant/tool/summary/compaction/custom 관리용 등)\n\n- 새로운 리프는 선택된 노드 id가 됩니다\n- 에디터에 미리 채워지지 않습니다\n\n### 현재 리프 선택\n\n- 무동작; 선택기가 \"이미 이 지점에 있습니다\" 메시지와 함께 닫힙니다\n\n```text\n선택 결정 (간략화):\n\n선택된 노드\n │\n ├─ 현재 리프인가? ── 예 ──> 선택기 닫기 (무동작)\n │\n ├─ user/custom_message인가? ── 예 ──> leaf := parentId (루트의 경우 resetLeaf)\n │ + 에디터 텍스트 미리 채우기\n │\n └─ 그 외 ──> leaf := 선택된 노드 id\n + 에디터 미리 채우기 없음\n```\n\n## 전환 시 요약 흐름\n\n요약 프롬프트는 `branchSummary.enabled`로 제어됩니다 (기본값: `false`).\n\n활성화된 경우, 노드를 선택한 후 UI가 다음을 묻습니다:\n\n- `요약 없음`\n- `요약`\n- `사용자 정의 프롬프트로 요약`\n\n흐름 세부 사항:\n\n- 요약 프롬프트에서 Escape를 누르면 트리 선택기가 다시 열립니다\n- 사용자 정의 프롬프트 취소 시 요약 선택 루프로 돌아갑니다\n- 요약 중에 UI는 로더를 표시하고 `Esc`를 `abortBranchSummary()`에 바인딩합니다\n- 요약이 중단되면 트리 선택기가 다시 열리고 이동이 적용되지 않습니다\n\n`navigateTree` 내부 동작:\n\n- 이전 리프에서 공통 조상까지 버려진 분기 항목을 수집합니다\n- `session_before_tree`를 발생시킵니다 (확장 기능이 취소하거나 요약을 삽입할 수 있음)\n- 요청되고 필요한 경우에만 기본 요약기를 사용합니다\n- 다음을 통해 이동을 적용합니다:\n - 요약이 있는 경우 `branchWithSummary(...)`\n - 요약 없는 비루트 이동의 경우 `branch(newLeafId)`\n - 요약 없는 루트 이동의 경우 `resetLeaf()`\n- 에이전트 대화를 재구축된 세션 컨텍스트로 교체합니다\n- `session_tree`를 발생시킵니다\n\n참고: 사용자가 요약을 요청했지만 요약할 내용이 없는 경우, 요약 항목을 생성하지 않고 탐색이 진행됩니다.\n\n## 레이블\n\n트리 UI에서의 레이블 편집은 `appendLabelChange(targetId, label)`을 호출합니다.\n\n- 비어 있지 않은 레이블은 확인된 레이블을 설정/업데이트합니다\n- 빈 레이블은 이를 지웁니다\n- 레이블은 추가 전용 `label` 항목으로 저장됩니다\n- 트리 노드는 원시 레이블 항목 기록이 아닌 확인된 레이블 상태를 표시합니다\n\n## `/tree` vs 인접 작업\n\n| 작업 | 범위 | 결과 |\n|---|---|---|\n| `/tree` | 현재 세션 파일 | 선택된 지점으로 리프를 이동 (동일 파일) |\n| `/branch` | 보통 현재 세션 파일 -> 새 세션 파일 | 기본적으로 선택된 **사용자** 메시지에서 새 세션 파일로 분기; `doubleEscapeAction = \"tree\"`인 경우, `/branch`는 대신 트리 탐색 UI를 엽니다 |\n| `/fork` | 전체 현재 세션 | 세션을 새로운 영속 세션 파일로 복제 |\n| `/resume` | 세션 목록 | 다른 세션 파일로 전환 |\n\n핵심 구분: `/tree`는 하나의 세션 파일 내에서의 탐색/위치 변경 도구입니다. `/branch`, `/fork`, `/resume`는 모두 세션 파일 컨텍스트를 변경합니다.\n\n## 운영자 워크플로우\n\n### 현재 분기를 잃지 않고 이전 사용자 프롬프트에서 다시 실행\n\n1. `/tree`\n2. 이전 사용자 메시지를 검색/선택\n3. `요약 없음` 선택 (필요한 경우 요약)\n4. 에디터에 미리 채워진 텍스트 편집\n5. 제출\n\n효과: 동일 세션 파일 내에서 선택된 지점으로부터 새 분기가 성장합니다.\n\n### 컨텍스트 브레드크럼과 함께 현재 분기 떠나기\n\n1. `branchSummary.enabled` 활성화\n2. `/tree`로 대상 노드 선택\n3. `요약` 선택 (또는 사용자 정의 프롬프트)\n\n효과: 계속하기 전에 대상 위치에 `branch_summary` 항목이 추가됩니다.\n\n### 숨겨진 관리용 항목 조사\n\n1. `/tree`\n2. `Alt+A` 누르기 (all)\n3. `model`, `thinking`, `custom` 또는 레이블 검색\n\n효과: 대화 노드뿐만 아니라 전체 내부 타임라인을 검사합니다.\n\n### 나중에 이동할 피벗 포인트 북마크\n\n1. `/tree`\n2. 항목으로 이동\n3. `Shift+L`을 누르고 레이블 설정\n4. 나중에 `Alt+L` (`labeled-only`)을 사용하여 빠르게 이동\n\n효과: 지속적인 분기 랜드마크 간 빠른 탐색이 가능합니다.\n",
|
|
482
483
|
"ko/tui/tui-runtime-internals.md": "---\ntitle: TUI 런타임 내부 구조\ndescription: '렌더링 파이프라인, 입력 처리, 상태 관리를 포함한 터미널 UI 런타임 내부 구조.'\nsidebar:\n order: 2\n label: 런타임 내부 구조\ni18n:\n sourceHash: 67e79fc1e1f3\n translator: machine\n---\n\n# TUI 런타임 내부 구조\n\n이 문서는 대화형 모드에서 터미널 입력부터 렌더링된 출력까지의 테마 외 런타임 경로를 설명합니다. `packages/tui`의 동작과 `packages/coding-agent` 컨트롤러의 통합에 초점을 맞춥니다.\n\n## 런타임 계층 및 소유권\n\n- **`packages/tui` 엔진**: 터미널 생명주기, stdin 정규화, 포커스 라우팅, 렌더 스케줄링, 차등 페인팅, 오버레이 합성, 하드웨어 커서 배치.\n- **`packages/coding-agent` 대화형 모드**: 컴포넌트 트리 구성, 에디터 콜백 및 키맵 바인딩, 에이전트/세션 이벤트 반응, 도메인 상태(스트리밍, 도구 실행, 재시도, 플랜 모드)를 UI 구성 요소로 변환.\n\n경계 규칙: TUI 엔진은 메시지에 독립적입니다. `Component.render(width)`, `handleInput(data)`, 포커스, 오버레이만 알고 있습니다. 에이전트 시맨틱은 대화형 컨트롤러에 유지됩니다.\n\n## 구현 파일\n\n- [`../src/modes/interactive-mode.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/modes/interactive-mode.ts)\n- [`../src/modes/controllers/event-controller.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/modes/controllers/event-controller.ts)\n- [`../src/modes/controllers/input-controller.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/modes/controllers/input-controller.ts)\n- [`../src/modes/components/custom-editor.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/modes/components/custom-editor.ts)\n- [`../../tui/src/tui.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/tui/src/tui.ts)\n- [`../../tui/src/terminal.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/tui/src/terminal.ts)\n- [`../../tui/src/editor-component.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/tui/src/editor-component.ts)\n- [`../../tui/src/stdin-buffer.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/tui/src/stdin-buffer.ts)\n- [`../../tui/src/components/loader.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/tui/src/components/loader.ts)\n\n## 부팅 및 컴포넌트 트리 조립\n\n`InteractiveMode`는 `TUI(new ProcessTerminal(), showHardwareCursor)`를 생성하고 다음과 같은 영구 컨테이너를 만듭니다:\n\n- `chatContainer`\n- `pendingMessagesContainer`\n- `statusContainer`\n- `todoContainer`\n- `statusLine`\n- `editorContainer` (`CustomEditor` 포함)\n\n`init()`은 해당 순서로 트리를 연결하고, 에디터에 포커스를 설정하며, `InputController`를 통해 입력 핸들러를 등록하고, TUI를 시작한 후 강제 렌더를 요청합니다.\n\n강제 렌더(`requestRender(true)`)는 다시 페인팅하기 전에 이전 줄 캐시와 커서 북키핑을 초기화합니다.\n\n## 터미널 생명주기 및 stdin 정규화\n\n`ProcessTerminal.start()`:\n\n1. 원시 모드 및 브래킷 붙여넣기를 활성화합니다.\n2. 리사이즈 핸들러를 연결합니다.\n3. 부분 이스케이프 청크를 완전한 시퀀스로 분리하기 위해 `StdinBuffer`를 생성합니다.\n4. Kitty 키보드 프로토콜 지원을 쿼리(`CSI ? u`)한 후, 지원되면 프로토콜 플래그를 활성화합니다.\n5. Windows에서는 `kernel32` 모드 플래그를 통해 VT 입력 활성화를 시도합니다.\n\n`StdinBuffer` 동작:\n\n- 분열된 이스케이프 시퀀스(CSI/OSC/DCS/APC/SS3)를 버퍼링합니다.\n- 시퀀스가 완료되거나 타임아웃으로 플러시될 때만 `data`를 방출합니다.\n- 브래킷 붙여넣기를 감지하고 원시 붙여넣기 텍스트와 함께 `paste` 이벤트를 방출합니다.\n\n이를 통해 부분 이스케이프 청크가 일반 키 입력으로 잘못 해석되는 것을 방지합니다.\n\n## 입력 라우팅 및 포커스 모델\n\n입력 경로:\n\n`stdin -> ProcessTerminal -> StdinBuffer -> TUI.#handleInput -> focusedComponent.handleInput`\n\n라우팅 세부 사항:\n\n1. TUI는 등록된 입력 리스너를 먼저 실행하여(`addInputListener`) 소비/변환 동작을 허용합니다.\n2. TUI는 컴포넌트 디스패치 전에 전역 디버그 단축키(`shift+ctrl+d`)를 처리합니다.\n3. 포커스된 컴포넌트가 이제 숨겨지거나 보이지 않는 오버레이에 속하면, TUI는 포커스를 다음 보이는 오버레이 또는 저장된 오버레이 이전 포커스로 재할당합니다.\n4. 포커스된 컴포넌트가 `wantsKeyRelease = true`로 설정하지 않는 한 키 해제 이벤트는 필터링됩니다.\n5. 디스패치 후 TUI는 렌더를 스케줄링합니다.\n\n`setFocus()`는 `Focusable.focused`도 전환하여 컴포넌트가 하드웨어 커서 배치를 위해 `CURSOR_MARKER`를 방출할지 여부를 제어합니다.\n\n## 키 처리 분리: 에디터 vs 컨트롤러\n\n`CustomEditor`는 우선순위가 높은 조합(escape, ctrl-c/d/z, ctrl-v, ctrl-p 변형, ctrl-t, alt-up, 확장 사용자 지정 키)을 먼저 가로채고, 나머지는 기본 `Editor` 동작(텍스트 편집, 히스토리, 자동 완성, 커서 이동)에 위임합니다.\n\n`InputController.setupKeyHandlers()`는 에디터 콜백을 모드 액션에 바인딩합니다:\n\n- `Escape`에서 취소/모드 종료\n- 이중 `Ctrl+C` 또는 빈 에디터 `Ctrl+D`에서 종료\n- `Ctrl+Z`에서 일시 중단/재개\n- 슬래시 명령 및 선택기 단축키\n- 후속/대기열 제거 토글 및 확장 토글\n\n이를 통해 키 파싱/에디터 메커니즘은 `packages/tui`에 유지되고 모드 시맨틱은 coding-agent 컨트롤러에 유지됩니다.\n\n## 렌더 루프 및 diff 전략\n\n`TUI.requestRender()`는 `process.nextTick`을 사용하여 틱당 하나의 렌더로 디바운싱됩니다. 동일한 턴에서 여러 상태 변경이 병합됩니다.\n\n`#doRender()` 파이프라인:\n\n1. 루트 컴포넌트 트리를 `newLines`로 렌더링합니다.\n2. 보이는 오버레이가 있으면 합성합니다.\n3. 보이는 뷰포트 줄에서 `CURSOR_MARKER`를 추출하고 제거합니다.\n4. 비이미지 줄에 세그먼트 리셋 접미사를 추가합니다.\n5. 전체 재페인트와 차등 패치 중에서 선택합니다:\n - 첫 번째 프레임\n - 너비 변경\n - `clearOnShrink`가 활성화되고 오버레이가 없는 상태에서 축소\n - 이전 뷰포트 위의 편집\n6. 차등 업데이트의 경우 변경된 줄 범위만 패치하고, 필요한 경우 오래된 후행 줄을 지웁니다.\n7. IME 지원을 위해 하드웨어 커서를 재배치합니다.\n\n렌더 쓰기는 플리커/티어링을 줄이기 위해 동기화된 출력 모드(`CSI ? 2026 h/l`)를 사용합니다.\n\n## 렌더 안전 제약\n\n`TUI`의 중요 안전 검사:\n\n- 비이미지 렌더링 줄은 터미널 너비를 초과해서는 안 됩니다. 오버플로우 시 예외를 발생시키고 크래시 진단을 작성합니다.\n- 오버레이 합성에는 방어적 잘라내기와 합성 후 너비 검증이 포함됩니다.\n- 너비 변경은 줄 바꿈 시맨틱이 변경되기 때문에 전체 재그리기를 강제합니다.\n- 커서 위치는 이동 전에 클램핑됩니다.\n\n이러한 제약은 단순한 관례가 아닌 런타임 적용 사항입니다.\n\n## 리사이즈 처리\n\n리사이즈 이벤트는 `ProcessTerminal`에서 `TUI.requestRender()`로 이벤트 기반으로 처리됩니다.\n\n효과:\n\n- 너비 변경 시 전체 재그리기가 트리거됩니다.\n- 뷰포트/상단 추적(`#previousViewportTop`, `#maxLinesRendered`)은 콘텐츠나 터미널 크기가 변경될 때 잘못된 상대 커서 계산을 방지합니다.\n- 오버레이 가시성은 터미널 크기에 의존할 수 있으며(`OverlayOptions.visible`), 리사이즈 후 오버레이가 보이지 않게 되면 포커스가 수정됩니다.\n\n## 스트리밍 및 증분 UI 업데이트\n\n`EventController`는 `AgentSessionEvent`를 구독하고 UI를 증분 방식으로 업데이트합니다:\n\n- `agent_start`: `statusContainer`에서 로더를 시작합니다.\n- `message_start` 어시스턴트: `streamingComponent`를 생성하고 마운트합니다.\n- `message_update`: 스트리밍 어시스턴트 콘텐츠를 업데이트하고, 도구 호출이 나타날 때 도구 실행 구성 요소를 생성/업데이트합니다.\n- `tool_execution_update/end`: 도구 결과 구성 요소와 완료 상태를 업데이트합니다.\n- `message_end`: 어시스턴트 스트림을 완료하고, 중단/오류 주석을 처리하며, 정상 중지 시 보류 중인 도구 인수를 완료로 표시합니다.\n- `agent_end`: 로더를 중지하고, 임시 스트림 상태를 지우며, 지연된 모델 전환을 플러시하고, 백그라운드 상태이면 완료 알림을 발행합니다.\n\n읽기 도구 그룹화는 의도적으로 상태를 유지하며(`#lastReadGroup`), 비읽기 중단이 발생할 때까지 연속적인 읽기 도구 호출을 하나의 시각적 블록으로 병합합니다.\n\n## 상태 및 로더 오케스트레이션\n\n상태 레인 소유권:\n\n- `statusContainer`는 임시 로더(`loadingAnimation`, `autoCompactionLoader`, `retryLoader`)를 보유합니다.\n- `statusLine`은 영구 상태/훅/플랜 표시기를 렌더링하고 에디터 상단 테두리 업데이트를 구동합니다.\n\n로더 동작:\n\n- `Loader`는 인터벌을 통해 80ms마다 업데이트하고 각 프레임에서 렌더를 요청합니다.\n- 자동 압축 및 자동 재시도 중에는 이스케이프 핸들러가 해당 작업을 취소하기 위해 일시적으로 재정의됩니다.\n- 종료/취소 경로에서 컨트롤러는 이전 이스케이프 핸들러를 복원하고 로더 구성 요소를 중지/지웁니다.\n\n## 모드 전환 및 백그라운드 처리\n\n### Bash/Python 입력 모드\n\n입력 텍스트 접두사가 에디터 테두리 모드 플래그를 전환합니다:\n\n- `!` -> bash 모드\n- `$` (비템플릿 리터럴 접두사) -> python 모드\n\nEscape는 에디터 텍스트를 지우고 테두리 색상을 복원하여 비활성 모드를 종료합니다. 실행이 활성 상태일 때 Escape는 실행 중인 작업을 대신 중단합니다.\n\n### 플랜 모드\n\n`InteractiveMode`는 플랜 모드 플래그, 상태 줄 상태, 활성 도구, 모델 전환을 추적합니다. 진입/종료 시 세션 모드 항목과 상태/UI 상태를 업데이트하며, 스트리밍이 활성 상태이면 지연된 모델 전환을 포함합니다.\n\n### 일시 중단/재개 (`Ctrl+Z`)\n\n`InputController.handleCtrlZ()`:\n\n1. TUI를 다시 시작하고 강제 렌더하기 위해 일회성 `SIGCONT` 핸들러를 등록합니다.\n2. 일시 중단 전에 TUI를 중지합니다.\n3. 프로세스 그룹에 `SIGTSTP`를 전송합니다.\n\n### 백그라운드 모드 (`/background` 또는 `/bg`)\n\n`handleBackgroundCommand()`:\n\n- 유휴 상태일 때 거부합니다.\n- 도구 UI 컨텍스트를 비대화형(`hasUI=false`)으로 전환하여 대화형 UI 도구가 빠르게 실패하도록 합니다.\n- 로더/상태 줄을 중지하고 포그라운드 이벤트 핸들러의 구독을 취소합니다.\n- 백그라운드 이벤트 핸들러를 구독합니다(주로 `agent_end`를 기다림).\n- TUI를 중지하고 `SIGTSTP`를 전송합니다(POSIX 작업 제어 경로).\n\n대기 중인 작업 없이 백그라운드에서 `agent_end` 발생 시, 컨트롤러는 완료 알림을 전송하고 종료합니다.\n\n## 취소 경로\n\n주요 취소 입력:\n\n- 활성 스트림 로더 중 `Escape`: 대기 중인 메시지를 에디터에 복원하고 에이전트를 중단합니다.\n- bash/python 실행 중 `Escape`: 실행 중인 명령을 중단합니다.\n- 자동 압축/재시도 중 `Escape`: 임시 이스케이프 핸들러를 통해 전용 중단 메서드를 호출합니다.\n- `Ctrl+C` 단일 누름: 에디터 지우기; 500ms 내 두 번 누름: 종료.\n\n취소는 상태 조건부입니다. 동일한 키가 런타임 상태에 따라 중단, 모드 종료, 선택기 트리거, 또는 아무 동작 없음을 의미할 수 있습니다.\n\n## 이벤트 기반 vs 스로틀 동작\n\n이벤트 기반 업데이트:\n\n- 에이전트 세션 이벤트(`EventController`)\n- 키 입력 콜백(`InputController`)\n- 터미널 리사이즈 콜백\n- `InteractiveMode`의 테마/브랜치 감시자\n\n스로틀/디바운스 경로:\n\n- TUI 렌더링은 틱 디바운싱됩니다(`requestRender` 병합).\n- 로더 애니메이션은 고정 인터벌(80ms)로, 각 프레임에서 렌더를 요청합니다.\n- 에디터 자동 완성 업데이트(`Editor` 내부)는 디바운스 타이머를 사용하여 타이핑 중 재계산 오버헤드를 줄입니다.\n\n따라서 런타임은 이벤트 기반 상태 전환과 제한된 렌더 주기를 혼합하여 재페인트 폭풍 없이 대화형 응답성을 유지합니다.\n",
|
|
483
484
|
"ko/tui/tui.md": "---\ntitle: 확장 기능 및 커스텀 도구를 위한 TUI 통합\ndescription: '확장 기능, 커스텀 도구, 커스텀 렌더러를 위한 TUI 통합 계약.'\nsidebar:\n order: 1\n label: 확장 기능 통합\ni18n:\n sourceHash: 47f8f2b2045e\n translator: machine\n---\n\n# 확장 기능 및 커스텀 도구를 위한 TUI 통합\n\n이 문서는 확장 UI, 커스텀 도구 UI, 커스텀 렌더러를 위해 `packages/coding-agent`와 `packages/tui`에서 사용하는 **현재** TUI 계약을 다룹니다.\n\n## 이 서브시스템이란\n\n런타임은 두 개의 레이어로 구성됩니다:\n\n- **렌더링 엔진 (`packages/tui`)**: 차분 터미널 렌더러, 입력 디스패치, 포커스, 오버레이, 커서 배치.\n- **통합 레이어 (`packages/coding-agent`)**: 확장/커스텀 도구 컴포넌트를 마운트하고, 키바인딩/테마를 연결하며, 에디터 상태를 복원합니다.\n\n## 모드별 런타임 동작\n\n| 모드 | `ctx.ui.custom(...)` 사용 가능 여부 | 비고 |\n| --- | --- | --- |\n| 인터랙티브 TUI | 지원됨 | 컴포넌트가 에디터 영역에 마운트되고 포커스되며, 반드시 `done(result)`를 호출하여 resolve해야 합니다. |\n| 백그라운드/헤드리스 | 비인터랙티브 | UI 컨텍스트는 no-op입니다 (`hasUI === false`). |\n| RPC 모드 | 지원되지 않음 | `custom()`은 `Promise<never>`를 반환하며 TUI 컴포넌트를 마운트하지 않습니다. |\n\n확장/도구가 비인터랙티브 모드에서 실행될 수 있다면, `ctx.hasUI` / `pi.hasUI`로 가드하세요.\n\n## 핵심 컴포넌트 계약 (`@f5-sales-demo/pi-tui`)\n\n`packages/tui/src/tui.ts`에서 정의합니다:\n\n```ts\nexport interface Component {\n render(width: number): string[];\n handleInput?(data: string): void;\n wantsKeyRelease?: boolean;\n invalidate(): void;\n}\n```\n\n`Focusable`은 별도입니다:\n\n```ts\nexport interface Focusable {\n focused: boolean;\n}\n```\n\n커서 동작은 `CURSOR_MARKER`를 사용합니다 (`getCursorPosition`이 아님). 포커스된 컴포넌트는 렌더링된 텍스트에 마커를 출력하고, `TUI`가 이를 추출하여 하드웨어 커서를 위치시킵니다.\n\n## 렌더링 제약 조건 (터미널 안전성)\n\n`render(width)` 출력은 반드시 터미널에 안전해야 합니다:\n\n1. **어떤 라인에서도 `width`를 초과하지 마세요**. 이미지가 아닌 라인이 오버플로우되면 렌더러가 에러를 던집니다.\n2. **문자열 길이가 아닌 시각적 너비를 측정하세요**: `visibleWidth()`를 사용합니다.\n3. **ANSI 인식 텍스트를 잘라내거나 줄바꿈하세요**: `truncateToWidth()` / `wrapTextWithAnsi()`를 사용합니다.\n4. **외부 소스의 탭/콘텐츠를 정제하세요**: `replaceTabs()`를 사용합니다 (그리고 coding-agent 렌더 경로의 상위 레벨 정제기도 사용합니다).\n\n최소 패턴:\n\n```ts\nimport { replaceTabs, truncateToWidth } from \"@f5-sales-demo/pi-tui\";\n\nrender(width: number): string[] {\n return this.lines.map(line => truncateToWidth(replaceTabs(line), width));\n}\n```\n\n## 입력 처리 및 키바인딩\n\n### 원시 키 매칭\n\n탐색 키와 조합에는 `matchesKey(data, \"...\")`를 사용하세요.\n\n### 사용자 구성 앱 키바인딩 존중\n\n확장 UI 팩토리는 `KeybindingsManager`(인터랙티브 모드)를 수신하므로, 키를 하드코딩하는 대신 매핑된 액션을 사용할 수 있습니다:\n\n```ts\nif (keybindings.matches(data, \"interrupt\")) {\n done(undefined);\n return;\n}\n```\n\n### 키 릴리스/반복 이벤트\n\n키 릴리스 이벤트는 컴포넌트에서 다음을 설정하지 않으면 필터링됩니다:\n\n```ts\nwantsKeyRelease = true;\n```\n\n필요한 경우 `isKeyRelease()` / `isKeyRepeat()`를 사용하세요.\n\n## 포커스, 오버레이, 커서\n\n- `TUI.setFocus(component)`는 해당 컴포넌트로 입력을 라우팅합니다.\n- 오버레이 API는 `TUI`에 존재하지만 (`showOverlay`, `OverlayHandle`), 인터랙티브 모드에서 확장 `ctx.ui.custom` 마운팅은 현재 에디터 컴포넌트 영역을 직접 교체합니다.\n- `custom(..., options?: { overlay?: boolean })` 옵션은 확장 타입에 존재하지만, 현재 인터랙티브 확장 마운팅에서는 이 옵션을 무시합니다.\n\n## 마운트 포인트 및 반환 계약\n\n## 1) 확장 UI (`ExtensionUIContext`)\n\n현재 시그니처 (`extensibility/extensions/types.ts`):\n\n```ts\ncustom<T>(\n factory: (\n tui: TUI,\n theme: Theme,\n keybindings: KeybindingsManager,\n done: (result: T) => void,\n ) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>,\n options?: { overlay?: boolean },\n): Promise<T>\n```\n\n인터랙티브 모드에서의 동작 (`extension-ui-controller.ts`):\n\n- 에디터 텍스트를 저장합니다.\n- 에디터 컴포넌트를 사용자의 컴포넌트로 교체합니다.\n- 사용자의 컴포넌트에 포커스를 줍니다.\n- `done(result)` 호출 시: `component.dispose?.()`를 호출하고, 에디터와 텍스트를 복원하며, 에디터에 포커스를 주고, 프로미스를 resolve합니다.\n\n따라서 `done(...)`은 완료를 위해 필수입니다.\n\n## 2) 훅/커스텀 도구 UI 컨텍스트 (레거시 타이핑)\n\n`HookUIContext.custom`은 훅/커스텀 도구 타입에서 `(tui, theme, done)`으로 타이핑되어 있습니다.\n내부 인터랙티브 구현은 팩토리를 `(tui, theme, keybindings, done)`으로 호출합니다. JS 소비자는 추가 인자를 사용할 수 있으며, 타입 레벨 호환성은 여전히 3인자 레거시 시그니처를 반영합니다.\n\n커스텀 도구는 일반적으로 팩토리 스코프의 `pi.ui` 객체를 통해 동일한 UI 진입점을 사용한 다음, 선택된 값을 일반 도구 콘텐츠로 반환합니다:\n\n```ts\nasync execute(toolCallId, params, onUpdate, ctx, signal) {\n if (!pi.hasUI) {\n return { content: [{ type: \"text\", text: \"UI unavailable\" }] };\n }\n\n const picked = await pi.ui.custom<string | undefined>((tui, theme, done) => {\n const component = new MyPickerComponent(done, signal);\n return component;\n });\n\n return { content: [{ type: \"text\", text: picked ? `Picked: ${picked}` : \"Cancelled\" }] };\n}\n```\n\n## 3) 커스텀 도구 호출/결과 렌더러\n\n커스텀 도구와 확장 도구는 다음에서 컴포넌트를 반환할 수 있습니다:\n\n- `renderCall(args, theme)`\n- `renderResult(result, options, theme, args?)`\n\n`options`에는 현재 다음이 포함됩니다:\n\n- `expanded: boolean`\n- `isPartial: boolean`\n- `spinnerFrame?: number`\n\n이러한 렌더러는 `ToolExecutionComponent`에 의해 마운트됩니다.\n\n## 생명주기 및 취소\n\n- `dispose()`는 타입 레벨에서 선택 사항이지만, 타이머, 서브프로세스, 워처, 소켓, 또는 오버레이를 소유하는 경우 구현해야 합니다.\n- `done(...)`은 컴포넌트 플로우에서 정확히 한 번 호출되어야 합니다.\n- 취소 가능한 장시간 실행 UI의 경우, `CancellableLoader`와 `AbortSignal`을 결합하고 `onAbort`에서 `done(...)`을 호출하세요.\n\n취소 패턴 예시:\n\n```ts\nconst loader = new CancellableLoader(tui, theme.fg(\"accent\"), theme.fg(\"muted\"), \"Working...\");\nloader.onAbort = () => done(undefined);\nvoid doWork(loader.signal).then(result => done(result));\nreturn loader;\n```\n\n## 실제 커스텀 컴포넌트 예시 (확장 명령)\n\n```ts\nimport type { Component } from \"@f5-sales-demo/pi-tui\";\nimport { SelectList, matchesKey, replaceTabs, truncateToWidth } from \"@f5-sales-demo/pi-tui\";\nimport { getSelectListTheme, type ExtensionAPI } from \"@f5-sales-demo/xcsh\";\n\nclass Picker implements Component {\n list: SelectList;\n keybindings: any;\n done: (value: string | undefined) => void;\n\n constructor(\n items: Array<{ value: string; label: string }>,\n keybindings: any,\n done: (value: string | undefined) => void,\n ) {\n this.list = new SelectList(items, 8, getSelectListTheme());\n this.keybindings = keybindings;\n this.done = done;\n this.list.onSelect = item => this.done(item.value);\n this.list.onCancel = () => this.done(undefined);\n }\n\n handleInput(data: string): void {\n if (this.keybindings.matches(data, \"interrupt\")) {\n this.done(undefined);\n return;\n }\n this.list.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.list.render(width).map(line => truncateToWidth(replaceTabs(line), width));\n }\n\n invalidate(): void {\n this.list.invalidate();\n }\n}\n\nexport default function extension(pi: ExtensionAPI): void {\n pi.registerCommand(\"pick-model\", {\n description: \"Pick a model profile\",\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) return;\n\n const selected = await ctx.ui.custom<string | undefined>((tui, theme, keybindings, done) => {\n const items = [\n { value: \"fast\", label: theme.fg(\"accent\", \"Fast\") },\n { value: \"balanced\", label: \"Balanced\" },\n { value: \"quality\", label: \"Quality\" },\n ];\n return new Picker(items, keybindings, done);\n });\n\n if (selected) ctx.ui.notify(`Selected profile: ${selected}`, \"info\");\n },\n });\n}\n```\n\n## 주요 구현 파일\n\n- `packages/tui/src/tui.ts` — `Component`, `Focusable`, 커서 마커, 포커스, 오버레이, 입력 디스패치.\n- `packages/tui/src/utils.ts` — 너비/잘라내기/정제 프리미티브.\n- `packages/tui/src/keys.ts` / `keybindings.ts` — 키 파싱 및 구성 가능한 액션 매핑.\n- `packages/coding-agent/src/modes/controllers/extension-ui-controller.ts` — 확장/훅/커스텀 도구 UI의 인터랙티브 마운팅/언마운팅.\n- `packages/coding-agent/src/extensibility/extensions/types.ts` — 확장 UI 및 렌더러 계약.\n- `packages/coding-agent/src/extensibility/hooks/types.ts` — 훅 UI 계약 (레거시 custom 시그니처).\n- `packages/coding-agent/src/extensibility/custom-tools/types.ts` — 커스텀 도구 execute/render 계약.\n- `packages/coding-agent/src/modes/components/tool-execution.ts` — `renderCall`/`renderResult` 컴포넌트 마운팅 및 부분 상태 옵션.\n- `packages/coding-agent/src/tools/context.ts` — 도구 UI 컨텍스트 전파 (`hasUI`, `ui`).\n",
|
|
484
|
-
"plans/provider-agnostic-dynamic-model-routing.md": "# Provider-Agnostic Dynamic Model Routing for xcsh\n\n## 1. Summary and decisions\n\nImplement a routing coordinator at the AgentSession boundary. It will profile each top-level task, select an appropriate model tier, account for context capacity, optionally dispatch bounded read-only subagents, and escalate only from validated evidence.\n\nThe router will complement—not replace—existing model roles, retry fallbacks, context promotion, compaction, and task execution.\n\nKey decisions:\n\n- Routing applies to any provider with an explicit tier-pool definition.\n- Ship reviewed presets; never infer tiers from arbitrary model names.\n- Initial presets:\n - OpenAI: Luna → utility, Terra → balanced, Sol → frontier.\n - Anthropic: Haiku → utility, Sonnet → balanced, Opus → frontier.\n - LiteLLM: separate OpenAI and Anthropic pools under the same litellm provider.\n\n- Direct OpenAI and Anthropic use the same router through provider-specific pools.\n- Untiered providers and models outside a pool pass through unchanged.\n- Routing is family-sticky by default. Cross-family/provider routing requires an explicitly declared mixed pool or the existing retry fallback mechanism.\n- Default mode is off; rollout proceeds through explicit shadow, then opt-in auto.\n- A manual model selection is a hard pin until `/route auto`.\n- Upgrades occur immediately; downshifts require two consecutive lower-tier profiles.\n- The router chooses once before a tool loop and remains fixed during it. Existing retry fallback and context-overflow promotion remain emergency exceptions.\n- Autonomous delegation is limited to read-only work, at most three subtasks, with no recursive autonomous delegation.\n- No separate routing dollar budget. Existing concurrency, recursion, authentication, safety, and approval controls remain authoritative.\n\n## 2. Architecture and public interfaces\n\n### Capability and configuration model\n\nAdd a routing settings group:\n\n```yaml\nrouting:\n mode: off # off | shadow | auto\n profiler: hybrid # rules | hybrid\n familyPolicy: sticky # sticky | configured-mixed\n delegation: read-only # off | read-only\n delegationMaxTasks: 3\n downshiftAfterTurns: 2\n tierEffort:\n utility: low\n balanced: medium\n frontier: high\n pools: {} # Overrides or additional explicit pools\n disabledPresets: []\n```\n\nEach pool contains ordered, fully qualified model selectors for utility, balanced, and frontier. Selectors must be unique within a pool. Non-mixed pools must use one provider; mixed pools must explicitly opt in.\n\nBuilt-in pools:\n\n- `openai/gpt-5.6`: direct OpenAI models (e.g. `gpt-4o-mini` for utility, `gpt-4o` for balanced, `o3-mini`/`gpt-4.5-preview` for frontier).\n- `anthropic/claude`: direct Anthropic models (e.g. `claude-3-5-haiku-latest` for utility, `claude-3-5-sonnet-latest` for balanced, `claude-3-opus-latest` for frontier).\n- `litellm/openai`: internal LiteLLM Luna, Terra, and Sol (`gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`).\n- `litellm/anthropic`: internal LiteLLM Haiku, Sonnet, and Opus.\n\nAt implementation start, pin the exact Anthropic and LiteLLM IDs from authenticated model inventories and official documentation. Missing models degrade the pool; a pool with fewer than two available tiers is ineligible and passes through.\n\nConfiguration precedence:\n\n1. Explicit user pool override.\n2. Reviewed built-in preset.\n3. No pool and no name inference.\n\nCandidate selection intersects the pool with authenticated, enabled, runtime-discovered, and `--models`-scoped models.\n\n### Core types\n\nIntroduce public routing types:\n\n```typescript\ntype RoutingTier = \"utility\" | \"balanced\" | \"frontier\";\ntype RoutingMode = \"off\" | \"shadow\" | \"auto\";\ntype RoutingDecisionSource = \"rules\" | \"classifier\" | \"hybrid\";\n\ninterface TaskProfile {\n complexityScore: number;\n desiredTier: RoutingTier;\n confidence: number;\n reasons: RoutingReasonCode[];\n requiredCapabilities: {\n vision: boolean;\n tools: boolean;\n minimumContextTokens: number;\n };\n delegation?: ReadOnlyDelegationPlan;\n}\n\ninterface RoutingDecision {\n epochId: string;\n mode: RoutingMode;\n poolId?: string;\n anchorModel: string;\n desiredTier?: RoutingTier;\n effectiveTier?: RoutingTier;\n selectedModel?: string;\n source?: RoutingDecisionSource;\n applied: boolean;\n reasons: RoutingReasonCode[];\n}\n\ninterface RoutingOutcome {\n epochId: string;\n status: \"accepted\" | \"rejected\";\n evidence: RoutingOutcomeEvidence[];\n safeToContinue?: boolean;\n}\n```\n\nExtend `AgentSession` with:\n\n- `getRoutingStatus()`\n- `setRoutingMode(mode)`\n- `clearRoutingPin()`\n- `recordRoutingOutcome(outcome)`\n- model-switch source metadata distinguishing manual, routing, retry fallback, and context promotion.\n\nExpose session events:\n\n- `routing_decision`\n- `routing_applied`\n- `routing_delegated`\n- `routing_escalated`\n- `routing_skipped`\n\nEvents include provider, pool, tier, model, sanitized reason codes, context estimate, decision duration, classifier usage, and token usage. They must never contain prompt text, credentials, headers, or tool output.\n\nPersist mode overrides, pins, active pool, tier, downshift streak, and escalation floor as non-context session custom entries. On session resume, reset, or branch switching, downshift streak counters and escalation floors are contextually re-evaluated against the active turn branch history rather than relying on flat global custom entries.\n\n### Profiling and resolution\n\nDeterministic profiling starts at score 30:\n\n- +25: prior validated rejection.\n- +20: architecture, migration, security analysis, or explicit deep-review intent.\n- +15: mutation spanning multiple targets/repositories or at least three independent deliverables.\n- +10: image/special capability requirement.\n- +10: context usage at least 60%; +20 at least 80%.\n- +10: material ambiguity or missing acceptance conditions.\n- -20: exact, single-step read, extraction, classification, summarization, or mechanical operation involving at most one target.\n\nClamp to 0–100:\n\n- 0–30: utility\n- 31–69: balanced\n- 70–100: frontier\n\nHard capability, context, safety, and validated-outcome floors cannot be lowered by the classifier.\n\nIn hybrid mode, an ambiguous balanced profile invokes a one-shot structured classifier through the utility model in the active pool. It receives the bounded current request and structured metadata—not the conversation transcript—and has no tools. Confidence below 0.75, timeout, malformed output, or unavailable utility tier resolves to balanced.\n\nContext resolution uses the existing context estimator and compaction reserve. A candidate is eligible only when:\n\n`estimated input + max(existing reserveTokens, 15% of candidate context) < candidate contextWindow`\n\nThe resolver searches the desired tier, then higher tiers. It never selects a lower tier than the required quality/capability floor.\n\n### Runtime flow\n\n```mermaid\nflowchart LR\n A[Top-level prompt] --> B{Mode, pin, pool and fallback gate}\n B -->|Ineligible| C[Pass through and emit skipped]\n B -->|Eligible| D[Deterministic task profile]\n D --> E{Ambiguous and hybrid?}\n E -->|Yes| F[Utility structured classifier]\n E -->|No| G[Capability and context floors]\n F --> G\n G --> H[Pool resolver and downshift hysteresis]\n H --> I{Mode}\n I -->|Shadow| J[Record proposed route]\n I -->|Auto| K[Temporary sourced model switch]\n K --> L[Optional read-only delegation]\n J --> M[Normal agent loop]\n L --> M\n M --> N[Validated outcome]\n N -->|Accepted| O[Clear escalation floor]\n N -->|Rejected and safe| P[One higher-tier continuation]\n N -->|Rejected and unsafe| Q[Record next-turn tier floor]\n```\n\nThe coordinator runs after retry-fallback restoration but before API-key validation and compaction. It skips while an existing retry fallback remains active.\n\nA rejected, trusted outcome may cause at most one post-loop escalation continuation. It switches one tier upward, continues from the existing transcript and tool results, and does not replay the prompt or completed actions. Unsafe continuations only set a floor for the next turn. Free-form model self-assessment cannot trigger escalation.\n\nAutonomous delegation requires at least two independent read-only information targets. The classifier may return two or three schema-validated subtasks. Delegates:\n\n- Use only read, grep, find, ls, lsp, and approved read-only search tools.\n- Receive a minimal task/context pack.\n- Use utility by default and balanced only when their own profile requires it.\n- Cannot spawn children.\n- Run through existing task concurrency and cancellation controls.\n- Return results as attributed context for the parent.\n- Never run in shadow mode.\n\nCommands:\n\n- `/route status`: display effective mode, eligibility, pool, pin, active tier/model, downshift streak, and last decision.\n- `/route off`: stop future routing and retain the current model.\n- `/route shadow`: calculate and report decisions without switching or delegating.\n- `/route auto`: clear the manual model pin and route within the pool containing the current model.\n\n## 3. Acceptance matrix and rollout\n\nRequired behavior:\n\n- LiteLLM can independently route its OpenAI and Anthropic families without crossing them.\n- Direct OpenAI and Anthropic use the same generic coordinator and pool contract.\n- An untiered provider, unknown model, unavailable pool, or single-tier pool never changes models.\n- Off and shadow modes never change the active model or launch delegates.\n- Manual model selection remains fixed until `/route auto`.\n- Context and capability requirements can raise but never lower the selected tier.\n- A downshift requires two consecutive qualifying turns.\n- Auxiliary classification is skipped for deterministic profiles.\n- Router-controlled model choice remains fixed through the normal tool loop.\n- Retry fallback and context promotion retain their existing behavior.\n- Autonomous delegates are read-only, bounded, non-recursive, cancellable, and accounted for.\n- Escalation requires trusted validation evidence and never blindly replays a turn.\n- Session resume reproduces the prior routing state without adding routing metadata to model context.\n- All route decisions are observable without leaking prompt or credential data.\n",
|
|
485
|
+
"plans/provider-agnostic-dynamic-model-routing.md": "# Provider-Agnostic Dynamic Model Routing\n\n## Executive status\n\nThe production router is implemented at the `AgentSession` boundary. It supports explicit provider-qualified pools, utility/balanced/frontier tiers, off/shadow/auto modes, deterministic and hybrid classification, context eligibility, hysteresis, manual pins, escalation and rollback, read-only delegation, persistence, telemetry, and route commands.\n\nThe authenticated routing-matrix harness has been redesigned under issue #3114. Its deterministic and mocked-network evidence is authoritative for code paths, but the project is not empirically complete until a clean exact-`origin/main` report proves all five required lanes through real authenticated inference.\n\nCI, unit tests, dry runs, bundled catalog entries, missing-credential BLOCKED results, and completion-auditor statements are not live acceptance evidence.\n\n## Scope and non-goals\n\nThe canonical profile requires direct OpenAI, direct Anthropic, LiteLLM OpenAI-family, LiteLLM Anthropic-family, and an explicitly configured Google Vertex pool. Four scenarios and three repetitions produce 60 measured rows; one warmup per lane produces five warmup rows.\n\nOther providers may opt in only through explicit capability and tier-pool configuration. Untiered providers remain on their selected model. Model names never imply tiers.\n\nThis work does not add translations, infer gateway upstream providers, treat Azure credentials as direct OpenAI credentials, substitute unavailable tier models, or run paid inference before deterministic gates pass.\n\n## Runtime architecture\n\n```text\nAgentSession\n -> RoutingCoordinator\n -> deterministic/hybrid profiler\n -> explicit pool and live model candidates\n -> capability/context resolver\n -> state machine and hysteresis\n -> model switch or shadow decision\n -> bounded read-only delegation\n -> outcome, escalation, rollback\n -> persistence and sanitized telemetry\n```\n\nManual selection is a hard pin until `/route auto`. Context and capability floors can promote but not demote. Downshifts require consecutive lower-tier profiles. Retry fallback and context-overflow handling remain emergency mechanisms. Delegation is read-only, bounded, non-recursive, cancellable, and token-accounted.\n\nThe harness is a separate evidence pipeline:\n\n```text\nCLI profile\n -> lane capabilities\n -> credential resolvers\n -> provider inventory adapters\n -> per-lane tier reconciliation\n -> warmup rows\n -> measured routing and inference rows\n -> evidence classifier\n -> schema validation, recursive redaction, secret scan\n -> external report and hash receipt\n```\n\n## Provider capability model\n\n| Lane | Client transport | Family | Pool | Inventory | Authentication | Attribution |\n| --- | --- | --- | --- | --- | --- | --- |\n| `openai` | OpenAI Responses | OpenAI | `openai/gpt-5.6` | Authenticated OpenAI `/v1/models` | Existing xcsh direct OpenAI resolver | Endpoint, request, client, raw response model |\n| `anthropic` | Anthropic Messages | Anthropic | `anthropic/claude` | Authenticated Anthropic `/v1/models` | Existing xcsh API-key/OAuth resolver with LiteLLM fallback disabled | Endpoint, request, client, raw response model |\n| `litellm-openai` | OpenAI-compatible | OpenAI | `litellm/openai` | Its own authenticated LiteLLM endpoint | Lane-specific key/base URL, then xcsh LiteLLM resolver | Endpoint, request, client, raw response model; upstream provider may be unproven |\n| `litellm-anthropic` | Anthropic Messages-compatible | Anthropic | `litellm/anthropic` | Its own authenticated LiteLLM endpoint | Separate Anthropic-compatible base URL and LiteLLM credential | Endpoint, request, client, raw response model; upstream provider may be unproven |\n| `google-vertex` | Vertex | Google | `google-vertex/gemini` | Authenticated Model Garden publisher list | Real ADC access token and project/location | Endpoint, request, and client; the current SDK stream does not expose a response-reported model |\n\nLane identity is independent of provider name. This keeps direct Anthropic and Anthropic-over-LiteLLM distinct.\n\n`AssistantMessage.provider` and `model` remain client/request fields for compatibility. Optional `responseAttribution` records server evidence only. Missing server evidence remains absent and fails lanes that declare response-model proof mandatory.\n\n## Inventory architecture\n\nFour inventories remain distinct:\n\n1. Bundled catalog metadata, which can inform display, context, and cost only.\n2. Explicit configured utility/balanced/frontier models.\n3. Models returned by the lane's authenticated live endpoint.\n4. Eligible candidates: configured tiers intersected with that same lane's live inventory and runtime constraints.\n\nAll three tiers must exist for every canonical lane. Candidate inventories are never combined across endpoints.\n\nInventory states are `AVAILABLE`, `BLOCKED_AUTH`, `BLOCKED_NETWORK`, `BLOCKED_RATE_LIMIT`, `UNSUPPORTED_DISCOVERY`, `FAIL_SCHEMA`, `FAIL_EMPTY_INVENTORY`, and `FAIL_MISSING_TIERS`. Dry-run inventory is `SIMULATED`. No failed live state falls back to bundled success.\n\n## Evidence and benchmark contract\n\nEvidence is recorded separately for requested model, routing-selected tier/model, client provider, endpoint fingerprint, server-reported response model, server-reported upstream provider when available, stop reason, usage, exact content, and multimodal consumption.\n\nLiteLLM authority is capability-relative: a report may establish endpoint, request, client, response model, tier, usage, and content while stating that the true gateway upstream provider is unproven. The report must never infer it.\n\nStatuses:\n\n- `PASS`: every required assertion for the row passed.\n- `FAIL`: deterministic routing, schema, attribution, stop, usage, content, report, or security behavior failed.\n- `BLOCKED`: authentication, network, rate limit, or provider availability prevented evaluation.\n- `SKIPPED_UNTIERED`: optional provider has no configured pool; illegal for canonical required lanes.\n- `SIMULATED`: dry-run row; never counted as PASS.\n\nDefault counts are five warmups and 60 measured rows. `matrixComplete` requires exact counts and every live inventory, warmup, and measured row PASS. `authoritative` additionally requires non-dry execution, clean exact final HEAD, positive usage, declared response attribution, schema validation, recursive redaction, and secret-scan success.\n\nExit codes are 0 for successful requested-mode execution, 1 for behavior/schema/security failure, 2 for an environmentally BLOCKED or incomplete required matrix, and 64 for invalid CLI configuration. A successful dry run may exit 0 but remains non-complete and non-authoritative.\n\nThe utility, balanced, and frontier prompts contain deterministic profiler signals and require marker-only output. The multimodal fixture contains a visible code absent from the prompt; the model must inspect the image to produce the expected answer.\n\n## TDD and staged UAT\n\nEvery behavior is introduced with a failing focused test, minimal implementation, focused green run, coding-agent suite, type check, lint, and dry run.\n\nMocked HTTP coverage includes successful provider schemas, empty inventory, missing tiers, 401, 403, 404, 429, 500, malformed JSON, DNS/network failure, timeout/abort, ADC, OAuth/API-key headers, no bundled fallback, redaction, attribution gaps, warmup failures, and partial/all-BLOCKED contracts.\n\nPaid UAT is staged:\n\n1. Stage A: unit tests, mocked HTTP, type/lint checks, dry run, schema validation, and secret tests.\n2. Stage B: LiteLLM OpenAI utility with one warmup and one repetition; then balanced/frontier only after success.\n3. Stage C: both LiteLLM lanes, one warmup and one repetition per scenario.\n4. Stage D: final clean `origin/main`, all five lanes, five warmups, 60 measured rows, recursive scan.\n\nThe complete paid matrix is never used as a debugging loop.\n\n## Reporting, security, and rollout\n\nSchema-v2 reports record Git state, parameters, capability declarations, sanitized endpoint fingerprints, inventory reconciliation, first-class warmups and measurements, timestamps, durations, usage, attribution sources, counts, authority, and security state. Reports are written outside the repository with mode 0600.\n\nThe writer recursively redacts resolved secrets, credential-shaped fields, authorization values, URL credentials, query tokens, and credential paths. It validates the final candidate against the checked-in schema, scans the exact bytes with Gitleaks, atomically publishes unchanged bytes, and writes a SHA-256 receipt. Scan failure publishes no report and exits 1.\n\nOperational rollout remains off by default, then shadow, then per-lane automatic enablement beginning with the two LiteLLM lanes. Monitor decisions, reason codes, latency, token/cost distribution, failures, BLOCKED rate, escalation, and rollback. Provider outages never create inferred substitutes. `/route off` or per-lane disablement is the safe rollback.\n\n## Tracked completion ledger\n\n- [x] RM-01 provider-specific inventory adapters and credential resolvers\n - Implementation target: capability registry, OpenAI-compatible, Anthropic, LiteLLM, and Vertex Model Garden adapters; AuthStorage/API-key/OAuth/ADC resolution.\n - Failing test: provider schema, header, missing credential, and ADC cases in `bench-routing-matrix.test.ts`.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: mocked request/response assertions with no real inference.\n - Completion claim: all adapters use provider-specific URLs, schemas, and authentication; none substitutes a bundled inventory.\n - Reviewer evidence: 22 focused tests pass, including OpenAI, Anthropic, two independent LiteLLM endpoints, and Vertex.\n- [x] RM-02 live, bundled, configured, and eligible inventory separation\n - Implementation target: explicit inventory states, configured-tier reconciliation, and lane-qualified candidate construction.\n - Failing test: empty inventory, missing tier, separate endpoint, and failed-discovery cases.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: report inventory rows with discovered IDs, missing tiers, eligible candidates, and endpoint fingerprints.\n - Completion claim: only the authenticated lane inventory can make a configured tier eligible.\n - Reviewer evidence: focused tests prove missing tiers fail and failed discovery never falls back.\n- [x] RM-03 typed response extraction and exact-output scenarios\n - Implementation target: content-block parser and utility/balanced/frontier prompts that require silent reasoning and one exact marker.\n - Failing test: text, thinking, tool/error, invalid block, whitespace, and task-profile cases.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: measured rows with sanitized reason codes and exact marker results.\n - Completion claim: extraction deterministically joins text blocks and rejects unexpected behavioral blocks.\n - Reviewer evidence: content extraction and all four tier-profile tests pass.\n- [x] RM-04 genuine response attribution\n - Implementation target: optional server-evidence fields on `AssistantMessage`, populated from OpenAI and Anthropic response bodies only.\n - Failing test: missing response model and a server model different from the request.\n - Verification command: `bun test test/response-attribution.test.ts test/anthropic-stream-envelope.test.ts --max-concurrency 2` in `packages/ai`.\n - Required artifact: report fields identify evidence source or explicitly omit unavailable evidence.\n - Completion claim: requested model is never reused as response-reported model; Vertex and gateway upstream limitations are declared.\n - Reviewer evidence: six focused transport tests pass and capability-relative classifier tests reject missing required evidence.\n- [x] RM-05 first-class warmup and contract integration\n - Implementation target: one row per warmup with model/provider/stop/usage checks, expected counts, completeness, authority, and exit status.\n - Failing test: behavioral warmup failure plus partial/all-BLOCKED matrices.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: five default warmup rows and 60 default measured rows.\n - Completion claim: any required warmup FAIL/BLOCKED makes the matrix incomplete, non-authoritative, and nonzero for live execution.\n - Reviewer evidence: contract tests and the 5/60 dry-run count pass.\n- [x] RM-06 image-derived multimodal validation\n - Implementation target: deterministic embedded PNG bearing `ROUTE-7C` and a prompt whose expected marker is absent from its text.\n - Failing test: assert typed image content, expected MIME type, and marker absence from the prompt.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: visual scenario row with the exact image-derived marker.\n - Completion claim: a passing visual response must obtain the answer from image content.\n - Reviewer evidence: fixture contract and multimodal tier profiling tests pass.\n- [x] RM-07 mocked network and failure taxonomy\n - Implementation target: status mapping for 401/403/404/429/500, malformed/empty schemas, DNS/network, timeout/abort, and redacted diagnostics.\n - Failing test: one deterministic mocked-network case per state and authentication variant.\n - Verification command: `bun test test/bench-routing-matrix.test.ts --max-concurrency 2`.\n - Required artifact: focused test output containing 22 PASS and zero FAIL.\n - Completion claim: environmental blocks and behavioral/schema failures remain distinguishable without leaking request details.\n - Reviewer evidence: focused suite passes with 67 assertions.\n- [x] RM-08 report schema and security publication gate\n - Implementation target: schema v2, recursive redaction, 0600 temporary file, Gitleaks scan, atomic rename, and SHA-256 receipt.\n - Failing test: malformed report shape and nested secret/header/URL/query/path values.\n - Verification command: `bun run bench:routing-matrix --dry-run` and `git diff --check`.\n - Required artifact: out-of-repository report plus `.sha256` receipt.\n - Completion claim: unvalidated or secret-scan-failing bytes are never published as the final report.\n - Reviewer evidence: dry run published `/tmp/routing-matrix-reports/2026-08-11T13-44-10-446Z/routing-matrix-report.json`; schema and scan passed.\n- [x] RM-09 deterministic Stage A gate\n - Implementation target: focused tests, full AI and coding-agent suites, formatting, type checking, dry run, and secret scan.\n - Failing test: the pre-implementation harness tests failed until live-path exports and behavior existed.\n - Verification command: `bun run check`, AI focused tests, and `bun run test` in `packages/coding-agent`.\n - Required artifact: command logs and dry-run report.\n - Completion claim: Stage A is green before any paid call is attempted.\n - Reviewer evidence: coding-agent 6,529 pass/559 skip/0 fail; AI package and focused suites pass; check and dry run exit zero.\n- [ ] RM-10 Stage B authenticated LiteLLM OpenAI smoke\n - Implementation target: `litellm-openai`, one warmup, utility at one repetition, then balanced/frontier only after utility passes.\n - Failing test: the first authenticated smoke must expose any endpoint, inventory, attribution, or inference defect.\n - Verification command: `bun run bench:routing-matrix --lanes litellm-openai --scenarios utility-greeting --warmups 1 --repetitions 1`.\n - Required artifact: clean, redacted smoke report outside the repository.\n - Completion claim: live inventory, warmup, and utility measurement all PASS with valid usage and required attribution.\n - Reviewer evidence: blocked on 2026-08-11 because neither LiteLLM endpoint nor credential is configured; no paid call was made.\n- [ ] RM-11 Stage C two-family LiteLLM matrix\n - Implementation target: both LiteLLM lanes, all required scenarios, one warmup and one repetition.\n - Failing test: cross-family pool/model selection, independent inventory, marker, or attribution mismatch fails its row.\n - Verification command: `bun run bench:routing-matrix --lanes litellm-openai,litellm-anthropic --warmups 1 --repetitions 1`.\n - Required artifact: redacted two-lane report and hash receipt.\n - Completion claim: 2/2 warmups and 8/8 measured rows PASS with no FAIL/BLOCKED.\n - Reviewer evidence: pending RM-10 and authorized credentials.\n- [ ] RM-12 Stage D authoritative five-lane matrix\n - Implementation target: all canonical required lanes, one warmup, four scenarios, and three measured repetitions.\n - Failing test: any missing inventory tier, warmup, row, usage, required attribution, or scan makes the run non-authoritative.\n - Verification command: `bun run bench:routing-matrix` on clean current `origin/main`.\n - Required artifact: redacted exact-head report with five warmups, 60 measurements, and hash receipt.\n - Completion claim: `passedWarmups === 5`, `passedMeasured === 60`, `matrixComplete === true`, `authoritative === true`, exit 0.\n - Reviewer evidence: pending RM-10/RM-11, all five authorized credentials, and merge to current main.\n- [ ] RM-13 final exact-head empirical review\n - Implementation target: independently compare report SHA, Git SHA/cleanliness, schema, counts, evidence limitations, and recursive secret scan.\n - Failing test: any mismatch between report claims and current main rejects completion.\n - Verification command: schema validation, `sha256sum -c`, Gitleaks directory scan, and GitHub required-check review.\n - Required artifact: reviewer acceptance linked to the exact authoritative report.\n - Completion claim: project is empirically complete only after the reviewer accepts the clean exact-head authenticated evidence.\n - Reviewer evidence: pending RM-12.\n\nThe unchecked items require configured authorized credentials and real inference. Until they pass, the project remains implemented but empirically incomplete.\n\n## Risks and unresolved product decisions\n\n- Canonical availability risk: any configured tier absent from a live inventory blocks that entire required lane; changing the canonical tier is a reviewed product decision, not a harness fallback.\n- Attribution limitation: LiteLLM may not expose its true upstream provider and the current Vertex SDK stream does not report a serving model. Authority is therefore capability-relative and must retain these explicit omissions.\n- Credential topology: the two LiteLLM families require independently addressable inventory/inference configuration even if an installation chooses to share one key.\n- Vertex inventory compatibility: Model Garden permissions and regional availability may differ from inference permissions; authenticated UAT must confirm the chosen project/location.\n- Cost control: Stage D is prohibited as a debugging loop and remains gated on successful Stages B and C.\n- Final product decision: reviewers must explicitly accept capability-relative attribution, or require gateway/SDK changes that expose stronger upstream evidence before declaring RM-13 complete.\n",
|
|
485
486
|
"pt-br/configuration/blob-artifact-architecture.md": "---\ntitle: Arquitetura de Armazenamento de Blobs e Artefatos\ndescription: >-\n Armazenamento de blobs endereçável por conteúdo e registro de artefatos para\n mídia de sessão, capturas de tela e saídas de ferramentas.\nsidebar:\n order: 7\n label: Armazenamento de blobs e artefatos\ni18n:\n sourceHash: 7a8855b81324\n translator: machine\n---\n\n# Arquitetura de armazenamento de blobs e artefatos\n\nEste documento descreve como o coding-agent armazena payloads grandes/binários fora do JSONL de sessão, como a saída truncada de ferramentas é persistida e como as URLs internas (`artifact://`, `agent://`) resolvem de volta para os dados armazenados.\n\n## Por que dois sistemas de armazenamento existem\n\nO runtime utiliza dois mecanismos de persistência diferentes para diferentes formatos de dados:\n\n- **Blobs endereçados por conteúdo** (`blob:sha256:<hash>`): armazenamento global orientado a binários, usado para externalizar payloads base64 de imagens grandes das entradas de sessão persistidas.\n- **Artefatos com escopo de sessão** (arquivos sob `<arquivoDeSessão-sem-.jsonl>/`): arquivos de texto por sessão usados para saídas completas de ferramentas e saídas de subagentes.\n\nEles são intencionalmente separados:\n\n- o armazenamento de blobs otimiza a deduplicação e referências estáveis por hash de conteúdo,\n- o armazenamento de artefatos otimiza ferramentas de sessão append-only e recuperação por humanos/ferramentas através de IDs locais.\n\n## Limites de armazenamento e layout em disco\n\n## Limite do armazenamento de blobs (global)\n\n`SessionManager` constrói `BlobStore(getBlobsDir())`, então os arquivos de blob ficam em um diretório global compartilhado de blobs (não em uma pasta de sessão).\n\nNomenclatura de arquivos de blob:\n\n- caminho do arquivo: `<blobsDir>/<sha256-hex>`\n- sem extensão\n- string de referência armazenada nas entradas: `blob:sha256:<sha256-hex>`\n\nImplicações:\n\n- o mesmo conteúdo binário entre sessões resolve para o mesmo hash/caminho,\n- escritas são idempotentes no nível do conteúdo,\n- blobs podem sobreviver a qualquer arquivo de sessão individual.\n\n## Limite de artefatos (local à sessão)\n\n`ArtifactManager` deriva o diretório de artefatos a partir do caminho do arquivo de sessão:\n\n- arquivo de sessão: `.../<timestamp>_<sessionId>.jsonl`\n- diretório de artefatos: `.../<timestamp>_<sessionId>/` (remove `.jsonl`)\n\nOs tipos de artefatos compartilham este diretório:\n\n- arquivos de saída de ferramenta truncada: `<numericId>.<toolType>.log` (para `artifact://`)\n- arquivos de saída de subagente: `<outputId>.md` (para `agent://`)\n\n## Esquemas de alocação de IDs e nomes\n\n## IDs de blob: hash de conteúdo\n\n`BlobStore.put()` computa SHA-256 sobre os bytes binários brutos e retorna:\n\n- `hash`: digest hexadecimal,\n- `path`: `<blobsDir>/<hash>`,\n- `ref`: `blob:sha256:<hash>`.\n\nNenhum contador local de sessão é utilizado.\n\n## IDs de artefato: inteiro monotônico local à sessão\n\n`ArtifactManager` escaneia os arquivos de artefato `*.log` existentes no primeiro uso para encontrar o ID numérico máximo existente e define `nextId = max + 1`.\n\nComportamento de alocação:\n\n- formato do arquivo: `{id}.{toolType}.log`\n- IDs são strings sequenciais (`\"0\"`, `\"1\"`, ...)\n- a retomada não sobrescreve artefatos existentes porque o escaneamento acontece antes da alocação.\n\nSe o diretório de artefatos estiver ausente, o escaneamento retorna lista vazia e a alocação começa do `0`.\n\n## IDs de saída de agente (`agent://`)\n\n`AgentOutputManager` aloca IDs para saídas de subagentes como `<index>-<requestedId>` (opcionalmente aninhado sob prefixo pai, por exemplo, `0-Parent.1-Child`). Ele escaneia arquivos `.md` existentes na inicialização para continuar a partir do próximo índice na retomada.\n\n## Fluxo de dados de persistência\n\n## 1) Caminho de reescrita na persistência de entradas de sessão\n\nAntes que as entradas de sessão sejam escritas (`#rewriteFile` / persistência incremental), `SessionManager` chama `prepareEntryForPersistence()` (via `truncateForPersistence`).\n\nComportamentos-chave:\n\n1. **Truncamento de strings grandes**: strings superdimensionadas são cortadas e sufixadas com `\"[Session persistence truncated large content]\"`.\n2. **Remoção de campos transientes**: `partialJson` e `jsonlEvents` são removidos das entradas persistidas.\n3. **Externalização de imagens para blobs**:\n - aplica-se apenas a blocos de imagem em arrays `content`,\n - apenas quando `data` não é já uma referência de blob,\n - apenas quando o comprimento do base64 é pelo menos o limite (`BLOB_EXTERNALIZE_THRESHOLD = 1024`),\n - substitui base64 inline por `blob:sha256:<hash>`.\n\nIsso mantém o JSONL de sessão compacto enquanto preserva a recuperabilidade.\n\n## 2) Caminho de reidratação no carregamento de sessão\n\nAo abrir uma sessão (`setSessionFile`), após as migrações, `SessionManager` executa `resolveBlobRefsInEntries()`.\n\nPara cada bloco de imagem de message/custom-message com `blob:sha256:<hash>`:\n\n- lê os bytes do blob a partir do armazenamento de blobs,\n- converte os bytes de volta para base64,\n- modifica a entrada em memória para inline base64 para consumidores em tempo de execução.\n\nSe o blob estiver ausente:\n\n- `resolveImageData()` registra um aviso,\n- retorna a string de referência original sem alteração,\n- o carregamento continua (sem crash).\n\n## 3) Caminho de despejo/truncamento de saída de ferramenta\n\n`OutputSink` alimenta a saída em streaming no bash/python/ssh e executores relacionados.\n\nComportamento:\n\n1. Cada chunk é sanitizado e adicionado ao buffer de cauda em memória.\n2. Quando os bytes em memória excedem o limite de despejo (`DEFAULT_MAX_BYTES`, 50KB), o sink marca a saída como truncada.\n3. Se um caminho de artefato está disponível, o sink abre um escritor de arquivo e escreve:\n - o conteúdo já em buffer uma vez,\n - todos os chunks subsequentes.\n4. O buffer em memória é sempre aparado para a janela de cauda para exibição.\n5. `dump()` retorna um resumo incluindo `artifactId` apenas quando o file sink foi criado com sucesso.\n\nEfeito prático:\n\n- UI/retorno de ferramenta mostra a cauda truncada,\n- a saída completa é preservada no arquivo de artefato e referenciada como `artifact://<id>`.\n\nSe a criação do file sink falhar (erro de I/O, caminho ausente, etc.), o sink silenciosamente faz fallback para truncamento somente em memória; a saída completa não é persistida.\n\n## Modelo de acesso por URL\n\n## Referências `blob:`\n\n`blob:sha256:<hash>` é uma referência de persistência dentro dos payloads de entradas de sessão, não um esquema de URL interno tratado pelo roteador. A resolução é feita pelo `SessionManager` durante o carregamento da sessão.\n\n## `artifact://<id>`\n\nTratado pelo `ArtifactProtocolHandler`:\n\n- requer diretório de artefatos de sessão ativo,\n- o ID deve ser numérico,\n- resolve por correspondência do prefixo do nome de arquivo `<id>.`,\n- retorna texto bruto (`text/plain`) do arquivo `.log` correspondente,\n- quando ausente, o erro inclui lista de IDs de artefatos disponíveis.\n\nComportamento com diretório ausente:\n\n- se o diretório de artefatos não existir, lança `No artifacts directory found`.\n\n## `agent://<id>`\n\nTratado pelo `AgentProtocolHandler` sobre `<artifactsDir>/<id>.md`:\n\n- a forma simples retorna texto markdown,\n- as formas `/path` ou `?q=` realizam extração JSON,\n- extração por path e query não podem ser combinadas,\n- se extração é solicitada, o conteúdo do arquivo deve ser parseado como JSON.\n\nComportamento com diretório ausente:\n\n- lança `No artifacts directory found`.\n\nComportamento com saída ausente:\n\n- lança `Not found: <id>` com IDs disponíveis dos arquivos `.md` existentes.\n\nIntegração com a ferramenta read:\n\n- `read` suporta paginação com offset/limit para leituras de URL interna sem extração,\n- rejeita `offset/limit` quando extração `agent://` é utilizada.\n\n## Semânticas de retomada, fork e movimentação\n\n## Retomada\n\n- `ArtifactManager` escaneia arquivos `{id}.*.log` existentes na primeira alocação e continua a numeração.\n- `AgentOutputManager` escaneia IDs de saída `.md` existentes e continua a numeração.\n- `SessionManager` reidrata referências de blob para base64 no carregamento.\n\n## Fork\n\n`SessionManager.fork()` cria um novo arquivo de sessão com novo ID de sessão e link `parentSession`, então retorna os caminhos de arquivo antigo/novo. A cópia de artefatos é tratada pelo `AgentSession.fork()`:\n\n- tenta cópia recursiva do diretório de artefatos antigo para o novo diretório de artefatos,\n- diretório antigo ausente é tolerado,\n- erros de cópia que não são ENOENT são registrados como avisos e o fork ainda é concluído.\n\nImplicações de ID após o fork:\n\n- se a cópia foi bem-sucedida, os contadores de artefatos na nova sessão continuam após o ID máximo copiado,\n- se a cópia falhou/foi ignorada, os IDs de artefatos da nova sessão começam do `0`.\n\nImplicações de blob após o fork:\n\n- blobs são globais e endereçados por conteúdo, então nenhuma cópia de diretório de blobs é necessária.\n\n## Mover para novo cwd\n\n`SessionManager.moveTo()` renomeia tanto o arquivo de sessão quanto o diretório de artefatos para o novo diretório de sessão padrão, com lógica de rollback se uma etapa posterior falhar. Isso preserva a identidade dos artefatos enquanto realoca o escopo da sessão.\n\n## Tratamento de falhas e caminhos de fallback\n\n| Caso | Comportamento |\n| --- | --- |\n| Arquivo de blob ausente durante reidratação | Avisa e mantém a string de referência `blob:sha256:` em memória |\n| Blob read ENOENT via `BlobStore.get` | Retorna `null` |\n| Diretório de artefatos ausente (`ArtifactManager.listFiles`) | Retorna lista vazia (alocação pode começar do zero) |\n| Diretório de artefatos ausente (`artifact://` / `agent://`) | Lança explicitamente `No artifacts directory found` |\n| ID de artefato não encontrado | Lança com listagem de IDs disponíveis |\n| Falha na inicialização do escritor de artefato do OutputSink | Continua com truncamento somente de cauda (sem artefato de saída completa) |\n| Sem arquivo de sessão (alguns caminhos de tarefa) | Ferramenta Task faz fallback para diretório de artefatos temporário para saídas de subagente |\n\n## Externalização de blob binário vs artefatos de saída de texto\n\n- **Externalização de blob** é para payloads de imagens binárias dentro do conteúdo de entradas de sessão persistidas; substitui base64 inline no JSONL por referências de conteúdo estáveis.\n- **Artefatos** são arquivos de texto simples para saída de execução e saída de subagente; são endereçáveis por IDs locais à sessão através de URLs internas.\n\nOs dois sistemas se intersectam apenas indiretamente (ambos reduzem o inchaço do JSONL de sessão) mas possuem caminhos diferentes de identidade, tempo de vida e recuperação.\n\n## Arquivos de implementação\n\n- [`src/session/blob-store.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/blob-store.ts) — formato de referência de blob, hashing, put/get, helpers de externalização/resolução.\n- [`src/session/artifacts.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/artifacts.ts) — modelo de diretório de artefatos de sessão e alocação de ID numérico de artefato.\n- [`src/session/streaming-output.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/streaming-output.ts) — comportamento de truncamento/despejo-para-arquivo do `OutputSink` e metadados de resumo.\n- [`src/session/session-manager.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/session-manager.ts) — transformações de persistência, reidratação de blob no carregamento, interações de fork/movimentação de sessão.\n- [`src/session/agent-session.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/session/agent-session.ts) — cópia de diretório de artefatos durante fork interativo.\n- [`src/tools/output-utils.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/tools/output-utils.ts) — bootstrap do gerenciador de artefatos de ferramentas e alocação de caminho de artefato por ferramenta.\n- [`src/internal-urls/artifact-protocol.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/internal-urls/artifact-protocol.ts) — resolver de `artifact://`.\n- [`src/internal-urls/agent-protocol.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/internal-urls/agent-protocol.ts) — resolver de `agent://` + extração JSON.\n- [`src/sdk.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/sdk.ts) — wiring do roteador de URLs internas e resolver de diretório de artefatos.\n- [`src/task/output-manager.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/task/output-manager.ts) — alocação de ID de saída de agente com escopo de sessão para `agent://`.\n- [`src/task/executor.ts`](https://github.com/f5-sales-demo/xcsh/blob/main/packages/coding-agent/src/task/executor.ts) — escritas de artefatos de saída de subagente (`<id>.md`) e fallback para diretório de artefatos temporário.\n",
|
|
486
487
|
"pt-br/configuration/config-usage.md": "---\ntitle: Descoberta e Resolução de Configuração\ndescription: >-\n Como o xcsh descobre, resolve e organiza configurações a partir das raízes de\n projeto, usuário e empresa.\nsidebar:\n order: 1\n label: Configuração\ni18n:\n sourceHash: e38bd9792499\n translator: machine\n---\n\n# Descoberta e Resolução de Configuração\n\nEste documento descreve como o coding-agent resolve a configuração atualmente: quais raízes são escaneadas, como a precedência funciona e como a configuração resolvida é consumida por settings, skills, hooks, tools e extensões.\n\n## Escopo\n\nImplementação principal:\n\n- `src/config.ts`\n- `src/config/settings.ts`\n- `src/config/settings-schema.ts`\n- `src/discovery/builtin.ts`\n- `src/discovery/helpers.ts`\n\nPontos-chave de integração:\n\n- `src/capability/index.ts`\n- `src/discovery/index.ts`\n- `src/extensibility/skills.ts`\n- `src/extensibility/hooks/loader.ts`\n- `src/extensibility/custom-tools/loader.ts`\n- `src/extensibility/extensions/loader.ts`\n\n---\n\n## Fluxo de resolução (visual)\n\n```text\n Config roots (ordered)\n┌───────────────────────────────────────┐\n│ 1) ~/.xcsh/agent + <cwd>/.xcsh │\n│ 2) ~/.claude + <cwd>/.claude │\n│ 3) ~/.codex + <cwd>/.codex │\n│ 4) ~/.gemini + <cwd>/.gemini │\n└───────────────────────────────────────┘\n │\n ▼\n config.ts helper resolution\n (getConfigDirs/findConfigFile/findNearest...)\n │\n ▼\n capability providers enumerate items\n (native, claude, codex, gemini, agents, etc.)\n │\n ▼\n priority sort + per-capability dedup\n │\n ▼\n subsystem-specific consumption\n (settings, skills, hooks, tools, extensions)\n```\n\n## 1) Raízes de configuração e ordem de fontes\n\n## Raízes canônicas\n\n`src/config.ts` define uma lista fixa de prioridade de fontes:\n\n1. `.xcsh` (nativo)\n2. `.claude`\n3. `.codex`\n4. `.gemini`\n\nBases de nível de usuário:\n\n- `~/.xcsh/agent`\n- `~/.claude`\n- `~/.codex`\n- `~/.gemini`\n\nBases de nível de projeto:\n\n- `<cwd>/.xcsh`\n- `<cwd>/.claude`\n- `<cwd>/.codex`\n- `<cwd>/.gemini`\n\n`CONFIG_DIR_NAME` é `.xcsh` (`packages/utils/src/dirs.ts`).\n\n## Restrição importante\n\nOs helpers genéricos em `src/config.ts` **não** incluem `.pi` na ordem de descoberta de fontes.\n\n---\n\n## 2) Helpers principais de descoberta (`src/config.ts`)\n\n## `getConfigDirs(subpath, options)`\n\nRetorna entradas ordenadas:\n\n- Entradas de nível de usuário primeiro (por prioridade de fonte)\n- Depois entradas de nível de projeto (pela mesma prioridade de fonte)\n\nOpções:\n\n- `user` (padrão `true`)\n- `project` (padrão `true`)\n- `cwd` (padrão `getProjectDir()`)\n- `existingOnly` (padrão `false`)\n\nEsta API é utilizada para buscas de configuração baseadas em diretórios (commands, hooks, tools, agents, etc.).\n\n## `findConfigFile(subpath, options)` / `findConfigFileWithMeta(...)`\n\nBusca o primeiro arquivo existente entre as bases ordenadas, retorna a primeira correspondência (apenas o caminho ou caminho+metadados).\n\n## `findAllNearestProjectConfigDirs(subpath, cwd)`\n\nPercorre os diretórios ancestrais para cima e retorna o **diretório existente mais próximo por base de fonte** (`.xcsh`, `.claude`, `.codex`, `.gemini`), depois ordena os resultados por prioridade de fonte.\n\nUse isso quando a configuração de projeto deve ser herdada de diretórios ancestrais (comportamento de monorepo/workspace aninhado).\n\n---\n\n## 3) Wrapper de arquivo de configuração (`ConfigFile<T>` em `src/config.ts`)\n\n`ConfigFile<T>` é o carregador com validação de schema para arquivos de configuração únicos.\n\nFormatos suportados:\n\n- `.yml` / `.yaml`\n- `.json` / `.jsonc`\n\nComportamento:\n\n- Valida os dados parseados com AJV contra um schema TypeBox fornecido.\n- Armazena em cache o resultado do carregamento até `invalidate()`.\n- Retorna resultado de três estados via `tryLoad()`:\n - `ok`\n - `not-found`\n - `error` (`ConfigError` com contexto de schema/parse)\n\nMigração legada ainda suportada:\n\n- Se o caminho alvo é `.yml`/`.yaml`, um `.json` adjacente é migrado automaticamente uma vez (`migrateJsonToYml`).\n\n---\n\n## 4) Modelo de resolução de settings (`src/config/settings.ts`)\n\nO modelo de settings em tempo de execução é organizado em camadas:\n\n1. Settings globais: `~/.xcsh/agent/config.yml`\n2. Settings de projeto: descobertas via capability de settings (`settings.json` dos providers)\n3. Overrides em tempo de execução: em memória, não persistentes\n4. Valores padrão do schema: do `SETTINGS_SCHEMA`\n\nCaminho efetivo de leitura:\n\n`defaults <- global <- project <- overrides`\n\nComportamento de escrita:\n\n- `settings.set(...)` escreve na camada **global** (`config.yml`) e enfileira salvamento em background.\n- Settings de projeto são somente leitura a partir da descoberta de capabilities.\n\n## Comportamento de migração ainda ativo\n\nNa inicialização, se `config.yml` não existe:\n\n1. Migra de `~/.xcsh/agent/settings.json` (renomeado para `.bak` em caso de sucesso)\n2. Mescla com settings legadas do DB de `agent.db`\n3. Escreve o resultado mesclado em `config.yml`\n\nMigrações em nível de campo em `#migrateRawSettings`:\n\n- `queueMode` -> `steeringMode`\n- `ask.timeout` milissegundos -> segundos quando o valor antigo parece ser ms (`> 1000`)\n- `theme: \"...\"` flat legado -> estrutura `theme.dark/theme.light`\n\n---\n\n## 5) Integração capability/discovery\n\nA maioria dos fluxos de carregamento de configuração não-core passa pelo registro de capabilities (`src/capability/index.ts` + `src/discovery/index.ts`).\n\n## Ordenação de providers\n\nProviders são ordenados por prioridade numérica (maior primeiro). Exemplos de prioridades:\n\n- Native OMP (`builtin.ts`): `100`\n- Claude: `80`\n- Codex / agents / Claude marketplace: `70`\n- Gemini: `60`\n\n```text\nProvider precedence (higher wins)\n\nnative (.xcsh) priority 100\nclaude priority 80\ncodex / agents / ... priority 70\ngemini priority 60\n```\n\n## Semântica de deduplicação\n\nCapabilities definem uma `key(item)`:\n\n- mesma chave => primeiro item vence (item de maior prioridade/carregado primeiro)\n- sem chave (`undefined`) => sem deduplicação, todos os itens são mantidos\n\nChaves relevantes:\n\n- skills: `name`\n- tools: `name`\n- hooks: `${type}:${tool}:${name}`\n- extension modules: `name`\n- extensions: `name`\n- settings: sem deduplicação (todos os itens são preservados)\n\n---\n\n## 6) Comportamento do provider nativo `.xcsh` (`src/discovery/builtin.ts`)\n\nO provider nativo (`id: native`) lê de:\n\n- projeto: `<cwd>/.xcsh/...`\n- usuário: `~/.xcsh/agent/...`\n\n### Regra de admissão de diretório\n\n`builtin.ts` só inclui uma raiz de configuração se o diretório existir **e não estiver vazio** (`ifNonEmptyDir`).\n\n### Carregamento específico por escopo\n\n- Skills: `skills/*/SKILL.md`\n- Slash commands: `commands/*.md`\n- Rules: `rules/*.{md,mdc}`\n- Prompts: `prompts/*.md`\n- Instructions: `instructions/*.md`\n- Hooks: `hooks/pre/*`, `hooks/post/*`\n- Tools: `tools/*.json|*.md` e `tools/<name>/index.ts`\n- Extension modules: descobertos em `extensions/` (+ array de strings legado `settings.json.extensions`)\n- Extensions: `extensions/<name>/gemini-extension.json`\n- Settings capability: `settings.json`\n\n### Nuance de busca de projeto mais próximo\n\nPara `SYSTEM.md` e `XCSH.md`, o provider nativo usa a busca de diretório `.xcsh` de projeto no ancestral mais próximo (subindo a árvore) mas ainda exige que o diretório `.xcsh` não esteja vazio.\n\n---\n\n## 7) Como os principais subsistemas consomem a configuração\n\n## Subsistema de settings\n\n- `Settings.init()` carrega o `config.yml` global + itens descobertos da capability de settings do projeto.\n- Apenas itens de capability com `level === \"project\"` são mesclados na camada de projeto.\n\n## Subsistema de skills\n\n- `extensibility/skills.ts` carrega via `loadCapability(skillCapability.id, { cwd })`.\n- Aplica toggles e filtros de fonte (`ignoredSkills`, `includeSkills`, diretórios customizados).\n- Toggles com nomes legados ainda existem (`skills.enablePiUser`, `skills.enablePiProject`) mas controlam o provider nativo (`provider === \"native\"`).\n\n## Subsistema de hooks\n\n- `discoverAndLoadHooks()` resolve caminhos de hooks a partir da capability de hooks + caminhos configurados explicitamente.\n- Depois carrega módulos via importação do Bun.\n\n## Subsistema de tools\n\n- `discoverAndLoadCustomTools()` resolve caminhos de tools a partir da capability de tools + caminhos de tools de plugins + caminhos configurados explicitamente.\n- Arquivos de tools declarativos `.md/.json` são apenas metadados; o carregamento executável espera módulos de código.\n\n## Subsistema de extensões\n\n- `discoverAndLoadExtensions()` resolve módulos de extensão a partir da capability de extension-module mais caminhos explícitos.\n- A implementação atual intencionalmente mantém apenas itens de capability com `_source.provider === \"native\"` antes do carregamento.\n\n---\n\n## 8) Regras de precedência nas quais confiar\n\nUse este modelo mental:\n\n1. A ordenação de diretórios de fonte do `config.ts` determina a ordem dos caminhos candidatos.\n2. A prioridade do provider de capability determina a precedência entre providers.\n3. A deduplicação por chave de capability determina o comportamento de colisão (primeiro vence para capabilities com chave).\n4. A lógica de merge específica do subsistema pode alterar ainda mais a precedência efetiva (especialmente settings).\n\n### Ressalva específica de settings\n\nItens de capability de settings não são deduplicados; `Settings.#loadProjectSettings()` faz deep-merge dos itens de projeto na ordem retornada. Como o merge aplica valores de itens posteriores sobre valores anteriores, o comportamento efetivo de override depende da ordem de emissão do provider, não apenas da semântica de chave de capability.\n\n---\n\n## 9) Comportamentos de legado/compatibilidade ainda presentes\n\n- Migração de JSON -> YAML do `ConfigFile` para arquivos destinados a YAML.\n- Migração de settings de `settings.json` e `agent.db` para `config.yml`.\n- Migrações de chaves de settings (`queueMode`, `ask.timeout`, `theme` flat).\n- Compatibilidade de manifesto de extensão: o loader aceita tanto seções de manifesto `package.json.xcsh` quanto `package.json.pi`.\n- Nomes de settings legados `skills.enablePiUser` / `skills.enablePiProject` ainda são gates ativos para a fonte nativa de skills.\n\nSe esses caminhos de compatibilidade forem removidos no código, atualize este documento imediatamente; vários comportamentos em tempo de execução ainda dependem deles hoje.\n",
|
|
487
488
|
"pt-br/configuration/environment-variables.md": "---\ntitle: Variáveis de Ambiente\ndescription: >-\n Referência de variáveis de ambiente de runtime para configuração e controle de\n comportamento do xcsh.\nsidebar:\n order: 2\n label: Variáveis de ambiente\ni18n:\n sourceHash: e2890f963c02\n translator: machine\n---\n\n# Variáveis de Ambiente (Referência de Runtime Atual)\n\nEsta referência é derivada dos caminhos de código atuais em:\n\n- `packages/coding-agent/src/**`\n- `packages/ai/src/**` (resolução de provedor/autenticação utilizada pelo coding-agent)\n- `packages/utils/src/**` e `packages/tui/src/**` onde essas variáveis afetam diretamente o runtime do coding-agent\n\nDocumenta apenas o comportamento ativo.\n\n## Modelo de resolução e precedência\n\nA maioria das consultas em runtime utiliza `$env` de `@f5-sales-demo/pi-utils` (`packages/utils/src/env.ts`).\n\nOrdem de carregamento do `$env`:\n\n1. Ambiente de processo existente (`Bun.env`)\n2. `.env` do projeto (`$PWD/.env`) para chaves ainda não definidas\n3. `.env` do diretório home (`~/.env`) para chaves ainda não definidas\n\nRegra adicional em arquivos `.env`: chaves `XCSH_*` são espelhadas para chaves `PI_*` durante o parse.\n\n---\n\n## 1) Autenticação de modelo/provedor\n\nEstas são consumidas via `getEnvApiKey()` (`packages/ai/src/stream.ts`), salvo indicação contrária.\n\n### Credenciais principais de provedor\n\n| Variável | Usada para | Necessária quando | Notas / precedência |\n|---------------------------------|---|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|\n| `ANTHROPIC_OAUTH_TOKEN` | Autenticação na API Anthropic | Usando Anthropic com autenticação por token OAuth | Tem precedência sobre `ANTHROPIC_API_KEY` na resolução de autenticação do provedor |\n| `ANTHROPIC_API_KEY` | Autenticação na API Anthropic | Usando Anthropic sem token OAuth | Fallback após `ANTHROPIC_OAUTH_TOKEN` |\n| `ANTHROPIC_FOUNDRY_API_KEY` | Anthropic via Azure Foundry / gateway empresarial | `CLAUDE_CODE_USE_FOUNDRY` habilitado | Tem precedência sobre `ANTHROPIC_OAUTH_TOKEN` e `ANTHROPIC_API_KEY` quando o modo Foundry está habilitado |\n| `OPENAI_API_KEY` | Autenticação OpenAI | Usando provedores da família OpenAI sem argumento apiKey explícito | Usado pelos provedores OpenAI Completions/Responses |\n| `GEMINI_API_KEY` | Autenticação Google Gemini | Usando modelos do provedor `google` | Chave principal para mapeamento do provedor Gemini |\n| `GOOGLE_API_KEY` | Fallback de autenticação da ferramenta de imagem Gemini | Usando a ferramenta `gemini_image` sem `GEMINI_API_KEY` | Usado pelo caminho de fallback da ferramenta de imagem do coding-agent |\n| `GROQ_API_KEY` | Autenticação Groq | Usando modelos Groq | |\n| `CEREBRAS_API_KEY` | Autenticação Cerebras | Usando modelos Cerebras | |\n| `TOGETHER_API_KEY` | Autenticação Together | Usando provedor `together` | |\n| `HUGGINGFACE_HUB_TOKEN` | Autenticação Hugging Face | Usando provedor `huggingface` | Variável de ambiente principal do token Hugging Face |\n| `HF_TOKEN` | Autenticação Hugging Face | Usando provedor `huggingface` | Fallback quando `HUGGINGFACE_HUB_TOKEN` não está definido |\n| `SYNTHETIC_API_KEY` | Autenticação Synthetic | Usando modelos Synthetic | |\n| `NVIDIA_API_KEY` | Autenticação NVIDIA | Usando provedor `nvidia` | |\n| `NANO_GPT_API_KEY` | Autenticação NanoGPT | Usando provedor `nanogpt` | |\n| `VENICE_API_KEY` | Autenticação Venice | Usando provedor `venice` | |\n| `LITELLM_API_KEY` | Autenticação LiteLLM | Usando provedor `litellm` | Chave de proxy LiteLLM compatível com OpenAI. Quando definido com `LITELLM_BASE_URL`, habilita a auto-configuração do `models.yml` |\n| `LM_STUDIO_API_KEY` | Autenticação LM Studio (opcional) | Usando provedor `lm-studio` com hosts autenticados | LM Studio local geralmente roda sem autenticação; qualquer token não vazio funciona quando uma chave é necessária |\n| `OLLAMA_API_KEY` | Autenticação Ollama (opcional) | Usando provedor `ollama` com hosts autenticados | Ollama local geralmente roda sem autenticação; qualquer token não vazio funciona quando uma chave é necessária |\n| `LLAMA_CPP_API_KEY` | Autenticação Ollama (opcional) | Usando `llama-server` com parâmetro `--api-key` | llama.cpp local geralmente roda sem autenticação; qualquer token não vazio funciona quando uma chave é configurada |\n| `XIAOMI_API_KEY` | Autenticação Xiaomi MiMo | Usando provedor `xiaomi` | |\n| `MOONSHOT_API_KEY` | Autenticação Moonshot | Usando provedor `moonshot` | |\n| `XAI_API_KEY` | Autenticação xAI | Usando modelos xAI | |\n| `OPENROUTER_API_KEY` | Autenticação OpenRouter | Usando modelos OpenRouter | Também usado pela ferramenta de imagem quando o provedor preferido/auto é OpenRouter |\n| `MISTRAL_API_KEY` | Autenticação Mistral | Usando modelos Mistral | |\n| `ZAI_API_KEY` | Autenticação z.ai | Usando modelos z.ai | Também usado pelo provedor de busca web z.ai |\n| `MINIMAX_API_KEY` | Autenticação MiniMax | Usando provedor `minimax` | |\n| `MINIMAX_CODE_API_KEY` | Autenticação MiniMax Code | Usando provedor `minimax-code` | |\n| `MINIMAX_CODE_CN_API_KEY` | Autenticação MiniMax Code CN | Usando provedor `minimax-code-cn` | |\n| `OPENCODE_API_KEY` | Autenticação OpenCode | Usando modelos OpenCode | |\n| `QIANFAN_API_KEY` | Autenticação Qianfan | Usando provedor `qianfan` | |\n| `QWEN_OAUTH_TOKEN` | Autenticação Qwen Portal | Usando `qwen-portal` com token OAuth | Tem precedência sobre `QWEN_PORTAL_API_KEY` |\n| `QWEN_PORTAL_API_KEY` | Autenticação Qwen Portal | Usando `qwen-portal` com chave API | Fallback após `QWEN_OAUTH_TOKEN` |\n| `ZENMUX_API_KEY` | Autenticação ZenMux | Usando provedor `zenmux` | Usado para rotas compatíveis com OpenAI e Anthropic do ZenMux |\n| `VLLM_API_KEY` | Autenticação/descoberta opt-in do vLLM | Usando provedor `vllm` (servidores locais compatíveis com OpenAI) | Qualquer valor não vazio funciona para servidores locais sem autenticação |\n| `CURSOR_ACCESS_TOKEN` | Autenticação do provedor Cursor | Usando provedor Cursor | |\n| `AI_GATEWAY_API_KEY` | Autenticação Vercel AI Gateway | Usando provedor `vercel-ai-gateway` | |\n| `CLOUDFLARE_AI_GATEWAY_API_KEY` | Autenticação Cloudflare AI Gateway | Usando provedor `cloudflare-ai-gateway` | A URL base deve ser configurada como `https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/anthropic` |\n\n### Cadeias de token GitHub/Copilot\n\n| Variável | Usada para | Cadeia |\n|---|---|---|\n| `COPILOT_GITHUB_TOKEN` | Autenticação do provedor GitHub Copilot | `COPILOT_GITHUB_TOKEN` → `GH_TOKEN` → `GITHUB_TOKEN` |\n| `GH_TOKEN` | Fallback do Copilot; autenticação na API GitHub no web scraper | No web scraper: `GITHUB_TOKEN` → `GH_TOKEN` |\n| `GITHUB_TOKEN` | Fallback do Copilot; autenticação na API GitHub no web scraper | No web scraper: verificado antes de `GH_TOKEN` |\n\n---\n\n## 2) Configuração de runtime específica por provedor\n\n### Anthropic Foundry Gateway (Azure / proxy empresarial)\n\nQuando `CLAUDE_CODE_USE_FOUNDRY` está habilitado, as requisições Anthropic mudam para o modo Foundry:\n\n- A URL base é resolvida a partir de `FOUNDRY_BASE_URL` (o fallback permanece como a URL base padrão/do modelo se não definida).\n- A resolução da chave API para o provedor `anthropic` torna-se:\n `ANTHROPIC_FOUNDRY_API_KEY` → `ANTHROPIC_OAUTH_TOKEN` → `ANTHROPIC_API_KEY`.\n- `ANTHROPIC_CUSTOM_HEADERS` é interpretado como pares `chave: valor` separados por vírgula/nova linha e mesclados nos cabeçalhos da requisição.\n- Material TLS de cliente/servidor pode ser injetado a partir de valores de ambiente:\n `NODE_EXTRA_CA_CERTS`, `CLAUDE_CODE_CLIENT_CERT`, `CLAUDE_CODE_CLIENT_KEY`.\n Cada um aceita:\n - um caminho de sistema de arquivos para conteúdo PEM, ou\n - PEM inline (incluindo sequências `\\n` escapadas).\n\n| Variável | Tipo de valor | Comportamento |\n|---|---|---|\n| `CLAUDE_CODE_USE_FOUNDRY` | String tipo booleano (`1`, `true`, `yes`, `on`) | Habilita o modo Foundry para o provedor Anthropic |\n| `FOUNDRY_BASE_URL` | String URL | URL base do endpoint Anthropic no modo Foundry |\n| `ANTHROPIC_FOUNDRY_API_KEY` | String de token | Usado para `Authorization: Bearer <token>` |\n| `ANTHROPIC_CUSTOM_HEADERS` | String de lista de cabeçalhos | Cabeçalhos extras; formato `header-a: valor, header-b: valor` ou separados por nova linha |\n| `NODE_EXTRA_CA_CERTS` | Caminho PEM ou PEM inline | Cadeia CA extra para validação de certificado do servidor |\n| `CLAUDE_CODE_CLIENT_CERT` | Caminho PEM ou PEM inline | Certificado de cliente mTLS |\n| `CLAUDE_CODE_CLIENT_KEY` | Caminho PEM ou PEM inline | Chave privada do cliente mTLS (deve ser pareada com o certificado) |\n\n### Amazon Bedrock\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `AWS_REGION` | Fonte principal de região |\n| `AWS_DEFAULT_REGION` | Fallback se `AWS_REGION` não estiver definida |\n| `AWS_PROFILE` | Habilita o caminho de autenticação por perfil nomeado |\n| `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` | Habilita o caminho de autenticação por chave IAM |\n| `AWS_BEARER_TOKEN_BEDROCK` | Habilita o caminho de autenticação por bearer token |\n| `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` / `AWS_CONTAINER_CREDENTIALS_FULL_URI` | Habilita o caminho de credencial de tarefa ECS |\n| `AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN` | Habilita o caminho de autenticação por web identity |\n| `AWS_BEDROCK_SKIP_AUTH` | Se `1`, injeta credenciais fictícias (cenários de proxy/sem autenticação) |\n| `AWS_BEDROCK_FORCE_HTTP1` | Se `1`, força o handler de requisição Node HTTP/1 |\n\nFallback de região no código do provedor: `options.region` → `AWS_REGION` → `AWS_DEFAULT_REGION` → `us-east-1`.\n\n### Azure OpenAI Responses\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `AZURE_OPENAI_API_KEY` | Obrigatória a menos que a chave API seja passada como opção |\n| `AZURE_OPENAI_API_VERSION` | Padrão `v1` |\n| `AZURE_OPENAI_BASE_URL` | Override direto da URL base |\n| `AZURE_OPENAI_RESOURCE_NAME` | Usado para construir a URL base: `https://<resource>.openai.azure.com/openai/v1` |\n| `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` | String de mapeamento opcional: `modelId=deploymentName,model2=deployment2` |\n\nResolução da URL base: opção `azureBaseUrl` → env `AZURE_OPENAI_BASE_URL` → opção/env resource name → `model.baseUrl`.\n\n### Google Vertex AI\n\n| Variável | Obrigatória? | Notas |\n|---|---|---|\n| `GOOGLE_CLOUD_PROJECT` | Sim (a menos que passada nas opções) | Fallback: `GCLOUD_PROJECT` |\n| `GCLOUD_PROJECT` | Fallback | Usada como fonte alternativa de ID do projeto |\n| `GOOGLE_CLOUD_LOCATION` | Sim (a menos que passada nas opções) | Sem padrão no provedor |\n| `GOOGLE_APPLICATION_CREDENTIALS` | Condicional | Se definida, o arquivo deve existir; caso contrário, o caminho de fallback ADC é verificado (`~/.config/gcloud/application_default_credentials.json`) |\n\n### Kimi\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `KIMI_CODE_OAUTH_HOST` | Override principal do host OAuth |\n| `KIMI_OAUTH_HOST` | Override de fallback do host OAuth |\n| `KIMI_CODE_BASE_URL` | Substitui a URL base do endpoint de uso do Kimi (`usage/kimi.ts`) |\n\nCadeia do host OAuth: `KIMI_CODE_OAUTH_HOST` → `KIMI_OAUTH_HOST` → `https://auth.kimi.com`.\n\n### Compatibilidade Antigravity/Gemini image\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `PI_AI_ANTIGRAVITY_VERSION` | Substitui a tag de versão do user-agent Antigravity no provedor Gemini CLI |\n\n### OpenAI Codex responses (controles de funcionalidade/debug)\n\n| Variável | Comportamento |\n|---|---|\n| `PI_CODEX_DEBUG` | `1`/`true` habilita logs de debug do provedor Codex |\n| `PI_CODEX_WEBSOCKET` | `1`/`true` habilita preferência de transporte websocket |\n| `PI_CODEX_WEBSOCKET_V2` | `1`/`true` habilita caminho websocket v2 |\n| `PI_CODEX_WEBSOCKET_IDLE_TIMEOUT_MS` | Override de inteiro positivo (padrão 300000) |\n| `PI_CODEX_WEBSOCKET_RETRY_BUDGET` | Override de inteiro não negativo (padrão 5) |\n| `PI_CODEX_WEBSOCKET_RETRY_DELAY_MS` | Override de backoff base em inteiro positivo (padrão 500) |\n\n### Debug do provedor Cursor\n\n| Variável | Comportamento |\n|---|---|\n| `DEBUG_CURSOR` | Habilita logs de debug do provedor; `2`/`verbose` para trechos detalhados de payload |\n| `DEBUG_CURSOR_LOG` | Caminho de arquivo opcional para saída de log de debug JSONL |\n\n### Chave de compatibilidade de cache de prompt\n\n| Variável | Comportamento |\n|---|---|\n| `PI_CACHE_RETENTION` | Se `long`, habilita retenção longa onde suportado (`anthropic`, `openai-responses`, resolução de retenção Bedrock) |\n\n---\n\n## 3) Subsistema de busca web\n\n### Credenciais de provedor de busca\n\n| Variável | Usada por |\n|---|---|\n| `EXA_API_KEY` | Provedor de busca Exa e ferramentas MCP Exa |\n| `BRAVE_API_KEY` | Provedor de busca Brave |\n| `PERPLEXITY_API_KEY` | Modo chave API do provedor de busca Perplexity |\n| `TAVILY_API_KEY` | Provedor de busca Tavily |\n| `ZAI_API_KEY` | Provedor de busca z.ai (também verifica OAuth armazenado em `agent.db`) |\n| `OPENAI_API_KEY` / OAuth Codex no DB | Disponibilidade/autenticação do provedor de busca Codex |\n\n### Cadeia de autenticação de busca web Anthropic\n\n`packages/coding-agent/src/web/search/auth.ts` resolve credenciais de busca web Anthropic nesta ordem:\n\n1. `ANTHROPIC_SEARCH_API_KEY` (+ opcional `ANTHROPIC_SEARCH_BASE_URL`)\n2. Entrada de provedor em `models.json` com `api: \"anthropic-messages\"`\n3. Credenciais OAuth Anthropic de `agent.db` (não deve expirar dentro do buffer de 5 minutos)\n4. Fallback genérico de env Anthropic: chave do provedor (`ANTHROPIC_FOUNDRY_API_KEY`/`ANTHROPIC_OAUTH_TOKEN`/`ANTHROPIC_API_KEY`) + opcional `ANTHROPIC_BASE_URL` (`FOUNDRY_BASE_URL` quando o modo Foundry está habilitado)\n\nVariáveis relacionadas:\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `ANTHROPIC_SEARCH_API_KEY` | Chave de busca explícita de maior prioridade |\n| `ANTHROPIC_SEARCH_BASE_URL` | Padrão `https://api.anthropic.com` quando omitida |\n| `ANTHROPIC_SEARCH_MODEL` | Padrão `claude-haiku-4-5` |\n| `ANTHROPIC_BASE_URL` | URL base de fallback genérica para o caminho de autenticação nível 4 |\n\n### Flag de comportamento do fluxo OAuth Perplexity\n\n| Variável | Comportamento |\n|---|---|\n| `PI_AUTH_NO_BORROW` | Se definida, desabilita o caminho de empréstimo de token de aplicativo nativo macOS no fluxo de login Perplexity |\n\n---\n\n## 4) Ferramentas Python e runtime de kernel\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `PI_PY` | Override do modo de ferramenta Python: `0`/`bash`=`bash-only`, `1`/`py`=`ipy-only`, `mix`/`both`=`both`; valores inválidos são ignorados |\n| `PI_PYTHON_SKIP_CHECK` | Se `1`, pula verificações de disponibilidade/aquecimento do kernel Python |\n| `PI_PYTHON_GATEWAY_URL` | Se definida, usa gateway de kernel externo em vez do gateway compartilhado local |\n| `PI_PYTHON_GATEWAY_TOKEN` | Token de autenticação opcional para gateway externo (`Authorization: token <value>`) |\n| `PI_PYTHON_IPC_TRACE` | Se `1`, habilita caminho de rastreamento IPC de baixo nível no módulo de kernel |\n| `VIRTUAL_ENV` | Caminho de venv de maior prioridade para resolução do runtime Python |\n\nComportamento condicional extra:\n\n- Se `BUN_ENV=test` ou `NODE_ENV=test`, as verificações de disponibilidade do Python são tratadas como OK e o aquecimento é ignorado.\n- A filtragem de ambiente Python nega chaves API comuns e permite variáveis base seguras + prefixos `LC_`, `XDG_`, `PI_`.\n\n---\n\n## 5) Toggles de comportamento do agente/runtime\n\n| Variável | Padrão / comportamento |\n|----------------------------|----------------------------------------------------------------------------------------------|\n| `PI_SMOL_MODEL` | Override efêmero de model-role para `smol` (CLI `--smol` tem precedência) |\n| `PI_SLOW_MODEL` | Override efêmero de model-role para `slow` (CLI `--slow` tem precedência) |\n| `PI_PLAN_MODEL` | Override efêmero de model-role para `plan` (CLI `--plan` tem precedência) |\n| `PI_NO_TITLE` | Se definida (qualquer valor não vazio), desabilita a geração automática de título de sessão na primeira mensagem do usuário |\n| `NULL_PROMPT` | Se `true`, o construtor de prompt de sistema retorna string vazia |\n| `PI_BLOCKED_AGENT` | Bloqueia um tipo específico de subagente na ferramenta de tarefa |\n| `PI_SUBPROCESS_CMD` | Substitui o comando de spawn do subagente (bypass da resolução `xcsh` / `xcsh.cmd`) |\n| `PI_TASK_MAX_OUTPUT_BYTES` | Máximo de bytes de saída capturados por subagente (padrão `500000`) |\n| `PI_TASK_MAX_OUTPUT_LINES` | Máximo de linhas de saída capturadas por subagente (padrão `5000`) |\n| `PI_TIMING` | Se `1`, habilita logs de instrumentação de timing de startup/ferramenta |\n| `PI_DEBUG_STARTUP` | Habilita prints de debug de estágio de startup para stderr em múltiplos caminhos de startup |\n| `PI_PACKAGE_DIR` | Substitui a resolução do diretório base de assets do pacote (busca de caminhos de docs/exemplos/changelog) |\n| `PI_DISABLE_LSPMUX` | Se `1`, desabilita detecção/integração do lspmux e força o spawn direto do servidor LSP |\n| `LITELLM_BASE_URL` | URL base do proxy LiteLLM. Quando definida com `LITELLM_API_KEY`, dispara a auto-geração do `models.yml` na primeira execução e auto-reparo em cada startup |\n| `LM_STUDIO_BASE_URL` | Override da URL base de descoberta implícita padrão do LM Studio (`http://127.0.0.1:1234/v1` se não definida) |\n| `OLLAMA_BASE_URL` | Override da URL base de descoberta implícita padrão do Ollama (`http://127.0.0.1:11434` se não definida) |\n| `LLAMA_CPP_BASE_URL` | Override da URL base de descoberta implícita padrão do Llama.cpp (`http://127.0.0.1:8080` se não definida) |\n| `PI_EDIT_VARIANT` | Se `hashline`, força o modo de exibição hashline read/grep quando a ferramenta de edição está disponível |\n| `PI_NO_PTY` | Se `1`, desabilita o caminho PTY interativo para a ferramenta bash |\n\n`PI_NO_PTY` também é definida internamente quando o CLI `--no-pty` é usado.\n\n---\n\n## 6) Caminhos raiz de armazenamento e configuração\n\nEstas são consumidas via `@f5-sales-demo/pi-utils/dirs` e afetam onde o coding-agent armazena dados.\n\n| Variável | Padrão / comportamento |\n|---|---|\n| `PI_CONFIG_DIR` | Nome do diretório raiz de configuração sob o home (padrão `.xcsh`) |\n| `PI_CODING_AGENT_DIR` | Override completo para o diretório do agente (padrão `~/<PI_CONFIG_DIR ou .xcsh>/agent`) |\n| `PWD` | Usado ao fazer correspondência do diretório de trabalho atual canônico em helpers de caminho |\n\n---\n\n## 7) Ambiente de execução de shell/ferramentas\n\n(De `packages/utils/src/procmgr.ts` e integração da ferramenta bash do coding-agent.)\n\n| Variável | Comportamento |\n|---|---|\n| `PI_BASH_NO_CI` | Suprime a injeção automática de `CI=true` no ambiente de shell gerado |\n| `CLAUDE_BASH_NO_CI` | Alias legado de fallback para `PI_BASH_NO_CI` |\n| `PI_BASH_NO_LOGIN` | Destinada a desabilitar o modo de shell de login |\n| `CLAUDE_BASH_NO_LOGIN` | Alias legado de fallback para `PI_BASH_NO_LOGIN` |\n| `PI_SHELL_PREFIX` | Wrapper de prefixo de comando opcional |\n| `CLAUDE_CODE_SHELL_PREFIX` | Alias legado de fallback para `PI_SHELL_PREFIX` |\n| `VISUAL` | Comando de editor externo preferido |\n| `EDITOR` | Comando de editor externo de fallback |\n\nNota da implementação atual: `PI_BASH_NO_LOGIN`/`CLAUDE_BASH_NO_LOGIN` são lidas, mas a implementação atual de `getShellArgs()` retorna `['-l','-c']` em ambas as ramificações (efetivamente sem efeito hoje).\n\n---\n\n## 8) Detecção de UI/tema/sessão (env auto-detectado)\n\nEstas são lidas como sinais de runtime; geralmente são definidas pelo terminal/SO em vez de configuradas manualmente.\n\n| Variável | Usada para |\n|---|---|\n| `COLORTERM`, `TERM`, `WT_SESSION` | Detecção de capacidade de cor (modo de cor do tema) |\n| `COLORFGBG` | Auto-detecção de fundo claro/escuro do terminal |\n| `TERM_PROGRAM`, `TERM_PROGRAM_VERSION`, `TERMINAL_EMULATOR` | Identidade do terminal no prompt/contexto do sistema |\n| `KDE_FULL_SESSION`, `XDG_CURRENT_DESKTOP`, `DESKTOP_SESSION`, `XDG_SESSION_DESKTOP`, `GDMSESSION`, `WINDOWMANAGER` | Detecção de desktop/gerenciador de janelas no prompt/contexto do sistema |\n| `KITTY_WINDOW_ID`, `TMUX_PANE`, `TERM_SESSION_ID`, `WT_SESSION` | IDs de breadcrumb de sessão estáveis por terminal |\n| `SHELL`, `ComSpec`, `TERM_PROGRAM`, `TERM` | Diagnósticos de informações do sistema |\n| `APPDATA`, `XDG_CONFIG_HOME` | Resolução de caminho de configuração do lspmux |\n| `HOME` | Encurtamento de caminho na UI de comando MCP |\n\n---\n\n## 9) Flags de carregamento nativo/debug\n\n| Variável | Comportamento |\n|---|---|\n| `PI_DEV` | Habilita diagnósticos verbosos de carregamento de addon nativo em `packages/natives` |\n\n## 10) Flags de runtime da TUI (pacote compartilhado, afeta a UX do coding-agent)\n\n| Variável | Comportamento |\n|---|---|\n| `PI_NOTIFICATIONS` | `off` / `0` / `false` suprimem notificações de desktop |\n| `PI_TUI_WRITE_LOG` | Se definida, registra escritas da TUI em arquivo |\n| `PI_HARDWARE_CURSOR` | Se `1`, habilita modo de cursor de hardware |\n| `PI_CLEAR_ON_SHRINK` | Se `1`, limpa linhas vazias quando o conteúdo encolhe |\n| `PI_DEBUG_REDRAW` | Se `1`, habilita log de debug de redesenho |\n| `PI_TUI_DEBUG` | Se `1`, habilita caminho de dump de debug profundo da TUI |\n\n---\n\n## 11) Controles de geração de commit\n\n| Variável | Comportamento |\n|---|---|\n| `PI_COMMIT_TEST_FALLBACK` | Se `true` (case-insensitive), força o caminho de geração de commit por fallback |\n| `PI_COMMIT_NO_FALLBACK` | Se `true`, desabilita fallback quando o agente não retorna nenhuma proposta |\n| `PI_COMMIT_MAP_REDUCE` | Se `false`, desabilita o caminho de análise de commit por map-reduce |\n| `DEBUG` | Se definida, stack traces de erro do agente de commit são impressos |\n\n---\n\n## Variáveis sensíveis à segurança\n\nTrate estas como segredos; não as registre em logs nem as commit:\n\n- Chaves de provedor/API e credenciais OAuth/bearer (todas as `*_API_KEY`, `*_TOKEN`, tokens de acesso/refresh OAuth)\n- Credenciais de nuvem (`AWS_*`, o caminho de `GOOGLE_APPLICATION_CREDENTIALS` pode expor material de conta de serviço)\n- Variáveis de autenticação de busca/provedor (`EXA_API_KEY`, `BRAVE_API_KEY`, `PERPLEXITY_API_KEY`, chaves de busca Anthropic)\n- Material mTLS Foundry (`CLAUDE_CODE_CLIENT_CERT`, `CLAUDE_CODE_CLIENT_KEY`, `NODE_EXTRA_CA_CERTS` quando aponta para bundles de CA privados)\n\nO runtime Python também remove explicitamente muitas variáveis de chave comuns antes de gerar subprocessos de kernel (`packages/coding-agent/src/ipy/runtime.ts`).\n",
|