npcsh 0.3.30__py3-none-any.whl → 0.3.31__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- npcsh/cli.py +30 -10
- npcsh/image.py +0 -2
- npcsh/npc_compiler.py +12 -0
- npcsh/npc_team/npcsh.ctx +8 -2
- npcsh/npc_team/tools/generic_search.tool +9 -1
- npcsh/search.py +15 -8
- npcsh/shell.py +87 -75
- npcsh/shell_helpers.py +24 -3
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/generic_search.tool +9 -1
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/npcsh.ctx +8 -2
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/METADATA +12 -21
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/RECORD +36 -36
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/bash_executer.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/calculator.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/celona.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/code_executor.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/eriane.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/image_generation.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/lineru.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/local_search.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/maurawa.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/npcsh_executor.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/raone.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/screen_cap.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/slean.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/sql_executor.tool +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/test_pipeline.py +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/turnic.npc +0 -0
- {npcsh-0.3.30.data → npcsh-0.3.31.data}/data/npcsh/npc_team/welxor.npc +0 -0
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/WHEEL +0 -0
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/entry_points.txt +0 -0
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/licenses/LICENSE +0 -0
- {npcsh-0.3.30.dist-info → npcsh-0.3.31.dist-info}/top_level.txt +0 -0
npcsh/cli.py
CHANGED
|
@@ -33,6 +33,7 @@ from .llm_funcs import (
|
|
|
33
33
|
get_stream,
|
|
34
34
|
get_conversation,
|
|
35
35
|
)
|
|
36
|
+
from .plonk import plonk, action_space
|
|
36
37
|
from .search import search_web
|
|
37
38
|
from .shell_helpers import *
|
|
38
39
|
import os
|
|
@@ -54,10 +55,12 @@ def main():
|
|
|
54
55
|
"assemble",
|
|
55
56
|
"build",
|
|
56
57
|
"compile",
|
|
58
|
+
"chat",
|
|
57
59
|
"init",
|
|
58
60
|
"new",
|
|
59
61
|
"plonk",
|
|
60
62
|
"sample",
|
|
63
|
+
"search",
|
|
61
64
|
"select",
|
|
62
65
|
"serve",
|
|
63
66
|
"spool",
|
|
@@ -165,6 +168,10 @@ def main():
|
|
|
165
168
|
"directory", nargs="?", default=".", help="Directory to build project in"
|
|
166
169
|
)
|
|
167
170
|
|
|
171
|
+
# chat
|
|
172
|
+
chat_parser = subparsers.add_parser("chat", help="chat with an NPC")
|
|
173
|
+
chat_parser.add_argument("-n", "--npc_name", help="name of npc")
|
|
174
|
+
|
|
168
175
|
# Compile command
|
|
169
176
|
compile_parser = subparsers.add_parser("compile", help="Compile an NPC")
|
|
170
177
|
compile_parser.add_argument("path", help="Path to NPC file")
|
|
@@ -300,7 +307,7 @@ def main():
|
|
|
300
307
|
|
|
301
308
|
# Web search
|
|
302
309
|
search_parser = subparsers.add_parser("search", help="search the web")
|
|
303
|
-
search_parser.add_argument("query", help="search query")
|
|
310
|
+
search_parser.add_argument("--query", "-q", help="search query")
|
|
304
311
|
search_parser.add_argument(
|
|
305
312
|
"--search_provider",
|
|
306
313
|
"-sp",
|
|
@@ -317,7 +324,7 @@ def main():
|
|
|
317
324
|
|
|
318
325
|
# Voice chat
|
|
319
326
|
whisper_parser = subparsers.add_parser("whisper", help="start voice chat")
|
|
320
|
-
whisper_parser.add_argument("npc_name", help="name of the NPC to chat with")
|
|
327
|
+
whisper_parser.add_argument("-n", "--npc_name", help="name of the NPC to chat with")
|
|
321
328
|
|
|
322
329
|
args = parser.parse_args()
|
|
323
330
|
|
|
@@ -367,6 +374,13 @@ def main():
|
|
|
367
374
|
port=args.port if args.port else 5337,
|
|
368
375
|
cors_origins=cors_origins,
|
|
369
376
|
)
|
|
377
|
+
elif args.command == "chat":
|
|
378
|
+
npc_name = args.npc_name
|
|
379
|
+
npc_path = get_npc_path(npc_name, NPCSH_DB_PATH)
|
|
380
|
+
current_npc = load_npc_from_file(npc_path, sqlite3.connect(NPCSH_DB_PATH))
|
|
381
|
+
return enter_spool_mode(
|
|
382
|
+
model=args.model, provider=args.provider, npc=current_npc
|
|
383
|
+
)
|
|
370
384
|
|
|
371
385
|
elif args.command == "init":
|
|
372
386
|
if args.templates:
|
|
@@ -395,16 +409,18 @@ def main():
|
|
|
395
409
|
)
|
|
396
410
|
|
|
397
411
|
elif args.command == "compile":
|
|
398
|
-
|
|
412
|
+
npc_compiler = NPCCompiler(npc_directory, NPCSH_DB_PATH)
|
|
413
|
+
compiled = npc_compiler.compile(args.path)
|
|
414
|
+
print("NPC compiled to:", compiled)
|
|
399
415
|
|
|
400
416
|
elif args.command == "plonk":
|
|
401
417
|
task = args.task or args.spell
|
|
402
418
|
npc_name = args.name
|
|
403
|
-
|
|
404
|
-
task
|
|
405
|
-
|
|
406
|
-
model=args.model or
|
|
407
|
-
provider=args.provider or
|
|
419
|
+
plonk(
|
|
420
|
+
task,
|
|
421
|
+
action_space,
|
|
422
|
+
model=args.model or NPCSH_CHAT_MODEL,
|
|
423
|
+
provider=args.provider or NPCSH_CHAT_PROVIDER,
|
|
408
424
|
)
|
|
409
425
|
|
|
410
426
|
elif args.command == "sample":
|
|
@@ -443,10 +459,14 @@ def main():
|
|
|
443
459
|
model=args.model,
|
|
444
460
|
provider=args.provider,
|
|
445
461
|
)
|
|
446
|
-
print(result)
|
|
462
|
+
print(result["output"])
|
|
447
463
|
|
|
448
464
|
elif args.command == "whisper":
|
|
449
|
-
|
|
465
|
+
npc_name = args.npc_name
|
|
466
|
+
npc_path = get_npc_path(npc_name, NPCSH_DB_PATH)
|
|
467
|
+
current_npc = load_npc_from_file(npc_path, sqlite3.connect(NPCSH_DB_PATH))
|
|
468
|
+
|
|
469
|
+
enter_whisper_mode(npc=current_npc)
|
|
450
470
|
|
|
451
471
|
elif args.command == "tool":
|
|
452
472
|
result = invoke_tool(
|
npcsh/image.py
CHANGED
npcsh/npc_compiler.py
CHANGED
|
@@ -501,6 +501,18 @@ class SilentUndefined(Undefined):
|
|
|
501
501
|
return ""
|
|
502
502
|
|
|
503
503
|
|
|
504
|
+
class Context:
|
|
505
|
+
def __init__(self, context=None, mcp_servers=None, databases=None, files=None):
|
|
506
|
+
self.context = context
|
|
507
|
+
self.mcp_servers = mcp_servers
|
|
508
|
+
self.databases = databases
|
|
509
|
+
self.files = files
|
|
510
|
+
|
|
511
|
+
def load_context_file(self, path):
|
|
512
|
+
with open(path, "r") as f:
|
|
513
|
+
self.context = yaml.safe_load(f)
|
|
514
|
+
|
|
515
|
+
|
|
504
516
|
class Tool:
|
|
505
517
|
def __init__(self, tool_data: dict):
|
|
506
518
|
if not tool_data or not isinstance(tool_data, dict):
|
npcsh/npc_team/npcsh.ctx
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
context: |
|
|
2
2
|
The npcsh NPC team is devoted to providing a safe and helpful
|
|
3
3
|
environment for users where they can work and be as successful as possible.
|
|
4
4
|
npcsh is a command-line tool that makes it easy for users to harness
|
|
5
|
-
the power of LLMs from a command line shell.
|
|
5
|
+
the power of LLMs from a command line shell.
|
|
6
|
+
databases:
|
|
7
|
+
- ~/npcsh_history.db
|
|
8
|
+
mcp_servers:
|
|
9
|
+
- /path/to/mcp/server.py
|
|
10
|
+
- @npm for server
|
|
11
|
+
|
|
@@ -2,13 +2,21 @@ tool_name: "internet_search"
|
|
|
2
2
|
description: Searches the web for information based on a query in order to verify timiely details (e.g. current events) or to corroborate information in uncertain situations. Should be mainly only used when users specifically request a search, otherwise an LLMs basic knowledge should be sufficient.
|
|
3
3
|
inputs:
|
|
4
4
|
- query
|
|
5
|
+
- provider: ''
|
|
5
6
|
steps:
|
|
6
7
|
- engine: "python"
|
|
7
8
|
code: |
|
|
8
9
|
from npcsh.search import search_web
|
|
10
|
+
from npcsh.npc_sysenv import NPCSH_SEARCH_PROVIDER
|
|
9
11
|
query = "{{ query }}"
|
|
12
|
+
provider = '{{ provider }}'
|
|
13
|
+
if provider.strip() != '':
|
|
14
|
+
results = search_web(query, num_results=5, provider = provider)
|
|
15
|
+
else:
|
|
16
|
+
results = search_web(query, num_results=5, provider = NPCSH_SEARCH_PROVIDER)
|
|
17
|
+
|
|
10
18
|
print('QUERY in tool', query)
|
|
11
|
-
results = search_web(query, num_results=5)
|
|
19
|
+
results = search_web(query, num_results=5, provider = NPCSH_SEARCH_PROVIDER)
|
|
12
20
|
print('RESULTS in tool', results)
|
|
13
21
|
- engine: "natural"
|
|
14
22
|
code: |
|
npcsh/search.py
CHANGED
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
|
|
6
6
|
from bs4 import BeautifulSoup
|
|
7
7
|
from duckduckgo_search import DDGS
|
|
8
|
+
from duckduckgo_search.exceptions import DuckDuckGoSearchException
|
|
8
9
|
|
|
9
10
|
try:
|
|
10
11
|
from googlesearch import search
|
|
@@ -41,7 +42,6 @@ def search_perplexity(
|
|
|
41
42
|
"max_tokens": max_tokens,
|
|
42
43
|
"temperature": temperature,
|
|
43
44
|
"top_p": top_p,
|
|
44
|
-
"search_domain_filter": ["perplexity.ai"],
|
|
45
45
|
"return_images": False,
|
|
46
46
|
"return_related_questions": False,
|
|
47
47
|
"search_recency_filter": "month",
|
|
@@ -58,6 +58,7 @@ def search_perplexity(
|
|
|
58
58
|
# Make the POST request to the API
|
|
59
59
|
response = requests.post(url, json=payload, headers=headers)
|
|
60
60
|
response = json.loads(response.text)
|
|
61
|
+
print(response)
|
|
61
62
|
return [response["choices"][0]["message"]["content"], response["citations"]]
|
|
62
63
|
|
|
63
64
|
|
|
@@ -89,13 +90,19 @@ def search_web(
|
|
|
89
90
|
|
|
90
91
|
if provider == "duckduckgo":
|
|
91
92
|
ddgs = DDGS()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
try:
|
|
94
|
+
search_results = ddgs.text(query, max_results=num_results)
|
|
95
|
+
print(search_results, type(search_results))
|
|
96
|
+
urls = [r["href"] for r in search_results]
|
|
97
|
+
results = [
|
|
98
|
+
{"title": r["title"], "link": r["href"], "content": r["body"]}
|
|
99
|
+
for r in search_results
|
|
100
|
+
]
|
|
101
|
+
except DuckDuckGoSearchException as e:
|
|
102
|
+
print("DuckDuckGo search failed: ", e)
|
|
103
|
+
urls = []
|
|
104
|
+
results = []
|
|
105
|
+
|
|
99
106
|
else: # google
|
|
100
107
|
urls = list(search(query, num_results=num_results))
|
|
101
108
|
# google shit doesnt seem to be working anymore, apparently a lbock they made on browsers without js?
|
npcsh/shell.py
CHANGED
|
@@ -407,88 +407,100 @@ def main() -> None:
|
|
|
407
407
|
)
|
|
408
408
|
|
|
409
409
|
str_output = ""
|
|
410
|
-
|
|
410
|
+
try:
|
|
411
|
+
if NPCSH_STREAM_OUTPUT and hasattr(output, "__iter__"):
|
|
412
|
+
|
|
413
|
+
buffer = ""
|
|
414
|
+
in_code = False
|
|
415
|
+
code_buffer = ""
|
|
416
|
+
|
|
417
|
+
for chunk in output:
|
|
418
|
+
|
|
419
|
+
if provider == "anthropic":
|
|
420
|
+
chunk_content = (
|
|
421
|
+
chunk.delta.text
|
|
422
|
+
if chunk.type == "content_block_delta"
|
|
423
|
+
else None
|
|
424
|
+
)
|
|
425
|
+
elif provider in ["openai", "deepseek", "openai-like"]:
|
|
426
|
+
chunk_content = "".join(
|
|
427
|
+
c.delta.content
|
|
428
|
+
for c in chunk.choices
|
|
429
|
+
if c.delta.content
|
|
430
|
+
)
|
|
431
|
+
elif provider == "ollama":
|
|
432
|
+
chunk_content = chunk["message"]["content"]
|
|
433
|
+
else:
|
|
434
|
+
continue
|
|
411
435
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
code_buffer = ""
|
|
436
|
+
if not chunk_content:
|
|
437
|
+
continue
|
|
415
438
|
|
|
416
|
-
|
|
439
|
+
str_output += chunk_content
|
|
440
|
+
# print(str_output, "str_output")
|
|
441
|
+
# Process the content character by character
|
|
442
|
+
for char in chunk_content:
|
|
443
|
+
buffer += char
|
|
417
444
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
445
|
+
# Check for triple backticks
|
|
446
|
+
if buffer.endswith("```"):
|
|
447
|
+
if not in_code:
|
|
448
|
+
# Start of code block
|
|
449
|
+
in_code = True
|
|
450
|
+
# Print everything before the backticks
|
|
451
|
+
print(buffer[:-3], end="")
|
|
452
|
+
buffer = ""
|
|
453
|
+
code_buffer = ""
|
|
454
|
+
else:
|
|
455
|
+
# End of code block
|
|
456
|
+
in_code = False
|
|
457
|
+
# Remove the backticks from the end of the buffer
|
|
458
|
+
buffer = buffer[:-3]
|
|
459
|
+
# Add buffer to code content and render
|
|
460
|
+
code_buffer += buffer
|
|
461
|
+
|
|
462
|
+
# Check for and strip language tag
|
|
463
|
+
if (
|
|
464
|
+
"\n" in code_buffer
|
|
465
|
+
and code_buffer.index("\n") < 15
|
|
466
|
+
):
|
|
467
|
+
first_line, rest = code_buffer.split("\n", 1)
|
|
468
|
+
if (
|
|
469
|
+
first_line.strip()
|
|
470
|
+
and not "```" in first_line
|
|
471
|
+
):
|
|
472
|
+
code_buffer = rest
|
|
432
473
|
|
|
433
|
-
|
|
434
|
-
|
|
474
|
+
# Render the code block
|
|
475
|
+
render_code_block(code_buffer)
|
|
435
476
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if not in_code:
|
|
445
|
-
# Start of code block
|
|
446
|
-
in_code = True
|
|
447
|
-
# Print everything before the backticks
|
|
448
|
-
print(buffer[:-3], end="")
|
|
449
|
-
buffer = ""
|
|
450
|
-
code_buffer = ""
|
|
477
|
+
# Reset buffers
|
|
478
|
+
buffer = ""
|
|
479
|
+
code_buffer = ""
|
|
480
|
+
elif in_code:
|
|
481
|
+
# Just add to code buffer
|
|
482
|
+
code_buffer += char
|
|
483
|
+
if len(buffer) >= 3: # Keep buffer small while in code
|
|
484
|
+
buffer = buffer[-3:]
|
|
451
485
|
else:
|
|
452
|
-
#
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
buffer = ""
|
|
470
|
-
code_buffer = ""
|
|
471
|
-
elif in_code:
|
|
472
|
-
# Just add to code buffer
|
|
473
|
-
code_buffer += char
|
|
474
|
-
if len(buffer) >= 3: # Keep buffer small while in code
|
|
475
|
-
buffer = buffer[-3:]
|
|
476
|
-
else:
|
|
477
|
-
# Regular text - print if buffer gets too large
|
|
478
|
-
if len(buffer) > 100:
|
|
479
|
-
print(buffer[:-3], end="")
|
|
480
|
-
buffer = buffer[
|
|
481
|
-
-3:
|
|
482
|
-
] # Keep last 3 chars to check for backticks
|
|
483
|
-
|
|
484
|
-
# Handle any remaining content
|
|
485
|
-
if in_code:
|
|
486
|
-
render_code_block(code_buffer)
|
|
487
|
-
else:
|
|
488
|
-
print(buffer, end="")
|
|
486
|
+
# Regular text - print if buffer gets too large
|
|
487
|
+
if len(buffer) > 100:
|
|
488
|
+
print(buffer[:-3], end="")
|
|
489
|
+
buffer = buffer[
|
|
490
|
+
-3:
|
|
491
|
+
] # Keep last 3 chars to check for backticks
|
|
492
|
+
|
|
493
|
+
# Handle any remaining content
|
|
494
|
+
if in_code:
|
|
495
|
+
render_code_block(code_buffer)
|
|
496
|
+
else:
|
|
497
|
+
print(buffer, end="")
|
|
498
|
+
|
|
499
|
+
if str_output:
|
|
500
|
+
output = str_output
|
|
501
|
+
except:
|
|
502
|
+
output = None
|
|
489
503
|
|
|
490
|
-
if str_output:
|
|
491
|
-
output = str_output
|
|
492
504
|
print("\n")
|
|
493
505
|
|
|
494
506
|
if isinstance(output, str):
|
npcsh/shell_helpers.py
CHANGED
|
@@ -1631,6 +1631,9 @@ def ots(
|
|
|
1631
1631
|
output = analyze_image(
|
|
1632
1632
|
user_prompt, file_path, filename, npc=npc, model=model, provider=provider
|
|
1633
1633
|
)
|
|
1634
|
+
messages = [
|
|
1635
|
+
{"role": "user", "content": user_prompt},
|
|
1636
|
+
]
|
|
1634
1637
|
|
|
1635
1638
|
else:
|
|
1636
1639
|
output = capture_screenshot(npc=npc)
|
|
@@ -1651,12 +1654,15 @@ def ots(
|
|
|
1651
1654
|
# messages = output["messages"]
|
|
1652
1655
|
|
|
1653
1656
|
output = output["response"]
|
|
1654
|
-
|
|
1657
|
+
messages = [
|
|
1658
|
+
{"role": "user", "content": user_prompt},
|
|
1659
|
+
]
|
|
1655
1660
|
if output:
|
|
1656
1661
|
if isinstance(output, dict) and "filename" in output:
|
|
1657
1662
|
message = f"Screenshot captured: {output['filename']}\nFull path: {output['file_path']}\nLLM-ready data available."
|
|
1658
1663
|
else: # This handles both LLM responses and error messages (both strings)
|
|
1659
1664
|
message = output
|
|
1665
|
+
messages.append({"role": "assistant", "content": message})
|
|
1660
1666
|
return {"messages": messages, "output": message} # Return the message
|
|
1661
1667
|
else: # Handle the case where capture_screenshot returns None
|
|
1662
1668
|
print("Screenshot capture failed.")
|
|
@@ -2042,6 +2048,18 @@ def execute_slash_command(
|
|
|
2042
2048
|
device = part.split("=")[1]
|
|
2043
2049
|
if part.startswith("rag_similarity_threshold="):
|
|
2044
2050
|
rag_similarity_threshold = float(part.split("=")[1])
|
|
2051
|
+
if part.startswith("model="):
|
|
2052
|
+
model = part.split("=")[1]
|
|
2053
|
+
|
|
2054
|
+
if part.startswith("provider="):
|
|
2055
|
+
provider = part.split("=")[1]
|
|
2056
|
+
if part.startswith("api_url="):
|
|
2057
|
+
api_url = part.split("=")[1]
|
|
2058
|
+
if part.startswith("api_key="):
|
|
2059
|
+
api_key = part.split("=")[1]
|
|
2060
|
+
|
|
2061
|
+
# load the npc properly
|
|
2062
|
+
|
|
2045
2063
|
match = re.search(r"files=\s*\[(.*?)\]", command)
|
|
2046
2064
|
files = []
|
|
2047
2065
|
if match:
|
|
@@ -2066,10 +2084,11 @@ def execute_slash_command(
|
|
|
2066
2084
|
|
|
2067
2085
|
print(f"Reattached to previous conversation:\n\n")
|
|
2068
2086
|
output = enter_spool_mode(
|
|
2069
|
-
command_history,
|
|
2070
2087
|
inherit_last,
|
|
2071
2088
|
files=files,
|
|
2072
2089
|
npc=npc,
|
|
2090
|
+
model=model,
|
|
2091
|
+
provider=provider,
|
|
2073
2092
|
rag_similarity_threshold=rag_similarity_threshold,
|
|
2074
2093
|
device=device,
|
|
2075
2094
|
messages=spool_context,
|
|
@@ -2082,7 +2101,6 @@ def execute_slash_command(
|
|
|
2082
2101
|
return {"messages": [], "output": "No previous conversation found."}
|
|
2083
2102
|
|
|
2084
2103
|
output = enter_spool_mode(
|
|
2085
|
-
command_history,
|
|
2086
2104
|
inherit_last,
|
|
2087
2105
|
files=files,
|
|
2088
2106
|
npc=npc,
|
|
@@ -2367,11 +2385,13 @@ def execute_command(
|
|
|
2367
2385
|
valid_npcs = get_db_npcs(db_path)
|
|
2368
2386
|
|
|
2369
2387
|
npc_name = get_npc_from_command(command)
|
|
2388
|
+
|
|
2370
2389
|
if npc_name is None:
|
|
2371
2390
|
npc_name = "sibiji" # Default NPC
|
|
2372
2391
|
npc_path = get_npc_path(npc_name, db_path)
|
|
2373
2392
|
|
|
2374
2393
|
npc = load_npc_from_file(npc_path, db_conn)
|
|
2394
|
+
current_npc = npc
|
|
2375
2395
|
else:
|
|
2376
2396
|
valid_npcs = [current_npc]
|
|
2377
2397
|
npc = current_npc
|
|
@@ -3163,6 +3183,7 @@ def enter_spool_mode(
|
|
|
3163
3183
|
Dict : The messages and output.
|
|
3164
3184
|
|
|
3165
3185
|
"""
|
|
3186
|
+
|
|
3166
3187
|
command_history = CommandHistory()
|
|
3167
3188
|
npc_info = f" (NPC: {npc.name})" if npc else ""
|
|
3168
3189
|
print(f"Entering spool mode{npc_info}. Type '/sq' to exit spool mode.")
|
|
@@ -2,13 +2,21 @@ tool_name: "internet_search"
|
|
|
2
2
|
description: Searches the web for information based on a query in order to verify timiely details (e.g. current events) or to corroborate information in uncertain situations. Should be mainly only used when users specifically request a search, otherwise an LLMs basic knowledge should be sufficient.
|
|
3
3
|
inputs:
|
|
4
4
|
- query
|
|
5
|
+
- provider: ''
|
|
5
6
|
steps:
|
|
6
7
|
- engine: "python"
|
|
7
8
|
code: |
|
|
8
9
|
from npcsh.search import search_web
|
|
10
|
+
from npcsh.npc_sysenv import NPCSH_SEARCH_PROVIDER
|
|
9
11
|
query = "{{ query }}"
|
|
12
|
+
provider = '{{ provider }}'
|
|
13
|
+
if provider.strip() != '':
|
|
14
|
+
results = search_web(query, num_results=5, provider = provider)
|
|
15
|
+
else:
|
|
16
|
+
results = search_web(query, num_results=5, provider = NPCSH_SEARCH_PROVIDER)
|
|
17
|
+
|
|
10
18
|
print('QUERY in tool', query)
|
|
11
|
-
results = search_web(query, num_results=5)
|
|
19
|
+
results = search_web(query, num_results=5, provider = NPCSH_SEARCH_PROVIDER)
|
|
12
20
|
print('RESULTS in tool', results)
|
|
13
21
|
- engine: "natural"
|
|
14
22
|
code: |
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
context: |
|
|
2
2
|
The npcsh NPC team is devoted to providing a safe and helpful
|
|
3
3
|
environment for users where they can work and be as successful as possible.
|
|
4
4
|
npcsh is a command-line tool that makes it easy for users to harness
|
|
5
|
-
the power of LLMs from a command line shell.
|
|
5
|
+
the power of LLMs from a command line shell.
|
|
6
|
+
databases:
|
|
7
|
+
- ~/npcsh_history.db
|
|
8
|
+
mcp_servers:
|
|
9
|
+
- /path/to/mcp/server.py
|
|
10
|
+
- @npm for server
|
|
11
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: npcsh
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.31
|
|
4
4
|
Summary: npcsh is a command line tool for integrating LLMs into everyday workflows and for orchestrating teams of NPCs.
|
|
5
5
|
Home-page: https://github.com/cagostino/npcsh
|
|
6
6
|
Author: Christopher Agostino
|
|
@@ -112,22 +112,23 @@ Interested to stay in the loop and to hear the latest and greatest about `npcsh`
|
|
|
112
112
|
## TLDR Cheat Sheet
|
|
113
113
|
Users can take advantage of `npcsh` through its custom shell or through a command-line interface (CLI) tool. Below is a cheat sheet that shows how to use `npcsh` commands in both the shell and the CLI. For the npcsh commands to work, one must activate `npcsh` by typing it in a shell.
|
|
114
114
|
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
115
118
|
| Task | npc CLI | npcsh |
|
|
116
119
|
|----------|----------|----------|
|
|
117
120
|
| Ask a generic question | npc 'prompt' | 'prompt' |
|
|
118
121
|
| Compile an NPC | npc compile /path/to/npc.npc | /compile /path/to/npc.npc |
|
|
119
122
|
| Computer use | npc plonk -n 'npc_name' -sp 'task for plonk to carry out '| /plonk -n 'npc_name' -sp 'task for plonk to carry out ' |
|
|
120
123
|
| Conjure an NPC team from context and templates | npc init -t 'template1, template2' -ctx 'context' | /conjure -t 'template1, 'template2' -ctx 'context' |
|
|
121
|
-
| Enter a chat with an NPC (NPC needs to be compiled first) | npc npc_name | /npc_name |
|
|
124
|
+
| Enter a chat with an NPC (NPC needs to be compiled first) | npc chat -n npc_name | /spool npc=<npc_name> |
|
|
122
125
|
| Generate image | npc vixynt 'prompt' | /vixynt prompt |
|
|
123
126
|
| Get a sample LLM response | npc sample 'prompt' | /sample prompt for llm |
|
|
124
|
-
| Invoke a tool | npc tool {tool_name} -args --flags | /tool_name -args --flags |
|
|
125
|
-
| Search locally | npc tool local_search -args --flags | /local_search -args --flags |
|
|
126
127
|
| Search for a term in the npcsh_db only in conversations with a specific npc | npc rag -n 'npc_name' -f 'filename' -q 'query' | /rag -n 'npc_name' -f 'filename' -q 'query' |
|
|
127
|
-
| Search the web | npc search -
|
|
128
|
+
| Search the web | npc search -q "cal golden bears football schedule" -sp perplexity | /search -p perplexity 'cal bears football schedule' |
|
|
128
129
|
| Serve an NPC team | npc serve --port 5337 --cors='http://localhost:5137/' | /serve --port 5337 --cors='http://localhost:5137/' |
|
|
129
130
|
| Screenshot analysis | npc ots | /ots |
|
|
130
|
-
| Voice Chat | npc whisper 'npc_name' | /whisper |
|
|
131
|
+
| Voice Chat | npc whisper -n 'npc_name' | /whisper |
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
## Python Examples
|
|
@@ -725,19 +726,6 @@ The code in the visible section of your VS Code window appears to be a script fo
|
|
|
725
726
|
In summary, this code automates the process of capturing a screenshot, saving it with a unique filename, and analyzing that image for specific content or patterns.
|
|
726
727
|
|
|
727
728
|
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
```npcsh
|
|
731
|
-
npcsh> What is the biggest file in my current folder?
|
|
732
|
-
|
|
733
|
-
LLM suggests the following bash command: ls -S | head -n 1
|
|
734
|
-
|
|
735
|
-
Running command: ls -S | head -n 1
|
|
736
|
-
|
|
737
|
-
Command executed with output: image_20241111_000033.png
|
|
738
|
-
|
|
739
|
-
I ran the command ls -S | head -n 1 in your current folder. This command sorts all files by size in descending order and then selects the first entry, which represents the largest file. The result of this operation shows that the biggest file in your current folder is image_20241111_000033.png.
|
|
740
|
-
|
|
741
729
|
```
|
|
742
730
|
|
|
743
731
|
```npcsh
|
|
@@ -869,7 +857,7 @@ and then the associated image :
|
|
|
869
857
|
An important facet that makes `npcsh` so powerful is the ability to pipe outputs from one tool call to another. This allows for the chaining of commands and the creation of complex workflows. For example, you can use the output of a search to generate an image, or you can use the output of an image analysis to generate a report. Here is an example of how this might look in practice:
|
|
870
858
|
```npcsh
|
|
871
859
|
npcsh> what is the gdp of russia in 2024? | /vixynt 'generate an image that contains {0}'
|
|
872
|
-
|
|
860
|
+
```
|
|
873
861
|
### Executing Bash Commands
|
|
874
862
|
You can execute bash commands directly within npcsh. The LLM can also generate and execute bash commands based on your natural language requests.
|
|
875
863
|
For example:
|
|
@@ -1167,7 +1155,10 @@ Search can be accomplished through the `/search` macro. You can specify the prov
|
|
|
1167
1155
|
you must set a perplexity api key as an environment variable as described above. The default provider is duckduckgo.
|
|
1168
1156
|
|
|
1169
1157
|
NOTE: while google is an available search engine, they recently implemented changes (early 2025) that make the python google search package no longer as reliable.
|
|
1170
|
-
|
|
1158
|
+
Duckduckgo's search toool also givies rate limit errors often, so until a more robust
|
|
1159
|
+
solution is implemented for it, Perplexity's will be the most reliable.
|
|
1160
|
+
|
|
1161
|
+
|
|
1171
1162
|
|
|
1172
1163
|
|
|
1173
1164
|
```npcsh
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
npcsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
npcsh/audio.py,sha256=DsRJ4Fq30kuq820dBwNy5otiZ7IFaRLSXYc1RZ4qlOk,5938
|
|
3
|
-
npcsh/cli.py,sha256=
|
|
3
|
+
npcsh/cli.py,sha256=2lKzc5bvPvvY_Er1_8JL3Fjbn-K_7Swj8Y1Z5nXDxB8,17118
|
|
4
4
|
npcsh/command_history.py,sha256=epzP6okq03Jk1FpnC_Vr-yZPloXgmv0JcVy4h1RcVVI,17131
|
|
5
5
|
npcsh/conversation.py,sha256=h-OfKwP88o9YYzQW1lx-dguN_lxIVTWxkmpJBLt2_1Q,8953
|
|
6
6
|
npcsh/data_models.py,sha256=pUoSQtHEWpQUdgd2TRpPYB6mUmEtyaPgKPHuKtU3MW4,721
|
|
7
7
|
npcsh/dataframes.py,sha256=OPVtc2q976R8c93HkE6tIl9hFOsDgwaFQEKQQAmNC1g,5263
|
|
8
8
|
npcsh/embeddings.py,sha256=CJMivZZZKUH2Ck2VK9LWKgjVRgpbzd32OabM3czKiFQ,5547
|
|
9
9
|
npcsh/helpers.py,sha256=aiK6kzf1jEYTHFssSxMOhPWDIcRvE0jXyrxWqh0coek,18992
|
|
10
|
-
npcsh/image.py,sha256=
|
|
10
|
+
npcsh/image.py,sha256=7mNDmtcOGPqkgahdf3F1rbViTwgEvi2PlPeFuSd6Dvo,10429
|
|
11
11
|
npcsh/image_gen.py,sha256=PZQfFBtyXQuxfs1x2mJGL4RkudnKdzZp5Xem9gSevG0,2047
|
|
12
12
|
npcsh/knowledge_graph.py,sha256=YIE0SJmUUfYrn1GqG6L7lWG0dIsQBun7A5CeA86PO6o,31442
|
|
13
13
|
npcsh/llm_funcs.py,sha256=lhjhyua11UyKE5mQLJ7ziDtSNVelHKBFqr0QSKrSAYc,68254
|
|
14
14
|
npcsh/load_data.py,sha256=Vh6YGxFVGWBMcn4cDrIgy8sC7QGCrWk0niJyR3l-k9U,1967
|
|
15
15
|
npcsh/main.py,sha256=rpf_2ysx3cR3eHsrvZApprJ-3D3-OrWcJ15bM1bc97I,81
|
|
16
16
|
npcsh/model_runner.py,sha256=riS6Hx3M7mj5erMm7OwBA8yufXYseVEbMYTRSfaDh2Y,6427
|
|
17
|
-
npcsh/npc_compiler.py,sha256=
|
|
17
|
+
npcsh/npc_compiler.py,sha256=Dy5MJG-NHwNayZKiMA1oFEkPPJ75Hnxvenf09x53Nec,105284
|
|
18
18
|
npcsh/npc_sysenv.py,sha256=g5LPYo8g6jlKd22fWVGghanLCr7tqjxytKvFbu0k-C0,11505
|
|
19
19
|
npcsh/plonk.py,sha256=ewdkX6K1V9kLFkrNsQ5oGXLiuFaLev9mxXBY-B0PKus,9926
|
|
20
20
|
npcsh/response.py,sha256=DFh6uoIw06SqPqKGv9DGHzoltprUHJSz6ZxgFBZRzX8,22478
|
|
21
|
-
npcsh/search.py,sha256=
|
|
21
|
+
npcsh/search.py,sha256=hIgqb_ymEfZMPLt5p-EZzLW_kaESmvlCyqKwB5ieFWI,8828
|
|
22
22
|
npcsh/serve.py,sha256=Zy47IdaGCt5ziGnQ5KHTQH1K7xXyo7trwUMVDOLNxvU,48246
|
|
23
|
-
npcsh/shell.py,sha256=
|
|
24
|
-
npcsh/shell_helpers.py,sha256=
|
|
23
|
+
npcsh/shell.py,sha256=BElVJf9cFj-AG2hCvmiavwDdZzsxLXP5XxMylJV17WI,18857
|
|
24
|
+
npcsh/shell_helpers.py,sha256=KaIegrlVS4fd-z1m9weP3iPkaIJgZgCdpOeNgmCGkec,116069
|
|
25
25
|
npcsh/stream.py,sha256=gEwanrb5g4Fmu10fVN-3Gu_i434GWtE6zNZrhjQJ6EA,21995
|
|
26
26
|
npcsh/video.py,sha256=Fv9Sii6LIEOI6D_1eoEu7DA8Es3mUYxEPcX3dac2Lt0,1935
|
|
27
27
|
npcsh/npc_team/corca.npc,sha256=9qs7922thBESU4r5GRygqAjvg9zvhQyMYqqyb4wwSew,662
|
|
28
28
|
npcsh/npc_team/foreman.npc,sha256=WqB8jLfBToGmr8c1vip1KOnTHxfXlGXwDUGnZoDMQr0,327
|
|
29
|
-
npcsh/npc_team/npcsh.ctx,sha256=
|
|
29
|
+
npcsh/npc_team/npcsh.ctx,sha256=cJW1HXtTihQ970iF_53rsyysGFa-E6u3BjAHGb1tMPI,380
|
|
30
30
|
npcsh/npc_team/sibiji.npc,sha256=MJZHU9xXmvUbZvwpX1wWinvkrwYiKm1J63t37l0EYGE,202
|
|
31
31
|
npcsh/npc_team/assembly_lines/test_pipeline.py,sha256=GKIcqw0fXDHsUDfMvu7GTj5cfPnqs7aX5xxiKPs2xCc,5657
|
|
32
32
|
npcsh/npc_team/templates/analytics/celona.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -40,37 +40,37 @@ npcsh/npc_team/templates/software/welxor.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
|
40
40
|
npcsh/npc_team/tools/bash_executer.tool,sha256=Myn87qJ6u-oWzZLZkd6TjxXE_TT-z3oGh5Wzs2TcD3I,836
|
|
41
41
|
npcsh/npc_team/tools/calculator.tool,sha256=ZKmQ0VusuJj8Ib5MDqC8MTDaqWIZCxzpazWPVkYZqYc,197
|
|
42
42
|
npcsh/npc_team/tools/code_executor.tool,sha256=L0gerbPkDgykgwvto_aKC8oUOrfv5lF2DhE51JEUFHM,511
|
|
43
|
-
npcsh/npc_team/tools/generic_search.tool,sha256=
|
|
43
|
+
npcsh/npc_team/tools/generic_search.tool,sha256=6RFEZJK6HmEbuvpSnQctUGxchmQYjAwQlMcJGzu_OS4,1094
|
|
44
44
|
npcsh/npc_team/tools/image_generation.tool,sha256=CaTkdjxWLFtMAghPvZnToMSwHbMQVusojhd9R9jybmI,577
|
|
45
45
|
npcsh/npc_team/tools/local_search.tool,sha256=g9Hc_Xx08fc6lu1IHvdwYU_18KxcOoHDwvIAfrGmn3U,6852
|
|
46
46
|
npcsh/npc_team/tools/npcsh_executor.tool,sha256=mavPowr8qXyPUuqRGqb5u1L8motyFoAyb4Xni4AjlFg,178
|
|
47
47
|
npcsh/npc_team/tools/screen_cap.tool,sha256=v7l54PWWdgszdd-n_DFqI9nyMlBSeYeNIfQsdFYSZ_4,1389
|
|
48
48
|
npcsh/npc_team/tools/sql_executor.tool,sha256=kEgxpb_9QUJpj8MEbzJY-isATG6Pi3KfVuffpwaoESM,808
|
|
49
|
-
npcsh-0.3.
|
|
50
|
-
npcsh-0.3.
|
|
51
|
-
npcsh-0.3.
|
|
52
|
-
npcsh-0.3.
|
|
53
|
-
npcsh-0.3.
|
|
54
|
-
npcsh-0.3.
|
|
55
|
-
npcsh-0.3.
|
|
56
|
-
npcsh-0.3.
|
|
57
|
-
npcsh-0.3.
|
|
58
|
-
npcsh-0.3.
|
|
59
|
-
npcsh-0.3.
|
|
60
|
-
npcsh-0.3.
|
|
61
|
-
npcsh-0.3.
|
|
62
|
-
npcsh-0.3.
|
|
63
|
-
npcsh-0.3.
|
|
64
|
-
npcsh-0.3.
|
|
65
|
-
npcsh-0.3.
|
|
66
|
-
npcsh-0.3.
|
|
67
|
-
npcsh-0.3.
|
|
68
|
-
npcsh-0.3.
|
|
69
|
-
npcsh-0.3.
|
|
70
|
-
npcsh-0.3.
|
|
71
|
-
npcsh-0.3.
|
|
72
|
-
npcsh-0.3.
|
|
73
|
-
npcsh-0.3.
|
|
74
|
-
npcsh-0.3.
|
|
75
|
-
npcsh-0.3.
|
|
76
|
-
npcsh-0.3.
|
|
49
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/bash_executer.tool,sha256=Myn87qJ6u-oWzZLZkd6TjxXE_TT-z3oGh5Wzs2TcD3I,836
|
|
50
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/calculator.tool,sha256=ZKmQ0VusuJj8Ib5MDqC8MTDaqWIZCxzpazWPVkYZqYc,197
|
|
51
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/celona.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/code_executor.tool,sha256=L0gerbPkDgykgwvto_aKC8oUOrfv5lF2DhE51JEUFHM,511
|
|
53
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/corca.npc,sha256=9qs7922thBESU4r5GRygqAjvg9zvhQyMYqqyb4wwSew,662
|
|
54
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/eriane.npc,sha256=5z6L-RjEouEp06SLOzkQoOCEi0eb1K-CxVnvyIbNK3g,299
|
|
55
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/foreman.npc,sha256=WqB8jLfBToGmr8c1vip1KOnTHxfXlGXwDUGnZoDMQr0,327
|
|
56
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/generic_search.tool,sha256=6RFEZJK6HmEbuvpSnQctUGxchmQYjAwQlMcJGzu_OS4,1094
|
|
57
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/image_generation.tool,sha256=CaTkdjxWLFtMAghPvZnToMSwHbMQVusojhd9R9jybmI,577
|
|
58
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/lineru.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/local_search.tool,sha256=g9Hc_Xx08fc6lu1IHvdwYU_18KxcOoHDwvIAfrGmn3U,6852
|
|
60
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/maurawa.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/npcsh.ctx,sha256=cJW1HXtTihQ970iF_53rsyysGFa-E6u3BjAHGb1tMPI,380
|
|
62
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/npcsh_executor.tool,sha256=mavPowr8qXyPUuqRGqb5u1L8motyFoAyb4Xni4AjlFg,178
|
|
63
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/raone.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/screen_cap.tool,sha256=v7l54PWWdgszdd-n_DFqI9nyMlBSeYeNIfQsdFYSZ_4,1389
|
|
65
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/sibiji.npc,sha256=MJZHU9xXmvUbZvwpX1wWinvkrwYiKm1J63t37l0EYGE,202
|
|
66
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/slean.npc,sha256=to3-d7qWMzhrYAeXalzNqVdt_3wROFGEfhprVXDttos,326
|
|
67
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/sql_executor.tool,sha256=kEgxpb_9QUJpj8MEbzJY-isATG6Pi3KfVuffpwaoESM,808
|
|
68
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/test_pipeline.py,sha256=GKIcqw0fXDHsUDfMvu7GTj5cfPnqs7aX5xxiKPs2xCc,5657
|
|
69
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/turnic.npc,sha256=odTFzQTN01-xaWXvjoC698htaFi6mvrzfKMAob8Yqb0,335
|
|
70
|
+
npcsh-0.3.31.data/data/npcsh/npc_team/welxor.npc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
|
+
npcsh-0.3.31.dist-info/licenses/LICENSE,sha256=j0YPvce7Ng9e32zYOu0EmXjXeJ0Nwawd0RA3uSGGH4E,1070
|
|
72
|
+
npcsh-0.3.31.dist-info/METADATA,sha256=Tas3A6_9dSVxgqBPiYZcTcdsFIWyCXmcEQsuXDQ6IPo,82638
|
|
73
|
+
npcsh-0.3.31.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
74
|
+
npcsh-0.3.31.dist-info/entry_points.txt,sha256=Y2rAM_m1er_Effxc0DXtGh36sC1FOUfefqGAt6vEte0,64
|
|
75
|
+
npcsh-0.3.31.dist-info/top_level.txt,sha256=kHSNgKMCkfjV95-DH0YSp1LLBi0HXdF3w57j7MQON3E,6
|
|
76
|
+
npcsh-0.3.31.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|