loki-mode 7.28.2 → 7.30.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/README.md +4 -3
- package/SKILL.md +8 -2
- package/VERSION +1 -1
- package/autonomy/loki +285 -26
- package/autonomy/mcp-launch.sh +282 -0
- package/autonomy/provider-offer.sh +249 -0
- package/autonomy/quickstart.sh +584 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +10 -1
- package/docs/competitive/emergence-others-analysis.md +1 -1
- package/docs/competitive/replit-lovable-analysis.md +2 -2
- package/loki-ts/dist/loki.js +208 -208
- package/mcp/__init__.py +1 -1
- package/mcp/server.py +186 -35
- package/package.json +1 -1
- package/templates/simple-todo-app.md +3 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# quickstart.sh -- guided first-build interview (v7.29.0, design feature 3).
|
|
3
|
+
#
|
|
4
|
+
# `loki quickstart` is a thin orchestrator over three already-shipped pieces:
|
|
5
|
+
# 1. the provider install offer (autonomy/provider-offer.sh, slice B)
|
|
6
|
+
# 2. the honest cost estimator (show_prd_plan in autonomy/loki, slice A)
|
|
7
|
+
# 3. cmd_start (autonomy/loki) for the actual build
|
|
8
|
+
# plus one new, deterministic, offline keyword matcher over templates/.
|
|
9
|
+
#
|
|
10
|
+
# It NEVER reimplements the runner and NEVER fabricates a number: every figure
|
|
11
|
+
# in step 4 comes from the same estimator cmd_start will run with, so the quote
|
|
12
|
+
# equals the charge by construction (the slice-A honesty keystone).
|
|
13
|
+
#
|
|
14
|
+
# Sourcing contract (load-bearing for tests): this file defines functions ONLY.
|
|
15
|
+
# It runs no top-level command and never calls `main`. autonomy/loki sources it
|
|
16
|
+
# near the top so cmd_quickstart and its helpers are in scope for the dispatch
|
|
17
|
+
# case. Tests source it directly, override the _qs_non_interactive predicate, and
|
|
18
|
+
# stub cmd_start / provider_offer_gate to prove the composition without spending
|
|
19
|
+
# or starting a build. Because it is sourced (not a subprocess), it relies on the
|
|
20
|
+
# caller (autonomy/loki) for SKILL_DIR, the color vars, show_prd_plan,
|
|
21
|
+
# provider_offer_gate, and cmd_start; the test harness provides stubs for those
|
|
22
|
+
# it does not exercise for real.
|
|
23
|
+
|
|
24
|
+
# Guard against double-source.
|
|
25
|
+
if [ -n "${_LOKI_QUICKSTART_SOURCED:-}" ]; then
|
|
26
|
+
return 0 2>/dev/null || true
|
|
27
|
+
fi
|
|
28
|
+
_LOKI_QUICKSTART_SOURCED=1
|
|
29
|
+
|
|
30
|
+
# --- Self-contained colors (ANSI-interpreted, _QS_-prefixed) ---------------
|
|
31
|
+
# autonomy/loki's own BOLD/RED/etc. hold LITERAL "\033[..." strings meant for
|
|
32
|
+
# `echo -e`; this file uses printf, so it defines its OWN $'...'-interpreted
|
|
33
|
+
# vars (the provider-offer.sh pattern). They are _QS_-prefixed so sourcing this
|
|
34
|
+
# file never clobbers loki's color globals (the rest of the CLI uses echo -e).
|
|
35
|
+
# Honors NO_COLOR and non-TTY.
|
|
36
|
+
if [ -n "${NO_COLOR:-}" ] || [ ! -t 1 ]; then
|
|
37
|
+
_QS_BOLD=''; _QS_DIM=''; _QS_CYAN=''; _QS_YELLOW=''; _QS_RED=''; _QS_NC=''
|
|
38
|
+
else
|
|
39
|
+
_QS_BOLD=$'\033[1m'
|
|
40
|
+
_QS_DIM=$'\033[2m'
|
|
41
|
+
_QS_CYAN=$'\033[0;36m'
|
|
42
|
+
_QS_YELLOW=$'\033[1;33m'
|
|
43
|
+
_QS_RED=$'\033[0;31m'
|
|
44
|
+
_QS_NC=$'\033[0m'
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# _qs_templates_dir: resolve the templates directory. Prefers SKILL_DIR (set by
|
|
48
|
+
# autonomy/loki); falls back to this script's sibling templates/ for tests.
|
|
49
|
+
_qs_templates_dir() {
|
|
50
|
+
if [ -n "${SKILL_DIR:-}" ] && [ -d "${SKILL_DIR}/templates" ]; then
|
|
51
|
+
printf '%s\n' "${SKILL_DIR}/templates"
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
local self_dir
|
|
55
|
+
self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
56
|
+
printf '%s\n' "$(cd "$self_dir/.." && pwd)/templates"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# _qs_non_interactive: true (0) when we must NEVER prompt (non-TTY or CI).
|
|
60
|
+
# Named (not inlined) so tests can override it to drive the interview without a
|
|
61
|
+
# real terminal. Mirrors provider-offer.sh's _po_non_interactive idiom.
|
|
62
|
+
_qs_non_interactive() {
|
|
63
|
+
[ ! -t 0 ] && return 0
|
|
64
|
+
[ ! -t 1 ] && return 0
|
|
65
|
+
[ -n "${CI:-}" ] && return 0
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# _qs_assume_yes: true when the user opted into auto-confirm (--yes /
|
|
70
|
+
# LOKI_ASSUME_YES / the LOKI_AUTO_CONFIRM that --yes already sets at loki:1013).
|
|
71
|
+
_qs_assume_yes() {
|
|
72
|
+
[ "${LOKI_ASSUME_YES:-}" = "1" ] && return 0
|
|
73
|
+
[ "${LOKI_ASSUME_YES:-}" = "true" ] && return 0
|
|
74
|
+
[ "${LOKI_AUTO_CONFIRM:-}" = "true" ] && return 0
|
|
75
|
+
return 1
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# _qs_keyword_map: curated keyword -> template -> weight table (design 3.5).
|
|
79
|
+
# Format per line: keyword:template:weight. Deterministic, offline, no LLM.
|
|
80
|
+
# A template's own flagship term carries a higher weight so the head noun wins
|
|
81
|
+
# (e.g. "todo" -> simple-todo-app outranks incidental account/user matches).
|
|
82
|
+
_qs_keyword_map() {
|
|
83
|
+
cat <<'MAP'
|
|
84
|
+
todo:simple-todo-app:5
|
|
85
|
+
list:simple-todo-app:3
|
|
86
|
+
auth:rest-api-auth:3
|
|
87
|
+
auth:saas-starter:3
|
|
88
|
+
login:rest-api-auth:3
|
|
89
|
+
login:saas-starter:3
|
|
90
|
+
account:saas-starter:4
|
|
91
|
+
accounts:saas-starter:4
|
|
92
|
+
account:rest-api-auth:3
|
|
93
|
+
accounts:rest-api-auth:3
|
|
94
|
+
user:saas-starter:3
|
|
95
|
+
users:saas-starter:3
|
|
96
|
+
user:rest-api-auth:2
|
|
97
|
+
users:rest-api-auth:2
|
|
98
|
+
signup:saas-starter:3
|
|
99
|
+
tenant:saas-starter:3
|
|
100
|
+
saas:saas-starter:3
|
|
101
|
+
subscription:saas-starter:3
|
|
102
|
+
billing:saas-starter:3
|
|
103
|
+
api:rest-api:3
|
|
104
|
+
api:api-only:3
|
|
105
|
+
endpoint:rest-api:3
|
|
106
|
+
endpoints:rest-api:3
|
|
107
|
+
rest:rest-api:3
|
|
108
|
+
backend:rest-api:3
|
|
109
|
+
bot:discord-bot:3
|
|
110
|
+
bot:slack-bot:3
|
|
111
|
+
discord:discord-bot:3
|
|
112
|
+
slack:slack-bot:3
|
|
113
|
+
chat:ai-chatbot:3
|
|
114
|
+
chatbot:ai-chatbot:3
|
|
115
|
+
ai:ai-chatbot:3
|
|
116
|
+
llm:ai-chatbot:3
|
|
117
|
+
shop:e-commerce:3
|
|
118
|
+
store:e-commerce:3
|
|
119
|
+
ecommerce:e-commerce:3
|
|
120
|
+
commerce:e-commerce:3
|
|
121
|
+
cart:e-commerce:3
|
|
122
|
+
blog:blog-platform:3
|
|
123
|
+
cms:blog-platform:3
|
|
124
|
+
post:blog-platform:3
|
|
125
|
+
posts:blog-platform:3
|
|
126
|
+
dashboard:dashboard:3
|
|
127
|
+
analytics:dashboard:3
|
|
128
|
+
admin:dashboard:3
|
|
129
|
+
cli:cli-tool:3
|
|
130
|
+
terminal:cli-tool:3
|
|
131
|
+
command:cli-tool:3
|
|
132
|
+
game:game:3
|
|
133
|
+
play:game:3
|
|
134
|
+
mobile:mobile-app:3
|
|
135
|
+
ios:mobile-app:3
|
|
136
|
+
android:mobile-app:3
|
|
137
|
+
scraper:web-scraper:3
|
|
138
|
+
scrape:web-scraper:3
|
|
139
|
+
crawl:web-scraper:3
|
|
140
|
+
pipeline:data-pipeline:3
|
|
141
|
+
etl:data-pipeline:3
|
|
142
|
+
data:data-pipeline:3
|
|
143
|
+
microservice:microservice:3
|
|
144
|
+
service:microservice:3
|
|
145
|
+
library:npm-library:3
|
|
146
|
+
package:npm-library:3
|
|
147
|
+
npm:npm-library:3
|
|
148
|
+
extension:chrome-extension:3
|
|
149
|
+
chrome:chrome-extension:3
|
|
150
|
+
browser:chrome-extension:3
|
|
151
|
+
landing:static-landing-page:3
|
|
152
|
+
static:static-landing-page:3
|
|
153
|
+
marketing:static-landing-page:3
|
|
154
|
+
fullstack:full-stack-demo:3
|
|
155
|
+
MAP
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# _qs_is_stopword: filter generic words that would add filename-token noise
|
|
159
|
+
# (e.g. "app" matching mobile-app for every brief). Returns 0 for a stopword.
|
|
160
|
+
_qs_is_stopword() {
|
|
161
|
+
case "$1" in
|
|
162
|
+
a|an|the|my|your|our|with|for|and|to|of|in|on|app|application|build|make|create|want|that|this|some|simple) return 0;;
|
|
163
|
+
esac
|
|
164
|
+
return 1
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# _qs_score_templates <brief>: print the top-3 closest templates, one name per
|
|
168
|
+
# line, in deterministic rank order. simple-todo-app is the guaranteed default:
|
|
169
|
+
# it gets a +1 baseline and wins exact-score ties (priority column in the sort).
|
|
170
|
+
# Scoring: +2 per non-stopword token that matches a template filename token,
|
|
171
|
+
# plus the curated keyword weights. No network, no provider, no LLM.
|
|
172
|
+
_qs_score_templates() {
|
|
173
|
+
local brief="$1"
|
|
174
|
+
local tdir; tdir="$(_qs_templates_dir)"
|
|
175
|
+
local brief_lc; brief_lc=$(printf '%s' "$brief" | tr '[:upper:]' '[:lower:]')
|
|
176
|
+
|
|
177
|
+
declare -A scores
|
|
178
|
+
local name f
|
|
179
|
+
while IFS= read -r f; do
|
|
180
|
+
[ -z "$f" ] && continue
|
|
181
|
+
name=$(basename "$f" .md)
|
|
182
|
+
[ "$name" = "README" ] && continue
|
|
183
|
+
scores["$name"]=0
|
|
184
|
+
done < <(ls "$tdir"/*.md 2>/dev/null)
|
|
185
|
+
|
|
186
|
+
# No templates resolvable: fall back to the guaranteed default only.
|
|
187
|
+
if [ "${#scores[@]}" -eq 0 ]; then
|
|
188
|
+
printf 'simple-todo-app\n'
|
|
189
|
+
return 0
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
local -a tokens
|
|
193
|
+
read -ra tokens <<< "$(printf '%s' "$brief_lc" | tr -cs 'a-z0-9' ' ')"
|
|
194
|
+
|
|
195
|
+
local tok kw tmpl wt
|
|
196
|
+
for tok in "${tokens[@]}"; do
|
|
197
|
+
[ -z "$tok" ] && continue
|
|
198
|
+
_qs_is_stopword "$tok" && continue
|
|
199
|
+
for name in "${!scores[@]}"; do
|
|
200
|
+
case "-$name-" in
|
|
201
|
+
*"-$tok-"*) scores["$name"]=$(( ${scores["$name"]} + 2 ));;
|
|
202
|
+
esac
|
|
203
|
+
done
|
|
204
|
+
while IFS=: read -r kw tmpl wt; do
|
|
205
|
+
[ -z "$kw" ] && continue
|
|
206
|
+
[ -z "$wt" ] && wt=3
|
|
207
|
+
if [ "$tok" = "$kw" ] && [ -n "${scores[$tmpl]+x}" ]; then
|
|
208
|
+
scores["$tmpl"]=$(( ${scores["$tmpl"]} + wt ))
|
|
209
|
+
fi
|
|
210
|
+
done < <(_qs_keyword_map)
|
|
211
|
+
done
|
|
212
|
+
|
|
213
|
+
# Guaranteed default baseline.
|
|
214
|
+
if [ -n "${scores[simple-todo-app]+x}" ]; then
|
|
215
|
+
scores["simple-todo-app"]=$(( ${scores["simple-todo-app"]} + 1 ))
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Emit "score<TAB>priority<TAB>name"; sort by score desc, priority asc
|
|
219
|
+
# (simple-todo-app=0 wins ties), then name asc for full determinism.
|
|
220
|
+
local prio
|
|
221
|
+
for name in "${!scores[@]}"; do
|
|
222
|
+
prio=1
|
|
223
|
+
[ "$name" = "simple-todo-app" ] && prio=0
|
|
224
|
+
printf '%s\t%s\t%s\n' "${scores[$name]}" "$prio" "$name"
|
|
225
|
+
done | sort -t$'\t' -k1,1nr -k2,2n -k3,3 | head -3 | cut -f3
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
# _qs_template_summary <name>: a short one-line description for the picker.
|
|
229
|
+
# Read from the template's first prose line would be fragile; use a small
|
|
230
|
+
# curated table so the picker copy is stable and honest.
|
|
231
|
+
_qs_template_summary() {
|
|
232
|
+
case "$1" in
|
|
233
|
+
simple-todo-app) printf 'A minimal todo list app';;
|
|
234
|
+
saas-starter) printf 'Multi-tenant SaaS with auth';;
|
|
235
|
+
rest-api-auth) printf 'REST API with authentication';;
|
|
236
|
+
rest-api) printf 'REST API service';;
|
|
237
|
+
api-only) printf 'Backend API, no frontend';;
|
|
238
|
+
ai-chatbot) printf 'AI chatbot with an LLM backend';;
|
|
239
|
+
blog-platform) printf 'Blog / CMS platform';;
|
|
240
|
+
chrome-extension) printf 'Chrome browser extension';;
|
|
241
|
+
cli-tool) printf 'Command-line tool';;
|
|
242
|
+
dashboard) printf 'Analytics / admin dashboard';;
|
|
243
|
+
data-pipeline) printf 'Data pipeline / ETL';;
|
|
244
|
+
discord-bot) printf 'Discord bot';;
|
|
245
|
+
e-commerce) printf 'E-commerce storefront';;
|
|
246
|
+
full-stack-demo) printf 'Full-stack demo app';;
|
|
247
|
+
game) printf 'Browser game';;
|
|
248
|
+
microservice) printf 'Standalone microservice';;
|
|
249
|
+
mobile-app) printf 'Mobile app';;
|
|
250
|
+
npm-library) printf 'Publishable npm library';;
|
|
251
|
+
slack-bot) printf 'Slack bot';;
|
|
252
|
+
static-landing-page) printf 'Static marketing landing page';;
|
|
253
|
+
web-scraper) printf 'Web scraper';;
|
|
254
|
+
*) printf 'PRD template';;
|
|
255
|
+
esac
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# _qs_emit_plan <prd_path>: render the step-4 plan block from the REAL estimator.
|
|
259
|
+
# Honesty invariant: NO LOKI_COMPLEXITY override is passed, so the complexity,
|
|
260
|
+
# iterations, and cost are exactly what cmd_start will run with (cmd_start
|
|
261
|
+
# auto-detects complexity from the same PRD). Returns 0 if a number was shown,
|
|
262
|
+
# non-zero if the estimator gave no result (caller falls back to a no-number
|
|
263
|
+
# confirm, never fabricating a figure).
|
|
264
|
+
_qs_emit_plan() {
|
|
265
|
+
local prd_path="$1" template_name="$2"
|
|
266
|
+
local plan_json=""
|
|
267
|
+
plan_json=$(show_prd_plan "$prd_path" "true" "false" 2>/dev/null) || plan_json=""
|
|
268
|
+
if [ -z "$plan_json" ]; then
|
|
269
|
+
return 1
|
|
270
|
+
fi
|
|
271
|
+
local parsed
|
|
272
|
+
parsed=$(printf '%s' "$plan_json" | python3 -c "
|
|
273
|
+
import json, sys
|
|
274
|
+
try:
|
|
275
|
+
d = json.load(sys.stdin)
|
|
276
|
+
except Exception:
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
cost = d.get('cost', {}).get('total_usd')
|
|
279
|
+
time_est = d.get('time', {}).get('estimated')
|
|
280
|
+
iters = d.get('iterations', {}).get('estimated')
|
|
281
|
+
rng = d.get('iterations', {}).get('range', [])
|
|
282
|
+
tier = d.get('complexity', {}).get('tier', '')
|
|
283
|
+
if cost is None or time_est is None or iters is None:
|
|
284
|
+
sys.exit(1)
|
|
285
|
+
rng_str = ''
|
|
286
|
+
if isinstance(rng, list) and len(rng) == 2:
|
|
287
|
+
rng_str = ' (range {}-{})'.format(rng[0], rng[1])
|
|
288
|
+
print(tier.upper())
|
|
289
|
+
print('{:.2f}'.format(float(cost)))
|
|
290
|
+
print(time_est)
|
|
291
|
+
print('{}{}'.format(iters, rng_str))
|
|
292
|
+
" 2>/dev/null) || parsed=""
|
|
293
|
+
if [ -z "$parsed" ]; then
|
|
294
|
+
return 1
|
|
295
|
+
fi
|
|
296
|
+
local tier_u cost_u time_u iter_u
|
|
297
|
+
tier_u=$(printf '%s' "$parsed" | sed -n '1p')
|
|
298
|
+
cost_u=$(printf '%s' "$parsed" | sed -n '2p')
|
|
299
|
+
time_u=$(printf '%s' "$parsed" | sed -n '3p')
|
|
300
|
+
iter_u=$(printf '%s' "$parsed" | sed -n '4p')
|
|
301
|
+
|
|
302
|
+
printf ' Template: %s\n' "$template_name"
|
|
303
|
+
printf ' Complexity: %s\n' "$tier_u"
|
|
304
|
+
printf ' Cost: ~$%s\n' "$cost_u"
|
|
305
|
+
printf ' Time: ~%s\n' "$time_u"
|
|
306
|
+
printf ' Iterations: %s\n' "$iter_u"
|
|
307
|
+
printf '\n'
|
|
308
|
+
printf ' This is an estimate. Actual usage depends on PRD complexity, the AI\n'
|
|
309
|
+
printf ' provider, and how many iterations the build needs.\n'
|
|
310
|
+
printf '\n'
|
|
311
|
+
return 0
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# _qs_help: concise usage for `loki quickstart --help`.
|
|
315
|
+
_qs_help() {
|
|
316
|
+
printf '%sloki quickstart%s - guided first build (setup, idea, template, plan, go)\n' "$_QS_BOLD" "$_QS_NC"
|
|
317
|
+
printf '\n'
|
|
318
|
+
printf 'A 4-step interview that takes you from a clean install to a verified\n'
|
|
319
|
+
printf 'first build. Press Enter at every step to build the sample Todo app.\n'
|
|
320
|
+
printf '\n'
|
|
321
|
+
printf 'Usage: loki quickstart [IDEA|PRD-PATH] [options]\n'
|
|
322
|
+
printf '\n'
|
|
323
|
+
printf 'Arguments:\n'
|
|
324
|
+
printf ' IDEA A one-line description (pre-fills step 2)\n'
|
|
325
|
+
printf ' PRD-PATH A path to an existing PRD file (skips steps 2-3)\n'
|
|
326
|
+
printf '\n'
|
|
327
|
+
printf 'Options:\n'
|
|
328
|
+
printf ' --yes, -y Auto-confirm the final build prompt (still shows the plan)\n'
|
|
329
|
+
printf ' --help, -h Show this help and exit\n'
|
|
330
|
+
printf '\n'
|
|
331
|
+
printf 'Steps:\n'
|
|
332
|
+
printf ' 1. Setup Check for an AI provider; offer to install if missing\n'
|
|
333
|
+
printf ' 2. Build Describe what you want, or Enter for the sample Todo app\n'
|
|
334
|
+
printf ' 3. Template Pick the closest starting template (offline keyword match)\n'
|
|
335
|
+
printf ' 4. Plan Review the honest cost/time estimate, then confirm\n'
|
|
336
|
+
printf '\n'
|
|
337
|
+
printf 'The PRD is written to ./prd.md in the current directory, then the build\n'
|
|
338
|
+
printf 'starts. For non-interactive automation use: loki start <prd> --yes\n'
|
|
339
|
+
return 0
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# cmd_quickstart: the 4-step guided interview. Composes provider_offer_gate
|
|
343
|
+
# (slice B), show_prd_plan (slice A), the template matcher, and cmd_start.
|
|
344
|
+
#
|
|
345
|
+
# Order is load-bearing:
|
|
346
|
+
# --help (exit 0) -> non-TTY/CI gate (hint + exit 2) -> provider gate ->
|
|
347
|
+
# step 2 (idea / PRD path) -> step 3 (template) -> step 4 (plan + confirm) ->
|
|
348
|
+
# write PRD to CWD -> cmd_start --yes --no-plan (subshelled; it execs the runner).
|
|
349
|
+
cmd_quickstart() {
|
|
350
|
+
local positional=""
|
|
351
|
+
local assume_yes=false
|
|
352
|
+
if _qs_assume_yes; then assume_yes=true; fi
|
|
353
|
+
|
|
354
|
+
while [ $# -gt 0 ]; do
|
|
355
|
+
case "$1" in
|
|
356
|
+
--help|-h)
|
|
357
|
+
_qs_help
|
|
358
|
+
exit 0
|
|
359
|
+
;;
|
|
360
|
+
--yes|-y)
|
|
361
|
+
assume_yes=true
|
|
362
|
+
shift
|
|
363
|
+
;;
|
|
364
|
+
--*)
|
|
365
|
+
printf '%sUnknown option: %s%s\n' "$_QS_RED" "$1" "$_QS_NC" >&2
|
|
366
|
+
printf "Run 'loki quickstart --help' for usage.\n" >&2
|
|
367
|
+
exit 2
|
|
368
|
+
;;
|
|
369
|
+
*)
|
|
370
|
+
if [ -z "$positional" ]; then
|
|
371
|
+
positional="$1"
|
|
372
|
+
else
|
|
373
|
+
printf '%sUnexpected extra argument: %s%s\n' "$_QS_RED" "$1" "$_QS_NC" >&2
|
|
374
|
+
printf "Run 'loki quickstart --help' for usage.\n" >&2
|
|
375
|
+
exit 2
|
|
376
|
+
fi
|
|
377
|
+
shift
|
|
378
|
+
;;
|
|
379
|
+
esac
|
|
380
|
+
done
|
|
381
|
+
|
|
382
|
+
# Non-TTY / CI: quickstart is interactive by definition. Never hang on read;
|
|
383
|
+
# print the automation hint to stderr and exit 2 (design 3.8).
|
|
384
|
+
if _qs_non_interactive; then
|
|
385
|
+
printf 'loki quickstart is interactive and needs a terminal. For automation use: loki start <prd> --yes\n' >&2
|
|
386
|
+
exit 2
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
printf '\n'
|
|
390
|
+
printf '%sLoki Mode quickstart -- four quick questions, then your build starts.%s\n' "$_QS_BOLD" "$_QS_NC"
|
|
391
|
+
printf '\n'
|
|
392
|
+
|
|
393
|
+
# ----- Step 1 of 4: Setup (reuse the slice-B provider offer) -------------
|
|
394
|
+
printf '%sStep 1 of 4: Setup%s\n' "$_QS_BOLD" "$_QS_NC"
|
|
395
|
+
printf ' Checking for an AI provider CLI ...\n'
|
|
396
|
+
if detect_any_provider; then
|
|
397
|
+
local found=""
|
|
398
|
+
local _p
|
|
399
|
+
for _p in claude codex cline aider; do
|
|
400
|
+
if command -v "$_p" >/dev/null 2>&1; then found="$_p"; break; fi
|
|
401
|
+
done
|
|
402
|
+
printf ' Found: %s. Good.\n' "$found"
|
|
403
|
+
else
|
|
404
|
+
# Run the inline install + login offer. provider_offer_gate returns 2 if
|
|
405
|
+
# no provider ends up available (declined, or install failed).
|
|
406
|
+
if ! provider_offer_gate; then
|
|
407
|
+
printf '%sNo provider available; cannot start a build. Install one and re-run loki quickstart.%s\n' "$_QS_RED" "$_QS_NC" >&2
|
|
408
|
+
exit 2
|
|
409
|
+
fi
|
|
410
|
+
fi
|
|
411
|
+
printf '\n'
|
|
412
|
+
|
|
413
|
+
# ----- Step 2 of 4: What to build ---------------------------------------
|
|
414
|
+
# A positional PRD path skips steps 2-3 entirely (design 3.8). A positional
|
|
415
|
+
# one-liner pre-fills the idea. Otherwise prompt (Enter = sample Todo app).
|
|
416
|
+
local prd_source="" # an existing PRD file path, when the user has one
|
|
417
|
+
local brief="" # the one-line idea (drives template matching)
|
|
418
|
+
local template_name=""
|
|
419
|
+
|
|
420
|
+
if [ -n "$positional" ] && [ -f "$positional" ]; then
|
|
421
|
+
prd_source="$positional"
|
|
422
|
+
printf '%sUsing your PRD: %s%s\n' "$_QS_DIM" "$positional" "$_QS_NC"
|
|
423
|
+
printf '\n'
|
|
424
|
+
else
|
|
425
|
+
printf '%sStep 2 of 4: What do you want to build?%s\n' "$_QS_BOLD" "$_QS_NC"
|
|
426
|
+
printf ' Describe it in one line, or paste a path to a PRD file.\n'
|
|
427
|
+
printf ' (Press Enter to build the sample Todo app.)\n'
|
|
428
|
+
if [ -n "$positional" ]; then
|
|
429
|
+
brief="$positional"
|
|
430
|
+
printf '> %s\n' "$brief"
|
|
431
|
+
else
|
|
432
|
+
local answer=""
|
|
433
|
+
printf '> '
|
|
434
|
+
read -r answer 2>/dev/null || answer=""
|
|
435
|
+
# If the typed value is an existing file, treat it as a PRD path.
|
|
436
|
+
if [ -n "$answer" ] && [ -f "$answer" ]; then
|
|
437
|
+
prd_source="$answer"
|
|
438
|
+
else
|
|
439
|
+
brief="$answer"
|
|
440
|
+
fi
|
|
441
|
+
fi
|
|
442
|
+
printf '\n'
|
|
443
|
+
fi
|
|
444
|
+
|
|
445
|
+
# ----- Step 3 of 4: Pick a template (skipped if a PRD path was given) ----
|
|
446
|
+
if [ -z "$prd_source" ]; then
|
|
447
|
+
local -a top3=()
|
|
448
|
+
local line
|
|
449
|
+
while IFS= read -r line; do
|
|
450
|
+
[ -n "$line" ] && top3+=("$line")
|
|
451
|
+
done < <(_qs_score_templates "$brief")
|
|
452
|
+
|
|
453
|
+
# Defensive: guarantee a default if scoring produced nothing.
|
|
454
|
+
if [ "${#top3[@]}" -eq 0 ]; then
|
|
455
|
+
top3=("simple-todo-app")
|
|
456
|
+
fi
|
|
457
|
+
|
|
458
|
+
printf '%sStep 3 of 4: Pick a starting template%s\n' "$_QS_BOLD" "$_QS_NC"
|
|
459
|
+
if [ -n "$brief" ]; then
|
|
460
|
+
printf ' Closest matches for "%s":\n' "$brief"
|
|
461
|
+
else
|
|
462
|
+
printf ' Closest matches for the sample Todo app:\n'
|
|
463
|
+
fi
|
|
464
|
+
local i=1 t suffix
|
|
465
|
+
for t in "${top3[@]}"; do
|
|
466
|
+
suffix=""
|
|
467
|
+
[ "$i" -eq 1 ] && suffix=" (default)"
|
|
468
|
+
printf ' %d) %-18s %s%s\n' "$i" "$t" "$(_qs_template_summary "$t")" "$suffix"
|
|
469
|
+
i=$((i + 1))
|
|
470
|
+
done
|
|
471
|
+
printf ' Choose 1-%d, or press Enter for 1.\n' "${#top3[@]}"
|
|
472
|
+
|
|
473
|
+
local pick=""
|
|
474
|
+
printf '> '
|
|
475
|
+
read -r pick 2>/dev/null || pick=""
|
|
476
|
+
printf '\n'
|
|
477
|
+
|
|
478
|
+
case "$pick" in
|
|
479
|
+
""|1) template_name="${top3[0]}";;
|
|
480
|
+
2) template_name="${top3[1]:-${top3[0]}}";;
|
|
481
|
+
3) template_name="${top3[2]:-${top3[0]}}";;
|
|
482
|
+
*) template_name="${top3[0]}";; # any unexpected input -> the default
|
|
483
|
+
esac
|
|
484
|
+
|
|
485
|
+
local tdir; tdir="$(_qs_templates_dir)"
|
|
486
|
+
prd_source="$tdir/$template_name.md"
|
|
487
|
+
if [ ! -f "$prd_source" ]; then
|
|
488
|
+
printf '%sTemplate file not found: %s%s\n' "$_QS_RED" "$prd_source" "$_QS_NC" >&2
|
|
489
|
+
exit 1
|
|
490
|
+
fi
|
|
491
|
+
else
|
|
492
|
+
template_name="$(basename "$prd_source")"
|
|
493
|
+
fi
|
|
494
|
+
|
|
495
|
+
# ----- Step 4 of 4: Review the plan (reuse the slice-A estimator) --------
|
|
496
|
+
printf '%sStep 4 of 4: Review the plan%s\n' "$_QS_BOLD" "$_QS_NC"
|
|
497
|
+
local estimate_ok=true
|
|
498
|
+
if ! _qs_emit_plan "$prd_source" "$template_name"; then
|
|
499
|
+
estimate_ok=false
|
|
500
|
+
printf '%sCould not compute a cost estimate (the estimator did not return a result).%s\n' "$_QS_YELLOW" "$_QS_NC"
|
|
501
|
+
printf '\n'
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
# ----- Confirm ----------------------------------------------------------
|
|
505
|
+
if [ "$assume_yes" != true ]; then
|
|
506
|
+
local confirm=""
|
|
507
|
+
if [ "$estimate_ok" = true ]; then
|
|
508
|
+
# Default YES.
|
|
509
|
+
printf 'Start the build now? [Y/n] '
|
|
510
|
+
read -r confirm 2>/dev/null || confirm=""
|
|
511
|
+
if [[ -n "$confirm" && ! "$confirm" =~ ^[Yy] ]]; then
|
|
512
|
+
printf '\nCancelled. Nothing was spent.\n'
|
|
513
|
+
exit 0
|
|
514
|
+
fi
|
|
515
|
+
else
|
|
516
|
+
# No honest number available: default NO (the safe direction).
|
|
517
|
+
printf 'Start the build anyway? [y/N] '
|
|
518
|
+
read -r confirm 2>/dev/null || confirm=""
|
|
519
|
+
if [[ ! "$confirm" =~ ^[Yy] ]]; then
|
|
520
|
+
printf '\nCancelled. Nothing was spent.\n'
|
|
521
|
+
exit 0
|
|
522
|
+
fi
|
|
523
|
+
fi
|
|
524
|
+
fi
|
|
525
|
+
|
|
526
|
+
# ----- Land the PRD at ./prd.md (design 3.6) ----------------------------
|
|
527
|
+
local target="./prd.md"
|
|
528
|
+
if [ -e "$target" ]; then
|
|
529
|
+
local overwrite=""
|
|
530
|
+
printf 'prd.md already exists. Overwrite? [y/N] '
|
|
531
|
+
read -r overwrite 2>/dev/null || overwrite=""
|
|
532
|
+
if [[ ! "$overwrite" =~ ^[Yy] ]]; then
|
|
533
|
+
# Declining to overwrite one file must never silently destroy
|
|
534
|
+
# another (bug-hunt MEDIUM): the fallback gets the same existence
|
|
535
|
+
# guard, walking numbered suffixes until a free name is found.
|
|
536
|
+
target="./prd-quickstart.md"
|
|
537
|
+
local _qs_n=2
|
|
538
|
+
while [ -e "$target" ]; do
|
|
539
|
+
target="./prd-quickstart-${_qs_n}.md"
|
|
540
|
+
_qs_n=$((_qs_n + 1))
|
|
541
|
+
if [ "$_qs_n" -gt 100 ]; then
|
|
542
|
+
printf '%sCould not find a free PRD filename (prd-quickstart-*.md all taken).%s\n' "$_QS_RED" "$_QS_NC" >&2
|
|
543
|
+
exit 1
|
|
544
|
+
fi
|
|
545
|
+
done
|
|
546
|
+
fi
|
|
547
|
+
fi
|
|
548
|
+
if ! cp "$prd_source" "$target" 2>/dev/null; then
|
|
549
|
+
printf '%sCould not write the PRD to the current directory. Try a writable directory.%s\n' "$_QS_RED" "$_QS_NC" >&2
|
|
550
|
+
exit 1
|
|
551
|
+
fi
|
|
552
|
+
|
|
553
|
+
printf '\n'
|
|
554
|
+
printf 'Starting your build. Progress streams here in the terminal.\n'
|
|
555
|
+
printf ' PRD saved to: %s\n' "$target"
|
|
556
|
+
printf " Tip: run 'loki dashboard' in another terminal to watch in a browser.\n"
|
|
557
|
+
printf '\n'
|
|
558
|
+
|
|
559
|
+
# ----- Compose with cmd_start -------------------------------------------
|
|
560
|
+
# Consent was collected in step 4, so --yes is correct. The plan was already
|
|
561
|
+
# shown in step 4, so --no-plan avoids double-printing it. No --simple: the
|
|
562
|
+
# estimate shown was the auto-detect estimate, and the runner's own
|
|
563
|
+
# complexity detection agrees with the estimator for the default PRD
|
|
564
|
+
# (verified: detect_complexity and show_prd_plan both classify the sample
|
|
565
|
+
# Todo app SIMPLE), so the quote matches the charge.
|
|
566
|
+
#
|
|
567
|
+
# cmd_start EXECS the runner (loki:1856, _loki_new_session_exec), so it never
|
|
568
|
+
# returns into this function. We wrap it in a subshell -- the exact pattern
|
|
569
|
+
# cmd_demo uses (loki:9337) -- so the exec replaces the SUBSHELL while the
|
|
570
|
+
# interactive controlling tty (and Ctrl+C) is preserved, the build runs in
|
|
571
|
+
# the foreground, and on failure this function's honest message stays
|
|
572
|
+
# reachable. We do NOT auto-open a dashboard: the default `loki start` does
|
|
573
|
+
# not start one (it is gated on --api, loki:1825), and starting one here
|
|
574
|
+
# would bind port 57374, which quickstart deliberately must not own.
|
|
575
|
+
local start_exit=0
|
|
576
|
+
( cmd_start "$target" --yes --no-plan ) || start_exit=$?
|
|
577
|
+
|
|
578
|
+
if [ "$start_exit" -ne 0 ]; then
|
|
579
|
+
printf "%sThe build did not start cleanly. Run 'loki doctor' and try 'loki start ./prd.md'.%s\n" "$_QS_RED" "$_QS_NC" >&2
|
|
580
|
+
exit "$start_exit"
|
|
581
|
+
fi
|
|
582
|
+
|
|
583
|
+
return 0
|
|
584
|
+
}
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v7.
|
|
5
|
+
**Version:** v7.30.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -128,6 +128,15 @@ package, while `loki-mode-sdk` is the thin client.
|
|
|
128
128
|
|
|
129
129
|
## Quick Start
|
|
130
130
|
|
|
131
|
+
New here? `loki quickstart` (v7.29.0) walks you through your first build in
|
|
132
|
+
four questions (setup check, one-line idea, template pick, plan review with
|
|
133
|
+
a real cost estimate before anything is spent). Pressing Enter at every step
|
|
134
|
+
builds the sample Todo app.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
loki quickstart
|
|
138
|
+
```
|
|
139
|
+
|
|
131
140
|
Drop a spec -- any artifact that describes what you want built -- and Loki
|
|
132
141
|
Mode takes it from spec to deployed app. Specs can be a markdown PRD, a
|
|
133
142
|
GitHub issue URL, or a YAML feature description.
|
|
@@ -297,7 +297,7 @@ Developers who value open-source tooling, speed, and terminal-native workflows.
|
|
|
297
297
|
| **Benchmark (SWE-bench)** | N/A | N/A | 80.9% (Opus 4.5) | 56.8% (Pro) | Configurable (uses any model) |
|
|
298
298
|
| **CLI Interface** | No (Python API) | No (web UI) | Yes | Yes | Yes |
|
|
299
299
|
| **IDE Integration** | No | No | Yes (VS Code, JetBrains) | No | Yes (VS Code extension) |
|
|
300
|
-
| **MCP Support** | No | No | Yes | Yes | Yes (
|
|
300
|
+
| **MCP Support** | No | No | Yes | Yes | Yes (34 tools) |
|
|
301
301
|
| **Cost (Heavy Use)** | Enterprise contract | $100/mo | $200/mo or API | $20-200/mo or API | $0 + API costs |
|
|
302
302
|
| **Context Window** | Model-dependent | N/A | 200K tokens | Model-dependent | Model-dependent |
|
|
303
303
|
|
|
@@ -368,7 +368,7 @@ Replit Agent has evolved rapidly through four major versions:
|
|
|
368
368
|
| Figma | MCP + Import | Builder.io plugin | No |
|
|
369
369
|
| GitHub | Yes | Bidirectional sync | Full Git workflow |
|
|
370
370
|
| Slack/Notion/Linear | Native connectors | No | Via MCP (extensible) |
|
|
371
|
-
| Custom MCP | Yes | No | Yes (
|
|
371
|
+
| Custom MCP | Yes | No | Yes (34 MCP tools) |
|
|
372
372
|
| Salesforce | Native connector | No | No |
|
|
373
373
|
| BigQuery/Snowflake | Native connectors | No | No |
|
|
374
374
|
|
|
@@ -544,7 +544,7 @@ When positioning Loki Mode against Replit and Lovable, emphasize:
|
|
|
544
544
|
| Dashboard active sessions | Monitoring only | Build-along interface |
|
|
545
545
|
| Figma integration | None | MCP connector live |
|
|
546
546
|
| Starter templates | 13 PRD templates | +5 full-stack starter kits |
|
|
547
|
-
| MCP connectors |
|
|
547
|
+
| MCP connectors | 34 tools | 25+ tools with common services |
|
|
548
548
|
| Cost transparency | Token tracking exists | Real-time cost dashboard |
|
|
549
549
|
|
|
550
550
|
---
|