loopat 0.1.14 → 0.1.16
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/package.json +1 -1
- package/server/src/index.ts +43 -40
- package/server/src/loops.ts +44 -6
- package/server/src/workspace.ts +0 -157
- package/web/dist/assets/{CodeEditor-BVELa8v3.js → CodeEditor-DJwtgiEt.js} +1 -1
- package/web/dist/assets/{Editor-DAe5119W.js → Editor-D5SIZSfL.js} +1 -1
- package/web/dist/assets/{Markdown-YZ1MUKQv.js → Markdown-FW9p4n8V.js} +1 -1
- package/web/dist/assets/{MilkdownEditor-DfpB9w26.js → MilkdownEditor-DI84bRst.js} +1 -1
- package/web/dist/assets/{Terminal-DJKsrLxO.js → Terminal-M6gPrnuw.js} +1 -1
- package/web/dist/assets/index-DYV--2-0.css +1 -0
- package/web/dist/assets/{index-C9m1r5nZ.js → index-pXRgSPlJ.js} +63 -64
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-WGzQgZlS.css +0 -1
package/package.json
CHANGED
package/server/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { createBunWebSocket } from "hono/bun"
|
|
|
4
4
|
import { existsSync } from "node:fs"
|
|
5
5
|
import { execSync, execFile } from "node:child_process"
|
|
6
6
|
import { promisify } from "node:util"
|
|
7
|
-
import { listLoops, createLoop, getLoop, loopExists, patchLoopMeta, backfillAllMounts, ensureWorkspaceDirs, provisionUserPersonal, importPersonalFromRepo, setupPersonalViaProvider, listPersonalReposViaProvider, authenticateViaProvider, providerTokenHelp, isPersonalFresh, ensureUiNotesWorktree, syncUiNotes, ffUpdateUiNotes, notesBehind, inspectPersonalDirty, syncPersonalToRemote, deletePersonalVault, pullPersonalFromRemote, pushPersonalToRemote, ensureContextMounts, effectiveDriver, isDriver, distillLoop, inspectRepoSync, pullRepoFromRemote, pushRepoToRemote } from "./loops"
|
|
7
|
+
import { listLoops, createLoop, getLoop, loopExists, patchLoopMeta, backfillAllMounts, ensureWorkspaceDirs, provisionUserPersonal, importPersonalFromRepo, setupPersonalViaProvider, listPersonalReposViaProvider, authenticateViaProvider, providerTokenHelp, isPersonalFresh, ensureUiNotesWorktree, syncUiNotes, ffUpdateUiNotes, notesBehind, inspectPersonalDirty, syncPersonalToRemote, deletePersonalVault, pullPersonalFromRemote, pushPersonalToRemote, ensureContextMounts, effectiveDriver, isDriver, distillLoop, inspectRepoSync, pullRepoFromRemote, pushRepoToRemote, ensureUserContext, promoteKnowledgeConfig } from "./loops"
|
|
8
8
|
import { getEphemeralHostPort } from "./podman"
|
|
9
9
|
import { startMcpAuth, completeMcpAuth, probeOAuthSupport, evictOAuthProbe, parseBearerEnvName, type OAuthSupport } from "./mcp-oauth"
|
|
10
10
|
import { DEFAULT_VAULT, loadVaultEnvs } from "./vaults"
|
|
@@ -30,7 +30,7 @@ import { ensurePersonalKeypair, getPublicKey } from "./personal-keys"
|
|
|
30
30
|
// keep both callable without import-order-dependent shadowing.
|
|
31
31
|
import { getSession, destroySession as destroyLoopSession, restartSession, getActivitySnapshot } from "./session"
|
|
32
32
|
import { listDir, listDirRecursive, readWorkdirFile, writeWorkdirFile, deleteWorkdirFile, createWorkdirFolder } from "./files"
|
|
33
|
-
import { vaultList, vaultFlatList, vaultRead, vaultWrite, vaultCreateFile, vaultCreateFolder, vaultDelete, vaultBacklinks,
|
|
33
|
+
import { vaultList, vaultFlatList, vaultRead, vaultWrite, vaultCreateFile, vaultCreateFolder, vaultDelete, vaultBacklinks, listTopics, type VaultId } from "./workspace"
|
|
34
34
|
// sandboxes module removed — no /api/sandboxes/* routes in the profile model.
|
|
35
35
|
// Use /api/profiles + /api/personal/default-profiles instead.
|
|
36
36
|
import { attachTerm, detachTerm, writeTerm, resizeTerm, killTerm } from "./term"
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
personalReposDir,
|
|
56
56
|
loopsDir,
|
|
57
57
|
} from "./paths"
|
|
58
|
-
import { loadConfig, loadPersonalConfig, savePersonalConfig, saveWorkspaceConfig, loadTokenUsage, getActiveProvider, readPersonalDiskRaw, savePersonalDisk, describeApiKeyRef, writeVaultEnv, deleteVaultEnv, type ProviderConfig, type ModelEntry } from "./config"
|
|
58
|
+
import { loadConfig, loadPersonalConfig, savePersonalConfig, saveWorkspaceConfig, loadTokenUsage, getActiveProvider, readPersonalDiskRaw, savePersonalDisk, describeApiKeyRef, writeVaultEnv, deleteVaultEnv, loadKnowledgeConfig, saveKnowledgeConfig, type ProviderConfig, type ModelEntry } from "./config"
|
|
59
59
|
import { listBoards, createBoard, renameBoard, listKanbanColumns, addCard, toggleCard, deleteCard, moveCard, updateCardMeta, updateCardBlock, reorderCards, createColumn, deleteColumn, readKanbanConfig, saveColumnOrder, setColumnColor, renameColumn, assignDriverForCard, createLoopFromCard, linkLoopToCard, kanbanUserCtx } from "./kanban"
|
|
60
60
|
import { printBootstrapBanner } from "./bootstrap"
|
|
61
61
|
import { serveHostExec, hostExecSocketPath } from "./host-exec"
|
|
@@ -2259,43 +2259,33 @@ app.get("/api/workspace/backlinks", requireAuth, async (c) => {
|
|
|
2259
2259
|
return c.json({ backlinks: await vaultBacklinks(vault as VaultId, path, userId) })
|
|
2260
2260
|
})
|
|
2261
2261
|
|
|
2262
|
-
|
|
2263
|
-
|
|
2262
|
+
// Context repos roster — DECLARATIVE, lives in the per-user knowledge repo's
|
|
2263
|
+
// .loopat/config.json (notes remote + repos[]). Physical clones are still
|
|
2264
|
+
// on-demand at loop creation (ensureRepoCloned). GET returns the roster; PUT
|
|
2265
|
+
// rewrites it and promotes (commit + push) back to the knowledge repo.
|
|
2266
|
+
app.get("/api/context/repos", requireAuth, async (c) => {
|
|
2267
|
+
const u = c.get("userId") as string
|
|
2268
|
+
const kcfg = await loadKnowledgeConfig(u)
|
|
2269
|
+
return c.json({ notes: kcfg.notes ?? null, repos: kcfg.repos ?? [] })
|
|
2264
2270
|
})
|
|
2265
2271
|
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
app.post("/api/workspace/repos", requireAuth, async (c) => {
|
|
2272
|
+
app.put("/api/context/repos", requireAuth, async (c) => {
|
|
2273
|
+
const u = c.get("userId") as string
|
|
2269
2274
|
const body = await c.req.json().catch(() => ({}))
|
|
2270
|
-
const
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
const detail = await readRepoDetail(name)
|
|
2285
|
-
if (!detail) return c.json({ error: "not found" }, 404)
|
|
2286
|
-
// recent loops on this repo
|
|
2287
|
-
const loops = await listLoops()
|
|
2288
|
-
const recent = loops.filter((l) => (l as any).repo === name).slice(0, 8)
|
|
2289
|
-
return c.json({ ...detail, recentLoops: recent })
|
|
2290
|
-
})
|
|
2291
|
-
|
|
2292
|
-
// `git pull --ff-only` in the repo. Fast-forward only — diverged branches
|
|
2293
|
-
// surface as an error so the user resolves them in their own checkout.
|
|
2294
|
-
app.post("/api/workspace/repo/:name/pull", requireAuth, async (c) => {
|
|
2295
|
-
const name = c.req.param("name") ?? ""
|
|
2296
|
-
const r = await pullRepo(name)
|
|
2297
|
-
if (!r.ok) return c.json({ error: r.error }, 400)
|
|
2298
|
-
return c.json({ ok: true, output: r.output })
|
|
2275
|
+
const repos = Array.isArray(body.repos)
|
|
2276
|
+
? body.repos.filter((r: any) => r?.name && r?.git).map((r: any) => ({ name: String(r.name).trim(), git: String(r.git).trim() }))
|
|
2277
|
+
: []
|
|
2278
|
+
const notes = body?.notes?.git ? { git: String(body.notes.git).trim() } : undefined
|
|
2279
|
+
// Need the per-user knowledge repo present to write + promote. Best-effort
|
|
2280
|
+
// clone it first (from personal.knowledge).
|
|
2281
|
+
await ensureUserContext(u).catch(() => {})
|
|
2282
|
+
if (!existsSync(join(personalKnowledgeDir(u), ".git"))) {
|
|
2283
|
+
return c.json({ error: "knowledge repo not available — set personal.knowledge and make sure your key can clone it" }, 400)
|
|
2284
|
+
}
|
|
2285
|
+
await saveKnowledgeConfig(u, { notes, repos })
|
|
2286
|
+
const r = await promoteKnowledgeConfig(u)
|
|
2287
|
+
if (!r.ok) return c.json({ error: r.error, savedLocally: true }, 400)
|
|
2288
|
+
return c.json({ ok: true, notes: notes ?? null, repos })
|
|
2299
2289
|
})
|
|
2300
2290
|
|
|
2301
2291
|
// ── topics ──
|
|
@@ -3114,13 +3104,26 @@ app.get("*", async (c, next) => {
|
|
|
3114
3104
|
// Try to serve the exact file
|
|
3115
3105
|
const file = Bun.file(join(webDist, path === "/" ? "index.html" : path))
|
|
3116
3106
|
if (await file.exists()) {
|
|
3107
|
+
// Hashed build assets are content-addressed → cache hard. HTML must always
|
|
3108
|
+
// revalidate so a version swap (new chunk names) is picked up immediately.
|
|
3109
|
+
const isAsset = path.startsWith("/assets/")
|
|
3117
3110
|
return new Response(file, {
|
|
3118
|
-
headers: {
|
|
3111
|
+
headers: {
|
|
3112
|
+
"content-type": file.type,
|
|
3113
|
+
"cache-control": isAsset ? "public, max-age=31536000, immutable" : "no-cache",
|
|
3114
|
+
},
|
|
3119
3115
|
})
|
|
3120
3116
|
}
|
|
3121
|
-
//
|
|
3117
|
+
// A missing build asset (a stale chunk after a deploy, e.g. when a browser
|
|
3118
|
+
// still holds an old index.html) must 404 — NOT fall through to index.html,
|
|
3119
|
+
// or the browser loads HTML as a JS module and throws "Failed to fetch
|
|
3120
|
+
// dynamically imported module". Only extensionless paths are real SPA routes.
|
|
3121
|
+
if (path.startsWith("/assets/") || /\.[a-zA-Z0-9]+$/.test(path)) {
|
|
3122
|
+
return c.notFound()
|
|
3123
|
+
}
|
|
3124
|
+
// SPA fallback (real client-side routes) — always revalidate.
|
|
3122
3125
|
return new Response(Bun.file(indexHtml), {
|
|
3123
|
-
headers: { "content-type": "text/html" },
|
|
3126
|
+
headers: { "content-type": "text/html", "cache-control": "no-cache" },
|
|
3124
3127
|
})
|
|
3125
3128
|
})
|
|
3126
3129
|
|
package/server/src/loops.ts
CHANGED
|
@@ -88,6 +88,13 @@ export type LoopMeta = {
|
|
|
88
88
|
pendingDriverNote?: { from: string; to: string; at: string }
|
|
89
89
|
repo?: string
|
|
90
90
|
branch?: string
|
|
91
|
+
/**
|
|
92
|
+
* Context-setup problems captured at loop creation (e.g. the per-user
|
|
93
|
+
* knowledge/notes clone failed — bad/again-missing key, no access). Surfaced
|
|
94
|
+
* as a banner in the loop UI so the user isn't left with a silently-empty
|
|
95
|
+
* context. Empty/absent = context set up cleanly.
|
|
96
|
+
*/
|
|
97
|
+
contextWarnings?: string[]
|
|
91
98
|
config?: {
|
|
92
99
|
default_model?: string
|
|
93
100
|
default_model_source?: "personal" | "workspace"
|
|
@@ -336,7 +343,8 @@ async function ensureContextRepo(dir: string, name: string, url?: string): Promi
|
|
|
336
343
|
* interactive host-key prompt. Host-side git overrides that config via
|
|
337
344
|
* GIT_SSH_COMMAND (env beats config), so the sandbox path is never used here.
|
|
338
345
|
*/
|
|
339
|
-
export async function ensureUserContext(user: string, vault: string = "default"): Promise<
|
|
346
|
+
export async function ensureUserContext(user: string, vault: string = "default"): Promise<string[]> {
|
|
347
|
+
const errors: string[] = []
|
|
340
348
|
const cfg = await loadPersonalConfig(user, vault)
|
|
341
349
|
const sshEnv = { ...process.env, GIT_SSH_COMMAND: sshCommandForUser(user, vault) }
|
|
342
350
|
// Sandbox-side promote: core.sshCommand points at the vault key's SANDBOX path
|
|
@@ -350,7 +358,7 @@ export async function ensureUserContext(user: string, vault: string = "default")
|
|
|
350
358
|
// STRICT, per the context model: personal wins even when empty — an empty url
|
|
351
359
|
// means the dir is REMOVED so the loop sees nothing (no fallback to any
|
|
352
360
|
// workspace default). Returns whether the repo exists afterwards.
|
|
353
|
-
const ensurePerUserRepo = async (dir: string, url: string | undefined): Promise<boolean> => {
|
|
361
|
+
const ensurePerUserRepo = async (dir: string, url: string | undefined, label: string): Promise<boolean> => {
|
|
354
362
|
if (!url) {
|
|
355
363
|
try { await rm(dir, { recursive: true, force: true }) } catch {}
|
|
356
364
|
return false
|
|
@@ -365,7 +373,13 @@ export async function ensureUserContext(user: string, vault: string = "default")
|
|
|
365
373
|
await execFileP("git", ["clone", "--", url, dir], { env: sshEnv, timeout: 60_000 })
|
|
366
374
|
console.log(`[loopat] cloned per-user context ${url} → ${dir}`)
|
|
367
375
|
} catch (e: any) {
|
|
376
|
+
// Concise reason for the UI warning: prefer the meaningful failure line
|
|
377
|
+
// (e.g. "Permission denied (publickey)") over git's trailing boilerplate
|
|
378
|
+
// ("…and the repository exists."), which reads as a false all-clear.
|
|
379
|
+
const lines = (e?.stderr ?? e?.message ?? String(e)).toString().split("\n").map((s: string) => s.trim()).filter(Boolean)
|
|
380
|
+
const reason = lines.find((l: string) => /permission denied|fatal:|not found|could not read|access denied|authentication failed|host key/i.test(l)) ?? lines.pop() ?? "clone failed"
|
|
368
381
|
console.warn(`[loopat] per-user context clone failed (${url}): ${e?.stderr ?? e?.message ?? e}`)
|
|
382
|
+
errors.push(`${label}: couldn't clone ${url} — ${reason}`)
|
|
369
383
|
return false
|
|
370
384
|
}
|
|
371
385
|
}
|
|
@@ -377,10 +391,11 @@ export async function ensureUserContext(user: string, vault: string = "default")
|
|
|
377
391
|
// knowledge is the entry pointer (personal-declared url); clone it first, then
|
|
378
392
|
// read ITS .loopat/config.json for the notes remote + repo roster — notes and
|
|
379
393
|
// repos now live inside the per-user knowledge repo, not in personal config.
|
|
380
|
-
const hasKnowledge = await ensurePerUserRepo(personalKnowledgeDir(user), cfg.knowledge?.git)
|
|
394
|
+
const hasKnowledge = await ensurePerUserRepo(personalKnowledgeDir(user), cfg.knowledge?.git, "knowledge")
|
|
381
395
|
const kcfg = hasKnowledge ? await loadKnowledgeConfig(user) : { notes: undefined, repos: [] as RepoSpec[] }
|
|
382
|
-
await ensurePerUserRepo(personalNotesDir(user), kcfg.notes?.git)
|
|
396
|
+
await ensurePerUserRepo(personalNotesDir(user), kcfg.notes?.git, "notes")
|
|
383
397
|
await writeReposManifest(personalReposDir(user), kcfg.repos ?? [])
|
|
398
|
+
return errors
|
|
384
399
|
}
|
|
385
400
|
|
|
386
401
|
/**
|
|
@@ -1603,6 +1618,26 @@ export async function pushRepoToRemote(dir: string, user?: string): Promise<Repo
|
|
|
1603
1618
|
return { ok: true, message: `pushed to origin/${branch}` }
|
|
1604
1619
|
}
|
|
1605
1620
|
|
|
1621
|
+
/**
|
|
1622
|
+
* Promote a just-written knowledge `.loopat/config.json` (repos/notes roster)
|
|
1623
|
+
* back to the knowledge repo's origin: stage + commit + push with the vault key.
|
|
1624
|
+
* The config was written by saveKnowledgeConfig(user, …) into the per-user
|
|
1625
|
+
* knowledge clone. "nothing to commit" is success (idempotent save).
|
|
1626
|
+
*/
|
|
1627
|
+
export async function promoteKnowledgeConfig(user: string): Promise<RepoSyncResult> {
|
|
1628
|
+
const dir = personalKnowledgeDir(user)
|
|
1629
|
+
if (!existsSyncBase(join(dir, ".git"))) return { ok: false, error: "knowledge repo not cloned" }
|
|
1630
|
+
await execFileP("git", ["-C", dir, "add", ".loopat/config.json"]).catch(() => {})
|
|
1631
|
+
try {
|
|
1632
|
+
await execFileP("git", ["-C", dir, "-c", "user.email=loopat@local", "-c", "user.name=loopat",
|
|
1633
|
+
"commit", "-m", "chore(loopat): update .loopat/config.json (repos/notes roster)"])
|
|
1634
|
+
} catch (e: any) {
|
|
1635
|
+
if (/nothing to commit/i.test((e?.stdout ?? e?.stderr ?? "").toString())) return { ok: true, message: "no change" }
|
|
1636
|
+
return { ok: false, error: `commit failed: ${e?.stderr ?? e?.message ?? e}` }
|
|
1637
|
+
}
|
|
1638
|
+
return await pushRepoToRemote(dir, user)
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1606
1641
|
/**
|
|
1607
1642
|
* Wipe personal/<user>/ AND the saved git-crypt key. Deploy keypair stays
|
|
1608
1643
|
* (it's the SSH identity, reusable for the next import). Re-scaffolds an
|
|
@@ -1939,9 +1974,12 @@ export async function createLoop(opts: {
|
|
|
1939
1974
|
// Pull the per-user knowledge/notes FIRST: clones the user's knowledge repo
|
|
1940
1975
|
// (from personal.knowledge) and reads its .loopat/config.json for the notes
|
|
1941
1976
|
// remote + repo roster — which the workdir clone-on-demand below depends on.
|
|
1942
|
-
|
|
1943
|
-
|
|
1977
|
+
// Surface any clone failures (bad key / no access) as a loop banner so the
|
|
1978
|
+
// user isn't left with a silently-empty context.
|
|
1979
|
+
const ctxWarnings = await ensureUserContext(opts.createdBy, opts.vault ?? "default").catch(
|
|
1980
|
+
(e: any) => { console.warn(`[loopat] ensureUserContext(${opts.createdBy}): ${e?.message ?? e}`); return [`context init failed: ${e?.message ?? e}`] },
|
|
1944
1981
|
)
|
|
1982
|
+
if (ctxWarnings.length) meta.contextWarnings = ctxWarnings
|
|
1945
1983
|
|
|
1946
1984
|
// workdir = git worktree add (if repo selected) OR plain mkdir
|
|
1947
1985
|
if (opts.repo) {
|
package/server/src/workspace.ts
CHANGED
|
@@ -15,9 +15,6 @@ import {
|
|
|
15
15
|
personalReposDir,
|
|
16
16
|
personalDir,
|
|
17
17
|
uiNotesDir,
|
|
18
|
-
// workspace-level repos admin (addRepo/listRepos/...) — superseded by the
|
|
19
|
-
// per-user knowledge-config repo roster in batch4b; kept until then.
|
|
20
|
-
workspaceReposDir,
|
|
21
18
|
} from "./paths"
|
|
22
19
|
|
|
23
20
|
const execFileP = promisify(execFile)
|
|
@@ -247,12 +244,6 @@ export async function vaultDelete(vault: VaultId, relPath: string, user: string)
|
|
|
247
244
|
return { ok: true }
|
|
248
245
|
}
|
|
249
246
|
|
|
250
|
-
export type RepoEntry = {
|
|
251
|
-
name: string
|
|
252
|
-
path: string
|
|
253
|
-
remote?: string
|
|
254
|
-
}
|
|
255
|
-
|
|
256
247
|
export type Backlink = {
|
|
257
248
|
path: string // file path that links to the target
|
|
258
249
|
preview: string // first line of context around the link
|
|
@@ -354,151 +345,3 @@ export async function listTopics(loopTitles: { id: string; title: string }[]): P
|
|
|
354
345
|
})
|
|
355
346
|
}
|
|
356
347
|
|
|
357
|
-
export type RepoDetail = RepoEntry & {
|
|
358
|
-
branch?: string
|
|
359
|
-
status: "online" | "offline"
|
|
360
|
-
readme?: string
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
export async function readRepoDetail(name: string): Promise<RepoDetail | null> {
|
|
364
|
-
const path = join(workspaceReposDir(), name)
|
|
365
|
-
try {
|
|
366
|
-
const s = await stat(path)
|
|
367
|
-
if (!s.isDirectory()) return null
|
|
368
|
-
} catch {
|
|
369
|
-
return null
|
|
370
|
-
}
|
|
371
|
-
let remote: string | undefined
|
|
372
|
-
let branch: string | undefined
|
|
373
|
-
let online: "online" | "offline" = "online"
|
|
374
|
-
try {
|
|
375
|
-
const { stdout } = await execFileP("git", ["-C", path, "remote", "get-url", "origin"])
|
|
376
|
-
remote = stdout.trim()
|
|
377
|
-
} catch {
|
|
378
|
-
online = "offline"
|
|
379
|
-
}
|
|
380
|
-
try {
|
|
381
|
-
const { stdout } = await execFileP("git", ["-C", path, "symbolic-ref", "--short", "HEAD"])
|
|
382
|
-
branch = stdout.trim()
|
|
383
|
-
} catch {}
|
|
384
|
-
let readme: string | undefined
|
|
385
|
-
for (const candidate of ["README.md", "readme.md", "README", "Readme.md"]) {
|
|
386
|
-
try {
|
|
387
|
-
const buf = await readFile(join(path, candidate), "utf8")
|
|
388
|
-
readme = buf
|
|
389
|
-
break
|
|
390
|
-
} catch {}
|
|
391
|
-
}
|
|
392
|
-
return { name, path, remote, branch, status: online, readme }
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const REPO_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/
|
|
396
|
-
|
|
397
|
-
function isRepoUrl(source: string): boolean {
|
|
398
|
-
return /:\/\//.test(source) || /^git@/.test(source)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function expandHome(p: string): string {
|
|
402
|
-
if (p === "~") return homedir()
|
|
403
|
-
if (p.startsWith("~/")) return join(homedir(), p.slice(2))
|
|
404
|
-
return p
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
export function deriveRepoName(source: string): string {
|
|
408
|
-
let s = source.trim().replace(/[?#].*$/, "")
|
|
409
|
-
s = s.replace(/\/+$/, "").replace(/\.git$/i, "")
|
|
410
|
-
const m = s.match(/[/:]([^/:]+)$/)
|
|
411
|
-
return (m ? m[1] : s).trim()
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Register a repo under workspaceReposDir(). Source can be either:
|
|
416
|
-
* - a git URL (http/https/ssh/git@) → `git clone` into the target
|
|
417
|
-
* - a local filesystem path → symlink into the target
|
|
418
|
-
* Symlinks are preferred for local working trees so edits in the source
|
|
419
|
-
* tree show up in loops without re-cloning.
|
|
420
|
-
*/
|
|
421
|
-
export async function addRepo(opts: { name: string; source: string }): Promise<{ ok: boolean; name?: string; kind?: "clone" | "symlink"; error?: string }> {
|
|
422
|
-
const source = (opts.source || "").trim()
|
|
423
|
-
if (!source) return { ok: false, error: "source required" }
|
|
424
|
-
const name = (opts.name || "").trim()
|
|
425
|
-
if (!REPO_NAME_RE.test(name)) {
|
|
426
|
-
return { ok: false, error: "invalid name (letters/digits/_.-, max 64, must start with alnum)" }
|
|
427
|
-
}
|
|
428
|
-
const root = workspaceReposDir()
|
|
429
|
-
const target = join(root, name)
|
|
430
|
-
try {
|
|
431
|
-
await lstat(target)
|
|
432
|
-
return { ok: false, error: "already exists" }
|
|
433
|
-
} catch {}
|
|
434
|
-
await mkdir(root, { recursive: true })
|
|
435
|
-
if (isRepoUrl(source)) {
|
|
436
|
-
try {
|
|
437
|
-
await execFileP("git", ["clone", source, target], { timeout: 300_000 })
|
|
438
|
-
return { ok: true, name, kind: "clone" }
|
|
439
|
-
} catch (e: any) {
|
|
440
|
-
const msg = (e?.stderr || e?.stdout || e?.message || "clone failed").toString().trim()
|
|
441
|
-
return { ok: false, error: msg }
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const abs = resolvePath(expandHome(source))
|
|
445
|
-
try {
|
|
446
|
-
const s = await stat(abs)
|
|
447
|
-
if (!s.isDirectory()) return { ok: false, error: "source path is not a directory" }
|
|
448
|
-
} catch {
|
|
449
|
-
return { ok: false, error: "source path does not exist" }
|
|
450
|
-
}
|
|
451
|
-
try {
|
|
452
|
-
await symlink(abs, target)
|
|
453
|
-
return { ok: true, name, kind: "symlink" }
|
|
454
|
-
} catch (e: any) {
|
|
455
|
-
return { ok: false, error: e?.message ?? "symlink failed" }
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export async function pullRepo(name: string): Promise<{ ok: boolean; output?: string; error?: string }> {
|
|
460
|
-
const path = join(workspaceReposDir(), name)
|
|
461
|
-
try {
|
|
462
|
-
const s = await stat(path)
|
|
463
|
-
if (!s.isDirectory()) return { ok: false, error: "not found" }
|
|
464
|
-
} catch {
|
|
465
|
-
return { ok: false, error: "not found" }
|
|
466
|
-
}
|
|
467
|
-
if (!existsSync(join(path, ".git"))) return { ok: false, error: "not a git repo" }
|
|
468
|
-
try {
|
|
469
|
-
const { stdout, stderr } = await execFileP("git", ["-C", path, "pull", "--ff-only"], { timeout: 60_000 })
|
|
470
|
-
return { ok: true, output: `${stdout}${stderr}`.trim() }
|
|
471
|
-
} catch (e: any) {
|
|
472
|
-
const msg = (e?.stderr || e?.stdout || e?.message || "pull failed").toString().trim()
|
|
473
|
-
return { ok: false, error: msg }
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
export async function listRepos(): Promise<RepoEntry[]> {
|
|
478
|
-
const root = workspaceReposDir()
|
|
479
|
-
let names: string[] = []
|
|
480
|
-
try {
|
|
481
|
-
names = await readdir(root)
|
|
482
|
-
} catch {
|
|
483
|
-
return []
|
|
484
|
-
}
|
|
485
|
-
const out: RepoEntry[] = []
|
|
486
|
-
for (const name of names) {
|
|
487
|
-
const p = join(root, name)
|
|
488
|
-
let target = p
|
|
489
|
-
try {
|
|
490
|
-
const s = await stat(p)
|
|
491
|
-
if (!s.isDirectory()) continue
|
|
492
|
-
target = p
|
|
493
|
-
} catch {
|
|
494
|
-
continue
|
|
495
|
-
}
|
|
496
|
-
let remote: string | undefined
|
|
497
|
-
try {
|
|
498
|
-
const { stdout } = await execFileP("git", ["-C", target, "remote", "get-url", "origin"])
|
|
499
|
-
remote = stdout.trim()
|
|
500
|
-
} catch {}
|
|
501
|
-
out.push({ name, path: target, remote })
|
|
502
|
-
}
|
|
503
|
-
return out
|
|
504
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{C as e,x as t,y as n}from"./index-
|
|
1
|
+
import{C as e,x as t,y as n}from"./index-pXRgSPlJ.js";import{n as r,r as i,t as a}from"./w3c-keyname-BOAvb0qz.js";var o=e(t(),1),s=[],c=[];(()=>{let e=`lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o`.split(`,`).map(e=>e?parseInt(e,36):1);for(let t=0,n=0;t<e.length;t++)(t%2?c:s).push(n+=e[t])})();function l(e){if(e<768)return!1;for(let t=0,n=s.length;;){let r=t+n>>1;if(e<s[r])n=r;else if(e>=c[r])t=r+1;else return!0;if(t==n)return!1}}function u(e){return e>=127462&&e<=127487}var d=8205;function f(e,t,n=!0,r=!0){return(n?p:m)(e,t,r)}function p(e,t,n){if(t==e.length)return t;t&&g(e.charCodeAt(t))&&_(e.charCodeAt(t-1))&&t--;let r=h(e,t);for(t+=v(r);t<e.length;){let i=h(e,t);if(r==d||i==d||n&&l(i))t+=v(i),r=i;else if(u(i)){let n=0,r=t-2;for(;r>=0&&u(h(e,r));)n++,r-=2;if(n%2==0)break;t+=2}else break}return t}function m(e,t,n){for(;t>0;){let r=p(e,t-2,n);if(r<t)return r;t--}return 0}function h(e,t){let n=e.charCodeAt(t);if(!_(n)||t+1==e.length)return n;let r=e.charCodeAt(t+1);return g(r)?(n-55296<<10)+(r-56320)+65536:n}function g(e){return e>=56320&&e<57344}function _(e){return e>=55296&&e<56320}function v(e){return e<65536?1:2}var y=class e{lineAt(e){if(e<0||e>this.length)throw RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,t,n){[e,t]=w(this,e,t);let r=[];return this.decompose(0,e,r,2),n.length&&n.decompose(0,n.length,r,3),this.decompose(t,this.length,r,1),x.from(r,this.length-(t-e)+n.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,t=this.length){[e,t]=w(this,e,t);let n=[];return this.decompose(e,t,n,0),x.from(n,t-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let t=this.scanIdentical(e,1),n=this.length-this.scanIdentical(e,-1),r=new C(this),i=new C(e);for(let e=t,a=t;;){if(r.next(e),i.next(e),e=0,r.lineBreak!=i.lineBreak||r.done!=i.done||r.value!=i.value)return!1;if(a+=r.value.length,r.done||a>=n)return!0}}iter(e=1){return new C(this,e)}iterRange(e,t=this.length){return new ne(this,e,t)}iterLines(e,t){let n;if(e==null)n=this.iter();else{t??=this.lines+1;let r=this.line(e).from;n=this.iterRange(r,Math.max(r,t==this.lines+1?this.length:t<=1?0:this.line(t-1).to))}return new re(n)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(t){if(t.length==0)throw RangeError(`A document must have at least one line`);return t.length==1&&!t[0]?e.empty:t.length<=32?new b(t):x.from(b.split(t,[]))}},b=class e extends y{constructor(e,t=ee(e)){super(),this.text=e,this.length=t}get lines(){return this.text.length}get children(){return null}lineInner(e,t,n,r){for(let i=0;;i++){let a=this.text[i],o=r+a.length;if((t?n:o)>=e)return new ie(r,o,n,a);r=o+1,n++}}decompose(t,n,r,i){let a=t<=0&&n>=this.length?this:new e(S(this.text,t,n),Math.min(n,this.length)-Math.max(0,t));if(i&1){let t=r.pop(),n=te(a.text,t.text.slice(),0,a.length);if(n.length<=32)r.push(new e(n,t.length+a.length));else{let t=n.length>>1;r.push(new e(n.slice(0,t)),new e(n.slice(t)))}}else r.push(a)}replace(t,n,r){if(!(r instanceof e))return super.replace(t,n,r);[t,n]=w(this,t,n);let i=te(this.text,te(r.text,S(this.text,0,t)),n),a=this.length+r.length-(n-t);return i.length<=32?new e(i,a):x.from(e.split(i,[]),a)}sliceString(e,t=this.length,n=`
|
|
2
2
|
`){[e,t]=w(this,e,t);let r=``;for(let i=0,a=0;i<=t&&a<this.text.length;a++){let o=this.text[a],s=i+o.length;i>e&&a&&(r+=n),e<s&&t>i&&(r+=o.slice(Math.max(0,e-i),t-i)),i=s+1}return r}flatten(e){for(let t of this.text)e.push(t)}scanIdentical(){return 0}static split(t,n){let r=[],i=-1;for(let a of t)r.push(a),i+=a.length+1,r.length==32&&(n.push(new e(r,i)),r=[],i=-1);return i>-1&&n.push(new e(r,i)),n}},x=class e extends y{constructor(e,t){super(),this.children=e,this.length=t,this.lines=0;for(let t of e)this.lines+=t.lines}lineInner(e,t,n,r){for(let i=0;;i++){let a=this.children[i],o=r+a.length,s=n+a.lines-1;if((t?s:o)>=e)return a.lineInner(e,t,n,r);r=o+1,n=s+1}}decompose(e,t,n,r){for(let i=0,a=0;a<=t&&i<this.children.length;i++){let o=this.children[i],s=a+o.length;if(e<=s&&t>=a){let i=r&(a<=e|(s>=t?2:0));a>=e&&s<=t&&!i?n.push(o):o.decompose(e-a,t-a,n,i)}a=s+1}}replace(t,n,r){if([t,n]=w(this,t,n),r.lines<this.lines)for(let i=0,a=0;i<this.children.length;i++){let o=this.children[i],s=a+o.length;if(t>=a&&n<=s){let c=o.replace(t-a,n-a,r),l=this.lines-o.lines+c.lines;if(c.lines<l>>4&&c.lines>l>>6){let a=this.children.slice();return a[i]=c,new e(a,this.length-(n-t)+r.length)}return super.replace(a,s,c)}a=s+1}return super.replace(t,n,r)}sliceString(e,t=this.length,n=`
|
|
3
3
|
`){[e,t]=w(this,e,t);let r=``;for(let i=0,a=0;i<this.children.length&&a<=t;i++){let o=this.children[i],s=a+o.length;a>e&&i&&(r+=n),e<s&&t>a&&(r+=o.sliceString(e-a,t-a,n)),a=s+1}return r}flatten(e){for(let t of this.children)t.flatten(e)}scanIdentical(t,n){if(!(t instanceof e))return 0;let r=0,[i,a,o,s]=n>0?[0,0,this.children.length,t.children.length]:[this.children.length-1,t.children.length-1,-1,-1];for(;;i+=n,a+=n){if(i==o||a==s)return r;let e=this.children[i],c=t.children[a];if(e!=c)return r+e.scanIdentical(c,n);r+=e.length+1}}static from(t,n=t.reduce((e,t)=>e+t.length+1,-1)){let r=0;for(let e of t)r+=e.lines;if(r<32){let e=[];for(let n of t)n.flatten(e);return new b(e,n)}let i=Math.max(32,r>>5),a=i<<1,o=i>>1,s=[],c=0,l=-1,u=[];function d(t){let n;if(t.lines>a&&t instanceof e)for(let e of t.children)d(e);else t.lines>o&&(c>o||!c)?(f(),s.push(t)):t instanceof b&&c&&(n=u[u.length-1])instanceof b&&t.lines+n.lines<=32?(c+=t.lines,l+=t.length+1,u[u.length-1]=new b(n.text.concat(t.text),n.length+1+t.length)):(c+t.lines>i&&f(),c+=t.lines,l+=t.length+1,u.push(t))}function f(){c!=0&&(s.push(u.length==1?u[0]:e.from(u,l)),l=-1,c=u.length=0)}for(let e of t)d(e);return f(),s.length==1?s[0]:new e(s,n)}};y.empty=new b([``],0);function ee(e){let t=-1;for(let n of e)t+=n.length+1;return t}function te(e,t,n=0,r=1e9){for(let i=0,a=0,o=!0;a<e.length&&i<=r;a++){let s=e[a],c=i+s.length;c>=n&&(c>r&&(s=s.slice(0,r-i)),i<n&&(s=s.slice(n-i)),o?(t[t.length-1]+=s,o=!1):t.push(s)),i=c+1}return t}function S(e,t,n){return te(e,[``],t,n)}var C=class{constructor(e,t=1){this.dir=t,this.done=!1,this.lineBreak=!1,this.value=``,this.nodes=[e],this.offsets=[t>0?1:(e instanceof b?e.text.length:e.children.length)<<1]}nextInner(e,t){for(this.done=this.lineBreak=!1;;){let n=this.nodes.length-1,r=this.nodes[n],i=this.offsets[n],a=i>>1,o=r instanceof b?r.text.length:r.children.length;if(a==(t>0?o:0)){if(n==0)return this.done=!0,this.value=``,this;t>0&&this.offsets[n-1]++,this.nodes.pop(),this.offsets.pop()}else if((i&1)==(t>0?0:1)){if(this.offsets[n]+=t,e==0)return this.lineBreak=!0,this.value=`
|
|
4
4
|
`,this;e--}else if(r instanceof b){let i=r.text[a+(t<0?-1:0)];if(this.offsets[n]+=t,i.length>Math.max(0,e))return this.value=e==0?i:t>0?i.slice(e):i.slice(0,i.length-e),this;e-=i.length}else{let i=r.children[a+(t<0?-1:0)];e>i.length?(e-=i.length,this.offsets[n]+=t):(t<0&&this.offsets[n]--,this.nodes.push(i),this.offsets.push(t>0?1:(i instanceof b?i.text.length:i.children.length)<<1))}}}next(e=0){return e<0&&(this.nextInner(-e,-this.dir),e=this.value.length),this.nextInner(e,this.dir)}},ne=class{constructor(e,t,n){this.value=``,this.done=!1,this.cursor=new C(e,t>n?-1:1),this.pos=t>n?e.length:0,this.from=Math.min(t,n),this.to=Math.max(t,n)}nextInner(e,t){if(t<0?this.pos<=this.from:this.pos>=this.to)return this.value=``,this.done=!0,this;e+=Math.max(0,t<0?this.pos-this.to:this.from-this.pos);let n=t<0?this.pos-this.from:this.to-this.pos;e>n&&(e=n),n-=e;let{value:r}=this.cursor.next(e);return this.pos+=(r.length+e)*t,this.value=r.length<=n?r:t<0?r.slice(r.length-n):r.slice(0,n),this.done=!this.value,this}next(e=0){return e<0?e=Math.max(e,this.from-this.pos):e>0&&(e=Math.min(e,this.to-this.pos)),this.nextInner(e,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=``}},re=class{constructor(e){this.inner=e,this.afterBreak=!0,this.value=``,this.done=!1}next(e=0){let{done:t,lineBreak:n,value:r}=this.inner.next(e);return t&&this.afterBreak?(this.value=``,this.afterBreak=!1):t?(this.done=!0,this.value=``):n?this.afterBreak?this.value=``:(this.afterBreak=!0,this.next()):(this.value=r,this.afterBreak=!1),this}get lineBreak(){return!1}};typeof Symbol<`u`&&(y.prototype[Symbol.iterator]=function(){return this.iter()},C.prototype[Symbol.iterator]=ne.prototype[Symbol.iterator]=re.prototype[Symbol.iterator]=function(){return this});var ie=class{constructor(e,t,n,r){this.from=e,this.to=t,this.number=n,this.text=r}get length(){return this.to-this.from}};function w(e,t,n){return t=Math.max(0,Math.min(e.length,t)),[t,Math.max(t,Math.min(e.length,n))]}function T(e,t,n=!0,r=!0){return f(e,t,n,r)}function ae(e){return e>=56320&&e<57344}function oe(e){return e>=55296&&e<56320}function se(e,t){let n=e.charCodeAt(t);if(!oe(n)||t+1==e.length)return n;let r=e.charCodeAt(t+1);return ae(r)?(n-55296<<10)+(r-56320)+65536:n}function ce(e){return e<=65535?String.fromCharCode(e):(e-=65536,String.fromCharCode((e>>10)+55296,(e&1023)+56320))}function le(e){return e<65536?1:2}var ue=/\r\n?|\n/,de=(function(e){return e[e.Simple=0]=`Simple`,e[e.TrackDel=1]=`TrackDel`,e[e.TrackBefore=2]=`TrackBefore`,e[e.TrackAfter=3]=`TrackAfter`,e})(de||={}),fe=class e{constructor(e){this.sections=e}get length(){let e=0;for(let t=0;t<this.sections.length;t+=2)e+=this.sections[t];return e}get newLength(){let e=0;for(let t=0;t<this.sections.length;t+=2){let n=this.sections[t+1];e+=n<0?this.sections[t]:n}return e}get empty(){return this.sections.length==0||this.sections.length==2&&this.sections[1]<0}iterGaps(e){for(let t=0,n=0,r=0;t<this.sections.length;){let i=this.sections[t++],a=this.sections[t++];a<0?(e(n,r,i),r+=i):r+=a,n+=i}}iterChangedRanges(e,t=!1){ge(this,e,t)}get invertedDesc(){let t=[];for(let e=0;e<this.sections.length;){let n=this.sections[e++],r=this.sections[e++];r<0?t.push(n,r):t.push(r,n)}return new e(t)}composeDesc(e){return this.empty?e:e.empty?this:ve(this,e)}mapDesc(e,t=!1){return e.empty?this:_e(this,e,t)}mapPos(e,t=-1,n=de.Simple){let r=0,i=0;for(let a=0;a<this.sections.length;){let o=this.sections[a++],s=this.sections[a++],c=r+o;if(s<0){if(c>e)return i+(e-r);i+=o}else{if(n!=de.Simple&&c>=e&&(n==de.TrackDel&&r<e&&c>e||n==de.TrackBefore&&r<e||n==de.TrackAfter&&c>e))return null;if(c>e||c==e&&t<0&&!o)return e==r||t<0?i:i+s;i+=s}r=c}if(e>r)throw RangeError(`Position ${e} is out of range for changeset of length ${r}`);return i}touchesRange(e,t=e){for(let n=0,r=0;n<this.sections.length&&r<=t;){let i=this.sections[n++],a=this.sections[n++],o=r+i;if(a>=0&&r<=t&&o>=e)return r<e&&o>t?`cover`:!0;r=o}return!1}toString(){let e=``;for(let t=0;t<this.sections.length;){let n=this.sections[t++],r=this.sections[t++];e+=(e?` `:``)+n+(r>=0?`:`+r:``)}return e}toJSON(){return this.sections}static fromJSON(t){if(!Array.isArray(t)||t.length%2||t.some(e=>typeof e!=`number`))throw RangeError(`Invalid JSON representation of ChangeDesc`);return new e(t)}static create(t){return new e(t)}},pe=class e extends fe{constructor(e,t){super(e),this.inserted=t}apply(e){if(this.length!=e.length)throw RangeError(`Applying change set to a document with the wrong length`);return ge(this,(t,n,r,i,a)=>e=e.replace(r,r+(n-t),a),!1),e}mapDesc(e,t=!1){return _e(this,e,t,!0)}invert(t){let n=this.sections.slice(),r=[];for(let e=0,i=0;e<n.length;e+=2){let a=n[e],o=n[e+1];if(o>=0){n[e]=o,n[e+1]=a;let s=e>>1;for(;r.length<s;)r.push(y.empty);r.push(a?t.slice(i,i+a):y.empty)}i+=a}return new e(n,r)}compose(e){return this.empty?e:e.empty?this:ve(this,e,!0)}map(e,t=!1){return e.empty?this:_e(this,e,t,!0)}iterChanges(e,t=!1){ge(this,e,t)}get desc(){return fe.create(this.sections)}filter(t){let n=[],r=[],i=[],a=new ye(this);done:for(let e=0,o=0;;){let s=e==t.length?1e9:t[e++];for(;o<s||o==s&&a.len==0;){if(a.done)break done;let e=Math.min(a.len,s-o);me(i,e,-1);let t=a.ins==-1?-1:a.off==0?a.ins:0;me(n,e,t),t>0&&he(r,n,a.text),a.forward(e),o+=e}let c=t[e++];for(;o<c;){if(a.done)break done;let e=Math.min(a.len,c-o);me(n,e,-1),me(i,e,a.ins==-1?-1:a.off==0?a.ins:0),a.forward(e),o+=e}}return{changes:new e(n,r),filtered:fe.create(i)}}toJSON(){let e=[];for(let t=0;t<this.sections.length;t+=2){let n=this.sections[t],r=this.sections[t+1];r<0?e.push(n):r==0?e.push([n]):e.push([n].concat(this.inserted[t>>1].toJSON()))}return e}static of(t,n,r){let i=[],a=[],o=0,s=null;function c(t=!1){if(!t&&!i.length)return;o<n&&me(i,n-o,-1);let r=new e(i,a);s=s?s.compose(r.map(s)):r,i=[],a=[],o=0}function l(t){if(Array.isArray(t))for(let e of t)l(e);else if(t instanceof e){if(t.length!=n)throw RangeError(`Mismatched change set length (got ${t.length}, expected ${n})`);c(),s=s?s.compose(t.map(s)):t}else{let{from:e,to:s=e,insert:l}=t;if(e>s||e<0||s>n)throw RangeError(`Invalid change range ${e} to ${s} (in doc of length ${n})`);let u=l?typeof l==`string`?y.of(l.split(r||ue)):l:y.empty,d=u.length;if(e==s&&d==0)return;e<o&&c(),e>o&&me(i,e-o,-1),me(i,s-e,d),he(a,i,u),o=s}}return l(t),c(!s),s}static empty(t){return new e(t?[t,-1]:[],[])}static fromJSON(t){if(!Array.isArray(t))throw RangeError(`Invalid JSON representation of ChangeSet`);let n=[],r=[];for(let e=0;e<t.length;e++){let i=t[e];if(typeof i==`number`)n.push(i,-1);else if(!Array.isArray(i)||typeof i[0]!=`number`||i.some((e,t)=>t&&typeof e!=`string`))throw RangeError(`Invalid JSON representation of ChangeSet`);else if(i.length==1)n.push(i[0],0);else{for(;r.length<e;)r.push(y.empty);r[e]=y.of(i.slice(1)),n.push(i[0],r[e].length)}}return new e(n,r)}static createSet(t,n){return new e(t,n)}};function me(e,t,n,r=!1){if(t==0&&n<=0)return;let i=e.length-2;i>=0&&n<=0&&n==e[i+1]?e[i]+=t:i>=0&&t==0&&e[i]==0?e[i+1]+=n:r?(e[i]+=t,e[i+1]+=n):e.push(t,n)}function he(e,t,n){if(n.length==0)return;let r=t.length-2>>1;if(r<e.length)e[e.length-1]=e[e.length-1].append(n);else{for(;e.length<r;)e.push(y.empty);e.push(n)}}function ge(e,t,n){let r=e.inserted;for(let i=0,a=0,o=0;o<e.sections.length;){let s=e.sections[o++],c=e.sections[o++];if(c<0)i+=s,a+=s;else{let l=i,u=a,d=y.empty;for(;l+=s,u+=c,c&&r&&(d=d.append(r[o-2>>1])),!(n||o==e.sections.length||e.sections[o+1]<0);)s=e.sections[o++],c=e.sections[o++];t(i,l,a,u,d),i=l,a=u}}}function _e(e,t,n,r=!1){let i=[],a=r?[]:null,o=new ye(e),s=new ye(t);for(let e=-1;;)if(o.done&&s.len||s.done&&o.len)throw Error(`Mismatched change set lengths`);else if(o.ins==-1&&s.ins==-1){let e=Math.min(o.len,s.len);me(i,e,-1),o.forward(e),s.forward(e)}else if(s.ins>=0&&(o.ins<0||e==o.i||o.off==0&&(s.len<o.len||s.len==o.len&&!n))){let t=s.len;for(me(i,s.ins,-1);t;){let n=Math.min(o.len,t);o.ins>=0&&e<o.i&&o.len<=n&&(me(i,0,o.ins),a&&he(a,i,o.text),e=o.i),o.forward(n),t-=n}s.next()}else if(o.ins>=0){let t=0,n=o.len;for(;n;)if(s.ins==-1){let e=Math.min(n,s.len);t+=e,n-=e,s.forward(e)}else if(s.ins==0&&s.len<n)n-=s.len,s.next();else break;me(i,t,e<o.i?o.ins:0),a&&e<o.i&&he(a,i,o.text),e=o.i,o.forward(o.len-n)}else if(o.done&&s.done)return a?pe.createSet(i,a):fe.create(i);else throw Error(`Mismatched change set lengths`)}function ve(e,t,n=!1){let r=[],i=n?[]:null,a=new ye(e),o=new ye(t);for(let e=!1;;)if(a.done&&o.done)return i?pe.createSet(r,i):fe.create(r);else if(a.ins==0)me(r,a.len,0,e),a.next();else if(o.len==0&&!o.done)me(r,0,o.ins,e),i&&he(i,r,o.text),o.next();else if(a.done||o.done)throw Error(`Mismatched change set lengths`);else{let t=Math.min(a.len2,o.len),n=r.length;if(a.ins==-1){let n=o.ins==-1?-1:o.off?0:o.ins;me(r,t,n,e),i&&n&&he(i,r,o.text)}else o.ins==-1?(me(r,a.off?0:a.len,t,e),i&&he(i,r,a.textBit(t))):(me(r,a.off?0:a.len,o.off?0:o.ins,e),i&&!o.off&&he(i,r,o.text));e=(a.ins>t||o.ins>=0&&o.len>t)&&(e||r.length>n),a.forward2(t),o.forward(t)}}var ye=class{constructor(e){this.set=e,this.i=0,this.next()}next(){let{sections:e}=this.set;this.i<e.length?(this.len=e[this.i++],this.ins=e[this.i++]):(this.len=0,this.ins=-2),this.off=0}get done(){return this.ins==-2}get len2(){return this.ins<0?this.len:this.ins}get text(){let{inserted:e}=this.set,t=this.i-2>>1;return t>=e.length?y.empty:e[t]}textBit(e){let{inserted:t}=this.set,n=this.i-2>>1;return n>=t.length&&!e?y.empty:t[n].slice(this.off,e==null?void 0:this.off+e)}forward(e){e==this.len?this.next():(this.len-=e,this.off+=e)}forward2(e){this.ins==-1?this.forward(e):e==this.ins?this.next():(this.ins-=e,this.off+=e)}},be=class e{constructor(e,t,n){this.from=e,this.to=t,this.flags=n}get anchor(){return this.flags&32?this.to:this.from}get head(){return this.flags&32?this.from:this.to}get empty(){return this.from==this.to}get assoc(){return this.flags&8?-1:this.flags&16?1:0}get bidiLevel(){let e=this.flags&7;return e==7?null:e}get goalColumn(){let e=this.flags>>6;return e==16777215?void 0:e}map(t,n=-1){let r,i;return this.empty?r=i=t.mapPos(this.from,n):(r=t.mapPos(this.from,1),i=t.mapPos(this.to,-1)),r==this.from&&i==this.to?this:new e(r,i,this.flags)}extend(e,t=e,n=0){if(e<=this.anchor&&t>=this.anchor)return E.range(e,t,void 0,void 0,n);let r=Math.abs(e-this.anchor)>Math.abs(t-this.anchor)?e:t;return E.range(this.anchor,r,void 0,void 0,n)}eq(e,t=!1){return this.anchor==e.anchor&&this.head==e.head&&this.goalColumn==e.goalColumn&&(!t||!this.empty||this.assoc==e.assoc)}toJSON(){return{anchor:this.anchor,head:this.head}}static fromJSON(e){if(!e||typeof e.anchor!=`number`||typeof e.head!=`number`)throw RangeError(`Invalid JSON representation for SelectionRange`);return E.range(e.anchor,e.head)}static create(t,n,r){return new e(t,n,r)}},E=class e{constructor(e,t){this.ranges=e,this.mainIndex=t}map(t,n=-1){return t.empty?this:e.create(this.ranges.map(e=>e.map(t,n)),this.mainIndex)}eq(e,t=!1){if(this.ranges.length!=e.ranges.length||this.mainIndex!=e.mainIndex)return!1;for(let n=0;n<this.ranges.length;n++)if(!this.ranges[n].eq(e.ranges[n],t))return!1;return!0}get main(){return this.ranges[this.mainIndex]}asSingle(){return this.ranges.length==1?this:new e([this.main],0)}addRange(t,n=!0){return e.create([t].concat(this.ranges),n?0:this.mainIndex+1)}replaceRange(t,n=this.mainIndex){let r=this.ranges.slice();return r[n]=t,e.create(r,this.mainIndex)}toJSON(){return{ranges:this.ranges.map(e=>e.toJSON()),main:this.mainIndex}}static fromJSON(t){if(!t||!Array.isArray(t.ranges)||typeof t.main!=`number`||t.main>=t.ranges.length)throw RangeError(`Invalid JSON representation for EditorSelection`);return new e(t.ranges.map(e=>be.fromJSON(e)),t.main)}static single(t,n=t){return new e([e.range(t,n)],0)}static create(t,n=0){if(t.length==0)throw RangeError(`A selection needs at least one range`);for(let r=0,i=0;i<t.length;i++){let a=t[i];if(a.empty?a.from<=r:a.from<r)return e.normalized(t.slice(),n);r=a.to}return new e(t,n)}static cursor(e,t=0,n,r){return be.create(e,e,(t==0?0:t<0?8:16)|(n==null?7:Math.min(6,n))|(r??16777215)<<6)}static range(e,t,n,r,i){let a=(n??16777215)<<6|(r==null?7:Math.min(6,r));return!i&&e!=t&&(i=t<e?1:-1),t<e?be.create(t,e,48|a):be.create(e,t,(i?i<0?8:16:0)|a)}static normalized(t,n=0){let r=t[n];t.sort((e,t)=>e.from-t.from),n=t.indexOf(r);for(let r=1;r<t.length;r++){let i=t[r],a=t[r-1];if(i.empty?i.from<=a.to:i.from<a.to){let o=a.from,s=Math.max(i.to,a.to);r<=n&&n--,t.splice(--r,2,i.anchor>i.head?e.range(s,o):e.range(o,s))}}return new e(t,n)}};function xe(e,t){for(let n of e.ranges)if(n.to>t)throw RangeError(`Selection points outside of document`)}var Se=0,D=class e{constructor(e,t,n,r,i){this.combine=e,this.compareInput=t,this.compare=n,this.isStatic=r,this.id=Se++,this.default=e([]),this.extensions=typeof i==`function`?i(this):i}get reader(){return this}static define(t={}){return new e(t.combine||(e=>e),t.compareInput||((e,t)=>e===t),t.compare||(t.combine?(e,t)=>e===t:Ce),!!t.static,t.enables)}of(e){return new we([],this,0,e)}compute(e,t){if(this.isStatic)throw Error(`Can't compute a static facet`);return new we(e,this,1,t)}computeN(e,t){if(this.isStatic)throw Error(`Can't compute a static facet`);return new we(e,this,2,t)}from(e,t){return t||=e=>e,this.compute([e],n=>t(n.field(e)))}};function Ce(e,t){return e==t||e.length==t.length&&e.every((e,n)=>e===t[n])}var we=class{constructor(e,t,n,r){this.dependencies=e,this.facet=t,this.type=n,this.value=r,this.id=Se++}dynamicSlot(e){let t=this.value,n=this.facet.compareInput,r=this.id,i=e[r]>>1,a=this.type==2,o=!1,s=!1,c=[];for(let t of this.dependencies)t==`doc`?o=!0:t==`selection`?s=!0:(e[t.id]??1)&1||c.push(e[t.id]);return{create(e){return e.values[i]=t(e),1},update(e,r){if(o&&r.docChanged||s&&(r.docChanged||r.selection)||Ee(e,c)){let r=t(e);if(a?!Te(r,e.values[i],n):!n(r,e.values[i]))return e.values[i]=r,1}return 0},reconfigure:(e,o)=>{let s,c=o.config.address[r];if(c!=null){let r=ze(o,c);if(this.dependencies.every(t=>t instanceof D?o.facet(t)===e.facet(t):t instanceof ke?o.field(t,!1)==e.field(t,!1):!0)||(a?Te(s=t(e),r,n):n(s=t(e),r)))return e.values[i]=r,0}else s=t(e);return e.values[i]=s,1}}}};function Te(e,t,n){if(e.length!=t.length)return!1;for(let r=0;r<e.length;r++)if(!n(e[r],t[r]))return!1;return!0}function Ee(e,t){let n=!1;for(let r of t)Re(e,r)&1&&(n=!0);return n}function De(e,t,n){let r=n.map(t=>e[t.id]),i=n.map(e=>e.type),a=r.filter(e=>!(e&1)),o=e[t.id]>>1;function s(e){let n=[];for(let t=0;t<r.length;t++){let a=ze(e,r[t]);if(i[t]==2)for(let e of a)n.push(e);else n.push(a)}return t.combine(n)}return{create(e){for(let t of r)Re(e,t);return e.values[o]=s(e),1},update(e,n){if(!Ee(e,a))return 0;let r=s(e);return t.compare(r,e.values[o])?0:(e.values[o]=r,1)},reconfigure(e,i){let a=Ee(e,r),c=i.config.facets[t.id],l=i.facet(t);if(c&&!a&&Ce(n,c))return e.values[o]=l,0;let u=s(e);return t.compare(u,l)?(e.values[o]=l,0):(e.values[o]=u,1)}}}var Oe=D.define({static:!0}),ke=class e{constructor(e,t,n,r,i){this.id=e,this.createF=t,this.updateF=n,this.compareF=r,this.spec=i,this.provides=void 0}static define(t){let n=new e(Se++,t.create,t.update,t.compare||((e,t)=>e===t),t);return t.provide&&(n.provides=t.provide(n)),n}create(e){return(e.facet(Oe).find(e=>e.field==this)?.create||this.createF)(e)}slot(e){let t=e[this.id]>>1;return{create:e=>(e.values[t]=this.create(e),1),update:(e,n)=>{let r=e.values[t],i=this.updateF(r,n);return this.compareF(r,i)?0:(e.values[t]=i,1)},reconfigure:(e,n)=>{let r=e.facet(Oe),i=n.facet(Oe),a;return(a=r.find(e=>e.field==this))&&a!=i.find(e=>e.field==this)?(e.values[t]=a.create(e),1):n.config.address[this.id]==null?(e.values[t]=this.create(e),1):(e.values[t]=n.field(this),0)}}}init(e){return[this,Oe.of({field:this,create:e})]}get extension(){return this}},Ae={lowest:4,low:3,default:2,high:1,highest:0};function je(e){return t=>new Ne(t,e)}var Me={highest:je(Ae.highest),high:je(Ae.high),default:je(Ae.default),low:je(Ae.low),lowest:je(Ae.lowest)},Ne=class{constructor(e,t){this.inner=e,this.prec=t}},Pe=class e{of(e){return new Fe(this,e)}reconfigure(t){return e.reconfigure.of({compartment:this,extension:t})}get(e){return e.config.compartments.get(this)}},Fe=class{constructor(e,t){this.compartment=e,this.inner=t}},Ie=class e{constructor(e,t,n,r,i,a){for(this.base=e,this.compartments=t,this.dynamicSlots=n,this.address=r,this.staticValues=i,this.facets=a,this.statusTemplate=[];this.statusTemplate.length<n.length;)this.statusTemplate.push(0)}staticFacet(e){let t=this.address[e.id];return t==null?e.default:this.staticValues[t>>1]}static resolve(t,n,r){let i=[],a=Object.create(null),o=new Map;for(let e of Le(t,n,o))e instanceof ke?i.push(e):(a[e.facet.id]||(a[e.facet.id]=[])).push(e);let s=Object.create(null),c=[],l=[];for(let e of i)s[e.id]=l.length<<1,l.push(t=>e.slot(t));let u=r?.config.facets;for(let e in a){let t=a[e],n=t[0].facet,i=u&&u[e]||[];if(t.every(e=>e.type==0))if(s[n.id]=c.length<<1|1,Ce(i,t))c.push(r.facet(n));else{let e=n.combine(t.map(e=>e.value));c.push(r&&n.compare(e,r.facet(n))?r.facet(n):e)}else{for(let e of t)e.type==0?(s[e.id]=c.length<<1|1,c.push(e.value)):(s[e.id]=l.length<<1,l.push(t=>e.dynamicSlot(t)));s[n.id]=l.length<<1,l.push(e=>De(e,n,t))}}return new e(t,o,l.map(e=>e(s)),s,c,a)}};function Le(e,t,n){let r=[[],[],[],[],[]],i=new Map;function a(e,o){let s=i.get(e);if(s!=null){if(s<=o)return;let t=r[s].indexOf(e);t>-1&&r[s].splice(t,1),e instanceof Fe&&n.delete(e.compartment)}if(i.set(e,o),Array.isArray(e))for(let t of e)a(t,o);else if(e instanceof Fe){if(n.has(e.compartment))throw RangeError(`Duplicate use of compartment in extensions`);let r=t.get(e.compartment)||e.inner;n.set(e.compartment,r),a(r,o)}else if(e instanceof Ne)a(e.inner,e.prec);else if(e instanceof ke)r[o].push(e),e.provides&&a(e.provides,o);else if(e instanceof we)r[o].push(e),e.facet.extensions&&a(e.facet.extensions,Ae.default);else{let t=e.extension;if(!t)throw Error(`Unrecognized extension value in extension set (${e}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);a(t,o)}}return a(e,Ae.default),r.reduce((e,t)=>e.concat(t))}function Re(e,t){if(t&1)return 2;let n=t>>1,r=e.status[n];if(r==4)throw Error(`Cyclic dependency between fields and/or facets`);if(r&2)return r;e.status[n]=4;let i=e.computeSlot(e,e.config.dynamicSlots[n]);return e.status[n]=2|i}function ze(e,t){return t&1?e.config.staticValues[t>>1]:e.values[t>>1]}var Be=D.define(),Ve=D.define({combine:e=>e.some(e=>e),static:!0}),He=D.define({combine:e=>e.length?e[0]:void 0,static:!0}),Ue=D.define(),We=D.define(),Ge=D.define(),Ke=D.define({combine:e=>e.length?e[0]:!1}),qe=class{constructor(e,t){this.type=e,this.value=t}static define(){return new Je}},Je=class{of(e){return new qe(this,e)}},Ye=class{constructor(e){this.map=e}of(e){return new O(this,e)}},O=class e{constructor(e,t){this.type=e,this.value=t}map(t){let n=this.type.map(this.value,t);return n===void 0?void 0:n==this.value?this:new e(this.type,n)}is(e){return this.type==e}static define(e={}){return new Ye(e.map||(e=>e))}static mapEffects(e,t){if(!e.length)return e;let n=[];for(let r of e){let e=r.map(t);e&&n.push(e)}return n}};O.reconfigure=O.define(),O.appendConfig=O.define();var Xe=class e{constructor(t,n,r,i,a,o){this.startState=t,this.changes=n,this.selection=r,this.effects=i,this.annotations=a,this.scrollIntoView=o,this._doc=null,this._state=null,r&&xe(r,n.newLength),a.some(t=>t.type==e.time)||(this.annotations=a.concat(e.time.of(Date.now())))}static create(t,n,r,i,a,o){return new e(t,n,r,i,a,o)}get newDoc(){return this._doc||=this.changes.apply(this.startState.doc)}get newSelection(){return this.selection||this.startState.selection.map(this.changes)}get state(){return this._state||this.startState.applyTransaction(this),this._state}annotation(e){for(let t of this.annotations)if(t.type==e)return t.value}get docChanged(){return!this.changes.empty}get reconfigured(){return this.startState.config!=this.state.config}isUserEvent(t){let n=this.annotation(e.userEvent);return!!(n&&(n==t||n.length>t.length&&n.slice(0,t.length)==t&&n[t.length]==`.`))}};Xe.time=qe.define(),Xe.userEvent=qe.define(),Xe.addToHistory=qe.define(),Xe.remote=qe.define();function Ze(e,t){let n=[];for(let r=0,i=0;;){let a,o;if(r<e.length&&(i==t.length||t[i]>=e[r]))a=e[r++],o=e[r++];else if(i<t.length)a=t[i++],o=t[i++];else return n;!n.length||n[n.length-1]<a?n.push(a,o):n[n.length-1]<o&&(n[n.length-1]=o)}}function Qe(e,t,n){let r,i,a;return n?(r=t.changes,i=pe.empty(t.changes.length),a=e.changes.compose(t.changes)):(r=t.changes.map(e.changes),i=e.changes.mapDesc(t.changes,!0),a=e.changes.compose(r)),{changes:a,selection:t.selection?t.selection.map(i):e.selection?.map(r),effects:O.mapEffects(e.effects,r).concat(O.mapEffects(t.effects,i)),annotations:e.annotations.length?e.annotations.concat(t.annotations):t.annotations,scrollIntoView:e.scrollIntoView||t.scrollIntoView}}function $e(e,t,n){let r=t.selection,i=it(t.annotations);return t.userEvent&&(i=i.concat(Xe.userEvent.of(t.userEvent))),{changes:t.changes instanceof pe?t.changes:pe.of(t.changes||[],n,e.facet(He)),selection:r&&(r instanceof E?r:E.single(r.anchor,r.head)),effects:it(t.effects),annotations:i,scrollIntoView:!!t.scrollIntoView}}function et(e,t,n){let r=$e(e,t.length?t[0]:{},e.doc.length);t.length&&t[0].filter===!1&&(n=!1);for(let i=1;i<t.length;i++){t[i].filter===!1&&(n=!1);let a=!!t[i].sequential;r=Qe(r,$e(e,t[i],a?r.changes.newLength:e.doc.length),a)}let i=Xe.create(e,r.changes,r.selection,r.effects,r.annotations,r.scrollIntoView);return nt(n?tt(i):i)}function tt(e){let t=e.startState,n=!0;for(let r of t.facet(Ue)){let t=r(e);if(t===!1){n=!1;break}Array.isArray(t)&&(n=n===!0?t:Ze(n,t))}if(n!==!0){let r,i;if(n===!1)i=e.changes.invertedDesc,r=pe.empty(t.doc.length);else{let t=e.changes.filter(n);r=t.changes,i=t.filtered.mapDesc(t.changes).invertedDesc}e=Xe.create(t,r,e.selection&&e.selection.map(i),O.mapEffects(e.effects,i),e.annotations,e.scrollIntoView)}let r=t.facet(We);for(let n=r.length-1;n>=0;n--){let i=r[n](e);e=i instanceof Xe?i:Array.isArray(i)&&i.length==1&&i[0]instanceof Xe?i[0]:et(t,it(i),!1)}return e}function nt(e){let t=e.startState,n=t.facet(Ge),r=e;for(let i=n.length-1;i>=0;i--){let a=n[i](e);a&&Object.keys(a).length&&(r=Qe(r,$e(t,a,e.changes.newLength),!0))}return r==e?e:Xe.create(t,e.changes,e.selection,r.effects,r.annotations,r.scrollIntoView)}var rt=[];function it(e){return e==null?rt:Array.isArray(e)?e:[e]}var k=(function(e){return e[e.Word=0]=`Word`,e[e.Space=1]=`Space`,e[e.Other=2]=`Other`,e})(k||={}),at=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,ot;try{ot=RegExp(`[\\p{Alphabetic}\\p{Number}_]`,`u`)}catch{}function st(e){if(ot)return ot.test(e);for(let t=0;t<e.length;t++){let n=e[t];if(/\w/.test(n)||n>``&&(n.toUpperCase()!=n.toLowerCase()||at.test(n)))return!0}return!1}function ct(e){return t=>{if(!/\S/.test(t))return k.Space;if(st(t))return k.Word;for(let n=0;n<e.length;n++)if(t.indexOf(e[n])>-1)return k.Word;return k.Other}}var A=class e{constructor(e,t,n,r,i,a){this.config=e,this.doc=t,this.selection=n,this.values=r,this.status=e.statusTemplate.slice(),this.computeSlot=i,a&&(a._state=this);for(let e=0;e<this.config.dynamicSlots.length;e++)Re(this,e<<1);this.computeSlot=null}field(e,t=!0){let n=this.config.address[e.id];if(n==null){if(t)throw RangeError(`Field is not present in this state`);return}return Re(this,n),ze(this,n)}update(...e){return et(this,e,!0)}applyTransaction(t){let n=this.config,{base:r,compartments:i}=n;for(let e of t.effects)e.is(Pe.reconfigure)?(n&&=(i=new Map,n.compartments.forEach((e,t)=>i.set(t,e)),null),i.set(e.value.compartment,e.value.extension)):e.is(O.reconfigure)?(n=null,r=e.value):e.is(O.appendConfig)&&(n=null,r=it(r).concat(e.value));let a;n?a=t.startState.values.slice():(n=Ie.resolve(r,i,this),a=new e(n,this.doc,this.selection,n.dynamicSlots.map(()=>null),(e,t)=>t.reconfigure(e,this),null).values);let o=t.startState.facet(Ve)?t.newSelection:t.newSelection.asSingle();new e(n,t.newDoc,o,a,(e,n)=>n.update(e,t),t)}replaceSelection(e){return typeof e==`string`&&(e=this.toText(e)),this.changeByRange(t=>({changes:{from:t.from,to:t.to,insert:e},range:E.cursor(t.from+e.length)}))}changeByRange(e){let t=this.selection,n=e(t.ranges[0]),r=this.changes(n.changes),i=[n.range],a=it(n.effects);for(let n=1;n<t.ranges.length;n++){let o=e(t.ranges[n]),s=this.changes(o.changes),c=s.map(r);for(let e=0;e<n;e++)i[e]=i[e].map(c);let l=r.mapDesc(s,!0);i.push(o.range.map(l)),r=r.compose(c),a=O.mapEffects(a,c).concat(O.mapEffects(it(o.effects),l))}return{changes:r,selection:E.create(i,t.mainIndex),effects:a}}changes(t=[]){return t instanceof pe?t:pe.of(t,this.doc.length,this.facet(e.lineSeparator))}toText(t){return y.of(t.split(this.facet(e.lineSeparator)||ue))}sliceDoc(e=0,t=this.doc.length){return this.doc.sliceString(e,t,this.lineBreak)}facet(e){let t=this.config.address[e.id];return t==null?e.default:(Re(this,t),ze(this,t))}toJSON(e){let t={doc:this.sliceDoc(),selection:this.selection.toJSON()};if(e)for(let n in e){let r=e[n];r instanceof ke&&this.config.address[r.id]!=null&&(t[n]=r.spec.toJSON(this.field(e[n]),this))}return t}static fromJSON(t,n={},r){if(!t||typeof t.doc!=`string`)throw RangeError(`Invalid JSON representation for EditorState`);let i=[];if(r){for(let e in r)if(Object.prototype.hasOwnProperty.call(t,e)){let n=r[e],a=t[e];i.push(n.init(e=>n.spec.fromJSON(a,e)))}}return e.create({doc:t.doc,selection:E.fromJSON(t.selection),extensions:n.extensions?i.concat([n.extensions]):i})}static create(t={}){let n=Ie.resolve(t.extensions||[],new Map),r=t.doc instanceof y?t.doc:y.of((t.doc||``).split(n.staticFacet(e.lineSeparator)||ue)),i=t.selection?t.selection instanceof E?t.selection:E.single(t.selection.anchor,t.selection.head):E.single(0);return xe(i,r.length),n.staticFacet(Ve)||(i=i.asSingle()),new e(n,r,i,n.dynamicSlots.map(()=>null),(e,t)=>t.create(e),null)}get tabSize(){return this.facet(e.tabSize)}get lineBreak(){return this.facet(e.lineSeparator)||`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{C as e,_ as t,b as n,v as r,x as i,y as a}from"./index-
|
|
1
|
+
import{C as e,_ as t,b as n,v as r,x as i,y as a}from"./index-pXRgSPlJ.js";import{CodeEditor as o}from"./CodeEditor-DJwtgiEt.js";var s=n(`text-wrap`,[[`path`,{d:`m16 16-3 3 3 3`,key:`117b85`}],[`path`,{d:`M3 12h14.5a1 1 0 0 1 0 7H13`,key:`18xa6z`}],[`path`,{d:`M3 19h6`,key:`1ygdsz`}],[`path`,{d:`M3 5h18`,key:`1u36vt`}]]),c=e(i(),1),l=a();function u(){try{if(localStorage.getItem(`loopat:editor:wordWrap`)===`0`)return!1}catch{}return!0}function d({loopId:e,path:n,onSelectionChange:i}){let[a,d]=(0,c.useState)(``),[f,p]=(0,c.useState)(``),[m,h]=(0,c.useState)(!1),[g,_]=(0,c.useState)(!1),[v,y]=(0,c.useState)(u);(0,c.useEffect)(()=>{if(!n){d(``),p(``);return}h(!0),t(e,n).then(e=>{let t=e?.content??``;d(t),p(t)}).finally(()=>h(!1))},[e,n]);let b=n&&f!==a,x=async()=>{if(!(!n||g)){_(!0);try{await r(e,n,f)&&d(f)}finally{_(!1)}}};return n?(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`flex-1 min-h-0 relative`,onKeyDown:e=>{(e.metaKey||e.ctrlKey)&&e.key===`s`&&(e.preventDefault(),x())},children:m?(0,l.jsx)(`div`,{className:`h-full w-full flex items-center justify-center text-[12px] text-gray-400`,children:`loading…`}):(0,l.jsx)(o,{path:n,value:f,onChange:p,wordWrap:v,onSelectionChange:i})}),(0,l.jsxs)(`div`,{className:`border-t border-gray-200 px-3 py-1.5 text-[11px] text-gray-500 flex items-center gap-3`,children:[(0,l.jsx)(`span`,{className:`truncate`,children:n}),b&&(0,l.jsx)(`button`,{onClick:x,className:`text-orange-600 hover:underline`,title:`ctrl/⌘+S`,children:g?`saving…`:`unsaved · save`}),(0,l.jsx)(`span`,{className:`flex-1`}),(0,l.jsx)(`button`,{onClick:()=>{let e=!v;y(e);try{localStorage.setItem(`loopat:editor:wordWrap`,e?`1`:`0`)}catch{}},className:`flex items-center gap-1 hover:text-gray-700 transition-colors ${v?`text-gray-500`:`text-gray-300`}`,title:v?`word wrap: on`:`word wrap: off`,children:(0,l.jsx)(s,{size:13})}),(0,l.jsx)(`span`,{children:`utf-8 · LF`})]})]}):(0,l.jsx)(`div`,{className:`flex-1 min-h-0 flex items-center justify-center text-[13px] text-gray-500 px-8 text-center`,children:`没打开文件 · 在 ▤ workdir 里点一个`})}export{d as Editor};
|