loki-mode 11.8.1 → 11.10.1

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 (90) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/backlog.py +15 -3
  4. package/autonomy/lib/workspace.py +95 -4
  5. package/autonomy/loki +189 -108
  6. package/autonomy/trigger-server.py +302 -4
  7. package/bin/loki +1 -1
  8. package/completions/_loki +34 -1
  9. package/completions/loki.bash +10 -3
  10. package/dashboard/__init__.py +1 -1
  11. package/docs/ARCHITECTURE.md +0 -1
  12. package/docs/CLI-REFERENCE.md +1 -1
  13. package/docs/COMPONENTS.md +1 -1
  14. package/docs/DEPLOY-PLAN.md +13 -3
  15. package/docs/INSTALLATION.md +1 -1
  16. package/docs/WORKSPACES.md +1 -1
  17. package/docs/dev/architecture-reference.md +1 -1
  18. package/docs/sentry-intake.md +15 -1
  19. package/docs/v10/D61-SPEED.md +2 -0
  20. package/docs/v10/PROGRESS.md +25 -1
  21. package/loki-ts/dist/loki.js +1016 -946
  22. package/mcp/__init__.py +1 -1
  23. package/package.json +2 -2
  24. package/packages/control-plane/dist/ask-tools-server.js +13 -4
  25. package/packages/control-plane/dist/server.js +457 -279
  26. package/packages/control-plane/src/server/diffstat.ts +10 -2
  27. package/packages/control-plane/src/server/legacy/routes-control.ts +8 -4
  28. package/packages/control-plane/src/server/routes/checkpoints.ts +11 -2
  29. package/packages/control-plane/ui/dist/assets/index-u8cd6TRQ.js +190 -0
  30. package/packages/control-plane/ui/dist/index.html +1 -1
  31. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  32. package/web-app/dist/assets/{AdminPage-BnIg9ilA.js → AdminPage-D3PgG7SH.js} +1 -1
  33. package/web-app/dist/assets/{Avatar-0BTVsQ2A.js → Avatar-Ct77hvlG.js} +1 -1
  34. package/web-app/dist/assets/{Badge-Bbq8CXgn.js → Badge-Cg_gZaJF.js} +1 -1
  35. package/web-app/dist/assets/{Button-CKD4n0ld.js → Button-i9r2G84n.js} +1 -1
  36. package/web-app/dist/assets/{CockpitPage-DJhLNLAz.js → CockpitPage-C3UyLXyp.js} +1 -1
  37. package/web-app/dist/assets/{ComparePage-Di2akuII.js → ComparePage-B1dXHga_.js} +1 -1
  38. package/web-app/dist/assets/{ErrorBoundary-9lhsYG-z.js → ErrorBoundary-CQ_xREw0.js} +1 -1
  39. package/web-app/dist/assets/{EvidenceReceiptPanel-CQDGXvDr.js → EvidenceReceiptPanel-DwUxd_Xi.js} +1 -1
  40. package/web-app/dist/assets/{GitHubIssuesPanel-Y_w2k9Ej.js → GitHubIssuesPanel-C0jAnuAd.js} +1 -1
  41. package/web-app/dist/assets/{GitHubPRsPanel-pMSQedCv.js → GitHubPRsPanel-B4pNXJMz.js} +1 -1
  42. package/web-app/dist/assets/{HomePage-CIAkiGdt.js → HomePage-BC9UTS1l.js} +2 -2
  43. package/web-app/dist/assets/{LoginPage-BES4Pk6k.js → LoginPage-CnpdwK8F.js} +1 -1
  44. package/web-app/dist/assets/{MagicPage-B154fMhi.js → MagicPage-Bj0lZuNp.js} +1 -1
  45. package/web-app/dist/assets/{MetricsPage-BcNyaiUO.js → MetricsPage-yyw3VnfX.js} +1 -1
  46. package/web-app/dist/assets/{NotFoundPage-D28FqYxG.js → NotFoundPage-LMxkJP15.js} +1 -1
  47. package/web-app/dist/assets/{ProjectPage-C_O3u8Jx.js → ProjectPage-2x0MRkNu.js} +3 -3
  48. package/web-app/dist/assets/{ProjectsPage-uqdahuPA.js → ProjectsPage-A8J8o1gj.js} +1 -1
  49. package/web-app/dist/assets/{SettingsPage-DLvVA9OZ.js → SettingsPage-fwvOVcRb.js} +1 -1
  50. package/web-app/dist/assets/{ShowcasePage-BAZP8vsm.js → ShowcasePage-DqI4sUwk.js} +1 -1
  51. package/web-app/dist/assets/{SystemSettingsPage-DPYZkLWh.js → SystemSettingsPage-CyytfNo_.js} +1 -1
  52. package/web-app/dist/assets/{TeamsPage-BgSyb5Pd.js → TeamsPage-BTTe76W1.js} +1 -1
  53. package/web-app/dist/assets/{TemplatesPage-D_Jh5VU1.js → TemplatesPage-CIp3OTlL.js} +1 -1
  54. package/web-app/dist/assets/{TerminalOutput-4v8poDKb.js → TerminalOutput-dX5L4ky-.js} +1 -1
  55. package/web-app/dist/assets/{activity-CE2b6kdw.js → activity-uHXr2AaF.js} +1 -1
  56. package/web-app/dist/assets/{bell-CxJDlLSR.js → bell-D6RbxRMo.js} +1 -1
  57. package/web-app/dist/assets/{bot-C2WuK4zw.js → bot-D31w2Mu6.js} +1 -1
  58. package/web-app/dist/assets/{check-81epVldw.js → check-CoKJksbr.js} +1 -1
  59. package/web-app/dist/assets/{chevron-left-B6EXh_3C.js → chevron-left-Bjx7oX7s.js} +1 -1
  60. package/web-app/dist/assets/{circle-alert-0iqoo-iy.js → circle-alert-DOAh8Jmi.js} +1 -1
  61. package/web-app/dist/assets/{clock-CFrBpNUp.js → clock-DgEXPNWH.js} +1 -1
  62. package/web-app/dist/assets/{cloud-BBSFhUT_.js → cloud-0dXJFzBv.js} +1 -1
  63. package/web-app/dist/assets/{code-xml-BCU2V1rq.js → code-xml-DytQ_bq7.js} +1 -1
  64. package/web-app/dist/assets/{database-D2hvO52K.js → database-Qyjryb72.js} +1 -1
  65. package/web-app/dist/assets/{dollar-sign-CXFA9b6T.js → dollar-sign-BzhTVy1e.js} +1 -1
  66. package/web-app/dist/assets/{file-code-corner-CqTCEEfS.js → file-code-corner-DTdSOALw.js} +1 -1
  67. package/web-app/dist/assets/{file-plus-DYFbkGbs.js → file-plus-VdjOG1RK.js} +1 -1
  68. package/web-app/dist/assets/{globe-DpYHLobk.js → globe-BhxNOfyM.js} +1 -1
  69. package/web-app/dist/assets/{hammer-CZ97SEYo.js → hammer-MQzrw8ee.js} +1 -1
  70. package/web-app/dist/assets/{index-DzswgpRo.js → index-DaxrMbHf.js} +3 -3
  71. package/web-app/dist/assets/{layers-2Tq0edx4.js → layers-C7nusTP-.js} +1 -1
  72. package/web-app/dist/assets/{loader-circle-BFP4kUX-.js → loader-circle-B1qBkgOY.js} +1 -1
  73. package/web-app/dist/assets/{lock-DkKdZH4d.js → lock-BdkOxK2O.js} +1 -1
  74. package/web-app/dist/assets/{package-ChOGD8yf.js → package-RVyK96Zn.js} +1 -1
  75. package/web-app/dist/assets/{plus-hggB1o6b.js → plus-ntmwFRrp.js} +1 -1
  76. package/web-app/dist/assets/{refresh-cw-DYwVLOeF.js → refresh-cw-BJ39b_PP.js} +1 -1
  77. package/web-app/dist/assets/{rotate-ccw-CUdY506q.js → rotate-ccw-uPx_-3vz.js} +1 -1
  78. package/web-app/dist/assets/{scroll-text-Wvidz5uN.js → scroll-text-D9qvXkj-.js} +1 -1
  79. package/web-app/dist/assets/{server-O11QmkCN.js → server-gs4xmD8Y.js} +1 -1
  80. package/web-app/dist/assets/{shield-alert-DXXx27uV.js → shield-alert-O2_YffGI.js} +1 -1
  81. package/web-app/dist/assets/{thumbs-up-DF8ivs3A.js → thumbs-up-B3RVBhQx.js} +1 -1
  82. package/web-app/dist/assets/{trash-2-LA6PW0Nf.js → trash-2-DEUt7qhq.js} +1 -1
  83. package/web-app/dist/assets/{trending-down-Bw_vLKHT.js → trending-down-oyTns4UZ.js} +1 -1
  84. package/web-app/dist/assets/{trending-up-tX8motha.js → trending-up-CdpZK0Oc.js} +1 -1
  85. package/web-app/dist/assets/{upload-CxtTWJd2.js → upload-D9sbjjC8.js} +1 -1
  86. package/web-app/dist/assets/{usePolling-D-P5Iofq.js → usePolling-6ognrnyV.js} +1 -1
  87. package/web-app/dist/assets/{user-dKTcuUFq.js → user-CBKc8QoI.js} +1 -1
  88. package/web-app/dist/index.html +1 -1
  89. package/memory/rag_injector.py +0 -161
  90. package/packages/control-plane/ui/dist/assets/index-DbLzr87u.js +0 -190
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.8.1
6
+ # Loki Mode v11.10.1
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
 
