@dev-sergeev/datalab-kit 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +23 -5
- package/THIRD_PARTY_NOTICES.md +6 -2
- package/dist/extension.js +8 -1
- package/dist/recap.d.ts +2 -0
- package/dist/recap.js +31 -0
- package/docs/adr/0002-package-delivery.md +2 -0
- package/node_modules/@pi-plugins/elapsed/LICENSE +21 -0
- package/node_modules/@pi-plugins/elapsed/README.md +45 -0
- package/node_modules/@pi-plugins/elapsed/dist/index.d.mts +8 -0
- package/node_modules/@pi-plugins/elapsed/dist/index.d.mts.map +1 -0
- package/node_modules/@pi-plugins/elapsed/dist/index.mjs +47 -0
- package/node_modules/@pi-plugins/elapsed/dist/index.mjs.map +1 -0
- package/node_modules/@pi-plugins/elapsed/package.json +65 -0
- package/node_modules/@tifan/pi-recap/README.md +61 -0
- package/node_modules/@tifan/pi-recap/package.json +43 -0
- package/node_modules/@tifan/pi-recap/src/index.ts +584 -0
- package/node_modules/@tifan/pi-recap/src/model-picker.ts +233 -0
- package/node_modules/@tifan/pi-recap/src/models.ts +183 -0
- package/node_modules/@tifan/pi-recap/src/sanitize.ts +119 -0
- package/node_modules/@tifan/pi-recap/src/tui.ts +155 -0
- package/node_modules/@zigai/pi-extension-internals/README.md +24 -0
- package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.d.ts +21 -0
- package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.js +233 -0
- package/node_modules/@zigai/pi-extension-internals/dist/index.d.ts +6 -0
- package/node_modules/@zigai/pi-extension-internals/dist/index.js +3 -0
- package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.d.ts +34 -0
- package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.js +272 -0
- package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.d.ts +11 -0
- package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.js +139 -0
- package/node_modules/@zigai/pi-extension-internals/package.json +41 -0
- package/node_modules/@zigai/pi-extension-settings/LICENSE +21 -0
- package/node_modules/@zigai/pi-extension-settings/README.md +36 -0
- package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts +23 -0
- package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js +75 -0
- package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts +3 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js +5 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts +6 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli.js +87 -0
- package/node_modules/@zigai/pi-extension-settings/dist/cli.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts +2 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js +2 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts +159 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition.js +248 -0
- package/node_modules/@zigai/pi-extension-settings/dist/definition.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts +10 -0
- package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/file-system.js +115 -0
- package/node_modules/@zigai/pi-extension-settings/dist/file-system.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts +2 -0
- package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/index.js +2 -0
- package/node_modules/@zigai/pi-extension-settings/dist/index.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts +18 -0
- package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/json-value.js +56 -0
- package/node_modules/@zigai/pi-extension-settings/dist/json-value.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts +11 -0
- package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/paths.js +23 -0
- package/node_modules/@zigai/pi-extension-settings/dist/paths.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts +5 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js +21 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts +106 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.js +122 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.ts +2537 -0
- package/node_modules/@zigai/pi-extension-settings/dist/pi.ts.map +7 -0
- package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts +10 -0
- package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/projects.js +177 -0
- package/node_modules/@zigai/pi-extension-settings/dist/projects.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts +40 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.js +158 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts +158 -0
- package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts.map +7 -0
- package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts +19 -0
- package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js +168 -0
- package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts +9 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js +242 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts +59 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js +98 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts +80 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js +144 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts +5 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js +30 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts +10 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js +16 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts +54 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js +202 -0
- package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts +5 -0
- package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js +9 -0
- package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js.map +1 -0
- package/node_modules/@zigai/pi-extension-settings/docs/generation.md +71 -0
- package/node_modules/@zigai/pi-extension-settings/docs/manual-setup.md +98 -0
- package/node_modules/@zigai/pi-extension-settings/docs/runtime.md +100 -0
- package/node_modules/@zigai/pi-extension-settings/docs/ui-controls.md +31 -0
- package/node_modules/@zigai/pi-extension-settings/package.json +97 -0
- package/node_modules/@zigai/pi-mention-anything/README.md +113 -0
- package/node_modules/@zigai/pi-mention-anything/config.schema.json +313 -0
- package/node_modules/@zigai/pi-mention-anything/docs/command-protocol.md +106 -0
- package/node_modules/@zigai/pi-mention-anything/docs/providers.md +128 -0
- package/node_modules/@zigai/pi-mention-anything/examples/query-command.mjs +96 -0
- package/node_modules/@zigai/pi-mention-anything/examples/recursive-tree.ts +28 -0
- package/node_modules/@zigai/pi-mention-anything/examples/static.ts +28 -0
- package/node_modules/@zigai/pi-mention-anything/examples/tmux.ts +90 -0
- package/node_modules/@zigai/pi-mention-anything/examples/tree-settings.json +25 -0
- package/node_modules/@zigai/pi-mention-anything/package.json +58 -0
- package/node_modules/@zigai/pi-mention-anything/src/api.ts +75 -0
- package/node_modules/@zigai/pi-mention-anything/src/autocomplete.ts +231 -0
- package/node_modules/@zigai/pi-mention-anything/src/chain-autocomplete.ts +596 -0
- package/node_modules/@zigai/pi-mention-anything/src/chain-syntax.ts +345 -0
- package/node_modules/@zigai/pi-mention-anything/src/command-provider.ts +291 -0
- package/node_modules/@zigai/pi-mention-anything/src/configured-source.ts +66 -0
- package/node_modules/@zigai/pi-mention-anything/src/editor.ts +180 -0
- package/node_modules/@zigai/pi-mention-anything/src/expand-mentions.ts +162 -0
- package/node_modules/@zigai/pi-mention-anything/src/index.ts +54 -0
- package/node_modules/@zigai/pi-mention-anything/src/initial-suggestions.ts +190 -0
- package/node_modules/@zigai/pi-mention-anything/src/list-provider.ts +71 -0
- package/node_modules/@zigai/pi-mention-anything/src/mention-hub.ts +307 -0
- package/node_modules/@zigai/pi-mention-anything/src/mention-resolution.ts +374 -0
- package/node_modules/@zigai/pi-mention-anything/src/mention-syntax.ts +105 -0
- package/node_modules/@zigai/pi-mention-anything/src/register-mention.ts +89 -0
- package/node_modules/@zigai/pi-mention-anything/src/rendering.ts +53 -0
- package/node_modules/@zigai/pi-mention-anything/src/selected-items.ts +21 -0
- package/node_modules/@zigai/pi-mention-anything/src/selection-history.ts +135 -0
- package/node_modules/@zigai/pi-mention-anything/src/settings-input.ts +317 -0
- package/node_modules/@zigai/pi-mention-anything/src/settings.prevalidated.ts +57 -0
- package/node_modules/@zigai/pi-mention-anything/src/settings.ts +52 -0
- package/node_modules/@zigai/pi-mention-anything/src/source-contract.ts +174 -0
- package/node_modules/@zigai/pi-mention-anything/src/source-controller.ts +1070 -0
- package/node_modules/@zigai/pi-mention-anything/src/source-runtime.ts +99 -0
- package/node_modules/@zigai/pi-mention-skill/README.md +60 -0
- package/node_modules/@zigai/pi-mention-skill/config.schema.json +81 -0
- package/node_modules/@zigai/pi-mention-skill/package.json +56 -0
- package/node_modules/@zigai/pi-mention-skill/src/index.ts +60 -0
- package/node_modules/@zigai/pi-mention-skill/src/settings-input.ts +74 -0
- package/node_modules/@zigai/pi-mention-skill/src/settings.prevalidated.ts +18 -0
- package/node_modules/@zigai/pi-mention-skill/src/settings.ts +54 -0
- package/node_modules/@zigai/pi-mention-skill/src/skill-commands.ts +18 -0
- package/node_modules/@zigai/pi-mention-skill/src/skill-content.ts +60 -0
- package/node_modules/@zigai/pi-mention-skill/src/skill-provider.ts +105 -0
- package/node_modules/@zigai/pi-mention-skill/src/slash-skill-filter.ts +29 -0
- package/node_modules/argparse/LICENSE +21 -0
- package/node_modules/argparse/README.md +257 -0
- package/node_modules/argparse/index.js +3 -0
- package/node_modules/argparse/lib/action/append/constant.js +47 -0
- package/node_modules/argparse/lib/action/append.js +53 -0
- package/node_modules/argparse/lib/action/count.js +40 -0
- package/node_modules/argparse/lib/action/help.js +47 -0
- package/node_modules/argparse/lib/action/store/constant.js +43 -0
- package/node_modules/argparse/lib/action/store/false.js +27 -0
- package/node_modules/argparse/lib/action/store/true.js +26 -0
- package/node_modules/argparse/lib/action/store.js +50 -0
- package/node_modules/argparse/lib/action/subparsers.js +149 -0
- package/node_modules/argparse/lib/action/version.js +47 -0
- package/node_modules/argparse/lib/action.js +146 -0
- package/node_modules/argparse/lib/action_container.js +482 -0
- package/node_modules/argparse/lib/argparse.js +14 -0
- package/node_modules/argparse/lib/argument/error.js +50 -0
- package/node_modules/argparse/lib/argument/exclusive.js +54 -0
- package/node_modules/argparse/lib/argument/group.js +75 -0
- package/node_modules/argparse/lib/argument_parser.js +1161 -0
- package/node_modules/argparse/lib/const.js +21 -0
- package/node_modules/argparse/lib/help/added_formatters.js +87 -0
- package/node_modules/argparse/lib/help/formatter.js +795 -0
- package/node_modules/argparse/lib/namespace.js +76 -0
- package/node_modules/argparse/lib/utils.js +57 -0
- package/node_modules/argparse/package.json +34 -0
- package/node_modules/esprima/LICENSE.BSD +21 -0
- package/node_modules/esprima/README.md +46 -0
- package/node_modules/esprima/bin/esparse.js +139 -0
- package/node_modules/esprima/bin/esvalidate.js +236 -0
- package/node_modules/esprima/dist/esprima.js +6709 -0
- package/node_modules/esprima/package.json +112 -0
- package/node_modules/extend-shallow/LICENSE +21 -0
- package/node_modules/extend-shallow/README.md +61 -0
- package/node_modules/extend-shallow/index.js +33 -0
- package/node_modules/extend-shallow/package.json +56 -0
- package/node_modules/graceful-fs/LICENSE +15 -0
- package/node_modules/graceful-fs/README.md +143 -0
- package/node_modules/graceful-fs/clone.js +23 -0
- package/node_modules/graceful-fs/graceful-fs.js +448 -0
- package/node_modules/graceful-fs/legacy-streams.js +118 -0
- package/node_modules/graceful-fs/package.json +53 -0
- package/node_modules/graceful-fs/polyfills.js +355 -0
- package/node_modules/gray-matter/LICENSE +21 -0
- package/node_modules/gray-matter/README.md +565 -0
- package/node_modules/gray-matter/gray-matter.d.ts +114 -0
- package/node_modules/gray-matter/index.js +228 -0
- package/node_modules/gray-matter/lib/defaults.js +18 -0
- package/node_modules/gray-matter/lib/engine.js +30 -0
- package/node_modules/gray-matter/lib/engines.js +54 -0
- package/node_modules/gray-matter/lib/excerpt.js +32 -0
- package/node_modules/gray-matter/lib/parse.js +13 -0
- package/node_modules/gray-matter/lib/stringify.js +56 -0
- package/node_modules/gray-matter/lib/to-file.js +43 -0
- package/node_modules/gray-matter/lib/utils.js +66 -0
- package/node_modules/gray-matter/package.json +127 -0
- package/node_modules/is-extendable/LICENSE +21 -0
- package/node_modules/is-extendable/README.md +72 -0
- package/node_modules/is-extendable/index.js +13 -0
- package/node_modules/is-extendable/package.json +51 -0
- package/node_modules/js-yaml/LICENSE +21 -0
- package/node_modules/js-yaml/README.md +302 -0
- package/node_modules/js-yaml/bin/js-yaml.js +132 -0
- package/node_modules/js-yaml/dist/js-yaml.js +4024 -0
- package/node_modules/js-yaml/dist/js-yaml.min.js +1 -0
- package/node_modules/js-yaml/index.js +7 -0
- package/node_modules/js-yaml/lib/js-yaml/common.js +59 -0
- package/node_modules/js-yaml/lib/js-yaml/dumper.js +850 -0
- package/node_modules/js-yaml/lib/js-yaml/exception.js +43 -0
- package/node_modules/js-yaml/lib/js-yaml/loader.js +1679 -0
- package/node_modules/js-yaml/lib/js-yaml/mark.js +76 -0
- package/node_modules/js-yaml/lib/js-yaml/schema/core.js +18 -0
- package/node_modules/js-yaml/lib/js-yaml/schema/default_full.js +25 -0
- package/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js +28 -0
- package/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js +17 -0
- package/node_modules/js-yaml/lib/js-yaml/schema/json.js +25 -0
- package/node_modules/js-yaml/lib/js-yaml/schema.js +108 -0
- package/node_modules/js-yaml/lib/js-yaml/type/binary.js +138 -0
- package/node_modules/js-yaml/lib/js-yaml/type/bool.js +35 -0
- package/node_modules/js-yaml/lib/js-yaml/type/float.js +116 -0
- package/node_modules/js-yaml/lib/js-yaml/type/int.js +173 -0
- package/node_modules/js-yaml/lib/js-yaml/type/js/function.js +93 -0
- package/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js +60 -0
- package/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js +28 -0
- package/node_modules/js-yaml/lib/js-yaml/type/map.js +8 -0
- package/node_modules/js-yaml/lib/js-yaml/type/merge.js +12 -0
- package/node_modules/js-yaml/lib/js-yaml/type/null.js +34 -0
- package/node_modules/js-yaml/lib/js-yaml/type/omap.js +44 -0
- package/node_modules/js-yaml/lib/js-yaml/type/pairs.js +53 -0
- package/node_modules/js-yaml/lib/js-yaml/type/seq.js +8 -0
- package/node_modules/js-yaml/lib/js-yaml/type/set.js +29 -0
- package/node_modules/js-yaml/lib/js-yaml/type/str.js +8 -0
- package/node_modules/js-yaml/lib/js-yaml/type/timestamp.js +88 -0
- package/node_modules/js-yaml/lib/js-yaml/type.js +61 -0
- package/node_modules/js-yaml/lib/js-yaml.js +39 -0
- package/node_modules/js-yaml/package.json +52 -0
- package/node_modules/kind-of/LICENSE +21 -0
- package/node_modules/kind-of/README.md +367 -0
- package/node_modules/kind-of/index.js +129 -0
- package/node_modules/kind-of/package.json +88 -0
- package/node_modules/pi-toggle-skills/README.md +213 -0
- package/node_modules/pi-toggle-skills/package.json +60 -0
- package/node_modules/pi-toggle-skills/src/index.ts +112 -0
- package/node_modules/pi-toggle-skills/src/skill-discovery.ts +258 -0
- package/node_modules/pi-toggle-skills/src/skill-selector.ts +435 -0
- package/node_modules/pi-toggle-skills/toggle-skills.ts +316 -0
- package/node_modules/pi-toggle-skills/vitest.config.ts +15 -0
- package/node_modules/proper-lockfile/LICENSE +21 -0
- package/node_modules/proper-lockfile/README.md +183 -0
- package/node_modules/proper-lockfile/index.js +40 -0
- package/node_modules/proper-lockfile/lib/adapter.js +85 -0
- package/node_modules/proper-lockfile/lib/lockfile.js +342 -0
- package/node_modules/proper-lockfile/lib/mtime-precision.js +55 -0
- package/node_modules/proper-lockfile/node_modules/retry/.npmignore +3 -0
- package/node_modules/proper-lockfile/node_modules/retry/.travis.yml +15 -0
- package/node_modules/proper-lockfile/node_modules/retry/License +21 -0
- package/node_modules/proper-lockfile/node_modules/retry/Makefile +18 -0
- package/node_modules/proper-lockfile/node_modules/retry/README.md +227 -0
- package/node_modules/proper-lockfile/node_modules/retry/equation.gif +0 -0
- package/node_modules/proper-lockfile/node_modules/retry/example/dns.js +31 -0
- package/node_modules/proper-lockfile/node_modules/retry/example/stop.js +40 -0
- package/node_modules/proper-lockfile/node_modules/retry/index.js +1 -0
- package/node_modules/proper-lockfile/node_modules/retry/lib/retry.js +100 -0
- package/node_modules/proper-lockfile/node_modules/retry/lib/retry_operation.js +158 -0
- package/node_modules/proper-lockfile/node_modules/retry/package.json +32 -0
- package/node_modules/proper-lockfile/node_modules/retry/test/common.js +10 -0
- package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-forever.js +24 -0
- package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-operation.js +258 -0
- package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-wrap.js +101 -0
- package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-timeouts.js +69 -0
- package/node_modules/proper-lockfile/package.json +71 -0
- package/node_modules/section-matter/LICENSE +21 -0
- package/node_modules/section-matter/README.md +236 -0
- package/node_modules/section-matter/index.js +136 -0
- package/node_modules/section-matter/package.json +55 -0
- package/node_modules/signal-exit/LICENSE.txt +16 -0
- package/node_modules/signal-exit/README.md +39 -0
- package/node_modules/signal-exit/index.js +202 -0
- package/node_modules/signal-exit/package.json +38 -0
- package/node_modules/signal-exit/signals.js +53 -0
- package/node_modules/sprintf-js/.npmignore +1 -0
- package/node_modules/sprintf-js/LICENSE +24 -0
- package/node_modules/sprintf-js/README.md +88 -0
- package/node_modules/sprintf-js/bower.json +14 -0
- package/node_modules/sprintf-js/demo/angular.html +20 -0
- package/node_modules/sprintf-js/dist/angular-sprintf.min.js +4 -0
- package/node_modules/sprintf-js/dist/angular-sprintf.min.js.map +1 -0
- package/node_modules/sprintf-js/dist/angular-sprintf.min.map +1 -0
- package/node_modules/sprintf-js/dist/sprintf.min.js +4 -0
- package/node_modules/sprintf-js/dist/sprintf.min.js.map +1 -0
- package/node_modules/sprintf-js/dist/sprintf.min.map +1 -0
- package/node_modules/sprintf-js/gruntfile.js +36 -0
- package/node_modules/sprintf-js/package.json +22 -0
- package/node_modules/sprintf-js/src/angular-sprintf.js +18 -0
- package/node_modules/sprintf-js/src/sprintf.js +208 -0
- package/node_modules/sprintf-js/test/test.js +82 -0
- package/node_modules/strip-bom-string/LICENSE +21 -0
- package/node_modules/strip-bom-string/README.md +66 -0
- package/node_modules/strip-bom-string/index.js +15 -0
- package/node_modules/strip-bom-string/package.json +60 -0
- package/package.json +13 -4
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill discovery and frontmatter manipulation for pi-toggle-skills.
|
|
3
|
+
*
|
|
4
|
+
* Scans the standard pi skill directories to find SKILL.md files,
|
|
5
|
+
* parses their YAML frontmatter, and provides safe round-trip editing
|
|
6
|
+
* via gray-matter.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type ToggleSkill,
|
|
11
|
+
DISABLE_MODEL_INVOCATION_KEY,
|
|
12
|
+
isDisabled,
|
|
13
|
+
deduplicateSkills,
|
|
14
|
+
} from "./index.js";
|
|
15
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import matter from "gray-matter";
|
|
17
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync, realpathSync } from "node:fs";
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
import { join, basename, dirname } from "node:path";
|
|
20
|
+
|
|
21
|
+
// Skill directories to scan (in priority order, matching pi's discovery)
|
|
22
|
+
|
|
23
|
+
function getGlobalPiSkillDirs(): string[] {
|
|
24
|
+
return [join(getAgentDir(), "skills")];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getGlobalAgentsSkillDirs(): string[] {
|
|
28
|
+
return [join(homedir(), ".agents", "skills")];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getProjectSkillDirs(cwd: string): string[] {
|
|
32
|
+
return [join(cwd, ".pi", "skills"), join(cwd, ".agents", "skills")];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Skill source identifier for diagnostics. */
|
|
36
|
+
type SkillSource = "global-pi" | "global-agents" | "project-pi" | "project-agents";
|
|
37
|
+
|
|
38
|
+
export interface SkillDir {
|
|
39
|
+
path: string;
|
|
40
|
+
source: SkillSource;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getAllSkillDirs(cwd: string): SkillDir[] {
|
|
44
|
+
const dirs: SkillDir[] = [];
|
|
45
|
+
|
|
46
|
+
for (const path of getGlobalPiSkillDirs()) {
|
|
47
|
+
dirs.push({ path, source: "global-pi" });
|
|
48
|
+
}
|
|
49
|
+
for (const path of getGlobalAgentsSkillDirs()) {
|
|
50
|
+
dirs.push({ path, source: "global-agents" });
|
|
51
|
+
}
|
|
52
|
+
for (const path of getProjectSkillDirs(cwd)) {
|
|
53
|
+
dirs.push({ path, source: "project-pi" });
|
|
54
|
+
}
|
|
55
|
+
// Deduplicate by resolved (real) path so that symlinked directories
|
|
56
|
+
// (e.g. ~/.agents/skills → ~/.pi/agent/skills) are not scanned twice.
|
|
57
|
+
const seen = new Set<string>();
|
|
58
|
+
return dirs.filter((d) => {
|
|
59
|
+
let resolved = d.path;
|
|
60
|
+
try { resolved = realpathSync(d.path); } catch { /* path doesn't exist yet */ }
|
|
61
|
+
if (seen.has(resolved)) return false;
|
|
62
|
+
seen.add(resolved);
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Options for discoverSkills. */
|
|
68
|
+
export interface DiscoverSkillsOptions {
|
|
69
|
+
/** If provided, override the skill directories to scan (for testing). */
|
|
70
|
+
skillDirs?: SkillDir[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Discover all skills across standard locations.
|
|
75
|
+
* Returns deduplicated skills (first found wins, matching pi's behavior).
|
|
76
|
+
*/
|
|
77
|
+
export function discoverSkills(cwd: string, options?: DiscoverSkillsOptions): ToggleSkill[] {
|
|
78
|
+
const allSkills: ToggleSkill[] = [];
|
|
79
|
+
const dirs = options?.skillDirs ?? getAllSkillDirs(cwd);
|
|
80
|
+
|
|
81
|
+
for (const dir of dirs) {
|
|
82
|
+
if (!existsSync(dir.path)) continue;
|
|
83
|
+
const skills = loadSkillsFromDir(dir.path, dir.source);
|
|
84
|
+
allSkills.push(...skills);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return deduplicateSkills(allSkills);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Load skills from a directory tree.
|
|
92
|
+
*
|
|
93
|
+
* Mirrors pi's discovery rules:
|
|
94
|
+
* - If a directory contains SKILL.md, treat it as a skill (don't recurse further)
|
|
95
|
+
* - Otherwise, load direct .md children in the root
|
|
96
|
+
* - Recurse into subdirectories to find SKILL.md
|
|
97
|
+
*/
|
|
98
|
+
function loadSkillsFromDir(dir: string, source: SkillSource): ToggleSkill[] {
|
|
99
|
+
const skills: ToggleSkill[] = [];
|
|
100
|
+
|
|
101
|
+
if (!existsSync(dir)) return skills;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
105
|
+
|
|
106
|
+
// Check for SKILL.md in this directory
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
if (entry.name !== "SKILL.md") continue;
|
|
109
|
+
|
|
110
|
+
const fullPath = join(dir, entry.name);
|
|
111
|
+
const skill = loadSkillFromFile(fullPath);
|
|
112
|
+
if (skill) skills.push(skill);
|
|
113
|
+
|
|
114
|
+
// SKILL.md found — don't look for other .md files or recurse
|
|
115
|
+
return skills;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// No SKILL.md — check root .md files (only in .pi/skills/ and ~/.pi/agent/skills/)
|
|
119
|
+
const isDiscoverableRoot = source === "global-pi" || source === "project-pi";
|
|
120
|
+
if (isDiscoverableRoot) {
|
|
121
|
+
for (const entry of entries) {
|
|
122
|
+
if (entry.name.startsWith(".")) continue;
|
|
123
|
+
if (entry.name === "node_modules") continue;
|
|
124
|
+
if (!entry.name.endsWith(".md")) continue;
|
|
125
|
+
|
|
126
|
+
const fullPath = join(dir, entry.name);
|
|
127
|
+
let isFile = entry.isFile();
|
|
128
|
+
if (entry.isSymbolicLink()) {
|
|
129
|
+
try { isFile = statSync(fullPath).isFile(); } catch { continue; }
|
|
130
|
+
}
|
|
131
|
+
if (!isFile) continue;
|
|
132
|
+
|
|
133
|
+
const skill = loadSkillFromFile(fullPath);
|
|
134
|
+
if (skill) skills.push(skill);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Recurse into subdirectories
|
|
139
|
+
for (const entry of entries) {
|
|
140
|
+
if (entry.name.startsWith(".")) continue;
|
|
141
|
+
if (entry.name === "node_modules") continue;
|
|
142
|
+
|
|
143
|
+
const fullPath = join(dir, entry.name);
|
|
144
|
+
let isDirectory = entry.isDirectory();
|
|
145
|
+
|
|
146
|
+
if (entry.isSymbolicLink()) {
|
|
147
|
+
try { isDirectory = statSync(fullPath).isDirectory(); } catch { continue; }
|
|
148
|
+
}
|
|
149
|
+
if (!isDirectory) continue;
|
|
150
|
+
|
|
151
|
+
const subSkills = loadSkillsFromDir(fullPath, source);
|
|
152
|
+
skills.push(...subSkills);
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
// Permission errors, etc. — skip silently.
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return skills;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Load a single skill from a SKILL.md (or root .md) file.
|
|
163
|
+
* Returns null if the file can't be parsed or is missing a description.
|
|
164
|
+
*/
|
|
165
|
+
function loadSkillFromFile(filePath: string): ToggleSkill | null {
|
|
166
|
+
try {
|
|
167
|
+
const rawContent = readFileSync(filePath, "utf8");
|
|
168
|
+
const { data: frontmatter } = parseFrontmatter(rawContent);
|
|
169
|
+
const skillDir = dirname(filePath);
|
|
170
|
+
const parentDirName = basename(skillDir);
|
|
171
|
+
|
|
172
|
+
const name = (frontmatter.name as string) || parentDirName;
|
|
173
|
+
const description = frontmatter.description as string;
|
|
174
|
+
|
|
175
|
+
// Skills without description are not loaded by pi — skip them
|
|
176
|
+
if (!description || description.trim() === "") return null;
|
|
177
|
+
|
|
178
|
+
// Resolve symlinks so that the same physical SKILL.md reached via
|
|
179
|
+
// different alias paths (e.g. ~/.agents/skills/x vs ~/.pi/agent/skills/x)
|
|
180
|
+
// gets the same filePath and is correctly deduplicated.
|
|
181
|
+
let realFilePath = filePath;
|
|
182
|
+
try { realFilePath = realpathSync(filePath); } catch { /* keep as-is */ }
|
|
183
|
+
const realBaseDir = dirname(realFilePath);
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
name,
|
|
187
|
+
description,
|
|
188
|
+
filePath: realFilePath,
|
|
189
|
+
baseDir: realBaseDir,
|
|
190
|
+
disabled: isDisabled(frontmatter),
|
|
191
|
+
};
|
|
192
|
+
} catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parse YAML frontmatter from a string using gray-matter.
|
|
199
|
+
*/
|
|
200
|
+
export function parseFrontmatter(content: string): { data: Record<string, unknown>; content: string } {
|
|
201
|
+
const parsed = matter(content);
|
|
202
|
+
return { data: parsed.data as Record<string, unknown>, content: parsed.content };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Toggle disable-model-invocation in a SKILL.md file.
|
|
207
|
+
*
|
|
208
|
+
* When disabling: sets `disable-model-invocation: true`
|
|
209
|
+
* When enabling: removes the key entirely (false is the default)
|
|
210
|
+
*
|
|
211
|
+
* Returns true if the file was written, false on error.
|
|
212
|
+
*/
|
|
213
|
+
export function toggleSkillInvocation(filePath: string, disabled: boolean): boolean {
|
|
214
|
+
try {
|
|
215
|
+
const rawContent = readFileSync(filePath, "utf8");
|
|
216
|
+
const parsed = matter(rawContent);
|
|
217
|
+
|
|
218
|
+
if (disabled) {
|
|
219
|
+
parsed.data[DISABLE_MODEL_INVOCATION_KEY] = true;
|
|
220
|
+
} else {
|
|
221
|
+
// Remove the key when enabling (false is the default / absent state)
|
|
222
|
+
delete parsed.data[DISABLE_MODEL_INVOCATION_KEY];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const output = matter.stringify(parsed.content, parsed.data);
|
|
226
|
+
writeFileSync(filePath, output, "utf8");
|
|
227
|
+
return true;
|
|
228
|
+
} catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Apply a batch of toggle changes to disk.
|
|
235
|
+
* Returns the list of filePaths that were successfully written.
|
|
236
|
+
*/
|
|
237
|
+
export function applyChanges(
|
|
238
|
+
skills: ReadonlyArray<ToggleSkill>,
|
|
239
|
+
changes: ReadonlyArray<{ filePath: string; newDisabled: boolean }>,
|
|
240
|
+
): string[] {
|
|
241
|
+
const written: string[] = [];
|
|
242
|
+
const skillsByPath = new Map<string, ToggleSkill>();
|
|
243
|
+
for (const skill of skills) {
|
|
244
|
+
skillsByPath.set(skill.filePath, skill);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for (const change of changes) {
|
|
248
|
+
const skill = skillsByPath.get(change.filePath);
|
|
249
|
+
// Only write if the target state differs from what we last read
|
|
250
|
+
if (skill && skill.disabled !== change.newDisabled) {
|
|
251
|
+
if (toggleSkillInvocation(change.filePath, change.newDisabled)) {
|
|
252
|
+
written.push(change.filePath);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return written;
|
|
258
|
+
}
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToggleSkillSelectorComponent — an interactive TUI for toggling which
|
|
3
|
+
* skills are visible in pi's system prompt.
|
|
4
|
+
*
|
|
5
|
+
* Modeled after pi-hide-providers' HideProviderSelectorComponent:
|
|
6
|
+
* - Lists all discovered skills with their enabled/disabled status
|
|
7
|
+
* - Search/filter via Input component
|
|
8
|
+
* - Enter toggles disable-model-invocation for the selected skill
|
|
9
|
+
* - Ctrl+A / Ctrl+D bulk disable/enable (respects search filter)
|
|
10
|
+
* - Ctrl+S to save changes to disk and reload pi
|
|
11
|
+
* - Esc to cancel (discard in-memory toggles)
|
|
12
|
+
*
|
|
13
|
+
* Changes are collected in-memory and only written to disk on Ctrl+S.
|
|
14
|
+
* After writing, the user runs /reload so the skill list in the system prompt updates.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
Container,
|
|
19
|
+
type Component,
|
|
20
|
+
fuzzyFilter,
|
|
21
|
+
getKeybindings,
|
|
22
|
+
Input,
|
|
23
|
+
Key,
|
|
24
|
+
matchesKey,
|
|
25
|
+
Spacer,
|
|
26
|
+
Text,
|
|
27
|
+
truncateToWidth,
|
|
28
|
+
wrapTextWithAnsi,
|
|
29
|
+
} from "@earendil-works/pi-tui";
|
|
30
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
31
|
+
import { DynamicBorder, keyText } from "@earendil-works/pi-coding-agent";
|
|
32
|
+
import { type ToggleSkill, formatSkillStatus } from "./index.js";
|
|
33
|
+
|
|
34
|
+
interface DisplayItem {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
filePath: string;
|
|
38
|
+
disabled: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ToggleSkillSelectorResult {
|
|
42
|
+
/** Skills with their final toggle states. */
|
|
43
|
+
skills: ToggleSkill[];
|
|
44
|
+
/** If true, the user cancelled and changes should not be written. */
|
|
45
|
+
cancelled: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class ToggleSkillSelectorComponent implements Component {
|
|
49
|
+
private theme: Theme;
|
|
50
|
+
private done: (result: ToggleSkillSelectorResult) => void;
|
|
51
|
+
|
|
52
|
+
// All skill items (immutable original list)
|
|
53
|
+
private allItems: DisplayItem[] = [];
|
|
54
|
+
|
|
55
|
+
// Current in-memory toggle states (keyed by filePath)
|
|
56
|
+
private disabledMap: Map<string, boolean> = new Map();
|
|
57
|
+
|
|
58
|
+
// UI state
|
|
59
|
+
private lastWidth = 80;
|
|
60
|
+
private filteredItems: DisplayItem[] = [];
|
|
61
|
+
private selectedIndex = 0;
|
|
62
|
+
private maxVisible = 10;
|
|
63
|
+
private searchInput: Input;
|
|
64
|
+
private listContainer: Container;
|
|
65
|
+
private footerText: Text;
|
|
66
|
+
private hasChanges = false;
|
|
67
|
+
private originalSkills: ToggleSkill[] = [];
|
|
68
|
+
|
|
69
|
+
// Focusable
|
|
70
|
+
private _focused = false;
|
|
71
|
+
get focused(): boolean {
|
|
72
|
+
return this._focused;
|
|
73
|
+
}
|
|
74
|
+
set focused(value: boolean) {
|
|
75
|
+
this._focused = value;
|
|
76
|
+
this.searchInput.focused = value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
constructor(
|
|
80
|
+
theme: Theme,
|
|
81
|
+
skills: ToggleSkill[],
|
|
82
|
+
done: (result: ToggleSkillSelectorResult) => void,
|
|
83
|
+
) {
|
|
84
|
+
this.theme = theme;
|
|
85
|
+
this.done = done;
|
|
86
|
+
this.originalSkills = skills;
|
|
87
|
+
|
|
88
|
+
// Build display items and initial state map
|
|
89
|
+
for (const skill of skills) {
|
|
90
|
+
this.allItems.push({
|
|
91
|
+
name: skill.name,
|
|
92
|
+
description: skill.description,
|
|
93
|
+
filePath: skill.filePath,
|
|
94
|
+
disabled: skill.disabled,
|
|
95
|
+
});
|
|
96
|
+
this.disabledMap.set(skill.filePath, skill.disabled);
|
|
97
|
+
}
|
|
98
|
+
this.filteredItems = [...this.allItems];
|
|
99
|
+
|
|
100
|
+
this.searchInput = new Input();
|
|
101
|
+
this.listContainer = new Container();
|
|
102
|
+
this.footerText = new Text(this.getFooterText(), 0, 0);
|
|
103
|
+
|
|
104
|
+
this.searchInput.onSubmit = () => {
|
|
105
|
+
if (this.filteredItems[this.selectedIndex]) {
|
|
106
|
+
this.toggleItem(this.filteredItems[this.selectedIndex]);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
this.updateList();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
render(width: number): string[] {
|
|
114
|
+
if (this.lastWidth !== width) {
|
|
115
|
+
this.lastWidth = width;
|
|
116
|
+
this.updateList();
|
|
117
|
+
}
|
|
118
|
+
const lines: string[] = [];
|
|
119
|
+
|
|
120
|
+
lines.push(...new DynamicBorder((s) => this.theme.fg("accent", s)).render(width));
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push(
|
|
123
|
+
truncateToWidth(
|
|
124
|
+
this.theme.fg("accent", this.theme.bold("Toggle Skill Visibility")),
|
|
125
|
+
width,
|
|
126
|
+
"",
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
lines.push(
|
|
130
|
+
...wrapTextWithAnsi(
|
|
131
|
+
this.theme.fg(
|
|
132
|
+
"muted",
|
|
133
|
+
`Toggle disable-model-invocation on skills. Hidden skills won't appear in the system prompt.`,
|
|
134
|
+
),
|
|
135
|
+
width,
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
lines.push("");
|
|
139
|
+
lines.push(...this.searchInput.render(width));
|
|
140
|
+
lines.push("");
|
|
141
|
+
lines.push(...this.listContainer.render(width));
|
|
142
|
+
lines.push("");
|
|
143
|
+
lines.push(...this.footerText.render(width));
|
|
144
|
+
lines.push(...new DynamicBorder((s) => this.theme.fg("accent", s)).render(width));
|
|
145
|
+
|
|
146
|
+
return lines.map((line) => truncateToWidth(line, width, ""));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
handleInput(data: string): void {
|
|
150
|
+
const kb = getKeybindings();
|
|
151
|
+
|
|
152
|
+
if (kb.matches(data, "tui.select.up")) {
|
|
153
|
+
if (this.filteredItems.length === 0) return;
|
|
154
|
+
this.selectedIndex =
|
|
155
|
+
this.selectedIndex === 0
|
|
156
|
+
? this.filteredItems.length - 1
|
|
157
|
+
: this.selectedIndex - 1;
|
|
158
|
+
this.updateList();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (kb.matches(data, "tui.select.down")) {
|
|
163
|
+
if (this.filteredItems.length === 0) return;
|
|
164
|
+
this.selectedIndex =
|
|
165
|
+
this.selectedIndex === this.filteredItems.length - 1
|
|
166
|
+
? 0
|
|
167
|
+
: this.selectedIndex + 1;
|
|
168
|
+
this.updateList();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Enter — toggle selected item
|
|
173
|
+
if (kb.matches(data, "tui.select.confirm")) {
|
|
174
|
+
const item = this.filteredItems[this.selectedIndex];
|
|
175
|
+
if (item) {
|
|
176
|
+
this.toggleItem(item);
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Ctrl+A — disable all (filtered if search active)
|
|
182
|
+
if (matchesKey(data, Key.ctrl("a"))) {
|
|
183
|
+
const targets = this.getFilterTargets();
|
|
184
|
+
this.disableSkills(targets);
|
|
185
|
+
this.hasChanges = true;
|
|
186
|
+
this.refresh();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Ctrl+D — enable all (filtered if search active)
|
|
191
|
+
if (matchesKey(data, Key.ctrl("d"))) {
|
|
192
|
+
const targets = this.getFilterTargets();
|
|
193
|
+
this.enableSkills(targets);
|
|
194
|
+
this.hasChanges = true;
|
|
195
|
+
this.refresh();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Ctrl+S — save and close
|
|
200
|
+
if (matchesKey(data, Key.ctrl("s"))) {
|
|
201
|
+
this.finish(false);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Escape — cancel
|
|
206
|
+
if (matchesKey(data, Key.escape)) {
|
|
207
|
+
this.finish(true);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Ctrl+C — clear search or cancel if empty
|
|
212
|
+
if (matchesKey(data, Key.ctrl("c"))) {
|
|
213
|
+
if (this.searchInput.getValue()) {
|
|
214
|
+
this.searchInput.setValue("");
|
|
215
|
+
this.refresh();
|
|
216
|
+
} else {
|
|
217
|
+
this.finish(true);
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Pass everything else to search input
|
|
223
|
+
this.searchInput.handleInput(data);
|
|
224
|
+
this.refresh();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
invalidate(): void {
|
|
228
|
+
this.searchInput.invalidate();
|
|
229
|
+
this.listContainer.invalidate();
|
|
230
|
+
this.footerText.invalidate();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Internal helpers
|
|
234
|
+
|
|
235
|
+
private getFilterTargets(): DisplayItem[] {
|
|
236
|
+
const query = this.searchInput.getValue();
|
|
237
|
+
return query ? this.filteredItems : this.allItems;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private getFooterText(): string {
|
|
241
|
+
const allCount = this.allItems.length;
|
|
242
|
+
const hiddenCount = this.allItems.filter((item) => this.disabledMap.get(item.filePath) ?? item.disabled).length;
|
|
243
|
+
const visibleCount = allCount - hiddenCount;
|
|
244
|
+
|
|
245
|
+
const parts: string[] = [
|
|
246
|
+
`${keyText("tui.select.confirm")} toggle`,
|
|
247
|
+
`ctrl+a hide all`,
|
|
248
|
+
`ctrl+d show all`,
|
|
249
|
+
`ctrl+s save & reload`,
|
|
250
|
+
`${visibleCount} visible · ${hiddenCount} hidden`,
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
const text = parts.join(" · ");
|
|
254
|
+
return this.hasChanges
|
|
255
|
+
? this.theme.fg("dim", ` ${text} `) + this.theme.fg("warning", "(unsaved)")
|
|
256
|
+
: this.theme.fg("dim", ` ${text}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private refresh(): void {
|
|
260
|
+
const query = this.searchInput.getValue();
|
|
261
|
+
this.filteredItems = query
|
|
262
|
+
? fuzzyFilter(
|
|
263
|
+
this.allItems,
|
|
264
|
+
query,
|
|
265
|
+
(item: DisplayItem) => `${item.name} ${item.description} ${item.filePath}`,
|
|
266
|
+
)
|
|
267
|
+
: [...this.allItems];
|
|
268
|
+
|
|
269
|
+
// Update disabled status from the map
|
|
270
|
+
for (const item of this.filteredItems) {
|
|
271
|
+
item.disabled = this.disabledMap.get(item.filePath) ?? item.disabled;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this.selectedIndex = Math.min(
|
|
275
|
+
this.selectedIndex,
|
|
276
|
+
Math.max(0, this.filteredItems.length - 1),
|
|
277
|
+
);
|
|
278
|
+
this.updateList();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private updateList(): void {
|
|
282
|
+
this.listContainer.clear();
|
|
283
|
+
|
|
284
|
+
if (this.filteredItems.length === 0) {
|
|
285
|
+
this.listContainer.addChild(
|
|
286
|
+
new Text(this.theme.fg("muted", " No matching skills"), 0, 0),
|
|
287
|
+
);
|
|
288
|
+
this.footerText.setText(this.getFooterText());
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const startIndex = Math.max(
|
|
293
|
+
0,
|
|
294
|
+
Math.min(
|
|
295
|
+
this.selectedIndex - Math.floor(this.maxVisible / 2),
|
|
296
|
+
this.filteredItems.length - this.maxVisible,
|
|
297
|
+
),
|
|
298
|
+
);
|
|
299
|
+
const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
|
|
300
|
+
|
|
301
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
302
|
+
const item = this.filteredItems[i];
|
|
303
|
+
if (!item) continue;
|
|
304
|
+
|
|
305
|
+
const isSelected = i === this.selectedIndex;
|
|
306
|
+
const prefix = isSelected ? this.theme.fg("accent", "→ ") : " ";
|
|
307
|
+
const nameText = isSelected
|
|
308
|
+
? this.theme.fg("accent", item.name)
|
|
309
|
+
: item.name;
|
|
310
|
+
const status = item.disabled
|
|
311
|
+
? this.theme.fg("dim", " ✗")
|
|
312
|
+
: this.theme.fg("success", " ✓");
|
|
313
|
+
|
|
314
|
+
this.listContainer.addChild(
|
|
315
|
+
new Text(`${prefix}${nameText}${status}`, 0, 0),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Scroll indicator
|
|
320
|
+
if (startIndex > 0 || endIndex < this.filteredItems.length) {
|
|
321
|
+
this.listContainer.addChild(
|
|
322
|
+
new Text(
|
|
323
|
+
this.theme.fg("muted", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`),
|
|
324
|
+
0,
|
|
325
|
+
0,
|
|
326
|
+
),
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Detail area for the selected item
|
|
331
|
+
if (this.filteredItems.length > 0) {
|
|
332
|
+
const selected = this.filteredItems[this.selectedIndex];
|
|
333
|
+
this.listContainer.addChild(new Spacer(1));
|
|
334
|
+
this.listContainer.addChild(
|
|
335
|
+
new Text(
|
|
336
|
+
this.theme.fg("dim", ` Source: ${selected.filePath}`),
|
|
337
|
+
0,
|
|
338
|
+
0,
|
|
339
|
+
),
|
|
340
|
+
);
|
|
341
|
+
const descLines = this.wrapDescription(selected.description);
|
|
342
|
+
for (let i = 0; i < descLines.length; i++) {
|
|
343
|
+
const prefix = i === 0 ? " Description: " : " ";
|
|
344
|
+
this.listContainer.addChild(
|
|
345
|
+
new Text(this.theme.fg("muted", `${prefix}${descLines[i]}`), 0, 0),
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
this.footerText.setText(this.getFooterText());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Toggle a single item between disabled and enabled. */
|
|
354
|
+
private toggleItem(item: DisplayItem): void {
|
|
355
|
+
const current = this.disabledMap.get(item.filePath) ?? item.disabled;
|
|
356
|
+
this.disabledMap.set(item.filePath, !current);
|
|
357
|
+
this.hasChanges = this.hasChanges || current !== this.getOriginalState(item.filePath);
|
|
358
|
+
// Recompute hasChanges against originals
|
|
359
|
+
this.recheckHasChanges();
|
|
360
|
+
this.refresh();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Disable all given items. */
|
|
364
|
+
private disableSkills(items: DisplayItem[]): void {
|
|
365
|
+
for (const item of items) {
|
|
366
|
+
this.disabledMap.set(item.filePath, true);
|
|
367
|
+
}
|
|
368
|
+
this.recheckHasChanges();
|
|
369
|
+
this.refresh();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Enable all given items. */
|
|
373
|
+
private enableSkills(items: DisplayItem[]): void {
|
|
374
|
+
for (const item of items) {
|
|
375
|
+
this.disabledMap.set(item.filePath, false);
|
|
376
|
+
}
|
|
377
|
+
this.recheckHasChanges();
|
|
378
|
+
this.refresh();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Word-wrap a description string, fitting the terminal width. */
|
|
382
|
+
private wrapDescription(text: string): string[] {
|
|
383
|
+
const label = " Description: ";
|
|
384
|
+
const indent = " ";
|
|
385
|
+
const firstLineWidth = Math.max(20, this.lastWidth - label.length);
|
|
386
|
+
const contLineWidth = Math.max(20, this.lastWidth - indent.length);
|
|
387
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
388
|
+
const lines: string[] = [];
|
|
389
|
+
let currentLine = "";
|
|
390
|
+
|
|
391
|
+
for (const word of words) {
|
|
392
|
+
const lineLen = currentLine.length === 0 ? 0 : currentLine.length + 1;
|
|
393
|
+
const limit = lines.length === 0 ? firstLineWidth : contLineWidth;
|
|
394
|
+
if (lineLen + word.length > limit && currentLine.length > 0) {
|
|
395
|
+
lines.push(currentLine);
|
|
396
|
+
currentLine = word;
|
|
397
|
+
} else {
|
|
398
|
+
currentLine = currentLine.length === 0 ? word : `${currentLine} ${word}`;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (currentLine.length > 0) {
|
|
402
|
+
lines.push(currentLine);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return lines;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Check if any item's state differs from its original. */
|
|
409
|
+
private getOriginalState(filePath: string): boolean {
|
|
410
|
+
return this.originalSkills.find((s) => s.filePath === filePath)?.disabled ?? false;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private recheckHasChanges(): void {
|
|
414
|
+
this.hasChanges = this.allItems.some((item) => {
|
|
415
|
+
const current = this.disabledMap.get(item.filePath) ?? item.disabled;
|
|
416
|
+
return current !== this.getOriginalState(item.filePath);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Build final skill list from current toggle states and close. */
|
|
421
|
+
private finish(cancelled: boolean): void {
|
|
422
|
+
if (cancelled) {
|
|
423
|
+
this.done({ skills: this.originalSkills, cancelled: true });
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Build updated skills from original + current toggle states
|
|
428
|
+
const updatedSkills: ToggleSkill[] = this.originalSkills.map((skill) => ({
|
|
429
|
+
...skill,
|
|
430
|
+
disabled: this.disabledMap.get(skill.filePath) ?? skill.disabled,
|
|
431
|
+
}));
|
|
432
|
+
|
|
433
|
+
this.done({ skills: updatedSkills, cancelled: false });
|
|
434
|
+
}
|
|
435
|
+
}
|