loki-mode 9.54.0 → 9.54.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +10 -1
- package/autonomy/lib/proof-generator.py +36 -5
- package/autonomy/run.sh +234 -31
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_v2.py +4 -0
- package/dashboard/audit.py +9 -1
- package/dashboard/auth.py +16 -4
- package/dashboard/registry.py +34 -12
- package/dashboard/rigour_integration.py +25 -17
- package/dashboard/server.py +252 -104
- package/dashboard/static/cost.html +55 -26
- package/dashboard/static/index.html +475 -1544
- package/dashboard/static/proofs.html +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/air-gapped.md +7 -2
- package/docs/image-provenance.md +4 -2
- package/docs/v10/BACKLOG.md +41 -2
- package/docs/v10/BOARD.md +105 -0
- package/docs/v10/DECISIONS.md +71 -0
- package/docs/v10/PROGRESS.md +43 -0
- package/docs/v10/SWARM-PROMPT.md +98 -0
- package/docs/v10/SWARM.md +237 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/aider.sh +8 -0
- package/providers/cline.sh +8 -0
- package/providers/codex.sh +9 -0
- package/providers/opencode.sh +9 -0
- package/web-app/dist/assets/AdminPage-CZrBkzRF.js +32 -0
- package/web-app/dist/assets/Avatar-gQIp6FBI.js +11 -0
- package/web-app/dist/assets/{Badge-BF3mhT57.js → Badge-D2_fBTFY.js} +1 -1
- package/web-app/dist/assets/{Button-BDp9aJ9q.js → Button-D5qDd2ef.js} +1 -1
- package/web-app/dist/assets/CockpitPage-DVMk2RUK.js +47 -0
- package/web-app/dist/assets/ComparePage-NMLyE1xL.js +1 -0
- package/web-app/dist/assets/{ErrorBoundary-ut3wrUmu.js → ErrorBoundary-BRABI-BT.js} +1 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-D2LNKqUx.js +1 -0
- package/web-app/dist/assets/GitHubIssuesPanel-BC5GzKUN.js +7 -0
- package/web-app/dist/assets/{GitHubPRsPanel-DurZgSaj.js → GitHubPRsPanel-BSlmoVTS.js} +3 -3
- package/web-app/dist/assets/HomePage-D_CDMoen.js +12 -0
- package/web-app/dist/assets/{LoginPage-HeRGJeZy.js → LoginPage-BBNA_N9t.js} +1 -1
- package/web-app/dist/assets/{MagicPage-CUKrqsZs.js → MagicPage-CnFRZCMx.js} +1 -1
- package/web-app/dist/assets/MetricsPage-CPfLMRlh.js +6 -0
- package/web-app/dist/assets/{NotFoundPage-BZDZ-B77.js → NotFoundPage-lA0XSGTz.js} +1 -1
- package/web-app/dist/assets/ProjectPage-CNAPbr9z.js +256 -0
- package/web-app/dist/assets/ProjectsPage-CMtm8goN.js +6 -0
- package/web-app/dist/assets/SettingsPage-BhIjVMYE.js +10 -0
- package/web-app/dist/assets/{ShowcasePage-BGS2jTGH.js → ShowcasePage-BndtGeYo.js} +1 -1
- package/web-app/dist/assets/SystemSettingsPage-euXI-KXE.js +1 -0
- package/web-app/dist/assets/TeamsPage-ClUKecun.js +11 -0
- package/web-app/dist/assets/TemplatesPage-BWHWVk0L.js +29 -0
- package/web-app/dist/assets/{TerminalOutput-togzv9Zl.js → TerminalOutput-Cv3N3Szf.js} +1 -1
- package/web-app/dist/assets/{activity-Dreyb_Kr.js → activity-dEhz-bXR.js} +1 -1
- package/web-app/dist/assets/{bell-DWH0drES.js → bell-B3XUMq1t.js} +1 -1
- package/web-app/dist/assets/{bot-78MoCuDl.js → bot-X-ssNlwR.js} +1 -1
- package/web-app/dist/assets/{check-ikfylPst.js → check-C_9Nx7kb.js} +1 -1
- package/web-app/dist/assets/{chevron-left-DXUqkd8J.js → chevron-left-tvNswo3A.js} +1 -1
- package/web-app/dist/assets/{circle-alert-Da74VO8P.js → circle-alert-CSB88nEs.js} +1 -1
- package/web-app/dist/assets/{clock-mlGCFq8l.js → clock-C8p2e4NI.js} +1 -1
- package/web-app/dist/assets/{cloud-B_Y5ZrIO.js → cloud-CKp2ZvhG.js} +1 -1
- package/web-app/dist/assets/{code-xml-Bbom7YWV.js → code-xml-dY70LCHD.js} +1 -1
- package/web-app/dist/assets/{database-CLcofiVp.js → database-DObn5fmn.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-C5mkjXIM.js → dollar-sign-DSu6n3K3.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CVrkaOQP.js → file-code-corner-DpCnS73z.js} +1 -1
- package/web-app/dist/assets/{file-plus-BV9240gX.js → file-plus-D3IPKCf1.js} +1 -1
- package/web-app/dist/assets/{globe-aZ0Zso4I.js → globe-C9QXkgH_.js} +1 -1
- package/web-app/dist/assets/{hammer-EgOQNukG.js → hammer-D_FtWe1y.js} +1 -1
- package/web-app/dist/assets/index-CI54rara.css +1 -0
- package/web-app/dist/assets/{index-DvZ0Kk2x.js → index-Cz7q1bvC.js} +2 -2
- package/web-app/dist/assets/{layers-BOVKmepE.js → layers-DsW7jnJX.js} +1 -1
- package/web-app/dist/assets/{loader-circle-0K8yLgHl.js → loader-circle-B3HspjKR.js} +1 -1
- package/web-app/dist/assets/{lock-XzlDMy8M.js → lock-DSI29pct.js} +1 -1
- package/web-app/dist/assets/{package-BtXTKusI.js → package-CLNxtA2x.js} +1 -1
- package/web-app/dist/assets/{plus-PxeiD8ju.js → plus-DyI4WC4_.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CjqzYczt.js → refresh-cw-D2dv0xA0.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CY0os4DH.js → rotate-ccw-CBvihA-a.js} +1 -1
- package/web-app/dist/assets/scroll-text-DvoOvAl_.js +6 -0
- package/web-app/dist/assets/{server-pIIs9vNp.js → server-DenWvSUt.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CsDqKXwA.js → shield-alert-40cX_FvG.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-CAh3HVzH.js → thumbs-up-BrjZ6QuV.js} +12 -7
- package/web-app/dist/assets/trash-2-C6evwkEH.js +16 -0
- package/web-app/dist/assets/{trending-down-DrtBd_C9.js → trending-down-CfbZis3O.js} +1 -1
- package/web-app/dist/assets/{trending-up-D-DbCHXm.js → trending-up-DWuEK3WC.js} +1 -1
- package/web-app/dist/assets/{upload-D4l6DCOt.js → upload-B9DFBcPG.js} +1 -1
- package/web-app/dist/assets/{usePolling-D0aoTX80.js → usePolling-BryVC-T1.js} +1 -1
- package/web-app/dist/assets/{user-BQf_XJO_.js → user-DMRXwZiw.js} +1 -1
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +122 -47
- package/web-app/dist/assets/AdminPage-y6_b2Xo4.js +0 -32
- package/web-app/dist/assets/Avatar-BFPkXhIJ.js +0 -6
- package/web-app/dist/assets/CockpitPage-5TKICCoA.js +0 -47
- package/web-app/dist/assets/ComparePage-BSuNsUHy.js +0 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-CcaBwEI-.js +0 -1
- package/web-app/dist/assets/GitHubIssuesPanel-DJeYgzAa.js +0 -12
- package/web-app/dist/assets/HomePage-Bs451LAy.js +0 -28
- package/web-app/dist/assets/MetricsPage-DvY1csgz.js +0 -6
- package/web-app/dist/assets/ProjectPage-CqHkEZkl.js +0 -257
- package/web-app/dist/assets/ProjectsPage-CLvCK1Y8.js +0 -6
- package/web-app/dist/assets/SettingsPage-DP7OmdwP.js +0 -10
- package/web-app/dist/assets/SystemSettingsPage-P_rlLh0x.js +0 -1
- package/web-app/dist/assets/TeamsPage-DxtBDcBC.js +0 -11
- package/web-app/dist/assets/TemplatesPage-5e-faH3W.js +0 -29
- package/web-app/dist/assets/folder-open-D_6yV78G.js +0 -11
- package/web-app/dist/assets/index-BSgmPwC0.css +0 -1
- package/web-app/dist/assets/lightbulb-DdASgqOG.js +0 -6
- package/web-app/dist/assets/mail-COu670_W.js +0 -6
- package/web-app/dist/assets/minus-bQpUt9ff.js +0 -6
- package/web-app/dist/assets/save-v8qep5cY.js +0 -6
- package/web-app/dist/assets/trash-2-Dt6urTyY.js +0 -6
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# The swarm
|
|
2
|
+
|
|
3
|
+
Adopted 2026-09-26, superseding the one-cycle-at-a-time loop in `docs/v10/PROGRESS.md`
|
|
4
|
+
for everything after cycle 4. Goal: 10-20x more releases per day than cycles
|
|
5
|
+
1-4 (about 3 releases in 18 hours), without weakening anything in
|
|
6
|
+
`docs/LOKI-10-BUILD-PROMPT.md` sections 2, 5b or 5c, or any global "never do"
|
|
7
|
+
rule. Full text of the founder's prompt: `docs/v10/SWARM-PROMPT.md`.
|
|
8
|
+
|
|
9
|
+
## Why cycles were slow
|
|
10
|
+
|
|
11
|
+
Each cycle batched 3-6 slices into one release, reviewed the whole batch in
|
|
12
|
+
serial council rounds (cycle 1 took 9 rounds, cycle 3 took 6, cycle 4's P7
|
|
13
|
+
property was found falsely PROVEN in three consecutive rounds before a fourth
|
|
14
|
+
caught it), then verified every channel before the next cycle started. Every
|
|
15
|
+
release waited on the slowest slice and on every round.
|
|
16
|
+
|
|
17
|
+
## Changes from the swarm prompt, and why (see DECISIONS.md D12, D13)
|
|
18
|
+
|
|
19
|
+
- **D12: unanimous APPROVE, not "3 of 4".** The founder's prompt scored
|
|
20
|
+
HIGH-tier review as "3 of 4 approve". CLAUDE.md's SDLC fleet pattern
|
|
21
|
+
requires unanimous APPROVE and a full re-run on any CONCERN or REJECT.
|
|
22
|
+
Cycle-4 round 3 was APPROVE, APPROVE, CONCERN, and the concern was a real
|
|
23
|
+
false PROVEN; a vote-count rule would have shipped it. A HIGH-tier round may
|
|
24
|
+
add a fourth adversarial reviewer for extra recall, but any reviewer's
|
|
25
|
+
blocking finding with a working reproduction blocks the slice regardless of
|
|
26
|
+
the count, and the whole council re-runs after the fix.
|
|
27
|
+
- **D13: every review or council agent pins its model explicitly.** Round 4
|
|
28
|
+
of the cycle-4 council was launched with two of three lenses left to
|
|
29
|
+
inherit the session model; the session model changed between launch and
|
|
30
|
+
the lenses resolving, so a round meant to run 2 Opus + 1 Sonnet in fact ran
|
|
31
|
+
3 Sonnet-5 lenses. It was killed and relaunched with every lens pinned.
|
|
32
|
+
Every council, review or HIGH-tier script from here on sets `model`
|
|
33
|
+
explicitly; composition is enforced by the script, never assumed from the
|
|
34
|
+
session.
|
|
35
|
+
- **Section 5c.5 (single writer) still governs.** One agent, the Release
|
|
36
|
+
Captain, writes `main`, `VERSION`, tags and publishes. Builders are each a
|
|
37
|
+
single writer on their own declared file set, never on `main`. Parallel
|
|
38
|
+
reviewers are read-only. This is what the swarm's role split already is;
|
|
39
|
+
it is restated here because the swarm looks superficially like
|
|
40
|
+
peer-to-peer and it is not.
|
|
41
|
+
- **`scripts/release.sh` is stale**, covering only `VERSION`,
|
|
42
|
+
`package.json`, `vscode-extension/package.json`. The Captain does not run
|
|
43
|
+
it as-is; the Captain follows CLAUDE.md's 14-file release checklist
|
|
44
|
+
directly (see Captain brief below), and fixing `scripts/release.sh` to
|
|
45
|
+
match is a queued LOW slice (BOARD).
|
|
46
|
+
- **Budget:** the founder was asked whether to size wave 1 to a conservative
|
|
47
|
+
estimate or launch at planned scale without a live cost feed, given
|
|
48
|
+
cycle-5 alone had already run about 3.3M subagent output tokens before the
|
|
49
|
+
swarm started. Founder chose full scale. METRICS.md still records a
|
|
50
|
+
labelled *estimate* per wave (subagent token counts from workflow
|
|
51
|
+
journals, not exact billing) so spend stays visible even though it does
|
|
52
|
+
not gate wave size. If a wave's estimate would cross a plausible reading of
|
|
53
|
+
founder-queue item 3, the swarm drops to 3 builders, keeps shipping LOW
|
|
54
|
+
slices, and adds a founder-queue line asking for a clearer budget signal.
|
|
55
|
+
|
|
56
|
+
## Roles
|
|
57
|
+
|
|
58
|
+
All roles are agents spawned through `Workflow`, run in git worktrees for
|
|
59
|
+
isolation except the Product Owner and Release Captain, which touch shared
|
|
60
|
+
state files and must serialize.
|
|
61
|
+
|
|
62
|
+
### 1. Product Owner (PO)
|
|
63
|
+
|
|
64
|
+
One agent per wave planning step (re-spawned fresh each time it is needed;
|
|
65
|
+
it writes `BACKLOG.md` and `BOARD.md`, never code). Ranks the backlog per
|
|
66
|
+
build-prompt section 3 (moat and red-main first, then metric-moved / effort).
|
|
67
|
+
Cuts work into release-sized slices:
|
|
68
|
+
|
|
69
|
+
- under about 300 changed lines;
|
|
70
|
+
- one owner;
|
|
71
|
+
- a declared file set that overlaps no other in-flight slice (hot files and
|
|
72
|
+
generated bundles are never in a builder's file set: see "Hot files"
|
|
73
|
+
below);
|
|
74
|
+
- acceptance checks written before building (the Wall, section 5c.1);
|
|
75
|
+
- a risk tier (HIGH / MEDIUM / LOW, see Reviewers).
|
|
76
|
+
|
|
77
|
+
Keeps roughly twice the builder count of ready slices queued.
|
|
78
|
+
|
|
79
|
+
### 2. Builders
|
|
80
|
+
|
|
81
|
+
6-10 in parallel, `isolation: "worktree"`, one slice each, single writer on
|
|
82
|
+
that slice. Each builder:
|
|
83
|
+
|
|
84
|
+
- runs `git merge --ff-only <captain's current main sha>` first (worktrees
|
|
85
|
+
cut from origin/main, not local main: see memory
|
|
86
|
+
`feedback-worktree-agents-base-branch`);
|
|
87
|
+
- implements with red-then-green tests;
|
|
88
|
+
- runs diff-scoped tests plus `bash tests/moat/run.sh` in its own worktree;
|
|
89
|
+
- never touches `main`, `VERSION`, or any hot file or bundle listed below;
|
|
90
|
+
- returns BLOCKED (never guesses past its file set) if the slice needs a
|
|
91
|
+
file outside its declared set, so the PO can re-slice.
|
|
92
|
+
|
|
93
|
+
### 3. Reviewers
|
|
94
|
+
|
|
95
|
+
Read-only, parallel, diff-scoped, tiered by risk. Every finding needs a
|
|
96
|
+
reproduction (file:line, a concrete failing scenario, the fix). Models are
|
|
97
|
+
always pinned explicitly (D13):
|
|
98
|
+
|
|
99
|
+
- **HIGH** (verifier, Seal, gates, council, exit codes, auth, secrets,
|
|
100
|
+
`tests/moat`, anything touching the trust core): 3 reviewers with
|
|
101
|
+
different lenses (correctness, security/bypass, fail-closed) plus 1
|
|
102
|
+
adversarial reviewer told to find a false pass. All 4 pinned to `opus`
|
|
103
|
+
except the adversarial slot, which may run `sonnet` for a genuinely
|
|
104
|
+
different read. **Unanimous APPROVE required (D12).** Any blocking finding
|
|
105
|
+
with a reproduction blocks regardless of the other votes; after a fix,
|
|
106
|
+
the whole HIGH council re-runs from round 1.
|
|
107
|
+
- **MEDIUM** (runtime, CLI behavior, dashboard logic without a trust-core
|
|
108
|
+
path): 2 reviewers, pinned `opus`. Unanimous APPROVE required; one
|
|
109
|
+
CONCERN re-runs both after the fix.
|
|
110
|
+
- **LOW** (docs, copy, tests-only, UI with no data path, deleting
|
|
111
|
+
unreachable code): 1 reviewer, may be pinned `sonnet`. APPROVE required;
|
|
112
|
+
a CONCERN re-runs it after the fix.
|
|
113
|
+
|
|
114
|
+
After 3 rounds at any tier without unanimous APPROVE, the slice goes back to
|
|
115
|
+
the PO to be cut smaller. It never blocks the line: other slices keep moving
|
|
116
|
+
through the pipeline.
|
|
117
|
+
|
|
118
|
+
### 4. Release Captain
|
|
119
|
+
|
|
120
|
+
Exactly one, never parallelized, serialized by a promise chain within one
|
|
121
|
+
Workflow run (see "Cross-wave exclusion"). The only agent allowed to write
|
|
122
|
+
`main`, bump `VERSION`, tag, or publish. For each approved slice, in order:
|
|
123
|
+
|
|
124
|
+
1. Rebase the slice onto current `origin/main`.
|
|
125
|
+
2. Apply any hot-file additions the slice requested (below), mechanically.
|
|
126
|
+
3. Rebuild every bundle the slice's file set could affect (below).
|
|
127
|
+
4. Run `bash scripts/local-ci.sh` (fast tier) and `bash tests/moat/run.sh`.
|
|
128
|
+
The ratchet (`pending.txt` shrink-only, `cases.txt` grow-only, D2) must
|
|
129
|
+
not regress; a regression refuses the merge and returns the slice to its
|
|
130
|
+
builder.
|
|
131
|
+
5. Stage by name (never `git add -A`), commit with the repo-local asklokesh
|
|
132
|
+
identity, push.
|
|
133
|
+
6. Bump `VERSION` and the other 13 files per CLAUDE.md's release checklist
|
|
134
|
+
(`scripts/release.sh` is stale; do this directly, not through the
|
|
135
|
+
script), rebuild dashboard and dist, run the full pre-publish validation,
|
|
136
|
+
commit as the push head, push with `PRE_PUSH_SKIP=1` (D5).
|
|
137
|
+
7. Wait for the previous release's required-ci (Tests, Bun Parity, Security
|
|
138
|
+
Audit) to go green before bumping `VERSION` again, so releases never
|
|
139
|
+
cancel each other's CI (the v9.7-v9.9 failure, and
|
|
140
|
+
`feedback-release-push-cancels-tests`). If several slices are ready
|
|
141
|
+
while waiting, batch them into the next release rather than idle.
|
|
142
|
+
8. On a code conflict, send the slice back to its builder with the new base.
|
|
143
|
+
The Captain never resolves a code conflict itself.
|
|
144
|
+
9. After a required-ci failure, rerun the failed job once; if the second
|
|
145
|
+
run also fails, do a full `gh run rerun` (never `--failed`) on the whole
|
|
146
|
+
Release run, and wait out the roughly 4-minute npm propagation window
|
|
147
|
+
before treating a publish as real
|
|
148
|
+
(`feedback-release-rerun-must-be-full-not-failed`,
|
|
149
|
+
`feedback-npm-propagation-window-4min`).
|
|
150
|
+
|
|
151
|
+
**Hot files** (never in any builder's declared file set; the Captain applies
|
|
152
|
+
requested additions mechanically at merge time):
|
|
153
|
+
`tests/moat/cases.txt`, `tests/moat/pending.txt` (merge with
|
|
154
|
+
`scratchpad/union_cases.py`'s approach: union for cases, intersection-aware
|
|
155
|
+
shrink for pending), `CHANGELOG.md`, `docs/v10/BACKLOG.md`,
|
|
156
|
+
`docs/v10/BOARD.md`, `docs/v10/PROGRESS.md`, `docs/v10/METRICS.md`,
|
|
157
|
+
`scripts/local-ci.sh` (`_FAST_KEEP` entries and `run_check` call sites),
|
|
158
|
+
`tests/run-all-tests.sh`.
|
|
159
|
+
|
|
160
|
+
**Generated bundles** (never edited by hand by a builder; the Captain
|
|
161
|
+
rebuilds all three after every merge that could touch their sources):
|
|
162
|
+
`loki-ts/dist/loki.js` (from `loki-ts/src`), `dashboard/static/index.html`
|
|
163
|
+
and `dashboard-ui/dist` (from `dashboard-ui/scripts/build-standalone.js` and
|
|
164
|
+
components), `web-app/dist` (from `web-app/src`).
|
|
165
|
+
|
|
166
|
+
**Cross-wave exclusion:** a promise chain only serializes within one
|
|
167
|
+
`Workflow` run. The swarm runs the PO-refill and Captain-queue loop inside a
|
|
168
|
+
single long-running `Workflow` invocation rather than launching a fresh one
|
|
169
|
+
per wave, so there is exactly one Captain at any time. If a script must be
|
|
170
|
+
edited and re-invoked, the previous run is stopped first (`TaskStop`) and its
|
|
171
|
+
in-flight slices are recovered from `BOARD.md` before the new run starts.
|
|
172
|
+
|
|
173
|
+
### 5. Channel Verifier
|
|
174
|
+
|
|
175
|
+
One, async, read-only, spawned after each release. Checks npm `latest` and
|
|
176
|
+
`gitHead`, the tag, the GitHub release, Docker amd64/arm64, the Homebrew
|
|
177
|
+
sha256, and a smoke test from a fresh PATH. Never blocks the next merge. A
|
|
178
|
+
failure becomes a HIGH-priority fix-forward slice through the normal PO
|
|
179
|
+
queue. Never unpublishes or deletes a version.
|
|
180
|
+
|
|
181
|
+
## Orchestration
|
|
182
|
+
|
|
183
|
+
- Repeated `Workflow` waves inside one long run: the PO produces up to 10
|
|
184
|
+
ready slices, then `pipeline(slices, build -> verify -> review/fix loop ->
|
|
185
|
+
captain queue)`. `pipeline`, not `parallel`, so a LOW slice ships while a
|
|
186
|
+
HIGH slice is still mid-review.
|
|
187
|
+
- The Captain step in the pipeline is itself a promise chain
|
|
188
|
+
(`captainQueue = captainQueue.then(() => mergeAndRelease(slice))`), so
|
|
189
|
+
exactly one merge or release runs at a time even though builders and
|
|
190
|
+
reviewers for other slices run concurrently.
|
|
191
|
+
- BOARD.md (slice id, owner, file set, tier, status, blockers) is the
|
|
192
|
+
coordination surface between agents; only the PO and the Captain write it.
|
|
193
|
+
- The next wave's PO step starts as soon as ready slices run low; the
|
|
194
|
+
script never waits on Channel Verifier output before starting more work.
|
|
195
|
+
|
|
196
|
+
## Speed levers, in priority order
|
|
197
|
+
|
|
198
|
+
1. One slice, one release.
|
|
199
|
+
2. Risk-tiered review; most slices are LOW or MEDIUM.
|
|
200
|
+
3. Parallel reviewers per slice instead of serial whole-batch rounds.
|
|
201
|
+
4. Asynchronous channel verification.
|
|
202
|
+
5. Diff-scoped tests while building; the full fast tier plus moat run only
|
|
203
|
+
at merge.
|
|
204
|
+
6. Flaky tests: rerun once, record it in `BACKLOG.md`, open a slice. Never
|
|
205
|
+
pass a flake silently (BACKLOG 93).
|
|
206
|
+
|
|
207
|
+
## Guardrails (restated; speed pressure erodes them first)
|
|
208
|
+
|
|
209
|
+
- Priority when goals conflict: moat > Seal accuracy > delivered accuracy >
|
|
210
|
+
cost > speed (build prompt 5b).
|
|
211
|
+
- The moat ratchet never regresses on `main`.
|
|
212
|
+
- If two releases in a row fail required-ci, stop releasing, fix `main`,
|
|
213
|
+
resume only when green.
|
|
214
|
+
- No force push. Never delete versions or tags. Never disable a test or
|
|
215
|
+
guard to get green.
|
|
216
|
+
- Every "never do" item in build-prompt section 1 still applies without
|
|
217
|
+
exception, swarm or not.
|
|
218
|
+
- Section 5c.5 (single writer): one agent writes a given change; parallel
|
|
219
|
+
agents are read-only; parallelize only across independent items under one
|
|
220
|
+
central coordinator, never peer-to-peer.
|
|
221
|
+
- Section 5c.11 (injection-safe intake): P9's split jobs and token
|
|
222
|
+
withholding (cycle 5) are the concrete form of this rule; the swarm's own
|
|
223
|
+
agent-authored slices never combine untrusted input, an agent, and push
|
|
224
|
+
rights either.
|
|
225
|
+
|
|
226
|
+
## Metrics (appended to METRICS.md after every wave)
|
|
227
|
+
|
|
228
|
+
- releases in the last 24h
|
|
229
|
+
- median slice lead time (ready to npm)
|
|
230
|
+
- review rounds per slice, by tier
|
|
231
|
+
- moat proven count
|
|
232
|
+
- required-ci failures
|
|
233
|
+
- spend estimate (subagent output tokens from workflow journals x published
|
|
234
|
+
per-token price, labelled ESTIMATE, not exact billing)
|
|
235
|
+
|
|
236
|
+
Target: at least 30 releases per 24h at steady state, moat proven count never
|
|
237
|
+
decreasing.
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var dt=Object.create;var{getPrototypeOf:pt,defineProperty:jG,getOwnPropertyNames:ct}=Object;var lt=Object.prototype.hasOwnProperty;function it($){return this[$]}var at,ot,st=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?at??=new WeakMap:ot??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?dt(pt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of ct($))if(!lt.call(J,q))jG(J,q,{get:it.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var Zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var nt=($)=>$;function rt($,X){this[$]=nt.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:rt.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var WR={};B1(WR,{lokiDir:()=>h0,homeLokiDir:()=>GQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>O1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as tt}from"url";import{existsSync as Kq}from"fs";import{homedir as et}from"os";function $e(){let $=HR;for(let X=0;X<6;X++){if(Kq(h2($,"VERSION"))&&Kq(h2($,"autonomy/run.sh")))return $;let Q=LG($);if(Q===$)break;$=Q}return h2(HR,"..","..","..")}function AG($){let X=$;for(let Q=0;Q<6;Q++){if(Kq(h2(X,"VERSION"))&&Kq(h2(X,"autonomy/run.sh")))return X;let z=LG(X);if(z===X)break;X=z}return h2($,"..","..","..")}function h0(){return process.env.LOKI_DIR??h2(process.cwd(),".loki")}function GQ(){return h2(et(),".loki")}var HR,O1;var k1=s(()=>{HR=LG(tt(import.meta.url));O1=$e()});import{readFileSync as Xe}from"fs";import{resolve as Qe,dirname as ze}from"path";import{fileURLToPath as Ze}from"url";function L9(){if(t3!==null)return t3;let $="9.54.
|
|
2
|
+
var dt=Object.create;var{getPrototypeOf:pt,defineProperty:jG,getOwnPropertyNames:ct}=Object;var lt=Object.prototype.hasOwnProperty;function it($){return this[$]}var at,ot,st=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?at??=new WeakMap:ot??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?dt(pt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of ct($))if(!lt.call(J,q))jG(J,q,{get:it.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var Zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var nt=($)=>$;function rt($,X){this[$]=nt.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:rt.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var WR={};B1(WR,{lokiDir:()=>h0,homeLokiDir:()=>GQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>O1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as tt}from"url";import{existsSync as Kq}from"fs";import{homedir as et}from"os";function $e(){let $=HR;for(let X=0;X<6;X++){if(Kq(h2($,"VERSION"))&&Kq(h2($,"autonomy/run.sh")))return $;let Q=LG($);if(Q===$)break;$=Q}return h2(HR,"..","..","..")}function AG($){let X=$;for(let Q=0;Q<6;Q++){if(Kq(h2(X,"VERSION"))&&Kq(h2(X,"autonomy/run.sh")))return X;let z=LG(X);if(z===X)break;X=z}return h2($,"..","..","..")}function h0(){return process.env.LOKI_DIR??h2(process.cwd(),".loki")}function GQ(){return h2(et(),".loki")}var HR,O1;var k1=s(()=>{HR=LG(tt(import.meta.url));O1=$e()});import{readFileSync as Xe}from"fs";import{resolve as Qe,dirname as ze}from"path";import{fileURLToPath as Ze}from"url";function L9(){if(t3!==null)return t3;let $="9.54.2";if(typeof $==="string"&&$.length>0)return t3=$,t3;try{let X=ze(Ze(import.meta.url)),Q=AG(X);t3=Xe(Qe(Q,"VERSION"),"utf-8").trim()}catch{t3="unknown"}return t3}var t3=null;var Jq=s(()=>{k1()});var LR={};B1(LR,{runOrThrow:()=>Ae,run:()=>X1,readStreamCapped:()=>qq,commandVersion:()=>Te,commandExists:()=>g5,ShellError:()=>TG,MAX_STDOUT_BYTES:()=>jR});async function qq($,X=jR){let Q=$.getReader(),z=new TextDecoder,Z="",K=0;try{while(K<X){let{done:J,value:q}=await Q.read();if(J)break;if(!q)continue;if(K+=q.byteLength,K>X){let V=q.byteLength-(K-X);Z+=z.decode(q.subarray(0,V),{stream:!0});break}Z+=z.decode(q,{stream:!0})}Z+=z.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return Z}async function X1($,X={}){let Q=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),z,Z;if(X.timeoutMs&&X.timeoutMs>0)z=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[K,J,q]=await Promise.all([qq(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:K,stderr:J,exitCode:q}}finally{if(z)clearTimeout(z);if(Z)clearTimeout(Z)}}async function Ae($,X={}){let Q=await X1($,X);if(Q.exitCode!==0)throw new TG(`command failed (${Q.exitCode}): ${$.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function g5($){let X=Ce($),Q=await X1(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Ce($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function Te($,X="--version"){if(!await g5($))return null;let z=await X1([$,X],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var jR=16777216,TG;var y8=s(()=>{TG=class TG extends Error{message;exitCode;stdout;stderr;constructor($,X,Q,z){super($);this.message=$;this.exitCode=X;this.stdout=Q;this.stderr=z;this.name="ShellError"}}});function g2($){return De?"":$}var De,p0,$5,Z1,E61,A1,f1,m5,n;var e7=s(()=>{De=(process.env.NO_COLOR??"").length>0;p0=g2("\x1B[0;31m"),$5=g2("\x1B[0;32m"),Z1=g2("\x1B[1;33m"),E61=g2("\x1B[0;34m"),A1=g2("\x1B[0;36m"),f1=g2("\x1B[1m"),m5=g2("\x1B[2m"),n=g2("\x1B[0m")});import{existsSync as ye}from"fs";async function Z2(){if(BQ!==void 0)return BQ;let $="/opt/homebrew/bin/python3.12";if(ye($))return BQ=$,$;let X=await g5("python3.12");if(X)return BQ=X,X;let Q=await g5("python3");return BQ=Q,Q}async function I4($,X={}){let Q=await Z2();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return X1([Q,"-c",$],X)}var BQ;var m2=s(()=>{y8()});var gR={};B1(gR,{runStatus:()=>Z00});import{existsSync as u5,readFileSync as T9,readdirSync as kR,statSync as SR}from"fs";import{resolve as A5,basename as se}from"path";import{homedir as ne}from"os";function yR($){let X=Math.trunc($);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function bR($,X,Q){if(X===0)return null;let z=Math.trunc($*100/X),Z=Math.trunc($*Yq/X);if(Z>Yq)Z=Yq;let K=Yq-Z,J=$5;if(z>=80)J=p0;else if(z>=50)J=Z1;let q="=".repeat(Math.max(0,Z))+" ".repeat(Math.max(0,K)),V=yR($),Y=yR(X);return` ${f1}${Q}${n} ${J}[${q}]${n} ${z}% (${V} / ${Y})`}async function te(){if(await g5("jq"))return!0;return process.stdout.write(`${p0}Error: jq is required but not installed.${n}
|
|
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)
|
|
@@ -1345,4 +1345,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1345
1345
|
`),2}case"start":{let{runStart:z}=await Promise.resolve().then(() => (gt(),ht));return z(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1346
1346
|
`),process.stderr.write(mt),2}}ER();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var H61=await U61(Bun.argv.slice(2));process.exit(H61);
|
|
1347
1347
|
|
|
1348
|
-
//# debugId=
|
|
1348
|
+
//# debugId=CF1319BA2D6A59CC478BB2F881D9252C
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "9.54.
|
|
4
|
+
"version": "9.54.2",
|
|
5
5
|
"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 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider, opencode).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "9.54.
|
|
5
|
+
"version": "9.54.2",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|
package/providers/aider.sh
CHANGED
|
@@ -109,6 +109,12 @@ provider_version() {
|
|
|
109
109
|
aider --version 2>/dev/null | head -1
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
# Commit hygiene, the sentence providers/claude.sh (and the Bun
|
|
113
|
+
# AUTONOMY_OVERRIDE_TEXT) puts in Claude's system prompt. Aider takes no
|
|
114
|
+
# system prompt here, so it leads every prompt the functions below send
|
|
115
|
+
# (BACKLOG 74: an agent's own `git add -A` commits the user's files).
|
|
116
|
+
PROVIDER_COMMIT_HYGIENE='Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.'
|
|
117
|
+
|
|
112
118
|
# Invocation function
|
|
113
119
|
# --message: single instruction mode (process and exit)
|
|
114
120
|
# --yes-always: auto-approve all prompts
|
|
@@ -116,6 +122,7 @@ provider_version() {
|
|
|
116
122
|
provider_invoke() {
|
|
117
123
|
local prompt="$1"
|
|
118
124
|
shift
|
|
125
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
119
126
|
local model="$AIDER_DEFAULT_MODEL"
|
|
120
127
|
local extra_flags="${LOKI_AIDER_FLAGS:-}"
|
|
121
128
|
# shellcheck disable=SC2086
|
|
@@ -150,6 +157,7 @@ resolve_model_for_tier() {
|
|
|
150
157
|
provider_invoke_argv() {
|
|
151
158
|
local tier="${1:-development}"
|
|
152
159
|
local prompt="${2:-}"
|
|
160
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
153
161
|
local model
|
|
154
162
|
model="$(provider_get_tier_param "$tier" 2>/dev/null || printf '%s' "")"
|
|
155
163
|
_LOKI_INVOKE_ARGV=(aider --yes-always --no-auto-commits)
|
package/providers/cline.sh
CHANGED
|
@@ -107,6 +107,12 @@ provider_version() {
|
|
|
107
107
|
cline --version 2>/dev/null | head -1
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
# Commit hygiene, the sentence providers/claude.sh (and the Bun
|
|
111
|
+
# AUTONOMY_OVERRIDE_TEXT) puts in Claude's system prompt. Cline takes no
|
|
112
|
+
# system prompt here, so it leads every prompt the functions below send
|
|
113
|
+
# (BACKLOG 74: an agent's own `git add -A` commits the user's files).
|
|
114
|
+
PROVIDER_COMMIT_HYGIENE='Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.'
|
|
115
|
+
|
|
110
116
|
# Invocation function
|
|
111
117
|
# Uses -y (YOLO) for autonomous mode, positional prompt
|
|
112
118
|
# BUG-PROV-009 fix: build model flag as array to prevent word-splitting on model
|
|
@@ -114,6 +120,7 @@ provider_version() {
|
|
|
114
120
|
provider_invoke() {
|
|
115
121
|
local prompt="$1"
|
|
116
122
|
shift
|
|
123
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
117
124
|
local model="${LOKI_CLINE_MODEL:-}"
|
|
118
125
|
local model_args=()
|
|
119
126
|
[[ -n "$model" ]] && model_args=("-m" "$model")
|
|
@@ -148,6 +155,7 @@ resolve_model_for_tier() {
|
|
|
148
155
|
provider_invoke_argv() {
|
|
149
156
|
local tier="${1:-development}"
|
|
150
157
|
local prompt="${2:-}"
|
|
158
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
151
159
|
local model
|
|
152
160
|
model="$(provider_get_tier_param "$tier" 2>/dev/null || printf '%s' "")"
|
|
153
161
|
_LOKI_INVOKE_ARGV=(cline -y)
|
package/providers/codex.sh
CHANGED
|
@@ -209,9 +209,16 @@ _codex_model_flag() {
|
|
|
209
209
|
return 0
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
# Commit hygiene, the sentence providers/claude.sh (and the Bun
|
|
213
|
+
# AUTONOMY_OVERRIDE_TEXT) puts in Claude's system prompt. Codex takes no
|
|
214
|
+
# system prompt here, so it leads every prompt the functions below send
|
|
215
|
+
# (BACKLOG 74: an agent's own `git add -A` commits the user's files).
|
|
216
|
+
PROVIDER_COMMIT_HYGIENE='Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.'
|
|
217
|
+
|
|
212
218
|
provider_invoke() {
|
|
213
219
|
local prompt="$1"
|
|
214
220
|
shift
|
|
221
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
215
222
|
local model_flag=()
|
|
216
223
|
while IFS= read -r _mf; do
|
|
217
224
|
[ -n "$_mf" ] && model_flag+=("$_mf")
|
|
@@ -302,6 +309,7 @@ provider_invoke_with_tier() {
|
|
|
302
309
|
local tier="$1"
|
|
303
310
|
local prompt="$2"
|
|
304
311
|
shift 2
|
|
312
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
305
313
|
local effort
|
|
306
314
|
effort=$(resolve_model_for_tier "$tier")
|
|
307
315
|
|
|
@@ -360,6 +368,7 @@ provider_invoke_with_tier() {
|
|
|
360
368
|
provider_invoke_argv() {
|
|
361
369
|
local tier="${1:-development}"
|
|
362
370
|
local prompt="${2:-}"
|
|
371
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
363
372
|
|
|
364
373
|
# DO NOT pass provider_get_tier_param to --model. For Codex that function
|
|
365
374
|
# returns an EFFORT LEVEL (xhigh/high/low), not a model name -- the note at
|
package/providers/opencode.sh
CHANGED
|
@@ -117,6 +117,12 @@ provider_get_tier_param() {
|
|
|
117
117
|
esac
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
# Commit hygiene, the sentence providers/claude.sh (and the Bun
|
|
121
|
+
# AUTONOMY_OVERRIDE_TEXT) puts in Claude's system prompt. opencode takes no
|
|
122
|
+
# system prompt here, so it leads every prompt the functions below send
|
|
123
|
+
# (BACKLOG 74: an agent's own `git add -A` commits the user's files).
|
|
124
|
+
PROVIDER_COMMIT_HYGIENE='Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.'
|
|
125
|
+
|
|
120
126
|
# provider_invoke <prompt> -- run one non-interactive turn.
|
|
121
127
|
provider_invoke() {
|
|
122
128
|
# CONTRACT: prompt is $1, and EXTRA ARGS MUST PASS THROUGH. The first cut of
|
|
@@ -130,6 +136,7 @@ provider_invoke() {
|
|
|
130
136
|
local prompt="$1"
|
|
131
137
|
shift
|
|
132
138
|
[ -n "$prompt" ] || return 1
|
|
139
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
133
140
|
command -v opencode >/dev/null 2>&1 || return 127
|
|
134
141
|
opencode run --auto --model "$PROVIDER_MODEL_DEVELOPMENT" "$prompt" "$@"
|
|
135
142
|
}
|
|
@@ -143,6 +150,7 @@ provider_invoke_with_tier() {
|
|
|
143
150
|
shift 2
|
|
144
151
|
[ -n "$tier" ] || tier="development"
|
|
145
152
|
[ -n "$prompt" ] || return 1
|
|
153
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
146
154
|
command -v opencode >/dev/null 2>&1 || return 127
|
|
147
155
|
local model
|
|
148
156
|
model="$(provider_get_tier_param "$tier")"
|
|
@@ -153,6 +161,7 @@ provider_invoke_with_tier() {
|
|
|
153
161
|
provider_invoke_argv() {
|
|
154
162
|
local tier="${1:-development}"
|
|
155
163
|
local prompt="${2:-}"
|
|
164
|
+
prompt="$PROVIDER_COMMIT_HYGIENE"$'\n\n'"$prompt"
|
|
156
165
|
local model
|
|
157
166
|
model="$(provider_get_tier_param "$tier")"
|
|
158
167
|
_LOKI_INVOKE_ARGV=(opencode run --auto --model "$model" "$prompt")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-Cz7q1bvC.js";import{B as C}from"./Button-D5qDd2ef.js";import{T as $e}from"./trending-up-DWuEK3WC.js";import{C as z}from"./clock-C8p2e4NI.js";import{A as Be,U as ue,M as De}from"./Avatar-gQIp6FBI.js";import{A as J}from"./activity-dEhz-bXR.js";import{R as pe}from"./refresh-cw-D2dv0xA0.js";import{G as ze}from"./globe-C9QXkgH_.js";import{C as Le}from"./chevron-left-tvNswo3A.js";import{C as je}from"./check-C_9Nx7kb.js";import{D as Y}from"./dollar-sign-DSu6n3K3.js";import{U as Te}from"./user-DMRXwZiw.js";import{D as Me}from"./database-DObn5fmn.js";import{L as Ue}from"./lock-DSI29pct.js";import{S as Re}from"./scroll-text-DvoOvAl_.js";import{S as Ie}from"./shield-alert-40cX_FvG.js";/**
|
|
2
|
+
* @license lucide-react v0.577.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const Oe=[["path",{d:"M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16",key:"jecpp"}],["rect",{width:"20",height:"14",x:"2",y:"6",rx:"2",key:"i6l2r4"}]],_e=L("briefcase",Oe);/**
|
|
7
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const Pe=[["path",{d:"M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z",key:"pzmjnu"}],["path",{d:"M21.21 15.89A10 10 0 1 1 8 2.83",key:"k2fpak"}]],Ge=L("chart-pie",Pe);/**
|
|
12
|
+
* @license lucide-react v0.577.0 - ISC
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the ISC license.
|
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
16
|
+
*/const He=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],K=L("download",He);/**
|
|
17
|
+
* @license lucide-react v0.577.0 - ISC
|
|
18
|
+
*
|
|
19
|
+
* This source code is licensed under the ISC license.
|
|
20
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
21
|
+
*/const Ve=[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]],We=L("funnel",Ve);/**
|
|
22
|
+
* @license lucide-react v0.577.0 - ISC
|
|
23
|
+
*
|
|
24
|
+
* This source code is licensed under the ISC license.
|
|
25
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
26
|
+
*/const qe=[["circle",{cx:"9",cy:"12",r:"3",key:"u3jwor"}],["rect",{width:"20",height:"14",x:"2",y:"5",rx:"7",key:"g7kal2"}]],Ze=L("toggle-left",qe);/**
|
|
27
|
+
* @license lucide-react v0.577.0 - ISC
|
|
28
|
+
*
|
|
29
|
+
* This source code is licensed under the ISC license.
|
|
30
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
31
|
+
*/const Je=[["circle",{cx:"15",cy:"12",r:"3",key:"1afu0r"}],["rect",{width:"20",height:"14",x:"2",y:"5",rx:"7",key:"g7kal2"}]],Ye=L("toggle-right",Je);function R({children:s}){return e.jsxs("p",{className:"text-sm text-[#939084] py-4",children:[e.jsx("span",{className:"font-medium text-[#6B6960]",children:"Not recorded."})," ",s]})}function Ke({data:s}){const[r,c]=x.useState(null);if(s.length===0)return null;const n=600,a=200,t={top:20,right:20,bottom:30,left:60},j=n-t.left-t.right,o=a-t.top-t.bottom,b=Math.max(...s.map(i=>i.tokens)),h=0,m=b-h||1,E=s.map((i,N)=>({x:t.left+N/(s.length-1)*j,y:t.top+o-(i.tokens-h)/m*o,...i})),v=E.map((i,N)=>`${N===0?"M":"L"} ${i.x} ${i.y}`).join(" "),u=`${v} L ${E[E.length-1].x} ${t.top+o} L ${E[0].x} ${t.top+o} Z`,p=i=>i>=1e6?`${(i/1e6).toFixed(1)}M`:i>=1e3?`${(i/1e3).toFixed(0)}K`:String(i),k=Array.from({length:5},(i,N)=>({value:h+m*N/4,y:t.top+o-N/4*o}));return e.jsxs("svg",{viewBox:`0 0 ${n} ${a}`,className:"w-full",preserveAspectRatio:"xMidYMid meet",children:[k.map((i,N)=>e.jsxs("g",{children:[e.jsx("line",{x1:t.left,y1:i.y,x2:n-t.right,y2:i.y,stroke:"currentColor",strokeOpacity:"0.08",strokeDasharray:"4 4"}),e.jsx("text",{x:t.left-8,y:i.y+4,textAnchor:"end",className:"text-[10px] fill-[#939084]",children:p(i.value)})]},N)),e.jsx("path",{d:u,fill:"url(#tokenGradient)",opacity:"0.15"}),e.jsx("path",{d:v,fill:"none",stroke:"#553DE9",strokeWidth:"2",strokeLinejoin:"round"}),e.jsx("defs",{children:e.jsxs("linearGradient",{id:"tokenGradient",x1:"0",y1:"0",x2:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"#553DE9"}),e.jsx("stop",{offset:"100%",stopColor:"#553DE9",stopOpacity:"0"})]})}),E.map((i,N)=>e.jsxs("g",{children:[e.jsx("circle",{cx:i.x,cy:i.y,r:r===N?5:3,fill:r===N?"#553DE9":"white",stroke:"#553DE9",strokeWidth:"2",className:"cursor-pointer transition-all",onMouseEnter:()=>c(N),onMouseLeave:()=>c(null)}),r===N&&e.jsxs("g",{children:[e.jsx("rect",{x:i.x-50,y:i.y-36,width:"100",height:"24",rx:"4",fill:"#36342E"}),e.jsxs("text",{x:i.x,y:i.y-20,textAnchor:"middle",className:"text-[10px] fill-white font-mono",children:[p(i.tokens)," | ",i.date.slice(5)]})]})]},N)),[0,Math.floor(s.length/2),s.length-1].map(i=>e.jsx("text",{x:E[i].x,y:a-4,textAnchor:"middle",className:"text-[10px] fill-[#939084]",children:s[i].date.slice(5)},i))]})}function Xe({data:s}){const[r,c]=x.useState(null),n=s.reduce((m,E)=>m+E.cost,0),a=160,t=a/2,j=60,o=40;let b=-90;const h=s.map((m,E)=>{const v=m.percentage/100*360,u=b,p=b+v;b=p;const k=u*Math.PI/180,i=p*Math.PI/180,N=v>180?1:0,g=r===E?j+4:j,F=[`M ${t+o*Math.cos(k)} ${t+o*Math.sin(k)}`,`L ${t+g*Math.cos(k)} ${t+g*Math.sin(k)}`,`A ${g} ${g} 0 ${N} 1 ${t+g*Math.cos(i)} ${t+g*Math.sin(i)}`,`L ${t+o*Math.cos(i)} ${t+o*Math.sin(i)}`,`A ${o} ${o} 0 ${N} 0 ${t+o*Math.cos(k)} ${t+o*Math.sin(k)}`,"Z"].join(" ");return{...m,path:F,index:E}});return e.jsxs("div",{className:"flex items-center gap-6",children:[e.jsxs("svg",{width:a,height:a,viewBox:`0 0 ${a} ${a}`,children:[h.map(m=>e.jsx("path",{d:m.path,fill:m.color,opacity:r!==null&&r!==m.index?.4:1,className:"cursor-pointer transition-opacity",onMouseEnter:()=>c(m.index),onMouseLeave:()=>c(null)},m.index)),e.jsx("text",{x:t,y:t-6,textAnchor:"middle",className:"text-xs fill-[#939084]",children:"Total"}),e.jsxs("text",{x:t,y:t+12,textAnchor:"middle",className:"text-sm fill-[#36342E] dark:fill-[#E8E6E3] font-semibold",children:["$",n.toFixed(2)]})]}),e.jsx("div",{className:"flex flex-col gap-2",children:s.map((m,E)=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",onMouseEnter:()=>c(E),onMouseLeave:()=>c(null),children:[e.jsx("span",{className:"w-3 h-3 rounded-sm flex-shrink-0",style:{backgroundColor:m.color}}),e.jsx("span",{className:"text-[#36342E] dark:text-[#E8E6E3]",children:m.provider}),e.jsxs("span",{className:"text-[#939084] ml-auto font-mono",children:["$",m.cost.toFixed(2)]})]},E))})]})}function Qe({data:s}){const r=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],c=Math.max(...s.flat()),n=a=>{const t=c>0?a/c:0;return t===0?"bg-[#F8F4F0] dark:bg-[#1A1A1E]":t<.25?"bg-[#553DE9]/10":t<.5?"bg-[#553DE9]/25":t<.75?"bg-[#553DE9]/50":"bg-[#553DE9]/80"};return e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("div",{className:"inline-block",children:[e.jsx("div",{className:"flex gap-0.5 mb-1 ml-10",children:Array.from({length:24},(a,t)=>e.jsx("div",{className:"w-4 text-center text-[9px] text-[#939084]",children:t%6===0?`${t}`:""},t))}),s.map((a,t)=>e.jsxs("div",{className:"flex items-center gap-0.5 mb-0.5",children:[e.jsx("span",{className:"w-8 text-right text-[10px] text-[#939084] mr-1",children:r[t]}),a.map((j,o)=>e.jsx("div",{className:`w-4 h-4 rounded-sm ${n(j)} transition-colors`,title:`${r[t]} ${o}:00 - ${j} builds`},o))]},t)),e.jsxs("div",{className:"flex items-center gap-1 mt-2 ml-10",children:[e.jsx("span",{className:"text-[10px] text-[#939084]",children:"Less"}),["bg-[#F8F4F0] dark:bg-[#1A1A1E]","bg-[#553DE9]/10","bg-[#553DE9]/25","bg-[#553DE9]/50","bg-[#553DE9]/80"].map((a,t)=>e.jsx("div",{className:`w-3 h-3 rounded-sm ${a}`},t)),e.jsx("span",{className:"text-[10px] text-[#939084]",children:"More"})]})]})})}function es({data:s={},className:r=""}){var t,j,o,b;const c=Object.values(s).some(h=>h!=null),n=x.useCallback(()=>{const h=new Blob([JSON.stringify(s,null,2)],{type:"application/json"}),m=URL.createObjectURL(h),E=document.createElement("a");E.href=m,E.download=`usage-analytics-${new Date().toISOString().split("T")[0]}.json`,E.click(),URL.revokeObjectURL(m)},[s]),a=s.buildSuccessRate;return e.jsxs("div",{className:`space-y-6 ${r}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(re,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"Usage Analytics"})]}),c&&e.jsx(C,{size:"sm",variant:"ghost",icon:K,onClick:n,children:"Export"})]}),e.jsxs("div",{className:"card p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx($e,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Token Usage (30 Days)"})]}),(t=s.tokenUsage)!=null&&t.length?e.jsx(Ke,{data:s.tokenUsage}):e.jsx(R,{children:"No endpoint on this server reports daily token usage."})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"card p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(Ge,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Cost by Model"})]}),(j=s.costBreakdown)!=null&&j.length?e.jsx(Xe,{data:s.costBreakdown}):e.jsx(R,{children:"No run on this project has recorded a cost yet."})]}),e.jsxs("div",{className:"card p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(ne,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Build Success Rate"})]}),a!=null?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-4 mb-4",children:[e.jsxs("span",{className:"text-3xl font-bold text-[#36342E] dark:text-[#E8E6E3]",children:[a,"%"]}),e.jsxs("div",{className:"text-xs text-[#939084]",children:[e.jsxs("div",{children:[s.successfulBuilds," passed"]}),e.jsxs("div",{children:[s.failedBuilds," failed"]}),e.jsxs("div",{children:[s.totalBuilds," total"]})]})]}),e.jsx("div",{className:"h-3 bg-[#F8F4F0] dark:bg-[#1A1A1E] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all",style:{width:`${a}%`,background:a>=80?"#1FC5A8":a>=60?"#F59E0B":"#C45B5B"}})})]}):e.jsx(R,{children:"Build outcomes are not tracked here. Verified outcomes appear as Evidence Receipts on the Metrics page."}),e.jsxs("div",{className:"mt-6",children:[e.jsx("h4",{className:"text-xs font-medium text-[#939084] uppercase tracking-wider mb-2",children:"Top Templates"}),(o=s.templateUsage)!=null&&o.length?e.jsx("div",{className:"space-y-2",children:s.templateUsage.slice(0,5).map((h,m)=>e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm text-[#36342E] dark:text-[#E8E6E3]",children:[m+1,". ",h.name]}),e.jsxs("span",{className:"text-xs font-mono text-[#939084]",children:[h.count," builds"]})]},m))}):e.jsx(R,{children:"Template usage is not recorded."})]})]})]}),e.jsxs("div",{className:"card p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(z,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Peak Usage Hours"})]}),(b=s.peakHours)!=null&&b.length?e.jsx(Qe,{data:s.peakHours}):e.jsx(R,{children:"Build start times are not aggregated by hour on this server."})]})]})}const se={auth:"#553DE9",project:"#1FC5A8",admin:"#F59E0B",deploy:"#C45B5B",api:"#6366F1",system:"#939084"};function ss({category:s}){return e.jsx("span",{className:"px-1.5 py-0.5 rounded text-[10px] font-medium uppercase tracking-wide",style:{backgroundColor:`${se[s]}15`,color:se[s]},children:s})}function ts({events:s,onFetch:r,pollInterval:c=3e4,className:n=""}){const[a,t]=x.useState(s??[]),[j,o]=x.useState(null),[b,h]=x.useState(""),[m,E]=x.useState(""),[v,u]=x.useState(""),[p,k]=x.useState(""),[i,N]=x.useState(""),[g,F]=x.useState(!1),[d,f]=x.useState(null),[y,w]=x.useState(1),[T,X]=x.useState(!1),G=x.useRef(null),M=15;x.useEffect(()=>{if(!r)return;const l=async()=>{try{const A=await r({search:b,user:m,actionType:v,dateFrom:p,dateTo:i});t(A),o(null)}catch(A){o(A instanceof Error?A.message:"request failed")}};if(l(),!(c<=0))return G.current=setInterval(l,c),()=>{G.current&&clearInterval(G.current)}},[r,c,b,m,v,p,i]);const fe=[...new Set(a.map(l=>l.user))].sort(),Ee=[...new Set(a.map(l=>l.action))].sort(),B=a.filter(l=>{if(b){const A=b.toLowerCase();if(!(l.action.toLowerCase().includes(A)||l.user.toLowerCase().includes(A)||l.target.toLowerCase().includes(A)||l.details.toLowerCase().includes(A)||l.ip.includes(A)))return!1}return!(m&&l.user!==m||v&&l.action!==v||p&&l.timestamp<p||i&&l.timestamp>i+"T23:59:59")}),D=Math.ceil(B.length/M),Q=B.slice((y-1)*M,y*M);x.useEffect(()=>{w(1)},[b,m,v,p,i]);const be=x.useCallback(()=>{const l=["Timestamp","User","Action","Target","Details","IP","Category"],A=B.map($=>[$.timestamp,$.user,$.action,$.target,`"${$.details.replace(/"/g,'""')}"`,$.ip,$.category]),S=[l.join(","),...A.map($=>$.join(","))].join(`
|
|
32
|
+
`),ke=new Blob([S],{type:"text/csv"}),ee=URL.createObjectURL(ke),H=document.createElement("a");H.href=ee,H.download=`audit-log-${new Date().toISOString().split("T")[0]}.csv`,H.click(),URL.revokeObjectURL(ee)},[B]),ve=x.useCallback(async()=>{if(r){X(!0);try{const l=await r({search:b,user:m,actionType:v,dateFrom:p,dateTo:i});t(l),o(null)}catch(l){o(l instanceof Error?l.message:"request failed")}finally{X(!1)}}},[r,b,m,v,p,i]),Ne=l=>new Date(l).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1});return e.jsxs("div",{className:`space-y-4 ${n}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(J,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"Audit Trail"}),!j&&e.jsxs("span",{className:"text-xs text-[#939084] ml-1",children:[B.length," event",B.length!==1?"s":""]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{size:"sm",variant:"ghost",icon:pe,onClick:ve,loading:T,children:"Refresh"}),e.jsx(C,{size:"sm",variant:"ghost",icon:K,onClick:be,children:"CSV"})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(le,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[#939084]"}),e.jsx("input",{type:"text",value:b,onChange:l=>h(l.target.value),placeholder:"Search events...",className:"w-full pl-9 pr-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3] placeholder-[#939084]"})]}),e.jsx(C,{size:"sm",variant:g?"secondary":"ghost",icon:We,onClick:()=>F(!g),children:"Filters"})]}),g&&e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3 p-3 border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg bg-[#F8F4F0] dark:bg-[#222228]",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"User"}),e.jsxs("select",{value:m,onChange:l=>E(l.target.value),className:"w-full px-2 py-1.5 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]",children:[e.jsx("option",{value:"",children:"All Users"}),fe.map(l=>e.jsx("option",{value:l,children:l},l))]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"Action"}),e.jsxs("select",{value:v,onChange:l=>u(l.target.value),className:"w-full px-2 py-1.5 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]",children:[e.jsx("option",{value:"",children:"All Actions"}),Ee.map(l=>e.jsx("option",{value:l,children:l},l))]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"From"}),e.jsx("input",{type:"date",value:p,onChange:l=>k(l.target.value),className:"w-full px-2 py-1.5 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"To"}),e.jsx("input",{type:"date",value:i,onChange:l=>N(l.target.value),className:"w-full px-2 py-1.5 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]"})]})]})]}),e.jsx("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"bg-[#F8F4F0] dark:bg-[#222228]",children:[e.jsx("th",{className:"w-8 px-2 py-2.5"}),e.jsx("th",{className:"text-left px-3 py-2.5 text-xs font-medium text-[#6B6960]",children:"Timestamp"}),e.jsx("th",{className:"text-left px-3 py-2.5 text-xs font-medium text-[#6B6960]",children:"User"}),e.jsx("th",{className:"text-left px-3 py-2.5 text-xs font-medium text-[#6B6960]",children:"Action"}),e.jsx("th",{className:"text-left px-3 py-2.5 text-xs font-medium text-[#6B6960]",children:"Target"}),e.jsx("th",{className:"text-left px-3 py-2.5 text-xs font-medium text-[#6B6960] hidden md:table-cell",children:"IP"})]})}),e.jsxs("tbody",{children:[Q.map(l=>e.jsxs(e.Fragment,{children:[e.jsxs("tr",{className:"border-t border-[#ECEAE3] dark:border-[#2A2A30] hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors cursor-pointer",onClick:()=>f(d===l.id?null:l.id),children:[e.jsx("td",{className:"px-2 py-2.5 text-center",children:d===l.id?e.jsx(ie,{size:12,className:"text-[#939084]"}):e.jsx(P,{size:12,className:"text-[#939084]"})}),e.jsx("td",{className:"px-3 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-[#939084]",children:[e.jsx(z,{size:12}),e.jsx("span",{className:"font-mono",children:Ne(l.timestamp)})]})}),e.jsx("td",{className:"px-3 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(Be,{name:l.user.split("@")[0],size:"sm"}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] truncate max-w-[150px]",children:l.user})]})}),e.jsx("td",{className:"px-3 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ss,{category:l.category}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:l.action})]})}),e.jsx("td",{className:"px-3 py-2.5",children:e.jsx("span",{className:"text-[#6B6960] truncate max-w-[120px] block",children:l.target||"--"})}),e.jsx("td",{className:"px-3 py-2.5 hidden md:table-cell",children:e.jsxs("div",{className:"flex items-center gap-1 text-xs text-[#939084]",children:[e.jsx(ze,{size:12}),e.jsx("span",{className:"font-mono",children:l.ip||"--"})]})})]},l.id),d===l.id&&e.jsx("tr",{className:"bg-[#F8F4F0] dark:bg-[#222228]",children:e.jsx("td",{colSpan:6,className:"px-6 py-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(ye,{size:14,className:"text-[#939084] flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"text-sm text-[#6B6960]",children:[e.jsx("p",{className:"font-medium text-[#201515] dark:text-[#E8E6E3] mb-1",children:"Details"}),e.jsx("p",{children:l.details}),e.jsxs("div",{className:"flex items-center gap-4 mt-2 text-xs text-[#939084]",children:[e.jsxs("span",{children:["Event ID: ",l.id]}),e.jsxs("span",{children:["Full timestamp: ",new Date(l.timestamp).toISOString()]}),e.jsxs("span",{children:["IP: ",l.ip||"not recorded"]})]})]})]})})},`${l.id}-details`)]})),Q.length===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,className:"px-4 py-8 text-center text-sm text-[#939084]",children:j?`Could not load the audit log (${j}). Nothing is shown rather than a guess.`:a.length===0?"No audit events recorded yet.":"No events match your filters."})})]})]})}),D>1&&e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-xs text-[#939084]",children:["Showing ",(y-1)*M+1,"-",Math.min(y*M,B.length)," of ",B.length]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("button",{onClick:()=>w(l=>Math.max(1,l-1)),disabled:y===1,className:"p-1.5 rounded-lg text-[#939084] hover:bg-[#F8F4F0] dark:hover:bg-[#222228] disabled:opacity-40 transition-colors",children:e.jsx(Le,{size:16})}),Array.from({length:Math.min(D,5)},(l,A)=>{let S;return D<=5||y<=3?S=A+1:y>=D-2?S=D-4+A:S=y-2+A,e.jsx("button",{onClick:()=>w(S),className:`w-8 h-8 rounded-lg text-xs font-medium transition-colors ${y===S?"bg-[#553DE9] text-white":"text-[#939084] hover:bg-[#F8F4F0] dark:hover:bg-[#222228]"}`,children:S},S)}),e.jsx("button",{onClick:()=>w(l=>Math.min(D,l+1)),disabled:y===D,className:"p-1.5 rounded-lg text-[#939084] hover:bg-[#F8F4F0] dark:hover:bg-[#222228] disabled:opacity-40 transition-colors",children:e.jsx(P,{size:16})})]})]})]})}const V={admin:{label:"Admin",color:"#553DE9"},editor:{label:"Editor",color:"#1FC5A8"},viewer:{label:"Viewer",color:"#939084"}},te={active:{label:"Active",color:"#1FC5A8"},inactive:{label:"Inactive",color:"#939084"},invited:{label:"Invited",color:"#F59E0B"}};function q(s){if(!s)return"Never";const r=Date.now()-new Date(s).getTime(),c=Math.floor(r/6e4);if(c<1)return"Just now";if(c<60)return`${c}m ago`;const n=Math.floor(c/60);if(n<24)return`${n}h ago`;const a=Math.floor(n/24);return a<30?`${a}d ago`:`${Math.floor(a/30)}mo ago`}function ge(s){return s.split(" ").map(r=>r[0]).join("").toUpperCase().slice(0,2)}function as({onSubmit:s,onCancel:r}){const[c,n]=x.useState(""),[a,t]=x.useState("editor");return e.jsxs("div",{className:"border border-[#553DE9]/20 bg-[#553DE9]/5 dark:bg-[#553DE9]/10 rounded-lg p-4 space-y-3",children:[e.jsx("h4",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3]",children:"Invite New User"}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"md:col-span-2",children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"Email"}),e.jsxs("div",{className:"relative",children:[e.jsx(De,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[#939084]"}),e.jsx("input",{type:"email",value:c,onChange:j=>n(j.target.value),placeholder:"colleague@company.com",className:"w-full pl-9 pr-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3] placeholder-[#939084]",autoFocus:!0})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"Role"}),e.jsxs("select",{value:a,onChange:j=>t(j.target.value),className:"w-full px-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]",children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"editor",children:"Editor"}),e.jsx("option",{value:"viewer",children:"Viewer"})]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{size:"sm",icon:ue,onClick:()=>s(c,a),disabled:!c.trim()||!c.includes("@"),children:"Send Invite"}),e.jsx(C,{size:"sm",variant:"ghost",onClick:r,children:"Cancel"})]})]})}function rs({user:s,onClose:r,onChangeRole:c,onToggleStatus:n}){return e.jsxs("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[s.avatar_url?e.jsx("img",{src:s.avatar_url,alt:"",className:"w-10 h-10 rounded-full"}):e.jsx("div",{className:"w-10 h-10 rounded-full bg-[#553DE9] flex items-center justify-center text-white text-sm font-bold",children:ge(s.name)}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-[#201515] dark:text-[#E8E6E3]",children:s.name}),e.jsx("p",{className:"text-xs text-[#939084]",children:s.email})]})]}),e.jsx("button",{onClick:r,className:"p-1 rounded-lg text-[#939084] hover:bg-[#F8F4F0] dark:hover:bg-[#222228]",children:e.jsx(ce,{size:16})})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-sm",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"Role"}),e.jsxs("select",{value:s.role,onChange:a=>c(a.target.value),className:"w-full px-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]",children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"editor",children:"Editor"}),e.jsx("option",{value:"viewer",children:"Viewer"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-[#6B6960] mb-1",children:"Status"}),e.jsx("button",{onClick:n,className:"flex items-center gap-2 px-3 py-2 w-full rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-sm text-left hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors",children:s.status==="active"?e.jsxs(e.Fragment,{children:[e.jsx(Ye,{size:16,className:"text-[#1FC5A8]"}),e.jsx("span",{className:"text-[#1FC5A8]",children:"Active"})]}):e.jsxs(e.Fragment,{children:[e.jsx(Ze,{size:16,className:"text-[#939084]"}),e.jsx("span",{className:"text-[#939084]",children:"Inactive"})]})})]})]}),e.jsxs("div",{className:"flex items-center gap-6 text-xs text-[#939084] pt-2 border-t border-[#ECEAE3] dark:border-[#2A2A30]",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(z,{size:12}),e.jsxs("span",{children:["Last active: ",q(s.lastActive)]})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(z,{size:12}),e.jsxs("span",{children:["Joined: ",q(s.joinedAt)]})]})]})]})}function ns({users:s,onChangeRole:r,onToggleStatus:c,onInviteUser:n,className:a=""}){const[t,j]=x.useState(s??[]),[o,b]=x.useState(""),[h,m]=x.useState(""),[E,v]=x.useState(!1),[u,p]=x.useState(null),k=t.filter(d=>{if(o){const f=o.toLowerCase();if(!d.name.toLowerCase().includes(f)&&!d.email.toLowerCase().includes(f))return!1}return!(h&&d.role!==h)}),i=t.find(d=>d.id===u)||null,N=x.useCallback(async(d,f)=>{if(!n)return;await n(d,f);const y={id:`u-${Date.now()}`,name:d.split("@")[0],email:d,role:f,status:"invited",lastActive:null,joinedAt:new Date().toISOString()};j(w=>[...w,y]),v(!1)},[n]),g=x.useCallback(async(d,f)=>{r&&(await r(d,f),j(y=>y.map(w=>w.id===d?{...w,role:f}:w)))},[r]),F=x.useCallback(async d=>{const f=t.find(w=>w.id===d);if(!f||!c)return;const y=f.status!=="active";await c(d,y),j(w=>w.map(T=>T.id===d?{...T,status:y?"active":"inactive"}:T))},[t,c]);return s?e.jsxs("div",{className:`space-y-4 ${a}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(I,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"User Management"}),e.jsxs("span",{className:"text-xs text-[#939084]",children:[t.length," users"]})]}),!E&&n&&e.jsx(C,{size:"sm",variant:"secondary",icon:ue,onClick:()=>v(!0),children:"Invite User"})]}),E&&e.jsx(as,{onSubmit:N,onCancel:()=>v(!1)}),i&&e.jsx(rs,{user:i,onClose:()=>p(null),onChangeRole:d=>g(i.id,d),onToggleStatus:()=>F(i.id)}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(le,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[#939084]"}),e.jsx("input",{type:"text",value:o,onChange:d=>b(d.target.value),placeholder:"Search users...",className:"w-full pl-9 pr-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3] placeholder-[#939084]"})]}),e.jsxs("select",{value:h,onChange:d=>m(d.target.value),className:"px-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3]",children:[e.jsx("option",{value:"",children:"All Roles"}),e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"editor",children:"Editor"}),e.jsx("option",{value:"viewer",children:"Viewer"})]})]}),e.jsxs("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg overflow-hidden divide-y divide-[#ECEAE3] dark:divide-[#2A2A30]",children:[k.map(d=>e.jsxs("button",{type:"button",onClick:()=>p(u===d.id?null:d.id),className:`w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors ${u===d.id?"bg-[#F8F4F0] dark:bg-[#222228]":""}`,children:[d.avatar_url?e.jsx("img",{src:d.avatar_url,alt:"",className:"w-8 h-8 rounded-full flex-shrink-0"}):e.jsx("div",{className:"w-8 h-8 rounded-full bg-[#553DE9] flex items-center justify-center text-white text-xs font-bold flex-shrink-0",children:ge(d.name)}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium text-[#201515] dark:text-[#E8E6E3] truncate",children:d.name}),e.jsx("p",{className:"text-xs text-[#939084] truncate",children:d.email})]}),e.jsx("span",{className:"px-2 py-0.5 rounded text-[10px] font-medium flex-shrink-0",style:{backgroundColor:`${V[d.role].color}15`,color:V[d.role].color},children:V[d.role].label}),e.jsxs("div",{className:"flex items-center gap-1.5 flex-shrink-0",children:[e.jsx("span",{className:"w-2 h-2 rounded-full",style:{backgroundColor:te[d.status].color}}),e.jsx("span",{className:"text-xs text-[#939084] hidden md:inline",children:te[d.status].label})]}),e.jsx("span",{className:"text-xs text-[#939084] flex-shrink-0 hidden lg:inline w-16 text-right",children:q(d.lastActive)}),e.jsx(P,{size:14,className:"text-[#939084] flex-shrink-0"})]},d.id)),k.length===0&&e.jsx("div",{className:"px-4 py-8 text-center text-sm text-[#939084]",children:"No users match your search."})]})]}):e.jsxs("div",{className:`space-y-4 ${a}`,children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(I,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"User Management"})]}),e.jsxs("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg px-4 py-8 text-center",children:[e.jsx("p",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Not connected"}),e.jsx("p",{className:"text-xs text-[#939084] mt-1",children:"This server has no user directory, so no users are listed. Team membership is managed on the Teams page."})]})]})}function ls({project:s,onApprove:r,onReject:c}){const[n,a]=x.useState(!1),[t,j]=x.useState(""),[o,b]=x.useState(!1);return e.jsxs("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg overflow-hidden",children:[e.jsxs("button",{type:"button",onClick:()=>a(!n),className:"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors",children:[n?e.jsx(ie,{size:14,className:"text-[#939084]"}):e.jsx(P,{size:14,className:"text-[#939084]"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-[#201515] dark:text-[#E8E6E3]",children:s.name}),e.jsx("span",{className:"px-1.5 py-0.5 rounded text-[10px] font-medium bg-[#F59E0B]/10 text-[#F59E0B]",children:"Pending"})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-[#939084] mt-0.5",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(Te,{size:10}),s.submittedBy]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(de,{size:10}),s.template]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(Y,{size:10}),"~$",s.estimatedCost.toFixed(2)]})]})]}),e.jsx("span",{className:"text-xs text-[#939084] flex-shrink-0",children:new Date(s.submittedAt).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1})})]}),n&&e.jsxs("div",{className:"px-4 pb-4 pt-2 border-t border-[#ECEAE3] dark:border-[#2A2A30] space-y-3",children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-[#6B6960]",children:"Template"}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:s.template})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-[#6B6960]",children:"Provider"}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:s.provider})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-[#6B6960]",children:"Est. Cost"}),e.jsxs("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:["$",s.estimatedCost.toFixed(2)]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-[#6B6960]",children:"Est. Iterations"}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:s.estimatedIterations})]})]}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:s.description}),o?e.jsxs("div",{className:"space-y-2",children:[e.jsx("textarea",{value:t,onChange:h=>j(h.target.value),placeholder:"Add a comment (optional)...",rows:2,className:"w-full px-3 py-2 text-sm rounded-lg border border-[#ECEAE3] dark:border-[#2A2A30] bg-white dark:bg-[#1A1A1E] text-[#201515] dark:text-[#E8E6E3] placeholder-[#939084] resize-none"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(C,{size:"sm",icon:je,onClick:()=>r(t),children:"Approve"}),e.jsx(C,{size:"sm",variant:"danger",icon:ce,onClick:()=>c(t),children:"Reject"}),e.jsx(C,{size:"sm",variant:"ghost",onClick:()=>b(!1),children:"Cancel"})]})]}):e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(C,{size:"sm",variant:"secondary",icon:Ae,onClick:()=>b(!0),children:"Review"})})]})]})}function is({configs:s}){return e.jsx("div",{className:"space-y-3",children:s.map(r=>{const c=r.budgetLimit>0?r.budgetUsed/r.budgetLimit*100:0,n=c>=r.alertThreshold,a=c>=100;return e.jsxs("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg p-3",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-sm font-medium text-[#201515] dark:text-[#E8E6E3]",children:r.projectName}),e.jsxs("div",{className:"flex items-center gap-2",children:[n&&e.jsx(Z,{size:14,className:a?"text-[#C45B5B]":"text-[#F59E0B]"}),e.jsxs("span",{className:"text-xs font-mono text-[#939084]",children:["$",r.budgetUsed.toFixed(2)," / $",r.budgetLimit.toFixed(2)]})]})]}),e.jsx("div",{className:"h-2 bg-[#F8F4F0] dark:bg-[#1A1A1E] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all",style:{width:`${Math.min(c,100)}%`,background:a?"#C45B5B":n?"#F59E0B":"#1FC5A8"}})}),e.jsxs("div",{className:"flex items-center justify-between mt-1",children:[e.jsxs("span",{className:"text-[10px] text-[#939084]",children:[c.toFixed(0),"% used"]}),e.jsxs("span",{className:"text-[10px] text-[#939084]",children:["Alert at ",r.alertThreshold,"%"]})]})]},r.projectId)})})}function W({children:s}){return e.jsxs("div",{className:"text-center py-8",children:[e.jsx(oe,{size:24,className:"mx-auto text-[#939084] mb-2"}),e.jsx("p",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Not connected"}),e.jsx("p",{className:"text-xs text-[#939084] mt-1",children:s})]})}function cs({pendingProjects:s,budgetConfigs:r,onApproveProject:c,onRejectProject:n,className:a=""}){const[t,j]=x.useState(s??[]),[o,b]=x.useState("approvals"),h=t.filter(u=>u.status==="pending").length,m=x.useCallback(async(u,p)=>{c&&(await c(u,p),j(k=>k.map(i=>i.id===u?{...i,status:"approved"}:i)))},[c]),E=x.useCallback(async(u,p)=>{n&&(await n(u,p),j(k=>k.map(i=>i.id===u?{...i,status:"rejected"}:i)))},[n]),v=[{id:"approvals",label:"Approvals",icon:je,count:h},{id:"budgets",label:"Budgets",icon:Y},{id:"templates",label:"Templates",icon:de}];return e.jsxs("div",{className:`space-y-4 ${a}`,children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(_e,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"Project Governance"})]}),e.jsx("div",{className:"flex items-center gap-1 border-b border-[#ECEAE3] dark:border-[#2A2A30]",children:v.map(u=>e.jsxs("button",{onClick:()=>b(u.id),className:`flex items-center gap-1.5 px-3 py-2 text-xs font-medium border-b-2 transition-colors ${o===u.id?"border-[#553DE9] text-[#553DE9]":"border-transparent text-[#939084] hover:text-[#36342E] dark:hover:text-[#E8E6E3]"}`,children:[e.jsx(u.icon,{size:14}),u.label,u.count!==void 0&&u.count>0&&e.jsx("span",{className:"ml-1 px-1.5 py-0.5 rounded-full text-[10px] bg-[#553DE9]/10 text-[#553DE9]",children:u.count})]},u.id))}),o==="approvals"&&!s&&e.jsx(W,{children:"No project approval workflow is wired to this server, so nothing is waiting and nothing has been reviewed."}),o==="approvals"&&s&&e.jsx("div",{className:"space-y-3",children:t.filter(u=>u.status==="pending").length===0?e.jsxs("div",{className:"text-center py-8",children:[e.jsx(oe,{size:24,className:"mx-auto text-[#939084] mb-2"}),e.jsx("p",{className:"text-sm text-[#939084]",children:"No pending approvals"}),e.jsx("p",{className:"text-xs text-[#939084] mt-1",children:"All project requests have been reviewed."})]}):t.filter(u=>u.status==="pending").map(u=>e.jsx(ls,{project:u,onApprove:p=>m(u.id,p),onReject:p=>E(u.id,p)},u.id))}),o==="budgets"&&(r?e.jsx(is,{configs:r}):e.jsx(W,{children:"No per-project budgets are served here. A run's spend cap is set with LOKI_BUDGET_LIMIT and shown on the Metrics page."})),o==="templates"&&e.jsx(W,{children:"Template restrictions are not stored or enforced by this server, so none are shown."})]})}function ds({status:s}){switch(s){case"pass":return e.jsx(xe,{size:18,className:"text-[#1FC5A8]"});case"fail":return e.jsx(me,{size:18,className:"text-[#C45B5B]"});case"warning":return e.jsx(Z,{size:18,className:"text-[#F59E0B]"})}}const os={security:Ue,access:I,data:Me,audit:Ce};function xs({score:s}){const t=2*Math.PI*56,o=270/360*t,b=s/100*o,h=s>=80?"#1FC5A8":s>=60?"#F59E0B":"#C45B5B",m=135;return e.jsxs("div",{className:"relative inline-flex items-center justify-center",children:[e.jsxs("svg",{width:140,height:140,viewBox:"0 0 140 140",children:[e.jsx("circle",{cx:70,cy:70,r:56,fill:"none",stroke:"currentColor",strokeOpacity:"0.08",strokeWidth:10,strokeDasharray:`${o} ${t}`,strokeLinecap:"round",transform:`rotate(${m} 70 70)`}),e.jsx("circle",{cx:70,cy:70,r:56,fill:"none",stroke:h,strokeWidth:10,strokeDasharray:`${b} ${t}`,strokeLinecap:"round",transform:`rotate(${m} 70 70)`,className:"transition-all duration-700"})]}),e.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center",children:[e.jsxs("span",{className:"text-3xl font-bold text-[#36342E] dark:text-[#E8E6E3]",children:[s,"%"]}),e.jsx("span",{className:"text-xs text-[#939084]",children:"Compliant"})]})]})}function ms({items:s,onRefresh:r,className:c=""}){const[n,a]=x.useState(s??[]),[t,j]=x.useState(!1),[o,b]=x.useState(null),[h,m]=x.useState(!1),E=n.filter(g=>g.status==="pass").length,v=n.filter(g=>g.status==="warning").length,u=n.filter(g=>g.status==="fail").length,p=n.length>0?Math.round(E/n.length*100):null,k=x.useCallback(async()=>{j(!0);try{if(r){const g=await r();a(g)}}catch{}finally{j(!1)}},[r]),i=x.useCallback(()=>{m(!0);const g={generatedAt:new Date().toISOString(),overallScore:p,summary:{pass:E,warning:v,fail:u,total:n.length},items:n.map(y=>({title:y.title,status:y.status,category:y.category,details:y.details,lastChecked:y.lastChecked}))},F=new Blob([JSON.stringify(g,null,2)],{type:"application/json"}),d=URL.createObjectURL(F),f=document.createElement("a");f.href=d,f.download=`compliance-report-${new Date().toISOString().split("T")[0]}.json`,f.click(),URL.revokeObjectURL(d),setTimeout(()=>m(!1),1e3)},[n,p,E,v,u]),N=["security","access","data","audit"];return e.jsxs("div",{className:`space-y-6 ${c}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(we,{size:18,className:"text-[#553DE9]"}),e.jsx("h3",{className:"text-sm font-semibold text-[#201515] dark:text-[#E8E6E3] uppercase tracking-wider",children:"Compliance"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[r&&e.jsx(C,{size:"sm",variant:"ghost",icon:pe,onClick:k,loading:t,children:"Refresh"}),p!==null&&e.jsx(C,{size:"sm",variant:"secondary",icon:K,onClick:i,loading:h,children:"Generate Report"})]})]}),p===null?e.jsxs("div",{className:"card p-6 text-center",children:[e.jsx("p",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Not connected"}),e.jsx("p",{className:"text-xs text-[#939084] mt-1",children:"No compliance checks are wired to this server, so there is no score. Nothing here has been checked."})]}):e.jsx("div",{className:"card p-6",children:e.jsxs("div",{className:"flex items-center gap-8",children:[e.jsx(xs,{score:p}),e.jsxs("div",{className:"flex-1 space-y-3",children:[e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Compliance Score"}),e.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(xe,{size:16,className:"text-[#1FC5A8]"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-lg font-bold text-[#36342E] dark:text-[#E8E6E3]",children:E}),e.jsx("span",{className:"text-xs text-[#939084] ml-1",children:"Passing"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Z,{size:16,className:"text-[#F59E0B]"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-lg font-bold text-[#36342E] dark:text-[#E8E6E3]",children:v}),e.jsx("span",{className:"text-xs text-[#939084] ml-1",children:"Warnings"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(me,{size:16,className:"text-[#C45B5B]"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-lg font-bold text-[#36342E] dark:text-[#E8E6E3]",children:u}),e.jsx("span",{className:"text-xs text-[#939084] ml-1",children:"Failing"})]})]})]})]})]})}),N.map(g=>{const F=n.filter(f=>f.category===g);if(F.length===0)return null;const d=os[g];return e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(d,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-xs font-semibold text-[#6B6960] uppercase tracking-wider",children:g})]}),e.jsx("div",{className:"border border-[#ECEAE3] dark:border-[#2A2A30] rounded-lg overflow-hidden divide-y divide-[#ECEAE3] dark:divide-[#2A2A30]",children:F.map(f=>e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>b(o===f.id?null:f.id),className:"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors",children:[e.jsx(ds,{status:f.status}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium text-[#201515] dark:text-[#E8E6E3]",children:f.title}),e.jsx("p",{className:"text-xs text-[#939084] truncate",children:f.description})]}),e.jsxs("div",{className:"flex items-center gap-1 text-[10px] text-[#939084] flex-shrink-0",children:[e.jsx(z,{size:10}),"Checked ",new Date(f.lastChecked).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1})]})]}),o===f.id&&e.jsxs("div",{className:"px-4 pb-3 pt-1 bg-[#F8F4F0] dark:bg-[#222228]",children:[f.details&&e.jsx("p",{className:"text-sm text-[#6B6960] mb-2",children:f.details}),f.remediationUrl&&f.status!=="pass"&&e.jsxs("a",{href:f.remediationUrl,className:"inline-flex items-center gap-1 text-xs text-[#553DE9] hover:underline",children:[e.jsx(Fe,{size:12}),"Fix this issue"]})]})]},f.id))})]},g)})]})}function hs(s){return s==null?"Not recorded":`$${s.toFixed(2)}`}function O(s,r){return s===void 0?"...":s===null?"Unavailable":r(s)}const ae=["#553DE9","#1FC5A8","#F59E0B","#6366F1","#C45B5B","#939084"];function us(s){if(!s||s.cost_recorded!==!0)return;const r=Object.entries(s.by_model||{}).map(([n,a])=>{const t=typeof a=="number"?a:a==null?void 0:a.cost_usd;return{model:n,usd:typeof t=="number"&&isFinite(t)?t:null}}).filter(n=>n.usd!==null);if(r.length===0)return;const c=r.reduce((n,a)=>n+a.usd,0);return r.map((n,a)=>({provider:n.model,cost:n.usd,percentage:c>0?n.usd/c*100:0,color:ae[a%ae.length]}))}function ps(s){const r=s.split(".")[0].toLowerCase();return["user","auth","login","logout"].includes(r)?"auth":["team","member","role","settings"].includes(r)?"admin":["deploy","build","session"].includes(r)?"deploy":["key","secret","api"].includes(r)?"api":r==="project"?"project":"system"}function js(s){return{id:s.id,timestamp:s.timestamp,user:s.user||"unknown",action:s.action,target:s.target||"",details:s.details||"",ip:"",category:ps(s.action)}}function _({label:s,value:r,note:c,icon:n,color:a}){return e.jsx("div",{className:"card p-4",children:e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-[#6B6960] uppercase tracking-wider",children:s}),e.jsx("p",{className:"text-2xl font-bold text-[#36342E] dark:text-[#E8E6E3] mt-1",children:r}),e.jsx("p",{className:"text-xs mt-1 text-[#939084]",children:c})]}),e.jsx("div",{className:"p-2 rounded-lg",style:{backgroundColor:`${a}10`,color:a},children:e.jsx(n,{size:20})})]})})}function gs({entries:s}){const r=n=>new Date(n).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}),c=(s||[]).slice().sort((n,a)=>n.timestamp<a.timestamp?1:-1).slice(0,20);return e.jsxs("div",{className:"card p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(J,{size:14,className:"text-[#553DE9]"}),e.jsx("h4",{className:"text-sm font-medium text-[#36342E] dark:text-[#E8E6E3]",children:"Recent Activity"})]}),e.jsx("p",{className:"text-[11px] text-[#939084] mb-3",children:"From this server's recent-activity log. It keeps the last 500 entries and is not tamper-evident."}),s===void 0&&e.jsx("p",{className:"text-sm text-[#939084]",children:"Loading..."}),s===null&&e.jsx("p",{className:"text-sm text-[#939084]",children:"Could not load the activity log. Nothing is shown rather than a guess."}),s&&c.length===0&&e.jsx("p",{className:"text-sm text-[#939084]",children:"No activity recorded yet."}),c.length>0&&e.jsx("div",{className:"space-y-1 max-h-[400px] overflow-y-auto terminal-scroll",children:c.map(n=>e.jsxs("div",{className:"flex items-center gap-3 px-2 py-1.5 rounded-lg hover:bg-[#F8F4F0] dark:hover:bg-[#222228] transition-colors",children:[e.jsx("span",{className:"text-[10px] font-mono text-[#939084] flex-shrink-0 w-24",children:r(n.timestamp)}),e.jsx("div",{className:"flex-1 min-w-0",children:e.jsxs("span",{className:"text-xs",children:[e.jsx("span",{className:"text-[#553DE9] font-medium",children:n.user||"unknown"}),e.jsxs("span",{className:"text-[#6B6960]",children:[" ",n.action," "]}),e.jsx("span",{className:"text-[#201515] dark:text-[#E8E6E3] font-medium",children:n.target})]})})]},n.id))})]})}function fs(){return e.jsxs("div",{className:"max-w-[500px] mx-auto px-6 py-20 text-center",children:[e.jsx(Ie,{size:48,className:"mx-auto text-[#C45B5B] mb-4"}),e.jsx("h1",{className:"font-heading text-h1 text-[#36342E] dark:text-[#E8E6E3] mb-2",children:"Access Denied"}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:"You do not have permission to access the admin dashboard. Contact your organization administrator for access."})]})}const Es=[{id:"overview",label:"Overview",icon:J},{id:"users",label:"Users",icon:I},{id:"analytics",label:"Analytics",icon:re},{id:"governance",label:"Governance",icon:he},{id:"audit",label:"Audit Trail",icon:z},{id:"compliance",label:"Compliance",icon:ne}];function Ms(){const{user:s,isLocalMode:r}=Se(),[c,n]=x.useState("overview"),[a,t]=x.useState({projects:void 0,teams:void 0,cost:void 0,audit:void 0}),j=r||(s==null?void 0:s.authenticated)===!0;x.useEffect(()=>{if(!j)return;let h=!1;return Promise.allSettled([U.getSessionsHistory(),U.getTeams(),U.getCost(),U.getAuditLog()]).then(([m,E,v,u])=>{if(h)return;const p=g=>g.status==="fulfilled"?g.value:null,k=p(E),i=p(m),N=p(u);t({projects:Array.isArray(i)?i.length:null,teams:Array.isArray(k)?{count:k.length,members:k.reduce((g,F)=>{var d;return g+(((d=F.members)==null?void 0:d.length)??0)},0)}:null,cost:p(v),audit:Array.isArray(N)?N:null})}),()=>{h=!0}},[j]);const o=x.useCallback(async()=>(await U.getAuditLog()).map(js),[]);if(!j)return e.jsx(fs,{});const b=us(a.cost);return e.jsxs("div",{className:"max-w-[1200px] mx-auto px-6 py-8",children:[e.jsx("div",{className:"flex items-center justify-between mb-6",children:e.jsx("h1",{className:"font-heading text-h1 text-[#36342E] dark:text-[#E8E6E3]",children:"Admin"})}),e.jsx("div",{className:"flex items-center gap-1 border-b border-[#ECEAE3] dark:border-[#2A2A30] mb-6 overflow-x-auto",children:Es.map(h=>e.jsxs("button",{onClick:()=>n(h.id),className:`flex items-center gap-1.5 px-3 py-2 text-xs font-medium border-b-2 transition-colors whitespace-nowrap ${c===h.id?"border-[#553DE9] text-[#553DE9]":"border-transparent text-[#939084] hover:text-[#36342E] dark:hover:text-[#E8E6E3]"}`,children:[e.jsx(h.icon,{size:14}),h.label]},h.id))}),c==="overview"&&e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",children:[e.jsx(_,{label:"Projects",value:O(a.projects,String),note:"Recent project folders (history lists up to 20 per location)",icon:he,color:"#1FC5A8"}),e.jsx(_,{label:"Teams",value:O(a.teams,h=>String(h.count)),note:a.teams?`${a.teams.members} member${a.teams.members===1?"":"s"}`:"Team membership",icon:I,color:"#553DE9"}),e.jsx(_,{label:"Total cost",value:O(a.cost,h=>hs(h.estimated_cost_usd)),note:"Recorded for the current project",icon:Y,color:"#C45B5B"}),e.jsx(_,{label:"Audit events",value:O(a.audit,h=>String(h.length)),note:"Recent-activity log entries",icon:Re,color:"#F59E0B"})]}),e.jsx(gs,{entries:a.audit})]}),c==="users"&&e.jsx(ns,{}),c==="analytics"&&e.jsx(es,{data:b?{costBreakdown:b}:{}}),c==="governance"&&e.jsx(cs,{}),c==="audit"&&e.jsx(ts,{onFetch:o}),c==="compliance"&&e.jsx(ms,{})]})}export{Ms as default};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{c as l,j as s}from"./index-Cz7q1bvC.js";/**
|
|
2
|
+
* @license lucide-react v0.577.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const x=[["path",{d:"m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7",key:"132q7q"}],["rect",{x:"2",y:"4",width:"20",height:"16",rx:"2",key:"izxlao"}]],m=l("mail",x);/**
|
|
7
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const d=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]],p=l("user-plus",d),b={sm:{container:"w-6 h-6",text:"text-[10px]",dot:"w-2 h-2 -bottom-0.5 -right-0.5"},md:{container:"w-8 h-8",text:"text-xs",dot:"w-2.5 h-2.5 -bottom-0.5 -right-0.5"},lg:{container:"w-11 h-11",text:"text-sm",dot:"w-3 h-3 -bottom-0.5 -right-0.5"}},g={online:"bg-[#1FC5A8]",offline:"bg-[#939084]",away:"bg-[#E5A940]"};function u(e){let t=0;for(let n=0;n<e.length;n++)t=e.charCodeAt(n)+((t<<5)-t);return Math.abs(t)}const i=["bg-[#553DE9]","bg-[#D63384]","bg-[#1FC5A8]","bg-[#E5A940]","bg-[#3B82F6]","bg-[#8B5CF6]","bg-[#EC4899]","bg-[#06B6D4]"];function f(e){var n;const t=e.trim().split(/\s+/);return t.length>=2?(t[0][0]+t[t.length-1][0]).toUpperCase():(((n=t[0])==null?void 0:n[0])||"?").toUpperCase()}function A({name:e,image:t,size:n="md",status:r,className:a=""}){const o=b[n],c=i[u(e)%i.length],h=f(e);return s.jsxs("span",{className:`relative inline-flex flex-shrink-0 ${a}`,children:[t?s.jsx("img",{src:t,alt:e,className:`${o.container} rounded-full object-cover`}):s.jsx("span",{className:`${o.container} ${c} rounded-full inline-flex items-center justify-center text-white font-semibold ${o.text}`,title:e,children:h}),r&&s.jsx("span",{className:`absolute ${o.dot} ${g[r]} rounded-full border-2 border-white dark:border-[#1A1A1E]`,title:r})]})}export{A,m as M,p as U};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-Cz7q1bvC.js";import{C as r}from"./clock-C8p2e4NI.js";import{C as a}from"./circle-alert-CSB88nEs.js";import{C as l}from"./check-C_9Nx7kb.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
|