@@ -483,4 +483,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
483
483
 
484
484
  ---
485
485
 
486
- **v11.8.1 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.10.1 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.8.1
1
+ 11.10.1
@@ -196,6 +196,7 @@ def load_dag(path, group):
196
196
  raise ValueError("unit %s task text starts with '-' and would be read as an option" % uid)
197
197
  units.append({"n": n, "id": uid, "deps": deps[uid], "write_set": list(u.get("writeSet") or []),
198
198
  "task": task, "done": u.get("done") is True,
199
+ "base": str(u.get("base") or ""),
199
200
  "spec": u["spec"] if isinstance(u.get("spec"), str) and os.path.isabs(u["spec"]) else ""})
200
201
  return group, units
201
202
 
@@ -265,6 +266,17 @@ def main(argv):
265
266
  return die("this checkout's origin is %r, not %s; cd into a checkout of %s"
266
267
  % (origin_slug(top) or "unknown", a.repo, a.repo))
267
268
 
269
+ for u in dag_units:
270
+ b = u["base"]
271
+ if not b or re.match(r"^[0-9a-f]{7,64}$", b):
272
+ continue
273
+ # A ref-name base is resolved to a SHA; an unresolvable one fails loudly, never falls back to origin/HEAD.
274
+ r = git("rev-parse", "--verify", "-q", "--end-of-options", b + "^{commit}", cwd=top) if not b.startswith("-") else None
275
+ sha = r.stdout.strip() if r is not None and r.returncode == 0 else ""
276
+ if not re.match(r"^[0-9a-f]{40,64}$", sha):
277
+ return die("unit %s base %r is not a commit SHA or a resolvable ref" % (u["id"], b))
278
+ u["base"] = sha
279
+
268
280
  try:
