loki-mode 11.47.0 → 11.49.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.
Files changed (72) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/claude-flags.sh +37 -2
  4. package/autonomy/lib/claude_permissions.py +23 -3
  5. package/dashboard/__init__.py +1 -1
  6. package/docs/CLI-REFERENCE.md +1 -1
  7. package/docs/INSTALLATION.md +1 -1
  8. package/docs/environment-variables.md +28 -0
  9. package/loki-ts/dist/loki.js +1092 -1092
  10. package/mcp/__init__.py +1 -1
  11. package/package.json +2 -2
  12. package/packages/control-plane/dist/server.js +1 -0
  13. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  14. package/providers/model_catalog.json +16 -0
  15. package/src/policies/claude_permissions.js +68 -1
  16. package/web-app/dist/assets/{AdminPage-CZ9dEfIB.js → AdminPage-C1HHZc-J.js} +1 -1
  17. package/web-app/dist/assets/{Avatar-DujAUHDi.js → Avatar-wEFOQcHL.js} +1 -1
  18. package/web-app/dist/assets/{Badge-BFGA5sMq.js → Badge-Dc9sQtw_.js} +1 -1
  19. package/web-app/dist/assets/{Button-BAygWU3K.js → Button-BGp6VrBR.js} +1 -1
  20. package/web-app/dist/assets/{CockpitPage-4_NbNG2t.js → CockpitPage-BqjyCJa8.js} +1 -1
  21. package/web-app/dist/assets/{ComparePage-BqVSI8j-.js → ComparePage-BVXGR8HF.js} +1 -1
  22. package/web-app/dist/assets/{ErrorBoundary-D4esh0Po.js → ErrorBoundary-CH69sxaD.js} +1 -1
  23. package/web-app/dist/assets/{EvidenceReceiptPanel-BKD993kY.js → EvidenceReceiptPanel-D-CIV45K.js} +1 -1
  24. package/web-app/dist/assets/{GitHubIssuesPanel-CE9sUyyx.js → GitHubIssuesPanel-Dp4Ft5jA.js} +1 -1
  25. package/web-app/dist/assets/{GitHubPRsPanel-D_8M0f3L.js → GitHubPRsPanel-G-gu0P0R.js} +1 -1
  26. package/web-app/dist/assets/{HomePage-BRo7CzCf.js → HomePage-CvyHQCl9.js} +2 -2
  27. package/web-app/dist/assets/{LoginPage-BfILRf1-.js → LoginPage-XpHi-pV0.js} +1 -1
  28. package/web-app/dist/assets/{MagicPage-DUA0x44Q.js → MagicPage-BSmPnTXK.js} +1 -1
  29. package/web-app/dist/assets/{MetricsPage-C_cgrQFc.js → MetricsPage-C931Oabi.js} +1 -1
  30. package/web-app/dist/assets/{NotFoundPage-BkLESJYY.js → NotFoundPage-fWXhbQ9M.js} +1 -1
  31. package/web-app/dist/assets/{ProjectPage-4uJKYy6N.js → ProjectPage-VO_6GA0a.js} +3 -3
  32. package/web-app/dist/assets/{ProjectsPage-udqsbJU3.js → ProjectsPage-D3VyZ6c8.js} +1 -1
  33. package/web-app/dist/assets/{SettingsPage-KnMxTW-7.js → SettingsPage-shQpxQjv.js} +1 -1
  34. package/web-app/dist/assets/{ShowcasePage-BQ61Jeid.js → ShowcasePage-DtZch3K-.js} +1 -1
  35. package/web-app/dist/assets/{SystemSettingsPage-BWZ3hytq.js → SystemSettingsPage-DesmAV7u.js} +1 -1
  36. package/web-app/dist/assets/{TeamsPage-CIEiCIbQ.js → TeamsPage-CRQkBkx9.js} +1 -1
  37. package/web-app/dist/assets/{TemplatesPage-C2D9YjRR.js → TemplatesPage-C6nhbyrS.js} +1 -1
  38. package/web-app/dist/assets/{TerminalOutput-zEzopKzx.js → TerminalOutput-DGKcTFFe.js} +1 -1
  39. package/web-app/dist/assets/{activity-D6L-9OIS.js → activity-CVuv1ph2.js} +1 -1
  40. package/web-app/dist/assets/{bell-BrMGAPWi.js → bell-B1xDZ3LV.js} +1 -1
  41. package/web-app/dist/assets/{bot-1XHJmh2W.js → bot-CQVmG43s.js} +1 -1
  42. package/web-app/dist/assets/{check-D4hVla_R.js → check-B19ttfq9.js} +1 -1
  43. package/web-app/dist/assets/{chevron-left-CXcz0jNZ.js → chevron-left-DqUogX5b.js} +1 -1
  44. package/web-app/dist/assets/{circle-alert-aGzcd-0K.js → circle-alert-InQqmiUI.js} +1 -1
  45. package/web-app/dist/assets/{clock-DeCE1tPl.js → clock-CP0I5TCk.js} +1 -1
  46. package/web-app/dist/assets/{cloud-I97EopE2.js → cloud-DKGJYkpu.js} +1 -1
  47. package/web-app/dist/assets/{code-xml--VbtYyNQ.js → code-xml-BkL-4N9W.js} +1 -1
  48. package/web-app/dist/assets/{database-BqZMNZw4.js → database-BPKpzfBP.js} +1 -1
  49. package/web-app/dist/assets/{dollar-sign-jnlZgSPQ.js → dollar-sign-De9YPsGE.js} +1 -1
  50. package/web-app/dist/assets/{file-code-corner-DN0X80ZV.js → file-code-corner-DSN5T2Ag.js} +1 -1
  51. package/web-app/dist/assets/{file-plus-5Dm_ERqo.js → file-plus-BtdOs7ht.js} +1 -1
  52. package/web-app/dist/assets/{globe-BF7CeyOQ.js → globe-CggcgjDt.js} +1 -1
  53. package/web-app/dist/assets/{hammer-DVr5vwrD.js → hammer-CuBLOpnS.js} +1 -1
  54. package/web-app/dist/assets/{index-DfaI3_pA.js → index-rFaT3sTE.js} +3 -3
  55. package/web-app/dist/assets/{layers-BUYqrs21.js → layers-CWJGgbcJ.js} +1 -1
  56. package/web-app/dist/assets/{loader-circle-DCBrMAmc.js → loader-circle-CKh0Oblz.js} +1 -1
  57. package/web-app/dist/assets/{lock-BEGUDKkK.js → lock-CfXFgkO9.js} +1 -1
  58. package/web-app/dist/assets/{package-DoePV7Bp.js → package-C8mnUBlX.js} +1 -1
  59. package/web-app/dist/assets/{plus-DMTZOM4j.js → plus-EvGxVuun.js} +1 -1
  60. package/web-app/dist/assets/{refresh-cw-e5duny7P.js → refresh-cw-CDyZuh6Z.js} +1 -1
  61. package/web-app/dist/assets/{rotate-ccw-tTIYb8K2.js → rotate-ccw-FJx9akI_.js} +1 -1
  62. package/web-app/dist/assets/{scroll-text-BIthWabj.js → scroll-text-DPJjg6gB.js} +1 -1
  63. package/web-app/dist/assets/{server-CDT2z91H.js → server-J-Ia9p6W.js} +1 -1
  64. package/web-app/dist/assets/{shield-alert-BQRbTXQU.js → shield-alert--PN1Fn0v.js} +1 -1
  65. package/web-app/dist/assets/{thumbs-up-DOdq_J3X.js → thumbs-up-DrAu18vu.js} +1 -1
  66. package/web-app/dist/assets/{trash-2-Bm3DhnUz.js → trash-2-BOcW-2CM.js} +1 -1
  67. package/web-app/dist/assets/{trending-down-BJQf-LfU.js → trending-down-D0BBklCI.js} +1 -1
  68. package/web-app/dist/assets/{trending-up-DNAQ6LH_.js → trending-up-032Orpnw.js} +1 -1
  69. package/web-app/dist/assets/{upload-C344jljR.js → upload-n5LSoJlJ.js} +1 -1
  70. package/web-app/dist/assets/{usePolling-B4kVlTLX.js → usePolling-C5DYYKqa.js} +1 -1
  71. package/web-app/dist/assets/{user-B2G-aOXw.js → user-Co1n_361.js} +1 -1
  72. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Runs an autonomous software factory that knows what it is supposed to deliver and proves it did, with a signed receipt. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.47.0
