loopat 0.1.50 → 0.1.51
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/loops.ts +42 -12
- package/server/templates/CLAUDE.md +1 -0
- package/web/dist/assets/{CodeEditor-DtHZtsPs.js → CodeEditor-JV36Z3V5.js} +8 -8
- package/web/dist/assets/Editor-5Z34f3Gn.js +1 -0
- package/web/dist/assets/Markdown-DizYBjeA.js +5 -0
- package/web/dist/assets/{MilkdownEditor-D2-3eNpY.js → MilkdownEditor-t_CG4MJj.js} +9 -9
- package/web/dist/assets/{Terminal-trnCVajY.js → Terminal-Vi3Ufhgi.js} +2 -2
- package/web/dist/assets/index-DDLq89pd.js +145 -0
- package/web/dist/assets/{jsx-runtime-Bt-cYkS5.js → jsx-runtime-DAYmCNe8.js} +1 -1
- package/web/dist/assets/lib-B8L80SIn.js +18 -0
- package/web/dist/index.html +3 -2
- package/web/dist/assets/Editor-C7JCzVsf.js +0 -1
- package/web/dist/assets/Markdown-DPZuNxt-.js +0 -5
- package/web/dist/assets/index-CRS7bmLR.js +0 -162
- /package/web/dist/assets/{w3c-keyname-BOAvb0qz.js → w3c-keyname-DXh_HxYD.js} +0 -0
package/package.json
CHANGED
package/server/src/loops.ts
CHANGED
|
@@ -453,8 +453,23 @@ async function ensureRepoMirror(user: string, name: string, sshCommand?: string)
|
|
|
453
453
|
if (!spec?.git) return null
|
|
454
454
|
const dir = personalRepoCacheDir(user, name)
|
|
455
455
|
const env = sshCommand ? { ...process.env, GIT_SSH_COMMAND: sshCommand } : process.env
|
|
456
|
-
//
|
|
456
|
+
// Pin the STANDARD fetch refspec (default branch → refs/remotes/origin/<def>)
|
|
457
|
+
// so worktrees off this mirror get an ordinary `origin/<def>` tracking ref —
|
|
458
|
+
// `git rebase origin/<def>`, `git status` ahead/behind, `git log origin/<def>`
|
|
459
|
+
// all work as in any normal clone. Self-healing: re-assert it on EVERY ensure
|
|
460
|
+
// (incl. caches pinned by the old non-standard `+…:refs/heads/<def>` refspec),
|
|
461
|
+
// then fetch so the standard ref materializes.
|
|
462
|
+
const assertStandardRefspec = async () => {
|
|
463
|
+
const def = await execFileP("git", ["-C", dir, "symbolic-ref", "--short", "HEAD"])
|
|
464
|
+
.then((r) => r.stdout.trim()).catch(() => "")
|
|
465
|
+
if (def) {
|
|
466
|
+
await execFileP("git", ["-C", dir, "config", "remote.origin.fetch", `+refs/heads/${def}:refs/remotes/origin/${def}`]).catch(() => {})
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
// Already mirrored → re-assert the standard refspec, then fetch (incremental,
|
|
470
|
+
// fast). HEAD presence == bare repo.
|
|
457
471
|
if (existsSyncBase(join(dir, "HEAD"))) {
|
|
472
|
+
await assertStandardRefspec()
|
|
458
473
|
await execFileP("git", ["-C", dir, "fetch", "--quiet", "origin"], { env, timeout: 60_000 }).catch(() => {})
|
|
459
474
|
return dir
|
|
460
475
|
}
|
|
@@ -474,13 +489,13 @@ async function ensureRepoMirror(user: string, name: string, sshCommand?: string)
|
|
|
474
489
|
await execFileP("git", ["clone", "--bare", "--single-branch", "--", spec.git, dir], { env, timeout: 300_000 })
|
|
475
490
|
}
|
|
476
491
|
// A bare clone sets NO fetch refspec, so `git fetch origin` wouldn't advance
|
|
477
|
-
// any ref. Pin one for JUST the default branch
|
|
478
|
-
// refs/heads/<
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
492
|
+
// any ref. Pin the STANDARD one for JUST the default branch
|
|
493
|
+
// (+refs/heads/<def>:refs/remotes/origin/<def>) so worktrees off this mirror
|
|
494
|
+
// get an ordinary `origin/<def>` tracking ref — and the mirror stays small.
|
|
495
|
+
await assertStandardRefspec()
|
|
496
|
+
// Materialize refs/remotes/origin/<def> now (the clone only wrote
|
|
497
|
+
// refs/heads/<def>), so the very first worktree already tracks origin.
|
|
498
|
+
await execFileP("git", ["-C", dir, "fetch", "--quiet", "origin"], { env, timeout: 60_000 }).catch(() => {})
|
|
484
499
|
console.log(`[loopat] mirrored ${spec.git} → ${dir}`)
|
|
485
500
|
return dir
|
|
486
501
|
} catch (e: any) {
|
|
@@ -2059,6 +2074,14 @@ async function remoteDefaultBranch(dir: string): Promise<string> {
|
|
|
2059
2074
|
const m = stdout.match(/ref:\s+refs\/heads\/(\S+)\s+HEAD/)
|
|
2060
2075
|
if (m?.[1]) return m[1]
|
|
2061
2076
|
} catch {}
|
|
2077
|
+
// Bare mirrors don't carry a refs/remotes/origin/HEAD, but their own HEAD
|
|
2078
|
+
// symbolic-ref names the default branch the clone tracked — cheaper than (and
|
|
2079
|
+
// a fallback for) ls-remote, and correct for `ensureRepoMirror`'s mirrors.
|
|
2080
|
+
try {
|
|
2081
|
+
const { stdout } = await execFileP("git", ["-C", dir, "symbolic-ref", "--short", "HEAD"])
|
|
2082
|
+
const b = stdout.trim().replace(/^origin\//, "")
|
|
2083
|
+
if (b) return b
|
|
2084
|
+
} catch {}
|
|
2062
2085
|
return "main"
|
|
2063
2086
|
}
|
|
2064
2087
|
|
|
@@ -2206,10 +2229,17 @@ export async function createLoop(opts: {
|
|
|
2206
2229
|
const branch = `loop/${(await shortBranchSlug(meta.title))}-${id.slice(0, 6)}`
|
|
2207
2230
|
try {
|
|
2208
2231
|
// ① pull (docs/context-flow.md): ensureRepoMirror already fetched, so the
|
|
2209
|
-
// mirror's
|
|
2210
|
-
// the
|
|
2211
|
-
//
|
|
2212
|
-
|
|
2232
|
+
// mirror's `origin/<default>` tracking ref is the latest consensus. Open
|
|
2233
|
+
// the loop branch off `origin/<default>` (not the bare mirror's HEAD) so
|
|
2234
|
+
// the worktree is an ORDINARY clone: it has a real `origin/<default>`
|
|
2235
|
+
// tracking ref and `git rebase origin/<default>` / `git status`
|
|
2236
|
+
// ahead-behind work with nothing special to learn. Fall back to HEAD only
|
|
2237
|
+
// if origin/<default> can't be resolved (offline / empty remote).
|
|
2238
|
+
const start = await remoteStartPoint(repoPath, userSsh)
|
|
2239
|
+
const addArgs = start
|
|
2240
|
+
? ["-C", repoPath, "worktree", "add", "-b", branch, loopWorkdir(id), start]
|
|
2241
|
+
: ["-C", repoPath, "worktree", "add", "-b", branch, loopWorkdir(id)]
|
|
2242
|
+
await execFileP("git", addArgs)
|
|
2213
2243
|
meta.repo = opts.repo
|
|
2214
2244
|
meta.branch = branch
|
|
2215
2245
|
} catch (e: any) {
|
|
@@ -71,6 +71,7 @@ For team memory: when an insight is genuinely team-relevant (a convention everyo
|
|
|
71
71
|
- **Don't echo sensitive values** (API keys, tokens, SSH key material, anything that looks like a credential) to chat. Reference by filename or env var name instead.
|
|
72
72
|
- **Default to short, direct answers**. Don't announce a plan unless the task is genuinely large.
|
|
73
73
|
- **Read before Edit on long files**; avoid guessing surrounding context.
|
|
74
|
+
- **`origin` is the source of truth — finishing means pushing to origin.** The workdir is an ordinary git worktree with a normal `origin/<default>` tracking ref, so `git rebase origin/<default>`, `git status` ahead/behind, and `git log origin/<default>` all work as usual. A local commit is NOT "done": work is only preserved and shared once it reaches origin — open a PR, or push directly when that's the team's flow. Don't consider a task complete while it lives only in local commits.
|
|
74
75
|
|
|
75
76
|
## collaboration
|
|
76
77
|
|