269
281
  issues = ([{"number": n, "title": ""} for n in numbers] if numbers
270
282
  else list_issues(a.repo, a.label, env) if (a.all or a.label) else [])
@@ -315,7 +327,7 @@ def main(argv):
315
327
  "deps": [key_of[d] for d in u["deps"]],
316
328
  "env": {"LOKI_GROUP_ID": group, "LOKI_UNIT_ID": u["id"], "LOKI_UNIT_N": str(u["n"]),
317
329
  "LOKI_UNIT_DEPS": ",".join(u["deps"]), "LOKI_UNIT_WRITE_SET": "\n".join(u["write_set"])},
318
- "done": u["done"]}
330
+ "done": u["done"], "base": u["base"]}
319
331
  if u["spec"]: # frozen group acceptance for unit_mode (wall.ts)
320
332
  spec[k]["env"].update(LOKI_UNIT_SPEC=u["spec"], LOKI_SPEED="1")
321
333
  state = {k: {"status": "queued", "ok": None, "cost": None, "ran": False} for k in spec}
@@ -393,13 +405,13 @@ def main(argv):
393
405
  # Shared worktree prep (D51-B05): per-base lock, clean start point, deps copied.
394
406
  git("branch", "-D", s["branch"], cwd=top)
395
407
  try:
