@ridit/lens 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +2028 -207
- package/hello.py +51 -0
- package/package.json +3 -4
- package/src/colors.ts +9 -0
- package/src/components/chat/ChatMessage.tsx +573 -66
- package/src/components/chat/ChatOverlays.tsx +28 -1
- package/src/components/chat/ChatRunner.tsx +250 -69
- package/src/index.tsx +60 -60
- package/src/types/chat.ts +18 -1
- package/src/utils/chat.ts +805 -32
- package/src/utils/thinking.tsx +20 -1
- package/tsconfig.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -44359,6 +44359,14 @@ var build_default = Spinner;
|
|
|
44359
44359
|
|
|
44360
44360
|
// src/colors.ts
|
|
44361
44361
|
var ACCENT = "#DA7758";
|
|
44362
|
+
var TOKEN_KEYWORD = "#B385C9";
|
|
44363
|
+
var TOKEN_STRING = "#85C98A";
|
|
44364
|
+
var TOKEN_NUMBER = "#E8C170";
|
|
44365
|
+
var TOKEN_PROPERTY = "#79C5D4";
|
|
44366
|
+
var TOKEN_ENTITY = "#7AABDB";
|
|
44367
|
+
var TOKEN_TEXT = "#E8E8E8";
|
|
44368
|
+
var TOKEN_MUTED = "#888888";
|
|
44369
|
+
var TOKEN_COMMENT = "#777777";
|
|
44362
44370
|
|
|
44363
44371
|
// src/utils/thinking.tsx
|
|
44364
44372
|
var import_react30 = __toESM(require_react(), 1);
|
|
@@ -44404,6 +44412,26 @@ var PHRASES = {
|
|
|
44404
44412
|
"chefkiss incoming...",
|
|
44405
44413
|
"slay mode: on...",
|
|
44406
44414
|
"rizzing up an answer...",
|
|
44415
|
+
"rizzing up a baddie answer...",
|
|
44416
|
+
"sigma grindset: activated...",
|
|
44417
|
+
"NPC behavior: disabled...",
|
|
44418
|
+
"unaliving my writer's block...",
|
|
44419
|
+
"caught in 4K thinking...",
|
|
44420
|
+
"delulu but make it accurate...",
|
|
44421
|
+
"ate and left no crumbs...",
|
|
44422
|
+
"rent free in the codebase...",
|
|
44423
|
+
"understood the assignment (fr fr)...",
|
|
44424
|
+
"giving main character energy...",
|
|
44425
|
+
"no thoughts, head full...",
|
|
44426
|
+
"built different response incoming...",
|
|
44427
|
+
"chronically online and loving it...",
|
|
44428
|
+
"touch grass? not yet...",
|
|
44429
|
+
"this response is bussin...",
|
|
44430
|
+
"lowkey highkey computing...",
|
|
44431
|
+
"it's giving Einstein...",
|
|
44432
|
+
"we do a little thinking...",
|
|
44433
|
+
"gigachad analysis mode...",
|
|
44434
|
+
"the audacity to be this smart...",
|
|
44407
44435
|
"consulting the void...",
|
|
44408
44436
|
"asking my other personalities...",
|
|
44409
44437
|
"reading the codebase tea leaves...",
|
|
@@ -48635,11 +48663,11 @@ ${f.content.slice(0, 2000)}
|
|
|
48635
48663
|
\`\`\``).join(`
|
|
48636
48664
|
|
|
48637
48665
|
`);
|
|
48638
|
-
return `You are an expert software engineer assistant with access to the user's codebase and
|
|
48666
|
+
return `You are an expert software engineer assistant with access to the user's codebase and eleven tools.
|
|
48639
48667
|
|
|
48640
48668
|
## TOOLS
|
|
48641
48669
|
|
|
48642
|
-
You have exactly
|
|
48670
|
+
You have exactly eleven tools. To use a tool you MUST wrap it in the exact XML tags shown below — no other format will work.
|
|
48643
48671
|
|
|
48644
48672
|
### 1. fetch — load a URL
|
|
48645
48673
|
<fetch>https://example.com</fetch>
|
|
@@ -48650,19 +48678,47 @@ You have exactly six tools. To use a tool you MUST wrap it in the exact XML tags
|
|
|
48650
48678
|
### 3. read-file — read a file from the repo
|
|
48651
48679
|
<read-file>src/foo.ts</read-file>
|
|
48652
48680
|
|
|
48653
|
-
### 4.
|
|
48681
|
+
### 4. read-folder — list contents of a folder (files + subfolders, one level deep)
|
|
48682
|
+
<read-folder>src/components</read-folder>
|
|
48683
|
+
|
|
48684
|
+
### 5. grep — search for a pattern across files in the repo (cross-platform, no shell needed)
|
|
48685
|
+
<grep>
|
|
48686
|
+
{"pattern": "ChatRunner", "glob": "src/**/*.tsx"}
|
|
48687
|
+
</grep>
|
|
48688
|
+
|
|
48689
|
+
### 6. write-file — create or overwrite a file
|
|
48654
48690
|
<write-file>
|
|
48655
48691
|
{"path": "data/output.csv", "content": "col1,col2
|
|
48656
48692
|
val1,val2"}
|
|
48657
48693
|
</write-file>
|
|
48658
48694
|
|
|
48659
|
-
###
|
|
48695
|
+
### 7. delete-file — permanently delete a single file
|
|
48696
|
+
<delete-file>src/old-component.tsx</delete-file>
|
|
48697
|
+
|
|
48698
|
+
### 8. delete-folder — permanently delete a folder and all its contents
|
|
48699
|
+
<delete-folder>src/legacy</delete-folder>
|
|
48700
|
+
|
|
48701
|
+
### 9. open-url — open a URL in the user's default browser
|
|
48702
|
+
<open-url>https://github.com/owner/repo</open-url>
|
|
48703
|
+
|
|
48704
|
+
### 10. generate-pdf — generate a PDF file from markdown-style content
|
|
48705
|
+
<generate-pdf>
|
|
48706
|
+
{"path": "output/report.pdf", "content": "# Title
|
|
48707
|
+
|
|
48708
|
+
Some body text.
|
|
48709
|
+
|
|
48710
|
+
## Section
|
|
48711
|
+
|
|
48712
|
+
More content."}
|
|
48713
|
+
</generate-pdf>
|
|
48714
|
+
|
|
48715
|
+
### 11. search — search the internet for anything you are unsure about
|
|
48660
48716
|
<search>how to use React useEffect cleanup function</search>
|
|
48661
48717
|
|
|
48662
|
-
###
|
|
48718
|
+
### 12. clone — clone a GitHub repo so you can explore and discuss it
|
|
48663
48719
|
<clone>https://github.com/owner/repo</clone>
|
|
48664
48720
|
|
|
48665
|
-
###
|
|
48721
|
+
### 13. changes — propose code edits (shown as a diff for user approval)
|
|
48666
48722
|
<changes>
|
|
48667
48723
|
{"summary": "what changed and why", "patches": [{"path": "src/foo.ts", "content": "COMPLETE file content", "isNew": false}]}
|
|
48668
48724
|
</changes>
|
|
@@ -48675,16 +48731,50 @@ val1,val2"}
|
|
|
48675
48731
|
4. NEVER print a URL, command, filename, or JSON blob as plain text when you should be using a tool
|
|
48676
48732
|
5. NEVER say "I'll fetch" / "run this command" / "here's the write-file" — just emit the tag
|
|
48677
48733
|
6. NEVER use shell to run git clone — always use the clone tag instead
|
|
48678
|
-
7.
|
|
48679
|
-
8.
|
|
48680
|
-
9.
|
|
48681
|
-
10.
|
|
48682
|
-
11.
|
|
48683
|
-
12.
|
|
48684
|
-
13.
|
|
48685
|
-
14.
|
|
48686
|
-
15.
|
|
48687
|
-
16.
|
|
48734
|
+
7. NEVER use shell to list files or folders (no ls, dir, find, git ls-files, tree) — ALWAYS use read-folder instead
|
|
48735
|
+
8. NEVER use shell to read a file (no cat, type, Get-Content) — ALWAYS use read-file instead
|
|
48736
|
+
9. NEVER use shell grep, findstr, or Select-String to search file contents — ALWAYS use grep instead
|
|
48737
|
+
10. shell is ONLY for running code, installing packages, building, testing — not for filesystem inspection
|
|
48738
|
+
11. write-file content field must be the COMPLETE file content, never empty or placeholder
|
|
48739
|
+
12. After a write-file succeeds, do NOT repeat it — trust the result and move on
|
|
48740
|
+
13. After a write-file succeeds, tell the user it is done immediately — do NOT auto-read the file back to verify
|
|
48741
|
+
14. NEVER apologize and redo a tool call you already made — if write-file or shell ran and returned a result, it worked, do not run it again
|
|
48742
|
+
15. NEVER say "I made a mistake" and repeat the same tool — one attempt is enough, trust the output
|
|
48743
|
+
16. NEVER second-guess yourself mid-response — commit to your answer
|
|
48744
|
+
17. If a read-folder or read-file returns "not found", accept it and move on — do NOT retry the same path
|
|
48745
|
+
18. If you have already retrieved a result for a path in this conversation, do NOT request it again — use the result you already have
|
|
48746
|
+
19. Every shell command runs from the repo root — \`cd\` has NO persistent effect. NEVER use \`cd\` alone. Use full paths or combine with && e.g. \`cd list && bun run index.ts\`
|
|
48747
|
+
20. write-file paths are relative to the repo root — if creating files in a subfolder write the full relative path e.g. \`list/src/index.tsx\` NOT \`src/index.tsx\`
|
|
48748
|
+
21. When scaffolding a new project in a subfolder, ALL write-file paths must start with that subfolder name e.g. \`list/package.json\`, \`list/src/index.tsx\`
|
|
48749
|
+
22. For JSX/TSX files always use \`.tsx\` extension and include \`/** @jsxImportSource react */\` or ensure tsconfig has jsx set — bun needs this to parse JSX
|
|
48750
|
+
23. When explaining how to use a tool in text, use [tag] bracket notation or a fenced code block — NEVER emit a real XML tool tag as part of an explanation or example
|
|
48751
|
+
24. NEVER chain tool calls unless the user's request explicitly requires multiple steps
|
|
48752
|
+
25. NEVER read files, list folders, or run tools that were not asked for in the current user message
|
|
48753
|
+
|
|
48754
|
+
## CRITICAL: READ BEFORE YOU WRITE
|
|
48755
|
+
|
|
48756
|
+
These rules are mandatory whenever you plan to edit or create a file:
|
|
48757
|
+
|
|
48758
|
+
### Before modifying ANY existing file:
|
|
48759
|
+
1. ALWAYS use read-file on the exact file you plan to change FIRST
|
|
48760
|
+
2. Study the full current content — understand every import, every export, every type, every existing feature
|
|
48761
|
+
3. Your changes patch MUST preserve ALL existing functionality — do not remove or rewrite things that were not part of the request
|
|
48762
|
+
4. If you are unsure what other files import from the file you are editing, use read-folder on the parent directory first to see what exists nearby, then read-file the relevant ones
|
|
48763
|
+
|
|
48764
|
+
### Before adding a feature that touches multiple files:
|
|
48765
|
+
1. Use read-folder on the relevant directory to see what files exist
|
|
48766
|
+
2. Use read-file on each file you plan to touch
|
|
48767
|
+
3. Only then emit a changes tag — with patches that are surgical additions, not wholesale rewrites
|
|
48768
|
+
|
|
48769
|
+
### The golden rule for write-file and changes:
|
|
48770
|
+
- The output file must contain EVERYTHING the original had, PLUS your new additions
|
|
48771
|
+
- NEVER produce a file that is shorter than the original unless you are explicitly asked to delete things
|
|
48772
|
+
- If you catch yourself rewriting a file from scratch, STOP — go back and read the original first
|
|
48773
|
+
|
|
48774
|
+
## WHEN TO USE read-folder:
|
|
48775
|
+
- Before editing files in an unfamiliar directory — list it first to understand the structure
|
|
48776
|
+
- When a feature spans multiple files and you are not sure what exists
|
|
48777
|
+
- When the user asks you to explore or explain a part of the codebase
|
|
48688
48778
|
|
|
48689
48779
|
## SCAFFOLDING A NEW PROJECT (follow this exactly)
|
|
48690
48780
|
|
|
@@ -48708,14 +48798,28 @@ When the user asks to create a new CLI/app in a subfolder (e.g. "make a todo app
|
|
|
48708
48798
|
|
|
48709
48799
|
- User shares any URL → fetch it immediately
|
|
48710
48800
|
- User asks to run anything → shell it immediately
|
|
48711
|
-
- User asks to
|
|
48801
|
+
- User asks to open a link, open a URL, or visit a website → open-url it immediately, do NOT use fetch
|
|
48802
|
+
- User asks to delete a file → delete-file it immediately (requires approval)
|
|
48803
|
+
- User asks to delete a folder or directory → delete-folder it immediately (requires approval)
|
|
48804
|
+
- User asks to search for a pattern in files, find usages, find where something is defined → grep it immediately, NEVER use shell grep/findstr/Select-String
|
|
48805
|
+
- User asks to read a file → read-file it immediately, NEVER use shell cat/type
|
|
48806
|
+
- User asks what files are in a folder, or to explore/list a directory → read-folder it immediately, NEVER use shell ls/dir/find/git ls-files
|
|
48807
|
+
- User asks to explore a folder or directory → read-folder it immediately
|
|
48712
48808
|
- User asks to save/create/write a file → write-file it immediately, then read-file to verify
|
|
48809
|
+
- User asks to modify/edit/add to an existing file → read-file it FIRST, then emit changes
|
|
48713
48810
|
- User shares a GitHub URL and wants to clone/explore/discuss it → use clone immediately, NEVER use shell git clone
|
|
48714
48811
|
- After clone succeeds, you will see context about the clone in the conversation. Wait for the user to ask a specific question before using any tools. Do NOT auto-read files, do NOT emit any tool tags until the user asks.
|
|
48715
48812
|
- You are unsure about an API, library, error, concept, or piece of code → search it immediately
|
|
48716
48813
|
- User asks about something recent or that you might not know → search it immediately
|
|
48717
48814
|
- You are about to say "I'm not sure" or "I don't know" → search instead of guessing
|
|
48718
48815
|
|
|
48816
|
+
## shell IS ONLY FOR:
|
|
48817
|
+
- Running code: \`node script.js\`, \`bun run dev\`, \`python main.py\`
|
|
48818
|
+
- Installing packages: \`npm install\`, \`pip install\`
|
|
48819
|
+
- Building/testing: \`npm run build\`, \`bun test\`
|
|
48820
|
+
- Git operations other than clone: \`git status\`, \`git log\`, \`git diff\`
|
|
48821
|
+
- Anything that EXECUTES — not reads or lists
|
|
48822
|
+
|
|
48719
48823
|
## CODEBASE
|
|
48720
48824
|
|
|
48721
48825
|
${fileList.length > 0 ? fileList : "(no files indexed)"}
|
|
@@ -48723,6 +48827,353 @@ ${fileList.length > 0 ? fileList : "(no files indexed)"}
|
|
|
48723
48827
|
${historySummary}`;
|
|
48724
48828
|
}
|
|
48725
48829
|
var FEW_SHOT_MESSAGES = [
|
|
48830
|
+
{
|
|
48831
|
+
role: "user",
|
|
48832
|
+
content: "delete src/old-component.tsx"
|
|
48833
|
+
},
|
|
48834
|
+
{
|
|
48835
|
+
role: "assistant",
|
|
48836
|
+
content: "<delete-file>src/old-component.tsx</delete-file>"
|
|
48837
|
+
},
|
|
48838
|
+
{
|
|
48839
|
+
role: "user",
|
|
48840
|
+
content: `Here is the output from delete-file of src/old-component.tsx:
|
|
48841
|
+
|
|
48842
|
+
Deleted: /repo/src/old-component.tsx
|
|
48843
|
+
|
|
48844
|
+
Please continue your response based on this output.`
|
|
48845
|
+
},
|
|
48846
|
+
{
|
|
48847
|
+
role: "assistant",
|
|
48848
|
+
content: "Done — `src/old-component.tsx` has been deleted."
|
|
48849
|
+
},
|
|
48850
|
+
{
|
|
48851
|
+
role: "user",
|
|
48852
|
+
content: "delete the legacy folder"
|
|
48853
|
+
},
|
|
48854
|
+
{
|
|
48855
|
+
role: "assistant",
|
|
48856
|
+
content: "<delete-folder>src/legacy</delete-folder>"
|
|
48857
|
+
},
|
|
48858
|
+
{
|
|
48859
|
+
role: "user",
|
|
48860
|
+
content: `Here is the output from delete-folder of src/legacy:
|
|
48861
|
+
|
|
48862
|
+
Deleted folder: /repo/src/legacy
|
|
48863
|
+
|
|
48864
|
+
Please continue your response based on this output.`
|
|
48865
|
+
},
|
|
48866
|
+
{
|
|
48867
|
+
role: "assistant",
|
|
48868
|
+
content: "Done — the `src/legacy` folder and all its contents have been deleted."
|
|
48869
|
+
},
|
|
48870
|
+
{
|
|
48871
|
+
role: "user",
|
|
48872
|
+
content: "open https://github.com/microsoft/typescript"
|
|
48873
|
+
},
|
|
48874
|
+
{
|
|
48875
|
+
role: "assistant",
|
|
48876
|
+
content: "<open-url>https://github.com/microsoft/typescript</open-url>"
|
|
48877
|
+
},
|
|
48878
|
+
{
|
|
48879
|
+
role: "user",
|
|
48880
|
+
content: `Here is the output from open-url https://github.com/microsoft/typescript:
|
|
48881
|
+
|
|
48882
|
+
Opened: https://github.com/microsoft/typescript
|
|
48883
|
+
|
|
48884
|
+
Please continue your response based on this output.`
|
|
48885
|
+
},
|
|
48886
|
+
{
|
|
48887
|
+
role: "assistant",
|
|
48888
|
+
content: "Opened the TypeScript GitHub page in your browser."
|
|
48889
|
+
},
|
|
48890
|
+
{
|
|
48891
|
+
role: "user",
|
|
48892
|
+
content: "generate a PDF report about the project and save it to docs/report.pdf"
|
|
48893
|
+
},
|
|
48894
|
+
{
|
|
48895
|
+
role: "assistant",
|
|
48896
|
+
content: `<generate-pdf>
|
|
48897
|
+
{"path": "docs/report.pdf", "content": "# Project Report\\n\\n## Overview\\n\\nThis document summarizes the project.\\n\\n## Details\\n\\nMore content here."}
|
|
48898
|
+
</generate-pdf>`
|
|
48899
|
+
},
|
|
48900
|
+
{
|
|
48901
|
+
role: "user",
|
|
48902
|
+
content: `Here is the output from generate-pdf to docs/report.pdf:
|
|
48903
|
+
|
|
48904
|
+
PDF generated: /repo/docs/report.pdf
|
|
48905
|
+
|
|
48906
|
+
Please continue your response based on this output.`
|
|
48907
|
+
},
|
|
48908
|
+
{
|
|
48909
|
+
role: "assistant",
|
|
48910
|
+
content: "Done — the PDF report has been saved to `docs/report.pdf`."
|
|
48911
|
+
},
|
|
48912
|
+
{
|
|
48913
|
+
role: "user",
|
|
48914
|
+
content: 'grep -R "ChatRunner" -n src'
|
|
48915
|
+
},
|
|
48916
|
+
{
|
|
48917
|
+
role: "assistant",
|
|
48918
|
+
content: `<grep>
|
|
48919
|
+
{"pattern": "ChatRunner", "glob": "src/**/*"}
|
|
48920
|
+
</grep>`
|
|
48921
|
+
},
|
|
48922
|
+
{
|
|
48923
|
+
role: "user",
|
|
48924
|
+
content: `Here is the output from grep for "ChatRunner":
|
|
48925
|
+
|
|
48926
|
+
grep /ChatRunner/ src/**/* — 3 match(es) in 2 file(s)
|
|
48927
|
+
|
|
48928
|
+
src/index.tsx
|
|
48929
|
+
12: import { ChatRunner } from "./components/chat/ChatRunner";
|
|
48930
|
+
|
|
48931
|
+
src/components/chat/ChatRunner.tsx
|
|
48932
|
+
1: export const ChatRunner = ...
|
|
48933
|
+
|
|
48934
|
+
Please continue your response based on this output.`
|
|
48935
|
+
},
|
|
48936
|
+
{
|
|
48937
|
+
role: "assistant",
|
|
48938
|
+
content: "`ChatRunner` is defined in `src/components/chat/ChatRunner.tsx` and imported in `src/index.tsx`."
|
|
48939
|
+
},
|
|
48940
|
+
{
|
|
48941
|
+
role: "user",
|
|
48942
|
+
content: "find all usages of useInput in the codebase"
|
|
48943
|
+
},
|
|
48944
|
+
{
|
|
48945
|
+
role: "assistant",
|
|
48946
|
+
content: `<grep>
|
|
48947
|
+
{"pattern": "useInput", "glob": "src/**/*.tsx"}
|
|
48948
|
+
</grep>`
|
|
48949
|
+
},
|
|
48950
|
+
{
|
|
48951
|
+
role: "user",
|
|
48952
|
+
content: `Here is the output from grep for "useInput":
|
|
48953
|
+
|
|
48954
|
+
grep /useInput/ src/**/*.tsx — 2 match(es) in 1 file(s)
|
|
48955
|
+
|
|
48956
|
+
src/components/chat/ChatRunner.tsx
|
|
48957
|
+
5: import { useInput } from "ink";
|
|
48958
|
+
210: useInput((input, key) => {
|
|
48959
|
+
|
|
48960
|
+
Please continue your response based on this output.`
|
|
48961
|
+
},
|
|
48962
|
+
{
|
|
48963
|
+
role: "assistant",
|
|
48964
|
+
content: "`useInput` is used in `src/components/chat/ChatRunner.tsx` — imported on line 5 and called on line 210."
|
|
48965
|
+
},
|
|
48966
|
+
{
|
|
48967
|
+
role: "user",
|
|
48968
|
+
content: "show me how to use the read-file tool"
|
|
48969
|
+
},
|
|
48970
|
+
{
|
|
48971
|
+
role: "assistant",
|
|
48972
|
+
content: "To read a file, emit the tag alone in your response — nothing else on that turn:\n\n```text\n[read-file]src/components/Header.tsx[/read-file]\n```\n\nThe result comes back as the next user message and you can then analyze it."
|
|
48973
|
+
},
|
|
48974
|
+
{
|
|
48975
|
+
role: "user",
|
|
48976
|
+
content: "show me an example of the shell tool"
|
|
48977
|
+
},
|
|
48978
|
+
{
|
|
48979
|
+
role: "assistant",
|
|
48980
|
+
content: "To run a shell command, emit only the tag:\n\n```text\n[shell]node -v[/shell]\n```\n\nThe stdout/stderr is returned and you can read it in the next turn."
|
|
48981
|
+
},
|
|
48982
|
+
{
|
|
48983
|
+
role: "user",
|
|
48984
|
+
content: "read src folder"
|
|
48985
|
+
},
|
|
48986
|
+
{
|
|
48987
|
+
role: "assistant",
|
|
48988
|
+
content: "<read-folder>src</read-folder>"
|
|
48989
|
+
},
|
|
48990
|
+
{
|
|
48991
|
+
role: "user",
|
|
48992
|
+
content: `Here is the output from read-folder of src:
|
|
48993
|
+
|
|
48994
|
+
Folder: src (4 entries)
|
|
48995
|
+
|
|
48996
|
+
Files:
|
|
48997
|
+
index.ts
|
|
48998
|
+
App.tsx
|
|
48999
|
+
|
|
49000
|
+
Subfolders:
|
|
49001
|
+
components/
|
|
49002
|
+
utils/
|
|
49003
|
+
|
|
49004
|
+
Please continue your response based on this output.`
|
|
49005
|
+
},
|
|
49006
|
+
{
|
|
49007
|
+
role: "assistant",
|
|
49008
|
+
content: "The `src` folder contains `index.ts`, `App.tsx`, plus subfolders `components/` and `utils/`."
|
|
49009
|
+
},
|
|
49010
|
+
{
|
|
49011
|
+
role: "user",
|
|
49012
|
+
content: "list src folder"
|
|
49013
|
+
},
|
|
49014
|
+
{
|
|
49015
|
+
role: "assistant",
|
|
49016
|
+
content: "<read-folder>src</read-folder>"
|
|
49017
|
+
},
|
|
49018
|
+
{
|
|
49019
|
+
role: "user",
|
|
49020
|
+
content: `Here is the output from read-folder of src:
|
|
49021
|
+
|
|
49022
|
+
Folder: src (4 entries)
|
|
49023
|
+
|
|
49024
|
+
Files:
|
|
49025
|
+
index.ts
|
|
49026
|
+
App.tsx
|
|
49027
|
+
|
|
49028
|
+
Subfolders:
|
|
49029
|
+
components/
|
|
49030
|
+
utils/
|
|
49031
|
+
|
|
49032
|
+
Please continue your response based on this output.`
|
|
49033
|
+
},
|
|
49034
|
+
{
|
|
49035
|
+
role: "assistant",
|
|
49036
|
+
content: "The `src` folder contains `index.ts`, `App.tsx`, plus subfolders `components/` and `utils/`."
|
|
49037
|
+
},
|
|
49038
|
+
{
|
|
49039
|
+
role: "user",
|
|
49040
|
+
content: "what files are in src/components?"
|
|
49041
|
+
},
|
|
49042
|
+
{
|
|
49043
|
+
role: "assistant",
|
|
49044
|
+
content: "<read-folder>src/components</read-folder>"
|
|
49045
|
+
},
|
|
49046
|
+
{
|
|
49047
|
+
role: "user",
|
|
49048
|
+
content: `Here is the output from read-folder of src/components:
|
|
49049
|
+
|
|
49050
|
+
Folder: src/components (5 entries)
|
|
49051
|
+
|
|
49052
|
+
Files:
|
|
49053
|
+
Header.tsx
|
|
49054
|
+
Footer.tsx
|
|
49055
|
+
Button.tsx
|
|
49056
|
+
|
|
49057
|
+
Subfolders:
|
|
49058
|
+
ui/
|
|
49059
|
+
forms/
|
|
49060
|
+
|
|
49061
|
+
Please continue your response based on this output.`
|
|
49062
|
+
},
|
|
49063
|
+
{
|
|
49064
|
+
role: "assistant",
|
|
49065
|
+
content: "The `src/components` folder has 3 files — `Header.tsx`, `Footer.tsx`, `Button.tsx` — plus two subfolders: `ui/` and `forms/`."
|
|
49066
|
+
},
|
|
49067
|
+
{
|
|
49068
|
+
role: "user",
|
|
49069
|
+
content: "list the files in src/utils"
|
|
49070
|
+
},
|
|
49071
|
+
{
|
|
49072
|
+
role: "assistant",
|
|
49073
|
+
content: "<read-folder>src/utils</read-folder>"
|
|
49074
|
+
},
|
|
49075
|
+
{
|
|
49076
|
+
role: "user",
|
|
49077
|
+
content: `Here is the output from read-folder of src/utils:
|
|
49078
|
+
|
|
49079
|
+
Folder: src/utils (3 entries)
|
|
49080
|
+
|
|
49081
|
+
Files:
|
|
49082
|
+
api.ts
|
|
49083
|
+
helpers.ts
|
|
49084
|
+
format.ts
|
|
49085
|
+
|
|
49086
|
+
Please continue your response based on this output.`
|
|
49087
|
+
},
|
|
49088
|
+
{
|
|
49089
|
+
role: "assistant",
|
|
49090
|
+
content: "The `src/utils` folder contains 3 files: `api.ts`, `helpers.ts`, and `format.ts`."
|
|
49091
|
+
},
|
|
49092
|
+
{
|
|
49093
|
+
role: "user",
|
|
49094
|
+
content: "show me what's in the src directory"
|
|
49095
|
+
},
|
|
49096
|
+
{
|
|
49097
|
+
role: "assistant",
|
|
49098
|
+
content: "<read-folder>src</read-folder>"
|
|
49099
|
+
},
|
|
49100
|
+
{
|
|
49101
|
+
role: "user",
|
|
49102
|
+
content: `Here is the output from read-folder of src:
|
|
49103
|
+
|
|
49104
|
+
Folder: src (4 entries)
|
|
49105
|
+
|
|
49106
|
+
Files:
|
|
49107
|
+
index.ts
|
|
49108
|
+
App.tsx
|
|
49109
|
+
|
|
49110
|
+
Subfolders:
|
|
49111
|
+
components/
|
|
49112
|
+
utils/
|
|
49113
|
+
|
|
49114
|
+
Please continue your response based on this output.`
|
|
49115
|
+
},
|
|
49116
|
+
{
|
|
49117
|
+
role: "assistant",
|
|
49118
|
+
content: "The `src` directory has 2 files (`index.ts`, `App.tsx`) and 2 subfolders (`components/`, `utils/`)."
|
|
49119
|
+
},
|
|
49120
|
+
{
|
|
49121
|
+
role: "user",
|
|
49122
|
+
content: "show me the project structure"
|
|
49123
|
+
},
|
|
49124
|
+
{
|
|
49125
|
+
role: "assistant",
|
|
49126
|
+
content: "<read-folder>.</read-folder>"
|
|
49127
|
+
},
|
|
49128
|
+
{
|
|
49129
|
+
role: "user",
|
|
49130
|
+
content: `Here is the output from read-folder of .:
|
|
49131
|
+
|
|
49132
|
+
Folder: . (5 entries)
|
|
49133
|
+
|
|
49134
|
+
Files:
|
|
49135
|
+
package.json
|
|
49136
|
+
tsconfig.json
|
|
49137
|
+
README.md
|
|
49138
|
+
|
|
49139
|
+
Subfolders:
|
|
49140
|
+
src/
|
|
49141
|
+
node_modules/
|
|
49142
|
+
|
|
49143
|
+
Please continue your response based on this output.`
|
|
49144
|
+
},
|
|
49145
|
+
{
|
|
49146
|
+
role: "assistant",
|
|
49147
|
+
content: "The project root has 3 files (`package.json`, `tsconfig.json`, `README.md`) and the `src/` folder for source code."
|
|
49148
|
+
},
|
|
49149
|
+
{
|
|
49150
|
+
role: "user",
|
|
49151
|
+
content: "what does the project look like?"
|
|
49152
|
+
},
|
|
49153
|
+
{
|
|
49154
|
+
role: "assistant",
|
|
49155
|
+
content: "<read-folder>.</read-folder>"
|
|
49156
|
+
},
|
|
49157
|
+
{
|
|
49158
|
+
role: "user",
|
|
49159
|
+
content: `Here is the output from read-folder of .:
|
|
49160
|
+
|
|
49161
|
+
Folder: . (4 entries)
|
|
49162
|
+
|
|
49163
|
+
Files:
|
|
49164
|
+
package.json
|
|
49165
|
+
README.md
|
|
49166
|
+
|
|
49167
|
+
Subfolders:
|
|
49168
|
+
src/
|
|
49169
|
+
dist/
|
|
49170
|
+
|
|
49171
|
+
Please continue your response based on this output.`
|
|
49172
|
+
},
|
|
49173
|
+
{
|
|
49174
|
+
role: "assistant",
|
|
49175
|
+
content: "The repo root contains `package.json` and `README.md`, with source code in `src/` and compiled output in `dist/`."
|
|
49176
|
+
},
|
|
48726
49177
|
{
|
|
48727
49178
|
role: "user",
|
|
48728
49179
|
content: "fetch https://api.github.com/repos/microsoft/typescript"
|
|
@@ -48763,21 +49214,54 @@ Please continue your response based on this output.`
|
|
|
48763
49214
|
},
|
|
48764
49215
|
{
|
|
48765
49216
|
role: "assistant",
|
|
48766
|
-
content: "
|
|
49217
|
+
content: "Done — `ts-info.json` has been saved."
|
|
49218
|
+
},
|
|
49219
|
+
{
|
|
49220
|
+
role: "user",
|
|
49221
|
+
content: "write it to a file called hello.py"
|
|
49222
|
+
},
|
|
49223
|
+
{
|
|
49224
|
+
role: "assistant",
|
|
49225
|
+
content: `<write-file>
|
|
49226
|
+
{"path": "hello.py", "content": "# hello.py\\nprint('hello')"}
|
|
49227
|
+
</write-file>`
|
|
49228
|
+
},
|
|
49229
|
+
{
|
|
49230
|
+
role: "user",
|
|
49231
|
+
content: `Here is the output from write-file to hello.py:
|
|
49232
|
+
|
|
49233
|
+
Written: /repo/hello.py (2 lines, 32 bytes)
|
|
49234
|
+
|
|
49235
|
+
Please continue your response based on this output.`
|
|
49236
|
+
},
|
|
49237
|
+
{
|
|
49238
|
+
role: "assistant",
|
|
49239
|
+
content: "Done — `hello.py` has been written."
|
|
49240
|
+
},
|
|
49241
|
+
{
|
|
49242
|
+
role: "user",
|
|
49243
|
+
content: "add a logout button to src/components/Header.tsx"
|
|
49244
|
+
},
|
|
49245
|
+
{
|
|
49246
|
+
role: "assistant",
|
|
49247
|
+
content: "<read-file>src/components/Header.tsx</read-file>"
|
|
48767
49248
|
},
|
|
48768
49249
|
{
|
|
48769
49250
|
role: "user",
|
|
48770
|
-
content: `Here is the output from read-file of
|
|
49251
|
+
content: `Here is the output from read-file of src/components/Header.tsx:
|
|
48771
49252
|
|
|
48772
|
-
File:
|
|
49253
|
+
File: src/components/Header.tsx (42 lines)
|
|
48773
49254
|
|
|
48774
|
-
|
|
49255
|
+
import React from 'react';
|
|
49256
|
+
// ... full file content ...
|
|
48775
49257
|
|
|
48776
49258
|
Please continue your response based on this output.`
|
|
48777
49259
|
},
|
|
48778
49260
|
{
|
|
48779
49261
|
role: "assistant",
|
|
48780
|
-
content:
|
|
49262
|
+
content: `<changes>
|
|
49263
|
+
{"summary": "Add logout button to Header — preserves all existing nav items and imports", "patches": [{"path": "src/components/Header.tsx", "content": "// complete file with logout button added", "isNew": false}]}
|
|
49264
|
+
</changes>`
|
|
48781
49265
|
},
|
|
48782
49266
|
{
|
|
48783
49267
|
role: "user",
|
|
@@ -48837,11 +49321,21 @@ Please continue your response based on this output.`
|
|
|
48837
49321
|
}
|
|
48838
49322
|
];
|
|
48839
49323
|
function parseResponse(text) {
|
|
49324
|
+
const scanText = text.replace(/```[\s\S]*?```/g, (m) => " ".repeat(m.length));
|
|
48840
49325
|
const candidates = [];
|
|
48841
49326
|
const patterns = [
|
|
48842
49327
|
{ kind: "fetch", re: /<fetch>([\s\S]*?)<\/fetch>/g },
|
|
48843
49328
|
{ kind: "shell", re: /<shell>([\s\S]*?)<\/shell>/g },
|
|
48844
49329
|
{ kind: "read-file", re: /<read-file>([\s\S]*?)<\/read-file>/g },
|
|
49330
|
+
{ kind: "read-folder", re: /<read-folder>([\s\S]*?)<\/read-folder>/g },
|
|
49331
|
+
{ kind: "grep", re: /<grep>([\s\S]*?)<\/grep>/g },
|
|
49332
|
+
{ kind: "delete-file", re: /<delete-file>([\s\S]*?)<\/delete-file>/g },
|
|
49333
|
+
{
|
|
49334
|
+
kind: "delete-folder",
|
|
49335
|
+
re: /<delete-folder>([\s\S]*?)<\/delete-folder>/g
|
|
49336
|
+
},
|
|
49337
|
+
{ kind: "open-url", re: /<open-url>([\s\S]*?)<\/open-url>/g },
|
|
49338
|
+
{ kind: "generate-pdf", re: /<generate-pdf>([\s\S]*?)<\/generate-pdf>/g },
|
|
48845
49339
|
{ kind: "write-file", re: /<write-file>([\s\S]*?)<\/write-file>/g },
|
|
48846
49340
|
{ kind: "search", re: /<search>([\s\S]*?)<\/search>/g },
|
|
48847
49341
|
{ kind: "clone", re: /<clone>([\s\S]*?)<\/clone>/g },
|
|
@@ -48849,22 +49343,32 @@ function parseResponse(text) {
|
|
|
48849
49343
|
{ kind: "fetch", re: /```fetch\r?\n([\s\S]*?)\r?\n```/g },
|
|
48850
49344
|
{ kind: "shell", re: /```shell\r?\n([\s\S]*?)\r?\n```/g },
|
|
48851
49345
|
{ kind: "read-file", re: /```read-file\r?\n([\s\S]*?)\r?\n```/g },
|
|
49346
|
+
{ kind: "read-folder", re: /```read-folder\r?\n([\s\S]*?)\r?\n```/g },
|
|
48852
49347
|
{ kind: "write-file", re: /```write-file\r?\n([\s\S]*?)\r?\n```/g },
|
|
48853
49348
|
{ kind: "search", re: /```search\r?\n([\s\S]*?)\r?\n```/g },
|
|
48854
49349
|
{ kind: "changes", re: /```changes\r?\n([\s\S]*?)\r?\n```/g }
|
|
48855
49350
|
];
|
|
48856
49351
|
for (const { kind: kind2, re } of patterns) {
|
|
48857
49352
|
re.lastIndex = 0;
|
|
48858
|
-
const m = re.exec(
|
|
48859
|
-
if (m)
|
|
48860
|
-
|
|
49353
|
+
const m = re.exec(scanText);
|
|
49354
|
+
if (m) {
|
|
49355
|
+
const originalRe = new RegExp(re.source, re.flags.replace("g", ""));
|
|
49356
|
+
const originalMatch = originalRe.exec(text.slice(m.index));
|
|
49357
|
+
if (originalMatch) {
|
|
49358
|
+
const fakeMatch = Object.assign([
|
|
49359
|
+
text.slice(m.index, m.index + originalMatch[0].length),
|
|
49360
|
+
originalMatch[1]
|
|
49361
|
+
], { index: m.index, input: text, groups: undefined });
|
|
49362
|
+
candidates.push({ index: m.index, kind: kind2, match: fakeMatch });
|
|
49363
|
+
}
|
|
49364
|
+
}
|
|
48861
49365
|
}
|
|
48862
49366
|
if (candidates.length === 0)
|
|
48863
49367
|
return { kind: "text", content: text.trim() };
|
|
48864
49368
|
candidates.sort((a, b) => a.index - b.index);
|
|
48865
49369
|
const { kind, match } = candidates[0];
|
|
48866
|
-
const before2 = text.slice(0, match.index).trim();
|
|
48867
|
-
const body = match[1].trim();
|
|
49370
|
+
const before2 = text.slice(0, match.index).replace(/<(fetch|shell|read-file|read-folder|write-file|search|clone|changes)[^>]*>[\s\S]*?<\/\1>/g, "").trim();
|
|
49371
|
+
const body = (match[1] ?? "").trim();
|
|
48868
49372
|
if (kind === "changes") {
|
|
48869
49373
|
try {
|
|
48870
49374
|
const parsed = JSON.parse(body);
|
|
@@ -48882,6 +49386,42 @@ function parseResponse(text) {
|
|
|
48882
49386
|
}
|
|
48883
49387
|
if (kind === "read-file")
|
|
48884
49388
|
return { kind: "read-file", content: before2, filePath: body };
|
|
49389
|
+
if (kind === "read-folder")
|
|
49390
|
+
return { kind: "read-folder", content: before2, folderPath: body };
|
|
49391
|
+
if (kind === "delete-file")
|
|
49392
|
+
return { kind: "delete-file", content: before2, filePath: body };
|
|
49393
|
+
if (kind === "delete-folder")
|
|
49394
|
+
return { kind: "delete-folder", content: before2, folderPath: body };
|
|
49395
|
+
if (kind === "open-url") {
|
|
49396
|
+
const url = body.replace(/^<|>$/g, "").trim();
|
|
49397
|
+
return { kind: "open-url", content: before2, url };
|
|
49398
|
+
}
|
|
49399
|
+
if (kind === "generate-pdf") {
|
|
49400
|
+
try {
|
|
49401
|
+
const parsed = JSON.parse(body);
|
|
49402
|
+
return {
|
|
49403
|
+
kind: "generate-pdf",
|
|
49404
|
+
content: before2,
|
|
49405
|
+
filePath: parsed.path ?? parsed.filePath ?? "output.pdf",
|
|
49406
|
+
pdfContent: parsed.content ?? ""
|
|
49407
|
+
};
|
|
49408
|
+
} catch {
|
|
49409
|
+
return { kind: "text", content: text };
|
|
49410
|
+
}
|
|
49411
|
+
}
|
|
49412
|
+
if (kind === "grep") {
|
|
49413
|
+
try {
|
|
49414
|
+
const parsed = JSON.parse(body);
|
|
49415
|
+
return {
|
|
49416
|
+
kind: "grep",
|
|
49417
|
+
content: before2,
|
|
49418
|
+
pattern: parsed.pattern,
|
|
49419
|
+
glob: parsed.glob ?? "**/*"
|
|
49420
|
+
};
|
|
49421
|
+
} catch {
|
|
49422
|
+
return { kind: "grep", content: before2, pattern: body, glob: "**/*" };
|
|
49423
|
+
}
|
|
49424
|
+
}
|
|
48885
49425
|
if (kind === "write-file") {
|
|
48886
49426
|
try {
|
|
48887
49427
|
const parsed = JSON.parse(body);
|
|
@@ -48918,7 +49458,7 @@ function buildApiMessages(messages) {
|
|
|
48918
49458
|
content: "The tool call was denied by the user. Please respond without using that tool."
|
|
48919
49459
|
};
|
|
48920
49460
|
}
|
|
48921
|
-
const label = m.toolName === "shell" ? `shell command \`${m.content}\`` : m.toolName === "fetch" ? `fetch of ${m.content}` : m.toolName === "read-file" ? `read-file of ${m.content}` : m.toolName === "search" ? `web search for "${m.content}"` : `write-file to ${m.content}`;
|
|
49461
|
+
const label = m.toolName === "shell" ? `shell command \`${m.content}\`` : m.toolName === "fetch" ? `fetch of ${m.content}` : m.toolName === "read-file" ? `read-file of ${m.content}` : m.toolName === "read-folder" ? `read-folder of ${m.content}` : m.toolName === "grep" ? `grep for "${m.content}"` : m.toolName === "delete-file" ? `delete-file of ${m.content}` : m.toolName === "delete-folder" ? `delete-folder of ${m.content}` : m.toolName === "open-url" ? `open-url ${m.content}` : m.toolName === "generate-pdf" ? `generate-pdf to ${m.content}` : m.toolName === "search" ? `web search for "${m.content}"` : `write-file to ${m.content}`;
|
|
48922
49462
|
return {
|
|
48923
49463
|
role: "user",
|
|
48924
49464
|
content: `Here is the output from the ${label}:
|
|
@@ -48931,7 +49471,7 @@ Please continue your response based on this output.`
|
|
|
48931
49471
|
return { role: m.role, content: m.content };
|
|
48932
49472
|
});
|
|
48933
49473
|
}
|
|
48934
|
-
async function callChat(provider, systemPrompt, messages) {
|
|
49474
|
+
async function callChat(provider, systemPrompt, messages, abortSignal) {
|
|
48935
49475
|
const apiMessages = [...FEW_SHOT_MESSAGES, ...buildApiMessages(messages)];
|
|
48936
49476
|
let url;
|
|
48937
49477
|
let headers;
|
|
@@ -48964,6 +49504,7 @@ async function callChat(provider, systemPrompt, messages) {
|
|
|
48964
49504
|
}
|
|
48965
49505
|
const controller = new AbortController;
|
|
48966
49506
|
const timer = setTimeout(() => controller.abort(), 60000);
|
|
49507
|
+
abortSignal?.addEventListener("abort", () => controller.abort());
|
|
48967
49508
|
const res = await fetch(url, {
|
|
48968
49509
|
method: "POST",
|
|
48969
49510
|
headers,
|
|
@@ -49237,164 +49778,1315 @@ ${topics}`);
|
|
|
49237
49778
|
if (snippets.length === 0 && links.length === 0) {
|
|
49238
49779
|
return `No results found for: ${query}`;
|
|
49239
49780
|
}
|
|
49240
|
-
const parts = [`Search results for: ${query}`];
|
|
49241
|
-
if (snippets.length > 0)
|
|
49242
|
-
parts.push(`Snippets:
|
|
49243
|
-
${snippets.join(`
|
|
49244
|
-
`)}`);
|
|
49245
|
-
if (links.length > 0)
|
|
49246
|
-
parts.push(`Links:
|
|
49247
|
-
${links.join(`
|
|
49248
|
-
`)}`);
|
|
49249
|
-
return parts.join(`
|
|
49250
|
-
|
|
49251
|
-
`);
|
|
49252
|
-
} catch (err) {
|
|
49253
|
-
return `Search failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
49254
|
-
}
|
|
49781
|
+
const parts = [`Search results for: ${query}`];
|
|
49782
|
+
if (snippets.length > 0)
|
|
49783
|
+
parts.push(`Snippets:
|
|
49784
|
+
${snippets.join(`
|
|
49785
|
+
`)}`);
|
|
49786
|
+
if (links.length > 0)
|
|
49787
|
+
parts.push(`Links:
|
|
49788
|
+
${links.join(`
|
|
49789
|
+
`)}`);
|
|
49790
|
+
return parts.join(`
|
|
49791
|
+
|
|
49792
|
+
`);
|
|
49793
|
+
} catch (err) {
|
|
49794
|
+
return `Search failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
49795
|
+
}
|
|
49796
|
+
}
|
|
49797
|
+
function readFile(filePath, repoPath) {
|
|
49798
|
+
const candidates = path14.isAbsolute(filePath) ? [filePath] : [filePath, path14.join(repoPath, filePath)];
|
|
49799
|
+
for (const candidate of candidates) {
|
|
49800
|
+
if (existsSync10(candidate)) {
|
|
49801
|
+
try {
|
|
49802
|
+
const content = readFileSync10(candidate, "utf-8");
|
|
49803
|
+
const lines = content.split(`
|
|
49804
|
+
`).length;
|
|
49805
|
+
return `File: ${candidate} (${lines} lines)
|
|
49806
|
+
|
|
49807
|
+
${content.slice(0, 8000)}${content.length > 8000 ? `
|
|
49808
|
+
|
|
49809
|
+
… (truncated)` : ""}`;
|
|
49810
|
+
} catch (err) {
|
|
49811
|
+
return `Error reading file: ${err instanceof Error ? err.message : String(err)}`;
|
|
49812
|
+
}
|
|
49813
|
+
}
|
|
49814
|
+
}
|
|
49815
|
+
return `File not found: ${filePath}. If reading from a cloned repo, use the full absolute path e.g. C:\\Users\\...\\repo\\file.ts`;
|
|
49816
|
+
}
|
|
49817
|
+
function readFolder(folderPath, repoPath) {
|
|
49818
|
+
const sanitized = folderPath.replace(/^(ls|dir|find|tree|cat|read|ls -la?|ls -al?)\s+/i, "").trim();
|
|
49819
|
+
const candidates = path14.isAbsolute(sanitized) ? [sanitized] : [sanitized, path14.join(repoPath, sanitized)];
|
|
49820
|
+
for (const candidate of candidates) {
|
|
49821
|
+
if (!existsSync10(candidate))
|
|
49822
|
+
continue;
|
|
49823
|
+
let stat;
|
|
49824
|
+
try {
|
|
49825
|
+
stat = statSync4(candidate);
|
|
49826
|
+
} catch {
|
|
49827
|
+
continue;
|
|
49828
|
+
}
|
|
49829
|
+
if (!stat.isDirectory()) {
|
|
49830
|
+
return `Not a directory: ${candidate}. Use read-file to read a file.`;
|
|
49831
|
+
}
|
|
49832
|
+
let entries;
|
|
49833
|
+
try {
|
|
49834
|
+
entries = readdirSync3(candidate, { encoding: "utf-8" });
|
|
49835
|
+
} catch (err) {
|
|
49836
|
+
return `Error reading folder: ${err instanceof Error ? err.message : String(err)}`;
|
|
49837
|
+
}
|
|
49838
|
+
const files = [];
|
|
49839
|
+
const subfolders = [];
|
|
49840
|
+
for (const entry of entries) {
|
|
49841
|
+
if (entry.startsWith(".") && entry !== ".env")
|
|
49842
|
+
continue;
|
|
49843
|
+
const full = path14.join(candidate, entry);
|
|
49844
|
+
try {
|
|
49845
|
+
if (statSync4(full).isDirectory()) {
|
|
49846
|
+
subfolders.push(`${entry}/`);
|
|
49847
|
+
} else {
|
|
49848
|
+
files.push(entry);
|
|
49849
|
+
}
|
|
49850
|
+
} catch {}
|
|
49851
|
+
}
|
|
49852
|
+
const total = files.length + subfolders.length;
|
|
49853
|
+
const lines = [`Folder: ${candidate} (${total} entries)`, ""];
|
|
49854
|
+
if (files.length > 0) {
|
|
49855
|
+
lines.push("Files:");
|
|
49856
|
+
files.forEach((f) => lines.push(` ${f}`));
|
|
49857
|
+
}
|
|
49858
|
+
if (subfolders.length > 0) {
|
|
49859
|
+
if (files.length > 0)
|
|
49860
|
+
lines.push("");
|
|
49861
|
+
lines.push("Subfolders:");
|
|
49862
|
+
subfolders.forEach((d) => lines.push(` ${d}`));
|
|
49863
|
+
}
|
|
49864
|
+
if (total === 0) {
|
|
49865
|
+
lines.push("(empty folder)");
|
|
49866
|
+
}
|
|
49867
|
+
return lines.join(`
|
|
49868
|
+
`);
|
|
49869
|
+
}
|
|
49870
|
+
return `Folder not found: ${sanitized}`;
|
|
49871
|
+
}
|
|
49872
|
+
function grepFiles(pattern, glob, repoPath) {
|
|
49873
|
+
let regex2;
|
|
49874
|
+
try {
|
|
49875
|
+
regex2 = new RegExp(pattern, "i");
|
|
49876
|
+
} catch {
|
|
49877
|
+
regex2 = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
|
|
49878
|
+
}
|
|
49879
|
+
const globToFilter = (g) => {
|
|
49880
|
+
const cleaned = g.replace(/^\*\*\//, "");
|
|
49881
|
+
const parts = cleaned.split("/");
|
|
49882
|
+
const ext = parts[parts.length - 1];
|
|
49883
|
+
const prefix = parts.slice(0, -1).join("/");
|
|
49884
|
+
return (rel) => {
|
|
49885
|
+
if (ext?.startsWith("*.")) {
|
|
49886
|
+
const extSuffix = ext.slice(1);
|
|
49887
|
+
if (!rel.endsWith(extSuffix))
|
|
49888
|
+
return false;
|
|
49889
|
+
} else if (ext && !ext.includes("*")) {
|
|
49890
|
+
if (!rel.endsWith(ext))
|
|
49891
|
+
return false;
|
|
49892
|
+
}
|
|
49893
|
+
if (prefix && !prefix.includes("*")) {
|
|
49894
|
+
if (!rel.startsWith(prefix))
|
|
49895
|
+
return false;
|
|
49896
|
+
}
|
|
49897
|
+
return true;
|
|
49898
|
+
};
|
|
49899
|
+
};
|
|
49900
|
+
const filter2 = globToFilter(glob);
|
|
49901
|
+
const allFiles = walkDir3(repoPath);
|
|
49902
|
+
const matchedFiles = allFiles.filter(filter2);
|
|
49903
|
+
if (matchedFiles.length === 0) {
|
|
49904
|
+
return `No files matched glob: ${glob}`;
|
|
49905
|
+
}
|
|
49906
|
+
const results = [];
|
|
49907
|
+
let totalMatches = 0;
|
|
49908
|
+
for (const relPath of matchedFiles) {
|
|
49909
|
+
const fullPath = path14.join(repoPath, relPath);
|
|
49910
|
+
let content;
|
|
49911
|
+
try {
|
|
49912
|
+
content = readFileSync10(fullPath, "utf-8");
|
|
49913
|
+
} catch {
|
|
49914
|
+
continue;
|
|
49915
|
+
}
|
|
49916
|
+
const lines = content.split(`
|
|
49917
|
+
`);
|
|
49918
|
+
const fileMatches = [];
|
|
49919
|
+
lines.forEach((line, i) => {
|
|
49920
|
+
if (regex2.test(line)) {
|
|
49921
|
+
fileMatches.push(` ${i + 1}: ${line.trimEnd()}`);
|
|
49922
|
+
totalMatches++;
|
|
49923
|
+
}
|
|
49924
|
+
});
|
|
49925
|
+
if (fileMatches.length > 0) {
|
|
49926
|
+
results.push(`${relPath}
|
|
49927
|
+
${fileMatches.join(`
|
|
49928
|
+
`)}`);
|
|
49929
|
+
}
|
|
49930
|
+
if (totalMatches >= 200) {
|
|
49931
|
+
results.push("(truncated — too many matches)");
|
|
49932
|
+
break;
|
|
49933
|
+
}
|
|
49934
|
+
}
|
|
49935
|
+
if (results.length === 0) {
|
|
49936
|
+
return `No matches for /${pattern}/ in ${matchedFiles.length} file(s) matching ${glob}`;
|
|
49937
|
+
}
|
|
49938
|
+
return `grep /${pattern}/ ${glob} — ${totalMatches} match(es) in ${results.length} file(s)
|
|
49939
|
+
|
|
49940
|
+
${results.join(`
|
|
49941
|
+
|
|
49942
|
+
`)}`;
|
|
49943
|
+
}
|
|
49944
|
+
function writeFile(filePath, content, repoPath) {
|
|
49945
|
+
const fullPath = path14.isAbsolute(filePath) ? filePath : path14.join(repoPath, filePath);
|
|
49946
|
+
try {
|
|
49947
|
+
const dir = path14.dirname(fullPath);
|
|
49948
|
+
if (!existsSync10(dir))
|
|
49949
|
+
mkdirSync4(dir, { recursive: true });
|
|
49950
|
+
writeFileSync6(fullPath, content, "utf-8");
|
|
49951
|
+
const lines = content.split(`
|
|
49952
|
+
`).length;
|
|
49953
|
+
return `Written: ${fullPath} (${lines} lines, ${content.length} bytes)`;
|
|
49954
|
+
} catch (err) {
|
|
49955
|
+
return `Error writing file: ${err instanceof Error ? err.message : String(err)}`;
|
|
49956
|
+
}
|
|
49957
|
+
}
|
|
49958
|
+
function deleteFile(filePath, repoPath) {
|
|
49959
|
+
const fullPath = path14.isAbsolute(filePath) ? filePath : path14.join(repoPath, filePath);
|
|
49960
|
+
try {
|
|
49961
|
+
if (!existsSync10(fullPath))
|
|
49962
|
+
return `File not found: ${fullPath}`;
|
|
49963
|
+
const { unlinkSync } = __require("fs");
|
|
49964
|
+
unlinkSync(fullPath);
|
|
49965
|
+
return `Deleted: ${fullPath}`;
|
|
49966
|
+
} catch (err) {
|
|
49967
|
+
return `Error deleting file: ${err instanceof Error ? err.message : String(err)}`;
|
|
49968
|
+
}
|
|
49969
|
+
}
|
|
49970
|
+
function deleteFolder(folderPath, repoPath) {
|
|
49971
|
+
const fullPath = path14.isAbsolute(folderPath) ? folderPath : path14.join(repoPath, folderPath);
|
|
49972
|
+
try {
|
|
49973
|
+
if (!existsSync10(fullPath))
|
|
49974
|
+
return `Folder not found: ${fullPath}`;
|
|
49975
|
+
const { rmSync } = __require("fs");
|
|
49976
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
49977
|
+
return `Deleted folder: ${fullPath}`;
|
|
49978
|
+
} catch (err) {
|
|
49979
|
+
return `Error deleting folder: ${err instanceof Error ? err.message : String(err)}`;
|
|
49980
|
+
}
|
|
49981
|
+
}
|
|
49982
|
+
function openUrl(url) {
|
|
49983
|
+
try {
|
|
49984
|
+
const { execSync: execSync2 } = __require("child_process");
|
|
49985
|
+
const platform2 = process.platform;
|
|
49986
|
+
if (platform2 === "win32") {
|
|
49987
|
+
execSync2(`start "" "${url}"`, { stdio: "ignore" });
|
|
49988
|
+
} else if (platform2 === "darwin") {
|
|
49989
|
+
execSync2(`open "${url}"`, { stdio: "ignore" });
|
|
49990
|
+
} else {
|
|
49991
|
+
execSync2(`xdg-open "${url}"`, { stdio: "ignore" });
|
|
49992
|
+
}
|
|
49993
|
+
return `Opened: ${url}`;
|
|
49994
|
+
} catch (err) {
|
|
49995
|
+
return `Error opening URL: ${err instanceof Error ? err.message : String(err)}`;
|
|
49996
|
+
}
|
|
49997
|
+
}
|
|
49998
|
+
function generatePdf(filePath, content, repoPath) {
|
|
49999
|
+
const fullPath = path14.isAbsolute(filePath) ? filePath : path14.join(repoPath, filePath);
|
|
50000
|
+
try {
|
|
50001
|
+
const dir = path14.dirname(fullPath);
|
|
50002
|
+
if (!existsSync10(dir))
|
|
50003
|
+
mkdirSync4(dir, { recursive: true });
|
|
50004
|
+
const escaped = content.replace(/\\/g, "\\\\").replace(/"""/g, "\\\"\\\"\\\"").replace(/\r/g, "");
|
|
50005
|
+
const script = `
|
|
50006
|
+
import sys
|
|
50007
|
+
try:
|
|
50008
|
+
from reportlab.lib.pagesizes import letter
|
|
50009
|
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, HRFlowable
|
|
50010
|
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
50011
|
+
from reportlab.lib.units import inch
|
|
50012
|
+
from reportlab.lib import colors
|
|
50013
|
+
except ImportError:
|
|
50014
|
+
import subprocess
|
|
50015
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "reportlab", "--break-system-packages", "-q"])
|
|
50016
|
+
from reportlab.lib.pagesizes import letter
|
|
50017
|
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, HRFlowable
|
|
50018
|
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
50019
|
+
from reportlab.lib.units import inch
|
|
50020
|
+
from reportlab.lib import colors
|
|
50021
|
+
|
|
50022
|
+
doc = SimpleDocTemplate(
|
|
50023
|
+
r"""${fullPath}""",
|
|
50024
|
+
pagesize=letter,
|
|
50025
|
+
rightMargin=inch,
|
|
50026
|
+
leftMargin=inch,
|
|
50027
|
+
topMargin=inch,
|
|
50028
|
+
bottomMargin=inch,
|
|
50029
|
+
)
|
|
50030
|
+
|
|
50031
|
+
styles = getSampleStyleSheet()
|
|
50032
|
+
styles.add(ParagraphStyle(name="H1", parent=styles["Heading1"], fontSize=22, spaceAfter=10))
|
|
50033
|
+
styles.add(ParagraphStyle(name="H2", parent=styles["Heading2"], fontSize=16, spaceAfter=8))
|
|
50034
|
+
styles.add(ParagraphStyle(name="H3", parent=styles["Heading3"], fontSize=13, spaceAfter=6))
|
|
50035
|
+
styles.add(ParagraphStyle(name="Body", parent=styles["Normal"], fontSize=11, leading=16, spaceAfter=8))
|
|
50036
|
+
styles.add(ParagraphStyle(name="Bullet", parent=styles["Normal"], fontSize=11, leading=16, leftIndent=20, spaceAfter=4, bulletIndent=10))
|
|
50037
|
+
|
|
50038
|
+
raw = """${escaped}"""
|
|
50039
|
+
|
|
50040
|
+
story = []
|
|
50041
|
+
for line in raw.split("\\n"):
|
|
50042
|
+
s = line.rstrip()
|
|
50043
|
+
if s.startswith("### "):
|
|
50044
|
+
story.append(Paragraph(s[4:], styles["H3"]))
|
|
50045
|
+
elif s.startswith("## "):
|
|
50046
|
+
story.append(Spacer(1, 6))
|
|
50047
|
+
story.append(Paragraph(s[3:], styles["H2"]))
|
|
50048
|
+
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.grey, spaceAfter=4))
|
|
50049
|
+
elif s.startswith("# "):
|
|
50050
|
+
story.append(Paragraph(s[2:], styles["H1"]))
|
|
50051
|
+
story.append(HRFlowable(width="100%", thickness=1, color=colors.black, spaceAfter=6))
|
|
50052
|
+
elif s.startswith("- ") or s.startswith("* "):
|
|
50053
|
+
story.append(Paragraph(u"\\u2022 " + s[2:], styles["Bullet"]))
|
|
50054
|
+
elif s.startswith("---"):
|
|
50055
|
+
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.grey, spaceAfter=4))
|
|
50056
|
+
elif s == "":
|
|
50057
|
+
story.append(Spacer(1, 6))
|
|
50058
|
+
else:
|
|
50059
|
+
import re
|
|
50060
|
+
s = re.sub(r"\\*\\*(.+?)\\*\\*", r"<b>\\1</b>", s)
|
|
50061
|
+
s = re.sub(r"\\*(.+?)\\*", r"<i>\\1</i>", s)
|
|
50062
|
+
s = re.sub(r"\`(.+?)\`", r"<font name='Courier'>\\1</font>", s)
|
|
50063
|
+
story.append(Paragraph(s, styles["Body"]))
|
|
50064
|
+
|
|
50065
|
+
doc.build(story)
|
|
50066
|
+
print("OK")
|
|
50067
|
+
`.replace("${fullPath}", fullPath.replace(/\\/g, "/")).replace("${escaped}", escaped);
|
|
50068
|
+
const os6 = __require("os");
|
|
50069
|
+
const tmpFile = path14.join(os6.tmpdir(), `lens_pdf_${Date.now()}.py`);
|
|
50070
|
+
writeFileSync6(tmpFile, script, "utf-8");
|
|
50071
|
+
const { execSync: execSync2 } = __require("child_process");
|
|
50072
|
+
execSync2(`python "${tmpFile}"`, { stdio: "pipe" });
|
|
50073
|
+
try {
|
|
50074
|
+
__require("fs").unlinkSync(tmpFile);
|
|
50075
|
+
} catch {}
|
|
50076
|
+
return `PDF generated: ${fullPath}`;
|
|
50077
|
+
} catch (err) {
|
|
50078
|
+
return `Error generating PDF: ${err instanceof Error ? err.message : String(err)}`;
|
|
50079
|
+
}
|
|
50080
|
+
}
|
|
50081
|
+
|
|
50082
|
+
// node_modules/sugar-high/lib/index.js
|
|
50083
|
+
var JSXBrackets = new Set(["<", ">", "{", "}", "[", "]"]);
|
|
50084
|
+
var Keywords_Js = new Set([
|
|
50085
|
+
"for",
|
|
50086
|
+
"do",
|
|
50087
|
+
"while",
|
|
50088
|
+
"if",
|
|
50089
|
+
"else",
|
|
50090
|
+
"return",
|
|
50091
|
+
"function",
|
|
50092
|
+
"var",
|
|
50093
|
+
"let",
|
|
50094
|
+
"const",
|
|
50095
|
+
"true",
|
|
50096
|
+
"false",
|
|
50097
|
+
"undefined",
|
|
50098
|
+
"this",
|
|
50099
|
+
"new",
|
|
50100
|
+
"delete",
|
|
50101
|
+
"typeof",
|
|
50102
|
+
"in",
|
|
50103
|
+
"instanceof",
|
|
50104
|
+
"void",
|
|
50105
|
+
"break",
|
|
50106
|
+
"continue",
|
|
50107
|
+
"switch",
|
|
50108
|
+
"case",
|
|
50109
|
+
"default",
|
|
50110
|
+
"throw",
|
|
50111
|
+
"try",
|
|
50112
|
+
"catch",
|
|
50113
|
+
"finally",
|
|
50114
|
+
"debugger",
|
|
50115
|
+
"with",
|
|
50116
|
+
"yield",
|
|
50117
|
+
"async",
|
|
50118
|
+
"await",
|
|
50119
|
+
"class",
|
|
50120
|
+
"extends",
|
|
50121
|
+
"super",
|
|
50122
|
+
"import",
|
|
50123
|
+
"export",
|
|
50124
|
+
"from",
|
|
50125
|
+
"static"
|
|
50126
|
+
]);
|
|
50127
|
+
var Signs = new Set([
|
|
50128
|
+
"+",
|
|
50129
|
+
"-",
|
|
50130
|
+
"*",
|
|
50131
|
+
"/",
|
|
50132
|
+
"%",
|
|
50133
|
+
"=",
|
|
50134
|
+
"!",
|
|
50135
|
+
"&",
|
|
50136
|
+
"|",
|
|
50137
|
+
"^",
|
|
50138
|
+
"~",
|
|
50139
|
+
"!",
|
|
50140
|
+
"?",
|
|
50141
|
+
":",
|
|
50142
|
+
".",
|
|
50143
|
+
",",
|
|
50144
|
+
";",
|
|
50145
|
+
`'`,
|
|
50146
|
+
'"',
|
|
50147
|
+
".",
|
|
50148
|
+
"(",
|
|
50149
|
+
")",
|
|
50150
|
+
"[",
|
|
50151
|
+
"]",
|
|
50152
|
+
"#",
|
|
50153
|
+
"@",
|
|
50154
|
+
"\\",
|
|
50155
|
+
...JSXBrackets
|
|
50156
|
+
]);
|
|
50157
|
+
var DefaultOptions = {
|
|
50158
|
+
keywords: Keywords_Js,
|
|
50159
|
+
onCommentStart: isCommentStart_Js,
|
|
50160
|
+
onCommentEnd: isCommentEnd_Js
|
|
50161
|
+
};
|
|
50162
|
+
var TokenTypes = [
|
|
50163
|
+
"identifier",
|
|
50164
|
+
"keyword",
|
|
50165
|
+
"string",
|
|
50166
|
+
"class",
|
|
50167
|
+
"property",
|
|
50168
|
+
"entity",
|
|
50169
|
+
"jsxliterals",
|
|
50170
|
+
"sign",
|
|
50171
|
+
"comment",
|
|
50172
|
+
"break",
|
|
50173
|
+
"space"
|
|
50174
|
+
];
|
|
50175
|
+
var [
|
|
50176
|
+
T_IDENTIFIER,
|
|
50177
|
+
T_KEYWORD,
|
|
50178
|
+
T_STRING,
|
|
50179
|
+
T_CLS_NUMBER,
|
|
50180
|
+
T_PROPERTY,
|
|
50181
|
+
T_ENTITY,
|
|
50182
|
+
T_JSX_LITERALS,
|
|
50183
|
+
T_SIGN,
|
|
50184
|
+
T_COMMENT,
|
|
50185
|
+
T_BREAK,
|
|
50186
|
+
T_SPACE
|
|
50187
|
+
] = TokenTypes.map((_, i) => i);
|
|
50188
|
+
function isSpaces(str) {
|
|
50189
|
+
return /^[^\S\r\n]+$/g.test(str);
|
|
50190
|
+
}
|
|
50191
|
+
function isSign(ch) {
|
|
50192
|
+
return Signs.has(ch);
|
|
50193
|
+
}
|
|
50194
|
+
function isWord(chr) {
|
|
50195
|
+
return /^[\w_]+$/.test(chr) || hasUnicode(chr);
|
|
50196
|
+
}
|
|
50197
|
+
function isCls(str) {
|
|
50198
|
+
const chr0 = str[0];
|
|
50199
|
+
return isWord(chr0) && chr0 === chr0.toUpperCase() || str === "null";
|
|
50200
|
+
}
|
|
50201
|
+
function hasUnicode(s) {
|
|
50202
|
+
return /[^\u0000-\u007f]/.test(s);
|
|
50203
|
+
}
|
|
50204
|
+
function isAlpha(chr) {
|
|
50205
|
+
return /^[a-zA-Z]$/.test(chr);
|
|
50206
|
+
}
|
|
50207
|
+
function isIdentifierChar(chr) {
|
|
50208
|
+
return isAlpha(chr) || hasUnicode(chr);
|
|
50209
|
+
}
|
|
50210
|
+
function isIdentifier(str) {
|
|
50211
|
+
return isIdentifierChar(str[0]) && (str.length === 1 || isWord(str.slice(1)));
|
|
50212
|
+
}
|
|
50213
|
+
function isStrTemplateChr(chr) {
|
|
50214
|
+
return chr === "`";
|
|
50215
|
+
}
|
|
50216
|
+
function isSingleQuotes(chr) {
|
|
50217
|
+
return chr === '"' || chr === "'";
|
|
50218
|
+
}
|
|
50219
|
+
function isStringQuotation(chr) {
|
|
50220
|
+
return isSingleQuotes(chr) || isStrTemplateChr(chr);
|
|
50221
|
+
}
|
|
50222
|
+
function isCommentStart_Js(curr, next) {
|
|
50223
|
+
const str = curr + next;
|
|
50224
|
+
if (str === "/*")
|
|
50225
|
+
return 2;
|
|
50226
|
+
return str === "//" ? 1 : 0;
|
|
50227
|
+
}
|
|
50228
|
+
function isCommentEnd_Js(prev, curr) {
|
|
50229
|
+
return prev + curr === "*/" ? 2 : curr === `
|
|
50230
|
+
` ? 1 : 0;
|
|
50231
|
+
}
|
|
50232
|
+
function isRegexStart(str) {
|
|
50233
|
+
return str[0] === "/" && !isCommentStart_Js(str[0], str[1]);
|
|
50234
|
+
}
|
|
50235
|
+
function tokenize3(code, options) {
|
|
50236
|
+
const {
|
|
50237
|
+
keywords,
|
|
50238
|
+
onCommentStart,
|
|
50239
|
+
onCommentEnd
|
|
50240
|
+
} = { ...DefaultOptions, ...options };
|
|
50241
|
+
let current = "";
|
|
50242
|
+
let type = -1;
|
|
50243
|
+
let last2 = [-1, ""];
|
|
50244
|
+
let beforeLast = [-2, ""];
|
|
50245
|
+
const tokens = [];
|
|
50246
|
+
let __jsxEnter = false;
|
|
50247
|
+
let __jsxTag = 0;
|
|
50248
|
+
let __jsxExpr = false;
|
|
50249
|
+
let __jsxStack = 0;
|
|
50250
|
+
const __jsxChild = () => __jsxEnter && !__jsxExpr && !__jsxTag;
|
|
50251
|
+
const inJsxTag = () => __jsxTag && !__jsxChild();
|
|
50252
|
+
const inJsxLiterals = () => !__jsxTag && __jsxChild() && !__jsxExpr && __jsxStack > 0;
|
|
50253
|
+
let __strQuote = null;
|
|
50254
|
+
let __regexQuoteStart = false;
|
|
50255
|
+
let __strTemplateExprStack = 0;
|
|
50256
|
+
let __strTemplateQuoteStack = 0;
|
|
50257
|
+
const inStringQuotes = () => __strQuote !== null;
|
|
50258
|
+
const inRegexQuotes = () => __regexQuoteStart;
|
|
50259
|
+
const inStrTemplateLiterals = () => __strTemplateQuoteStack > __strTemplateExprStack;
|
|
50260
|
+
const inStrTemplateExpr = () => __strTemplateQuoteStack > 0 && __strTemplateQuoteStack === __strTemplateExprStack;
|
|
50261
|
+
const inStringContent = () => inStringQuotes() || inStrTemplateLiterals();
|
|
50262
|
+
function classify(token) {
|
|
50263
|
+
const isLineBreak = token === `
|
|
50264
|
+
`;
|
|
50265
|
+
if (inJsxTag()) {
|
|
50266
|
+
if (inStringQuotes()) {
|
|
50267
|
+
return T_STRING;
|
|
50268
|
+
}
|
|
50269
|
+
const [, lastToken] = last2;
|
|
50270
|
+
if (isIdentifier(token)) {
|
|
50271
|
+
if (lastToken === "<" || lastToken === "</")
|
|
50272
|
+
return T_ENTITY;
|
|
50273
|
+
}
|
|
50274
|
+
}
|
|
50275
|
+
const isJsxLiterals = inJsxLiterals();
|
|
50276
|
+
if (isJsxLiterals)
|
|
50277
|
+
return T_JSX_LITERALS;
|
|
50278
|
+
if (inStringQuotes() || inStrTemplateLiterals()) {
|
|
50279
|
+
return T_STRING;
|
|
50280
|
+
} else if (keywords.has(token)) {
|
|
50281
|
+
return last2[1] === "." ? T_IDENTIFIER : T_KEYWORD;
|
|
50282
|
+
} else if (isLineBreak) {
|
|
50283
|
+
return T_BREAK;
|
|
50284
|
+
} else if (isSpaces(token)) {
|
|
50285
|
+
return T_SPACE;
|
|
50286
|
+
} else if (token.split("").every(isSign)) {
|
|
50287
|
+
return T_SIGN;
|
|
50288
|
+
} else if (isCls(token)) {
|
|
50289
|
+
return inJsxTag() ? T_IDENTIFIER : T_CLS_NUMBER;
|
|
50290
|
+
} else {
|
|
50291
|
+
if (isIdentifier(token)) {
|
|
50292
|
+
const isLastPropDot = last2[1] === "." && isIdentifier(beforeLast[1]);
|
|
50293
|
+
if (!inStringContent() && !isLastPropDot)
|
|
50294
|
+
return T_IDENTIFIER;
|
|
50295
|
+
if (isLastPropDot)
|
|
50296
|
+
return T_PROPERTY;
|
|
50297
|
+
}
|
|
50298
|
+
return T_STRING;
|
|
50299
|
+
}
|
|
50300
|
+
}
|
|
50301
|
+
const append = (type_, token_) => {
|
|
50302
|
+
if (token_) {
|
|
50303
|
+
current = token_;
|
|
50304
|
+
}
|
|
50305
|
+
if (current) {
|
|
50306
|
+
type = type_ || classify(current);
|
|
50307
|
+
const pair = [type, current];
|
|
50308
|
+
if (type !== T_SPACE && type !== T_BREAK) {
|
|
50309
|
+
beforeLast = last2;
|
|
50310
|
+
last2 = pair;
|
|
50311
|
+
}
|
|
50312
|
+
tokens.push(pair);
|
|
50313
|
+
}
|
|
50314
|
+
current = "";
|
|
50315
|
+
};
|
|
50316
|
+
for (let i = 0;i < code.length; i++) {
|
|
50317
|
+
const curr = code[i];
|
|
50318
|
+
const prev = code[i - 1];
|
|
50319
|
+
const next = code[i + 1];
|
|
50320
|
+
const p_c = prev + curr;
|
|
50321
|
+
const c_n = curr + next;
|
|
50322
|
+
if (isSingleQuotes(curr) && !inJsxLiterals() && !inStrTemplateLiterals()) {
|
|
50323
|
+
append();
|
|
50324
|
+
if (prev !== `\\`) {
|
|
50325
|
+
if (__strQuote && curr === __strQuote) {
|
|
50326
|
+
__strQuote = null;
|
|
50327
|
+
} else if (!__strQuote) {
|
|
50328
|
+
__strQuote = curr;
|
|
50329
|
+
}
|
|
50330
|
+
}
|
|
50331
|
+
append(T_STRING, curr);
|
|
50332
|
+
continue;
|
|
50333
|
+
}
|
|
50334
|
+
if (!inStrTemplateLiterals()) {
|
|
50335
|
+
if (prev !== "\\n" && isStrTemplateChr(curr)) {
|
|
50336
|
+
append();
|
|
50337
|
+
append(T_STRING, curr);
|
|
50338
|
+
__strTemplateQuoteStack++;
|
|
50339
|
+
continue;
|
|
50340
|
+
}
|
|
50341
|
+
}
|
|
50342
|
+
if (inStrTemplateLiterals()) {
|
|
50343
|
+
if (prev !== "\\n" && isStrTemplateChr(curr)) {
|
|
50344
|
+
if (__strTemplateQuoteStack > 0) {
|
|
50345
|
+
append();
|
|
50346
|
+
__strTemplateQuoteStack--;
|
|
50347
|
+
append(T_STRING, curr);
|
|
50348
|
+
continue;
|
|
50349
|
+
}
|
|
50350
|
+
}
|
|
50351
|
+
if (c_n === "${") {
|
|
50352
|
+
__strTemplateExprStack++;
|
|
50353
|
+
append(T_STRING);
|
|
50354
|
+
append(T_SIGN, c_n);
|
|
50355
|
+
i++;
|
|
50356
|
+
continue;
|
|
50357
|
+
}
|
|
50358
|
+
}
|
|
50359
|
+
if (inStrTemplateExpr() && curr === "}") {
|
|
50360
|
+
append();
|
|
50361
|
+
__strTemplateExprStack--;
|
|
50362
|
+
append(T_SIGN, curr);
|
|
50363
|
+
continue;
|
|
50364
|
+
}
|
|
50365
|
+
if (__jsxChild()) {
|
|
50366
|
+
if (curr === "{") {
|
|
50367
|
+
append();
|
|
50368
|
+
append(T_SIGN, curr);
|
|
50369
|
+
__jsxExpr = true;
|
|
50370
|
+
continue;
|
|
50371
|
+
}
|
|
50372
|
+
}
|
|
50373
|
+
if (__jsxEnter) {
|
|
50374
|
+
if (!__jsxTag && curr === "<") {
|
|
50375
|
+
append();
|
|
50376
|
+
if (next === "/") {
|
|
50377
|
+
__jsxTag = 2;
|
|
50378
|
+
current = c_n;
|
|
50379
|
+
i++;
|
|
50380
|
+
} else {
|
|
50381
|
+
__jsxTag = 1;
|
|
50382
|
+
current = curr;
|
|
50383
|
+
}
|
|
50384
|
+
append(T_SIGN);
|
|
50385
|
+
continue;
|
|
50386
|
+
}
|
|
50387
|
+
if (__jsxTag) {
|
|
50388
|
+
if (curr === ">" && !"/=".includes(prev)) {
|
|
50389
|
+
append();
|
|
50390
|
+
if (__jsxTag === 1) {
|
|
50391
|
+
__jsxTag = 0;
|
|
50392
|
+
__jsxStack++;
|
|
50393
|
+
} else {
|
|
50394
|
+
__jsxTag = 0;
|
|
50395
|
+
__jsxEnter = false;
|
|
50396
|
+
}
|
|
50397
|
+
append(T_SIGN, curr);
|
|
50398
|
+
continue;
|
|
50399
|
+
}
|
|
50400
|
+
if (c_n === "/>" || c_n === "</") {
|
|
50401
|
+
if (current !== "<" && current !== "/") {
|
|
50402
|
+
append();
|
|
50403
|
+
}
|
|
50404
|
+
if (c_n === "/>") {
|
|
50405
|
+
__jsxTag = 0;
|
|
50406
|
+
} else {
|
|
50407
|
+
__jsxStack--;
|
|
50408
|
+
}
|
|
50409
|
+
if (!__jsxStack)
|
|
50410
|
+
__jsxEnter = false;
|
|
50411
|
+
current = c_n;
|
|
50412
|
+
i++;
|
|
50413
|
+
append(T_SIGN);
|
|
50414
|
+
continue;
|
|
50415
|
+
}
|
|
50416
|
+
if (curr === "<") {
|
|
50417
|
+
append();
|
|
50418
|
+
current = curr;
|
|
50419
|
+
append(T_SIGN);
|
|
50420
|
+
continue;
|
|
50421
|
+
}
|
|
50422
|
+
if (next === "-" && !inStringContent() && !inJsxLiterals()) {
|
|
50423
|
+
if (current) {
|
|
50424
|
+
append(T_PROPERTY, current + curr + next);
|
|
50425
|
+
i++;
|
|
50426
|
+
continue;
|
|
50427
|
+
}
|
|
50428
|
+
}
|
|
50429
|
+
if (next === "=" && !inStringContent()) {
|
|
50430
|
+
if (!isSpaces(curr)) {
|
|
50431
|
+
if (isSpaces(current)) {
|
|
50432
|
+
append();
|
|
50433
|
+
}
|
|
50434
|
+
const prop = current + curr;
|
|
50435
|
+
if (isIdentifier(prop)) {
|
|
50436
|
+
append(T_PROPERTY, prop);
|
|
50437
|
+
continue;
|
|
50438
|
+
}
|
|
50439
|
+
}
|
|
50440
|
+
}
|
|
50441
|
+
}
|
|
50442
|
+
}
|
|
50443
|
+
if (!__jsxTag && (curr === "<" && isIdentifierChar(next) || c_n === "</")) {
|
|
50444
|
+
__jsxTag = next === "/" ? 2 : 1;
|
|
50445
|
+
if (curr === "<" && (next === "/" || isAlpha(next))) {
|
|
50446
|
+
if (!inStringContent() && !inJsxLiterals() && !inRegexQuotes()) {
|
|
50447
|
+
__jsxEnter = true;
|
|
50448
|
+
}
|
|
50449
|
+
}
|
|
50450
|
+
}
|
|
50451
|
+
const isQuotationChar = isStringQuotation(curr);
|
|
50452
|
+
const isStringTemplateLiterals = inStrTemplateLiterals();
|
|
50453
|
+
const isRegexChar = !__jsxEnter && isRegexStart(c_n);
|
|
50454
|
+
const isJsxLiterals = inJsxLiterals();
|
|
50455
|
+
if (isQuotationChar || isStringTemplateLiterals || isSingleQuotes(__strQuote)) {
|
|
50456
|
+
current += curr;
|
|
50457
|
+
} else if (isRegexChar) {
|
|
50458
|
+
append();
|
|
50459
|
+
const [lastType, lastToken] = last2;
|
|
50460
|
+
if (isRegexChar && lastType !== -1 && !(lastType === T_SIGN && lastToken !== ")" || lastType === T_COMMENT)) {
|
|
50461
|
+
current = curr;
|
|
50462
|
+
append();
|
|
50463
|
+
continue;
|
|
50464
|
+
}
|
|
50465
|
+
__regexQuoteStart = true;
|
|
50466
|
+
const start = i++;
|
|
50467
|
+
const isEof = () => i >= code.length;
|
|
50468
|
+
const isEol = () => isEof() || code[i] === `
|
|
50469
|
+
`;
|
|
50470
|
+
let foundClose = false;
|
|
50471
|
+
for (;!isEol(); i++) {
|
|
50472
|
+
if (code[i] === "/" && code[i - 1] !== "\\") {
|
|
50473
|
+
foundClose = true;
|
|
50474
|
+
while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
|
|
50475
|
+
i++;
|
|
50476
|
+
}
|
|
50477
|
+
break;
|
|
50478
|
+
}
|
|
50479
|
+
}
|
|
50480
|
+
__regexQuoteStart = false;
|
|
50481
|
+
if (start !== i && foundClose) {
|
|
50482
|
+
current = code.slice(start, i + 1);
|
|
50483
|
+
append(T_STRING);
|
|
50484
|
+
} else {
|
|
50485
|
+
current = curr;
|
|
50486
|
+
append();
|
|
50487
|
+
i = start;
|
|
50488
|
+
}
|
|
50489
|
+
} else if (onCommentStart(curr, next)) {
|
|
50490
|
+
append();
|
|
50491
|
+
const start = i;
|
|
50492
|
+
const startCommentType = onCommentStart(curr, next);
|
|
50493
|
+
if (startCommentType) {
|
|
50494
|
+
for (;i < code.length; i++) {
|
|
50495
|
+
const endCommentType = onCommentEnd(code[i - 1], code[i]);
|
|
50496
|
+
if (endCommentType == startCommentType)
|
|
50497
|
+
break;
|
|
50498
|
+
}
|
|
50499
|
+
}
|
|
50500
|
+
current = code.slice(start, i + 1);
|
|
50501
|
+
append(T_COMMENT);
|
|
50502
|
+
} else if (curr === " " || curr === `
|
|
50503
|
+
`) {
|
|
50504
|
+
if (curr === " " && (isSpaces(current) || !current || isJsxLiterals)) {
|
|
50505
|
+
current += curr;
|
|
50506
|
+
if (next === "<") {
|
|
50507
|
+
append();
|
|
50508
|
+
}
|
|
50509
|
+
} else {
|
|
50510
|
+
append();
|
|
50511
|
+
current = curr;
|
|
50512
|
+
append();
|
|
50513
|
+
}
|
|
50514
|
+
} else {
|
|
50515
|
+
if (__jsxExpr && curr === "}") {
|
|
50516
|
+
append();
|
|
50517
|
+
current = curr;
|
|
50518
|
+
append();
|
|
50519
|
+
__jsxExpr = false;
|
|
50520
|
+
} else if (isJsxLiterals && !JSXBrackets.has(curr) || inStrTemplateLiterals() || (isWord(curr) === isWord(current[current.length - 1]) || __jsxChild()) && !Signs.has(curr)) {
|
|
50521
|
+
current += curr;
|
|
50522
|
+
} else {
|
|
50523
|
+
if (p_c === "</") {
|
|
50524
|
+
current = p_c;
|
|
50525
|
+
}
|
|
50526
|
+
append();
|
|
50527
|
+
if (p_c !== "</") {
|
|
50528
|
+
current = curr;
|
|
50529
|
+
}
|
|
50530
|
+
if (c_n === "</" || c_n === "/>") {
|
|
50531
|
+
current = c_n;
|
|
50532
|
+
append();
|
|
50533
|
+
i++;
|
|
50534
|
+
} else if (JSXBrackets.has(curr))
|
|
50535
|
+
append();
|
|
50536
|
+
}
|
|
50537
|
+
}
|
|
50538
|
+
}
|
|
50539
|
+
append();
|
|
50540
|
+
return tokens;
|
|
50541
|
+
}
|
|
50542
|
+
var SugarHigh = {
|
|
50543
|
+
TokenTypes,
|
|
50544
|
+
TokenMap: new Map(TokenTypes.map((type, i) => [type, i]))
|
|
50545
|
+
};
|
|
50546
|
+
|
|
50547
|
+
// src/components/chat/ChatMessage.tsx
|
|
50548
|
+
var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
|
|
50549
|
+
var T_IDENTIFIER2 = 0;
|
|
50550
|
+
var T_KEYWORD2 = 1;
|
|
50551
|
+
var T_STRING2 = 2;
|
|
50552
|
+
var T_CLS_NUMBER2 = 3;
|
|
50553
|
+
var T_PROPERTY2 = 4;
|
|
50554
|
+
var T_ENTITY2 = 5;
|
|
50555
|
+
var T_JSX_LITERAL = 6;
|
|
50556
|
+
var T_SIGN2 = 7;
|
|
50557
|
+
var T_COMMENT2 = 8;
|
|
50558
|
+
var T_BREAK2 = 9;
|
|
50559
|
+
var T_SPACE2 = 10;
|
|
50560
|
+
var JS_LANGS = new Set([
|
|
50561
|
+
"js",
|
|
50562
|
+
"javascript",
|
|
50563
|
+
"jsx",
|
|
50564
|
+
"ts",
|
|
50565
|
+
"typescript",
|
|
50566
|
+
"tsx",
|
|
50567
|
+
"mjs",
|
|
50568
|
+
"cjs"
|
|
50569
|
+
]);
|
|
50570
|
+
function tokenColor(type) {
|
|
50571
|
+
switch (type) {
|
|
50572
|
+
case T_KEYWORD2:
|
|
50573
|
+
return TOKEN_KEYWORD;
|
|
50574
|
+
case T_STRING2:
|
|
50575
|
+
return TOKEN_STRING;
|
|
50576
|
+
case T_CLS_NUMBER2:
|
|
50577
|
+
return TOKEN_NUMBER;
|
|
50578
|
+
case T_PROPERTY2:
|
|
50579
|
+
return TOKEN_PROPERTY;
|
|
50580
|
+
case T_ENTITY2:
|
|
50581
|
+
return TOKEN_ENTITY;
|
|
50582
|
+
case T_JSX_LITERAL:
|
|
50583
|
+
return TOKEN_TEXT;
|
|
50584
|
+
case T_SIGN2:
|
|
50585
|
+
return TOKEN_MUTED;
|
|
50586
|
+
case T_COMMENT2:
|
|
50587
|
+
return TOKEN_COMMENT;
|
|
50588
|
+
case T_IDENTIFIER2:
|
|
50589
|
+
return TOKEN_TEXT;
|
|
50590
|
+
default:
|
|
50591
|
+
return TOKEN_TEXT;
|
|
50592
|
+
}
|
|
50593
|
+
}
|
|
50594
|
+
var PYTHON_KW = new Set([
|
|
50595
|
+
"def",
|
|
50596
|
+
"class",
|
|
50597
|
+
"import",
|
|
50598
|
+
"from",
|
|
50599
|
+
"return",
|
|
50600
|
+
"if",
|
|
50601
|
+
"elif",
|
|
50602
|
+
"else",
|
|
50603
|
+
"for",
|
|
50604
|
+
"while",
|
|
50605
|
+
"in",
|
|
50606
|
+
"not",
|
|
50607
|
+
"and",
|
|
50608
|
+
"or",
|
|
50609
|
+
"is",
|
|
50610
|
+
"None",
|
|
50611
|
+
"True",
|
|
50612
|
+
"False",
|
|
50613
|
+
"try",
|
|
50614
|
+
"except",
|
|
50615
|
+
"finally",
|
|
50616
|
+
"with",
|
|
50617
|
+
"as",
|
|
50618
|
+
"pass",
|
|
50619
|
+
"break",
|
|
50620
|
+
"continue",
|
|
50621
|
+
"raise",
|
|
50622
|
+
"yield",
|
|
50623
|
+
"lambda",
|
|
50624
|
+
"async",
|
|
50625
|
+
"await",
|
|
50626
|
+
"del",
|
|
50627
|
+
"global",
|
|
50628
|
+
"nonlocal",
|
|
50629
|
+
"assert"
|
|
50630
|
+
]);
|
|
50631
|
+
var RUST_KW = new Set([
|
|
50632
|
+
"fn",
|
|
50633
|
+
"let",
|
|
50634
|
+
"mut",
|
|
50635
|
+
"const",
|
|
50636
|
+
"struct",
|
|
50637
|
+
"enum",
|
|
50638
|
+
"impl",
|
|
50639
|
+
"trait",
|
|
50640
|
+
"pub",
|
|
50641
|
+
"use",
|
|
50642
|
+
"mod",
|
|
50643
|
+
"match",
|
|
50644
|
+
"if",
|
|
50645
|
+
"else",
|
|
50646
|
+
"loop",
|
|
50647
|
+
"while",
|
|
50648
|
+
"for",
|
|
50649
|
+
"in",
|
|
50650
|
+
"return",
|
|
50651
|
+
"self",
|
|
50652
|
+
"Self",
|
|
50653
|
+
"super",
|
|
50654
|
+
"where",
|
|
50655
|
+
"type",
|
|
50656
|
+
"as",
|
|
50657
|
+
"ref",
|
|
50658
|
+
"move",
|
|
50659
|
+
"unsafe",
|
|
50660
|
+
"extern",
|
|
50661
|
+
"dyn",
|
|
50662
|
+
"async",
|
|
50663
|
+
"await",
|
|
50664
|
+
"true",
|
|
50665
|
+
"false",
|
|
50666
|
+
"Some",
|
|
50667
|
+
"None",
|
|
50668
|
+
"Ok",
|
|
50669
|
+
"Err"
|
|
50670
|
+
]);
|
|
50671
|
+
var GO_KW = new Set([
|
|
50672
|
+
"func",
|
|
50673
|
+
"var",
|
|
50674
|
+
"const",
|
|
50675
|
+
"type",
|
|
50676
|
+
"struct",
|
|
50677
|
+
"interface",
|
|
50678
|
+
"package",
|
|
50679
|
+
"import",
|
|
50680
|
+
"return",
|
|
50681
|
+
"if",
|
|
50682
|
+
"else",
|
|
50683
|
+
"for",
|
|
50684
|
+
"range",
|
|
50685
|
+
"switch",
|
|
50686
|
+
"case",
|
|
50687
|
+
"default",
|
|
50688
|
+
"break",
|
|
50689
|
+
"continue",
|
|
50690
|
+
"goto",
|
|
50691
|
+
"defer",
|
|
50692
|
+
"go",
|
|
50693
|
+
"chan",
|
|
50694
|
+
"map",
|
|
50695
|
+
"make",
|
|
50696
|
+
"new",
|
|
50697
|
+
"nil",
|
|
50698
|
+
"true",
|
|
50699
|
+
"false",
|
|
50700
|
+
"error"
|
|
50701
|
+
]);
|
|
50702
|
+
var SHELL_KW = new Set([
|
|
50703
|
+
"if",
|
|
50704
|
+
"then",
|
|
50705
|
+
"else",
|
|
50706
|
+
"elif",
|
|
50707
|
+
"fi",
|
|
50708
|
+
"for",
|
|
50709
|
+
"do",
|
|
50710
|
+
"done",
|
|
50711
|
+
"while",
|
|
50712
|
+
"case",
|
|
50713
|
+
"esac",
|
|
50714
|
+
"in",
|
|
50715
|
+
"function",
|
|
50716
|
+
"return",
|
|
50717
|
+
"echo",
|
|
50718
|
+
"export",
|
|
50719
|
+
"local",
|
|
50720
|
+
"source",
|
|
50721
|
+
"exit"
|
|
50722
|
+
]);
|
|
50723
|
+
var CSS_AT = /^@[\w-]+/;
|
|
50724
|
+
var CSS_PROP = /^[\w-]+(?=\s*:)/;
|
|
50725
|
+
function tokenizeGeneric(code, lang) {
|
|
50726
|
+
const keywords = lang === "python" || lang === "py" ? PYTHON_KW : lang === "rust" || lang === "rs" ? RUST_KW : lang === "go" ? GO_KW : lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh" ? SHELL_KW : new Set;
|
|
50727
|
+
const lines = code.split(`
|
|
50728
|
+
`);
|
|
50729
|
+
return lines.map((line) => {
|
|
50730
|
+
const tokens = [];
|
|
50731
|
+
let i = 0;
|
|
50732
|
+
const push = (color, text) => {
|
|
50733
|
+
if (text)
|
|
50734
|
+
tokens.push({ color, text });
|
|
50735
|
+
};
|
|
50736
|
+
while (i < line.length) {
|
|
50737
|
+
const rest2 = line.slice(i);
|
|
50738
|
+
const commentPrefixes = lang === "python" || lang === "py" ? ["#"] : lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh" ? ["#"] : lang === "css" || lang === "scss" ? ["//", "/*"] : lang === "html" || lang === "xml" ? ["<!--"] : lang === "sql" ? ["--", "#"] : ["//", "#"];
|
|
50739
|
+
let matchedComment = false;
|
|
50740
|
+
for (const prefix of commentPrefixes) {
|
|
50741
|
+
if (rest2.startsWith(prefix)) {
|
|
50742
|
+
push(TOKEN_COMMENT, line.slice(i));
|
|
50743
|
+
i = line.length;
|
|
50744
|
+
matchedComment = true;
|
|
50745
|
+
break;
|
|
50746
|
+
}
|
|
50747
|
+
}
|
|
50748
|
+
if (matchedComment)
|
|
50749
|
+
continue;
|
|
50750
|
+
if (line[i] === '"' || line[i] === "'" || line[i] === "`") {
|
|
50751
|
+
const quote = line[i];
|
|
50752
|
+
let j = i + 1;
|
|
50753
|
+
while (j < line.length) {
|
|
50754
|
+
if (line[j] === "\\") {
|
|
50755
|
+
j += 2;
|
|
50756
|
+
continue;
|
|
50757
|
+
}
|
|
50758
|
+
if (line[j] === quote) {
|
|
50759
|
+
j++;
|
|
50760
|
+
break;
|
|
50761
|
+
}
|
|
50762
|
+
j++;
|
|
50763
|
+
}
|
|
50764
|
+
push(TOKEN_STRING, line.slice(i, j));
|
|
50765
|
+
i = j;
|
|
50766
|
+
continue;
|
|
50767
|
+
}
|
|
50768
|
+
const numMatch = rest2.match(/^-?\d+\.?\d*/);
|
|
50769
|
+
if (numMatch && (i === 0 || !/\w/.test(line[i - 1] ?? ""))) {
|
|
50770
|
+
push(TOKEN_NUMBER, numMatch[0]);
|
|
50771
|
+
i += numMatch[0].length;
|
|
50772
|
+
continue;
|
|
50773
|
+
}
|
|
50774
|
+
if (lang === "css" || lang === "scss") {
|
|
50775
|
+
const atMatch = rest2.match(CSS_AT);
|
|
50776
|
+
if (atMatch) {
|
|
50777
|
+
push(TOKEN_KEYWORD, atMatch[0]);
|
|
50778
|
+
i += atMatch[0].length;
|
|
50779
|
+
continue;
|
|
50780
|
+
}
|
|
50781
|
+
const propMatch = rest2.match(CSS_PROP);
|
|
50782
|
+
if (propMatch) {
|
|
50783
|
+
push(TOKEN_PROPERTY, propMatch[0]);
|
|
50784
|
+
i += propMatch[0].length;
|
|
50785
|
+
continue;
|
|
50786
|
+
}
|
|
50787
|
+
}
|
|
50788
|
+
if ((lang === "html" || lang === "xml") && line[i] === "<") {
|
|
50789
|
+
const tagMatch = rest2.match(/^<\/?[\w:-]+/);
|
|
50790
|
+
if (tagMatch) {
|
|
50791
|
+
push(TOKEN_ENTITY, tagMatch[0]);
|
|
50792
|
+
i += tagMatch[0].length;
|
|
50793
|
+
continue;
|
|
50794
|
+
}
|
|
50795
|
+
}
|
|
50796
|
+
const wordMatch = rest2.match(/^[a-zA-Z_$][\w$]*/);
|
|
50797
|
+
if (wordMatch) {
|
|
50798
|
+
const word = wordMatch[0];
|
|
50799
|
+
push(keywords.has(word) ? TOKEN_KEYWORD : TOKEN_TEXT, word);
|
|
50800
|
+
i += word.length;
|
|
50801
|
+
continue;
|
|
50802
|
+
}
|
|
50803
|
+
const opMatch = rest2.match(/^[^\w\s"'`]+/);
|
|
50804
|
+
if (opMatch) {
|
|
50805
|
+
push(TOKEN_MUTED, opMatch[0]);
|
|
50806
|
+
i += opMatch[0].length;
|
|
50807
|
+
continue;
|
|
50808
|
+
}
|
|
50809
|
+
push(TOKEN_TEXT, line[i]);
|
|
50810
|
+
i++;
|
|
50811
|
+
}
|
|
50812
|
+
return tokens;
|
|
50813
|
+
});
|
|
49255
50814
|
}
|
|
49256
|
-
function
|
|
49257
|
-
|
|
49258
|
-
|
|
49259
|
-
|
|
49260
|
-
|
|
49261
|
-
|
|
49262
|
-
|
|
49263
|
-
|
|
49264
|
-
|
|
49265
|
-
|
|
49266
|
-
|
|
49267
|
-
|
|
49268
|
-
|
|
49269
|
-
|
|
49270
|
-
|
|
50815
|
+
function HighlightedLine({ tokens }) {
|
|
50816
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50817
|
+
children: [
|
|
50818
|
+
" ",
|
|
50819
|
+
tokens.map((t, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50820
|
+
color: t.color,
|
|
50821
|
+
children: t.text
|
|
50822
|
+
}, i, false, undefined, this))
|
|
50823
|
+
]
|
|
50824
|
+
}, undefined, true, undefined, this);
|
|
50825
|
+
}
|
|
50826
|
+
function CodeBlock({ lang, code }) {
|
|
50827
|
+
const normalizedLang = lang.toLowerCase().trim();
|
|
50828
|
+
let lines;
|
|
50829
|
+
if (JS_LANGS.has(normalizedLang)) {
|
|
50830
|
+
const tokens = tokenize3(code);
|
|
50831
|
+
const lineAccum = [[]];
|
|
50832
|
+
for (const [type, value] of tokens) {
|
|
50833
|
+
if (type === T_BREAK2) {
|
|
50834
|
+
lineAccum.push([]);
|
|
50835
|
+
} else if (type !== T_SPACE2) {
|
|
50836
|
+
lineAccum[lineAccum.length - 1].push({
|
|
50837
|
+
color: tokenColor(type),
|
|
50838
|
+
text: value
|
|
50839
|
+
});
|
|
50840
|
+
} else {
|
|
50841
|
+
lineAccum[lineAccum.length - 1].push({
|
|
50842
|
+
color: TOKEN_TEXT,
|
|
50843
|
+
text: value
|
|
50844
|
+
});
|
|
49271
50845
|
}
|
|
49272
50846
|
}
|
|
50847
|
+
lines = lineAccum;
|
|
50848
|
+
} else if (normalizedLang) {
|
|
50849
|
+
lines = tokenizeGeneric(code, normalizedLang);
|
|
50850
|
+
} else {
|
|
50851
|
+
lines = code.split(`
|
|
50852
|
+
`).map((l) => [{ color: TOKEN_TEXT, text: l }]);
|
|
49273
50853
|
}
|
|
49274
|
-
return
|
|
49275
|
-
|
|
49276
|
-
|
|
49277
|
-
|
|
49278
|
-
|
|
49279
|
-
|
|
49280
|
-
|
|
49281
|
-
|
|
49282
|
-
|
|
49283
|
-
|
|
49284
|
-
|
|
49285
|
-
|
|
49286
|
-
|
|
49287
|
-
|
|
49288
|
-
}
|
|
50854
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50855
|
+
flexDirection: "column",
|
|
50856
|
+
marginY: 1,
|
|
50857
|
+
marginLeft: 2,
|
|
50858
|
+
children: [
|
|
50859
|
+
normalizedLang ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50860
|
+
color: TOKEN_MUTED,
|
|
50861
|
+
dimColor: true,
|
|
50862
|
+
children: normalizedLang
|
|
50863
|
+
}, undefined, false, undefined, this) : null,
|
|
50864
|
+
lines.map((lineTokens, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(HighlightedLine, {
|
|
50865
|
+
tokens: lineTokens
|
|
50866
|
+
}, i, false, undefined, this))
|
|
50867
|
+
]
|
|
50868
|
+
}, undefined, true, undefined, this);
|
|
49289
50869
|
}
|
|
49290
|
-
|
|
49291
|
-
// src/components/chat/ChatMessage.tsx
|
|
49292
|
-
var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
|
|
49293
50870
|
function InlineText({ text }) {
|
|
49294
|
-
const parts = text.split(/(
|
|
50871
|
+
const parts = text.split(/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g);
|
|
49295
50872
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
|
|
49296
50873
|
children: parts.map((part, i) => {
|
|
49297
|
-
if (part.startsWith("
|
|
50874
|
+
if (part.startsWith("**") && part.endsWith("**")) {
|
|
49298
50875
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49299
|
-
|
|
50876
|
+
bold: true,
|
|
50877
|
+
color: TOKEN_TEXT,
|
|
50878
|
+
children: part.slice(2, -2)
|
|
50879
|
+
}, i, false, undefined, this);
|
|
50880
|
+
}
|
|
50881
|
+
if (part.startsWith("*") && part.endsWith("*") && part.length > 2) {
|
|
50882
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50883
|
+
italic: true,
|
|
50884
|
+
color: TOKEN_TEXT,
|
|
49300
50885
|
children: part.slice(1, -1)
|
|
49301
50886
|
}, i, false, undefined, this);
|
|
49302
50887
|
}
|
|
49303
|
-
if (part.startsWith("
|
|
50888
|
+
if (part.startsWith("`") && part.endsWith("`")) {
|
|
49304
50889
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49305
|
-
|
|
49306
|
-
|
|
49307
|
-
children: part.slice(2, -2)
|
|
50890
|
+
color: ACCENT,
|
|
50891
|
+
children: part.slice(1, -1)
|
|
49308
50892
|
}, i, false, undefined, this);
|
|
49309
50893
|
}
|
|
49310
50894
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49311
|
-
color:
|
|
50895
|
+
color: TOKEN_TEXT,
|
|
49312
50896
|
children: part
|
|
49313
50897
|
}, i, false, undefined, this);
|
|
49314
50898
|
})
|
|
49315
50899
|
}, undefined, false, undefined, this);
|
|
49316
50900
|
}
|
|
49317
|
-
function
|
|
50901
|
+
function Heading({ level, text }) {
|
|
50902
|
+
if (level === 1) {
|
|
50903
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50904
|
+
marginTop: 1,
|
|
50905
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50906
|
+
color: ACCENT,
|
|
50907
|
+
bold: true,
|
|
50908
|
+
underline: true,
|
|
50909
|
+
children: text
|
|
50910
|
+
}, undefined, false, undefined, this)
|
|
50911
|
+
}, undefined, false, undefined, this);
|
|
50912
|
+
}
|
|
50913
|
+
if (level === 2) {
|
|
50914
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50915
|
+
marginTop: 1,
|
|
50916
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50917
|
+
color: ACCENT,
|
|
50918
|
+
bold: true,
|
|
50919
|
+
children: text
|
|
50920
|
+
}, undefined, false, undefined, this)
|
|
50921
|
+
}, undefined, false, undefined, this);
|
|
50922
|
+
}
|
|
49318
50923
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
49319
|
-
|
|
49320
|
-
|
|
49321
|
-
|
|
50924
|
+
marginTop: 1,
|
|
50925
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50926
|
+
color: TOKEN_TEXT,
|
|
50927
|
+
bold: true,
|
|
50928
|
+
children: text
|
|
50929
|
+
}, undefined, false, undefined, this)
|
|
50930
|
+
}, undefined, false, undefined, this);
|
|
50931
|
+
}
|
|
50932
|
+
function BulletItem({ text }) {
|
|
50933
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50934
|
+
gap: 1,
|
|
49322
50935
|
children: [
|
|
49323
|
-
|
|
49324
|
-
color: "gray",
|
|
49325
|
-
children: lang
|
|
49326
|
-
}, undefined, false, undefined, this),
|
|
49327
|
-
code.split(`
|
|
49328
|
-
`).map((line, i) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50936
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49329
50937
|
color: ACCENT,
|
|
50938
|
+
children: "*"
|
|
50939
|
+
}, undefined, false, undefined, this),
|
|
50940
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50941
|
+
flexShrink: 1,
|
|
50942
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
|
|
50943
|
+
text
|
|
50944
|
+
}, undefined, false, undefined, this)
|
|
50945
|
+
}, undefined, false, undefined, this)
|
|
50946
|
+
]
|
|
50947
|
+
}, undefined, true, undefined, this);
|
|
50948
|
+
}
|
|
50949
|
+
function NumberedItem({ num, text }) {
|
|
50950
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50951
|
+
gap: 1,
|
|
50952
|
+
children: [
|
|
50953
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50954
|
+
color: TOKEN_MUTED,
|
|
49330
50955
|
children: [
|
|
49331
|
-
|
|
49332
|
-
|
|
50956
|
+
num,
|
|
50957
|
+
"."
|
|
49333
50958
|
]
|
|
49334
|
-
},
|
|
50959
|
+
}, undefined, true, undefined, this),
|
|
50960
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
50961
|
+
flexShrink: 1,
|
|
50962
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
|
|
50963
|
+
text
|
|
50964
|
+
}, undefined, false, undefined, this)
|
|
50965
|
+
}, undefined, false, undefined, this)
|
|
49335
50966
|
]
|
|
49336
50967
|
}, undefined, true, undefined, this);
|
|
49337
50968
|
}
|
|
49338
|
-
function
|
|
49339
|
-
const segments = content.split(/(```[\s\S]*?```)/g);
|
|
50969
|
+
function BlockQuote({ text }) {
|
|
49340
50970
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
49341
|
-
|
|
49342
|
-
|
|
49343
|
-
|
|
49344
|
-
|
|
50971
|
+
gap: 1,
|
|
50972
|
+
marginLeft: 1,
|
|
50973
|
+
children: [
|
|
50974
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50975
|
+
color: TOKEN_MUTED,
|
|
50976
|
+
children: "│"
|
|
50977
|
+
}, undefined, false, undefined, this),
|
|
50978
|
+
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
50979
|
+
color: TOKEN_MUTED,
|
|
50980
|
+
dimColor: true,
|
|
50981
|
+
children: text
|
|
50982
|
+
}, undefined, false, undefined, this)
|
|
50983
|
+
]
|
|
50984
|
+
}, undefined, true, undefined, this);
|
|
50985
|
+
}
|
|
50986
|
+
function parseBlocks(content) {
|
|
50987
|
+
const blocks = [];
|
|
50988
|
+
const segments = content.split(/(```[\s\S]*?```)/g);
|
|
50989
|
+
for (const seg of segments) {
|
|
50990
|
+
if (seg.startsWith("```")) {
|
|
50991
|
+
const lines = seg.slice(3).split(`
|
|
49345
50992
|
`);
|
|
49346
|
-
|
|
49347
|
-
|
|
50993
|
+
const lang = lines[0]?.trim() ?? "";
|
|
50994
|
+
const code = lines.slice(1).join(`
|
|
49348
50995
|
`).replace(/```\s*$/, "").trimEnd();
|
|
49349
|
-
|
|
49350
|
-
|
|
49351
|
-
|
|
49352
|
-
|
|
49353
|
-
|
|
49354
|
-
const
|
|
49355
|
-
|
|
49356
|
-
|
|
49357
|
-
|
|
49358
|
-
|
|
49359
|
-
|
|
49360
|
-
|
|
49361
|
-
|
|
49362
|
-
|
|
49363
|
-
|
|
49364
|
-
|
|
49365
|
-
|
|
49366
|
-
|
|
49367
|
-
|
|
49368
|
-
|
|
49369
|
-
|
|
49370
|
-
|
|
49371
|
-
|
|
49372
|
-
|
|
49373
|
-
|
|
49374
|
-
|
|
49375
|
-
|
|
49376
|
-
|
|
49377
|
-
|
|
49378
|
-
|
|
49379
|
-
|
|
49380
|
-
|
|
49381
|
-
|
|
49382
|
-
|
|
49383
|
-
|
|
49384
|
-
|
|
49385
|
-
|
|
49386
|
-
|
|
49387
|
-
|
|
49388
|
-
|
|
49389
|
-
|
|
49390
|
-
|
|
50996
|
+
blocks.push({ type: "code", lang, code });
|
|
50997
|
+
continue;
|
|
50998
|
+
}
|
|
50999
|
+
for (const line of seg.split(`
|
|
51000
|
+
`)) {
|
|
51001
|
+
const trimmed = line.trim();
|
|
51002
|
+
if (!trimmed)
|
|
51003
|
+
continue;
|
|
51004
|
+
const h3 = trimmed.match(/^### (.+)$/);
|
|
51005
|
+
const h2 = trimmed.match(/^## (.+)$/);
|
|
51006
|
+
const h1 = trimmed.match(/^# (.+)$/);
|
|
51007
|
+
if (h3) {
|
|
51008
|
+
blocks.push({ type: "heading", level: 3, text: h3[1] });
|
|
51009
|
+
continue;
|
|
51010
|
+
}
|
|
51011
|
+
if (h2) {
|
|
51012
|
+
blocks.push({ type: "heading", level: 2, text: h2[1] });
|
|
51013
|
+
continue;
|
|
51014
|
+
}
|
|
51015
|
+
if (h1) {
|
|
51016
|
+
blocks.push({ type: "heading", level: 1, text: h1[1] });
|
|
51017
|
+
continue;
|
|
51018
|
+
}
|
|
51019
|
+
if (/^[-*_]{3,}$/.test(trimmed)) {
|
|
51020
|
+
blocks.push({ type: "hr" });
|
|
51021
|
+
continue;
|
|
51022
|
+
}
|
|
51023
|
+
if (trimmed.startsWith("> ")) {
|
|
51024
|
+
blocks.push({ type: "blockquote", text: trimmed.slice(2).trim() });
|
|
51025
|
+
continue;
|
|
51026
|
+
}
|
|
51027
|
+
if (/^[-*•]\s/.test(trimmed)) {
|
|
51028
|
+
blocks.push({ type: "bullet", text: trimmed.slice(2).trim() });
|
|
51029
|
+
continue;
|
|
51030
|
+
}
|
|
51031
|
+
const numMatch = trimmed.match(/^(\d+)\.\s(.+)/);
|
|
51032
|
+
if (numMatch) {
|
|
51033
|
+
blocks.push({
|
|
51034
|
+
type: "numbered",
|
|
51035
|
+
num: numMatch[1],
|
|
51036
|
+
text: numMatch[2]
|
|
51037
|
+
});
|
|
51038
|
+
continue;
|
|
51039
|
+
}
|
|
51040
|
+
blocks.push({ type: "paragraph", text: trimmed });
|
|
51041
|
+
}
|
|
51042
|
+
}
|
|
51043
|
+
return blocks;
|
|
51044
|
+
}
|
|
51045
|
+
function MessageBody({ content }) {
|
|
51046
|
+
const blocks = parseBlocks(content);
|
|
51047
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
51048
|
+
flexDirection: "column",
|
|
51049
|
+
children: blocks.map((block, i) => {
|
|
51050
|
+
switch (block.type) {
|
|
51051
|
+
case "heading":
|
|
51052
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Heading, {
|
|
51053
|
+
level: block.level,
|
|
51054
|
+
text: block.text
|
|
51055
|
+
}, i, false, undefined, this);
|
|
51056
|
+
case "code":
|
|
51057
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(CodeBlock, {
|
|
51058
|
+
lang: block.lang,
|
|
51059
|
+
code: block.code
|
|
51060
|
+
}, i, false, undefined, this);
|
|
51061
|
+
case "bullet":
|
|
51062
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(BulletItem, {
|
|
51063
|
+
text: block.text
|
|
51064
|
+
}, i, false, undefined, this);
|
|
51065
|
+
case "numbered":
|
|
51066
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(NumberedItem, {
|
|
51067
|
+
num: block.num,
|
|
51068
|
+
text: block.text
|
|
51069
|
+
}, i, false, undefined, this);
|
|
51070
|
+
case "blockquote":
|
|
51071
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(BlockQuote, {
|
|
51072
|
+
text: block.text
|
|
51073
|
+
}, i, false, undefined, this);
|
|
51074
|
+
case "hr":
|
|
51075
|
+
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
51076
|
+
marginY: 1,
|
|
51077
|
+
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
51078
|
+
color: TOKEN_MUTED,
|
|
51079
|
+
dimColor: true,
|
|
51080
|
+
children: "─".repeat(40)
|
|
51081
|
+
}, undefined, false, undefined, this)
|
|
51082
|
+
}, i, false, undefined, this);
|
|
51083
|
+
case "paragraph":
|
|
49391
51084
|
return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
49392
51085
|
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InlineText, {
|
|
49393
|
-
text:
|
|
51086
|
+
text: block.text
|
|
49394
51087
|
}, undefined, false, undefined, this)
|
|
49395
|
-
},
|
|
49396
|
-
|
|
49397
|
-
}, si, false, undefined, this);
|
|
51088
|
+
}, i, false, undefined, this);
|
|
51089
|
+
}
|
|
49398
51090
|
})
|
|
49399
51091
|
}, undefined, false, undefined, this);
|
|
49400
51092
|
}
|
|
@@ -49405,11 +51097,11 @@ function StaticMessage({ msg }) {
|
|
|
49405
51097
|
gap: 1,
|
|
49406
51098
|
children: [
|
|
49407
51099
|
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49408
|
-
color:
|
|
51100
|
+
color: TOKEN_MUTED,
|
|
49409
51101
|
children: ">"
|
|
49410
51102
|
}, undefined, false, undefined, this),
|
|
49411
51103
|
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49412
|
-
color:
|
|
51104
|
+
color: TOKEN_TEXT,
|
|
49413
51105
|
bold: true,
|
|
49414
51106
|
children: msg.content
|
|
49415
51107
|
}, undefined, false, undefined, this)
|
|
@@ -49421,6 +51113,12 @@ function StaticMessage({ msg }) {
|
|
|
49421
51113
|
shell: "$",
|
|
49422
51114
|
fetch: "~>",
|
|
49423
51115
|
"read-file": "r",
|
|
51116
|
+
"read-folder": "d",
|
|
51117
|
+
grep: "/",
|
|
51118
|
+
"delete-file": "x",
|
|
51119
|
+
"delete-folder": "X",
|
|
51120
|
+
"open-url": "↗",
|
|
51121
|
+
"generate-pdf": "P",
|
|
49424
51122
|
"write-file": "w",
|
|
49425
51123
|
search: "?"
|
|
49426
51124
|
};
|
|
@@ -49438,7 +51136,7 @@ function StaticMessage({ msg }) {
|
|
|
49438
51136
|
children: icon
|
|
49439
51137
|
}, undefined, false, undefined, this),
|
|
49440
51138
|
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49441
|
-
color: msg.approved ?
|
|
51139
|
+
color: msg.approved ? TOKEN_MUTED : "red",
|
|
49442
51140
|
dimColor: !msg.approved,
|
|
49443
51141
|
children: label
|
|
49444
51142
|
}, undefined, false, undefined, this),
|
|
@@ -49451,7 +51149,7 @@ function StaticMessage({ msg }) {
|
|
|
49451
51149
|
msg.approved && msg.result && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
|
|
49452
51150
|
marginLeft: 2,
|
|
49453
51151
|
children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49454
|
-
color:
|
|
51152
|
+
color: TOKEN_MUTED,
|
|
49455
51153
|
children: [
|
|
49456
51154
|
msg.result.split(`
|
|
49457
51155
|
`)[0]?.slice(0, 120),
|
|
@@ -49485,11 +51183,11 @@ function StaticMessage({ msg }) {
|
|
|
49485
51183
|
gap: 1,
|
|
49486
51184
|
children: [
|
|
49487
51185
|
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49488
|
-
color: msg.applied ? "green" :
|
|
51186
|
+
color: msg.applied ? "green" : TOKEN_MUTED,
|
|
49489
51187
|
children: msg.applied ? "✓" : "·"
|
|
49490
51188
|
}, undefined, false, undefined, this),
|
|
49491
51189
|
/* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
|
|
49492
|
-
color: msg.applied ? "green" :
|
|
51190
|
+
color: msg.applied ? "green" : TOKEN_MUTED,
|
|
49493
51191
|
dimColor: !msg.applied,
|
|
49494
51192
|
children: msg.applied ? "changes applied" : "changes skipped"
|
|
49495
51193
|
}, undefined, false, undefined, this)
|
|
@@ -49642,6 +51340,30 @@ function PermissionPrompt({
|
|
|
49642
51340
|
icon = "r";
|
|
49643
51341
|
label = "read";
|
|
49644
51342
|
value = tool.filePath;
|
|
51343
|
+
} else if (tool.type === "read-folder") {
|
|
51344
|
+
icon = "d";
|
|
51345
|
+
label = "folder";
|
|
51346
|
+
value = tool.folderPath;
|
|
51347
|
+
} else if (tool.type === "grep") {
|
|
51348
|
+
icon = "/";
|
|
51349
|
+
label = "grep";
|
|
51350
|
+
value = `${tool.pattern} ${tool.glob}`;
|
|
51351
|
+
} else if (tool.type === "delete-file") {
|
|
51352
|
+
icon = "x";
|
|
51353
|
+
label = "delete";
|
|
51354
|
+
value = tool.filePath;
|
|
51355
|
+
} else if (tool.type === "delete-folder") {
|
|
51356
|
+
icon = "X";
|
|
51357
|
+
label = "delete folder";
|
|
51358
|
+
value = tool.folderPath;
|
|
51359
|
+
} else if (tool.type === "open-url") {
|
|
51360
|
+
icon = "↗";
|
|
51361
|
+
label = "open";
|
|
51362
|
+
value = tool.url;
|
|
51363
|
+
} else if (tool.type === "generate-pdf") {
|
|
51364
|
+
icon = "P";
|
|
51365
|
+
label = "pdf";
|
|
51366
|
+
value = tool.filePath;
|
|
49645
51367
|
} else if (tool.type === "write-file") {
|
|
49646
51368
|
icon = "w";
|
|
49647
51369
|
label = "write";
|
|
@@ -49734,16 +51456,23 @@ function TypewriterText({
|
|
|
49734
51456
|
children: displayed
|
|
49735
51457
|
}, undefined, false, undefined, this);
|
|
49736
51458
|
}
|
|
49737
|
-
function ShortcutBar() {
|
|
51459
|
+
function ShortcutBar({ autoApprove }) {
|
|
49738
51460
|
return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
|
|
49739
51461
|
gap: 3,
|
|
49740
51462
|
marginTop: 0,
|
|
49741
|
-
children:
|
|
49742
|
-
|
|
49743
|
-
|
|
49744
|
-
|
|
49745
|
-
|
|
49746
|
-
|
|
51463
|
+
children: [
|
|
51464
|
+
/* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
|
|
51465
|
+
color: "gray",
|
|
51466
|
+
dimColor: true,
|
|
51467
|
+
children: "enter send · ^v paste · ^c exit"
|
|
51468
|
+
}, undefined, false, undefined, this),
|
|
51469
|
+
/* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
|
|
51470
|
+
color: autoApprove ? "green" : "gray",
|
|
51471
|
+
dimColor: !autoApprove,
|
|
51472
|
+
children: autoApprove ? "⚡ auto" : "/auto"
|
|
51473
|
+
}, undefined, false, undefined, this)
|
|
51474
|
+
]
|
|
51475
|
+
}, undefined, true, undefined, this);
|
|
49747
51476
|
}
|
|
49748
51477
|
function CloneOfferView({
|
|
49749
51478
|
stage,
|
|
@@ -51519,7 +53248,8 @@ var jsx_dev_runtime22 = __toESM(require_jsx_dev_runtime(), 1);
|
|
|
51519
53248
|
var COMMANDS = [
|
|
51520
53249
|
{ cmd: "/timeline", desc: "browse commit history" },
|
|
51521
53250
|
{ cmd: "/clear history", desc: "wipe session memory for this repo" },
|
|
51522
|
-
{ cmd: "/review", desc: "review current codebsae" }
|
|
53251
|
+
{ cmd: "/review", desc: "review current codebsae" },
|
|
53252
|
+
{ cmd: "/auto", desc: "toggle auto-approve for read/search tools" }
|
|
51523
53253
|
];
|
|
51524
53254
|
function CommandPalette({
|
|
51525
53255
|
query,
|
|
@@ -51564,6 +53294,9 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51564
53294
|
const [clonedUrls, setClonedUrls] = import_react48.useState(new Set);
|
|
51565
53295
|
const [showTimeline, setShowTimeline] = import_react48.useState(false);
|
|
51566
53296
|
const [showReview, setShowReview] = import_react48.useState(false);
|
|
53297
|
+
const [autoApprove, setAutoApprove] = import_react48.useState(false);
|
|
53298
|
+
const abortControllerRef = import_react48.useRef(null);
|
|
53299
|
+
const toolResultCache = import_react48.useRef(new Map);
|
|
51567
53300
|
const inputBuffer = import_react48.useRef("");
|
|
51568
53301
|
const flushTimer = import_react48.useRef(null);
|
|
51569
53302
|
const thinkingPhrase = useThinkingPhrase(stage.type === "thinking");
|
|
@@ -51583,6 +53316,10 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51583
53316
|
}, 16);
|
|
51584
53317
|
};
|
|
51585
53318
|
const handleError = (currentAll) => (err) => {
|
|
53319
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
53320
|
+
setStage({ type: "idle" });
|
|
53321
|
+
return;
|
|
53322
|
+
}
|
|
51586
53323
|
const errMsg = {
|
|
51587
53324
|
role: "assistant",
|
|
51588
53325
|
content: `Error: ${err instanceof Error ? err.message : "Something went wrong"}`,
|
|
@@ -51592,7 +53329,11 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51592
53329
|
setCommitted((prev) => [...prev, errMsg]);
|
|
51593
53330
|
setStage({ type: "idle" });
|
|
51594
53331
|
};
|
|
51595
|
-
const processResponse = (raw, currentAll) => {
|
|
53332
|
+
const processResponse = (raw, currentAll, signal) => {
|
|
53333
|
+
if (signal.aborted) {
|
|
53334
|
+
setStage({ type: "idle" });
|
|
53335
|
+
return;
|
|
53336
|
+
}
|
|
51596
53337
|
const parsed = parseResponse(raw);
|
|
51597
53338
|
if (parsed.kind === "changes") {
|
|
51598
53339
|
if (parsed.patches.length === 0) {
|
|
@@ -51626,7 +53367,7 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51626
53367
|
});
|
|
51627
53368
|
return;
|
|
51628
53369
|
}
|
|
51629
|
-
if (parsed.kind === "shell" || parsed.kind === "fetch" || parsed.kind === "read-file" || parsed.kind === "write-file" || parsed.kind === "search") {
|
|
53370
|
+
if (parsed.kind === "shell" || parsed.kind === "fetch" || parsed.kind === "read-file" || parsed.kind === "read-folder" || parsed.kind === "grep" || parsed.kind === "write-file" || parsed.kind === "delete-file" || parsed.kind === "delete-folder" || parsed.kind === "open-url" || parsed.kind === "generate-pdf" || parsed.kind === "search") {
|
|
51630
53371
|
let tool;
|
|
51631
53372
|
if (parsed.kind === "shell") {
|
|
51632
53373
|
tool = { type: "shell", command: parsed.command };
|
|
@@ -51634,6 +53375,22 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51634
53375
|
tool = { type: "fetch", url: parsed.url };
|
|
51635
53376
|
} else if (parsed.kind === "read-file") {
|
|
51636
53377
|
tool = { type: "read-file", filePath: parsed.filePath };
|
|
53378
|
+
} else if (parsed.kind === "read-folder") {
|
|
53379
|
+
tool = { type: "read-folder", folderPath: parsed.folderPath };
|
|
53380
|
+
} else if (parsed.kind === "grep") {
|
|
53381
|
+
tool = { type: "grep", pattern: parsed.pattern, glob: parsed.glob };
|
|
53382
|
+
} else if (parsed.kind === "delete-file") {
|
|
53383
|
+
tool = { type: "delete-file", filePath: parsed.filePath };
|
|
53384
|
+
} else if (parsed.kind === "delete-folder") {
|
|
53385
|
+
tool = { type: "delete-folder", folderPath: parsed.folderPath };
|
|
53386
|
+
} else if (parsed.kind === "open-url") {
|
|
53387
|
+
tool = { type: "open-url", url: parsed.url };
|
|
53388
|
+
} else if (parsed.kind === "generate-pdf") {
|
|
53389
|
+
tool = {
|
|
53390
|
+
type: "generate-pdf",
|
|
53391
|
+
filePath: parsed.filePath,
|
|
53392
|
+
content: parsed.pdfContent
|
|
53393
|
+
};
|
|
51637
53394
|
} else if (parsed.kind === "search") {
|
|
51638
53395
|
tool = { type: "search", query: parsed.query };
|
|
51639
53396
|
} else {
|
|
@@ -51652,13 +53409,16 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51652
53409
|
setAllMessages([...currentAll, preambleMsg]);
|
|
51653
53410
|
setCommitted((prev) => [...prev, preambleMsg]);
|
|
51654
53411
|
}
|
|
51655
|
-
|
|
51656
|
-
|
|
51657
|
-
|
|
51658
|
-
|
|
51659
|
-
|
|
51660
|
-
|
|
51661
|
-
|
|
53412
|
+
const isSafeTool = parsed.kind === "read-file" || parsed.kind === "read-folder" || parsed.kind === "grep" || parsed.kind === "fetch" || parsed.kind === "open-url" || parsed.kind === "search";
|
|
53413
|
+
const executeAndContinue = async (approved) => {
|
|
53414
|
+
let result2 = "(denied by user)";
|
|
53415
|
+
if (approved) {
|
|
53416
|
+
const cacheKey = parsed.kind === "read-file" ? `read-file:${parsed.filePath}` : parsed.kind === "read-folder" ? `read-folder:${parsed.folderPath}` : parsed.kind === "grep" ? `grep:${parsed.pattern}:${parsed.glob}` : null;
|
|
53417
|
+
if (cacheKey && toolResultCache.current.has(cacheKey)) {
|
|
53418
|
+
result2 = toolResultCache.current.get(cacheKey) + `
|
|
53419
|
+
|
|
53420
|
+
[NOTE: This result was already retrieved earlier. Do not request it again.]`;
|
|
53421
|
+
} else {
|
|
51662
53422
|
try {
|
|
51663
53423
|
setStage({ type: "thinking" });
|
|
51664
53424
|
if (parsed.kind === "shell") {
|
|
@@ -51667,47 +53427,80 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51667
53427
|
result2 = await fetchUrl(parsed.url);
|
|
51668
53428
|
} else if (parsed.kind === "read-file") {
|
|
51669
53429
|
result2 = readFile(parsed.filePath, repoPath);
|
|
53430
|
+
} else if (parsed.kind === "read-folder") {
|
|
53431
|
+
result2 = readFolder(parsed.folderPath, repoPath);
|
|
53432
|
+
} else if (parsed.kind === "grep") {
|
|
53433
|
+
result2 = grepFiles(parsed.pattern, parsed.glob, repoPath);
|
|
53434
|
+
} else if (parsed.kind === "delete-file") {
|
|
53435
|
+
result2 = deleteFile(parsed.filePath, repoPath);
|
|
53436
|
+
} else if (parsed.kind === "delete-folder") {
|
|
53437
|
+
result2 = deleteFolder(parsed.folderPath, repoPath);
|
|
53438
|
+
} else if (parsed.kind === "open-url") {
|
|
53439
|
+
result2 = openUrl(parsed.url);
|
|
53440
|
+
} else if (parsed.kind === "generate-pdf") {
|
|
53441
|
+
result2 = generatePdf(parsed.filePath, parsed.pdfContent, repoPath);
|
|
51670
53442
|
} else if (parsed.kind === "write-file") {
|
|
51671
53443
|
result2 = writeFile(parsed.filePath, parsed.fileContent, repoPath);
|
|
51672
53444
|
} else if (parsed.kind === "search") {
|
|
51673
53445
|
result2 = await searchWeb(parsed.query);
|
|
51674
53446
|
}
|
|
53447
|
+
if (cacheKey) {
|
|
53448
|
+
toolResultCache.current.set(cacheKey, result2);
|
|
53449
|
+
}
|
|
51675
53450
|
} catch (err) {
|
|
51676
53451
|
result2 = `Error: ${err instanceof Error ? err.message : "failed"}`;
|
|
51677
53452
|
}
|
|
51678
53453
|
}
|
|
51679
|
-
|
|
51680
|
-
|
|
51681
|
-
|
|
51682
|
-
|
|
51683
|
-
|
|
51684
|
-
|
|
51685
|
-
|
|
51686
|
-
|
|
51687
|
-
|
|
51688
|
-
|
|
51689
|
-
|
|
51690
|
-
|
|
51691
|
-
|
|
51692
|
-
|
|
51693
|
-
});
|
|
51694
|
-
}
|
|
51695
|
-
const toolName = parsed.kind === "shell" ? "shell" : parsed.kind === "fetch" ? "fetch" : parsed.kind === "read-file" ? "read-file" : parsed.kind === "search" ? "search" : "write-file";
|
|
51696
|
-
const toolContent = parsed.kind === "shell" ? parsed.command : parsed.kind === "fetch" ? parsed.url : parsed.kind === "search" ? parsed.query : parsed.filePath;
|
|
51697
|
-
const toolMsg = {
|
|
51698
|
-
role: "assistant",
|
|
51699
|
-
type: "tool",
|
|
51700
|
-
toolName,
|
|
51701
|
-
content: toolContent,
|
|
51702
|
-
result: result2,
|
|
51703
|
-
approved
|
|
53454
|
+
}
|
|
53455
|
+
if (approved && !result2.startsWith("Error:")) {
|
|
53456
|
+
const kindMap2 = {
|
|
53457
|
+
shell: "shell-run",
|
|
53458
|
+
fetch: "url-fetched",
|
|
53459
|
+
"read-file": "file-read",
|
|
53460
|
+
"read-folder": "file-read",
|
|
53461
|
+
grep: "file-read",
|
|
53462
|
+
"delete-file": "file-written",
|
|
53463
|
+
"delete-folder": "file-written",
|
|
53464
|
+
"open-url": "url-fetched",
|
|
53465
|
+
"generate-pdf": "file-written",
|
|
53466
|
+
"write-file": "file-written",
|
|
53467
|
+
search: "url-fetched"
|
|
51704
53468
|
};
|
|
51705
|
-
|
|
51706
|
-
|
|
51707
|
-
|
|
51708
|
-
|
|
51709
|
-
|
|
53469
|
+
appendHistory({
|
|
53470
|
+
kind: kindMap2[parsed.kind] ?? "shell-run",
|
|
53471
|
+
detail: parsed.kind === "shell" ? parsed.command : parsed.kind === "fetch" ? parsed.url : parsed.kind === "search" ? parsed.query : parsed.kind === "read-folder" ? parsed.folderPath : parsed.kind === "grep" ? `${parsed.pattern} ${parsed.glob}` : parsed.kind === "delete-file" ? parsed.filePath : parsed.kind === "delete-folder" ? parsed.folderPath : parsed.kind === "open-url" ? parsed.url : parsed.kind === "generate-pdf" ? parsed.filePath : parsed.filePath,
|
|
53472
|
+
summary: result2.split(`
|
|
53473
|
+
`)[0]?.slice(0, 120) ?? "",
|
|
53474
|
+
repoPath
|
|
53475
|
+
});
|
|
51710
53476
|
}
|
|
53477
|
+
const toolName = parsed.kind === "shell" ? "shell" : parsed.kind === "fetch" ? "fetch" : parsed.kind === "read-file" ? "read-file" : parsed.kind === "read-folder" ? "read-folder" : parsed.kind === "grep" ? "grep" : parsed.kind === "delete-file" ? "delete-file" : parsed.kind === "delete-folder" ? "delete-folder" : parsed.kind === "open-url" ? "open-url" : parsed.kind === "generate-pdf" ? "generate-pdf" : parsed.kind === "search" ? "search" : "write-file";
|
|
53478
|
+
const toolContent = parsed.kind === "shell" ? parsed.command : parsed.kind === "fetch" ? parsed.url : parsed.kind === "search" ? parsed.query : parsed.kind === "read-folder" ? parsed.folderPath : parsed.kind === "grep" ? `${parsed.pattern} — ${parsed.glob}` : parsed.kind === "delete-file" ? parsed.filePath : parsed.kind === "delete-folder" ? parsed.folderPath : parsed.kind === "open-url" ? parsed.url : parsed.kind === "generate-pdf" ? parsed.filePath : parsed.filePath;
|
|
53479
|
+
const toolMsg = {
|
|
53480
|
+
role: "assistant",
|
|
53481
|
+
type: "tool",
|
|
53482
|
+
toolName,
|
|
53483
|
+
content: toolContent,
|
|
53484
|
+
result: result2,
|
|
53485
|
+
approved
|
|
53486
|
+
};
|
|
53487
|
+
const withTool = [...currentAll, toolMsg];
|
|
53488
|
+
setAllMessages(withTool);
|
|
53489
|
+
setCommitted((prev) => [...prev, toolMsg]);
|
|
53490
|
+
const nextAbort = new AbortController;
|
|
53491
|
+
abortControllerRef.current = nextAbort;
|
|
53492
|
+
setStage({ type: "thinking" });
|
|
53493
|
+
callChat(provider, systemPrompt, withTool, nextAbort.signal).then((r) => processResponse(r, withTool, nextAbort.signal)).catch(handleError(withTool));
|
|
53494
|
+
};
|
|
53495
|
+
if (autoApprove && isSafeTool) {
|
|
53496
|
+
executeAndContinue(true);
|
|
53497
|
+
return;
|
|
53498
|
+
}
|
|
53499
|
+
setStage({
|
|
53500
|
+
type: "permission",
|
|
53501
|
+
tool,
|
|
53502
|
+
pendingMessages: currentAll,
|
|
53503
|
+
resolve: executeAndContinue
|
|
51711
53504
|
});
|
|
51712
53505
|
return;
|
|
51713
53506
|
}
|
|
@@ -51757,6 +53550,18 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51757
53550
|
setShowReview(true);
|
|
51758
53551
|
return;
|
|
51759
53552
|
}
|
|
53553
|
+
if (text.trim().toLowerCase() === "/auto") {
|
|
53554
|
+
const next = !autoApprove;
|
|
53555
|
+
setAutoApprove(next);
|
|
53556
|
+
const msg = {
|
|
53557
|
+
role: "assistant",
|
|
53558
|
+
content: next ? "Auto-approve ON — read, search, grep and folder tools will run without asking. Write and code changes still require approval." : "Auto-approve OFF — all tools will ask for permission.",
|
|
53559
|
+
type: "text"
|
|
53560
|
+
};
|
|
53561
|
+
setCommitted((prev) => [...prev, msg]);
|
|
53562
|
+
setAllMessages((prev) => [...prev, msg]);
|
|
53563
|
+
return;
|
|
53564
|
+
}
|
|
51760
53565
|
if (text.trim().toLowerCase() === "/clear history") {
|
|
51761
53566
|
clearRepoHistory(repoPath);
|
|
51762
53567
|
const clearedMsg = {
|
|
@@ -51772,12 +53577,21 @@ var ChatRunner = ({ repoPath }) => {
|
|
|
51772
53577
|
const nextAll = [...allMessages, userMsg];
|
|
51773
53578
|
setCommitted((prev) => [...prev, userMsg]);
|
|
51774
53579
|
setAllMessages(nextAll);
|
|
53580
|
+
toolResultCache.current.clear();
|
|
53581
|
+
const abort = new AbortController;
|
|
53582
|
+
abortControllerRef.current = abort;
|
|
51775
53583
|
setStage({ type: "thinking" });
|
|
51776
|
-
callChat(provider, systemPrompt, nextAll).then((raw) => processResponse(raw, nextAll)).catch(handleError(nextAll));
|
|
53584
|
+
callChat(provider, systemPrompt, nextAll, abort.signal).then((raw) => processResponse(raw, nextAll, abort.signal)).catch(handleError(nextAll));
|
|
51777
53585
|
};
|
|
51778
53586
|
use_input_default((input, key) => {
|
|
51779
53587
|
if (showTimeline)
|
|
51780
53588
|
return;
|
|
53589
|
+
if (stage.type === "thinking" && key.escape) {
|
|
53590
|
+
abortControllerRef.current?.abort();
|
|
53591
|
+
abortControllerRef.current = null;
|
|
53592
|
+
setStage({ type: "idle" });
|
|
53593
|
+
return;
|
|
53594
|
+
}
|
|
51781
53595
|
if (stage.type === "idle") {
|
|
51782
53596
|
if (key.ctrl && input === "c") {
|
|
51783
53597
|
process.exit(0);
|
|
@@ -52109,6 +53923,11 @@ Tip: type /timeline to browse commit history.`,
|
|
|
52109
53923
|
}, undefined, false, undefined, this),
|
|
52110
53924
|
/* @__PURE__ */ jsx_dev_runtime22.jsxDEV(TypewriterText, {
|
|
52111
53925
|
text: thinkingPhrase
|
|
53926
|
+
}, undefined, false, undefined, this),
|
|
53927
|
+
/* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
|
|
53928
|
+
color: "gray",
|
|
53929
|
+
dimColor: true,
|
|
53930
|
+
children: "· esc cancel"
|
|
52112
53931
|
}, undefined, false, undefined, this)
|
|
52113
53932
|
]
|
|
52114
53933
|
}, undefined, true, undefined, this),
|
|
@@ -52134,7 +53953,9 @@ Tip: type /timeline to browse commit history.`,
|
|
|
52134
53953
|
setInputValue("");
|
|
52135
53954
|
}
|
|
52136
53955
|
}, undefined, false, undefined, this),
|
|
52137
|
-
/* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ShortcutBar, {
|
|
53956
|
+
/* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ShortcutBar, {
|
|
53957
|
+
autoApprove
|
|
53958
|
+
}, undefined, false, undefined, this)
|
|
52138
53959
|
]
|
|
52139
53960
|
}, undefined, true, undefined, this)
|
|
52140
53961
|
]
|