runcastle 1.2.3 → 1.2.4
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 +303 -188
- package/drizzle/0019_freezing_natasha_romanoff.sql +2 -0
- package/drizzle/meta/0019_snapshot.json +860 -0
- package/drizzle/meta/_journal.json +7 -0
- package/index.js +298 -183
- package/package.json +1 -1
- package/web/assets/{index-BhOja4Fc.js → index-CzDDtq7w.js} +38 -38
- package/web/index.html +1 -1
package/bin/runcastle.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(exports_paths, {
|
|
|
26
26
|
projectWorktreesDir: () => projectWorktreesDir,
|
|
27
27
|
prodDataDir: () => prodDataDir,
|
|
28
28
|
logsDir: () => logsDir,
|
|
29
|
+
installIdPath: () => installIdPath,
|
|
29
30
|
featureDocsRel: () => featureDocsRel,
|
|
30
31
|
envPath: () => envPath,
|
|
31
32
|
devDataDir: () => devDataDir,
|
|
@@ -64,6 +65,9 @@ function configPath() {
|
|
|
64
65
|
function envPath() {
|
|
65
66
|
return join(dataDir(), ".env");
|
|
66
67
|
}
|
|
68
|
+
function installIdPath() {
|
|
69
|
+
return join(dataDir(), "install-id");
|
|
70
|
+
}
|
|
67
71
|
function logsDir() {
|
|
68
72
|
return join(dataDir(), "logs");
|
|
69
73
|
}
|
|
@@ -246,7 +250,7 @@ var init_ids = () => {};
|
|
|
246
250
|
|
|
247
251
|
// ../core/src/schemas.ts
|
|
248
252
|
import * as z2 from "zod";
|
|
249
|
-
var Phase, TicketStatus, SessionKind, RunStatus, FeatureStatus, SessionStatus, TicketInput, Ticket, WaypointType, WaypointStatus, WaypointDisposition, WaypointInput, Waypoint, TestNoteStatus, TestNote, PREPARED_KEYS, PreparedKey, DRIVE_LOOP_KEYS, FindingSource, PROJECT_NAME_MAX = 80, ProjectName, Project, ProjectFinding, Feature, SessionRow, Run, SettingSource, SettingScope, SettingField, SettingsView, SettingsUpdateInput, EventRow;
|
|
253
|
+
var Phase, TicketStatus, SessionKind, SessionPurpose, MergeBranchPair, RunStatus, FeatureStatus, SessionStatus, TicketInput, Ticket, WaypointType, WaypointStatus, WaypointDisposition, WaypointInput, Waypoint, TestNoteStatus, TestNote, PREPARED_KEYS, PreparedKey, DRIVE_LOOP_KEYS, FindingSource, PROJECT_NAME_MAX = 80, ProjectName, Project, ProjectFinding, Feature, SessionRow, Run, SettingSource, SettingScope, SettingField, SettingsView, SettingsUpdateInput, EventRow;
|
|
250
254
|
var init_schemas = __esm(() => {
|
|
251
255
|
Phase = z2.enum([
|
|
252
256
|
"ideation",
|
|
@@ -266,6 +270,11 @@ var init_schemas = __esm(() => {
|
|
|
266
270
|
"prepare",
|
|
267
271
|
"project"
|
|
268
272
|
]);
|
|
273
|
+
SessionPurpose = z2.enum(["resolve-conflict"]);
|
|
274
|
+
MergeBranchPair = z2.object({
|
|
275
|
+
mergeFrom: z2.string(),
|
|
276
|
+
mergeInto: z2.string()
|
|
277
|
+
});
|
|
269
278
|
RunStatus = z2.enum(["running", "succeeded", "failed", "cancelled"]);
|
|
270
279
|
FeatureStatus = z2.enum(["active", "shipped", "archived"]);
|
|
271
280
|
SessionStatus = z2.enum(["launching", "live", "ended"]);
|
|
@@ -382,6 +391,8 @@ var init_schemas = __esm(() => {
|
|
|
382
391
|
featureId: z2.string().optional(),
|
|
383
392
|
projectId: z2.string().optional(),
|
|
384
393
|
kind: SessionKind,
|
|
394
|
+
purpose: SessionPurpose.optional(),
|
|
395
|
+
purposeData: MergeBranchPair.optional(),
|
|
385
396
|
ccSessionId: z2.string().optional(),
|
|
386
397
|
transcriptPath: z2.string().optional(),
|
|
387
398
|
status: SessionStatus,
|
|
@@ -620,6 +631,8 @@ var init_db_schema = __esm(() => {
|
|
|
620
631
|
projectId: text("project_id"),
|
|
621
632
|
lap: integer("lap").notNull().default(1),
|
|
622
633
|
kind: text("kind").notNull().$type(),
|
|
634
|
+
purpose: text("purpose").$type(),
|
|
635
|
+
purposeData: text("purpose_data", { mode: "json" }).$type(),
|
|
623
636
|
ccSessionId: text("cc_session_id"),
|
|
624
637
|
transcriptPath: text("transcript_path"),
|
|
625
638
|
status: text("status").notNull().$type(),
|
|
@@ -1566,6 +1579,8 @@ function rowToSession(row) {
|
|
|
1566
1579
|
featureId: row.featureId ?? undefined,
|
|
1567
1580
|
projectId: row.projectId ?? undefined,
|
|
1568
1581
|
kind: row.kind,
|
|
1582
|
+
purpose: row.purpose ?? undefined,
|
|
1583
|
+
purposeData: row.purposeData ?? undefined,
|
|
1569
1584
|
ccSessionId: row.ccSessionId ?? undefined,
|
|
1570
1585
|
transcriptPath: row.transcriptPath ?? undefined,
|
|
1571
1586
|
status: row.status,
|
|
@@ -3181,10 +3196,24 @@ async function conflictedFiles(g) {
|
|
|
3181
3196
|
return [];
|
|
3182
3197
|
}
|
|
3183
3198
|
}
|
|
3199
|
+
async function mergeInProgressAt(worktreePath) {
|
|
3200
|
+
try {
|
|
3201
|
+
return await mergeInProgress(git(worktreePath));
|
|
3202
|
+
} catch {
|
|
3203
|
+
return false;
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
async function isAncestor(repoPath, ancestor, descendant) {
|
|
3207
|
+
try {
|
|
3208
|
+
const out = await git(repoPath).raw(["rev-list", "--count", ancestor, `^${descendant}`]);
|
|
3209
|
+
return out.trim() === "0";
|
|
3210
|
+
} catch {
|
|
3211
|
+
return false;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3184
3214
|
async function mergeInProgress(g) {
|
|
3185
3215
|
try {
|
|
3186
|
-
await g.raw(["rev-parse", "--verify", "--quiet", "MERGE_HEAD"]);
|
|
3187
|
-
return true;
|
|
3216
|
+
return (await g.raw(["rev-parse", "--verify", "--quiet", "MERGE_HEAD"])).trim() !== "";
|
|
3188
3217
|
} catch {
|
|
3189
3218
|
return false;
|
|
3190
3219
|
}
|
|
@@ -3214,6 +3243,8 @@ function createSessionRow(ctx, input) {
|
|
|
3214
3243
|
projectId: input.projectId ?? null,
|
|
3215
3244
|
lap: input.featureId ? getFeatureRow(ctx, input.featureId).lap : 1,
|
|
3216
3245
|
kind: input.kind,
|
|
3246
|
+
purpose: input.purpose ?? null,
|
|
3247
|
+
purposeData: input.purposeData ?? null,
|
|
3217
3248
|
ccSessionId: null,
|
|
3218
3249
|
transcriptPath: null,
|
|
3219
3250
|
status: "launching",
|
|
@@ -6658,6 +6689,8 @@ function guardsEdits(kind) {
|
|
|
6658
6689
|
function evaluateEditGuard(input) {
|
|
6659
6690
|
if (!guardsEdits(input.kind))
|
|
6660
6691
|
return null;
|
|
6692
|
+
if (input.purpose === "resolve-conflict" && input.mergeInProgress)
|
|
6693
|
+
return null;
|
|
6661
6694
|
if (!input.toolName || !EDIT_TOOLS.includes(input.toolName))
|
|
6662
6695
|
return null;
|
|
6663
6696
|
if (!input.filePath)
|
|
@@ -6834,22 +6867,40 @@ function handleUserPrompt(ctx, sessionId, feature, payload) {
|
|
|
6834
6867
|
}
|
|
6835
6868
|
};
|
|
6836
6869
|
}
|
|
6837
|
-
function handleSessionEnd(ctx,
|
|
6838
|
-
markSessionEnded(ctx,
|
|
6839
|
-
releaseForSession(ctx,
|
|
6870
|
+
async function handleSessionEnd(ctx, session, feature) {
|
|
6871
|
+
markSessionEnded(ctx, session.id);
|
|
6872
|
+
releaseForSession(ctx, session.id);
|
|
6840
6873
|
emit(ctx, feature.id, {
|
|
6841
6874
|
type: "session.ended",
|
|
6842
6875
|
message: "session ended",
|
|
6843
|
-
data: { sessionId }
|
|
6876
|
+
data: { sessionId: session.id }
|
|
6844
6877
|
});
|
|
6878
|
+
await noteResolvedMerge(ctx, session, feature);
|
|
6845
6879
|
return {};
|
|
6846
6880
|
}
|
|
6847
|
-
function
|
|
6881
|
+
async function noteResolvedMerge(ctx, session, feature) {
|
|
6882
|
+
const pair = session.purpose === "resolve-conflict" ? session.purposeData : undefined;
|
|
6883
|
+
if (!pair)
|
|
6884
|
+
return;
|
|
6885
|
+
try {
|
|
6886
|
+
if (!await isAncestor(session.worktreePath, pair.mergeFrom, pair.mergeInto))
|
|
6887
|
+
return;
|
|
6888
|
+
emit(ctx, feature.id, {
|
|
6889
|
+
type: "merge.resolved",
|
|
6890
|
+
message: `merge conflict resolved \u2014 ${pair.mergeFrom} is in ${pair.mergeInto}`,
|
|
6891
|
+
data: { sessionId: session.id, ...pair }
|
|
6892
|
+
});
|
|
6893
|
+
} catch {}
|
|
6894
|
+
}
|
|
6895
|
+
async function handlePreToolUse(session, feature, payload) {
|
|
6848
6896
|
const toolName = typeof payload?.tool_name === "string" ? payload.tool_name : undefined;
|
|
6849
6897
|
const toolInput = payload?.tool_input ?? {};
|
|
6850
6898
|
const path = typeof toolInput.file_path === "string" ? toolInput.file_path : typeof toolInput.notebook_path === "string" ? toolInput.notebook_path : undefined;
|
|
6899
|
+
const mergeInProgress2 = session.purpose === "resolve-conflict" ? await mergeInProgressAt(session.worktreePath) : false;
|
|
6851
6900
|
const denial = evaluateEditGuard({
|
|
6852
6901
|
kind: session.kind,
|
|
6902
|
+
purpose: session.purpose,
|
|
6903
|
+
mergeInProgress: mergeInProgress2,
|
|
6853
6904
|
worktreePath: session.worktreePath,
|
|
6854
6905
|
toolName,
|
|
6855
6906
|
filePath: path,
|
|
@@ -6878,6 +6929,7 @@ var init_hooks = __esm(() => {
|
|
|
6878
6929
|
init_edit_guard();
|
|
6879
6930
|
init_sessions();
|
|
6880
6931
|
init_events();
|
|
6932
|
+
init_git();
|
|
6881
6933
|
init_prep();
|
|
6882
6934
|
init_repo();
|
|
6883
6935
|
init_tickets();
|
|
@@ -6915,7 +6967,7 @@ var init_hooks = __esm(() => {
|
|
|
6915
6967
|
case "session-end":
|
|
6916
6968
|
return c.json(handleProjectScopedSessionEnd(ctx, session));
|
|
6917
6969
|
case "pre-tool":
|
|
6918
|
-
return c.json(handlePreToolUse(session, undefined, body.payload));
|
|
6970
|
+
return c.json(await handlePreToolUse(session, undefined, body.payload));
|
|
6919
6971
|
default:
|
|
6920
6972
|
return c.json({});
|
|
6921
6973
|
}
|
|
@@ -6929,9 +6981,9 @@ var init_hooks = __esm(() => {
|
|
|
6929
6981
|
case "user-prompt":
|
|
6930
6982
|
return c.json(handleUserPrompt(ctx, sessionId, feature, body.payload));
|
|
6931
6983
|
case "session-end":
|
|
6932
|
-
return c.json(handleSessionEnd(ctx,
|
|
6984
|
+
return c.json(await handleSessionEnd(ctx, session, feature));
|
|
6933
6985
|
case "pre-tool":
|
|
6934
|
-
return c.json(handlePreToolUse(session, feature, body.payload));
|
|
6986
|
+
return c.json(await handlePreToolUse(session, feature, body.payload));
|
|
6935
6987
|
default:
|
|
6936
6988
|
return c.json({});
|
|
6937
6989
|
}
|
|
@@ -7073,6 +7125,166 @@ var init_web = __esm(() => {
|
|
|
7073
7125
|
};
|
|
7074
7126
|
});
|
|
7075
7127
|
|
|
7128
|
+
// src/version.ts
|
|
7129
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
7130
|
+
import { dirname as dirname5, join as join12 } from "path";
|
|
7131
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7132
|
+
function runcastleVersion() {
|
|
7133
|
+
if (cached2)
|
|
7134
|
+
return cached2;
|
|
7135
|
+
const here = dirname5(fileURLToPath4(import.meta.url));
|
|
7136
|
+
for (const pkgPath of [join12(here, "..", "package.json"), join12(here, "package.json")]) {
|
|
7137
|
+
try {
|
|
7138
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
7139
|
+
if (typeof pkg.version === "string") {
|
|
7140
|
+
cached2 = pkg.version;
|
|
7141
|
+
return cached2;
|
|
7142
|
+
}
|
|
7143
|
+
} catch {}
|
|
7144
|
+
}
|
|
7145
|
+
cached2 = UNKNOWN_VERSION;
|
|
7146
|
+
return cached2;
|
|
7147
|
+
}
|
|
7148
|
+
var cached2, UNKNOWN_VERSION = "0.0.0";
|
|
7149
|
+
var init_version = () => {};
|
|
7150
|
+
|
|
7151
|
+
// src/services/install-id.ts
|
|
7152
|
+
import { randomUUID } from "crypto";
|
|
7153
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
|
|
7154
|
+
import { dirname as dirname6 } from "path";
|
|
7155
|
+
function getInstallId() {
|
|
7156
|
+
const file = installIdPath();
|
|
7157
|
+
try {
|
|
7158
|
+
if (existsSync13(file)) {
|
|
7159
|
+
const existing = readFileSync7(file, "utf8").trim();
|
|
7160
|
+
if (UUID_RE.test(existing))
|
|
7161
|
+
return existing;
|
|
7162
|
+
}
|
|
7163
|
+
const id = randomUUID();
|
|
7164
|
+
mkdirSync6(dirname6(file), { recursive: true });
|
|
7165
|
+
writeFileSync2(file, `${id}
|
|
7166
|
+
`);
|
|
7167
|
+
return id;
|
|
7168
|
+
} catch {
|
|
7169
|
+
return randomUUID();
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
7172
|
+
var UUID_RE;
|
|
7173
|
+
var init_install_id = __esm(() => {
|
|
7174
|
+
init_paths();
|
|
7175
|
+
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7176
|
+
});
|
|
7177
|
+
|
|
7178
|
+
// src/services/update-check.ts
|
|
7179
|
+
function parse(version) {
|
|
7180
|
+
const cleaned = version.trim().replace(/^v/, "");
|
|
7181
|
+
const [core = "", pre = ""] = cleaned.split("-", 2);
|
|
7182
|
+
const release2 = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
7183
|
+
return { release: release2, pre: pre ? pre.split(".") : [] };
|
|
7184
|
+
}
|
|
7185
|
+
function compareSemver(a, b) {
|
|
7186
|
+
const pa = parse(a);
|
|
7187
|
+
const pb = parse(b);
|
|
7188
|
+
const len = Math.max(pa.release.length, pb.release.length);
|
|
7189
|
+
for (let i = 0;i < len; i++) {
|
|
7190
|
+
const diff = (pa.release[i] ?? 0) - (pb.release[i] ?? 0);
|
|
7191
|
+
if (diff !== 0)
|
|
7192
|
+
return diff;
|
|
7193
|
+
}
|
|
7194
|
+
if (pa.pre.length === 0 && pb.pre.length === 0)
|
|
7195
|
+
return 0;
|
|
7196
|
+
if (pa.pre.length === 0)
|
|
7197
|
+
return 1;
|
|
7198
|
+
if (pb.pre.length === 0)
|
|
7199
|
+
return -1;
|
|
7200
|
+
const preLen = Math.max(pa.pre.length, pb.pre.length);
|
|
7201
|
+
for (let i = 0;i < preLen; i++) {
|
|
7202
|
+
const x = pa.pre[i];
|
|
7203
|
+
const y = pb.pre[i];
|
|
7204
|
+
if (x === undefined)
|
|
7205
|
+
return -1;
|
|
7206
|
+
if (y === undefined)
|
|
7207
|
+
return 1;
|
|
7208
|
+
const nx = Number(x);
|
|
7209
|
+
const ny = Number(y);
|
|
7210
|
+
const bothNumeric = !Number.isNaN(nx) && !Number.isNaN(ny);
|
|
7211
|
+
const cmp = bothNumeric ? nx - ny : x < y ? -1 : x > y ? 1 : 0;
|
|
7212
|
+
if (cmp !== 0)
|
|
7213
|
+
return cmp;
|
|
7214
|
+
}
|
|
7215
|
+
return 0;
|
|
7216
|
+
}
|
|
7217
|
+
function doNotTrack(env) {
|
|
7218
|
+
const raw = env.DO_NOT_TRACK;
|
|
7219
|
+
return raw !== undefined && raw !== "" && raw !== "0";
|
|
7220
|
+
}
|
|
7221
|
+
async function latestFromNpm(fetchImpl) {
|
|
7222
|
+
try {
|
|
7223
|
+
const res = await fetchImpl(NPM_LATEST_URL);
|
|
7224
|
+
if (!res.ok)
|
|
7225
|
+
return null;
|
|
7226
|
+
const body = await res.json();
|
|
7227
|
+
return typeof body.version === "string" ? body.version : null;
|
|
7228
|
+
} catch {
|
|
7229
|
+
return null;
|
|
7230
|
+
}
|
|
7231
|
+
}
|
|
7232
|
+
async function latestFromPing(fetchImpl, current2) {
|
|
7233
|
+
try {
|
|
7234
|
+
const res = await fetchImpl(PING_URL, {
|
|
7235
|
+
method: "POST",
|
|
7236
|
+
headers: { "content-type": "application/json" },
|
|
7237
|
+
body: JSON.stringify({
|
|
7238
|
+
installId: getInstallId(),
|
|
7239
|
+
version: current2,
|
|
7240
|
+
platform: process.platform
|
|
7241
|
+
})
|
|
7242
|
+
});
|
|
7243
|
+
if (!res.ok)
|
|
7244
|
+
return null;
|
|
7245
|
+
const body = await res.json();
|
|
7246
|
+
return typeof body.latest === "string" ? body.latest : null;
|
|
7247
|
+
} catch {
|
|
7248
|
+
return null;
|
|
7249
|
+
}
|
|
7250
|
+
}
|
|
7251
|
+
async function checkForUpdate(opts) {
|
|
7252
|
+
const { current: current2 } = opts;
|
|
7253
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
7254
|
+
const env = opts.env ?? process.env;
|
|
7255
|
+
if (current2 === UNKNOWN_VERSION)
|
|
7256
|
+
return NO_UPDATE(current2);
|
|
7257
|
+
const latest = doNotTrack(env) ? await latestFromNpm(fetchImpl) : await latestFromPing(fetchImpl, current2) ?? await latestFromNpm(fetchImpl);
|
|
7258
|
+
if (!latest)
|
|
7259
|
+
return NO_UPDATE(current2);
|
|
7260
|
+
return {
|
|
7261
|
+
current: current2,
|
|
7262
|
+
latest,
|
|
7263
|
+
updateAvailable: compareSemver(latest, current2) > 0,
|
|
7264
|
+
command: UPDATE_COMMAND
|
|
7265
|
+
};
|
|
7266
|
+
}
|
|
7267
|
+
async function getUpdateInfo(current2, fetchImpl) {
|
|
7268
|
+
if (cache)
|
|
7269
|
+
return cache;
|
|
7270
|
+
const info = await checkForUpdate({ current: current2, fetchImpl });
|
|
7271
|
+
if (info.latest !== null)
|
|
7272
|
+
cache = info;
|
|
7273
|
+
return info;
|
|
7274
|
+
}
|
|
7275
|
+
var PACKAGE_NAME = "runcastle", UPDATE_COMMAND, PING_URL = "https://ping.runcastle.dev/ping", NPM_LATEST_URL, NO_UPDATE = (current2) => ({
|
|
7276
|
+
current: current2,
|
|
7277
|
+
latest: null,
|
|
7278
|
+
updateAvailable: false,
|
|
7279
|
+
command: UPDATE_COMMAND
|
|
7280
|
+
}), cache;
|
|
7281
|
+
var init_update_check = __esm(() => {
|
|
7282
|
+
init_version();
|
|
7283
|
+
init_install_id();
|
|
7284
|
+
UPDATE_COMMAND = `bun add -g ${PACKAGE_NAME}@latest`;
|
|
7285
|
+
NPM_LATEST_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
7286
|
+
});
|
|
7287
|
+
|
|
7076
7288
|
// src/trpc/context.ts
|
|
7077
7289
|
import { initTRPC } from "@trpc/server";
|
|
7078
7290
|
var t, errorMapping, router, publicProcedure, createCallerFactory;
|
|
@@ -7121,11 +7333,11 @@ var init_events2 = __esm(() => {
|
|
|
7121
7333
|
});
|
|
7122
7334
|
|
|
7123
7335
|
// src/launcher/artifacts.ts
|
|
7124
|
-
import { mkdirSync as
|
|
7125
|
-
import { fileURLToPath as
|
|
7126
|
-
import { join as
|
|
7336
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
7337
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7338
|
+
import { join as join13 } from "path";
|
|
7127
7339
|
function hookClientPath() {
|
|
7128
|
-
return resolveAsset(ASSET_ENV.hookClient,
|
|
7340
|
+
return resolveAsset(ASSET_ENV.hookClient, fileURLToPath5(new URL("./hook-client.ts", import.meta.url)));
|
|
7129
7341
|
}
|
|
7130
7342
|
function serverUrlFor(config2) {
|
|
7131
7343
|
return `http://localhost:${config2.serverPort}`;
|
|
@@ -7547,16 +7759,16 @@ function renderMcpConfig(session, config2) {
|
|
|
7547
7759
|
async function writeSessionArtifacts(input) {
|
|
7548
7760
|
const { session, feature, config: config2, waypoint, prepare, projectBrief, lap } = input;
|
|
7549
7761
|
const dir = sessionDir(session.id);
|
|
7550
|
-
|
|
7551
|
-
const systemPromptPath =
|
|
7552
|
-
const settingsPath =
|
|
7553
|
-
const mcpConfigPath =
|
|
7762
|
+
mkdirSync7(dir, { recursive: true });
|
|
7763
|
+
const systemPromptPath = join13(dir, "system-prompt.md");
|
|
7764
|
+
const settingsPath = join13(dir, "settings.json");
|
|
7765
|
+
const mcpConfigPath = join13(dir, "mcp.json");
|
|
7554
7766
|
const systemPrompt = feature ? renderSystemPrompt(feature, session.kind, waypoint, lap) : prepare ? renderPreparePrompt(prepare) : projectBrief ? renderProjectPrompt(projectBrief) : (() => {
|
|
7555
7767
|
throw new Error(`session ${session.id} has no feature and no project-session brief`);
|
|
7556
7768
|
})();
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7769
|
+
writeFileSync3(systemPromptPath, systemPrompt, "utf8");
|
|
7770
|
+
writeFileSync3(settingsPath, JSON.stringify(renderSettings(hookClientPath(), session.kind), null, 2), "utf8");
|
|
7771
|
+
writeFileSync3(mcpConfigPath, JSON.stringify(renderMcpConfig(session, config2), null, 2), "utf8");
|
|
7560
7772
|
return { systemPromptPath, settingsPath, mcpConfigPath };
|
|
7561
7773
|
}
|
|
7562
7774
|
var RUNCASTLE_MCP_ALLOW_RULES, SESSION_BASH_READ_RULES, SESSION_BASH_WRITE_RULES, SESSION_BASH_ALLOW_RULES, SESSION_START_SOURCES;
|
|
@@ -7600,9 +7812,9 @@ var init_artifacts = __esm(() => {
|
|
|
7600
7812
|
});
|
|
7601
7813
|
|
|
7602
7814
|
// src/launcher/launcher.ts
|
|
7603
|
-
import { existsSync as
|
|
7604
|
-
import { dirname as
|
|
7605
|
-
import { fileURLToPath as
|
|
7815
|
+
import { existsSync as existsSync14 } from "fs";
|
|
7816
|
+
import { dirname as dirname7, join as join14, resolve as resolve9 } from "path";
|
|
7817
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
7606
7818
|
import { and as and9, eq as eq11 } from "drizzle-orm";
|
|
7607
7819
|
function ptyExitMessage(exitCode) {
|
|
7608
7820
|
const label = typeof exitCode === "number" ? String(exitCode) : "unknown";
|
|
@@ -7634,23 +7846,23 @@ function resolveClaudeExecutable() {
|
|
|
7634
7846
|
function claudeSpawnTarget(claudeArgs) {
|
|
7635
7847
|
return spawnTargetFor(resolveClaudeExecutable(), claudeArgs);
|
|
7636
7848
|
}
|
|
7637
|
-
function resolvePluginDir(fromDir =
|
|
7638
|
-
const rel =
|
|
7849
|
+
function resolvePluginDir(fromDir = dirname7(fileURLToPath6(import.meta.url))) {
|
|
7850
|
+
const rel = join14("packages", "skills", "packs", "runcastle");
|
|
7639
7851
|
const override = process.env[SKILLS_DIR_ENV];
|
|
7640
7852
|
if (override) {
|
|
7641
|
-
const dir2 =
|
|
7642
|
-
if (
|
|
7853
|
+
const dir2 = join14(resolve9(override), "packs", "runcastle");
|
|
7854
|
+
if (existsSync14(dir2))
|
|
7643
7855
|
return dir2;
|
|
7644
7856
|
throw new Error(`${SKILLS_DIR_ENV}=${override} has no plugin dir at ${dir2}`);
|
|
7645
7857
|
}
|
|
7646
7858
|
const searched = [];
|
|
7647
7859
|
let dir = fromDir;
|
|
7648
7860
|
for (let i = 0;i < 8; i += 1) {
|
|
7649
|
-
const candidate =
|
|
7861
|
+
const candidate = join14(dir, rel);
|
|
7650
7862
|
searched.push(candidate);
|
|
7651
|
-
if (
|
|
7863
|
+
if (existsSync14(candidate))
|
|
7652
7864
|
return candidate;
|
|
7653
|
-
const parent =
|
|
7865
|
+
const parent = dirname7(dir);
|
|
7654
7866
|
if (parent === dir)
|
|
7655
7867
|
break;
|
|
7656
7868
|
dir = parent;
|
|
@@ -7719,6 +7931,8 @@ async function launchSession(ctx, input, opts = {}) {
|
|
|
7719
7931
|
const session = createSessionRow(ctx, {
|
|
7720
7932
|
featureId: feature.id,
|
|
7721
7933
|
kind: input.kind,
|
|
7934
|
+
purpose: input.purpose,
|
|
7935
|
+
purposeData: input.purposeData,
|
|
7722
7936
|
worktreePath
|
|
7723
7937
|
});
|
|
7724
7938
|
const plan = planKickoff({ kind: input.kind, lap: feature.lap, kickoffLine: input.kickoffLine });
|
|
@@ -8166,7 +8380,9 @@ var init_feature = __esm(() => {
|
|
|
8166
8380
|
launchSession: publicProcedure.input(z6.object({
|
|
8167
8381
|
featureId: z6.string(),
|
|
8168
8382
|
kind: SessionKind,
|
|
8169
|
-
kickoffLine: z6.string().min(1).optional()
|
|
8383
|
+
kickoffLine: z6.string().min(1).optional(),
|
|
8384
|
+
purpose: SessionPurpose.optional(),
|
|
8385
|
+
purposeData: MergeBranchPair.optional()
|
|
8170
8386
|
})).mutation(({ ctx, input }) => launchSession(ctx, input)),
|
|
8171
8387
|
workWaypoint: publicProcedure.input(z6.object({ featureId: z6.string(), waypointId: z6.string(), endLive: z6.boolean().optional() })).mutation(({ ctx, input }) => workWaypoint(ctx, input)),
|
|
8172
8388
|
converge: publicProcedure.input(z6.object({ featureId: z6.string(), overrideReason: z6.string().min(1).optional() })).mutation(({ ctx, input }) => converge(ctx, { featureId: input.featureId, overrideReason: input.overrideReason })),
|
|
@@ -8217,9 +8433,9 @@ var init_feature = __esm(() => {
|
|
|
8217
8433
|
});
|
|
8218
8434
|
|
|
8219
8435
|
// src/services/fsbrowse.ts
|
|
8220
|
-
import { existsSync as
|
|
8436
|
+
import { existsSync as existsSync15, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
8221
8437
|
import { homedir as homedir2 } from "os";
|
|
8222
|
-
import { basename, dirname as
|
|
8438
|
+
import { basename, dirname as dirname8, isAbsolute as isAbsolute2, join as join15, resolve as resolve10, sep as sep3 } from "path";
|
|
8223
8439
|
function expandPath(input, home = homedir2()) {
|
|
8224
8440
|
const trimmed = input.trim();
|
|
8225
8441
|
if (trimmed === "")
|
|
@@ -8228,12 +8444,12 @@ function expandPath(input, home = homedir2()) {
|
|
|
8228
8444
|
if (out === "~")
|
|
8229
8445
|
out = home;
|
|
8230
8446
|
else if (out.startsWith("~/") || out.startsWith("~\\"))
|
|
8231
|
-
out =
|
|
8447
|
+
out = join15(home, out.slice(2));
|
|
8232
8448
|
return resolve10(out);
|
|
8233
8449
|
}
|
|
8234
8450
|
function looksLikeRepo(dir) {
|
|
8235
8451
|
try {
|
|
8236
|
-
return
|
|
8452
|
+
return existsSync15(join15(dir, ".git"));
|
|
8237
8453
|
} catch {
|
|
8238
8454
|
return false;
|
|
8239
8455
|
}
|
|
@@ -8244,20 +8460,20 @@ function listRoots(home = homedir2()) {
|
|
|
8244
8460
|
for (let code = 67;code <= 90; code++) {
|
|
8245
8461
|
const drive = `${String.fromCharCode(code)}:${sep3}`;
|
|
8246
8462
|
try {
|
|
8247
|
-
if (
|
|
8463
|
+
if (existsSync15(drive))
|
|
8248
8464
|
roots.push({ label: drive.replace(/\\$/, ""), path: drive, kind: "drive" });
|
|
8249
8465
|
} catch {}
|
|
8250
8466
|
}
|
|
8251
8467
|
} else {
|
|
8252
8468
|
roots.push({ label: "/", path: "/", kind: "drive" });
|
|
8253
8469
|
}
|
|
8254
|
-
if (
|
|
8470
|
+
if (existsSync15(home))
|
|
8255
8471
|
roots.push({ label: "Home", path: home, kind: "home" });
|
|
8256
8472
|
const seen = new Set(roots.map(pathKey));
|
|
8257
8473
|
for (const name of COMMON_DIRS) {
|
|
8258
|
-
const candidate =
|
|
8474
|
+
const candidate = join15(home, name);
|
|
8259
8475
|
const key = pathKey({ path: candidate });
|
|
8260
|
-
if (seen.has(key) || !
|
|
8476
|
+
if (seen.has(key) || !existsSync15(candidate))
|
|
8261
8477
|
continue;
|
|
8262
8478
|
seen.add(key);
|
|
8263
8479
|
roots.push({ label: name, path: candidate, kind: "common" });
|
|
@@ -8272,7 +8488,7 @@ function crumbsFor(dir) {
|
|
|
8272
8488
|
let cur = dir;
|
|
8273
8489
|
for (;; ) {
|
|
8274
8490
|
out.unshift({ name: basename(cur) || cur, path: cur });
|
|
8275
|
-
const parent =
|
|
8491
|
+
const parent = dirname8(cur);
|
|
8276
8492
|
if (parent === cur)
|
|
8277
8493
|
break;
|
|
8278
8494
|
cur = parent;
|
|
@@ -8280,7 +8496,7 @@ function crumbsFor(dir) {
|
|
|
8280
8496
|
return out;
|
|
8281
8497
|
}
|
|
8282
8498
|
function parentOf(dir) {
|
|
8283
|
-
const parent =
|
|
8499
|
+
const parent = dirname8(dir);
|
|
8284
8500
|
return parent === dir ? null : parent;
|
|
8285
8501
|
}
|
|
8286
8502
|
function browseDir(input, showHidden = false, home = homedir2()) {
|
|
@@ -8288,13 +8504,13 @@ function browseDir(input, showHidden = false, home = homedir2()) {
|
|
|
8288
8504
|
if (!isAbsolute2(target)) {
|
|
8289
8505
|
throw new InvalidInputError(`path is not absolute: ${target}`);
|
|
8290
8506
|
}
|
|
8291
|
-
if (!
|
|
8507
|
+
if (!existsSync15(target)) {
|
|
8292
8508
|
throw new InvalidInputError(`path does not exist: ${target}`);
|
|
8293
8509
|
}
|
|
8294
8510
|
let dir = target;
|
|
8295
8511
|
try {
|
|
8296
8512
|
if (!statSync2(target).isDirectory())
|
|
8297
|
-
dir =
|
|
8513
|
+
dir = dirname8(target);
|
|
8298
8514
|
} catch (e) {
|
|
8299
8515
|
throw new InvalidInputError(`cannot read path: ${target} (${errMsg4(e)})`);
|
|
8300
8516
|
}
|
|
@@ -8316,7 +8532,7 @@ function browseDir(input, showHidden = false, home = homedir2()) {
|
|
|
8316
8532
|
continue;
|
|
8317
8533
|
if (!showHidden && name.startsWith("."))
|
|
8318
8534
|
continue;
|
|
8319
|
-
const path =
|
|
8535
|
+
const path = join15(dir, name);
|
|
8320
8536
|
const isSymlink = dirent.isSymbolicLink();
|
|
8321
8537
|
if (isSymlink && !showHidden)
|
|
8322
8538
|
continue;
|
|
@@ -8353,8 +8569,8 @@ var init_fsbrowse = __esm(() => {
|
|
|
8353
8569
|
});
|
|
8354
8570
|
|
|
8355
8571
|
// src/services/projects.ts
|
|
8356
|
-
import { existsSync as
|
|
8357
|
-
import { basename as basename2, join as
|
|
8572
|
+
import { existsSync as existsSync16 } from "fs";
|
|
8573
|
+
import { basename as basename2, join as join16 } from "path";
|
|
8358
8574
|
import { eq as eq12, isNull } from "drizzle-orm";
|
|
8359
8575
|
function listProjects(ctx) {
|
|
8360
8576
|
return ctx.db.select().from(projects).where(isNull(projects.closedAt)).all().map(rowToProject);
|
|
@@ -8435,7 +8651,7 @@ async function assertRepoTolerant(ctx, repoPath) {
|
|
|
8435
8651
|
} catch (e) {
|
|
8436
8652
|
if (!isNotImplemented(e))
|
|
8437
8653
|
throw e;
|
|
8438
|
-
if (!
|
|
8654
|
+
if (!existsSync16(join16(repoPath, ".git"))) {
|
|
8439
8655
|
throw new InvalidInputError(`not a git repository: ${repoPath}`);
|
|
8440
8656
|
}
|
|
8441
8657
|
}
|
|
@@ -8508,15 +8724,15 @@ var init_run = __esm(() => {
|
|
|
8508
8724
|
});
|
|
8509
8725
|
|
|
8510
8726
|
// src/services/settings.ts
|
|
8511
|
-
import { existsSync as
|
|
8512
|
-
import { dirname as
|
|
8727
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
8728
|
+
import { dirname as dirname9 } from "path";
|
|
8513
8729
|
import * as z9 from "zod";
|
|
8514
8730
|
import { eq as eq13 } from "drizzle-orm";
|
|
8515
8731
|
function readRawConfig(configFile) {
|
|
8516
|
-
if (!
|
|
8732
|
+
if (!existsSync17(configFile))
|
|
8517
8733
|
return {};
|
|
8518
8734
|
try {
|
|
8519
|
-
const parsed = JSON.parse(
|
|
8735
|
+
const parsed = JSON.parse(readFileSync8(configFile, "utf8"));
|
|
8520
8736
|
if (typeof parsed !== "object" || parsed === null)
|
|
8521
8737
|
return {};
|
|
8522
8738
|
return foldLegacyModelConfig(parsed);
|
|
@@ -8655,8 +8871,8 @@ function updateSettings(ctx, input, io = {}) {
|
|
|
8655
8871
|
function writeGlobal(configFile, configKey, value) {
|
|
8656
8872
|
const raw = readRawConfig(configFile);
|
|
8657
8873
|
raw[configKey] = value;
|
|
8658
|
-
|
|
8659
|
-
|
|
8874
|
+
mkdirSync8(dirname9(configFile), { recursive: true });
|
|
8875
|
+
writeFileSync4(configFile, `${JSON.stringify(raw, null, 2)}
|
|
8660
8876
|
`);
|
|
8661
8877
|
}
|
|
8662
8878
|
function updateStepModel(ctx, input, configFile, io) {
|
|
@@ -8694,8 +8910,8 @@ function writeStepModel(configFile, step, value) {
|
|
|
8694
8910
|
else
|
|
8695
8911
|
stepModels[step] = value;
|
|
8696
8912
|
raw.stepModels = stepModels;
|
|
8697
|
-
|
|
8698
|
-
|
|
8913
|
+
mkdirSync8(dirname9(configFile), { recursive: true });
|
|
8914
|
+
writeFileSync4(configFile, `${JSON.stringify(raw, null, 2)}
|
|
8699
8915
|
`);
|
|
8700
8916
|
}
|
|
8701
8917
|
function field(view, key) {
|
|
@@ -9072,9 +9288,9 @@ var init_system_exec = __esm(() => {
|
|
|
9072
9288
|
});
|
|
9073
9289
|
|
|
9074
9290
|
// src/services/setup.ts
|
|
9075
|
-
import { copyFileSync, existsSync as
|
|
9076
|
-
import { dirname as
|
|
9077
|
-
import { fileURLToPath as
|
|
9291
|
+
import { copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
9292
|
+
import { dirname as dirname10, join as join17 } from "path";
|
|
9293
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
9078
9294
|
async function writeGitIdentity(exec, identity) {
|
|
9079
9295
|
const name = identity.name.trim();
|
|
9080
9296
|
const email = identity.email.trim();
|
|
@@ -9149,16 +9365,16 @@ async function resolveRuntime(exec, preferred) {
|
|
|
9149
9365
|
function resolveSandcastleBin() {
|
|
9150
9366
|
try {
|
|
9151
9367
|
const mainUrl = import.meta.resolve("@ai-hero/sandcastle");
|
|
9152
|
-
let dir =
|
|
9368
|
+
let dir = dirname10(fileURLToPath7(mainUrl));
|
|
9153
9369
|
for (let hops = 0;hops < 6; hops++) {
|
|
9154
|
-
const manifestPath =
|
|
9155
|
-
if (
|
|
9156
|
-
const manifest = JSON.parse(
|
|
9370
|
+
const manifestPath = join17(dir, "package.json");
|
|
9371
|
+
if (existsSync18(manifestPath)) {
|
|
9372
|
+
const manifest = JSON.parse(readFileSync9(manifestPath, "utf8"));
|
|
9157
9373
|
if (manifest.name === "@ai-hero/sandcastle" && manifest.bin?.sandcastle) {
|
|
9158
|
-
return
|
|
9374
|
+
return join17(dir, manifest.bin.sandcastle);
|
|
9159
9375
|
}
|
|
9160
9376
|
}
|
|
9161
|
-
const parent =
|
|
9377
|
+
const parent = dirname10(dir);
|
|
9162
9378
|
if (parent === dir)
|
|
9163
9379
|
break;
|
|
9164
9380
|
dir = parent;
|
|
@@ -9180,21 +9396,21 @@ function terminalSpec(kind, opts) {
|
|
|
9180
9396
|
};
|
|
9181
9397
|
}
|
|
9182
9398
|
function sandcastleTemplateDir() {
|
|
9183
|
-
return resolveAsset(ASSET_ENV.sandcastleTemplate,
|
|
9399
|
+
return resolveAsset(ASSET_ENV.sandcastleTemplate, fileURLToPath7(new URL("../assets/sandcastle", import.meta.url)));
|
|
9184
9400
|
}
|
|
9185
9401
|
function scaffoldSandcastleConfig(templateDir, targetDir) {
|
|
9186
|
-
const dir =
|
|
9187
|
-
if (
|
|
9402
|
+
const dir = join17(targetDir, ".sandcastle");
|
|
9403
|
+
if (existsSync18(dir))
|
|
9188
9404
|
return { scaffolded: false, dir };
|
|
9189
|
-
|
|
9405
|
+
mkdirSync9(dir, { recursive: true });
|
|
9190
9406
|
for (const name of readdirSync6(templateDir)) {
|
|
9191
|
-
copyFileSync(
|
|
9407
|
+
copyFileSync(join17(templateDir, name), join17(dir, name));
|
|
9192
9408
|
}
|
|
9193
9409
|
return { scaffolded: true, dir };
|
|
9194
9410
|
}
|
|
9195
9411
|
function prepareSandboxBuildContext() {
|
|
9196
9412
|
const target = sandboxBuildDir();
|
|
9197
|
-
|
|
9413
|
+
mkdirSync9(target, { recursive: true });
|
|
9198
9414
|
scaffoldSandcastleConfig(sandcastleTemplateDir(), target);
|
|
9199
9415
|
return target;
|
|
9200
9416
|
}
|
|
@@ -9230,10 +9446,10 @@ function createTokenVerifier(exec) {
|
|
|
9230
9446
|
function fileAfkTokenIo(exec) {
|
|
9231
9447
|
const path = envPath();
|
|
9232
9448
|
return {
|
|
9233
|
-
read: () =>
|
|
9449
|
+
read: () => existsSync18(path) ? readFileSync9(path, "utf8") : "",
|
|
9234
9450
|
write: (content) => {
|
|
9235
|
-
|
|
9236
|
-
|
|
9451
|
+
mkdirSync9(dirname10(path), { recursive: true });
|
|
9452
|
+
writeFileSync5(path, content, "utf8");
|
|
9237
9453
|
},
|
|
9238
9454
|
verify: createTokenVerifier(exec)
|
|
9239
9455
|
};
|
|
@@ -9286,110 +9502,6 @@ var init_setup2 = __esm(() => {
|
|
|
9286
9502
|
});
|
|
9287
9503
|
});
|
|
9288
9504
|
|
|
9289
|
-
// src/version.ts
|
|
9290
|
-
import { readFileSync as readFileSync8 } from "fs";
|
|
9291
|
-
import { dirname as dirname9, join as join17 } from "path";
|
|
9292
|
-
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
9293
|
-
function runcastleVersion() {
|
|
9294
|
-
if (cached2)
|
|
9295
|
-
return cached2;
|
|
9296
|
-
const here = dirname9(fileURLToPath7(import.meta.url));
|
|
9297
|
-
for (const pkgPath of [join17(here, "..", "package.json"), join17(here, "package.json")]) {
|
|
9298
|
-
try {
|
|
9299
|
-
const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
9300
|
-
if (typeof pkg.version === "string") {
|
|
9301
|
-
cached2 = pkg.version;
|
|
9302
|
-
return cached2;
|
|
9303
|
-
}
|
|
9304
|
-
} catch {}
|
|
9305
|
-
}
|
|
9306
|
-
cached2 = UNKNOWN_VERSION;
|
|
9307
|
-
return cached2;
|
|
9308
|
-
}
|
|
9309
|
-
var cached2, UNKNOWN_VERSION = "0.0.0";
|
|
9310
|
-
var init_version = () => {};
|
|
9311
|
-
|
|
9312
|
-
// src/services/update-check.ts
|
|
9313
|
-
function parse(version) {
|
|
9314
|
-
const cleaned = version.trim().replace(/^v/, "");
|
|
9315
|
-
const [core = "", pre = ""] = cleaned.split("-", 2);
|
|
9316
|
-
const release2 = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
9317
|
-
return { release: release2, pre: pre ? pre.split(".") : [] };
|
|
9318
|
-
}
|
|
9319
|
-
function compareSemver(a, b) {
|
|
9320
|
-
const pa = parse(a);
|
|
9321
|
-
const pb = parse(b);
|
|
9322
|
-
const len = Math.max(pa.release.length, pb.release.length);
|
|
9323
|
-
for (let i = 0;i < len; i++) {
|
|
9324
|
-
const diff = (pa.release[i] ?? 0) - (pb.release[i] ?? 0);
|
|
9325
|
-
if (diff !== 0)
|
|
9326
|
-
return diff;
|
|
9327
|
-
}
|
|
9328
|
-
if (pa.pre.length === 0 && pb.pre.length === 0)
|
|
9329
|
-
return 0;
|
|
9330
|
-
if (pa.pre.length === 0)
|
|
9331
|
-
return 1;
|
|
9332
|
-
if (pb.pre.length === 0)
|
|
9333
|
-
return -1;
|
|
9334
|
-
const preLen = Math.max(pa.pre.length, pb.pre.length);
|
|
9335
|
-
for (let i = 0;i < preLen; i++) {
|
|
9336
|
-
const x = pa.pre[i];
|
|
9337
|
-
const y = pb.pre[i];
|
|
9338
|
-
if (x === undefined)
|
|
9339
|
-
return -1;
|
|
9340
|
-
if (y === undefined)
|
|
9341
|
-
return 1;
|
|
9342
|
-
const nx = Number(x);
|
|
9343
|
-
const ny = Number(y);
|
|
9344
|
-
const bothNumeric = !Number.isNaN(nx) && !Number.isNaN(ny);
|
|
9345
|
-
const cmp = bothNumeric ? nx - ny : x < y ? -1 : x > y ? 1 : 0;
|
|
9346
|
-
if (cmp !== 0)
|
|
9347
|
-
return cmp;
|
|
9348
|
-
}
|
|
9349
|
-
return 0;
|
|
9350
|
-
}
|
|
9351
|
-
async function checkForUpdate(opts) {
|
|
9352
|
-
const { current: current2 } = opts;
|
|
9353
|
-
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
9354
|
-
if (current2 === UNKNOWN_VERSION)
|
|
9355
|
-
return NO_UPDATE(current2);
|
|
9356
|
-
try {
|
|
9357
|
-
const res = await fetchImpl(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
|
|
9358
|
-
if (!res.ok)
|
|
9359
|
-
return NO_UPDATE(current2);
|
|
9360
|
-
const body = await res.json();
|
|
9361
|
-
const latest = typeof body.version === "string" ? body.version : null;
|
|
9362
|
-
if (!latest)
|
|
9363
|
-
return NO_UPDATE(current2);
|
|
9364
|
-
return {
|
|
9365
|
-
current: current2,
|
|
9366
|
-
latest,
|
|
9367
|
-
updateAvailable: compareSemver(latest, current2) > 0,
|
|
9368
|
-
command: UPDATE_COMMAND
|
|
9369
|
-
};
|
|
9370
|
-
} catch {
|
|
9371
|
-
return NO_UPDATE(current2);
|
|
9372
|
-
}
|
|
9373
|
-
}
|
|
9374
|
-
async function getUpdateInfo(current2, fetchImpl) {
|
|
9375
|
-
if (cache)
|
|
9376
|
-
return cache;
|
|
9377
|
-
const info = await checkForUpdate({ current: current2, fetchImpl });
|
|
9378
|
-
if (info.latest !== null)
|
|
9379
|
-
cache = info;
|
|
9380
|
-
return info;
|
|
9381
|
-
}
|
|
9382
|
-
var PACKAGE_NAME = "runcastle", UPDATE_COMMAND, NO_UPDATE = (current2) => ({
|
|
9383
|
-
current: current2,
|
|
9384
|
-
latest: null,
|
|
9385
|
-
updateAvailable: false,
|
|
9386
|
-
command: UPDATE_COMMAND
|
|
9387
|
-
}), cache;
|
|
9388
|
-
var init_update_check = __esm(() => {
|
|
9389
|
-
init_version();
|
|
9390
|
-
UPDATE_COMMAND = `bun add -g ${PACKAGE_NAME}@latest`;
|
|
9391
|
-
});
|
|
9392
|
-
|
|
9393
9505
|
// src/trpc/routers/system.ts
|
|
9394
9506
|
var systemRouter;
|
|
9395
9507
|
var init_system = __esm(() => {
|
|
@@ -9403,8 +9515,8 @@ var init_system = __esm(() => {
|
|
|
9403
9515
|
});
|
|
9404
9516
|
|
|
9405
9517
|
// src/services/test-notes.ts
|
|
9406
|
-
import { mkdirSync as
|
|
9407
|
-
import { dirname as
|
|
9518
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
9519
|
+
import { dirname as dirname11 } from "path";
|
|
9408
9520
|
import { asc as asc4, eq as eq14 } from "drizzle-orm";
|
|
9409
9521
|
function rowToNote(row) {
|
|
9410
9522
|
return {
|
|
@@ -9549,8 +9661,8 @@ function renderTestNotes(ctx, feature) {
|
|
|
9549
9661
|
lines.push(noteLine(ctx, note));
|
|
9550
9662
|
}
|
|
9551
9663
|
const path = featureDocPath(projectForFeature(ctx, feature), feature, "test-notes.md");
|
|
9552
|
-
|
|
9553
|
-
|
|
9664
|
+
mkdirSync10(dirname11(path), { recursive: true });
|
|
9665
|
+
writeFileSync6(path, `${lines.join(`
|
|
9554
9666
|
`)}
|
|
9555
9667
|
`, "utf8");
|
|
9556
9668
|
}
|
|
@@ -9749,6 +9861,7 @@ async function startServer() {
|
|
|
9749
9861
|
websocket: terminalWebSocket
|
|
9750
9862
|
});
|
|
9751
9863
|
console.log(`runcastle${process.env.RUNCASTLE_DEV ? " [dev]" : ""} server listening on ` + `http://localhost:${config2.serverPort} \u2014 data dir: ${dataDir()}`);
|
|
9864
|
+
getUpdateInfo(runcastleVersion()).catch(() => {});
|
|
9752
9865
|
const SHUTDOWN_KEY = Symbol.for("runcastle.shutdown.wired");
|
|
9753
9866
|
const g = globalThis;
|
|
9754
9867
|
if (!g[SHUTDOWN_KEY]) {
|
|
@@ -9774,7 +9887,9 @@ var init_src2 = __esm(() => {
|
|
|
9774
9887
|
init_hooks();
|
|
9775
9888
|
init_stream();
|
|
9776
9889
|
init_web();
|
|
9890
|
+
init_update_check();
|
|
9777
9891
|
init_router();
|
|
9892
|
+
init_version();
|
|
9778
9893
|
init_reconcile_runs();
|
|
9779
9894
|
});
|
|
9780
9895
|
|
|
@@ -9832,7 +9947,7 @@ __export(exports_cli, {
|
|
|
9832
9947
|
resolveDoctorEnv: () => resolveDoctorEnv,
|
|
9833
9948
|
parseMode: () => parseMode
|
|
9834
9949
|
});
|
|
9835
|
-
import { existsSync as
|
|
9950
|
+
import { existsSync as existsSync19, readFileSync as readFileSync10 } from "fs";
|
|
9836
9951
|
function parseMode(argv) {
|
|
9837
9952
|
return argv.includes("--gate") || argv.includes("--boot") ? "gate" : "diagnostic";
|
|
9838
9953
|
}
|
|
@@ -9840,8 +9955,8 @@ function envWithToken() {
|
|
|
9840
9955
|
const merged = { ...process.env };
|
|
9841
9956
|
try {
|
|
9842
9957
|
const path = envPath();
|
|
9843
|
-
if (
|
|
9844
|
-
const fromFile = parseEnvFile(
|
|
9958
|
+
if (existsSync19(path)) {
|
|
9959
|
+
const fromFile = parseEnvFile(readFileSync10(path, "utf8")).CLAUDE_CODE_OAUTH_TOKEN;
|
|
9845
9960
|
if (fromFile && fromFile.length > 0)
|
|
9846
9961
|
merged.CLAUDE_CODE_OAUTH_TOKEN = fromFile;
|
|
9847
9962
|
}
|
|
@@ -9883,7 +9998,7 @@ var init_cli = __esm(() => {
|
|
|
9883
9998
|
// src/bin/runcastle.ts
|
|
9884
9999
|
init_asset_paths();
|
|
9885
10000
|
init_version();
|
|
9886
|
-
import { dirname as
|
|
10001
|
+
import { dirname as dirname12, resolve as resolve11 } from "path";
|
|
9887
10002
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
9888
10003
|
function parseCommand(argv) {
|
|
9889
10004
|
const [first, ...rest] = argv;
|
|
@@ -9908,7 +10023,7 @@ Usage:
|
|
|
9908
10023
|
runcastle --help Show this help
|
|
9909
10024
|
`;
|
|
9910
10025
|
async function main(argv) {
|
|
9911
|
-
applyInstalledAssetEnv(resolve11(
|
|
10026
|
+
applyInstalledAssetEnv(resolve11(dirname12(fileURLToPath8(import.meta.url)), ".."));
|
|
9912
10027
|
const { command, args } = parseCommand(argv);
|
|
9913
10028
|
switch (command) {
|
|
9914
10029
|
case "version":
|