396
- worktree_prep.prepare_worktree(top, wt, s["branch"])
408
+ worktree_prep.prepare_worktree(top, wt, s["branch"], base=s.get("base") or None)
397
409
  r = None
398
410
  except (RuntimeError, subprocess.CalledProcessError) as e:
399
411
  msg = getattr(e, "stderr", None) or str(e)
400
412
  r = subprocess.CompletedProcess([], 1, "", msg)
401
413
  else:
402
- r = git("worktree", "add", "-B", s["branch"], wt, "HEAD", cwd=top)
414
+ r = git("worktree", "add", "-B", s["branch"], wt, s.get("base") or "HEAD", cwd=top)
403
415
  if r is not None and r.returncode != 0:
404
416
  err = (r.stderr.strip().splitlines() or ["git error"])[-1]
405
417
  state[k].update(status="FAILED: worktree: " + redact(err, token), ok=False)
@@ -585,6 +585,85 @@ def _dep_tokens(root):
585
585
  return toks
586
586
 
587
587
 
588
+ _SRC_EXT = (".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go")
589
+ _SKIP_DIRS = {"node_modules", ".git", "dist", "build", "vendor", "venv", ".venv", "__pycache__", ".loki"}
590
+ _SCAN_MAX_FILES = 400
591
+ _SCAN_MAX_BYTES = 262144
592
+ _JS_SPEC = re.compile(r"""(?:from\s*|require\s*\(\s*|import\s*\(?\s*)["']([^"']+)["']""")
593
+ _PY_IMPORT = re.compile(r"^\s*(?:from\s+([A-Za-z_][\w.]*)\s+import\b|import\s+([A-Za-z_][\w.]*))")
594
+ _GO_IMPORT = re.compile(r'^\s*(?:import\s+)?(?:[\w.]+\s+)?"([^"]+)"\s*$')
595
+ _SPEC_KEY = re.compile(r"""["']?(?:inputSpec|input|target)["']?\s*[:=]\s*["']?([^"',\s}]+)""")
596
+ _GEN_CONFIG = re.compile(
597
+ r"^(openapitools\.json|openapi-generator.*\.(?:ya?ml|json)|orval\.config\.\w+|\.orvalrc(?:\.\w+)?)$")
598
+
599
+
600
+ def _spec_hits(path, ext):
601
+ """Yield (line number, imported specifier) for one source file."""
602
+ text = _read(path)
603
+ if text is None or len(text) > _SCAN_MAX_BYTES:
604
+ return
605
+ for n, line in enumerate(text.splitlines(), 1):
606
+ if ext == ".py":
607
+ m = _PY_IMPORT.match(line)
608
+ if m:
609
+ yield n, (m.group(1) or m.group(2)).lower().replace("_", "-")
610
+ elif ext == ".go":
611
+ m = _GO_IMPORT.match(line)
612
+ if m:
613
+ yield n, m.group(1).lower()
614
+ else:
615
+ for m in _JS_SPEC.finditer(line):
616
+ yield n, m.group(1).lower()
617
+
618
+
619
+ def _import_evidence(root, ids):
620
+ """First file:line per sibling whose package/module name a source file imports (bounded scan)."""
621
+ found, seen = {}, 0
622
+ for dirpath, dirs, files in os.walk(root):
623
+ dirs[:] = sorted(d for d in dirs if d not in _SKIP_DIRS)
624
+ for fn in sorted(files):
625
+ ext = os.path.splitext(fn)[1]
626
+ if ext not in _SRC_EXT:
627
+ continue
628
+ seen += 1
629
+ if seen > _SCAN_MAX_FILES:
630
+ return found
631
+ path = os.path.join(dirpath, fn)
632
+ for n, spec in _spec_hits(path, ext):
633
+ if spec.startswith("."):
634
+ continue
635
+ for o, oids in ids.items():
636
+ if o not in found and any(spec == i or spec.startswith(i + "/") or spec.startswith(i + ".")
637
+ for i in oids):
638
+ found[o] = "%s:%d (imports %s)" % (os.path.relpath(path, root), n, spec)
639
+ return found
640
+
641
+
642
+ def _openapi_evidence(root, roots):
643
+ """file:line per sibling whose checkout holds the spec a client generator config points at."""
644
+ found = {}
645
+ try:
646
+ names = sorted(os.listdir(root))
647
+ except OSError:
648
+ return found
649
+ for fn in names:
650
+ path = os.path.join(root, fn)
651
+ if not _GEN_CONFIG.match(fn) or not os.path.isfile(path):
652
+ continue
653
+ text = _read(path) or ""
654
+ for n, line in enumerate(text.splitlines(), 1):
655
+ for m in _SPEC_KEY.finditer(line):
656
+ val = m.group(1)
657
+ if "://" in val:
658
+ continue
659
+ target = os.path.realpath(os.path.join(root, val))
660
+ for o, oroot in roots.items():
661
+ if oroot and o not in found and os.path.realpath(oroot) != os.path.realpath(root) and \
662
+ (target + os.sep).startswith(os.path.realpath(oroot) + os.sep):
663
+ found[o] = "%s:%d (spec %s)" % (fn, n, val)
664
+ return found
665
+
666
+
588
667
  def infer(name, workspaces, say=say):
