@devstationlabs/cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devstation.js +183 -51
- package/package.json +1 -1
package/devstation.js
CHANGED
|
@@ -12510,7 +12510,7 @@ import { existsSync as existsSync12 } from "fs";
|
|
|
12510
12510
|
|
|
12511
12511
|
// src/lib/agent/cli/args.ts
|
|
12512
12512
|
var CLI_NAME = "devstation";
|
|
12513
|
-
var VERSION = "0.1.
|
|
12513
|
+
var VERSION = "0.1.4";
|
|
12514
12514
|
var COMMANDS = new Set([
|
|
12515
12515
|
"chat",
|
|
12516
12516
|
"run",
|
|
@@ -12731,7 +12731,7 @@ var SESSION_HELP = ` /undo rewind the last checkpoint
|
|
|
12731
12731
|
import { accessSync, constants as constants2, existsSync as existsSync10 } from "fs";
|
|
12732
12732
|
|
|
12733
12733
|
// src/lib/agent/git.ts
|
|
12734
|
-
import { existsSync } from "fs";
|
|
12734
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
12735
12735
|
import { join } from "path";
|
|
12736
12736
|
|
|
12737
12737
|
// src/lib/agent/shell.ts
|
|
@@ -12949,7 +12949,16 @@ function cloneTargetProblem(target) {
|
|
|
12949
12949
|
// src/lib/agent/git.ts
|
|
12950
12950
|
var CHECKPOINT_PREFIX = "agent checkpoint:";
|
|
12951
12951
|
function isRepo(root) {
|
|
12952
|
-
|
|
12952
|
+
const dotGit = join(root, ".git");
|
|
12953
|
+
if (!existsSync(dotGit))
|
|
12954
|
+
return false;
|
|
12955
|
+
try {
|
|
12956
|
+
if (statSync(dotGit).isFile())
|
|
12957
|
+
return readFileSync(dotGit, "utf8").startsWith("gitdir:");
|
|
12958
|
+
} catch {
|
|
12959
|
+
return false;
|
|
12960
|
+
}
|
|
12961
|
+
return existsSync(join(dotGit, "HEAD"));
|
|
12953
12962
|
}
|
|
12954
12963
|
function quote(value) {
|
|
12955
12964
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -13074,7 +13083,7 @@ import {
|
|
|
13074
13083
|
cpSync,
|
|
13075
13084
|
existsSync as existsSync3,
|
|
13076
13085
|
mkdirSync as mkdirSync2,
|
|
13077
|
-
readFileSync as
|
|
13086
|
+
readFileSync as readFileSync3,
|
|
13078
13087
|
readdirSync as readdirSync2,
|
|
13079
13088
|
rmSync,
|
|
13080
13089
|
writeFileSync as writeFileSync2
|
|
@@ -13085,10 +13094,10 @@ import { dirname as dirname2, join as join3 } from "path";
|
|
|
13085
13094
|
import {
|
|
13086
13095
|
existsSync as existsSync2,
|
|
13087
13096
|
mkdirSync,
|
|
13088
|
-
readFileSync,
|
|
13097
|
+
readFileSync as readFileSync2,
|
|
13089
13098
|
readdirSync,
|
|
13090
13099
|
realpathSync,
|
|
13091
|
-
statSync,
|
|
13100
|
+
statSync as statSync2,
|
|
13092
13101
|
writeFileSync
|
|
13093
13102
|
} from "fs";
|
|
13094
13103
|
import { dirname, isAbsolute, join as join2, relative, resolve, sep } from "path";
|
|
@@ -13165,10 +13174,10 @@ class Workspace {
|
|
|
13165
13174
|
if (!existsSync2(resolved.absolute)) {
|
|
13166
13175
|
return { ok: false, reason: `There is no file at ${relativePath}.` };
|
|
13167
13176
|
}
|
|
13168
|
-
if (
|
|
13177
|
+
if (statSync2(resolved.absolute).isDirectory()) {
|
|
13169
13178
|
return { ok: false, reason: `${relativePath} is a directory, not a file.` };
|
|
13170
13179
|
}
|
|
13171
|
-
const buffer =
|
|
13180
|
+
const buffer = readFileSync2(resolved.absolute);
|
|
13172
13181
|
if (looksBinary(buffer)) {
|
|
13173
13182
|
return {
|
|
13174
13183
|
ok: false,
|
|
@@ -13188,10 +13197,10 @@ class Workspace {
|
|
|
13188
13197
|
if (!resolved.ok)
|
|
13189
13198
|
return { ok: false, reason: resolved.reason };
|
|
13190
13199
|
if (existsSync2(resolved.absolute)) {
|
|
13191
|
-
if (
|
|
13200
|
+
if (statSync2(resolved.absolute).isDirectory()) {
|
|
13192
13201
|
return { ok: false, reason: `${relativePath} is a directory.` };
|
|
13193
13202
|
}
|
|
13194
|
-
if (looksBinary(
|
|
13203
|
+
if (looksBinary(readFileSync2(resolved.absolute))) {
|
|
13195
13204
|
return { ok: false, reason: `${relativePath} is a binary file and was not overwritten.` };
|
|
13196
13205
|
}
|
|
13197
13206
|
}
|
|
@@ -13203,7 +13212,7 @@ class Workspace {
|
|
|
13203
13212
|
const resolved = this.resolve(relativePath);
|
|
13204
13213
|
return resolved.ok && existsSync2(resolved.absolute);
|
|
13205
13214
|
}
|
|
13206
|
-
list(subdir = ".") {
|
|
13215
|
+
list(subdir = ".", limit = Number.POSITIVE_INFINITY) {
|
|
13207
13216
|
const base = subdir === "." || subdir === "" ? { ok: true, absolute: this.root } : this.resolve(subdir);
|
|
13208
13217
|
if (!base.ok || !existsSync2(base.absolute))
|
|
13209
13218
|
return [];
|
|
@@ -13212,6 +13221,8 @@ class Workspace {
|
|
|
13212
13221
|
const out = [];
|
|
13213
13222
|
const walk = (dir) => {
|
|
13214
13223
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
13224
|
+
if (out.length >= limit)
|
|
13225
|
+
return;
|
|
13215
13226
|
if (entry.name.startsWith(".") && skip.has(entry.name))
|
|
13216
13227
|
continue;
|
|
13217
13228
|
if (skip.has(entry.name))
|
|
@@ -13244,7 +13255,7 @@ function listSnapshots(root) {
|
|
|
13244
13255
|
if (!existsSync3(manifest))
|
|
13245
13256
|
continue;
|
|
13246
13257
|
try {
|
|
13247
|
-
found.push(JSON.parse(
|
|
13258
|
+
found.push(JSON.parse(readFileSync3(manifest, "utf8")));
|
|
13248
13259
|
} catch {}
|
|
13249
13260
|
}
|
|
13250
13261
|
return found.sort((a, b) => b.id.localeCompare(a.id));
|
|
@@ -18122,9 +18133,9 @@ import {
|
|
|
18122
18133
|
chmodSync,
|
|
18123
18134
|
existsSync as existsSync4,
|
|
18124
18135
|
mkdirSync as mkdirSync3,
|
|
18125
|
-
readFileSync as
|
|
18136
|
+
readFileSync as readFileSync4,
|
|
18126
18137
|
renameSync,
|
|
18127
|
-
statSync as
|
|
18138
|
+
statSync as statSync3,
|
|
18128
18139
|
writeFileSync as writeFileSync3
|
|
18129
18140
|
} from "fs";
|
|
18130
18141
|
import { dirname as dirname4, join as join5 } from "path";
|
|
@@ -18159,7 +18170,7 @@ function readSettingsFile(path4, problems = []) {
|
|
|
18159
18170
|
if (!existsSync4(path4))
|
|
18160
18171
|
return {};
|
|
18161
18172
|
try {
|
|
18162
|
-
const raw = JSON.parse(
|
|
18173
|
+
const raw = JSON.parse(readFileSync4(path4, "utf8"));
|
|
18163
18174
|
const out = {};
|
|
18164
18175
|
if (raw.provider !== undefined) {
|
|
18165
18176
|
const named = typeof raw.provider === "string" ? raw.provider.toLowerCase() : raw.provider;
|
|
@@ -18204,11 +18215,11 @@ function readCredentials(home, problems = []) {
|
|
|
18204
18215
|
if (!existsSync4(path4))
|
|
18205
18216
|
return {};
|
|
18206
18217
|
try {
|
|
18207
|
-
const mode =
|
|
18218
|
+
const mode = statSync3(path4).mode & 511;
|
|
18208
18219
|
if (mode & 63) {
|
|
18209
18220
|
problems.push(`${path4} is readable by other users (mode ${mode.toString(8)}). Fix it: chmod 600 ${path4}`);
|
|
18210
18221
|
}
|
|
18211
|
-
const raw = JSON.parse(
|
|
18222
|
+
const raw = JSON.parse(readFileSync4(path4, "utf8"));
|
|
18212
18223
|
const out = {};
|
|
18213
18224
|
for (const id of PROVIDER_IDS) {
|
|
18214
18225
|
if (typeof raw[id] === "string" && raw[id].trim())
|
|
@@ -18456,7 +18467,7 @@ async function embedMissing(store, provider, options = {}) {
|
|
|
18456
18467
|
import { join as join7 } from "path";
|
|
18457
18468
|
|
|
18458
18469
|
// src/lib/agent/repo-session.ts
|
|
18459
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
18470
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
18460
18471
|
import { join as join6, relative as relative2, sep as sep2 } from "path";
|
|
18461
18472
|
var SKIP_DIRS = new Set([
|
|
18462
18473
|
".git",
|
|
@@ -18500,9 +18511,9 @@ function readWorkspace(root, maxFileBytes = 1024 * 1024) {
|
|
|
18500
18511
|
}
|
|
18501
18512
|
if (!item.isFile())
|
|
18502
18513
|
continue;
|
|
18503
|
-
if (
|
|
18514
|
+
if (statSync4(full).size > maxFileBytes)
|
|
18504
18515
|
continue;
|
|
18505
|
-
const buffer =
|
|
18516
|
+
const buffer = readFileSync5(full);
|
|
18506
18517
|
if (looksBinary(buffer))
|
|
18507
18518
|
continue;
|
|
18508
18519
|
files[relative2(root, full).split(sep2).join("/")] = buffer.toString("utf8");
|
|
@@ -18511,6 +18522,69 @@ function readWorkspace(root, maxFileBytes = 1024 * 1024) {
|
|
|
18511
18522
|
walk3(root);
|
|
18512
18523
|
return files;
|
|
18513
18524
|
}
|
|
18525
|
+
var INDEX_SKIP_DIRS = new Set([
|
|
18526
|
+
...SKIP_DIRS,
|
|
18527
|
+
"target",
|
|
18528
|
+
"coverage",
|
|
18529
|
+
"__pycache__",
|
|
18530
|
+
".venv",
|
|
18531
|
+
"venv",
|
|
18532
|
+
".gradle",
|
|
18533
|
+
"out"
|
|
18534
|
+
]);
|
|
18535
|
+
var HIDDEN_KEEP = new Set([".github"]);
|
|
18536
|
+
function readWorkspaceBounded(root, opts = {}) {
|
|
18537
|
+
const maxFiles = opts.maxFiles ?? 20000;
|
|
18538
|
+
const until = Date.now() + (opts.deadlineMs ?? 1e4);
|
|
18539
|
+
const maxBytes = opts.maxFileBytes ?? 1024 * 1024;
|
|
18540
|
+
const files = {};
|
|
18541
|
+
let seen = 0;
|
|
18542
|
+
let stopped = null;
|
|
18543
|
+
const walk3 = (dir) => {
|
|
18544
|
+
let entries;
|
|
18545
|
+
try {
|
|
18546
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
18547
|
+
} catch {
|
|
18548
|
+
return;
|
|
18549
|
+
}
|
|
18550
|
+
for (const item of entries) {
|
|
18551
|
+
if (stopped)
|
|
18552
|
+
return;
|
|
18553
|
+
if (item.isSymbolicLink())
|
|
18554
|
+
continue;
|
|
18555
|
+
const full = join6(dir, item.name);
|
|
18556
|
+
if (item.isDirectory()) {
|
|
18557
|
+
if (INDEX_SKIP_DIRS.has(item.name))
|
|
18558
|
+
continue;
|
|
18559
|
+
if (item.name.startsWith(".") && !HIDDEN_KEEP.has(item.name))
|
|
18560
|
+
continue;
|
|
18561
|
+
walk3(full);
|
|
18562
|
+
continue;
|
|
18563
|
+
}
|
|
18564
|
+
if (!item.isFile())
|
|
18565
|
+
continue;
|
|
18566
|
+
if (seen >= maxFiles) {
|
|
18567
|
+
stopped = "max-files";
|
|
18568
|
+
return;
|
|
18569
|
+
}
|
|
18570
|
+
if ((seen & 63) === 0 && Date.now() > until) {
|
|
18571
|
+
stopped = "deadline";
|
|
18572
|
+
return;
|
|
18573
|
+
}
|
|
18574
|
+
seen++;
|
|
18575
|
+
try {
|
|
18576
|
+
if (statSync4(full).size > maxBytes)
|
|
18577
|
+
continue;
|
|
18578
|
+
const buffer = readFileSync5(full);
|
|
18579
|
+
if (looksBinary(buffer))
|
|
18580
|
+
continue;
|
|
18581
|
+
files[relative2(root, full).split(sep2).join("/")] = buffer.toString("utf8");
|
|
18582
|
+
} catch {}
|
|
18583
|
+
}
|
|
18584
|
+
};
|
|
18585
|
+
walk3(root);
|
|
18586
|
+
return { files, stopped };
|
|
18587
|
+
}
|
|
18514
18588
|
var MAX_TITLE = 72;
|
|
18515
18589
|
function proposalFor(goal, result, files) {
|
|
18516
18590
|
const firstLine = (goal || result.summary).split(`
|
|
@@ -18879,7 +18953,7 @@ class MemoryStore {
|
|
|
18879
18953
|
this.db.run("DELETE FROM chunks WHERE path = ?", [path4]);
|
|
18880
18954
|
this.db.run("DELETE FROM files WHERE path = ?", [path4]);
|
|
18881
18955
|
}
|
|
18882
|
-
reindex(files) {
|
|
18956
|
+
reindex(files, options = {}) {
|
|
18883
18957
|
const result = { scanned: 0, reindexed: 0, removed: 0, chunks: 0 };
|
|
18884
18958
|
this.db.run("BEGIN");
|
|
18885
18959
|
try {
|
|
@@ -18892,9 +18966,11 @@ class MemoryStore {
|
|
|
18892
18966
|
result.chunks += this.replaceFile(path4, content);
|
|
18893
18967
|
result.reindexed++;
|
|
18894
18968
|
}
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18969
|
+
if (!options.partial) {
|
|
18970
|
+
for (const gone of known) {
|
|
18971
|
+
this.removeFile(gone);
|
|
18972
|
+
result.removed++;
|
|
18973
|
+
}
|
|
18898
18974
|
}
|
|
18899
18975
|
this.db.run("COMMIT");
|
|
18900
18976
|
} catch (error2) {
|
|
@@ -18979,8 +19055,27 @@ function openStore(root) {
|
|
|
18979
19055
|
return new MemoryStore(storePath(root));
|
|
18980
19056
|
}
|
|
18981
19057
|
async function indexWorkspace(root, options = {}) {
|
|
19058
|
+
const started = Date.now();
|
|
19059
|
+
const home = options.home ?? process.env.HOME ?? "";
|
|
19060
|
+
const strip2 = (p) => p.replace(/\/+$/, "");
|
|
19061
|
+
if (home && strip2(root) === strip2(home)) {
|
|
19062
|
+
return {
|
|
19063
|
+
scanned: 0,
|
|
19064
|
+
reindexed: 0,
|
|
19065
|
+
removed: 0,
|
|
19066
|
+
chunks: 0,
|
|
19067
|
+
embedded: 0,
|
|
19068
|
+
embeddingModel: null,
|
|
19069
|
+
stopped: "home",
|
|
19070
|
+
ms: 0
|
|
19071
|
+
};
|
|
19072
|
+
}
|
|
18982
19073
|
const store = options.store ?? openStore(root);
|
|
18983
|
-
const
|
|
19074
|
+
const read = readWorkspaceBounded(root, {
|
|
19075
|
+
maxFiles: options.maxFiles,
|
|
19076
|
+
deadlineMs: options.deadlineMs
|
|
19077
|
+
});
|
|
19078
|
+
const result = store.reindex(read.files, { partial: read.stopped !== null });
|
|
18984
19079
|
let embedded = 0;
|
|
18985
19080
|
if (options.embeddings) {
|
|
18986
19081
|
try {
|
|
@@ -18989,11 +19084,17 @@ async function indexWorkspace(root, options = {}) {
|
|
|
18989
19084
|
embedded = 0;
|
|
18990
19085
|
}
|
|
18991
19086
|
}
|
|
18992
|
-
return {
|
|
19087
|
+
return {
|
|
19088
|
+
...result,
|
|
19089
|
+
embedded,
|
|
19090
|
+
embeddingModel: options.embeddings?.model ?? null,
|
|
19091
|
+
stopped: read.stopped,
|
|
19092
|
+
ms: Date.now() - started
|
|
19093
|
+
};
|
|
18993
19094
|
}
|
|
18994
19095
|
|
|
18995
19096
|
// src/lib/agent/memory/project-memory.ts
|
|
18996
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as
|
|
19097
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
18997
19098
|
import { dirname as dirname6, join as join8 } from "path";
|
|
18998
19099
|
var DEFAULT_FILE = "PROJECT_MEMORY.md";
|
|
18999
19100
|
var HEADER = `# Project memory
|
|
@@ -19012,7 +19113,7 @@ function readMemory(root) {
|
|
|
19012
19113
|
const path4 = memoryPath(root);
|
|
19013
19114
|
if (!existsSync5(path4))
|
|
19014
19115
|
return [];
|
|
19015
|
-
return parseMemory(
|
|
19116
|
+
return parseMemory(readFileSync6(path4, "utf8"));
|
|
19016
19117
|
}
|
|
19017
19118
|
var ENTRY = /^- \[([^\]]+)\](?:\s*\(([^)]*)\))?\s+([\s\S]*)$/;
|
|
19018
19119
|
function parseMemory(text) {
|
|
@@ -19036,7 +19137,7 @@ function remember(root, note, tag = null, now = new Date) {
|
|
|
19036
19137
|
if (!text) {
|
|
19037
19138
|
return { ok: false, path: path4, message: "There was nothing to remember." };
|
|
19038
19139
|
}
|
|
19039
|
-
const existing = existsSync5(path4) ?
|
|
19140
|
+
const existing = existsSync5(path4) ? readFileSync6(path4, "utf8") : "";
|
|
19040
19141
|
const entries = parseMemory(existing);
|
|
19041
19142
|
const normal = (value) => value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
19042
19143
|
if (entries.some((entry) => normal(entry.note) === normal(text))) {
|
|
@@ -19072,7 +19173,7 @@ function renderMemory(entries) {
|
|
|
19072
19173
|
|
|
19073
19174
|
// src/lib/agent/mcp.ts
|
|
19074
19175
|
import { spawn as spawn3 } from "child_process";
|
|
19075
|
-
import { existsSync as existsSync6, readFileSync as
|
|
19176
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
19076
19177
|
import { join as join9 } from "path";
|
|
19077
19178
|
function configPaths(root, home = process.env.HOME ?? "") {
|
|
19078
19179
|
return [
|
|
@@ -19087,7 +19188,7 @@ function loadConfig(root, home = process.env.HOME ?? "") {
|
|
|
19087
19188
|
if (!existsSync6(path4))
|
|
19088
19189
|
continue;
|
|
19089
19190
|
try {
|
|
19090
|
-
const parsed = JSON.parse(
|
|
19191
|
+
const parsed = JSON.parse(readFileSync7(path4, "utf8"));
|
|
19091
19192
|
for (const [name, server] of Object.entries(parsed.mcpServers ?? {})) {
|
|
19092
19193
|
if (server && typeof server.command === "string")
|
|
19093
19194
|
merged.mcpServers[name] = server;
|
|
@@ -19347,11 +19448,11 @@ function failedResult(message) {
|
|
|
19347
19448
|
|
|
19348
19449
|
// src/lib/agent/sandbox-exec.ts
|
|
19349
19450
|
import { randomBytes } from "crypto";
|
|
19350
|
-
import { existsSync as existsSync8, statSync as
|
|
19451
|
+
import { existsSync as existsSync8, statSync as statSync6, unlinkSync } from "fs";
|
|
19351
19452
|
import { isAbsolute as isAbsolute3, join as join11, relative as relative4, resolve as resolve3, sep as sep4 } from "path";
|
|
19352
19453
|
|
|
19353
19454
|
// src/lib/agent/project.ts
|
|
19354
|
-
import { existsSync as existsSync7, readFileSync as
|
|
19455
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
19355
19456
|
import { dirname as dirname7, join as join10, relative as relative3, sep as sep3 } from "path";
|
|
19356
19457
|
var SKIP = new Set([
|
|
19357
19458
|
"node_modules",
|
|
@@ -19378,7 +19479,7 @@ var MANIFESTS = [
|
|
|
19378
19479
|
var MAX_DEPTH = 2;
|
|
19379
19480
|
function readScripts(absolute) {
|
|
19380
19481
|
try {
|
|
19381
|
-
const parsed = JSON.parse(
|
|
19482
|
+
const parsed = JSON.parse(readFileSync8(absolute, "utf8"));
|
|
19382
19483
|
return parsed.scripts ?? {};
|
|
19383
19484
|
} catch {
|
|
19384
19485
|
return {};
|
|
@@ -19411,7 +19512,7 @@ function detectManifests(root) {
|
|
|
19411
19512
|
continue;
|
|
19412
19513
|
const child = join10(dir, entry);
|
|
19413
19514
|
try {
|
|
19414
|
-
if (
|
|
19515
|
+
if (statSync5(child).isDirectory())
|
|
19415
19516
|
scan(child, depth + 1);
|
|
19416
19517
|
} catch {}
|
|
19417
19518
|
}
|
|
@@ -19685,7 +19786,7 @@ function sandboxExecutor(options) {
|
|
|
19685
19786
|
return "The sandbox could not write to the workspace. Check the mount and try --no-sandbox.";
|
|
19686
19787
|
}
|
|
19687
19788
|
try {
|
|
19688
|
-
const stat2 =
|
|
19789
|
+
const stat2 = statSync6(path4);
|
|
19689
19790
|
const [uid, gid] = user.split(":").map(Number);
|
|
19690
19791
|
if (stat2.uid !== uid || stat2.gid !== gid) {
|
|
19691
19792
|
return `The sandbox writes files as ${stat2.uid}:${stat2.gid} but this account is ${user}. ` + "Files it creates would not be yours to edit, and git would stop trusting the " + "repository, so it was not started. Run with --no-sandbox, or set " + "DEVSTATION_SANDBOX_USER.";
|
|
@@ -19953,8 +20054,20 @@ function fail(reason) {
|
|
|
19953
20054
|
function executeFileTool(workspace, name, args) {
|
|
19954
20055
|
switch (name) {
|
|
19955
20056
|
case "list_files": {
|
|
19956
|
-
const
|
|
19957
|
-
|
|
20057
|
+
const LIMIT = 2000;
|
|
20058
|
+
const files = workspace.list(String(args.path ?? "."), LIMIT + 1);
|
|
20059
|
+
if (files.length === 0)
|
|
20060
|
+
return { ok: true, output: "The workspace is empty." };
|
|
20061
|
+
if (files.length > LIMIT) {
|
|
20062
|
+
return {
|
|
20063
|
+
ok: true,
|
|
20064
|
+
output: `${files.slice(0, LIMIT).join(`
|
|
20065
|
+
`)}
|
|
20066
|
+
|
|
20067
|
+
` + `(Stopped at ${LIMIT} files: this directory is very large. List a subdirectory, or search for what you need.)`
|
|
20068
|
+
};
|
|
20069
|
+
}
|
|
20070
|
+
return { ok: true, output: files.join(`
|
|
19958
20071
|
`) };
|
|
19959
20072
|
}
|
|
19960
20073
|
case "read_file": {
|
|
@@ -19991,7 +20104,10 @@ function executeFileTool(workspace, name, args) {
|
|
|
19991
20104
|
return fail("No search query was given.");
|
|
19992
20105
|
const hits = [];
|
|
19993
20106
|
let truncated = false;
|
|
19994
|
-
|
|
20107
|
+
const MAX_SCAN = 20000;
|
|
20108
|
+
const scanned = workspace.list(".", MAX_SCAN + 1);
|
|
20109
|
+
const scanLimited = scanned.length > MAX_SCAN;
|
|
20110
|
+
for (const path4 of scanned.slice(0, MAX_SCAN)) {
|
|
19995
20111
|
const file = workspace.read(path4);
|
|
19996
20112
|
if (!file.ok)
|
|
19997
20113
|
continue;
|
|
@@ -20010,14 +20126,18 @@ function executeFileTool(workspace, name, args) {
|
|
|
20010
20126
|
if (truncated)
|
|
20011
20127
|
break;
|
|
20012
20128
|
}
|
|
20013
|
-
|
|
20014
|
-
|
|
20129
|
+
const scanNote = scanLimited ? `
|
|
20130
|
+
|
|
20131
|
+
(Searched the first ${MAX_SCAN} files only: this workspace is very large. Search a subdirectory.)` : "";
|
|
20132
|
+
if (hits.length === 0) {
|
|
20133
|
+
return { ok: true, output: `No match for "${args.query}".${scanNote}` };
|
|
20134
|
+
}
|
|
20015
20135
|
return {
|
|
20016
20136
|
ok: true,
|
|
20017
|
-
output: truncated ? `${hits.join(`
|
|
20137
|
+
output: `${truncated ? `${hits.join(`
|
|
20018
20138
|
`)}
|
|
20019
20139
|
\u2026 more matches not shown` : hits.join(`
|
|
20020
|
-
`)
|
|
20140
|
+
`)}${scanNote}`
|
|
20021
20141
|
};
|
|
20022
20142
|
}
|
|
20023
20143
|
default:
|
|
@@ -20738,10 +20858,10 @@ import {
|
|
|
20738
20858
|
appendFileSync,
|
|
20739
20859
|
existsSync as existsSync9,
|
|
20740
20860
|
mkdirSync as mkdirSync6,
|
|
20741
|
-
readFileSync as
|
|
20861
|
+
readFileSync as readFileSync9,
|
|
20742
20862
|
readdirSync as readdirSync6,
|
|
20743
20863
|
renameSync as renameSync2,
|
|
20744
|
-
statSync as
|
|
20864
|
+
statSync as statSync7,
|
|
20745
20865
|
writeFileSync as writeFileSync5
|
|
20746
20866
|
} from "fs";
|
|
20747
20867
|
import { join as join12 } from "path";
|
|
@@ -20804,7 +20924,7 @@ class SessionStore {
|
|
|
20804
20924
|
if (!existsSync9(path4))
|
|
20805
20925
|
return null;
|
|
20806
20926
|
try {
|
|
20807
|
-
return JSON.parse(
|
|
20927
|
+
return JSON.parse(readFileSync9(path4, "utf8"));
|
|
20808
20928
|
} catch {
|
|
20809
20929
|
return null;
|
|
20810
20930
|
}
|
|
@@ -20826,10 +20946,10 @@ class SessionStore {
|
|
|
20826
20946
|
const path4 = this.eventPath(id);
|
|
20827
20947
|
if (!existsSync9(path4))
|
|
20828
20948
|
return { events: [], offset: 0 };
|
|
20829
|
-
const size =
|
|
20949
|
+
const size = statSync7(path4).size;
|
|
20830
20950
|
if (size <= fromByte)
|
|
20831
20951
|
return { events: [], offset: size };
|
|
20832
|
-
const text =
|
|
20952
|
+
const text = readFileSync9(path4, "utf8").slice(fromByte);
|
|
20833
20953
|
const events = [];
|
|
20834
20954
|
let consumed = 0;
|
|
20835
20955
|
for (const line of text.split(`
|
|
@@ -20973,9 +21093,21 @@ async function runCommand(context, goal, options = {}) {
|
|
|
20973
21093
|
executor = built.executor;
|
|
20974
21094
|
}
|
|
20975
21095
|
const embeddings = embeddingsFromEnv();
|
|
21096
|
+
const firstIndex = !existsSync10(storePath(context.root));
|
|
21097
|
+
if (firstIndex && !options.quiet)
|
|
21098
|
+
terminal.out("Indexing the workspace so the agent can search it\u2026");
|
|
20976
21099
|
const memory = openStore(context.root);
|
|
20977
21100
|
try {
|
|
20978
|
-
await indexWorkspace(context.root, { store: memory, embeddings });
|
|
21101
|
+
const indexed = await indexWorkspace(context.root, { store: memory, embeddings });
|
|
21102
|
+
if (!options.quiet) {
|
|
21103
|
+
if (indexed.stopped === "home") {
|
|
21104
|
+
terminal.err("Not indexing your home directory. The agent can still read and list files; cd into a project for a real index.");
|
|
21105
|
+
} else if (indexed.stopped) {
|
|
21106
|
+
terminal.err(`Indexed ${indexed.scanned} files and stopped at the ${indexed.stopped === "deadline" ? "time" : "file"} limit: this workspace is very large. cd into the project you mean.`);
|
|
21107
|
+
} else if (firstIndex || indexed.ms > 1500) {
|
|
21108
|
+
terminal.out(`Indexed ${indexed.scanned} files in ${(indexed.ms / 1000).toFixed(1)}s.`);
|
|
21109
|
+
}
|
|
21110
|
+
}
|
|
20979
21111
|
} catch {}
|
|
20980
21112
|
const mcp = await McpHub.start(loadConfig(context.root));
|
|
20981
21113
|
for (const status of mcp.status) {
|
|
@@ -22160,7 +22292,7 @@ function lineReader(rl, write) {
|
|
|
22160
22292
|
// src/lib/agent/cli/upgrade.ts
|
|
22161
22293
|
import { spawnSync } from "child_process";
|
|
22162
22294
|
import { createHash as createHash2 } from "crypto";
|
|
22163
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync8, readFileSync as
|
|
22295
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync10, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
22164
22296
|
import { dirname as dirname8, join as join14 } from "path";
|
|
22165
22297
|
var PACKAGE = "@devstationlabs/cli";
|
|
22166
22298
|
var REPO = "linoxbt/dev-shipyard";
|
|
@@ -22301,7 +22433,7 @@ function notifyIfOutdated(terminal, opts = {}) {
|
|
|
22301
22433
|
const path4 = join14(homeDir, ".devstation", "update-check.json");
|
|
22302
22434
|
let cached = {};
|
|
22303
22435
|
try {
|
|
22304
|
-
cached = JSON.parse(
|
|
22436
|
+
cached = JSON.parse(readFileSync10(path4, "utf8"));
|
|
22305
22437
|
} catch {}
|
|
22306
22438
|
if (cached.latest && compareVersions(cached.latest, VERSION) > 0) {
|
|
22307
22439
|
terminal.err(`devstation ${cached.latest} is available (you have ${VERSION}). Run: devstation upgrade`);
|