spacecode 2.10.1 → 2.10.3
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/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/repl.mjs +269 -1357
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -3490,12 +3490,6 @@ function truncateOutput(text, maxChars) {
|
|
|
3490
3490
|
|
|
3491
3491
|
` + text.slice(text.length - effectiveTail);
|
|
3492
3492
|
}
|
|
3493
|
-
function createSimpleRouter(opts) {
|
|
3494
|
-
const threshold = opts.complexAfterTurn ?? 5;
|
|
3495
|
-
return (turn, _lastToolCount) => {
|
|
3496
|
-
return turn > threshold ? opts.complex : opts.default;
|
|
3497
|
-
};
|
|
3498
|
-
}
|
|
3499
3493
|
async function runAgentLoop(prompt, config, executor, emit, signal, existingMessages) {
|
|
3500
3494
|
const defaultModel = config.model ?? DEFAULT_MODEL;
|
|
3501
3495
|
const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
@@ -4211,98 +4205,9 @@ ${s.lines.join("\n")}`)].join("\n");
|
|
|
4211
4205
|
});
|
|
4212
4206
|
|
|
4213
4207
|
// ../agent/src/storage/file-store.ts
|
|
4214
|
-
var FileStore;
|
|
4215
4208
|
var init_file_store = __esm({
|
|
4216
4209
|
"../agent/src/storage/file-store.ts"() {
|
|
4217
4210
|
"use strict";
|
|
4218
|
-
FileStore = class {
|
|
4219
|
-
constructor(db, sessionId) {
|
|
4220
|
-
this.db = db;
|
|
4221
|
-
this.sessionId = sessionId;
|
|
4222
|
-
}
|
|
4223
|
-
async readFile(path12) {
|
|
4224
|
-
const stmt = this.db.prepare(
|
|
4225
|
-
"SELECT content, status FROM session_files WHERE session_id = ? AND path = ?"
|
|
4226
|
-
).bind(this.sessionId, path12);
|
|
4227
|
-
const row = await stmt.first();
|
|
4228
|
-
if (row) {
|
|
4229
|
-
if (row.status === "deleted") return null;
|
|
4230
|
-
if (row.content !== null) return row.content;
|
|
4231
|
-
}
|
|
4232
|
-
return null;
|
|
4233
|
-
}
|
|
4234
|
-
async writeFile(path12, content) {
|
|
4235
|
-
await this.db.prepare(
|
|
4236
|
-
`INSERT OR REPLACE INTO session_files (session_id, path, status, content, updated_at)
|
|
4237
|
-
VALUES (?, ?, 'created', ?, ?)`
|
|
4238
|
-
).bind(this.sessionId, path12, content, Date.now()).run();
|
|
4239
|
-
}
|
|
4240
|
-
async editFile(path12, oldStr, newStr) {
|
|
4241
|
-
const content = await this.readFile(path12);
|
|
4242
|
-
if (content === null) {
|
|
4243
|
-
return { success: false, error: `File not found: ${path12}` };
|
|
4244
|
-
}
|
|
4245
|
-
if (!content.includes(oldStr)) {
|
|
4246
|
-
return { success: false, error: `String not found in ${path12}` };
|
|
4247
|
-
}
|
|
4248
|
-
const occurrences = content.split(oldStr).length - 1;
|
|
4249
|
-
if (occurrences > 1) {
|
|
4250
|
-
return { success: false, error: `String appears ${occurrences} times in ${path12}. Provide more context to make it unique.` };
|
|
4251
|
-
}
|
|
4252
|
-
const newContent = content.replace(oldStr, newStr);
|
|
4253
|
-
await this.db.prepare(
|
|
4254
|
-
`INSERT OR REPLACE INTO session_files (session_id, path, status, content, updated_at)
|
|
4255
|
-
VALUES (?, ?, 'modified', ?, ?)`
|
|
4256
|
-
).bind(this.sessionId, path12, newContent, Date.now()).run();
|
|
4257
|
-
return { success: true };
|
|
4258
|
-
}
|
|
4259
|
-
async listDirectory(dirPath) {
|
|
4260
|
-
const prefix = dirPath.endsWith("/") ? dirPath : `${dirPath}/`;
|
|
4261
|
-
const stmt = this.db.prepare(
|
|
4262
|
-
`SELECT DISTINCT path FROM session_files
|
|
4263
|
-
WHERE session_id = ? AND path LIKE ? AND status != 'deleted'`
|
|
4264
|
-
).bind(this.sessionId, `${prefix}%`);
|
|
4265
|
-
const { results } = await stmt.all();
|
|
4266
|
-
const children = /* @__PURE__ */ new Set();
|
|
4267
|
-
for (const row of results) {
|
|
4268
|
-
const relative2 = row.path.slice(prefix.length);
|
|
4269
|
-
const firstSlash = relative2.indexOf("/");
|
|
4270
|
-
if (firstSlash === -1) {
|
|
4271
|
-
children.add(relative2);
|
|
4272
|
-
} else {
|
|
4273
|
-
children.add(relative2.slice(0, firstSlash + 1));
|
|
4274
|
-
}
|
|
4275
|
-
}
|
|
4276
|
-
return Array.from(children).sort();
|
|
4277
|
-
}
|
|
4278
|
-
async getDirtyFiles() {
|
|
4279
|
-
const stmt = this.db.prepare(
|
|
4280
|
-
`SELECT path, content, status FROM session_files
|
|
4281
|
-
WHERE session_id = ? AND status IN ('modified', 'created')`
|
|
4282
|
-
).bind(this.sessionId);
|
|
4283
|
-
const { results } = await stmt.all();
|
|
4284
|
-
return results;
|
|
4285
|
-
}
|
|
4286
|
-
async markClean(paths) {
|
|
4287
|
-
if (paths.length === 0) return;
|
|
4288
|
-
const stmts = paths.map(
|
|
4289
|
-
(p) => this.db.prepare(
|
|
4290
|
-
`UPDATE session_files SET status = 'clean', updated_at = ? WHERE session_id = ? AND path = ?`
|
|
4291
|
-
).bind(Date.now(), this.sessionId, p)
|
|
4292
|
-
);
|
|
4293
|
-
await this.db.batch(stmts);
|
|
4294
|
-
}
|
|
4295
|
-
async upsertFiles(files) {
|
|
4296
|
-
if (files.length === 0) return;
|
|
4297
|
-
const stmts = files.map(
|
|
4298
|
-
(f) => this.db.prepare(
|
|
4299
|
-
`INSERT OR REPLACE INTO session_files (session_id, path, status, content, updated_at)
|
|
4300
|
-
VALUES (?, ?, ?, ?, ?)`
|
|
4301
|
-
).bind(this.sessionId, f.path, f.status, f.content, Date.now())
|
|
4302
|
-
);
|
|
4303
|
-
await this.db.batch(stmts);
|
|
4304
|
-
}
|
|
4305
|
-
};
|
|
4306
4211
|
}
|
|
4307
4212
|
});
|
|
4308
4213
|
|
|
@@ -4329,9 +4234,9 @@ function createFileTools(store) {
|
|
|
4329
4234
|
readCache.clear();
|
|
4330
4235
|
listCache.clear();
|
|
4331
4236
|
}
|
|
4332
|
-
function invalidatePath(
|
|
4333
|
-
readCache.delete(
|
|
4334
|
-
const parent =
|
|
4237
|
+
function invalidatePath(path13) {
|
|
4238
|
+
readCache.delete(path13);
|
|
4239
|
+
const parent = path13.includes("/") ? path13.slice(0, path13.lastIndexOf("/") + 1) : "";
|
|
4335
4240
|
listCache.delete(parent);
|
|
4336
4241
|
listCache.delete("");
|
|
4337
4242
|
listCache.delete(".");
|
|
@@ -4339,36 +4244,36 @@ function createFileTools(store) {
|
|
|
4339
4244
|
}
|
|
4340
4245
|
const handlers = {
|
|
4341
4246
|
read_file: async (input) => {
|
|
4342
|
-
const
|
|
4343
|
-
const cached3 = readCache.get(
|
|
4247
|
+
const path13 = input.path;
|
|
4248
|
+
const cached3 = readCache.get(path13);
|
|
4344
4249
|
if (cached3 !== void 0) {
|
|
4345
4250
|
return { output: cached3 };
|
|
4346
4251
|
}
|
|
4347
|
-
const content = await store.readFile(
|
|
4252
|
+
const content = await store.readFile(path13);
|
|
4348
4253
|
if (content === null) {
|
|
4349
|
-
return { output: `File not found: ${
|
|
4254
|
+
return { output: `File not found: ${path13}`, is_error: true };
|
|
4350
4255
|
}
|
|
4351
|
-
readCache.set(
|
|
4256
|
+
readCache.set(path13, content);
|
|
4352
4257
|
return { output: content };
|
|
4353
4258
|
},
|
|
4354
4259
|
write_file: async (input) => {
|
|
4355
|
-
const
|
|
4260
|
+
const path13 = input.path;
|
|
4356
4261
|
const content = input.content;
|
|
4357
|
-
await store.writeFile(
|
|
4358
|
-
invalidatePath(
|
|
4359
|
-
readCache.set(
|
|
4360
|
-
return { output: `Written: ${
|
|
4262
|
+
await store.writeFile(path13, content);
|
|
4263
|
+
invalidatePath(path13);
|
|
4264
|
+
readCache.set(path13, content);
|
|
4265
|
+
return { output: `Written: ${path13}` };
|
|
4361
4266
|
},
|
|
4362
4267
|
edit_file: async (input) => {
|
|
4363
|
-
const
|
|
4268
|
+
const path13 = input.path;
|
|
4364
4269
|
const oldStr = input.old_string;
|
|
4365
4270
|
const newStr = input.new_string;
|
|
4366
|
-
let content = readCache.get(
|
|
4271
|
+
let content = readCache.get(path13);
|
|
4367
4272
|
if (content === void 0) {
|
|
4368
|
-
const stored = await store.readFile(
|
|
4273
|
+
const stored = await store.readFile(path13);
|
|
4369
4274
|
if (stored === null) {
|
|
4370
4275
|
return {
|
|
4371
|
-
output: `File not found: ${
|
|
4276
|
+
output: `File not found: ${path13}. Did you read the file first?`,
|
|
4372
4277
|
is_error: true
|
|
4373
4278
|
};
|
|
4374
4279
|
}
|
|
@@ -4378,41 +4283,41 @@ function createFileTools(store) {
|
|
|
4378
4283
|
if (lineNumbers.length === 0) {
|
|
4379
4284
|
const lineCount = content.split("\n").length;
|
|
4380
4285
|
return {
|
|
4381
|
-
output: `old_string not found in ${
|
|
4286
|
+
output: `old_string not found in ${path13}. The file has ${lineCount} lines. Did you read the file first?`,
|
|
4382
4287
|
is_error: true
|
|
4383
4288
|
};
|
|
4384
4289
|
}
|
|
4385
4290
|
if (lineNumbers.length > 1) {
|
|
4386
4291
|
const locations = lineNumbers.map((ln) => ` - line ${ln}`).join("\n");
|
|
4387
4292
|
return {
|
|
4388
|
-
output: `old_string matches ${lineNumbers.length} locations in ${
|
|
4293
|
+
output: `old_string matches ${lineNumbers.length} locations in ${path13}:
|
|
4389
4294
|
${locations}
|
|
4390
4295
|
Include more surrounding context to make old_string unique.`,
|
|
4391
4296
|
is_error: true
|
|
4392
4297
|
};
|
|
4393
4298
|
}
|
|
4394
|
-
const result = await store.editFile(
|
|
4299
|
+
const result = await store.editFile(path13, oldStr, newStr);
|
|
4395
4300
|
if (!result.success) {
|
|
4396
4301
|
return { output: result.error, is_error: true };
|
|
4397
4302
|
}
|
|
4398
|
-
invalidatePath(
|
|
4399
|
-
const updated = await store.readFile(
|
|
4400
|
-
if (updated !== null) readCache.set(
|
|
4401
|
-
return { output: `Edited: ${
|
|
4303
|
+
invalidatePath(path13);
|
|
4304
|
+
const updated = await store.readFile(path13);
|
|
4305
|
+
if (updated !== null) readCache.set(path13, updated);
|
|
4306
|
+
return { output: `Edited: ${path13}` };
|
|
4402
4307
|
},
|
|
4403
4308
|
list_directory: async (input) => {
|
|
4404
|
-
const
|
|
4405
|
-
const cached3 = listCache.get(
|
|
4309
|
+
const path13 = input.path;
|
|
4310
|
+
const cached3 = listCache.get(path13);
|
|
4406
4311
|
if (cached3 !== void 0) {
|
|
4407
4312
|
if (cached3.length === 0) {
|
|
4408
|
-
return { output: `Empty or not found: ${
|
|
4313
|
+
return { output: `Empty or not found: ${path13}` };
|
|
4409
4314
|
}
|
|
4410
4315
|
return { output: cached3.join("\n") };
|
|
4411
4316
|
}
|
|
4412
|
-
const entries = await store.listDirectory(
|
|
4413
|
-
listCache.set(
|
|
4317
|
+
const entries = await store.listDirectory(path13);
|
|
4318
|
+
listCache.set(path13, entries);
|
|
4414
4319
|
if (entries.length === 0) {
|
|
4415
|
-
return { output: `Empty or not found: ${
|
|
4320
|
+
return { output: `Empty or not found: ${path13}` };
|
|
4416
4321
|
}
|
|
4417
4322
|
return { output: entries.join("\n") };
|
|
4418
4323
|
}
|
|
@@ -4480,234 +4385,15 @@ var init_files = __esm({
|
|
|
4480
4385
|
});
|
|
4481
4386
|
|
|
4482
4387
|
// ../agent/src/storage/indexer.ts
|
|
4483
|
-
var
|
|
4388
|
+
var MAX_FILE_SIZE;
|
|
4484
4389
|
var init_indexer = __esm({
|
|
4485
4390
|
"../agent/src/storage/indexer.ts"() {
|
|
4486
4391
|
"use strict";
|
|
4487
|
-
CHUNK_SIZE = 500;
|
|
4488
|
-
CHUNK_OVERLAP = 100;
|
|
4489
|
-
BATCH_SIZE = 50;
|
|
4490
4392
|
MAX_FILE_SIZE = 100 * 1024;
|
|
4491
|
-
INDEXABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4492
|
-
".ts",
|
|
4493
|
-
".js",
|
|
4494
|
-
".py",
|
|
4495
|
-
".go",
|
|
4496
|
-
".rs",
|
|
4497
|
-
".java",
|
|
4498
|
-
".tsx",
|
|
4499
|
-
".jsx",
|
|
4500
|
-
".md",
|
|
4501
|
-
".json",
|
|
4502
|
-
".yaml",
|
|
4503
|
-
".yml",
|
|
4504
|
-
".toml",
|
|
4505
|
-
".sql",
|
|
4506
|
-
".sh",
|
|
4507
|
-
".css",
|
|
4508
|
-
".html"
|
|
4509
|
-
]);
|
|
4510
|
-
RepoIndexer = class {
|
|
4511
|
-
config;
|
|
4512
|
-
model;
|
|
4513
|
-
constructor(config) {
|
|
4514
|
-
this.config = config;
|
|
4515
|
-
this.model = config.embeddingModel || "@cf/bge-base-en-v1.5";
|
|
4516
|
-
}
|
|
4517
|
-
/**
|
|
4518
|
-
* Index files into Vectorize. Skips if repo+commit is already indexed.
|
|
4519
|
-
* Returns number of chunks indexed.
|
|
4520
|
-
*/
|
|
4521
|
-
async indexFiles(files) {
|
|
4522
|
-
const existing = await this.config.db.prepare(
|
|
4523
|
-
"SELECT COUNT(*) as count FROM repo_files WHERE repo_id = ? AND commit_sha = ?"
|
|
4524
|
-
).bind(this.config.repoId, this.config.commitSha).first();
|
|
4525
|
-
if (existing && existing.count > 0) {
|
|
4526
|
-
return 0;
|
|
4527
|
-
}
|
|
4528
|
-
const chunks = files.flatMap((f) => this.chunkFile(f.path, f.content));
|
|
4529
|
-
if (chunks.length === 0) return 0;
|
|
4530
|
-
let totalIndexed = 0;
|
|
4531
|
-
for (let i = 0; i < chunks.length; i += BATCH_SIZE) {
|
|
4532
|
-
const batch = chunks.slice(i, i + BATCH_SIZE);
|
|
4533
|
-
const texts = batch.map((c) => c.content);
|
|
4534
|
-
const embedResult = await this.config.ai.run(this.model, { text: texts });
|
|
4535
|
-
const vectors = batch.map((chunk, j2) => ({
|
|
4536
|
-
id: chunk.id,
|
|
4537
|
-
values: embedResult.data[j2],
|
|
4538
|
-
metadata: {
|
|
4539
|
-
path: chunk.path,
|
|
4540
|
-
repo_id: this.config.repoId,
|
|
4541
|
-
start_line: String(chunk.startLine),
|
|
4542
|
-
end_line: String(chunk.endLine)
|
|
4543
|
-
}
|
|
4544
|
-
}));
|
|
4545
|
-
await this.config.vectorize.upsert(vectors);
|
|
4546
|
-
totalIndexed += vectors.length;
|
|
4547
|
-
}
|
|
4548
|
-
const stmts = files.map(
|
|
4549
|
-
(f) => this.config.db.prepare(
|
|
4550
|
-
`INSERT OR REPLACE INTO repo_files (repo_id, commit_sha, path, size, hash)
|
|
4551
|
-
VALUES (?, ?, ?, ?, ?)`
|
|
4552
|
-
).bind(
|
|
4553
|
-
this.config.repoId,
|
|
4554
|
-
this.config.commitSha,
|
|
4555
|
-
f.path,
|
|
4556
|
-
f.content.length,
|
|
4557
|
-
this.simpleHash(f.content)
|
|
4558
|
-
)
|
|
4559
|
-
);
|
|
4560
|
-
for (let i = 0; i < stmts.length; i += 100) {
|
|
4561
|
-
await this.config.db.batch(stmts.slice(i, i + 100));
|
|
4562
|
-
}
|
|
4563
|
-
return totalIndexed;
|
|
4564
|
-
}
|
|
4565
|
-
/**
|
|
4566
|
-
* Delta re-index: index only files that changed.
|
|
4567
|
-
*/
|
|
4568
|
-
async reindexFile(path12, content) {
|
|
4569
|
-
const prefix = `${this.config.repoId}:${path12}:`;
|
|
4570
|
-
const oldIds = Array.from({ length: 100 }, (_2, i) => `${prefix}${i}`);
|
|
4571
|
-
await this.config.vectorize.deleteByIds(oldIds);
|
|
4572
|
-
const chunks = this.chunkFile(path12, content);
|
|
4573
|
-
if (chunks.length === 0) return 0;
|
|
4574
|
-
const texts = chunks.map((c) => c.content);
|
|
4575
|
-
const embedResult = await this.config.ai.run(this.model, { text: texts });
|
|
4576
|
-
const vectors = chunks.map((chunk, j2) => ({
|
|
4577
|
-
id: chunk.id,
|
|
4578
|
-
values: embedResult.data[j2],
|
|
4579
|
-
metadata: {
|
|
4580
|
-
path: chunk.path,
|
|
4581
|
-
repo_id: this.config.repoId,
|
|
4582
|
-
start_line: String(chunk.startLine),
|
|
4583
|
-
end_line: String(chunk.endLine)
|
|
4584
|
-
}
|
|
4585
|
-
}));
|
|
4586
|
-
await this.config.vectorize.upsert(vectors);
|
|
4587
|
-
return vectors.length;
|
|
4588
|
-
}
|
|
4589
|
-
/**
|
|
4590
|
-
* Check if a repo+commit is already indexed.
|
|
4591
|
-
*/
|
|
4592
|
-
async isIndexed() {
|
|
4593
|
-
const result = await this.config.db.prepare(
|
|
4594
|
-
"SELECT COUNT(*) as count FROM repo_files WHERE repo_id = ? AND commit_sha = ?"
|
|
4595
|
-
).bind(this.config.repoId, this.config.commitSha).first();
|
|
4596
|
-
return (result?.count ?? 0) > 0;
|
|
4597
|
-
}
|
|
4598
|
-
/**
|
|
4599
|
-
* Read all files from a FileStore and index those with indexable extensions.
|
|
4600
|
-
* Skips files larger than 100KB.
|
|
4601
|
-
* Returns the number of chunks indexed.
|
|
4602
|
-
*/
|
|
4603
|
-
async indexFromStore(store, basePath = "/") {
|
|
4604
|
-
const storeDb = store.db;
|
|
4605
|
-
const sessionId = store.sessionId;
|
|
4606
|
-
const prefix = basePath === "/" ? "" : basePath;
|
|
4607
|
-
const allFiles = await storeDb.prepare(
|
|
4608
|
-
`SELECT path, content FROM session_files
|
|
4609
|
-
WHERE session_id = ? AND status != 'deleted' AND path LIKE ?`
|
|
4610
|
-
).bind(sessionId, `${prefix}%`).all();
|
|
4611
|
-
const files = [];
|
|
4612
|
-
for (const row of allFiles.results) {
|
|
4613
|
-
const dotIndex = row.path.lastIndexOf(".");
|
|
4614
|
-
if (dotIndex === -1) continue;
|
|
4615
|
-
const ext = row.path.slice(dotIndex);
|
|
4616
|
-
if (!INDEXABLE_EXTENSIONS.has(ext)) continue;
|
|
4617
|
-
if (row.content && row.content.length > MAX_FILE_SIZE) continue;
|
|
4618
|
-
if (!row.content) continue;
|
|
4619
|
-
files.push({ path: row.path, content: row.content });
|
|
4620
|
-
}
|
|
4621
|
-
if (files.length === 0) return 0;
|
|
4622
|
-
return this.indexFiles(files);
|
|
4623
|
-
}
|
|
4624
|
-
chunkFile(path12, content) {
|
|
4625
|
-
if (content.length === 0) return [];
|
|
4626
|
-
const chunks = [];
|
|
4627
|
-
let charPos = 0;
|
|
4628
|
-
let lineNum = 1;
|
|
4629
|
-
let chunkIndex = 0;
|
|
4630
|
-
while (charPos < content.length) {
|
|
4631
|
-
const chunkContent = content.slice(charPos, charPos + CHUNK_SIZE);
|
|
4632
|
-
const startLine = lineNum;
|
|
4633
|
-
const linesInChunk = chunkContent.split("\n").length - 1;
|
|
4634
|
-
const endLine = startLine + linesInChunk;
|
|
4635
|
-
chunks.push({
|
|
4636
|
-
id: `${this.config.repoId}:${path12}:${chunkIndex}`,
|
|
4637
|
-
path: path12,
|
|
4638
|
-
content: chunkContent,
|
|
4639
|
-
startLine,
|
|
4640
|
-
endLine
|
|
4641
|
-
});
|
|
4642
|
-
chunkIndex++;
|
|
4643
|
-
const advance = CHUNK_SIZE - CHUNK_OVERLAP;
|
|
4644
|
-
charPos += advance;
|
|
4645
|
-
const advancedContent = content.slice(charPos - advance, charPos);
|
|
4646
|
-
lineNum += (advancedContent.match(/\n/g) || []).length;
|
|
4647
|
-
}
|
|
4648
|
-
return chunks;
|
|
4649
|
-
}
|
|
4650
|
-
simpleHash(content) {
|
|
4651
|
-
let hash = 0;
|
|
4652
|
-
for (let i = 0; i < content.length; i++) {
|
|
4653
|
-
const char = content.charCodeAt(i);
|
|
4654
|
-
hash = (hash << 5) - hash + char;
|
|
4655
|
-
hash |= 0;
|
|
4656
|
-
}
|
|
4657
|
-
return hash.toString(16);
|
|
4658
|
-
}
|
|
4659
|
-
};
|
|
4660
4393
|
}
|
|
4661
4394
|
});
|
|
4662
4395
|
|
|
4663
4396
|
// ../agent/src/tools/search.ts
|
|
4664
|
-
function createSearchTool(config) {
|
|
4665
|
-
const model = config.embeddingModel || "@cf/bge-base-en-v1.5";
|
|
4666
|
-
return async (input) => {
|
|
4667
|
-
const query = input.query;
|
|
4668
|
-
const limit = input.limit || 10;
|
|
4669
|
-
if (!query || query.trim().length === 0) {
|
|
4670
|
-
return { output: "Search query cannot be empty", is_error: true };
|
|
4671
|
-
}
|
|
4672
|
-
try {
|
|
4673
|
-
let embedResult;
|
|
4674
|
-
try {
|
|
4675
|
-
embedResult = await config.ai.run(model, { text: [query] });
|
|
4676
|
-
} catch {
|
|
4677
|
-
return { output: `Semantic search is not available. Use the bash tool with grep to search the codebase instead.
|
|
4678
|
-
Example: bash -c "grep -rn 'pattern' ."` };
|
|
4679
|
-
}
|
|
4680
|
-
const queryVector = embedResult.data[0];
|
|
4681
|
-
const results = await config.vectorize.query(queryVector, {
|
|
4682
|
-
topK: limit,
|
|
4683
|
-
filter: { repo_id: config.repoId },
|
|
4684
|
-
returnMetadata: "all"
|
|
4685
|
-
});
|
|
4686
|
-
if (results.matches.length === 0) {
|
|
4687
|
-
return { output: "No results found." };
|
|
4688
|
-
}
|
|
4689
|
-
const byFile = /* @__PURE__ */ new Map();
|
|
4690
|
-
for (const match of results.matches) {
|
|
4691
|
-
const path12 = match.metadata?.path ?? "unknown";
|
|
4692
|
-
if (!byFile.has(path12)) byFile.set(path12, []);
|
|
4693
|
-
byFile.get(path12).push({
|
|
4694
|
-
score: match.score,
|
|
4695
|
-
startLine: match.metadata?.start_line ?? "?",
|
|
4696
|
-
endLine: match.metadata?.end_line ?? "?"
|
|
4697
|
-
});
|
|
4698
|
-
}
|
|
4699
|
-
const lines2 = [];
|
|
4700
|
-
for (const [path12, matches] of byFile) {
|
|
4701
|
-
const bestScore = Math.max(...matches.map((m2) => m2.score));
|
|
4702
|
-
const lineRanges = matches.sort((a, b2) => Number(a.startLine) - Number(b2.startLine)).map((m2) => `L${m2.startLine}-${m2.endLine}`).join(", ");
|
|
4703
|
-
lines2.push(`${path12} (score: ${bestScore.toFixed(3)}) \u2014 ${lineRanges}`);
|
|
4704
|
-
}
|
|
4705
|
-
return { output: lines2.join("\n") };
|
|
4706
|
-
} catch (err) {
|
|
4707
|
-
return { output: `Search failed: ${err instanceof Error ? err.message : String(err)}`, is_error: true };
|
|
4708
|
-
}
|
|
4709
|
-
};
|
|
4710
|
-
}
|
|
4711
4397
|
function createHostSearchTool(exec2) {
|
|
4712
4398
|
return async (input) => {
|
|
4713
4399
|
const query = input.query;
|
|
@@ -4748,126 +4434,9 @@ var init_search = __esm({
|
|
|
4748
4434
|
});
|
|
4749
4435
|
|
|
4750
4436
|
// ../agent/src/tools/sentry.ts
|
|
4751
|
-
function formatIssue(issue) {
|
|
4752
|
-
return `[${issue.shortId}] ${issue.title}
|
|
4753
|
-
Level: ${issue.level} | Count: ${issue.count} | Last seen: ${issue.lastSeen}`;
|
|
4754
|
-
}
|
|
4755
|
-
function formatIssueDetail(issue) {
|
|
4756
|
-
const lines2 = [];
|
|
4757
|
-
lines2.push(`Issue: ${issue.shortId} (${issue.id})`);
|
|
4758
|
-
lines2.push(`Title: ${issue.title}`);
|
|
4759
|
-
lines2.push(`Culprit: ${issue.culprit}`);
|
|
4760
|
-
lines2.push(`Level: ${issue.level} | Count: ${issue.count}`);
|
|
4761
|
-
lines2.push(`First seen: ${issue.firstSeen}`);
|
|
4762
|
-
lines2.push(`Last seen: ${issue.lastSeen}`);
|
|
4763
|
-
if (issue.metadata.type || issue.metadata.value) {
|
|
4764
|
-
lines2.push(`
|
|
4765
|
-
Error: ${issue.metadata.type ?? ""}: ${issue.metadata.value ?? ""}`);
|
|
4766
|
-
}
|
|
4767
|
-
if (issue.tags.length > 0) {
|
|
4768
|
-
lines2.push(`
|
|
4769
|
-
Tags:`);
|
|
4770
|
-
for (const tag of issue.tags) {
|
|
4771
|
-
lines2.push(` ${tag.key}: ${tag.value}`);
|
|
4772
|
-
}
|
|
4773
|
-
}
|
|
4774
|
-
if (issue.stackTrace && issue.stackTrace.length > 0) {
|
|
4775
|
-
lines2.push(`
|
|
4776
|
-
Stack trace:`);
|
|
4777
|
-
for (const frame of issue.stackTrace) {
|
|
4778
|
-
lines2.push(` ${frame.filename}:${frame.lineNo} in ${frame.function}`);
|
|
4779
|
-
if (frame.context.length > 0) {
|
|
4780
|
-
for (const [lineNo, code] of frame.context) {
|
|
4781
|
-
const marker = lineNo === frame.lineNo ? ">" : " ";
|
|
4782
|
-
lines2.push(` ${marker} ${lineNo}: ${code}`);
|
|
4783
|
-
}
|
|
4784
|
-
}
|
|
4785
|
-
}
|
|
4786
|
-
}
|
|
4787
|
-
return lines2.join("\n");
|
|
4788
|
-
}
|
|
4789
|
-
function createSentryTools(fetchFn) {
|
|
4790
|
-
const handlers = {
|
|
4791
|
-
sentry_list_issues: async (input) => {
|
|
4792
|
-
const project = input.project;
|
|
4793
|
-
const query = input.query;
|
|
4794
|
-
const params = new URLSearchParams();
|
|
4795
|
-
if (project) params.set("project", project);
|
|
4796
|
-
if (query) params.set("query", query);
|
|
4797
|
-
const qs = params.toString();
|
|
4798
|
-
const path12 = `/api/sentry/issues${qs ? `?${qs}` : ""}`;
|
|
4799
|
-
try {
|
|
4800
|
-
const res = await fetchFn(path12);
|
|
4801
|
-
if (!res.ok) {
|
|
4802
|
-
const text = await res.text();
|
|
4803
|
-
return { output: `Sentry API error (${res.status}): ${text}`, is_error: true };
|
|
4804
|
-
}
|
|
4805
|
-
const issues = await res.json();
|
|
4806
|
-
if (issues.length === 0) {
|
|
4807
|
-
return { output: "No unresolved issues found." };
|
|
4808
|
-
}
|
|
4809
|
-
return { output: issues.map(formatIssue).join("\n\n") };
|
|
4810
|
-
} catch (err) {
|
|
4811
|
-
return { output: `Failed to list Sentry issues: ${err.message}`, is_error: true };
|
|
4812
|
-
}
|
|
4813
|
-
},
|
|
4814
|
-
sentry_get_issue: async (input) => {
|
|
4815
|
-
const issueId = input.issue_id;
|
|
4816
|
-
if (!issueId) {
|
|
4817
|
-
return { output: "Missing required parameter: issue_id", is_error: true };
|
|
4818
|
-
}
|
|
4819
|
-
try {
|
|
4820
|
-
const res = await fetchFn(`/api/sentry/issues/${encodeURIComponent(issueId)}`);
|
|
4821
|
-
if (!res.ok) {
|
|
4822
|
-
const text = await res.text();
|
|
4823
|
-
return { output: `Sentry API error (${res.status}): ${text}`, is_error: true };
|
|
4824
|
-
}
|
|
4825
|
-
const issue = await res.json();
|
|
4826
|
-
return { output: formatIssueDetail(issue) };
|
|
4827
|
-
} catch (err) {
|
|
4828
|
-
return { output: `Failed to get Sentry issue: ${err.message}`, is_error: true };
|
|
4829
|
-
}
|
|
4830
|
-
}
|
|
4831
|
-
};
|
|
4832
|
-
return { handlers };
|
|
4833
|
-
}
|
|
4834
|
-
var SENTRY_LIST_ISSUES_TOOL, SENTRY_GET_ISSUE_TOOL, SENTRY_TOOL_DEFINITIONS;
|
|
4835
4437
|
var init_sentry = __esm({
|
|
4836
4438
|
"../agent/src/tools/sentry.ts"() {
|
|
4837
4439
|
"use strict";
|
|
4838
|
-
SENTRY_LIST_ISSUES_TOOL = {
|
|
4839
|
-
name: "sentry_list_issues",
|
|
4840
|
-
description: "List unresolved Sentry issues. Optionally filter by project slug or search query.",
|
|
4841
|
-
input_schema: {
|
|
4842
|
-
type: "object",
|
|
4843
|
-
properties: {
|
|
4844
|
-
project: {
|
|
4845
|
-
type: "string",
|
|
4846
|
-
description: "Sentry project slug to filter by (optional)"
|
|
4847
|
-
},
|
|
4848
|
-
query: {
|
|
4849
|
-
type: "string",
|
|
4850
|
-
description: "Search query to filter issues (optional)"
|
|
4851
|
-
}
|
|
4852
|
-
},
|
|
4853
|
-
required: []
|
|
4854
|
-
}
|
|
4855
|
-
};
|
|
4856
|
-
SENTRY_GET_ISSUE_TOOL = {
|
|
4857
|
-
name: "sentry_get_issue",
|
|
4858
|
-
description: "Get detailed information about a Sentry issue including its stack trace.",
|
|
4859
|
-
input_schema: {
|
|
4860
|
-
type: "object",
|
|
4861
|
-
properties: {
|
|
4862
|
-
issue_id: {
|
|
4863
|
-
type: "string",
|
|
4864
|
-
description: "The Sentry issue ID"
|
|
4865
|
-
}
|
|
4866
|
-
},
|
|
4867
|
-
required: ["issue_id"]
|
|
4868
|
-
}
|
|
4869
|
-
};
|
|
4870
|
-
SENTRY_TOOL_DEFINITIONS = [SENTRY_LIST_ISSUES_TOOL, SENTRY_GET_ISSUE_TOOL];
|
|
4871
4440
|
}
|
|
4872
4441
|
});
|
|
4873
4442
|
|
|
@@ -4966,83 +4535,9 @@ var init_github = __esm({
|
|
|
4966
4535
|
});
|
|
4967
4536
|
|
|
4968
4537
|
// ../agent/src/tools/preview.ts
|
|
4969
|
-
function formatResult(body) {
|
|
4970
|
-
switch (body.status) {
|
|
4971
|
-
case "ready":
|
|
4972
|
-
return { output: `Preview ready: ${body.url}
|
|
4973
|
-
Framework: ${body.framework ?? "unknown"}` };
|
|
4974
|
-
case "starting":
|
|
4975
|
-
return {
|
|
4976
|
-
output: `Preview server is starting (still compiling). URL will be: ${body.url ?? "unknown"}
|
|
4977
|
-
Check again in a few seconds by calling this tool again.`
|
|
4978
|
-
};
|
|
4979
|
-
case "crashed":
|
|
4980
|
-
return {
|
|
4981
|
-
output: `Preview server crashed.${body.url ? ` URL was: ${body.url}` : ""}${body.exitCode !== void 0 ? ` Exit code: ${body.exitCode}` : ""}${body.logs ? `
|
|
4982
|
-
Logs:
|
|
4983
|
-
${body.logs}` : ""}${body.error ? `
|
|
4984
|
-
${body.error}` : ""}`,
|
|
4985
|
-
is_error: true
|
|
4986
|
-
};
|
|
4987
|
-
default:
|
|
4988
|
-
return { output: body.error ?? "Unknown preview status", is_error: true };
|
|
4989
|
-
}
|
|
4990
|
-
}
|
|
4991
|
-
function createPreviewTool(fetchFn) {
|
|
4992
|
-
return async (_input) => {
|
|
4993
|
-
let startBody;
|
|
4994
|
-
try {
|
|
4995
|
-
const startRes = await fetchFn("/preview", { method: "POST" });
|
|
4996
|
-
startBody = await startRes.json();
|
|
4997
|
-
if (!startRes.ok) {
|
|
4998
|
-
return { output: startBody.error ?? `Failed to start preview (HTTP ${startRes.status})`, is_error: true };
|
|
4999
|
-
}
|
|
5000
|
-
} catch (err) {
|
|
5001
|
-
return { output: `Failed to start preview: ${err.message}`, is_error: true };
|
|
5002
|
-
}
|
|
5003
|
-
if (startBody.status !== "starting") {
|
|
5004
|
-
return formatResult(startBody);
|
|
5005
|
-
}
|
|
5006
|
-
let lastPollError;
|
|
5007
|
-
for (let attempt = 0; attempt < POLL_ATTEMPTS; attempt++) {
|
|
5008
|
-
await new Promise((resolve2) => setTimeout(resolve2, POLL_DELAY_MS));
|
|
5009
|
-
try {
|
|
5010
|
-
const statusRes = await fetchFn("/preview", { method: "GET" });
|
|
5011
|
-
const statusBody = await statusRes.json();
|
|
5012
|
-
lastPollError = void 0;
|
|
5013
|
-
if (statusBody.status === "ready" || statusBody.status === "crashed") {
|
|
5014
|
-
return formatResult(statusBody);
|
|
5015
|
-
}
|
|
5016
|
-
} catch (err) {
|
|
5017
|
-
lastPollError = err instanceof Error ? err.message : String(err);
|
|
5018
|
-
console.error("Preview status poll failed, retrying", { error: lastPollError });
|
|
5019
|
-
}
|
|
5020
|
-
}
|
|
5021
|
-
if (lastPollError) {
|
|
5022
|
-
return {
|
|
5023
|
-
output: `Could not confirm preview status after ${POLL_ATTEMPTS} attempts (last error: ${lastPollError}). The server may still be starting, or status checks may be failing \u2014 try calling this tool again.`,
|
|
5024
|
-
is_error: true
|
|
5025
|
-
};
|
|
5026
|
-
}
|
|
5027
|
-
return formatResult(startBody);
|
|
5028
|
-
};
|
|
5029
|
-
}
|
|
5030
|
-
var PREVIEW_TOOL, PREVIEW_TOOL_DEFINITIONS, POLL_ATTEMPTS, POLL_DELAY_MS;
|
|
5031
4538
|
var init_preview = __esm({
|
|
5032
4539
|
"../agent/src/tools/preview.ts"() {
|
|
5033
4540
|
"use strict";
|
|
5034
|
-
PREVIEW_TOOL = {
|
|
5035
|
-
name: "preview",
|
|
5036
|
-
description: 'Start or check the status of the front-end dev server preview for this workspace and get a live URL to view the current state of the app. Call this after making a front-end change to verify it visually. The result distinguishes "starting" (server launching, still compiling) from "ready" (server is up, safe to view) from "crashed" (server process died \u2014 check logs in the result).',
|
|
5037
|
-
input_schema: {
|
|
5038
|
-
type: "object",
|
|
5039
|
-
properties: {},
|
|
5040
|
-
required: []
|
|
5041
|
-
}
|
|
5042
|
-
};
|
|
5043
|
-
PREVIEW_TOOL_DEFINITIONS = [PREVIEW_TOOL];
|
|
5044
|
-
POLL_ATTEMPTS = 3;
|
|
5045
|
-
POLL_DELAY_MS = 1500;
|
|
5046
4541
|
}
|
|
5047
4542
|
});
|
|
5048
4543
|
|
|
@@ -5109,414 +4604,23 @@ var init_todo = __esm({
|
|
|
5109
4604
|
});
|
|
5110
4605
|
|
|
5111
4606
|
// ../agent/src/tools/codegen.ts
|
|
5112
|
-
async function detectStackType(fileStore) {
|
|
5113
|
-
if (await fileStore.readFile("wrangler.toml") !== null || await fileStore.readFile("wrangler.jsonc") !== null) return "worker";
|
|
5114
|
-
if (await fileStore.readFile("app.json") !== null || await fileStore.readFile("expo.json") !== null) return "mobile";
|
|
5115
|
-
if (await fileStore.readFile("next.config.js") !== null || await fileStore.readFile("next.config.ts") !== null || await fileStore.readFile("next.config.mjs") !== null) return "pages";
|
|
5116
|
-
return "worker";
|
|
5117
|
-
}
|
|
5118
|
-
async function cancelBuild(baseUrl, buildId, authHeader) {
|
|
5119
|
-
try {
|
|
5120
|
-
const res = await fetch(`${baseUrl}/builds/${buildId}/cancel`, {
|
|
5121
|
-
method: "POST",
|
|
5122
|
-
headers: { "Authorization": authHeader }
|
|
5123
|
-
});
|
|
5124
|
-
if (!res.ok) console.error(`[codegen] cancel of build ${buildId} failed: HTTP ${res.status}`);
|
|
5125
|
-
} catch (err) {
|
|
5126
|
-
console.error(`[codegen] cancel of build ${buildId} failed:`, err);
|
|
5127
|
-
}
|
|
5128
|
-
}
|
|
5129
|
-
function createCodegenTools(fileStore, config) {
|
|
5130
|
-
const handlers = {
|
|
5131
|
-
build_feature: async (input, onOutput) => {
|
|
5132
|
-
const title = input.title;
|
|
5133
|
-
const requirements = input.requirements;
|
|
5134
|
-
const context = input.context;
|
|
5135
|
-
const stackTypeOverride = input.stackType;
|
|
5136
|
-
if (!title || !requirements) {
|
|
5137
|
-
return { output: "Missing required parameters: title and requirements", is_error: true };
|
|
5138
|
-
}
|
|
5139
|
-
const stackType = stackTypeOverride ?? await detectStackType(fileStore);
|
|
5140
|
-
const toolId = crypto.randomUUID();
|
|
5141
|
-
if (config.jwtToken) {
|
|
5142
|
-
const baseUrl = "https://api.codemindhq.dev";
|
|
5143
|
-
const authHeader = `Bearer ${config.jwtToken}`;
|
|
5144
|
-
onOutput?.(toolId, "stdout", `[codegen] Submitting build...
|
|
5145
|
-
`);
|
|
5146
|
-
const submitRes = await fetch(`${baseUrl}/builds`, {
|
|
5147
|
-
method: "POST",
|
|
5148
|
-
headers: { "Content-Type": "application/json", "Authorization": authHeader },
|
|
5149
|
-
body: JSON.stringify({
|
|
5150
|
-
product: config.product ?? "spacecode",
|
|
5151
|
-
repoUrl: config.repoUrl,
|
|
5152
|
-
storyTitle: title,
|
|
5153
|
-
acceptanceCriteria: requirements,
|
|
5154
|
-
architectureContext: context ?? "",
|
|
5155
|
-
stackType,
|
|
5156
|
-
skipCommit: true
|
|
5157
|
-
})
|
|
5158
|
-
});
|
|
5159
|
-
if (!submitRes.ok) {
|
|
5160
|
-
const err = await submitRes.text().catch(() => "unknown");
|
|
5161
|
-
throw new Error(`Codegen submit error: ${submitRes.status} ${err}`);
|
|
5162
|
-
}
|
|
5163
|
-
const { id: buildId2 } = await submitRes.json();
|
|
5164
|
-
onOutput?.(toolId, "stdout", `[codegen] Build ${buildId2} queued, waiting...
|
|
5165
|
-
`);
|
|
5166
|
-
const baseDelay = CODEGEN_POLL_INTERVAL_MS;
|
|
5167
|
-
let status = "queued";
|
|
5168
|
-
let consecutiveFailures = 0;
|
|
5169
|
-
for (let i = 0; i < CODEGEN_POLL_MAX_ATTEMPTS && status !== "completed"; i++) {
|
|
5170
|
-
await new Promise((r) => setTimeout(r, baseDelay));
|
|
5171
|
-
const poll = await fetch(`${baseUrl}/builds/${buildId2}`, {
|
|
5172
|
-
headers: { "Authorization": authHeader }
|
|
5173
|
-
});
|
|
5174
|
-
if (!poll.ok) {
|
|
5175
|
-
consecutiveFailures++;
|
|
5176
|
-
if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {
|
|
5177
|
-
await cancelBuild(baseUrl, buildId2, authHeader);
|
|
5178
|
-
throw new Error(`Codegen build ${buildId2}: polling failed ${consecutiveFailures} times in a row (last HTTP ${poll.status}); build cancelled`);
|
|
5179
|
-
}
|
|
5180
|
-
continue;
|
|
5181
|
-
}
|
|
5182
|
-
consecutiveFailures = 0;
|
|
5183
|
-
const b2 = await poll.json();
|
|
5184
|
-
status = b2.status;
|
|
5185
|
-
if (b2.error) throw new Error(`Codegen failed: ${b2.error}`);
|
|
5186
|
-
if (TERMINAL_FAILURE_STATUSES.has(status)) {
|
|
5187
|
-
throw new Error(`Build ${buildId2} ended with status: ${status}`);
|
|
5188
|
-
}
|
|
5189
|
-
}
|
|
5190
|
-
if (status !== "completed") {
|
|
5191
|
-
await cancelBuild(baseUrl, buildId2, authHeader);
|
|
5192
|
-
throw new Error(`Build ${buildId2} did not finish within ${CODEGEN_POLL_MAX_ATTEMPTS * baseDelay / 1e3}s (last status: ${status}); cancelled`);
|
|
5193
|
-
}
|
|
5194
|
-
const filesRes = await fetch(`${baseUrl}/builds/${buildId2}/files`, {
|
|
5195
|
-
headers: { "Authorization": authHeader }
|
|
5196
|
-
});
|
|
5197
|
-
if (!filesRes.ok) throw new Error(`Failed to fetch files: ${filesRes.status}`);
|
|
5198
|
-
const { files: files2 } = await filesRes.json();
|
|
5199
|
-
if (!files2?.length) throw new Error("Build completed but no files generated");
|
|
5200
|
-
const written2 = [];
|
|
5201
|
-
for (const file of files2) {
|
|
5202
|
-
await fileStore.writeFile(file.path, file.content);
|
|
5203
|
-
written2.push(file.path);
|
|
5204
|
-
}
|
|
5205
|
-
onOutput?.(toolId, "stdout", `[codegen] ${files2.length} files written
|
|
5206
|
-
`);
|
|
5207
|
-
return {
|
|
5208
|
-
output: [
|
|
5209
|
-
`Generated ${files2.length} files for: ${title}`,
|
|
5210
|
-
"",
|
|
5211
|
-
"Files written to workspace:",
|
|
5212
|
-
...written2.map((p) => ` ${p}`),
|
|
5213
|
-
"",
|
|
5214
|
-
"Run tests to verify, then commit when ready."
|
|
5215
|
-
].join("\n")
|
|
5216
|
-
};
|
|
5217
|
-
}
|
|
5218
|
-
if (!config.codegenUrl) {
|
|
5219
|
-
throw new Error("No codegen backend configured (set jwtToken or codegenUrl)");
|
|
5220
|
-
}
|
|
5221
|
-
const res = await fetch(`${config.codegenUrl}/builds?mode=interactive`, {
|
|
5222
|
-
method: "POST",
|
|
5223
|
-
headers: {
|
|
5224
|
-
"Content-Type": "application/json",
|
|
5225
|
-
"Authorization": `Bearer ${config.apiKey}`,
|
|
5226
|
-
"x-tenant-id": config.tenantId ?? ""
|
|
5227
|
-
},
|
|
5228
|
-
body: JSON.stringify({
|
|
5229
|
-
product: config.product,
|
|
5230
|
-
repoUrl: config.repoUrl,
|
|
5231
|
-
storyTitle: title,
|
|
5232
|
-
acceptanceCriteria: requirements,
|
|
5233
|
-
architectureContext: context ?? "",
|
|
5234
|
-
stackType,
|
|
5235
|
-
skipCommit: true
|
|
5236
|
-
})
|
|
5237
|
-
});
|
|
5238
|
-
if (!res.ok) {
|
|
5239
|
-
const err = await res.text().catch(() => "unknown");
|
|
5240
|
-
throw new Error(`Codegen service error: ${res.status} ${err}`);
|
|
5241
|
-
}
|
|
5242
|
-
const reader = res.body?.getReader();
|
|
5243
|
-
if (!reader) throw new Error("No response body");
|
|
5244
|
-
const decoder = new TextDecoder();
|
|
5245
|
-
let buildId = "";
|
|
5246
|
-
let summary = "";
|
|
5247
|
-
let buffer = "";
|
|
5248
|
-
let currentEvent = "";
|
|
5249
|
-
try {
|
|
5250
|
-
while (true) {
|
|
5251
|
-
const { done, value } = await reader.read();
|
|
5252
|
-
if (done) break;
|
|
5253
|
-
buffer += decoder.decode(value, { stream: true });
|
|
5254
|
-
const lines2 = buffer.split("\n");
|
|
5255
|
-
buffer = lines2.pop() ?? "";
|
|
5256
|
-
for (const line of lines2) {
|
|
5257
|
-
if (line.startsWith("event: ")) {
|
|
5258
|
-
currentEvent = line.slice(7).trim();
|
|
5259
|
-
continue;
|
|
5260
|
-
}
|
|
5261
|
-
if (!line.startsWith("data: ")) continue;
|
|
5262
|
-
let data;
|
|
5263
|
-
try {
|
|
5264
|
-
data = JSON.parse(line.slice(6));
|
|
5265
|
-
} catch (parseErr) {
|
|
5266
|
-
throw new Error(`Codegen stream sent malformed event data: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
5267
|
-
}
|
|
5268
|
-
if (currentEvent === "phase" && onOutput) {
|
|
5269
|
-
const count = data.componentCount ? ` (${data.componentCount} components)` : "";
|
|
5270
|
-
onOutput(toolId, "stdout", `[codegen] ${data.phase}: ${data.status}${count}
|
|
5271
|
-
`);
|
|
5272
|
-
}
|
|
5273
|
-
if (currentEvent === "component" && onOutput) {
|
|
5274
|
-
const status = data.fromLibrary ? "reused from library" : data.status;
|
|
5275
|
-
onOutput(toolId, "stdout", `[codegen] ${data.name}: ${status}
|
|
5276
|
-
`);
|
|
5277
|
-
}
|
|
5278
|
-
if (currentEvent === "error") {
|
|
5279
|
-
throw new Error(`Codegen error: ${data.message}`);
|
|
5280
|
-
}
|
|
5281
|
-
if (currentEvent === "complete") {
|
|
5282
|
-
buildId = data.buildId;
|
|
5283
|
-
summary = `Generated ${data.filesGenerated ?? 0} files (${data.componentsReused ?? 0} reused)`;
|
|
5284
|
-
}
|
|
5285
|
-
currentEvent = "";
|
|
5286
|
-
}
|
|
5287
|
-
}
|
|
5288
|
-
} finally {
|
|
5289
|
-
reader.releaseLock();
|
|
5290
|
-
}
|
|
5291
|
-
if (!buildId) {
|
|
5292
|
-
throw new Error("Codegen stream ended without completion");
|
|
5293
|
-
}
|
|
5294
|
-
const buildRes = await fetch(`${config.codegenUrl}/builds/${buildId}`, {
|
|
5295
|
-
headers: {
|
|
5296
|
-
"Authorization": `Bearer ${config.apiKey}`,
|
|
5297
|
-
"x-tenant-id": config.tenantId ?? ""
|
|
5298
|
-
}
|
|
5299
|
-
});
|
|
5300
|
-
if (!buildRes.ok) {
|
|
5301
|
-
throw new Error(`Failed to fetch build result: ${buildRes.status}`);
|
|
5302
|
-
}
|
|
5303
|
-
const build2 = await buildRes.json();
|
|
5304
|
-
if (!build2.result) {
|
|
5305
|
-
throw new Error("Build completed but no files in result");
|
|
5306
|
-
}
|
|
5307
|
-
let files;
|
|
5308
|
-
try {
|
|
5309
|
-
const parsed = JSON.parse(build2.result);
|
|
5310
|
-
files = parsed.files ?? [];
|
|
5311
|
-
} catch {
|
|
5312
|
-
throw new Error("Failed to parse build result");
|
|
5313
|
-
}
|
|
5314
|
-
if (files.length === 0) {
|
|
5315
|
-
throw new Error("Codegen produced no files");
|
|
5316
|
-
}
|
|
5317
|
-
const written = [];
|
|
5318
|
-
for (const file of files) {
|
|
5319
|
-
await fileStore.writeFile(file.path, file.content);
|
|
5320
|
-
written.push(file.path);
|
|
5321
|
-
}
|
|
5322
|
-
return {
|
|
5323
|
-
output: [
|
|
5324
|
-
summary,
|
|
5325
|
-
"",
|
|
5326
|
-
"Files written to workspace:",
|
|
5327
|
-
...written.map((p) => ` ${p}`),
|
|
5328
|
-
"",
|
|
5329
|
-
"Run tests to verify, then commit when ready."
|
|
5330
|
-
].join("\n")
|
|
5331
|
-
};
|
|
5332
|
-
}
|
|
5333
|
-
};
|
|
5334
|
-
return { handlers };
|
|
5335
|
-
}
|
|
5336
|
-
var BUILD_FEATURE_TOOL, CODEGEN_TOOL_DEFINITIONS, CODEGEN_POLL_INTERVAL_MS, CODEGEN_POLL_MAX_ATTEMPTS, MAX_CONSECUTIVE_POLL_FAILURES, TERMINAL_FAILURE_STATUSES;
|
|
5337
4607
|
var init_codegen = __esm({
|
|
5338
4608
|
"../agent/src/tools/codegen.ts"() {
|
|
5339
4609
|
"use strict";
|
|
5340
|
-
BUILD_FEATURE_TOOL = {
|
|
5341
|
-
name: "build_feature",
|
|
5342
|
-
description: "Generate a complete feature using the platform codegen service. Produces multiple files with tests, leveraging a library of reusable components. Use this for multi-file features, new modules, or significant refactors. Files are written to the workspace \u2014 run tests afterwards to verify. Prefer this over manually writing multiple files.",
|
|
5343
|
-
input_schema: {
|
|
5344
|
-
type: "object",
|
|
5345
|
-
properties: {
|
|
5346
|
-
title: {
|
|
5347
|
-
type: "string",
|
|
5348
|
-
description: 'Feature title (e.g., "Add user authentication with sessions and API keys")'
|
|
5349
|
-
},
|
|
5350
|
-
requirements: {
|
|
5351
|
-
type: "string",
|
|
5352
|
-
description: "Acceptance criteria or detailed requirements for the feature"
|
|
5353
|
-
},
|
|
5354
|
-
context: {
|
|
5355
|
-
type: "string",
|
|
5356
|
-
description: "Architecture context \u2014 existing code patterns, tech stack, conventions."
|
|
5357
|
-
},
|
|
5358
|
-
stackType: {
|
|
5359
|
-
type: "string",
|
|
5360
|
-
enum: ["worker", "mobile", "pages"],
|
|
5361
|
-
description: "Override auto-detected stack type. Usually not needed."
|
|
5362
|
-
}
|
|
5363
|
-
},
|
|
5364
|
-
required: ["title", "requirements"]
|
|
5365
|
-
}
|
|
5366
|
-
};
|
|
5367
|
-
CODEGEN_TOOL_DEFINITIONS = [BUILD_FEATURE_TOOL];
|
|
5368
|
-
CODEGEN_POLL_INTERVAL_MS = 5e3;
|
|
5369
|
-
CODEGEN_POLL_MAX_ATTEMPTS = 120;
|
|
5370
|
-
MAX_CONSECUTIVE_POLL_FAILURES = 5;
|
|
5371
|
-
TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set(["failed", "cancelled", "canceled", "error"]);
|
|
5372
4610
|
}
|
|
5373
4611
|
});
|
|
5374
4612
|
|
|
5375
4613
|
// ../agent/src/sandbox/snapshot-manager.ts
|
|
5376
|
-
var SnapshotManager;
|
|
5377
4614
|
var init_snapshot_manager = __esm({
|
|
5378
4615
|
"../agent/src/sandbox/snapshot-manager.ts"() {
|
|
5379
4616
|
"use strict";
|
|
5380
|
-
SnapshotManager = class {
|
|
5381
|
-
constructor(config) {
|
|
5382
|
-
this.config = config;
|
|
5383
|
-
}
|
|
5384
|
-
/**
|
|
5385
|
-
* Get or create a container for the given repo+lockfile.
|
|
5386
|
-
* If a snapshot exists, restore from it (~1-3s).
|
|
5387
|
-
* If not, create fresh container (~30-60s), then snapshot it for next time.
|
|
5388
|
-
*/
|
|
5389
|
-
async getOrCreateContainer(repoId, lockfileHash, setupFn) {
|
|
5390
|
-
const existing = await this.config.db.prepare(
|
|
5391
|
-
"SELECT backup_handle, image_version FROM repo_snapshots WHERE repo_id = ? AND lockfile_hash = ?"
|
|
5392
|
-
).bind(repoId, lockfileHash).first();
|
|
5393
|
-
if (existing && existing.image_version === this.config.imageVersion) {
|
|
5394
|
-
const sandbox2 = await this.config.sandboxNs.restore(existing.backup_handle);
|
|
5395
|
-
await this.config.db.prepare(
|
|
5396
|
-
"UPDATE repo_snapshots SET last_used_at = ? WHERE repo_id = ? AND lockfile_hash = ?"
|
|
5397
|
-
).bind(Date.now(), repoId, lockfileHash).run();
|
|
5398
|
-
return sandbox2;
|
|
5399
|
-
}
|
|
5400
|
-
const sandbox = await this.config.sandboxNs.create();
|
|
5401
|
-
if (setupFn) {
|
|
5402
|
-
await setupFn(sandbox);
|
|
5403
|
-
}
|
|
5404
|
-
const handle = await sandbox.backup();
|
|
5405
|
-
await this.config.db.prepare(
|
|
5406
|
-
`INSERT OR REPLACE INTO repo_snapshots (repo_id, lockfile_hash, backup_handle, image_version, created_at, last_used_at, ttl_hours)
|
|
5407
|
-
VALUES (?, ?, ?, ?, ?, ?, 168)`
|
|
5408
|
-
).bind(repoId, lockfileHash, handle, this.config.imageVersion, Date.now(), Date.now()).run();
|
|
5409
|
-
return sandbox;
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Clean up expired snapshots (older than TTL).
|
|
5413
|
-
*/
|
|
5414
|
-
async cleanupExpired() {
|
|
5415
|
-
const now = Date.now();
|
|
5416
|
-
const result = await this.config.db.prepare(
|
|
5417
|
-
"SELECT repo_id, lockfile_hash FROM repo_snapshots WHERE (last_used_at + ttl_hours * 3600000) < ?"
|
|
5418
|
-
).bind(now).all();
|
|
5419
|
-
if (result.results.length === 0) return 0;
|
|
5420
|
-
const stmts = result.results.map(
|
|
5421
|
-
(r) => this.config.db.prepare(
|
|
5422
|
-
"DELETE FROM repo_snapshots WHERE repo_id = ? AND lockfile_hash = ?"
|
|
5423
|
-
).bind(r.repo_id, r.lockfile_hash)
|
|
5424
|
-
);
|
|
5425
|
-
await this.config.db.batch(stmts);
|
|
5426
|
-
return result.results.length;
|
|
5427
|
-
}
|
|
5428
|
-
};
|
|
5429
4617
|
}
|
|
5430
4618
|
});
|
|
5431
4619
|
|
|
5432
4620
|
// ../agent/src/sandbox/sync.ts
|
|
5433
|
-
async function syncBeforeBash(store, sandbox, workDir) {
|
|
5434
|
-
const dirtyFiles = await store.getDirtyFiles();
|
|
5435
|
-
const errors = [];
|
|
5436
|
-
let pushed = 0;
|
|
5437
|
-
for (const file of dirtyFiles) {
|
|
5438
|
-
try {
|
|
5439
|
-
const fullPath = `${workDir}/${file.path}`;
|
|
5440
|
-
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
5441
|
-
await sandbox.exec(`mkdir -p '${dir}'`);
|
|
5442
|
-
await sandbox.writeFile(fullPath, file.content);
|
|
5443
|
-
pushed++;
|
|
5444
|
-
} catch (err) {
|
|
5445
|
-
errors.push(`Failed to push ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5446
|
-
}
|
|
5447
|
-
}
|
|
5448
|
-
return { filesPushed: pushed, errors };
|
|
5449
|
-
}
|
|
5450
|
-
async function syncAfterBash(store, sandbox, workDir) {
|
|
5451
|
-
const errors = [];
|
|
5452
|
-
let pulled = 0;
|
|
5453
|
-
const gitResult = await sandbox.exec(`cd '${workDir}' && git status --short`);
|
|
5454
|
-
if (gitResult.exitCode !== 0) {
|
|
5455
|
-
return { filesPulled: 0, errors: [`git status failed: ${gitResult.stderr}`] };
|
|
5456
|
-
}
|
|
5457
|
-
if (!gitResult.stdout.trim()) {
|
|
5458
|
-
return { filesPulled: 0, errors: [] };
|
|
5459
|
-
}
|
|
5460
|
-
const changedFiles = parseGitStatus(gitResult.stdout);
|
|
5461
|
-
const fileEntries = [];
|
|
5462
|
-
for (const file of changedFiles) {
|
|
5463
|
-
if (file.status === "deleted") {
|
|
5464
|
-
fileEntries.push({ path: file.path, content: "", status: "deleted" });
|
|
5465
|
-
pulled++;
|
|
5466
|
-
continue;
|
|
5467
|
-
}
|
|
5468
|
-
if (isGeneratedPath(file.path)) continue;
|
|
5469
|
-
try {
|
|
5470
|
-
const content = await sandbox.readFile(`${workDir}/${file.path}`);
|
|
5471
|
-
fileEntries.push({
|
|
5472
|
-
path: file.path,
|
|
5473
|
-
content,
|
|
5474
|
-
status: file.status === "new" ? "created" : "modified"
|
|
5475
|
-
});
|
|
5476
|
-
pulled++;
|
|
5477
|
-
} catch (err) {
|
|
5478
|
-
errors.push(`Failed to pull ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5479
|
-
}
|
|
5480
|
-
}
|
|
5481
|
-
if (fileEntries.length > 0) {
|
|
5482
|
-
await store.upsertFiles(fileEntries);
|
|
5483
|
-
}
|
|
5484
|
-
return { filesPulled: pulled, errors };
|
|
5485
|
-
}
|
|
5486
|
-
function parseGitStatus(output) {
|
|
5487
|
-
const entries = [];
|
|
5488
|
-
for (const line of output.split("\n")) {
|
|
5489
|
-
if (!line.trim()) continue;
|
|
5490
|
-
const statusCode = line.substring(0, 2);
|
|
5491
|
-
const path12 = line.substring(3).trim();
|
|
5492
|
-
if (!path12) continue;
|
|
5493
|
-
if (statusCode.includes("D")) {
|
|
5494
|
-
entries.push({ path: path12, status: "deleted" });
|
|
5495
|
-
} else if (statusCode === "??" || statusCode.includes("A")) {
|
|
5496
|
-
entries.push({ path: path12, status: "new" });
|
|
5497
|
-
} else {
|
|
5498
|
-
entries.push({ path: path12, status: "modified" });
|
|
5499
|
-
}
|
|
5500
|
-
}
|
|
5501
|
-
return entries;
|
|
5502
|
-
}
|
|
5503
|
-
function isGeneratedPath(path12) {
|
|
5504
|
-
return GENERATED_PATTERNS.some((p) => path12.startsWith(p) || path12.includes(`/${p}`));
|
|
5505
|
-
}
|
|
5506
|
-
var GENERATED_PATTERNS;
|
|
5507
4621
|
var init_sync = __esm({
|
|
5508
4622
|
"../agent/src/sandbox/sync.ts"() {
|
|
5509
4623
|
"use strict";
|
|
5510
|
-
GENERATED_PATTERNS = [
|
|
5511
|
-
"node_modules/",
|
|
5512
|
-
"dist/",
|
|
5513
|
-
".cache/",
|
|
5514
|
-
".next/",
|
|
5515
|
-
"__pycache__/",
|
|
5516
|
-
".pytest_cache/",
|
|
5517
|
-
"coverage/",
|
|
5518
|
-
".git/"
|
|
5519
|
-
];
|
|
5520
4624
|
}
|
|
5521
4625
|
});
|
|
5522
4626
|
|
|
@@ -5927,17 +5031,11 @@ import * as path2 from "node:path";
|
|
|
5927
5031
|
function truncate(e) {
|
|
5928
5032
|
return e.subject.length > MAX_SUBJECT ? { ...e, subject: e.subject.slice(0, MAX_SUBJECT) + "...[truncated]" } : e;
|
|
5929
5033
|
}
|
|
5930
|
-
var MAX_SUBJECT,
|
|
5034
|
+
var MAX_SUBJECT, FileAuditLog;
|
|
5931
5035
|
var init_audit_log = __esm({
|
|
5932
5036
|
"../agent/src/host/audit-log.ts"() {
|
|
5933
5037
|
"use strict";
|
|
5934
5038
|
MAX_SUBJECT = 4096;
|
|
5935
|
-
MemoryAuditLog = class {
|
|
5936
|
-
entries = [];
|
|
5937
|
-
async record(entry) {
|
|
5938
|
-
this.entries.push(truncate(entry));
|
|
5939
|
-
}
|
|
5940
|
-
};
|
|
5941
5039
|
FileAuditLog = class {
|
|
5942
5040
|
constructor(file) {
|
|
5943
5041
|
this.file = file;
|
|
@@ -5951,89 +5049,23 @@ var init_audit_log = __esm({
|
|
|
5951
5049
|
});
|
|
5952
5050
|
|
|
5953
5051
|
// ../agent/src/host/cloud-host.ts
|
|
5954
|
-
var CloudHost;
|
|
5955
5052
|
var init_cloud_host = __esm({
|
|
5956
5053
|
"../agent/src/host/cloud-host.ts"() {
|
|
5957
5054
|
"use strict";
|
|
5958
|
-
CloudHost = class {
|
|
5959
|
-
kind = "cloud";
|
|
5960
|
-
files;
|
|
5961
|
-
execFn;
|
|
5962
|
-
constructor(config) {
|
|
5963
|
-
this.files = config.files;
|
|
5964
|
-
this.execFn = config.exec;
|
|
5965
|
-
}
|
|
5966
|
-
exec(command, onOutput) {
|
|
5967
|
-
return this.execFn(command, onOutput);
|
|
5968
|
-
}
|
|
5969
|
-
};
|
|
5970
5055
|
}
|
|
5971
5056
|
});
|
|
5972
5057
|
|
|
5973
5058
|
// ../agent/src/replay-buffer.ts
|
|
5974
|
-
var ReplayBuffer;
|
|
5975
5059
|
var init_replay_buffer = __esm({
|
|
5976
5060
|
"../agent/src/replay-buffer.ts"() {
|
|
5977
5061
|
"use strict";
|
|
5978
|
-
ReplayBuffer = class {
|
|
5979
|
-
buffer = [];
|
|
5980
|
-
maxSize;
|
|
5981
|
-
constructor(maxSize = 1e3) {
|
|
5982
|
-
this.maxSize = maxSize;
|
|
5983
|
-
}
|
|
5984
|
-
/** Add an event, evicting the oldest if at capacity. */
|
|
5985
|
-
push(event) {
|
|
5986
|
-
if (this.buffer.length >= this.maxSize) {
|
|
5987
|
-
this.buffer.shift();
|
|
5988
|
-
}
|
|
5989
|
-
this.buffer.push(event);
|
|
5990
|
-
}
|
|
5991
|
-
/** Return all events with seq > lastSeq, in order. */
|
|
5992
|
-
getAfter(lastSeq) {
|
|
5993
|
-
return this.buffer.filter((e) => e.seq > lastSeq);
|
|
5994
|
-
}
|
|
5995
|
-
/** Current number of buffered events. */
|
|
5996
|
-
get size() {
|
|
5997
|
-
return this.buffer.length;
|
|
5998
|
-
}
|
|
5999
|
-
/** Lowest seq still in the buffer, or 0 if empty. */
|
|
6000
|
-
get oldestSeq() {
|
|
6001
|
-
return this.buffer.length > 0 ? this.buffer[0].seq : 0;
|
|
6002
|
-
}
|
|
6003
|
-
/** Highest seq in the buffer, or 0 if empty. */
|
|
6004
|
-
get newestSeq() {
|
|
6005
|
-
return this.buffer.length > 0 ? this.buffer[this.buffer.length - 1].seq : 0;
|
|
6006
|
-
}
|
|
6007
|
-
/** Clear the buffer. */
|
|
6008
|
-
clear() {
|
|
6009
|
-
this.buffer = [];
|
|
6010
|
-
}
|
|
6011
|
-
};
|
|
6012
5062
|
}
|
|
6013
5063
|
});
|
|
6014
5064
|
|
|
6015
5065
|
// ../agent/src/sandbox/lockfile-hash.ts
|
|
6016
|
-
async function sha256(content) {
|
|
6017
|
-
const data = new TextEncoder().encode(content);
|
|
6018
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
6019
|
-
const hashArray = new Uint8Array(hashBuffer);
|
|
6020
|
-
return Array.from(hashArray).map((b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
6021
|
-
}
|
|
6022
|
-
async function computeLockfileHash(readFile11) {
|
|
6023
|
-
for (const name of LOCKFILES) {
|
|
6024
|
-
const content = await readFile11(name);
|
|
6025
|
-
if (content) {
|
|
6026
|
-
const hash = await sha256(content);
|
|
6027
|
-
return hash.slice(0, 12);
|
|
6028
|
-
}
|
|
6029
|
-
}
|
|
6030
|
-
return "none";
|
|
6031
|
-
}
|
|
6032
|
-
var LOCKFILES;
|
|
6033
5066
|
var init_lockfile_hash = __esm({
|
|
6034
5067
|
"../agent/src/sandbox/lockfile-hash.ts"() {
|
|
6035
5068
|
"use strict";
|
|
6036
|
-
LOCKFILES = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"];
|
|
6037
5069
|
}
|
|
6038
5070
|
});
|
|
6039
5071
|
|
|
@@ -6518,12 +5550,12 @@ function frontmatterDescription(text) {
|
|
|
6518
5550
|
const line = m2[1].split("\n").find((l) => l.startsWith("description:"));
|
|
6519
5551
|
return line ? line.slice("description:".length).trim().slice(0, 300) : "";
|
|
6520
5552
|
}
|
|
6521
|
-
async function readOptional(fs6,
|
|
5553
|
+
async function readOptional(fs6, path13, report) {
|
|
6522
5554
|
try {
|
|
6523
|
-
return await fs6.readFile(
|
|
5555
|
+
return await fs6.readFile(path13);
|
|
6524
5556
|
} catch (err) {
|
|
6525
5557
|
if (isEnoent(err)) return null;
|
|
6526
|
-
report.errors.push({ path:
|
|
5558
|
+
report.errors.push({ path: path13, message: err instanceof Error ? err.message : String(err) });
|
|
6527
5559
|
return null;
|
|
6528
5560
|
}
|
|
6529
5561
|
}
|
|
@@ -6554,17 +5586,17 @@ async function readClaudeAssets({ fs: fs6, home, projectDirs }) {
|
|
|
6554
5586
|
report.notes.push(`Memory read from ${memDir} (namespaced as "${key}.*")`);
|
|
6555
5587
|
const seen = /* @__PURE__ */ new Set();
|
|
6556
5588
|
for (const entry of entries.filter((e) => e.endsWith(".md")).sort()) {
|
|
6557
|
-
const
|
|
6558
|
-
const text = await readOptional(fs6,
|
|
5589
|
+
const path13 = `${memDir}/${entry}`;
|
|
5590
|
+
const text = await readOptional(fs6, path13, report);
|
|
6559
5591
|
if (text === null) continue;
|
|
6560
5592
|
const base = entry === "MEMORY.md" ? "index" : entry.slice(0, -3).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
6561
5593
|
const name = `${key}.${base}`;
|
|
6562
5594
|
if (!NAME_RE3.test(name)) {
|
|
6563
|
-
report.errors.push({ path:
|
|
5595
|
+
report.errors.push({ path: path13, message: `cannot derive a valid asset name from "${entry}"` });
|
|
6564
5596
|
continue;
|
|
6565
5597
|
}
|
|
6566
5598
|
if (seen.has(name)) {
|
|
6567
|
-
report.errors.push({ path:
|
|
5599
|
+
report.errors.push({ path: path13, message: `name collision on "${name}"` });
|
|
6568
5600
|
continue;
|
|
6569
5601
|
}
|
|
6570
5602
|
seen.add(name);
|
|
@@ -6573,7 +5605,7 @@ async function readClaudeAssets({ fs: fs6, home, projectDirs }) {
|
|
|
6573
5605
|
name,
|
|
6574
5606
|
description: entry === "MEMORY.md" ? "Memory index" : frontmatterDescription(text),
|
|
6575
5607
|
content: text,
|
|
6576
|
-
source:
|
|
5608
|
+
source: path13
|
|
6577
5609
|
});
|
|
6578
5610
|
}
|
|
6579
5611
|
return report;
|
|
@@ -6592,28 +5624,28 @@ async function readCommands(fs6, home, report) {
|
|
|
6592
5624
|
}
|
|
6593
5625
|
const seen = /* @__PURE__ */ new Set();
|
|
6594
5626
|
for (const entry of [...entries].sort()) {
|
|
6595
|
-
const
|
|
5627
|
+
const path13 = `${dir}/${entry}`;
|
|
6596
5628
|
if (!entry.endsWith(".md")) {
|
|
6597
|
-
if (!entry.startsWith(".")) report.notes.push(`Skipped ${
|
|
5629
|
+
if (!entry.startsWith(".")) report.notes.push(`Skipped ${path13}: only top-level .md command files are imported (subdirectories are not supported)`);
|
|
6598
5630
|
continue;
|
|
6599
5631
|
}
|
|
6600
5632
|
const name = entry.slice(0, -3);
|
|
6601
5633
|
if (!COMMAND_NAME_RE.test(name)) {
|
|
6602
|
-
report.errors.push({ path:
|
|
5634
|
+
report.errors.push({ path: path13, message: `command name "${name}" must start with a letter and use only letters, digits, - and _` });
|
|
6603
5635
|
continue;
|
|
6604
5636
|
}
|
|
6605
5637
|
if (seen.has(name.toLowerCase())) {
|
|
6606
|
-
report.errors.push({ path:
|
|
5638
|
+
report.errors.push({ path: path13, message: `command name collision on "${name}" (names are case-insensitive)` });
|
|
6607
5639
|
continue;
|
|
6608
5640
|
}
|
|
6609
|
-
const text = await readOptional(fs6,
|
|
5641
|
+
const text = await readOptional(fs6, path13, report);
|
|
6610
5642
|
if (text === null) continue;
|
|
6611
5643
|
if (Buffer.byteLength(text, "utf8") > MAX_ASSET_BYTES) {
|
|
6612
|
-
report.errors.push({ path:
|
|
5644
|
+
report.errors.push({ path: path13, message: `skipped: ${Buffer.byteLength(text, "utf8")} bytes is over the ${MAX_ASSET_BYTES} byte asset limit` });
|
|
6613
5645
|
continue;
|
|
6614
5646
|
}
|
|
6615
5647
|
seen.add(name.toLowerCase());
|
|
6616
|
-
report.assets.push({ kind: "command", name, description: parseCommandFile(text).description, content: text, source:
|
|
5648
|
+
report.assets.push({ kind: "command", name, description: parseCommandFile(text).description, content: text, source: path13 });
|
|
6617
5649
|
}
|
|
6618
5650
|
}
|
|
6619
5651
|
async function listFiles(fs6, dir, rel, out, report) {
|
|
@@ -6666,8 +5698,8 @@ async function readSkills(fs6, home, report) {
|
|
|
6666
5698
|
const siblings = [];
|
|
6667
5699
|
const slugs = /* @__PURE__ */ new Set();
|
|
6668
5700
|
for (const rel of files.filter((f) => f !== "SKILL.md")) {
|
|
6669
|
-
const
|
|
6670
|
-
const content = await readOptional(fs6,
|
|
5701
|
+
const path13 = `${root}/${dir}/${rel}`;
|
|
5702
|
+
const content = await readOptional(fs6, path13, report);
|
|
6671
5703
|
if (content === null) continue;
|
|
6672
5704
|
const size = Buffer.byteLength(content, "utf8");
|
|
6673
5705
|
const name = siblingAssetName(parsed.name, rel);
|
|
@@ -6676,33 +5708,33 @@ async function readSkills(fs6, home, report) {
|
|
|
6676
5708
|
continue;
|
|
6677
5709
|
}
|
|
6678
5710
|
slugs.add(name);
|
|
6679
|
-
siblings.push({ kind: "skill", name, description: `${SIBLING_PREFIX}${rel}`, content, source:
|
|
5711
|
+
siblings.push({ kind: "skill", name, description: `${SIBLING_PREFIX}${rel}`, content, source: path13 });
|
|
6680
5712
|
}
|
|
6681
5713
|
if (siblings.some((s) => isScriptPath(s.description.slice(SIBLING_PREFIX.length)))) report.notes.push(`Skill ${parsed.name}: ships scripts, not runnable until permitted (they run through bash and its permission rules)`);
|
|
6682
5714
|
report.assets.push({ kind: "skill", name: parsed.name, description: parsed.description, content: text, source: skillPath }, ...siblings);
|
|
6683
5715
|
}
|
|
6684
5716
|
}
|
|
6685
5717
|
async function readMcpServers(fs6, home, projectDirs, report) {
|
|
6686
|
-
const
|
|
6687
|
-
const text = await readOptional(fs6,
|
|
5718
|
+
const path13 = `${home}/.claude.json`;
|
|
5719
|
+
const text = await readOptional(fs6, path13, report);
|
|
6688
5720
|
if (text === null) return;
|
|
6689
5721
|
const { servers, errors } = normalizeClaudeJsonMcp(text, projectDirs);
|
|
6690
|
-
for (const e of errors) report.errors.push({ path:
|
|
5722
|
+
for (const e of errors) report.errors.push({ path: path13, message: e });
|
|
6691
5723
|
const seen = /* @__PURE__ */ new Set();
|
|
6692
5724
|
for (const s of servers) {
|
|
6693
5725
|
if (!NAME_RE3.test(s.name)) {
|
|
6694
|
-
report.errors.push({ path:
|
|
5726
|
+
report.errors.push({ path: path13, message: `MCP server name "${s.name}" must use only letters, digits, . _ - (max 100)` });
|
|
6695
5727
|
continue;
|
|
6696
5728
|
}
|
|
6697
5729
|
if (seen.has(s.name.toLowerCase())) {
|
|
6698
|
-
report.errors.push({ path:
|
|
5730
|
+
report.errors.push({ path: path13, message: `MCP server name collision on "${s.name}" (names are case-insensitive)` });
|
|
6699
5731
|
continue;
|
|
6700
5732
|
}
|
|
6701
5733
|
seen.add(s.name.toLowerCase());
|
|
6702
5734
|
const { literalKeys, ...def } = s;
|
|
6703
5735
|
const content = JSON.stringify(def, null, 2);
|
|
6704
5736
|
if (Buffer.byteLength(content, "utf8") > MAX_ASSET_BYTES) {
|
|
6705
|
-
report.errors.push({ path:
|
|
5737
|
+
report.errors.push({ path: path13, message: `MCP server "${s.name}" skipped: over the ${MAX_ASSET_BYTES} byte asset limit` });
|
|
6706
5738
|
continue;
|
|
6707
5739
|
}
|
|
6708
5740
|
if (literalKeys.length > 0) {
|
|
@@ -6716,7 +5748,7 @@ async function readMcpServers(fs6, home, projectDirs, report) {
|
|
|
6716
5748
|
name: s.name,
|
|
6717
5749
|
description: s.transport === "stdio" ? `stdio: ${s.command}` : `http: ${s.url}`,
|
|
6718
5750
|
content,
|
|
6719
|
-
source: `${
|
|
5751
|
+
source: `${path13} (${s.scope})`
|
|
6720
5752
|
});
|
|
6721
5753
|
}
|
|
6722
5754
|
}
|
|
@@ -6739,10 +5771,10 @@ var init_claude_sources = __esm({
|
|
|
6739
5771
|
// ../agent/src/import/profile-client.ts
|
|
6740
5772
|
function createProfileClient({ baseUrl, apiKey, fetch: doFetch, timeoutMs = 8e3 }) {
|
|
6741
5773
|
const root = baseUrl.replace(/\/+$/, "");
|
|
6742
|
-
async function call(method,
|
|
5774
|
+
async function call(method, path13, init = {}) {
|
|
6743
5775
|
let res;
|
|
6744
5776
|
try {
|
|
6745
|
-
res = await doFetch(`${root}/api/profile${
|
|
5777
|
+
res = await doFetch(`${root}/api/profile${path13}`, {
|
|
6746
5778
|
method,
|
|
6747
5779
|
headers: { Authorization: `Bearer ${apiKey}`, ...init.body !== void 0 ? { "content-type": "application/json" } : {}, ...init.headers },
|
|
6748
5780
|
...init.body !== void 0 ? { body: JSON.stringify(init.body) } : {},
|
|
@@ -6759,7 +5791,7 @@ function createProfileClient({ baseUrl, apiKey, fetch: doFetch, timeoutMs = 8e3
|
|
|
6759
5791
|
body = void 0;
|
|
6760
5792
|
}
|
|
6761
5793
|
const detail = typeof body === "object" && body !== null && "error" in body ? String(body.error) : res.statusText;
|
|
6762
|
-
throw new ProfileApiError(res.status, `profile ${method} ${
|
|
5794
|
+
throw new ProfileApiError(res.status, `profile ${method} ${path13} -> ${res.status} ${detail}`, body);
|
|
6763
5795
|
}
|
|
6764
5796
|
const enc = encodeURIComponent;
|
|
6765
5797
|
return {
|
|
@@ -6874,7 +5906,7 @@ function createMemoryReadTool(client, projectKey2) {
|
|
|
6874
5906
|
}
|
|
6875
5907
|
};
|
|
6876
5908
|
}
|
|
6877
|
-
var MEMORY_READ_TOOL,
|
|
5909
|
+
var MEMORY_READ_TOOL, SAFE;
|
|
6878
5910
|
var init_memory_tool = __esm({
|
|
6879
5911
|
"../agent/src/import/memory-tool.ts"() {
|
|
6880
5912
|
"use strict";
|
|
@@ -6887,7 +5919,6 @@ var init_memory_tool = __esm({
|
|
|
6887
5919
|
required: ["name"]
|
|
6888
5920
|
}
|
|
6889
5921
|
};
|
|
6890
|
-
MEMORY_TOOL_DEFINITIONS = [MEMORY_READ_TOOL];
|
|
6891
5922
|
SAFE = /^[A-Za-z0-9._-]{1,100}$/;
|
|
6892
5923
|
}
|
|
6893
5924
|
});
|
|
@@ -6969,9 +6000,6 @@ function splitSections(text) {
|
|
|
6969
6000
|
const preamble = starts[0] === 0 ? "" : lines2.slice(0, starts[0]).join("\n") + "\n";
|
|
6970
6001
|
return { preamble, sections: sections2 };
|
|
6971
6002
|
}
|
|
6972
|
-
function joinSections(split) {
|
|
6973
|
-
return split.preamble + split.sections.map((s) => s.text).join("");
|
|
6974
|
-
}
|
|
6975
6003
|
var init_instruction_sections = __esm({
|
|
6976
6004
|
"../agent/src/import/instruction-sections.ts"() {
|
|
6977
6005
|
"use strict";
|
|
@@ -7140,7 +6168,7 @@ function createInstructionsReadTool(client) {
|
|
|
7140
6168
|
}
|
|
7141
6169
|
};
|
|
7142
6170
|
}
|
|
7143
|
-
var INSTRUCTIONS_READ_TOOL,
|
|
6171
|
+
var INSTRUCTIONS_READ_TOOL, SAFE2;
|
|
7144
6172
|
var init_instructions_tool = __esm({
|
|
7145
6173
|
"../agent/src/import/instructions-tool.ts"() {
|
|
7146
6174
|
"use strict";
|
|
@@ -7154,7 +6182,6 @@ var init_instructions_tool = __esm({
|
|
|
7154
6182
|
required: ["name"]
|
|
7155
6183
|
}
|
|
7156
6184
|
};
|
|
7157
|
-
INSTRUCTIONS_TOOL_DEFINITIONS = [INSTRUCTIONS_READ_TOOL];
|
|
7158
6185
|
SAFE2 = /^[a-z0-9-]{1,40}$/;
|
|
7159
6186
|
}
|
|
7160
6187
|
});
|
|
@@ -7255,7 +6282,7 @@ var init_trust = __esm({
|
|
|
7255
6282
|
// ../agent/src/import/source-changes.ts
|
|
7256
6283
|
function fingerprintSources(files, hash) {
|
|
7257
6284
|
const fingerprint = {};
|
|
7258
|
-
for (const [
|
|
6285
|
+
for (const [path13, content] of Object.entries(files)) fingerprint[path13] = hash(content);
|
|
7259
6286
|
return fingerprint;
|
|
7260
6287
|
}
|
|
7261
6288
|
function diffSources(before, after) {
|
|
@@ -7356,9 +6383,9 @@ function allOffConfig() {
|
|
|
7356
6383
|
function isPlainObject2(value) {
|
|
7357
6384
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7358
6385
|
}
|
|
7359
|
-
function parseImportsConfig(text,
|
|
6386
|
+
function parseImportsConfig(text, path13) {
|
|
7360
6387
|
if (text === null) return { config: allOffConfig() };
|
|
7361
|
-
const fail = (reason) => ({ config: allOffConfig(), error: `${
|
|
6388
|
+
const fail = (reason) => ({ config: allOffConfig(), error: `${path13}: ${reason}` });
|
|
7362
6389
|
let parsed;
|
|
7363
6390
|
try {
|
|
7364
6391
|
parsed = JSON.parse(text);
|
|
@@ -7387,9 +6414,6 @@ function parseImportsConfig(text, path12) {
|
|
|
7387
6414
|
}
|
|
7388
6415
|
return { config };
|
|
7389
6416
|
}
|
|
7390
|
-
function serializeImportsConfig(config) {
|
|
7391
|
-
return JSON.stringify({ version: 1, categories: config.categories, models: config.models }, null, 2);
|
|
7392
|
-
}
|
|
7393
6417
|
var IMPORT_CATEGORIES, MODEL_KEYS;
|
|
7394
6418
|
var init_imports_config = __esm({
|
|
7395
6419
|
"../agent/src/import/imports-config.ts"() {
|
|
@@ -7982,141 +7006,6 @@ var init_mcp_client = __esm({
|
|
|
7982
7006
|
});
|
|
7983
7007
|
|
|
7984
7008
|
// ../agent/src/index.ts
|
|
7985
|
-
var src_exports = {};
|
|
7986
|
-
__export(src_exports, {
|
|
7987
|
-
AdaptPlanError: () => AdaptPlanError,
|
|
7988
|
-
BASH_TOOL_DEFINITION: () => BASH_TOOL_DEFINITION,
|
|
7989
|
-
BUILD_FEATURE_TOOL: () => BUILD_FEATURE_TOOL,
|
|
7990
|
-
CALL_TIMEOUT_MS: () => CALL_TIMEOUT_MS,
|
|
7991
|
-
CODEGEN_TOOL_DEFINITIONS: () => CODEGEN_TOOL_DEFINITIONS,
|
|
7992
|
-
CONNECT_TIMEOUT_MS: () => CONNECT_TIMEOUT_MS,
|
|
7993
|
-
CREATE_PR_TOOL: () => CREATE_PR_TOOL,
|
|
7994
|
-
CloudHost: () => CloudHost,
|
|
7995
|
-
DEFAULT_MAX_CONTEXT_TOKENS: () => DEFAULT_MAX_CONTEXT_TOKENS,
|
|
7996
|
-
DEFAULT_PROFILE_BUDGET_CHARS: () => DEFAULT_PROFILE_BUDGET_CHARS,
|
|
7997
|
-
EDIT_FILE_TOOL: () => EDIT_FILE_TOOL,
|
|
7998
|
-
FILE_TOOL_DEFINITIONS: () => FILE_TOOL_DEFINITIONS,
|
|
7999
|
-
FileAuditLog: () => FileAuditLog,
|
|
8000
|
-
FileStore: () => FileStore,
|
|
8001
|
-
GITHUB_TOOL_DEFINITIONS: () => GITHUB_TOOL_DEFINITIONS,
|
|
8002
|
-
IMPORT_CATEGORIES: () => IMPORT_CATEGORIES,
|
|
8003
|
-
INSTRUCTIONS_READ_TOOL: () => INSTRUCTIONS_READ_TOOL,
|
|
8004
|
-
INSTRUCTIONS_TOOL_DEFINITIONS: () => INSTRUCTIONS_TOOL_DEFINITIONS,
|
|
8005
|
-
LIST_DIRECTORY_TOOL: () => LIST_DIRECTORY_TOOL,
|
|
8006
|
-
LocalHost: () => LocalHost,
|
|
8007
|
-
MAX_ASSET_BYTES: () => MAX_ASSET_BYTES,
|
|
8008
|
-
MAX_CORE_CHARS: () => MAX_CORE_CHARS,
|
|
8009
|
-
MCP_PROTOCOL_VERSION: () => MCP_PROTOCOL_VERSION,
|
|
8010
|
-
MEMORY_READ_TOOL: () => MEMORY_READ_TOOL,
|
|
8011
|
-
MEMORY_TOOL_DEFINITIONS: () => MEMORY_TOOL_DEFINITIONS,
|
|
8012
|
-
McpProtocolError: () => McpProtocolError,
|
|
8013
|
-
MemoryAuditLog: () => MemoryAuditLog,
|
|
8014
|
-
PERMISSION_MODES: () => PERMISSION_MODES,
|
|
8015
|
-
PREVIEW_TOOL: () => PREVIEW_TOOL,
|
|
8016
|
-
PREVIEW_TOOL_DEFINITIONS: () => PREVIEW_TOOL_DEFINITIONS,
|
|
8017
|
-
PendingRequests: () => PendingRequests,
|
|
8018
|
-
PermissionState: () => PermissionState,
|
|
8019
|
-
PolicyViolation: () => PolicyViolation,
|
|
8020
|
-
ProfileApiError: () => ProfileApiError,
|
|
8021
|
-
READ_FILE_TOOL: () => READ_FILE_TOOL,
|
|
8022
|
-
RESULT_CAP_CHARS: () => RESULT_CAP_CHARS,
|
|
8023
|
-
ReplayBuffer: () => ReplayBuffer,
|
|
8024
|
-
RepoIndexer: () => RepoIndexer,
|
|
8025
|
-
RpcAbortError: () => RpcAbortError,
|
|
8026
|
-
RpcClosedError: () => RpcClosedError,
|
|
8027
|
-
RpcError: () => RpcError,
|
|
8028
|
-
RpcTimeoutError: () => RpcTimeoutError,
|
|
8029
|
-
SEARCH_TOOL: () => SEARCH_TOOL,
|
|
8030
|
-
SENTRY_GET_ISSUE_TOOL: () => SENTRY_GET_ISSUE_TOOL,
|
|
8031
|
-
SENTRY_LIST_ISSUES_TOOL: () => SENTRY_LIST_ISSUES_TOOL,
|
|
8032
|
-
SENTRY_TOOL_DEFINITIONS: () => SENTRY_TOOL_DEFINITIONS,
|
|
8033
|
-
SIBLING_PREFIX: () => SIBLING_PREFIX,
|
|
8034
|
-
SKILLS_BUDGET_CHARS: () => SKILLS_BUDGET_CHARS,
|
|
8035
|
-
SKILL_TOOL: () => SKILL_TOOL,
|
|
8036
|
-
SnapshotManager: () => SnapshotManager,
|
|
8037
|
-
TODO_TOOL: () => TODO_TOOL,
|
|
8038
|
-
TODO_TOOL_DEFINITIONS: () => TODO_TOOL_DEFINITIONS,
|
|
8039
|
-
TOOL_NAME_MAP: () => TOOL_NAME_MAP,
|
|
8040
|
-
TrustError: () => TrustError,
|
|
8041
|
-
TrustStore: () => TrustStore,
|
|
8042
|
-
WRITE_FILE_TOOL: () => WRITE_FILE_TOOL,
|
|
8043
|
-
allOffConfig: () => allOffConfig,
|
|
8044
|
-
applyPlan: () => applyPlan,
|
|
8045
|
-
buildCommandRegistry: () => buildCommandRegistry,
|
|
8046
|
-
buildProfileSection: () => buildProfileSection,
|
|
8047
|
-
buildRuleSet: () => buildRuleSet,
|
|
8048
|
-
buildSkillsSection: () => buildSkillsSection,
|
|
8049
|
-
buildSystemPrompt: () => buildSystemPrompt,
|
|
8050
|
-
buildTranscriptForSummarization: () => buildTranscriptForSummarization,
|
|
8051
|
-
checkCoverage: () => checkCoverage,
|
|
8052
|
-
classifyCommand: () => classifyCommand,
|
|
8053
|
-
classifyRpcMessage: () => classifyRpcMessage,
|
|
8054
|
-
claudeProjectSlug: () => claudeProjectSlug,
|
|
8055
|
-
computeLockfileHash: () => computeLockfileHash,
|
|
8056
|
-
createBashTool: () => createBashTool,
|
|
8057
|
-
createCodegenTools: () => createCodegenTools,
|
|
8058
|
-
createFileTools: () => createFileTools,
|
|
8059
|
-
createGitHubTools: () => createGitHubTools,
|
|
8060
|
-
createHostSearchTool: () => createHostSearchTool,
|
|
8061
|
-
createHostToolExecutor: () => createHostToolExecutor,
|
|
8062
|
-
createInstructionsReadTool: () => createInstructionsReadTool,
|
|
8063
|
-
createMcpClient: () => createMcpClient,
|
|
8064
|
-
createMemoryReadTool: () => createMemoryReadTool,
|
|
8065
|
-
createPreviewTool: () => createPreviewTool,
|
|
8066
|
-
createProfileClient: () => createProfileClient,
|
|
8067
|
-
createProfileSkillSource: () => createProfileSkillSource,
|
|
8068
|
-
createRpcSession: () => createRpcSession,
|
|
8069
|
-
createSearchTool: () => createSearchTool,
|
|
8070
|
-
createSentryTools: () => createSentryTools,
|
|
8071
|
-
createSimpleRouter: () => createSimpleRouter,
|
|
8072
|
-
createSkillTool: () => createSkillTool,
|
|
8073
|
-
createTodoTool: () => createTodoTool,
|
|
8074
|
-
defaultModeFor: () => defaultModeFor,
|
|
8075
|
-
diffSources: () => diffSources,
|
|
8076
|
-
estimateTokens: () => estimateTokens,
|
|
8077
|
-
estimateTotalTokens: () => estimateTotalTokens,
|
|
8078
|
-
expandCommand: () => expandCommand,
|
|
8079
|
-
expandRefs: () => expandRefs,
|
|
8080
|
-
expandServerEnv: () => expandServerEnv,
|
|
8081
|
-
extractRuleLines: () => extractRuleLines,
|
|
8082
|
-
findUnsupported: () => findUnsupported,
|
|
8083
|
-
fingerprintSources: () => fingerprintSources,
|
|
8084
|
-
flattenMessageText: () => flattenMessageText,
|
|
8085
|
-
formatSkillBody: () => formatSkillBody,
|
|
8086
|
-
formatSourceChanges: () => formatSourceChanges,
|
|
8087
|
-
formatToolResult: () => formatToolResult,
|
|
8088
|
-
getCachedTools: () => getCachedTools,
|
|
8089
|
-
guardHost: () => guardHost,
|
|
8090
|
-
isReadOnlyCommand: () => isReadOnlyCommand,
|
|
8091
|
-
joinSections: () => joinSections,
|
|
8092
|
-
listMcpSpawns: () => listMcpSpawns,
|
|
8093
|
-
loadProfile: () => loadProfile,
|
|
8094
|
-
normalizeClaudeJsonMcp: () => normalizeClaudeJsonMcp,
|
|
8095
|
-
parseCommandFile: () => parseCommandFile,
|
|
8096
|
-
parseGitStatus: () => parseGitStatus,
|
|
8097
|
-
parseImportsConfig: () => parseImportsConfig,
|
|
8098
|
-
parseSkillFile: () => parseSkillFile,
|
|
8099
|
-
parseTodos: () => parseTodos,
|
|
8100
|
-
parseToolCache: () => parseToolCache,
|
|
8101
|
-
prepareAdaptation: () => prepareAdaptation,
|
|
8102
|
-
projectKey: () => projectKey,
|
|
8103
|
-
putCachedTools: () => putCachedTools,
|
|
8104
|
-
readClaudeAssets: () => readClaudeAssets,
|
|
8105
|
-
renderProjectCard: () => renderProjectCard,
|
|
8106
|
-
runAgentLoop: () => runAgentLoop,
|
|
8107
|
-
safeSkillPath: () => safeSkillPath,
|
|
8108
|
-
sameTools: () => sameTools,
|
|
8109
|
-
serializeImportsConfig: () => serializeImportsConfig,
|
|
8110
|
-
serializeToolCache: () => serializeToolCache,
|
|
8111
|
-
serverCacheKey: () => serverCacheKey,
|
|
8112
|
-
siblingAssetName: () => siblingAssetName,
|
|
8113
|
-
splitCommand: () => splitCommand,
|
|
8114
|
-
splitSections: () => splitSections,
|
|
8115
|
-
summarizeConversation: () => summarizeConversation,
|
|
8116
|
-
syncAfterBash: () => syncAfterBash,
|
|
8117
|
-
syncBeforeBash: () => syncBeforeBash,
|
|
8118
|
-
translateToolNames: () => translateToolNames
|
|
8119
|
-
});
|
|
8120
7009
|
var init_src = __esm({
|
|
8121
7010
|
"../agent/src/index.ts"() {
|
|
8122
7011
|
init_loop();
|
|
@@ -8179,14 +7068,9 @@ var init_src = __esm({
|
|
|
8179
7068
|
});
|
|
8180
7069
|
|
|
8181
7070
|
// src/api-key.ts
|
|
8182
|
-
var api_key_exports = {};
|
|
8183
|
-
__export(api_key_exports, {
|
|
8184
|
-
MISSING_KEY_MESSAGE: () => MISSING_KEY_MESSAGE,
|
|
8185
|
-
resolveApiKey: () => resolveApiKey
|
|
8186
|
-
});
|
|
8187
7071
|
import { join } from "node:path";
|
|
8188
7072
|
async function resolveApiKey(deps) {
|
|
8189
|
-
const { env: env3, readFile:
|
|
7073
|
+
const { env: env3, readFile: readFile12, homedir: homedir3 } = deps;
|
|
8190
7074
|
for (const name of ["SPACECODE_API_KEY", "ANTHROPIC_API_KEY"]) {
|
|
8191
7075
|
const value = env3[name]?.trim();
|
|
8192
7076
|
if (value) return value;
|
|
@@ -8195,7 +7079,7 @@ async function resolveApiKey(deps) {
|
|
|
8195
7079
|
const file = join(dir, "auth.json");
|
|
8196
7080
|
let raw;
|
|
8197
7081
|
try {
|
|
8198
|
-
raw = await
|
|
7082
|
+
raw = await readFile12(file);
|
|
8199
7083
|
} catch (err) {
|
|
8200
7084
|
if (err.code === "ENOENT") return null;
|
|
8201
7085
|
throw new Error(`Cannot read ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -8228,26 +7112,26 @@ __export(import_gate_exports, {
|
|
|
8228
7112
|
importGateStatus: () => importGateStatus,
|
|
8229
7113
|
nodeTrustFs: () => nodeTrustFs,
|
|
8230
7114
|
readRepoSources: () => readRepoSources,
|
|
8231
|
-
sha256: () =>
|
|
7115
|
+
sha256: () => sha256,
|
|
8232
7116
|
writeTextAtomic: () => writeTextAtomic
|
|
8233
7117
|
});
|
|
8234
7118
|
import { createHash, randomUUID } from "node:crypto";
|
|
8235
7119
|
import { chmod, mkdir, readFile, readdir, realpath, rename, writeFile } from "node:fs/promises";
|
|
8236
7120
|
import { dirname as dirname3, join as join2 } from "node:path";
|
|
8237
|
-
async function readOrNull(
|
|
7121
|
+
async function readOrNull(path13) {
|
|
8238
7122
|
try {
|
|
8239
|
-
return await readFile(
|
|
7123
|
+
return await readFile(path13, "utf8");
|
|
8240
7124
|
} catch (err) {
|
|
8241
7125
|
if (err.code === "ENOENT") return null;
|
|
8242
7126
|
throw err;
|
|
8243
7127
|
}
|
|
8244
7128
|
}
|
|
8245
|
-
async function writeTextAtomic(
|
|
8246
|
-
await mkdir(dirname3(
|
|
8247
|
-
const tmp = `${
|
|
7129
|
+
async function writeTextAtomic(path13, text) {
|
|
7130
|
+
await mkdir(dirname3(path13), { recursive: true });
|
|
7131
|
+
const tmp = `${path13}.${process.pid}.${randomUUID()}.tmp`;
|
|
8248
7132
|
await writeFile(tmp, text, { mode: 384 });
|
|
8249
7133
|
await chmod(tmp, 384);
|
|
8250
|
-
await rename(tmp,
|
|
7134
|
+
await rename(tmp, path13);
|
|
8251
7135
|
}
|
|
8252
7136
|
async function readRepoSources(cwd2) {
|
|
8253
7137
|
const files = {};
|
|
@@ -8301,7 +7185,7 @@ function nodeTrustFs() {
|
|
|
8301
7185
|
function createNodeTrustStore(configDir) {
|
|
8302
7186
|
let store = trustStores.get(configDir);
|
|
8303
7187
|
if (!store) {
|
|
8304
|
-
store = new TrustStore({ fs: nodeTrustFs(), path: join2(configDir, "trust.json"), hash:
|
|
7188
|
+
store = new TrustStore({ fs: nodeTrustFs(), path: join2(configDir, "trust.json"), hash: sha256 });
|
|
8305
7189
|
trustStores.set(configDir, store);
|
|
8306
7190
|
}
|
|
8307
7191
|
return store;
|
|
@@ -8333,7 +7217,7 @@ async function importGateStatus(deps) {
|
|
|
8333
7217
|
}
|
|
8334
7218
|
return lines2;
|
|
8335
7219
|
}
|
|
8336
|
-
var REPO_SOURCE_FILES, MAX_REPO_SKILL_FILES, MAX_REPO_SKILL_BYTES,
|
|
7220
|
+
var REPO_SOURCE_FILES, MAX_REPO_SKILL_FILES, MAX_REPO_SKILL_BYTES, sha256, trustStores;
|
|
8337
7221
|
var init_import_gate = __esm({
|
|
8338
7222
|
"src/import-gate.ts"() {
|
|
8339
7223
|
"use strict";
|
|
@@ -8341,7 +7225,7 @@ var init_import_gate = __esm({
|
|
|
8341
7225
|
REPO_SOURCE_FILES = [".mcp.json", ".claude/settings.json", ".claude/settings.local.json", "CLAUDE.local.md"];
|
|
8342
7226
|
MAX_REPO_SKILL_FILES = 200;
|
|
8343
7227
|
MAX_REPO_SKILL_BYTES = 256 * 1024;
|
|
8344
|
-
|
|
7228
|
+
sha256 = (text) => createHash("sha256").update(text).digest("hex");
|
|
8345
7229
|
trustStores = /* @__PURE__ */ new Map();
|
|
8346
7230
|
}
|
|
8347
7231
|
});
|
|
@@ -8527,12 +7411,6 @@ var init_mcp_loader = __esm({
|
|
|
8527
7411
|
});
|
|
8528
7412
|
|
|
8529
7413
|
// src/profile-runtime.ts
|
|
8530
|
-
var profile_runtime_exports = {};
|
|
8531
|
-
__export(profile_runtime_exports, {
|
|
8532
|
-
DEFAULT_BACKEND_URL: () => DEFAULT_BACKEND_URL,
|
|
8533
|
-
backendUrl: () => backendUrl,
|
|
8534
|
-
prepareProfile: () => prepareProfile
|
|
8535
|
-
});
|
|
8536
7414
|
import { join as join5 } from "node:path";
|
|
8537
7415
|
function backendUrl(env3) {
|
|
8538
7416
|
return env3.SPACECODE_BACKEND_URL?.trim() || env3.SPACECODE_API_URL?.trim() || DEFAULT_BACKEND_URL;
|
|
@@ -9023,15 +7901,24 @@ var init_mcp_manager = __esm({
|
|
|
9023
7901
|
}
|
|
9024
7902
|
}
|
|
9025
7903
|
}
|
|
9026
|
-
/**
|
|
7904
|
+
/**
|
|
7905
|
+
* Starts servers in the background. A server whose tools came from the cache is NOT started here: it starts on its first call
|
|
7906
|
+
* (`begin`), so an unused server never spawns. Every other server starts now, because its tools (or why it is skipped) are unknown.
|
|
7907
|
+
* Resolves when those have connected or failed; callers need not await it.
|
|
7908
|
+
*/
|
|
9027
7909
|
start() {
|
|
9028
|
-
this.startPromise ??= Promise.all(this.deps.defs.map((def) =>
|
|
9029
|
-
const p = this.startOne(def);
|
|
9030
|
-
this.connected.set(def.name, p);
|
|
9031
|
-
return p;
|
|
9032
|
-
})).then(() => void 0);
|
|
7910
|
+
this.startPromise ??= Promise.all(this.deps.defs.filter((def) => !this.cachedTools.has(def.name)).map((def) => this.begin(def))).then(() => void 0);
|
|
9033
7911
|
return this.startPromise;
|
|
9034
7912
|
}
|
|
7913
|
+
/** Starts one server once; later callers share the same attempt. */
|
|
7914
|
+
begin(def) {
|
|
7915
|
+
let p = this.connected.get(def.name);
|
|
7916
|
+
if (!p) {
|
|
7917
|
+
p = this.startOne(def);
|
|
7918
|
+
this.connected.set(def.name, p);
|
|
7919
|
+
}
|
|
7920
|
+
return p;
|
|
7921
|
+
}
|
|
9035
7922
|
/** Tools whose full names are valid and unique, plus the ones that are not. */
|
|
9036
7923
|
usable(server, listed) {
|
|
9037
7924
|
const tools = [];
|
|
@@ -9148,9 +8035,10 @@ var init_mcp_manager = __esm({
|
|
|
9148
8035
|
}
|
|
9149
8036
|
return out;
|
|
9150
8037
|
}
|
|
9151
|
-
/** A call on a cached tool waits for
|
|
8038
|
+
/** A call on a cached tool starts its server if it is not running yet, waits for it to connect (bounded by the connect timeout) and then goes through the normal checks. */
|
|
9152
8039
|
async callWhenReady(server, tool, input) {
|
|
9153
|
-
|
|
8040
|
+
const def = this.deps.defs.find((d) => d.name === server);
|
|
8041
|
+
if (def) await this.begin(def);
|
|
9154
8042
|
const state = this.servers.get(server);
|
|
9155
8043
|
if (state?.status === "ready" && !state.tools.some((t) => t.name === tool)) {
|
|
9156
8044
|
return { output: `MCP server "${server}" no longer offers ${tool}; its tool list changed since it was cached.`, is_error: true };
|
|
@@ -9202,7 +8090,7 @@ var init_mcp_manager = __esm({
|
|
|
9202
8090
|
const s = this.servers.get(def.name);
|
|
9203
8091
|
if (s === void 0) {
|
|
9204
8092
|
const cached3 = this.cachedTools.get(def.name);
|
|
9205
|
-
if (cached3) lines2.push(`mcp: ${def.name}
|
|
8093
|
+
if (cached3) lines2.push(`mcp: ${def.name} not started, ${cached3.length} tools from cache (starts on first use)`);
|
|
9206
8094
|
continue;
|
|
9207
8095
|
}
|
|
9208
8096
|
if (s.status === "ready") lines2.push(`mcp: ${s.name} ready, ${s.tools.length} tools${s.skippedTools.length ? ` (not usable: ${s.skippedTools.join(", ")})` : ""}`);
|
|
@@ -9226,13 +8114,9 @@ var init_mcp_manager = __esm({
|
|
|
9226
8114
|
});
|
|
9227
8115
|
|
|
9228
8116
|
// src/mcp/approve-mcp.ts
|
|
9229
|
-
var approve_mcp_exports = {};
|
|
9230
|
-
__export(approve_mcp_exports, {
|
|
9231
|
-
runApproveMcp: () => runApproveMcp
|
|
9232
|
-
});
|
|
9233
8117
|
async function runApproveMcp(deps) {
|
|
9234
8118
|
const { defs, statusLines } = await loadMcpDefs(deps);
|
|
9235
|
-
for (const l of statusLines) deps.log(l);
|
|
8119
|
+
if (!deps.quiet) for (const l of statusLines) deps.log(l);
|
|
9236
8120
|
const stdio = defs.filter((d) => d.transport === "stdio");
|
|
9237
8121
|
const todo = [];
|
|
9238
8122
|
for (const d of stdio) {
|
|
@@ -9240,13 +8124,15 @@ async function runApproveMcp(deps) {
|
|
|
9240
8124
|
if (await deps.trust.stdioStatus(key) === "unapproved") todo.push(d);
|
|
9241
8125
|
}
|
|
9242
8126
|
if (todo.length === 0) {
|
|
9243
|
-
deps.log(stdio.length === 0 ? "No stdio MCP servers to approve." : "Every stdio MCP server is already approved on this machine.");
|
|
8127
|
+
if (!deps.quiet) deps.log(stdio.length === 0 ? "No stdio MCP servers to approve." : "Every stdio MCP server is already approved on this machine.");
|
|
9244
8128
|
return 0;
|
|
9245
8129
|
}
|
|
9246
8130
|
if (!deps.ask) {
|
|
9247
8131
|
deps.log(`${todo.length} MCP server(s) need approval, but this is not an interactive terminal: nothing was approved.`);
|
|
9248
8132
|
return 1;
|
|
9249
8133
|
}
|
|
8134
|
+
if (deps.quiet) deps.log(`
|
|
8135
|
+
${todo.length} imported MCP server(s) want to run a command on this machine. Nothing spawns until you approve it (you can also run \`spacecode approve-mcp\` later).`);
|
|
9250
8136
|
let approved = 0;
|
|
9251
8137
|
for (const d of todo) {
|
|
9252
8138
|
deps.log(`
|
|
@@ -9274,19 +8160,65 @@ var init_approve_mcp = __esm({
|
|
|
9274
8160
|
}
|
|
9275
8161
|
});
|
|
9276
8162
|
|
|
8163
|
+
// src/mcp/approve-mcp-node.ts
|
|
8164
|
+
var approve_mcp_node_exports = {};
|
|
8165
|
+
__export(approve_mcp_node_exports, {
|
|
8166
|
+
runApproveMcpOnNode: () => runApproveMcpOnNode
|
|
8167
|
+
});
|
|
8168
|
+
import os from "node:os";
|
|
8169
|
+
import path3 from "node:path";
|
|
8170
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
8171
|
+
async function runApproveMcpOnNode(opts) {
|
|
8172
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || path3.join(os.homedir(), ".spacecode");
|
|
8173
|
+
const apiKey = await resolveApiKey({ env: process.env, readFile: (p) => readFile2(p, "utf-8"), homedir: os.homedir }).catch(() => null);
|
|
8174
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
8175
|
+
const { createInterface } = interactive ? await import("node:readline/promises") : { createInterface: void 0 };
|
|
8176
|
+
const rl = createInterface ? createInterface({ input: process.stdin, output: process.stdout }) : void 0;
|
|
8177
|
+
try {
|
|
8178
|
+
return await runApproveMcp({
|
|
8179
|
+
configDir,
|
|
8180
|
+
cwd: process.cwd(),
|
|
8181
|
+
readFile: (p) => readFile2(p, "utf-8"),
|
|
8182
|
+
client: apiKey ? createProfileClient({ baseUrl: backendUrl(process.env), apiKey, fetch }) : null,
|
|
8183
|
+
trust: createNodeTrustStore(configDir),
|
|
8184
|
+
...rl ? { ask: async (q2) => {
|
|
8185
|
+
try {
|
|
8186
|
+
return await rl.question(q2);
|
|
8187
|
+
} catch {
|
|
8188
|
+
return null;
|
|
8189
|
+
}
|
|
8190
|
+
} } : {},
|
|
8191
|
+
log: (line) => console.log(line),
|
|
8192
|
+
quiet: opts.quiet
|
|
8193
|
+
});
|
|
8194
|
+
} finally {
|
|
8195
|
+
rl?.close();
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
var init_approve_mcp_node = __esm({
|
|
8199
|
+
"src/mcp/approve-mcp-node.ts"() {
|
|
8200
|
+
"use strict";
|
|
8201
|
+
init_src();
|
|
8202
|
+
init_approve_mcp();
|
|
8203
|
+
init_import_gate();
|
|
8204
|
+
init_api_key();
|
|
8205
|
+
init_profile_runtime();
|
|
8206
|
+
}
|
|
8207
|
+
});
|
|
8208
|
+
|
|
9277
8209
|
// src/repo-trust-prompt.ts
|
|
9278
8210
|
var repo_trust_prompt_exports = {};
|
|
9279
8211
|
__export(repo_trust_prompt_exports, {
|
|
9280
8212
|
describeRepoSources: () => describeRepoSources,
|
|
9281
8213
|
promptRepoTrust: () => promptRepoTrust
|
|
9282
8214
|
});
|
|
9283
|
-
function ruleLists(
|
|
8215
|
+
function ruleLists(path13, text, lines2, warnings) {
|
|
9284
8216
|
let data;
|
|
9285
8217
|
try {
|
|
9286
8218
|
data = JSON.parse(text);
|
|
9287
8219
|
} catch (err) {
|
|
9288
8220
|
if (!(err instanceof SyntaxError)) throw err;
|
|
9289
|
-
warnings.push(`${
|
|
8221
|
+
warnings.push(`${path13}: not valid JSON, nothing from it loads`);
|
|
9290
8222
|
return;
|
|
9291
8223
|
}
|
|
9292
8224
|
const perms = typeof data === "object" && data !== null ? data.permissions : void 0;
|
|
@@ -9294,7 +8226,7 @@ function ruleLists(path12, text, lines2, warnings) {
|
|
|
9294
8226
|
for (const effect of ["allow", "deny", "ask"]) {
|
|
9295
8227
|
const list2 = perms[effect];
|
|
9296
8228
|
if (!Array.isArray(list2)) continue;
|
|
9297
|
-
for (const rule of list2) if (typeof rule === "string") lines2.push(` ${effect}: ${show2(rule)} (${
|
|
8229
|
+
for (const rule of list2) if (typeof rule === "string") lines2.push(` ${effect}: ${show2(rule)} (${path13})`);
|
|
9298
8230
|
}
|
|
9299
8231
|
}
|
|
9300
8232
|
function describeRepoSources(files) {
|
|
@@ -9540,7 +8472,7 @@ __export(base_exports, {
|
|
|
9540
8472
|
synchronizedOutput: () => synchronizedOutput
|
|
9541
8473
|
});
|
|
9542
8474
|
import process2 from "node:process";
|
|
9543
|
-
import
|
|
8475
|
+
import os2 from "node:os";
|
|
9544
8476
|
var ESC, OSC, BEL, SEP, isTerminalApp, isWindows2, isTmux, cwdFunction, wrapOsc, cursorTo, cursorMove, cursorUp, cursorDown, cursorForward, cursorBackward, cursorLeft, cursorSavePosition, cursorRestorePosition, cursorGetPosition, cursorNextLine, cursorPrevLine, cursorHide, cursorShow, eraseLines, eraseEndLine, eraseStartLine, eraseLine, eraseDown, eraseUp, eraseScreen, scrollUp, scrollDown, clearScreen, clearViewport, isOldWindows, clearTerminal, enterAlternativeScreen, exitAlternativeScreen, beginSynchronizedOutput, endSynchronizedOutput, synchronizedOutput, beep, link, image, iTerm, ConEmu, setCwd;
|
|
9545
8477
|
var init_base = __esm({
|
|
9546
8478
|
"../../node_modules/ansi-escapes/base.js"() {
|
|
@@ -9623,7 +8555,7 @@ var init_base = __esm({
|
|
|
9623
8555
|
if (isBrowser || !isWindows2) {
|
|
9624
8556
|
return false;
|
|
9625
8557
|
}
|
|
9626
|
-
const parts =
|
|
8558
|
+
const parts = os2.release().split(".");
|
|
9627
8559
|
const major = Number(parts[0]);
|
|
9628
8560
|
const build2 = Number(parts[2] ?? 0);
|
|
9629
8561
|
if (major < 10) {
|
|
@@ -31903,10 +30835,10 @@ var require_react_reconciler_development = __commonJS({
|
|
|
31903
30835
|
var setErrorHandler = null;
|
|
31904
30836
|
var setSuspenseHandler = null;
|
|
31905
30837
|
{
|
|
31906
|
-
var copyWithDeleteImpl = function(obj,
|
|
31907
|
-
var key =
|
|
30838
|
+
var copyWithDeleteImpl = function(obj, path13, index2) {
|
|
30839
|
+
var key = path13[index2];
|
|
31908
30840
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
31909
|
-
if (index2 + 1 ===
|
|
30841
|
+
if (index2 + 1 === path13.length) {
|
|
31910
30842
|
if (isArray(updated)) {
|
|
31911
30843
|
updated.splice(key, 1);
|
|
31912
30844
|
} else {
|
|
@@ -31914,11 +30846,11 @@ var require_react_reconciler_development = __commonJS({
|
|
|
31914
30846
|
}
|
|
31915
30847
|
return updated;
|
|
31916
30848
|
}
|
|
31917
|
-
updated[key] = copyWithDeleteImpl(obj[key],
|
|
30849
|
+
updated[key] = copyWithDeleteImpl(obj[key], path13, index2 + 1);
|
|
31918
30850
|
return updated;
|
|
31919
30851
|
};
|
|
31920
|
-
var copyWithDelete = function(obj,
|
|
31921
|
-
return copyWithDeleteImpl(obj,
|
|
30852
|
+
var copyWithDelete = function(obj, path13) {
|
|
30853
|
+
return copyWithDeleteImpl(obj, path13, 0);
|
|
31922
30854
|
};
|
|
31923
30855
|
var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
|
|
31924
30856
|
var oldKey = oldPath[index2];
|
|
@@ -31956,17 +30888,17 @@ var require_react_reconciler_development = __commonJS({
|
|
|
31956
30888
|
}
|
|
31957
30889
|
return copyWithRenameImpl(obj, oldPath, newPath, 0);
|
|
31958
30890
|
};
|
|
31959
|
-
var copyWithSetImpl = function(obj,
|
|
31960
|
-
if (index2 >=
|
|
30891
|
+
var copyWithSetImpl = function(obj, path13, index2, value) {
|
|
30892
|
+
if (index2 >= path13.length) {
|
|
31961
30893
|
return value;
|
|
31962
30894
|
}
|
|
31963
|
-
var key =
|
|
30895
|
+
var key = path13[index2];
|
|
31964
30896
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
31965
|
-
updated[key] = copyWithSetImpl(obj[key],
|
|
30897
|
+
updated[key] = copyWithSetImpl(obj[key], path13, index2 + 1, value);
|
|
31966
30898
|
return updated;
|
|
31967
30899
|
};
|
|
31968
|
-
var copyWithSet = function(obj,
|
|
31969
|
-
return copyWithSetImpl(obj,
|
|
30900
|
+
var copyWithSet = function(obj, path13, value) {
|
|
30901
|
+
return copyWithSetImpl(obj, path13, 0, value);
|
|
31970
30902
|
};
|
|
31971
30903
|
var findHook = function(fiber, id) {
|
|
31972
30904
|
var currentHook2 = fiber.memoizedState;
|
|
@@ -31976,10 +30908,10 @@ var require_react_reconciler_development = __commonJS({
|
|
|
31976
30908
|
}
|
|
31977
30909
|
return currentHook2;
|
|
31978
30910
|
};
|
|
31979
|
-
overrideHookState = function(fiber, id,
|
|
30911
|
+
overrideHookState = function(fiber, id, path13, value) {
|
|
31980
30912
|
var hook = findHook(fiber, id);
|
|
31981
30913
|
if (hook !== null) {
|
|
31982
|
-
var newState = copyWithSet(hook.memoizedState,
|
|
30914
|
+
var newState = copyWithSet(hook.memoizedState, path13, value);
|
|
31983
30915
|
hook.memoizedState = newState;
|
|
31984
30916
|
hook.baseState = newState;
|
|
31985
30917
|
fiber.memoizedProps = assign({}, fiber.memoizedProps);
|
|
@@ -31989,10 +30921,10 @@ var require_react_reconciler_development = __commonJS({
|
|
|
31989
30921
|
}
|
|
31990
30922
|
}
|
|
31991
30923
|
};
|
|
31992
|
-
overrideHookStateDeletePath = function(fiber, id,
|
|
30924
|
+
overrideHookStateDeletePath = function(fiber, id, path13) {
|
|
31993
30925
|
var hook = findHook(fiber, id);
|
|
31994
30926
|
if (hook !== null) {
|
|
31995
|
-
var newState = copyWithDelete(hook.memoizedState,
|
|
30927
|
+
var newState = copyWithDelete(hook.memoizedState, path13);
|
|
31996
30928
|
hook.memoizedState = newState;
|
|
31997
30929
|
hook.baseState = newState;
|
|
31998
30930
|
fiber.memoizedProps = assign({}, fiber.memoizedProps);
|
|
@@ -32015,8 +30947,8 @@ var require_react_reconciler_development = __commonJS({
|
|
|
32015
30947
|
}
|
|
32016
30948
|
}
|
|
32017
30949
|
};
|
|
32018
|
-
overrideProps = function(fiber,
|
|
32019
|
-
fiber.pendingProps = copyWithSet(fiber.memoizedProps,
|
|
30950
|
+
overrideProps = function(fiber, path13, value) {
|
|
30951
|
+
fiber.pendingProps = copyWithSet(fiber.memoizedProps, path13, value);
|
|
32020
30952
|
if (fiber.alternate) {
|
|
32021
30953
|
fiber.alternate.pendingProps = fiber.pendingProps;
|
|
32022
30954
|
}
|
|
@@ -32025,8 +30957,8 @@ var require_react_reconciler_development = __commonJS({
|
|
|
32025
30957
|
scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
|
|
32026
30958
|
}
|
|
32027
30959
|
};
|
|
32028
|
-
overridePropsDeletePath = function(fiber,
|
|
32029
|
-
fiber.pendingProps = copyWithDelete(fiber.memoizedProps,
|
|
30960
|
+
overridePropsDeletePath = function(fiber, path13) {
|
|
30961
|
+
fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path13);
|
|
32030
30962
|
if (fiber.alternate) {
|
|
32031
30963
|
fiber.alternate.pendingProps = fiber.pendingProps;
|
|
32032
30964
|
}
|
|
@@ -37882,7 +36814,7 @@ var init_ansi_styles2 = __esm({
|
|
|
37882
36814
|
|
|
37883
36815
|
// ../../node_modules/chalk/source/vendor/supports-color/index.js
|
|
37884
36816
|
import process4 from "node:process";
|
|
37885
|
-
import
|
|
36817
|
+
import os3 from "node:os";
|
|
37886
36818
|
import tty from "node:tty";
|
|
37887
36819
|
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process4.argv) {
|
|
37888
36820
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
@@ -37940,7 +36872,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
37940
36872
|
return min;
|
|
37941
36873
|
}
|
|
37942
36874
|
if (process4.platform === "win32") {
|
|
37943
|
-
const osRelease =
|
|
36875
|
+
const osRelease = os3.release().split(".");
|
|
37944
36876
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
37945
36877
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
37946
36878
|
}
|
|
@@ -39731,8 +38663,8 @@ var init_ErrorOverview = __esm({
|
|
|
39731
38663
|
init_dist3();
|
|
39732
38664
|
init_Box();
|
|
39733
38665
|
init_Text();
|
|
39734
|
-
cleanupPath = (
|
|
39735
|
-
return
|
|
38666
|
+
cleanupPath = (path13) => {
|
|
38667
|
+
return path13?.replace(`file://${cwd()}/`, "");
|
|
39736
38668
|
};
|
|
39737
38669
|
stackUtils = new import_stack_utils.default({
|
|
39738
38670
|
cwd: cwd(),
|
|
@@ -42971,7 +41903,7 @@ var require_has_flag = __commonJS({
|
|
|
42971
41903
|
var require_supports_colors = __commonJS({
|
|
42972
41904
|
"../../node_modules/@colors/colors/lib/system/supports-colors.js"(exports, module) {
|
|
42973
41905
|
"use strict";
|
|
42974
|
-
var
|
|
41906
|
+
var os7 = __require("os");
|
|
42975
41907
|
var hasFlag2 = require_has_flag();
|
|
42976
41908
|
var env3 = process.env;
|
|
42977
41909
|
var forceColor = void 0;
|
|
@@ -43009,7 +41941,7 @@ var require_supports_colors = __commonJS({
|
|
|
43009
41941
|
}
|
|
43010
41942
|
var min = forceColor ? 1 : 0;
|
|
43011
41943
|
if (process.platform === "win32") {
|
|
43012
|
-
var osRelease =
|
|
41944
|
+
var osRelease = os7.release().split(".");
|
|
43013
41945
|
if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
43014
41946
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
43015
41947
|
}
|
|
@@ -87094,15 +86026,15 @@ var require_route = __commonJS({
|
|
|
87094
86026
|
};
|
|
87095
86027
|
}
|
|
87096
86028
|
function wrapConversion(toModel, graph) {
|
|
87097
|
-
const
|
|
86029
|
+
const path13 = [graph[toModel].parent, toModel];
|
|
87098
86030
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
87099
86031
|
let cur = graph[toModel].parent;
|
|
87100
86032
|
while (graph[cur].parent) {
|
|
87101
|
-
|
|
86033
|
+
path13.unshift(graph[cur].parent);
|
|
87102
86034
|
fn = link2(conversions[graph[cur].parent][cur], fn);
|
|
87103
86035
|
cur = graph[cur].parent;
|
|
87104
86036
|
}
|
|
87105
|
-
fn.conversion =
|
|
86037
|
+
fn.conversion = path13;
|
|
87106
86038
|
return fn;
|
|
87107
86039
|
}
|
|
87108
86040
|
module.exports = function(fromModel) {
|
|
@@ -87342,7 +86274,7 @@ var require_has_flag2 = __commonJS({
|
|
|
87342
86274
|
var require_supports_color = __commonJS({
|
|
87343
86275
|
"../../node_modules/supports-color/index.js"(exports, module) {
|
|
87344
86276
|
"use strict";
|
|
87345
|
-
var
|
|
86277
|
+
var os7 = __require("os");
|
|
87346
86278
|
var tty2 = __require("tty");
|
|
87347
86279
|
var hasFlag2 = require_has_flag2();
|
|
87348
86280
|
var { env: env3 } = process;
|
|
@@ -87390,7 +86322,7 @@ var require_supports_color = __commonJS({
|
|
|
87390
86322
|
return min;
|
|
87391
86323
|
}
|
|
87392
86324
|
if (process.platform === "win32") {
|
|
87393
|
-
const osRelease =
|
|
86325
|
+
const osRelease = os7.release().split(".");
|
|
87394
86326
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
87395
86327
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
87396
86328
|
}
|
|
@@ -102323,9 +101255,9 @@ var init_credential_filter = __esm({
|
|
|
102323
101255
|
});
|
|
102324
101256
|
|
|
102325
101257
|
// src/session/session-store.ts
|
|
102326
|
-
import { chmod as chmod2, mkdir as mkdir2, open, readdir as readdir2, readFile as
|
|
101258
|
+
import { chmod as chmod2, mkdir as mkdir2, open, readdir as readdir2, readFile as readFile3, rename as rename2, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
102327
101259
|
import { randomBytes } from "node:crypto";
|
|
102328
|
-
import
|
|
101260
|
+
import path4 from "node:path";
|
|
102329
101261
|
function redactCredentials(value) {
|
|
102330
101262
|
if (typeof value === "string") return containsCredential(value) ? REDACTED : value;
|
|
102331
101263
|
if (Array.isArray(value)) return value.map(redactCredentials);
|
|
@@ -102400,7 +101332,7 @@ var init_session_store = __esm({
|
|
|
102400
101332
|
}
|
|
102401
101333
|
fileFor(id) {
|
|
102402
101334
|
if (!ID.test(id)) throw new SessionError(this.dir, `Invalid session id ${JSON.stringify(id)}`);
|
|
102403
|
-
return
|
|
101335
|
+
return path4.join(this.dir, `${id}.jsonl`);
|
|
102404
101336
|
}
|
|
102405
101337
|
async save(session2) {
|
|
102406
101338
|
const file = this.fileFor(session2.meta.id);
|
|
@@ -102429,7 +101361,7 @@ var init_session_store = __esm({
|
|
|
102429
101361
|
if (size > MAX_SESSION_BYTES) {
|
|
102430
101362
|
throw new SessionError(file, `Session is ${size} bytes, over the ${MAX_SESSION_BYTES}-byte cap; not loaded`);
|
|
102431
101363
|
}
|
|
102432
|
-
text = await
|
|
101364
|
+
text = await readFile3(file, "utf8");
|
|
102433
101365
|
} catch (err) {
|
|
102434
101366
|
if (err instanceof SessionError) throw err;
|
|
102435
101367
|
throw new SessionError(file, `Could not read session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
@@ -102453,7 +101385,7 @@ var init_session_store = __esm({
|
|
|
102453
101385
|
try {
|
|
102454
101386
|
sessions.push((await this.load(name.slice(0, -".jsonl".length))).meta);
|
|
102455
101387
|
} catch (err) {
|
|
102456
|
-
errors.push(err instanceof SessionError ? err : new SessionError(
|
|
101388
|
+
errors.push(err instanceof SessionError ? err : new SessionError(path4.join(this.dir, name), String(err), { cause: err }));
|
|
102457
101389
|
}
|
|
102458
101390
|
}
|
|
102459
101391
|
sessions.sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -103527,17 +102459,17 @@ function isSubsequence(needle, hay) {
|
|
|
103527
102459
|
for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) if (hay[j2] === needle[i]) i++;
|
|
103528
102460
|
return i === needle.length;
|
|
103529
102461
|
}
|
|
103530
|
-
function tier(
|
|
103531
|
-
const base =
|
|
102462
|
+
function tier(path13, q2) {
|
|
102463
|
+
const base = path13.slice(path13.lastIndexOf("/") + 1);
|
|
103532
102464
|
if (base.startsWith(q2)) return 0;
|
|
103533
102465
|
if (base.includes(q2)) return 1;
|
|
103534
|
-
if (
|
|
102466
|
+
if (path13.includes(q2)) return 2;
|
|
103535
102467
|
return 3;
|
|
103536
102468
|
}
|
|
103537
102469
|
function rankPaths(paths, query, limit = 8) {
|
|
103538
102470
|
if (query === "") return paths.slice(0, limit);
|
|
103539
102471
|
const q2 = query.toLowerCase();
|
|
103540
|
-
return paths.map((
|
|
102472
|
+
return paths.map((path13) => ({ path: path13, lower: path13.toLowerCase() })).filter(({ lower }) => isSubsequence(q2, lower)).map(({ path: path13, lower }) => ({ path: path13, rank: tier(lower, q2) })).sort((a, b2) => a.rank - b2.rank || a.path.length - b2.path.length || (a.path < b2.path ? -1 : a.path > b2.path ? 1 : 0)).slice(0, limit).map((m2) => m2.path);
|
|
103541
102473
|
}
|
|
103542
102474
|
var init_mention_rank = __esm({
|
|
103543
102475
|
"src/editor/mention-rank.ts"() {
|
|
@@ -103554,9 +102486,9 @@ function activeMention(text, cursor) {
|
|
|
103554
102486
|
const explicit = token[1] === "!";
|
|
103555
102487
|
return { start, query: token.slice(explicit ? 2 : 1), explicit };
|
|
103556
102488
|
}
|
|
103557
|
-
function insertMention(text, cursor, mention,
|
|
103558
|
-
if (/\s/.test(
|
|
103559
|
-
const inserted = `@${mention.explicit ? "!" : ""}${
|
|
102489
|
+
function insertMention(text, cursor, mention, path13) {
|
|
102490
|
+
if (/\s/.test(path13)) return { text, cursor };
|
|
102491
|
+
const inserted = `@${mention.explicit ? "!" : ""}${path13}`;
|
|
103560
102492
|
const head = text.slice(0, mention.start) + inserted;
|
|
103561
102493
|
const next = text[cursor];
|
|
103562
102494
|
if (next !== void 0 && /\s/.test(next)) return { text: head + text.slice(cursor), cursor: head.length + 1 };
|
|
@@ -103926,20 +102858,20 @@ var init_history_store = __esm({
|
|
|
103926
102858
|
});
|
|
103927
102859
|
|
|
103928
102860
|
// src/editor/history-file-io.ts
|
|
103929
|
-
import { chmod as chmod3, mkdir as mkdir3, readFile as
|
|
103930
|
-
import
|
|
102861
|
+
import { chmod as chmod3, mkdir as mkdir3, readFile as readFile4, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
|
|
102862
|
+
import path5 from "node:path";
|
|
103931
102863
|
function createFileHistoryIO(file) {
|
|
103932
102864
|
return {
|
|
103933
102865
|
async read() {
|
|
103934
102866
|
try {
|
|
103935
|
-
return await
|
|
102867
|
+
return await readFile4(file, "utf8");
|
|
103936
102868
|
} catch (err) {
|
|
103937
102869
|
if (err.code === "ENOENT") return null;
|
|
103938
102870
|
throw err;
|
|
103939
102871
|
}
|
|
103940
102872
|
},
|
|
103941
102873
|
async write(content) {
|
|
103942
|
-
await mkdir3(
|
|
102874
|
+
await mkdir3(path5.dirname(file), { recursive: true, mode: 448 });
|
|
103943
102875
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
103944
102876
|
await writeFile3(tmp, content, { mode: 384 });
|
|
103945
102877
|
await chmod3(tmp, 384);
|
|
@@ -104101,10 +103033,10 @@ var init_session_commands = __esm({
|
|
|
104101
103033
|
});
|
|
104102
103034
|
|
|
104103
103035
|
// src/local-toolset.ts
|
|
104104
|
-
import * as
|
|
104105
|
-
import * as
|
|
103036
|
+
import * as os4 from "node:os";
|
|
103037
|
+
import * as path6 from "node:path";
|
|
104106
103038
|
function createLocalToolset(opts) {
|
|
104107
|
-
const auditFile = opts.auditFile ??
|
|
103039
|
+
const auditFile = opts.auditFile ?? path6.join(os4.homedir(), ".spacecode", "audit.jsonl");
|
|
104108
103040
|
const host = guardHost(new LocalHost(opts.cwd), {
|
|
104109
103041
|
audit: new FileAuditLog(auditFile),
|
|
104110
103042
|
mode: opts.yolo ? "yolo" : "enforce",
|
|
@@ -104134,7 +103066,7 @@ var init_local_toolset = __esm({
|
|
|
104134
103066
|
|
|
104135
103067
|
// src/project-card-scan.ts
|
|
104136
103068
|
import { execFile as execFile3 } from "node:child_process";
|
|
104137
|
-
import { readdir as readdir3, readFile as
|
|
103069
|
+
import { readdir as readdir3, readFile as readFile5 } from "node:fs/promises";
|
|
104138
103070
|
import { join as join7 } from "node:path";
|
|
104139
103071
|
function digestLines(md) {
|
|
104140
103072
|
return md.split("\n").map((l) => l.trim()).filter((l) => l && !/^#\s/.test(l) && !/^[|\s:-]+$/.test(l) && !/^\|\s*(area|task|priority|date|issue|id)\b/i.test(l)).slice(0, 12);
|
|
@@ -104235,13 +103167,13 @@ var init_project_card_scan = __esm({
|
|
|
104235
103167
|
MAX_BACKLOG = 6;
|
|
104236
103168
|
DIGEST_FILES = ["CLAUDE.md", "TODO.md", "BUGS.md", "ISSUES.md", "CHANGELOG.md", "README.md"];
|
|
104237
103169
|
nodeScanIo = {
|
|
104238
|
-
async readdir(
|
|
104239
|
-
const entries = await readdir3(
|
|
103170
|
+
async readdir(path13) {
|
|
103171
|
+
const entries = await readdir3(path13, { withFileTypes: true });
|
|
104240
103172
|
return entries.map((e) => ({ name: e.name, isDir: e.isDirectory() }));
|
|
104241
103173
|
},
|
|
104242
|
-
async readFile(
|
|
103174
|
+
async readFile(path13) {
|
|
104243
103175
|
try {
|
|
104244
|
-
return await
|
|
103176
|
+
return await readFile5(path13, "utf8");
|
|
104245
103177
|
} catch (err) {
|
|
104246
103178
|
if (err.code === "ENOENT") return null;
|
|
104247
103179
|
throw err;
|
|
@@ -104594,9 +103526,9 @@ var init_mention_resolver = __esm({
|
|
|
104594
103526
|
|
|
104595
103527
|
// src/editor/node-mention-fs.ts
|
|
104596
103528
|
import { open as open2, realpath as realpath2, stat as stat2 } from "node:fs/promises";
|
|
104597
|
-
import
|
|
103529
|
+
import path7 from "node:path";
|
|
104598
103530
|
function isInside(root, target) {
|
|
104599
|
-
return target === root || target.startsWith(root.endsWith(
|
|
103531
|
+
return target === root || target.startsWith(root.endsWith(path7.sep) ? root : root + path7.sep);
|
|
104600
103532
|
}
|
|
104601
103533
|
function createNodeMentionFS(cwd2) {
|
|
104602
103534
|
let rootPromise;
|
|
@@ -104641,10 +103573,10 @@ var init_node_mention_fs = __esm({
|
|
|
104641
103573
|
|
|
104642
103574
|
// src/editor/node-read-dir.ts
|
|
104643
103575
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
104644
|
-
import
|
|
103576
|
+
import path8 from "node:path";
|
|
104645
103577
|
function createNodeReadDir(cwd2) {
|
|
104646
103578
|
return async (rel) => {
|
|
104647
|
-
const entries = await readdir4(
|
|
103579
|
+
const entries = await readdir4(path8.join(cwd2, rel), { withFileTypes: true });
|
|
104648
103580
|
return entries.map((e) => ({ name: e.name, isFile: e.isFile(), isDirectory: e.isDirectory() }));
|
|
104649
103581
|
};
|
|
104650
103582
|
}
|
|
@@ -104655,11 +103587,11 @@ var init_node_read_dir = __esm({
|
|
|
104655
103587
|
});
|
|
104656
103588
|
|
|
104657
103589
|
// src/editor/node-mentions.ts
|
|
104658
|
-
import { readFile as
|
|
104659
|
-
import
|
|
103590
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
103591
|
+
import path9 from "node:path";
|
|
104660
103592
|
async function readGitignore(cwd2) {
|
|
104661
103593
|
try {
|
|
104662
|
-
return createGitignoreMatcher(await
|
|
103594
|
+
return createGitignoreMatcher(await readFile6(path9.join(cwd2, ".gitignore"), "utf8"));
|
|
104663
103595
|
} catch (err) {
|
|
104664
103596
|
if (err.code === "ENOENT") return () => false;
|
|
104665
103597
|
throw err;
|
|
@@ -104769,7 +103701,7 @@ var init_recording_chunks = __esm({
|
|
|
104769
103701
|
|
|
104770
103702
|
// src/recording/recorder.ts
|
|
104771
103703
|
import { createHash as createHash4 } from "node:crypto";
|
|
104772
|
-
import { mkdir as mkdir4, readFile as
|
|
103704
|
+
import { mkdir as mkdir4, readFile as readFile7, rename as rename4, rm as rm2, writeFile as writeFile4, readdir as readdir5, stat as stat3 } from "node:fs/promises";
|
|
104773
103705
|
import { join as join9 } from "node:path";
|
|
104774
103706
|
function projectHash(root) {
|
|
104775
103707
|
return createHash4("sha256").update(root).digest("hex");
|
|
@@ -104793,7 +103725,7 @@ function createRecorder(deps) {
|
|
|
104793
103725
|
if (cached3) return cached3;
|
|
104794
103726
|
let st;
|
|
104795
103727
|
try {
|
|
104796
|
-
st = JSON.parse(await
|
|
103728
|
+
st = JSON.parse(await readFile7(stateFile(sessionId), "utf8"));
|
|
104797
103729
|
} catch (e) {
|
|
104798
103730
|
if (e.code !== "ENOENT") {
|
|
104799
103731
|
const bad = join9(deps.dir, "bad");
|
|
@@ -104988,15 +103920,15 @@ var init_recorder = __esm({
|
|
|
104988
103920
|
});
|
|
104989
103921
|
|
|
104990
103922
|
// src/recording/recording-runtime.ts
|
|
104991
|
-
import { mkdir as mkdir5, readFile as
|
|
103923
|
+
import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile5, stat as stat4 } from "node:fs/promises";
|
|
104992
103924
|
import { join as join10, sep as sep2 } from "node:path";
|
|
104993
103925
|
function matchesExclude(pattern, root) {
|
|
104994
103926
|
const re3 = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, `[^${sep2 === "\\" ? "\\\\" : "/"}]*`).replace(/\u0000/g, ".*");
|
|
104995
103927
|
return new RegExp(`^${re3}(?:[/\\\\].*)?$`).test(root);
|
|
104996
103928
|
}
|
|
104997
|
-
async function exists(
|
|
103929
|
+
async function exists(path13) {
|
|
104998
103930
|
try {
|
|
104999
|
-
await stat4(
|
|
103931
|
+
await stat4(path13);
|
|
105000
103932
|
return true;
|
|
105001
103933
|
} catch (e) {
|
|
105002
103934
|
if (e.code === "ENOENT") return false;
|
|
@@ -105013,7 +103945,7 @@ function createRecordingRuntime(deps) {
|
|
|
105013
103945
|
if (deps.env.SPACECODE_RECORD?.trim().toLowerCase() === "off") return "SPACECODE_RECORD=off";
|
|
105014
103946
|
let cfg = {};
|
|
105015
103947
|
try {
|
|
105016
|
-
cfg = JSON.parse(await
|
|
103948
|
+
cfg = JSON.parse(await readFile8(join10(deps.configDir, "config.json"), "utf8"));
|
|
105017
103949
|
} catch (e) {
|
|
105018
103950
|
if (e.code !== "ENOENT") return `~/.spacecode/config.json is unreadable (${e instanceof Error ? e.message : String(e)}); fix it to record`;
|
|
105019
103951
|
}
|
|
@@ -105162,21 +104094,21 @@ var init_skills_command = __esm({
|
|
|
105162
104094
|
});
|
|
105163
104095
|
|
|
105164
104096
|
// src/mcp/tool-cache-file.ts
|
|
105165
|
-
import { readFile as
|
|
104097
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
105166
104098
|
import { join as join11 } from "node:path";
|
|
105167
104099
|
function nodeToolCache(configDir) {
|
|
105168
|
-
const
|
|
104100
|
+
const path13 = join11(configDir, "mcp-tools-cache.json");
|
|
105169
104101
|
return {
|
|
105170
104102
|
read: async () => {
|
|
105171
104103
|
try {
|
|
105172
|
-
return await
|
|
104104
|
+
return await readFile9(path13, "utf8");
|
|
105173
104105
|
} catch (err) {
|
|
105174
104106
|
if (err.code === "ENOENT") return null;
|
|
105175
104107
|
throw err;
|
|
105176
104108
|
}
|
|
105177
104109
|
},
|
|
105178
|
-
write: (text) => writeTextAtomic(
|
|
105179
|
-
hash:
|
|
104110
|
+
write: (text) => writeTextAtomic(path13, text),
|
|
104111
|
+
hash: sha256
|
|
105180
104112
|
};
|
|
105181
104113
|
}
|
|
105182
104114
|
var init_tool_cache_file = __esm({
|
|
@@ -105187,11 +104119,11 @@ var init_tool_cache_file = __esm({
|
|
|
105187
104119
|
});
|
|
105188
104120
|
|
|
105189
104121
|
// src/permission-rules-loader.ts
|
|
105190
|
-
import { readFile as
|
|
104122
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
105191
104123
|
import { join as join12 } from "node:path";
|
|
105192
|
-
async function readOrNull2(
|
|
104124
|
+
async function readOrNull2(path13) {
|
|
105193
104125
|
try {
|
|
105194
|
-
return await
|
|
104126
|
+
return await readFile10(path13, "utf8");
|
|
105195
104127
|
} catch (err) {
|
|
105196
104128
|
if (err.code === "ENOENT") return null;
|
|
105197
104129
|
throw err;
|
|
@@ -105258,7 +104190,7 @@ var init_permission_rules_loader = __esm({
|
|
|
105258
104190
|
// src/import-reload.ts
|
|
105259
104191
|
async function checkRepoSources(deps, loaded) {
|
|
105260
104192
|
const files = await readRepoSources(deps.cwd);
|
|
105261
|
-
const current = fingerprintSources(files,
|
|
104193
|
+
const current = fingerprintSources(files, sha256);
|
|
105262
104194
|
const status = Object.keys(files).length === 0 ? "untrusted" : await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, files);
|
|
105263
104195
|
return { current, changes: diffSources(loaded, current), trusted: status === "trusted" || status === "session" };
|
|
105264
104196
|
}
|
|
@@ -105279,7 +104211,7 @@ async function describeReload(deps, loaded) {
|
|
|
105279
104211
|
async function trustCurrentSources(deps) {
|
|
105280
104212
|
const files = await readRepoSources(deps.cwd);
|
|
105281
104213
|
await createNodeTrustStore(deps.configDir).setRepo(deps.cwd, files, "trusted");
|
|
105282
|
-
return fingerprintSources(files,
|
|
104214
|
+
return fingerprintSources(files, sha256);
|
|
105283
104215
|
}
|
|
105284
104216
|
var init_import_reload = __esm({
|
|
105285
104217
|
"src/import-reload.ts"() {
|
|
@@ -105379,7 +104311,7 @@ var init_command_loader = __esm({
|
|
|
105379
104311
|
});
|
|
105380
104312
|
|
|
105381
104313
|
// src/useReplController.ts
|
|
105382
|
-
import { readFile as
|
|
104314
|
+
import { readFile as readFile11, writeFile as writeFile6, mkdir as mkdir6 } from "node:fs/promises";
|
|
105383
104315
|
import { homedir as homedir2 } from "node:os";
|
|
105384
104316
|
import { join as join14 } from "node:path";
|
|
105385
104317
|
import { execFile as execFile4 } from "node:child_process";
|
|
@@ -105404,7 +104336,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105404
104336
|
}, [turnStartedAt]);
|
|
105405
104337
|
const projectRoot = (0, import_react30.useMemo)(() => process.cwd(), []);
|
|
105406
104338
|
const promptTemplates = (0, import_react30.useCallback)(
|
|
105407
|
-
() => loadPromptTemplates({ env: process.env, readFile: (p) =>
|
|
104339
|
+
() => loadPromptTemplates({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), writeFile: (p, d) => writeFile6(p, d, "utf-8"), mkdir: (p) => mkdir6(p, { recursive: true }).then(() => void 0), homedir: homedir2, fetch }),
|
|
105408
104340
|
[]
|
|
105409
104341
|
);
|
|
105410
104342
|
(0, import_react30.useEffect)(() => {
|
|
@@ -105424,7 +104356,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105424
104356
|
projectRoot,
|
|
105425
104357
|
fetch,
|
|
105426
104358
|
baseUrl: backendUrl(process.env),
|
|
105427
|
-
resolveApiKey: () => resolveApiKey({ env: process.env, readFile: (p) =>
|
|
104359
|
+
resolveApiKey: () => resolveApiKey({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: homedir2 }).catch(() => null),
|
|
105428
104360
|
log: (m2) => console.error(`[agent-ui] ${m2}`)
|
|
105429
104361
|
});
|
|
105430
104362
|
const resumeListRef = (0, import_react30.useRef)([]);
|
|
@@ -105451,7 +104383,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105451
104383
|
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join14(homedir2(), ".spacecode"),
|
|
105452
104384
|
cwd: process.cwd(),
|
|
105453
104385
|
env: process.env,
|
|
105454
|
-
readFile: (p) =>
|
|
104386
|
+
readFile: (p) => readFile11(p, "utf-8"),
|
|
105455
104387
|
homedir: homedir2,
|
|
105456
104388
|
fetch,
|
|
105457
104389
|
builtins: SLASH_COMMANDS.map((c) => c.name)
|
|
@@ -105677,12 +104609,12 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105677
104609
|
return;
|
|
105678
104610
|
}
|
|
105679
104611
|
try {
|
|
105680
|
-
const baseline = loadedSourcesRef.current ?? fingerprintSources(await readRepoSources(process.cwd()),
|
|
104612
|
+
const baseline = loadedSourcesRef.current ?? fingerprintSources(await readRepoSources(process.cwd()), sha256);
|
|
105681
104613
|
if (rest[0] === "trust") {
|
|
105682
104614
|
loadedSourcesRef.current = await trustCurrentSources(deps);
|
|
105683
104615
|
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105684
104616
|
rulesRef.current = loaded.rules;
|
|
105685
|
-
const cmds = await loadCommands({ configDir, cwd: process.cwd(), env: process.env, readFile: (p) =>
|
|
104617
|
+
const cmds = await loadCommands({ configDir, cwd: process.cwd(), env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: homedir2, fetch, builtins: SLASH_COMMANDS.map((c) => c.name) });
|
|
105686
104618
|
setCommandsLoaded(cmds);
|
|
105687
104619
|
notice(["Trusted the repo import sources as they are now.", ...loaded.statusLines, ...cmds.statusLines, "MCP servers and skills apply on the next start."].join("\n"));
|
|
105688
104620
|
} else notice((await describeReload(deps, baseline)).join("\n"));
|
|
@@ -105762,7 +104694,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105762
104694
|
}
|
|
105763
104695
|
setIsRunning(true);
|
|
105764
104696
|
try {
|
|
105765
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
104697
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: homedir2 });
|
|
105766
104698
|
if (!apiKey2) {
|
|
105767
104699
|
notice(MISSING_KEY_MESSAGE);
|
|
105768
104700
|
return;
|
|
@@ -105784,7 +104716,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105784
104716
|
}
|
|
105785
104717
|
case "model": {
|
|
105786
104718
|
try {
|
|
105787
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
104719
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: homedir2 });
|
|
105788
104720
|
if (!apiKey2) {
|
|
105789
104721
|
notice(MISSING_KEY_MESSAGE);
|
|
105790
104722
|
return;
|
|
@@ -105819,7 +104751,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105819
104751
|
}
|
|
105820
104752
|
case "skills": {
|
|
105821
104753
|
const state = profileRef.current;
|
|
105822
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
104754
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: homedir2 }).catch(() => null);
|
|
105823
104755
|
const client = apiKey2 ? createProfileClient({ baseUrl: backendUrl(process.env), apiKey: apiKey2, fetch }) : null;
|
|
105824
104756
|
notice(await runSkillsCommand(slash.args, { source: state?.skills ?? null, client, statusLines: state?.statusLines.filter((l) => l.startsWith("skills")) ?? ["skills: not loaded yet (loads on your first message)"] }));
|
|
105825
104757
|
return;
|
|
@@ -105841,7 +104773,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105841
104773
|
try {
|
|
105842
104774
|
apiKey = await resolveApiKey({
|
|
105843
104775
|
env: process.env,
|
|
105844
|
-
readFile: (p) =>
|
|
104776
|
+
readFile: (p) => readFile11(p, "utf-8"),
|
|
105845
104777
|
homedir: homedir2
|
|
105846
104778
|
});
|
|
105847
104779
|
} catch (err) {
|
|
@@ -105894,7 +104826,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105894
104826
|
}
|
|
105895
104827
|
profilePromiseRef.current ??= prepareProfile({
|
|
105896
104828
|
env: process.env,
|
|
105897
|
-
readFile: (p) =>
|
|
104829
|
+
readFile: (p) => readFile11(p, "utf-8"),
|
|
105898
104830
|
writeFile: (p, d) => writeFile6(p, d, { encoding: "utf-8", mode: 384 }),
|
|
105899
104831
|
mkdir: async (p) => {
|
|
105900
104832
|
await mkdir6(p, { recursive: true });
|
|
@@ -105905,7 +104837,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105905
104837
|
gitRoot: gitTopLevel,
|
|
105906
104838
|
importGate: async () => {
|
|
105907
104839
|
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join14(homedir2(), ".spacecode");
|
|
105908
|
-
const fingerprint = fingerprintSources(await readRepoSources(process.cwd()),
|
|
104840
|
+
const fingerprint = fingerprintSources(await readRepoSources(process.cwd()), sha256);
|
|
105909
104841
|
const gate = await importGateStatus({ configDir, cwd: process.cwd(), interactive: Boolean(process.stdin.isTTY) });
|
|
105910
104842
|
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105911
104843
|
rulesRef.current = loaded.rules;
|
|
@@ -106201,12 +105133,12 @@ var init_TurnViewer = __esm({
|
|
|
106201
105133
|
});
|
|
106202
105134
|
|
|
106203
105135
|
// src/render/resume-rows.ts
|
|
106204
|
-
import
|
|
105136
|
+
import path10 from "node:path";
|
|
106205
105137
|
function orderSessions(sessions, projectRoot) {
|
|
106206
105138
|
return [...sessions.filter((s) => s.projectRoot === projectRoot), ...sessions.filter((s) => s.projectRoot !== projectRoot)];
|
|
106207
105139
|
}
|
|
106208
105140
|
function formatResumeRow(meta, now, columns, sep3 = "\xB7", ellipsis = "\u2026") {
|
|
106209
|
-
const project =
|
|
105141
|
+
const project = path10.basename(meta.projectRoot) || meta.projectRoot;
|
|
106210
105142
|
const tail = [meta.turns !== void 0 ? `${meta.turns} turn${meta.turns === 1 ? "" : "s"}` : null, formatCost(estimateCostUsd(meta.tokens.input, meta.tokens.output))].filter(Boolean).join(` ${sep3} `);
|
|
106211
105143
|
const head = `${formatAge(meta.updatedAt, now)} ${sep3} ${project} ${sep3} `;
|
|
106212
105144
|
const fixed = head.length + 2 + ` ${sep3} ${tail}`.length;
|
|
@@ -106351,14 +105283,14 @@ var App_exports = {};
|
|
|
106351
105283
|
__export(App_exports, {
|
|
106352
105284
|
App: () => App2
|
|
106353
105285
|
});
|
|
106354
|
-
import
|
|
106355
|
-
import
|
|
105286
|
+
import os5 from "node:os";
|
|
105287
|
+
import path11 from "node:path";
|
|
106356
105288
|
function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2, git: gitRunner, interactivePicker = true, fullscreen: fullscreen2 = false }) {
|
|
106357
105289
|
const promptHistory = (0, import_react34.useMemo)(
|
|
106358
|
-
() => history ?? new PromptHistory(createFileHistoryIO(
|
|
105290
|
+
() => history ?? new PromptHistory(createFileHistoryIO(path11.join(os5.homedir(), ".spacecode", "history"))),
|
|
106359
105291
|
[history]
|
|
106360
105292
|
);
|
|
106361
|
-
const sessionStore = (0, import_react34.useMemo)(() => sessions ?? new SessionStore(
|
|
105293
|
+
const sessionStore = (0, import_react34.useMemo)(() => sessions ?? new SessionStore(path11.join(os5.homedir(), ".spacecode", "sessions")), [sessions]);
|
|
106362
105294
|
const runGit = (0, import_react34.useMemo)(() => gitRunner ?? createNodeGitRunner(process.cwd()), [gitRunner]);
|
|
106363
105295
|
const startedAtRef = (0, import_react34.useRef)(Date.now());
|
|
106364
105296
|
const [viewingRaw, setViewing] = (0, import_react34.useState)(false);
|
|
@@ -106448,7 +105380,7 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
|
|
|
106448
105380
|
viewing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows: rows - 2, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
|
|
106449
105381
|
picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ResumePicker, { sessions: resumeFound.sessions, errors: resumeFound.errors, projectRoot: process.cwd(), now: /* @__PURE__ */ new Date(), rows: rows - 2, columns, preview: resume.preview, onResume: resume.load, onDelete: resume.remove, onClose: () => setResumeFound(null), onEscape: swallowEsc }),
|
|
106450
105382
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, display: hidden ? "none" : "flex", children: [
|
|
106451
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ??
|
|
105383
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ?? path11.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }) }),
|
|
106452
105384
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Transcript, { scroll, onMeasure, children: [
|
|
106453
105385
|
notices.map((n, i) => typeof n === "string" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("action"), children: n }, i) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorBlock, { view: n.error }, i)),
|
|
106454
105386
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }),
|
|
@@ -106478,7 +105410,7 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
|
|
|
106478
105410
|
] });
|
|
106479
105411
|
}
|
|
106480
105412
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
106481
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ??
|
|
105413
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ?? path11.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }),
|
|
106482
105414
|
notices.map((n, i) => typeof n === "string" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("action"), children: n }, i) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorBlock, { view: n.error }, i)),
|
|
106483
105415
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Static, { items: [BANNER, ...turns], children: (turn) => typeof turn === "symbol" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }, "banner") : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
106484
105416
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
|
|
@@ -106572,8 +105504,8 @@ init_color_policy();
|
|
|
106572
105504
|
applyColorPolicy(process.env, Boolean(process.stdout.isTTY));
|
|
106573
105505
|
|
|
106574
105506
|
// src/index.tsx
|
|
106575
|
-
import
|
|
106576
|
-
import
|
|
105507
|
+
import os6 from "node:os";
|
|
105508
|
+
import path12 from "node:path";
|
|
106577
105509
|
import fs5 from "node:fs";
|
|
106578
105510
|
import util2 from "node:util";
|
|
106579
105511
|
|
|
@@ -106659,7 +105591,7 @@ function clearOnResize(stdout) {
|
|
|
106659
105591
|
var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
|
|
106660
105592
|
if (process.argv[2] === "import-claude") {
|
|
106661
105593
|
const { runImportClaude: runImportClaude2 } = await Promise.resolve().then(() => (init_import_claude(), import_claude_exports));
|
|
106662
|
-
const { readFile:
|
|
105594
|
+
const { readFile: readFile12, readdir: readdir6 } = await import("node:fs/promises");
|
|
106663
105595
|
const { execFile: execFile5 } = await import("node:child_process");
|
|
106664
105596
|
const gitRoot = () => new Promise((resolve2) => {
|
|
106665
105597
|
execFile5("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() }, (err, stdout) => resolve2(err ? null : stdout.trim() || null));
|
|
@@ -106667,9 +105599,9 @@ if (process.argv[2] === "import-claude") {
|
|
|
106667
105599
|
const code = await runImportClaude2({
|
|
106668
105600
|
argv: process.argv.slice(2),
|
|
106669
105601
|
env: process.env,
|
|
106670
|
-
fs: { readFile: (p) =>
|
|
106671
|
-
readFile: (p) =>
|
|
106672
|
-
homedir:
|
|
105602
|
+
fs: { readFile: (p) => readFile12(p, "utf-8"), readdir: (p) => readdir6(p) },
|
|
105603
|
+
readFile: (p) => readFile12(p, "utf-8"),
|
|
105604
|
+
homedir: os6.homedir,
|
|
106673
105605
|
cwd: process.cwd(),
|
|
106674
105606
|
gitRoot,
|
|
106675
105607
|
fetch,
|
|
@@ -106688,37 +105620,8 @@ if (process.argv[2] === "import-claude") {
|
|
|
106688
105620
|
process.exit(code);
|
|
106689
105621
|
}
|
|
106690
105622
|
if (process.argv[2] === "approve-mcp") {
|
|
106691
|
-
const {
|
|
106692
|
-
|
|
106693
|
-
const { resolveApiKey: resolveApiKey2 } = await Promise.resolve().then(() => (init_api_key(), api_key_exports));
|
|
106694
|
-
const { backendUrl: backendUrl2 } = await Promise.resolve().then(() => (init_profile_runtime(), profile_runtime_exports));
|
|
106695
|
-
const { createProfileClient: createProfileClient2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
106696
|
-
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
106697
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || path11.join(os5.homedir(), ".spacecode");
|
|
106698
|
-
const apiKey = await resolveApiKey2({ env: process.env, readFile: (p) => readFile11(p, "utf-8"), homedir: os5.homedir }).catch(() => null);
|
|
106699
|
-
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
106700
|
-
const { createInterface } = interactive ? await import("node:readline/promises") : { createInterface: void 0 };
|
|
106701
|
-
const rl = createInterface ? createInterface({ input: process.stdin, output: process.stdout }) : void 0;
|
|
106702
|
-
try {
|
|
106703
|
-
const code = await runApproveMcp2({
|
|
106704
|
-
configDir,
|
|
106705
|
-
cwd: process.cwd(),
|
|
106706
|
-
readFile: (p) => readFile11(p, "utf-8"),
|
|
106707
|
-
client: apiKey ? createProfileClient2({ baseUrl: backendUrl2(process.env), apiKey, fetch }) : null,
|
|
106708
|
-
trust: createNodeTrustStore2(configDir),
|
|
106709
|
-
...rl ? { ask: async (q2) => {
|
|
106710
|
-
try {
|
|
106711
|
-
return await rl.question(q2);
|
|
106712
|
-
} catch {
|
|
106713
|
-
return null;
|
|
106714
|
-
}
|
|
106715
|
-
} } : {},
|
|
106716
|
-
log: (line) => console.log(line)
|
|
106717
|
-
});
|
|
106718
|
-
process.exitCode = code;
|
|
106719
|
-
} finally {
|
|
106720
|
-
rl?.close();
|
|
106721
|
-
}
|
|
105623
|
+
const { runApproveMcpOnNode: runApproveMcpOnNode2 } = await Promise.resolve().then(() => (init_approve_mcp_node(), approve_mcp_node_exports));
|
|
105624
|
+
process.exitCode = await runApproveMcpOnNode2({ quiet: false });
|
|
106722
105625
|
process.exit(process.exitCode ?? 0);
|
|
106723
105626
|
}
|
|
106724
105627
|
var repoName = process.env.REPO_NAME || process.cwd().split("/").pop() || void 0;
|
|
@@ -106735,7 +105638,7 @@ if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
|
106735
105638
|
const { promptRepoTrust: promptRepoTrust2 } = await Promise.resolve().then(() => (init_repo_trust_prompt(), repo_trust_prompt_exports));
|
|
106736
105639
|
const files = await readRepoSources2(process.cwd());
|
|
106737
105640
|
if (Object.keys(files).length > 0) {
|
|
106738
|
-
const store = createNodeTrustStore2(process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105641
|
+
const store = createNodeTrustStore2(process.env.SPACECODE_CONFIG_DIR?.trim() || path12.join(os6.homedir(), ".spacecode"));
|
|
106739
105642
|
if (await store.repoStatus(process.cwd(), files) === "untrusted") {
|
|
106740
105643
|
const { createInterface } = await import("node:readline/promises");
|
|
106741
105644
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -106763,6 +105666,15 @@ if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
|
106763
105666
|
`);
|
|
106764
105667
|
}
|
|
106765
105668
|
}
|
|
105669
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
105670
|
+
try {
|
|
105671
|
+
const { runApproveMcpOnNode: runApproveMcpOnNode2 } = await Promise.resolve().then(() => (init_approve_mcp_node(), approve_mcp_node_exports));
|
|
105672
|
+
await runApproveMcpOnNode2({ quiet: true });
|
|
105673
|
+
} catch (err) {
|
|
105674
|
+
process.stderr.write(`MCP approval check failed (${err instanceof Error ? err.message : String(err)}); imported MCP servers stay unapproved.
|
|
105675
|
+
`);
|
|
105676
|
+
}
|
|
105677
|
+
}
|
|
106766
105678
|
var restoreCiVariables = hideCiVariables(process.env, Boolean(process.stdout.isTTY));
|
|
106767
105679
|
var render3;
|
|
106768
105680
|
var App3;
|
|
@@ -106774,9 +105686,9 @@ try {
|
|
|
106774
105686
|
var fullscreen = shouldUseFullscreen(process.env, process.stdout, Boolean(process.stdin.isTTY));
|
|
106775
105687
|
var session;
|
|
106776
105688
|
if (fullscreen) {
|
|
106777
|
-
const dir =
|
|
105689
|
+
const dir = path12.join(os6.homedir(), ".spacecode");
|
|
106778
105690
|
fs5.mkdirSync(dir, { recursive: true });
|
|
106779
|
-
const restoreConsole = redirectConsole(
|
|
105691
|
+
const restoreConsole = redirectConsole(path12.join(dir, "repl.log"));
|
|
106780
105692
|
session = enterFullscreen(process.stdout, process);
|
|
106781
105693
|
session.onLeave(restoreConsole);
|
|
106782
105694
|
session.onLeave(clearOnResize(process.stdout));
|