6
+ # Loki Mode v11.49.0
7
7
 
8
8
  **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
9
9
 
@@ -476,4 +476,4 @@ Implemented, planned and deprecated items, with the version each landed in: `ski
476
476
 
477
477
  ---
478
478
 
479
- **v11.47.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
479
+ **v11.49.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.47.0
1
+ 11.49.0
@@ -6,7 +6,7 @@
6
6
  # Every value derives from RARV tier, complexity score, and budget config.
7
7
  #
8
8
  # Public API (all functions are pure: they read env + filesystem, write stdout).
9
- # loki_effort_for_tier <tier> [complexity] -- emit one of: low|medium|high|xhigh|max
9
+ # loki_effort_for_tier <tier> [complexity] [model] -- emit one of: low|medium|high|xhigh|max
10
10
  # loki_remaining_budget -- emit dollar amount remaining as plain int/float, OR empty when unlimited
11
11
  # loki_fallback_for_primary <model> -- emit fallback model alias (opus->sonnet, sonnet->haiku if allowed), OR empty when no fallback applies
12
12
  # loki_claude_flag_supported <flag> -- 0 if `claude --help` lists the flag, 1 otherwise
@@ -26,6 +26,7 @@ __LOKI_CLAUDE_FLAGS_SH_LOADED=1
26
26
  loki_effort_for_tier() {
27
27
  local tier="${1:-development}"
28
28
  local complexity="${2:-${LOKI_COMPLEXITY:-standard}}"
29
+ local model="${3:-}"
29
30
  local effort=""
30
31
  case "$tier" in
31
32
  planning) effort="xhigh" ;;
@@ -46,6 +47,27 @@ loki_effort_for_tier() {
46
47
  # xhigh stays xhigh; max not auto-reached.
47
48
  esac
48
49
  fi
50
+ # Clamp to the model's catalog effort.levels (mirror of effortForTier's model argument).
51
+ # A model with an empty levels list takes no effort parameter: emit nothing and callers omit --effort.
52
+ if [ -n "$model" ] && command -v python3 >/dev/null 2>&1; then
53
+ local catalog="${LOKI_MODEL_CATALOG:-${BASH_SOURCE[0]%/*}/../../providers/model_catalog.json}"
54
+ effort="$(python3 - "$catalog" "$model" "$effort" <<'PYEOF' 2>/dev/null || printf '%s' "$effort"
55
+ import json, sys
56
+ path, model, effort = sys.argv[1:4]
57
+ order = ["low", "medium", "high", "xhigh", "max"]
58
+ c = json.load(open(path))["providers"]["claude"]
59
+ mid = c.get("cli_aliases", {}).get(model, model)
60
+ levels = next((m.get("effort", {}).get("levels") for m in c["models"] if m["id"] == mid or m.get("alias") == model), None)
61
+ if levels is not None and len(levels) == 0:
62
+ effort = ""
63
+ elif levels and effort not in levels:
64
+ ok = [l for l in order if l in levels]
65
+ below = [l for l in ok if order.index(l) <= order.index(effort)]
66
+ effort = below[-1] if below else ok[0]
67
+ print(effort, end="")
68
+ PYEOF
69
+ )"
70
+ fi
49
71
  printf '%s' "$effort"
50
72
  }
51
73
 
@@ -1116,9 +1138,22 @@ loki_permission_policy_banner() {
1116
1138
  _loki_claude_permission_argv() {
1117
1139
  _LOKI_PERM_ARGV=(--dangerously-skip-permissions)
1118
1140
  _loki_permission_warn_unknown_once
1119
- [ "$(_loki_permission_policy_mode)" = "legacy" ] && return 0
1120
1141
  local _helper _out _a
1121
1142
  _helper="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/src/policies/claude_permissions.js"
1143
+ if [ "$(_loki_permission_policy_mode)" = "legacy" ]; then
1144
+ # w2-07: legacy keeps bypass but carries the default web/credential deny rules (same js source).
1145
+ # Unusable compiler or helper failure fails closed to plan, like compiled mode and the TS route.
1146
+ _LOKI_PERM_ARGV=(--permission-mode plan)
1147
+ if ! command -v node >/dev/null 2>&1 || [ ! -f "$_helper" ]; then
1148
+ echo "[loki] WARNING: legacy permission policy: compiler unavailable; using most restrictive mode (plan)" >&2
1149
+ return 0
1150
+ fi
1151
+ _out="$(node "$_helper" --legacy-args)" || return 0
1152
+ [ -n "$_out" ] || return 0
1153
+ _LOKI_PERM_ARGV=()
1154
+ while IFS= read -r _a; do _LOKI_PERM_ARGV+=("$_a"); done <<< "$_out"
1155
+ return 0
1156
+ fi
1122
1157
  _LOKI_PERM_ARGV=(--permission-mode plan)
1123
1158
  if ! command -v node >/dev/null 2>&1 || [ ! -f "$_helper" ]; then
1124
1159
  echo "[loki] WARNING: compiled permission policy: compiler unavailable; using most restrictive mode (plan)" >&2
@@ -14,7 +14,6 @@ import subprocess
14
14
  import sys
15
15
  from pathlib import Path
16
16
 
17
- _LEGACY = ["--dangerously-skip-permissions"]
18
17
  _FAIL_CLOSED = ["--permission-mode", "plan"]
19
18
  _unknown_warned = False
20
19
 
@@ -30,16 +29,37 @@ def _has_operator_policy(node: str | None, helper: Path, env: dict) -> bool:
30
29
  return done.stdout.strip() == "1"
31
30
 
32
31
 
32
+ def _legacy_argv(env: dict) -> list:
33
+ """Legacy bypass flag plus the default web/credential deny rules (w2-07), from the same js helper.
34
+
35
+ An unusable compiler fails closed to plan with a warning, like compiled mode and the TS route.
36
+ """
37
+ helper = Path(__file__).resolve().parents[2] / "src" / "policies" / "claude_permissions.js"
38
+ node = shutil.which("node")
39
+ if node is None or not helper.is_file():
40
+ print("[loki] WARNING: legacy permission policy: compiler unavailable; using most restrictive mode (plan)", file=sys.stderr)
41
+ return list(_FAIL_CLOSED)
42
+ try:
43
+ done = subprocess.run([node, str(helper), "--legacy-args"], capture_output=True, text=True,
44
+ timeout=30, env=dict(env), check=False)
45
+ except (OSError, subprocess.SubprocessError):
46
+ return list(_FAIL_CLOSED)
47
+ if done.stderr:
48
+ sys.stderr.write(done.stderr)
49
+ args = [a for a in done.stdout.split("\n") if a]
50
+ return args if done.returncode == 0 and args else list(_FAIL_CLOSED)
51
+
52
+
33
53
  def claude_permission_argv(project_dir: str | None = None, env: dict | None = None) -> list:
34
54
  env = os.environ if env is None else env
35
55
  mode = env.get("LOKI_PERMISSION_POLICY", "")
36
56
  if mode == "legacy":
37
- return list(_LEGACY)
57
+ return _legacy_argv(env)
38
58
  global _unknown_warned
39
59
  helper = Path(__file__).resolve().parents[2] / "src" / "policies" / "claude_permissions.js"
40
60
  node = shutil.which("node")
41
61
  if mode == "" and not _has_operator_policy(node, helper, env):
42
- return list(_LEGACY)
62
+ return _legacy_argv(env)
43
63
  if mode not in ("", "compiled") and not _unknown_warned:
44
64
  _unknown_warned = True
45
65
  print(f"[loki] WARNING: LOKI_PERMISSION_POLICY={mode}: unknown value; using compiled", file=sys.stderr)
@@ -7,6 +7,6 @@ Modules:
7
7
  control: Session control helpers (status, atomic writes, origin check)
8
8
  """
9
9
 
10
- __version__ = "11.47.0"
10
+ __version__ = "11.49.0"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -1,6 +1,6 @@
1
1
  # CLI reference
2
2
 
3
- Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.47.0. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.49.0. Do not edit by hand.
4
4
  Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
5
5
 
6
6
  | Command | Description |
@@ -2,7 +2,7 @@
2
2
 
3
3
  Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
4
4
 
5
- **Version:** v11.47.0
5
+ **Version:** v11.49.0
6
6
 
7
7
  **Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
8
8
 
@@ -95,6 +95,34 @@ model sees a countdown across the whole loop and wraps up instead of running out
95
95
  It is advisory only; `LOKI_BUDGET_LIMIT` is the enforcing cap. Unset, zero or a
96
96
  non-integer sends nothing.
97
97
 
98
+ ### Web access is now off by default
99
+
100
+ Claude workers can no longer search or fetch from the web, and cannot read secret
101
+ files, unless you opt in. This is intended, not a bug. A worker that follows a
102
+ prompt-injected instruction in a web page or a file could otherwise send your
103
+ credentials to an outside site, so the default denies the tools that make that
104
+ possible:
105
+
106
+ - `WebFetch` and `WebSearch` are denied.
107
+ - `Read` of anything matching `.env*` (so `.env`, `.env.local`, `.envrc`, `.env.prod`, `.env.keys`, and the templates `.env.example`, `.env.sample`, `.env.template`), `*.pem`, and anything under `.aws/` or `.ssh/` is denied, anywhere on disk. The templates are blocked too: a deny beats any allow, so they cannot be carved out of the glob without missing secret names.
108
+
109
+ This applies to every Claude route (shell, TypeScript and Python launch sites),
110
+ whether `LOKI_PERMISSION_POLICY` is `compiled` or `legacy`. If the policy cannot
111
+ be compiled (invalid `LOKI_WEB_ALLOW_DOMAINS`, or Node missing), Loki prints a
112
+ warning and runs in `plan` mode instead of skipping the rules. Punycode (`xn--`)
113
+ domains are rejected the same way.
114
+
115
+ This is not complete secret-file protection: `Read` denies do not stop
116
+ `Bash(cat .env)` under `--dangerously-skip-permissions`.
117
+
118
+ To turn web access back on:
119
+
120
+ | Setting | Effect |
121
+ |---|---|
122
+ | `LOKI_WEB_ALLOW_DOMAINS=docs.python.org,*.example.com` | Allows `WebFetch` for those hostnames only (comma list, ASCII hostnames). `WebSearch` stays denied. Enforced with `LOKI_PERMISSION_POLICY=compiled`; the legacy route keeps both web tools denied and warns. |
123
+ | `allow` entry for `WebFetch` or `WebSearch` in your `claude_permissions` policy | Keeps that tool enabled. |
124
+ | `LOKI_WEB_POLICY=off` | Disables this policy entirely: no web or credential deny rules, the previous behavior. |
125
+
98
126
  ## Steering the loop
99
127
 
100
128
  These control how the engine decides what to do next. Every one is on by