loki-mode 9.48.1 → 9.49.2
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/.github/workflows/loki-issue-to-pr.yml +1 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +166 -13
- package/autonomy/provider-offer.sh +47 -0
- package/autonomy/quickstart.sh +306 -9
- package/dashboard/__init__.py +1 -1
- package/dashboard/static/index.html +7 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/KNOWN-ISSUES.md +42 -0
- package/loki-ts/dist/loki.js +317 -317
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-PyyVXg4b.js → AdminPage-DpV2vW3y.js} +1 -1
- package/web-app/dist/assets/{Avatar-CTUlr_Xf.js → Avatar-BXeMYK1_.js} +1 -1
- package/web-app/dist/assets/{Badge-BQeXvmg8.js → Badge-D8WddQk1.js} +1 -1
- package/web-app/dist/assets/{Button-Dc6-P6pz.js → Button-CFzTTVeJ.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BspOJ3Fv.js → CockpitPage-D1eQe9QF.js} +4 -4
- package/web-app/dist/assets/{ComparePage-CFXIM--Z.js → ComparePage-uX3OPphr.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-C7vQYDW9.js → ErrorBoundary-wE3oxaG6.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-CqjsjTOs.js → EvidenceReceiptPanel-B_Wouz6N.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DyuNDMgD.js → GitHubIssuesPanel-DRlEeFuw.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BtAq20xF.js → GitHubPRsPanel-CCv6_I74.js} +2 -2
- package/web-app/dist/assets/{HomePage-BuVFOrO8.js → HomePage-EG-jq8nR.js} +1 -1
- package/web-app/dist/assets/{LoginPage-CuhhrxGb.js → LoginPage-CEOnBICH.js} +1 -1
- package/web-app/dist/assets/{MagicPage-D2KZPX3F.js → MagicPage-DeWaFdsG.js} +1 -1
- package/web-app/dist/assets/MetricsPage-CG8CuSSJ.js +6 -0
- package/web-app/dist/assets/{NotFoundPage-CTnnaWlL.js → NotFoundPage-Mz5rOat6.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-uJFaoM8-.js → ProjectPage-D2Fh6tVw.js} +8 -8
- package/web-app/dist/assets/{ProjectsPage-8lKAOBIW.js → ProjectsPage-B8cRWkWa.js} +2 -2
- package/web-app/dist/assets/{SettingsPage-D1BBd5qy.js → SettingsPage-DKpsst6x.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CmQ0n8iO.js → ShowcasePage-qab065PM.js} +1 -1
- package/web-app/dist/assets/SystemSettingsPage-9qmEH2Y6.js +1 -0
- package/web-app/dist/assets/{TeamsPage-BS0TtVUa.js → TeamsPage-CW6lvW-0.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-C2zPnnf2.js → TemplatesPage-B-a61T6a.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Dle1klqq.js → TerminalOutput-CJy13rAn.js} +1 -1
- package/web-app/dist/assets/{activity-DQp5U9f9.js → activity-CA4moIvC.js} +1 -1
- package/web-app/dist/assets/{bell-BqkTmgL7.js → bell-JyOeobLN.js} +1 -1
- package/web-app/dist/assets/{bot-DILhaIGH.js → bot-Cu4UwP5w.js} +1 -1
- package/web-app/dist/assets/{check-BC9x7oPm.js → check-Drzd8-9c.js} +1 -1
- package/web-app/dist/assets/{chevron-left--yqvAfjx.js → chevron-left-ClvdXm3Y.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DOH6PcgZ.js → circle-alert-CstyZfKG.js} +1 -1
- package/web-app/dist/assets/{clock-DKSDFsE6.js → clock-Bnz6tlQN.js} +1 -1
- package/web-app/dist/assets/{cloud-DRBU3JYs.js → cloud-IPIgE4P3.js} +1 -1
- package/web-app/dist/assets/{code-xml-D2LqszR9.js → code-xml-BOZbQiOt.js} +1 -1
- package/web-app/dist/assets/{database-D7ceedlh.js → database-CHclPjog.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-D0A47egY.js → dollar-sign-D6RFNgdZ.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CH_Qbtjo.js → file-code-corner-CNayCvOY.js} +1 -1
- package/web-app/dist/assets/{file-plus-CUNMjHk9.js → file-plus-BmVfFwsX.js} +1 -1
- package/web-app/dist/assets/folder-open-ChzGfLRr.js +11 -0
- package/web-app/dist/assets/{globe-gZnaGg8N.js → globe-DtXgCG3Z.js} +1 -1
- package/web-app/dist/assets/{hammer-BhJC5DMK.js → hammer-DCa0I_7V.js} +1 -1
- package/web-app/dist/assets/{index-BMmYYws0.js → index-Cu-njJ8o.js} +3 -3
- package/web-app/dist/assets/index-D98GzaW8.css +1 -0
- package/web-app/dist/assets/{layers-glXeoUbJ.js → layers-DxIhn7NZ.js} +1 -1
- package/web-app/dist/assets/{lightbulb-gXn8H0Lf.js → lightbulb-D7Pzhd06.js} +1 -1
- package/web-app/dist/assets/{loader-circle-Do2ke8xm.js → loader-circle-DXgc_u5I.js} +1 -1
- package/web-app/dist/assets/{lock-Bgplb1_n.js → lock-qRAVU53b.js} +1 -1
- package/web-app/dist/assets/{mail-j4Lo8hfB.js → mail-CHe3KyCw.js} +1 -1
- package/web-app/dist/assets/{minus-dhrzKSK5.js → minus-B8p0FoYZ.js} +1 -1
- package/web-app/dist/assets/{package-CInWQQ97.js → package-C5LDn8SI.js} +1 -1
- package/web-app/dist/assets/{plus-BpYvoLlZ.js → plus-CRd_FHOA.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-F6koqEgF.js → refresh-cw-DKoSN8s3.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CQ2W5S8f.js → rotate-ccw-Nf8zB8G0.js} +1 -1
- package/web-app/dist/assets/{save-DMCYGm06.js → save-B8ytQLgW.js} +1 -1
- package/web-app/dist/assets/{server-Bj8EX4Z1.js → server-D_VRDkaD.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CiYuulCU.js → shield-alert-PsDkSyFD.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BqEh1puP.js → thumbs-up-Da1QQhqo.js} +11 -6
- package/web-app/dist/assets/{trash-2-CCwouZJJ.js → trash-2-ChoylpGQ.js} +1 -1
- package/web-app/dist/assets/{trending-down-Cx1vhE4o.js → trending-down-CX2fUeho.js} +1 -1
- package/web-app/dist/assets/{trending-up-BUhVYJ2T.js → trending-up-CGyYgZH7.js} +1 -1
- package/web-app/dist/assets/{upload-D5IsZeFM.js → upload-KkeVyg67.js} +1 -1
- package/web-app/dist/assets/{usePolling-CJbfhFcH.js → usePolling-C5f4xrXD.js} +1 -1
- package/web-app/dist/assets/{user-BRLhezsD.js → user-WCGccIST.js} +1 -1
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +121 -1
- package/web-app/dist/assets/MetricsPage-DFEYJl9z.js +0 -6
- package/web-app/dist/assets/SystemSettingsPage-CSHaVyuD.js +0 -6
- package/web-app/dist/assets/copy-BKW4U4Qr.js +0 -6
- package/web-app/dist/assets/folder-open-CQ_SVq94.js +0 -6
- package/web-app/dist/assets/git-commit-horizontal-DQUBe0oD.js +0 -6
- package/web-app/dist/assets/index-84JUN_aA.css +0 -1
|
@@ -61,7 +61,7 @@ jobs:
|
|
|
61
61
|
# Pinned to a TAG, not @main. A moving ref would hand every user
|
|
62
62
|
# whatever main holds at the moment their issue is labeled, including a
|
|
63
63
|
# half-landed release. Bump this line deliberately.
|
|
64
|
-
uses: asklokesh/loki-mode/.github/actions/issue-to-pr@v9.
|
|
64
|
+
uses: asklokesh/loki-mode/.github/actions/issue-to-pr@v9.49.2
|
|
65
65
|
env:
|
|
66
66
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
67
67
|
with:
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v9.
|
|
6
|
+
# Loki Mode v9.49.2
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
470
470
|
|
|
471
471
|
---
|
|
472
472
|
|
|
473
|
-
**v9.
|
|
473
|
+
**v9.49.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.
|
|
1
|
+
9.49.2
|
package/autonomy/loki
CHANGED
|
@@ -13538,10 +13538,34 @@ except Exception:
|
|
|
13538
13538
|
"$HOME/.cline/skills/loki-mode:Cline CLI"
|
|
13539
13539
|
"$HOME/.aider/skills/loki-mode:Aider CLI"
|
|
13540
13540
|
)
|
|
13541
|
+
# SEVERITY DEPENDS ON WHOSE SKILL IT IS (v9.48.x). A dangling skill symlink
|
|
13542
|
+
# used to block unconditionally, so a stale link left by an old checkout
|
|
13543
|
+
# path exited 1 on a HEALTHY machine -- while the Provider Availability
|
|
13544
|
+
# section three lines above said that same provider was "not installed".
|
|
13545
|
+
# Doctor contradicted itself on one screen and told the user to fix a tool
|
|
13546
|
+
# they do not have.
|
|
13547
|
+
#
|
|
13548
|
+
# The link only blocks when it belongs to the provider a build would
|
|
13549
|
+
# actually launch. Anything else is inert state: still reported, with the
|
|
13550
|
+
# dangling target and the fix, but not a reason to refuse to start.
|
|
13551
|
+
#
|
|
13552
|
+
# `|| true` is mandatory under `set -euo pipefail`: the accessor returns
|
|
13553
|
+
# non-zero when no provider resolves (a bare call would abort doctor), and
|
|
13554
|
+
# an empty id then makes every entry non-blocking -- the same direction the
|
|
13555
|
+
# No-AI-provider blocker above already covers.
|
|
13556
|
+
local _selected_provider=""
|
|
13557
|
+
if declare -f effective_provider_id >/dev/null 2>&1; then
|
|
13558
|
+
_selected_provider="$(effective_provider_id 2>/dev/null || true)"
|
|
13559
|
+
fi
|
|
13541
13560
|
for entry in "${skill_dirs[@]}"; do
|
|
13542
13561
|
local sdir="${entry%%:*}"
|
|
13543
13562
|
local sname="${entry#*:}"
|
|
13544
13563
|
local short_path="${sdir/$HOME/~}"
|
|
13564
|
+
# Provider id from the directory, never a parallel list: `.claude` ->
|
|
13565
|
+
# `claude`. A fifth hand-maintained list is how the lists in this repo
|
|
13566
|
+
# have drifted from auto_detect_provider before (v8.76.0, v8.82.0).
|
|
13567
|
+
local _sid="${sdir#"$HOME"/.}"
|
|
13568
|
+
_sid="${_sid%%/*}"
|
|
13545
13569
|
if [ -f "$sdir/SKILL.md" ]; then
|
|
13546
13570
|
echo -e " ${GREEN}PASS${NC} $sname ${DIM}$short_path${NC}"
|
|
13547
13571
|
pass_count=$((pass_count + 1))
|
|
@@ -13560,10 +13584,22 @@ except Exception:
|
|
|
13560
13584
|
_target=$(ls -ld "$sdir" 2>/dev/null | sed -e 's/^[^>]*-> //')
|
|
13561
13585
|
[ -n "$_target" ] || _target="unknown"
|
|
13562
13586
|
fi
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13587
|
+
# Blocking ONLY for the provider a build would actually use. The
|
|
13588
|
+
# non-blocking arm is a WARN rather than a non-counted FAIL on
|
|
13589
|
+
# purpose: a red FAIL badge that never reaches `N failed` or the
|
|
13590
|
+
# `Blocking (N)` list makes the summary disagree with the screen.
|
|
13591
|
+
# Either way the dangling target and the fix are still printed --
|
|
13592
|
+
# the stale link is reported, never silently swallowed.
|
|
13593
|
+
if [ -n "$_selected_provider" ] && [ "$_sid" = "$_selected_provider" ]; then
|
|
13594
|
+
echo -e " ${RED}FAIL${NC} $sname ${DIM}(broken symlink -> $_target)${NC}"
|
|
13595
|
+
echo -e " ${YELLOW}Fix: loki setup-skill${NC}"
|
|
13596
|
+
_doctor_block "$sname is a broken symlink. Fix: loki setup-skill"
|
|
13597
|
+
fail_count=$((fail_count + 1))
|
|
13598
|
+
else
|
|
13599
|
+
echo -e " ${YELLOW}WARN${NC} $sname ${DIM}(broken symlink -> $_target)${NC}"
|
|
13600
|
+
echo -e " ${YELLOW}Fix: loki setup-skill${NC}"
|
|
13601
|
+
warn_count=$((warn_count + 1))
|
|
13602
|
+
fi
|
|
13567
13603
|
else
|
|
13568
13604
|
echo -e " ${YELLOW}WARN${NC} $sname ${DIM}(not found - run 'loki setup-skill')${NC}"
|
|
13569
13605
|
warn_count=$((warn_count + 1))
|
|
@@ -14183,14 +14219,26 @@ memory = {
|
|
|
14183
14219
|
#
|
|
14184
14220
|
# CAUTION: this block lives inside a DOUBLE-QUOTED python3 -c program, so no
|
|
14185
14221
|
# apostrophes and no double quotes anywhere here, comments included.
|
|
14222
|
+
#
|
|
14223
|
+
# SEVERITY MIRRORS THE TEXT PATH: a dangling link is a failure only for the
|
|
14224
|
+
# provider a build would actually use. Read from the SAME payload the text
|
|
14225
|
+
# route uses (LOKI_PROVIDER_AVAILABILITY, set by cmd_doctor_json), parsed here
|
|
14226
|
+
# rather than via a second env var so the two cannot disagree. LOKI_PROVIDER
|
|
14227
|
+
# wins for the same reason effective_provider_id honors it.
|
|
14186
14228
|
_SKILL_ENTRIES = (
|
|
14187
|
-
('Claude Code', '.claude/skills/loki-mode'),
|
|
14188
|
-
('Codex CLI', '.codex/skills/loki-mode'),
|
|
14189
|
-
('Cline CLI', '.cline/skills/loki-mode'),
|
|
14190
|
-
('Aider CLI', '.aider/skills/loki-mode'),
|
|
14229
|
+
('Claude Code', '.claude/skills/loki-mode', 'claude'),
|
|
14230
|
+
('Codex CLI', '.codex/skills/loki-mode', 'codex'),
|
|
14231
|
+
('Cline CLI', '.cline/skills/loki-mode', 'cline'),
|
|
14232
|
+
('Aider CLI', '.aider/skills/loki-mode', 'aider'),
|
|
14191
14233
|
)
|
|
14234
|
+
try:
|
|
14235
|
+
_sk_pa = os.environ.get('LOKI_PROVIDER_AVAILABILITY', '').strip()
|
|
14236
|
+
_sk_selected = (json.loads(_sk_pa).get('selected') or '') if _sk_pa else ''
|
|
14237
|
+
except Exception:
|
|
14238
|
+
_sk_selected = ''
|
|
14239
|
+
_sk_selected = os.environ.get('LOKI_PROVIDER', '') or _sk_selected
|
|
14192
14240
|
skills = []
|
|
14193
|
-
for _sk_name, _sk_rel in _SKILL_ENTRIES:
|
|
14241
|
+
for _sk_name, _sk_rel, _sk_id in _SKILL_ENTRIES:
|
|
14194
14242
|
_sk_dir = os.path.join(os.path.expanduser('~'), _sk_rel)
|
|
14195
14243
|
# JSON is commonly archived or forwarded to automation. Keep the useful
|
|
14196
14244
|
# user-relative location without exposing the machine-specific home path.
|
|
@@ -14200,8 +14248,14 @@ for _sk_name, _sk_rel in _SKILL_ENTRIES:
|
|
|
14200
14248
|
'detail': None, 'required': 'required'})
|
|
14201
14249
|
elif os.path.islink(_sk_dir):
|
|
14202
14250
|
# islink is true for a DANGLING link (lstat-based), which is exactly
|
|
14203
|
-
# the broken case the text path reports
|
|
14204
|
-
|
|
14251
|
+
# the broken case the text path reports. fail only for the effective
|
|
14252
|
+
# provider; otherwise warn, matching the text path badge for badge.
|
|
14253
|
+
# `required` stays 'required' in both arms: an absent link has always
|
|
14254
|
+
# been warn+required, so the warn arm introduces no new shape, and a
|
|
14255
|
+
# consumer keys on `status`.
|
|
14256
|
+
_sk_blocking = bool(_sk_selected) and _sk_id == _sk_selected
|
|
14257
|
+
skills.append({'name': _sk_name, 'path': _sk_json_path,
|
|
14258
|
+
'status': 'fail' if _sk_blocking else 'warn',
|
|
14205
14259
|
'detail': 'broken symlink. Fix: loki setup-skill',
|
|
14206
14260
|
'required': 'required'})
|
|
14207
14261
|
else:
|
|
@@ -17358,12 +17412,111 @@ if manifests:
|
|
|
17358
17412
|
echo -e "${RED}Error: No repositories found matching: ${multi_repo}${NC}"
|
|
17359
17413
|
return 1
|
|
17360
17414
|
fi
|
|
17361
|
-
|
|
17415
|
+
# ORCHESTRATION (v9.49.0): --multi-repo now MIGRATES each discovered
|
|
17416
|
+
# repository, one at a time, instead of only listing them.
|
|
17417
|
+
#
|
|
17418
|
+
# WHY A WRAPPER AND NOT SURGERY INSIDE THIS FUNCTION: cmd_migrate_start
|
|
17419
|
+
# is self-contained per codebase_path (manifest, secret scan, phases)
|
|
17420
|
+
# and was measured to have 20 `return`s and ZERO `exit`s, so it is
|
|
17421
|
+
# safe to call in a loop -- a failing repo returns a code instead of
|
|
17422
|
+
# killing the run. Recursing once per repo reuses every existing gate
|
|
17423
|
+
# rather than reimplementing the pipeline.
|
|
17424
|
+
#
|
|
17425
|
+
# PARTIAL-FAILURE SEMANTICS: continue-and-report, decided on the
|
|
17426
|
+
# codebase's own precedent, not preference:
|
|
17427
|
+
# - the task schema already has `blocked` as a first-class state
|
|
17428
|
+
# alongside `completed` (mcp/server.py:888), so "some units did not
|
|
17429
|
+
# finish" is already expressible
|
|
17430
|
+
# - run.sh carries 562 best-effort sites: the house style is degrade
|
|
17431
|
+
# honestly, do not abort
|
|
17432
|
+
# - fail-closed is reserved for DEPENDENCY violations (a migrate phase
|
|
17433
|
+
# refusing to run without its predecessor's artifacts, :17575), and
|
|
17434
|
+
# independent repositories have no such dependency on each other
|
|
17435
|
+
# One repo failing therefore must not deny the other four their result.
|
|
17436
|
+
# The per-repo status table plus a non-zero aggregate exit code is what
|
|
17437
|
+
# makes that honest rather than silent.
|
|
17438
|
+
#
|
|
17439
|
+
# LOKI_MULTI_REPO_SEQUENTIAL=0 is NOT offered: these share a migrations
|
|
17440
|
+
# dir and a dashboard port, and parallel runs would interleave output
|
|
17441
|
+
# into an unreadable report.
|
|
17442
|
+
if [ "$repo_count" -gt 1 ] && [ "${_LOKI_MR_CHILD:-0}" != "1" ]; then
|
|
17443
|
+
echo -e "${BOLD}Multi-repo migration${NC} ($repo_count repositories, sequential)"
|
|
17444
|
+
echo "---"
|
|
17445
|
+
for repo in "${repos[@]}"; do echo " - $repo"; done
|
|
17446
|
+
echo ""
|
|
17447
|
+
|
|
17448
|
+
local _mr_ok=0 _mr_bad=0
|
|
17449
|
+
local _mr_rows=""
|
|
17450
|
+
local _mr_repo _mr_rc
|
|
17451
|
+
for _mr_repo in "${repos[@]}"; do
|
|
17452
|
+
echo ""
|
|
17453
|
+
echo -e "${CYAN}=== [$((_mr_ok + _mr_bad + 1))/$repo_count] $_mr_repo ===${NC}"
|
|
17454
|
+
_mr_rc=0
|
|
17455
|
+
# _LOKI_MR_CHILD guards the recursion: the child sees the same
|
|
17456
|
+
# --multi-repo argument and must NOT re-enter this block.
|
|
17457
|
+
_LOKI_MR_CHILD=1 cmd_migrate_start \
|
|
17458
|
+
"$_mr_repo" "$target" "$plan_only" "$phase" "$parallel" \
|
|
17459
|
+
"$compliance" "$dry_run" "$resume" "" "$export_report" \
|
|
17460
|
+
"$no_dashboard" "$no_docs" || _mr_rc=$?
|
|
17461
|
+
if [ "$_mr_rc" -eq 0 ]; then
|
|
17462
|
+
_mr_ok=$((_mr_ok + 1))
|
|
17463
|
+
_mr_rows="${_mr_rows} OK ${_mr_repo}"$'\n'
|
|
17464
|
+
else
|
|
17465
|
+
_mr_bad=$((_mr_bad + 1))
|
|
17466
|
+
_mr_rows="${_mr_rows} BLOCKED ${_mr_repo} (exit ${_mr_rc})"$'\n'
|
|
17467
|
+
fi
|
|
17468
|
+
done
|
|
17469
|
+
|
|
17470
|
+
echo ""
|
|
17471
|
+
echo -e "${BOLD}Multi-repo result${NC}"
|
|
17472
|
+
echo "---"
|
|
17473
|
+
printf '%s' "$_mr_rows"
|
|
17474
|
+
echo ""
|
|
17475
|
+
echo " ${_mr_ok} of ${repo_count} migrated, ${_mr_bad} blocked."
|
|
17476
|
+
if [ "$_mr_bad" -gt 0 ]; then
|
|
17477
|
+
# A non-zero exit is what keeps "continue" from becoming
|
|
17478
|
+
# "silently tolerate": CI and `loki next` both branch on it.
|
|
17479
|
+
echo -e "${YELLOW}Some repositories did not complete. Re-run just those, or inspect them with 'loki why'.${NC}"
|
|
17480
|
+
return 1
|
|
17481
|
+
fi
|
|
17482
|
+
return 0
|
|
17483
|
+
fi
|
|
17484
|
+
|
|
17485
|
+
# HONESTY (single-repo, or a --multi-repo glob that matched exactly one):
|
|
17486
|
+
# this flag DISCOVERS repositories; it does not migrate them.
|
|
17487
|
+
# `repos[]` is populated here and never referenced again -- everything
|
|
17488
|
+
# below operates on the single "$codebase_path". The old message said
|
|
17489
|
+
# "Multi-repo migration (3 repositories)" and listed all three, then
|
|
17490
|
+
# created one migration scoped to the first. A user reading that
|
|
17491
|
+
# believed three repos were migrated when one was.
|
|
17492
|
+
#
|
|
17493
|
+
# Orchestrating a real migration across repositories is a separate piece
|
|
17494
|
+
# of work (dependency order, per-repo gates, per-repo receipts). Until
|
|
17495
|
+
# that exists, this says exactly what it does and hands the user the
|
|
17496
|
+
# commands that cover the rest, rather than implying coverage it has not
|
|
17497
|
+
# delivered.
|
|
17498
|
+
local _mr_others=$((repo_count - 1))
|
|
17499
|
+
echo -e "${BOLD}Repositories found${NC} ($repo_count)"
|
|
17362
17500
|
echo "---"
|
|
17363
17501
|
for repo in "${repos[@]}"; do
|
|
17364
|
-
|
|
17502
|
+
if [ "$repo" = "$codebase_path" ]; then
|
|
17503
|
+
echo " - $repo (migrating now)"
|
|
17504
|
+
else
|
|
17505
|
+
echo " - $repo"
|
|
17506
|
+
fi
|
|
17365
17507
|
done
|
|
17366
17508
|
echo ""
|
|
17509
|
+
if [ "$_mr_others" -gt 0 ]; then
|
|
17510
|
+
echo -e "${YELLOW}--multi-repo discovers repositories; it does not migrate them together.${NC}"
|
|
17511
|
+
echo "This run migrates only: $codebase_path"
|
|
17512
|
+
echo ""
|
|
17513
|
+
echo "To cover the others, run each one:"
|
|
17514
|
+
for repo in "${repos[@]}"; do
|
|
17515
|
+
[ "$repo" = "$codebase_path" ] && continue
|
|
17516
|
+
echo " loki modernize migrate \"$repo\" --target \"$target\""
|
|
17517
|
+
done
|
|
17518
|
+
echo ""
|
|
17519
|
+
fi
|
|
17367
17520
|
fi
|
|
17368
17521
|
|
|
17369
17522
|
local migration_dir
|
|
@@ -464,6 +464,49 @@ render_provider_availability() {
|
|
|
464
464
|
) || return 1
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
+
# effective_provider_id: print the provider id a build would ACTUALLY use, or
|
|
468
|
+
# nothing when none is resolvable. Exit status is 0 only when an id was printed.
|
|
469
|
+
#
|
|
470
|
+
# WHY IT EXISTS. Doctor grades a dangling skill symlink, and the severity of
|
|
471
|
+
# that depends on WHOSE skill it is. A stale link for a provider the user does
|
|
472
|
+
# not use is inert state; the same link for the provider a build will launch is
|
|
473
|
+
# a real blocker. Both the text route and the Bun route need that one id, and
|
|
474
|
+
# both previously re-derived it inside their own subshells (the two callers
|
|
475
|
+
# below). Deriving it a third and fourth time is exactly the drift this file's
|
|
476
|
+
# header exists to prevent, so it is extracted here once.
|
|
477
|
+
#
|
|
478
|
+
# LOKI_PROVIDER WINS. render_provider_availability prints "override with
|
|
479
|
+
# LOKI_PROVIDER" two lines above, so honoring auto-detection alone would grade
|
|
480
|
+
# a skill link against a provider the very same screen says is not in use.
|
|
481
|
+
# The override is NOT validated against installed state on purpose: an explicit
|
|
482
|
+
# LOKI_PROVIDER is the user's stated intent, and a build would carry it through.
|
|
483
|
+
#
|
|
484
|
+
# DEGRADES SILENTLY, like its two siblings: a missing or unsourceable loader
|
|
485
|
+
# prints nothing and returns non-zero, and the caller falls back to treating
|
|
486
|
+
# every entry as non-blocking rather than erroring.
|
|
487
|
+
effective_provider_id() {
|
|
488
|
+
if [ -n "${LOKI_PROVIDER:-}" ]; then
|
|
489
|
+
printf '%s\n' "$LOKI_PROVIDER"
|
|
490
|
+
return 0
|
|
491
|
+
fi
|
|
492
|
+
|
|
493
|
+
local _po_here
|
|
494
|
+
_po_here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || return 1
|
|
495
|
+
local _loader="$_po_here/providers/loader.sh"
|
|
496
|
+
[ -f "$_loader" ] || return 1
|
|
497
|
+
|
|
498
|
+
local _sel
|
|
499
|
+
_sel="$(
|
|
500
|
+
# shellcheck source=/dev/null
|
|
501
|
+
source "$_loader" >/dev/null 2>&1 || exit 1
|
|
502
|
+
declare -f auto_detect_provider >/dev/null 2>&1 || exit 1
|
|
503
|
+
auto_detect_provider 2>/dev/null
|
|
504
|
+
)" || return 1
|
|
505
|
+
|
|
506
|
+
[ -n "$_sel" ] || return 1
|
|
507
|
+
printf '%s\n' "$_sel"
|
|
508
|
+
}
|
|
509
|
+
|
|
467
510
|
# provider_availability_json: the same data as one JSON object, for doctor --json.
|
|
468
511
|
# Separate from the renderer so neither format has to parse the other. Same
|
|
469
512
|
# degrade rule: no loader means no output and a non-zero status.
|
|
@@ -517,6 +560,10 @@ if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
|
517
560
|
# routes call these so the two renderings cannot drift apart.
|
|
518
561
|
providers) render_provider_availability ;;
|
|
519
562
|
providers-json) provider_availability_json ;;
|
|
563
|
+
# The provider id a build would actually use, for the Bun doctor's
|
|
564
|
+
# skill-severity decision. Same one-implementation rule as the two
|
|
565
|
+
# above: doctor.ts reads this instead of re-deriving the priority list.
|
|
566
|
+
effective-provider) effective_provider_id ;;
|
|
520
567
|
*) offer_provider_install report ;;
|
|
521
568
|
esac
|
|
522
569
|
fi
|