loki-mode 6.64.0 → 6.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/run.sh +61 -21
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +59 -2
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/web-app/dist/assets/{Badge-8l0OZCRe.js → Badge-CecAeNGh.js} +1 -1
- package/web-app/dist/assets/{Button-6k_tnJgc.js → Button-BAwZY3QB.js} +1 -1
- package/web-app/dist/assets/{Card-DwkzVihG.js → Card-3YIYrz1X.js} +1 -1
- package/web-app/dist/assets/{HomePage-C0-_6Avk.js → HomePage-DYS0zqqT.js} +1 -1
- package/web-app/dist/assets/{LoginPage-BlJm-Tzr.js → LoginPage-D5Jj_Q44.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CsRjjzWq.js → NotFoundPage-DLG6ORdp.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-DQG_ZYM7.js → ProjectPage-D-ZyzZUT.js} +12 -12
- package/web-app/dist/assets/{ProjectsPage-BAQOc1tx.js → ProjectsPage-CMacaz1V.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DiKaBtvg.js → SettingsPage-B9XKC6ge.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-CyxNji74.js → TemplatesPage-Bq8ASiy4.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-BLPNvDc5.js → TerminalOutput-rQ65EXIP.js} +1 -1
- package/web-app/dist/assets/{arrow-left-dP_J0CkC.js → arrow-left-BcsRbWot.js} +1 -1
- package/web-app/dist/assets/{clock-CGZn7bQ1.js → clock-DUeIWW98.js} +1 -1
- package/web-app/dist/assets/{external-link-ypPFWwc1.js → external-link-lxSyZieU.js} +1 -1
- package/web-app/dist/assets/{index-tGQw_JnU.js → index-Cyfnu-vw.js} +2 -2
- package/web-app/dist/index.html +1 -1
- package/web-app/server.py +133 -45
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with minimal human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v6.64.
|
|
6
|
+
# Loki Mode v6.64.1
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -267,4 +267,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
267
267
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
268
268
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
269
269
|
|
|
270
|
-
**v6.64.
|
|
270
|
+
**v6.64.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.64.
|
|
1
|
+
6.64.1
|
package/autonomy/run.sh
CHANGED
|
@@ -8849,10 +8849,14 @@ for section_name, section_content in sections.items():
|
|
|
8849
8849
|
if is_feature_section:
|
|
8850
8850
|
# Extract numbered items or bullet points
|
|
8851
8851
|
for line in section_content.split("\n"):
|
|
8852
|
+
raw_line = line
|
|
8852
8853
|
line = line.strip()
|
|
8853
8854
|
# Match: "1. Feature name" or "- Feature name" or "* Feature name"
|
|
8854
8855
|
m = re.match(r'^(?:\d+[\.\)]\s*|\-\s+|\*\s+)(.+)', line)
|
|
8855
8856
|
if m:
|
|
8857
|
+
# BUG-V63-003 fix: skip indented sub-bullets (check raw_line before strip)
|
|
8858
|
+
if raw_line and raw_line[0] in (' ', '\t'):
|
|
8859
|
+
continue
|
|
8856
8860
|
feature_text = m.group(1).strip()
|
|
8857
8861
|
if len(feature_text) > 10: # Skip very short lines
|
|
8858
8862
|
features.append({
|
|
@@ -8881,13 +8885,24 @@ if not features:
|
|
|
8881
8885
|
def extract_acceptance_criteria(section_name, sections):
|
|
8882
8886
|
"""Extract testable criteria from section content."""
|
|
8883
8887
|
criteria = []
|
|
8888
|
+
seen_criteria = set() # BUG-V63-004 fix: deduplicate criteria
|
|
8884
8889
|
content = sections.get(section_name, "")
|
|
8885
8890
|
for line in content.split("\n"):
|
|
8891
|
+
raw_line = line
|
|
8886
8892
|
line = line.strip()
|
|
8887
|
-
|
|
8893
|
+
# BUG-V63-003 fix: check indentation on raw_line before strip
|
|
8894
|
+
if raw_line and raw_line[0] in (' ', '\t'):
|
|
8895
|
+
# Indented sub-bullet
|
|
8896
|
+
if line.startswith(("- ", "* ")):
|
|
8897
|
+
text = re.sub(r'^[\-\*]\s+', '', line).strip()
|
|
8898
|
+
if len(text) > 5 and text not in seen_criteria:
|
|
8899
|
+
criteria.append(text)
|
|
8900
|
+
seen_criteria.add(text)
|
|
8901
|
+
elif line.startswith(("- ", "* ")):
|
|
8888
8902
|
text = re.sub(r'^[\-\*]\s+', '', line).strip()
|
|
8889
|
-
if len(text) > 5:
|
|
8903
|
+
if len(text) > 5 and text not in seen_criteria:
|
|
8890
8904
|
criteria.append(text)
|
|
8905
|
+
seen_criteria.add(text)
|
|
8891
8906
|
# Also check for acceptance criteria section
|
|
8892
8907
|
for key in ["acceptance criteria", "success criteria", "definition of done"]:
|
|
8893
8908
|
for sname, scontent in sections.items():
|
|
@@ -8896,7 +8911,10 @@ def extract_acceptance_criteria(section_name, sections):
|
|
|
8896
8911
|
cline = cline.strip()
|
|
8897
8912
|
m = re.match(r'^(?:\d+[\.\)]\s*|\-\s+|\*\s+|\[.\]\s*)(.+)', cline)
|
|
8898
8913
|
if m:
|
|
8899
|
-
|
|
8914
|
+
text = m.group(1).strip()
|
|
8915
|
+
if text not in seen_criteria:
|
|
8916
|
+
criteria.append(text)
|
|
8917
|
+
seen_criteria.add(text)
|
|
8900
8918
|
return criteria[:10] # Cap at 10
|
|
8901
8919
|
|
|
8902
8920
|
# Determine priority based on position (earlier = higher)
|
|
@@ -8913,20 +8931,37 @@ def get_priority(index, total):
|
|
|
8913
8931
|
# Build task queue entries
|
|
8914
8932
|
pending_path = ".loki/queue/pending.json"
|
|
8915
8933
|
existing = []
|
|
8934
|
+
wrapper = None # BUG-V63-005 fix: preserve dict wrapper if present
|
|
8916
8935
|
if os.path.exists(pending_path):
|
|
8917
8936
|
try:
|
|
8918
8937
|
with open(pending_path, "r") as f:
|
|
8919
|
-
|
|
8920
|
-
if isinstance(
|
|
8921
|
-
existing =
|
|
8922
|
-
|
|
8923
|
-
|
|
8938
|
+
raw_data = json.load(f)
|
|
8939
|
+
if isinstance(raw_data, list):
|
|
8940
|
+
existing = raw_data
|
|
8941
|
+
wrapper = None
|
|
8942
|
+
elif isinstance(raw_data, dict):
|
|
8943
|
+
existing = raw_data.get("tasks", [])
|
|
8944
|
+
wrapper = {k: v for k, v in raw_data.items() if k != "tasks"}
|
|
8924
8945
|
except (json.JSONDecodeError, FileNotFoundError):
|
|
8925
8946
|
existing = []
|
|
8926
8947
|
|
|
8927
8948
|
existing_ids = {t.get("id") for t in existing if isinstance(t, dict)}
|
|
8928
8949
|
added = 0
|
|
8929
8950
|
|
|
8951
|
+
# BUG-V63-001 fix: extract audience once with flag to break both loops
|
|
8952
|
+
audience = "a user"
|
|
8953
|
+
audience_found = False
|
|
8954
|
+
for key in ["target audience", "users", "user personas", "audience"]:
|
|
8955
|
+
if audience_found:
|
|
8956
|
+
break
|
|
8957
|
+
for sname in sections:
|
|
8958
|
+
if key in sname.lower():
|
|
8959
|
+
first_line = sections[sname].split("\n")[0].strip()
|
|
8960
|
+
if first_line:
|
|
8961
|
+
audience = first_line[:100]
|
|
8962
|
+
audience_found = True
|
|
8963
|
+
break
|
|
8964
|
+
|
|
8930
8965
|
for i, feat in enumerate(features):
|
|
8931
8966
|
task_id = f"prd-{i+1:03d}"
|
|
8932
8967
|
if task_id in existing_ids:
|
|
@@ -8954,25 +8989,20 @@ for i, feat in enumerate(features):
|
|
|
8954
8989
|
if criteria:
|
|
8955
8990
|
task["acceptance_criteria"] = criteria
|
|
8956
8991
|
|
|
8957
|
-
# Add user story format
|
|
8958
|
-
# Try to extract target audience for user story
|
|
8959
|
-
audience = "a user"
|
|
8960
|
-
for key in ["target audience", "users", "user personas", "audience"]:
|
|
8961
|
-
for sname in sections:
|
|
8962
|
-
if key in sname.lower():
|
|
8963
|
-
# Extract first line
|
|
8964
|
-
first_line = sections[sname].split("\n")[0].strip()
|
|
8965
|
-
if first_line:
|
|
8966
|
-
audience = first_line[:100]
|
|
8967
|
-
break
|
|
8968
|
-
|
|
8969
8992
|
task["user_story"] = f"As {audience}, I want to {feat['title'].lower().rstrip('.')}, so that the product delivers its core value."
|
|
8970
8993
|
|
|
8971
8994
|
existing.append(task)
|
|
8972
8995
|
added += 1
|
|
8973
8996
|
|
|
8997
|
+
# BUG-V63-005 fix: write back in original format (dict wrapper or bare list)
|
|
8998
|
+
if wrapper is not None:
|
|
8999
|
+
wrapper["tasks"] = existing
|
|
9000
|
+
output = wrapper
|
|
9001
|
+
else:
|
|
9002
|
+
output = existing
|
|
9003
|
+
|
|
8974
9004
|
with open(pending_path, "w") as f:
|
|
8975
|
-
json.dump(
|
|
9005
|
+
json.dump(output, f, indent=2)
|
|
8976
9006
|
|
|
8977
9007
|
print(f"Extracted {added} tasks from PRD ({len(features)} features found)", file=sys.stderr)
|
|
8978
9008
|
PRD_PARSE_EOF
|
|
@@ -9053,6 +9083,16 @@ run_autonomous() {
|
|
|
9053
9083
|
load_state
|
|
9054
9084
|
local retry=$RETRY_COUNT
|
|
9055
9085
|
|
|
9086
|
+
# Notify dashboard of active project directory (for AI Chat cross-directory usage)
|
|
9087
|
+
if command -v curl &>/dev/null; then
|
|
9088
|
+
local project_cwd
|
|
9089
|
+
project_cwd="$(pwd)"
|
|
9090
|
+
curl -sf -X POST "http://127.0.0.1:${DASHBOARD_PORT}/api/focus" \
|
|
9091
|
+
-H "Content-Type: application/json" \
|
|
9092
|
+
-d "{\"project_dir\": \"${project_cwd}\"}" \
|
|
9093
|
+
>/dev/null 2>&1 || true
|
|
9094
|
+
fi
|
|
9095
|
+
|
|
9056
9096
|
# Initialize Cross-Provider Failover (v6.19.0)
|
|
9057
9097
|
init_failover_state
|
|
9058
9098
|
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -1621,6 +1621,51 @@ async def get_cross_project_learnings():
|
|
|
1621
1621
|
return learnings
|
|
1622
1622
|
|
|
1623
1623
|
|
|
1624
|
+
# =============================================================================
|
|
1625
|
+
# Active Project Focus (for AI Chat / cross-directory usage)
|
|
1626
|
+
# =============================================================================
|
|
1627
|
+
|
|
1628
|
+
class FocusRequest(BaseModel):
|
|
1629
|
+
"""Schema for setting the active project directory."""
|
|
1630
|
+
project_dir: str
|
|
1631
|
+
|
|
1632
|
+
|
|
1633
|
+
@app.post("/api/focus")
|
|
1634
|
+
async def set_focus(request: FocusRequest):
|
|
1635
|
+
"""Set the active project directory for .loki/ resolution.
|
|
1636
|
+
|
|
1637
|
+
When the dashboard runs in one CWD but a session (e.g. AI Chat) runs
|
|
1638
|
+
in a different project directory, call this endpoint so the dashboard
|
|
1639
|
+
reads .loki/ from the correct location.
|
|
1640
|
+
"""
|
|
1641
|
+
global _active_project_dir
|
|
1642
|
+
project_dir = request.project_dir.strip()
|
|
1643
|
+
if not project_dir:
|
|
1644
|
+
raise HTTPException(status_code=400, detail="project_dir must not be empty")
|
|
1645
|
+
p = _Path(project_dir)
|
|
1646
|
+
if not p.is_dir():
|
|
1647
|
+
raise HTTPException(status_code=400, detail=f"Directory does not exist: {project_dir}")
|
|
1648
|
+
_active_project_dir = str(p.resolve())
|
|
1649
|
+
return {"project_dir": _active_project_dir, "loki_dir": str(_get_loki_dir())}
|
|
1650
|
+
|
|
1651
|
+
|
|
1652
|
+
@app.get("/api/focus")
|
|
1653
|
+
async def get_focus():
|
|
1654
|
+
"""Get the currently focused project directory."""
|
|
1655
|
+
return {
|
|
1656
|
+
"project_dir": _active_project_dir,
|
|
1657
|
+
"loki_dir": str(_get_loki_dir()),
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
|
|
1661
|
+
@app.delete("/api/focus")
|
|
1662
|
+
async def clear_focus():
|
|
1663
|
+
"""Clear the active project directory override (revert to CWD-based resolution)."""
|
|
1664
|
+
global _active_project_dir
|
|
1665
|
+
_active_project_dir = None
|
|
1666
|
+
return {"project_dir": None, "loki_dir": str(_get_loki_dir())}
|
|
1667
|
+
|
|
1668
|
+
|
|
1624
1669
|
# =============================================================================
|
|
1625
1670
|
# Enterprise Features (Optional - enabled via environment variables)
|
|
1626
1671
|
# =============================================================================
|
|
@@ -1816,18 +1861,30 @@ async def get_audit_summary(days: int = 7):
|
|
|
1816
1861
|
# File-based Session Endpoints (reads from .loki/ flat files)
|
|
1817
1862
|
# =============================================================================
|
|
1818
1863
|
|
|
1864
|
+
# Active project directory override (set via API or run.sh notification)
|
|
1865
|
+
# When set, _get_loki_dir() resolves .loki/ relative to this path instead of CWD.
|
|
1866
|
+
_active_project_dir: Optional[str] = None
|
|
1867
|
+
|
|
1868
|
+
|
|
1819
1869
|
def _get_loki_dir() -> _Path:
|
|
1820
1870
|
"""Get LOKI_DIR, refreshing from env on each call for consistency.
|
|
1821
1871
|
|
|
1822
1872
|
Resolution order:
|
|
1823
1873
|
1. LOKI_DIR env var (set by run.sh during active sessions)
|
|
1824
|
-
2.
|
|
1825
|
-
3.
|
|
1874
|
+
2. _active_project_dir (set via /api/focus API for cross-directory projects)
|
|
1875
|
+
3. .loki/ in current working directory
|
|
1876
|
+
4. ~/.loki/ as global fallback
|
|
1826
1877
|
"""
|
|
1827
1878
|
env_dir = os.environ.get("LOKI_DIR")
|
|
1828
1879
|
if env_dir:
|
|
1829
1880
|
return _Path(env_dir)
|
|
1830
1881
|
|
|
1882
|
+
# Check API-set project directory (for AI Chat running in different CWD)
|
|
1883
|
+
if _active_project_dir:
|
|
1884
|
+
project_loki = _Path(_active_project_dir) / ".loki"
|
|
1885
|
+
if project_loki.is_dir():
|
|
1886
|
+
return project_loki
|
|
1887
|
+
|
|
1831
1888
|
# Check CWD first
|
|
1832
1889
|
cwd_loki = _Path.cwd() / ".loki"
|
|
1833
1890
|
if cwd_loki.is_dir():
|
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as m,r,j as e}from"./index-
|
|
1
|
+
import{c as m,r,j as e}from"./index-Cyfnu-vw.js";import{C as g,a as p}from"./clock-DUeIWW98.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s}from"./index-
|
|
1
|
+
import{j as s}from"./index-Cyfnu-vw.js";const n={none:"p-0",sm:"p-3",md:"p-4",lg:"p-6"};function p({hover:e=!1,padding:d="md",className:t="",children:a,onClick:r}){return s.jsx("div",{role:r?"button":void 0,tabIndex:r?0:void 0,onClick:r,onKeyDown:r?o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r())}:void 0,className:["bg-white border border-[#ECEAE3] rounded-[5px] shadow-card",e&&"hover:shadow-card-hover transition-shadow duration-200",r&&"cursor-pointer",n[d],t].filter(Boolean).join(" "),children:a})}export{p as C};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{j as e,r as l,a as h,u as be,b as ge}from"./index-
|
|
1
|
+
import{j as e,r as l,a as h,u as be,b as ge}from"./index-Cyfnu-vw.js";import{u as I,B as je}from"./Badge-CecAeNGh.js";import{P as ve,a as Ne,S as ye,E as C,T as we}from"./TerminalOutput-rQ65EXIP.js";import"./clock-DUeIWW98.js";function ke(t){if(t<60)return`${Math.round(t)}s`;if(t<3600)return`${Math.floor(t/60)}m ${Math.round(t%60)}s`;const s=Math.floor(t/3600),n=Math.floor(t%3600/60);return`${s}h ${n}m`}function Se(t,s){if(!t||t<=0)return"--";const n={simple:{opus:1,haiku:1,total:3},standard:{opus:2,haiku:2,total:5},complex:{opus:3,haiku:3,total:8}},r=n[s]||n.standard;return t<=r.opus?"Opus":t>r.total-r.haiku?"Haiku":"Sonnet"}function Ce({status:t,prdSummary:s,onStop:n,onPause:r,onResume:a,isPaused:c}){const i=t?Se(t.iteration??0,t.complexity||"standard"):"--",o=c??(t==null?void 0:t.paused)??!1;return e.jsxs("div",{className:"card px-5 py-3 flex items-center gap-6 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted uppercase tracking-wider font-medium",children:"Phase"}),e.jsx("span",{className:"font-mono font-semibold text-ink",children:(t==null?void 0:t.phase)||"idle"})]}),e.jsx("div",{className:"w-px h-5 bg-border"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted uppercase tracking-wider font-medium",children:"Complexity"}),e.jsx("span",{className:`font-mono font-semibold ${(t==null?void 0:t.complexity)==="complex"?"text-warning":(t==null?void 0:t.complexity)==="simple"?"text-success":"text-ink"}`,children:(t==null?void 0:t.complexity)||"standard"})]}),e.jsx("div",{className:"w-px h-5 bg-border"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted uppercase tracking-wider font-medium",children:"Model"}),e.jsx("span",{className:`font-mono font-semibold px-2 py-0.5 rounded-md text-xs ${i==="Opus"?"bg-primary/10 text-primary":i==="Haiku"?"bg-success/10 text-success":"bg-primary/10 text-primary"}`,children:i})]}),e.jsx("div",{className:"w-px h-5 bg-border"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted uppercase tracking-wider font-medium",children:"Tasks"}),e.jsx("span",{className:"font-mono text-ink",children:t!=null&&t.current_task?e.jsx("span",{className:"text-xs",children:t.current_task}):e.jsx("span",{className:"text-muted",children:"--"})}),((t==null?void 0:t.pending_tasks)??0)>0&&e.jsxs("span",{className:"text-xs text-primary font-mono",children:["+",t==null?void 0:t.pending_tasks," pending"]})]}),s&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"w-px h-5 bg-border"}),e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("span",{className:"text-xs text-muted uppercase tracking-wider font-medium flex-shrink-0",children:"Building"}),e.jsx("span",{className:"text-xs font-mono text-ink truncate max-w-[220px]",title:s,children:s.length>60?s.slice(0,60)+"...":s})]})]}),e.jsx("div",{className:"flex-1"}),((t==null?void 0:t.uptime)??0)>0&&e.jsx("span",{className:"font-mono text-xs text-muted",children:ke((t==null?void 0:t.uptime)??0)}),(r||a)&&e.jsxs("button",{onClick:o?a:r,className:"flex items-center gap-1.5 px-4 py-1.5 rounded-btn text-xs font-semibold border border-warning/30 text-warning hover:bg-warning/10 transition-colors",children:[o?e.jsx(ve,{size:14}):e.jsx(Ne,{size:14}),o?"Resume":"Pause"]}),n&&e.jsxs("button",{onClick:n,className:"flex items-center gap-1.5 px-4 py-1.5 rounded-btn text-xs font-semibold bg-danger/10 text-danger border border-danger/20 hover:bg-danger/20 transition-colors",children:[e.jsx(ye,{size:14}),"Stop"]})]})}function Ee({status:t}){const s=[{label:"Iteration",value:t?t.iteration.toString():"--",color:"text-primary"},{label:"Agents",value:t?t.running_agents.toString():"--",color:t&&t.running_agents>0?"text-success":"text-muted"},{label:"Pending",value:t?t.pending_tasks.toString():"--",color:t&&t.pending_tasks>0?"text-warning":"text-muted"},{label:"Provider",value:(t==null?void 0:t.provider)||"--",color:"text-primary"}];return e.jsx("div",{className:"grid grid-cols-4 gap-3",children:s.map(n=>e.jsxs("div",{className:"card p-4 text-center",children:[e.jsx("div",{className:`text-2xl font-bold font-mono ${n.color}`,children:n.value}),e.jsx("div",{className:"text-xs text-muted font-medium mt-1 uppercase tracking-wider",children:n.label})]},n.label))})}function Pe({plan:t,loading:s,onConfirm:n,onCancel:r}){return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/30 backdrop-blur-sm",children:e.jsxs("div",{className:"card w-full max-w-lg mx-4 p-6 rounded-card shadow-card-hover",children:[e.jsx("h2",{className:"text-lg font-bold text-ink mb-4",children:"Build Estimate"}),s?e.jsxs("div",{className:"flex flex-col items-center py-8 gap-3",children:[e.jsx("div",{className:"w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin"}),e.jsx("p",{className:"text-sm text-muted",children:"Analyzing PRD..."}),e.jsxs("div",{className:"flex gap-3 mt-4",children:[e.jsx("button",{onClick:r,className:"px-4 py-2 text-sm font-medium text-muted hover:text-ink transition-colors",children:"Cancel"}),e.jsx("button",{onClick:n,className:"px-4 py-2 text-sm font-medium text-primary hover:text-primary/80 transition-colors underline",children:"Skip analysis, build now"})]})]}):t?e.jsxs(e.Fragment,{children:[t.returncode!==0&&e.jsxs("div",{className:"mb-4 px-3 py-2 rounded-btn bg-warning/10 border border-warning/20 text-warning text-xs",children:["loki plan exited with code ",t.returncode," - showing partial results"]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3 mb-4",children:[e.jsxs("div",{className:"card rounded-card p-3",children:[e.jsx("div",{className:"text-xs font-semibold text-muted-accessible uppercase tracking-wider mb-1",children:"Complexity"}),e.jsx("div",{className:"text-base font-bold text-ink capitalize",children:t.complexity})]}),e.jsxs("div",{className:"card rounded-card p-3",children:[e.jsx("div",{className:"text-xs font-semibold text-muted-accessible uppercase tracking-wider mb-1",children:"Est. Cost"}),e.jsx("div",{className:"text-base font-bold text-ink",children:t.cost_estimate})]}),e.jsxs("div",{className:"card rounded-card p-3",children:[e.jsx("div",{className:"text-xs font-semibold text-muted-accessible uppercase tracking-wider mb-1",children:"Iterations"}),e.jsx("div",{className:"text-base font-bold text-ink",children:t.iterations})]}),e.jsxs("div",{className:"card rounded-card p-3",children:[e.jsx("div",{className:"text-xs font-semibold text-muted-accessible uppercase tracking-wider mb-1",children:"Phases"}),e.jsx("div",{className:"text-xs text-ink capitalize",children:t.phases.join(", ")})]})]}),t.output_text&&e.jsxs("details",{className:"mb-4",children:[e.jsx("summary",{className:"text-xs text-muted cursor-pointer hover:text-ink transition-colors",children:"Raw output"}),e.jsx("pre",{className:"mt-2 text-xs font-mono text-muted-accessible bg-black/5 rounded-card p-3 overflow-auto max-h-40 whitespace-pre-wrap",children:t.output_text})]}),e.jsxs("div",{className:"flex gap-3 justify-end",children:[e.jsx("button",{onClick:r,className:"px-4 py-2 text-sm font-medium text-muted hover:text-ink transition-colors",children:"Cancel"}),e.jsx("button",{onClick:n,className:"px-5 py-2 rounded-card text-sm font-semibold bg-primary text-white hover:bg-primary/90 transition-all shadow-button",children:"Start Build"})]})]}):e.jsx("div",{className:"text-sm text-muted py-4",children:"No plan data available."})]})})}function _e({onSubmit:t,running:s,error:n,provider:r,onProviderChange:a,initialPrd:c}){const[i,o]=l.useState(""),[m,b]=l.useState(""),[f,y]=l.useState("claude"),[d,g]=l.useState(""),j=r??f,[v,w]=l.useState(!1),[k,T]=l.useState([]),[x,E]=l.useState(!1),[N,M]=l.useState(!1),[P,A]=l.useState(!1),[z,_]=l.useState(null),[F,$]=l.useState(!1),[O,B]=l.useState(!1);l.useEffect(()=>{h.getTemplates().then(p=>{T(p),E(!1)}).catch(()=>{T([]),E(!0)})},[]),l.useEffect(()=>{c&&o(c)},[c]),l.useEffect(()=>{if(c)return;const p=localStorage.getItem("loki-prd-draft");p&&o(p),h.getPrdPrefill().then(({content:L})=>{L&&o(L)}).catch(()=>{})},[c]),l.useEffect(()=>{i.trim()?localStorage.setItem("loki-prd-draft",i):localStorage.removeItem("loki-prd-draft")},[i]);const R=l.useCallback(async(p,L)=>{b(L),w(!1);try{const G=await h.getTemplateContent(p);o(G.content)}catch{o(`# ${L}
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as r,u as o,r as c,j as e}from"./index-
|
|
1
|
+
import{g as r,u as o,r as c,j as e}from"./index-Cyfnu-vw.js";function x(){const{user:l,loading:t,login:i,isLocalMode:n}=r(),s=o();return c.useEffect(()=>{!t&&(l||n)&&s("/",{replace:!0})},[l,t,n,s]),t?e.jsx("div",{className:"h-screen bg-[#FAF9F6] flex items-center justify-center text-[#6B6960] text-sm",children:"Loading..."}):e.jsx("div",{className:"h-screen bg-[#FAF9F6] flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-sm mx-auto px-6",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("h1",{className:"font-heading text-3xl font-bold text-[#36342E] mb-1",children:"Purple Lab"}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:"Autonomous agent workspace powered by Loki"})]}),e.jsxs("div",{className:"bg-white rounded-lg border border-[#ECEAE3] shadow-sm p-6 space-y-4",children:[e.jsx("h2",{className:"text-base font-medium text-[#36342E] text-center",children:"Sign in to continue"}),e.jsxs("button",{type:"button",onClick:()=>i("github"),className:"w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-[5px] border border-[#ECEAE3] bg-[#24292f] text-white text-sm font-medium hover:bg-[#1b1f23] transition-colors",children:[e.jsx("svg",{className:"w-5 h-5",fill:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"})}),"Sign in with GitHub"]}),e.jsxs("button",{type:"button",onClick:()=>i("google"),className:"w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-[5px] border border-[#ECEAE3] bg-white text-[#36342E] text-sm font-medium hover:bg-[#F8F4F0] transition-colors",children:[e.jsxs("svg",{className:"w-5 h-5",viewBox:"0 0 24 24",children:[e.jsx("path",{fill:"#4285F4",d:"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"}),e.jsx("path",{fill:"#34A853",d:"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"}),e.jsx("path",{fill:"#FBBC05",d:"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"}),e.jsx("path",{fill:"#EA4335",d:"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"})]}),"Sign in with Google"]}),e.jsxs("div",{className:"relative",children:[e.jsx("div",{className:"absolute inset-0 flex items-center",children:e.jsx("div",{className:"w-full border-t border-[#ECEAE3]"})}),e.jsx("div",{className:"relative flex justify-center text-xs",children:e.jsx("span",{className:"bg-white px-2 text-[#939084]",children:"or"})})]}),e.jsx("button",{type:"button",onClick:()=>s("/"),className:"w-full text-center text-sm text-[#6B6960] hover:text-[#553DE9] transition-colors py-1",children:"Continue without account (local mode)"})]}),e.jsx("p",{className:"text-xs text-[#939084] text-center mt-4",children:"Local mode stores everything on your machine. Sign in for cloud sync and collaboration."})]})})}export{x as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e,L as t,H as s}from"./index-
|
|
1
|
+
import{j as e,L as t,H as s}from"./index-Cyfnu-vw.js";import{A as o}from"./arrow-left-BcsRbWot.js";function i(){return e.jsxs("div",{className:"flex flex-col items-center justify-center h-full min-h-[60vh] p-8 text-center",children:[e.jsx("div",{className:"text-6xl font-heading font-bold text-primary/20 mb-4",children:"404"}),e.jsx("h1",{className:"text-h3 font-heading font-bold text-ink mb-2",children:"Page not found"}),e.jsx("p",{className:"text-sm text-muted-accessible mb-6 max-w-xs",children:"The page you are looking for does not exist or has been moved."}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("button",{onClick:()=>window.history.back(),className:"inline-flex items-center gap-1.5 px-4 py-2 text-xs font-medium rounded-btn border border-border text-secondary hover:bg-hover transition-colors",children:[e.jsx(o,{size:14}),"Go Back"]}),e.jsxs(t,{to:"/",className:"inline-flex items-center gap-1.5 px-4 py-2 text-xs font-medium rounded-btn bg-primary text-white hover:bg-[#4432c4] transition-colors shadow-button",children:[e.jsx(s,{size:14}),"Home"]})]})]})}export{i as default};
|