claude-code-tools 0.2.0__py3-none-any.whl → 1.4.1__py3-none-any.whl
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.
- claude_code_tools/__init__.py +1 -1
- claude_code_tools/action_rpc.py +407 -0
- claude_code_tools/aichat.py +2460 -0
- claude_code_tools/claude_continue.py +299 -0
- claude_code_tools/codex_continue.py +309 -0
- claude_code_tools/config.py +93 -0
- claude_code_tools/delete_session.py +194 -0
- claude_code_tools/export_all.py +342 -0
- claude_code_tools/export_claude_session.py +481 -0
- claude_code_tools/export_codex_session.py +466 -0
- claude_code_tools/export_session.py +577 -0
- claude_code_tools/find_claude_session.py +1280 -118
- claude_code_tools/find_codex_session.py +946 -79
- claude_code_tools/find_original_session.py +134 -0
- claude_code_tools/find_session.py +1088 -0
- claude_code_tools/find_trimmed_sessions.py +259 -0
- claude_code_tools/gdoc2md.py +220 -0
- claude_code_tools/md2gdoc.py +549 -0
- claude_code_tools/node_menu_ui.py +406 -0
- claude_code_tools/search_index.py +1321 -0
- claude_code_tools/session_lineage.py +260 -0
- claude_code_tools/session_menu.py +187 -0
- claude_code_tools/session_menu_cli.py +448 -0
- claude_code_tools/session_utils.py +1313 -0
- claude_code_tools/smart_trim.py +424 -0
- claude_code_tools/smart_trim_core.py +616 -0
- claude_code_tools/tmux_cli_controller.py +55 -36
- claude_code_tools/trim_session.py +817 -0
- claude_code_tools/trim_session_claude.py +319 -0
- claude_code_tools/trim_session_codex.py +344 -0
- claude_code_tools-1.4.1.dist-info/METADATA +1113 -0
- claude_code_tools-1.4.1.dist-info/RECORD +1813 -0
- {claude_code_tools-0.2.0.dist-info → claude_code_tools-1.4.1.dist-info}/WHEEL +1 -1
- {claude_code_tools-0.2.0.dist-info → claude_code_tools-1.4.1.dist-info}/entry_points.txt +3 -2
- docs/lmsh.md +27 -5
- docs/local-llm-setup.md +286 -0
- docs/reddit-aichat-resume-v2.md +80 -0
- docs/reddit-aichat-resume.md +29 -0
- docs/reddit-aichat.md +79 -0
- docs/rollover-details.md +67 -0
- node_ui/action_config.js +72 -0
- node_ui/menu.js +2321 -0
- node_ui/node_modules/.bin/is-in-ci +5 -0
- node_ui/node_modules/.bin/loose-envify +16 -0
- node_ui/node_modules/.package-lock.json +714 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/README.md +248 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.d.ts +11 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.js +41 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/diff.d.ts +6 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/diff.js +17 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/diff.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/index.d.ts +6 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/index.js +7 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/index.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/reduce.d.ts +5 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/reduce.js +27 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/reduce.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/styledChars.d.ts +6 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/styledChars.js +38 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/styledChars.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/tokenize.d.ts +12 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/tokenize.js +70 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/tokenize.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/undo.d.ts +3 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/undo.js +11 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/build/undo.js.map +1 -0
- node_ui/node_modules/@alcalzone/ansi-tokenize/package.json +63 -0
- node_ui/node_modules/ansi-escapes/base.d.ts +292 -0
- node_ui/node_modules/ansi-escapes/base.js +198 -0
- node_ui/node_modules/ansi-escapes/index.d.ts +2 -0
- node_ui/node_modules/ansi-escapes/index.js +2 -0
- node_ui/node_modules/ansi-escapes/license +9 -0
- node_ui/node_modules/ansi-escapes/package.json +70 -0
- node_ui/node_modules/ansi-escapes/readme.md +284 -0
- node_ui/node_modules/ansi-regex/index.d.ts +33 -0
- node_ui/node_modules/ansi-regex/index.js +14 -0
- node_ui/node_modules/ansi-regex/license +9 -0
- node_ui/node_modules/ansi-regex/package.json +61 -0
- node_ui/node_modules/ansi-regex/readme.md +66 -0
- node_ui/node_modules/ansi-styles/index.d.ts +236 -0
- node_ui/node_modules/ansi-styles/index.js +223 -0
- node_ui/node_modules/ansi-styles/license +9 -0
- node_ui/node_modules/ansi-styles/package.json +54 -0
- node_ui/node_modules/ansi-styles/readme.md +173 -0
- node_ui/node_modules/auto-bind/index.d.ts +50 -0
- node_ui/node_modules/auto-bind/index.js +41 -0
- node_ui/node_modules/auto-bind/license +9 -0
- node_ui/node_modules/auto-bind/package.json +51 -0
- node_ui/node_modules/auto-bind/react.d.ts +26 -0
- node_ui/node_modules/auto-bind/react.js +28 -0
- node_ui/node_modules/auto-bind/readme.md +92 -0
- node_ui/node_modules/chalk/license +9 -0
- node_ui/node_modules/chalk/package.json +83 -0
- node_ui/node_modules/chalk/readme.md +325 -0
- node_ui/node_modules/chalk/source/index.d.ts +320 -0
- node_ui/node_modules/chalk/source/index.js +225 -0
- node_ui/node_modules/chalk/source/utilities.js +33 -0
- node_ui/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- node_ui/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- node_ui/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- node_ui/node_modules/chalk/source/vendor/supports-color/browser.js +30 -0
- node_ui/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- node_ui/node_modules/chalk/source/vendor/supports-color/index.js +182 -0
- node_ui/node_modules/cli-boxes/boxes.json +82 -0
- node_ui/node_modules/cli-boxes/index.d.ts +127 -0
- node_ui/node_modules/cli-boxes/index.js +6 -0
- node_ui/node_modules/cli-boxes/license +9 -0
- node_ui/node_modules/cli-boxes/package.json +42 -0
- node_ui/node_modules/cli-boxes/readme.md +115 -0
- node_ui/node_modules/cli-cursor/index.d.ts +47 -0
- node_ui/node_modules/cli-cursor/index.js +39 -0
- node_ui/node_modules/cli-cursor/license +9 -0
- node_ui/node_modules/cli-cursor/package.json +49 -0
- node_ui/node_modules/cli-cursor/readme.md +51 -0
- node_ui/node_modules/cli-truncate/index.d.ts +116 -0
- node_ui/node_modules/cli-truncate/index.js +99 -0
- node_ui/node_modules/cli-truncate/license +9 -0
- node_ui/node_modules/cli-truncate/node_modules/slice-ansi/index.js +105 -0
- node_ui/node_modules/cli-truncate/node_modules/slice-ansi/license +10 -0
- node_ui/node_modules/cli-truncate/node_modules/slice-ansi/package.json +53 -0
- node_ui/node_modules/cli-truncate/node_modules/slice-ansi/readme.md +66 -0
- node_ui/node_modules/cli-truncate/package.json +51 -0
- node_ui/node_modules/cli-truncate/readme.md +150 -0
- node_ui/node_modules/code-excerpt/dist/index.d.ts +9 -0
- node_ui/node_modules/code-excerpt/dist/index.js +27 -0
- node_ui/node_modules/code-excerpt/license +21 -0
- node_ui/node_modules/code-excerpt/package.json +43 -0
- node_ui/node_modules/code-excerpt/readme.md +65 -0
- node_ui/node_modules/convert-to-spaces/dist/index.d.ts +2 -0
- node_ui/node_modules/convert-to-spaces/dist/index.js +4 -0
- node_ui/node_modules/convert-to-spaces/license +21 -0
- node_ui/node_modules/convert-to-spaces/package.json +40 -0
- node_ui/node_modules/convert-to-spaces/readme.md +39 -0
- node_ui/node_modules/emoji-regex/LICENSE-MIT.txt +20 -0
- node_ui/node_modules/emoji-regex/README.md +107 -0
- node_ui/node_modules/emoji-regex/index.d.ts +3 -0
- node_ui/node_modules/emoji-regex/index.js +4 -0
- node_ui/node_modules/emoji-regex/index.mjs +4 -0
- node_ui/node_modules/emoji-regex/package.json +45 -0
- node_ui/node_modules/environment/index.d.ts +74 -0
- node_ui/node_modules/environment/index.js +47 -0
- node_ui/node_modules/environment/license +9 -0
- node_ui/node_modules/environment/package.json +74 -0
- node_ui/node_modules/environment/readme.md +94 -0
- node_ui/node_modules/escape-string-regexp/index.d.ts +16 -0
- node_ui/node_modules/escape-string-regexp/index.js +11 -0
- node_ui/node_modules/escape-string-regexp/license +9 -0
- node_ui/node_modules/escape-string-regexp/package.json +40 -0
- node_ui/node_modules/escape-string-regexp/readme.md +34 -0
- node_ui/node_modules/figures/index.d.ts +269 -0
- node_ui/node_modules/figures/index.js +322 -0
- node_ui/node_modules/figures/license +9 -0
- node_ui/node_modules/figures/package.json +46 -0
- node_ui/node_modules/figures/readme.md +328 -0
- node_ui/node_modules/get-east-asian-width/index.d.ts +60 -0
- node_ui/node_modules/get-east-asian-width/index.js +30 -0
- node_ui/node_modules/get-east-asian-width/license +9 -0
- node_ui/node_modules/get-east-asian-width/lookup.js +403 -0
- node_ui/node_modules/get-east-asian-width/package.json +70 -0
- node_ui/node_modules/get-east-asian-width/readme.md +65 -0
- node_ui/node_modules/indent-string/index.d.ts +38 -0
- node_ui/node_modules/indent-string/index.js +38 -0
- node_ui/node_modules/indent-string/license +9 -0
- node_ui/node_modules/indent-string/package.json +40 -0
- node_ui/node_modules/indent-string/readme.md +73 -0
- node_ui/node_modules/ink/build/apply-styles.js +175 -0
- node_ui/node_modules/ink/build/build-layout.js +77 -0
- node_ui/node_modules/ink/build/calculate-wrapped-text.js +53 -0
- node_ui/node_modules/ink/build/colorize.d.ts +3 -0
- node_ui/node_modules/ink/build/colorize.js +48 -0
- node_ui/node_modules/ink/build/colorize.js.map +1 -0
- node_ui/node_modules/ink/build/components/App.d.ts +61 -0
- node_ui/node_modules/ink/build/components/App.js +286 -0
- node_ui/node_modules/ink/build/components/App.js.map +1 -0
- node_ui/node_modules/ink/build/components/AppContext.d.ts +12 -0
- node_ui/node_modules/ink/build/components/AppContext.js +11 -0
- node_ui/node_modules/ink/build/components/AppContext.js.map +1 -0
- node_ui/node_modules/ink/build/components/Box.d.ts +62 -0
- node_ui/node_modules/ink/build/components/Box.js +20 -0
- node_ui/node_modules/ink/build/components/Box.js.map +1 -0
- node_ui/node_modules/ink/build/components/Color.js +62 -0
- node_ui/node_modules/ink/build/components/ErrorOverview.d.ts +6 -0
- node_ui/node_modules/ink/build/components/ErrorOverview.js +79 -0
- node_ui/node_modules/ink/build/components/ErrorOverview.js.map +1 -0
- node_ui/node_modules/ink/build/components/FocusContext.d.ts +17 -0
- node_ui/node_modules/ink/build/components/FocusContext.js +17 -0
- node_ui/node_modules/ink/build/components/FocusContext.js.map +1 -0
- node_ui/node_modules/ink/build/components/Newline.d.ts +13 -0
- node_ui/node_modules/ink/build/components/Newline.js +8 -0
- node_ui/node_modules/ink/build/components/Newline.js.map +1 -0
- node_ui/node_modules/ink/build/components/Spacer.d.ts +6 -0
- node_ui/node_modules/ink/build/components/Spacer.js +10 -0
- node_ui/node_modules/ink/build/components/Spacer.js.map +1 -0
- node_ui/node_modules/ink/build/components/Static.d.ts +31 -0
- node_ui/node_modules/ink/build/components/Static.js +33 -0
- node_ui/node_modules/ink/build/components/Static.js.map +1 -0
- node_ui/node_modules/ink/build/components/StderrContext.d.ts +19 -0
- node_ui/node_modules/ink/build/components/StderrContext.js +13 -0
- node_ui/node_modules/ink/build/components/StderrContext.js.map +1 -0
- node_ui/node_modules/ink/build/components/StdinContext.d.ts +26 -0
- node_ui/node_modules/ink/build/components/StdinContext.js +19 -0
- node_ui/node_modules/ink/build/components/StdinContext.js.map +1 -0
- node_ui/node_modules/ink/build/components/StdoutContext.d.ts +19 -0
- node_ui/node_modules/ink/build/components/StdoutContext.js +13 -0
- node_ui/node_modules/ink/build/components/StdoutContext.js.map +1 -0
- node_ui/node_modules/ink/build/components/Text.d.ts +49 -0
- node_ui/node_modules/ink/build/components/Text.js +40 -0
- node_ui/node_modules/ink/build/components/Text.js.map +1 -0
- node_ui/node_modules/ink/build/components/Transform.d.ts +15 -0
- node_ui/node_modules/ink/build/components/Transform.js +14 -0
- node_ui/node_modules/ink/build/components/Transform.js.map +1 -0
- node_ui/node_modules/ink/build/devtools-window-polyfill.d.ts +1 -0
- node_ui/node_modules/ink/build/devtools-window-polyfill.js +64 -0
- node_ui/node_modules/ink/build/devtools-window-polyfill.js.map +1 -0
- node_ui/node_modules/ink/build/devtools.d.ts +1 -0
- node_ui/node_modules/ink/build/devtools.js +9 -0
- node_ui/node_modules/ink/build/devtools.js.map +1 -0
- node_ui/node_modules/ink/build/dom.d.ts +42 -0
- node_ui/node_modules/ink/build/dom.js +117 -0
- node_ui/node_modules/ink/build/dom.js.map +1 -0
- node_ui/node_modules/ink/build/experimental/apply-style.js +140 -0
- node_ui/node_modules/ink/build/experimental/dom.js +123 -0
- node_ui/node_modules/ink/build/experimental/output.js +91 -0
- node_ui/node_modules/ink/build/experimental/reconciler.js +141 -0
- node_ui/node_modules/ink/build/experimental/renderer.js +81 -0
- node_ui/node_modules/ink/build/get-max-width.d.ts +3 -0
- node_ui/node_modules/ink/build/get-max-width.js +10 -0
- node_ui/node_modules/ink/build/get-max-width.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-app.d.ts +5 -0
- node_ui/node_modules/ink/build/hooks/use-app.js +8 -0
- node_ui/node_modules/ink/build/hooks/use-app.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-focus-manager.d.ts +34 -0
- node_ui/node_modules/ink/build/hooks/use-focus-manager.js +18 -0
- node_ui/node_modules/ink/build/hooks/use-focus-manager.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-focus.d.ts +34 -0
- node_ui/node_modules/ink/build/hooks/use-focus.js +47 -0
- node_ui/node_modules/ink/build/hooks/use-focus.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-input.d.ts +97 -0
- node_ui/node_modules/ink/build/hooks/use-input.js +96 -0
- node_ui/node_modules/ink/build/hooks/use-input.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-stderr.d.ts +5 -0
- node_ui/node_modules/ink/build/hooks/use-stderr.js +8 -0
- node_ui/node_modules/ink/build/hooks/use-stderr.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-stdin.d.ts +5 -0
- node_ui/node_modules/ink/build/hooks/use-stdin.js +8 -0
- node_ui/node_modules/ink/build/hooks/use-stdin.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/use-stdout.d.ts +5 -0
- node_ui/node_modules/ink/build/hooks/use-stdout.js +8 -0
- node_ui/node_modules/ink/build/hooks/use-stdout.js.map +1 -0
- node_ui/node_modules/ink/build/hooks/useInput.js +38 -0
- node_ui/node_modules/ink/build/index.d.ts +27 -0
- node_ui/node_modules/ink/build/index.js +16 -0
- node_ui/node_modules/ink/build/index.js.map +1 -0
- node_ui/node_modules/ink/build/ink.d.ts +38 -0
- node_ui/node_modules/ink/build/ink.js +235 -0
- node_ui/node_modules/ink/build/ink.js.map +1 -0
- node_ui/node_modules/ink/build/instance.js +205 -0
- node_ui/node_modules/ink/build/instances.d.ts +4 -0
- node_ui/node_modules/ink/build/instances.js +8 -0
- node_ui/node_modules/ink/build/instances.js.map +1 -0
- node_ui/node_modules/ink/build/log-update.d.ts +13 -0
- node_ui/node_modules/ink/build/log-update.js +37 -0
- node_ui/node_modules/ink/build/log-update.js.map +1 -0
- node_ui/node_modules/ink/build/measure-element.d.ts +16 -0
- node_ui/node_modules/ink/build/measure-element.js +9 -0
- node_ui/node_modules/ink/build/measure-element.js.map +1 -0
- node_ui/node_modules/ink/build/measure-text.d.ts +6 -0
- node_ui/node_modules/ink/build/measure-text.js +20 -0
- node_ui/node_modules/ink/build/measure-text.js.map +1 -0
- node_ui/node_modules/ink/build/output.d.ts +35 -0
- node_ui/node_modules/ink/build/output.js +148 -0
- node_ui/node_modules/ink/build/output.js.map +1 -0
- node_ui/node_modules/ink/build/parse-keypress.d.ts +15 -0
- node_ui/node_modules/ink/build/parse-keypress.js +225 -0
- node_ui/node_modules/ink/build/parse-keypress.js.map +1 -0
- node_ui/node_modules/ink/build/reconciler.d.ts +4 -0
- node_ui/node_modules/ink/build/reconciler.js +219 -0
- node_ui/node_modules/ink/build/reconciler.js.map +1 -0
- node_ui/node_modules/ink/build/render-border.d.ts +4 -0
- node_ui/node_modules/ink/build/render-border.js +73 -0
- node_ui/node_modules/ink/build/render-border.js.map +1 -0
- node_ui/node_modules/ink/build/render-node-to-output.d.ts +10 -0
- node_ui/node_modules/ink/build/render-node-to-output.js +99 -0
- node_ui/node_modules/ink/build/render-node-to-output.js.map +1 -0
- node_ui/node_modules/ink/build/render.d.ts +68 -0
- node_ui/node_modules/ink/build/render.js +48 -0
- node_ui/node_modules/ink/build/render.js.map +1 -0
- node_ui/node_modules/ink/build/renderer.d.ts +8 -0
- node_ui/node_modules/ink/build/renderer.js +36 -0
- node_ui/node_modules/ink/build/renderer.js.map +1 -0
- node_ui/node_modules/ink/build/squash-text-nodes.d.ts +3 -0
- node_ui/node_modules/ink/build/squash-text-nodes.js +35 -0
- node_ui/node_modules/ink/build/squash-text-nodes.js.map +1 -0
- node_ui/node_modules/ink/build/styles.d.ts +243 -0
- node_ui/node_modules/ink/build/styles.js +229 -0
- node_ui/node_modules/ink/build/styles.js.map +1 -0
- node_ui/node_modules/ink/build/wrap-text.d.ts +3 -0
- node_ui/node_modules/ink/build/wrap-text.js +31 -0
- node_ui/node_modules/ink/build/wrap-text.js.map +1 -0
- node_ui/node_modules/ink/license +9 -0
- node_ui/node_modules/ink/package.json +197 -0
- node_ui/node_modules/ink/readme.md +2153 -0
- node_ui/node_modules/ink-select-input/build/Indicator.d.ts +6 -0
- node_ui/node_modules/ink-select-input/build/Indicator.js +8 -0
- node_ui/node_modules/ink-select-input/build/Indicator.js.map +1 -0
- node_ui/node_modules/ink-select-input/build/Item.d.ts +7 -0
- node_ui/node_modules/ink-select-input/build/Item.js +7 -0
- node_ui/node_modules/ink-select-input/build/Item.js.map +1 -0
- node_ui/node_modules/ink-select-input/build/SelectInput.d.ts +49 -0
- node_ui/node_modules/ink-select-input/build/SelectInput.js +83 -0
- node_ui/node_modules/ink-select-input/build/SelectInput.js.map +1 -0
- node_ui/node_modules/ink-select-input/build/index.d.ts +3 -0
- node_ui/node_modules/ink-select-input/build/index.js +4 -0
- node_ui/node_modules/ink-select-input/build/index.js.map +1 -0
- node_ui/node_modules/ink-select-input/license +9 -0
- node_ui/node_modules/ink-select-input/node_modules/figures/index.d.ts +279 -0
- node_ui/node_modules/ink-select-input/node_modules/figures/index.js +292 -0
- node_ui/node_modules/ink-select-input/node_modules/figures/license +9 -0
- node_ui/node_modules/ink-select-input/node_modules/figures/package.json +49 -0
- node_ui/node_modules/ink-select-input/node_modules/figures/readme.md +337 -0
- node_ui/node_modules/ink-select-input/node_modules/is-unicode-supported/index.d.ts +12 -0
- node_ui/node_modules/ink-select-input/node_modules/is-unicode-supported/index.js +21 -0
- node_ui/node_modules/ink-select-input/node_modules/is-unicode-supported/license +9 -0
- node_ui/node_modules/ink-select-input/node_modules/is-unicode-supported/package.json +47 -0
- node_ui/node_modules/ink-select-input/node_modules/is-unicode-supported/readme.md +35 -0
- node_ui/node_modules/ink-select-input/package.json +83 -0
- node_ui/node_modules/ink-select-input/readme.md +98 -0
- node_ui/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
- node_ui/node_modules/is-fullwidth-code-point/index.js +40 -0
- node_ui/node_modules/is-fullwidth-code-point/license +9 -0
- node_ui/node_modules/is-fullwidth-code-point/package.json +45 -0
- node_ui/node_modules/is-fullwidth-code-point/readme.md +43 -0
- node_ui/node_modules/is-in-ci/cli.js +5 -0
- node_ui/node_modules/is-in-ci/index.d.ts +15 -0
- node_ui/node_modules/is-in-ci/index.js +11 -0
- node_ui/node_modules/is-in-ci/license +9 -0
- node_ui/node_modules/is-in-ci/package.json +48 -0
- node_ui/node_modules/is-in-ci/readme.md +43 -0
- node_ui/node_modules/is-unicode-supported/index.d.ts +12 -0
- node_ui/node_modules/is-unicode-supported/index.js +17 -0
- node_ui/node_modules/is-unicode-supported/license +9 -0
- node_ui/node_modules/is-unicode-supported/package.json +43 -0
- node_ui/node_modules/is-unicode-supported/readme.md +35 -0
- node_ui/node_modules/js-tokens/CHANGELOG.md +151 -0
- node_ui/node_modules/js-tokens/LICENSE +21 -0
- node_ui/node_modules/js-tokens/README.md +240 -0
- node_ui/node_modules/js-tokens/index.js +23 -0
- node_ui/node_modules/js-tokens/package.json +30 -0
- node_ui/node_modules/lodash/LICENSE +47 -0
- node_ui/node_modules/lodash/README.md +39 -0
- node_ui/node_modules/lodash/_DataView.js +7 -0
- node_ui/node_modules/lodash/_Hash.js +32 -0
- node_ui/node_modules/lodash/_LazyWrapper.js +28 -0
- node_ui/node_modules/lodash/_ListCache.js +32 -0
- node_ui/node_modules/lodash/_LodashWrapper.js +22 -0
- node_ui/node_modules/lodash/_Map.js +7 -0
- node_ui/node_modules/lodash/_MapCache.js +32 -0
- node_ui/node_modules/lodash/_Promise.js +7 -0
- node_ui/node_modules/lodash/_Set.js +7 -0
- node_ui/node_modules/lodash/_SetCache.js +27 -0
- node_ui/node_modules/lodash/_Stack.js +27 -0
- node_ui/node_modules/lodash/_Symbol.js +6 -0
- node_ui/node_modules/lodash/_Uint8Array.js +6 -0
- node_ui/node_modules/lodash/_WeakMap.js +7 -0
- node_ui/node_modules/lodash/_apply.js +21 -0
- node_ui/node_modules/lodash/_arrayAggregator.js +22 -0
- node_ui/node_modules/lodash/_arrayEach.js +22 -0
- node_ui/node_modules/lodash/_arrayEachRight.js +21 -0
- node_ui/node_modules/lodash/_arrayEvery.js +23 -0
- node_ui/node_modules/lodash/_arrayFilter.js +25 -0
- node_ui/node_modules/lodash/_arrayIncludes.js +17 -0
- node_ui/node_modules/lodash/_arrayIncludesWith.js +22 -0
- node_ui/node_modules/lodash/_arrayLikeKeys.js +49 -0
- node_ui/node_modules/lodash/_arrayMap.js +21 -0
- node_ui/node_modules/lodash/_arrayPush.js +20 -0
- node_ui/node_modules/lodash/_arrayReduce.js +26 -0
- node_ui/node_modules/lodash/_arrayReduceRight.js +24 -0
- node_ui/node_modules/lodash/_arraySample.js +15 -0
- node_ui/node_modules/lodash/_arraySampleSize.js +17 -0
- node_ui/node_modules/lodash/_arrayShuffle.js +15 -0
- node_ui/node_modules/lodash/_arraySome.js +23 -0
- node_ui/node_modules/lodash/_asciiSize.js +12 -0
- node_ui/node_modules/lodash/_asciiToArray.js +12 -0
- node_ui/node_modules/lodash/_asciiWords.js +15 -0
- node_ui/node_modules/lodash/_assignMergeValue.js +20 -0
- node_ui/node_modules/lodash/_assignValue.js +28 -0
- node_ui/node_modules/lodash/_assocIndexOf.js +21 -0
- node_ui/node_modules/lodash/_baseAggregator.js +21 -0
- node_ui/node_modules/lodash/_baseAssign.js +17 -0
- node_ui/node_modules/lodash/_baseAssignIn.js +17 -0
- node_ui/node_modules/lodash/_baseAssignValue.js +25 -0
- node_ui/node_modules/lodash/_baseAt.js +23 -0
- node_ui/node_modules/lodash/_baseClamp.js +22 -0
- node_ui/node_modules/lodash/_baseClone.js +166 -0
- node_ui/node_modules/lodash/_baseConforms.js +18 -0
- node_ui/node_modules/lodash/_baseConformsTo.js +27 -0
- node_ui/node_modules/lodash/_baseCreate.js +30 -0
- node_ui/node_modules/lodash/_baseDelay.js +21 -0
- node_ui/node_modules/lodash/_baseDifference.js +67 -0
- node_ui/node_modules/lodash/_baseEach.js +14 -0
- node_ui/node_modules/lodash/_baseEachRight.js +14 -0
- node_ui/node_modules/lodash/_baseEvery.js +21 -0
- node_ui/node_modules/lodash/_baseExtremum.js +32 -0
- node_ui/node_modules/lodash/_baseFill.js +32 -0
- node_ui/node_modules/lodash/_baseFilter.js +21 -0
- node_ui/node_modules/lodash/_baseFindIndex.js +24 -0
- node_ui/node_modules/lodash/_baseFindKey.js +23 -0
- node_ui/node_modules/lodash/_baseFlatten.js +38 -0
- node_ui/node_modules/lodash/_baseFor.js +16 -0
- node_ui/node_modules/lodash/_baseForOwn.js +16 -0
- node_ui/node_modules/lodash/_baseForOwnRight.js +16 -0
- node_ui/node_modules/lodash/_baseForRight.js +15 -0
- node_ui/node_modules/lodash/_baseFunctions.js +19 -0
- node_ui/node_modules/lodash/_baseGet.js +24 -0
- node_ui/node_modules/lodash/_baseGetAllKeys.js +20 -0
- node_ui/node_modules/lodash/_baseGetTag.js +28 -0
- node_ui/node_modules/lodash/_baseGt.js +14 -0
- node_ui/node_modules/lodash/_baseHas.js +19 -0
- node_ui/node_modules/lodash/_baseHasIn.js +13 -0
- node_ui/node_modules/lodash/_baseInRange.js +18 -0
- node_ui/node_modules/lodash/_baseIndexOf.js +20 -0
- node_ui/node_modules/lodash/_baseIndexOfWith.js +23 -0
- node_ui/node_modules/lodash/_baseIntersection.js +74 -0
- node_ui/node_modules/lodash/_baseInverter.js +21 -0
- node_ui/node_modules/lodash/_baseInvoke.js +24 -0
- node_ui/node_modules/lodash/_baseIsArguments.js +18 -0
- node_ui/node_modules/lodash/_baseIsArrayBuffer.js +17 -0
- node_ui/node_modules/lodash/_baseIsDate.js +18 -0
- node_ui/node_modules/lodash/_baseIsEqual.js +28 -0
- node_ui/node_modules/lodash/_baseIsEqualDeep.js +83 -0
- node_ui/node_modules/lodash/_baseIsMap.js +18 -0
- node_ui/node_modules/lodash/_baseIsMatch.js +62 -0
- node_ui/node_modules/lodash/_baseIsNaN.js +12 -0
- node_ui/node_modules/lodash/_baseIsNative.js +47 -0
- node_ui/node_modules/lodash/_baseIsRegExp.js +18 -0
- node_ui/node_modules/lodash/_baseIsSet.js +18 -0
- node_ui/node_modules/lodash/_baseIsTypedArray.js +60 -0
- node_ui/node_modules/lodash/_baseIteratee.js +31 -0
- node_ui/node_modules/lodash/_baseKeys.js +30 -0
- node_ui/node_modules/lodash/_baseKeysIn.js +33 -0
- node_ui/node_modules/lodash/_baseLodash.js +10 -0
- node_ui/node_modules/lodash/_baseLt.js +14 -0
- node_ui/node_modules/lodash/_baseMap.js +22 -0
- node_ui/node_modules/lodash/_baseMatches.js +22 -0
- node_ui/node_modules/lodash/_baseMatchesProperty.js +33 -0
- node_ui/node_modules/lodash/_baseMean.js +20 -0
- node_ui/node_modules/lodash/_baseMerge.js +42 -0
- node_ui/node_modules/lodash/_baseMergeDeep.js +94 -0
- node_ui/node_modules/lodash/_baseNth.js +20 -0
- node_ui/node_modules/lodash/_baseOrderBy.js +49 -0
- node_ui/node_modules/lodash/_basePick.js +19 -0
- node_ui/node_modules/lodash/_basePickBy.js +30 -0
- node_ui/node_modules/lodash/_baseProperty.js +14 -0
- node_ui/node_modules/lodash/_basePropertyDeep.js +16 -0
- node_ui/node_modules/lodash/_basePropertyOf.js +14 -0
- node_ui/node_modules/lodash/_basePullAll.js +51 -0
- node_ui/node_modules/lodash/_basePullAt.js +37 -0
- node_ui/node_modules/lodash/_baseRandom.js +18 -0
- node_ui/node_modules/lodash/_baseRange.js +28 -0
- node_ui/node_modules/lodash/_baseReduce.js +23 -0
- node_ui/node_modules/lodash/_baseRepeat.js +35 -0
- node_ui/node_modules/lodash/_baseRest.js +17 -0
- node_ui/node_modules/lodash/_baseSample.js +15 -0
- node_ui/node_modules/lodash/_baseSampleSize.js +18 -0
- node_ui/node_modules/lodash/_baseSet.js +51 -0
- node_ui/node_modules/lodash/_baseSetData.js +17 -0
- node_ui/node_modules/lodash/_baseSetToString.js +22 -0
- node_ui/node_modules/lodash/_baseShuffle.js +15 -0
- node_ui/node_modules/lodash/_baseSlice.js +31 -0
- node_ui/node_modules/lodash/_baseSome.js +22 -0
- node_ui/node_modules/lodash/_baseSortBy.js +21 -0
- node_ui/node_modules/lodash/_baseSortedIndex.js +42 -0
- node_ui/node_modules/lodash/_baseSortedIndexBy.js +67 -0
- node_ui/node_modules/lodash/_baseSortedUniq.js +30 -0
- node_ui/node_modules/lodash/_baseSum.js +24 -0
- node_ui/node_modules/lodash/_baseTimes.js +20 -0
- node_ui/node_modules/lodash/_baseToNumber.js +24 -0
- node_ui/node_modules/lodash/_baseToPairs.js +18 -0
- node_ui/node_modules/lodash/_baseToString.js +37 -0
- node_ui/node_modules/lodash/_baseTrim.js +19 -0
- node_ui/node_modules/lodash/_baseUnary.js +14 -0
- node_ui/node_modules/lodash/_baseUniq.js +72 -0
- node_ui/node_modules/lodash/_baseUnset.js +20 -0
- node_ui/node_modules/lodash/_baseUpdate.js +18 -0
- node_ui/node_modules/lodash/_baseValues.js +19 -0
- node_ui/node_modules/lodash/_baseWhile.js +26 -0
- node_ui/node_modules/lodash/_baseWrapperValue.js +25 -0
- node_ui/node_modules/lodash/_baseXor.js +36 -0
- node_ui/node_modules/lodash/_baseZipObject.js +23 -0
- node_ui/node_modules/lodash/_cacheHas.js +13 -0
- node_ui/node_modules/lodash/_castArrayLikeObject.js +14 -0
- node_ui/node_modules/lodash/_castFunction.js +14 -0
- node_ui/node_modules/lodash/_castPath.js +21 -0
- node_ui/node_modules/lodash/_castRest.js +14 -0
- node_ui/node_modules/lodash/_castSlice.js +18 -0
- node_ui/node_modules/lodash/_charsEndIndex.js +19 -0
- node_ui/node_modules/lodash/_charsStartIndex.js +20 -0
- node_ui/node_modules/lodash/_cloneArrayBuffer.js +16 -0
- node_ui/node_modules/lodash/_cloneBuffer.js +35 -0
- node_ui/node_modules/lodash/_cloneDataView.js +16 -0
- node_ui/node_modules/lodash/_cloneRegExp.js +17 -0
- node_ui/node_modules/lodash/_cloneSymbol.js +18 -0
- node_ui/node_modules/lodash/_cloneTypedArray.js +16 -0
- node_ui/node_modules/lodash/_compareAscending.js +41 -0
- node_ui/node_modules/lodash/_compareMultiple.js +44 -0
- node_ui/node_modules/lodash/_composeArgs.js +39 -0
- node_ui/node_modules/lodash/_composeArgsRight.js +41 -0
- node_ui/node_modules/lodash/_copyArray.js +20 -0
- node_ui/node_modules/lodash/_copyObject.js +40 -0
- node_ui/node_modules/lodash/_copySymbols.js +16 -0
- node_ui/node_modules/lodash/_copySymbolsIn.js +16 -0
- node_ui/node_modules/lodash/_coreJsData.js +6 -0
- node_ui/node_modules/lodash/_countHolders.js +21 -0
- node_ui/node_modules/lodash/_createAggregator.js +23 -0
- node_ui/node_modules/lodash/_createAssigner.js +37 -0
- node_ui/node_modules/lodash/_createBaseEach.js +32 -0
- node_ui/node_modules/lodash/_createBaseFor.js +25 -0
- node_ui/node_modules/lodash/_createBind.js +28 -0
- node_ui/node_modules/lodash/_createCaseFirst.js +33 -0
- node_ui/node_modules/lodash/_createCompounder.js +24 -0
- node_ui/node_modules/lodash/_createCtor.js +37 -0
- node_ui/node_modules/lodash/_createCurry.js +46 -0
- node_ui/node_modules/lodash/_createFind.js +25 -0
- node_ui/node_modules/lodash/_createFlow.js +78 -0
- node_ui/node_modules/lodash/_createHybrid.js +92 -0
- node_ui/node_modules/lodash/_createInverter.js +17 -0
- node_ui/node_modules/lodash/_createMathOperation.js +38 -0
- node_ui/node_modules/lodash/_createOver.js +27 -0
- node_ui/node_modules/lodash/_createPadding.js +33 -0
- node_ui/node_modules/lodash/_createPartial.js +43 -0
- node_ui/node_modules/lodash/_createRange.js +30 -0
- node_ui/node_modules/lodash/_createRecurry.js +56 -0
- node_ui/node_modules/lodash/_createRelationalOperation.js +20 -0
- node_ui/node_modules/lodash/_createRound.js +35 -0
- node_ui/node_modules/lodash/_createSet.js +19 -0
- node_ui/node_modules/lodash/_createToPairs.js +30 -0
- node_ui/node_modules/lodash/_createWrap.js +106 -0
- node_ui/node_modules/lodash/_customDefaultsAssignIn.js +29 -0
- node_ui/node_modules/lodash/_customDefaultsMerge.js +28 -0
- node_ui/node_modules/lodash/_customOmitClone.js +16 -0
- node_ui/node_modules/lodash/_deburrLetter.js +71 -0
- node_ui/node_modules/lodash/_defineProperty.js +11 -0
- node_ui/node_modules/lodash/_equalArrays.js +84 -0
- node_ui/node_modules/lodash/_equalByTag.js +112 -0
- node_ui/node_modules/lodash/_equalObjects.js +90 -0
- node_ui/node_modules/lodash/_escapeHtmlChar.js +21 -0
- node_ui/node_modules/lodash/_escapeStringChar.js +22 -0
- node_ui/node_modules/lodash/_flatRest.js +16 -0
- node_ui/node_modules/lodash/_freeGlobal.js +4 -0
- node_ui/node_modules/lodash/_getAllKeys.js +16 -0
- node_ui/node_modules/lodash/_getAllKeysIn.js +17 -0
- node_ui/node_modules/lodash/_getData.js +15 -0
- node_ui/node_modules/lodash/_getFuncName.js +31 -0
- node_ui/node_modules/lodash/_getHolder.js +13 -0
- node_ui/node_modules/lodash/_getMapData.js +18 -0
- node_ui/node_modules/lodash/_getMatchData.js +24 -0
- node_ui/node_modules/lodash/_getNative.js +17 -0
- node_ui/node_modules/lodash/_getPrototype.js +6 -0
- node_ui/node_modules/lodash/_getRawTag.js +46 -0
- node_ui/node_modules/lodash/_getSymbols.js +30 -0
- node_ui/node_modules/lodash/_getSymbolsIn.js +25 -0
- node_ui/node_modules/lodash/_getTag.js +58 -0
- node_ui/node_modules/lodash/_getValue.js +13 -0
- node_ui/node_modules/lodash/_getView.js +33 -0
- node_ui/node_modules/lodash/_getWrapDetails.js +17 -0
- node_ui/node_modules/lodash/_hasPath.js +39 -0
- node_ui/node_modules/lodash/_hasUnicode.js +26 -0
- node_ui/node_modules/lodash/_hasUnicodeWord.js +15 -0
- node_ui/node_modules/lodash/_hashClear.js +15 -0
- node_ui/node_modules/lodash/_hashDelete.js +17 -0
- node_ui/node_modules/lodash/_hashGet.js +30 -0
- node_ui/node_modules/lodash/_hashHas.js +23 -0
- node_ui/node_modules/lodash/_hashSet.js +23 -0
- node_ui/node_modules/lodash/_initCloneArray.js +26 -0
- node_ui/node_modules/lodash/_initCloneByTag.js +77 -0
- node_ui/node_modules/lodash/_initCloneObject.js +18 -0
- node_ui/node_modules/lodash/_insertWrapDetails.js +23 -0
- node_ui/node_modules/lodash/_isFlattenable.js +20 -0
- node_ui/node_modules/lodash/_isIndex.js +25 -0
- node_ui/node_modules/lodash/_isIterateeCall.js +30 -0
- node_ui/node_modules/lodash/_isKey.js +29 -0
- node_ui/node_modules/lodash/_isKeyable.js +15 -0
- node_ui/node_modules/lodash/_isLaziable.js +28 -0
- node_ui/node_modules/lodash/_isMaskable.js +14 -0
- node_ui/node_modules/lodash/_isMasked.js +20 -0
- node_ui/node_modules/lodash/_isPrototype.js +18 -0
- node_ui/node_modules/lodash/_isStrictComparable.js +15 -0
- node_ui/node_modules/lodash/_iteratorToArray.js +18 -0
- node_ui/node_modules/lodash/_lazyClone.js +23 -0
- node_ui/node_modules/lodash/_lazyReverse.js +23 -0
- node_ui/node_modules/lodash/_lazyValue.js +69 -0
- node_ui/node_modules/lodash/_listCacheClear.js +13 -0
- node_ui/node_modules/lodash/_listCacheDelete.js +35 -0
- node_ui/node_modules/lodash/_listCacheGet.js +19 -0
- node_ui/node_modules/lodash/_listCacheHas.js +16 -0
- node_ui/node_modules/lodash/_listCacheSet.js +26 -0
- node_ui/node_modules/lodash/_mapCacheClear.js +21 -0
- node_ui/node_modules/lodash/_mapCacheDelete.js +18 -0
- node_ui/node_modules/lodash/_mapCacheGet.js +16 -0
- node_ui/node_modules/lodash/_mapCacheHas.js +16 -0
- node_ui/node_modules/lodash/_mapCacheSet.js +22 -0
- node_ui/node_modules/lodash/_mapToArray.js +18 -0
- node_ui/node_modules/lodash/_matchesStrictComparable.js +20 -0
- node_ui/node_modules/lodash/_memoizeCapped.js +26 -0
- node_ui/node_modules/lodash/_mergeData.js +90 -0
- node_ui/node_modules/lodash/_metaMap.js +6 -0
- node_ui/node_modules/lodash/_nativeCreate.js +6 -0
- node_ui/node_modules/lodash/_nativeKeys.js +6 -0
- node_ui/node_modules/lodash/_nativeKeysIn.js +20 -0
- node_ui/node_modules/lodash/_nodeUtil.js +30 -0
- node_ui/node_modules/lodash/_objectToString.js +22 -0
- node_ui/node_modules/lodash/_overArg.js +15 -0
- node_ui/node_modules/lodash/_overRest.js +36 -0
- node_ui/node_modules/lodash/_parent.js +16 -0
- node_ui/node_modules/lodash/_reEscape.js +4 -0
- node_ui/node_modules/lodash/_reEvaluate.js +4 -0
- node_ui/node_modules/lodash/_reInterpolate.js +4 -0
- node_ui/node_modules/lodash/_realNames.js +4 -0
- node_ui/node_modules/lodash/_reorder.js +29 -0
- node_ui/node_modules/lodash/_replaceHolders.js +29 -0
- node_ui/node_modules/lodash/_root.js +9 -0
- node_ui/node_modules/lodash/_safeGet.js +21 -0
- node_ui/node_modules/lodash/_setCacheAdd.js +19 -0
- node_ui/node_modules/lodash/_setCacheHas.js +14 -0
- node_ui/node_modules/lodash/_setData.js +20 -0
- node_ui/node_modules/lodash/_setToArray.js +18 -0
- node_ui/node_modules/lodash/_setToPairs.js +18 -0
- node_ui/node_modules/lodash/_setToString.js +14 -0
- node_ui/node_modules/lodash/_setWrapToString.js +21 -0
- node_ui/node_modules/lodash/_shortOut.js +37 -0
- node_ui/node_modules/lodash/_shuffleSelf.js +28 -0
- node_ui/node_modules/lodash/_stackClear.js +15 -0
- node_ui/node_modules/lodash/_stackDelete.js +18 -0
- node_ui/node_modules/lodash/_stackGet.js +14 -0
- node_ui/node_modules/lodash/_stackHas.js +14 -0
- node_ui/node_modules/lodash/_stackSet.js +34 -0
- node_ui/node_modules/lodash/_strictIndexOf.js +23 -0
- node_ui/node_modules/lodash/_strictLastIndexOf.js +21 -0
- node_ui/node_modules/lodash/_stringSize.js +18 -0
- node_ui/node_modules/lodash/_stringToArray.js +18 -0
- node_ui/node_modules/lodash/_stringToPath.js +27 -0
- node_ui/node_modules/lodash/_toKey.js +21 -0
- node_ui/node_modules/lodash/_toSource.js +26 -0
- node_ui/node_modules/lodash/_trimmedEndIndex.js +19 -0
- node_ui/node_modules/lodash/_unescapeHtmlChar.js +21 -0
- node_ui/node_modules/lodash/_unicodeSize.js +44 -0
- node_ui/node_modules/lodash/_unicodeToArray.js +40 -0
- node_ui/node_modules/lodash/_unicodeWords.js +69 -0
- node_ui/node_modules/lodash/_updateWrapDetails.js +46 -0
- node_ui/node_modules/lodash/_wrapperClone.js +23 -0
- node_ui/node_modules/lodash/add.js +22 -0
- node_ui/node_modules/lodash/after.js +42 -0
- node_ui/node_modules/lodash/array.js +67 -0
- node_ui/node_modules/lodash/ary.js +29 -0
- node_ui/node_modules/lodash/assign.js +58 -0
- node_ui/node_modules/lodash/assignIn.js +40 -0
- node_ui/node_modules/lodash/assignInWith.js +38 -0
- node_ui/node_modules/lodash/assignWith.js +37 -0
- node_ui/node_modules/lodash/at.js +23 -0
- node_ui/node_modules/lodash/attempt.js +35 -0
- node_ui/node_modules/lodash/before.js +40 -0
- node_ui/node_modules/lodash/bind.js +57 -0
- node_ui/node_modules/lodash/bindAll.js +41 -0
- node_ui/node_modules/lodash/bindKey.js +68 -0
- node_ui/node_modules/lodash/camelCase.js +29 -0
- node_ui/node_modules/lodash/capitalize.js +23 -0
- node_ui/node_modules/lodash/castArray.js +44 -0
- node_ui/node_modules/lodash/ceil.js +26 -0
- node_ui/node_modules/lodash/chain.js +38 -0
- node_ui/node_modules/lodash/chunk.js +50 -0
- node_ui/node_modules/lodash/clamp.js +39 -0
- node_ui/node_modules/lodash/clone.js +36 -0
- node_ui/node_modules/lodash/cloneDeep.js +29 -0
- node_ui/node_modules/lodash/cloneDeepWith.js +40 -0
- node_ui/node_modules/lodash/cloneWith.js +42 -0
- node_ui/node_modules/lodash/collection.js +30 -0
- node_ui/node_modules/lodash/commit.js +33 -0
- node_ui/node_modules/lodash/compact.js +31 -0
- node_ui/node_modules/lodash/concat.js +43 -0
- node_ui/node_modules/lodash/cond.js +60 -0
- node_ui/node_modules/lodash/conforms.js +35 -0
- node_ui/node_modules/lodash/conformsTo.js +32 -0
- node_ui/node_modules/lodash/constant.js +26 -0
- node_ui/node_modules/lodash/core.js +3877 -0
- node_ui/node_modules/lodash/core.min.js +29 -0
- node_ui/node_modules/lodash/countBy.js +40 -0
- node_ui/node_modules/lodash/create.js +43 -0
- node_ui/node_modules/lodash/curry.js +57 -0
- node_ui/node_modules/lodash/curryRight.js +54 -0
- node_ui/node_modules/lodash/date.js +3 -0
- node_ui/node_modules/lodash/debounce.js +191 -0
- node_ui/node_modules/lodash/deburr.js +45 -0
- node_ui/node_modules/lodash/defaultTo.js +25 -0
- node_ui/node_modules/lodash/defaults.js +64 -0
- node_ui/node_modules/lodash/defaultsDeep.js +30 -0
- node_ui/node_modules/lodash/defer.js +26 -0
- node_ui/node_modules/lodash/delay.js +28 -0
- node_ui/node_modules/lodash/difference.js +33 -0
- node_ui/node_modules/lodash/differenceBy.js +44 -0
- node_ui/node_modules/lodash/differenceWith.js +40 -0
- node_ui/node_modules/lodash/divide.js +22 -0
- node_ui/node_modules/lodash/drop.js +38 -0
- node_ui/node_modules/lodash/dropRight.js +39 -0
- node_ui/node_modules/lodash/dropRightWhile.js +45 -0
- node_ui/node_modules/lodash/dropWhile.js +45 -0
- node_ui/node_modules/lodash/each.js +1 -0
- node_ui/node_modules/lodash/eachRight.js +1 -0
- node_ui/node_modules/lodash/endsWith.js +43 -0
- node_ui/node_modules/lodash/entries.js +1 -0
- node_ui/node_modules/lodash/entriesIn.js +1 -0
- node_ui/node_modules/lodash/eq.js +37 -0
- node_ui/node_modules/lodash/escape.js +43 -0
- node_ui/node_modules/lodash/escapeRegExp.js +32 -0
- node_ui/node_modules/lodash/every.js +56 -0
- node_ui/node_modules/lodash/extend.js +1 -0
- node_ui/node_modules/lodash/extendWith.js +1 -0
- node_ui/node_modules/lodash/fill.js +45 -0
- node_ui/node_modules/lodash/filter.js +52 -0
- node_ui/node_modules/lodash/find.js +42 -0
- node_ui/node_modules/lodash/findIndex.js +55 -0
- node_ui/node_modules/lodash/findKey.js +44 -0
- node_ui/node_modules/lodash/findLast.js +25 -0
- node_ui/node_modules/lodash/findLastIndex.js +59 -0
- node_ui/node_modules/lodash/findLastKey.js +44 -0
- node_ui/node_modules/lodash/first.js +1 -0
- node_ui/node_modules/lodash/flake.lock +40 -0
- node_ui/node_modules/lodash/flake.nix +20 -0
- node_ui/node_modules/lodash/flatMap.js +29 -0
- node_ui/node_modules/lodash/flatMapDeep.js +31 -0
- node_ui/node_modules/lodash/flatMapDepth.js +31 -0
- node_ui/node_modules/lodash/flatten.js +22 -0
- node_ui/node_modules/lodash/flattenDeep.js +25 -0
- node_ui/node_modules/lodash/flattenDepth.js +33 -0
- node_ui/node_modules/lodash/flip.js +28 -0
- node_ui/node_modules/lodash/floor.js +26 -0
- node_ui/node_modules/lodash/flow.js +27 -0
- node_ui/node_modules/lodash/flowRight.js +26 -0
- node_ui/node_modules/lodash/forEach.js +41 -0
- node_ui/node_modules/lodash/forEachRight.js +31 -0
- node_ui/node_modules/lodash/forIn.js +39 -0
- node_ui/node_modules/lodash/forInRight.js +37 -0
- node_ui/node_modules/lodash/forOwn.js +36 -0
- node_ui/node_modules/lodash/forOwnRight.js +34 -0
- node_ui/node_modules/lodash/fp/F.js +1 -0
- node_ui/node_modules/lodash/fp/T.js +1 -0
- node_ui/node_modules/lodash/fp/__.js +1 -0
- node_ui/node_modules/lodash/fp/_baseConvert.js +569 -0
- node_ui/node_modules/lodash/fp/_convertBrowser.js +18 -0
- node_ui/node_modules/lodash/fp/_falseOptions.js +7 -0
- node_ui/node_modules/lodash/fp/_mapping.js +358 -0
- node_ui/node_modules/lodash/fp/_util.js +16 -0
- node_ui/node_modules/lodash/fp/add.js +5 -0
- node_ui/node_modules/lodash/fp/after.js +5 -0
- node_ui/node_modules/lodash/fp/all.js +1 -0
- node_ui/node_modules/lodash/fp/allPass.js +1 -0
- node_ui/node_modules/lodash/fp/always.js +1 -0
- node_ui/node_modules/lodash/fp/any.js +1 -0
- node_ui/node_modules/lodash/fp/anyPass.js +1 -0
- node_ui/node_modules/lodash/fp/apply.js +1 -0
- node_ui/node_modules/lodash/fp/array.js +2 -0
- node_ui/node_modules/lodash/fp/ary.js +5 -0
- node_ui/node_modules/lodash/fp/assign.js +5 -0
- node_ui/node_modules/lodash/fp/assignAll.js +5 -0
- node_ui/node_modules/lodash/fp/assignAllWith.js +5 -0
- node_ui/node_modules/lodash/fp/assignIn.js +5 -0
- node_ui/node_modules/lodash/fp/assignInAll.js +5 -0
- node_ui/node_modules/lodash/fp/assignInAllWith.js +5 -0
- node_ui/node_modules/lodash/fp/assignInWith.js +5 -0
- node_ui/node_modules/lodash/fp/assignWith.js +5 -0
- node_ui/node_modules/lodash/fp/assoc.js +1 -0
- node_ui/node_modules/lodash/fp/assocPath.js +1 -0
- node_ui/node_modules/lodash/fp/at.js +5 -0
- node_ui/node_modules/lodash/fp/attempt.js +5 -0
- node_ui/node_modules/lodash/fp/before.js +5 -0
- node_ui/node_modules/lodash/fp/bind.js +5 -0
- node_ui/node_modules/lodash/fp/bindAll.js +5 -0
- node_ui/node_modules/lodash/fp/bindKey.js +5 -0
- node_ui/node_modules/lodash/fp/camelCase.js +5 -0
- node_ui/node_modules/lodash/fp/capitalize.js +5 -0
- node_ui/node_modules/lodash/fp/castArray.js +5 -0
- node_ui/node_modules/lodash/fp/ceil.js +5 -0
- node_ui/node_modules/lodash/fp/chain.js +5 -0
- node_ui/node_modules/lodash/fp/chunk.js +5 -0
- node_ui/node_modules/lodash/fp/clamp.js +5 -0
- node_ui/node_modules/lodash/fp/clone.js +5 -0
- node_ui/node_modules/lodash/fp/cloneDeep.js +5 -0
- node_ui/node_modules/lodash/fp/cloneDeepWith.js +5 -0
- node_ui/node_modules/lodash/fp/cloneWith.js +5 -0
- node_ui/node_modules/lodash/fp/collection.js +2 -0
- node_ui/node_modules/lodash/fp/commit.js +5 -0
- node_ui/node_modules/lodash/fp/compact.js +5 -0
- node_ui/node_modules/lodash/fp/complement.js +1 -0
- node_ui/node_modules/lodash/fp/compose.js +1 -0
- node_ui/node_modules/lodash/fp/concat.js +5 -0
- node_ui/node_modules/lodash/fp/cond.js +5 -0
- node_ui/node_modules/lodash/fp/conforms.js +1 -0
- node_ui/node_modules/lodash/fp/conformsTo.js +5 -0
- node_ui/node_modules/lodash/fp/constant.js +5 -0
- node_ui/node_modules/lodash/fp/contains.js +1 -0
- node_ui/node_modules/lodash/fp/convert.js +18 -0
- node_ui/node_modules/lodash/fp/countBy.js +5 -0
- node_ui/node_modules/lodash/fp/create.js +5 -0
- node_ui/node_modules/lodash/fp/curry.js +5 -0
- node_ui/node_modules/lodash/fp/curryN.js +5 -0
- node_ui/node_modules/lodash/fp/curryRight.js +5 -0
- node_ui/node_modules/lodash/fp/curryRightN.js +5 -0
- node_ui/node_modules/lodash/fp/date.js +2 -0
- node_ui/node_modules/lodash/fp/debounce.js +5 -0
- node_ui/node_modules/lodash/fp/deburr.js +5 -0
- node_ui/node_modules/lodash/fp/defaultTo.js +5 -0
- node_ui/node_modules/lodash/fp/defaults.js +5 -0
- node_ui/node_modules/lodash/fp/defaultsAll.js +5 -0
- node_ui/node_modules/lodash/fp/defaultsDeep.js +5 -0
- node_ui/node_modules/lodash/fp/defaultsDeepAll.js +5 -0
- node_ui/node_modules/lodash/fp/defer.js +5 -0
- node_ui/node_modules/lodash/fp/delay.js +5 -0
- node_ui/node_modules/lodash/fp/difference.js +5 -0
- node_ui/node_modules/lodash/fp/differenceBy.js +5 -0
- node_ui/node_modules/lodash/fp/differenceWith.js +5 -0
- node_ui/node_modules/lodash/fp/dissoc.js +1 -0
- node_ui/node_modules/lodash/fp/dissocPath.js +1 -0
- node_ui/node_modules/lodash/fp/divide.js +5 -0
- node_ui/node_modules/lodash/fp/drop.js +5 -0
- node_ui/node_modules/lodash/fp/dropLast.js +1 -0
- node_ui/node_modules/lodash/fp/dropLastWhile.js +1 -0
- node_ui/node_modules/lodash/fp/dropRight.js +5 -0
- node_ui/node_modules/lodash/fp/dropRightWhile.js +5 -0
- node_ui/node_modules/lodash/fp/dropWhile.js +5 -0
- node_ui/node_modules/lodash/fp/each.js +1 -0
- node_ui/node_modules/lodash/fp/eachRight.js +1 -0
- node_ui/node_modules/lodash/fp/endsWith.js +5 -0
- node_ui/node_modules/lodash/fp/entries.js +1 -0
- node_ui/node_modules/lodash/fp/entriesIn.js +1 -0
- node_ui/node_modules/lodash/fp/eq.js +5 -0
- node_ui/node_modules/lodash/fp/equals.js +1 -0
- node_ui/node_modules/lodash/fp/escape.js +5 -0
- node_ui/node_modules/lodash/fp/escapeRegExp.js +5 -0
- node_ui/node_modules/lodash/fp/every.js +5 -0
- node_ui/node_modules/lodash/fp/extend.js +1 -0
- node_ui/node_modules/lodash/fp/extendAll.js +1 -0
- node_ui/node_modules/lodash/fp/extendAllWith.js +1 -0
- node_ui/node_modules/lodash/fp/extendWith.js +1 -0
- node_ui/node_modules/lodash/fp/fill.js +5 -0
- node_ui/node_modules/lodash/fp/filter.js +5 -0
- node_ui/node_modules/lodash/fp/find.js +5 -0
- node_ui/node_modules/lodash/fp/findFrom.js +5 -0
- node_ui/node_modules/lodash/fp/findIndex.js +5 -0
- node_ui/node_modules/lodash/fp/findIndexFrom.js +5 -0
- node_ui/node_modules/lodash/fp/findKey.js +5 -0
- node_ui/node_modules/lodash/fp/findLast.js +5 -0
- node_ui/node_modules/lodash/fp/findLastFrom.js +5 -0
- node_ui/node_modules/lodash/fp/findLastIndex.js +5 -0
- node_ui/node_modules/lodash/fp/findLastIndexFrom.js +5 -0
- node_ui/node_modules/lodash/fp/findLastKey.js +5 -0
- node_ui/node_modules/lodash/fp/first.js +1 -0
- node_ui/node_modules/lodash/fp/flatMap.js +5 -0
- node_ui/node_modules/lodash/fp/flatMapDeep.js +5 -0
- node_ui/node_modules/lodash/fp/flatMapDepth.js +5 -0
- node_ui/node_modules/lodash/fp/flatten.js +5 -0
- node_ui/node_modules/lodash/fp/flattenDeep.js +5 -0
- node_ui/node_modules/lodash/fp/flattenDepth.js +5 -0
- node_ui/node_modules/lodash/fp/flip.js +5 -0
- node_ui/node_modules/lodash/fp/floor.js +5 -0
- node_ui/node_modules/lodash/fp/flow.js +5 -0
- node_ui/node_modules/lodash/fp/flowRight.js +5 -0
- node_ui/node_modules/lodash/fp/forEach.js +5 -0
- node_ui/node_modules/lodash/fp/forEachRight.js +5 -0
- node_ui/node_modules/lodash/fp/forIn.js +5 -0
- node_ui/node_modules/lodash/fp/forInRight.js +5 -0
- node_ui/node_modules/lodash/fp/forOwn.js +5 -0
- node_ui/node_modules/lodash/fp/forOwnRight.js +5 -0
- node_ui/node_modules/lodash/fp/fromPairs.js +5 -0
- node_ui/node_modules/lodash/fp/function.js +2 -0
- node_ui/node_modules/lodash/fp/functions.js +5 -0
- node_ui/node_modules/lodash/fp/functionsIn.js +5 -0
- node_ui/node_modules/lodash/fp/get.js +5 -0
- node_ui/node_modules/lodash/fp/getOr.js +5 -0
- node_ui/node_modules/lodash/fp/groupBy.js +5 -0
- node_ui/node_modules/lodash/fp/gt.js +5 -0
- node_ui/node_modules/lodash/fp/gte.js +5 -0
- node_ui/node_modules/lodash/fp/has.js +5 -0
- node_ui/node_modules/lodash/fp/hasIn.js +5 -0
- node_ui/node_modules/lodash/fp/head.js +5 -0
- node_ui/node_modules/lodash/fp/identical.js +1 -0
- node_ui/node_modules/lodash/fp/identity.js +5 -0
- node_ui/node_modules/lodash/fp/inRange.js +5 -0
- node_ui/node_modules/lodash/fp/includes.js +5 -0
- node_ui/node_modules/lodash/fp/includesFrom.js +5 -0
- node_ui/node_modules/lodash/fp/indexBy.js +1 -0
- node_ui/node_modules/lodash/fp/indexOf.js +5 -0
- node_ui/node_modules/lodash/fp/indexOfFrom.js +5 -0
- node_ui/node_modules/lodash/fp/init.js +1 -0
- node_ui/node_modules/lodash/fp/initial.js +5 -0
- node_ui/node_modules/lodash/fp/intersection.js +5 -0
- node_ui/node_modules/lodash/fp/intersectionBy.js +5 -0
- node_ui/node_modules/lodash/fp/intersectionWith.js +5 -0
- node_ui/node_modules/lodash/fp/invert.js +5 -0
- node_ui/node_modules/lodash/fp/invertBy.js +5 -0
- node_ui/node_modules/lodash/fp/invertObj.js +1 -0
- node_ui/node_modules/lodash/fp/invoke.js +5 -0
- node_ui/node_modules/lodash/fp/invokeArgs.js +5 -0
- node_ui/node_modules/lodash/fp/invokeArgsMap.js +5 -0
- node_ui/node_modules/lodash/fp/invokeMap.js +5 -0
- node_ui/node_modules/lodash/fp/isArguments.js +5 -0
- node_ui/node_modules/lodash/fp/isArray.js +5 -0
- node_ui/node_modules/lodash/fp/isArrayBuffer.js +5 -0
- node_ui/node_modules/lodash/fp/isArrayLike.js +5 -0
- node_ui/node_modules/lodash/fp/isArrayLikeObject.js +5 -0
- node_ui/node_modules/lodash/fp/isBoolean.js +5 -0
- node_ui/node_modules/lodash/fp/isBuffer.js +5 -0
- node_ui/node_modules/lodash/fp/isDate.js +5 -0
- node_ui/node_modules/lodash/fp/isElement.js +5 -0
- node_ui/node_modules/lodash/fp/isEmpty.js +5 -0
- node_ui/node_modules/lodash/fp/isEqual.js +5 -0
- node_ui/node_modules/lodash/fp/isEqualWith.js +5 -0
- node_ui/node_modules/lodash/fp/isError.js +5 -0
- node_ui/node_modules/lodash/fp/isFinite.js +5 -0
- node_ui/node_modules/lodash/fp/isFunction.js +5 -0
- node_ui/node_modules/lodash/fp/isInteger.js +5 -0
- node_ui/node_modules/lodash/fp/isLength.js +5 -0
- node_ui/node_modules/lodash/fp/isMap.js +5 -0
- node_ui/node_modules/lodash/fp/isMatch.js +5 -0
- node_ui/node_modules/lodash/fp/isMatchWith.js +5 -0
- node_ui/node_modules/lodash/fp/isNaN.js +5 -0
- node_ui/node_modules/lodash/fp/isNative.js +5 -0
- node_ui/node_modules/lodash/fp/isNil.js +5 -0
- node_ui/node_modules/lodash/fp/isNull.js +5 -0
- node_ui/node_modules/lodash/fp/isNumber.js +5 -0
- node_ui/node_modules/lodash/fp/isObject.js +5 -0
- node_ui/node_modules/lodash/fp/isObjectLike.js +5 -0
- node_ui/node_modules/lodash/fp/isPlainObject.js +5 -0
- node_ui/node_modules/lodash/fp/isRegExp.js +5 -0
- node_ui/node_modules/lodash/fp/isSafeInteger.js +5 -0
- node_ui/node_modules/lodash/fp/isSet.js +5 -0
- node_ui/node_modules/lodash/fp/isString.js +5 -0
- node_ui/node_modules/lodash/fp/isSymbol.js +5 -0
- node_ui/node_modules/lodash/fp/isTypedArray.js +5 -0
- node_ui/node_modules/lodash/fp/isUndefined.js +5 -0
- node_ui/node_modules/lodash/fp/isWeakMap.js +5 -0
- node_ui/node_modules/lodash/fp/isWeakSet.js +5 -0
- node_ui/node_modules/lodash/fp/iteratee.js +5 -0
- node_ui/node_modules/lodash/fp/join.js +5 -0
- node_ui/node_modules/lodash/fp/juxt.js +1 -0
- node_ui/node_modules/lodash/fp/kebabCase.js +5 -0
- node_ui/node_modules/lodash/fp/keyBy.js +5 -0
- node_ui/node_modules/lodash/fp/keys.js +5 -0
- node_ui/node_modules/lodash/fp/keysIn.js +5 -0
- node_ui/node_modules/lodash/fp/lang.js +2 -0
- node_ui/node_modules/lodash/fp/last.js +5 -0
- node_ui/node_modules/lodash/fp/lastIndexOf.js +5 -0
- node_ui/node_modules/lodash/fp/lastIndexOfFrom.js +5 -0
- node_ui/node_modules/lodash/fp/lowerCase.js +5 -0
- node_ui/node_modules/lodash/fp/lowerFirst.js +5 -0
- node_ui/node_modules/lodash/fp/lt.js +5 -0
- node_ui/node_modules/lodash/fp/lte.js +5 -0
- node_ui/node_modules/lodash/fp/map.js +5 -0
- node_ui/node_modules/lodash/fp/mapKeys.js +5 -0
- node_ui/node_modules/lodash/fp/mapValues.js +5 -0
- node_ui/node_modules/lodash/fp/matches.js +1 -0
- node_ui/node_modules/lodash/fp/matchesProperty.js +5 -0
- node_ui/node_modules/lodash/fp/math.js +2 -0
- node_ui/node_modules/lodash/fp/max.js +5 -0
- node_ui/node_modules/lodash/fp/maxBy.js +5 -0
- node_ui/node_modules/lodash/fp/mean.js +5 -0
- node_ui/node_modules/lodash/fp/meanBy.js +5 -0
- node_ui/node_modules/lodash/fp/memoize.js +5 -0
- node_ui/node_modules/lodash/fp/merge.js +5 -0
- node_ui/node_modules/lodash/fp/mergeAll.js +5 -0
- node_ui/node_modules/lodash/fp/mergeAllWith.js +5 -0
- node_ui/node_modules/lodash/fp/mergeWith.js +5 -0
- node_ui/node_modules/lodash/fp/method.js +5 -0
- node_ui/node_modules/lodash/fp/methodOf.js +5 -0
- node_ui/node_modules/lodash/fp/min.js +5 -0
- node_ui/node_modules/lodash/fp/minBy.js +5 -0
- node_ui/node_modules/lodash/fp/mixin.js +5 -0
- node_ui/node_modules/lodash/fp/multiply.js +5 -0
- node_ui/node_modules/lodash/fp/nAry.js +1 -0
- node_ui/node_modules/lodash/fp/negate.js +5 -0
- node_ui/node_modules/lodash/fp/next.js +5 -0
- node_ui/node_modules/lodash/fp/noop.js +5 -0
- node_ui/node_modules/lodash/fp/now.js +5 -0
- node_ui/node_modules/lodash/fp/nth.js +5 -0
- node_ui/node_modules/lodash/fp/nthArg.js +5 -0
- node_ui/node_modules/lodash/fp/number.js +2 -0
- node_ui/node_modules/lodash/fp/object.js +2 -0
- node_ui/node_modules/lodash/fp/omit.js +5 -0
- node_ui/node_modules/lodash/fp/omitAll.js +1 -0
- node_ui/node_modules/lodash/fp/omitBy.js +5 -0
- node_ui/node_modules/lodash/fp/once.js +5 -0
- node_ui/node_modules/lodash/fp/orderBy.js +5 -0
- node_ui/node_modules/lodash/fp/over.js +5 -0
- node_ui/node_modules/lodash/fp/overArgs.js +5 -0
- node_ui/node_modules/lodash/fp/overEvery.js +5 -0
- node_ui/node_modules/lodash/fp/overSome.js +5 -0
- node_ui/node_modules/lodash/fp/pad.js +5 -0
- node_ui/node_modules/lodash/fp/padChars.js +5 -0
- node_ui/node_modules/lodash/fp/padCharsEnd.js +5 -0
- node_ui/node_modules/lodash/fp/padCharsStart.js +5 -0
- node_ui/node_modules/lodash/fp/padEnd.js +5 -0
- node_ui/node_modules/lodash/fp/padStart.js +5 -0
- node_ui/node_modules/lodash/fp/parseInt.js +5 -0
- node_ui/node_modules/lodash/fp/partial.js +5 -0
- node_ui/node_modules/lodash/fp/partialRight.js +5 -0
- node_ui/node_modules/lodash/fp/partition.js +5 -0
- node_ui/node_modules/lodash/fp/path.js +1 -0
- node_ui/node_modules/lodash/fp/pathEq.js +1 -0
- node_ui/node_modules/lodash/fp/pathOr.js +1 -0
- node_ui/node_modules/lodash/fp/paths.js +1 -0
- node_ui/node_modules/lodash/fp/pick.js +5 -0
- node_ui/node_modules/lodash/fp/pickAll.js +1 -0
- node_ui/node_modules/lodash/fp/pickBy.js +5 -0
- node_ui/node_modules/lodash/fp/pipe.js +1 -0
- node_ui/node_modules/lodash/fp/placeholder.js +6 -0
- node_ui/node_modules/lodash/fp/plant.js +5 -0
- node_ui/node_modules/lodash/fp/pluck.js +1 -0
- node_ui/node_modules/lodash/fp/prop.js +1 -0
- node_ui/node_modules/lodash/fp/propEq.js +1 -0
- node_ui/node_modules/lodash/fp/propOr.js +1 -0
- node_ui/node_modules/lodash/fp/property.js +1 -0
- node_ui/node_modules/lodash/fp/propertyOf.js +5 -0
- node_ui/node_modules/lodash/fp/props.js +1 -0
- node_ui/node_modules/lodash/fp/pull.js +5 -0
- node_ui/node_modules/lodash/fp/pullAll.js +5 -0
- node_ui/node_modules/lodash/fp/pullAllBy.js +5 -0
- node_ui/node_modules/lodash/fp/pullAllWith.js +5 -0
- node_ui/node_modules/lodash/fp/pullAt.js +5 -0
- node_ui/node_modules/lodash/fp/random.js +5 -0
- node_ui/node_modules/lodash/fp/range.js +5 -0
- node_ui/node_modules/lodash/fp/rangeRight.js +5 -0
- node_ui/node_modules/lodash/fp/rangeStep.js +5 -0
- node_ui/node_modules/lodash/fp/rangeStepRight.js +5 -0
- node_ui/node_modules/lodash/fp/rearg.js +5 -0
- node_ui/node_modules/lodash/fp/reduce.js +5 -0
- node_ui/node_modules/lodash/fp/reduceRight.js +5 -0
- node_ui/node_modules/lodash/fp/reject.js +5 -0
- node_ui/node_modules/lodash/fp/remove.js +5 -0
- node_ui/node_modules/lodash/fp/repeat.js +5 -0
- node_ui/node_modules/lodash/fp/replace.js +5 -0
- node_ui/node_modules/lodash/fp/rest.js +5 -0
- node_ui/node_modules/lodash/fp/restFrom.js +5 -0
- node_ui/node_modules/lodash/fp/result.js +5 -0
- node_ui/node_modules/lodash/fp/reverse.js +5 -0
- node_ui/node_modules/lodash/fp/round.js +5 -0
- node_ui/node_modules/lodash/fp/sample.js +5 -0
- node_ui/node_modules/lodash/fp/sampleSize.js +5 -0
- node_ui/node_modules/lodash/fp/seq.js +2 -0
- node_ui/node_modules/lodash/fp/set.js +5 -0
- node_ui/node_modules/lodash/fp/setWith.js +5 -0
- node_ui/node_modules/lodash/fp/shuffle.js +5 -0
- node_ui/node_modules/lodash/fp/size.js +5 -0
- node_ui/node_modules/lodash/fp/slice.js +5 -0
- node_ui/node_modules/lodash/fp/snakeCase.js +5 -0
- node_ui/node_modules/lodash/fp/some.js +5 -0
- node_ui/node_modules/lodash/fp/sortBy.js +5 -0
- node_ui/node_modules/lodash/fp/sortedIndex.js +5 -0
- node_ui/node_modules/lodash/fp/sortedIndexBy.js +5 -0
- node_ui/node_modules/lodash/fp/sortedIndexOf.js +5 -0
- node_ui/node_modules/lodash/fp/sortedLastIndex.js +5 -0
- node_ui/node_modules/lodash/fp/sortedLastIndexBy.js +5 -0
- node_ui/node_modules/lodash/fp/sortedLastIndexOf.js +5 -0
- node_ui/node_modules/lodash/fp/sortedUniq.js +5 -0
- node_ui/node_modules/lodash/fp/sortedUniqBy.js +5 -0
- node_ui/node_modules/lodash/fp/split.js +5 -0
- node_ui/node_modules/lodash/fp/spread.js +5 -0
- node_ui/node_modules/lodash/fp/spreadFrom.js +5 -0
- node_ui/node_modules/lodash/fp/startCase.js +5 -0
- node_ui/node_modules/lodash/fp/startsWith.js +5 -0
- node_ui/node_modules/lodash/fp/string.js +2 -0
- node_ui/node_modules/lodash/fp/stubArray.js +5 -0
- node_ui/node_modules/lodash/fp/stubFalse.js +5 -0
- node_ui/node_modules/lodash/fp/stubObject.js +5 -0
- node_ui/node_modules/lodash/fp/stubString.js +5 -0
- node_ui/node_modules/lodash/fp/stubTrue.js +5 -0
- node_ui/node_modules/lodash/fp/subtract.js +5 -0
- node_ui/node_modules/lodash/fp/sum.js +5 -0
- node_ui/node_modules/lodash/fp/sumBy.js +5 -0
- node_ui/node_modules/lodash/fp/symmetricDifference.js +1 -0
- node_ui/node_modules/lodash/fp/symmetricDifferenceBy.js +1 -0
- node_ui/node_modules/lodash/fp/symmetricDifferenceWith.js +1 -0
- node_ui/node_modules/lodash/fp/tail.js +5 -0
- node_ui/node_modules/lodash/fp/take.js +5 -0
- node_ui/node_modules/lodash/fp/takeLast.js +1 -0
- node_ui/node_modules/lodash/fp/takeLastWhile.js +1 -0
- node_ui/node_modules/lodash/fp/takeRight.js +5 -0
- node_ui/node_modules/lodash/fp/takeRightWhile.js +5 -0
- node_ui/node_modules/lodash/fp/takeWhile.js +5 -0
- node_ui/node_modules/lodash/fp/tap.js +5 -0
- node_ui/node_modules/lodash/fp/template.js +5 -0
- node_ui/node_modules/lodash/fp/templateSettings.js +5 -0
- node_ui/node_modules/lodash/fp/throttle.js +5 -0
- node_ui/node_modules/lodash/fp/thru.js +5 -0
- node_ui/node_modules/lodash/fp/times.js +5 -0
- node_ui/node_modules/lodash/fp/toArray.js +5 -0
- node_ui/node_modules/lodash/fp/toFinite.js +5 -0
- node_ui/node_modules/lodash/fp/toInteger.js +5 -0
- node_ui/node_modules/lodash/fp/toIterator.js +5 -0
- node_ui/node_modules/lodash/fp/toJSON.js +5 -0
- node_ui/node_modules/lodash/fp/toLength.js +5 -0
- node_ui/node_modules/lodash/fp/toLower.js +5 -0
- node_ui/node_modules/lodash/fp/toNumber.js +5 -0
- node_ui/node_modules/lodash/fp/toPairs.js +5 -0
- node_ui/node_modules/lodash/fp/toPairsIn.js +5 -0
- node_ui/node_modules/lodash/fp/toPath.js +5 -0
- node_ui/node_modules/lodash/fp/toPlainObject.js +5 -0
- node_ui/node_modules/lodash/fp/toSafeInteger.js +5 -0
- node_ui/node_modules/lodash/fp/toString.js +5 -0
- node_ui/node_modules/lodash/fp/toUpper.js +5 -0
- node_ui/node_modules/lodash/fp/transform.js +5 -0
- node_ui/node_modules/lodash/fp/trim.js +5 -0
- node_ui/node_modules/lodash/fp/trimChars.js +5 -0
- node_ui/node_modules/lodash/fp/trimCharsEnd.js +5 -0
- node_ui/node_modules/lodash/fp/trimCharsStart.js +5 -0
- node_ui/node_modules/lodash/fp/trimEnd.js +5 -0
- node_ui/node_modules/lodash/fp/trimStart.js +5 -0
- node_ui/node_modules/lodash/fp/truncate.js +5 -0
- node_ui/node_modules/lodash/fp/unapply.js +1 -0
- node_ui/node_modules/lodash/fp/unary.js +5 -0
- node_ui/node_modules/lodash/fp/unescape.js +5 -0
- node_ui/node_modules/lodash/fp/union.js +5 -0
- node_ui/node_modules/lodash/fp/unionBy.js +5 -0
- node_ui/node_modules/lodash/fp/unionWith.js +5 -0
- node_ui/node_modules/lodash/fp/uniq.js +5 -0
- node_ui/node_modules/lodash/fp/uniqBy.js +5 -0
- node_ui/node_modules/lodash/fp/uniqWith.js +5 -0
- node_ui/node_modules/lodash/fp/uniqueId.js +5 -0
- node_ui/node_modules/lodash/fp/unnest.js +1 -0
- node_ui/node_modules/lodash/fp/unset.js +5 -0
- node_ui/node_modules/lodash/fp/unzip.js +5 -0
- node_ui/node_modules/lodash/fp/unzipWith.js +5 -0
- node_ui/node_modules/lodash/fp/update.js +5 -0
- node_ui/node_modules/lodash/fp/updateWith.js +5 -0
- node_ui/node_modules/lodash/fp/upperCase.js +5 -0
- node_ui/node_modules/lodash/fp/upperFirst.js +5 -0
- node_ui/node_modules/lodash/fp/useWith.js +1 -0
- node_ui/node_modules/lodash/fp/util.js +2 -0
- node_ui/node_modules/lodash/fp/value.js +5 -0
- node_ui/node_modules/lodash/fp/valueOf.js +5 -0
- node_ui/node_modules/lodash/fp/values.js +5 -0
- node_ui/node_modules/lodash/fp/valuesIn.js +5 -0
- node_ui/node_modules/lodash/fp/where.js +1 -0
- node_ui/node_modules/lodash/fp/whereEq.js +1 -0
- node_ui/node_modules/lodash/fp/without.js +5 -0
- node_ui/node_modules/lodash/fp/words.js +5 -0
- node_ui/node_modules/lodash/fp/wrap.js +5 -0
- node_ui/node_modules/lodash/fp/wrapperAt.js +5 -0
- node_ui/node_modules/lodash/fp/wrapperChain.js +5 -0
- node_ui/node_modules/lodash/fp/wrapperLodash.js +5 -0
- node_ui/node_modules/lodash/fp/wrapperReverse.js +5 -0
- node_ui/node_modules/lodash/fp/wrapperValue.js +5 -0
- node_ui/node_modules/lodash/fp/xor.js +5 -0
- node_ui/node_modules/lodash/fp/xorBy.js +5 -0
- node_ui/node_modules/lodash/fp/xorWith.js +5 -0
- node_ui/node_modules/lodash/fp/zip.js +5 -0
- node_ui/node_modules/lodash/fp/zipAll.js +5 -0
- node_ui/node_modules/lodash/fp/zipObj.js +1 -0
- node_ui/node_modules/lodash/fp/zipObject.js +5 -0
- node_ui/node_modules/lodash/fp/zipObjectDeep.js +5 -0
- node_ui/node_modules/lodash/fp/zipWith.js +5 -0
- node_ui/node_modules/lodash/fp.js +2 -0
- node_ui/node_modules/lodash/fromPairs.js +28 -0
- node_ui/node_modules/lodash/function.js +25 -0
- node_ui/node_modules/lodash/functions.js +31 -0
- node_ui/node_modules/lodash/functionsIn.js +31 -0
- node_ui/node_modules/lodash/get.js +33 -0
- node_ui/node_modules/lodash/groupBy.js +41 -0
- node_ui/node_modules/lodash/gt.js +29 -0
- node_ui/node_modules/lodash/gte.js +30 -0
- node_ui/node_modules/lodash/has.js +35 -0
- node_ui/node_modules/lodash/hasIn.js +34 -0
- node_ui/node_modules/lodash/head.js +23 -0
- node_ui/node_modules/lodash/identity.js +21 -0
- node_ui/node_modules/lodash/inRange.js +55 -0
- node_ui/node_modules/lodash/includes.js +53 -0
- node_ui/node_modules/lodash/index.js +1 -0
- node_ui/node_modules/lodash/indexOf.js +42 -0
- node_ui/node_modules/lodash/initial.js +22 -0
- node_ui/node_modules/lodash/intersection.js +30 -0
- node_ui/node_modules/lodash/intersectionBy.js +45 -0
- node_ui/node_modules/lodash/intersectionWith.js +41 -0
- node_ui/node_modules/lodash/invert.js +42 -0
- node_ui/node_modules/lodash/invertBy.js +56 -0
- node_ui/node_modules/lodash/invoke.js +24 -0
- node_ui/node_modules/lodash/invokeMap.js +41 -0
- node_ui/node_modules/lodash/isArguments.js +36 -0
- node_ui/node_modules/lodash/isArray.js +26 -0
- node_ui/node_modules/lodash/isArrayBuffer.js +27 -0
- node_ui/node_modules/lodash/isArrayLike.js +33 -0
- node_ui/node_modules/lodash/isArrayLikeObject.js +33 -0
- node_ui/node_modules/lodash/isBoolean.js +29 -0
- node_ui/node_modules/lodash/isBuffer.js +38 -0
- node_ui/node_modules/lodash/isDate.js +27 -0
- node_ui/node_modules/lodash/isElement.js +25 -0
- node_ui/node_modules/lodash/isEmpty.js +77 -0
- node_ui/node_modules/lodash/isEqual.js +35 -0
- node_ui/node_modules/lodash/isEqualWith.js +41 -0
- node_ui/node_modules/lodash/isError.js +36 -0
- node_ui/node_modules/lodash/isFinite.js +36 -0
- node_ui/node_modules/lodash/isFunction.js +37 -0
- node_ui/node_modules/lodash/isInteger.js +33 -0
- node_ui/node_modules/lodash/isLength.js +35 -0
- node_ui/node_modules/lodash/isMap.js +27 -0
- node_ui/node_modules/lodash/isMatch.js +36 -0
- node_ui/node_modules/lodash/isMatchWith.js +41 -0
- node_ui/node_modules/lodash/isNaN.js +38 -0
- node_ui/node_modules/lodash/isNative.js +40 -0
- node_ui/node_modules/lodash/isNil.js +25 -0
- node_ui/node_modules/lodash/isNull.js +22 -0
- node_ui/node_modules/lodash/isNumber.js +38 -0
- node_ui/node_modules/lodash/isObject.js +31 -0
- node_ui/node_modules/lodash/isObjectLike.js +29 -0
- node_ui/node_modules/lodash/isPlainObject.js +62 -0
- node_ui/node_modules/lodash/isRegExp.js +27 -0
- node_ui/node_modules/lodash/isSafeInteger.js +37 -0
- node_ui/node_modules/lodash/isSet.js +27 -0
- node_ui/node_modules/lodash/isString.js +30 -0
- node_ui/node_modules/lodash/isSymbol.js +29 -0
- node_ui/node_modules/lodash/isTypedArray.js +27 -0
- node_ui/node_modules/lodash/isUndefined.js +22 -0
- node_ui/node_modules/lodash/isWeakMap.js +28 -0
- node_ui/node_modules/lodash/isWeakSet.js +28 -0
- node_ui/node_modules/lodash/iteratee.js +53 -0
- node_ui/node_modules/lodash/join.js +26 -0
- node_ui/node_modules/lodash/kebabCase.js +28 -0
- node_ui/node_modules/lodash/keyBy.js +36 -0
- node_ui/node_modules/lodash/keys.js +37 -0
- node_ui/node_modules/lodash/keysIn.js +32 -0
- node_ui/node_modules/lodash/lang.js +58 -0
- node_ui/node_modules/lodash/last.js +20 -0
- node_ui/node_modules/lodash/lastIndexOf.js +46 -0
- node_ui/node_modules/lodash/lodash.js +17209 -0
- node_ui/node_modules/lodash/lodash.min.js +140 -0
- node_ui/node_modules/lodash/lowerCase.js +27 -0
- node_ui/node_modules/lodash/lowerFirst.js +22 -0
- node_ui/node_modules/lodash/lt.js +29 -0
- node_ui/node_modules/lodash/lte.js +30 -0
- node_ui/node_modules/lodash/map.js +53 -0
- node_ui/node_modules/lodash/mapKeys.js +36 -0
- node_ui/node_modules/lodash/mapValues.js +43 -0
- node_ui/node_modules/lodash/matches.js +46 -0
- node_ui/node_modules/lodash/matchesProperty.js +44 -0
- node_ui/node_modules/lodash/math.js +17 -0
- node_ui/node_modules/lodash/max.js +29 -0
- node_ui/node_modules/lodash/maxBy.js +34 -0
- node_ui/node_modules/lodash/mean.js +22 -0
- node_ui/node_modules/lodash/meanBy.js +31 -0
- node_ui/node_modules/lodash/memoize.js +73 -0
- node_ui/node_modules/lodash/merge.js +39 -0
- node_ui/node_modules/lodash/mergeWith.js +39 -0
- node_ui/node_modules/lodash/method.js +34 -0
- node_ui/node_modules/lodash/methodOf.js +33 -0
- node_ui/node_modules/lodash/min.js +29 -0
- node_ui/node_modules/lodash/minBy.js +34 -0
- node_ui/node_modules/lodash/mixin.js +74 -0
- node_ui/node_modules/lodash/multiply.js +22 -0
- node_ui/node_modules/lodash/negate.js +40 -0
- node_ui/node_modules/lodash/next.js +35 -0
- node_ui/node_modules/lodash/noop.js +17 -0
- node_ui/node_modules/lodash/now.js +23 -0
- node_ui/node_modules/lodash/nth.js +29 -0
- node_ui/node_modules/lodash/nthArg.js +32 -0
- node_ui/node_modules/lodash/number.js +5 -0
- node_ui/node_modules/lodash/object.js +49 -0
- node_ui/node_modules/lodash/omit.js +57 -0
- node_ui/node_modules/lodash/omitBy.js +29 -0
- node_ui/node_modules/lodash/once.js +25 -0
- node_ui/node_modules/lodash/orderBy.js +47 -0
- node_ui/node_modules/lodash/over.js +24 -0
- node_ui/node_modules/lodash/overArgs.js +61 -0
- node_ui/node_modules/lodash/overEvery.js +34 -0
- node_ui/node_modules/lodash/overSome.js +37 -0
- node_ui/node_modules/lodash/package.json +17 -0
- node_ui/node_modules/lodash/pad.js +49 -0
- node_ui/node_modules/lodash/padEnd.js +39 -0
- node_ui/node_modules/lodash/padStart.js +39 -0
- node_ui/node_modules/lodash/parseInt.js +43 -0
- node_ui/node_modules/lodash/partial.js +50 -0
- node_ui/node_modules/lodash/partialRight.js +49 -0
- node_ui/node_modules/lodash/partition.js +43 -0
- node_ui/node_modules/lodash/pick.js +25 -0
- node_ui/node_modules/lodash/pickBy.js +37 -0
- node_ui/node_modules/lodash/plant.js +48 -0
- node_ui/node_modules/lodash/property.js +32 -0
- node_ui/node_modules/lodash/propertyOf.js +30 -0
- node_ui/node_modules/lodash/pull.js +29 -0
- node_ui/node_modules/lodash/pullAll.js +29 -0
- node_ui/node_modules/lodash/pullAllBy.js +33 -0
- node_ui/node_modules/lodash/pullAllWith.js +32 -0
- node_ui/node_modules/lodash/pullAt.js +43 -0
- node_ui/node_modules/lodash/random.js +82 -0
- node_ui/node_modules/lodash/range.js +46 -0
- node_ui/node_modules/lodash/rangeRight.js +41 -0
- node_ui/node_modules/lodash/rearg.js +33 -0
- node_ui/node_modules/lodash/reduce.js +51 -0
- node_ui/node_modules/lodash/reduceRight.js +36 -0
- node_ui/node_modules/lodash/reject.js +46 -0
- node_ui/node_modules/lodash/release.md +48 -0
- node_ui/node_modules/lodash/remove.js +53 -0
- node_ui/node_modules/lodash/repeat.js +37 -0
- node_ui/node_modules/lodash/replace.js +29 -0
- node_ui/node_modules/lodash/rest.js +40 -0
- node_ui/node_modules/lodash/result.js +56 -0
- node_ui/node_modules/lodash/reverse.js +34 -0
- node_ui/node_modules/lodash/round.js +26 -0
- node_ui/node_modules/lodash/sample.js +24 -0
- node_ui/node_modules/lodash/sampleSize.js +37 -0
- node_ui/node_modules/lodash/seq.js +16 -0
- node_ui/node_modules/lodash/set.js +35 -0
- node_ui/node_modules/lodash/setWith.js +32 -0
- node_ui/node_modules/lodash/shuffle.js +25 -0
- node_ui/node_modules/lodash/size.js +46 -0
- node_ui/node_modules/lodash/slice.js +37 -0
- node_ui/node_modules/lodash/snakeCase.js +28 -0
- node_ui/node_modules/lodash/some.js +51 -0
- node_ui/node_modules/lodash/sortBy.js +48 -0
- node_ui/node_modules/lodash/sortedIndex.js +24 -0
- node_ui/node_modules/lodash/sortedIndexBy.js +33 -0
- node_ui/node_modules/lodash/sortedIndexOf.js +31 -0
- node_ui/node_modules/lodash/sortedLastIndex.js +25 -0
- node_ui/node_modules/lodash/sortedLastIndexBy.js +33 -0
- node_ui/node_modules/lodash/sortedLastIndexOf.js +31 -0
- node_ui/node_modules/lodash/sortedUniq.js +24 -0
- node_ui/node_modules/lodash/sortedUniqBy.js +26 -0
- node_ui/node_modules/lodash/split.js +52 -0
- node_ui/node_modules/lodash/spread.js +63 -0
- node_ui/node_modules/lodash/startCase.js +29 -0
- node_ui/node_modules/lodash/startsWith.js +39 -0
- node_ui/node_modules/lodash/string.js +33 -0
- node_ui/node_modules/lodash/stubArray.js +23 -0
- node_ui/node_modules/lodash/stubFalse.js +18 -0
- node_ui/node_modules/lodash/stubObject.js +23 -0
- node_ui/node_modules/lodash/stubString.js +18 -0
- node_ui/node_modules/lodash/stubTrue.js +18 -0
- node_ui/node_modules/lodash/subtract.js +22 -0
- node_ui/node_modules/lodash/sum.js +24 -0
- node_ui/node_modules/lodash/sumBy.js +33 -0
- node_ui/node_modules/lodash/tail.js +22 -0
- node_ui/node_modules/lodash/take.js +37 -0
- node_ui/node_modules/lodash/takeRight.js +39 -0
- node_ui/node_modules/lodash/takeRightWhile.js +45 -0
- node_ui/node_modules/lodash/takeWhile.js +45 -0
- node_ui/node_modules/lodash/tap.js +29 -0
- node_ui/node_modules/lodash/template.js +272 -0
- node_ui/node_modules/lodash/templateSettings.js +67 -0
- node_ui/node_modules/lodash/throttle.js +69 -0
- node_ui/node_modules/lodash/thru.js +28 -0
- node_ui/node_modules/lodash/times.js +51 -0
- node_ui/node_modules/lodash/toArray.js +58 -0
- node_ui/node_modules/lodash/toFinite.js +42 -0
- node_ui/node_modules/lodash/toInteger.js +36 -0
- node_ui/node_modules/lodash/toIterator.js +23 -0
- node_ui/node_modules/lodash/toJSON.js +1 -0
- node_ui/node_modules/lodash/toLength.js +38 -0
- node_ui/node_modules/lodash/toLower.js +28 -0
- node_ui/node_modules/lodash/toNumber.js +64 -0
- node_ui/node_modules/lodash/toPairs.js +30 -0
- node_ui/node_modules/lodash/toPairsIn.js +30 -0
- node_ui/node_modules/lodash/toPath.js +33 -0
- node_ui/node_modules/lodash/toPlainObject.js +32 -0
- node_ui/node_modules/lodash/toSafeInteger.js +37 -0
- node_ui/node_modules/lodash/toString.js +28 -0
- node_ui/node_modules/lodash/toUpper.js +28 -0
- node_ui/node_modules/lodash/transform.js +65 -0
- node_ui/node_modules/lodash/trim.js +47 -0
- node_ui/node_modules/lodash/trimEnd.js +41 -0
- node_ui/node_modules/lodash/trimStart.js +43 -0
- node_ui/node_modules/lodash/truncate.js +111 -0
- node_ui/node_modules/lodash/unary.js +22 -0
- node_ui/node_modules/lodash/unescape.js +34 -0
- node_ui/node_modules/lodash/union.js +26 -0
- node_ui/node_modules/lodash/unionBy.js +39 -0
- node_ui/node_modules/lodash/unionWith.js +34 -0
- node_ui/node_modules/lodash/uniq.js +25 -0
- node_ui/node_modules/lodash/uniqBy.js +31 -0
- node_ui/node_modules/lodash/uniqWith.js +28 -0
- node_ui/node_modules/lodash/uniqueId.js +28 -0
- node_ui/node_modules/lodash/unset.js +34 -0
- node_ui/node_modules/lodash/unzip.js +45 -0
- node_ui/node_modules/lodash/unzipWith.js +39 -0
- node_ui/node_modules/lodash/update.js +35 -0
- node_ui/node_modules/lodash/updateWith.js +33 -0
- node_ui/node_modules/lodash/upperCase.js +27 -0
- node_ui/node_modules/lodash/upperFirst.js +22 -0
- node_ui/node_modules/lodash/util.js +34 -0
- node_ui/node_modules/lodash/value.js +1 -0
- node_ui/node_modules/lodash/valueOf.js +1 -0
- node_ui/node_modules/lodash/values.js +34 -0
- node_ui/node_modules/lodash/valuesIn.js +32 -0
- node_ui/node_modules/lodash/without.js +31 -0
- node_ui/node_modules/lodash/words.js +35 -0
- node_ui/node_modules/lodash/wrap.js +30 -0
- node_ui/node_modules/lodash/wrapperAt.js +48 -0
- node_ui/node_modules/lodash/wrapperChain.js +34 -0
- node_ui/node_modules/lodash/wrapperLodash.js +147 -0
- node_ui/node_modules/lodash/wrapperReverse.js +44 -0
- node_ui/node_modules/lodash/wrapperValue.js +21 -0
- node_ui/node_modules/lodash/xor.js +28 -0
- node_ui/node_modules/lodash/xorBy.js +39 -0
- node_ui/node_modules/lodash/xorWith.js +34 -0
- node_ui/node_modules/lodash/zip.js +22 -0
- node_ui/node_modules/lodash/zipObject.js +24 -0
- node_ui/node_modules/lodash/zipObjectDeep.js +23 -0
- node_ui/node_modules/lodash/zipWith.js +32 -0
- node_ui/node_modules/lodash.isequal/LICENSE +47 -0
- node_ui/node_modules/lodash.isequal/README.md +18 -0
- node_ui/node_modules/lodash.isequal/index.js +1848 -0
- node_ui/node_modules/lodash.isequal/package.json +16 -0
- node_ui/node_modules/loose-envify/LICENSE +21 -0
- node_ui/node_modules/loose-envify/README.md +45 -0
- node_ui/node_modules/loose-envify/cli.js +16 -0
- node_ui/node_modules/loose-envify/custom.js +4 -0
- node_ui/node_modules/loose-envify/index.js +3 -0
- node_ui/node_modules/loose-envify/loose-envify.js +36 -0
- node_ui/node_modules/loose-envify/package.json +36 -0
- node_ui/node_modules/loose-envify/replace.js +65 -0
- node_ui/node_modules/meow/build/dependencies.js +8828 -0
- node_ui/node_modules/meow/build/index.d.ts +1425 -0
- node_ui/node_modules/meow/build/index.js +95 -0
- node_ui/node_modules/meow/build/licenses.md +1620 -0
- node_ui/node_modules/meow/build/options.js +92 -0
- node_ui/node_modules/meow/build/parser.js +84 -0
- node_ui/node_modules/meow/build/utils.js +7 -0
- node_ui/node_modules/meow/build/validate.js +122 -0
- node_ui/node_modules/meow/license +9 -0
- node_ui/node_modules/meow/package.json +105 -0
- node_ui/node_modules/meow/readme.md +314 -0
- node_ui/node_modules/mimic-fn/index.d.ts +54 -0
- node_ui/node_modules/mimic-fn/index.js +13 -0
- node_ui/node_modules/mimic-fn/license +9 -0
- node_ui/node_modules/mimic-fn/package.json +42 -0
- node_ui/node_modules/mimic-fn/readme.md +69 -0
- node_ui/node_modules/onetime/index.d.ts +64 -0
- node_ui/node_modules/onetime/index.js +44 -0
- node_ui/node_modules/onetime/license +9 -0
- node_ui/node_modules/onetime/package.json +43 -0
- node_ui/node_modules/onetime/readme.md +94 -0
- node_ui/node_modules/patch-console/dist/index.d.ts +4 -0
- node_ui/node_modules/patch-console/dist/index.js +45 -0
- node_ui/node_modules/patch-console/dist/index.js.map +1 -0
- node_ui/node_modules/patch-console/license +9 -0
- node_ui/node_modules/patch-console/package.json +53 -0
- node_ui/node_modules/patch-console/readme.md +62 -0
- node_ui/node_modules/react/LICENSE +21 -0
- node_ui/node_modules/react/README.md +37 -0
- node_ui/node_modules/react/cjs/react-jsx-dev-runtime.development.js +1315 -0
- node_ui/node_modules/react/cjs/react-jsx-dev-runtime.production.min.js +10 -0
- node_ui/node_modules/react/cjs/react-jsx-dev-runtime.profiling.min.js +10 -0
- node_ui/node_modules/react/cjs/react-jsx-runtime.development.js +1333 -0
- node_ui/node_modules/react/cjs/react-jsx-runtime.production.min.js +11 -0
- node_ui/node_modules/react/cjs/react-jsx-runtime.profiling.min.js +11 -0
- node_ui/node_modules/react/cjs/react.development.js +2740 -0
- node_ui/node_modules/react/cjs/react.production.min.js +26 -0
- node_ui/node_modules/react/cjs/react.shared-subset.development.js +20 -0
- node_ui/node_modules/react/cjs/react.shared-subset.production.min.js +10 -0
- node_ui/node_modules/react/index.js +7 -0
- node_ui/node_modules/react/jsx-dev-runtime.js +7 -0
- node_ui/node_modules/react/jsx-runtime.js +7 -0
- node_ui/node_modules/react/package.json +47 -0
- node_ui/node_modules/react/react.shared-subset.js +7 -0
- node_ui/node_modules/react/umd/react.development.js +3343 -0
- node_ui/node_modules/react/umd/react.production.min.js +31 -0
- node_ui/node_modules/react/umd/react.profiling.min.js +31 -0
- node_ui/node_modules/react-devtools-core/README.md +131 -0
- node_ui/node_modules/react-devtools-core/backend.js +1 -0
- node_ui/node_modules/react-devtools-core/dist/backend.js +16888 -0
- node_ui/node_modules/react-devtools-core/dist/backend.js.map +1 -0
- node_ui/node_modules/react-devtools-core/dist/importFile.worker.worker.js +2 -0
- node_ui/node_modules/react-devtools-core/dist/importFile.worker.worker.js.map +1 -0
- node_ui/node_modules/react-devtools-core/dist/parseHookNames.chunk.js +2 -0
- node_ui/node_modules/react-devtools-core/dist/parseHookNames.chunk.js.map +1 -0
- node_ui/node_modules/react-devtools-core/dist/parseSourceAndMetadata.worker.worker.js +2 -0
- node_ui/node_modules/react-devtools-core/dist/parseSourceAndMetadata.worker.worker.js.map +1 -0
- node_ui/node_modules/react-devtools-core/dist/standalone.js +3 -0
- node_ui/node_modules/react-devtools-core/dist/standalone.js.LICENSE.txt +41 -0
- node_ui/node_modules/react-devtools-core/dist/standalone.js.map +1 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/LICENSE +21 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/README.md +495 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/browser.js +8 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/index.js +10 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/buffer-util.js +129 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/constants.js +10 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/event-target.js +184 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/extension.js +223 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/limiter.js +55 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/permessage-deflate.js +518 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/receiver.js +607 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/sender.js +409 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/stream.js +180 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/validation.js +104 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/websocket-server.js +449 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/lib/websocket.js +1197 -0
- node_ui/node_modules/react-devtools-core/node_modules/ws/package.json +56 -0
- node_ui/node_modules/react-devtools-core/package.json +38 -0
- node_ui/node_modules/react-devtools-core/standalone.js +1 -0
- node_ui/node_modules/react-reconciler/LICENSE +21 -0
- node_ui/node_modules/react-reconciler/README.md +337 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler-constants.development.js +45 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler-constants.production.min.js +10 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler-reflection.development.js +660 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler-reflection.production.min.js +15 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler.development.js +21531 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler.production.min.js +234 -0
- node_ui/node_modules/react-reconciler/cjs/react-reconciler.profiling.min.js +255 -0
- node_ui/node_modules/react-reconciler/constants.js +7 -0
- node_ui/node_modules/react-reconciler/index.js +7 -0
- node_ui/node_modules/react-reconciler/package.json +40 -0
- node_ui/node_modules/react-reconciler/reflection.js +7 -0
- node_ui/node_modules/restore-cursor/index.d.ts +11 -0
- node_ui/node_modules/restore-cursor/index.js +11 -0
- node_ui/node_modules/restore-cursor/license +9 -0
- node_ui/node_modules/restore-cursor/package.json +55 -0
- node_ui/node_modules/restore-cursor/readme.md +31 -0
- node_ui/node_modules/scheduler/LICENSE +21 -0
- node_ui/node_modules/scheduler/README.md +9 -0
- node_ui/node_modules/scheduler/cjs/scheduler-unstable_mock.development.js +700 -0
- node_ui/node_modules/scheduler/cjs/scheduler-unstable_mock.production.min.js +20 -0
- node_ui/node_modules/scheduler/cjs/scheduler-unstable_post_task.development.js +207 -0
- node_ui/node_modules/scheduler/cjs/scheduler-unstable_post_task.production.min.js +14 -0
- node_ui/node_modules/scheduler/cjs/scheduler.development.js +634 -0
- node_ui/node_modules/scheduler/cjs/scheduler.production.min.js +19 -0
- node_ui/node_modules/scheduler/index.js +7 -0
- node_ui/node_modules/scheduler/package.json +36 -0
- node_ui/node_modules/scheduler/umd/scheduler-unstable_mock.development.js +699 -0
- node_ui/node_modules/scheduler/umd/scheduler-unstable_mock.production.min.js +19 -0
- node_ui/node_modules/scheduler/umd/scheduler.development.js +152 -0
- node_ui/node_modules/scheduler/umd/scheduler.production.min.js +146 -0
- node_ui/node_modules/scheduler/umd/scheduler.profiling.min.js +146 -0
- node_ui/node_modules/scheduler/unstable_mock.js +7 -0
- node_ui/node_modules/scheduler/unstable_post_task.js +7 -0
- node_ui/node_modules/shell-quote/.eslintrc +30 -0
- node_ui/node_modules/shell-quote/.github/FUNDING.yml +12 -0
- node_ui/node_modules/shell-quote/.nycrc +14 -0
- node_ui/node_modules/shell-quote/LICENSE +24 -0
- node_ui/node_modules/shell-quote/README.md +161 -0
- node_ui/node_modules/shell-quote/index.js +4 -0
- node_ui/node_modules/shell-quote/package.json +72 -0
- node_ui/node_modules/shell-quote/parse.js +226 -0
- node_ui/node_modules/shell-quote/print.py +3 -0
- node_ui/node_modules/shell-quote/quote.js +19 -0
- node_ui/node_modules/shell-quote/security.md +11 -0
- node_ui/node_modules/shell-quote/test/comment.js +16 -0
- node_ui/node_modules/shell-quote/test/env.js +52 -0
- node_ui/node_modules/shell-quote/test/env_fn.js +21 -0
- node_ui/node_modules/shell-quote/test/op.js +102 -0
- node_ui/node_modules/shell-quote/test/parse.js +44 -0
- node_ui/node_modules/shell-quote/test/quote.js +60 -0
- node_ui/node_modules/shell-quote/test/set.js +31 -0
- node_ui/node_modules/signal-exit/LICENSE.txt +16 -0
- node_ui/node_modules/signal-exit/README.md +39 -0
- node_ui/node_modules/signal-exit/index.js +202 -0
- node_ui/node_modules/signal-exit/package.json +38 -0
- node_ui/node_modules/signal-exit/signals.js +53 -0
- node_ui/node_modules/slice-ansi/index.d.ts +19 -0
- node_ui/node_modules/slice-ansi/index.js +169 -0
- node_ui/node_modules/slice-ansi/license +10 -0
- node_ui/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
- node_ui/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/index.js +12 -0
- node_ui/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/license +9 -0
- node_ui/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/package.json +53 -0
- node_ui/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/readme.md +31 -0
- node_ui/node_modules/slice-ansi/package.json +58 -0
- node_ui/node_modules/slice-ansi/readme.md +54 -0
- node_ui/node_modules/stack-utils/LICENSE.md +21 -0
- node_ui/node_modules/stack-utils/index.js +344 -0
- node_ui/node_modules/stack-utils/node_modules/escape-string-regexp/index.d.ts +18 -0
- node_ui/node_modules/stack-utils/node_modules/escape-string-regexp/index.js +11 -0
- node_ui/node_modules/stack-utils/node_modules/escape-string-regexp/license +9 -0
- node_ui/node_modules/stack-utils/node_modules/escape-string-regexp/package.json +43 -0
- node_ui/node_modules/stack-utils/node_modules/escape-string-regexp/readme.md +29 -0
- node_ui/node_modules/stack-utils/package.json +39 -0
- node_ui/node_modules/stack-utils/readme.md +143 -0
- node_ui/node_modules/string-width/index.d.ts +39 -0
- node_ui/node_modules/string-width/index.js +82 -0
- node_ui/node_modules/string-width/license +9 -0
- node_ui/node_modules/string-width/package.json +64 -0
- node_ui/node_modules/string-width/readme.md +66 -0
- node_ui/node_modules/strip-ansi/index.d.ts +15 -0
- node_ui/node_modules/strip-ansi/index.js +14 -0
- node_ui/node_modules/strip-ansi/license +9 -0
- node_ui/node_modules/strip-ansi/package.json +59 -0
- node_ui/node_modules/strip-ansi/readme.md +37 -0
- node_ui/node_modules/to-rotated/index.d.ts +18 -0
- node_ui/node_modules/to-rotated/index.js +24 -0
- node_ui/node_modules/to-rotated/license +9 -0
- node_ui/node_modules/to-rotated/package.json +46 -0
- node_ui/node_modules/to-rotated/readme.md +29 -0
- node_ui/node_modules/type-fest/index.d.ts +178 -0
- node_ui/node_modules/type-fest/license-cc0 +121 -0
- node_ui/node_modules/type-fest/license-mit +9 -0
- node_ui/node_modules/type-fest/package.json +91 -0
- node_ui/node_modules/type-fest/readme.md +1060 -0
- node_ui/node_modules/type-fest/source/all-union-fields.d.ts +88 -0
- node_ui/node_modules/type-fest/source/and.d.ts +25 -0
- node_ui/node_modules/type-fest/source/array-indices.d.ts +23 -0
- node_ui/node_modules/type-fest/source/array-slice.d.ts +109 -0
- node_ui/node_modules/type-fest/source/array-splice.d.ts +99 -0
- node_ui/node_modules/type-fest/source/array-tail.d.ts +76 -0
- node_ui/node_modules/type-fest/source/array-values.d.ts +22 -0
- node_ui/node_modules/type-fest/source/arrayable.d.ts +29 -0
- node_ui/node_modules/type-fest/source/async-return-type.d.ts +23 -0
- node_ui/node_modules/type-fest/source/asyncify.d.ts +32 -0
- node_ui/node_modules/type-fest/source/basic.d.ts +68 -0
- node_ui/node_modules/type-fest/source/camel-case.d.ts +89 -0
- node_ui/node_modules/type-fest/source/camel-cased-properties-deep.d.ts +97 -0
- node_ui/node_modules/type-fest/source/camel-cased-properties.d.ts +43 -0
- node_ui/node_modules/type-fest/source/conditional-except.d.ts +45 -0
- node_ui/node_modules/type-fest/source/conditional-keys.d.ts +47 -0
- node_ui/node_modules/type-fest/source/conditional-pick-deep.d.ts +118 -0
- node_ui/node_modules/type-fest/source/conditional-pick.d.ts +44 -0
- node_ui/node_modules/type-fest/source/conditional-simplify.d.ts +32 -0
- node_ui/node_modules/type-fest/source/delimiter-case.d.ts +78 -0
- node_ui/node_modules/type-fest/source/delimiter-cased-properties-deep.d.ts +106 -0
- node_ui/node_modules/type-fest/source/delimiter-cased-properties.d.ts +46 -0
- node_ui/node_modules/type-fest/source/distributed-omit.d.ts +89 -0
- node_ui/node_modules/type-fest/source/distributed-pick.d.ts +85 -0
- node_ui/node_modules/type-fest/source/empty-object.d.ts +46 -0
- node_ui/node_modules/type-fest/source/enforce-optional.d.ts +47 -0
- node_ui/node_modules/type-fest/source/entries.d.ts +62 -0
- node_ui/node_modules/type-fest/source/entry.d.ts +65 -0
- node_ui/node_modules/type-fest/source/exact.d.ts +68 -0
- node_ui/node_modules/type-fest/source/except.d.ts +108 -0
- node_ui/node_modules/type-fest/source/find-global-type.d.ts +64 -0
- node_ui/node_modules/type-fest/source/fixed-length-array.d.ts +43 -0
- node_ui/node_modules/type-fest/source/get.d.ts +219 -0
- node_ui/node_modules/type-fest/source/global-this.d.ts +21 -0
- node_ui/node_modules/type-fest/source/greater-than-or-equal.d.ts +22 -0
- node_ui/node_modules/type-fest/source/greater-than.d.ts +56 -0
- node_ui/node_modules/type-fest/source/has-optional-keys.d.ts +21 -0
- node_ui/node_modules/type-fest/source/has-readonly-keys.d.ts +21 -0
- node_ui/node_modules/type-fest/source/has-required-keys.d.ts +59 -0
- node_ui/node_modules/type-fest/source/has-writable-keys.d.ts +21 -0
- node_ui/node_modules/type-fest/source/if-any.d.ts +24 -0
- node_ui/node_modules/type-fest/source/if-empty-object.d.ts +26 -0
- node_ui/node_modules/type-fest/source/if-never.d.ts +24 -0
- node_ui/node_modules/type-fest/source/if-null.d.ts +24 -0
- node_ui/node_modules/type-fest/source/if-unknown.d.ts +24 -0
- node_ui/node_modules/type-fest/source/includes.d.ts +22 -0
- node_ui/node_modules/type-fest/source/int-closed-range.d.ts +35 -0
- node_ui/node_modules/type-fest/source/int-range.d.ts +55 -0
- node_ui/node_modules/type-fest/source/internal/array.d.ts +126 -0
- node_ui/node_modules/type-fest/source/internal/characters.d.ts +67 -0
- node_ui/node_modules/type-fest/source/internal/index.d.ts +8 -0
- node_ui/node_modules/type-fest/source/internal/keys.d.ts +97 -0
- node_ui/node_modules/type-fest/source/internal/numeric.d.ts +118 -0
- node_ui/node_modules/type-fest/source/internal/object.d.ts +236 -0
- node_ui/node_modules/type-fest/source/internal/string.d.ts +210 -0
- node_ui/node_modules/type-fest/source/internal/tuple.d.ts +90 -0
- node_ui/node_modules/type-fest/source/internal/type.d.ts +139 -0
- node_ui/node_modules/type-fest/source/invariant-of.d.ts +76 -0
- node_ui/node_modules/type-fest/source/is-any.d.ts +33 -0
- node_ui/node_modules/type-fest/source/is-equal.d.ts +31 -0
- node_ui/node_modules/type-fest/source/is-float.d.ts +41 -0
- node_ui/node_modules/type-fest/source/is-integer.d.ts +58 -0
- node_ui/node_modules/type-fest/source/is-literal.d.ts +296 -0
- node_ui/node_modules/type-fest/source/is-never.d.ts +42 -0
- node_ui/node_modules/type-fest/source/is-null.d.ts +20 -0
- node_ui/node_modules/type-fest/source/is-tuple.d.ts +89 -0
- node_ui/node_modules/type-fest/source/is-unknown.d.ts +52 -0
- node_ui/node_modules/type-fest/source/iterable-element.d.ts +64 -0
- node_ui/node_modules/type-fest/source/join.d.ts +68 -0
- node_ui/node_modules/type-fest/source/jsonifiable.d.ts +37 -0
- node_ui/node_modules/type-fest/source/jsonify.d.ts +122 -0
- node_ui/node_modules/type-fest/source/kebab-case.d.ts +44 -0
- node_ui/node_modules/type-fest/source/kebab-cased-properties-deep.d.ts +63 -0
- node_ui/node_modules/type-fest/source/kebab-cased-properties.d.ts +40 -0
- node_ui/node_modules/type-fest/source/keys-of-union.d.ts +42 -0
- node_ui/node_modules/type-fest/source/last-array-element.d.ts +38 -0
- node_ui/node_modules/type-fest/source/less-than-or-equal.d.ts +22 -0
- node_ui/node_modules/type-fest/source/less-than.d.ts +26 -0
- node_ui/node_modules/type-fest/source/literal-to-primitive-deep.d.ts +36 -0
- node_ui/node_modules/type-fest/source/literal-to-primitive.d.ts +36 -0
- node_ui/node_modules/type-fest/source/literal-union.d.ts +37 -0
- node_ui/node_modules/type-fest/source/merge-deep.d.ts +486 -0
- node_ui/node_modules/type-fest/source/merge-exclusive.d.ts +41 -0
- node_ui/node_modules/type-fest/source/merge.d.ts +48 -0
- node_ui/node_modules/type-fest/source/multidimensional-array.d.ts +44 -0
- node_ui/node_modules/type-fest/source/multidimensional-readonly-array.d.ts +48 -0
- node_ui/node_modules/type-fest/source/non-empty-object.d.ts +35 -0
- node_ui/node_modules/type-fest/source/non-empty-string.d.ts +28 -0
- node_ui/node_modules/type-fest/source/non-empty-tuple.d.ts +21 -0
- node_ui/node_modules/type-fest/source/numeric.d.ts +222 -0
- node_ui/node_modules/type-fest/source/observable-like.d.ts +63 -0
- node_ui/node_modules/type-fest/source/omit-deep.d.ts +167 -0
- node_ui/node_modules/type-fest/source/omit-index-signature.d.ts +95 -0
- node_ui/node_modules/type-fest/source/opaque.d.ts +1 -0
- node_ui/node_modules/type-fest/source/optional-keys-of.d.ts +39 -0
- node_ui/node_modules/type-fest/source/or.d.ts +25 -0
- node_ui/node_modules/type-fest/source/override-properties.d.ts +36 -0
- node_ui/node_modules/type-fest/source/package-json.d.ts +676 -0
- node_ui/node_modules/type-fest/source/partial-deep.d.ts +151 -0
- node_ui/node_modules/type-fest/source/partial-on-undefined-deep.d.ts +78 -0
- node_ui/node_modules/type-fest/source/pascal-case.d.ts +42 -0
- node_ui/node_modules/type-fest/source/pascal-cased-properties-deep.d.ts +62 -0
- node_ui/node_modules/type-fest/source/pascal-cased-properties.d.ts +36 -0
- node_ui/node_modules/type-fest/source/paths.d.ts +262 -0
- node_ui/node_modules/type-fest/source/pick-deep.d.ts +149 -0
- node_ui/node_modules/type-fest/source/pick-index-signature.d.ts +50 -0
- node_ui/node_modules/type-fest/source/primitive.d.ts +13 -0
- node_ui/node_modules/type-fest/source/promisable.d.ts +25 -0
- node_ui/node_modules/type-fest/source/readonly-deep.d.ts +81 -0
- node_ui/node_modules/type-fest/source/readonly-keys-of.d.ts +30 -0
- node_ui/node_modules/type-fest/source/readonly-tuple.d.ts +41 -0
- node_ui/node_modules/type-fest/source/replace.d.ts +85 -0
- node_ui/node_modules/type-fest/source/require-all-or-none.d.ts +51 -0
- node_ui/node_modules/type-fest/source/require-at-least-one.d.ts +47 -0
- node_ui/node_modules/type-fest/source/require-exactly-one.d.ts +45 -0
- node_ui/node_modules/type-fest/source/require-one-or-none.d.ts +46 -0
- node_ui/node_modules/type-fest/source/required-deep.d.ts +78 -0
- node_ui/node_modules/type-fest/source/required-keys-of.d.ts +30 -0
- node_ui/node_modules/type-fest/source/schema.d.ts +114 -0
- node_ui/node_modules/type-fest/source/screaming-snake-case.d.ts +28 -0
- node_ui/node_modules/type-fest/source/set-field-type.d.ts +65 -0
- node_ui/node_modules/type-fest/source/set-non-nullable-deep.d.ts +83 -0
- node_ui/node_modules/type-fest/source/set-non-nullable.d.ts +39 -0
- node_ui/node_modules/type-fest/source/set-optional.d.ts +38 -0
- node_ui/node_modules/type-fest/source/set-parameter-type.d.ts +117 -0
- node_ui/node_modules/type-fest/source/set-readonly.d.ts +39 -0
- node_ui/node_modules/type-fest/source/set-required-deep.d.ts +68 -0
- node_ui/node_modules/type-fest/source/set-required.d.ts +70 -0
- node_ui/node_modules/type-fest/source/set-return-type.d.ts +29 -0
- node_ui/node_modules/type-fest/source/shared-union-fields-deep.d.ts +178 -0
- node_ui/node_modules/type-fest/source/shared-union-fields.d.ts +76 -0
- node_ui/node_modules/type-fest/source/simplify-deep.d.ts +115 -0
- node_ui/node_modules/type-fest/source/simplify.d.ts +58 -0
- node_ui/node_modules/type-fest/source/single-key-object.d.ts +29 -0
- node_ui/node_modules/type-fest/source/snake-case.d.ts +45 -0
- node_ui/node_modules/type-fest/source/snake-cased-properties-deep.d.ts +63 -0
- node_ui/node_modules/type-fest/source/snake-cased-properties.d.ts +40 -0
- node_ui/node_modules/type-fest/source/split.d.ts +88 -0
- node_ui/node_modules/type-fest/source/spread.d.ts +84 -0
- node_ui/node_modules/type-fest/source/string-key-of.d.ts +25 -0
- node_ui/node_modules/type-fest/source/string-repeat.d.ts +47 -0
- node_ui/node_modules/type-fest/source/string-slice.d.ts +37 -0
- node_ui/node_modules/type-fest/source/stringified.d.ts +23 -0
- node_ui/node_modules/type-fest/source/structured-cloneable.d.ts +92 -0
- node_ui/node_modules/type-fest/source/subtract.d.ts +83 -0
- node_ui/node_modules/type-fest/source/sum.d.ts +78 -0
- node_ui/node_modules/type-fest/source/tagged-union.d.ts +51 -0
- node_ui/node_modules/type-fest/source/tagged.d.ts +256 -0
- node_ui/node_modules/type-fest/source/trim.d.ts +27 -0
- node_ui/node_modules/type-fest/source/tsconfig-json.d.ts +1294 -0
- node_ui/node_modules/type-fest/source/tuple-to-object.d.ts +42 -0
- node_ui/node_modules/type-fest/source/tuple-to-union.d.ts +51 -0
- node_ui/node_modules/type-fest/source/typed-array.d.ts +17 -0
- node_ui/node_modules/type-fest/source/undefined-on-partial-deep.d.ts +80 -0
- node_ui/node_modules/type-fest/source/union-to-intersection.d.ts +61 -0
- node_ui/node_modules/type-fest/source/union-to-tuple.d.ts +56 -0
- node_ui/node_modules/type-fest/source/unknown-array.d.ts +25 -0
- node_ui/node_modules/type-fest/source/unknown-map.d.ts +24 -0
- node_ui/node_modules/type-fest/source/unknown-record.d.ts +31 -0
- node_ui/node_modules/type-fest/source/unknown-set.d.ts +24 -0
- node_ui/node_modules/type-fest/source/value-of.d.ts +42 -0
- node_ui/node_modules/type-fest/source/words.d.ts +118 -0
- node_ui/node_modules/type-fest/source/writable-deep.d.ts +83 -0
- node_ui/node_modules/type-fest/source/writable-keys-of.d.ts +33 -0
- node_ui/node_modules/type-fest/source/writable.d.ts +68 -0
- node_ui/node_modules/widest-line/index.d.ts +12 -0
- node_ui/node_modules/widest-line/index.js +11 -0
- node_ui/node_modules/widest-line/license +9 -0
- node_ui/node_modules/widest-line/package.json +60 -0
- node_ui/node_modules/widest-line/readme.md +26 -0
- node_ui/node_modules/wrap-ansi/index.d.ts +41 -0
- node_ui/node_modules/wrap-ansi/index.js +222 -0
- node_ui/node_modules/wrap-ansi/license +9 -0
- node_ui/node_modules/wrap-ansi/package.json +69 -0
- node_ui/node_modules/wrap-ansi/readme.md +75 -0
- node_ui/node_modules/ws/LICENSE +20 -0
- node_ui/node_modules/ws/README.md +548 -0
- node_ui/node_modules/ws/browser.js +8 -0
- node_ui/node_modules/ws/index.js +13 -0
- node_ui/node_modules/ws/lib/buffer-util.js +131 -0
- node_ui/node_modules/ws/lib/constants.js +18 -0
- node_ui/node_modules/ws/lib/event-target.js +292 -0
- node_ui/node_modules/ws/lib/extension.js +203 -0
- node_ui/node_modules/ws/lib/limiter.js +55 -0
- node_ui/node_modules/ws/lib/permessage-deflate.js +528 -0
- node_ui/node_modules/ws/lib/receiver.js +706 -0
- node_ui/node_modules/ws/lib/sender.js +602 -0
- node_ui/node_modules/ws/lib/stream.js +161 -0
- node_ui/node_modules/ws/lib/subprotocol.js +62 -0
- node_ui/node_modules/ws/lib/validation.js +152 -0
- node_ui/node_modules/ws/lib/websocket-server.js +550 -0
- node_ui/node_modules/ws/lib/websocket.js +1388 -0
- node_ui/node_modules/ws/package.json +69 -0
- node_ui/node_modules/ws/wrapper.mjs +8 -0
- node_ui/node_modules/yoga-wasm-web/LICENSE +21 -0
- node_ui/node_modules/yoga-wasm-web/README.md +70 -0
- node_ui/node_modules/yoga-wasm-web/dist/asm.d.ts +6 -0
- node_ui/node_modules/yoga-wasm-web/dist/asm.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/auto.d.ts +7 -0
- node_ui/node_modules/yoga-wasm-web/dist/browser.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/generated/YGEnums.d.ts +328 -0
- node_ui/node_modules/yoga-wasm-web/dist/index.d.ts +7 -0
- node_ui/node_modules/yoga-wasm-web/dist/index.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/node.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/wrapAsm-57389177.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/wrapAsm-f766f97f.js +1 -0
- node_ui/node_modules/yoga-wasm-web/dist/wrapAsm.d.ts +176 -0
- node_ui/node_modules/yoga-wasm-web/dist/yoga.wasm +0 -0
- node_ui/node_modules/yoga-wasm-web/package.json +56 -0
- node_ui/package.json +21 -0
- claude_code_tools/codex_bridge_mcp.py +0 -333
- claude_code_tools-0.2.0.dist-info/METADATA +0 -495
- claude_code_tools-0.2.0.dist-info/RECORD +0 -22
- {claude_code_tools-0.2.0.dist-info → claude_code_tools-1.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,2460 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
aichat - Unified CLI for AI chat session management tools.
|
|
4
|
+
|
|
5
|
+
This provides a grouped command interface for managing Claude Code and
|
|
6
|
+
Codex sessions, following the pattern of tools like git, docker, etc.
|
|
7
|
+
|
|
8
|
+
All session-related tools are accessible as subcommands:
|
|
9
|
+
aichat search - Full-text search across all sessions
|
|
10
|
+
aichat resume - Resume a session (latest or by ID)
|
|
11
|
+
aichat menu - Interactive session menu
|
|
12
|
+
aichat trim - Trim session content
|
|
13
|
+
... and more
|
|
14
|
+
|
|
15
|
+
For backward compatibility, all flat commands (find-claude-session,
|
|
16
|
+
etc.) are still available.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SessionIDGroup(click.Group):
|
|
23
|
+
"""Custom group that treats unknown commands as session IDs for menu."""
|
|
24
|
+
|
|
25
|
+
def parse_args(self, ctx, args):
|
|
26
|
+
# If the first arg looks like a session ID (not a known command), route to menu
|
|
27
|
+
if args and args[0] not in self.commands and not args[0].startswith('-'):
|
|
28
|
+
# Treat as session ID - prepend 'menu' to make it a menu command
|
|
29
|
+
args = ['menu'] + args
|
|
30
|
+
return super().parse_args(ctx, args)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.group(cls=SessionIDGroup, invoke_without_command=True)
|
|
34
|
+
@click.version_option()
|
|
35
|
+
@click.option(
|
|
36
|
+
'--claude-home',
|
|
37
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
38
|
+
help='Claude home directory (default: ~/.claude or CLAUDE_CONFIG_DIR)',
|
|
39
|
+
)
|
|
40
|
+
@click.option(
|
|
41
|
+
'--codex-home',
|
|
42
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
43
|
+
help='Codex home directory (default: ~/.codex or CODEX_HOME)',
|
|
44
|
+
)
|
|
45
|
+
@click.pass_context
|
|
46
|
+
def main(ctx, claude_home, codex_home):
|
|
47
|
+
"""
|
|
48
|
+
Session management tools for Claude Code and Codex.
|
|
49
|
+
|
|
50
|
+
This is the recommended interface for managing AI chat sessions.
|
|
51
|
+
Each subcommand provides specialized functionality for finding,
|
|
52
|
+
managing, and manipulating session files.
|
|
53
|
+
|
|
54
|
+
For help on any subcommand, use:
|
|
55
|
+
|
|
56
|
+
\b
|
|
57
|
+
aichat COMMAND --help
|
|
58
|
+
|
|
59
|
+
Examples:
|
|
60
|
+
|
|
61
|
+
\b
|
|
62
|
+
aichat # Action menu for latest session(s)
|
|
63
|
+
aichat abc123-def456 # Shortcut for: aichat menu abc123-def456
|
|
64
|
+
aichat search "langroid" # Full-text search
|
|
65
|
+
aichat resume # Resume latest session
|
|
66
|
+
aichat resume abc123-def456 # Resume specific session
|
|
67
|
+
aichat menu abc123-def456
|
|
68
|
+
aichat trim session-id.jsonl
|
|
69
|
+
|
|
70
|
+
\b
|
|
71
|
+
Environment variables:
|
|
72
|
+
CLAUDE_CONFIG_DIR - Default Claude home (overridden by --claude-home)
|
|
73
|
+
CODEX_HOME - Default Codex home (overridden by --codex-home)
|
|
74
|
+
"""
|
|
75
|
+
# Store home dirs in context for subcommands to access
|
|
76
|
+
ctx.ensure_object(dict)
|
|
77
|
+
ctx.obj['claude_home'] = claude_home
|
|
78
|
+
ctx.obj['codex_home'] = codex_home
|
|
79
|
+
|
|
80
|
+
# Auto-index sessions on every aichat command (incremental, fast if up-to-date)
|
|
81
|
+
# Skip for build-index/clear-index to avoid double-indexing or state conflicts
|
|
82
|
+
# In JSON mode (-j/--json), suppress all output for clean parsing
|
|
83
|
+
import sys
|
|
84
|
+
skip_auto_index_cmds = ['build-index', 'clear-index', 'index-stats']
|
|
85
|
+
should_skip = any(cmd in sys.argv for cmd in skip_auto_index_cmds)
|
|
86
|
+
json_mode = any(arg in sys.argv for arg in ['-j', '--json'])
|
|
87
|
+
if not should_skip:
|
|
88
|
+
try:
|
|
89
|
+
from claude_code_tools.search_index import auto_index
|
|
90
|
+
from claude_code_tools.session_utils import get_claude_home, get_codex_home
|
|
91
|
+
# Respect CLI args, then env vars, then defaults
|
|
92
|
+
auto_index(
|
|
93
|
+
claude_home=get_claude_home(cli_arg=claude_home),
|
|
94
|
+
codex_home=get_codex_home(cli_arg=codex_home),
|
|
95
|
+
verbose=False,
|
|
96
|
+
silent=json_mode,
|
|
97
|
+
)
|
|
98
|
+
except ImportError:
|
|
99
|
+
pass # tantivy not installed
|
|
100
|
+
except Exception:
|
|
101
|
+
pass # Index errors shouldn't block commands
|
|
102
|
+
|
|
103
|
+
if ctx.invoked_subcommand is None:
|
|
104
|
+
# No subcommand - find latest sessions and show action menu
|
|
105
|
+
_find_and_run_session_ui(
|
|
106
|
+
session_id=None,
|
|
107
|
+
agent_constraint='both',
|
|
108
|
+
start_screen='action',
|
|
109
|
+
select_target='action',
|
|
110
|
+
results_title=' Select a session ',
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Shared help text for find commands
|
|
115
|
+
_FIND_OPTIONS_COMMON = """
|
|
116
|
+
Options:
|
|
117
|
+
KEYWORDS Comma-separated keywords to search (AND logic)
|
|
118
|
+
-g, --global Search across all projects
|
|
119
|
+
-n, --num-matches N Number of matches to display (default: 10)
|
|
120
|
+
--original Show only original sessions
|
|
121
|
+
--no-sub Exclude sub-agent sessions
|
|
122
|
+
--no-trim Exclude trimmed sessions
|
|
123
|
+
--no-roll Exclude rollover sessions
|
|
124
|
+
--min-lines N Only sessions with at least N lines
|
|
125
|
+
--before TIMESTAMP Sessions modified before (inclusive)
|
|
126
|
+
--after TIMESTAMP Sessions modified after (inclusive)
|
|
127
|
+
--no-ui Skip options menu, run search with CLI args directly
|
|
128
|
+
--simple-ui Use Rich table UI instead of Node UI"""
|
|
129
|
+
|
|
130
|
+
_FIND_OPTIONS_CODEX = _FIND_OPTIONS_COMMON.replace(
|
|
131
|
+
" --no-sub Exclude sub-agent sessions\n", ""
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
_FIND_TIMESTAMP_HELP = """
|
|
135
|
+
Timestamp formats: YYYYMMDD, YYYY-MM-DD, MM/DD/YY, MM/DD/YYYY
|
|
136
|
+
Optional time: T16:45:23, T16:45, T16"""
|
|
137
|
+
|
|
138
|
+
_FIND_CTX_SETTINGS = {
|
|
139
|
+
"ignore_unknown_options": True,
|
|
140
|
+
"allow_extra_args": True,
|
|
141
|
+
"allow_interspersed_args": False,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _find_and_run_session_ui(
|
|
146
|
+
session_id: str | None,
|
|
147
|
+
agent_constraint: str, # 'claude', 'codex', or 'both'
|
|
148
|
+
start_screen: str,
|
|
149
|
+
select_target: str | None = None,
|
|
150
|
+
results_title: str | None = None,
|
|
151
|
+
direct_action: str | None = None,
|
|
152
|
+
action_kwargs: dict | None = None,
|
|
153
|
+
) -> None:
|
|
154
|
+
"""
|
|
155
|
+
Find session(s) and run Node UI for the specified action.
|
|
156
|
+
|
|
157
|
+
If session_id is provided, routes to session_menu_cli.
|
|
158
|
+
Otherwise, finds latest sessions for current project/branch and shows UI.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
session_id: Optional explicit session ID or path
|
|
162
|
+
agent_constraint: 'claude', 'codex', or 'both'
|
|
163
|
+
start_screen: Screen to show when single session found
|
|
164
|
+
select_target: Screen to go to after selection (multiple sessions)
|
|
165
|
+
results_title: Title for selection screen
|
|
166
|
+
direct_action: If set, execute this action directly instead of showing UI
|
|
167
|
+
action_kwargs: Optional kwargs to pass to action
|
|
168
|
+
"""
|
|
169
|
+
import os
|
|
170
|
+
import subprocess
|
|
171
|
+
import sys
|
|
172
|
+
from pathlib import Path
|
|
173
|
+
|
|
174
|
+
from claude_code_tools.node_menu_ui import run_node_menu_ui
|
|
175
|
+
from claude_code_tools.search_index import SessionIndex
|
|
176
|
+
from claude_code_tools.session_menu_cli import execute_action
|
|
177
|
+
from claude_code_tools.session_utils import default_export_path
|
|
178
|
+
|
|
179
|
+
if session_id:
|
|
180
|
+
if direct_action:
|
|
181
|
+
# Direct action mode: bypass session_menu_cli for proper context
|
|
182
|
+
# This allows direct_action to be passed to Node UI for correct
|
|
183
|
+
# escape behavior (exit to shell vs. go to resume menu)
|
|
184
|
+
from claude_code_tools.session_utils import (
|
|
185
|
+
find_session_file,
|
|
186
|
+
default_export_path,
|
|
187
|
+
detect_agent_from_path,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Find session file
|
|
191
|
+
input_path = Path(session_id).expanduser()
|
|
192
|
+
if input_path.exists() and input_path.is_file():
|
|
193
|
+
session_file = input_path
|
|
194
|
+
agent = detect_agent_from_path(session_file)
|
|
195
|
+
project_path = str(session_file.parent)
|
|
196
|
+
git_branch = None
|
|
197
|
+
else:
|
|
198
|
+
result = find_session_file(session_id)
|
|
199
|
+
if not result:
|
|
200
|
+
print(f"Error: Session not found: {session_id}", file=sys.stderr)
|
|
201
|
+
sys.exit(1)
|
|
202
|
+
agent, session_file, project_path, git_branch = result
|
|
203
|
+
|
|
204
|
+
# Build session dict for Node UI
|
|
205
|
+
session_dict = {
|
|
206
|
+
"agent": agent,
|
|
207
|
+
"agent_display": "Claude" if agent == "claude" else "Codex",
|
|
208
|
+
"session_id": session_file.stem,
|
|
209
|
+
"mod_time": session_file.stat().st_mtime,
|
|
210
|
+
"create_time": session_file.stat().st_ctime,
|
|
211
|
+
"lines": 0, # Not needed for direct action
|
|
212
|
+
"project": Path(project_path).name,
|
|
213
|
+
"preview": "",
|
|
214
|
+
"cwd": project_path,
|
|
215
|
+
"branch": git_branch or "",
|
|
216
|
+
"file_path": str(session_file),
|
|
217
|
+
"default_export_path": str(default_export_path(session_file, agent)),
|
|
218
|
+
"is_trimmed": False,
|
|
219
|
+
"derivation_type": None,
|
|
220
|
+
"is_sidechain": False,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Handler for actions
|
|
224
|
+
def handler(sess, action, kwargs=None):
|
|
225
|
+
merged_kwargs = {**(action_kwargs or {}), **(kwargs or {})}
|
|
226
|
+
return execute_action(
|
|
227
|
+
action,
|
|
228
|
+
sess["agent"],
|
|
229
|
+
Path(sess["file_path"]),
|
|
230
|
+
sess["cwd"],
|
|
231
|
+
action_kwargs=merged_kwargs if merged_kwargs else None,
|
|
232
|
+
session_id=sess.get("session_id"),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
rpc_path = str(Path(__file__).parent / "action_rpc.py")
|
|
236
|
+
|
|
237
|
+
# Run Node UI directly with direct_action for proper escape behavior
|
|
238
|
+
run_node_menu_ui(
|
|
239
|
+
[session_dict],
|
|
240
|
+
[],
|
|
241
|
+
handler,
|
|
242
|
+
start_screen=start_screen,
|
|
243
|
+
rpc_path=rpc_path,
|
|
244
|
+
direct_action=direct_action,
|
|
245
|
+
)
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
# Normal mode (no direct_action): route through session_menu_cli
|
|
249
|
+
sys.argv = [
|
|
250
|
+
sys.argv[0].replace('aichat', 'session-menu'),
|
|
251
|
+
'--start-screen', start_screen,
|
|
252
|
+
session_id,
|
|
253
|
+
]
|
|
254
|
+
from claude_code_tools.session_menu_cli import main as menu_main
|
|
255
|
+
menu_main()
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
# No session provided - find latest sessions for current project and branch
|
|
259
|
+
current_cwd = os.getcwd()
|
|
260
|
+
current_branch = None
|
|
261
|
+
try:
|
|
262
|
+
result = subprocess.run(
|
|
263
|
+
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
|
264
|
+
capture_output=True, text=True, check=True
|
|
265
|
+
)
|
|
266
|
+
current_branch = result.stdout.strip()
|
|
267
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
# Use the Tantivy index for fast session lookup
|
|
271
|
+
index_path = Path.home() / ".cctools" / "search-index"
|
|
272
|
+
if not index_path.exists():
|
|
273
|
+
print(
|
|
274
|
+
"Session index not found. Run 'aichat search' first to build the index.",
|
|
275
|
+
file=sys.stderr
|
|
276
|
+
)
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
idx = SessionIndex(index_path)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
print(f"Failed to open session index: {e}", file=sys.stderr)
|
|
283
|
+
sys.exit(1)
|
|
284
|
+
|
|
285
|
+
candidates = []
|
|
286
|
+
used_fallback = False # Track if any agent fell back to any-branch
|
|
287
|
+
|
|
288
|
+
def _get_latest_session(agent: str) -> tuple[dict | None, bool]:
|
|
289
|
+
"""Get latest session for agent, with fallback to any branch.
|
|
290
|
+
|
|
291
|
+
Returns (session_dict, used_fallback).
|
|
292
|
+
"""
|
|
293
|
+
# First try with branch filter
|
|
294
|
+
if current_branch:
|
|
295
|
+
session = idx.get_latest_session(
|
|
296
|
+
cwd=current_cwd, branch=current_branch, agent=agent
|
|
297
|
+
)
|
|
298
|
+
if session:
|
|
299
|
+
return session, False
|
|
300
|
+
|
|
301
|
+
# Fallback: try without branch filter
|
|
302
|
+
session = idx.get_latest_session(cwd=current_cwd, agent=agent)
|
|
303
|
+
return session, bool(session) # used_fallback=True only if we found one
|
|
304
|
+
|
|
305
|
+
def _session_to_candidate(s: dict) -> dict:
|
|
306
|
+
"""Convert index session dict to UI candidate format."""
|
|
307
|
+
export_path = s.get("export_path", "")
|
|
308
|
+
session_file = Path(export_path) if export_path else None
|
|
309
|
+
agent = s.get("agent", "claude")
|
|
310
|
+
|
|
311
|
+
# Parse timestamps - index stores as ISO strings
|
|
312
|
+
mod_time = 0
|
|
313
|
+
create_time = 0
|
|
314
|
+
if s.get("modified"):
|
|
315
|
+
try:
|
|
316
|
+
from datetime import datetime
|
|
317
|
+
mod_time = datetime.fromisoformat(
|
|
318
|
+
s["modified"].replace("Z", "+00:00")
|
|
319
|
+
).timestamp()
|
|
320
|
+
except (ValueError, TypeError):
|
|
321
|
+
pass
|
|
322
|
+
if s.get("created"):
|
|
323
|
+
try:
|
|
324
|
+
from datetime import datetime
|
|
325
|
+
create_time = datetime.fromisoformat(
|
|
326
|
+
s["created"].replace("Z", "+00:00")
|
|
327
|
+
).timestamp()
|
|
328
|
+
except (ValueError, TypeError):
|
|
329
|
+
pass
|
|
330
|
+
|
|
331
|
+
# Build preview from last message content (convention: show most recent)
|
|
332
|
+
preview = ""
|
|
333
|
+
if s.get("last_msg_content"):
|
|
334
|
+
role = s.get("last_msg_role", "assistant")
|
|
335
|
+
preview = f"[{role}] {s['last_msg_content'][:200]}"
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
"agent": agent,
|
|
339
|
+
"agent_display": "Claude" if agent == "claude" else "Codex",
|
|
340
|
+
"session_id": s.get("session_id", ""),
|
|
341
|
+
"mod_time": mod_time,
|
|
342
|
+
"create_time": create_time,
|
|
343
|
+
"lines": s.get("lines", 0),
|
|
344
|
+
"project": s.get("project", ""),
|
|
345
|
+
"preview": preview,
|
|
346
|
+
"cwd": s.get("cwd", ""),
|
|
347
|
+
"branch": s.get("branch", ""),
|
|
348
|
+
"file_path": export_path,
|
|
349
|
+
"default_export_path": str(
|
|
350
|
+
default_export_path(session_file, agent)
|
|
351
|
+
) if session_file and session_file.exists() else "",
|
|
352
|
+
"is_trimmed": s.get("derivation_type") == "trimmed",
|
|
353
|
+
"derivation_type": s.get("derivation_type"),
|
|
354
|
+
"is_sidechain": s.get("is_sidechain") == "true",
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
# Find Claude sessions if applicable
|
|
358
|
+
if agent_constraint in ('claude', 'both'):
|
|
359
|
+
session, fallback = _get_latest_session("claude")
|
|
360
|
+
if session:
|
|
361
|
+
candidates.append(_session_to_candidate(session))
|
|
362
|
+
if fallback:
|
|
363
|
+
used_fallback = True
|
|
364
|
+
|
|
365
|
+
# Find Codex sessions if applicable
|
|
366
|
+
if agent_constraint in ('codex', 'both'):
|
|
367
|
+
session, fallback = _get_latest_session("codex")
|
|
368
|
+
if session:
|
|
369
|
+
candidates.append(_session_to_candidate(session))
|
|
370
|
+
if fallback:
|
|
371
|
+
used_fallback = True
|
|
372
|
+
|
|
373
|
+
# Build the unified scope message
|
|
374
|
+
project_name = Path(current_cwd).name
|
|
375
|
+
agent_desc = {
|
|
376
|
+
'claude': 'Claude',
|
|
377
|
+
'codex': 'Codex',
|
|
378
|
+
'both': 'Claude/Codex',
|
|
379
|
+
}.get(agent_constraint, 'Claude/Codex')
|
|
380
|
+
branch_part = f" on branch '{current_branch}'" if current_branch else ""
|
|
381
|
+
fallback_note = " (fallback to any branch if none found)" if current_branch else ""
|
|
382
|
+
scope_text = (
|
|
383
|
+
f"Latest {agent_desc} sessions for '{project_name}'{branch_part}{fallback_note}"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
if not candidates:
|
|
387
|
+
print(
|
|
388
|
+
f"No {agent_desc} sessions found for '{project_name}'"
|
|
389
|
+
f"{branch_part} (even with fallback to any branch).",
|
|
390
|
+
file=sys.stderr
|
|
391
|
+
)
|
|
392
|
+
sys.exit(1)
|
|
393
|
+
|
|
394
|
+
# Handler for when user selects and acts - returns 'back' if user wants to
|
|
395
|
+
# go back to menu
|
|
396
|
+
def handler(sess, action, kwargs=None):
|
|
397
|
+
session_file = Path(sess["file_path"])
|
|
398
|
+
merged_kwargs = {**(action_kwargs or {}), **(kwargs or {})}
|
|
399
|
+
return execute_action(
|
|
400
|
+
action,
|
|
401
|
+
sess["agent"],
|
|
402
|
+
session_file,
|
|
403
|
+
sess["cwd"],
|
|
404
|
+
action_kwargs=merged_kwargs if merged_kwargs else None,
|
|
405
|
+
session_id=sess.get("session_id"),
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
rpc_path = str(Path(__file__).parent / "action_rpc.py")
|
|
409
|
+
|
|
410
|
+
# If direct_action specified, execute it immediately for single session
|
|
411
|
+
if direct_action and len(candidates) == 1:
|
|
412
|
+
handler(candidates[0], direct_action, action_kwargs)
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
# Create handler that may execute direct_action after selection
|
|
416
|
+
def selection_handler(sess, action, kwargs=None):
|
|
417
|
+
if direct_action:
|
|
418
|
+
# Execute direct_action instead of whatever came from UI
|
|
419
|
+
return handler(sess, direct_action, action_kwargs)
|
|
420
|
+
else:
|
|
421
|
+
return handler(sess, action, kwargs)
|
|
422
|
+
|
|
423
|
+
if len(candidates) == 1:
|
|
424
|
+
# Single session - go directly to start_screen
|
|
425
|
+
run_node_menu_ui(
|
|
426
|
+
candidates,
|
|
427
|
+
[],
|
|
428
|
+
selection_handler,
|
|
429
|
+
start_screen=start_screen,
|
|
430
|
+
scope_line=scope_text,
|
|
431
|
+
rpc_path=rpc_path,
|
|
432
|
+
direct_action=direct_action,
|
|
433
|
+
)
|
|
434
|
+
else:
|
|
435
|
+
# Multiple sessions - show selection first
|
|
436
|
+
run_node_menu_ui(
|
|
437
|
+
candidates,
|
|
438
|
+
[],
|
|
439
|
+
selection_handler,
|
|
440
|
+
start_screen="results",
|
|
441
|
+
select_target=select_target or start_screen,
|
|
442
|
+
results_title=results_title or f" Select session for {start_screen} ",
|
|
443
|
+
start_zoomed=True,
|
|
444
|
+
scope_line=scope_text,
|
|
445
|
+
rpc_path=rpc_path,
|
|
446
|
+
direct_action=direct_action,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
@main.command("find", context_settings=_FIND_CTX_SETTINGS, add_help_option=False, hidden=True)
|
|
451
|
+
@click.pass_context
|
|
452
|
+
def find(ctx):
|
|
453
|
+
"""Find sessions across all agents (Claude Code, Codex, etc.)."""
|
|
454
|
+
import sys
|
|
455
|
+
sys.argv = [sys.argv[0].replace('aichat', 'find-session')] + ctx.args
|
|
456
|
+
from claude_code_tools.find_session import main as find_main
|
|
457
|
+
find_main()
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
find.__doc__ = f"""Find sessions across all agents (Claude Code, Codex, etc.).
|
|
461
|
+
{_FIND_OPTIONS_COMMON}
|
|
462
|
+
--agents AGENT [...] Limit to one or more agents (e.g., --agents claude,
|
|
463
|
+
--agents claude codex). Default: all.
|
|
464
|
+
{_FIND_TIMESTAMP_HELP}
|
|
465
|
+
|
|
466
|
+
Examples:
|
|
467
|
+
aichat find "langroid,MCP"
|
|
468
|
+
aichat find -g --min-lines 50 --agents claude
|
|
469
|
+
aichat find --after 11/20/25 --before 11/25/25
|
|
470
|
+
"""
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
@main.command("find-claude", context_settings=_FIND_CTX_SETTINGS, add_help_option=False, hidden=True)
|
|
474
|
+
@click.pass_context
|
|
475
|
+
def find_claude(ctx):
|
|
476
|
+
"""Find Claude Code sessions by keywords."""
|
|
477
|
+
import sys
|
|
478
|
+
sys.argv = [sys.argv[0].replace('aichat', 'find-claude-session')] + ctx.args
|
|
479
|
+
from claude_code_tools.find_claude_session import main as find_claude_main
|
|
480
|
+
find_claude_main()
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
find_claude.__doc__ = f"""Find Claude Code sessions by keywords.
|
|
484
|
+
{_FIND_OPTIONS_COMMON}
|
|
485
|
+
{_FIND_TIMESTAMP_HELP}
|
|
486
|
+
|
|
487
|
+
Examples:
|
|
488
|
+
aichat find-claude "bug fix"
|
|
489
|
+
aichat find-claude -g --min-lines 100
|
|
490
|
+
aichat find-claude --after 2025-11-01
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@main.command("find-codex", context_settings=_FIND_CTX_SETTINGS, add_help_option=False, hidden=True)
|
|
495
|
+
@click.pass_context
|
|
496
|
+
def find_codex(ctx):
|
|
497
|
+
"""Find Codex sessions by keywords."""
|
|
498
|
+
import sys
|
|
499
|
+
sys.argv = [sys.argv[0].replace('aichat', 'find-codex-session')] + ctx.args
|
|
500
|
+
from claude_code_tools.find_codex_session import main as find_codex_main
|
|
501
|
+
find_codex_main()
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
find_codex.__doc__ = f"""Find Codex sessions by keywords.
|
|
505
|
+
{_FIND_OPTIONS_CODEX}
|
|
506
|
+
{_FIND_TIMESTAMP_HELP}
|
|
507
|
+
|
|
508
|
+
Examples:
|
|
509
|
+
aichat find-codex "error"
|
|
510
|
+
aichat find-codex -g --after 11/15/25
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@main.command("find-original", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
515
|
+
@click.pass_context
|
|
516
|
+
def find_original(ctx):
|
|
517
|
+
"""Find the original session from a trimmed/continued session."""
|
|
518
|
+
import sys
|
|
519
|
+
sys.argv = [sys.argv[0].replace('aichat', 'find-original-session')] + ctx.args
|
|
520
|
+
from claude_code_tools.find_original_session import (
|
|
521
|
+
main as find_original_main,
|
|
522
|
+
)
|
|
523
|
+
find_original_main()
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
@main.command("find-derived", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
527
|
+
@click.pass_context
|
|
528
|
+
def find_derived(ctx):
|
|
529
|
+
"""Find derived sessions (trimmed/continued) from an original."""
|
|
530
|
+
import sys
|
|
531
|
+
sys.argv = [sys.argv[0].replace('aichat', 'find-trimmed-sessions')] + ctx.args
|
|
532
|
+
from claude_code_tools.find_trimmed_sessions import (
|
|
533
|
+
main as find_derived_main,
|
|
534
|
+
)
|
|
535
|
+
find_derived_main()
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
@main.command("menu", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
539
|
+
@click.pass_context
|
|
540
|
+
def menu(ctx):
|
|
541
|
+
"""Interactive menu for a specific session (by ID or path)."""
|
|
542
|
+
import sys
|
|
543
|
+
sys.argv = [sys.argv[0].replace('aichat', 'session-menu')] + ctx.args
|
|
544
|
+
from claude_code_tools.session_menu_cli import main as menu_main
|
|
545
|
+
menu_main()
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
@main.command("trim")
|
|
549
|
+
@click.argument("session", required=False)
|
|
550
|
+
@click.option("--tools", "-t",
|
|
551
|
+
help="Comma-separated tools to trim (e.g., 'bash,read,edit'). "
|
|
552
|
+
"Default: all tools.")
|
|
553
|
+
@click.option("--len", "-l", "threshold", type=int, default=500,
|
|
554
|
+
help="Minimum length threshold in chars for trimming (default: 500)")
|
|
555
|
+
@click.option("--trim-assistant", "-a", "trim_assistant", type=int,
|
|
556
|
+
help="Trim assistant messages: positive N trims first N over threshold, "
|
|
557
|
+
"negative N trims all except last |N| over threshold")
|
|
558
|
+
@click.option("--output-dir", "-o",
|
|
559
|
+
help="Output directory (default: same as input file)")
|
|
560
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
561
|
+
help="Force agent type (auto-detected if not specified)")
|
|
562
|
+
@click.option("--claude-home", help="Path to Claude home directory")
|
|
563
|
+
@click.option("--simple-ui", is_flag=True,
|
|
564
|
+
help="Use simple CLI trim instead of Node UI (requires session ID)")
|
|
565
|
+
def trim(session, tools, threshold, trim_assistant, output_dir, agent, claude_home, simple_ui):
|
|
566
|
+
"""Trim session to reduce size by truncating large tool outputs.
|
|
567
|
+
|
|
568
|
+
Trims tool call results and optionally assistant messages that exceed
|
|
569
|
+
the length threshold. Creates a new trimmed session file with lineage
|
|
570
|
+
metadata linking back to the original.
|
|
571
|
+
|
|
572
|
+
If no session ID provided, finds latest session for current project/branch
|
|
573
|
+
and opens the interactive trim menu.
|
|
574
|
+
|
|
575
|
+
\b
|
|
576
|
+
Examples:
|
|
577
|
+
aichat trim # Interactive menu for latest session
|
|
578
|
+
aichat trim abc123 # Interactive menu for specific session
|
|
579
|
+
aichat trim abc123 --simple-ui # Direct CLI trim with defaults
|
|
580
|
+
aichat trim abc123 -t bash,read -l 1000 # Trim specific tools, custom threshold
|
|
581
|
+
aichat trim abc123 -a 5 # Also trim first 5 long assistant msgs
|
|
582
|
+
|
|
583
|
+
\b
|
|
584
|
+
Options:
|
|
585
|
+
--tools, -t Which tool outputs to trim (default: all)
|
|
586
|
+
--len, -l Character threshold for trimming (default: 500)
|
|
587
|
+
--trim-assistant, -a Trim assistant messages too
|
|
588
|
+
--output-dir, -o Where to write trimmed file
|
|
589
|
+
"""
|
|
590
|
+
import sys
|
|
591
|
+
|
|
592
|
+
if simple_ui or tools or trim_assistant or output_dir:
|
|
593
|
+
# Direct CLI mode - need a session
|
|
594
|
+
if not session:
|
|
595
|
+
print("Error: Direct trim options require a session ID", file=sys.stderr)
|
|
596
|
+
print("Use 'aichat trim' without options for interactive mode", file=sys.stderr)
|
|
597
|
+
sys.exit(1)
|
|
598
|
+
|
|
599
|
+
# Build args for trim-session CLI
|
|
600
|
+
args = [session]
|
|
601
|
+
if tools:
|
|
602
|
+
args.extend(["--tools", tools])
|
|
603
|
+
if threshold != 500:
|
|
604
|
+
args.extend(["--len", str(threshold)])
|
|
605
|
+
if trim_assistant is not None:
|
|
606
|
+
args.extend(["--trim-assistant-messages", str(trim_assistant)])
|
|
607
|
+
if output_dir:
|
|
608
|
+
args.extend(["--output-dir", output_dir])
|
|
609
|
+
if agent:
|
|
610
|
+
args.extend(["--agent", agent])
|
|
611
|
+
if claude_home:
|
|
612
|
+
args.extend(["--claude-home", claude_home])
|
|
613
|
+
|
|
614
|
+
sys.argv = [sys.argv[0].replace('aichat', 'trim-session')] + args
|
|
615
|
+
from claude_code_tools.trim_session import main as trim_main
|
|
616
|
+
trim_main()
|
|
617
|
+
return
|
|
618
|
+
|
|
619
|
+
_find_and_run_session_ui(
|
|
620
|
+
session_id=session,
|
|
621
|
+
agent_constraint='both',
|
|
622
|
+
start_screen='trim_menu',
|
|
623
|
+
select_target='trim_menu',
|
|
624
|
+
results_title=' Which session to trim? ',
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
@main.command("smart-trim")
|
|
629
|
+
@click.argument("session", required=False)
|
|
630
|
+
@click.option("--instructions", "-i",
|
|
631
|
+
help="Custom instructions for what to prioritize when trimming")
|
|
632
|
+
@click.option("--exclude-types", "-e",
|
|
633
|
+
help="Comma-separated message types to never trim (default: user)")
|
|
634
|
+
@click.option("--preserve-recent", "-p", type=int, default=10,
|
|
635
|
+
help="Always preserve last N messages (default: 10)")
|
|
636
|
+
@click.option("--len", "-l", "content_threshold", type=int, default=200,
|
|
637
|
+
help="Minimum chars for content extraction (default: 200)")
|
|
638
|
+
@click.option("--output-dir", "-o",
|
|
639
|
+
help="Output directory (default: same as input)")
|
|
640
|
+
@click.option("--dry-run", "-n", is_flag=True,
|
|
641
|
+
help="Show what would be trimmed without doing it")
|
|
642
|
+
@click.option("--claude-home", help="Path to Claude home directory")
|
|
643
|
+
def smart_trim(session, instructions, exclude_types, preserve_recent, content_threshold,
|
|
644
|
+
output_dir, dry_run, claude_home):
|
|
645
|
+
"""Smart trim using Claude SDK agents (EXPERIMENTAL).
|
|
646
|
+
|
|
647
|
+
Uses an LLM to intelligently analyze the session and decide what can
|
|
648
|
+
be safely trimmed while preserving important context. Creates a new
|
|
649
|
+
trimmed session with lineage metadata.
|
|
650
|
+
|
|
651
|
+
If no session ID provided, finds latest session for current project/branch.
|
|
652
|
+
|
|
653
|
+
\b
|
|
654
|
+
Examples:
|
|
655
|
+
aichat smart-trim # Interactive for latest session
|
|
656
|
+
aichat smart-trim abc123 # Smart trim specific session
|
|
657
|
+
aichat smart-trim abc123 --dry-run # Preview what would be trimmed
|
|
658
|
+
aichat smart-trim abc123 -p 20 # Preserve last 20 messages
|
|
659
|
+
aichat smart-trim abc123 -e user,system # Never trim user or system msgs
|
|
660
|
+
aichat smart-trim abc123 -i "preserve auth-related messages"
|
|
661
|
+
|
|
662
|
+
\b
|
|
663
|
+
Options:
|
|
664
|
+
--instructions, -i Custom instructions for what to prioritize
|
|
665
|
+
--exclude-types, -e Message types to EXCLUDE from trimming
|
|
666
|
+
--preserve-recent, -p Keep last N messages untouched (default: 10)
|
|
667
|
+
--len, -l Min chars for content extraction (default: 200)
|
|
668
|
+
--dry-run, -n Preview only, don't actually trim
|
|
669
|
+
"""
|
|
670
|
+
import sys
|
|
671
|
+
from pathlib import Path
|
|
672
|
+
|
|
673
|
+
from claude_code_tools.session_utils import find_session_file, detect_agent_from_path
|
|
674
|
+
|
|
675
|
+
# If --instructions provided, use the handler function (same as TUI)
|
|
676
|
+
if instructions and session:
|
|
677
|
+
input_path = Path(session).expanduser()
|
|
678
|
+
if input_path.exists() and input_path.is_file():
|
|
679
|
+
session_file = input_path
|
|
680
|
+
detected_agent = detect_agent_from_path(session_file)
|
|
681
|
+
session_id = session_file.stem
|
|
682
|
+
project_path = str(session_file.parent)
|
|
683
|
+
else:
|
|
684
|
+
result = find_session_file(session)
|
|
685
|
+
if not result:
|
|
686
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
687
|
+
sys.exit(1)
|
|
688
|
+
detected_agent, session_file, project_path, _ = result
|
|
689
|
+
session_id = session_file.stem
|
|
690
|
+
|
|
691
|
+
# Use the handler function which supports custom_instructions
|
|
692
|
+
if detected_agent == "claude":
|
|
693
|
+
from claude_code_tools.find_claude_session import handle_smart_trim_resume_claude
|
|
694
|
+
handle_smart_trim_resume_claude(
|
|
695
|
+
session_id, project_path, claude_home,
|
|
696
|
+
custom_instructions=instructions,
|
|
697
|
+
)
|
|
698
|
+
else:
|
|
699
|
+
from claude_code_tools.find_codex_session import handle_smart_trim_resume_codex
|
|
700
|
+
from claude_code_tools.session_utils import get_codex_home
|
|
701
|
+
handle_smart_trim_resume_codex(
|
|
702
|
+
{"file_path": str(session_file), "cwd": project_path, "session_id": session_id},
|
|
703
|
+
Path(get_codex_home(cli_arg=None)),
|
|
704
|
+
custom_instructions=instructions,
|
|
705
|
+
)
|
|
706
|
+
return
|
|
707
|
+
|
|
708
|
+
# If any direct CLI options specified (but not instructions), use smart_trim.py
|
|
709
|
+
if exclude_types or preserve_recent != 10 or content_threshold != 200 or output_dir or dry_run:
|
|
710
|
+
if not session:
|
|
711
|
+
print("Error: Direct smart-trim options require a session ID", file=sys.stderr)
|
|
712
|
+
print("Use 'aichat smart-trim' without options for interactive mode", file=sys.stderr)
|
|
713
|
+
sys.exit(1)
|
|
714
|
+
|
|
715
|
+
# Build args for smart-trim CLI
|
|
716
|
+
args = [session]
|
|
717
|
+
if exclude_types:
|
|
718
|
+
args.extend(["--exclude-types", exclude_types])
|
|
719
|
+
if preserve_recent != 10:
|
|
720
|
+
args.extend(["--preserve-recent", str(preserve_recent)])
|
|
721
|
+
if content_threshold != 200:
|
|
722
|
+
args.extend(["--content-threshold", str(content_threshold)])
|
|
723
|
+
if output_dir:
|
|
724
|
+
args.extend(["--output-dir", output_dir])
|
|
725
|
+
if dry_run:
|
|
726
|
+
args.append("--dry-run")
|
|
727
|
+
if claude_home:
|
|
728
|
+
args.extend(["--claude-home", claude_home])
|
|
729
|
+
|
|
730
|
+
sys.argv = [sys.argv[0].replace('aichat', 'smart-trim')] + args
|
|
731
|
+
from claude_code_tools.smart_trim import main as smart_trim_main
|
|
732
|
+
smart_trim_main()
|
|
733
|
+
return
|
|
734
|
+
|
|
735
|
+
# Show interactive UI for entering instructions
|
|
736
|
+
# (whether session provided or not - find latest if not)
|
|
737
|
+
_find_and_run_session_ui(
|
|
738
|
+
session_id=session,
|
|
739
|
+
agent_constraint='both',
|
|
740
|
+
start_screen='smart_trim_form',
|
|
741
|
+
select_target='smart_trim_form',
|
|
742
|
+
results_title=' Which session to smart-trim? ',
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
@main.command("export", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
747
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False), help="Force export with specific agent")
|
|
748
|
+
@click.argument("session", required=False)
|
|
749
|
+
@click.pass_context
|
|
750
|
+
def export_session(ctx, agent, session):
|
|
751
|
+
"""Export session to text/markdown format.
|
|
752
|
+
|
|
753
|
+
If no session ID provided, finds latest session for current project/branch.
|
|
754
|
+
Auto-detects session type and uses matching export command.
|
|
755
|
+
Use --agent to override and force export with a specific agent.
|
|
756
|
+
"""
|
|
757
|
+
import sys
|
|
758
|
+
from pathlib import Path
|
|
759
|
+
from claude_code_tools.session_utils import detect_agent_from_path, find_session_file
|
|
760
|
+
|
|
761
|
+
if not session:
|
|
762
|
+
# No session provided - find latest and export directly
|
|
763
|
+
_find_and_run_session_ui(
|
|
764
|
+
session_id=None,
|
|
765
|
+
agent_constraint='both',
|
|
766
|
+
start_screen='action',
|
|
767
|
+
results_title=' Which session to export? ',
|
|
768
|
+
direct_action='export',
|
|
769
|
+
)
|
|
770
|
+
return
|
|
771
|
+
|
|
772
|
+
# Session provided - existing behavior
|
|
773
|
+
# Try to detect session type
|
|
774
|
+
detected_agent = None
|
|
775
|
+
session_file = None
|
|
776
|
+
|
|
777
|
+
# First check if it's a file path
|
|
778
|
+
input_path = Path(session).expanduser()
|
|
779
|
+
if input_path.exists() and input_path.is_file():
|
|
780
|
+
session_file = input_path
|
|
781
|
+
detected_agent = detect_agent_from_path(session_file)
|
|
782
|
+
else:
|
|
783
|
+
# Try to find by session ID
|
|
784
|
+
result = find_session_file(session)
|
|
785
|
+
if result:
|
|
786
|
+
detected_agent, session_file, _, _ = result
|
|
787
|
+
|
|
788
|
+
# Determine which agent to use
|
|
789
|
+
if agent:
|
|
790
|
+
# User explicitly specified agent
|
|
791
|
+
export_agent = agent.lower()
|
|
792
|
+
if detected_agent and detected_agent != export_agent:
|
|
793
|
+
print(f"\nDetected {detected_agent.upper()} session")
|
|
794
|
+
print(f"Exporting with {export_agent.upper()} (user specified)")
|
|
795
|
+
else:
|
|
796
|
+
print(f"\nExporting with {export_agent.upper()} (user specified)")
|
|
797
|
+
elif detected_agent:
|
|
798
|
+
# Use detected agent
|
|
799
|
+
export_agent = detected_agent
|
|
800
|
+
print(f"\nDetected {detected_agent.upper()} session")
|
|
801
|
+
print(f"Exporting with {export_agent.upper()}")
|
|
802
|
+
else:
|
|
803
|
+
# Default to Claude if cannot detect
|
|
804
|
+
export_agent = "claude"
|
|
805
|
+
print(f"\nCould not detect session type, defaulting to CLAUDE")
|
|
806
|
+
|
|
807
|
+
print()
|
|
808
|
+
|
|
809
|
+
# Route to appropriate export command
|
|
810
|
+
if export_agent == "claude":
|
|
811
|
+
sys.argv = [sys.argv[0].replace('aichat', 'export-claude-session'), session] + ctx.args
|
|
812
|
+
from claude_code_tools.export_claude_session import main as export_main
|
|
813
|
+
export_main()
|
|
814
|
+
else:
|
|
815
|
+
sys.argv = [sys.argv[0].replace('aichat', 'export-codex-session'), session] + ctx.args
|
|
816
|
+
from claude_code_tools.export_codex_session import main as export_main
|
|
817
|
+
export_main()
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
@main.command("export-claude", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
821
|
+
@click.pass_context
|
|
822
|
+
def export_claude(ctx):
|
|
823
|
+
"""Export Claude Code session to text/markdown format.
|
|
824
|
+
|
|
825
|
+
If no session ID provided, finds latest Claude session for current
|
|
826
|
+
project/branch.
|
|
827
|
+
"""
|
|
828
|
+
import sys
|
|
829
|
+
args = ctx.args
|
|
830
|
+
session_id = args[0] if args and not args[0].startswith('-') else None
|
|
831
|
+
|
|
832
|
+
if session_id:
|
|
833
|
+
# Pass to existing export CLI
|
|
834
|
+
sys.argv = [sys.argv[0].replace('aichat', 'export-claude-session')] + args
|
|
835
|
+
from claude_code_tools.export_claude_session import (
|
|
836
|
+
main as export_claude_main,
|
|
837
|
+
)
|
|
838
|
+
export_claude_main()
|
|
839
|
+
else:
|
|
840
|
+
# Find latest Claude session and export directly
|
|
841
|
+
_find_and_run_session_ui(
|
|
842
|
+
session_id=None,
|
|
843
|
+
agent_constraint='claude',
|
|
844
|
+
start_screen='action',
|
|
845
|
+
results_title=' Which Claude session to export? ',
|
|
846
|
+
direct_action='export',
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
@main.command("export-codex", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
851
|
+
@click.pass_context
|
|
852
|
+
def export_codex(ctx):
|
|
853
|
+
"""Export Codex session to text/markdown format.
|
|
854
|
+
|
|
855
|
+
If no session ID provided, finds latest Codex session for current
|
|
856
|
+
project/branch.
|
|
857
|
+
"""
|
|
858
|
+
import sys
|
|
859
|
+
args = ctx.args
|
|
860
|
+
session_id = args[0] if args and not args[0].startswith('-') else None
|
|
861
|
+
|
|
862
|
+
if session_id:
|
|
863
|
+
# Pass to existing export CLI
|
|
864
|
+
sys.argv = [sys.argv[0].replace('aichat', 'export-codex-session')] + args
|
|
865
|
+
from claude_code_tools.export_codex_session import (
|
|
866
|
+
main as export_codex_main,
|
|
867
|
+
)
|
|
868
|
+
export_codex_main()
|
|
869
|
+
else:
|
|
870
|
+
# Find latest Codex session and export directly
|
|
871
|
+
_find_and_run_session_ui(
|
|
872
|
+
session_id=None,
|
|
873
|
+
agent_constraint='codex',
|
|
874
|
+
start_screen='action',
|
|
875
|
+
results_title=' Which Codex session to export? ',
|
|
876
|
+
direct_action='export',
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
@main.command("delete", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
881
|
+
@click.pass_context
|
|
882
|
+
def delete(ctx):
|
|
883
|
+
"""Delete a session file with safety confirmation."""
|
|
884
|
+
import sys
|
|
885
|
+
sys.argv = [sys.argv[0].replace('aichat', 'delete-session')] + ctx.args
|
|
886
|
+
from claude_code_tools.delete_session import main as delete_main
|
|
887
|
+
delete_main()
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
@main.command("info")
|
|
891
|
+
@click.argument("session", required=False)
|
|
892
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
893
|
+
help="Force agent type (auto-detected if not specified)")
|
|
894
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
895
|
+
def info(session, agent, json_output):
|
|
896
|
+
"""Show information about a session.
|
|
897
|
+
|
|
898
|
+
Displays session metadata including file path, agent type, project,
|
|
899
|
+
branch, timestamps, message counts, and lineage (parent sessions).
|
|
900
|
+
|
|
901
|
+
If no session ID provided, shows info for latest session in current
|
|
902
|
+
project/branch.
|
|
903
|
+
|
|
904
|
+
\b
|
|
905
|
+
Examples:
|
|
906
|
+
aichat info # Info for latest session
|
|
907
|
+
aichat info abc123-def456 # Info for specific session
|
|
908
|
+
aichat info --json abc123 # Output as JSON
|
|
909
|
+
"""
|
|
910
|
+
import json as json_lib
|
|
911
|
+
import sys
|
|
912
|
+
from pathlib import Path
|
|
913
|
+
from datetime import datetime
|
|
914
|
+
|
|
915
|
+
from claude_code_tools.session_utils import (
|
|
916
|
+
find_session_file,
|
|
917
|
+
detect_agent_from_path,
|
|
918
|
+
extract_cwd_from_session,
|
|
919
|
+
count_user_messages,
|
|
920
|
+
default_export_path,
|
|
921
|
+
)
|
|
922
|
+
from claude_code_tools.session_lineage import get_continuation_lineage
|
|
923
|
+
|
|
924
|
+
# Find session file
|
|
925
|
+
if session:
|
|
926
|
+
input_path = Path(session).expanduser()
|
|
927
|
+
if input_path.exists() and input_path.is_file():
|
|
928
|
+
session_file = input_path
|
|
929
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
930
|
+
else:
|
|
931
|
+
result = find_session_file(session)
|
|
932
|
+
if not result:
|
|
933
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
934
|
+
sys.exit(1)
|
|
935
|
+
detected_agent, session_file, _, _ = result
|
|
936
|
+
if agent:
|
|
937
|
+
detected_agent = agent
|
|
938
|
+
else:
|
|
939
|
+
# No session provided - find latest
|
|
940
|
+
_find_and_run_session_ui(
|
|
941
|
+
session_id=None,
|
|
942
|
+
agent_constraint='both',
|
|
943
|
+
start_screen='action',
|
|
944
|
+
direct_action='path', # Just show path for now
|
|
945
|
+
)
|
|
946
|
+
return
|
|
947
|
+
|
|
948
|
+
# Gather session info
|
|
949
|
+
session_id = session_file.stem
|
|
950
|
+
mod_time = datetime.fromtimestamp(session_file.stat().st_mtime)
|
|
951
|
+
create_time = datetime.fromtimestamp(session_file.stat().st_ctime)
|
|
952
|
+
file_size = session_file.stat().st_size
|
|
953
|
+
line_count = sum(1 for _ in open(session_file))
|
|
954
|
+
|
|
955
|
+
# Extract metadata from session
|
|
956
|
+
from claude_code_tools.export_session import extract_session_metadata
|
|
957
|
+
metadata = extract_session_metadata(session_file, detected_agent)
|
|
958
|
+
cwd = metadata.get("cwd") or extract_cwd_from_session(session_file)
|
|
959
|
+
project = Path(cwd).name if cwd else "unknown"
|
|
960
|
+
custom_title = metadata.get("customTitle", "")
|
|
961
|
+
user_msg_count = count_user_messages(session_file, detected_agent)
|
|
962
|
+
|
|
963
|
+
# Get lineage
|
|
964
|
+
lineage = get_continuation_lineage(session_file, export_missing=False)
|
|
965
|
+
lineage_info = []
|
|
966
|
+
for node in lineage:
|
|
967
|
+
lineage_info.append({
|
|
968
|
+
"file": str(node.session_file),
|
|
969
|
+
"type": node.derivation_type or "original",
|
|
970
|
+
})
|
|
971
|
+
|
|
972
|
+
info_data = {
|
|
973
|
+
"session_id": session_id,
|
|
974
|
+
"agent": detected_agent,
|
|
975
|
+
"custom_title": custom_title,
|
|
976
|
+
"file_path": str(session_file),
|
|
977
|
+
"project": project,
|
|
978
|
+
"cwd": cwd,
|
|
979
|
+
"created": create_time.isoformat(),
|
|
980
|
+
"modified": mod_time.isoformat(),
|
|
981
|
+
"file_size_bytes": file_size,
|
|
982
|
+
"line_count": line_count,
|
|
983
|
+
"user_message_count": user_msg_count,
|
|
984
|
+
"export_path": str(default_export_path(session_file, detected_agent)),
|
|
985
|
+
"lineage": lineage_info,
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if json_output:
|
|
989
|
+
print(json_lib.dumps(info_data, indent=2))
|
|
990
|
+
else:
|
|
991
|
+
print(f"\n{'='*60}")
|
|
992
|
+
print(f"Session: {session_id}")
|
|
993
|
+
if custom_title:
|
|
994
|
+
print(f"Title: {custom_title}")
|
|
995
|
+
print(f"{'='*60}")
|
|
996
|
+
print(f"Agent: {detected_agent}")
|
|
997
|
+
print(f"Project: {project}")
|
|
998
|
+
print(f"CWD: {cwd}")
|
|
999
|
+
print(f"File: {session_file}")
|
|
1000
|
+
print(f"Created: {create_time.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
1001
|
+
print(f"Modified: {mod_time.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
1002
|
+
print(f"Size: {file_size:,} bytes")
|
|
1003
|
+
print(f"Lines: {line_count:,}")
|
|
1004
|
+
print(f"User msgs: {user_msg_count}")
|
|
1005
|
+
if lineage_info:
|
|
1006
|
+
print(f"\nLineage ({len(lineage_info)} sessions):")
|
|
1007
|
+
for i, node in enumerate(lineage_info):
|
|
1008
|
+
prefix = " └─" if i == len(lineage_info) - 1 else " ├─"
|
|
1009
|
+
fname = Path(node["file"]).name
|
|
1010
|
+
print(f"{prefix} {fname} ({node['type']})")
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
@main.command("copy")
|
|
1014
|
+
@click.argument("session", required=False)
|
|
1015
|
+
@click.option("--dest", "-d", help="Destination path (default: prompted)")
|
|
1016
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
1017
|
+
help="Force agent type (auto-detected if not specified)")
|
|
1018
|
+
def copy_session(session, dest, agent):
|
|
1019
|
+
"""Copy a session file to a new location.
|
|
1020
|
+
|
|
1021
|
+
If no session ID provided, finds latest session for current project/branch.
|
|
1022
|
+
|
|
1023
|
+
\b
|
|
1024
|
+
Examples:
|
|
1025
|
+
aichat copy abc123-def456 # Copy with prompted destination
|
|
1026
|
+
aichat copy abc123 -d ~/backups/ # Copy to specific directory
|
|
1027
|
+
aichat copy abc123 -d ./my-session.jsonl # Copy with specific filename
|
|
1028
|
+
"""
|
|
1029
|
+
import sys
|
|
1030
|
+
from pathlib import Path
|
|
1031
|
+
|
|
1032
|
+
from claude_code_tools.session_utils import find_session_file, detect_agent_from_path
|
|
1033
|
+
|
|
1034
|
+
if not session:
|
|
1035
|
+
_find_and_run_session_ui(
|
|
1036
|
+
session_id=None,
|
|
1037
|
+
agent_constraint='both',
|
|
1038
|
+
start_screen='action',
|
|
1039
|
+
direct_action='copy',
|
|
1040
|
+
)
|
|
1041
|
+
return
|
|
1042
|
+
|
|
1043
|
+
# Find session file
|
|
1044
|
+
input_path = Path(session).expanduser()
|
|
1045
|
+
if input_path.exists() and input_path.is_file():
|
|
1046
|
+
session_file = input_path
|
|
1047
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
1048
|
+
else:
|
|
1049
|
+
result = find_session_file(session)
|
|
1050
|
+
if not result:
|
|
1051
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
1052
|
+
sys.exit(1)
|
|
1053
|
+
detected_agent, session_file, _, _ = result
|
|
1054
|
+
if agent:
|
|
1055
|
+
detected_agent = agent
|
|
1056
|
+
|
|
1057
|
+
# Import agent-specific copy function
|
|
1058
|
+
if detected_agent == "claude":
|
|
1059
|
+
from claude_code_tools.find_claude_session import copy_session_file
|
|
1060
|
+
else:
|
|
1061
|
+
from claude_code_tools.find_codex_session import copy_session_file
|
|
1062
|
+
|
|
1063
|
+
copy_session_file(str(session_file), dest)
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
@main.command("query")
|
|
1067
|
+
@click.argument("session", required=False)
|
|
1068
|
+
@click.argument("question", required=False)
|
|
1069
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
1070
|
+
help="Force agent type (auto-detected if not specified)")
|
|
1071
|
+
def query_session(session, question, agent):
|
|
1072
|
+
"""Query a session with a question using an AI agent.
|
|
1073
|
+
|
|
1074
|
+
Exports the session and uses Claude to answer questions about its content.
|
|
1075
|
+
If no question provided, opens interactive query mode.
|
|
1076
|
+
|
|
1077
|
+
\b
|
|
1078
|
+
Examples:
|
|
1079
|
+
aichat query abc123 "What was the main bug fixed?"
|
|
1080
|
+
aichat query abc123 "Summarize the changes made"
|
|
1081
|
+
aichat query # Interactive mode for latest session
|
|
1082
|
+
"""
|
|
1083
|
+
import sys
|
|
1084
|
+
from pathlib import Path
|
|
1085
|
+
|
|
1086
|
+
from claude_code_tools.session_utils import find_session_file, detect_agent_from_path
|
|
1087
|
+
|
|
1088
|
+
if not session:
|
|
1089
|
+
_find_and_run_session_ui(
|
|
1090
|
+
session_id=None,
|
|
1091
|
+
agent_constraint='both',
|
|
1092
|
+
start_screen='query',
|
|
1093
|
+
direct_action='query',
|
|
1094
|
+
)
|
|
1095
|
+
return
|
|
1096
|
+
|
|
1097
|
+
# Find session file
|
|
1098
|
+
input_path = Path(session).expanduser()
|
|
1099
|
+
if input_path.exists() and input_path.is_file():
|
|
1100
|
+
session_file = input_path
|
|
1101
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
1102
|
+
else:
|
|
1103
|
+
result = find_session_file(session)
|
|
1104
|
+
if not result:
|
|
1105
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
1106
|
+
sys.exit(1)
|
|
1107
|
+
detected_agent, session_file, cwd, _ = result
|
|
1108
|
+
if agent:
|
|
1109
|
+
detected_agent = agent
|
|
1110
|
+
|
|
1111
|
+
# If no question, show interactive query UI
|
|
1112
|
+
if not question:
|
|
1113
|
+
from claude_code_tools.node_menu_ui import run_node_menu_ui
|
|
1114
|
+
from claude_code_tools.session_menu_cli import execute_action
|
|
1115
|
+
|
|
1116
|
+
rpc_path = str(Path(__file__).parent / "action_rpc.py")
|
|
1117
|
+
session_data = {
|
|
1118
|
+
"session_id": session_file.stem,
|
|
1119
|
+
"agent": detected_agent,
|
|
1120
|
+
"file_path": str(session_file),
|
|
1121
|
+
"cwd": str(session_file.parent),
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
def handler(sess, action, kwargs=None):
|
|
1125
|
+
return execute_action(
|
|
1126
|
+
action, sess["agent"], Path(sess["file_path"]),
|
|
1127
|
+
sess["cwd"], action_kwargs=kwargs
|
|
1128
|
+
)
|
|
1129
|
+
|
|
1130
|
+
run_node_menu_ui(
|
|
1131
|
+
[session_data], [], handler,
|
|
1132
|
+
start_screen="query",
|
|
1133
|
+
rpc_path=rpc_path,
|
|
1134
|
+
)
|
|
1135
|
+
return
|
|
1136
|
+
|
|
1137
|
+
# Direct query with provided question
|
|
1138
|
+
from claude_code_tools.session_utils import default_export_path
|
|
1139
|
+
|
|
1140
|
+
# Export session first
|
|
1141
|
+
if detected_agent == "claude":
|
|
1142
|
+
from claude_code_tools.find_claude_session import handle_export_session
|
|
1143
|
+
else:
|
|
1144
|
+
from claude_code_tools.find_codex_session import handle_export_session
|
|
1145
|
+
|
|
1146
|
+
export_path = default_export_path(session_file, detected_agent)
|
|
1147
|
+
handle_export_session(str(session_file))
|
|
1148
|
+
|
|
1149
|
+
# Query using Claude
|
|
1150
|
+
import subprocess
|
|
1151
|
+
prompt = f"Read the session transcript at {export_path} and answer: {question}"
|
|
1152
|
+
subprocess.run(["claude", "-p", prompt])
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
@main.command("clone")
|
|
1156
|
+
@click.argument("session", required=False)
|
|
1157
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
1158
|
+
help="Force agent type (auto-detected if not specified)")
|
|
1159
|
+
def clone_session_cmd(session, agent):
|
|
1160
|
+
"""Clone a session and resume the clone.
|
|
1161
|
+
|
|
1162
|
+
Creates a copy of the session with a new ID and resumes it,
|
|
1163
|
+
leaving the original session untouched.
|
|
1164
|
+
|
|
1165
|
+
If no session ID provided, finds latest session for current project/branch.
|
|
1166
|
+
|
|
1167
|
+
\b
|
|
1168
|
+
Examples:
|
|
1169
|
+
aichat clone abc123-def456 # Clone specific session
|
|
1170
|
+
aichat clone # Clone latest session
|
|
1171
|
+
"""
|
|
1172
|
+
import sys
|
|
1173
|
+
from pathlib import Path
|
|
1174
|
+
|
|
1175
|
+
from claude_code_tools.session_utils import find_session_file, detect_agent_from_path
|
|
1176
|
+
|
|
1177
|
+
if not session:
|
|
1178
|
+
_find_and_run_session_ui(
|
|
1179
|
+
session_id=None,
|
|
1180
|
+
agent_constraint='both',
|
|
1181
|
+
start_screen='resume',
|
|
1182
|
+
direct_action='clone',
|
|
1183
|
+
)
|
|
1184
|
+
return
|
|
1185
|
+
|
|
1186
|
+
# Find session file
|
|
1187
|
+
input_path = Path(session).expanduser()
|
|
1188
|
+
if input_path.exists() and input_path.is_file():
|
|
1189
|
+
session_file = input_path
|
|
1190
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
1191
|
+
cwd = str(session_file.parent)
|
|
1192
|
+
else:
|
|
1193
|
+
result = find_session_file(session)
|
|
1194
|
+
if not result:
|
|
1195
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
1196
|
+
sys.exit(1)
|
|
1197
|
+
detected_agent, session_file, cwd, _ = result
|
|
1198
|
+
if agent:
|
|
1199
|
+
detected_agent = agent
|
|
1200
|
+
|
|
1201
|
+
session_id = session_file.stem
|
|
1202
|
+
|
|
1203
|
+
# Execute clone
|
|
1204
|
+
if detected_agent == "claude":
|
|
1205
|
+
from claude_code_tools.find_claude_session import clone_session
|
|
1206
|
+
clone_session(session_id, cwd, shell_mode=False)
|
|
1207
|
+
else:
|
|
1208
|
+
from claude_code_tools.find_codex_session import clone_session
|
|
1209
|
+
clone_session(str(session_file), session_id, cwd, shell_mode=False)
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
@main.command("rollover")
|
|
1213
|
+
@click.argument("session", required=False)
|
|
1214
|
+
@click.option("--quick", is_flag=True,
|
|
1215
|
+
help="Quick rollover without context extraction (just preserve lineage)")
|
|
1216
|
+
@click.option("--prompt", "-p", help="Custom prompt for context extraction")
|
|
1217
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
1218
|
+
help="Force agent type (auto-detected if not specified)")
|
|
1219
|
+
def rollover(session, quick, prompt, agent):
|
|
1220
|
+
"""Rollover: hand off work to a fresh session with preserved lineage.
|
|
1221
|
+
|
|
1222
|
+
Creates a new session with a summary of the current work and links back
|
|
1223
|
+
to the parent session. The new session starts with full context available
|
|
1224
|
+
while the parent session is preserved intact.
|
|
1225
|
+
|
|
1226
|
+
\b
|
|
1227
|
+
Options:
|
|
1228
|
+
--quick Skip context extraction, just preserve lineage pointers
|
|
1229
|
+
--prompt Custom instructions for what context to extract
|
|
1230
|
+
|
|
1231
|
+
\b
|
|
1232
|
+
Examples:
|
|
1233
|
+
aichat rollover abc123 # Rollover with context extraction
|
|
1234
|
+
aichat rollover abc123 --quick # Quick rollover (lineage only)
|
|
1235
|
+
aichat rollover abc123 -p "Focus on the auth changes"
|
|
1236
|
+
aichat rollover # Rollover latest session
|
|
1237
|
+
"""
|
|
1238
|
+
import sys
|
|
1239
|
+
from pathlib import Path
|
|
1240
|
+
|
|
1241
|
+
from claude_code_tools.session_utils import (
|
|
1242
|
+
find_session_file,
|
|
1243
|
+
detect_agent_from_path,
|
|
1244
|
+
continue_with_options,
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
# If CLI options provided, use direct handler (backward compatible)
|
|
1248
|
+
if quick or prompt or agent:
|
|
1249
|
+
if not session:
|
|
1250
|
+
print("Error: --quick, --prompt, or --agent require a session ID",
|
|
1251
|
+
file=sys.stderr)
|
|
1252
|
+
print("Use 'aichat rollover' without options for interactive mode",
|
|
1253
|
+
file=sys.stderr)
|
|
1254
|
+
sys.exit(1)
|
|
1255
|
+
|
|
1256
|
+
# Find session file
|
|
1257
|
+
input_path = Path(session).expanduser()
|
|
1258
|
+
if input_path.exists() and input_path.is_file():
|
|
1259
|
+
session_file = input_path
|
|
1260
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
1261
|
+
else:
|
|
1262
|
+
result = find_session_file(session)
|
|
1263
|
+
if not result:
|
|
1264
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
1265
|
+
sys.exit(1)
|
|
1266
|
+
detected_agent, session_file, _, _ = result
|
|
1267
|
+
if agent:
|
|
1268
|
+
detected_agent = agent
|
|
1269
|
+
|
|
1270
|
+
# Execute rollover directly
|
|
1271
|
+
rollover_type = "quick" if quick else "context"
|
|
1272
|
+
continue_with_options(
|
|
1273
|
+
str(session_file),
|
|
1274
|
+
detected_agent,
|
|
1275
|
+
preset_prompt=prompt,
|
|
1276
|
+
rollover_type=rollover_type,
|
|
1277
|
+
)
|
|
1278
|
+
return
|
|
1279
|
+
|
|
1280
|
+
# Show interactive Node UI for rollover options
|
|
1281
|
+
# (whether session provided or not - find latest if not)
|
|
1282
|
+
# Start at lineage screen, with direct_action for proper escape behavior
|
|
1283
|
+
_find_and_run_session_ui(
|
|
1284
|
+
session_id=session,
|
|
1285
|
+
agent_constraint='both',
|
|
1286
|
+
start_screen='lineage',
|
|
1287
|
+
select_target='lineage',
|
|
1288
|
+
results_title=' Which session to rollover? ',
|
|
1289
|
+
direct_action='continue',
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
|
|
1293
|
+
@main.command("lineage")
|
|
1294
|
+
@click.argument("session", required=False)
|
|
1295
|
+
@click.option("--agent", type=click.Choice(["claude", "codex"], case_sensitive=False),
|
|
1296
|
+
help="Force agent type (auto-detected if not specified)")
|
|
1297
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
1298
|
+
def lineage(session, agent, json_output):
|
|
1299
|
+
"""Show the parent lineage chain of a session.
|
|
1300
|
+
|
|
1301
|
+
Traces back through continue_metadata and trim_metadata to find
|
|
1302
|
+
all ancestor sessions, from the current session back to the original.
|
|
1303
|
+
|
|
1304
|
+
\b
|
|
1305
|
+
Examples:
|
|
1306
|
+
aichat lineage abc123-def456 # Show lineage for specific session
|
|
1307
|
+
aichat lineage # Show lineage for latest session
|
|
1308
|
+
aichat lineage abc123 --json # Output as JSON
|
|
1309
|
+
"""
|
|
1310
|
+
import json as json_lib
|
|
1311
|
+
import sys
|
|
1312
|
+
from pathlib import Path
|
|
1313
|
+
from datetime import datetime
|
|
1314
|
+
|
|
1315
|
+
from claude_code_tools.session_utils import find_session_file, detect_agent_from_path
|
|
1316
|
+
from claude_code_tools.session_lineage import get_full_lineage_chain
|
|
1317
|
+
|
|
1318
|
+
if not session:
|
|
1319
|
+
_find_and_run_session_ui(
|
|
1320
|
+
session_id=None,
|
|
1321
|
+
agent_constraint='both',
|
|
1322
|
+
start_screen='lineage',
|
|
1323
|
+
)
|
|
1324
|
+
return
|
|
1325
|
+
|
|
1326
|
+
# Find session file
|
|
1327
|
+
input_path = Path(session).expanduser()
|
|
1328
|
+
if input_path.exists() and input_path.is_file():
|
|
1329
|
+
session_file = input_path
|
|
1330
|
+
detected_agent = agent or detect_agent_from_path(session_file)
|
|
1331
|
+
else:
|
|
1332
|
+
result = find_session_file(session)
|
|
1333
|
+
if not result:
|
|
1334
|
+
print(f"Error: Session not found: {session}", file=sys.stderr)
|
|
1335
|
+
sys.exit(1)
|
|
1336
|
+
detected_agent, session_file, _, _ = result
|
|
1337
|
+
if agent:
|
|
1338
|
+
detected_agent = agent
|
|
1339
|
+
|
|
1340
|
+
# Get lineage (returns newest-first, ending with original)
|
|
1341
|
+
lineage_chain = get_full_lineage_chain(session_file)
|
|
1342
|
+
|
|
1343
|
+
# Check if this is an original session (only one item with type "original")
|
|
1344
|
+
if len(lineage_chain) == 1 and lineage_chain[0][1] == "original":
|
|
1345
|
+
print("No lineage found (this is an original session).")
|
|
1346
|
+
return
|
|
1347
|
+
|
|
1348
|
+
lineage_data = []
|
|
1349
|
+
for path, derivation_type in lineage_chain:
|
|
1350
|
+
mod_time = datetime.fromtimestamp(path.stat().st_mtime)
|
|
1351
|
+
lineage_data.append({
|
|
1352
|
+
"session_id": path.stem,
|
|
1353
|
+
"file_path": str(path),
|
|
1354
|
+
"derivation_type": derivation_type,
|
|
1355
|
+
"modified": mod_time.isoformat(),
|
|
1356
|
+
})
|
|
1357
|
+
|
|
1358
|
+
if json_output:
|
|
1359
|
+
print(json_lib.dumps(lineage_data, indent=2))
|
|
1360
|
+
else:
|
|
1361
|
+
print(f"\nLineage for: {session_file.stem}")
|
|
1362
|
+
print(f"{'='*60}")
|
|
1363
|
+
print(f"Chain has {len(lineage_data)} session(s):\n")
|
|
1364
|
+
|
|
1365
|
+
for i, node in enumerate(lineage_data):
|
|
1366
|
+
# Current session or ancestor
|
|
1367
|
+
if i == 0:
|
|
1368
|
+
marker = "► "
|
|
1369
|
+
else:
|
|
1370
|
+
marker = " "
|
|
1371
|
+
|
|
1372
|
+
dtype = node["derivation_type"]
|
|
1373
|
+
fname = Path(node["file_path"]).name
|
|
1374
|
+
mod = node["modified"][:10]
|
|
1375
|
+
|
|
1376
|
+
if i == len(lineage_data) - 1:
|
|
1377
|
+
prefix = f"{marker}└─"
|
|
1378
|
+
else:
|
|
1379
|
+
prefix = f"{marker}├─"
|
|
1380
|
+
|
|
1381
|
+
print(f"{prefix} [{dtype:10}] {fname} ({mod})")
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
@main.command("resume", context_settings={"ignore_unknown_options": True, "allow_extra_args": True, "allow_interspersed_args": False})
|
|
1385
|
+
@click.option(
|
|
1386
|
+
'--claude-home',
|
|
1387
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
1388
|
+
help='Claude home directory (default: ~/.claude or CLAUDE_CONFIG_DIR)',
|
|
1389
|
+
)
|
|
1390
|
+
@click.option(
|
|
1391
|
+
'--codex-home',
|
|
1392
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
1393
|
+
help='Codex home directory (default: ~/.codex or CODEX_HOME)',
|
|
1394
|
+
)
|
|
1395
|
+
@click.pass_context
|
|
1396
|
+
def resume_session(ctx, claude_home, codex_home):
|
|
1397
|
+
"""Resume a session with various options (resume, clone, trim, continue).
|
|
1398
|
+
|
|
1399
|
+
If no session ID provided, finds latest session for current project/branch.
|
|
1400
|
+
Shows resume menu with options: resume as-is, clone, trim+resume,
|
|
1401
|
+
smart-trim, or continue with context.
|
|
1402
|
+
|
|
1403
|
+
\b
|
|
1404
|
+
Environment variables:
|
|
1405
|
+
CLAUDE_CONFIG_DIR - Default Claude home (overridden by --claude-home)
|
|
1406
|
+
CODEX_HOME - Default Codex home (overridden by --codex-home)
|
|
1407
|
+
"""
|
|
1408
|
+
# Merge with parent context options (CLI arg takes precedence)
|
|
1409
|
+
claude_home = claude_home or (ctx.obj or {}).get('claude_home')
|
|
1410
|
+
codex_home = codex_home or (ctx.obj or {}).get('codex_home')
|
|
1411
|
+
|
|
1412
|
+
args = ctx.args
|
|
1413
|
+
session_id = args[0] if args and not args[0].startswith('-') else None
|
|
1414
|
+
_find_and_run_session_ui(
|
|
1415
|
+
session_id=session_id,
|
|
1416
|
+
agent_constraint='both',
|
|
1417
|
+
start_screen='resume',
|
|
1418
|
+
select_target='resume',
|
|
1419
|
+
results_title=' Which session to resume? ',
|
|
1420
|
+
)
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
# =============================================================================
|
|
1424
|
+
# Search Infrastructure Commands
|
|
1425
|
+
# =============================================================================
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
@main.command("clear-index")
|
|
1429
|
+
@click.option(
|
|
1430
|
+
"--index", "-i",
|
|
1431
|
+
type=click.Path(),
|
|
1432
|
+
default="~/.cctools/search-index",
|
|
1433
|
+
help="Index directory (default: ~/.cctools/search-index/)",
|
|
1434
|
+
)
|
|
1435
|
+
@click.option("--dry-run", "-n", is_flag=True, help="Show what would be deleted")
|
|
1436
|
+
def clear_index(index, dry_run):
|
|
1437
|
+
"""Clear the Tantivy search index.
|
|
1438
|
+
|
|
1439
|
+
Deletes the entire index directory to allow a fresh rebuild.
|
|
1440
|
+
"""
|
|
1441
|
+
import shutil
|
|
1442
|
+
from pathlib import Path
|
|
1443
|
+
|
|
1444
|
+
index_path = Path(index).expanduser()
|
|
1445
|
+
|
|
1446
|
+
if not index_path.exists():
|
|
1447
|
+
print(f"Index directory does not exist: {index_path}")
|
|
1448
|
+
return
|
|
1449
|
+
|
|
1450
|
+
# Count files for info
|
|
1451
|
+
file_count = sum(1 for _ in index_path.rglob("*") if _.is_file())
|
|
1452
|
+
|
|
1453
|
+
if dry_run:
|
|
1454
|
+
print(f"Dry run: would delete index at {index_path}")
|
|
1455
|
+
print(f" {file_count} files would be removed")
|
|
1456
|
+
else:
|
|
1457
|
+
shutil.rmtree(index_path)
|
|
1458
|
+
print(f"✅ Cleared index at {index_path}")
|
|
1459
|
+
print(f" {file_count} files removed")
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
@main.command("clear-exports", hidden=True)
|
|
1463
|
+
@click.option("--verbose", "-v", is_flag=True, help="Show what's being deleted")
|
|
1464
|
+
@click.option("--dry-run", "-n", is_flag=True, help="Show what would be deleted")
|
|
1465
|
+
def clear_exports(verbose, dry_run):
|
|
1466
|
+
"""Clear all exported session files from project directories.
|
|
1467
|
+
|
|
1468
|
+
Finds export files in per-project directories:
|
|
1469
|
+
{project}/exported-sessions/{agent}/*.txt
|
|
1470
|
+
|
|
1471
|
+
Use this before re-exporting to ensure a clean slate.
|
|
1472
|
+
"""
|
|
1473
|
+
from claude_code_tools.export_all import (
|
|
1474
|
+
collect_sessions_to_export,
|
|
1475
|
+
extract_export_dir_from_session,
|
|
1476
|
+
)
|
|
1477
|
+
|
|
1478
|
+
print("Scanning for export files to delete...")
|
|
1479
|
+
sessions = collect_sessions_to_export()
|
|
1480
|
+
print(f"Found {len(sessions)} sessions to check")
|
|
1481
|
+
|
|
1482
|
+
deleted_count = 0
|
|
1483
|
+
dirs_cleaned = set()
|
|
1484
|
+
|
|
1485
|
+
with click.progressbar(
|
|
1486
|
+
sessions,
|
|
1487
|
+
label="Scanning",
|
|
1488
|
+
show_pos=True,
|
|
1489
|
+
item_show_func=lambda x: x[0].name if x else "",
|
|
1490
|
+
) as bar:
|
|
1491
|
+
for session_file, agent in bar:
|
|
1492
|
+
export_dir = extract_export_dir_from_session(session_file, agent=agent)
|
|
1493
|
+
if export_dir and export_dir.exists():
|
|
1494
|
+
export_file = export_dir / f"{session_file.stem}.txt"
|
|
1495
|
+
if export_file.exists():
|
|
1496
|
+
if dry_run:
|
|
1497
|
+
if verbose:
|
|
1498
|
+
print(f"\nWould delete: {export_file}")
|
|
1499
|
+
else:
|
|
1500
|
+
if verbose:
|
|
1501
|
+
print(f"\nDeleting: {export_file}")
|
|
1502
|
+
export_file.unlink()
|
|
1503
|
+
deleted_count += 1
|
|
1504
|
+
dirs_cleaned.add(export_dir)
|
|
1505
|
+
|
|
1506
|
+
if dry_run:
|
|
1507
|
+
print(f"\nDry run: would delete {deleted_count} files "
|
|
1508
|
+
f"from {len(dirs_cleaned)} directories")
|
|
1509
|
+
else:
|
|
1510
|
+
print(f"\n✅ Cleared {deleted_count} export files "
|
|
1511
|
+
f"from {len(dirs_cleaned)} directories")
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
@main.command("export-all", hidden=True)
|
|
1515
|
+
@click.option("--force", "-f", is_flag=True, help="Re-export all (ignore mtime)")
|
|
1516
|
+
@click.option("--verbose", "-v", is_flag=True, help="Show detailed progress and failures")
|
|
1517
|
+
def export_all(force, verbose):
|
|
1518
|
+
"""Export all sessions with YAML front matter for indexing.
|
|
1519
|
+
|
|
1520
|
+
Each session is exported to its own project directory:
|
|
1521
|
+
{project}/exported-sessions/{agent}/{session_id}.txt
|
|
1522
|
+
|
|
1523
|
+
Skips sessions that haven't changed since last export (unless --force).
|
|
1524
|
+
"""
|
|
1525
|
+
from claude_code_tools.export_all import (
|
|
1526
|
+
collect_sessions_to_export,
|
|
1527
|
+
export_single_session,
|
|
1528
|
+
)
|
|
1529
|
+
|
|
1530
|
+
print("Collecting sessions...")
|
|
1531
|
+
sessions = collect_sessions_to_export()
|
|
1532
|
+
print(f"Found {len(sessions)} sessions to process")
|
|
1533
|
+
|
|
1534
|
+
stats: dict = {
|
|
1535
|
+
"exported": 0,
|
|
1536
|
+
"skipped": 0,
|
|
1537
|
+
"failed": 0,
|
|
1538
|
+
"exported_files": [],
|
|
1539
|
+
"failures": [],
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
with click.progressbar(
|
|
1543
|
+
sessions,
|
|
1544
|
+
label="Exporting",
|
|
1545
|
+
show_pos=True,
|
|
1546
|
+
item_show_func=lambda x: x[0].name if x else "",
|
|
1547
|
+
) as bar:
|
|
1548
|
+
for session_file, agent in bar:
|
|
1549
|
+
result = export_single_session(session_file, agent, force)
|
|
1550
|
+
|
|
1551
|
+
if result["status"] == "exported":
|
|
1552
|
+
stats["exported"] += 1
|
|
1553
|
+
stats["exported_files"].append(result["export_file"])
|
|
1554
|
+
elif result["status"] == "skipped":
|
|
1555
|
+
stats["skipped"] += 1
|
|
1556
|
+
if result["export_file"]:
|
|
1557
|
+
stats["exported_files"].append(result["export_file"])
|
|
1558
|
+
else: # failed
|
|
1559
|
+
stats["failed"] += 1
|
|
1560
|
+
stats["failures"].append({
|
|
1561
|
+
"session": str(session_file),
|
|
1562
|
+
"agent": agent,
|
|
1563
|
+
"error": result["error"],
|
|
1564
|
+
})
|
|
1565
|
+
|
|
1566
|
+
print(f"\n✅ Export complete:")
|
|
1567
|
+
print(f" Exported: {stats['exported']}")
|
|
1568
|
+
print(f" Skipped: {stats['skipped']} (up-to-date)")
|
|
1569
|
+
print(f" Failed: {stats['failed']}")
|
|
1570
|
+
print(f" Total export files: {len(stats['exported_files'])}")
|
|
1571
|
+
|
|
1572
|
+
if stats["failures"] and verbose:
|
|
1573
|
+
print(f"\n⚠️ Failures ({len(stats['failures'])}):")
|
|
1574
|
+
for failure in stats["failures"]:
|
|
1575
|
+
print(f" {failure['session']}")
|
|
1576
|
+
print(f" Error: {failure['error']}")
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
@main.command("build-index")
|
|
1580
|
+
@click.option(
|
|
1581
|
+
"--claude-home",
|
|
1582
|
+
type=click.Path(),
|
|
1583
|
+
default=None,
|
|
1584
|
+
help="Claude home directory (default: ~/.claude or CLAUDE_CONFIG_DIR)",
|
|
1585
|
+
)
|
|
1586
|
+
@click.option(
|
|
1587
|
+
"--codex-home",
|
|
1588
|
+
type=click.Path(),
|
|
1589
|
+
default=None,
|
|
1590
|
+
help="Codex home directory (default: ~/.codex or CODEX_HOME)",
|
|
1591
|
+
)
|
|
1592
|
+
def build_index(claude_home, codex_home):
|
|
1593
|
+
"""Build/update the Tantivy search index from JSONL session files.
|
|
1594
|
+
|
|
1595
|
+
Indexes sessions directly from JSONL files (no export step needed).
|
|
1596
|
+
Incremental by default - only indexes new/modified sessions.
|
|
1597
|
+
|
|
1598
|
+
Use 'aichat clear-index' first if you want a full rebuild.
|
|
1599
|
+
"""
|
|
1600
|
+
from claude_code_tools.search_index import auto_index
|
|
1601
|
+
from claude_code_tools.session_utils import get_claude_home, get_codex_home
|
|
1602
|
+
|
|
1603
|
+
claude_home_path = get_claude_home(cli_arg=claude_home)
|
|
1604
|
+
codex_home_path = get_codex_home(cli_arg=codex_home)
|
|
1605
|
+
|
|
1606
|
+
print("Building search index...")
|
|
1607
|
+
stats = auto_index(
|
|
1608
|
+
claude_home=claude_home_path,
|
|
1609
|
+
codex_home=codex_home_path,
|
|
1610
|
+
verbose=True,
|
|
1611
|
+
silent=False, # Show tqdm progress bar
|
|
1612
|
+
)
|
|
1613
|
+
|
|
1614
|
+
print(f"\n✅ Index build complete:")
|
|
1615
|
+
print(f" Indexed: {stats['indexed']}")
|
|
1616
|
+
print(f" Skipped: {stats['skipped']} (unchanged)")
|
|
1617
|
+
failed = stats['failed']
|
|
1618
|
+
if failed > 0:
|
|
1619
|
+
empty = stats.get('empty', 0)
|
|
1620
|
+
parse_err = stats.get('parse_error', 0)
|
|
1621
|
+
index_err = stats.get('index_error', 0)
|
|
1622
|
+
print(f" Failed: {failed} (empty: {empty}, parse: {parse_err}, "
|
|
1623
|
+
f"index: {index_err})")
|
|
1624
|
+
else:
|
|
1625
|
+
print(f" Failed: 0")
|
|
1626
|
+
print(f" Total: {stats['total_files']} "
|
|
1627
|
+
f"(Claude: {stats.get('claude_files', '?')}, "
|
|
1628
|
+
f"Codex: {stats.get('codex_files', '?')})")
|
|
1629
|
+
|
|
1630
|
+
|
|
1631
|
+
def _scan_session_files(
|
|
1632
|
+
claude_home: "Path",
|
|
1633
|
+
codex_home: "Path",
|
|
1634
|
+
) -> dict:
|
|
1635
|
+
"""
|
|
1636
|
+
Scan filesystem for all JSONL session files and read their metadata.
|
|
1637
|
+
|
|
1638
|
+
Returns dict with:
|
|
1639
|
+
- files: dict mapping file_path (str) -> {path, is_subagent, agent, ...}
|
|
1640
|
+
- counts: {claude_resumable, claude_subagent, codex_resumable, codex_subagent}
|
|
1641
|
+
- errors: list of files that couldn't be parsed
|
|
1642
|
+
"""
|
|
1643
|
+
import json
|
|
1644
|
+
from claude_code_tools.session_utils import is_valid_session
|
|
1645
|
+
|
|
1646
|
+
files = {}
|
|
1647
|
+
counts = {
|
|
1648
|
+
"claude_resumable": 0,
|
|
1649
|
+
"claude_subagent": 0,
|
|
1650
|
+
"codex_resumable": 0,
|
|
1651
|
+
"codex_subagent": 0,
|
|
1652
|
+
"claude_invalid": 0,
|
|
1653
|
+
"codex_invalid": 0,
|
|
1654
|
+
}
|
|
1655
|
+
errors = []
|
|
1656
|
+
|
|
1657
|
+
# Scan Claude sessions
|
|
1658
|
+
claude_projects = claude_home / "projects"
|
|
1659
|
+
if claude_projects.exists():
|
|
1660
|
+
for jsonl_path in claude_projects.glob("**/*.jsonl"):
|
|
1661
|
+
is_subagent = jsonl_path.name.startswith("agent-")
|
|
1662
|
+
try:
|
|
1663
|
+
with open(jsonl_path) as f:
|
|
1664
|
+
first_line = f.readline().strip()
|
|
1665
|
+
if first_line:
|
|
1666
|
+
data = json.loads(first_line)
|
|
1667
|
+
|
|
1668
|
+
# Skip sessions run from inside claude_home or codex_home
|
|
1669
|
+
cwd = data.get("cwd", "")
|
|
1670
|
+
claude_home_str = str(claude_home)
|
|
1671
|
+
codex_home_str = str(codex_home)
|
|
1672
|
+
if cwd and (
|
|
1673
|
+
cwd.startswith(claude_home_str)
|
|
1674
|
+
or cwd.startswith(codex_home_str)
|
|
1675
|
+
):
|
|
1676
|
+
continue
|
|
1677
|
+
# Use file path as key (unique per file)
|
|
1678
|
+
file_key = str(jsonl_path)
|
|
1679
|
+
|
|
1680
|
+
# Check if actually resumable (has user/assistant messages)
|
|
1681
|
+
if is_subagent:
|
|
1682
|
+
is_resumable = True # Subagents are always valid
|
|
1683
|
+
else:
|
|
1684
|
+
is_resumable = is_valid_session(jsonl_path)
|
|
1685
|
+
|
|
1686
|
+
if not is_resumable:
|
|
1687
|
+
counts["claude_invalid"] += 1
|
|
1688
|
+
continue # Skip non-resumable files
|
|
1689
|
+
|
|
1690
|
+
files[file_key] = {
|
|
1691
|
+
"path": jsonl_path,
|
|
1692
|
+
"is_subagent": is_subagent,
|
|
1693
|
+
"agent": "claude",
|
|
1694
|
+
"session_id": data.get("sessionId", ""),
|
|
1695
|
+
}
|
|
1696
|
+
if is_subagent:
|
|
1697
|
+
counts["claude_subagent"] += 1
|
|
1698
|
+
else:
|
|
1699
|
+
counts["claude_resumable"] += 1
|
|
1700
|
+
except Exception as e:
|
|
1701
|
+
errors.append({"path": jsonl_path, "error": str(e)})
|
|
1702
|
+
|
|
1703
|
+
# Scan Codex sessions
|
|
1704
|
+
if codex_home.exists():
|
|
1705
|
+
for jsonl_path in codex_home.glob("**/*.jsonl"):
|
|
1706
|
+
is_subagent = jsonl_path.name.startswith("agent-")
|
|
1707
|
+
try:
|
|
1708
|
+
with open(jsonl_path) as f:
|
|
1709
|
+
first_line = f.readline().strip()
|
|
1710
|
+
if first_line:
|
|
1711
|
+
data = json.loads(first_line)
|
|
1712
|
+
|
|
1713
|
+
# Skip sessions run from inside claude_home or codex_home
|
|
1714
|
+
cwd = data.get("cwd", "")
|
|
1715
|
+
claude_home_str = str(claude_home)
|
|
1716
|
+
codex_home_str = str(codex_home)
|
|
1717
|
+
if cwd and (
|
|
1718
|
+
cwd.startswith(claude_home_str)
|
|
1719
|
+
or cwd.startswith(codex_home_str)
|
|
1720
|
+
):
|
|
1721
|
+
continue
|
|
1722
|
+
# Use file path as key (unique per file)
|
|
1723
|
+
file_key = str(jsonl_path)
|
|
1724
|
+
|
|
1725
|
+
# Check if actually resumable (has user/assistant messages)
|
|
1726
|
+
if is_subagent:
|
|
1727
|
+
is_resumable = True # Subagents are always valid
|
|
1728
|
+
else:
|
|
1729
|
+
is_resumable = is_valid_session(jsonl_path)
|
|
1730
|
+
|
|
1731
|
+
if not is_resumable:
|
|
1732
|
+
counts["codex_invalid"] += 1
|
|
1733
|
+
continue # Skip non-resumable files
|
|
1734
|
+
|
|
1735
|
+
files[file_key] = {
|
|
1736
|
+
"path": jsonl_path,
|
|
1737
|
+
"is_subagent": is_subagent,
|
|
1738
|
+
"agent": "codex",
|
|
1739
|
+
"session_id": data.get("sessionId", "") or data.get("id", ""),
|
|
1740
|
+
}
|
|
1741
|
+
if is_subagent:
|
|
1742
|
+
counts["codex_subagent"] += 1
|
|
1743
|
+
else:
|
|
1744
|
+
counts["codex_resumable"] += 1
|
|
1745
|
+
except Exception as e:
|
|
1746
|
+
errors.append({"path": jsonl_path, "error": str(e)})
|
|
1747
|
+
|
|
1748
|
+
return {"files": files, "counts": counts, "errors": errors}
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
@main.command("index-stats")
|
|
1752
|
+
@click.option(
|
|
1753
|
+
"--index", "-i",
|
|
1754
|
+
type=click.Path(),
|
|
1755
|
+
default="~/.cctools/search-index",
|
|
1756
|
+
help="Index directory",
|
|
1757
|
+
)
|
|
1758
|
+
@click.option("--cwd", "-c", help="Filter to specific cwd path")
|
|
1759
|
+
@click.option(
|
|
1760
|
+
"--claude-home",
|
|
1761
|
+
type=click.Path(),
|
|
1762
|
+
default=None,
|
|
1763
|
+
help="Claude home directory (default: ~/.claude or CLAUDE_CONFIG_DIR)",
|
|
1764
|
+
)
|
|
1765
|
+
@click.option(
|
|
1766
|
+
"--codex-home",
|
|
1767
|
+
type=click.Path(),
|
|
1768
|
+
default=None,
|
|
1769
|
+
help="Codex home directory (default: ~/.codex or CODEX_HOME)",
|
|
1770
|
+
)
|
|
1771
|
+
def index_stats(index, cwd, claude_home, codex_home):
|
|
1772
|
+
"""Show statistics about the Tantivy search index with reconciliation.
|
|
1773
|
+
|
|
1774
|
+
Compares index contents against actual session files on disk to identify
|
|
1775
|
+
missing or orphaned sessions.
|
|
1776
|
+
"""
|
|
1777
|
+
from collections import Counter
|
|
1778
|
+
from pathlib import Path
|
|
1779
|
+
|
|
1780
|
+
try:
|
|
1781
|
+
from claude_code_tools.search_index import SessionIndex
|
|
1782
|
+
except ImportError:
|
|
1783
|
+
print("Error: tantivy not installed")
|
|
1784
|
+
return
|
|
1785
|
+
|
|
1786
|
+
from claude_code_tools.session_utils import get_claude_home, get_codex_home
|
|
1787
|
+
|
|
1788
|
+
index_path = Path(index).expanduser()
|
|
1789
|
+
claude_home_path = get_claude_home(cli_arg=claude_home)
|
|
1790
|
+
codex_home_path = get_codex_home(cli_arg=codex_home)
|
|
1791
|
+
|
|
1792
|
+
if not index_path.exists():
|
|
1793
|
+
print(f"Index not found at {index_path}")
|
|
1794
|
+
return
|
|
1795
|
+
|
|
1796
|
+
# === Filesystem scan ===
|
|
1797
|
+
print("Scanning filesystem...")
|
|
1798
|
+
fs_data = _scan_session_files(claude_home_path, codex_home_path)
|
|
1799
|
+
fs_files = fs_data["files"]
|
|
1800
|
+
fs_counts = fs_data["counts"]
|
|
1801
|
+
fs_errors = fs_data["errors"]
|
|
1802
|
+
|
|
1803
|
+
print("\n=== Filesystem ===")
|
|
1804
|
+
print(f"Claude resumable: {fs_counts['claude_resumable']}")
|
|
1805
|
+
print(f"Claude subagent: {fs_counts['claude_subagent']}")
|
|
1806
|
+
print(f"Codex resumable: {fs_counts['codex_resumable']}")
|
|
1807
|
+
print(f"Codex subagent: {fs_counts['codex_subagent']}")
|
|
1808
|
+
total_valid = (
|
|
1809
|
+
fs_counts['claude_resumable'] + fs_counts['claude_subagent'] +
|
|
1810
|
+
fs_counts['codex_resumable'] + fs_counts['codex_subagent']
|
|
1811
|
+
)
|
|
1812
|
+
total_invalid = fs_counts['claude_invalid'] + fs_counts['codex_invalid']
|
|
1813
|
+
print(f"Total valid: {total_valid}")
|
|
1814
|
+
if total_invalid > 0:
|
|
1815
|
+
print(f"Skipped invalid: {total_invalid} (no resumable messages)")
|
|
1816
|
+
|
|
1817
|
+
if fs_errors:
|
|
1818
|
+
print(f"Parse errors: {len(fs_errors)}")
|
|
1819
|
+
|
|
1820
|
+
# === Index stats ===
|
|
1821
|
+
idx = SessionIndex(index_path)
|
|
1822
|
+
results = idx.get_recent(limit=100000)
|
|
1823
|
+
|
|
1824
|
+
print("\n=== Index ===")
|
|
1825
|
+
print(f"Total documents: {len(results)}")
|
|
1826
|
+
|
|
1827
|
+
# Build index lookup by export_path (unique key for each indexed file)
|
|
1828
|
+
# Filter to only entries matching the specified claude_home/codex_home
|
|
1829
|
+
indexed_by_path = {}
|
|
1830
|
+
claude_home_str = str(claude_home_path)
|
|
1831
|
+
codex_home_str = str(codex_home_path)
|
|
1832
|
+
|
|
1833
|
+
for r in results:
|
|
1834
|
+
fpath = r.get("export_path", "")
|
|
1835
|
+
stored_home = r.get("claude_home", "")
|
|
1836
|
+
# Only include if home matches (claude or codex)
|
|
1837
|
+
if fpath and (stored_home == claude_home_str or stored_home == codex_home_str):
|
|
1838
|
+
indexed_by_path[fpath] = {
|
|
1839
|
+
"agent": r.get("agent", ""),
|
|
1840
|
+
"session_id": r.get("session_id", ""),
|
|
1841
|
+
"is_subagent": "agent-" in fpath,
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
# Also count unique session IDs for display (filtered)
|
|
1845
|
+
unique_session_ids = set(
|
|
1846
|
+
r.get("session_id", "") for r in results
|
|
1847
|
+
if r.get("session_id") and r.get("claude_home") in (claude_home_str, codex_home_str)
|
|
1848
|
+
)
|
|
1849
|
+
print(f"Unique session IDs: {len(unique_session_ids)} (for specified homes)")
|
|
1850
|
+
print(f"Total file paths: {len(indexed_by_path)}")
|
|
1851
|
+
|
|
1852
|
+
# === Reconciliation ===
|
|
1853
|
+
print("\n=== Reconciliation (by file path) ===")
|
|
1854
|
+
|
|
1855
|
+
fs_paths = set(fs_files.keys())
|
|
1856
|
+
idx_paths = set(indexed_by_path.keys())
|
|
1857
|
+
|
|
1858
|
+
missing_from_index = fs_paths - idx_paths
|
|
1859
|
+
orphaned_in_index = idx_paths - fs_paths
|
|
1860
|
+
in_sync = fs_paths & idx_paths
|
|
1861
|
+
|
|
1862
|
+
print(f"Files on disk: {len(fs_paths)}")
|
|
1863
|
+
print(f"Files indexed: {len(idx_paths)}")
|
|
1864
|
+
print(f"In sync: {len(in_sync)}")
|
|
1865
|
+
|
|
1866
|
+
if not missing_from_index and not orphaned_in_index:
|
|
1867
|
+
print("✅ Index is fully in sync with filesystem")
|
|
1868
|
+
else:
|
|
1869
|
+
if missing_from_index:
|
|
1870
|
+
print(f"❌ Missing from index: {len(missing_from_index)}")
|
|
1871
|
+
# Count by type
|
|
1872
|
+
missing_subagent = sum(
|
|
1873
|
+
1 for p in missing_from_index if fs_files[p]["is_subagent"]
|
|
1874
|
+
)
|
|
1875
|
+
missing_resumable = len(missing_from_index) - missing_subagent
|
|
1876
|
+
print(f" ({missing_resumable} resumable, {missing_subagent} subagent)")
|
|
1877
|
+
# Show a few examples
|
|
1878
|
+
for fpath in list(missing_from_index)[:3]:
|
|
1879
|
+
info = fs_files[fpath]
|
|
1880
|
+
stype = "subagent" if info["is_subagent"] else "resumable"
|
|
1881
|
+
fname = info["path"].name
|
|
1882
|
+
print(f" - {fname} ({info['agent']}, {stype})")
|
|
1883
|
+
if len(missing_from_index) > 3:
|
|
1884
|
+
print(f" ... and {len(missing_from_index) - 3} more")
|
|
1885
|
+
|
|
1886
|
+
if orphaned_in_index:
|
|
1887
|
+
print(f"⚠️ Orphaned in index (file gone): {len(orphaned_in_index)}")
|
|
1888
|
+
# Count by type
|
|
1889
|
+
orphan_subagent = sum(
|
|
1890
|
+
1 for p in orphaned_in_index if indexed_by_path[p]["is_subagent"]
|
|
1891
|
+
)
|
|
1892
|
+
orphan_resumable = len(orphaned_in_index) - orphan_subagent
|
|
1893
|
+
print(f" ({orphan_resumable} resumable, {orphan_subagent} subagent)")
|
|
1894
|
+
for fpath in list(orphaned_in_index)[:3]:
|
|
1895
|
+
info = indexed_by_path[fpath]
|
|
1896
|
+
fname = fpath.split("/")[-1]
|
|
1897
|
+
print(f" - {fname} ({info['agent']})")
|
|
1898
|
+
if len(orphaned_in_index) > 3:
|
|
1899
|
+
print(f" ... and {len(orphaned_in_index) - 3} more")
|
|
1900
|
+
|
|
1901
|
+
# Count by cwd if filter specified
|
|
1902
|
+
if cwd:
|
|
1903
|
+
matching = [r for r in results if r.get("cwd") == cwd]
|
|
1904
|
+
matching_unique = set(r.get("session_id") for r in matching)
|
|
1905
|
+
print(f"\nWith cwd '{cwd}':")
|
|
1906
|
+
print(f" Documents: {len(matching)}")
|
|
1907
|
+
print(f" Unique sessions: {len(matching_unique)}")
|
|
1908
|
+
|
|
1909
|
+
# Top cwds
|
|
1910
|
+
cwd_counts = Counter(r.get("cwd", "unknown") for r in results)
|
|
1911
|
+
print("\nTop 5 cwds:")
|
|
1912
|
+
for path, count in cwd_counts.most_common(5):
|
|
1913
|
+
short = path[-50:] if len(path) > 50 else path
|
|
1914
|
+
print(f" {count:4d} | ...{short}" if len(path) > 50 else f" {count:4d} | {short}")
|
|
1915
|
+
|
|
1916
|
+
# Claude home stats
|
|
1917
|
+
claude_home_counts = Counter(r.get("claude_home", "") for r in results)
|
|
1918
|
+
print("\nClaude homes:")
|
|
1919
|
+
for home, count in claude_home_counts.most_common(10):
|
|
1920
|
+
home_display = home if home else "(empty)"
|
|
1921
|
+
print(f" {count:4d} | {home_display}")
|
|
1922
|
+
|
|
1923
|
+
|
|
1924
|
+
@main.command("search")
|
|
1925
|
+
@click.option(
|
|
1926
|
+
'--claude-home',
|
|
1927
|
+
'claude_home_arg',
|
|
1928
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
1929
|
+
help='Path to Claude home directory (overrides CLAUDE_CONFIG_DIR env var)',
|
|
1930
|
+
)
|
|
1931
|
+
@click.option(
|
|
1932
|
+
'--codex-home',
|
|
1933
|
+
'codex_home_arg',
|
|
1934
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
1935
|
+
help='Path to Codex home directory (overrides CODEX_HOME env var)',
|
|
1936
|
+
)
|
|
1937
|
+
@click.option('-g', '--global', 'global_search', is_flag=True,
|
|
1938
|
+
help='Search across all projects (not just current)')
|
|
1939
|
+
@click.option('--dir', 'filter_dir',
|
|
1940
|
+
help='Filter to directory[:branch] (overrides -g)')
|
|
1941
|
+
@click.option('--branch', 'filter_branch',
|
|
1942
|
+
help='Filter to specific git branch (only effective when not global)')
|
|
1943
|
+
@click.option('-n', '--num-results', type=int, default=None,
|
|
1944
|
+
help='Limit number of results displayed')
|
|
1945
|
+
@click.option('--no-original', is_flag=True, help='Exclude original sessions')
|
|
1946
|
+
@click.option('--sub-agent', is_flag=True, help='Include sub-agent sessions (additive)')
|
|
1947
|
+
@click.option('--no-trimmed', is_flag=True, help='Exclude trimmed sessions')
|
|
1948
|
+
@click.option('--no-rollover', is_flag=True, help='Exclude rollover sessions')
|
|
1949
|
+
@click.option('--min-lines', type=int, default=None,
|
|
1950
|
+
help='Only show sessions with at least N lines')
|
|
1951
|
+
@click.option('--after', metavar='DATE',
|
|
1952
|
+
help='Sessions modified after date (YYYYMMDD, MM/DD/YY)')
|
|
1953
|
+
@click.option('--before', metavar='DATE',
|
|
1954
|
+
help='Sessions modified before date (YYYYMMDD, MM/DD/YY)')
|
|
1955
|
+
@click.option('--agent', type=click.Choice(['claude', 'codex', 'all']),
|
|
1956
|
+
default='all', help='Filter by agent type')
|
|
1957
|
+
@click.option('--json', 'json_output', is_flag=True,
|
|
1958
|
+
help='Output as JSONL for AI agents. Fields per line: session_id, '
|
|
1959
|
+
'agent, project, branch, cwd, lines, created, modified, '
|
|
1960
|
+
'first_msg, last_msg, file_path, derivation_type, '
|
|
1961
|
+
'is_sidechain, snippet')
|
|
1962
|
+
@click.option('--by-time', 'by_time', is_flag=True,
|
|
1963
|
+
help='Sort results by last-modified time (default: sort by relevance)')
|
|
1964
|
+
@click.argument('query', required=False)
|
|
1965
|
+
def search(
|
|
1966
|
+
claude_home_arg, codex_home_arg, global_search, filter_dir, filter_branch,
|
|
1967
|
+
num_results, no_original, sub_agent, no_trimmed, no_rollover, min_lines,
|
|
1968
|
+
after, before, agent, json_output, by_time, query
|
|
1969
|
+
):
|
|
1970
|
+
"""Launch interactive TUI for full-text session search.
|
|
1971
|
+
|
|
1972
|
+
Provides fast Tantivy-based search across all Claude and Codex sessions
|
|
1973
|
+
with auto-indexing, keyword highlighting, and session actions.
|
|
1974
|
+
|
|
1975
|
+
\b
|
|
1976
|
+
Examples:
|
|
1977
|
+
aichat search # Interactive TUI
|
|
1978
|
+
aichat search "langroid agent" # Pre-fill search query
|
|
1979
|
+
aichat search -g --after 11/20/25 # Global, recent sessions
|
|
1980
|
+
aichat search --dir ~/Git/myproj # Filter to specific directory
|
|
1981
|
+
aichat search --json "MCP" # JSON output (sorted by relevance)
|
|
1982
|
+
aichat search --json --by-time # JSON output sorted by time
|
|
1983
|
+
|
|
1984
|
+
\b
|
|
1985
|
+
Notes:
|
|
1986
|
+
--dir overrides -g (global) when both are specified.
|
|
1987
|
+
--by-time sorts by last-modified time; default is relevance.
|
|
1988
|
+
|
|
1989
|
+
\b
|
|
1990
|
+
Environment variables:
|
|
1991
|
+
CLAUDE_CONFIG_DIR - Default Claude home (overridden by --claude-home)
|
|
1992
|
+
CODEX_HOME - Default Codex home (overridden by --codex-home)
|
|
1993
|
+
"""
|
|
1994
|
+
import json as json_lib
|
|
1995
|
+
import os
|
|
1996
|
+
import subprocess
|
|
1997
|
+
import sys
|
|
1998
|
+
import tempfile
|
|
1999
|
+
from pathlib import Path
|
|
2000
|
+
|
|
2001
|
+
# Find Rust binary - check PATH first (cargo install), then local dev build
|
|
2002
|
+
import shutil
|
|
2003
|
+
rust_binary_name = "aichat-search"
|
|
2004
|
+
rust_binary = shutil.which(rust_binary_name)
|
|
2005
|
+
if rust_binary:
|
|
2006
|
+
rust_binary = Path(rust_binary)
|
|
2007
|
+
else:
|
|
2008
|
+
# Fall back to local development build
|
|
2009
|
+
rust_binary = (
|
|
2010
|
+
Path(__file__).parent.parent
|
|
2011
|
+
/ "rust-search-ui"
|
|
2012
|
+
/ "target"
|
|
2013
|
+
/ "release"
|
|
2014
|
+
/ rust_binary_name
|
|
2015
|
+
)
|
|
2016
|
+
if not rust_binary.exists():
|
|
2017
|
+
print(f"Error: {rust_binary_name} not found.", file=sys.stderr)
|
|
2018
|
+
print("Install with: cargo install aichat-search", file=sys.stderr)
|
|
2019
|
+
print("Or build locally: cd rust-search-ui && cargo build --release",
|
|
2020
|
+
file=sys.stderr)
|
|
2021
|
+
return
|
|
2022
|
+
|
|
2023
|
+
# Resolve home directories (CLI arg > env var > default)
|
|
2024
|
+
from claude_code_tools.session_utils import get_claude_home, get_codex_home
|
|
2025
|
+
claude_home = get_claude_home(cli_arg=claude_home_arg)
|
|
2026
|
+
codex_home = get_codex_home(cli_arg=codex_home_arg)
|
|
2027
|
+
|
|
2028
|
+
# Build CLI args for Rust binary
|
|
2029
|
+
rust_args = [str(rust_binary)]
|
|
2030
|
+
|
|
2031
|
+
# Home directories
|
|
2032
|
+
rust_args.extend(["--claude-home", str(claude_home)])
|
|
2033
|
+
rust_args.extend(["--codex-home", str(codex_home)])
|
|
2034
|
+
|
|
2035
|
+
# Filter options
|
|
2036
|
+
if filter_dir:
|
|
2037
|
+
# --dir overrides -g
|
|
2038
|
+
# Support dir:branch format - extract branch if present before resolving path
|
|
2039
|
+
if ':' in filter_dir and not filter_dir.startswith('/') or (
|
|
2040
|
+
':' in filter_dir and filter_dir.count(':') == 1 and
|
|
2041
|
+
'/' not in filter_dir.split(':')[-1]
|
|
2042
|
+
):
|
|
2043
|
+
# Has branch suffix (dir:branch format)
|
|
2044
|
+
parts = filter_dir.rsplit(':', 1)
|
|
2045
|
+
dir_part = parts[0]
|
|
2046
|
+
branch_part = parts[1] if len(parts) > 1 else None
|
|
2047
|
+
resolved_dir = str(Path(dir_part).resolve())
|
|
2048
|
+
if branch_part:
|
|
2049
|
+
rust_args.extend(["--dir", f"{resolved_dir}:{branch_part}"])
|
|
2050
|
+
else:
|
|
2051
|
+
rust_args.extend(["--dir", resolved_dir])
|
|
2052
|
+
else:
|
|
2053
|
+
rust_args.extend(["--dir", str(Path(filter_dir).resolve())])
|
|
2054
|
+
elif global_search:
|
|
2055
|
+
rust_args.append("--global")
|
|
2056
|
+
if filter_branch:
|
|
2057
|
+
rust_args.extend(["--branch", filter_branch])
|
|
2058
|
+
if num_results:
|
|
2059
|
+
rust_args.extend(["--num-results", str(num_results)])
|
|
2060
|
+
if no_original:
|
|
2061
|
+
rust_args.append("--no-original")
|
|
2062
|
+
if sub_agent:
|
|
2063
|
+
rust_args.append("--sub-agent")
|
|
2064
|
+
if no_trimmed:
|
|
2065
|
+
rust_args.append("--no-trimmed")
|
|
2066
|
+
if no_rollover:
|
|
2067
|
+
rust_args.append("--no-rollover")
|
|
2068
|
+
if min_lines:
|
|
2069
|
+
rust_args.extend(["--min-lines", str(min_lines)])
|
|
2070
|
+
if after:
|
|
2071
|
+
rust_args.extend(["--after", after])
|
|
2072
|
+
if before:
|
|
2073
|
+
rust_args.extend(["--before", before])
|
|
2074
|
+
if agent and agent != "all":
|
|
2075
|
+
rust_args.extend(["--agent", agent])
|
|
2076
|
+
if query:
|
|
2077
|
+
rust_args.extend(["--query", query])
|
|
2078
|
+
if by_time:
|
|
2079
|
+
rust_args.append("--by-time")
|
|
2080
|
+
|
|
2081
|
+
# JSON output mode - run Rust with --json, output to stdout, exit
|
|
2082
|
+
if json_output:
|
|
2083
|
+
rust_args.append("--json")
|
|
2084
|
+
try:
|
|
2085
|
+
result = subprocess.run(rust_args, capture_output=True, text=True)
|
|
2086
|
+
# Output JSON to stdout (errors to stderr)
|
|
2087
|
+
# Use end='' to avoid double newline (Rust already adds one)
|
|
2088
|
+
if result.stdout:
|
|
2089
|
+
print(result.stdout, end='')
|
|
2090
|
+
if result.returncode != 0 and result.stderr:
|
|
2091
|
+
print(result.stderr, file=sys.stderr)
|
|
2092
|
+
sys.exit(result.returncode)
|
|
2093
|
+
except Exception as e:
|
|
2094
|
+
print(f"Error running search: {e}", file=sys.stderr)
|
|
2095
|
+
sys.exit(1)
|
|
2096
|
+
|
|
2097
|
+
# Import for interactive TUI mode
|
|
2098
|
+
from claude_code_tools.node_menu_ui import run_node_menu_ui, run_dir_confirm_ui
|
|
2099
|
+
from claude_code_tools.session_menu_cli import execute_action
|
|
2100
|
+
|
|
2101
|
+
# RPC path for action execution
|
|
2102
|
+
rpc_path = str(Path(__file__).parent / "action_rpc.py")
|
|
2103
|
+
|
|
2104
|
+
def action_handler(sess, action, kwargs):
|
|
2105
|
+
"""Handle action from Node menu."""
|
|
2106
|
+
agent_type = sess.get("agent", "claude")
|
|
2107
|
+
file_path = sess.get("file_path")
|
|
2108
|
+
cwd = sess.get("cwd") or "."
|
|
2109
|
+
|
|
2110
|
+
if not file_path:
|
|
2111
|
+
print(f"Error: No file_path for session {sess.get('session_id')}")
|
|
2112
|
+
return
|
|
2113
|
+
|
|
2114
|
+
return execute_action(
|
|
2115
|
+
action=action,
|
|
2116
|
+
agent=agent_type,
|
|
2117
|
+
session_file=Path(file_path),
|
|
2118
|
+
project_path=cwd,
|
|
2119
|
+
action_kwargs=kwargs,
|
|
2120
|
+
session_id=sess.get("session_id"),
|
|
2121
|
+
)
|
|
2122
|
+
|
|
2123
|
+
def check_directory_and_confirm(sess):
|
|
2124
|
+
"""Check if session is from different directory and get user confirmation.
|
|
2125
|
+
|
|
2126
|
+
Returns:
|
|
2127
|
+
(proceed, original_dir) tuple:
|
|
2128
|
+
- proceed: True if user wants to proceed, False if cancelled
|
|
2129
|
+
- original_dir: The directory before any change (to restore on cancel),
|
|
2130
|
+
or None if no directory change was made
|
|
2131
|
+
"""
|
|
2132
|
+
session_dir = sess.get("cwd") or "."
|
|
2133
|
+
current_dir = os.getcwd()
|
|
2134
|
+
|
|
2135
|
+
# If same directory, proceed (no restore needed)
|
|
2136
|
+
if os.path.realpath(session_dir) == os.path.realpath(current_dir):
|
|
2137
|
+
return (True, None)
|
|
2138
|
+
|
|
2139
|
+
# Show confirmation dialog
|
|
2140
|
+
choice = run_dir_confirm_ui(current_dir, session_dir)
|
|
2141
|
+
|
|
2142
|
+
if choice == "yes":
|
|
2143
|
+
# Change directory and proceed
|
|
2144
|
+
original_dir = current_dir
|
|
2145
|
+
try:
|
|
2146
|
+
os.chdir(session_dir)
|
|
2147
|
+
except Exception as e:
|
|
2148
|
+
print(f"Error changing directory: {e}")
|
|
2149
|
+
original_dir = None # No restore needed if change failed
|
|
2150
|
+
return (True, original_dir)
|
|
2151
|
+
elif choice == "no":
|
|
2152
|
+
# Proceed without changing directory (no restore needed)
|
|
2153
|
+
return (True, None)
|
|
2154
|
+
else:
|
|
2155
|
+
# 'cancel' or None - user wants to go back
|
|
2156
|
+
return (False, None)
|
|
2157
|
+
|
|
2158
|
+
# Main loop: Rust TUI → Node menu → back to Rust TUI
|
|
2159
|
+
while True:
|
|
2160
|
+
# Create temp file for IPC
|
|
2161
|
+
fd, out_path = tempfile.mkstemp(suffix="-rust-ui.json")
|
|
2162
|
+
os.close(fd)
|
|
2163
|
+
|
|
2164
|
+
# Run Rust TUI (interactive - needs TTY)
|
|
2165
|
+
tui_args = rust_args + [out_path]
|
|
2166
|
+
try:
|
|
2167
|
+
result = subprocess.run(tui_args)
|
|
2168
|
+
except Exception as e:
|
|
2169
|
+
print(f"Error running Rust TUI: {e}")
|
|
2170
|
+
try:
|
|
2171
|
+
os.unlink(out_path)
|
|
2172
|
+
except Exception:
|
|
2173
|
+
pass
|
|
2174
|
+
return
|
|
2175
|
+
|
|
2176
|
+
if result.returncode != 0:
|
|
2177
|
+
try:
|
|
2178
|
+
os.unlink(out_path)
|
|
2179
|
+
except Exception:
|
|
2180
|
+
pass
|
|
2181
|
+
return
|
|
2182
|
+
|
|
2183
|
+
# Read JSON from temp file
|
|
2184
|
+
try:
|
|
2185
|
+
content = Path(out_path).read_text().strip()
|
|
2186
|
+
except Exception:
|
|
2187
|
+
content = ""
|
|
2188
|
+
finally:
|
|
2189
|
+
try:
|
|
2190
|
+
os.unlink(out_path)
|
|
2191
|
+
except Exception:
|
|
2192
|
+
pass
|
|
2193
|
+
|
|
2194
|
+
if not content:
|
|
2195
|
+
# User quit without selecting - exit the loop
|
|
2196
|
+
return
|
|
2197
|
+
|
|
2198
|
+
try:
|
|
2199
|
+
result = json_lib.loads(content)
|
|
2200
|
+
except json_lib.JSONDecodeError as e:
|
|
2201
|
+
print(f"Error parsing Rust output: {e}")
|
|
2202
|
+
print(f"Output was: {content[:200]}")
|
|
2203
|
+
return
|
|
2204
|
+
|
|
2205
|
+
# New format: {"session": {...}, "action": "...", "filter_state": {...}}
|
|
2206
|
+
# Legacy format: just the session object
|
|
2207
|
+
if "session" in result and "action" in result:
|
|
2208
|
+
selected = result["session"]
|
|
2209
|
+
action = result["action"]
|
|
2210
|
+
else:
|
|
2211
|
+
# Legacy: session only, show Node menu
|
|
2212
|
+
selected = result
|
|
2213
|
+
action = "menu"
|
|
2214
|
+
|
|
2215
|
+
# Extract and apply filter state for next loop iteration
|
|
2216
|
+
filter_state = result.get("filter_state", {})
|
|
2217
|
+
if filter_state:
|
|
2218
|
+
# Rebuild rust_args with preserved filter state
|
|
2219
|
+
rust_args = [str(rust_binary)]
|
|
2220
|
+
rust_args.extend(["--claude-home", str(claude_home)])
|
|
2221
|
+
rust_args.extend(["--codex-home", str(codex_home)])
|
|
2222
|
+
|
|
2223
|
+
# Scope: --dir overrides --global
|
|
2224
|
+
if filter_state.get("filter_dir"):
|
|
2225
|
+
rust_args.extend(["--dir", filter_state["filter_dir"]])
|
|
2226
|
+
elif filter_state.get("scope_global"):
|
|
2227
|
+
rust_args.append("--global")
|
|
2228
|
+
|
|
2229
|
+
# Branch filter
|
|
2230
|
+
if filter_state.get("filter_branch"):
|
|
2231
|
+
rust_args.extend(["--branch", filter_state["filter_branch"]])
|
|
2232
|
+
|
|
2233
|
+
# Session type filters
|
|
2234
|
+
# Subtractive: add --no-* when type is excluded
|
|
2235
|
+
# Additive: add --sub-agent when sub-agents are included
|
|
2236
|
+
if not filter_state.get("include_original", True):
|
|
2237
|
+
rust_args.append("--no-original")
|
|
2238
|
+
if filter_state.get("include_sub"):
|
|
2239
|
+
rust_args.append("--sub-agent")
|
|
2240
|
+
if not filter_state.get("include_trimmed", True):
|
|
2241
|
+
rust_args.append("--no-trimmed")
|
|
2242
|
+
if not filter_state.get("include_continued", True):
|
|
2243
|
+
rust_args.append("--no-rollover")
|
|
2244
|
+
|
|
2245
|
+
# Other filters
|
|
2246
|
+
if filter_state.get("filter_min_lines"):
|
|
2247
|
+
rust_args.extend(["--min-lines", str(filter_state["filter_min_lines"])])
|
|
2248
|
+
if filter_state.get("filter_after_date"):
|
|
2249
|
+
rust_args.extend(["--after", filter_state["filter_after_date"]])
|
|
2250
|
+
if filter_state.get("filter_before_date"):
|
|
2251
|
+
rust_args.extend(["--before", filter_state["filter_before_date"]])
|
|
2252
|
+
if filter_state.get("filter_agent"):
|
|
2253
|
+
rust_args.extend(["--agent", filter_state["filter_agent"]])
|
|
2254
|
+
if filter_state.get("query"):
|
|
2255
|
+
rust_args.extend(["--query", filter_state["query"]])
|
|
2256
|
+
if filter_state.get("sort_by_time"):
|
|
2257
|
+
rust_args.append("--by-time")
|
|
2258
|
+
|
|
2259
|
+
# Restore scroll/selection state
|
|
2260
|
+
if filter_state.get("selected") is not None:
|
|
2261
|
+
rust_args.extend(["--selected", str(filter_state["selected"])])
|
|
2262
|
+
if filter_state.get("list_scroll") is not None:
|
|
2263
|
+
rust_args.extend(["--scroll", str(filter_state["list_scroll"])])
|
|
2264
|
+
|
|
2265
|
+
# Preserve num_results if originally specified
|
|
2266
|
+
if num_results:
|
|
2267
|
+
rust_args.extend(["--num-results", str(num_results)])
|
|
2268
|
+
|
|
2269
|
+
# Convert ISO date strings from Rust to Unix timestamps
|
|
2270
|
+
def iso_to_timestamp(iso_str: str) -> float:
|
|
2271
|
+
"""Convert ISO date string to Unix timestamp."""
|
|
2272
|
+
if not iso_str:
|
|
2273
|
+
return 0.0
|
|
2274
|
+
try:
|
|
2275
|
+
from datetime import datetime
|
|
2276
|
+
# Handle both formats: with and without 'Z' suffix
|
|
2277
|
+
iso_str = iso_str.replace("Z", "+00:00")
|
|
2278
|
+
dt = datetime.fromisoformat(iso_str)
|
|
2279
|
+
return dt.timestamp()
|
|
2280
|
+
except (ValueError, TypeError):
|
|
2281
|
+
return 0.0
|
|
2282
|
+
|
|
2283
|
+
# Convert to session format expected by handlers
|
|
2284
|
+
# Rust sends 'created'/'modified' as ISO strings, Node UI expects
|
|
2285
|
+
# 'create_time'/'mod_time' as Unix timestamps
|
|
2286
|
+
session = {
|
|
2287
|
+
"session_id": selected.get("session_id", ""),
|
|
2288
|
+
"agent": selected.get("agent", "claude"),
|
|
2289
|
+
"agent_display": selected.get("agent", "claude").title(),
|
|
2290
|
+
"project": selected.get("project", ""),
|
|
2291
|
+
"branch": selected.get("branch", ""),
|
|
2292
|
+
"lines": selected.get("lines", 0),
|
|
2293
|
+
"file_path": selected.get("file_path", ""),
|
|
2294
|
+
"cwd": selected.get("cwd", ""),
|
|
2295
|
+
"is_sidechain": selected.get("is_sidechain", False),
|
|
2296
|
+
"create_time": iso_to_timestamp(selected.get("created", "")),
|
|
2297
|
+
"mod_time": iso_to_timestamp(selected.get("modified", "")),
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
# Extract cwd from file_path metadata if needed (for older export format)
|
|
2301
|
+
file_path = selected.get("file_path", "")
|
|
2302
|
+
if file_path and file_path.endswith(".txt"):
|
|
2303
|
+
try:
|
|
2304
|
+
with open(file_path, "r") as f:
|
|
2305
|
+
file_content = f.read(2000)
|
|
2306
|
+
if file_content.startswith("---\n"):
|
|
2307
|
+
end_idx = file_content.find("\n---\n", 4)
|
|
2308
|
+
if end_idx != -1:
|
|
2309
|
+
import yaml
|
|
2310
|
+
metadata = yaml.safe_load(file_content[4:end_idx])
|
|
2311
|
+
if metadata:
|
|
2312
|
+
session["cwd"] = metadata.get("cwd") or session["cwd"]
|
|
2313
|
+
session["file_path"] = metadata.get("file_path", file_path)
|
|
2314
|
+
except Exception:
|
|
2315
|
+
pass
|
|
2316
|
+
|
|
2317
|
+
print(f"Selected: {session['project']} / {session['session_id'][:12]}...")
|
|
2318
|
+
|
|
2319
|
+
# Track original directory for restoration on Ctrl+C
|
|
2320
|
+
original_dir_for_interrupt = None
|
|
2321
|
+
|
|
2322
|
+
try:
|
|
2323
|
+
# Dispatch based on action
|
|
2324
|
+
if action == "menu":
|
|
2325
|
+
# Legacy: show Node action menu, loop back on Escape
|
|
2326
|
+
run_node_menu_ui(
|
|
2327
|
+
sessions=[session],
|
|
2328
|
+
keywords=[],
|
|
2329
|
+
action_handler=action_handler,
|
|
2330
|
+
start_action=True,
|
|
2331
|
+
focus_session_id=session["session_id"],
|
|
2332
|
+
rpc_path=rpc_path,
|
|
2333
|
+
)
|
|
2334
|
+
# Loop back to Rust TUI
|
|
2335
|
+
elif action == "view":
|
|
2336
|
+
# View is handled in Rust, shouldn't reach here
|
|
2337
|
+
pass
|
|
2338
|
+
elif action in ("path", "copy", "export"):
|
|
2339
|
+
# Non-launch actions: go directly to nonlaunch screen
|
|
2340
|
+
run_node_menu_ui(
|
|
2341
|
+
sessions=[session],
|
|
2342
|
+
keywords=[],
|
|
2343
|
+
action_handler=action_handler,
|
|
2344
|
+
start_action=False,
|
|
2345
|
+
focus_session_id=session["session_id"],
|
|
2346
|
+
rpc_path=rpc_path,
|
|
2347
|
+
start_screen="nonlaunch",
|
|
2348
|
+
direct_action=action,
|
|
2349
|
+
)
|
|
2350
|
+
# Continue loop to return to Rust TUI
|
|
2351
|
+
elif action == "query":
|
|
2352
|
+
# Query: go directly to query screen
|
|
2353
|
+
run_node_menu_ui(
|
|
2354
|
+
sessions=[session],
|
|
2355
|
+
keywords=[],
|
|
2356
|
+
action_handler=action_handler,
|
|
2357
|
+
start_action=False,
|
|
2358
|
+
focus_session_id=session["session_id"],
|
|
2359
|
+
rpc_path=rpc_path,
|
|
2360
|
+
start_screen="query",
|
|
2361
|
+
direct_action="query",
|
|
2362
|
+
)
|
|
2363
|
+
# Continue loop to return to Rust TUI
|
|
2364
|
+
elif action == "suppress_resume":
|
|
2365
|
+
# Trim + resume: check directory first, then show trim form
|
|
2366
|
+
proceed, original_dir = check_directory_and_confirm(session)
|
|
2367
|
+
if not proceed:
|
|
2368
|
+
continue # User cancelled - pop back to Rust search
|
|
2369
|
+
original_dir_for_interrupt = original_dir
|
|
2370
|
+
run_node_menu_ui(
|
|
2371
|
+
sessions=[session],
|
|
2372
|
+
keywords=[],
|
|
2373
|
+
action_handler=action_handler,
|
|
2374
|
+
start_action=False,
|
|
2375
|
+
focus_session_id=session["session_id"],
|
|
2376
|
+
rpc_path=rpc_path,
|
|
2377
|
+
start_screen="trim",
|
|
2378
|
+
direct_action="suppress_resume",
|
|
2379
|
+
exit_on_back=True, # Pop back to Rust search on cancel
|
|
2380
|
+
)
|
|
2381
|
+
# If we return here, user cancelled - restore directory and pop back
|
|
2382
|
+
if original_dir:
|
|
2383
|
+
os.chdir(original_dir)
|
|
2384
|
+
elif action == "smart_trim_resume":
|
|
2385
|
+
# Smart trim: check directory first, then show options form
|
|
2386
|
+
proceed, original_dir = check_directory_and_confirm(session)
|
|
2387
|
+
if not proceed:
|
|
2388
|
+
continue # User cancelled - pop back to Rust search
|
|
2389
|
+
original_dir_for_interrupt = original_dir
|
|
2390
|
+
run_node_menu_ui(
|
|
2391
|
+
sessions=[session],
|
|
2392
|
+
keywords=[],
|
|
2393
|
+
action_handler=action_handler,
|
|
2394
|
+
start_action=False,
|
|
2395
|
+
focus_session_id=session["session_id"],
|
|
2396
|
+
rpc_path=rpc_path,
|
|
2397
|
+
start_screen="smart_trim_form",
|
|
2398
|
+
direct_action="smart_trim_resume",
|
|
2399
|
+
exit_on_back=True, # Pop back to Rust search on cancel
|
|
2400
|
+
)
|
|
2401
|
+
# If we return here, user cancelled - restore directory and pop back
|
|
2402
|
+
if original_dir:
|
|
2403
|
+
os.chdir(original_dir)
|
|
2404
|
+
elif action == "continue":
|
|
2405
|
+
# Continue with context: check directory first, then show options form
|
|
2406
|
+
proceed, original_dir = check_directory_and_confirm(session)
|
|
2407
|
+
if not proceed:
|
|
2408
|
+
continue # User cancelled - pop back to Rust search
|
|
2409
|
+
original_dir_for_interrupt = original_dir
|
|
2410
|
+
run_node_menu_ui(
|
|
2411
|
+
sessions=[session],
|
|
2412
|
+
keywords=[],
|
|
2413
|
+
action_handler=action_handler,
|
|
2414
|
+
start_action=False,
|
|
2415
|
+
focus_session_id=session["session_id"],
|
|
2416
|
+
rpc_path=rpc_path,
|
|
2417
|
+
start_screen="continue_form",
|
|
2418
|
+
direct_action="continue",
|
|
2419
|
+
exit_on_back=True, # Pop back to Rust search on cancel
|
|
2420
|
+
)
|
|
2421
|
+
# If we return here, user cancelled - restore directory and pop back
|
|
2422
|
+
if original_dir:
|
|
2423
|
+
os.chdir(original_dir)
|
|
2424
|
+
elif action in ("resume", "clone"):
|
|
2425
|
+
# Resume/clone: check directory first, then execute
|
|
2426
|
+
proceed, original_dir = check_directory_and_confirm(session)
|
|
2427
|
+
if not proceed:
|
|
2428
|
+
continue # User cancelled - pop back to Rust search
|
|
2429
|
+
original_dir_for_interrupt = original_dir
|
|
2430
|
+
# Note: if successful, action_handler calls os.execvp and never returns
|
|
2431
|
+
action_handler(session, action, {})
|
|
2432
|
+
# If we get here, something failed - restore directory and pop back
|
|
2433
|
+
if original_dir:
|
|
2434
|
+
os.chdir(original_dir)
|
|
2435
|
+
elif action == "delete":
|
|
2436
|
+
# Delete: already confirmed in Rust UI, just execute
|
|
2437
|
+
action_handler(session, action, {})
|
|
2438
|
+
# Remove deleted session from search index
|
|
2439
|
+
try:
|
|
2440
|
+
from claude_code_tools.search_index import SessionIndex
|
|
2441
|
+
idx = SessionIndex(Path("~/.cctools/search-index").expanduser())
|
|
2442
|
+
idx.prune_deleted()
|
|
2443
|
+
except Exception:
|
|
2444
|
+
pass # Index errors shouldn't block the UI
|
|
2445
|
+
# Loop back to Rust TUI (session list will refresh)
|
|
2446
|
+
else:
|
|
2447
|
+
print(f"Unknown action: {action}")
|
|
2448
|
+
# Continue loop
|
|
2449
|
+
except KeyboardInterrupt:
|
|
2450
|
+
# Ctrl+C pressed - restore directory if changed and pop back to search
|
|
2451
|
+
if original_dir_for_interrupt:
|
|
2452
|
+
try:
|
|
2453
|
+
os.chdir(original_dir_for_interrupt)
|
|
2454
|
+
except Exception:
|
|
2455
|
+
pass
|
|
2456
|
+
# Continue loop to return to Rust TUI
|
|
2457
|
+
|
|
2458
|
+
|
|
2459
|
+
if __name__ == "__main__":
|
|
2460
|
+
main()
|