@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,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-toggle-skills — toggle skill visibility in pi's system prompt.
|
|
3
|
+
*
|
|
4
|
+
* Toggles `disable-model-invocation` in SKILL.md frontmatter to control
|
|
5
|
+
* whether a skill appears in the model's available skills list.
|
|
6
|
+
*
|
|
7
|
+
* When a skill has `disable-model-invocation: true`, pi excludes it from
|
|
8
|
+
* the system prompt entirely. Users can still invoke it explicitly via
|
|
9
|
+
* /skill:name commands.
|
|
10
|
+
*
|
|
11
|
+
* This extension modifies SKILL.md files on disk. Changes require a /reload
|
|
12
|
+
* to take effect.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import {
|
|
17
|
+
TOGGLE_COMMAND_DESCRIPTION,
|
|
18
|
+
type ToggleSkill,
|
|
19
|
+
computeChanges,
|
|
20
|
+
} from "./src/index.js";
|
|
21
|
+
import {
|
|
22
|
+
discoverSkills,
|
|
23
|
+
toggleSkillInvocation,
|
|
24
|
+
applyChanges,
|
|
25
|
+
} from "./src/skill-discovery.js";
|
|
26
|
+
import { ToggleSkillSelectorComponent, type ToggleSkillSelectorResult } from "./src/skill-selector.js";
|
|
27
|
+
|
|
28
|
+
export default function (pi: ExtensionAPI) {
|
|
29
|
+
let currentSkills: ToggleSkill[] = [];
|
|
30
|
+
|
|
31
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
32
|
+
currentSkills = discoverSkills(ctx.cwd);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
pi.registerCommand("toggle-skills", {
|
|
36
|
+
description: TOGGLE_COMMAND_DESCRIPTION,
|
|
37
|
+
getArgumentCompletions(prefix: string) {
|
|
38
|
+
const subcommands = ["status", "enable", "disable", "list", "help"];
|
|
39
|
+
const matches = subcommands.filter((s) => s.startsWith(prefix));
|
|
40
|
+
return matches.length > 0 ? matches.map((s) => ({ value: s, label: s })) : null;
|
|
41
|
+
},
|
|
42
|
+
handler: async (args, ctx) => {
|
|
43
|
+
await handleToggleCommand(ctx, args.trim(), currentSkills, (skills) => {
|
|
44
|
+
currentSkills = skills;
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function handleToggleCommand(
|
|
51
|
+
ctx: ExtensionCommandContext,
|
|
52
|
+
args: string,
|
|
53
|
+
currentSkills: ToggleSkill[],
|
|
54
|
+
setSkills: (skills: ToggleSkill[]) => void,
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
const parts = args.split(/\s+/);
|
|
57
|
+
const subcommand = parts[0]?.toLowerCase() ?? "";
|
|
58
|
+
const rest = parts.slice(1).join(" ");
|
|
59
|
+
|
|
60
|
+
// /toggle-skills — open interactive TUI selector (default)
|
|
61
|
+
if (!subcommand) {
|
|
62
|
+
await showToggleSelector(ctx, currentSkills, setSkills);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// /toggle-skills list — show skills and their status
|
|
67
|
+
if (subcommand === "list") {
|
|
68
|
+
showStatus(ctx, currentSkills);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// /toggle-skills status — same as list
|
|
73
|
+
if (subcommand === "status") {
|
|
74
|
+
showStatus(ctx, currentSkills);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// /toggle-skills disable <name> — hide a skill from the system prompt
|
|
79
|
+
if (subcommand === "disable") {
|
|
80
|
+
if (!rest) {
|
|
81
|
+
ctx.ui.notify(
|
|
82
|
+
"Usage: /toggle-skills disable <skill-name>",
|
|
83
|
+
"warning",
|
|
84
|
+
);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const skill = findSkillByName(currentSkills, rest);
|
|
89
|
+
if (!skill) {
|
|
90
|
+
ctx.ui.notify(`Skill not found: "${rest}". Use /toggle-skills list to see available skills.`, "warning");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (skill.disabled) {
|
|
95
|
+
ctx.ui.notify(`Skill "${skill.name}" is already hidden.`, "info");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (toggleSkillInvocation(skill.filePath, true)) {
|
|
100
|
+
skill.disabled = true;
|
|
101
|
+
ctx.ui.notify(
|
|
102
|
+
`Disabled: "${skill.name}" — hidden from system prompt. Run /reload to apply.`,
|
|
103
|
+
"info",
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
ctx.ui.notify(`Failed to toggle skill "${skill.name}". Check file permissions.`, "error");
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// /toggle-skills enable <name> — show a skill in the system prompt
|
|
112
|
+
if (subcommand === "enable") {
|
|
113
|
+
if (!rest) {
|
|
114
|
+
ctx.ui.notify(
|
|
115
|
+
"Usage: /toggle-skills enable <skill-name>",
|
|
116
|
+
"warning",
|
|
117
|
+
);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const skill = findSkillByName(currentSkills, rest);
|
|
122
|
+
if (!skill) {
|
|
123
|
+
ctx.ui.notify(`Skill not found: "${rest}". Use /toggle-skills list to see available skills.`, "warning");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!skill.disabled) {
|
|
128
|
+
ctx.ui.notify(`Skill "${skill.name}" is already visible.`, "info");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (toggleSkillInvocation(skill.filePath, false)) {
|
|
133
|
+
skill.disabled = false;
|
|
134
|
+
ctx.ui.notify(
|
|
135
|
+
`Enabled: "${skill.name}" — visible in system prompt. Run /reload to apply.`,
|
|
136
|
+
"info",
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
ctx.ui.notify(`Failed to toggle skill "${skill.name}". Check file permissions.`, "error");
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// /toggle-skills help
|
|
145
|
+
if (subcommand === "help") {
|
|
146
|
+
ctx.ui.notify(
|
|
147
|
+
[
|
|
148
|
+
"pi-toggle-skills commands:",
|
|
149
|
+
" /toggle-skills Open interactive TUI to toggle skill visibility",
|
|
150
|
+
" /toggle-skills status Show current skills and their visibility",
|
|
151
|
+
" /toggle-skills list Same as /toggle-skills status",
|
|
152
|
+
" /toggle-skills disable <n> Hide a skill from the system prompt",
|
|
153
|
+
" /toggle-skills enable <n> Show a skill in the system prompt",
|
|
154
|
+
" /toggle-skills help This message",
|
|
155
|
+
"",
|
|
156
|
+
"Mechanism: toggles disable-model-invocation in SKILL.md frontmatter.",
|
|
157
|
+
" When true, the skill is excluded from the system prompt.",
|
|
158
|
+
" Users can still invoke hidden skills via /skill:name commands.",
|
|
159
|
+
" Changes require /reload to take effect.",
|
|
160
|
+
].join("\n"),
|
|
161
|
+
"info",
|
|
162
|
+
);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
ctx.ui.notify(
|
|
167
|
+
`Unknown subcommand: "${subcommand}". Use /toggle-skills help for usage.`,
|
|
168
|
+
"warning",
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Open the interactive TUI selector.
|
|
173
|
+
async function showToggleSelector(
|
|
174
|
+
ctx: ExtensionCommandContext,
|
|
175
|
+
currentSkills: ToggleSkill[],
|
|
176
|
+
setSkills: (skills: ToggleSkill[]) => void,
|
|
177
|
+
): Promise<void> {
|
|
178
|
+
if (currentSkills.length === 0) {
|
|
179
|
+
ctx.ui.notify("No skills found. Add skills to ~/.pi/agent/skills/ or .pi/skills/ first.", "warning");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (ctx.mode !== "tui") {
|
|
184
|
+
if (!ctx.hasUI) {
|
|
185
|
+
ctx.ui.notify("/toggle-skills requires a UI (TUI or GUI).", "error");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const items = currentSkills.map((s) => `${s.name}: ${s.disabled ? "disabled" : "enabled"}`);
|
|
189
|
+
const pick = await ctx.ui.select("Toggle skill \u2014 pick a skill to flip", items);
|
|
190
|
+
if (pick === undefined) return;
|
|
191
|
+
const idx = items.indexOf(pick);
|
|
192
|
+
if (idx < 0) return;
|
|
193
|
+
const skill = currentSkills[idx];
|
|
194
|
+
if (!skill) return;
|
|
195
|
+
const newDisabled = !skill.disabled;
|
|
196
|
+
const written = applyChanges(currentSkills, [{ filePath: skill.filePath, newDisabled }]);
|
|
197
|
+
if (written.length === 0) {
|
|
198
|
+
ctx.ui.notify("No files were written. Check file permissions.", "warning");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
setSkills(
|
|
202
|
+
currentSkills.map((s) => (s.filePath === skill.filePath ? { ...s, disabled: newDisabled } : s)),
|
|
203
|
+
);
|
|
204
|
+
ctx.ui.notify(
|
|
205
|
+
`Skill ${skill.name} ${newDisabled ? "disabled" : "enabled"}. /reload to take effect. Run /toggle-skills again for more.`,
|
|
206
|
+
"info",
|
|
207
|
+
);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const result = await ctx.ui.custom<ToggleSkillSelectorResult>(
|
|
212
|
+
(tui, theme, _kb, done) => {
|
|
213
|
+
const selector = new ToggleSkillSelectorComponent(
|
|
214
|
+
theme,
|
|
215
|
+
currentSkills,
|
|
216
|
+
(result) => done(result),
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
get focused() { return selector.focused; },
|
|
221
|
+
set focused(value: boolean) { selector.focused = value; },
|
|
222
|
+
render(width: number) {
|
|
223
|
+
return selector.render(width);
|
|
224
|
+
},
|
|
225
|
+
invalidate() {
|
|
226
|
+
selector.invalidate();
|
|
227
|
+
},
|
|
228
|
+
handleInput(data: string) {
|
|
229
|
+
selector.handleInput(data);
|
|
230
|
+
tui.requestRender();
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
if (!result || result.cancelled) {
|
|
237
|
+
ctx.ui.notify("Toggle selector cancelled.", "info");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Compute what changed
|
|
242
|
+
const changes = computeChanges(currentSkills, result.skills);
|
|
243
|
+
if (changes.length === 0) {
|
|
244
|
+
ctx.ui.notify("No changes to apply.", "info");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Write changes to disk
|
|
249
|
+
const written = applyChanges(currentSkills, changes);
|
|
250
|
+
if (written.length === 0) {
|
|
251
|
+
ctx.ui.notify("No files were written. Check file permissions.", "warning");
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
setSkills(result.skills);
|
|
256
|
+
|
|
257
|
+
// Summarize what changed
|
|
258
|
+
const disabled = changes.filter((c) => c.newDisabled).length;
|
|
259
|
+
const enabled = changes.length - disabled;
|
|
260
|
+
const parts: string[] = [];
|
|
261
|
+
if (enabled > 0) parts.push(`${enabled} enabled`);
|
|
262
|
+
if (disabled > 0) parts.push(`${disabled} disabled`);
|
|
263
|
+
const summary = parts.join(", ");
|
|
264
|
+
|
|
265
|
+
ctx.ui.notify(
|
|
266
|
+
`Skills updated: ${summary}. Run /reload to apply.`,
|
|
267
|
+
"info",
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function findSkillByName(skills: ReadonlyArray<ToggleSkill>, name: string): ToggleSkill | undefined {
|
|
272
|
+
// Exact match first
|
|
273
|
+
const exact = skills.find((s) => s.name === name);
|
|
274
|
+
if (exact) return exact;
|
|
275
|
+
|
|
276
|
+
// Prefix match
|
|
277
|
+
const prefix = skills.find((s) => s.name.startsWith(name));
|
|
278
|
+
if (prefix) return prefix;
|
|
279
|
+
|
|
280
|
+
// Fuzzy: contains
|
|
281
|
+
const fuzzy = skills.find((s) => s.name.includes(name));
|
|
282
|
+
return fuzzy;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function showStatus(
|
|
286
|
+
ctx: ExtensionCommandContext,
|
|
287
|
+
skills: ReadonlyArray<ToggleSkill>,
|
|
288
|
+
): void {
|
|
289
|
+
const lines: string[] = [];
|
|
290
|
+
|
|
291
|
+
if (skills.length === 0) {
|
|
292
|
+
lines.push("No skills found. Add skills to ~/.pi/agent/skills/ or .pi/skills/.");
|
|
293
|
+
} else {
|
|
294
|
+
const visible = skills.filter((s) => !s.disabled);
|
|
295
|
+
const hidden = skills.filter((s) => s.disabled);
|
|
296
|
+
|
|
297
|
+
if (hidden.length > 0) {
|
|
298
|
+
lines.push(`Visible skills (${visible.length}):`);
|
|
299
|
+
for (const skill of visible) {
|
|
300
|
+
lines.push(` ✓ ${skill.name}`);
|
|
301
|
+
}
|
|
302
|
+
lines.push("");
|
|
303
|
+
lines.push(`Hidden skills (${hidden.length}):`);
|
|
304
|
+
for (const skill of hidden) {
|
|
305
|
+
lines.push(` ✗ ${skill.name}`);
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
lines.push(`All skills visible (${skills.length}):`);
|
|
309
|
+
for (const skill of skills) {
|
|
310
|
+
lines.push(` ✓ ${skill.name}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
316
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: "node",
|
|
7
|
+
include: ["__tests__/**/*.test.ts"],
|
|
8
|
+
exclude: ["node_modules", "dist", ".idea", ".git", ".cache"],
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: "v8",
|
|
11
|
+
reporter: ["text", "json", "html"],
|
|
12
|
+
exclude: ["node_modules/", "**/*.d.ts", "**/*.test.ts"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Made With MOXY Lda <hello@moxy.studio>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# proper-lockfile
|
|
2
|
+
|
|
3
|
+
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][codecov-image]][codecov-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]
|
|
4
|
+
|
|
5
|
+
[npm-url]:https://npmjs.org/package/proper-lockfile
|
|
6
|
+
[downloads-image]:https://img.shields.io/npm/dm/proper-lockfile.svg
|
|
7
|
+
[npm-image]:https://img.shields.io/npm/v/proper-lockfile.svg
|
|
8
|
+
[travis-url]:https://travis-ci.org/moxystudio/node-proper-lockfile
|
|
9
|
+
[travis-image]:https://img.shields.io/travis/moxystudio/node-proper-lockfile/master.svg
|
|
10
|
+
[codecov-url]:https://codecov.io/gh/moxystudio/node-proper-lockfile
|
|
11
|
+
[codecov-image]:https://img.shields.io/codecov/c/github/moxystudio/node-proper-lockfile/master.svg
|
|
12
|
+
[david-dm-url]:https://david-dm.org/moxystudio/node-proper-lockfile
|
|
13
|
+
[david-dm-image]:https://img.shields.io/david/moxystudio/node-proper-lockfile.svg
|
|
14
|
+
[david-dm-dev-url]:https://david-dm.org/moxystudio/node-proper-lockfile?type=dev
|
|
15
|
+
[david-dm-dev-image]:https://img.shields.io/david/dev/moxystudio/node-proper-lockfile.svg
|
|
16
|
+
|
|
17
|
+
An inter-process and inter-machine lockfile utility that works on a local or network file system.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
`$ npm install proper-lockfile`
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Design
|
|
26
|
+
|
|
27
|
+
There are various ways to achieve [file locking](http://en.wikipedia.org/wiki/File_locking).
|
|
28
|
+
|
|
29
|
+
This library utilizes the `mkdir` strategy which works atomically on any kind of file system, even network based ones.
|
|
30
|
+
The lockfile path is based on the file path you are trying to lock by suffixing it with `.lock`.
|
|
31
|
+
|
|
32
|
+
When a lock is successfully acquired, the lockfile's `mtime` (modified time) is periodically updated to prevent staleness. This allows to effectively check if a lock is stale by checking its `mtime` against a stale threshold. If the update of the mtime fails several times, the lock might be compromised. The `mtime` is [supported](http://en.wikipedia.org/wiki/Comparison_of_file_systems) in almost every `filesystem`.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Comparison
|
|
36
|
+
|
|
37
|
+
This library is similar to [lockfile](https://github.com/isaacs/lockfile) but the latter has some drawbacks:
|
|
38
|
+
|
|
39
|
+
- It relies on `open` with `O_EXCL` flag which has problems in network file systems. `proper-lockfile` uses `mkdir` which doesn't have this issue.
|
|
40
|
+
|
|
41
|
+
> O_EXCL is broken on NFS file systems; programs which rely on it for performing locking tasks will contain a race condition.
|
|
42
|
+
|
|
43
|
+
- The lockfile staleness check is done via `ctime` (creation time) which is unsuitable for long running processes. `proper-lockfile` constantly updates lockfiles `mtime` to do proper staleness check.
|
|
44
|
+
|
|
45
|
+
- It does not check if the lockfile was compromised which can lead to undesirable situations. `proper-lockfile` checks the lockfile when updating the `mtime`.
|
|
46
|
+
|
|
47
|
+
- It has a default value of `0` for the stale option which isn't good because any crash or process kill that the package can't handle gracefully will leave the lock active forever.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Compromised
|
|
51
|
+
|
|
52
|
+
`proper-lockfile` does not detect cases in which:
|
|
53
|
+
|
|
54
|
+
- A `lockfile` is manually removed and someone else acquires the lock right after
|
|
55
|
+
- Different `stale`/`update` values are being used for the same file, possibly causing two locks to be acquired on the same file
|
|
56
|
+
|
|
57
|
+
`proper-lockfile` detects cases in which:
|
|
58
|
+
|
|
59
|
+
- Updates to the `lockfile` fail
|
|
60
|
+
- Updates take longer than expected, possibly causing the lock to become stale for a certain amount of time
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
As you see, the first two are a consequence of bad usage. Technically, it was possible to detect the first two but it would introduce complexity and eventual race conditions.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
### .lock(file, [options])
|
|
69
|
+
|
|
70
|
+
Tries to acquire a lock on `file` or rejects the promise on error.
|
|
71
|
+
|
|
72
|
+
If the lock succeeds, a `release` function is provided that should be called when you want to release the lock. The `release` function also rejects the promise on error (e.g. when the lock was already compromised).
|
|
73
|
+
|
|
74
|
+
Available options:
|
|
75
|
+
|
|
76
|
+
- `stale`: Duration in milliseconds in which the lock is considered stale, defaults to `10000` (minimum value is `5000`)
|
|
77
|
+
- `update`: The interval in milliseconds in which the lockfile's `mtime` will be updated, defaults to `stale/2` (minimum value is `1000`, maximum value is `stale/2`)
|
|
78
|
+
- `retries`: The number of retries or a [retry](https://www.npmjs.org/package/retry) options object, defaults to `0`
|
|
79
|
+
- `realpath`: Resolve symlinks using realpath, defaults to `true` (note that if `true`, the `file` must exist previously)
|
|
80
|
+
- `fs`: A custom fs to use, defaults to `graceful-fs`
|
|
81
|
+
- `onCompromised`: Called if the lock gets compromised, defaults to a function that simply throws the error which will probably cause the process to die
|
|
82
|
+
- `lockfilePath`: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass `file` as `<dir path>` and `options.lockfilePath` as `<dir path>/dir.lock`
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const lockfile = require('proper-lockfile');
|
|
87
|
+
|
|
88
|
+
lockfile.lock('some/file')
|
|
89
|
+
.then((release) => {
|
|
90
|
+
// Do something while the file is locked
|
|
91
|
+
|
|
92
|
+
// Call the provided release function when you're done,
|
|
93
|
+
// which will also return a promise
|
|
94
|
+
return release();
|
|
95
|
+
})
|
|
96
|
+
.catch((e) => {
|
|
97
|
+
// either lock could not be acquired
|
|
98
|
+
// or releasing it failed
|
|
99
|
+
console.error(e)
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Alternatively, you may use lockfile('some/file') directly.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
### .unlock(file, [options])
|
|
107
|
+
|
|
108
|
+
Releases a previously acquired lock on `file` or rejects the promise on error.
|
|
109
|
+
|
|
110
|
+
Whenever possible you should use the `release` function instead (as exemplified above). Still there are cases in which it's hard to keep a reference to it around code. In those cases `unlock()` might be handy.
|
|
111
|
+
|
|
112
|
+
Available options:
|
|
113
|
+
|
|
114
|
+
- `realpath`: Resolve symlinks using realpath, defaults to `true` (note that if `true`, the `file` must exist previously)
|
|
115
|
+
- `fs`: A custom fs to use, defaults to `graceful-fs`
|
|
116
|
+
- `lockfilePath`: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass `file` as `<dir path>` and `options.lockfilePath` as `<dir path>/dir.lock`
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
const lockfile = require('proper-lockfile');
|
|
121
|
+
|
|
122
|
+
lockfile.lock('some/file')
|
|
123
|
+
.then(() => {
|
|
124
|
+
// Do something while the file is locked
|
|
125
|
+
|
|
126
|
+
// Later..
|
|
127
|
+
return lockfile.unlock('some/file');
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### .check(file, [options])
|
|
132
|
+
|
|
133
|
+
Check if the file is locked and its lockfile is not stale, rejects the promise on error.
|
|
134
|
+
|
|
135
|
+
Available options:
|
|
136
|
+
|
|
137
|
+
- `stale`: Duration in milliseconds in which the lock is considered stale, defaults to `10000` (minimum value is `5000`)
|
|
138
|
+
- `realpath`: Resolve symlinks using realpath, defaults to `true` (note that if `true`, the `file` must exist previously)
|
|
139
|
+
- `fs`: A custom fs to use, defaults to `graceful-fs`
|
|
140
|
+
- `lockfilePath`: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass `file` as `<dir path>` and `options.lockfilePath` as `<dir path>/dir.lock`
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
const lockfile = require('proper-lockfile');
|
|
145
|
+
|
|
146
|
+
lockfile.check('some/file')
|
|
147
|
+
.then((isLocked) => {
|
|
148
|
+
// isLocked will be true if 'some/file' is locked, false otherwise
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### .lockSync(file, [options])
|
|
153
|
+
|
|
154
|
+
Sync version of `.lock()`.
|
|
155
|
+
Returns the `release` function or throws on error.
|
|
156
|
+
|
|
157
|
+
### .unlockSync(file, [options])
|
|
158
|
+
|
|
159
|
+
Sync version of `.unlock()`.
|
|
160
|
+
Throws on error.
|
|
161
|
+
|
|
162
|
+
### .checkSync(file, [options])
|
|
163
|
+
|
|
164
|
+
Sync version of `.check()`.
|
|
165
|
+
Returns a boolean or throws on error.
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
## Graceful exit
|
|
169
|
+
|
|
170
|
+
`proper-lockfile` automatically removes locks if the process exits, except if the process is killed with SIGKILL or it crashes due to a VM fatal error (e.g.: out of memory).
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
## Tests
|
|
174
|
+
|
|
175
|
+
`$ npm test`
|
|
176
|
+
`$ npm test -- --watch` during development
|
|
177
|
+
|
|
178
|
+
The test suite is very extensive. There's even a stress test to guarantee exclusiveness of locks.
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
Released under the [MIT License](https://www.opensource.org/licenses/mit-license.php).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const lockfile = require('./lib/lockfile');
|
|
4
|
+
const { toPromise, toSync, toSyncOptions } = require('./lib/adapter');
|
|
5
|
+
|
|
6
|
+
async function lock(file, options) {
|
|
7
|
+
const release = await toPromise(lockfile.lock)(file, options);
|
|
8
|
+
|
|
9
|
+
return toPromise(release);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function lockSync(file, options) {
|
|
13
|
+
const release = toSync(lockfile.lock)(file, toSyncOptions(options));
|
|
14
|
+
|
|
15
|
+
return toSync(release);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function unlock(file, options) {
|
|
19
|
+
return toPromise(lockfile.unlock)(file, options);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function unlockSync(file, options) {
|
|
23
|
+
return toSync(lockfile.unlock)(file, toSyncOptions(options));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function check(file, options) {
|
|
27
|
+
return toPromise(lockfile.check)(file, options);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function checkSync(file, options) {
|
|
31
|
+
return toSync(lockfile.check)(file, toSyncOptions(options));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = lock;
|
|
35
|
+
module.exports.lock = lock;
|
|
36
|
+
module.exports.unlock = unlock;
|
|
37
|
+
module.exports.lockSync = lockSync;
|
|
38
|
+
module.exports.unlockSync = unlockSync;
|
|
39
|
+
module.exports.check = check;
|
|
40
|
+
module.exports.checkSync = checkSync;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('graceful-fs');
|
|
4
|
+
|
|
5
|
+
function createSyncFs(fs) {
|
|
6
|
+
const methods = ['mkdir', 'realpath', 'stat', 'rmdir', 'utimes'];
|
|
7
|
+
const newFs = { ...fs };
|
|
8
|
+
|
|
9
|
+
methods.forEach((method) => {
|
|
10
|
+
newFs[method] = (...args) => {
|
|
11
|
+
const callback = args.pop();
|
|
12
|
+
let ret;
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
ret = fs[`${method}Sync`](...args);
|
|
16
|
+
} catch (err) {
|
|
17
|
+
return callback(err);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
callback(null, ret);
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return newFs;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ----------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
function toPromise(method) {
|
|
30
|
+
return (...args) => new Promise((resolve, reject) => {
|
|
31
|
+
args.push((err, result) => {
|
|
32
|
+
if (err) {
|
|
33
|
+
reject(err);
|
|
34
|
+
} else {
|
|
35
|
+
resolve(result);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
method(...args);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function toSync(method) {
|
|
44
|
+
return (...args) => {
|
|
45
|
+
let err;
|
|
46
|
+
let result;
|
|
47
|
+
|
|
48
|
+
args.push((_err, _result) => {
|
|
49
|
+
err = _err;
|
|
50
|
+
result = _result;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
method(...args);
|
|
54
|
+
|
|
55
|
+
if (err) {
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toSyncOptions(options) {
|
|
64
|
+
// Shallow clone options because we are oging to mutate them
|
|
65
|
+
options = { ...options };
|
|
66
|
+
|
|
67
|
+
// Transform fs to use the sync methods instead
|
|
68
|
+
options.fs = createSyncFs(options.fs || fs);
|
|
69
|
+
|
|
70
|
+
// Retries are not allowed because it requires the flow to be sync
|
|
71
|
+
if (
|
|
72
|
+
(typeof options.retries === 'number' && options.retries > 0) ||
|
|
73
|
+
(options.retries && typeof options.retries.retries === 'number' && options.retries.retries > 0)
|
|
74
|
+
) {
|
|
75
|
+
throw Object.assign(new Error('Cannot use retries with the sync api'), { code: 'ESYNC' });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return options;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = {
|
|
82
|
+
toPromise,
|
|
83
|
+
toSync,
|
|
84
|
+
toSyncOptions,
|
|
85
|
+
};
|