loki-mode 7.7.26 → 7.7.27

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 CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-to-product system. Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product via the RARV-C closure loop, with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v7.7.26
6
+ # Loki Mode v7.7.27
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -381,4 +381,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
381
381
 
382
382
  ---
383
383
 
384
- **v7.7.26 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
384
+ **v7.7.27 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.7.26
1
+ 7.7.27
Binary file
Binary file
@@ -0,0 +1,358 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta name="theme-color" content="#553DE9">
7
+ <title>Welcome to Loki Mode</title>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
11
+ <style>
12
+ :root {
13
+ --loki-bg-primary: #FAFAF7;
14
+ --loki-bg-secondary: #F2F0EB;
15
+ --loki-bg-card: rgba(255, 255, 255, 0.72);
16
+ --loki-text-primary: #1A1614;
17
+ --loki-text-secondary: #4A4640;
18
+ --loki-text-muted: #8A857C;
19
+ --loki-accent: #553DE9;
20
+ --loki-accent-hover: #4432c4;
21
+ --loki-accent-glow: rgba(85, 61, 233, 0.15);
22
+ --loki-border: rgba(0, 0, 0, 0.08);
23
+ --loki-success: #1AAF95;
24
+ --loki-glass-bg: rgba(255, 255, 255, 0.55);
25
+ --loki-glass-border: rgba(255, 255, 255, 0.35);
26
+ --loki-glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
27
+ --loki-transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
28
+ }
29
+ @media (prefers-color-scheme: dark) {
30
+ :root {
31
+ --loki-bg-primary: #0F0B1A;
32
+ --loki-bg-secondary: #150F24;
33
+ --loki-bg-card: rgba(30, 21, 51, 0.72);
34
+ --loki-text-primary: #F0ECF8;
35
+ --loki-text-secondary: #B8B0C8;
36
+ --loki-text-muted: #8A82A0;
37
+ --loki-border: rgba(255, 255, 255, 0.10);
38
+ --loki-glass-bg: rgba(30, 21, 51, 0.55);
39
+ --loki-glass-border: rgba(255, 255, 255, 0.10);
40
+ --loki-glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);
41
+ }
42
+ }
43
+ * { box-sizing: border-box; margin: 0; padding: 0; }
44
+ html, body { height: 100%; }
45
+ body {
46
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
47
+ background: var(--loki-bg-primary);
48
+ color: var(--loki-text-primary);
49
+ line-height: 1.55;
50
+ -webkit-font-smoothing: antialiased;
51
+ background-image: radial-gradient(circle at 15% 10%, var(--loki-accent-glow), transparent 40%);
52
+ }
53
+ .wrap { max-width: 880px; margin: 0 auto; padding: 56px 24px 72px; }
54
+ .brand { display: flex; align-items: center; gap: 10px; margin-bottom: 36px; }
55
+ .brand-mark {
56
+ width: 34px; height: 34px; border-radius: 9px;
57
+ background: linear-gradient(135deg, var(--loki-accent), #7B63FF);
58
+ display: flex; align-items: center; justify-content: center;
59
+ color: #fff; font-family: 'DM Serif Display', serif; font-size: 20px;
60
+ }
61
+ .brand-name { font-family: 'DM Serif Display', serif; font-size: 1.25rem; }
62
+ .brand-by { color: var(--loki-text-muted); font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; }
63
+ h1 { font-family: 'DM Serif Display', Georgia, serif; font-size: 2.6rem; font-weight: 400; line-height: 1.1; margin-bottom: 14px; letter-spacing: -0.01em; }
64
+ .lede { font-size: 1.12rem; color: var(--loki-text-secondary); max-width: 600px; margin-bottom: 8px; }
65
+ .ver { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; color: var(--loki-text-muted); margin-bottom: 36px; }
66
+ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-bottom: 40px; }
67
+ .card {
68
+ background: var(--loki-glass-bg);
69
+ border: 1px solid var(--loki-glass-border);
70
+ box-shadow: var(--loki-glass-shadow);
71
+ border-radius: 12px; padding: 18px 18px 20px;
72
+ backdrop-filter: blur(8px);
73
+ }
74
+ .card h3 { font-family: 'DM Serif Display', serif; font-size: 1.05rem; font-weight: 400; margin-bottom: 6px; }
75
+ .card p { font-size: 0.88rem; color: var(--loki-text-secondary); }
76
+ .card .tag { display: inline-block; font-family: 'JetBrains Mono', monospace; font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--loki-accent); margin-bottom: 10px; }
77
+ .form-card {
78
+ background: var(--loki-bg-card);
79
+ border: 1px solid var(--loki-border);
80
+ border-radius: 14px; padding: 26px; margin-bottom: 18px;
81
+ box-shadow: var(--loki-glass-shadow);
82
+ }
83
+ .form-card h2 { font-family: 'DM Serif Display', serif; font-weight: 400; font-size: 1.4rem; margin-bottom: 6px; }
84
+ .form-sub { color: var(--loki-text-muted); font-size: 0.9rem; margin-bottom: 22px; }
85
+ .field { margin-bottom: 18px; }
86
+ .field label { display: block; font-size: 0.82rem; font-weight: 500; margin-bottom: 7px; color: var(--loki-text-secondary); }
87
+ select {
88
+ width: 100%; padding: 10px 12px; font-family: inherit; font-size: 0.92rem;
89
+ color: var(--loki-text-primary); background: var(--loki-bg-primary);
90
+ border: 1px solid var(--loki-border); border-radius: 8px; appearance: none;
91
+ cursor: pointer; transition: border-color var(--loki-transition);
92
+ }
93
+ select:focus { outline: none; border-color: var(--loki-accent); box-shadow: 0 0 0 3px var(--loki-accent-glow); }
94
+ .chips { display: flex; flex-wrap: wrap; gap: 8px; }
95
+ .chip {
96
+ font-size: 0.84rem; padding: 7px 13px; border-radius: 999px;
97
+ border: 1px solid var(--loki-border); background: var(--loki-bg-primary);
98
+ color: var(--loki-text-secondary); cursor: pointer; user-select: none;
99
+ transition: all var(--loki-transition);
100
+ }
101
+ .chip[aria-pressed="true"] {
102
+ background: var(--loki-accent); color: #fff; border-color: var(--loki-accent);
103
+ }
104
+ .btn {
105
+ width: 100%; padding: 13px; font-family: inherit; font-size: 0.95rem; font-weight: 600;
106
+ color: #fff; background: var(--loki-accent); border: none; border-radius: 9px;
107
+ cursor: pointer; transition: background var(--loki-transition); margin-top: 6px;
108
+ }
109
+ .btn:hover { background: var(--loki-accent-hover); }
110
+ .btn:disabled { opacity: 0.55; cursor: not-allowed; }
111
+ .consent { font-size: 0.76rem; color: var(--loki-text-muted); margin-top: 14px; line-height: 1.5; }
112
+ .consent code { font-family: 'JetBrains Mono', monospace; font-size: 0.72rem; background: var(--loki-bg-secondary); padding: 1px 5px; border-radius: 4px; }
113
+ .cta-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
114
+ .cta {
115
+ display: inline-flex; align-items: center; gap: 7px; text-decoration: none;
116
+ font-size: 0.9rem; font-weight: 500; padding: 10px 16px; border-radius: 8px;
117
+ border: 1px solid var(--loki-border); color: var(--loki-text-primary);
118
+ background: var(--loki-bg-card); transition: all var(--loki-transition);
119
+ }
120
+ .cta:hover { border-color: var(--loki-accent); color: var(--loki-accent); }
121
+ .cta.primary { background: var(--loki-accent); color: #fff; border-color: var(--loki-accent); }
122
+ .cta.primary:hover { background: var(--loki-accent-hover); color: #fff; }
123
+ .quickstart {
124
+ font-family: 'JetBrains Mono', monospace; font-size: 0.85rem;
125
+ background: var(--loki-bg-secondary); border: 1px solid var(--loki-border);
126
+ border-radius: 8px; padding: 9px 13px; color: var(--loki-text-primary);
127
+ }
128
+ .research { margin-top: 34px; font-size: 0.76rem; color: var(--loki-text-muted); }
129
+ .research .rchips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
130
+ .rchip { font-family: 'JetBrains Mono', monospace; font-size: 0.68rem; padding: 3px 8px; border: 1px solid var(--loki-border); border-radius: 6px; }
131
+ .thanks { display: none; text-align: center; padding: 18px 0; }
132
+ .thanks.show { display: block; }
133
+ .thanks .check { width: 44px; height: 44px; border-radius: 50%; background: var(--loki-success); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 22px; margin-bottom: 12px; }
134
+ .disabled-note { display: none; font-size: 0.85rem; color: var(--loki-text-muted); background: var(--loki-bg-secondary); border: 1px solid var(--loki-border); border-radius: 8px; padding: 12px 14px; }
135
+ .disabled-note.show { display: block; }
136
+ footer { margin-top: 40px; font-size: 0.78rem; color: var(--loki-text-muted); }
137
+ footer a { color: var(--loki-accent); text-decoration: none; }
138
+ </style>
139
+ </head>
140
+ <body>
141
+ <div class="wrap">
142
+ <div class="brand">
143
+ <div class="brand-mark">L</div>
144
+ <div>
145
+ <div class="brand-name">Loki Mode</div>
146
+ <div class="brand-by">Powered by Autonomi</div>
147
+ </div>
148
+ </div>
149
+
150
+ <h1>Describe it. Walk away.<br>Get working, tested software.</h1>
151
+ <p class="lede">Loki takes a spec (a PRD, a GitHub issue, or a one-line brief) all the way to a deployed product, running its Reason-Act-Reflect-Verify-Close loop until the work is actually done, not just attempted.</p>
152
+ <div class="ver" id="ver">loki-mode</div>
153
+
154
+ <div class="cards">
155
+ <div class="card">
156
+ <span class="tag">Verified, not just generated</span>
157
+ <h3>Closure loop + council</h3>
158
+ <p>Every change passes a RARV-C cycle and a unanimous multi-reviewer council before it counts as done. A quality bar you can audit.</p>
159
+ </div>
160
+ <div class="card">
161
+ <span class="tag">Compounds over time</span>
162
+ <h3>Cross-project memory</h3>
163
+ <p>Lessons learned on one project surface on the next, so your agents stop repeating the same mistakes across your whole codebase.</p>
164
+ </div>
165
+ <div class="card">
166
+ <span class="tag">Yours to run</span>
167
+ <h3>Provider-agnostic and private</h3>
168
+ <p>Runs on Claude, Codex, Cline, or Aider. Your keys, your infrastructure, no vendor lock-in.</p>
169
+ </div>
170
+ </div>
171
+
172
+ <div class="form-card" id="formCard">
173
+ <h2>Tell us who you are</h2>
174
+ <p class="form-sub">Optional, takes 10 seconds, and helps us build the right thing.</p>
175
+
176
+ <div class="field">
177
+ <label for="role">Your role</label>
178
+ <select id="role">
179
+ <option value="">Select...</option>
180
+ <option>Founder / CEO</option>
181
+ <option>Engineering leader</option>
182
+ <option>Software engineer</option>
183
+ <option>Product manager</option>
184
+ <option>Designer</option>
185
+ <option>Student / learner</option>
186
+ <option>Researcher</option>
187
+ <option>Other</option>
188
+ </select>
189
+ </div>
190
+
191
+ <div class="field">
192
+ <label for="company">Company size</label>
193
+ <select id="company">
194
+ <option value="">Select...</option>
195
+ <option>Just me</option>
196
+ <option>2-10</option>
197
+ <option>11-50</option>
198
+ <option>51-200</option>
199
+ <option>201-1000</option>
200
+ <option>1000+</option>
201
+ </select>
202
+ </div>
203
+
204
+ <div class="field">
205
+ <label>Tools you use today</label>
206
+ <div class="chips" id="tools">
207
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Claude Code</span>
208
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Cursor</span>
209
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">OpenAI Codex</span>
210
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">GitHub Copilot</span>
211
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Cline</span>
212
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Aider</span>
213
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Replit</span>
214
+ <span class="chip" role="button" tabindex="0" aria-pressed="false">Other</span>
215
+ </div>
216
+ </div>
217
+
218
+ <button class="btn" id="submitBtn">Send and get started</button>
219
+ <p class="consent">
220
+ Sends <strong>anonymous</strong> usage analytics (your role, company size, and tools)
221
+ to help us improve the product. We <strong>never</strong> collect your prompts, PRDs, or
222
+ code. Opt out anytime with <code>LOKI_TELEMETRY_DISABLED=true</code> or <code>DO_NOT_TRACK=1</code>.
223
+ </p>
224
+ </div>
225
+
226
+ <div class="disabled-note" id="disabledNote">
227
+ Analytics are turned off for this session (LOKI_TELEMETRY_DISABLED / DO_NOT_TRACK).
228
+ Nothing will be sent. Welcome aboard regardless.
229
+ </div>
230
+
231
+ <div class="thanks" id="thanks">
232
+ <div class="check">&#10003;</div>
233
+ <h2 style="font-family:'DM Serif Display',serif;font-weight:400;">Thanks, you're all set.</h2>
234
+ <p style="color:var(--loki-text-secondary);margin-top:6px;">Point Loki at a spec and let it run.</p>
235
+ </div>
236
+
237
+ <div class="cta-row">
238
+ <a class="cta primary" href="https://www.autonomi.dev/docs" target="_blank" rel="noopener">Read the docs</a>
239
+ <span class="quickstart">loki start ./prd.md</span>
240
+ </div>
241
+
242
+ <div class="research">
243
+ Built on published research from Anthropic, Google DeepMind, OpenAI, and NVIDIA.
244
+ <div class="rchips">
245
+ <span class="rchip">Constitutional AI</span>
246
+ <span class="rchip">Scalable Oversight via Debate</span>
247
+ <span class="rchip">Agents SDK guardrails</span>
248
+ <span class="rchip">ToolOrchestra efficiency</span>
249
+ </div>
250
+ </div>
251
+
252
+ <footer>
253
+ Loki Mode by <a href="https://www.autonomi.dev/" target="_blank" rel="noopener">Autonomi</a>.
254
+ Questions? <a href="https://www.autonomi.dev/docs" target="_blank" rel="noopener">autonomi.dev/docs</a>
255
+ </footer>
256
+ </div>
257
+
258
+ <script>
259
+ (function () {
260
+ "use strict";
261
+ var POSTHOG_HOST = "https://us.i.posthog.com";
262
+ var POSTHOG_KEY = "phc_ya0vGBru41AJWtGNfZZ8H9W4yjoZy4KON0nnayS7s87";
263
+
264
+ // Read params the CLI may pass: ?telemetry=off, ?v=<version>, ?key=<override>, ?did=<distinct_id>
265
+ var params = new URLSearchParams(window.location.search);
266
+ var telemetryOff = params.get("telemetry") === "off";
267
+ var version = params.get("v") || "loki-mode";
268
+ if (params.get("key")) { POSTHOG_KEY = params.get("key"); }
269
+ var verEl = document.getElementById("ver");
270
+ if (verEl) { verEl.textContent = version; }
271
+
272
+ // distinct_id: prefer the id the CLI injects (the existing anonymous
273
+ // ~/.loki-telemetry-id), else a browser-local random id. Never an email
274
+ // or real name (the form has no such field).
275
+ function distinctId() {
276
+ var injected = params.get("did");
277
+ if (injected) { return injected; }
278
+ try {
279
+ var k = "loki_welcome_did";
280
+ var v = localStorage.getItem(k);
281
+ if (!v) {
282
+ v = (window.crypto && crypto.randomUUID) ? crypto.randomUUID()
283
+ : "web-" + Date.now() + "-" + Math.random().toString(36).slice(2);
284
+ localStorage.setItem(k, v);
285
+ }
286
+ return v;
287
+ } catch (e) {
288
+ return "web-anon";
289
+ }
290
+ }
291
+
292
+ var formCard = document.getElementById("formCard");
293
+ var disabledNote = document.getElementById("disabledNote");
294
+ var thanks = document.getElementById("thanks");
295
+ var submitBtn = document.getElementById("submitBtn");
296
+
297
+ // Opt-out: hide the form and return before any handler binds, so a
298
+ // capture can never fire. No network call happens on load either.
299
+ if (telemetryOff) {
300
+ if (formCard) { formCard.style.display = "none"; }
301
+ if (disabledNote) { disabledNote.classList.add("show"); }
302
+ return;
303
+ }
304
+
305
+ // Tool chips toggle (local UI state only).
306
+ var toolEls = Array.prototype.slice.call(document.querySelectorAll("#tools .chip"));
307
+ function toggleChip(el) {
308
+ var on = el.getAttribute("aria-pressed") === "true";
309
+ el.setAttribute("aria-pressed", on ? "false" : "true");
310
+ }
311
+ toolEls.forEach(function (el) {
312
+ el.addEventListener("click", function () { toggleChip(el); });
313
+ el.addEventListener("keydown", function (e) {
314
+ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleChip(el); }
315
+ });
316
+ });
317
+
318
+ // The ONLY network call in the page happens here, on explicit click.
319
+ submitBtn.addEventListener("click", function () {
320
+ var role = document.getElementById("role").value || "unspecified";
321
+ var company = document.getElementById("company").value || "unspecified";
322
+ var tools = toolEls
323
+ .filter(function (el) { return el.getAttribute("aria-pressed") === "true"; })
324
+ .map(function (el) { return el.textContent.trim(); });
325
+
326
+ var payload = {
327
+ api_key: POSTHOG_KEY,
328
+ event: "welcome_profile",
329
+ distinct_id: distinctId(),
330
+ properties: {
331
+ role: role,
332
+ company_size: company,
333
+ tools: tools,
334
+ source: "welcome_opener",
335
+ loki_version: version
336
+ // Deliberately NO prompt, PRD, code, file path, cwd, hostname,
337
+ // project name, email, or real name. Anonymous fields only.
338
+ }
339
+ };
340
+
341
+ submitBtn.disabled = true;
342
+ submitBtn.textContent = "Sending...";
343
+
344
+ fetch(POSTHOG_HOST + "/capture/", {
345
+ method: "POST",
346
+ headers: { "Content-Type": "application/json" },
347
+ body: JSON.stringify(payload),
348
+ keepalive: true
349
+ }).catch(function () { /* fire-and-forget; never block the user */ })
350
+ .finally(function () {
351
+ if (formCard) { formCard.style.display = "none"; }
352
+ if (thanks) { thanks.classList.add("show"); }
353
+ });
354
+ });
355
+ })();
356
+ </script>
357
+ </body>
358
+ </html>
package/autonomy/loki CHANGED
@@ -700,6 +700,10 @@ detect_arg_type() {
700
700
 
701
701
  # Start Loki Mode
702
702
  cmd_start() {
703
+ # First-run welcome (once): open the branded welcome page on the very
704
+ # first start. Writes ~/.loki/.welcomed and never repeats; non-blocking,
705
+ # and never auto-opens a browser in CI or non-interactive shells.
706
+ cmd_welcome_maybe_firstrun 2>/dev/null || true
703
707
  local args=()
704
708
  local prd_file=""
705
709
  local provider=""
@@ -3837,6 +3841,94 @@ cmd_dashboard_open() {
3837
3841
  fi
3838
3842
  }
3839
3843
 
3844
+ # Welcome opener (the "magic opener"). Shows a branded welcome page in the
3845
+ # browser, or a terminal welcome when no browser is available (headless,
3846
+ # Docker, CI). Honors telemetry opt-out (LOKI_TELEMETRY_DISABLED / DO_NOT_TRACK):
3847
+ # when opted out, the page is loaded with ?telemetry=off so its form is
3848
+ # disabled and no analytics are ever sent.
3849
+ WELCOME_MARKER="${HOME}/.loki/.welcomed"
3850
+
3851
+ _loki_telemetry_off() {
3852
+ [ "${LOKI_TELEMETRY_DISABLED:-}" = "true" ] && return 0
3853
+ [ "${DO_NOT_TRACK:-}" = "1" ] && return 0
3854
+ return 1
3855
+ }
3856
+
3857
+ cmd_welcome_terminal() {
3858
+ local ver="${1:-}"
3859
+ echo ""
3860
+ echo -e " ${BOLD}Loki Mode${NC} ${DIM}by Autonomi${NC}${ver:+ ${DIM}v${ver}${NC}}"
3861
+ echo ""
3862
+ echo -e " ${BOLD}Describe it. Walk away. Get working, tested software.${NC}"
3863
+ echo ""
3864
+ echo -e " Loki takes a spec (PRD, GitHub issue, or one-line brief) to a deployed"
3865
+ echo -e " product via the RARV-C closure loop, until the work is actually done."
3866
+ echo ""
3867
+ echo -e " ${CYAN}Closure loop + council${NC} Every change is verified by a unanimous council."
3868
+ echo -e " ${CYAN}Cross-project memory${NC} Lessons compound, so agents stop repeating mistakes."
3869
+ echo -e " ${CYAN}Provider-agnostic${NC} Claude, Codex, Cline, or Aider. Your keys, your infra."
3870
+ echo ""
3871
+ echo -e " Quick start: ${BOLD}loki start ./prd.md${NC}"
3872
+ echo -e " Docs: ${BOLD}https://www.autonomi.dev/docs${NC}"
3873
+ echo ""
3874
+ if _loki_telemetry_off; then
3875
+ echo -e " ${DIM}Analytics are off for this session. Nothing is sent.${NC}"
3876
+ else
3877
+ echo -e " ${DIM}Anonymous usage analytics help us improve the product. We never${NC}"
3878
+ echo -e " ${DIM}collect prompts, PRDs, or code. Opt out: LOKI_TELEMETRY_DISABLED=true${NC}"
3879
+ fi
3880
+ echo ""
3881
+ }
3882
+
3883
+ cmd_welcome() {
3884
+ local ver=""
3885
+ [ -f "${SKILL_DIR}/VERSION" ] && ver="$(cat "${SKILL_DIR}/VERSION" 2>/dev/null | tr -d '[:space:]')"
3886
+
3887
+ local welcome_file="${SKILL_DIR}/assets/welcome/welcome.html"
3888
+
3889
+ # Build the file URL with params: version, opt-out, and the existing
3890
+ # anonymous telemetry distinct-id (so browser + install share one id).
3891
+ local q="v=${ver}"
3892
+ if _loki_telemetry_off; then
3893
+ q="${q}&telemetry=off"
3894
+ else
3895
+ local idfile="${HOME}/.loki-telemetry-id"
3896
+ [ -f "$idfile" ] && q="${q}&did=$(cat "$idfile" 2>/dev/null | tr -d '[:space:]')"
3897
+ fi
3898
+
3899
+ # Headless / Docker / CI / no-browser: print the terminal welcome only.
3900
+ local has_browser=""
3901
+ if command -v open >/dev/null 2>&1; then has_browser="open"
3902
+ elif command -v xdg-open >/dev/null 2>&1; then has_browser="xdg-open"
3903
+ elif command -v start >/dev/null 2>&1; then has_browser="start"
3904
+ fi
3905
+
3906
+ if [ -z "$has_browser" ] || [ ! -f "$welcome_file" ] || [ -n "${CI:-}" ] || [ ! -t 1 ]; then
3907
+ cmd_welcome_terminal "$ver"
3908
+ [ -f "$welcome_file" ] && echo -e " ${DIM}Full welcome page: ${welcome_file}${NC}" && echo ""
3909
+ return 0
3910
+ fi
3911
+
3912
+ echo -e "${GREEN}Opening the Loki Mode welcome page in your browser...${NC}"
3913
+ "$has_browser" "file://${welcome_file}?${q}" >/dev/null 2>&1 || cmd_welcome_terminal "$ver"
3914
+ }
3915
+
3916
+ # First-run hook: open the welcome once, then never again. Browser only when
3917
+ # interactive + not CI + not opted out; otherwise nothing (no noisy auto-print
3918
+ # during a real run). Marker lives at ~/.loki/.welcomed.
3919
+ cmd_welcome_maybe_firstrun() {
3920
+ [ -f "$WELCOME_MARKER" ] && return 0
3921
+ mkdir -p "$(dirname "$WELCOME_MARKER")" 2>/dev/null || true
3922
+ : > "$WELCOME_MARKER" 2>/dev/null || true
3923
+ # Only auto-open on an interactive, non-CI terminal. cmd_welcome itself
3924
+ # re-checks for a browser and falls back to the terminal welcome, so we
3925
+ # gate purely on interactivity + CI here (grouped to avoid &&/|| precedence
3926
+ # ambiguity). Backgrounded so it never delays the start.
3927
+ if [ -t 1 ] && [ -z "${CI:-}" ]; then
3928
+ (cmd_welcome >/dev/null 2>&1 &) || true
3929
+ fi
3930
+ }
3931
+
3840
3932
  # Web app management
3841
3933
  # Purple Lab -- standalone product web UI for Loki Mode.
3842
3934
  # Runs on port 57375 (separate from dashboard at 57374).
@@ -12505,6 +12597,9 @@ main() {
12505
12597
  demo)
12506
12598
  cmd_demo "$@"
12507
12599
  ;;
12600
+ welcome)
12601
+ cmd_welcome "$@"
12602
+ ;;
12508
12603
  init)
12509
12604
  cmd_init "$@"
12510
12605
  ;;
@@ -173,8 +173,11 @@ console.log(' loki start --provider codex Start with OpenAI Codex');
173
173
  console.log(' loki start --provider gemini Start with Google Gemini');
174
174
  console.log(' loki status Check status');
175
175
  console.log(' loki doctor Verify installation');
176
+ console.log(' loki welcome Quick tour, docs, and setup');
176
177
  console.log(' loki --help Show all commands');
177
178
  console.log('');
179
+ console.log('New here? Run `loki welcome` for a 30-second tour.');
180
+ console.log('');
178
181
 
179
182
  // Anonymous install telemetry (fire-and-forget, silent)
180
183
  try {
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.7.26"
10
+ __version__ = "7.7.27"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v7.7.26
5
+ **Version:** v7.7.27
6
6
 
7
7
  ---
8
8
 
@@ -0,0 +1,106 @@
1
+ # Welcome Opener Plan (the "magic opener")
2
+
3
+ ## Goal
4
+ A polished welcome experience shown when people install the loki CLI or
5
+ run the Docker image. It (1) introduces Loki/Autonomi with the dashboard's
6
+ design language, (2) subtly highlights the research backing + memory
7
+ compounding moat, (3) offers a simple opt-in form collecting anonymous
8
+ role / business / tools, transmitted to PostHog on click, and (4) links to
9
+ autonomi.dev/docs.
10
+
11
+ ## Hard constraints (from the user + CLAUDE.md)
12
+ - Anonymous usage analytics for PRODUCT IMPROVEMENT ONLY. NEVER transmit
13
+ prompts, PRDs, code, or any project content. Disclosed, not covert.
14
+ - Reuse the EXISTING PostHog contract already in the codebase:
15
+ - host `https://us.i.posthog.com`, path `/capture/`
16
+ - public ingest key `phc_ya0vGBru41AJWtGNfZZ8H9W4yjoZy4KON0nnayS7s87`
17
+ (same key postinstall.js + autonomy/telemetry.sh already use; public
18
+ ingest keys are safe in client code), overridable by LOKI_POSTHOG_KEY.
19
+ - Honor opt-out: LOKI_TELEMETRY_DISABLED=true and DO_NOT_TRACK=1.
20
+ - Design must match the loki dashboard: accent #553DE9, light bg #FAFAF7 /
21
+ dark #0F0B1A, text #1A1614 / #F0ECF8, fonts DM Serif Display (headings),
22
+ Inter (body), JetBrains Mono (mono). Glass cards. Light + dark.
23
+ - No emojis, no em dashes anywhere.
24
+
25
+ ## Components
26
+
27
+ ### 1. web-app-less static page: `assets/welcome/welcome.html`
28
+ Self-contained single HTML file (inline CSS + JS, Google Fonts link), so
29
+ it works opened directly from disk OR served. Sections:
30
+ - Hero: "Loki Mode by Autonomi" + tagline "Describe it. Walk away. Get
31
+ working, tested software." + version (templated at serve time or left
32
+ generic).
33
+ - Three subtle highlight cards: (a) RARV-C closure + unanimous council
34
+ ("finishes the work, verified"), (b) Cross-project memory that compounds
35
+ ("your agents stop repeating mistakes across projects"), (c) Research
36
+ backing (Anthropic Constitutional AI / DeepMind debate / OpenAI Agents
37
+ SDK / NVIDIA ToolOrchestra) shown as small footnote-style chips, not
38
+ loud claims.
39
+ - Opt-in form: role (select), company size (select), primary tools
40
+ (multi-select chips: Claude Code, Cursor, Codex, Copilot, Cline, Aider,
41
+ other). A single "Send + get started" button. Consent line directly
42
+ under it: "Sends anonymous usage analytics (your role, company size,
43
+ tools) to help us improve the product. We never collect your prompts,
44
+ PRDs, or code. Opt out anytime with LOKI_TELEMETRY_DISABLED=true."
45
+ - CTA row: "Read the docs" -> https://www.autonomi.dev/docs ; "Quick
46
+ start" copyable `loki start ./prd.md`.
47
+ - On submit: POST to us.i.posthog.com/capture/ with event
48
+ `welcome_profile`, distinct_id = the existing ~/.loki-telemetry-id (or a
49
+ fresh uuid in browser localStorage if not injected), properties =
50
+ {role, company_size, tools, source:'welcome_opener', loki_version}.
51
+ Then show a thank-you state + the docs link. Submission is the ONLY
52
+ network call; nothing is sent on page load.
53
+ - Respect opt-out: if the page is served with ?telemetry=off (the CLI
54
+ passes this when LOKI_TELEMETRY_DISABLED/DO_NOT_TRACK is set), the form
55
+ is replaced with a "analytics disabled" note and the submit is a no-op.
56
+
57
+ ### 2. CLI command: `loki welcome`
58
+ - Mirrors cmd_dashboard_open idiom. Resolves the welcome.html path inside
59
+ the package, opens it with `open`/`xdg-open`. If no browser opener
60
+ (headless/Docker), prints the terminal fallback (see #4) + the file path
61
+ + the autonomi.dev/docs URL.
62
+ - Passes ?telemetry=off when opt-out env is set.
63
+ - Dispatch: add `welcome) cmd_welcome "$@" ;;` near the `demo)` case
64
+ (~autonomy/loki:12505) and a help line.
65
+
66
+ ### 3. First-run auto-open (once)
67
+ - Marker file: `~/.loki/.welcomed`. On first `loki start` (and at end of
68
+ postinstall when a browser is available + not CI + not opt-out), if the
69
+ marker is absent: open the welcome page once, then write the marker.
70
+ Never auto-open again. CI/non-TTY/Docker never auto-open a browser; they
71
+ only print the terminal welcome.
72
+ - postinstall.js already prints an install summary; append a one-line
73
+ "Run `loki welcome` for a quick tour" pointer (no auto browser launch in
74
+ postinstall to avoid surprising npm installs).
75
+
76
+ ### 4. Terminal fallback
77
+ - A clean ASCII/ANSI welcome (loki accent color) printed when no browser:
78
+ product one-liner, the 3 highlights as one line each, the docs URL, the
79
+ quick-start command, and the consent/opt-out line. No network call from
80
+ the terminal fallback (the form is browser-only; terminal just informs).
81
+
82
+ ## Files
83
+ - ADD `assets/welcome/welcome.html`
84
+ - ADD `assets/welcome/welcome.terminal.sh` (sourced helper that prints the
85
+ terminal welcome) OR inline in cmd_welcome.
86
+ - EDIT `autonomy/loki`: cmd_welcome + dispatch + help + first-run hook in
87
+ cmd_start.
88
+ - EDIT `bin/postinstall.js`: add the "Run `loki welcome`" pointer line.
89
+ - EDIT `package.json` "files": add `assets/`.
90
+ - EDIT `Dockerfile`, `Dockerfile.sandbox`: COPY assets/.
91
+ - ADD `tests/test-welcome-opener.sh`.
92
+ - Version bump 14 locations + CHANGELOG.
93
+
94
+ ## Privacy test matrix (must pass)
95
+ - Page load makes ZERO network calls (only submit does).
96
+ - Submit payload contains ONLY {role, company_size, tools, source,
97
+ loki_version, distinct_id}; never any file/prompt/PRD content.
98
+ - LOKI_TELEMETRY_DISABLED=true and DO_NOT_TRACK=1 each => form disabled,
99
+ no capture.
100
+ - `loki welcome` works headless (terminal fallback, no browser error).
101
+ - First-run marker opens once and not again.
102
+
103
+ ## Honesty
104
+ Highlights cite real, documented research (already in README Research
105
+ Foundation) and frame the memory moat as "retrieval/compounding," NOT a
106
+ claimed task-success number (consistent with prior honesty fixes).
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var _7=Object.defineProperty;var I7=(K)=>K;function P7(K,$){this[K]=I7.bind(null,$)}var v=(K,$)=>{for(var Q in $)_7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:P7.bind($,Q)})};var R=(K,$)=>()=>(K&&($=K(K=0)),$);var t=import.meta.require;var e1={};v(e1,{lokiDir:()=>P,homeLokiDir:()=>k1,findRepoRootForVersion:()=>N1,REPO_ROOT:()=>p});import{resolve as u,dirname as S1}from"path";import{fileURLToPath as L7}from"url";import{existsSync as J1}from"fs";import{homedir as R7}from"os";function E7(){let K=i1;for(let $=0;$<6;$++){if(J1(u(K,"VERSION"))&&J1(u(K,"autonomy/run.sh")))return K;let Q=S1(K);if(Q===K)break;K=Q}return u(i1,"..","..","..")}function N1(K){let $=K;for(let Q=0;Q<6;Q++){if(J1(u($,"VERSION"))&&J1(u($,"autonomy/run.sh")))return $;let X=S1($);if(X===$)break;$=X}return u(K,"..","..","..")}function P(){return process.env.LOKI_DIR??u(process.cwd(),".loki")}function k1(){return u(R7(),".loki")}var i1,p;var g=R(()=>{i1=S1(L7(import.meta.url));p=E7()});import{readFileSync as F7}from"fs";import{resolve as w7,dirname as x7}from"path";import{fileURLToPath as S7}from"url";function G1(){if(o!==null)return o;let K="7.7.26";if(typeof K==="string"&&K.length>0)return o=K,o;try{let $=x7(S7(import.meta.url)),Q=N1($);o=F7(w7(Q,"VERSION"),"utf-8").trim()}catch{o="unknown"}return o}var o=null;var D1=R(()=>{g()});var $0={};v($0,{runOrThrow:()=>N7,run:()=>k,commandVersion:()=>D7,commandExists:()=>h,ShellError:()=>C1});async function k(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[W,z,q]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:W,stderr:z,exitCode:q}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function N7(K,$={}){let Q=await k(K,$);if(Q.exitCode!==0)throw new C1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function h(K){let $=k7(K),Q=await k(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function k7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function D7(K,$="--version"){if(!await h(K))return null;let X=await k([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var C1;var n=R(()=>{C1=class C1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function c(K){return C7?"":K}var C7,E,b,F,T6,O,D,w,H;var a=R(()=>{C7=(process.env.NO_COLOR??"").length>0;E=c("\x1B[0;31m"),b=c("\x1B[0;32m"),F=c("\x1B[1;33m"),T6=c("\x1B[0;34m"),O=c("\x1B[0;36m"),D=c("\x1B[1m"),w=c("\x1B[2m"),H=c("\x1B[0m")});import{existsSync as c7}from"fs";async function i(){if(X1!==void 0)return X1;let K="/opt/homebrew/bin/python3.12";if(c7(K))return X1=K,K;let $=await h("python3.12");if($)return X1=$,$;let Q=await h("python3");return X1=Q,Q}async function s(K,$={}){let Q=await i();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return k([Q,"-c",K],$)}var X1;var Z1=R(()=>{n()});var G0={};v(G0,{runStatus:()=>Q5});import{existsSync as N,readFileSync as W1,readdirSync as W0,statSync as H0}from"fs";import{resolve as x,basename as a7}from"path";async function r7(){if(await h("jq"))return!0;return process.stdout.write(`${E}Error: jq is required but not installed.${H}
2
+ var _7=Object.defineProperty;var I7=(K)=>K;function P7(K,$){this[K]=I7.bind(null,$)}var v=(K,$)=>{for(var Q in $)_7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:P7.bind($,Q)})};var R=(K,$)=>()=>(K&&($=K(K=0)),$);var t=import.meta.require;var e1={};v(e1,{lokiDir:()=>P,homeLokiDir:()=>k1,findRepoRootForVersion:()=>N1,REPO_ROOT:()=>p});import{resolve as u,dirname as S1}from"path";import{fileURLToPath as L7}from"url";import{existsSync as J1}from"fs";import{homedir as R7}from"os";function E7(){let K=i1;for(let $=0;$<6;$++){if(J1(u(K,"VERSION"))&&J1(u(K,"autonomy/run.sh")))return K;let Q=S1(K);if(Q===K)break;K=Q}return u(i1,"..","..","..")}function N1(K){let $=K;for(let Q=0;Q<6;Q++){if(J1(u($,"VERSION"))&&J1(u($,"autonomy/run.sh")))return $;let X=S1($);if(X===$)break;$=X}return u(K,"..","..","..")}function P(){return process.env.LOKI_DIR??u(process.cwd(),".loki")}function k1(){return u(R7(),".loki")}var i1,p;var g=R(()=>{i1=S1(L7(import.meta.url));p=E7()});import{readFileSync as F7}from"fs";import{resolve as w7,dirname as x7}from"path";import{fileURLToPath as S7}from"url";function G1(){if(o!==null)return o;let K="7.7.27";if(typeof K==="string"&&K.length>0)return o=K,o;try{let $=x7(S7(import.meta.url)),Q=N1($);o=F7(w7(Q,"VERSION"),"utf-8").trim()}catch{o="unknown"}return o}var o=null;var D1=R(()=>{g()});var $0={};v($0,{runOrThrow:()=>N7,run:()=>k,commandVersion:()=>D7,commandExists:()=>h,ShellError:()=>C1});async function k(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[W,z,q]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:W,stderr:z,exitCode:q}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function N7(K,$={}){let Q=await k(K,$);if(Q.exitCode!==0)throw new C1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function h(K){let $=k7(K),Q=await k(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function k7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function D7(K,$="--version"){if(!await h(K))return null;let X=await k([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var C1;var n=R(()=>{C1=class C1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function c(K){return C7?"":K}var C7,E,b,F,T6,O,D,w,H;var a=R(()=>{C7=(process.env.NO_COLOR??"").length>0;E=c("\x1B[0;31m"),b=c("\x1B[0;32m"),F=c("\x1B[1;33m"),T6=c("\x1B[0;34m"),O=c("\x1B[0;36m"),D=c("\x1B[1m"),w=c("\x1B[2m"),H=c("\x1B[0m")});import{existsSync as c7}from"fs";async function i(){if(X1!==void 0)return X1;let K="/opt/homebrew/bin/python3.12";if(c7(K))return X1=K,K;let $=await h("python3.12");if($)return X1=$,$;let Q=await h("python3");return X1=Q,Q}async function s(K,$={}){let Q=await i();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return k([Q,"-c",K],$)}var X1;var Z1=R(()=>{n()});var G0={};v(G0,{runStatus:()=>Q5});import{existsSync as N,readFileSync as W1,readdirSync as W0,statSync as H0}from"fs";import{resolve as x,basename as a7}from"path";async function r7(){if(await h("jq"))return!0;return process.stdout.write(`${E}Error: jq is required but not installed.${H}
3
3
  `),process.stdout.write(`Install with:
4
4
  `),process.stdout.write(` brew install jq (macOS)
5
5
  `),process.stdout.write(` apt install jq (Debian/Ubuntu)
@@ -585,4 +585,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
585
585
  `),2}default:return process.stderr.write(`Unknown command: ${$}
586
586
  `),process.stderr.write(j7),2}}process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var X6=await Q6(Bun.argv.slice(2));process.exit(X6);
587
587
 
588
- //# debugId=CE941072AA747DCC64756E2164756E21
588
+ //# debugId=007306826576BB8664756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.7.26'
60
+ __version__ = '7.7.27'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "7.7.26",
3
+ "version": "7.7.27",
4
4
  "description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
5
5
  "keywords": [
6
6
  "agent",
@@ -64,6 +64,7 @@
64
64
  "files": [
65
65
  "SKILL.md",
66
66
  "VERSION",
67
+ "assets/",
67
68
  "tools/",
68
69
  "autonomy/",
69
70
  "providers/",