runcastle 1.0.18 → 1.0.20
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/bin/runcastle.js +199 -41
- package/index.js +195 -37
- package/package.json +1 -1
- package/web/assets/index-BIDKY6fS.css +1 -0
- package/web/assets/{index-CgbdxRlZ.js → index-CnpBTT2-.js} +20 -20
- package/web/index.html +2 -2
- package/web/assets/index-jQSjMQ_c.css +0 -1
package/bin/runcastle.js
CHANGED
|
@@ -1516,6 +1516,9 @@ function markSessionLive(ctx, id, input = {}) {
|
|
|
1516
1516
|
function kickoffLineFor(kind, override) {
|
|
1517
1517
|
return override ?? KICKOFF_LINES[kind];
|
|
1518
1518
|
}
|
|
1519
|
+
function resumeKickoffLine(kind) {
|
|
1520
|
+
return RESUME_KICKOFF_PREFIX + KICKOFF_LINES[kind];
|
|
1521
|
+
}
|
|
1519
1522
|
function setKickoffOverride(sessionId, line) {
|
|
1520
1523
|
pendingKickoffOverrides.set(sessionId, line);
|
|
1521
1524
|
}
|
|
@@ -1564,15 +1567,15 @@ function markSessionEnded(ctx, id) {
|
|
|
1564
1567
|
ctx.db.update(sessions).set({ status: "ended" }).where(eq4(sessions.id, id)).run();
|
|
1565
1568
|
return getSessionRow(ctx, id);
|
|
1566
1569
|
}
|
|
1567
|
-
function mostRecentResumableSession(ctx, featureId) {
|
|
1568
|
-
const row = ctx.db.select().from(sessions).where(and4(eq4(sessions.featureId, featureId), eq4(sessions.status, "ended"), isNotNull(sessions.ccSessionId))).orderBy(desc2(sql2`rowid`)).limit(1).get();
|
|
1570
|
+
function mostRecentResumableSession(ctx, featureId, kind) {
|
|
1571
|
+
const row = ctx.db.select().from(sessions).where(and4(eq4(sessions.featureId, featureId), eq4(sessions.status, "ended"), isNotNull(sessions.ccSessionId), ...kind ? [eq4(sessions.kind, kind)] : [])).orderBy(desc2(sql2`rowid`)).limit(1).get();
|
|
1569
1572
|
return row ? rowToSession(row) : null;
|
|
1570
1573
|
}
|
|
1571
1574
|
function mostRecentLiveSession(ctx) {
|
|
1572
1575
|
const row = ctx.db.select().from(sessions).where(eq4(sessions.status, "live")).orderBy(desc2(sql2`rowid`)).limit(1).get();
|
|
1573
1576
|
return row ? rowToSession(row) : null;
|
|
1574
1577
|
}
|
|
1575
|
-
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, pendingKickoffOverrides;
|
|
1578
|
+
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, RESUME_KICKOFF_PREFIX, pendingKickoffOverrides;
|
|
1576
1579
|
var init_sessions = __esm(() => {
|
|
1577
1580
|
init_src();
|
|
1578
1581
|
init_schema();
|
|
@@ -1588,6 +1591,7 @@ var init_sessions = __esm(() => {
|
|
|
1588
1591
|
converge: CONVERGE_KICKOFF_LINE,
|
|
1589
1592
|
revisit: "Proceed with your task: invoke the /runcastle:revisit skill and work through what the " + "human brings up."
|
|
1590
1593
|
};
|
|
1594
|
+
RESUME_KICKOFF_PREFIX = "We are picking this conversation back up \u2014 runcastle restarted and closed the terminal, " + "but this conversation is intact. Do NOT start over: tell me in one or two lines where we " + "left off and what is next, then carry on. Your original instruction was: ";
|
|
1591
1595
|
pendingKickoffOverrides = new Map;
|
|
1592
1596
|
});
|
|
1593
1597
|
|
|
@@ -5124,8 +5128,6 @@ async function launchSession(ctx, input, opts = {}) {
|
|
|
5124
5128
|
kind: input.kind,
|
|
5125
5129
|
worktreePath
|
|
5126
5130
|
});
|
|
5127
|
-
if (input.kickoffLine)
|
|
5128
|
-
setKickoffOverride(session.id, input.kickoffLine);
|
|
5129
5131
|
let waypoint;
|
|
5130
5132
|
let resumeSessionId;
|
|
5131
5133
|
let resumeUnavailableFrom;
|
|
@@ -5158,11 +5160,24 @@ async function launchSession(ctx, input, opts = {}) {
|
|
|
5158
5160
|
resumeUnavailableFrom = "revisit";
|
|
5159
5161
|
}
|
|
5160
5162
|
}
|
|
5163
|
+
if (input.kind !== "waypoint" && input.kind !== "revisit") {
|
|
5164
|
+
resumeSessionId = mostRecentResumableSession(ctx, feature.id, input.kind)?.ccSessionId;
|
|
5165
|
+
}
|
|
5166
|
+
const kickoffLine = input.kickoffLine ?? (resumeSessionId ? resumeKickoffLine(input.kind) : undefined);
|
|
5167
|
+
if (kickoffLine)
|
|
5168
|
+
setKickoffOverride(session.id, kickoffLine);
|
|
5161
5169
|
emit(ctx, feature.id, {
|
|
5162
5170
|
type: "session.launching",
|
|
5163
5171
|
message: `launching ${input.kind} session`,
|
|
5164
5172
|
data: { sessionId: session.id, kind: input.kind, worktreePath, waypointId: waypoint?.id }
|
|
5165
5173
|
});
|
|
5174
|
+
if (resumeSessionId) {
|
|
5175
|
+
emit(ctx, feature.id, {
|
|
5176
|
+
type: "session.resumed",
|
|
5177
|
+
message: `resuming the previous ${input.kind} conversation`,
|
|
5178
|
+
data: { sessionId: session.id, kind: input.kind, resumeSessionId }
|
|
5179
|
+
});
|
|
5180
|
+
}
|
|
5166
5181
|
if (input.kind === "revisit" && resumeUnavailableFrom) {
|
|
5167
5182
|
emit(ctx, feature.id, {
|
|
5168
5183
|
type: "session.resume_unavailable",
|
|
@@ -5431,9 +5446,143 @@ var init_feature = __esm(() => {
|
|
|
5431
5446
|
});
|
|
5432
5447
|
});
|
|
5433
5448
|
|
|
5449
|
+
// src/services/fsbrowse.ts
|
|
5450
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
5451
|
+
import { homedir as homedir2 } from "os";
|
|
5452
|
+
import { basename, dirname as dirname6, isAbsolute, join as join14, resolve as resolve8, sep as sep3 } from "path";
|
|
5453
|
+
function expandPath(input, home = homedir2()) {
|
|
5454
|
+
const trimmed = input.trim();
|
|
5455
|
+
if (trimmed === "")
|
|
5456
|
+
return trimmed;
|
|
5457
|
+
let out = trimmed;
|
|
5458
|
+
if (out === "~")
|
|
5459
|
+
out = home;
|
|
5460
|
+
else if (out.startsWith("~/") || out.startsWith("~\\"))
|
|
5461
|
+
out = join14(home, out.slice(2));
|
|
5462
|
+
return resolve8(out);
|
|
5463
|
+
}
|
|
5464
|
+
function looksLikeRepo(dir) {
|
|
5465
|
+
try {
|
|
5466
|
+
return existsSync14(join14(dir, ".git"));
|
|
5467
|
+
} catch {
|
|
5468
|
+
return false;
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
function listRoots(home = homedir2()) {
|
|
5472
|
+
const roots = [];
|
|
5473
|
+
if (process.platform === "win32") {
|
|
5474
|
+
for (let code = 67;code <= 90; code++) {
|
|
5475
|
+
const drive = `${String.fromCharCode(code)}:${sep3}`;
|
|
5476
|
+
try {
|
|
5477
|
+
if (existsSync14(drive))
|
|
5478
|
+
roots.push({ label: drive.replace(/\\$/, ""), path: drive, kind: "drive" });
|
|
5479
|
+
} catch {}
|
|
5480
|
+
}
|
|
5481
|
+
} else {
|
|
5482
|
+
roots.push({ label: "/", path: "/", kind: "drive" });
|
|
5483
|
+
}
|
|
5484
|
+
if (existsSync14(home))
|
|
5485
|
+
roots.push({ label: "Home", path: home, kind: "home" });
|
|
5486
|
+
const seen = new Set(roots.map(pathKey));
|
|
5487
|
+
for (const name of COMMON_DIRS) {
|
|
5488
|
+
const candidate = join14(home, name);
|
|
5489
|
+
const key = pathKey({ path: candidate });
|
|
5490
|
+
if (seen.has(key) || !existsSync14(candidate))
|
|
5491
|
+
continue;
|
|
5492
|
+
seen.add(key);
|
|
5493
|
+
roots.push({ label: name, path: candidate, kind: "common" });
|
|
5494
|
+
}
|
|
5495
|
+
return roots;
|
|
5496
|
+
}
|
|
5497
|
+
function pathKey(r) {
|
|
5498
|
+
return process.platform === "win32" ? r.path.toLowerCase() : r.path;
|
|
5499
|
+
}
|
|
5500
|
+
function crumbsFor(dir) {
|
|
5501
|
+
const out = [];
|
|
5502
|
+
let cur = dir;
|
|
5503
|
+
for (;; ) {
|
|
5504
|
+
out.unshift({ name: basename(cur) || cur, path: cur });
|
|
5505
|
+
const parent = dirname6(cur);
|
|
5506
|
+
if (parent === cur)
|
|
5507
|
+
break;
|
|
5508
|
+
cur = parent;
|
|
5509
|
+
}
|
|
5510
|
+
return out;
|
|
5511
|
+
}
|
|
5512
|
+
function parentOf(dir) {
|
|
5513
|
+
const parent = dirname6(dir);
|
|
5514
|
+
return parent === dir ? null : parent;
|
|
5515
|
+
}
|
|
5516
|
+
function browseDir(input, showHidden = false, home = homedir2()) {
|
|
5517
|
+
const target = input && input.trim() !== "" ? expandPath(input, home) : home;
|
|
5518
|
+
if (!isAbsolute(target)) {
|
|
5519
|
+
throw new InvalidInputError(`path is not absolute: ${target}`);
|
|
5520
|
+
}
|
|
5521
|
+
if (!existsSync14(target)) {
|
|
5522
|
+
throw new InvalidInputError(`path does not exist: ${target}`);
|
|
5523
|
+
}
|
|
5524
|
+
let dir = target;
|
|
5525
|
+
try {
|
|
5526
|
+
if (!statSync2(target).isDirectory())
|
|
5527
|
+
dir = dirname6(target);
|
|
5528
|
+
} catch (e) {
|
|
5529
|
+
throw new InvalidInputError(`cannot read path: ${target} (${errMsg2(e)})`);
|
|
5530
|
+
}
|
|
5531
|
+
let dirents;
|
|
5532
|
+
try {
|
|
5533
|
+
dirents = readdirSync5(dir, { withFileTypes: true, encoding: "utf8" });
|
|
5534
|
+
} catch (e) {
|
|
5535
|
+
throw new InvalidInputError(`cannot read directory: ${dir} (${errMsg2(e)})`);
|
|
5536
|
+
}
|
|
5537
|
+
const entries = [];
|
|
5538
|
+
let truncated = false;
|
|
5539
|
+
for (const dirent of dirents) {
|
|
5540
|
+
if (entries.length >= MAX_ENTRIES) {
|
|
5541
|
+
truncated = true;
|
|
5542
|
+
break;
|
|
5543
|
+
}
|
|
5544
|
+
const name = dirent.name;
|
|
5545
|
+
if (SKIP_ALWAYS.has(name))
|
|
5546
|
+
continue;
|
|
5547
|
+
if (!showHidden && name.startsWith("."))
|
|
5548
|
+
continue;
|
|
5549
|
+
const path = join14(dir, name);
|
|
5550
|
+
const isSymlink = dirent.isSymbolicLink();
|
|
5551
|
+
let isDirectory = dirent.isDirectory();
|
|
5552
|
+
if (isSymlink) {
|
|
5553
|
+
try {
|
|
5554
|
+
isDirectory = statSync2(path).isDirectory();
|
|
5555
|
+
} catch {
|
|
5556
|
+
continue;
|
|
5557
|
+
}
|
|
5558
|
+
}
|
|
5559
|
+
if (!isDirectory)
|
|
5560
|
+
continue;
|
|
5561
|
+
entries.push({ name, path, isRepo: looksLikeRepo(path), isSymlink });
|
|
5562
|
+
}
|
|
5563
|
+
entries.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
|
|
5564
|
+
return {
|
|
5565
|
+
dir,
|
|
5566
|
+
parent: parentOf(dir),
|
|
5567
|
+
crumbs: crumbsFor(dir),
|
|
5568
|
+
entries,
|
|
5569
|
+
isRepo: looksLikeRepo(dir),
|
|
5570
|
+
truncated
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
function errMsg2(e) {
|
|
5574
|
+
return e instanceof Error ? e.message : String(e);
|
|
5575
|
+
}
|
|
5576
|
+
var SKIP_ALWAYS, MAX_ENTRIES = 1000, COMMON_DIRS;
|
|
5577
|
+
var init_fsbrowse = __esm(() => {
|
|
5578
|
+
init_errors();
|
|
5579
|
+
SKIP_ALWAYS = new Set(["node_modules", "$RECYCLE.BIN", "System Volume Information"]);
|
|
5580
|
+
COMMON_DIRS = ["Projects", "projects", "code", "Code", "src", "dev", "repos", "git"];
|
|
5581
|
+
});
|
|
5582
|
+
|
|
5434
5583
|
// src/services/projects.ts
|
|
5435
|
-
import { existsSync as
|
|
5436
|
-
import { basename, join as
|
|
5584
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5585
|
+
import { basename as basename2, join as join15 } from "path";
|
|
5437
5586
|
import { eq as eq9, isNull } from "drizzle-orm";
|
|
5438
5587
|
function listProjects(ctx) {
|
|
5439
5588
|
return ctx.db.select().from(projects).where(isNull(projects.closedAt)).all().map(rowToProject);
|
|
@@ -5449,14 +5598,15 @@ function warnIfTranslatedMount(ctx, projectId, repoPath) {
|
|
|
5449
5598
|
message: `${repoPath} is a Windows drive mounted into Linux (/mnt) \u2014 git and burns pay a per-file translation tax here; clone the repo into the Linux filesystem (e.g. ~/projects) for native speed`
|
|
5450
5599
|
});
|
|
5451
5600
|
}
|
|
5452
|
-
async function openProject(ctx,
|
|
5601
|
+
async function openProject(ctx, rawPath) {
|
|
5602
|
+
const repoPath = expandPath(rawPath);
|
|
5453
5603
|
await assertRepoTolerant(ctx, repoPath);
|
|
5454
5604
|
const mainBranch = await detectMainBranchTolerant(ctx, repoPath);
|
|
5455
|
-
const name =
|
|
5456
|
-
const existing = getProjectByRepoPath(ctx, repoPath);
|
|
5605
|
+
const name = basename2(repoPath) || repoPath;
|
|
5606
|
+
const existing = getProjectByRepoPath(ctx, repoPath) ?? findProjectByCanonPath(ctx, repoPath);
|
|
5457
5607
|
if (existing) {
|
|
5458
|
-
ctx.db.update(projects).set({ mainBranch, closedAt: null }).where(eq9(projects.id, existing.id)).run();
|
|
5459
|
-
const reopened = { ...existing, mainBranch };
|
|
5608
|
+
ctx.db.update(projects).set({ mainBranch, repoPath, closedAt: null }).where(eq9(projects.id, existing.id)).run();
|
|
5609
|
+
const reopened = { ...existing, mainBranch, repoPath };
|
|
5460
5610
|
emitProject(ctx, existing.id, {
|
|
5461
5611
|
type: "project.opened",
|
|
5462
5612
|
message: `project ${existing.name} re-opened at ${repoPath} (${mainBranch})`
|
|
@@ -5503,13 +5653,17 @@ function renameProject(ctx, projectId, name) {
|
|
|
5503
5653
|
});
|
|
5504
5654
|
return { ...project, name };
|
|
5505
5655
|
}
|
|
5656
|
+
function findProjectByCanonPath(ctx, repoPath) {
|
|
5657
|
+
const key = canon(repoPath);
|
|
5658
|
+
return allProjects(ctx).find((p) => canon(p.repoPath) === key) ?? null;
|
|
5659
|
+
}
|
|
5506
5660
|
async function assertRepoTolerant(ctx, repoPath) {
|
|
5507
5661
|
try {
|
|
5508
5662
|
await assertRepo(repoPath);
|
|
5509
5663
|
} catch (e) {
|
|
5510
5664
|
if (!isNotImplemented(e))
|
|
5511
5665
|
throw e;
|
|
5512
|
-
if (!
|
|
5666
|
+
if (!existsSync15(join15(repoPath, ".git"))) {
|
|
5513
5667
|
throw new InvalidInputError(`not a git repository: ${repoPath}`);
|
|
5514
5668
|
}
|
|
5515
5669
|
}
|
|
@@ -5528,6 +5682,7 @@ var init_projects = __esm(() => {
|
|
|
5528
5682
|
init_schema();
|
|
5529
5683
|
init_errors();
|
|
5530
5684
|
init_events();
|
|
5685
|
+
init_fsbrowse();
|
|
5531
5686
|
init_git();
|
|
5532
5687
|
init_repo();
|
|
5533
5688
|
});
|
|
@@ -5536,12 +5691,15 @@ var init_projects = __esm(() => {
|
|
|
5536
5691
|
import * as z7 from "zod";
|
|
5537
5692
|
var projectRouter;
|
|
5538
5693
|
var init_project = __esm(() => {
|
|
5694
|
+
init_fsbrowse();
|
|
5539
5695
|
init_git();
|
|
5540
5696
|
init_projects();
|
|
5541
5697
|
init_repo();
|
|
5542
5698
|
init_context();
|
|
5543
5699
|
projectRouter = router({
|
|
5544
5700
|
list: publicProcedure.query(({ ctx }) => listProjects(ctx)),
|
|
5701
|
+
roots: publicProcedure.query(() => listRoots()),
|
|
5702
|
+
browse: publicProcedure.input(z7.object({ dir: z7.string().optional(), showHidden: z7.boolean().optional() }).optional()).query(({ input }) => browseDir(input?.dir, input?.showHidden ?? false)),
|
|
5545
5703
|
branches: publicProcedure.input(z7.object({ projectId: z7.string() })).query(({ ctx, input }) => listBranches(requireProjectById(ctx, input.projectId))),
|
|
5546
5704
|
open: publicProcedure.input(z7.object({ repoPath: z7.string().min(1) })).mutation(({ ctx, input }) => openProject(ctx, input.repoPath)),
|
|
5547
5705
|
close: publicProcedure.input(z7.object({ projectId: z7.string() })).mutation(({ ctx, input }) => closeProject(ctx, input.projectId)),
|
|
@@ -5568,12 +5726,12 @@ var init_run = __esm(() => {
|
|
|
5568
5726
|
});
|
|
5569
5727
|
|
|
5570
5728
|
// src/services/settings.ts
|
|
5571
|
-
import { existsSync as
|
|
5572
|
-
import { dirname as
|
|
5729
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
5730
|
+
import { dirname as dirname7 } from "path";
|
|
5573
5731
|
import * as z9 from "zod";
|
|
5574
5732
|
import { eq as eq10 } from "drizzle-orm";
|
|
5575
5733
|
function readRawConfig(configFile) {
|
|
5576
|
-
if (!
|
|
5734
|
+
if (!existsSync16(configFile))
|
|
5577
5735
|
return {};
|
|
5578
5736
|
try {
|
|
5579
5737
|
const parsed = JSON.parse(readFileSync6(configFile, "utf8"));
|
|
@@ -5695,7 +5853,7 @@ function updateSettings(ctx, input, io = {}) {
|
|
|
5695
5853
|
function writeGlobal(configFile, configKey, value) {
|
|
5696
5854
|
const raw = readRawConfig(configFile);
|
|
5697
5855
|
raw[configKey] = value;
|
|
5698
|
-
mkdirSync7(
|
|
5856
|
+
mkdirSync7(dirname7(configFile), { recursive: true });
|
|
5699
5857
|
writeFileSync3(configFile, `${JSON.stringify(raw, null, 2)}
|
|
5700
5858
|
`);
|
|
5701
5859
|
}
|
|
@@ -5734,7 +5892,7 @@ function writeStepModel(configFile, step, value) {
|
|
|
5734
5892
|
else
|
|
5735
5893
|
stepModels[step] = value;
|
|
5736
5894
|
raw.stepModels = stepModels;
|
|
5737
|
-
mkdirSync7(
|
|
5895
|
+
mkdirSync7(dirname7(configFile), { recursive: true });
|
|
5738
5896
|
writeFileSync3(configFile, `${JSON.stringify(raw, null, 2)}
|
|
5739
5897
|
`);
|
|
5740
5898
|
}
|
|
@@ -6016,7 +6174,7 @@ var init_doctor = __esm(() => {
|
|
|
6016
6174
|
// src/doctor/system-exec.ts
|
|
6017
6175
|
import { spawn as spawn2 } from "child_process";
|
|
6018
6176
|
function createSystemExec(opts = {}) {
|
|
6019
|
-
return (command, args) => new Promise((
|
|
6177
|
+
return (command, args) => new Promise((resolve9) => {
|
|
6020
6178
|
const resolved = resolveExecutable(command);
|
|
6021
6179
|
const isShim = /\.(cmd|bat)$/i.test(resolved);
|
|
6022
6180
|
const file = isShim ? process.env.ComSpec ?? "cmd.exe" : resolved;
|
|
@@ -6031,10 +6189,10 @@ function createSystemExec(opts = {}) {
|
|
|
6031
6189
|
stderr += d.toString();
|
|
6032
6190
|
});
|
|
6033
6191
|
child.on("error", (err) => {
|
|
6034
|
-
|
|
6192
|
+
resolve9({ ok: false, code: null, stdout, stderr: stderr || String(err) });
|
|
6035
6193
|
});
|
|
6036
6194
|
child.on("close", (code) => {
|
|
6037
|
-
|
|
6195
|
+
resolve9({ ok: true, code: code ?? 0, stdout, stderr });
|
|
6038
6196
|
});
|
|
6039
6197
|
});
|
|
6040
6198
|
}
|
|
@@ -6043,8 +6201,8 @@ var init_system_exec = __esm(() => {
|
|
|
6043
6201
|
});
|
|
6044
6202
|
|
|
6045
6203
|
// src/services/setup.ts
|
|
6046
|
-
import { copyFileSync, existsSync as
|
|
6047
|
-
import { dirname as
|
|
6204
|
+
import { copyFileSync, existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync7, readdirSync as readdirSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
6205
|
+
import { dirname as dirname8, join as join16 } from "path";
|
|
6048
6206
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
6049
6207
|
async function writeGitIdentity(exec, identity) {
|
|
6050
6208
|
const name = identity.name.trim();
|
|
@@ -6120,16 +6278,16 @@ async function resolveRuntime(exec, preferred) {
|
|
|
6120
6278
|
function resolveSandcastleBin() {
|
|
6121
6279
|
try {
|
|
6122
6280
|
const mainUrl = import.meta.resolve("@ai-hero/sandcastle");
|
|
6123
|
-
let dir =
|
|
6281
|
+
let dir = dirname8(fileURLToPath6(mainUrl));
|
|
6124
6282
|
for (let hops = 0;hops < 6; hops++) {
|
|
6125
|
-
const manifestPath =
|
|
6126
|
-
if (
|
|
6283
|
+
const manifestPath = join16(dir, "package.json");
|
|
6284
|
+
if (existsSync17(manifestPath)) {
|
|
6127
6285
|
const manifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
|
|
6128
6286
|
if (manifest.name === "@ai-hero/sandcastle" && manifest.bin?.sandcastle) {
|
|
6129
|
-
return
|
|
6287
|
+
return join16(dir, manifest.bin.sandcastle);
|
|
6130
6288
|
}
|
|
6131
6289
|
}
|
|
6132
|
-
const parent =
|
|
6290
|
+
const parent = dirname8(dir);
|
|
6133
6291
|
if (parent === dir)
|
|
6134
6292
|
break;
|
|
6135
6293
|
dir = parent;
|
|
@@ -6154,12 +6312,12 @@ function sandcastleTemplateDir() {
|
|
|
6154
6312
|
return resolveAsset(ASSET_ENV.sandcastleTemplate, fileURLToPath6(new URL("../assets/sandcastle", import.meta.url)));
|
|
6155
6313
|
}
|
|
6156
6314
|
function scaffoldSandcastleConfig(templateDir, targetDir) {
|
|
6157
|
-
const dir =
|
|
6158
|
-
if (
|
|
6315
|
+
const dir = join16(targetDir, ".sandcastle");
|
|
6316
|
+
if (existsSync17(dir))
|
|
6159
6317
|
return { scaffolded: false, dir };
|
|
6160
6318
|
mkdirSync8(dir, { recursive: true });
|
|
6161
|
-
for (const name of
|
|
6162
|
-
copyFileSync(
|
|
6319
|
+
for (const name of readdirSync6(templateDir)) {
|
|
6320
|
+
copyFileSync(join16(templateDir, name), join16(dir, name));
|
|
6163
6321
|
}
|
|
6164
6322
|
return { scaffolded: true, dir };
|
|
6165
6323
|
}
|
|
@@ -6184,9 +6342,9 @@ function createTokenVerifier(exec) {
|
|
|
6184
6342
|
function fileAfkTokenIo(exec) {
|
|
6185
6343
|
const path = envPath();
|
|
6186
6344
|
return {
|
|
6187
|
-
read: () =>
|
|
6345
|
+
read: () => existsSync17(path) ? readFileSync7(path, "utf8") : "",
|
|
6188
6346
|
write: (content) => {
|
|
6189
|
-
mkdirSync8(
|
|
6347
|
+
mkdirSync8(dirname8(path), { recursive: true });
|
|
6190
6348
|
writeFileSync4(path, content, "utf8");
|
|
6191
6349
|
},
|
|
6192
6350
|
verify: createTokenVerifier(exec)
|
|
@@ -6323,13 +6481,13 @@ var init_update_check = __esm(() => {
|
|
|
6323
6481
|
|
|
6324
6482
|
// src/version.ts
|
|
6325
6483
|
import { readFileSync as readFileSync8 } from "fs";
|
|
6326
|
-
import { dirname as
|
|
6484
|
+
import { dirname as dirname9, join as join17 } from "path";
|
|
6327
6485
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
6328
6486
|
function runcastleVersion() {
|
|
6329
6487
|
if (cached2)
|
|
6330
6488
|
return cached2;
|
|
6331
|
-
const here =
|
|
6332
|
-
for (const pkgPath of [
|
|
6489
|
+
const here = dirname9(fileURLToPath7(import.meta.url));
|
|
6490
|
+
for (const pkgPath of [join17(here, "..", "package.json"), join17(here, "package.json")]) {
|
|
6333
6491
|
try {
|
|
6334
6492
|
const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
6335
6493
|
if (typeof pkg.version === "string") {
|
|
@@ -6579,7 +6737,7 @@ __export(exports_cli, {
|
|
|
6579
6737
|
resolveDoctorEnv: () => resolveDoctorEnv,
|
|
6580
6738
|
parseMode: () => parseMode
|
|
6581
6739
|
});
|
|
6582
|
-
import { existsSync as
|
|
6740
|
+
import { existsSync as existsSync18, readFileSync as readFileSync9 } from "fs";
|
|
6583
6741
|
function parseMode(argv) {
|
|
6584
6742
|
return argv.includes("--gate") || argv.includes("--boot") ? "gate" : "diagnostic";
|
|
6585
6743
|
}
|
|
@@ -6587,7 +6745,7 @@ function envWithToken() {
|
|
|
6587
6745
|
const merged = { ...process.env };
|
|
6588
6746
|
try {
|
|
6589
6747
|
const path = envPath();
|
|
6590
|
-
if (
|
|
6748
|
+
if (existsSync18(path)) {
|
|
6591
6749
|
const fromFile = parseEnvFile(readFileSync9(path, "utf8")).CLAUDE_CODE_OAUTH_TOKEN;
|
|
6592
6750
|
if (fromFile && fromFile.length > 0)
|
|
6593
6751
|
merged.CLAUDE_CODE_OAUTH_TOKEN = fromFile;
|
|
@@ -6630,7 +6788,7 @@ var init_cli = __esm(() => {
|
|
|
6630
6788
|
// src/bin/runcastle.ts
|
|
6631
6789
|
init_asset_paths();
|
|
6632
6790
|
init_version();
|
|
6633
|
-
import { dirname as
|
|
6791
|
+
import { dirname as dirname10, resolve as resolve9 } from "path";
|
|
6634
6792
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
6635
6793
|
function parseCommand(argv) {
|
|
6636
6794
|
const [first, ...rest] = argv;
|
|
@@ -6655,7 +6813,7 @@ Usage:
|
|
|
6655
6813
|
runcastle --help Show this help
|
|
6656
6814
|
`;
|
|
6657
6815
|
async function main(argv) {
|
|
6658
|
-
applyInstalledAssetEnv(
|
|
6816
|
+
applyInstalledAssetEnv(resolve9(dirname10(fileURLToPath8(import.meta.url)), ".."));
|
|
6659
6817
|
const { command, args } = parseCommand(argv);
|
|
6660
6818
|
switch (command) {
|
|
6661
6819
|
case "version":
|