loki-mode 7.16.0 → 7.17.0
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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/agents/hub_install.py +652 -0
- package/autonomy/lib/assets_bundle.py +446 -0
- package/autonomy/loki +450 -8
- package/dashboard/__init__.py +1 -1
- package/dashboard/static/index.html +12 -17
- package/docs/INSTALLATION.md +1 -1
- package/docs/R10-MARKETPLACE-PLAN.md +137 -0
- package/docs/R8-SHAREABLE-TEAM-ASSETS-PLAN.md +129 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
package/autonomy/loki
CHANGED
|
@@ -613,6 +613,7 @@ show_help() {
|
|
|
613
613
|
echo " loki quick \"add dark mode\" # Single-task mode (3 iters max)"
|
|
614
614
|
echo " loki demo # 60-second interactive demo"
|
|
615
615
|
echo " loki init -t saas-starter # Scaffold from template"
|
|
616
|
+
echo " loki template install <src> # Install a community PRD template"
|
|
616
617
|
echo ""
|
|
617
618
|
echo " # Session ops + observability"
|
|
618
619
|
echo " loki status [--json] # Current status"
|
|
@@ -621,6 +622,7 @@ show_help() {
|
|
|
621
622
|
echo " loki doctor [--json] # System prereq + skill symlinks"
|
|
622
623
|
echo " loki logs # Tail recent log output"
|
|
623
624
|
echo " loki export json|markdown|csv|timeline # Export session"
|
|
625
|
+
echo " loki assets export team.tgz # Export shareable team assets (redacted)"
|
|
624
626
|
echo " loki cleanup # Kill orphaned processes"
|
|
625
627
|
echo ""
|
|
626
628
|
echo " # Providers + model routing"
|
|
@@ -6298,6 +6300,187 @@ cmd_export() {
|
|
|
6298
6300
|
esac
|
|
6299
6301
|
}
|
|
6300
6302
|
|
|
6303
|
+
# R8: Shareable team assets. Bundles a team's invested, reusable assets
|
|
6304
|
+
# (cross-project + project memory/learnings, the agent registry, PRD
|
|
6305
|
+
# templates, council config, optionally the R5 wiki) into a portable,
|
|
6306
|
+
# REDACTED tarball, and re-imports them into another project or fresh clone.
|
|
6307
|
+
#
|
|
6308
|
+
# Scope vs cmd_export: cmd_export emits a per-run SESSION SNAPSHOT
|
|
6309
|
+
# (json/md/csv/timeline) and is NOT portable or redacted. cmd_assets emits a
|
|
6310
|
+
# portable, redacted TEAM-ASSET tarball -- different scope, different artifact.
|
|
6311
|
+
# Redaction REUSES the single proof_redact chokepoint via the
|
|
6312
|
+
# autonomy/lib/assets_bundle.py helper. No second redactor or parallel exporter.
|
|
6313
|
+
cmd_assets() {
|
|
6314
|
+
local subcommand="${1:-help}"
|
|
6315
|
+
shift 2>/dev/null || true
|
|
6316
|
+
|
|
6317
|
+
local helper="$_LOKI_SCRIPT_DIR/lib/assets_bundle.py"
|
|
6318
|
+
if [ ! -f "$helper" ]; then
|
|
6319
|
+
echo -e "${RED}Error: assets helper not found at $helper${NC}" >&2
|
|
6320
|
+
return 1
|
|
6321
|
+
fi
|
|
6322
|
+
if ! command -v python3 &>/dev/null; then
|
|
6323
|
+
echo -e "${RED}Error: python3 is required for 'loki assets'${NC}" >&2
|
|
6324
|
+
return 1
|
|
6325
|
+
fi
|
|
6326
|
+
|
|
6327
|
+
# Project dir holds .loki/ (memory, council, wiki). Default to cwd.
|
|
6328
|
+
local project_dir
|
|
6329
|
+
project_dir="$(pwd)"
|
|
6330
|
+
|
|
6331
|
+
# repo_root holds agents/types.json + templates/. The export and import
|
|
6332
|
+
# roots are DELIBERATELY ASYMMETRIC (not a bug):
|
|
6333
|
+
# - EXPORT reads from the loki install ($SKILL_DIR), where a team's
|
|
6334
|
+
# edited registry / templates actually live and are read at runtime
|
|
6335
|
+
# (autonomy/loki:9781, 8840 read templates from $SKILL_DIR; cmd_agent
|
|
6336
|
+
# reads agents/types.json from the install first).
|
|
6337
|
+
# - IMPORT writes to the current working directory (the root of the
|
|
6338
|
+
# target clone the user is setting up), NEVER back into the install.
|
|
6339
|
+
# Writing into $SKILL_DIR would clobber the live install's shipped
|
|
6340
|
+
# registry / templates with redacted copies.
|
|
6341
|
+
# Honest limitation: agents/templates restore relative to cwd, so run
|
|
6342
|
+
# `loki assets import` from the root of the target clone. A global-install
|
|
6343
|
+
# user must copy the restored agents/ + templates/ into their install for
|
|
6344
|
+
# loki to read them at runtime (memory/learnings/council/wiki are unaffected
|
|
6345
|
+
# -- those restore to $HOME/.loki and <project>/.loki and take effect
|
|
6346
|
+
# immediately).
|
|
6347
|
+
local export_repo_root="${SKILL_DIR:-$(cd "$_LOKI_SCRIPT_DIR/.." && pwd)}"
|
|
6348
|
+
local import_repo_root="$project_dir"
|
|
6349
|
+
|
|
6350
|
+
case "$subcommand" in
|
|
6351
|
+
--help|-h|help|"")
|
|
6352
|
+
echo -e "${BOLD}loki assets${NC} - Export/import shareable team assets (R8)"
|
|
6353
|
+
echo ""
|
|
6354
|
+
echo "Bundles a team's reusable assets into a portable, redacted"
|
|
6355
|
+
echo "tarball so setup compounds into shared, importable value."
|
|
6356
|
+
echo ""
|
|
6357
|
+
echo "Usage:"
|
|
6358
|
+
echo " loki assets export <bundle.tgz> [--wiki] [--categories a,b,c]"
|
|
6359
|
+
echo " loki assets import <bundle.tgz> [--no-merge] [--into-install]"
|
|
6360
|
+
echo " loki assets inspect <bundle.tgz>"
|
|
6361
|
+
echo ""
|
|
6362
|
+
echo "Assets bundled (default):"
|
|
6363
|
+
echo " learnings ~/.loki/learnings/*.jsonl (cross-project)"
|
|
6364
|
+
echo " memory <project>/.loki/memory/** (episodic/semantic/skills)"
|
|
6365
|
+
echo " agents agents/types.json (agent registry)"
|
|
6366
|
+
echo " templates templates/*.md (PRD templates)"
|
|
6367
|
+
echo " council <project>/.loki/council/*.json (council config/state)"
|
|
6368
|
+
echo " wiki <project>/.loki/wiki/** (opt-in via --wiki)"
|
|
6369
|
+
echo ""
|
|
6370
|
+
echo "All bundled content is redacted via the proof_redact chokepoint:"
|
|
6371
|
+
echo "secrets, keys, tokens, and absolute home/repo paths are stripped"
|
|
6372
|
+
echo "before the bundle is written. Originals on disk are never changed."
|
|
6373
|
+
echo ""
|
|
6374
|
+
echo "Restore locations on import:"
|
|
6375
|
+
echo " learnings -> \$HOME/.loki/learnings (effective immediately)"
|
|
6376
|
+
echo " memory -> <cwd>/.loki/memory (effective immediately)"
|
|
6377
|
+
echo " council -> <cwd>/.loki/council (effective immediately)"
|
|
6378
|
+
echo " wiki -> <cwd>/.loki/wiki (effective immediately)"
|
|
6379
|
+
echo " agents -> <cwd>/agents/types.json"
|
|
6380
|
+
echo " templates -> <cwd>/templates/*.md"
|
|
6381
|
+
echo "Run import from the ROOT of the target clone. Note: agents and"
|
|
6382
|
+
echo "templates are read by loki from its install dir at runtime. On a"
|
|
6383
|
+
echo "global install, pass --into-install so agents/templates restore"
|
|
6384
|
+
echo "into the install dir and are read at runtime (default is cwd,"
|
|
6385
|
+
echo "which suits a repo-clone where loki runs from the clone root)."
|
|
6386
|
+
echo ""
|
|
6387
|
+
echo "Examples:"
|
|
6388
|
+
echo " loki assets export team-assets.tgz"
|
|
6389
|
+
echo " loki assets export team-assets.tgz --wiki"
|
|
6390
|
+
echo " loki assets import team-assets.tgz # merge learnings, overwrite rest"
|
|
6391
|
+
echo " loki assets import team-assets.tgz --no-merge"
|
|
6392
|
+
echo " loki assets inspect team-assets.tgz # show manifest only"
|
|
6393
|
+
return 0
|
|
6394
|
+
;;
|
|
6395
|
+
export)
|
|
6396
|
+
local out_path="${1:-}"
|
|
6397
|
+
if [ -z "$out_path" ]; then
|
|
6398
|
+
echo -e "${RED}Usage: loki assets export <bundle.tgz> [--wiki] [--categories a,b,c]${NC}" >&2
|
|
6399
|
+
return 1
|
|
6400
|
+
fi
|
|
6401
|
+
shift 2>/dev/null || true
|
|
6402
|
+
if ! _export_check_overwrite "$out_path"; then
|
|
6403
|
+
return 1
|
|
6404
|
+
fi
|
|
6405
|
+
echo "Bundling team assets (redacting secrets and paths)..."
|
|
6406
|
+
if LOKI_ASSETS_HOME="$HOME" LOKI_ASSETS_REPO="$export_repo_root" \
|
|
6407
|
+
LOKI_ASSETS_PROJECT="$project_dir" \
|
|
6408
|
+
python3 "$helper" export "$out_path" "$@"; then
|
|
6409
|
+
echo -e "${GREEN}Bundle written: $out_path${NC}"
|
|
6410
|
+
else
|
|
6411
|
+
echo -e "${RED}Export failed${NC}" >&2
|
|
6412
|
+
return 1
|
|
6413
|
+
fi
|
|
6414
|
+
;;
|
|
6415
|
+
import)
|
|
6416
|
+
local bundle_path="${1:-}"
|
|
6417
|
+
if [ -z "$bundle_path" ]; then
|
|
6418
|
+
echo -e "${RED}Usage: loki assets import <bundle.tgz> [--no-merge] [--into-install]${NC}" >&2
|
|
6419
|
+
return 1
|
|
6420
|
+
fi
|
|
6421
|
+
shift 2>/dev/null || true
|
|
6422
|
+
if [ ! -f "$bundle_path" ]; then
|
|
6423
|
+
echo -e "${RED}Error: bundle not found: $bundle_path${NC}" >&2
|
|
6424
|
+
return 1
|
|
6425
|
+
fi
|
|
6426
|
+
# --into-install: restore agents/templates into the loki install
|
|
6427
|
+
# ($SKILL_DIR) so a global-install user has them read at runtime,
|
|
6428
|
+
# instead of into cwd. Strip the flag before passing the rest to
|
|
6429
|
+
# the helper (the helper does not understand it). The install dir
|
|
6430
|
+
# is the same source export reads from, so this is the symmetric
|
|
6431
|
+
# round-trip for a global install. Off by default (cwd is safe).
|
|
6432
|
+
local _import_args=()
|
|
6433
|
+
local arg
|
|
6434
|
+
for arg in "$@"; do
|
|
6435
|
+
if [ "$arg" = "--into-install" ]; then
|
|
6436
|
+
import_repo_root="$export_repo_root"
|
|
6437
|
+
else
|
|
6438
|
+
_import_args+=("$arg")
|
|
6439
|
+
fi
|
|
6440
|
+
done
|
|
6441
|
+
if [ "$import_repo_root" = "$export_repo_root" ]; then
|
|
6442
|
+
echo "Importing team assets (agents/templates -> install dir: $import_repo_root)..."
|
|
6443
|
+
else
|
|
6444
|
+
echo "Importing team assets into this project/clone (cwd)..."
|
|
6445
|
+
fi
|
|
6446
|
+
# Bash 3.2 (macOS) errors on "${arr[@]}" when the array is empty
|
|
6447
|
+
# and set -u is active; guard with the count.
|
|
6448
|
+
if [ "${#_import_args[@]}" -gt 0 ]; then
|
|
6449
|
+
LOKI_ASSETS_HOME="$HOME" LOKI_ASSETS_REPO="$import_repo_root" \
|
|
6450
|
+
LOKI_ASSETS_PROJECT="$project_dir" \
|
|
6451
|
+
python3 "$helper" import "$bundle_path" "${_import_args[@]}"
|
|
6452
|
+
else
|
|
6453
|
+
LOKI_ASSETS_HOME="$HOME" LOKI_ASSETS_REPO="$import_repo_root" \
|
|
6454
|
+
LOKI_ASSETS_PROJECT="$project_dir" \
|
|
6455
|
+
python3 "$helper" import "$bundle_path"
|
|
6456
|
+
fi
|
|
6457
|
+
if [ $? -eq 0 ]; then
|
|
6458
|
+
echo -e "${GREEN}Import complete${NC}"
|
|
6459
|
+
else
|
|
6460
|
+
echo -e "${RED}Import failed${NC}" >&2
|
|
6461
|
+
return 1
|
|
6462
|
+
fi
|
|
6463
|
+
;;
|
|
6464
|
+
inspect)
|
|
6465
|
+
local bundle_path="${1:-}"
|
|
6466
|
+
if [ -z "$bundle_path" ]; then
|
|
6467
|
+
echo -e "${RED}Usage: loki assets inspect <bundle.tgz>${NC}" >&2
|
|
6468
|
+
return 1
|
|
6469
|
+
fi
|
|
6470
|
+
if [ ! -f "$bundle_path" ]; then
|
|
6471
|
+
echo -e "${RED}Error: bundle not found: $bundle_path${NC}" >&2
|
|
6472
|
+
return 1
|
|
6473
|
+
fi
|
|
6474
|
+
python3 "$helper" inspect "$bundle_path"
|
|
6475
|
+
;;
|
|
6476
|
+
*)
|
|
6477
|
+
echo -e "${RED}Unknown subcommand: $subcommand${NC}" >&2
|
|
6478
|
+
echo "Run 'loki assets --help' for usage."
|
|
6479
|
+
return 1
|
|
6480
|
+
;;
|
|
6481
|
+
esac
|
|
6482
|
+
}
|
|
6483
|
+
|
|
6301
6484
|
# Guard: check if output file exists and warn before overwriting
|
|
6302
6485
|
_export_check_overwrite() {
|
|
6303
6486
|
local output="$1"
|
|
@@ -9633,6 +9816,22 @@ cmd_init() {
|
|
|
9633
9816
|
echo -e "Selected: ${CYAN}$template_name${NC} ($(_get_template_label "$template_name"))"
|
|
9634
9817
|
fi
|
|
9635
9818
|
|
|
9819
|
+
# R10: a hub-installed template (.loki/templates/<name>.md) is also valid.
|
|
9820
|
+
# Resolve it via agents/hub_install.py (validates the name as a safe id).
|
|
9821
|
+
local _installed_tpl=""
|
|
9822
|
+
local _hub_py_init="$SKILL_DIR/agents/hub_install.py"
|
|
9823
|
+
[ -f "$_hub_py_init" ] || _hub_py_init="agents/hub_install.py"
|
|
9824
|
+
if [[ -f "$_hub_py_init" ]]; then
|
|
9825
|
+
_installed_tpl=$(TPL_NAME="$template_name" HUB_PY="$_hub_py_init" python3 -c "
|
|
9826
|
+
import os
|
|
9827
|
+
import importlib.util as ilu
|
|
9828
|
+
sp = ilu.spec_from_file_location('loki_hub_install', os.environ.get('HUB_PY'))
|
|
9829
|
+
m = ilu.module_from_spec(sp); sp.loader.exec_module(m)
|
|
9830
|
+
p = m.installed_template_path(os.environ['TPL_NAME'])
|
|
9831
|
+
print(p or '')
|
|
9832
|
+
" 2>/dev/null)
|
|
9833
|
+
fi
|
|
9834
|
+
|
|
9636
9835
|
# Validate template_name against known list before filesystem lookup
|
|
9637
9836
|
local _tpl_valid=false
|
|
9638
9837
|
for _tpl_check in "${TEMPLATE_NAMES[@]}"; do
|
|
@@ -9641,6 +9840,9 @@ cmd_init() {
|
|
|
9641
9840
|
break
|
|
9642
9841
|
fi
|
|
9643
9842
|
done
|
|
9843
|
+
if [[ -n "$_installed_tpl" ]]; then
|
|
9844
|
+
_tpl_valid=true
|
|
9845
|
+
fi
|
|
9644
9846
|
if ! $_tpl_valid; then
|
|
9645
9847
|
echo -e "${RED}Unknown template: $template_name${NC}"
|
|
9646
9848
|
echo ""
|
|
@@ -9649,18 +9851,23 @@ cmd_init() {
|
|
|
9649
9851
|
echo " $tname"
|
|
9650
9852
|
done
|
|
9651
9853
|
echo ""
|
|
9652
|
-
echo "Run 'loki init --list' for details."
|
|
9854
|
+
echo "Run 'loki init --list' for built-in details, 'loki template list' for installed."
|
|
9653
9855
|
exit 1
|
|
9654
9856
|
fi
|
|
9655
9857
|
|
|
9656
9858
|
# Resolve template file
|
|
9657
9859
|
local template_file=""
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9860
|
+
if [[ -n "$_installed_tpl" && -f "$_installed_tpl" ]]; then
|
|
9861
|
+
template_file="$_installed_tpl"
|
|
9862
|
+
fi
|
|
9863
|
+
if [[ -z "$template_file" ]]; then
|
|
9864
|
+
for dir in "$SKILL_DIR/templates" "$SKILL_DIR/examples"; do
|
|
9865
|
+
if [[ -f "$dir/${template_name}.md" ]]; then
|
|
9866
|
+
template_file="$dir/${template_name}.md"
|
|
9867
|
+
break
|
|
9868
|
+
fi
|
|
9869
|
+
done
|
|
9870
|
+
fi
|
|
9664
9871
|
|
|
9665
9872
|
if [[ -z "$template_file" ]]; then
|
|
9666
9873
|
echo -e "${RED}Unknown template: $template_name${NC}"
|
|
@@ -13094,6 +13301,9 @@ main() {
|
|
|
13094
13301
|
export)
|
|
13095
13302
|
cmd_export "$@"
|
|
13096
13303
|
;;
|
|
13304
|
+
assets)
|
|
13305
|
+
cmd_assets "$@"
|
|
13306
|
+
;;
|
|
13097
13307
|
config)
|
|
13098
13308
|
cmd_config "$@"
|
|
13099
13309
|
;;
|
|
@@ -13173,6 +13383,9 @@ main() {
|
|
|
13173
13383
|
agent)
|
|
13174
13384
|
cmd_agent "$@"
|
|
13175
13385
|
;;
|
|
13386
|
+
template)
|
|
13387
|
+
cmd_template "$@"
|
|
13388
|
+
;;
|
|
13176
13389
|
state)
|
|
13177
13390
|
cmd_state "$@"
|
|
13178
13391
|
;;
|
|
@@ -19562,6 +19775,104 @@ cmd_completions() {
|
|
|
19562
19775
|
esac
|
|
19563
19776
|
}
|
|
19564
19777
|
|
|
19778
|
+
cmd_template() {
|
|
19779
|
+
local subcommand="${1:-list}"
|
|
19780
|
+
shift 2>/dev/null || true
|
|
19781
|
+
|
|
19782
|
+
local script_dir
|
|
19783
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19784
|
+
local hub_py="${script_dir}/../agents/hub_install.py"
|
|
19785
|
+
[ -f "$hub_py" ] || hub_py="agents/hub_install.py"
|
|
19786
|
+
|
|
19787
|
+
case "$subcommand" in
|
|
19788
|
+
install)
|
|
19789
|
+
local source="${1:-}"
|
|
19790
|
+
if [ -z "$source" ]; then
|
|
19791
|
+
echo -e "${RED}Usage: loki template install <source>${NC}"
|
|
19792
|
+
echo " source: local path, git repo URL, or raw manifest URL"
|
|
19793
|
+
return 1
|
|
19794
|
+
fi
|
|
19795
|
+
if [ ! -f "$hub_py" ]; then
|
|
19796
|
+
echo -e "${RED}Error: agents/hub_install.py not found${NC}"
|
|
19797
|
+
return 1
|
|
19798
|
+
fi
|
|
19799
|
+
local result
|
|
19800
|
+
if result=$(python3 "$hub_py" install-template "$source" 2>&1); then
|
|
19801
|
+
TPL_RESULT="$result" python3 - << 'PYEOF'
|
|
19802
|
+
import json, os
|
|
19803
|
+
r = json.loads(os.environ["TPL_RESULT"])
|
|
19804
|
+
print(f"Installed template: {r['name']} ({r.get('label','')})")
|
|
19805
|
+
desc = r.get("description") or ""
|
|
19806
|
+
if desc:
|
|
19807
|
+
print(f" {desc}")
|
|
19808
|
+
print(f" body: {r.get('path','')}")
|
|
19809
|
+
print(f" source: {r.get('source','')}")
|
|
19810
|
+
ig = r.get("_ignored_executable_fields") or []
|
|
19811
|
+
if ig:
|
|
19812
|
+
print(f" NOTE: ignored executable-looking fields (never run): {', '.join(ig)}")
|
|
19813
|
+
print(f"Use with: loki init --template {r['name']}")
|
|
19814
|
+
PYEOF
|
|
19815
|
+
else
|
|
19816
|
+
echo -e "${RED}Install failed:${NC} $result"
|
|
19817
|
+
return 1
|
|
19818
|
+
fi
|
|
19819
|
+
;;
|
|
19820
|
+
|
|
19821
|
+
list|installed)
|
|
19822
|
+
echo -e "${BOLD}Hub-installed Templates${NC}"
|
|
19823
|
+
echo ""
|
|
19824
|
+
if [ ! -f "$hub_py" ]; then
|
|
19825
|
+
echo " (none)"
|
|
19826
|
+
else
|
|
19827
|
+
local _tpls_json
|
|
19828
|
+
_tpls_json="$(python3 "$hub_py" list-templates 2>/dev/null)"
|
|
19829
|
+
HUB_ITEMS="$_tpls_json" python3 - << 'PYEOF'
|
|
19830
|
+
import json, os
|
|
19831
|
+
try:
|
|
19832
|
+
items = json.loads(os.environ.get("HUB_ITEMS", "") or "[]")
|
|
19833
|
+
except Exception:
|
|
19834
|
+
items = []
|
|
19835
|
+
if not items:
|
|
19836
|
+
print(" (none)")
|
|
19837
|
+
else:
|
|
19838
|
+
for t in items:
|
|
19839
|
+
print(f" {t.get('name',''):24s} {t.get('label','')}")
|
|
19840
|
+
print(f"\n Total: {len(items)} installed template(s)")
|
|
19841
|
+
PYEOF
|
|
19842
|
+
fi
|
|
19843
|
+
;;
|
|
19844
|
+
|
|
19845
|
+
--help|-h|help)
|
|
19846
|
+
echo -e "${BOLD}loki template${NC} - PRD template marketplace (R10)"
|
|
19847
|
+
echo ""
|
|
19848
|
+
echo "Usage: loki template <command> [args]"
|
|
19849
|
+
echo ""
|
|
19850
|
+
echo "Commands:"
|
|
19851
|
+
echo " install <source> Install a community template (local/git/url manifest)"
|
|
19852
|
+
echo " list List templates installed from a hub source"
|
|
19853
|
+
echo " help Show this help"
|
|
19854
|
+
echo ""
|
|
19855
|
+
echo "Examples:"
|
|
19856
|
+
echo " loki template install ./my-template/manifest.json"
|
|
19857
|
+
echo " loki template install https://github.com/owner/loki-template-rust.git"
|
|
19858
|
+
echo " loki template list"
|
|
19859
|
+
echo ""
|
|
19860
|
+
echo "Installed templates are usable via 'loki init --template <name>'."
|
|
19861
|
+
echo "Built-in templates ship in templates/ (see 'loki init --list')."
|
|
19862
|
+
echo ""
|
|
19863
|
+
echo "Note: install is install-from-source (git/local/url). A hosted"
|
|
19864
|
+
echo "central hub registry is future work. Manifests are validated as"
|
|
19865
|
+
echo "DATA only; no code from a manifest is ever executed."
|
|
19866
|
+
echo ""
|
|
19867
|
+
;;
|
|
19868
|
+
*)
|
|
19869
|
+
echo -e "${RED}Unknown template command: $subcommand${NC}"
|
|
19870
|
+
echo "Run 'loki template help' for usage."
|
|
19871
|
+
return 1
|
|
19872
|
+
;;
|
|
19873
|
+
esac
|
|
19874
|
+
}
|
|
19875
|
+
|
|
19565
19876
|
# Agent type dispatch (v6.7.0)
|
|
19566
19877
|
cmd_agent() {
|
|
19567
19878
|
local subcommand="${1:-list}"
|
|
@@ -19592,6 +19903,20 @@ import json, sys, os
|
|
|
19592
19903
|
with open(os.environ["TYPES_FILE"]) as f:
|
|
19593
19904
|
agents = json.load(f)
|
|
19594
19905
|
|
|
19906
|
+
# R10: union built-in agents with hub-installed agents (.loki/agents/installed.json).
|
|
19907
|
+
try:
|
|
19908
|
+
import importlib.util as _ilu
|
|
19909
|
+
_hub_path = os.path.join(os.path.dirname(os.path.abspath(os.environ["TYPES_FILE"])), "hub_install.py")
|
|
19910
|
+
_spec = _ilu.spec_from_file_location("loki_hub_install", _hub_path)
|
|
19911
|
+
_hub = _ilu.module_from_spec(_spec)
|
|
19912
|
+
_spec.loader.exec_module(_hub)
|
|
19913
|
+
_seen = {a.get("type") for a in agents}
|
|
19914
|
+
for _inst in _hub.installed_agent_list():
|
|
19915
|
+
if _inst.get("type") not in _seen:
|
|
19916
|
+
agents.append(_inst)
|
|
19917
|
+
except Exception:
|
|
19918
|
+
pass
|
|
19919
|
+
|
|
19595
19920
|
filter_swarm = os.environ.get("FILTER_SWARM", "")
|
|
19596
19921
|
if filter_swarm and filter_swarm.startswith("--swarm"):
|
|
19597
19922
|
# Handle --swarm=X or --swarm X
|
|
@@ -19634,6 +19959,20 @@ import json, sys, os
|
|
|
19634
19959
|
with open(os.environ["TYPES_FILE"]) as f:
|
|
19635
19960
|
agents = json.load(f)
|
|
19636
19961
|
|
|
19962
|
+
# R10: include hub-installed agents in the lookup.
|
|
19963
|
+
try:
|
|
19964
|
+
import importlib.util as _ilu
|
|
19965
|
+
_hub_path = os.path.join(os.path.dirname(os.path.abspath(os.environ["TYPES_FILE"])), "hub_install.py")
|
|
19966
|
+
_spec = _ilu.spec_from_file_location("loki_hub_install", _hub_path)
|
|
19967
|
+
_hub = _ilu.module_from_spec(_spec)
|
|
19968
|
+
_spec.loader.exec_module(_hub)
|
|
19969
|
+
_seen = {a.get("type") for a in agents}
|
|
19970
|
+
for _inst in _hub.installed_agent_list():
|
|
19971
|
+
if _inst.get("type") not in _seen:
|
|
19972
|
+
agents.append(_inst)
|
|
19973
|
+
except Exception:
|
|
19974
|
+
pass
|
|
19975
|
+
|
|
19637
19976
|
target = os.environ["AGENT_TYPE"]
|
|
19638
19977
|
found = None
|
|
19639
19978
|
for a in agents:
|
|
@@ -19671,6 +20010,17 @@ PYEOF
|
|
|
19671
20010
|
import json, os
|
|
19672
20011
|
with open(os.environ['TYPES_FILE']) as f:
|
|
19673
20012
|
agents = json.load(f)
|
|
20013
|
+
try:
|
|
20014
|
+
import importlib.util as _ilu
|
|
20015
|
+
_hp = os.path.join(os.path.dirname(os.path.abspath(os.environ['TYPES_FILE'])), 'hub_install.py')
|
|
20016
|
+
_sp = _ilu.spec_from_file_location('loki_hub_install', _hp)
|
|
20017
|
+
_hub = _ilu.module_from_spec(_sp); _sp.loader.exec_module(_hub)
|
|
20018
|
+
_seen = {a.get('type') for a in agents}
|
|
20019
|
+
for _i in _hub.installed_agent_list():
|
|
20020
|
+
if _i.get('type') not in _seen:
|
|
20021
|
+
agents.append(_i)
|
|
20022
|
+
except Exception:
|
|
20023
|
+
pass
|
|
19674
20024
|
for a in agents:
|
|
19675
20025
|
if a['type'] == os.environ['AGENT_TYPE']:
|
|
19676
20026
|
print(a['persona'])
|
|
@@ -19742,6 +20092,17 @@ USER TASK: ${prompt}"
|
|
|
19742
20092
|
import json, os
|
|
19743
20093
|
with open(os.environ['TYPES_FILE']) as f:
|
|
19744
20094
|
agents = json.load(f)
|
|
20095
|
+
try:
|
|
20096
|
+
import importlib.util as _ilu
|
|
20097
|
+
_hp = os.path.join(os.path.dirname(os.path.abspath(os.environ['TYPES_FILE'])), 'hub_install.py')
|
|
20098
|
+
_sp = _ilu.spec_from_file_location('loki_hub_install', _hp)
|
|
20099
|
+
_hub = _ilu.module_from_spec(_sp); _sp.loader.exec_module(_hub)
|
|
20100
|
+
_seen = {a.get('type') for a in agents}
|
|
20101
|
+
for _i in _hub.installed_agent_list():
|
|
20102
|
+
if _i.get('type') not in _seen:
|
|
20103
|
+
agents.append(_i)
|
|
20104
|
+
except Exception:
|
|
20105
|
+
pass
|
|
19745
20106
|
for a in agents:
|
|
19746
20107
|
if a['type'] == os.environ['AGENT_TYPE']:
|
|
19747
20108
|
print(a['persona'])
|
|
@@ -19785,6 +20146,17 @@ for a in agents:
|
|
|
19785
20146
|
import json, os
|
|
19786
20147
|
with open(os.environ['TYPES_FILE']) as f:
|
|
19787
20148
|
agents = json.load(f)
|
|
20149
|
+
try:
|
|
20150
|
+
import importlib.util as _ilu
|
|
20151
|
+
_hp = os.path.join(os.path.dirname(os.path.abspath(os.environ['TYPES_FILE'])), 'hub_install.py')
|
|
20152
|
+
_sp = _ilu.spec_from_file_location('loki_hub_install', _hp)
|
|
20153
|
+
_hub = _ilu.module_from_spec(_sp); _sp.loader.exec_module(_hub)
|
|
20154
|
+
_seen = {a.get('type') for a in agents}
|
|
20155
|
+
for _i in _hub.installed_agent_list():
|
|
20156
|
+
if _i.get('type') not in _seen:
|
|
20157
|
+
agents.append(_i)
|
|
20158
|
+
except Exception:
|
|
20159
|
+
pass
|
|
19788
20160
|
for a in agents:
|
|
19789
20161
|
if a['type'] == os.environ['AGENT_TYPE']:
|
|
19790
20162
|
print(a['persona'])
|
|
@@ -19822,17 +20194,81 @@ $diff"
|
|
|
19822
20194
|
esac
|
|
19823
20195
|
;;
|
|
19824
20196
|
|
|
20197
|
+
install)
|
|
20198
|
+
# R10: install a community agent from a source (local path /
|
|
20199
|
+
# git repo / raw URL containing a manifest). DATA-ONLY install --
|
|
20200
|
+
# never executes code from the manifest. See agents/hub_install.py.
|
|
20201
|
+
local source="${1:-}"
|
|
20202
|
+
if [ -z "$source" ]; then
|
|
20203
|
+
echo -e "${RED}Usage: loki agent install <source>${NC}"
|
|
20204
|
+
echo " source: local path, git repo URL, or raw manifest URL"
|
|
20205
|
+
return 1
|
|
20206
|
+
fi
|
|
20207
|
+
local hub_py="${script_dir}/../agents/hub_install.py"
|
|
20208
|
+
[ -f "$hub_py" ] || hub_py="agents/hub_install.py"
|
|
20209
|
+
if [ ! -f "$hub_py" ]; then
|
|
20210
|
+
echo -e "${RED}Error: agents/hub_install.py not found${NC}"
|
|
20211
|
+
return 1
|
|
20212
|
+
fi
|
|
20213
|
+
local result
|
|
20214
|
+
if result=$(python3 "$hub_py" install-agent "$source" 2>&1); then
|
|
20215
|
+
AGENT_RESULT="$result" python3 - << 'PYEOF'
|
|
20216
|
+
import json, os
|
|
20217
|
+
r = json.loads(os.environ["AGENT_RESULT"])
|
|
20218
|
+
print(f"Installed agent: {r['type']} ({r.get('name','')})")
|
|
20219
|
+
print(f" swarm: {r.get('swarm','')}")
|
|
20220
|
+
print(f" source: {r.get('source','')}")
|
|
20221
|
+
ig = r.get("_ignored_executable_fields") or []
|
|
20222
|
+
if ig:
|
|
20223
|
+
print(f" NOTE: ignored executable-looking fields (never run): {', '.join(ig)}")
|
|
20224
|
+
print("Stored in .loki/agents/installed.json -- visible to 'loki agent list/info/run'.")
|
|
20225
|
+
PYEOF
|
|
20226
|
+
else
|
|
20227
|
+
echo -e "${RED}Install failed:${NC} $result"
|
|
20228
|
+
return 1
|
|
20229
|
+
fi
|
|
20230
|
+
;;
|
|
20231
|
+
|
|
20232
|
+
installed)
|
|
20233
|
+
# R10: list agents installed from a hub source.
|
|
20234
|
+
local hub_py="${script_dir}/../agents/hub_install.py"
|
|
20235
|
+
[ -f "$hub_py" ] || hub_py="agents/hub_install.py"
|
|
20236
|
+
echo -e "${BOLD}Hub-installed Agents${NC}"
|
|
20237
|
+
echo ""
|
|
20238
|
+
if [ ! -f "$hub_py" ]; then
|
|
20239
|
+
echo " (none)"
|
|
20240
|
+
else
|
|
20241
|
+
local _agents_json
|
|
20242
|
+
_agents_json="$(python3 "$hub_py" list-agents 2>/dev/null)"
|
|
20243
|
+
HUB_ITEMS="$_agents_json" python3 - << 'PYEOF'
|
|
20244
|
+
import json, os
|
|
20245
|
+
try:
|
|
20246
|
+
items = json.loads(os.environ.get("HUB_ITEMS", "") or "[]")
|
|
20247
|
+
except Exception:
|
|
20248
|
+
items = []
|
|
20249
|
+
if not items:
|
|
20250
|
+
print(" (none)")
|
|
20251
|
+
else:
|
|
20252
|
+
for a in items:
|
|
20253
|
+
print(f" {a.get('type',''):24s} {a.get('name','')} [{a.get('swarm','')}]")
|
|
20254
|
+
print(f"\n Total: {len(items)} installed agent(s)")
|
|
20255
|
+
PYEOF
|
|
20256
|
+
fi
|
|
20257
|
+
;;
|
|
20258
|
+
|
|
19825
20259
|
--help|-h|help)
|
|
19826
20260
|
echo -e "${BOLD}loki agent${NC} - Agent type dispatch (v6.7.0)"
|
|
19827
20261
|
echo ""
|
|
19828
20262
|
echo "Usage: loki agent <command> [args]"
|
|
19829
20263
|
echo ""
|
|
19830
20264
|
echo "Commands:"
|
|
19831
|
-
echo " list [--swarm NAME] List all agent types (
|
|
20265
|
+
echo " list [--swarm NAME] List all agent types (built-in + installed)"
|
|
19832
20266
|
echo " info <type> Show agent type details"
|
|
19833
20267
|
echo " run <type> \"<prompt>\" Single-shot: run prompt with agent persona"
|
|
19834
20268
|
echo " start <type> <prd|prompt> Full autonomous loop with agent persona"
|
|
19835
20269
|
echo " review [type] Code review with agent persona (default: ops-security)"
|
|
20270
|
+
echo " install <source> Install a community agent (local/git/url manifest)"
|
|
20271
|
+
echo " installed List agents installed from a hub source"
|
|
19836
20272
|
echo " help Show this help"
|
|
19837
20273
|
echo ""
|
|
19838
20274
|
echo "Examples:"
|
|
@@ -19842,6 +20278,12 @@ $diff"
|
|
|
19842
20278
|
echo " loki agent run eng-frontend \"Create a responsive navbar\""
|
|
19843
20279
|
echo " loki agent start eng-backend ./api-prd.md"
|
|
19844
20280
|
echo " loki agent review ops-security"
|
|
20281
|
+
echo " loki agent install ./my-agent/manifest.json"
|
|
20282
|
+
echo " loki agent install https://github.com/owner/loki-agent-rust.git"
|
|
20283
|
+
echo ""
|
|
20284
|
+
echo "Note: 'install' is install-from-source (git/local/url). A hosted"
|
|
20285
|
+
echo "central hub registry is future work. Manifests are validated as"
|
|
20286
|
+
echo "DATA only; no code from a manifest is ever executed."
|
|
19845
20287
|
echo ""
|
|
19846
20288
|
;;
|
|
19847
20289
|
*)
|