@caupulican/pi-adaptative 0.80.100 → 0.80.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/dist/config.d.ts +11 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +17 -3
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +72 -0
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +437 -46
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/autonomy/envelope-enforcement.d.ts +5 -0
  11. package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
  12. package/dist/core/autonomy/envelope-enforcement.js +28 -4
  13. package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
  14. package/dist/core/autonomy/path-scope.d.ts.map +1 -1
  15. package/dist/core/autonomy/path-scope.js +33 -2
  16. package/dist/core/autonomy/path-scope.js.map +1 -1
  17. package/dist/core/bash-executor.d.ts.map +1 -1
  18. package/dist/core/bash-executor.js +15 -7
  19. package/dist/core/bash-executor.js.map +1 -1
  20. package/dist/core/context/brain-curator.d.ts +10 -0
  21. package/dist/core/context/brain-curator.d.ts.map +1 -1
  22. package/dist/core/context/brain-curator.js +19 -2
  23. package/dist/core/context/brain-curator.js.map +1 -1
  24. package/dist/core/context-gc.d.ts +8 -3
  25. package/dist/core/context-gc.d.ts.map +1 -1
  26. package/dist/core/context-gc.js +5 -0
  27. package/dist/core/context-gc.js.map +1 -1
  28. package/dist/core/delegation/worker-actions.d.ts +0 -10
  29. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  30. package/dist/core/delegation/worker-actions.js +5 -7
  31. package/dist/core/delegation/worker-actions.js.map +1 -1
  32. package/dist/core/delegation/worker-result.d.ts +6 -0
  33. package/dist/core/delegation/worker-result.d.ts.map +1 -1
  34. package/dist/core/delegation/worker-result.js +10 -4
  35. package/dist/core/delegation/worker-result.js.map +1 -1
  36. package/dist/core/delegation/worker-runner.d.ts +3 -0
  37. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  38. package/dist/core/delegation/worker-runner.js +6 -1
  39. package/dist/core/delegation/worker-runner.js.map +1 -1
  40. package/dist/core/doctor.d.ts +66 -0
  41. package/dist/core/doctor.d.ts.map +1 -0
  42. package/dist/core/doctor.js +144 -0
  43. package/dist/core/doctor.js.map +1 -0
  44. package/dist/core/learning/learning-audit.d.ts +13 -1
  45. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  46. package/dist/core/learning/learning-audit.js +22 -1
  47. package/dist/core/learning/learning-audit.js.map +1 -1
  48. package/dist/core/learning/learning-gate.d.ts +3 -0
  49. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  50. package/dist/core/learning/learning-gate.js +13 -4
  51. package/dist/core/learning/learning-gate.js.map +1 -1
  52. package/dist/core/models/local-registration.d.ts +2 -0
  53. package/dist/core/models/local-registration.d.ts.map +1 -1
  54. package/dist/core/models/local-registration.js +2 -1
  55. package/dist/core/models/local-registration.js.map +1 -1
  56. package/dist/core/models/local-runtime.d.ts +76 -2
  57. package/dist/core/models/local-runtime.d.ts.map +1 -1
  58. package/dist/core/models/local-runtime.js +233 -21
  59. package/dist/core/models/local-runtime.js.map +1 -1
  60. package/dist/core/profile-resource-selection.d.ts +15 -3
  61. package/dist/core/profile-resource-selection.d.ts.map +1 -1
  62. package/dist/core/profile-resource-selection.js +19 -9
  63. package/dist/core/profile-resource-selection.js.map +1 -1
  64. package/dist/core/resource-loader.d.ts +20 -0
  65. package/dist/core/resource-loader.d.ts.map +1 -1
  66. package/dist/core/resource-loader.js +42 -16
  67. package/dist/core/resource-loader.js.map +1 -1
  68. package/dist/core/settings-manager.d.ts +30 -0
  69. package/dist/core/settings-manager.d.ts.map +1 -1
  70. package/dist/core/settings-manager.js +65 -3
  71. package/dist/core/settings-manager.js.map +1 -1
  72. package/dist/core/skills.d.ts +14 -0
  73. package/dist/core/skills.d.ts.map +1 -1
  74. package/dist/core/skills.js +8 -0
  75. package/dist/core/skills.js.map +1 -1
  76. package/dist/core/tools/fff-search-backend.d.ts +34 -1
  77. package/dist/core/tools/fff-search-backend.d.ts.map +1 -1
  78. package/dist/core/tools/fff-search-backend.js +43 -4
  79. package/dist/core/tools/fff-search-backend.js.map +1 -1
  80. package/dist/core/tools/find.d.ts +16 -0
  81. package/dist/core/tools/find.d.ts.map +1 -1
  82. package/dist/core/tools/find.js +17 -3
  83. package/dist/core/tools/find.js.map +1 -1
  84. package/dist/core/tools/grep.d.ts +20 -0
  85. package/dist/core/tools/grep.d.ts.map +1 -1
  86. package/dist/core/tools/grep.js +15 -3
  87. package/dist/core/tools/grep.js.map +1 -1
  88. package/dist/main.d.ts.map +1 -1
  89. package/dist/main.js +17 -0
  90. package/dist/main.js.map +1 -1
  91. package/dist/modes/interactive/components/fitness-role-selector.d.ts +6 -2
  92. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -1
  93. package/dist/modes/interactive/components/fitness-role-selector.js +55 -45
  94. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -1
  95. package/dist/modes/interactive/components/model-suggestion-selector.d.ts +13 -0
  96. package/dist/modes/interactive/components/model-suggestion-selector.d.ts.map +1 -0
  97. package/dist/modes/interactive/components/model-suggestion-selector.js +40 -0
  98. package/dist/modes/interactive/components/model-suggestion-selector.js.map +1 -0
  99. package/dist/modes/interactive/components/profile-resource-editor.d.ts +3 -0
  100. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  101. package/dist/modes/interactive/components/profile-resource-editor.js +16 -2
  102. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  103. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  104. package/dist/modes/interactive/components/settings-selector.js +98 -0
  105. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  106. package/dist/modes/interactive/interactive-mode.d.ts +8 -1
  107. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  108. package/dist/modes/interactive/interactive-mode.js +50 -12
  109. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  110. package/dist/utils/safe-write-stream.d.ts +8 -0
  111. package/dist/utils/safe-write-stream.d.ts.map +1 -1
  112. package/dist/utils/safe-write-stream.js +32 -0
  113. package/dist/utils/safe-write-stream.js.map +1 -1
  114. package/dist/utils/tools-manager.d.ts +92 -2
  115. package/dist/utils/tools-manager.d.ts.map +1 -1
  116. package/dist/utils/tools-manager.js +172 -32
  117. package/dist/utils/tools-manager.js.map +1 -1
  118. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  119. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  120. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  121. package/examples/extensions/sandbox/package-lock.json +2 -2
  122. package/examples/extensions/sandbox/package.json +1 -1
  123. package/examples/extensions/with-deps/package-lock.json +2 -2
  124. package/examples/extensions/with-deps/package.json +1 -1
  125. package/npm-shrinkwrap.json +12 -36
  126. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"profile-resource-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/profile-resource-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@caupulican/pi-tui\";\nimport {\n\tdecodeResourceSelection,\n\tdetectResourceFraming,\n\tencodeResourceSelectionWithFraming,\n\ttype ResourceFraming,\n} from \"../../../core/profile-resource-selection.ts\";\nimport type { ResourceProfileKind, ResourceProfileSettings } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport interface ProfileResourceItem {\n\tid: string;\n\tpath?: string;\n\tdescription?: string;\n}\n\nexport interface ProfileResourceEditorKind {\n\tkind: ResourceProfileKind; // \"tools\" | \"skills\" | \"extensions\" | \"agents\" | \"prompts\" | \"themes\"\n\tlabel: string; // display label, e.g. \"Tools\"\n\titems: ProfileResourceItem[]; // the available items of this kind\n}\n\nexport interface ProfileResourceEditorOptions {\n\tprofileName: string;\n\tprofileScope: string; // e.g. \"directory\" | \"project\" | \"global\" | \"session\" | \"reusable-file\"\n\tinitialResources: ResourceProfileSettings; // existing profile.resources; may be {}\n\tkinds: ProfileResourceEditorKind[]; // the six kinds, with their universes\n\tonSave: (resources: ResourceProfileSettings) => void; // called on ctrl+s with the encoded result\n\tonCancel: () => void; // called on esc\n\tonScopeChange?: () => void;\n\tonEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\tcwd?: string;\n\tagentDir?: string;\n\texternalResourceRoots?: string[];\n}\n\ninterface ResourceItem {\n\tid: string;\n\tenabled: boolean;\n\tpath?: string;\n\tdescription?: string;\n\tsourceLabel?: \"catalog\" | \"user\" | \"project\" | \"bundled\";\n\tisMissing?: boolean;\n}\n\nconst TOOL_DESCRIPTIONS: Record<string, string> = {\n\tread: \"Read files from the filesystem.\",\n\tbash: \"Execute arbitrary commands in the shell.\",\n\tedit: \"Edit files surgically.\",\n\twrite: \"Create new files or overwrite existing files.\",\n\tgrep: \"Search for text patterns using ripgrep.\",\n\tfind: \"Locate files matching a search query.\",\n\tls: \"List files and directories.\",\n\tskill_audit: \"Inspect and audit local skills.\",\n\tskillify: \"Convert a set of files/instructions into a skill.\",\n\textensionify: \"Package a tool or script as an extension.\",\n};\n\nexport function resolveResourceEditPath(\n\t_id: string,\n\tfilePath: string | undefined,\n\tkind: ResourceProfileKind,\n): string | undefined {\n\tif (kind === \"tools\") {\n\t\treturn undefined;\n\t}\n\n\tif (!filePath) {\n\t\treturn undefined;\n\t}\n\n\tif (kind === \"extensions\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst indexTs = path.join(filePath, \"index.ts\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\treturn indexTs;\n\t\t\t\t}\n\t\t\t\tconst indexJs = path.join(filePath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexJs)) {\n\t\t\t\t\treturn indexJs;\n\t\t\t\t}\n\t\t\t\tconst pkgJsonPath = path.join(filePath, \"package.json\");\n\t\t\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pkg = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\t\t\t\t\t\tif (typeof pkg.main === \"string\") {\n\t\t\t\t\t\t\tconst resolvedMain = path.resolve(filePath, pkg.main);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedMain)) {\n\t\t\t\t\t\t\t\treturn resolvedMain;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\treturn indexTs;\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\tif (kind === \"skills\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst skillMd = path.join(filePath, \"SKILL.md\");\n\t\t\t\tif (fs.existsSync(skillMd)) {\n\t\t\t\t\treturn skillMd;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\treturn filePath;\n}\n\nexport function classifyResourceSource(\n\tfilePath: string | undefined,\n\tcwd: string,\n\tagentDir: string,\n\texternalRoots: string[],\n): \"catalog\" | \"user\" | \"project\" | \"bundled\" {\n\tif (!filePath) {\n\t\treturn \"bundled\";\n\t}\n\n\tconst absolutePath = isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n\tconst normPath = resolve(absolutePath);\n\tconst normCwd = resolve(cwd);\n\tconst normAgentDir = agentDir ? resolve(agentDir) : \"\";\n\n\tfor (const extRoot of externalRoots) {\n\t\tconst normExt = resolve(extRoot);\n\t\tif (normPath.startsWith(normExt)) {\n\t\t\treturn \"catalog\";\n\t\t}\n\t}\n\n\tif (normAgentDir && normPath.startsWith(normAgentDir)) {\n\t\treturn \"user\";\n\t}\n\n\tif (normPath.startsWith(normCwd)) {\n\t\treturn \"project\";\n\t}\n\n\tif (normPath.includes(\"node_modules\")) {\n\t\treturn \"bundled\";\n\t}\n\n\treturn \"bundled\";\n}\n\nexport class ProfileResourceEditorComponent extends Container implements Focusable {\n\tprivate profileName: string;\n\tprivate profileScope: string;\n\tprivate kinds: ProfileResourceEditorKind[];\n\tprivate enabledByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate framingByKind: Map<ResourceProfileKind, ResourceFraming> = new Map();\n\tprivate missingIdsByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate currentKindIndex = 0;\n\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate externalResourceRoots: string[];\n\n\tprivate filteredItems: ResourceItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\tprivate kindHeaderText: Text;\n\tprivate listContainer: Container;\n\tprivate descriptionText: Text;\n\tprivate footerText: Text;\n\tprivate isDirty = false;\n\tprivate maxVisible = 8;\n\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate onSave: (resources: ResourceProfileSettings) => void;\n\tprivate onCancel: () => void;\n\tprivate onScopeChange?: () => void;\n\tprivate onEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\n\tconstructor(options: ProfileResourceEditorOptions) {\n\t\tsuper();\n\t\tthis.profileName = options.profileName;\n\t\tthis.profileScope = options.profileScope;\n\t\tthis.kinds = options.kinds;\n\t\tthis.onSave = options.onSave;\n\t\tthis.onCancel = options.onCancel;\n\t\tthis.onScopeChange = options.onScopeChange;\n\t\tthis.onEdit = options.onEdit;\n\t\tthis.cwd = options.cwd || process.cwd();\n\t\tthis.agentDir = options.agentDir || \"\";\n\t\tthis.externalResourceRoots = options.externalResourceRoots || [];\n\n\t\t// Initialize enabled, framing, and missing sets for each kind\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst filter = options.initialResources[kind.kind];\n\t\t\tconst allIds = kind.items.map((item) => item.id);\n\n\t\t\t// Compute missing items\n\t\t\tconst mentionedIds = new Set<string>();\n\t\t\tif (filter) {\n\t\t\t\tif (filter.allow) {\n\t\t\t\t\tfor (const id of filter.allow) {\n\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (filter.block) {\n\t\t\t\t\tfor (const id of filter.block) {\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst availableIds = new Set(allIds);\n\t\t\tconst missingSet = new Set<string>();\n\t\t\tfor (const id of mentionedIds) {\n\t\t\t\tif (!availableIds.has(id)) {\n\t\t\t\t\tmissingSet.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.missingIdsByKind.set(kind.kind, missingSet);\n\n\t\t\t// Decode against the DISCOVERABLE universe plus every id the profile itself mentions:\n\t\t\t// decoding only against the discoverable set silently drops grants for anything the\n\t\t\t// current environment cannot see (offline external root, or a collapsed universe),\n\t\t\t// and the next save would then corrupt the profile.\n\t\t\tconst enabledSet = decodeResourceSelection(filter, [...allIds, ...missingSet]);\n\t\t\tthis.enabledByKind.set(kind.kind, enabledSet);\n\t\t\tthis.framingByKind.set(kind.kind, detectResourceFraming(filter));\n\t\t}\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"accent\", theme.bold(`Library — editing \"${this.profileName}\" (${this.profileScope})`)),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Navigate kinds: ${keyText(\"tui.input.tab\")}. Toggle: ${keyText(\"tui.select.confirm\")}. Mode: ${theme.fg(\"accent\", \"a\")} allow / ${theme.fg(\"accent\", \"b\")} block. Scope: ${theme.fg(\"accent\", \"s\")} change. Edit: ${theme.fg(\"accent\", \"e\")}.`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Kind selector header\n\t\tthis.kindHeaderText = new Text(this.getKindHeaderText(), 0, 0);\n\t\tthis.addChild(this.kindHeaderText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Description area\n\t\tthis.descriptionText = new Text(\"\", 0, 0);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.descriptionText);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.refresh();\n\t}\n\n\tprivate getKindHeaderText(): string {\n\t\tconst kind = this.kinds[this.currentKindIndex]!;\n\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\tconst framingText = framing === \"allow\" ? \"allow-list\" : \"block-list\";\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled (${framingText})`;\n\t\tconst kindIndicator = this.kinds\n\t\t\t.map((k, i) => {\n\t\t\t\tconst marker = i === this.currentKindIndex ? \"●\" : \"○\";\n\t\t\t\treturn theme.fg(i === this.currentKindIndex ? \"accent\" : \"muted\", `${marker} ${k.label}`);\n\t\t\t})\n\t\t\t.join(\" \");\n\t\treturn `${kindIndicator} ${theme.fg(\"muted\", countText)}`;\n\t}\n\n\tprivate getCurrentKind(): ProfileResourceEditorKind {\n\t\treturn this.kinds[this.currentKindIndex]!;\n\t}\n\n\tprivate getCurrentEnabledSet(): Set<string> {\n\t\tconst kind = this.getCurrentKind();\n\t\treturn this.enabledByKind.get(kind.kind)!;\n\t}\n\n\tprivate buildItems(): ResourceItem[] {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\n\t\tconst items: ResourceItem[] = [];\n\n\t\t// Add all available items\n\t\tfor (const availableItem of kind.items) {\n\t\t\tconst isEnabled = enabledSet.has(availableItem.id);\n\t\t\tlet desc = availableItem.description;\n\t\t\tif (kind.kind === \"tools\" && !desc) {\n\t\t\t\tdesc = TOOL_DESCRIPTIONS[availableItem.id];\n\t\t\t}\n\t\t\titems.push({\n\t\t\t\tid: availableItem.id,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tpath: availableItem.path,\n\t\t\t\tdescription: desc,\n\t\t\t\tsourceLabel: classifyResourceSource(\n\t\t\t\t\tavailableItem.path,\n\t\t\t\t\tthis.cwd,\n\t\t\t\t\tthis.agentDir,\n\t\t\t\t\tthis.externalResourceRoots,\n\t\t\t\t),\n\t\t\t\tisMissing: false,\n\t\t\t});\n\t\t}\n\n\t\t// Add missing items\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tfor (const missingId of missingSet) {\n\t\t\tconst isEnabled = enabledSet.has(missingId);\n\t\t\titems.push({\n\t\t\t\tid: missingId,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tisMissing: true,\n\t\t\t\tdescription: \"Referenced in profile but missing from available resources.\",\n\t\t\t});\n\t\t}\n\n\t\t// Sort: enabled first, then disabled\n\t\tconst enabled: ResourceItem[] = [];\n\t\tconst disabled: ResourceItem[] = [];\n\t\tfor (const item of items) {\n\t\t\tif (item.enabled) {\n\t\t\t\tenabled.push(item);\n\t\t\t} else {\n\t\t\t\tdisabled.push(item);\n\t\t\t}\n\t\t}\n\t\treturn [...enabled, ...disabled];\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled`;\n\t\tconst parts = [\n\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t`${keyText(\"tui.input.tab\")} kind`,\n\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t`${theme.fg(\"accent\", \"e\")} edit`,\n\t\t\t`${theme.fg(\"accent\", \"Ctrl+Q\")}/${keyText(\"app.interrupt\")} cancel`,\n\t\t\tcountText,\n\t\t];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.id} ${i.description ?? \"\"}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst kind = this.getCurrentKind();\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tconst totalAvailableCount = kind.items.length + missingSet.size;\n\n\t\tif (totalAvailableCount === 0) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", \" (none available — add a Source or install resources)\"), 0, 0),\n\t\t\t);\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching resources\"), 0, 0));\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlet resourceText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\n\t\t\tif (item.isMissing) {\n\t\t\t\tresourceText = theme.fg(\"muted\", `${item.id} [missing]`);\n\t\t\t} else if (item.sourceLabel) {\n\t\t\t\tconst labelColor =\n\t\t\t\t\titem.sourceLabel === \"catalog\"\n\t\t\t\t\t\t? \"thinkingText\"\n\t\t\t\t\t\t: item.sourceLabel === \"project\"\n\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t: item.sourceLabel === \"user\"\n\t\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t\t: \"muted\";\n\t\t\t\tconst labelText = theme.fg(labelColor, ` [${item.sourceLabel}]`);\n\t\t\t\tresourceText = `${resourceText}${labelText}`;\n\t\t\t}\n\n\t\t\tconst status = item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${resourceText}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\t// Update description area for current selection\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem?.description) {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", ` Description: ${selectedItem.description}`));\n\t\t} else {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation within list\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch kind with Tab (cycles forward)\n\t\tif (kb.matches(data, \"tui.input.tab\")) {\n\t\t\tthis.currentKindIndex = (this.currentKindIndex + 1) % this.kinds.length;\n\t\t\tthis.selectedIndex = 0;\n\t\t\tthis.searchInput.setValue(\"\");\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Allow-list\n\t\tif (matchesKey(data, Key.ctrl(\"a\")) || (this.searchInput.getValue() === \"\" && data === \"a\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"allow\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Block-list\n\t\tif (matchesKey(data, Key.ctrl(\"b\")) || (this.searchInput.getValue() === \"\" && data === \"b\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"block\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Edit highlighted resource\n\t\tif (data === \"e\" && this.searchInput.getValue() === \"\") {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && !item.isMissing && item.path) {\n\t\t\t\tconst kind = this.getCurrentKind().kind;\n\t\t\t\tif (this.onEdit) {\n\t\t\t\t\tthis.onEdit(item.id, item.path, kind);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch scope: Scope selector\n\t\tif (matchesKey(data, Key.ctrl(\"o\")) || (this.searchInput.getValue() === \"\" && data === \"s\")) {\n\t\t\tif (this.onScopeChange) {\n\t\t\t\tthis.onScopeChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on space/enter\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\t\t\tif (enabledSet.has(item.id)) {\n\t\t\t\t\tenabledSet.delete(item.id);\n\t\t\t\t} else {\n\t\t\t\t\tenabledSet.add(item.id);\n\t\t\t\t}\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Save/persist to settings\n\t\tif (kb.matches(data, \"app.models.save\")) {\n\t\t\tthis.persistChanges();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape / Ctrl+Q - cancel (unconditional)\n\t\tif (\n\t\t\tkb.matches(data, \"app.interrupt\") ||\n\t\t\tmatchesKey(data, Key.escape) ||\n\t\t\tmatchesKey(data, Key.esc) ||\n\t\t\tmatchesKey(data, \"ctrl+q\")\n\t\t) {\n\t\t\tthis.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tprivate persistChanges(): void {\n\t\tconst resources: ResourceProfileSettings = {};\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\t\t// Persist against the same widened universe used at decode time: profile-referenced\n\t\t\t// ids that are not currently discoverable must survive a save untouched.\n\t\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) ?? new Set<string>();\n\t\t\tconst allIds = [...new Set([...kind.items.map((item) => item.id), ...missingSet])];\n\t\t\tconst encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing);\n\t\t\tif (encoded !== undefined) {\n\t\t\t\tresources[kind.kind] = encoded;\n\t\t\t}\n\t\t}\n\t\tthis.onSave(resources);\n\t\tthis.isDirty = false;\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
1
+ {"version":3,"file":"profile-resource-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/profile-resource-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@caupulican/pi-tui\";\nimport {\n\tdecodeResourceSelection,\n\tdetectResourceFraming,\n\tencodeResourceSelectionWithFraming,\n\ttype ResourceFraming,\n} from \"../../../core/profile-resource-selection.ts\";\nimport type {\n\tResourceProfileFilterSettings,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n} from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport interface ProfileResourceItem {\n\tid: string;\n\tpath?: string;\n\tdescription?: string;\n}\n\nexport interface ProfileResourceEditorKind {\n\tkind: ResourceProfileKind; // \"tools\" | \"skills\" | \"extensions\" | \"agents\" | \"prompts\" | \"themes\"\n\tlabel: string; // display label, e.g. \"Tools\"\n\titems: ProfileResourceItem[]; // the available items of this kind\n}\n\nexport interface ProfileResourceEditorOptions {\n\tprofileName: string;\n\tprofileScope: string; // e.g. \"directory\" | \"project\" | \"global\" | \"session\" | \"reusable-file\"\n\tinitialResources: ResourceProfileSettings; // existing profile.resources; may be {}\n\tkinds: ProfileResourceEditorKind[]; // the six kinds, with their universes\n\tonSave: (resources: ResourceProfileSettings) => void; // called on ctrl+s with the encoded result\n\tonCancel: () => void; // called on esc\n\tonScopeChange?: () => void;\n\tonEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\tcwd?: string;\n\tagentDir?: string;\n\texternalResourceRoots?: string[];\n}\n\ninterface ResourceItem {\n\tid: string;\n\tenabled: boolean;\n\tpath?: string;\n\tdescription?: string;\n\tsourceLabel?: \"catalog\" | \"user\" | \"project\" | \"bundled\";\n\tisMissing?: boolean;\n}\n\nconst TOOL_DESCRIPTIONS: Record<string, string> = {\n\tread: \"Read files from the filesystem.\",\n\tbash: \"Execute arbitrary commands in the shell.\",\n\tedit: \"Edit files surgically.\",\n\twrite: \"Create new files or overwrite existing files.\",\n\tgrep: \"Search for text patterns using ripgrep.\",\n\tfind: \"Locate files matching a search query.\",\n\tls: \"List files and directories.\",\n\tskill_audit: \"Inspect and audit local skills.\",\n\tskillify: \"Convert a set of files/instructions into a skill.\",\n\textensionify: \"Package a tool or script as an extension.\",\n};\n\nexport function resolveResourceEditPath(\n\t_id: string,\n\tfilePath: string | undefined,\n\tkind: ResourceProfileKind,\n): string | undefined {\n\tif (kind === \"tools\") {\n\t\treturn undefined;\n\t}\n\n\tif (!filePath) {\n\t\treturn undefined;\n\t}\n\n\tif (kind === \"extensions\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst indexTs = path.join(filePath, \"index.ts\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\treturn indexTs;\n\t\t\t\t}\n\t\t\t\tconst indexJs = path.join(filePath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexJs)) {\n\t\t\t\t\treturn indexJs;\n\t\t\t\t}\n\t\t\t\tconst pkgJsonPath = path.join(filePath, \"package.json\");\n\t\t\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pkg = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\t\t\t\t\t\tif (typeof pkg.main === \"string\") {\n\t\t\t\t\t\t\tconst resolvedMain = path.resolve(filePath, pkg.main);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedMain)) {\n\t\t\t\t\t\t\t\treturn resolvedMain;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\treturn indexTs;\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\tif (kind === \"skills\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst skillMd = path.join(filePath, \"SKILL.md\");\n\t\t\t\tif (fs.existsSync(skillMd)) {\n\t\t\t\t\treturn skillMd;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\treturn filePath;\n}\n\nexport function classifyResourceSource(\n\tfilePath: string | undefined,\n\tcwd: string,\n\tagentDir: string,\n\texternalRoots: string[],\n): \"catalog\" | \"user\" | \"project\" | \"bundled\" {\n\tif (!filePath) {\n\t\treturn \"bundled\";\n\t}\n\n\tconst absolutePath = isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n\tconst normPath = resolve(absolutePath);\n\tconst normCwd = resolve(cwd);\n\tconst normAgentDir = agentDir ? resolve(agentDir) : \"\";\n\n\tfor (const extRoot of externalRoots) {\n\t\tconst normExt = resolve(extRoot);\n\t\tif (normPath.startsWith(normExt)) {\n\t\t\treturn \"catalog\";\n\t\t}\n\t}\n\n\tif (normAgentDir && normPath.startsWith(normAgentDir)) {\n\t\treturn \"user\";\n\t}\n\n\tif (normPath.startsWith(normCwd)) {\n\t\treturn \"project\";\n\t}\n\n\tif (normPath.includes(\"node_modules\")) {\n\t\treturn \"bundled\";\n\t}\n\n\treturn \"bundled\";\n}\n\nexport class ProfileResourceEditorComponent extends Container implements Focusable {\n\tprivate profileName: string;\n\tprivate profileScope: string;\n\tprivate kinds: ProfileResourceEditorKind[];\n\tprivate enabledByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate framingByKind: Map<ResourceProfileKind, ResourceFraming> = new Map();\n\tprivate missingIdsByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\t/** The filter each kind was decoded from, so an all-enabled save preserves an enumerated grant\n\t * (or an already-wildcard grant) instead of widening it to allow:[\"*\"]. */\n\tprivate originalFilterByKind: Map<ResourceProfileKind, ResourceProfileFilterSettings | undefined> = new Map();\n\tprivate currentKindIndex = 0;\n\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate externalResourceRoots: string[];\n\n\tprivate filteredItems: ResourceItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\tprivate kindHeaderText: Text;\n\tprivate listContainer: Container;\n\tprivate descriptionText: Text;\n\tprivate footerText: Text;\n\tprivate isDirty = false;\n\tprivate maxVisible = 8;\n\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate onSave: (resources: ResourceProfileSettings) => void;\n\tprivate onCancel: () => void;\n\tprivate onScopeChange?: () => void;\n\tprivate onEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\n\tconstructor(options: ProfileResourceEditorOptions) {\n\t\tsuper();\n\t\tthis.profileName = options.profileName;\n\t\tthis.profileScope = options.profileScope;\n\t\tthis.kinds = options.kinds;\n\t\tthis.onSave = options.onSave;\n\t\tthis.onCancel = options.onCancel;\n\t\tthis.onScopeChange = options.onScopeChange;\n\t\tthis.onEdit = options.onEdit;\n\t\tthis.cwd = options.cwd || process.cwd();\n\t\tthis.agentDir = options.agentDir || \"\";\n\t\tthis.externalResourceRoots = options.externalResourceRoots || [];\n\n\t\t// Initialize enabled, framing, and missing sets for each kind\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst filter = options.initialResources[kind.kind];\n\t\t\tconst allIds = kind.items.map((item) => item.id);\n\n\t\t\t// Compute missing items\n\t\t\tconst mentionedIds = new Set<string>();\n\t\t\tif (filter) {\n\t\t\t\tif (filter.allow) {\n\t\t\t\t\tfor (const id of filter.allow) {\n\t\t\t\t\t\t// \"*\" is a grant-all framing marker, not a resource id — the block loop below\n\t\t\t\t\t\t// already excludes it; the allow loop must too, or it leaks into missingSet as\n\t\t\t\t\t\t// a fake \"missing item\" and rides along as a phantom enabled member through\n\t\t\t\t\t\t// decode/encode.\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (filter.block) {\n\t\t\t\t\tfor (const id of filter.block) {\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst availableIds = new Set(allIds);\n\t\t\tconst missingSet = new Set<string>();\n\t\t\tfor (const id of mentionedIds) {\n\t\t\t\tif (!availableIds.has(id)) {\n\t\t\t\t\tmissingSet.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.missingIdsByKind.set(kind.kind, missingSet);\n\n\t\t\t// Decode against the DISCOVERABLE universe plus every id the profile itself mentions:\n\t\t\t// decoding only against the discoverable set silently drops grants for anything the\n\t\t\t// current environment cannot see (offline external root, or a collapsed universe),\n\t\t\t// and the next save would then corrupt the profile.\n\t\t\tconst enabledSet = decodeResourceSelection(filter, [...allIds, ...missingSet]);\n\t\t\tthis.enabledByKind.set(kind.kind, enabledSet);\n\t\t\tthis.framingByKind.set(kind.kind, detectResourceFraming(filter));\n\t\t\tthis.originalFilterByKind.set(kind.kind, filter);\n\t\t}\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"accent\", theme.bold(`Library — editing \"${this.profileName}\" (${this.profileScope})`)),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Navigate kinds: ${keyText(\"tui.input.tab\")}. Toggle: ${keyText(\"tui.select.confirm\")}. Mode: ${theme.fg(\"accent\", \"a\")} allow / ${theme.fg(\"accent\", \"b\")} block. Scope: ${theme.fg(\"accent\", \"s\")} change. Edit: ${theme.fg(\"accent\", \"e\")}.`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Kind selector header\n\t\tthis.kindHeaderText = new Text(this.getKindHeaderText(), 0, 0);\n\t\tthis.addChild(this.kindHeaderText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Description area\n\t\tthis.descriptionText = new Text(\"\", 0, 0);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.descriptionText);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.refresh();\n\t}\n\n\tprivate getKindHeaderText(): string {\n\t\tconst kind = this.kinds[this.currentKindIndex]!;\n\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\tconst framingText = framing === \"allow\" ? \"allow-list\" : \"block-list\";\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled (${framingText})`;\n\t\tconst kindIndicator = this.kinds\n\t\t\t.map((k, i) => {\n\t\t\t\tconst marker = i === this.currentKindIndex ? \"●\" : \"○\";\n\t\t\t\treturn theme.fg(i === this.currentKindIndex ? \"accent\" : \"muted\", `${marker} ${k.label}`);\n\t\t\t})\n\t\t\t.join(\" \");\n\t\treturn `${kindIndicator} ${theme.fg(\"muted\", countText)}`;\n\t}\n\n\tprivate getCurrentKind(): ProfileResourceEditorKind {\n\t\treturn this.kinds[this.currentKindIndex]!;\n\t}\n\n\tprivate getCurrentEnabledSet(): Set<string> {\n\t\tconst kind = this.getCurrentKind();\n\t\treturn this.enabledByKind.get(kind.kind)!;\n\t}\n\n\tprivate buildItems(): ResourceItem[] {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\n\t\tconst items: ResourceItem[] = [];\n\n\t\t// Add all available items\n\t\tfor (const availableItem of kind.items) {\n\t\t\tconst isEnabled = enabledSet.has(availableItem.id);\n\t\t\tlet desc = availableItem.description;\n\t\t\tif (kind.kind === \"tools\" && !desc) {\n\t\t\t\tdesc = TOOL_DESCRIPTIONS[availableItem.id];\n\t\t\t}\n\t\t\titems.push({\n\t\t\t\tid: availableItem.id,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tpath: availableItem.path,\n\t\t\t\tdescription: desc,\n\t\t\t\tsourceLabel: classifyResourceSource(\n\t\t\t\t\tavailableItem.path,\n\t\t\t\t\tthis.cwd,\n\t\t\t\t\tthis.agentDir,\n\t\t\t\t\tthis.externalResourceRoots,\n\t\t\t\t),\n\t\t\t\tisMissing: false,\n\t\t\t});\n\t\t}\n\n\t\t// Add missing items\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tfor (const missingId of missingSet) {\n\t\t\tconst isEnabled = enabledSet.has(missingId);\n\t\t\titems.push({\n\t\t\t\tid: missingId,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tisMissing: true,\n\t\t\t\tdescription: \"Referenced in profile but missing from available resources.\",\n\t\t\t});\n\t\t}\n\n\t\t// Sort: enabled first, then disabled\n\t\tconst enabled: ResourceItem[] = [];\n\t\tconst disabled: ResourceItem[] = [];\n\t\tfor (const item of items) {\n\t\t\tif (item.enabled) {\n\t\t\t\tenabled.push(item);\n\t\t\t} else {\n\t\t\t\tdisabled.push(item);\n\t\t\t}\n\t\t}\n\t\treturn [...enabled, ...disabled];\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled`;\n\t\tconst parts = [\n\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t`${keyText(\"tui.input.tab\")} kind`,\n\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t`${theme.fg(\"accent\", \"e\")} edit`,\n\t\t\t`${theme.fg(\"accent\", \"Ctrl+Q\")}/${keyText(\"app.interrupt\")} cancel`,\n\t\t\tcountText,\n\t\t];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.id} ${i.description ?? \"\"}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst kind = this.getCurrentKind();\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tconst totalAvailableCount = kind.items.length + missingSet.size;\n\n\t\tif (totalAvailableCount === 0) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", \" (none available — add a Source or install resources)\"), 0, 0),\n\t\t\t);\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching resources\"), 0, 0));\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlet resourceText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\n\t\t\tif (item.isMissing) {\n\t\t\t\tresourceText = theme.fg(\"muted\", `${item.id} [missing]`);\n\t\t\t} else if (item.sourceLabel) {\n\t\t\t\tconst labelColor =\n\t\t\t\t\titem.sourceLabel === \"catalog\"\n\t\t\t\t\t\t? \"thinkingText\"\n\t\t\t\t\t\t: item.sourceLabel === \"project\"\n\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t: item.sourceLabel === \"user\"\n\t\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t\t: \"muted\";\n\t\t\t\tconst labelText = theme.fg(labelColor, ` [${item.sourceLabel}]`);\n\t\t\t\tresourceText = `${resourceText}${labelText}`;\n\t\t\t}\n\n\t\t\tconst status = item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${resourceText}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\t// Update description area for current selection\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem?.description) {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", ` Description: ${selectedItem.description}`));\n\t\t} else {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation within list\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch kind with Tab (cycles forward)\n\t\tif (kb.matches(data, \"tui.input.tab\")) {\n\t\t\tthis.currentKindIndex = (this.currentKindIndex + 1) % this.kinds.length;\n\t\t\tthis.selectedIndex = 0;\n\t\t\tthis.searchInput.setValue(\"\");\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Allow-list\n\t\tif (matchesKey(data, Key.ctrl(\"a\")) || (this.searchInput.getValue() === \"\" && data === \"a\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"allow\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Block-list\n\t\tif (matchesKey(data, Key.ctrl(\"b\")) || (this.searchInput.getValue() === \"\" && data === \"b\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"block\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Edit highlighted resource\n\t\tif (data === \"e\" && this.searchInput.getValue() === \"\") {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && !item.isMissing && item.path) {\n\t\t\t\tconst kind = this.getCurrentKind().kind;\n\t\t\t\tif (this.onEdit) {\n\t\t\t\t\tthis.onEdit(item.id, item.path, kind);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch scope: Scope selector\n\t\tif (matchesKey(data, Key.ctrl(\"o\")) || (this.searchInput.getValue() === \"\" && data === \"s\")) {\n\t\t\tif (this.onScopeChange) {\n\t\t\t\tthis.onScopeChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on space/enter\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\t\t\tif (enabledSet.has(item.id)) {\n\t\t\t\t\tenabledSet.delete(item.id);\n\t\t\t\t} else {\n\t\t\t\t\tenabledSet.add(item.id);\n\t\t\t\t}\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Save/persist to settings\n\t\tif (kb.matches(data, \"app.models.save\")) {\n\t\t\tthis.persistChanges();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape / Ctrl+Q - cancel (unconditional)\n\t\tif (\n\t\t\tkb.matches(data, \"app.interrupt\") ||\n\t\t\tmatchesKey(data, Key.escape) ||\n\t\t\tmatchesKey(data, Key.esc) ||\n\t\t\tmatchesKey(data, \"ctrl+q\")\n\t\t) {\n\t\t\tthis.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tprivate persistChanges(): void {\n\t\tconst resources: ResourceProfileSettings = {};\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\t\t// Persist against the same widened universe used at decode time: profile-referenced\n\t\t\t// ids that are not currently discoverable must survive a save untouched.\n\t\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) ?? new Set<string>();\n\t\t\tconst allIds = [...new Set([...kind.items.map((item) => item.id), ...missingSet])];\n\t\t\t// Pass the original filter so an all-enabled save preserves an enumerated grant (and only\n\t\t\t// keeps a wildcard when the grant was already a wildcard) — never widening it silently.\n\t\t\tconst encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing, {\n\t\t\t\toriginalFilter: this.originalFilterByKind.get(kind.kind),\n\t\t\t});\n\t\t\tif (encoded !== undefined) {\n\t\t\t\tresources[kind.kind] = encoded;\n\t\t\t}\n\t\t}\n\t\tthis.onSave(resources);\n\t\tthis.isDirty = false;\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
@@ -103,6 +103,9 @@ export class ProfileResourceEditorComponent extends Container {
103
103
  enabledByKind = new Map();
104
104
  framingByKind = new Map();
105
105
  missingIdsByKind = new Map();
106
+ /** The filter each kind was decoded from, so an all-enabled save preserves an enumerated grant
107
+ * (or an already-wildcard grant) instead of widening it to allow:["*"]. */
108
+ originalFilterByKind = new Map();
106
109
  currentKindIndex = 0;
107
110
  cwd;
108
111
  agentDir;
@@ -149,7 +152,13 @@ export class ProfileResourceEditorComponent extends Container {
149
152
  if (filter) {
150
153
  if (filter.allow) {
151
154
  for (const id of filter.allow) {
152
- mentionedIds.add(id);
155
+ // "*" is a grant-all framing marker, not a resource id — the block loop below
156
+ // already excludes it; the allow loop must too, or it leaks into missingSet as
157
+ // a fake "missing item" and rides along as a phantom enabled member through
158
+ // decode/encode.
159
+ if (id !== "*") {
160
+ mentionedIds.add(id);
161
+ }
153
162
  }
154
163
  }
155
164
  if (filter.block) {
@@ -175,6 +184,7 @@ export class ProfileResourceEditorComponent extends Container {
175
184
  const enabledSet = decodeResourceSelection(filter, [...allIds, ...missingSet]);
176
185
  this.enabledByKind.set(kind.kind, enabledSet);
177
186
  this.framingByKind.set(kind.kind, detectResourceFraming(filter));
187
+ this.originalFilterByKind.set(kind.kind, filter);
178
188
  }
179
189
  // Header
180
190
  this.addChild(new DynamicBorder());
@@ -457,7 +467,11 @@ export class ProfileResourceEditorComponent extends Container {
457
467
  // ids that are not currently discoverable must survive a save untouched.
458
468
  const missingSet = this.missingIdsByKind.get(kind.kind) ?? new Set();
459
469
  const allIds = [...new Set([...kind.items.map((item) => item.id), ...missingSet])];
460
- const encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing);
470
+ // Pass the original filter so an all-enabled save preserves an enumerated grant (and only
471
+ // keeps a wildcard when the grant was already a wildcard) — never widening it silently.
472
+ const encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing, {
473
+ originalFilter: this.originalFilterByKind.get(kind.kind),
474
+ });
461
475
  if (encoded !== undefined) {
462
476
  resources[kind.kind] = encoded;
463
477
  }
@@ -1 +1 @@
1
- {"version":3,"file":"profile-resource-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/profile-resource-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@caupulican/pi-tui\";\nimport {\n\tdecodeResourceSelection,\n\tdetectResourceFraming,\n\tencodeResourceSelectionWithFraming,\n\ttype ResourceFraming,\n} from \"../../../core/profile-resource-selection.ts\";\nimport type { ResourceProfileKind, ResourceProfileSettings } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport interface ProfileResourceItem {\n\tid: string;\n\tpath?: string;\n\tdescription?: string;\n}\n\nexport interface ProfileResourceEditorKind {\n\tkind: ResourceProfileKind; // \"tools\" | \"skills\" | \"extensions\" | \"agents\" | \"prompts\" | \"themes\"\n\tlabel: string; // display label, e.g. \"Tools\"\n\titems: ProfileResourceItem[]; // the available items of this kind\n}\n\nexport interface ProfileResourceEditorOptions {\n\tprofileName: string;\n\tprofileScope: string; // e.g. \"directory\" | \"project\" | \"global\" | \"session\" | \"reusable-file\"\n\tinitialResources: ResourceProfileSettings; // existing profile.resources; may be {}\n\tkinds: ProfileResourceEditorKind[]; // the six kinds, with their universes\n\tonSave: (resources: ResourceProfileSettings) => void; // called on ctrl+s with the encoded result\n\tonCancel: () => void; // called on esc\n\tonScopeChange?: () => void;\n\tonEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\tcwd?: string;\n\tagentDir?: string;\n\texternalResourceRoots?: string[];\n}\n\ninterface ResourceItem {\n\tid: string;\n\tenabled: boolean;\n\tpath?: string;\n\tdescription?: string;\n\tsourceLabel?: \"catalog\" | \"user\" | \"project\" | \"bundled\";\n\tisMissing?: boolean;\n}\n\nconst TOOL_DESCRIPTIONS: Record<string, string> = {\n\tread: \"Read files from the filesystem.\",\n\tbash: \"Execute arbitrary commands in the shell.\",\n\tedit: \"Edit files surgically.\",\n\twrite: \"Create new files or overwrite existing files.\",\n\tgrep: \"Search for text patterns using ripgrep.\",\n\tfind: \"Locate files matching a search query.\",\n\tls: \"List files and directories.\",\n\tskill_audit: \"Inspect and audit local skills.\",\n\tskillify: \"Convert a set of files/instructions into a skill.\",\n\textensionify: \"Package a tool or script as an extension.\",\n};\n\nexport function resolveResourceEditPath(\n\t_id: string,\n\tfilePath: string | undefined,\n\tkind: ResourceProfileKind,\n): string | undefined {\n\tif (kind === \"tools\") {\n\t\treturn undefined;\n\t}\n\n\tif (!filePath) {\n\t\treturn undefined;\n\t}\n\n\tif (kind === \"extensions\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst indexTs = path.join(filePath, \"index.ts\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\treturn indexTs;\n\t\t\t\t}\n\t\t\t\tconst indexJs = path.join(filePath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexJs)) {\n\t\t\t\t\treturn indexJs;\n\t\t\t\t}\n\t\t\t\tconst pkgJsonPath = path.join(filePath, \"package.json\");\n\t\t\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pkg = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\t\t\t\t\t\tif (typeof pkg.main === \"string\") {\n\t\t\t\t\t\t\tconst resolvedMain = path.resolve(filePath, pkg.main);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedMain)) {\n\t\t\t\t\t\t\t\treturn resolvedMain;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\treturn indexTs;\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\tif (kind === \"skills\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst skillMd = path.join(filePath, \"SKILL.md\");\n\t\t\t\tif (fs.existsSync(skillMd)) {\n\t\t\t\t\treturn skillMd;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\treturn filePath;\n}\n\nexport function classifyResourceSource(\n\tfilePath: string | undefined,\n\tcwd: string,\n\tagentDir: string,\n\texternalRoots: string[],\n): \"catalog\" | \"user\" | \"project\" | \"bundled\" {\n\tif (!filePath) {\n\t\treturn \"bundled\";\n\t}\n\n\tconst absolutePath = isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n\tconst normPath = resolve(absolutePath);\n\tconst normCwd = resolve(cwd);\n\tconst normAgentDir = agentDir ? resolve(agentDir) : \"\";\n\n\tfor (const extRoot of externalRoots) {\n\t\tconst normExt = resolve(extRoot);\n\t\tif (normPath.startsWith(normExt)) {\n\t\t\treturn \"catalog\";\n\t\t}\n\t}\n\n\tif (normAgentDir && normPath.startsWith(normAgentDir)) {\n\t\treturn \"user\";\n\t}\n\n\tif (normPath.startsWith(normCwd)) {\n\t\treturn \"project\";\n\t}\n\n\tif (normPath.includes(\"node_modules\")) {\n\t\treturn \"bundled\";\n\t}\n\n\treturn \"bundled\";\n}\n\nexport class ProfileResourceEditorComponent extends Container implements Focusable {\n\tprivate profileName: string;\n\tprivate profileScope: string;\n\tprivate kinds: ProfileResourceEditorKind[];\n\tprivate enabledByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate framingByKind: Map<ResourceProfileKind, ResourceFraming> = new Map();\n\tprivate missingIdsByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate currentKindIndex = 0;\n\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate externalResourceRoots: string[];\n\n\tprivate filteredItems: ResourceItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\tprivate kindHeaderText: Text;\n\tprivate listContainer: Container;\n\tprivate descriptionText: Text;\n\tprivate footerText: Text;\n\tprivate isDirty = false;\n\tprivate maxVisible = 8;\n\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate onSave: (resources: ResourceProfileSettings) => void;\n\tprivate onCancel: () => void;\n\tprivate onScopeChange?: () => void;\n\tprivate onEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\n\tconstructor(options: ProfileResourceEditorOptions) {\n\t\tsuper();\n\t\tthis.profileName = options.profileName;\n\t\tthis.profileScope = options.profileScope;\n\t\tthis.kinds = options.kinds;\n\t\tthis.onSave = options.onSave;\n\t\tthis.onCancel = options.onCancel;\n\t\tthis.onScopeChange = options.onScopeChange;\n\t\tthis.onEdit = options.onEdit;\n\t\tthis.cwd = options.cwd || process.cwd();\n\t\tthis.agentDir = options.agentDir || \"\";\n\t\tthis.externalResourceRoots = options.externalResourceRoots || [];\n\n\t\t// Initialize enabled, framing, and missing sets for each kind\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst filter = options.initialResources[kind.kind];\n\t\t\tconst allIds = kind.items.map((item) => item.id);\n\n\t\t\t// Compute missing items\n\t\t\tconst mentionedIds = new Set<string>();\n\t\t\tif (filter) {\n\t\t\t\tif (filter.allow) {\n\t\t\t\t\tfor (const id of filter.allow) {\n\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (filter.block) {\n\t\t\t\t\tfor (const id of filter.block) {\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst availableIds = new Set(allIds);\n\t\t\tconst missingSet = new Set<string>();\n\t\t\tfor (const id of mentionedIds) {\n\t\t\t\tif (!availableIds.has(id)) {\n\t\t\t\t\tmissingSet.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.missingIdsByKind.set(kind.kind, missingSet);\n\n\t\t\t// Decode against the DISCOVERABLE universe plus every id the profile itself mentions:\n\t\t\t// decoding only against the discoverable set silently drops grants for anything the\n\t\t\t// current environment cannot see (offline external root, or a collapsed universe),\n\t\t\t// and the next save would then corrupt the profile.\n\t\t\tconst enabledSet = decodeResourceSelection(filter, [...allIds, ...missingSet]);\n\t\t\tthis.enabledByKind.set(kind.kind, enabledSet);\n\t\t\tthis.framingByKind.set(kind.kind, detectResourceFraming(filter));\n\t\t}\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"accent\", theme.bold(`Library — editing \"${this.profileName}\" (${this.profileScope})`)),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Navigate kinds: ${keyText(\"tui.input.tab\")}. Toggle: ${keyText(\"tui.select.confirm\")}. Mode: ${theme.fg(\"accent\", \"a\")} allow / ${theme.fg(\"accent\", \"b\")} block. Scope: ${theme.fg(\"accent\", \"s\")} change. Edit: ${theme.fg(\"accent\", \"e\")}.`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Kind selector header\n\t\tthis.kindHeaderText = new Text(this.getKindHeaderText(), 0, 0);\n\t\tthis.addChild(this.kindHeaderText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Description area\n\t\tthis.descriptionText = new Text(\"\", 0, 0);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.descriptionText);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.refresh();\n\t}\n\n\tprivate getKindHeaderText(): string {\n\t\tconst kind = this.kinds[this.currentKindIndex]!;\n\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\tconst framingText = framing === \"allow\" ? \"allow-list\" : \"block-list\";\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled (${framingText})`;\n\t\tconst kindIndicator = this.kinds\n\t\t\t.map((k, i) => {\n\t\t\t\tconst marker = i === this.currentKindIndex ? \"●\" : \"○\";\n\t\t\t\treturn theme.fg(i === this.currentKindIndex ? \"accent\" : \"muted\", `${marker} ${k.label}`);\n\t\t\t})\n\t\t\t.join(\" \");\n\t\treturn `${kindIndicator} ${theme.fg(\"muted\", countText)}`;\n\t}\n\n\tprivate getCurrentKind(): ProfileResourceEditorKind {\n\t\treturn this.kinds[this.currentKindIndex]!;\n\t}\n\n\tprivate getCurrentEnabledSet(): Set<string> {\n\t\tconst kind = this.getCurrentKind();\n\t\treturn this.enabledByKind.get(kind.kind)!;\n\t}\n\n\tprivate buildItems(): ResourceItem[] {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\n\t\tconst items: ResourceItem[] = [];\n\n\t\t// Add all available items\n\t\tfor (const availableItem of kind.items) {\n\t\t\tconst isEnabled = enabledSet.has(availableItem.id);\n\t\t\tlet desc = availableItem.description;\n\t\t\tif (kind.kind === \"tools\" && !desc) {\n\t\t\t\tdesc = TOOL_DESCRIPTIONS[availableItem.id];\n\t\t\t}\n\t\t\titems.push({\n\t\t\t\tid: availableItem.id,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tpath: availableItem.path,\n\t\t\t\tdescription: desc,\n\t\t\t\tsourceLabel: classifyResourceSource(\n\t\t\t\t\tavailableItem.path,\n\t\t\t\t\tthis.cwd,\n\t\t\t\t\tthis.agentDir,\n\t\t\t\t\tthis.externalResourceRoots,\n\t\t\t\t),\n\t\t\t\tisMissing: false,\n\t\t\t});\n\t\t}\n\n\t\t// Add missing items\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tfor (const missingId of missingSet) {\n\t\t\tconst isEnabled = enabledSet.has(missingId);\n\t\t\titems.push({\n\t\t\t\tid: missingId,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tisMissing: true,\n\t\t\t\tdescription: \"Referenced in profile but missing from available resources.\",\n\t\t\t});\n\t\t}\n\n\t\t// Sort: enabled first, then disabled\n\t\tconst enabled: ResourceItem[] = [];\n\t\tconst disabled: ResourceItem[] = [];\n\t\tfor (const item of items) {\n\t\t\tif (item.enabled) {\n\t\t\t\tenabled.push(item);\n\t\t\t} else {\n\t\t\t\tdisabled.push(item);\n\t\t\t}\n\t\t}\n\t\treturn [...enabled, ...disabled];\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled`;\n\t\tconst parts = [\n\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t`${keyText(\"tui.input.tab\")} kind`,\n\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t`${theme.fg(\"accent\", \"e\")} edit`,\n\t\t\t`${theme.fg(\"accent\", \"Ctrl+Q\")}/${keyText(\"app.interrupt\")} cancel`,\n\t\t\tcountText,\n\t\t];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.id} ${i.description ?? \"\"}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst kind = this.getCurrentKind();\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tconst totalAvailableCount = kind.items.length + missingSet.size;\n\n\t\tif (totalAvailableCount === 0) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", \" (none available — add a Source or install resources)\"), 0, 0),\n\t\t\t);\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching resources\"), 0, 0));\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlet resourceText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\n\t\t\tif (item.isMissing) {\n\t\t\t\tresourceText = theme.fg(\"muted\", `${item.id} [missing]`);\n\t\t\t} else if (item.sourceLabel) {\n\t\t\t\tconst labelColor =\n\t\t\t\t\titem.sourceLabel === \"catalog\"\n\t\t\t\t\t\t? \"thinkingText\"\n\t\t\t\t\t\t: item.sourceLabel === \"project\"\n\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t: item.sourceLabel === \"user\"\n\t\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t\t: \"muted\";\n\t\t\t\tconst labelText = theme.fg(labelColor, ` [${item.sourceLabel}]`);\n\t\t\t\tresourceText = `${resourceText}${labelText}`;\n\t\t\t}\n\n\t\t\tconst status = item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${resourceText}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\t// Update description area for current selection\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem?.description) {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", ` Description: ${selectedItem.description}`));\n\t\t} else {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation within list\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch kind with Tab (cycles forward)\n\t\tif (kb.matches(data, \"tui.input.tab\")) {\n\t\t\tthis.currentKindIndex = (this.currentKindIndex + 1) % this.kinds.length;\n\t\t\tthis.selectedIndex = 0;\n\t\t\tthis.searchInput.setValue(\"\");\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Allow-list\n\t\tif (matchesKey(data, Key.ctrl(\"a\")) || (this.searchInput.getValue() === \"\" && data === \"a\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"allow\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Block-list\n\t\tif (matchesKey(data, Key.ctrl(\"b\")) || (this.searchInput.getValue() === \"\" && data === \"b\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"block\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Edit highlighted resource\n\t\tif (data === \"e\" && this.searchInput.getValue() === \"\") {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && !item.isMissing && item.path) {\n\t\t\t\tconst kind = this.getCurrentKind().kind;\n\t\t\t\tif (this.onEdit) {\n\t\t\t\t\tthis.onEdit(item.id, item.path, kind);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch scope: Scope selector\n\t\tif (matchesKey(data, Key.ctrl(\"o\")) || (this.searchInput.getValue() === \"\" && data === \"s\")) {\n\t\t\tif (this.onScopeChange) {\n\t\t\t\tthis.onScopeChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on space/enter\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\t\t\tif (enabledSet.has(item.id)) {\n\t\t\t\t\tenabledSet.delete(item.id);\n\t\t\t\t} else {\n\t\t\t\t\tenabledSet.add(item.id);\n\t\t\t\t}\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Save/persist to settings\n\t\tif (kb.matches(data, \"app.models.save\")) {\n\t\t\tthis.persistChanges();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape / Ctrl+Q - cancel (unconditional)\n\t\tif (\n\t\t\tkb.matches(data, \"app.interrupt\") ||\n\t\t\tmatchesKey(data, Key.escape) ||\n\t\t\tmatchesKey(data, Key.esc) ||\n\t\t\tmatchesKey(data, \"ctrl+q\")\n\t\t) {\n\t\t\tthis.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tprivate persistChanges(): void {\n\t\tconst resources: ResourceProfileSettings = {};\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\t\t// Persist against the same widened universe used at decode time: profile-referenced\n\t\t\t// ids that are not currently discoverable must survive a save untouched.\n\t\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) ?? new Set<string>();\n\t\t\tconst allIds = [...new Set([...kind.items.map((item) => item.id), ...missingSet])];\n\t\t\tconst encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing);\n\t\t\tif (encoded !== undefined) {\n\t\t\t\tresources[kind.kind] = encoded;\n\t\t\t}\n\t\t}\n\t\tthis.onSave(resources);\n\t\tthis.isDirty = false;\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
1
+ {"version":3,"file":"profile-resource-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/profile-resource-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@caupulican/pi-tui\";\nimport {\n\tdecodeResourceSelection,\n\tdetectResourceFraming,\n\tencodeResourceSelectionWithFraming,\n\ttype ResourceFraming,\n} from \"../../../core/profile-resource-selection.ts\";\nimport type {\n\tResourceProfileFilterSettings,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n} from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport interface ProfileResourceItem {\n\tid: string;\n\tpath?: string;\n\tdescription?: string;\n}\n\nexport interface ProfileResourceEditorKind {\n\tkind: ResourceProfileKind; // \"tools\" | \"skills\" | \"extensions\" | \"agents\" | \"prompts\" | \"themes\"\n\tlabel: string; // display label, e.g. \"Tools\"\n\titems: ProfileResourceItem[]; // the available items of this kind\n}\n\nexport interface ProfileResourceEditorOptions {\n\tprofileName: string;\n\tprofileScope: string; // e.g. \"directory\" | \"project\" | \"global\" | \"session\" | \"reusable-file\"\n\tinitialResources: ResourceProfileSettings; // existing profile.resources; may be {}\n\tkinds: ProfileResourceEditorKind[]; // the six kinds, with their universes\n\tonSave: (resources: ResourceProfileSettings) => void; // called on ctrl+s with the encoded result\n\tonCancel: () => void; // called on esc\n\tonScopeChange?: () => void;\n\tonEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\tcwd?: string;\n\tagentDir?: string;\n\texternalResourceRoots?: string[];\n}\n\ninterface ResourceItem {\n\tid: string;\n\tenabled: boolean;\n\tpath?: string;\n\tdescription?: string;\n\tsourceLabel?: \"catalog\" | \"user\" | \"project\" | \"bundled\";\n\tisMissing?: boolean;\n}\n\nconst TOOL_DESCRIPTIONS: Record<string, string> = {\n\tread: \"Read files from the filesystem.\",\n\tbash: \"Execute arbitrary commands in the shell.\",\n\tedit: \"Edit files surgically.\",\n\twrite: \"Create new files or overwrite existing files.\",\n\tgrep: \"Search for text patterns using ripgrep.\",\n\tfind: \"Locate files matching a search query.\",\n\tls: \"List files and directories.\",\n\tskill_audit: \"Inspect and audit local skills.\",\n\tskillify: \"Convert a set of files/instructions into a skill.\",\n\textensionify: \"Package a tool or script as an extension.\",\n};\n\nexport function resolveResourceEditPath(\n\t_id: string,\n\tfilePath: string | undefined,\n\tkind: ResourceProfileKind,\n): string | undefined {\n\tif (kind === \"tools\") {\n\t\treturn undefined;\n\t}\n\n\tif (!filePath) {\n\t\treturn undefined;\n\t}\n\n\tif (kind === \"extensions\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst indexTs = path.join(filePath, \"index.ts\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\treturn indexTs;\n\t\t\t\t}\n\t\t\t\tconst indexJs = path.join(filePath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexJs)) {\n\t\t\t\t\treturn indexJs;\n\t\t\t\t}\n\t\t\t\tconst pkgJsonPath = path.join(filePath, \"package.json\");\n\t\t\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pkg = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\t\t\t\t\t\tif (typeof pkg.main === \"string\") {\n\t\t\t\t\t\t\tconst resolvedMain = path.resolve(filePath, pkg.main);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedMain)) {\n\t\t\t\t\t\t\t\treturn resolvedMain;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\treturn indexTs;\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\tif (kind === \"skills\") {\n\t\ttry {\n\t\t\tconst stats = fs.statSync(filePath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tconst skillMd = path.join(filePath, \"SKILL.md\");\n\t\t\t\tif (fs.existsSync(skillMd)) {\n\t\t\t\t\treturn skillMd;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {}\n\t\treturn filePath;\n\t}\n\n\treturn filePath;\n}\n\nexport function classifyResourceSource(\n\tfilePath: string | undefined,\n\tcwd: string,\n\tagentDir: string,\n\texternalRoots: string[],\n): \"catalog\" | \"user\" | \"project\" | \"bundled\" {\n\tif (!filePath) {\n\t\treturn \"bundled\";\n\t}\n\n\tconst absolutePath = isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n\tconst normPath = resolve(absolutePath);\n\tconst normCwd = resolve(cwd);\n\tconst normAgentDir = agentDir ? resolve(agentDir) : \"\";\n\n\tfor (const extRoot of externalRoots) {\n\t\tconst normExt = resolve(extRoot);\n\t\tif (normPath.startsWith(normExt)) {\n\t\t\treturn \"catalog\";\n\t\t}\n\t}\n\n\tif (normAgentDir && normPath.startsWith(normAgentDir)) {\n\t\treturn \"user\";\n\t}\n\n\tif (normPath.startsWith(normCwd)) {\n\t\treturn \"project\";\n\t}\n\n\tif (normPath.includes(\"node_modules\")) {\n\t\treturn \"bundled\";\n\t}\n\n\treturn \"bundled\";\n}\n\nexport class ProfileResourceEditorComponent extends Container implements Focusable {\n\tprivate profileName: string;\n\tprivate profileScope: string;\n\tprivate kinds: ProfileResourceEditorKind[];\n\tprivate enabledByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\tprivate framingByKind: Map<ResourceProfileKind, ResourceFraming> = new Map();\n\tprivate missingIdsByKind: Map<ResourceProfileKind, Set<string>> = new Map();\n\t/** The filter each kind was decoded from, so an all-enabled save preserves an enumerated grant\n\t * (or an already-wildcard grant) instead of widening it to allow:[\"*\"]. */\n\tprivate originalFilterByKind: Map<ResourceProfileKind, ResourceProfileFilterSettings | undefined> = new Map();\n\tprivate currentKindIndex = 0;\n\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate externalResourceRoots: string[];\n\n\tprivate filteredItems: ResourceItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\tprivate kindHeaderText: Text;\n\tprivate listContainer: Container;\n\tprivate descriptionText: Text;\n\tprivate footerText: Text;\n\tprivate isDirty = false;\n\tprivate maxVisible = 8;\n\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate onSave: (resources: ResourceProfileSettings) => void;\n\tprivate onCancel: () => void;\n\tprivate onScopeChange?: () => void;\n\tprivate onEdit?: (id: string, path: string, kind: ResourceProfileKind) => void;\n\n\tconstructor(options: ProfileResourceEditorOptions) {\n\t\tsuper();\n\t\tthis.profileName = options.profileName;\n\t\tthis.profileScope = options.profileScope;\n\t\tthis.kinds = options.kinds;\n\t\tthis.onSave = options.onSave;\n\t\tthis.onCancel = options.onCancel;\n\t\tthis.onScopeChange = options.onScopeChange;\n\t\tthis.onEdit = options.onEdit;\n\t\tthis.cwd = options.cwd || process.cwd();\n\t\tthis.agentDir = options.agentDir || \"\";\n\t\tthis.externalResourceRoots = options.externalResourceRoots || [];\n\n\t\t// Initialize enabled, framing, and missing sets for each kind\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst filter = options.initialResources[kind.kind];\n\t\t\tconst allIds = kind.items.map((item) => item.id);\n\n\t\t\t// Compute missing items\n\t\t\tconst mentionedIds = new Set<string>();\n\t\t\tif (filter) {\n\t\t\t\tif (filter.allow) {\n\t\t\t\t\tfor (const id of filter.allow) {\n\t\t\t\t\t\t// \"*\" is a grant-all framing marker, not a resource id — the block loop below\n\t\t\t\t\t\t// already excludes it; the allow loop must too, or it leaks into missingSet as\n\t\t\t\t\t\t// a fake \"missing item\" and rides along as a phantom enabled member through\n\t\t\t\t\t\t// decode/encode.\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (filter.block) {\n\t\t\t\t\tfor (const id of filter.block) {\n\t\t\t\t\t\tif (id !== \"*\") {\n\t\t\t\t\t\t\tmentionedIds.add(id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst availableIds = new Set(allIds);\n\t\t\tconst missingSet = new Set<string>();\n\t\t\tfor (const id of mentionedIds) {\n\t\t\t\tif (!availableIds.has(id)) {\n\t\t\t\t\tmissingSet.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.missingIdsByKind.set(kind.kind, missingSet);\n\n\t\t\t// Decode against the DISCOVERABLE universe plus every id the profile itself mentions:\n\t\t\t// decoding only against the discoverable set silently drops grants for anything the\n\t\t\t// current environment cannot see (offline external root, or a collapsed universe),\n\t\t\t// and the next save would then corrupt the profile.\n\t\t\tconst enabledSet = decodeResourceSelection(filter, [...allIds, ...missingSet]);\n\t\t\tthis.enabledByKind.set(kind.kind, enabledSet);\n\t\t\tthis.framingByKind.set(kind.kind, detectResourceFraming(filter));\n\t\t\tthis.originalFilterByKind.set(kind.kind, filter);\n\t\t}\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"accent\", theme.bold(`Library — editing \"${this.profileName}\" (${this.profileScope})`)),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Navigate kinds: ${keyText(\"tui.input.tab\")}. Toggle: ${keyText(\"tui.select.confirm\")}. Mode: ${theme.fg(\"accent\", \"a\")} allow / ${theme.fg(\"accent\", \"b\")} block. Scope: ${theme.fg(\"accent\", \"s\")} change. Edit: ${theme.fg(\"accent\", \"e\")}.`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Kind selector header\n\t\tthis.kindHeaderText = new Text(this.getKindHeaderText(), 0, 0);\n\t\tthis.addChild(this.kindHeaderText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Description area\n\t\tthis.descriptionText = new Text(\"\", 0, 0);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.descriptionText);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.refresh();\n\t}\n\n\tprivate getKindHeaderText(): string {\n\t\tconst kind = this.kinds[this.currentKindIndex]!;\n\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\tconst framingText = framing === \"allow\" ? \"allow-list\" : \"block-list\";\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled (${framingText})`;\n\t\tconst kindIndicator = this.kinds\n\t\t\t.map((k, i) => {\n\t\t\t\tconst marker = i === this.currentKindIndex ? \"●\" : \"○\";\n\t\t\t\treturn theme.fg(i === this.currentKindIndex ? \"accent\" : \"muted\", `${marker} ${k.label}`);\n\t\t\t})\n\t\t\t.join(\" \");\n\t\treturn `${kindIndicator} ${theme.fg(\"muted\", countText)}`;\n\t}\n\n\tprivate getCurrentKind(): ProfileResourceEditorKind {\n\t\treturn this.kinds[this.currentKindIndex]!;\n\t}\n\n\tprivate getCurrentEnabledSet(): Set<string> {\n\t\tconst kind = this.getCurrentKind();\n\t\treturn this.enabledByKind.get(kind.kind)!;\n\t}\n\n\tprivate buildItems(): ResourceItem[] {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\n\t\tconst items: ResourceItem[] = [];\n\n\t\t// Add all available items\n\t\tfor (const availableItem of kind.items) {\n\t\t\tconst isEnabled = enabledSet.has(availableItem.id);\n\t\t\tlet desc = availableItem.description;\n\t\t\tif (kind.kind === \"tools\" && !desc) {\n\t\t\t\tdesc = TOOL_DESCRIPTIONS[availableItem.id];\n\t\t\t}\n\t\t\titems.push({\n\t\t\t\tid: availableItem.id,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tpath: availableItem.path,\n\t\t\t\tdescription: desc,\n\t\t\t\tsourceLabel: classifyResourceSource(\n\t\t\t\t\tavailableItem.path,\n\t\t\t\t\tthis.cwd,\n\t\t\t\t\tthis.agentDir,\n\t\t\t\t\tthis.externalResourceRoots,\n\t\t\t\t),\n\t\t\t\tisMissing: false,\n\t\t\t});\n\t\t}\n\n\t\t// Add missing items\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tfor (const missingId of missingSet) {\n\t\t\tconst isEnabled = enabledSet.has(missingId);\n\t\t\titems.push({\n\t\t\t\tid: missingId,\n\t\t\t\tenabled: isEnabled,\n\t\t\t\tisMissing: true,\n\t\t\t\tdescription: \"Referenced in profile but missing from available resources.\",\n\t\t\t});\n\t\t}\n\n\t\t// Sort: enabled first, then disabled\n\t\tconst enabled: ResourceItem[] = [];\n\t\tconst disabled: ResourceItem[] = [];\n\t\tfor (const item of items) {\n\t\t\tif (item.enabled) {\n\t\t\t\tenabled.push(item);\n\t\t\t} else {\n\t\t\t\tdisabled.push(item);\n\t\t\t}\n\t\t}\n\t\treturn [...enabled, ...disabled];\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst kind = this.getCurrentKind();\n\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\tconst countText = `${enabledSet.size}/${kind.items.length} enabled`;\n\t\tconst parts = [\n\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t`${keyText(\"tui.input.tab\")} kind`,\n\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t`${theme.fg(\"accent\", \"e\")} edit`,\n\t\t\t`${theme.fg(\"accent\", \"Ctrl+Q\")}/${keyText(\"app.interrupt\")} cancel`,\n\t\t\tcountText,\n\t\t];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.id} ${i.description ?? \"\"}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst kind = this.getCurrentKind();\n\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) || new Set<string>();\n\t\tconst totalAvailableCount = kind.items.length + missingSet.size;\n\n\t\tif (totalAvailableCount === 0) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", \" (none available — add a Source or install resources)\"), 0, 0),\n\t\t\t);\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching resources\"), 0, 0));\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlet resourceText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\n\t\t\tif (item.isMissing) {\n\t\t\t\tresourceText = theme.fg(\"muted\", `${item.id} [missing]`);\n\t\t\t} else if (item.sourceLabel) {\n\t\t\t\tconst labelColor =\n\t\t\t\t\titem.sourceLabel === \"catalog\"\n\t\t\t\t\t\t? \"thinkingText\"\n\t\t\t\t\t\t: item.sourceLabel === \"project\"\n\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t: item.sourceLabel === \"user\"\n\t\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t\t: \"muted\";\n\t\t\t\tconst labelText = theme.fg(labelColor, ` [${item.sourceLabel}]`);\n\t\t\t\tresourceText = `${resourceText}${labelText}`;\n\t\t\t}\n\n\t\t\tconst status = item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${resourceText}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\t// Update description area for current selection\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem?.description) {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", ` Description: ${selectedItem.description}`));\n\t\t} else {\n\t\t\tthis.descriptionText.setText(theme.fg(\"muted\", \" No description available\"));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation within list\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch kind with Tab (cycles forward)\n\t\tif (kb.matches(data, \"tui.input.tab\")) {\n\t\t\tthis.currentKindIndex = (this.currentKindIndex + 1) % this.kinds.length;\n\t\t\tthis.selectedIndex = 0;\n\t\t\tthis.searchInput.setValue(\"\");\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Allow-list\n\t\tif (matchesKey(data, Key.ctrl(\"a\")) || (this.searchInput.getValue() === \"\" && data === \"a\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"allow\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch framing: Block-list\n\t\tif (matchesKey(data, Key.ctrl(\"b\")) || (this.searchInput.getValue() === \"\" && data === \"b\")) {\n\t\t\tthis.framingByKind.set(this.getCurrentKind().kind, \"block\");\n\t\t\tthis.isDirty = true;\n\t\t\tthis.kindHeaderText.setText(this.getKindHeaderText());\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Edit highlighted resource\n\t\tif (data === \"e\" && this.searchInput.getValue() === \"\") {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && !item.isMissing && item.path) {\n\t\t\t\tconst kind = this.getCurrentKind().kind;\n\t\t\t\tif (this.onEdit) {\n\t\t\t\t\tthis.onEdit(item.id, item.path, kind);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Switch scope: Scope selector\n\t\tif (matchesKey(data, Key.ctrl(\"o\")) || (this.searchInput.getValue() === \"\" && data === \"s\")) {\n\t\t\tif (this.onScopeChange) {\n\t\t\t\tthis.onScopeChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on space/enter\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst enabledSet = this.getCurrentEnabledSet();\n\t\t\t\tif (enabledSet.has(item.id)) {\n\t\t\t\t\tenabledSet.delete(item.id);\n\t\t\t\t} else {\n\t\t\t\t\tenabledSet.add(item.id);\n\t\t\t\t}\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Save/persist to settings\n\t\tif (kb.matches(data, \"app.models.save\")) {\n\t\t\tthis.persistChanges();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape / Ctrl+Q - cancel (unconditional)\n\t\tif (\n\t\t\tkb.matches(data, \"app.interrupt\") ||\n\t\t\tmatchesKey(data, Key.escape) ||\n\t\t\tmatchesKey(data, Key.esc) ||\n\t\t\tmatchesKey(data, \"ctrl+q\")\n\t\t) {\n\t\t\tthis.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tprivate persistChanges(): void {\n\t\tconst resources: ResourceProfileSettings = {};\n\t\tfor (const kind of this.kinds) {\n\t\t\tconst enabledSet = this.enabledByKind.get(kind.kind)!;\n\t\t\tconst framing = this.framingByKind.get(kind.kind)!;\n\t\t\t// Persist against the same widened universe used at decode time: profile-referenced\n\t\t\t// ids that are not currently discoverable must survive a save untouched.\n\t\t\tconst missingSet = this.missingIdsByKind.get(kind.kind) ?? new Set<string>();\n\t\t\tconst allIds = [...new Set([...kind.items.map((item) => item.id), ...missingSet])];\n\t\t\t// Pass the original filter so an all-enabled save preserves an enumerated grant (and only\n\t\t\t// keeps a wildcard when the grant was already a wildcard) — never widening it silently.\n\t\t\tconst encoded = encodeResourceSelectionWithFraming(enabledSet, allIds, framing, {\n\t\t\t\toriginalFilter: this.originalFilterByKind.get(kind.kind),\n\t\t\t});\n\t\t\tif (encoded !== undefined) {\n\t\t\t\tresources[kind.kind] = encoded;\n\t\t\t}\n\t\t}\n\t\tthis.onSave(resources);\n\t\tthis.isDirty = false;\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}