@alook/daemon 0.1.31 → 0.1.32
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/cli/index.js +970 -193
- package/dist/index.js +821 -116
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -15979,6 +15979,7 @@ var TERMINAL_MEETING_STATUSES = [
|
|
|
15979
15979
|
MeetingStatus.COMPLETED,
|
|
15980
15980
|
MeetingStatus.FAILED
|
|
15981
15981
|
];
|
|
15982
|
+
var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
|
|
15982
15983
|
var COMMUNITY_BOT_NAME_MIN = 1;
|
|
15983
15984
|
var COMMUNITY_BOT_NAME_MAX = 32;
|
|
15984
15985
|
var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
|
|
@@ -16853,6 +16854,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
16853
16854
|
launchId: exports_external.string().min(1),
|
|
16854
16855
|
unreadNotice: exports_external.unknown()
|
|
16855
16856
|
}),
|
|
16857
|
+
exports_external.object({
|
|
16858
|
+
type: exports_external.literal("agent:event"),
|
|
16859
|
+
agentId: exports_external.string().min(1),
|
|
16860
|
+
config: exports_external.unknown(),
|
|
16861
|
+
launchId: exports_external.string().min(1),
|
|
16862
|
+
prompt: exports_external.string().min(1).max(32768)
|
|
16863
|
+
}),
|
|
16856
16864
|
exports_external.object({
|
|
16857
16865
|
type: exports_external.literal("agent:stop"),
|
|
16858
16866
|
agentId: exports_external.string().min(1)
|
|
@@ -17762,6 +17770,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
|
|
|
17762
17770
|
var CommunityBotAddToServerRequestSchema = exports_external.object({
|
|
17763
17771
|
botId: exports_external.string().min(1)
|
|
17764
17772
|
});
|
|
17773
|
+
var CommunityServerOnboardRequestSchema = exports_external.strictObject({
|
|
17774
|
+
botIds: exports_external.array(exports_external.string().min(1).max(128)).min(1).max(COMMUNITY_BOT_LIMIT_PER_OWNER).refine((ids) => new Set(ids).size === ids.length, "botIds must be unique"),
|
|
17775
|
+
wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
|
|
17776
|
+
});
|
|
17765
17777
|
var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
|
|
17766
17778
|
var CommunityAgentSeqSchema = exports_external.number().int().min(0);
|
|
17767
17779
|
var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
|
|
@@ -19557,13 +19569,13 @@ function createProxyServerApi(config2) {
|
|
|
19557
19569
|
|
|
19558
19570
|
// src/cli/daemonStart.ts
|
|
19559
19571
|
import * as fs12 from "fs";
|
|
19560
|
-
import * as
|
|
19572
|
+
import * as path17 from "path";
|
|
19561
19573
|
import * as crypto5 from "crypto";
|
|
19562
19574
|
import * as os3 from "os";
|
|
19563
|
-
import { homedir as
|
|
19575
|
+
import { homedir as homedir8 } from "os";
|
|
19564
19576
|
|
|
19565
19577
|
// src/discovery.ts
|
|
19566
|
-
import * as
|
|
19578
|
+
import * as path13 from "path";
|
|
19567
19579
|
import * as fs6 from "fs";
|
|
19568
19580
|
import { fileURLToPath } from "url";
|
|
19569
19581
|
// agent-driver/dist/host/default-host.js
|
|
@@ -20707,6 +20719,12 @@ function tryParseJsonLine(line) {
|
|
|
20707
20719
|
return null;
|
|
20708
20720
|
}
|
|
20709
20721
|
}
|
|
20722
|
+
function asRecord(value) {
|
|
20723
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
20724
|
+
}
|
|
20725
|
+
function tryParseJsonRecord(line) {
|
|
20726
|
+
return asRecord(tryParseJsonLine(line));
|
|
20727
|
+
}
|
|
20710
20728
|
|
|
20711
20729
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
20712
20730
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
@@ -21205,6 +21223,241 @@ class ClaudeTurnProtocol {
|
|
|
21205
21223
|
}
|
|
21206
21224
|
}
|
|
21207
21225
|
|
|
21226
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
21227
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
21228
|
+
import { homedir } from "node:os";
|
|
21229
|
+
import path7 from "node:path";
|
|
21230
|
+
import { createInterface } from "node:readline";
|
|
21231
|
+
|
|
21232
|
+
// agent-driver/dist/internal/recent-context.js
|
|
21233
|
+
import path6 from "node:path";
|
|
21234
|
+
import { createReadStream } from "node:fs";
|
|
21235
|
+
import { readdir, stat } from "node:fs/promises";
|
|
21236
|
+
function normalizeAbsolutePath(value) {
|
|
21237
|
+
if (typeof value !== "string" || !path6.isAbsolute(value))
|
|
21238
|
+
return null;
|
|
21239
|
+
return path6.normalize(value);
|
|
21240
|
+
}
|
|
21241
|
+
function normalizeModifiedAt(value) {
|
|
21242
|
+
const date5 = value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : null;
|
|
21243
|
+
if (!date5 || !Number.isFinite(date5.getTime()))
|
|
21244
|
+
return null;
|
|
21245
|
+
return date5.toISOString();
|
|
21246
|
+
}
|
|
21247
|
+
function isValidRecentContextTopK(value) {
|
|
21248
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
21249
|
+
}
|
|
21250
|
+
function isMissingPathError(error51) {
|
|
21251
|
+
return error51?.code === "ENOENT";
|
|
21252
|
+
}
|
|
21253
|
+
async function readFirstLine(filePath, maxBytes = 65536) {
|
|
21254
|
+
const stream = createReadStream(filePath, { highWaterMark: 1 });
|
|
21255
|
+
const bytes = [];
|
|
21256
|
+
let length = 0;
|
|
21257
|
+
try {
|
|
21258
|
+
for await (const chunk2 of stream) {
|
|
21259
|
+
const byte = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
21260
|
+
if (byte[0] === 10)
|
|
21261
|
+
break;
|
|
21262
|
+
if (length >= maxBytes)
|
|
21263
|
+
return null;
|
|
21264
|
+
bytes.push(byte);
|
|
21265
|
+
length += byte.length;
|
|
21266
|
+
}
|
|
21267
|
+
return length === 0 ? null : Buffer.concat(bytes, length).toString("utf8").replace(/\r$/, "");
|
|
21268
|
+
} catch (error51) {
|
|
21269
|
+
if (isMissingPathError(error51))
|
|
21270
|
+
return null;
|
|
21271
|
+
throw error51;
|
|
21272
|
+
} finally {
|
|
21273
|
+
stream.destroy();
|
|
21274
|
+
}
|
|
21275
|
+
}
|
|
21276
|
+
async function collectJsonlFileCandidates(root, options = {}) {
|
|
21277
|
+
const candidates = [];
|
|
21278
|
+
const readDirectory = options.readDirectory ?? ((directory) => readdir(directory, { withFileTypes: true }));
|
|
21279
|
+
const statPath = options.statPath ?? stat;
|
|
21280
|
+
const visit = async (directory, remainingDepth, includeFiles) => {
|
|
21281
|
+
let entries;
|
|
21282
|
+
try {
|
|
21283
|
+
entries = await readDirectory(directory);
|
|
21284
|
+
} catch (error51) {
|
|
21285
|
+
if (isMissingPathError(error51))
|
|
21286
|
+
return;
|
|
21287
|
+
throw error51;
|
|
21288
|
+
}
|
|
21289
|
+
await Promise.all(entries.map(async (entry) => {
|
|
21290
|
+
const entryPath = path6.join(directory, entry.name);
|
|
21291
|
+
if (entry.isDirectory() && remainingDepth > 0) {
|
|
21292
|
+
await visit(entryPath, remainingDepth - 1, true);
|
|
21293
|
+
} else if (includeFiles && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
21294
|
+
try {
|
|
21295
|
+
const metadata = await statPath(entryPath);
|
|
21296
|
+
if (metadata.isFile())
|
|
21297
|
+
candidates.push({ filePath: entryPath, modifiedAt: metadata.mtime });
|
|
21298
|
+
} catch (error51) {
|
|
21299
|
+
if (!isMissingPathError(error51))
|
|
21300
|
+
throw error51;
|
|
21301
|
+
}
|
|
21302
|
+
}
|
|
21303
|
+
}));
|
|
21304
|
+
};
|
|
21305
|
+
await visit(root, options.maxDepth ?? Number.POSITIVE_INFINITY, options.includeRootFiles ?? true);
|
|
21306
|
+
return candidates;
|
|
21307
|
+
}
|
|
21308
|
+
function retainNewest(values, key, value, topK) {
|
|
21309
|
+
const existing = values.get(key);
|
|
21310
|
+
if (existing) {
|
|
21311
|
+
if (value.modifiedAt > existing.modifiedAt)
|
|
21312
|
+
values.set(key, value);
|
|
21313
|
+
return;
|
|
21314
|
+
}
|
|
21315
|
+
if (values.size < topK) {
|
|
21316
|
+
values.set(key, value);
|
|
21317
|
+
return;
|
|
21318
|
+
}
|
|
21319
|
+
let oldest;
|
|
21320
|
+
for (const entry of values) {
|
|
21321
|
+
if (!oldest || entry[1].modifiedAt < oldest[1].modifiedAt)
|
|
21322
|
+
oldest = entry;
|
|
21323
|
+
}
|
|
21324
|
+
if (oldest && value.modifiedAt > oldest[1].modifiedAt) {
|
|
21325
|
+
values.delete(oldest[0]);
|
|
21326
|
+
values.set(key, value);
|
|
21327
|
+
}
|
|
21328
|
+
}
|
|
21329
|
+
|
|
21330
|
+
class RecentContextCollector {
|
|
21331
|
+
request;
|
|
21332
|
+
sessionFileCapability;
|
|
21333
|
+
sessions = new Map;
|
|
21334
|
+
projects = new Map;
|
|
21335
|
+
constructor(request, sessionFileCapability) {
|
|
21336
|
+
this.request = request;
|
|
21337
|
+
this.sessionFileCapability = sessionFileCapability;
|
|
21338
|
+
}
|
|
21339
|
+
add(candidate, target2 = "both") {
|
|
21340
|
+
const projectPath = normalizeAbsolutePath(candidate.projectPath);
|
|
21341
|
+
const modifiedAt = normalizeModifiedAt(candidate.modifiedAt);
|
|
21342
|
+
if (!projectPath || !modifiedAt)
|
|
21343
|
+
return;
|
|
21344
|
+
if (target2 !== "session") {
|
|
21345
|
+
retainNewest(this.projects, projectPath, { projectPath, modifiedAt }, this.request.recentProjectsTopK);
|
|
21346
|
+
}
|
|
21347
|
+
if (target2 === "project" || this.sessionFileCapability !== "supported")
|
|
21348
|
+
return;
|
|
21349
|
+
const sessionFilePath = normalizeAbsolutePath(candidate.sessionFilePath);
|
|
21350
|
+
if (!sessionFilePath)
|
|
21351
|
+
return;
|
|
21352
|
+
retainNewest(this.sessions, sessionFilePath, { sessionFilePath, projectPath, modifiedAt }, this.request.recentSessionFilesTopK);
|
|
21353
|
+
}
|
|
21354
|
+
get satisfied() {
|
|
21355
|
+
const sessionsSatisfied = this.sessionFileCapability === "unavailable" || this.sessions.size >= this.request.recentSessionFilesTopK;
|
|
21356
|
+
return sessionsSatisfied && this.projects.size >= this.request.recentProjectsTopK;
|
|
21357
|
+
}
|
|
21358
|
+
result() {
|
|
21359
|
+
const newestFirst = (left, right) => right.modifiedAt.localeCompare(left.modifiedAt);
|
|
21360
|
+
return {
|
|
21361
|
+
sessionFiles: {
|
|
21362
|
+
capability: this.sessionFileCapability,
|
|
21363
|
+
items: [...this.sessions.values()].sort(newestFirst).slice(0, this.request.recentSessionFilesTopK)
|
|
21364
|
+
},
|
|
21365
|
+
recentProjects: [...this.projects.values()].sort(newestFirst).slice(0, this.request.recentProjectsTopK)
|
|
21366
|
+
};
|
|
21367
|
+
}
|
|
21368
|
+
}
|
|
21369
|
+
function sanitizeRecentContextData(value, request) {
|
|
21370
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
21371
|
+
return null;
|
|
21372
|
+
const candidate = value;
|
|
21373
|
+
if (!candidate.sessionFiles || typeof candidate.sessionFiles !== "object" || Array.isArray(candidate.sessionFiles)) {
|
|
21374
|
+
return null;
|
|
21375
|
+
}
|
|
21376
|
+
const sessionFiles = candidate.sessionFiles;
|
|
21377
|
+
const capability = sessionFiles.capability;
|
|
21378
|
+
if (capability !== "supported" && capability !== "unavailable" || !Array.isArray(sessionFiles.items)) {
|
|
21379
|
+
return null;
|
|
21380
|
+
}
|
|
21381
|
+
if (!Array.isArray(candidate.recentProjects))
|
|
21382
|
+
return null;
|
|
21383
|
+
const collector = new RecentContextCollector(request, capability);
|
|
21384
|
+
if (capability === "supported") {
|
|
21385
|
+
for (const item of sessionFiles.items) {
|
|
21386
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
21387
|
+
continue;
|
|
21388
|
+
const record2 = item;
|
|
21389
|
+
collector.add({
|
|
21390
|
+
sessionFilePath: record2.sessionFilePath,
|
|
21391
|
+
projectPath: record2.projectPath,
|
|
21392
|
+
modifiedAt: record2.modifiedAt
|
|
21393
|
+
}, "session");
|
|
21394
|
+
}
|
|
21395
|
+
}
|
|
21396
|
+
for (const item of candidate.recentProjects) {
|
|
21397
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
21398
|
+
continue;
|
|
21399
|
+
const record2 = item;
|
|
21400
|
+
collector.add({ projectPath: record2.projectPath, modifiedAt: record2.modifiedAt }, "project");
|
|
21401
|
+
}
|
|
21402
|
+
return collector.result();
|
|
21403
|
+
}
|
|
21404
|
+
|
|
21405
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
21406
|
+
async function readClaudeProjectPath(filePath) {
|
|
21407
|
+
const input = createReadStream2(filePath);
|
|
21408
|
+
const lines = createInterface({ input, crlfDelay: Infinity });
|
|
21409
|
+
try {
|
|
21410
|
+
for await (const line of lines) {
|
|
21411
|
+
let record2;
|
|
21412
|
+
try {
|
|
21413
|
+
record2 = JSON.parse(line);
|
|
21414
|
+
} catch {
|
|
21415
|
+
continue;
|
|
21416
|
+
}
|
|
21417
|
+
if (!record2 || typeof record2 !== "object")
|
|
21418
|
+
continue;
|
|
21419
|
+
const cwd = record2.cwd;
|
|
21420
|
+
if (typeof cwd === "string" && path7.isAbsolute(cwd))
|
|
21421
|
+
return cwd;
|
|
21422
|
+
}
|
|
21423
|
+
return null;
|
|
21424
|
+
} catch (error51) {
|
|
21425
|
+
if (isMissingPathError(error51))
|
|
21426
|
+
return null;
|
|
21427
|
+
throw error51;
|
|
21428
|
+
} finally {
|
|
21429
|
+
lines.close();
|
|
21430
|
+
input.destroy();
|
|
21431
|
+
}
|
|
21432
|
+
}
|
|
21433
|
+
async function discoverClaudeRecentContext(request, dependencies = {}) {
|
|
21434
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
21435
|
+
if (collector.satisfied)
|
|
21436
|
+
return collector.result();
|
|
21437
|
+
const projectsRoot = path7.resolve(dependencies.projectsRoot ?? path7.join(process.env.CLAUDE_CONFIG_DIR || path7.join(homedir(), ".claude"), "projects"));
|
|
21438
|
+
const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
|
|
21439
|
+
const candidates = await collectJsonlFileCandidates(projectsRoot, {
|
|
21440
|
+
includeRootFiles: false,
|
|
21441
|
+
maxDepth: 1,
|
|
21442
|
+
readDirectory: dependencies.readDirectory,
|
|
21443
|
+
statPath: dependencies.statPath
|
|
21444
|
+
});
|
|
21445
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
21446
|
+
for (const candidate of candidates) {
|
|
21447
|
+
const projectPath = await readProjectPath(candidate.filePath);
|
|
21448
|
+
if (!projectPath)
|
|
21449
|
+
continue;
|
|
21450
|
+
collector.add({
|
|
21451
|
+
sessionFilePath: candidate.filePath,
|
|
21452
|
+
projectPath,
|
|
21453
|
+
modifiedAt: candidate.modifiedAt
|
|
21454
|
+
});
|
|
21455
|
+
if (collector.satisfied)
|
|
21456
|
+
break;
|
|
21457
|
+
}
|
|
21458
|
+
return collector.result();
|
|
21459
|
+
}
|
|
21460
|
+
|
|
21208
21461
|
// agent-driver/dist/adapters/claude/index.js
|
|
21209
21462
|
var CLAUDE_MODEL_CATALOG = {
|
|
21210
21463
|
updateMode: "unsupported",
|
|
@@ -21226,6 +21479,9 @@ class ClaudeDriver {
|
|
|
21226
21479
|
turnProtocol = new ClaudeTurnProtocol;
|
|
21227
21480
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
21228
21481
|
pendingInterrupt;
|
|
21482
|
+
discoverRecentContext(request) {
|
|
21483
|
+
return discoverClaudeRecentContext(request);
|
|
21484
|
+
}
|
|
21229
21485
|
beginTurn() {
|
|
21230
21486
|
this.pendingInterrupt = undefined;
|
|
21231
21487
|
const receipt = this.turnProtocol.beginTurn();
|
|
@@ -21489,16 +21745,16 @@ function normalizeFileChangeInput(item) {
|
|
|
21489
21745
|
for (const candidate of changePaths) {
|
|
21490
21746
|
if (typeof candidate !== "string")
|
|
21491
21747
|
continue;
|
|
21492
|
-
const
|
|
21493
|
-
if (!
|
|
21748
|
+
const path8 = candidate.trim();
|
|
21749
|
+
if (!path8 || seen.has(path8))
|
|
21494
21750
|
continue;
|
|
21495
|
-
seen.add(
|
|
21496
|
-
paths.push(
|
|
21751
|
+
seen.add(path8);
|
|
21752
|
+
paths.push(path8);
|
|
21497
21753
|
}
|
|
21498
21754
|
if (paths.length === 0 && typeof item?.path === "string") {
|
|
21499
|
-
const
|
|
21500
|
-
if (
|
|
21501
|
-
paths.push(
|
|
21755
|
+
const path8 = item.path.trim();
|
|
21756
|
+
if (path8)
|
|
21757
|
+
paths.push(path8);
|
|
21502
21758
|
}
|
|
21503
21759
|
return paths.length > 0 ? { path: paths.join(", ") } : {};
|
|
21504
21760
|
}
|
|
@@ -21867,7 +22123,7 @@ class CodexEventNormalizer {
|
|
|
21867
22123
|
|
|
21868
22124
|
// agent-driver/dist/adapters/codex/home.js
|
|
21869
22125
|
import * as os from "os";
|
|
21870
|
-
import * as
|
|
22126
|
+
import * as path8 from "path";
|
|
21871
22127
|
function readConfiguredCodexHome(env) {
|
|
21872
22128
|
const raw = env.CODEX_HOME;
|
|
21873
22129
|
return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
@@ -21875,8 +22131,8 @@ function readConfiguredCodexHome(env) {
|
|
|
21875
22131
|
function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
21876
22132
|
const raw = readConfiguredCodexHome(env);
|
|
21877
22133
|
if (raw)
|
|
21878
|
-
return
|
|
21879
|
-
return
|
|
22134
|
+
return path8.resolve(opts.cwd ?? process.cwd(), raw);
|
|
22135
|
+
return path8.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
|
|
21880
22136
|
}
|
|
21881
22137
|
|
|
21882
22138
|
// agent-driver/dist/internal/errors.js
|
|
@@ -21969,6 +22225,49 @@ function parsePiModelCatalog(values) {
|
|
|
21969
22225
|
return catalogFromIds(ids);
|
|
21970
22226
|
}
|
|
21971
22227
|
|
|
22228
|
+
// agent-driver/dist/adapters/codex/recent-context.js
|
|
22229
|
+
import path9 from "node:path";
|
|
22230
|
+
function isChildSession(payload) {
|
|
22231
|
+
if (payload.parentThreadId != null || payload.parent_thread_id != null)
|
|
22232
|
+
return true;
|
|
22233
|
+
const source = payload.source;
|
|
22234
|
+
if (typeof source === "string")
|
|
22235
|
+
return source.toLowerCase().startsWith("subagent");
|
|
22236
|
+
const sourceRecord = asRecord(source);
|
|
22237
|
+
return sourceRecord != null && (("subagent" in sourceRecord) || ("subAgent" in sourceRecord));
|
|
22238
|
+
}
|
|
22239
|
+
async function discoverCodexRecentContext(request, dependencies = {}) {
|
|
22240
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
22241
|
+
if (collector.satisfied)
|
|
22242
|
+
return collector.result();
|
|
22243
|
+
const sessionsRoot = path9.resolve(dependencies.sessionsRoot ?? path9.join(resolveCodexHomeRootFromEnv(), "sessions"));
|
|
22244
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
22245
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
22246
|
+
readDirectory: dependencies.readDirectory,
|
|
22247
|
+
statPath: dependencies.statPath
|
|
22248
|
+
});
|
|
22249
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
22250
|
+
for (const candidate of candidates) {
|
|
22251
|
+
const line = await readHeader(candidate.filePath);
|
|
22252
|
+
if (!line)
|
|
22253
|
+
continue;
|
|
22254
|
+
const header = tryParseJsonRecord(line);
|
|
22255
|
+
if (!header)
|
|
22256
|
+
continue;
|
|
22257
|
+
const payload = asRecord(header.payload);
|
|
22258
|
+
if (header.type !== "session_meta" || !payload || isChildSession(payload))
|
|
22259
|
+
continue;
|
|
22260
|
+
collector.add({
|
|
22261
|
+
sessionFilePath: candidate.filePath,
|
|
22262
|
+
projectPath: payload.cwd,
|
|
22263
|
+
modifiedAt: candidate.modifiedAt
|
|
22264
|
+
});
|
|
22265
|
+
if (collector.satisfied)
|
|
22266
|
+
break;
|
|
22267
|
+
}
|
|
22268
|
+
return collector.result();
|
|
22269
|
+
}
|
|
22270
|
+
|
|
21972
22271
|
// agent-driver/dist/adapters/codex/index.js
|
|
21973
22272
|
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
21974
22273
|
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
@@ -21997,6 +22296,9 @@ class CodexDriver {
|
|
|
21997
22296
|
eventNormalizer = new CodexEventNormalizer;
|
|
21998
22297
|
pendingAccountReadRequestIds = new Set;
|
|
21999
22298
|
requestId = 0;
|
|
22299
|
+
discoverRecentContext(request) {
|
|
22300
|
+
return discoverCodexRecentContext(request);
|
|
22301
|
+
}
|
|
22000
22302
|
codexHomeRoot = null;
|
|
22001
22303
|
proc = null;
|
|
22002
22304
|
pendingInitialPrompt = null;
|
|
@@ -23173,6 +23475,196 @@ class CursorAcpLane {
|
|
|
23173
23475
|
}
|
|
23174
23476
|
}
|
|
23175
23477
|
|
|
23478
|
+
// agent-driver/dist/internal/discovery-process.js
|
|
23479
|
+
import { StringDecoder } from "node:string_decoder";
|
|
23480
|
+
function toBuffer(chunk2) {
|
|
23481
|
+
if (Buffer.isBuffer(chunk2))
|
|
23482
|
+
return chunk2;
|
|
23483
|
+
if (chunk2 instanceof Uint8Array)
|
|
23484
|
+
return Buffer.from(chunk2.buffer, chunk2.byteOffset, chunk2.byteLength);
|
|
23485
|
+
return Buffer.from(String(chunk2));
|
|
23486
|
+
}
|
|
23487
|
+
async function cleanupProcess(process3, label) {
|
|
23488
|
+
if (process3.pid)
|
|
23489
|
+
await killProcessTree(process3.pid, { graceMs: 250 });
|
|
23490
|
+
else if (process3.exitCode === null && process3.signalCode === null && !process3.kill("SIGTERM")) {
|
|
23491
|
+
throw new Error(`${label} discovery cleanup failed`);
|
|
23492
|
+
}
|
|
23493
|
+
}
|
|
23494
|
+
function onStream(stream, event, listener) {
|
|
23495
|
+
stream?.on?.(event, listener);
|
|
23496
|
+
}
|
|
23497
|
+
function runBoundedDiscoveryProcess(options) {
|
|
23498
|
+
return new Promise((resolve2, reject) => {
|
|
23499
|
+
const decoder = new StringDecoder("utf8");
|
|
23500
|
+
let settled = false;
|
|
23501
|
+
let decoderEnded = false;
|
|
23502
|
+
let outputBytes = 0;
|
|
23503
|
+
const settle = (result, error51) => {
|
|
23504
|
+
if (settled)
|
|
23505
|
+
return;
|
|
23506
|
+
settled = true;
|
|
23507
|
+
clearTimeout(timer);
|
|
23508
|
+
if (!decoderEnded)
|
|
23509
|
+
decoder.end();
|
|
23510
|
+
Promise.resolve().then(() => options.cleanup?.(options.process) ?? cleanupProcess(options.process, options.label)).then(() => error51 ? reject(error51) : resolve2(result), () => reject(error51 ?? new Error(`${options.label} discovery cleanup failed`)));
|
|
23511
|
+
};
|
|
23512
|
+
const control = {
|
|
23513
|
+
get outputBytes() {
|
|
23514
|
+
return outputBytes;
|
|
23515
|
+
},
|
|
23516
|
+
finish: (result) => settle(result),
|
|
23517
|
+
fail: (message2) => settle(undefined, new Error(message2)),
|
|
23518
|
+
flushStdout: () => {
|
|
23519
|
+
if (settled || decoderEnded)
|
|
23520
|
+
return;
|
|
23521
|
+
decoderEnded = true;
|
|
23522
|
+
options.onStdout(decoder.end(), true, control);
|
|
23523
|
+
},
|
|
23524
|
+
write: (line) => {
|
|
23525
|
+
const stdin = options.process.stdin;
|
|
23526
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
|
|
23527
|
+
return control.fail(`${options.label} discovery transport is unavailable`);
|
|
23528
|
+
}
|
|
23529
|
+
try {
|
|
23530
|
+
stdin.write(line);
|
|
23531
|
+
} catch {
|
|
23532
|
+
control.fail(`${options.label} discovery transport write failed`);
|
|
23533
|
+
}
|
|
23534
|
+
}
|
|
23535
|
+
};
|
|
23536
|
+
const addBytes = (chunk2, decode3) => {
|
|
23537
|
+
if (settled)
|
|
23538
|
+
return;
|
|
23539
|
+
const bytes = toBuffer(chunk2);
|
|
23540
|
+
outputBytes += bytes.byteLength;
|
|
23541
|
+
if (outputBytes > options.outputMaxBytes) {
|
|
23542
|
+
control.fail(`${options.label} discovery output exceeded its bound`);
|
|
23543
|
+
} else if (decode3)
|
|
23544
|
+
options.onStdout(decoder.write(bytes), false, control);
|
|
23545
|
+
};
|
|
23546
|
+
const timer = setTimeout(() => control.fail(`${options.label} discovery timed out`), Math.max(1, options.timeoutMs));
|
|
23547
|
+
timer.unref?.();
|
|
23548
|
+
options.process.stdout?.on("data", (chunk2) => addBytes(chunk2, true));
|
|
23549
|
+
options.process.stderr?.on("data", (chunk2) => addBytes(chunk2, false));
|
|
23550
|
+
onStream(options.process.stdout, "end", control.flushStdout);
|
|
23551
|
+
for (const stream of [options.process.stdin, options.process.stdout, options.process.stderr]) {
|
|
23552
|
+
onStream(stream, "error", () => control.fail(`${options.label} discovery transport failed`));
|
|
23553
|
+
}
|
|
23554
|
+
options.process.on("error", () => control.fail(`${options.label} discovery process failed`));
|
|
23555
|
+
options.process.on(options.exitEvent, (code, signal) => options.onExit(code, signal, control));
|
|
23556
|
+
options.onStart?.(control);
|
|
23557
|
+
});
|
|
23558
|
+
}
|
|
23559
|
+
|
|
23560
|
+
// agent-driver/dist/adapters/cursor/recent-context.js
|
|
23561
|
+
var ACP_PROTOCOL_VERSION3 = 1;
|
|
23562
|
+
var AUTH_METHOD_ID3 = "cursor_login";
|
|
23563
|
+
var CURSOR_DISCOVERY_TIMEOUT_MS = 30000;
|
|
23564
|
+
var CURSOR_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
23565
|
+
async function discoverCursorRecentContext(request, dependencies = {}) {
|
|
23566
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
23567
|
+
if (collector.satisfied)
|
|
23568
|
+
return collector.result();
|
|
23569
|
+
const spec = resolveSpawnSpec("cursor-agent", ["acp"], request.command);
|
|
23570
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
|
|
23571
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
23572
|
+
env: { ...process.env, CI: "1" },
|
|
23573
|
+
shell: spec.shell
|
|
23574
|
+
});
|
|
23575
|
+
let buffer = "";
|
|
23576
|
+
let requestId = 0;
|
|
23577
|
+
let expectedId = 0;
|
|
23578
|
+
let expectedMethod = "";
|
|
23579
|
+
const seenCursors = new Set;
|
|
23580
|
+
const requestRpc = (method, params, control) => {
|
|
23581
|
+
expectedId = ++requestId;
|
|
23582
|
+
expectedMethod = method;
|
|
23583
|
+
control.write(`${jsonRpcRequest(method, params, expectedId)}
|
|
23584
|
+
`);
|
|
23585
|
+
};
|
|
23586
|
+
const requestPage = (control, cursor) => requestRpc("session/list", cursor ? { cursor } : {}, control);
|
|
23587
|
+
const onLine = (line, control) => {
|
|
23588
|
+
const message2 = asRecord(tryParseJsonLine(line));
|
|
23589
|
+
if (!message2 || message2.id !== expectedId)
|
|
23590
|
+
return;
|
|
23591
|
+
if (message2.error !== undefined)
|
|
23592
|
+
return control.fail("Cursor discovery request failed");
|
|
23593
|
+
const result = asRecord(message2.result);
|
|
23594
|
+
if (!result)
|
|
23595
|
+
return control.fail("Cursor discovery returned an invalid response");
|
|
23596
|
+
if (expectedMethod === "initialize") {
|
|
23597
|
+
if (result.protocolVersion !== ACP_PROTOCOL_VERSION3) {
|
|
23598
|
+
return control.fail("Cursor discovery protocol is incompatible");
|
|
23599
|
+
}
|
|
23600
|
+
const capabilities = asRecord(result.agentCapabilities);
|
|
23601
|
+
const sessionCapabilities = asRecord(capabilities?.sessionCapabilities);
|
|
23602
|
+
if (sessionCapabilities?.list !== true && !asRecord(sessionCapabilities?.list)) {
|
|
23603
|
+
return control.fail("Cursor session listing is unavailable");
|
|
23604
|
+
}
|
|
23605
|
+
const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
|
|
23606
|
+
if (!authMethods.some((method) => asRecord(method)?.id === AUTH_METHOD_ID3)) {
|
|
23607
|
+
return control.fail("Cursor discovery authentication is unavailable");
|
|
23608
|
+
}
|
|
23609
|
+
requestRpc("authenticate", { methodId: AUTH_METHOD_ID3 }, control);
|
|
23610
|
+
return;
|
|
23611
|
+
}
|
|
23612
|
+
if (expectedMethod === "authenticate") {
|
|
23613
|
+
requestPage(control);
|
|
23614
|
+
return;
|
|
23615
|
+
}
|
|
23616
|
+
if (expectedMethod !== "session/list")
|
|
23617
|
+
return control.fail("Cursor discovery state is invalid");
|
|
23618
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : Array.isArray(result.data) ? result.data : [];
|
|
23619
|
+
for (const value of sessions) {
|
|
23620
|
+
const session2 = asRecord(value);
|
|
23621
|
+
if (!session2)
|
|
23622
|
+
continue;
|
|
23623
|
+
collector.add({ projectPath: session2.cwd, modifiedAt: session2.updatedAt });
|
|
23624
|
+
if (collector.satisfied)
|
|
23625
|
+
return control.finish(collector.result());
|
|
23626
|
+
}
|
|
23627
|
+
const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : undefined;
|
|
23628
|
+
if (!nextCursor)
|
|
23629
|
+
return control.finish(collector.result());
|
|
23630
|
+
if (seenCursors.has(nextCursor))
|
|
23631
|
+
return control.fail("Cursor discovery cursor repeated");
|
|
23632
|
+
seenCursors.add(nextCursor);
|
|
23633
|
+
requestPage(control, nextCursor);
|
|
23634
|
+
};
|
|
23635
|
+
return runBoundedDiscoveryProcess({
|
|
23636
|
+
process: processHandle,
|
|
23637
|
+
label: "Cursor",
|
|
23638
|
+
timeoutMs: dependencies.timeoutMs ?? CURSOR_DISCOVERY_TIMEOUT_MS,
|
|
23639
|
+
outputMaxBytes: dependencies.outputMaxBytes ?? CURSOR_DISCOVERY_OUTPUT_MAX_BYTES,
|
|
23640
|
+
cleanup: dependencies.cleanup,
|
|
23641
|
+
exitEvent: "exit",
|
|
23642
|
+
onStdout: (text2, final, control) => {
|
|
23643
|
+
buffer += text2;
|
|
23644
|
+
const lines = buffer.split(`
|
|
23645
|
+
`);
|
|
23646
|
+
buffer = lines.pop() ?? "";
|
|
23647
|
+
for (const line of lines)
|
|
23648
|
+
if (line.trim())
|
|
23649
|
+
onLine(line, control);
|
|
23650
|
+
if (final && buffer.trim()) {
|
|
23651
|
+
const line = buffer;
|
|
23652
|
+
buffer = "";
|
|
23653
|
+
onLine(line, control);
|
|
23654
|
+
}
|
|
23655
|
+
},
|
|
23656
|
+
onExit: (_code, _signal, control) => control.fail("Cursor discovery process exited early"),
|
|
23657
|
+
onStart: (control) => requestRpc("initialize", {
|
|
23658
|
+
protocolVersion: ACP_PROTOCOL_VERSION3,
|
|
23659
|
+
clientCapabilities: {
|
|
23660
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
23661
|
+
terminal: false
|
|
23662
|
+
},
|
|
23663
|
+
clientInfo: { name: "alook-agent-driver-discovery", version: "0.1.31" }
|
|
23664
|
+
}, control)
|
|
23665
|
+
});
|
|
23666
|
+
}
|
|
23667
|
+
|
|
23176
23668
|
// agent-driver/dist/adapters/cursor/index.js
|
|
23177
23669
|
class CursorDriver {
|
|
23178
23670
|
catalogProbe;
|
|
@@ -23184,6 +23676,9 @@ class CursorDriver {
|
|
|
23184
23676
|
wakeStart: "immediate",
|
|
23185
23677
|
terminalOwnership: "transport_request"
|
|
23186
23678
|
};
|
|
23679
|
+
discoverRecentContext(request) {
|
|
23680
|
+
return discoverCursorRecentContext(request);
|
|
23681
|
+
}
|
|
23187
23682
|
constructor(catalogProbe = probeCursorAcpCatalog) {
|
|
23188
23683
|
this.catalogProbe = catalogProbe;
|
|
23189
23684
|
}
|
|
@@ -23678,7 +24173,7 @@ class OpenCodeServiceLane {
|
|
|
23678
24173
|
"/api/session/{sessionID}/permission/{requestID}/reply",
|
|
23679
24174
|
"/api/event"
|
|
23680
24175
|
];
|
|
23681
|
-
if (!paths || required2.some((
|
|
24176
|
+
if (!paths || required2.some((path10) => !record4(paths[path10]))) {
|
|
23682
24177
|
throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
|
|
23683
24178
|
}
|
|
23684
24179
|
}
|
|
@@ -23736,8 +24231,8 @@ class OpenCodeServiceLane {
|
|
|
23736
24231
|
const controller = new AbortController;
|
|
23737
24232
|
this.durableAbort = controller;
|
|
23738
24233
|
try {
|
|
23739
|
-
const
|
|
23740
|
-
const response = await this.openStream(
|
|
24234
|
+
const path10 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
|
|
24235
|
+
const response = await this.openStream(path10, controller, "durable event stream");
|
|
23741
24236
|
await this.catchUpHistory(true);
|
|
23742
24237
|
if (!this.isIdentity(identity))
|
|
23743
24238
|
return;
|
|
@@ -23811,12 +24306,12 @@ class OpenCodeServiceLane {
|
|
|
23811
24306
|
return;
|
|
23812
24307
|
this.protocolFailure(`OpenCode ${kind} stream stopped unexpectedly`, error51);
|
|
23813
24308
|
}
|
|
23814
|
-
async openStream(
|
|
24309
|
+
async openStream(path10, lifecycle, operation) {
|
|
23815
24310
|
const deadline = new AbortController;
|
|
23816
24311
|
const timeout = setTimeout(() => deadline.abort(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS);
|
|
23817
24312
|
timeout.unref?.();
|
|
23818
24313
|
try {
|
|
23819
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
24314
|
+
const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
23820
24315
|
method: "GET",
|
|
23821
24316
|
headers: this.headers({ accept: "text/event-stream" }),
|
|
23822
24317
|
signal: AbortSignal.any([lifecycle.signal, deadline.signal])
|
|
@@ -24243,8 +24738,8 @@ class OpenCodeServiceLane {
|
|
|
24243
24738
|
turnOwner: root.receipt
|
|
24244
24739
|
});
|
|
24245
24740
|
}
|
|
24246
|
-
async requestNoContent(
|
|
24247
|
-
const response = await this.fetchWithTimeout(
|
|
24741
|
+
async requestNoContent(path10, method, body, operation) {
|
|
24742
|
+
const response = await this.fetchWithTimeout(path10, {
|
|
24248
24743
|
method,
|
|
24249
24744
|
...body ? {
|
|
24250
24745
|
headers: { "content-type": "application/json" },
|
|
@@ -24254,7 +24749,7 @@ class OpenCodeServiceLane {
|
|
|
24254
24749
|
if (!response.ok)
|
|
24255
24750
|
throw new OpenCodeHttpError(response.status, operation);
|
|
24256
24751
|
}
|
|
24257
|
-
async fetchWithTimeout(
|
|
24752
|
+
async fetchWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
24258
24753
|
if (this.stopping)
|
|
24259
24754
|
throw new Error("OpenCode service lane is stopping");
|
|
24260
24755
|
const controller = new AbortController;
|
|
@@ -24262,7 +24757,7 @@ class OpenCodeServiceLane {
|
|
|
24262
24757
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
24263
24758
|
timer.unref?.();
|
|
24264
24759
|
try {
|
|
24265
|
-
return await this.fetchFn(`${this.baseUrl}${
|
|
24760
|
+
return await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
24266
24761
|
...init,
|
|
24267
24762
|
headers: this.headers(init.headers),
|
|
24268
24763
|
signal: controller.signal
|
|
@@ -24274,7 +24769,7 @@ class OpenCodeServiceLane {
|
|
|
24274
24769
|
this.requestControllers.delete(controller);
|
|
24275
24770
|
}
|
|
24276
24771
|
}
|
|
24277
|
-
async fetchJsonWithTimeout(
|
|
24772
|
+
async fetchJsonWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
24278
24773
|
if (this.stopping)
|
|
24279
24774
|
throw new OpenCodeStoppedError("OpenCode service lane is stopping");
|
|
24280
24775
|
const controller = new AbortController;
|
|
@@ -24286,7 +24781,7 @@ class OpenCodeServiceLane {
|
|
|
24286
24781
|
}, timeoutMs);
|
|
24287
24782
|
timer.unref?.();
|
|
24288
24783
|
try {
|
|
24289
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
24784
|
+
const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
24290
24785
|
...init,
|
|
24291
24786
|
headers: this.headers(init.headers),
|
|
24292
24787
|
signal: controller.signal
|
|
@@ -24379,6 +24874,75 @@ class OpenCodeServiceLane {
|
|
|
24379
24874
|
}
|
|
24380
24875
|
}
|
|
24381
24876
|
|
|
24877
|
+
// agent-driver/dist/adapters/opencode/recent-context.js
|
|
24878
|
+
var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
|
|
24879
|
+
var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
24880
|
+
function collectCommandOutput(command, args, shell, dependencies, timeoutMs, outputMaxBytes) {
|
|
24881
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(command, args, {
|
|
24882
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
24883
|
+
env: { ...process.env, CI: "1" },
|
|
24884
|
+
shell,
|
|
24885
|
+
stdin: "ignore"
|
|
24886
|
+
});
|
|
24887
|
+
let output = "";
|
|
24888
|
+
return runBoundedDiscoveryProcess({
|
|
24889
|
+
process: processHandle,
|
|
24890
|
+
label: "OpenCode",
|
|
24891
|
+
timeoutMs,
|
|
24892
|
+
outputMaxBytes,
|
|
24893
|
+
cleanup: dependencies.cleanup,
|
|
24894
|
+
exitEvent: "close",
|
|
24895
|
+
onStdout: (text2) => {
|
|
24896
|
+
output += text2;
|
|
24897
|
+
},
|
|
24898
|
+
onExit: (code, _signal, control) => {
|
|
24899
|
+
if (code !== 0)
|
|
24900
|
+
return control.fail("OpenCode session listing failed");
|
|
24901
|
+
control.flushStdout();
|
|
24902
|
+
control.finish({ output, outputBytes: control.outputBytes });
|
|
24903
|
+
}
|
|
24904
|
+
});
|
|
24905
|
+
}
|
|
24906
|
+
async function discoverOpenCodeRecentContext(request, dependencies = {}) {
|
|
24907
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
24908
|
+
if (collector.satisfied)
|
|
24909
|
+
return collector.result();
|
|
24910
|
+
const startedAt = Date.now();
|
|
24911
|
+
const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
|
|
24912
|
+
let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
|
|
24913
|
+
let maxCount = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, request.recentProjectsTopK * 10));
|
|
24914
|
+
while (!collector.satisfied) {
|
|
24915
|
+
const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
|
|
24916
|
+
if (remainingTimeoutMs <= 0)
|
|
24917
|
+
throw new Error("OpenCode discovery timed out");
|
|
24918
|
+
const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
|
|
24919
|
+
const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
|
|
24920
|
+
remainingOutputBytes -= commandOutput.outputBytes;
|
|
24921
|
+
let parsed;
|
|
24922
|
+
try {
|
|
24923
|
+
parsed = JSON.parse(commandOutput.output);
|
|
24924
|
+
} catch {
|
|
24925
|
+
throw new Error("OpenCode session listing returned invalid JSON");
|
|
24926
|
+
}
|
|
24927
|
+
if (!Array.isArray(parsed))
|
|
24928
|
+
throw new Error("OpenCode session listing returned an invalid response");
|
|
24929
|
+
for (const value of parsed) {
|
|
24930
|
+
const session2 = asRecord(value);
|
|
24931
|
+
if (!session2)
|
|
24932
|
+
continue;
|
|
24933
|
+
const modifiedAt = session2.updated ?? session2.updatedAt;
|
|
24934
|
+
collector.add({ projectPath: session2.directory, modifiedAt });
|
|
24935
|
+
}
|
|
24936
|
+
if (collector.satisfied || parsed.length < maxCount)
|
|
24937
|
+
break;
|
|
24938
|
+
const nextMaxCount = Math.min(Number.MAX_SAFE_INTEGER, maxCount * 2);
|
|
24939
|
+
if (nextMaxCount === maxCount)
|
|
24940
|
+
throw new Error("OpenCode session listing could not prove the requested Top-K");
|
|
24941
|
+
maxCount = nextMaxCount;
|
|
24942
|
+
}
|
|
24943
|
+
return collector.result();
|
|
24944
|
+
}
|
|
24945
|
+
|
|
24382
24946
|
// agent-driver/dist/adapters/opencode/index.js
|
|
24383
24947
|
function createOpenCodeMessageId() {
|
|
24384
24948
|
return `msg_${randomBytes3(16).toString("hex")}`;
|
|
@@ -24397,6 +24961,9 @@ class OpenCodeDriver {
|
|
|
24397
24961
|
constructor(outputProbe = probeCommandOutput) {
|
|
24398
24962
|
this.outputProbe = outputProbe;
|
|
24399
24963
|
}
|
|
24964
|
+
discoverRecentContext(request) {
|
|
24965
|
+
return discoverOpenCodeRecentContext(request);
|
|
24966
|
+
}
|
|
24400
24967
|
probe(command) {
|
|
24401
24968
|
const result = probeCliRuntime("opencode", {}, command);
|
|
24402
24969
|
if (result.status !== "healthy")
|
|
@@ -24443,8 +25010,8 @@ class OpenCodeDriver {
|
|
|
24443
25010
|
// agent-driver/dist/adapters/pi/index.js
|
|
24444
25011
|
import { createRequire as createRequire2 } from "module";
|
|
24445
25012
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync } from "fs";
|
|
24446
|
-
import { homedir as
|
|
24447
|
-
import * as
|
|
25013
|
+
import { homedir as homedir4 } from "os";
|
|
25014
|
+
import * as path12 from "path";
|
|
24448
25015
|
|
|
24449
25016
|
// agent-driver/dist/controller/sdk-host.js
|
|
24450
25017
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
@@ -24559,7 +25126,7 @@ class SdkLane {
|
|
|
24559
25126
|
|
|
24560
25127
|
// agent-driver/dist/adapters/pi/sessionDeps.js
|
|
24561
25128
|
import { readFileSync as readFileSync2 } from "fs";
|
|
24562
|
-
import * as
|
|
25129
|
+
import * as path10 from "path";
|
|
24563
25130
|
import { pathToFileURL } from "url";
|
|
24564
25131
|
var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
24565
25132
|
var cachedSdkPromise = null;
|
|
@@ -24568,9 +25135,9 @@ async function importPiSdkFromGlobalInstall() {
|
|
|
24568
25135
|
if (!dir) {
|
|
24569
25136
|
throw new Error(`${PI_SDK_PACKAGE_NAME} not found — install it (e.g. \`npm install -g ${PI_SDK_PACKAGE_NAME}\`) before launching a pi agent`);
|
|
24570
25137
|
}
|
|
24571
|
-
const pkg = JSON.parse(readFileSync2(
|
|
25138
|
+
const pkg = JSON.parse(readFileSync2(path10.join(dir, "package.json"), "utf-8"));
|
|
24572
25139
|
const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
|
|
24573
|
-
const entryPath =
|
|
25140
|
+
const entryPath = path10.join(dir, entry);
|
|
24574
25141
|
const barrel = await import(pathToFileURL(entryPath).href);
|
|
24575
25142
|
return withSessionDirHelper(barrel, entryPath);
|
|
24576
25143
|
}
|
|
@@ -24578,7 +25145,7 @@ async function withSessionDirHelper(barrel, entryPath) {
|
|
|
24578
25145
|
if (typeof barrel.getDefaultSessionDir === "function")
|
|
24579
25146
|
return barrel;
|
|
24580
25147
|
try {
|
|
24581
|
-
const deepPath =
|
|
25148
|
+
const deepPath = path10.join(path10.dirname(entryPath), "core", "session-manager.js");
|
|
24582
25149
|
const deep = await import(pathToFileURL(deepPath).href);
|
|
24583
25150
|
if (typeof deep.getDefaultSessionDir !== "function")
|
|
24584
25151
|
return barrel;
|
|
@@ -24658,6 +25225,51 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
|
|
|
24658
25225
|
};
|
|
24659
25226
|
}
|
|
24660
25227
|
|
|
25228
|
+
// agent-driver/dist/adapters/pi/recent-context.js
|
|
25229
|
+
import { homedir as homedir3 } from "node:os";
|
|
25230
|
+
import path11 from "node:path";
|
|
25231
|
+
function expandTildePath(value) {
|
|
25232
|
+
if (value === "~")
|
|
25233
|
+
return homedir3();
|
|
25234
|
+
if (value.startsWith("~/"))
|
|
25235
|
+
return path11.join(homedir3(), value.slice(2));
|
|
25236
|
+
return value;
|
|
25237
|
+
}
|
|
25238
|
+
async function discoverPiRecentContext(request, dependencies = {}) {
|
|
25239
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
25240
|
+
if (collector.satisfied)
|
|
25241
|
+
return collector.result();
|
|
25242
|
+
const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
|
|
25243
|
+
const sessionsRoot = path11.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path11.join(process.env.PI_CODING_AGENT_DIR || path11.join(homedir3(), ".pi", "agent"), "sessions")));
|
|
25244
|
+
const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
|
|
25245
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
25246
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
25247
|
+
includeRootFiles: scanDirectSessions,
|
|
25248
|
+
maxDepth: 1,
|
|
25249
|
+
readDirectory: dependencies.readDirectory,
|
|
25250
|
+
statPath: dependencies.statPath
|
|
25251
|
+
});
|
|
25252
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
25253
|
+
for (const candidate of candidates) {
|
|
25254
|
+
const line = await readHeader(candidate.filePath);
|
|
25255
|
+
if (!line)
|
|
25256
|
+
continue;
|
|
25257
|
+
const header = tryParseJsonRecord(line);
|
|
25258
|
+
if (!header)
|
|
25259
|
+
continue;
|
|
25260
|
+
if (header.type !== "session" || header.parentSession != null)
|
|
25261
|
+
continue;
|
|
25262
|
+
collector.add({
|
|
25263
|
+
sessionFilePath: candidate.filePath,
|
|
25264
|
+
projectPath: header.cwd,
|
|
25265
|
+
modifiedAt: candidate.modifiedAt
|
|
25266
|
+
});
|
|
25267
|
+
if (collector.satisfied)
|
|
25268
|
+
break;
|
|
25269
|
+
}
|
|
25270
|
+
return collector.result();
|
|
25271
|
+
}
|
|
25272
|
+
|
|
24661
25273
|
// agent-driver/dist/adapters/pi/index.js
|
|
24662
25274
|
var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
|
|
24663
25275
|
var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
|
|
@@ -24676,15 +25288,15 @@ function resolvePiSdkPackageDir(deps = {}) {
|
|
|
24676
25288
|
if (!binPath)
|
|
24677
25289
|
return;
|
|
24678
25290
|
try {
|
|
24679
|
-
let dir =
|
|
25291
|
+
let dir = path12.dirname(realpathSync(binPath));
|
|
24680
25292
|
const MAX_DEPTH = 8;
|
|
24681
25293
|
for (let i = 0;i < MAX_DEPTH; i++) {
|
|
24682
|
-
if (isPiSdkPackageJson(
|
|
25294
|
+
if (isPiSdkPackageJson(path12.join(dir, "package.json")))
|
|
24683
25295
|
return dir;
|
|
24684
|
-
const siblingDir =
|
|
24685
|
-
if (isPiSdkPackageJson(
|
|
25296
|
+
const siblingDir = path12.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
|
|
25297
|
+
if (isPiSdkPackageJson(path12.join(siblingDir, "package.json")))
|
|
24686
25298
|
return siblingDir;
|
|
24687
|
-
const parent =
|
|
25299
|
+
const parent = path12.dirname(dir);
|
|
24688
25300
|
if (parent === dir)
|
|
24689
25301
|
break;
|
|
24690
25302
|
dir = parent;
|
|
@@ -24701,21 +25313,21 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
24701
25313
|
}
|
|
24702
25314
|
const suffix = `_${sessionId}.jsonl`;
|
|
24703
25315
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
24704
|
-
return match ?
|
|
25316
|
+
return match ? path12.join(sessionDir, match) : null;
|
|
24705
25317
|
}
|
|
24706
25318
|
function resolvePiSessionDir(sdk, cwd) {
|
|
24707
25319
|
if (typeof sdk.getDefaultSessionDir === "function")
|
|
24708
25320
|
return sdk.getDefaultSessionDir(cwd);
|
|
24709
|
-
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() :
|
|
24710
|
-
const encoded = `--${
|
|
24711
|
-
return
|
|
25321
|
+
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path12.join(homedir4(), ".pi", "agent");
|
|
25322
|
+
const encoded = `--${path12.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
25323
|
+
return path12.join(agentDir, "sessions", encoded);
|
|
24712
25324
|
}
|
|
24713
25325
|
function resolvePiSdkVersionFromPath(deps = {}) {
|
|
24714
25326
|
const dir = resolvePiSdkPackageDir(deps);
|
|
24715
25327
|
if (!dir)
|
|
24716
25328
|
return;
|
|
24717
25329
|
try {
|
|
24718
|
-
const pkg = JSON.parse(readFileSync3(
|
|
25330
|
+
const pkg = JSON.parse(readFileSync3(path12.join(dir, "package.json"), "utf-8"));
|
|
24719
25331
|
return pkg.version;
|
|
24720
25332
|
} catch {
|
|
24721
25333
|
return;
|
|
@@ -24819,6 +25431,9 @@ class PiDriver {
|
|
|
24819
25431
|
};
|
|
24820
25432
|
sessionId = null;
|
|
24821
25433
|
terminalSequence = 0;
|
|
25434
|
+
discoverRecentContext(request) {
|
|
25435
|
+
return discoverPiRecentContext(request);
|
|
25436
|
+
}
|
|
24822
25437
|
constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
|
|
24823
25438
|
this.dependenciesFor = dependenciesFor;
|
|
24824
25439
|
this.loadSdk = loadSdk;
|
|
@@ -24964,6 +25579,9 @@ function assertAdapterCompatibility(registrationId, registeredCapabilities, adap
|
|
|
24964
25579
|
if (typeof candidate[method] !== "function")
|
|
24965
25580
|
throw new Error(`Adapter ${registrationId} is missing ${method}()`);
|
|
24966
25581
|
}
|
|
25582
|
+
if (candidate.discoverRecentContext !== undefined && typeof candidate.discoverRecentContext !== "function") {
|
|
25583
|
+
throw new Error(`Adapter ${registrationId} has an invalid discoverRecentContext()`);
|
|
25584
|
+
}
|
|
24967
25585
|
const instruction = candidate.instructionDelivery;
|
|
24968
25586
|
if (!instruction || instruction.kind !== "native" && instruction.kind !== "workspace_file") {
|
|
24969
25587
|
throw new Error(`Adapter ${registrationId} has an invalid instructionDelivery declaration`);
|
|
@@ -25185,8 +25803,8 @@ function ensureSymlinks(workDir, canonical = CANONICAL_FILE, aliases = SYMLINK_A
|
|
|
25185
25803
|
continue;
|
|
25186
25804
|
const aliasPath = join8(workDir, alias2);
|
|
25187
25805
|
try {
|
|
25188
|
-
const
|
|
25189
|
-
if (
|
|
25806
|
+
const stat2 = lstatSync(aliasPath);
|
|
25807
|
+
if (stat2.isSymbolicLink()) {
|
|
25190
25808
|
const target2 = readlinkSync(aliasPath);
|
|
25191
25809
|
if (target2 === canonical)
|
|
25192
25810
|
continue;
|
|
@@ -25349,6 +25967,7 @@ class LogicalAgentSession {
|
|
|
25349
25967
|
steeringDeliveries = new Set;
|
|
25350
25968
|
laneAdmissionTail = Promise.resolve();
|
|
25351
25969
|
laneAdmissionPending = 0;
|
|
25970
|
+
toolBoundaryOpen = true;
|
|
25352
25971
|
toolBoundaryFlushDisabled = false;
|
|
25353
25972
|
safeBoundaryFlush;
|
|
25354
25973
|
safeBoundaryDelivery;
|
|
@@ -25629,6 +26248,8 @@ class LogicalAgentSession {
|
|
|
25629
26248
|
this.turnError = undefined;
|
|
25630
26249
|
this.interruptedTurnId = undefined;
|
|
25631
26250
|
this.processTurnEnded = false;
|
|
26251
|
+
this.toolBoundaryOpen = true;
|
|
26252
|
+
this.toolBoundaryFlushDisabled = false;
|
|
25632
26253
|
this.state = "starting";
|
|
25633
26254
|
const generation = this.lifecycleGeneration;
|
|
25634
26255
|
const text2 = messages.map((message2) => message2.text).join(`
|
|
@@ -25861,6 +26482,7 @@ class LogicalAgentSession {
|
|
|
25861
26482
|
}
|
|
25862
26483
|
if (!this.startToolUse(event.callId))
|
|
25863
26484
|
return;
|
|
26485
|
+
this.toolBoundaryOpen = false;
|
|
25864
26486
|
const startedCallId = this.toolCallId(event.callId);
|
|
25865
26487
|
this.emit({
|
|
25866
26488
|
type: "tool_started",
|
|
@@ -25877,6 +26499,7 @@ class LogicalAgentSession {
|
|
|
25877
26499
|
}
|
|
25878
26500
|
if (!this.finishToolUse(event.callId))
|
|
25879
26501
|
return;
|
|
26502
|
+
this.toolBoundaryOpen = true;
|
|
25880
26503
|
const finishedCallId = this.toolCallId(event.callId);
|
|
25881
26504
|
this.emit({
|
|
25882
26505
|
type: "tool_finished",
|
|
@@ -25884,7 +26507,7 @@ class LogicalAgentSession {
|
|
|
25884
26507
|
...finishedCallId ? { callId: finishedCallId } : {},
|
|
25885
26508
|
name: event.name
|
|
25886
26509
|
});
|
|
25887
|
-
if (
|
|
26510
|
+
if (!this.toolBoundaryFlushDisabled)
|
|
25888
26511
|
this.flushSafeBoundaryQueue();
|
|
25889
26512
|
return;
|
|
25890
26513
|
case "compaction_started":
|
|
@@ -26030,6 +26653,7 @@ class LogicalAgentSession {
|
|
|
26030
26653
|
this.clearOutstandingToolUses();
|
|
26031
26654
|
this.compacting = false;
|
|
26032
26655
|
this.reviewing = false;
|
|
26656
|
+
this.toolBoundaryOpen = true;
|
|
26033
26657
|
this.toolBoundaryFlushDisabled = false;
|
|
26034
26658
|
this.state = "idle";
|
|
26035
26659
|
if (this.adapter.execution.lifetime === "turn") {
|
|
@@ -26051,7 +26675,7 @@ class LogicalAgentSession {
|
|
|
26051
26675
|
return this.safeBoundaryFlush;
|
|
26052
26676
|
}
|
|
26053
26677
|
canFlushSafeBoundaryQueue() {
|
|
26054
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
26678
|
+
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.toolBoundaryOpen && !this.toolBoundaryFlushDisabled && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
|
|
26055
26679
|
}
|
|
26056
26680
|
async drainSafeBoundaryQueue() {
|
|
26057
26681
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -26566,6 +27190,57 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
26566
27190
|
const registry2 = options.registry;
|
|
26567
27191
|
return {
|
|
26568
27192
|
backendIds: registry2.backendIds,
|
|
27193
|
+
async discoverRecentContext(input) {
|
|
27194
|
+
if (!isValidRecentContextTopK(input.recentSessionFilesTopK) || !isValidRecentContextTopK(input.recentProjectsTopK)) {
|
|
27195
|
+
return {
|
|
27196
|
+
ok: false,
|
|
27197
|
+
error: {
|
|
27198
|
+
category: "configuration",
|
|
27199
|
+
code: "invalid_recent_context_top_k",
|
|
27200
|
+
message: "Recent-context Top-K values must be non-negative safe integers",
|
|
27201
|
+
retryable: false
|
|
27202
|
+
}
|
|
27203
|
+
};
|
|
27204
|
+
}
|
|
27205
|
+
const registration = registry2.get(input.backend);
|
|
27206
|
+
try {
|
|
27207
|
+
assertRegistrationShape(registration);
|
|
27208
|
+
const adapter = registration.createAdapter();
|
|
27209
|
+
assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
|
|
27210
|
+
if (!adapter.discoverRecentContext) {
|
|
27211
|
+
return {
|
|
27212
|
+
ok: false,
|
|
27213
|
+
error: {
|
|
27214
|
+
category: "configuration",
|
|
27215
|
+
code: "recent_context_discovery_unsupported",
|
|
27216
|
+
message: `Backend ${input.backend} does not support recent-context discovery`,
|
|
27217
|
+
retryable: false
|
|
27218
|
+
}
|
|
27219
|
+
};
|
|
27220
|
+
}
|
|
27221
|
+
const command = registration.capabilities.commandOverride ? input.command : undefined;
|
|
27222
|
+
const discovered = await adapter.discoverRecentContext({
|
|
27223
|
+
recentSessionFilesTopK: input.recentSessionFilesTopK,
|
|
27224
|
+
recentProjectsTopK: input.recentProjectsTopK,
|
|
27225
|
+
...command ? { command } : {}
|
|
27226
|
+
});
|
|
27227
|
+
const sanitized = sanitizeRecentContextData(discovered, input);
|
|
27228
|
+
if (!sanitized)
|
|
27229
|
+
throw new Error(`Adapter ${input.backend} returned invalid recent-context data`);
|
|
27230
|
+
return { ok: true, ...sanitized };
|
|
27231
|
+
} catch (error51) {
|
|
27232
|
+
const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
|
|
27233
|
+
return {
|
|
27234
|
+
ok: false,
|
|
27235
|
+
error: {
|
|
27236
|
+
category: contractInvalid ? "internal" : "runtime_unavailable",
|
|
27237
|
+
code: contractInvalid ? "adapter_contract_invalid" : "recent_context_discovery_failed",
|
|
27238
|
+
message: contractInvalid ? `Backend ${input.backend} adapter contract is invalid` : `Backend ${input.backend} recent-context discovery failed`,
|
|
27239
|
+
retryable: !contractInvalid
|
|
27240
|
+
}
|
|
27241
|
+
};
|
|
27242
|
+
}
|
|
27243
|
+
},
|
|
26569
27244
|
async probe(input) {
|
|
26570
27245
|
const registration = registry2.get(input.backend);
|
|
26571
27246
|
const capabilities2 = registration.capabilities;
|
|
@@ -26704,22 +27379,22 @@ function listRuntimeIds() {
|
|
|
26704
27379
|
|
|
26705
27380
|
// src/discovery.ts
|
|
26706
27381
|
function resolveAlookCliPath(moduleDir) {
|
|
26707
|
-
const thisDir = moduleDir ??
|
|
26708
|
-
const target2 =
|
|
27382
|
+
const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
|
|
27383
|
+
const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
|
|
26709
27384
|
return fs6.existsSync(target2) ? target2 : null;
|
|
26710
27385
|
}
|
|
26711
27386
|
function deriveCliFallbackCandidates(cliPath) {
|
|
26712
27387
|
if (!cliPath)
|
|
26713
27388
|
return [];
|
|
26714
|
-
const normalized = cliPath.split(
|
|
27389
|
+
const normalized = cliPath.split(path13.sep).join("/");
|
|
26715
27390
|
const marker = "/node_modules/";
|
|
26716
27391
|
const idx = normalized.indexOf(marker);
|
|
26717
27392
|
if (idx === -1)
|
|
26718
27393
|
return [];
|
|
26719
27394
|
const globalRoot = cliPath.slice(0, idx + marker.length - 1);
|
|
26720
|
-
const tail =
|
|
27395
|
+
const tail = path13.join("dist", "cli", "index.js");
|
|
26721
27396
|
return [
|
|
26722
|
-
|
|
27397
|
+
path13.join(globalRoot, "@alook", "daemon", tail)
|
|
26723
27398
|
].filter((candidate) => candidate !== cliPath);
|
|
26724
27399
|
}
|
|
26725
27400
|
function resolveAlookCliPathWithFallback(primary) {
|
|
@@ -26861,11 +27536,11 @@ function readDaemonVersion() {
|
|
|
26861
27536
|
|
|
26862
27537
|
// src/cli/daemonRunner.ts
|
|
26863
27538
|
import * as fs11 from "node:fs";
|
|
26864
|
-
import * as
|
|
27539
|
+
import * as path16 from "node:path";
|
|
26865
27540
|
import { WebSocket } from "ws";
|
|
26866
27541
|
|
|
26867
27542
|
// src/daemon/createDaemon.ts
|
|
26868
|
-
import { homedir as
|
|
27543
|
+
import { homedir as homedir7 } from "os";
|
|
26869
27544
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
|
|
26870
27545
|
|
|
26871
27546
|
// src/util/rotatingFileSink.ts
|
|
@@ -26882,7 +27557,7 @@ import {
|
|
|
26882
27557
|
statSync,
|
|
26883
27558
|
unlinkSync as unlinkSync3
|
|
26884
27559
|
} from "node:fs";
|
|
26885
|
-
function createRotatingFileSink(
|
|
27560
|
+
function createRotatingFileSink(path14, maxBytes, opts = {}) {
|
|
26886
27561
|
const report = (operation, error51) => {
|
|
26887
27562
|
try {
|
|
26888
27563
|
opts.onError?.({ operation, error: error51 });
|
|
@@ -26892,8 +27567,8 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26892
27567
|
if (!existsSync6(filePath))
|
|
26893
27568
|
return true;
|
|
26894
27569
|
try {
|
|
26895
|
-
const
|
|
26896
|
-
if (!
|
|
27570
|
+
const stat2 = lstatSync2(filePath);
|
|
27571
|
+
if (!stat2.isFile()) {
|
|
26897
27572
|
if (opts.mode === undefined && !opts.hardMaxBytes)
|
|
26898
27573
|
return true;
|
|
26899
27574
|
report("unsafe_generation", new Error("log generation is not a regular file"));
|
|
@@ -26901,7 +27576,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26901
27576
|
}
|
|
26902
27577
|
if (opts.mode !== undefined)
|
|
26903
27578
|
chmodSync(filePath, opts.mode);
|
|
26904
|
-
if (opts.hardMaxBytes && maxBytes > 0 &&
|
|
27579
|
+
if (opts.hardMaxBytes && maxBytes > 0 && stat2.size > maxBytes) {
|
|
26905
27580
|
try {
|
|
26906
27581
|
unlinkSync3(filePath);
|
|
26907
27582
|
} catch (error51) {
|
|
@@ -26918,9 +27593,9 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26918
27593
|
};
|
|
26919
27594
|
const rotate = () => {
|
|
26920
27595
|
try {
|
|
26921
|
-
renameSync2(
|
|
27596
|
+
renameSync2(path14, `${path14}.1`);
|
|
26922
27597
|
if (opts.mode !== undefined)
|
|
26923
|
-
chmodSync(`${
|
|
27598
|
+
chmodSync(`${path14}.1`, opts.mode);
|
|
26924
27599
|
return true;
|
|
26925
27600
|
} catch (error51) {
|
|
26926
27601
|
report("rotate", error51);
|
|
@@ -26929,7 +27604,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26929
27604
|
};
|
|
26930
27605
|
const currentSize = () => {
|
|
26931
27606
|
try {
|
|
26932
|
-
return existsSync6(
|
|
27607
|
+
return existsSync6(path14) ? statSync(path14).size : 0;
|
|
26933
27608
|
} catch (error51) {
|
|
26934
27609
|
report("stat", error51);
|
|
26935
27610
|
return null;
|
|
@@ -26937,7 +27612,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26937
27612
|
};
|
|
26938
27613
|
const sink = {
|
|
26939
27614
|
secure() {
|
|
26940
|
-
return secureGeneration(`${
|
|
27615
|
+
return secureGeneration(`${path14}.1`) && secureGeneration(path14);
|
|
26941
27616
|
},
|
|
26942
27617
|
write(line) {
|
|
26943
27618
|
try {
|
|
@@ -26957,7 +27632,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26957
27632
|
const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
|
|
26958
27633
|
if (shouldRotate && !rotate() && opts.hardMaxBytes)
|
|
26959
27634
|
return;
|
|
26960
|
-
appendFileSync(
|
|
27635
|
+
appendFileSync(path14, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
|
|
26961
27636
|
} catch (error51) {
|
|
26962
27637
|
report("append", error51);
|
|
26963
27638
|
}
|
|
@@ -26965,7 +27640,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26965
27640
|
openSnapshot() {
|
|
26966
27641
|
const files = [];
|
|
26967
27642
|
try {
|
|
26968
|
-
for (const candidate of [`${
|
|
27643
|
+
for (const candidate of [`${path14}.1`, path14]) {
|
|
26969
27644
|
if (!existsSync6(candidate))
|
|
26970
27645
|
continue;
|
|
26971
27646
|
if (!secureGeneration(candidate))
|
|
@@ -26973,10 +27648,10 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26973
27648
|
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
26974
27649
|
const fd = openSync(candidate, constants.O_RDONLY | noFollow);
|
|
26975
27650
|
try {
|
|
26976
|
-
const
|
|
26977
|
-
if (!
|
|
27651
|
+
const stat2 = fstatSync(fd);
|
|
27652
|
+
if (!stat2.isFile())
|
|
26978
27653
|
throw new Error("snapshot source is not a regular file");
|
|
26979
|
-
files.push({ path: candidate, fd, size:
|
|
27654
|
+
files.push({ path: candidate, fd, size: stat2.size });
|
|
26980
27655
|
} catch (error51) {
|
|
26981
27656
|
closeSync(fd);
|
|
26982
27657
|
throw error51;
|
|
@@ -27126,11 +27801,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
|
|
|
27126
27801
|
|
|
27127
27802
|
// src/util/statusFile.ts
|
|
27128
27803
|
import { writeFileSync as writeFileSync4, renameSync as renameSync3 } from "node:fs";
|
|
27129
|
-
function writeStatusFile(
|
|
27804
|
+
function writeStatusFile(path14, snapshot) {
|
|
27130
27805
|
try {
|
|
27131
|
-
const tmp = `${
|
|
27806
|
+
const tmp = `${path14}.tmp`;
|
|
27132
27807
|
writeFileSync4(tmp, JSON.stringify(snapshot));
|
|
27133
|
-
renameSync3(tmp,
|
|
27808
|
+
renameSync3(tmp, path14);
|
|
27134
27809
|
} catch {}
|
|
27135
27810
|
}
|
|
27136
27811
|
|
|
@@ -27812,7 +28487,7 @@ import * as fs7 from "fs";
|
|
|
27812
28487
|
import * as http from "http";
|
|
27813
28488
|
import * as https from "https";
|
|
27814
28489
|
import * as os2 from "os";
|
|
27815
|
-
import * as
|
|
28490
|
+
import * as path14 from "path";
|
|
27816
28491
|
import { URL as URL2 } from "url";
|
|
27817
28492
|
var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
|
|
27818
28493
|
var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
|
|
@@ -27844,15 +28519,15 @@ class CredentialBroker {
|
|
|
27844
28519
|
this.voucherPrefix = config2.voucherPrefix ?? "vch_";
|
|
27845
28520
|
this.clientLabel = config2.clientLabel ?? "cli";
|
|
27846
28521
|
this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
|
|
27847
|
-
this.voucherDir = config2.voucherDir ??
|
|
28522
|
+
this.voucherDir = config2.voucherDir ?? path14.join(os2.tmpdir(), "agent-vouchers");
|
|
27848
28523
|
}
|
|
27849
28524
|
mint(agentId, launchId, capabilities2, runnerKey) {
|
|
27850
28525
|
if (!runnerKey)
|
|
27851
28526
|
throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
|
|
27852
28527
|
const voucher = randomVoucher(this.voucherPrefix);
|
|
27853
|
-
const dir =
|
|
28528
|
+
const dir = path14.join(this.voucherDir, sanitizeIdSegment(agentId));
|
|
27854
28529
|
fs7.mkdirSync(dir, { recursive: true });
|
|
27855
|
-
const voucherFile =
|
|
28530
|
+
const voucherFile = path14.join(dir, `${sanitizeIdSegment(launchId)}.token`);
|
|
27856
28531
|
fs7.writeFileSync(voucherFile, voucher, { mode: 384 });
|
|
27857
28532
|
this.registrations.set(voucher, {
|
|
27858
28533
|
agentId,
|
|
@@ -28920,7 +29595,7 @@ function runtimeModelName(config2) {
|
|
|
28920
29595
|
// agent-driver/dist/provider-quota.js
|
|
28921
29596
|
import { execFile } from "node:child_process";
|
|
28922
29597
|
import { readFile } from "node:fs/promises";
|
|
28923
|
-
import { homedir as
|
|
29598
|
+
import { homedir as homedir5 } from "node:os";
|
|
28924
29599
|
import { join as join11 } from "node:path";
|
|
28925
29600
|
import { promisify } from "node:util";
|
|
28926
29601
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
@@ -28949,7 +29624,7 @@ async function claudeCredentials(options) {
|
|
|
28949
29624
|
} catch {}
|
|
28950
29625
|
}
|
|
28951
29626
|
const env = options.env ?? process.env;
|
|
28952
|
-
const root = env.CLAUDE_CONFIG_DIR || join11(options.home ??
|
|
29627
|
+
const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir5(), ".claude");
|
|
28953
29628
|
try {
|
|
28954
29629
|
const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
|
|
28955
29630
|
return parseCredentials(value);
|
|
@@ -30305,6 +30980,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30305
30980
|
sent = session2.send(input);
|
|
30306
30981
|
if (exactOwner)
|
|
30307
30982
|
this.markPendingDeliveryObserved(exactOwner, input.id);
|
|
30983
|
+
this.log.info("steering message submitted to logical session", {
|
|
30984
|
+
agentId: effect.agentId,
|
|
30985
|
+
mode: effect.mode
|
|
30986
|
+
});
|
|
30308
30987
|
} catch (error51) {
|
|
30309
30988
|
if (exactOwner) {
|
|
30310
30989
|
this.settlePendingDelivery(exactOwner, input.id);
|
|
@@ -30350,7 +31029,6 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30350
31029
|
mode: effect.mode
|
|
30351
31030
|
});
|
|
30352
31031
|
}
|
|
30353
|
-
this.log.info("steering message sent to running agent", { agentId: effect.agentId, mode: effect.mode });
|
|
30354
31032
|
break;
|
|
30355
31033
|
}
|
|
30356
31034
|
case "stop":
|
|
@@ -31396,6 +32074,26 @@ class AgentRouter {
|
|
|
31396
32074
|
return;
|
|
31397
32075
|
}
|
|
31398
32076
|
break;
|
|
32077
|
+
case "agent:event":
|
|
32078
|
+
this.log.info("agent:event received", { agentId: cmd.agentId });
|
|
32079
|
+
try {
|
|
32080
|
+
await this.opts.onBeforeAgent?.(cmd.agentId);
|
|
32081
|
+
this.opts.manager.register(cmd.agentId, {
|
|
32082
|
+
runtimeConfig: cmd.config,
|
|
32083
|
+
launchId: cmd.launchId
|
|
32084
|
+
});
|
|
32085
|
+
this.running.add(cmd.agentId);
|
|
32086
|
+
this.opts.manager.deliver(cmd.agentId, {
|
|
32087
|
+
id: `${cmd.agentId}:event:${cmd.launchId}`,
|
|
32088
|
+
text: cmd.prompt
|
|
32089
|
+
});
|
|
32090
|
+
} catch (err) {
|
|
32091
|
+
this.log.warn("agent:event failed", {
|
|
32092
|
+
agentId: cmd.agentId,
|
|
32093
|
+
err: err instanceof Error ? err.message : String(err)
|
|
32094
|
+
});
|
|
32095
|
+
}
|
|
32096
|
+
break;
|
|
31399
32097
|
case "agent:reset":
|
|
31400
32098
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:reset", () => this.opts.manager.resetSession(cmd.agentId, {
|
|
31401
32099
|
runtimeConfig: cmd.config,
|
|
@@ -31626,11 +32324,11 @@ function timelineRowHash(line) {
|
|
|
31626
32324
|
}
|
|
31627
32325
|
function timelineFileGeneration(filePath, lines) {
|
|
31628
32326
|
try {
|
|
31629
|
-
const
|
|
31630
|
-
if (!
|
|
32327
|
+
const stat2 = fs9.lstatSync(filePath, { bigint: true });
|
|
32328
|
+
if (!stat2.isFile())
|
|
31631
32329
|
return null;
|
|
31632
32330
|
const digest = createHash2("sha256");
|
|
31633
|
-
digest.update(`${
|
|
32331
|
+
digest.update(`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
|
|
31634
32332
|
`);
|
|
31635
32333
|
for (const line of lines)
|
|
31636
32334
|
digest.update(line.text, "utf8").update(`
|
|
@@ -31688,9 +32386,9 @@ function compactLines(input) {
|
|
|
31688
32386
|
}
|
|
31689
32387
|
return suffix;
|
|
31690
32388
|
}
|
|
31691
|
-
function isRealDirectory(
|
|
32389
|
+
function isRealDirectory(path15) {
|
|
31692
32390
|
try {
|
|
31693
|
-
return fs9.lstatSync(
|
|
32391
|
+
return fs9.lstatSync(path15).isDirectory();
|
|
31694
32392
|
} catch {
|
|
31695
32393
|
return false;
|
|
31696
32394
|
}
|
|
@@ -31730,8 +32428,8 @@ function scanTimelineFile(filePath) {
|
|
|
31730
32428
|
let fd = null;
|
|
31731
32429
|
try {
|
|
31732
32430
|
fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
|
|
31733
|
-
const
|
|
31734
|
-
if (!
|
|
32431
|
+
const stat2 = fs9.fstatSync(fd);
|
|
32432
|
+
if (!stat2.isFile())
|
|
31735
32433
|
return null;
|
|
31736
32434
|
const chunk2 = Buffer.allocUnsafe(TIMELINE_READ_CHUNK_BYTES);
|
|
31737
32435
|
const newest = [];
|
|
@@ -31744,9 +32442,9 @@ function scanTimelineFile(filePath) {
|
|
|
31744
32442
|
let oversized = false;
|
|
31745
32443
|
let stop = false;
|
|
31746
32444
|
let discardIncompleteTail = false;
|
|
31747
|
-
if (
|
|
32445
|
+
if (stat2.size > 0) {
|
|
31748
32446
|
const last = Buffer.allocUnsafe(1);
|
|
31749
|
-
fs9.readSync(fd, last, 0, 1,
|
|
32447
|
+
fs9.readSync(fd, last, 0, 1, stat2.size - 1);
|
|
31750
32448
|
discardIncompleteTail = last[0] !== 10;
|
|
31751
32449
|
}
|
|
31752
32450
|
const resetPhysicalLine = () => {
|
|
@@ -31805,7 +32503,7 @@ function scanTimelineFile(filePath) {
|
|
|
31805
32503
|
}
|
|
31806
32504
|
resetPhysicalLine();
|
|
31807
32505
|
};
|
|
31808
|
-
let position =
|
|
32506
|
+
let position = stat2.size;
|
|
31809
32507
|
while (position > 0 && !stop) {
|
|
31810
32508
|
const start = Math.max(0, position - chunk2.length);
|
|
31811
32509
|
const requested = position - start;
|
|
@@ -31957,11 +32655,11 @@ function readResumeControlState(timelineDir) {
|
|
|
31957
32655
|
let fd = null;
|
|
31958
32656
|
try {
|
|
31959
32657
|
fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
|
|
31960
|
-
const
|
|
31961
|
-
if (!
|
|
32658
|
+
const stat2 = fs9.fstatSync(fd);
|
|
32659
|
+
if (!stat2.isFile() || stat2.size <= 0 || stat2.size > RESUME_CONTROL_MAX_BYTES) {
|
|
31962
32660
|
return { kind: "invalid" };
|
|
31963
32661
|
}
|
|
31964
|
-
const bounded = Buffer.allocUnsafe(
|
|
32662
|
+
const bounded = Buffer.allocUnsafe(stat2.size + 1);
|
|
31965
32663
|
let bytesRead = 0;
|
|
31966
32664
|
while (bytesRead < bounded.length) {
|
|
31967
32665
|
const count = fs9.readSync(fd, bounded, bytesRead, bounded.length - bytesRead, bytesRead);
|
|
@@ -31969,7 +32667,7 @@ function readResumeControlState(timelineDir) {
|
|
|
31969
32667
|
break;
|
|
31970
32668
|
bytesRead += count;
|
|
31971
32669
|
}
|
|
31972
|
-
if (bytesRead !==
|
|
32670
|
+
if (bytesRead !== stat2.size)
|
|
31973
32671
|
return { kind: "invalid" };
|
|
31974
32672
|
const raw = bounded.subarray(0, bytesRead).toString("utf8");
|
|
31975
32673
|
const value = JSON.parse(raw);
|
|
@@ -32895,7 +33593,7 @@ class MessageReminderScheduler {
|
|
|
32895
33593
|
|
|
32896
33594
|
// src/manager/agentDriverHost.ts
|
|
32897
33595
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32898
|
-
import { homedir as
|
|
33596
|
+
import { homedir as homedir6 } from "node:os";
|
|
32899
33597
|
import { join as join13 } from "node:path";
|
|
32900
33598
|
|
|
32901
33599
|
// src/drivers/gitIdentityEnv.ts
|
|
@@ -33021,7 +33719,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
33021
33719
|
hostUser: readHostGitIdentity() ?? undefined
|
|
33022
33720
|
}),
|
|
33023
33721
|
platformProtected: {
|
|
33024
|
-
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(
|
|
33722
|
+
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir6(), ".alook"),
|
|
33025
33723
|
ALOOK_ID: ctx.agentId,
|
|
33026
33724
|
ALOOK_CLI: ctx.agentCliPath,
|
|
33027
33725
|
ALOOK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -33342,13 +34040,13 @@ function createRuntimeRawLineTap(args) {
|
|
|
33342
34040
|
const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
|
|
33343
34041
|
const sinks = new Map;
|
|
33344
34042
|
const warned = new Set;
|
|
33345
|
-
const warnOnce = (agentId,
|
|
34043
|
+
const warnOnce = (agentId, path15, operation, error51) => {
|
|
33346
34044
|
if (warned.has(agentId))
|
|
33347
34045
|
return;
|
|
33348
34046
|
warned.add(agentId);
|
|
33349
34047
|
args.logger.warn("runtime raw trace sink failed", {
|
|
33350
34048
|
agentId,
|
|
33351
|
-
path:
|
|
34049
|
+
path: path15,
|
|
33352
34050
|
operation,
|
|
33353
34051
|
error: error51 instanceof Error ? error51.message : String(error51)
|
|
33354
34052
|
});
|
|
@@ -33357,10 +34055,10 @@ function createRuntimeRawLineTap(args) {
|
|
|
33357
34055
|
if (!args.enabledAgentIds.has(agentId))
|
|
33358
34056
|
return;
|
|
33359
34057
|
const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
|
|
33360
|
-
const
|
|
34058
|
+
const path15 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
|
|
33361
34059
|
const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
33362
34060
|
if (serializedBytes > maxBytes) {
|
|
33363
|
-
warnOnce(agentId,
|
|
34061
|
+
warnOnce(agentId, path15, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
|
|
33364
34062
|
return;
|
|
33365
34063
|
}
|
|
33366
34064
|
let sink = sinks.get(agentId);
|
|
@@ -33368,12 +34066,12 @@ function createRuntimeRawLineTap(args) {
|
|
|
33368
34066
|
try {
|
|
33369
34067
|
mkdirSync8(traceDir, { recursive: true });
|
|
33370
34068
|
} catch (error51) {
|
|
33371
|
-
warnOnce(agentId,
|
|
34069
|
+
warnOnce(agentId, path15, "mkdir", error51);
|
|
33372
34070
|
}
|
|
33373
|
-
sink = createRotatingFileSink(
|
|
34071
|
+
sink = createRotatingFileSink(path15, maxBytes, {
|
|
33374
34072
|
mode: 384,
|
|
33375
34073
|
hardMaxBytes: true,
|
|
33376
|
-
onError: ({ operation, error: error51 }) => warnOnce(agentId,
|
|
34074
|
+
onError: ({ operation, error: error51 }) => warnOnce(agentId, path15, operation, error51)
|
|
33377
34075
|
});
|
|
33378
34076
|
sinks.set(agentId, sink);
|
|
33379
34077
|
}
|
|
@@ -33465,7 +34163,7 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
|
|
|
33465
34163
|
}
|
|
33466
34164
|
async function createDaemon(opts) {
|
|
33467
34165
|
const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
|
|
33468
|
-
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${
|
|
34166
|
+
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir7()}/.alook`) + "/daemon";
|
|
33469
34167
|
const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
|
|
33470
34168
|
const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
|
|
33471
34169
|
const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
|
|
@@ -34171,12 +34869,12 @@ async function readPinnedJsonFile(args) {
|
|
|
34171
34869
|
}
|
|
34172
34870
|
}
|
|
34173
34871
|
fd = openSync3(args.path, constants3.O_RDONLY | noFollow);
|
|
34174
|
-
const
|
|
34175
|
-
if (!
|
|
34872
|
+
const stat2 = fstatSync3(fd);
|
|
34873
|
+
if (!stat2.isFile())
|
|
34176
34874
|
return { value: null, warnings: ["source_unavailable"] };
|
|
34177
|
-
if (
|
|
34875
|
+
if (stat2.size > args.maxBytes)
|
|
34178
34876
|
return { value: null, warnings: ["line_too_long"] };
|
|
34179
|
-
const bytes = readPinnedBytes(fd,
|
|
34877
|
+
const bytes = readPinnedBytes(fd, stat2.size);
|
|
34180
34878
|
try {
|
|
34181
34879
|
return { value: JSON.parse(bytes.toString("utf8")), warnings: [] };
|
|
34182
34880
|
} catch {
|
|
@@ -34254,7 +34952,7 @@ var DAEMON_LOG_DIAGNOSTIC_POLICY = [
|
|
|
34254
34952
|
reason: string5(32, { values: ["turn_end", "stopped", "terminate_stalled", "exit"] }),
|
|
34255
34953
|
sessionId: string5(256, { scrub: true })
|
|
34256
34954
|
} },
|
|
34257
|
-
{ header: "@alook/daemon:manager", message: "steering message
|
|
34955
|
+
{ header: "@alook/daemon:manager", message: "steering message submitted to logical session", scope: "target", fields: {
|
|
34258
34956
|
agentId: AGENT,
|
|
34259
34957
|
mode: string5(8, { values: ["busy", "idle"] })
|
|
34260
34958
|
} },
|
|
@@ -34809,7 +35507,7 @@ import { createHash as createHash4, randomBytes as randomBytes7 } from "node:cry
|
|
|
34809
35507
|
import {
|
|
34810
35508
|
chmodSync as chmodSync2,
|
|
34811
35509
|
closeSync as closeSync4,
|
|
34812
|
-
createReadStream,
|
|
35510
|
+
createReadStream as createReadStream3,
|
|
34813
35511
|
existsSync as existsSync7,
|
|
34814
35512
|
fsyncSync as fsyncSync2,
|
|
34815
35513
|
lstatSync as lstatSync5,
|
|
@@ -34832,7 +35530,7 @@ class CoordinatorError extends Error {
|
|
|
34832
35530
|
function defaultFsOps() {
|
|
34833
35531
|
return {
|
|
34834
35532
|
randomSuffix: () => randomBytes7(12).toString("hex"),
|
|
34835
|
-
open: (
|
|
35533
|
+
open: (path15, flags, mode) => openSync4(path15, flags, mode),
|
|
34836
35534
|
write: (fd, bytes) => {
|
|
34837
35535
|
writeSync(fd, bytes);
|
|
34838
35536
|
},
|
|
@@ -34845,10 +35543,10 @@ function defaultFsOps() {
|
|
|
34845
35543
|
rename: (from, to) => {
|
|
34846
35544
|
renameSync5(from, to);
|
|
34847
35545
|
},
|
|
34848
|
-
fsyncDirectory: (
|
|
35546
|
+
fsyncDirectory: (path15) => {
|
|
34849
35547
|
if (process.platform === "win32")
|
|
34850
35548
|
return;
|
|
34851
|
-
const fd = openSync4(
|
|
35549
|
+
const fd = openSync4(path15, "r");
|
|
34852
35550
|
try {
|
|
34853
35551
|
fsyncSync2(fd);
|
|
34854
35552
|
} finally {
|
|
@@ -34899,8 +35597,8 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34899
35597
|
const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
|
|
34900
35598
|
const ensureDir = () => {
|
|
34901
35599
|
if (existsSync7(dir)) {
|
|
34902
|
-
const
|
|
34903
|
-
if (!
|
|
35600
|
+
const stat2 = lstatSync5(dir);
|
|
35601
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
34904
35602
|
throw new CoordinatorError("local_artifact_invalid");
|
|
34905
35603
|
if (process.platform !== "win32")
|
|
34906
35604
|
chmodSync2(dir, 448);
|
|
@@ -34913,11 +35611,11 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34913
35611
|
args.logger?.warn("diagnostic local artifact invalid", { reportId, code: "local_artifact_invalid" });
|
|
34914
35612
|
} catch {}
|
|
34915
35613
|
};
|
|
34916
|
-
const removeExact = (
|
|
35614
|
+
const removeExact = (path15) => {
|
|
34917
35615
|
try {
|
|
34918
|
-
const
|
|
34919
|
-
if (
|
|
34920
|
-
unlinkSync6(
|
|
35616
|
+
const stat2 = lstatSync5(path15);
|
|
35617
|
+
if (stat2.isFile() && !stat2.isSymbolicLink())
|
|
35618
|
+
unlinkSync6(path15);
|
|
34921
35619
|
} catch {}
|
|
34922
35620
|
};
|
|
34923
35621
|
const cleanup = (reportId) => {
|
|
@@ -34955,12 +35653,12 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34955
35653
|
checkpoint(sidecar.phase === "collecting" ? "collecting_dir_fsynced" : "ready_dir_fsynced");
|
|
34956
35654
|
};
|
|
34957
35655
|
const committedArchive = (reportId) => {
|
|
34958
|
-
const
|
|
35656
|
+
const path15 = archivePath(reportId);
|
|
34959
35657
|
try {
|
|
34960
|
-
const
|
|
34961
|
-
if (!
|
|
35658
|
+
const stat2 = lstatSync5(path15);
|
|
35659
|
+
if (!stat2.isFile() || stat2.isSymbolicLink())
|
|
34962
35660
|
return null;
|
|
34963
|
-
const bytes = readFileSync6(
|
|
35661
|
+
const bytes = readFileSync6(path15);
|
|
34964
35662
|
return { sizeBytes: bytes.byteLength, sha256: createHash4("sha256").update(bytes).digest("hex") };
|
|
34965
35663
|
} catch {
|
|
34966
35664
|
return null;
|
|
@@ -35021,7 +35719,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35021
35719
|
if (stopped)
|
|
35022
35720
|
throw new CoordinatorError("coordinator_shutdown");
|
|
35023
35721
|
checkpoint("before_upload");
|
|
35024
|
-
const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 },
|
|
35722
|
+
const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream3(archivePath(sidecar.reportId)));
|
|
35025
35723
|
checkpoint("after_upload");
|
|
35026
35724
|
if (result.kind === "terminal") {
|
|
35027
35725
|
cleanup(sidecar.reportId);
|
|
@@ -35085,12 +35783,12 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35085
35783
|
return uploadReady(ready);
|
|
35086
35784
|
};
|
|
35087
35785
|
const readSidecar = (reportId) => {
|
|
35088
|
-
const
|
|
35786
|
+
const path15 = sidecarPath(reportId);
|
|
35089
35787
|
try {
|
|
35090
|
-
const
|
|
35091
|
-
if (!
|
|
35788
|
+
const stat2 = lstatSync5(path15);
|
|
35789
|
+
if (!stat2.isFile() || stat2.isSymbolicLink())
|
|
35092
35790
|
return null;
|
|
35093
|
-
return parseSidecar(JSON.parse(readFileSync6(
|
|
35791
|
+
return parseSidecar(JSON.parse(readFileSync6(path15, "utf8")));
|
|
35094
35792
|
} catch {
|
|
35095
35793
|
return null;
|
|
35096
35794
|
}
|
|
@@ -35178,9 +35876,9 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35178
35876
|
}
|
|
35179
35877
|
// src/diagnostics/httpTransport.ts
|
|
35180
35878
|
import { Readable as Readable2 } from "node:stream";
|
|
35181
|
-
function endpoint(serverUrl,
|
|
35879
|
+
function endpoint(serverUrl, path15) {
|
|
35182
35880
|
const base = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
|
|
35183
|
-
return new URL(
|
|
35881
|
+
return new URL(path15.replace(/^\//, ""), base).toString();
|
|
35184
35882
|
}
|
|
35185
35883
|
async function strictOutcome(response, allowed) {
|
|
35186
35884
|
try {
|
|
@@ -35244,29 +35942,29 @@ function createDiagnosticHttpTransport(args) {
|
|
|
35244
35942
|
// src/cli/daemonUpdate.ts
|
|
35245
35943
|
import * as crypto4 from "node:crypto";
|
|
35246
35944
|
import * as fs10 from "node:fs";
|
|
35247
|
-
import * as
|
|
35945
|
+
import * as path15 from "node:path";
|
|
35248
35946
|
import { spawn as spawn2 } from "node:child_process";
|
|
35249
35947
|
var UPDATE_INTENT_SCHEMA_VERSION = 1;
|
|
35250
35948
|
var UPDATE_LOG_MAX_BYTES = 512 * 1024;
|
|
35251
35949
|
var UPDATE_LOG_KEEP_BYTES = 256 * 1024;
|
|
35252
35950
|
var REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
|
|
35253
35951
|
function intentPath(baseDir, machineId) {
|
|
35254
|
-
return
|
|
35952
|
+
return path15.join(daemonDirById(baseDir, machineId), "update-intent.json");
|
|
35255
35953
|
}
|
|
35256
35954
|
function updateLogPath(baseDir, machineId) {
|
|
35257
|
-
return
|
|
35955
|
+
return path15.join(daemonDirById(baseDir, machineId), "update.log");
|
|
35258
35956
|
}
|
|
35259
35957
|
function updatePackageMapPath(baseDir, machineId) {
|
|
35260
|
-
return
|
|
35958
|
+
return path15.join(daemonDirById(baseDir, machineId), "update-package-map.json");
|
|
35261
35959
|
}
|
|
35262
35960
|
function ensurePrivateDir(dir) {
|
|
35263
35961
|
fs10.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
35264
35962
|
fs10.chmodSync(dir, 448);
|
|
35265
35963
|
}
|
|
35266
35964
|
function writePrivateJsonAtomic(filePath, value) {
|
|
35267
|
-
const dir =
|
|
35965
|
+
const dir = path15.dirname(filePath);
|
|
35268
35966
|
ensurePrivateDir(dir);
|
|
35269
|
-
const tempPath =
|
|
35967
|
+
const tempPath = path15.join(dir, `.${path15.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
|
|
35270
35968
|
let fd = fs10.openSync(tempPath, "wx", 384);
|
|
35271
35969
|
try {
|
|
35272
35970
|
fs10.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -35291,7 +35989,7 @@ function scrub(value) {
|
|
|
35291
35989
|
}
|
|
35292
35990
|
function appendUpdateLog(baseDir, machineId, event, fields = {}) {
|
|
35293
35991
|
const filePath = updateLogPath(baseDir, machineId);
|
|
35294
|
-
ensurePrivateDir(
|
|
35992
|
+
ensurePrivateDir(path15.dirname(filePath));
|
|
35295
35993
|
try {
|
|
35296
35994
|
if (fs10.existsSync(filePath) && fs10.statSync(filePath).size > UPDATE_LOG_MAX_BYTES) {
|
|
35297
35995
|
const data = fs10.readFileSync(filePath);
|
|
@@ -35318,8 +36016,8 @@ function tuplesEqual(value, expected) {
|
|
|
35318
36016
|
}
|
|
35319
36017
|
function readIntent(baseDir, machineId) {
|
|
35320
36018
|
const filePath = intentPath(baseDir, machineId);
|
|
35321
|
-
const
|
|
35322
|
-
if (!
|
|
36019
|
+
const stat2 = fs10.lstatSync(filePath);
|
|
36020
|
+
if (!stat2.isFile())
|
|
35323
36021
|
throw new Error("unsafe daemon update intent type");
|
|
35324
36022
|
fs10.chmodSync(filePath, 384);
|
|
35325
36023
|
const value = JSON.parse(fs10.readFileSync(filePath, "utf8"));
|
|
@@ -35334,12 +36032,81 @@ function removeIntentIfMatches(baseDir, machineId, requestId) {
|
|
|
35334
36032
|
fs10.unlinkSync(intentPath(baseDir, machineId));
|
|
35335
36033
|
} catch {}
|
|
35336
36034
|
}
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
36035
|
+
var defaultNpmLaunchFileProbe = {
|
|
36036
|
+
isFile(filePath) {
|
|
36037
|
+
try {
|
|
36038
|
+
return fs10.statSync(filePath).isFile();
|
|
36039
|
+
} catch {
|
|
36040
|
+
return false;
|
|
36041
|
+
}
|
|
36042
|
+
},
|
|
36043
|
+
isExecutable(filePath) {
|
|
36044
|
+
try {
|
|
36045
|
+
fs10.accessSync(filePath, fs10.constants.X_OK);
|
|
36046
|
+
return true;
|
|
36047
|
+
} catch {
|
|
36048
|
+
return false;
|
|
36049
|
+
}
|
|
35341
36050
|
}
|
|
35342
|
-
|
|
36051
|
+
};
|
|
36052
|
+
function pathEnvironment(env, platform) {
|
|
36053
|
+
if (platform !== "win32")
|
|
36054
|
+
return env.PATH;
|
|
36055
|
+
const entry = Object.entries(env).find(([key]) => key.toLowerCase() === "path");
|
|
36056
|
+
return entry?.[1];
|
|
36057
|
+
}
|
|
36058
|
+
function launchFromNpmPath(args) {
|
|
36059
|
+
const pathApi = args.platform === "win32" ? path15.win32 : path15.posix;
|
|
36060
|
+
if (!pathApi.isAbsolute(args.npmPath) || !args.probe.isFile(args.npmPath))
|
|
36061
|
+
return null;
|
|
36062
|
+
const extension = pathApi.extname(args.npmPath).toLowerCase();
|
|
36063
|
+
if ([".js", ".cjs", ".mjs"].includes(extension)) {
|
|
36064
|
+
return { file: args.nodePath, prefixArgs: [args.npmPath] };
|
|
36065
|
+
}
|
|
36066
|
+
if (args.platform === "win32" && [".cmd", ".bat"].includes(extension)) {
|
|
36067
|
+
const cliPath = pathApi.join(pathApi.dirname(args.npmPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
36068
|
+
return args.probe.isFile(cliPath) ? { file: args.nodePath, prefixArgs: [cliPath] } : null;
|
|
36069
|
+
}
|
|
36070
|
+
if (args.requireExecutable && !args.probe.isExecutable(args.npmPath))
|
|
36071
|
+
return null;
|
|
36072
|
+
return { file: args.npmPath, prefixArgs: [] };
|
|
36073
|
+
}
|
|
36074
|
+
function resolveNpmLaunchCommand(options = {}) {
|
|
36075
|
+
const env = options.env ?? process.env;
|
|
36076
|
+
const platform = options.platform ?? process.platform;
|
|
36077
|
+
const nodePath = options.nodePath ?? process.execPath;
|
|
36078
|
+
const probe = options.probe ?? defaultNpmLaunchFileProbe;
|
|
36079
|
+
const inherited = options.npmExecPath ?? env.npm_execpath;
|
|
36080
|
+
if (inherited) {
|
|
36081
|
+
const launch = launchFromNpmPath({
|
|
36082
|
+
npmPath: inherited,
|
|
36083
|
+
platform,
|
|
36084
|
+
nodePath,
|
|
36085
|
+
probe,
|
|
36086
|
+
requireExecutable: platform !== "win32"
|
|
36087
|
+
});
|
|
36088
|
+
if (launch)
|
|
36089
|
+
return launch;
|
|
36090
|
+
}
|
|
36091
|
+
const pathApi = platform === "win32" ? path15.win32 : path15.posix;
|
|
36092
|
+
const names = platform === "win32" ? ["npm.exe", "npm.cmd", "npm.bat", "npm"] : ["npm"];
|
|
36093
|
+
const pathValue = pathEnvironment(env, platform);
|
|
36094
|
+
for (const directory of pathValue?.split(pathApi.delimiter) ?? []) {
|
|
36095
|
+
if (!directory || !pathApi.isAbsolute(directory))
|
|
36096
|
+
continue;
|
|
36097
|
+
for (const name of names) {
|
|
36098
|
+
const launch = launchFromNpmPath({
|
|
36099
|
+
npmPath: pathApi.join(directory, name),
|
|
36100
|
+
platform,
|
|
36101
|
+
nodePath,
|
|
36102
|
+
probe,
|
|
36103
|
+
requireExecutable: platform !== "win32"
|
|
36104
|
+
});
|
|
36105
|
+
if (launch)
|
|
36106
|
+
return launch;
|
|
36107
|
+
}
|
|
36108
|
+
}
|
|
36109
|
+
throw new Error("npm launch context unavailable and no safe npm executable was found on PATH; daemon remains online");
|
|
35343
36110
|
}
|
|
35344
36111
|
function readTestPackageMap(baseDir, machineId) {
|
|
35345
36112
|
if (true)
|
|
@@ -35347,10 +36114,10 @@ function readTestPackageMap(baseDir, machineId) {
|
|
|
35347
36114
|
const filePath = updatePackageMapPath(baseDir, machineId);
|
|
35348
36115
|
if (!fs10.existsSync(filePath))
|
|
35349
36116
|
return null;
|
|
35350
|
-
const
|
|
35351
|
-
if (!
|
|
36117
|
+
const stat2 = fs10.lstatSync(filePath);
|
|
36118
|
+
if (!stat2.isFile())
|
|
35352
36119
|
throw new Error("unsafe daemon update package map type");
|
|
35353
|
-
if (process.platform !== "win32" && (
|
|
36120
|
+
if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {
|
|
35354
36121
|
throw new Error("daemon update package map must be mode 0600");
|
|
35355
36122
|
}
|
|
35356
36123
|
const parsed = JSON.parse(fs10.readFileSync(filePath, "utf8"));
|
|
@@ -35360,7 +36127,7 @@ function readTestPackageMap(baseDir, machineId) {
|
|
|
35360
36127
|
for (const [key, value] of Object.entries(parsed)) {
|
|
35361
36128
|
if (key !== "latest" && !parseReleaseVersion(key))
|
|
35362
36129
|
throw new Error("invalid daemon update package map key");
|
|
35363
|
-
if (typeof value !== "string" || !
|
|
36130
|
+
if (typeof value !== "string" || !path15.isAbsolute(value))
|
|
35364
36131
|
throw new Error("invalid daemon update package map value");
|
|
35365
36132
|
result[key] = value;
|
|
35366
36133
|
}
|
|
@@ -35374,9 +36141,9 @@ function packageSpec(baseDir, machineId, version3) {
|
|
|
35374
36141
|
}
|
|
35375
36142
|
function fixedNpmArgs(args) {
|
|
35376
36143
|
return [
|
|
35377
|
-
args.npmPath,
|
|
35378
36144
|
"exec",
|
|
35379
36145
|
"--yes",
|
|
36146
|
+
"--no-audit",
|
|
35380
36147
|
`--package=${args.packageSpec}`,
|
|
35381
36148
|
"--",
|
|
35382
36149
|
"alook-daemon",
|
|
@@ -35407,7 +36174,13 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
|
|
|
35407
36174
|
const current = pidTuple(readPidFile(pidfilePathById(context.baseDir, context.machineId)));
|
|
35408
36175
|
if (!current || current.pid !== context.pid || current.machineId !== context.machineId || current.startedAt !== context.startedAt || current.ownerToken !== context.ownerToken)
|
|
35409
36176
|
throw new Error("daemon ownership changed before update launch");
|
|
35410
|
-
const
|
|
36177
|
+
const npmLaunch = resolveNpmLaunchCommand({
|
|
36178
|
+
npmExecPath: deps.npmExecPath,
|
|
36179
|
+
env: deps.npmLaunchEnv,
|
|
36180
|
+
platform: deps.npmLaunchPlatform,
|
|
36181
|
+
nodePath: deps.npmLaunchNodePath,
|
|
36182
|
+
probe: deps.npmLaunchFileProbe
|
|
36183
|
+
});
|
|
35411
36184
|
requestId = crypto4.randomUUID();
|
|
35412
36185
|
const intent = {
|
|
35413
36186
|
schemaVersion: UPDATE_INTENT_SCHEMA_VERSION,
|
|
@@ -35417,14 +36190,16 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
|
|
|
35417
36190
|
writePrivateJsonAtomic(intentPath(context.baseDir, context.machineId), intent);
|
|
35418
36191
|
const logFd = openUpdateLog(context.baseDir, context.machineId);
|
|
35419
36192
|
try {
|
|
35420
|
-
const child = (deps.spawnProcess ?? spawn2)(
|
|
35421
|
-
|
|
35422
|
-
|
|
35423
|
-
|
|
35424
|
-
|
|
35425
|
-
|
|
35426
|
-
|
|
35427
|
-
|
|
36193
|
+
const child = (deps.spawnProcess ?? spawn2)(npmLaunch.file, [
|
|
36194
|
+
...npmLaunch.prefixArgs,
|
|
36195
|
+
...fixedNpmArgs({
|
|
36196
|
+
packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
|
|
36197
|
+
command: "replace",
|
|
36198
|
+
machineId: context.machineId,
|
|
36199
|
+
baseDir: context.baseDir,
|
|
36200
|
+
requestId
|
|
36201
|
+
})
|
|
36202
|
+
], {
|
|
35428
36203
|
detached: true,
|
|
35429
36204
|
shell: false,
|
|
35430
36205
|
stdio: ["ignore", logFd, logFd]
|
|
@@ -35465,14 +36240,16 @@ function removeOldPidfileIfMatches(baseDir, intent) {
|
|
|
35465
36240
|
async function runPinnedResume(args) {
|
|
35466
36241
|
const fd = openUpdateLog(args.baseDir, args.machineId);
|
|
35467
36242
|
try {
|
|
35468
|
-
const child = spawn2(
|
|
35469
|
-
|
|
35470
|
-
|
|
35471
|
-
|
|
35472
|
-
|
|
35473
|
-
|
|
35474
|
-
|
|
35475
|
-
|
|
36243
|
+
const child = spawn2(args.npmLaunch.file, [
|
|
36244
|
+
...args.npmLaunch.prefixArgs,
|
|
36245
|
+
...fixedNpmArgs({
|
|
36246
|
+
packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
|
|
36247
|
+
command: "resume",
|
|
36248
|
+
machineId: args.machineId,
|
|
36249
|
+
baseDir: args.baseDir,
|
|
36250
|
+
requestId: args.requestId
|
|
36251
|
+
})
|
|
36252
|
+
], {
|
|
35476
36253
|
shell: false,
|
|
35477
36254
|
stdio: ["ignore", fd, fd]
|
|
35478
36255
|
});
|
|
@@ -35516,7 +36293,7 @@ async function daemonReplace(opts) {
|
|
|
35516
36293
|
removeIntentIfMatches(baseDir, opts.id, opts.requestId);
|
|
35517
36294
|
throw new Error("daemon ownership changed before replacement");
|
|
35518
36295
|
}
|
|
35519
|
-
const
|
|
36296
|
+
const npmLaunch = resolveNpmLaunchCommand();
|
|
35520
36297
|
const acquired = acquireDaemonReplacementLock({ baseDir, machineId: opts.id, requestId: opts.requestId });
|
|
35521
36298
|
let oldStopped = false;
|
|
35522
36299
|
try {
|
|
@@ -35536,7 +36313,7 @@ async function daemonReplace(opts) {
|
|
|
35536
36313
|
} catch (error51) {
|
|
35537
36314
|
appendUpdateLog(baseDir, opts.id, "replacement_start_failed", { error: error51 });
|
|
35538
36315
|
await runPinnedResume({
|
|
35539
|
-
|
|
36316
|
+
npmLaunch,
|
|
35540
36317
|
version: launch.daemonVersion,
|
|
35541
36318
|
machineId: opts.id,
|
|
35542
36319
|
baseDir,
|
|
@@ -35659,7 +36436,7 @@ async function buildRunnerDiagnosticBundle(args) {
|
|
|
35659
36436
|
function createDaemonProcessLogger(daemonDir, foreground) {
|
|
35660
36437
|
fs11.mkdirSync(daemonDir, { recursive: true, mode: 448 });
|
|
35661
36438
|
fs11.chmodSync(daemonDir, 448);
|
|
35662
|
-
const logPath =
|
|
36439
|
+
const logPath = path16.join(daemonDir, "daemon.log");
|
|
35663
36440
|
let warnedOversize = false;
|
|
35664
36441
|
const sink = createRotatingFileSink(logPath, DAEMON_LOG_MAX_BYTES, {
|
|
35665
36442
|
mode: 384,
|
|
@@ -35895,16 +36672,16 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
|
|
|
35895
36672
|
var DEFAULT_SERVER_URL = "https://alook.ai";
|
|
35896
36673
|
var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
|
|
35897
36674
|
function resolveDefaultBaseDir() {
|
|
35898
|
-
const root = process.env.ALOOK_PROJECT_ROOT ||
|
|
35899
|
-
return
|
|
36675
|
+
const root = process.env.ALOOK_PROJECT_ROOT || path17.join(homedir8(), ".alook");
|
|
36676
|
+
return path17.join(root, "daemon");
|
|
35900
36677
|
}
|
|
35901
36678
|
var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
|
|
35902
36679
|
var log2 = createLogger2({ header: "@alook/daemon" });
|
|
35903
36680
|
function daemonsDir(baseDir) {
|
|
35904
|
-
return
|
|
36681
|
+
return path17.join(baseDir, "daemons");
|
|
35905
36682
|
}
|
|
35906
36683
|
function daemonDirById(baseDir, id) {
|
|
35907
|
-
return
|
|
36684
|
+
return path17.join(daemonsDir(baseDir), validateDaemonId(id));
|
|
35908
36685
|
}
|
|
35909
36686
|
function validateMachineId(machineId) {
|
|
35910
36687
|
if (!MACHINE_ID_PATTERN.test(machineId))
|
|
@@ -35920,10 +36697,10 @@ function validateDaemonId(id) {
|
|
|
35920
36697
|
return id;
|
|
35921
36698
|
}
|
|
35922
36699
|
function pidfilePathById(baseDir, id) {
|
|
35923
|
-
return
|
|
36700
|
+
return path17.join(daemonDirById(baseDir, id), "daemon.pid");
|
|
35924
36701
|
}
|
|
35925
36702
|
function statusFilePathById(baseDir, id) {
|
|
35926
|
-
return
|
|
36703
|
+
return path17.join(daemonDirById(baseDir, id), "status.json");
|
|
35927
36704
|
}
|
|
35928
36705
|
function isProcessAlive(pid) {
|
|
35929
36706
|
try {
|
|
@@ -35983,9 +36760,9 @@ function syncDirectory(dir) {
|
|
|
35983
36760
|
}
|
|
35984
36761
|
}
|
|
35985
36762
|
function writeExclusive(filePath, value) {
|
|
35986
|
-
const dir =
|
|
36763
|
+
const dir = path17.dirname(filePath);
|
|
35987
36764
|
ensurePrivateDir2(dir);
|
|
35988
|
-
const tempPath =
|
|
36765
|
+
const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
|
|
35989
36766
|
let fd = fs12.openSync(tempPath, "wx", 384);
|
|
35990
36767
|
try {
|
|
35991
36768
|
fs12.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -36007,9 +36784,9 @@ function writeExclusive(filePath, value) {
|
|
|
36007
36784
|
}
|
|
36008
36785
|
}
|
|
36009
36786
|
function writePrivateJsonAtomic2(filePath, value) {
|
|
36010
|
-
const dir =
|
|
36787
|
+
const dir = path17.dirname(filePath);
|
|
36011
36788
|
ensurePrivateDir2(dir);
|
|
36012
|
-
const tempPath =
|
|
36789
|
+
const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
|
|
36013
36790
|
let fd = fs12.openSync(tempPath, "wx", 384);
|
|
36014
36791
|
try {
|
|
36015
36792
|
fs12.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -36033,8 +36810,8 @@ function writePrivateJsonAtomic2(filePath, value) {
|
|
|
36033
36810
|
function secureExistingFile(filePath) {
|
|
36034
36811
|
if (!fs12.existsSync(filePath))
|
|
36035
36812
|
return;
|
|
36036
|
-
const
|
|
36037
|
-
if (!
|
|
36813
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
36814
|
+
if (!stat2.isFile())
|
|
36038
36815
|
throw new Error("unsafe daemon ownership file type");
|
|
36039
36816
|
fs12.chmodSync(filePath, 384);
|
|
36040
36817
|
}
|
|
@@ -36096,14 +36873,14 @@ function clearStaleOwnership(filePath, liveError) {
|
|
|
36096
36873
|
} catch {}
|
|
36097
36874
|
}
|
|
36098
36875
|
function replacementLockPathById(baseDir, machineId) {
|
|
36099
|
-
return
|
|
36876
|
+
return path17.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
|
|
36100
36877
|
}
|
|
36101
36878
|
function readReplacementLock(filePath) {
|
|
36102
36879
|
if (!fs12.existsSync(filePath))
|
|
36103
36880
|
return null;
|
|
36104
36881
|
try {
|
|
36105
|
-
const
|
|
36106
|
-
if (!
|
|
36882
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
36883
|
+
if (!stat2.isFile())
|
|
36107
36884
|
throw new Error("unsafe daemon replacement lock type");
|
|
36108
36885
|
fs12.chmodSync(filePath, 384);
|
|
36109
36886
|
const content = JSON.parse(fs12.readFileSync(filePath, "utf8"));
|
|
@@ -36166,7 +36943,7 @@ function checkReplacementLock(baseDir, machineId, resumeRequestId) {
|
|
|
36166
36943
|
}
|
|
36167
36944
|
function acquireDaemonReplacementLock(args) {
|
|
36168
36945
|
const lockPath = replacementLockPathById(args.baseDir, args.machineId);
|
|
36169
|
-
ensurePrivateDir2(
|
|
36946
|
+
ensurePrivateDir2(path17.dirname(lockPath));
|
|
36170
36947
|
checkReplacementLock(args.baseDir, args.machineId);
|
|
36171
36948
|
const lock = {
|
|
36172
36949
|
pid: process.pid,
|
|
@@ -36179,11 +36956,11 @@ function acquireDaemonReplacementLock(args) {
|
|
|
36179
36956
|
return { path: lockPath, lock };
|
|
36180
36957
|
}
|
|
36181
36958
|
function coarseStartLockPath(baseDir) {
|
|
36182
|
-
return
|
|
36959
|
+
return path17.join(daemonsDir(baseDir), ".start.lock");
|
|
36183
36960
|
}
|
|
36184
36961
|
function acquireCoarseLock(baseDir, ownerToken) {
|
|
36185
36962
|
const lf = coarseStartLockPath(baseDir);
|
|
36186
|
-
ensurePrivateDir2(
|
|
36963
|
+
ensurePrivateDir2(path17.dirname(lf));
|
|
36187
36964
|
secureExistingFile(lf);
|
|
36188
36965
|
clearStaleOwnership(lf, (pid) => new Error(`another daemon start is in progress on this machine (pid ${pid})`));
|
|
36189
36966
|
writeExclusive(lf, { pid: process.pid, machineId: "coarse", startedAt: new Date().toISOString(), ownerToken });
|
|
@@ -36192,7 +36969,7 @@ function acquireCoarseLock(baseDir, ownerToken) {
|
|
|
36192
36969
|
function acquireLaunchLock(baseDir, machineId, ownerToken, resumeRequestId) {
|
|
36193
36970
|
const daemonDir = daemonDirById(baseDir, machineId);
|
|
36194
36971
|
ensurePrivateDir2(daemonDir);
|
|
36195
|
-
const lockPath =
|
|
36972
|
+
const lockPath = path17.join(daemonDir, "daemon.launch.lock");
|
|
36196
36973
|
const finalPath = pidfilePathById(baseDir, machineId);
|
|
36197
36974
|
checkReplacementLock(baseDir, machineId, resumeRequestId);
|
|
36198
36975
|
secureExistingFile(lockPath);
|
|
@@ -36214,9 +36991,9 @@ function legacyPidfileCandidates(baseDir) {
|
|
|
36214
36991
|
const candidates = [];
|
|
36215
36992
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36216
36993
|
if (entry.isDirectory()) {
|
|
36217
|
-
candidates.push(
|
|
36994
|
+
candidates.push(path17.join(dir, entry.name, "daemon.pid"));
|
|
36218
36995
|
} else if (entry.isFile() && entry.name.endsWith(".pid")) {
|
|
36219
|
-
candidates.push(
|
|
36996
|
+
candidates.push(path17.join(dir, entry.name));
|
|
36220
36997
|
}
|
|
36221
36998
|
}
|
|
36222
36999
|
return candidates;
|
|
@@ -36288,7 +37065,7 @@ function daemonList(opts) {
|
|
|
36288
37065
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36289
37066
|
if (entry.isDirectory() && isDaemonId(entry.name)) {
|
|
36290
37067
|
const id = entry.name;
|
|
36291
|
-
pushRow(id,
|
|
37068
|
+
pushRow(id, path17.join(dir, id, "daemon.pid"), path17.join(dir, id, "status.json"));
|
|
36292
37069
|
}
|
|
36293
37070
|
}
|
|
36294
37071
|
return results;
|
|
@@ -36336,7 +37113,7 @@ function daemonIdsWithStatus(baseDir) {
|
|
|
36336
37113
|
return [];
|
|
36337
37114
|
const ids = [];
|
|
36338
37115
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36339
|
-
if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(
|
|
37116
|
+
if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path17.join(dir, entry.name, "status.json"))) {
|
|
36340
37117
|
ids.push(entry.name);
|
|
36341
37118
|
}
|
|
36342
37119
|
}
|
|
@@ -36399,16 +37176,16 @@ async function stopByPidfile(pf, notFoundHint) {
|
|
|
36399
37176
|
}
|
|
36400
37177
|
async function daemonStop(opts) {
|
|
36401
37178
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
36402
|
-
await stopByPidfile(
|
|
37179
|
+
await stopByPidfile(path17.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
|
|
36403
37180
|
}
|
|
36404
37181
|
function credentialFilePathByMachineId(baseDir, machineId) {
|
|
36405
|
-
return
|
|
37182
|
+
return path17.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
|
|
36406
37183
|
}
|
|
36407
37184
|
function readCredentialFile(filePath) {
|
|
36408
37185
|
if (!fs12.existsSync(filePath))
|
|
36409
37186
|
return null;
|
|
36410
|
-
const
|
|
36411
|
-
if (!
|
|
37187
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
37188
|
+
if (!stat2.isFile())
|
|
36412
37189
|
throw new Error("unsafe daemon credential file type");
|
|
36413
37190
|
fs12.chmodSync(filePath, 384);
|
|
36414
37191
|
try {
|
|
@@ -36449,7 +37226,7 @@ function findExistingCredentialForBearer(baseDir, bearer) {
|
|
|
36449
37226
|
for (const file2 of fs12.readdirSync(dir)) {
|
|
36450
37227
|
if (!file2.endsWith(".credential.json"))
|
|
36451
37228
|
continue;
|
|
36452
|
-
const parsed = readCredentialFile(
|
|
37229
|
+
const parsed = readCredentialFile(path17.join(dir, file2));
|
|
36453
37230
|
if (parsed && parsed.credential === bearer)
|
|
36454
37231
|
return parsed;
|
|
36455
37232
|
}
|
|
@@ -36730,7 +37507,7 @@ function waitForReceipt(child, prepared) {
|
|
|
36730
37507
|
};
|
|
36731
37508
|
const configuredTestTimeout = NaN;
|
|
36732
37509
|
const receiptTimeoutMs = Number.isFinite(configuredTestTimeout) && configuredTestTimeout > 0 ? configuredTestTimeout : START_RECEIPT_TIMEOUT_MS;
|
|
36733
|
-
const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${
|
|
37510
|
+
const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path17.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
|
|
36734
37511
|
child.on("message", (message2) => {
|
|
36735
37512
|
const accepted = message2;
|
|
36736
37513
|
if (accepted.type === "daemon:accepted") {
|
|
@@ -36749,7 +37526,7 @@ function waitForReceipt(child, prepared) {
|
|
|
36749
37526
|
settle(undefined, receipt);
|
|
36750
37527
|
});
|
|
36751
37528
|
child.once("exit", (code, signal) => {
|
|
36752
|
-
settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${
|
|
37529
|
+
settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path17.join(prepared.daemonDir, "daemon.log")}`));
|
|
36753
37530
|
});
|
|
36754
37531
|
child.once("error", (error51) => settle(error51));
|
|
36755
37532
|
});
|