589
668
  """Print suggested `after:` edges from manifests; never writes loki.yaml."""
590
669
  ws = workspaces.get(name)
@@ -598,7 +677,7 @@ def infer(name, workspaces, say=say):
598
677
  os.path.expanduser("~"), ".loki", "repos", _slug(e["repo"]))
599
678
  roots[e["repo"]] = root if os.path.isdir(root) else None
600
679
  ids = {e["repo"]: _identities(e, roots[e["repo"]]) if roots[e["repo"]] else set() for e in entries}
601
- proposed = {}
680
+ proposed, evidence = {}, {}
602
681
  for e in entries:
603
682
  repo = e["repo"]
604
683
  if not roots[repo]:
@@ -607,12 +686,21 @@ def infer(name, workspaces, say=say):
607
686
  continue
608
687
  toks = _dep_tokens(roots[repo])
609
688
  deps = list(e.get("after") or [])
610
- for other in entries:
611
- o = other["repo"]
612
- if o == repo or o in deps:
689
+ others = {x["repo"]: ids[x["repo"]] for x in entries if x["repo"] != repo}
690
+ imp = _import_evidence(roots[repo], others)
691
+ api = _openapi_evidence(roots[repo], {o: roots[o] for o in others})
692
+ for o in others:
693
+ if o in deps:
613
694
  continue
614
695
  if any(t == i or t.startswith(i + "/") for t in toks for i in ids[o]):
615
696
  deps.append(o)
697
+ evidence[(repo, o)] = "manifest dependency"
698
+ elif o in api:
699
+ deps.append(o)
700
+ evidence[(repo, o)] = api[o]
701
+ elif o in imp:
702
+ deps.append(o)
703
+ evidence[(repo, o)] = imp[o]
616
704
  proposed[repo] = deps
617
705
  try:
618
706
  order_repos({"repos": [{"repo": e["repo"], "after": proposed[e["repo"]]} for e in entries]})
@@ -623,6 +711,9 @@ def infer(name, workspaces, say=say):
623
711
  for e in entries:
624
712
  say("%s" % e["repo"])
625
713
  say(" after: [%s]" % ", ".join(proposed[e["repo"]]))
714
+ for d in proposed[e["repo"]]:
715
+ if (e["repo"], d) in evidence:
716
+ say(" %s: %s" % (d, evidence[(e["repo"], d)]))
626
717
  return 0
627
718
 
628
719