@basou/core 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +144 -14
- package/dist/index.js +237 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,10 +11,10 @@ async function resolveClaudeCodeCommand(lookup = isOnPath) {
|
|
|
11
11
|
throw new Error("Claude Code CLI not found in PATH. Install claude-code (or claude) first.");
|
|
12
12
|
}
|
|
13
13
|
async function isOnPath(command) {
|
|
14
|
-
return new Promise((
|
|
14
|
+
return new Promise((resolve3) => {
|
|
15
15
|
const child = spawn("which", [command], { stdio: "ignore" });
|
|
16
|
-
child.on("error", () =>
|
|
17
|
-
child.on("exit", (code) =>
|
|
16
|
+
child.on("error", () => resolve3(false));
|
|
17
|
+
child.on("exit", (code) => resolve3(code === 0));
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
function summarizeAdapterOutput(_stream, _raw) {
|
|
@@ -1372,7 +1372,8 @@ async function classifySuspect(paths, sessionId, session, now, onWarning) {
|
|
|
1372
1372
|
}
|
|
1373
1373
|
return { suspect: false, suspectReason: null };
|
|
1374
1374
|
}
|
|
1375
|
-
async function
|
|
1375
|
+
async function loadEntriesFromRoot(root, options) {
|
|
1376
|
+
const { paths } = root;
|
|
1376
1377
|
const sessionIds = await enumerateSessionDirs(paths);
|
|
1377
1378
|
const entries = [];
|
|
1378
1379
|
for (const sid of sessionIds) {
|
|
@@ -1402,10 +1403,50 @@ async function loadSessionEntries(paths, options) {
|
|
|
1402
1403
|
} catch {
|
|
1403
1404
|
options.onSkip?.(sid, "events_jsonl_unreadable");
|
|
1404
1405
|
}
|
|
1405
|
-
entries.push({
|
|
1406
|
+
entries.push({
|
|
1407
|
+
sessionId: sid,
|
|
1408
|
+
session,
|
|
1409
|
+
suspect,
|
|
1410
|
+
suspectReason,
|
|
1411
|
+
sourceRoot: paths,
|
|
1412
|
+
host: root.host
|
|
1413
|
+
});
|
|
1406
1414
|
}
|
|
1407
1415
|
return entries;
|
|
1408
1416
|
}
|
|
1417
|
+
async function loadSessionEntries(paths, options) {
|
|
1418
|
+
return loadEntriesFromRoot({ paths, host: null }, options);
|
|
1419
|
+
}
|
|
1420
|
+
async function loadFederatedSessionEntries(roots, options) {
|
|
1421
|
+
const out = [];
|
|
1422
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1423
|
+
const seenExternal = /* @__PURE__ */ new Set();
|
|
1424
|
+
for (const root of roots) {
|
|
1425
|
+
let entries;
|
|
1426
|
+
if (root.host === null) {
|
|
1427
|
+
entries = await loadEntriesFromRoot(root, options);
|
|
1428
|
+
} else {
|
|
1429
|
+
try {
|
|
1430
|
+
entries = await loadEntriesFromRoot(root, options);
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
options.onRootUnavailable?.(root.host, error);
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
for (const entry of entries) {
|
|
1437
|
+
if (seenIds.has(entry.sessionId)) continue;
|
|
1438
|
+
const ext = entry.session.session.source.external_id;
|
|
1439
|
+
if (typeof ext === "string" && ext.length > 0) {
|
|
1440
|
+
const extKey = `${entry.session.session.source.kind}:${ext}`;
|
|
1441
|
+
if (seenExternal.has(extKey)) continue;
|
|
1442
|
+
seenExternal.add(extKey);
|
|
1443
|
+
}
|
|
1444
|
+
seenIds.add(entry.sessionId);
|
|
1445
|
+
out.push(entry);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
return out;
|
|
1449
|
+
}
|
|
1409
1450
|
|
|
1410
1451
|
// src/decisions/decisions-renderer.ts
|
|
1411
1452
|
async function renderDecisions(input) {
|
|
@@ -4190,8 +4231,82 @@ async function resolveIdInternal(paths, input, kind, options = {}) {
|
|
|
4190
4231
|
return matches[0];
|
|
4191
4232
|
}
|
|
4192
4233
|
|
|
4234
|
+
// src/lib/source-root-scope.ts
|
|
4235
|
+
import { promises as fs } from "fs";
|
|
4236
|
+
import { homedir as osHomedir } from "os";
|
|
4237
|
+
import { basename as basename2, dirname as dirname3, isAbsolute, join as join14, normalize, relative, resolve as resolve2 } from "path";
|
|
4238
|
+
var AGENT_INFRA_DIRS = ["~/.claude", "~/.codex", "~/.basou"];
|
|
4239
|
+
async function realpathBestEffort(absPath) {
|
|
4240
|
+
let current = normalize(absPath);
|
|
4241
|
+
const tail = [];
|
|
4242
|
+
for (let guard = 0; guard < 4096; guard += 1) {
|
|
4243
|
+
try {
|
|
4244
|
+
const real = await fs.realpath(current);
|
|
4245
|
+
return tail.length > 0 ? join14(real, ...tail.reverse()) : real;
|
|
4246
|
+
} catch (error) {
|
|
4247
|
+
const code = error?.code;
|
|
4248
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
4249
|
+
return normalize(absPath);
|
|
4250
|
+
}
|
|
4251
|
+
const parent = dirname3(current);
|
|
4252
|
+
if (parent === current) return normalize(absPath);
|
|
4253
|
+
tail.push(basename2(current));
|
|
4254
|
+
current = parent;
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
return normalize(absPath);
|
|
4258
|
+
}
|
|
4259
|
+
function expandTilde(p, homedir4) {
|
|
4260
|
+
if (p === "~") return homedir4;
|
|
4261
|
+
if (p.startsWith("~/")) return join14(homedir4, p.slice(2));
|
|
4262
|
+
return p;
|
|
4263
|
+
}
|
|
4264
|
+
function toAbsolute(p, workingDirAbs, homedir4) {
|
|
4265
|
+
const expanded = expandTilde(p, homedir4);
|
|
4266
|
+
if (isAbsolute(expanded)) return normalize(expanded);
|
|
4267
|
+
return normalize(resolve2(workingDirAbs, expanded));
|
|
4268
|
+
}
|
|
4269
|
+
function isUnder(child, parent) {
|
|
4270
|
+
if (child === parent) return true;
|
|
4271
|
+
const rel = relative(parent, child);
|
|
4272
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
4273
|
+
}
|
|
4274
|
+
async function classifyFilesBySourceRoot(input) {
|
|
4275
|
+
const inRoot = [];
|
|
4276
|
+
const outOfRoot = [];
|
|
4277
|
+
if (input.files.length === 0) return { inRoot, outOfRoot };
|
|
4278
|
+
const homedir4 = input.homedir ?? osHomedir();
|
|
4279
|
+
const workingDirAbs = toAbsolute(input.workingDirectory, homedir4, homedir4);
|
|
4280
|
+
const declared = input.sourceRoots && input.sourceRoots.length > 0 ? [...input.sourceRoots] : ["."];
|
|
4281
|
+
const rootsAbs = [];
|
|
4282
|
+
for (const r of declared) {
|
|
4283
|
+
const expanded = expandTilde(r, homedir4);
|
|
4284
|
+
const abs = isAbsolute(expanded) ? normalize(expanded) : normalize(resolve2(input.masterRoot, expanded));
|
|
4285
|
+
rootsAbs.push(await realpathBestEffort(abs));
|
|
4286
|
+
}
|
|
4287
|
+
for (const e of input.extraInRoot ?? []) {
|
|
4288
|
+
const expanded = expandTilde(e, homedir4);
|
|
4289
|
+
const abs = isAbsolute(expanded) ? normalize(expanded) : normalize(resolve2(homedir4, expanded));
|
|
4290
|
+
rootsAbs.push(await realpathBestEffort(abs));
|
|
4291
|
+
}
|
|
4292
|
+
if (rootsAbs.length === 0) {
|
|
4293
|
+
return { inRoot: [...input.files], outOfRoot };
|
|
4294
|
+
}
|
|
4295
|
+
for (const file of input.files) {
|
|
4296
|
+
try {
|
|
4297
|
+
const abs = toAbsolute(file, workingDirAbs, homedir4);
|
|
4298
|
+
const real = await realpathBestEffort(abs);
|
|
4299
|
+
const within = rootsAbs.some((root) => isUnder(real, root));
|
|
4300
|
+
(within ? inRoot : outOfRoot).push(file);
|
|
4301
|
+
} catch {
|
|
4302
|
+
inRoot.push(file);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
return { inRoot, outOfRoot };
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4193
4308
|
// src/orientation/orientation-renderer.ts
|
|
4194
|
-
import { join as
|
|
4309
|
+
import { dirname as dirname4, join as join15 } from "path";
|
|
4195
4310
|
|
|
4196
4311
|
// src/storage/manifest.ts
|
|
4197
4312
|
import { lstat as lstat3 } from "fs/promises";
|
|
@@ -4344,7 +4459,13 @@ async function summarizeOrientation(input) {
|
|
|
4344
4459
|
const loadOpts = { now };
|
|
4345
4460
|
if (input.onSessionSkip !== void 0) loadOpts.onSkip = input.onSessionSkip;
|
|
4346
4461
|
if (input.onWarning !== void 0) loadOpts.onWarning = input.onWarning;
|
|
4347
|
-
const entries =
|
|
4462
|
+
const entries = input.federatedRoots !== void 0 && input.federatedRoots.length > 0 ? await loadFederatedSessionEntries(
|
|
4463
|
+
[{ paths: input.paths, host: null }, ...input.federatedRoots],
|
|
4464
|
+
{
|
|
4465
|
+
...loadOpts,
|
|
4466
|
+
...input.onHostUnavailable !== void 0 ? { onRootUnavailable: input.onHostUnavailable } : {}
|
|
4467
|
+
}
|
|
4468
|
+
) : await loadSessionEntries(input.paths, loadOpts);
|
|
4348
4469
|
const decisions = [];
|
|
4349
4470
|
let latestActivityAt = null;
|
|
4350
4471
|
let latestNote = null;
|
|
@@ -4354,7 +4475,7 @@ async function summarizeOrientation(input) {
|
|
|
4354
4475
|
}
|
|
4355
4476
|
};
|
|
4356
4477
|
for (const entry of entries) {
|
|
4357
|
-
const sessionDir =
|
|
4478
|
+
const sessionDir = join15(entry.sourceRoot.sessions, entry.sessionId);
|
|
4358
4479
|
const counted = entry.session.session.status !== "archived";
|
|
4359
4480
|
if (counted) noteActivity(entry.session.session.ended_at ?? entry.session.session.started_at);
|
|
4360
4481
|
try {
|
|
@@ -4366,12 +4487,18 @@ async function summarizeOrientation(input) {
|
|
|
4366
4487
|
decisionId: ev.decision_id,
|
|
4367
4488
|
title: ev.title,
|
|
4368
4489
|
occurredAt: ev.occurred_at,
|
|
4369
|
-
sessionId: entry.sessionId
|
|
4490
|
+
sessionId: entry.sessionId,
|
|
4491
|
+
host: entry.host
|
|
4370
4492
|
});
|
|
4371
4493
|
}
|
|
4372
4494
|
if (counted && ev.type === "note_added" && ev.kind === "next_step") {
|
|
4373
4495
|
if (latestNote === null || Date.parse(ev.occurred_at) > Date.parse(latestNote.occurredAt)) {
|
|
4374
|
-
latestNote = {
|
|
4496
|
+
latestNote = {
|
|
4497
|
+
body: ev.body,
|
|
4498
|
+
sessionId: entry.sessionId,
|
|
4499
|
+
occurredAt: ev.occurred_at,
|
|
4500
|
+
host: entry.host
|
|
4501
|
+
};
|
|
4375
4502
|
}
|
|
4376
4503
|
}
|
|
4377
4504
|
if (counted) noteActivity(ev.occurred_at);
|
|
@@ -4414,7 +4541,8 @@ async function summarizeOrientation(input) {
|
|
|
4414
4541
|
const suspects = entries.filter((e) => e.suspect).map((e) => ({
|
|
4415
4542
|
sessionId: e.sessionId,
|
|
4416
4543
|
status: e.session.session.status,
|
|
4417
|
-
reason: e.suspectReason
|
|
4544
|
+
reason: e.suspectReason,
|
|
4545
|
+
host: e.host
|
|
4418
4546
|
}));
|
|
4419
4547
|
const liveEntries = entries.filter(
|
|
4420
4548
|
(e) => e.session.session.status !== "archived" && e.session.session.source.kind !== "import"
|
|
@@ -4423,7 +4551,8 @@ async function summarizeOrientation(input) {
|
|
|
4423
4551
|
const latestSession = latestEntry !== void 0 ? {
|
|
4424
4552
|
sessionId: latestEntry.sessionId,
|
|
4425
4553
|
label: latestEntry.session.session.label ?? null,
|
|
4426
|
-
status: latestEntry.session.session.status
|
|
4554
|
+
status: latestEntry.session.session.status,
|
|
4555
|
+
host: latestEntry.host
|
|
4427
4556
|
} : null;
|
|
4428
4557
|
const activityEntries = entries.filter((e) => e.session.session.status !== "archived");
|
|
4429
4558
|
const newest = [...activityEntries].sort(
|
|
@@ -4444,8 +4573,27 @@ async function summarizeOrientation(input) {
|
|
|
4444
4573
|
}
|
|
4445
4574
|
const latestFiles = latestEntry?.session.session.related_files ?? [];
|
|
4446
4575
|
const uniqueFiles = new Set(latestFiles);
|
|
4447
|
-
const
|
|
4576
|
+
const sortedFiles = [...uniqueFiles].sort();
|
|
4577
|
+
const displayed = sortedFiles.slice(0, limit);
|
|
4448
4578
|
const overflow = Math.max(0, uniqueFiles.size - limit);
|
|
4579
|
+
let outOfRoot = [];
|
|
4580
|
+
if (latestEntry !== void 0 && latestEntry.host === null && sortedFiles.length > 0 && sourceRoots !== null && sourceRoots.length > 0) {
|
|
4581
|
+
try {
|
|
4582
|
+
const scope = await classifyFilesBySourceRoot({
|
|
4583
|
+
files: sortedFiles,
|
|
4584
|
+
workingDirectory: latestEntry.session.session.working_directory,
|
|
4585
|
+
sourceRoots,
|
|
4586
|
+
masterRoot: dirname4(input.paths.root),
|
|
4587
|
+
extraInRoot: AGENT_INFRA_DIRS
|
|
4588
|
+
});
|
|
4589
|
+
outOfRoot = scope.outOfRoot;
|
|
4590
|
+
} catch {
|
|
4591
|
+
outOfRoot = [];
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
const hosts = [
|
|
4595
|
+
...new Set(entries.map((e) => e.host).filter((h) => h !== null))
|
|
4596
|
+
].sort();
|
|
4449
4597
|
return {
|
|
4450
4598
|
generatedAt: input.nowIso,
|
|
4451
4599
|
sessionCount: entries.length,
|
|
@@ -4453,11 +4601,12 @@ async function summarizeOrientation(input) {
|
|
|
4453
4601
|
latestDecision: latestDecision ?? null,
|
|
4454
4602
|
decisionCount: decisions.length,
|
|
4455
4603
|
latestNote,
|
|
4456
|
-
relatedFiles: { displayed, overflow },
|
|
4604
|
+
relatedFiles: { displayed, overflow, outOfRoot },
|
|
4457
4605
|
inFlightTasks,
|
|
4458
4606
|
plannedTasks,
|
|
4459
4607
|
pendingApprovals,
|
|
4460
4608
|
suspects,
|
|
4609
|
+
hosts,
|
|
4461
4610
|
freshness: {
|
|
4462
4611
|
newestStartedAt: newest?.session.session.started_at ?? null,
|
|
4463
4612
|
newestSource: newest?.session.session.source.kind ?? null,
|
|
@@ -4485,11 +4634,15 @@ function formatOrientationBody(summary, opts) {
|
|
|
4485
4634
|
const lines = [];
|
|
4486
4635
|
const now = new Date(summary.generatedAt);
|
|
4487
4636
|
const newestRel = relativeAge(summary.freshness.newestStartedAt ?? void 0, now);
|
|
4637
|
+
const hostSuffix = (h) => h !== null ? ` @${h}` : "";
|
|
4488
4638
|
lines.push("# Orientation");
|
|
4489
4639
|
lines.push("");
|
|
4490
4640
|
lines.push(
|
|
4491
4641
|
`> Generated at ${summary.generatedAt} \xB7 sessions ${summary.sessionCount} \xB7 newest ${newestRel} \xB7 pending ${summary.pendingApprovals.length} \xB7 suspect ${summary.suspects.length}`
|
|
4492
4642
|
);
|
|
4643
|
+
if (summary.hosts.length > 0) {
|
|
4644
|
+
lines.push(`> hosts: local, ${summary.hosts.join(", ")}`);
|
|
4645
|
+
}
|
|
4493
4646
|
lines.push("");
|
|
4494
4647
|
lines.push("## \u4ECA\u3069\u3053\u306B\u3044\u308B");
|
|
4495
4648
|
lines.push("");
|
|
@@ -4497,9 +4650,9 @@ function formatOrientationBody(summary, opts) {
|
|
|
4497
4650
|
const s = summary.latestSession;
|
|
4498
4651
|
const sid = shortId(s.sessionId);
|
|
4499
4652
|
if (s.label !== null && s.label !== "") {
|
|
4500
|
-
lines.push(`- \u6700\u7D42 session: ${s.label} (${s.status}) [${sid}]`);
|
|
4653
|
+
lines.push(`- \u6700\u7D42 session: ${s.label} (${s.status}) [${sid}]${hostSuffix(s.host)}`);
|
|
4501
4654
|
} else {
|
|
4502
|
-
lines.push(`- \u6700\u7D42 session: ${sid} (${s.status})`);
|
|
4655
|
+
lines.push(`- \u6700\u7D42 session: ${sid} (${s.status})${hostSuffix(s.host)}`);
|
|
4503
4656
|
}
|
|
4504
4657
|
} else {
|
|
4505
4658
|
lines.push("- \u6700\u7D42 session: (no live sessions)");
|
|
@@ -4507,7 +4660,9 @@ function formatOrientationBody(summary, opts) {
|
|
|
4507
4660
|
if (summary.latestDecision !== null) {
|
|
4508
4661
|
const dec = summary.latestDecision;
|
|
4509
4662
|
const decAge = relativeAgeJa(dec.occurredAt, now);
|
|
4510
|
-
lines.push(
|
|
4663
|
+
lines.push(
|
|
4664
|
+
`- \u76F4\u8FD1\u306E\u5224\u65AD: ${dec.title} [${shortId(dec.decisionId)}] (${decAge})${hostSuffix(dec.host)}`
|
|
4665
|
+
);
|
|
4511
4666
|
const activityAt = summary.freshness.latestActivityAt;
|
|
4512
4667
|
if (activityAt !== null && isTrailingStale(activityAt, dec.occurredAt)) {
|
|
4513
4668
|
lines.push(
|
|
@@ -4529,6 +4684,15 @@ function formatOrientationBody(summary, opts) {
|
|
|
4529
4684
|
const shown = summary.relatedFiles.displayed.join(", ");
|
|
4530
4685
|
const more = summary.relatedFiles.overflow > 0 ? ` (... +${summary.relatedFiles.overflow} more)` : "";
|
|
4531
4686
|
lines.push(`- \u76F4\u8FD1\u306E\u5909\u66F4\u30D5\u30A1\u30A4\u30EB: ${shown}${more}`);
|
|
4687
|
+
if (summary.relatedFiles.outOfRoot.length > 0) {
|
|
4688
|
+
const OUT_OF_ROOT_DISPLAY = 10;
|
|
4689
|
+
const out = summary.relatedFiles.outOfRoot;
|
|
4690
|
+
const shownOut = out.slice(0, OUT_OF_ROOT_DISPLAY).join(", ");
|
|
4691
|
+
const outMore = out.length > OUT_OF_ROOT_DISPLAY ? ` (... +${out.length - OUT_OF_ROOT_DISPLAY} more)` : "";
|
|
4692
|
+
lines.push(
|
|
4693
|
+
` - \u26A0 source_roots \u5916 ${out.length} \u4EF6 (\u5225\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u53EF\u80FD\u6027): ${shownOut}${outMore}`
|
|
4694
|
+
);
|
|
4695
|
+
}
|
|
4532
4696
|
} else {
|
|
4533
4697
|
lines.push("- \u76F4\u8FD1\u306E\u5909\u66F4\u30D5\u30A1\u30A4\u30EB: (none recorded)");
|
|
4534
4698
|
}
|
|
@@ -4562,7 +4726,9 @@ function formatOrientationBody(summary, opts) {
|
|
|
4562
4726
|
lines.push("- (none)");
|
|
4563
4727
|
} else {
|
|
4564
4728
|
for (const e of summary.suspects) {
|
|
4565
|
-
lines.push(
|
|
4729
|
+
lines.push(
|
|
4730
|
+
`- ${shortId(e.sessionId)} (${e.status}) \u2014 ${suspectText(e.reason)}${hostSuffix(e.host)}`
|
|
4731
|
+
);
|
|
4566
4732
|
}
|
|
4567
4733
|
}
|
|
4568
4734
|
lines.push("");
|
|
@@ -4571,7 +4737,7 @@ function formatOrientationBody(summary, opts) {
|
|
|
4571
4737
|
if (summary.latestNote !== null) {
|
|
4572
4738
|
const noteAge = relativeAgeJa(summary.latestNote.occurredAt, now);
|
|
4573
4739
|
lines.push(
|
|
4574
|
-
`- \u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${noteAge}): ${noteSummary(summary.latestNote.body)} [session ${shortId(summary.latestNote.sessionId)}]`
|
|
4740
|
+
`- \u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${noteAge}): ${noteSummary(summary.latestNote.body)} [session ${shortId(summary.latestNote.sessionId)}]${hostSuffix(summary.latestNote.host)}`
|
|
4575
4741
|
);
|
|
4576
4742
|
const activityAt = summary.freshness.latestActivityAt;
|
|
4577
4743
|
if (activityAt !== null && isTrailingStale(activityAt, summary.latestNote.occurredAt)) {
|
|
@@ -4601,6 +4767,12 @@ function formatOrientationBody(summary, opts) {
|
|
|
4601
4767
|
lines.push("## \u3053\u308C\u306F\u6700\u65B0\u304B");
|
|
4602
4768
|
lines.push("");
|
|
4603
4769
|
for (const line of freshnessVerdict(summary, opts.staleness, now)) lines.push(line);
|
|
4770
|
+
if (summary.hosts.length > 0) {
|
|
4771
|
+
lines.push("");
|
|
4772
|
+
lines.push(
|
|
4773
|
+
"\u6CE8: \u9BAE\u5EA6\u5224\u5B9A\u306F\u3053\u306E\u30DE\u30B7\u30F3\u306E\u30ED\u30FC\u30AB\u30EB\u30B9\u30C8\u30A2\u306E\u307F\u304C\u5BFE\u8C61\u3067\u3059\u3002\u4ED6\u30DB\u30B9\u30C8\u306E\u53D6\u308A\u3053\u307C\u3057\u306F\u5224\u5B9A\u3067\u304D\u307E\u305B\u3093(\u5404\u30DB\u30B9\u30C8\u3067 basou refresh \u3092\u5B9F\u884C\u3057\u540C\u671F\u3057\u3066\u304F\u3060\u3055\u3044)\u3002"
|
|
4774
|
+
);
|
|
4775
|
+
}
|
|
4604
4776
|
if (opts.verbose) {
|
|
4605
4777
|
lines.push("");
|
|
4606
4778
|
lines.push("<!-- verbose: raw freshness telemetry -->");
|
|
@@ -4677,8 +4849,9 @@ function freshnessVerdict(summary, staleness, now) {
|
|
|
4677
4849
|
"\u6700\u65B0\u304B\u78BA\u8A8D\u3059\u308B\u306B\u306F `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
4678
4850
|
];
|
|
4679
4851
|
}
|
|
4852
|
+
const localScope = summary.hosts.length > 0 ? "\u3053\u306E\u30DB\u30B9\u30C8(\u30ED\u30FC\u30AB\u30EB)\u306E" : "";
|
|
4680
4853
|
const lines = [
|
|
4681
|
-
`\u2705 \u53D6\u308A\u8FBC\u307F\u306F\u6700\u65B0\u3067\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002\u672A\u53D6\u308A\u8FBC\u307F\u306E native \u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u3042\u308A\u307E\u305B\u3093\u3002`
|
|
4854
|
+
`\u2705 ${localScope}\u53D6\u308A\u8FBC\u307F\u306F\u6700\u65B0\u3067\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002\u672A\u53D6\u308A\u8FBC\u307F\u306E native \u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u3042\u308A\u307E\u305B\u3093\u3002`
|
|
4682
4855
|
];
|
|
4683
4856
|
if (suspectCount > 0) {
|
|
4684
4857
|
lines.push(`\u305F\u3060\u3057\u8981\u6CE8\u610F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${suspectCount} \u4EF6\u3042\u308A\u307E\u3059(\u4E0A\u8A18\u300C\u8981\u6CE8\u610F session\u300D\u53C2\u7167)\u3002`);
|
|
@@ -5301,10 +5474,10 @@ function planWorkspaceView(facts, existing = [], rosterNames = []) {
|
|
|
5301
5474
|
}
|
|
5302
5475
|
|
|
5303
5476
|
// src/report/report-renderer.ts
|
|
5304
|
-
import { join as
|
|
5477
|
+
import { join as join17 } from "path";
|
|
5305
5478
|
|
|
5306
5479
|
// src/stats/work-stats.ts
|
|
5307
|
-
import { join as
|
|
5480
|
+
import { join as join16 } from "path";
|
|
5308
5481
|
function resolveTimeZone(timeZone) {
|
|
5309
5482
|
if (timeZone !== void 0 && timeZone.length > 0) return timeZone;
|
|
5310
5483
|
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -5335,7 +5508,7 @@ async function computeWorkStats(input) {
|
|
|
5335
5508
|
const events = [];
|
|
5336
5509
|
let eventsUnreadable = false;
|
|
5337
5510
|
try {
|
|
5338
|
-
for await (const ev of replayEvents(
|
|
5511
|
+
for await (const ev of replayEvents(join16(input.paths.sessions, entry.sessionId), {
|
|
5339
5512
|
onWarning: (w) => input.onWarning?.(w, entry.sessionId)
|
|
5340
5513
|
})) {
|
|
5341
5514
|
events.push(ev);
|
|
@@ -5622,7 +5795,7 @@ async function renderReport(input) {
|
|
|
5622
5795
|
const statsBySession = new Map(stats.sessions.map((s) => [s.sessionId, s]));
|
|
5623
5796
|
const decisions = [];
|
|
5624
5797
|
for (const entry of entries) {
|
|
5625
|
-
const sessionDir =
|
|
5798
|
+
const sessionDir = join17(input.paths.sessions, entry.sessionId);
|
|
5626
5799
|
try {
|
|
5627
5800
|
for await (const ev of replayEvents(sessionDir, {
|
|
5628
5801
|
onWarning: (w) => input.onWarning?.(w, entry.sessionId)
|
|
@@ -5903,7 +6076,7 @@ function formatInt(n) {
|
|
|
5903
6076
|
// src/review/review-gaps.ts
|
|
5904
6077
|
import { existsSync, realpathSync } from "fs";
|
|
5905
6078
|
import { homedir as homedir2 } from "os";
|
|
5906
|
-
import { basename as
|
|
6079
|
+
import { basename as basename3, isAbsolute as isAbsolute2, join as join18 } from "path";
|
|
5907
6080
|
function stripQuotes(s) {
|
|
5908
6081
|
if (s.length >= 2 && (s[0] === '"' && s.at(-1) === '"' || s[0] === "'" && s.at(-1) === "'")) {
|
|
5909
6082
|
return s.slice(1, -1);
|
|
@@ -5927,7 +6100,7 @@ var repoRootCache = /* @__PURE__ */ new Map();
|
|
|
5927
6100
|
function isRepoRoot(realPath) {
|
|
5928
6101
|
const cached = repoRootCache.get(realPath);
|
|
5929
6102
|
if (cached !== void 0) return cached;
|
|
5930
|
-
const result = existsSync(
|
|
6103
|
+
const result = existsSync(join18(realPath, ".git"));
|
|
5931
6104
|
repoRootCache.set(realPath, result);
|
|
5932
6105
|
return result;
|
|
5933
6106
|
}
|
|
@@ -5936,7 +6109,7 @@ function normalizeRepoPath(p) {
|
|
|
5936
6109
|
let s = stripQuotes(p.trim()).replace(/\/+$/, "");
|
|
5937
6110
|
if (s.length === 0 || s === "~") return null;
|
|
5938
6111
|
if (s.startsWith("~/")) s = homedir2() + s.slice(1);
|
|
5939
|
-
if (
|
|
6112
|
+
if (isAbsolute2(s)) {
|
|
5940
6113
|
const real = resolveRealpath(s);
|
|
5941
6114
|
if (real !== null) {
|
|
5942
6115
|
return isRepoRoot(real) ? real : null;
|
|
@@ -5950,7 +6123,7 @@ function normalizeRepoPath(p) {
|
|
|
5950
6123
|
}
|
|
5951
6124
|
function normalizeRepoKey(p) {
|
|
5952
6125
|
const full = normalizeRepoPath(p);
|
|
5953
|
-
return full === null ? null :
|
|
6126
|
+
return full === null ? null : basename3(full);
|
|
5954
6127
|
}
|
|
5955
6128
|
function inspectCommand(args) {
|
|
5956
6129
|
const a = args.join(" ");
|
|
@@ -5964,7 +6137,7 @@ function inspectCommand(args) {
|
|
|
5964
6137
|
let m;
|
|
5965
6138
|
while ((m = re.exec(a)) !== null) {
|
|
5966
6139
|
const f = m[1];
|
|
5967
|
-
if (f !== void 0) files.add(
|
|
6140
|
+
if (f !== void 0) files.add(basename3(f));
|
|
5968
6141
|
}
|
|
5969
6142
|
}
|
|
5970
6143
|
return { files: [...files], examinedDiff };
|
|
@@ -5981,7 +6154,7 @@ function commitFiles(args) {
|
|
|
5981
6154
|
const a = args.join(" ");
|
|
5982
6155
|
const add = a.match(/git add\s+([^&|;]+)/);
|
|
5983
6156
|
if (!add?.[1]) return [];
|
|
5984
|
-
return add[1].split(/\s+/).filter((t) => /\.[A-Za-z]/.test(t) && !t.startsWith("-")).map((t) =>
|
|
6157
|
+
return add[1].split(/\s+/).filter((t) => /\.[A-Za-z]/.test(t) && !t.startsWith("-")).map((t) => basename3(t));
|
|
5985
6158
|
}
|
|
5986
6159
|
var REVIEW_SOURCE = "codex-import";
|
|
5987
6160
|
var DEFAULT_WINDOW_HOURS = 24;
|
|
@@ -5997,7 +6170,7 @@ async function findReviewGaps(input) {
|
|
|
5997
6170
|
const workUnits = /* @__PURE__ */ new Map();
|
|
5998
6171
|
const unknownCommits = /* @__PURE__ */ new Map();
|
|
5999
6172
|
for (const entry of entries) {
|
|
6000
|
-
const sessionDir =
|
|
6173
|
+
const sessionDir = join18(input.paths.sessions, entry.sessionId);
|
|
6001
6174
|
const isReview = entry.session.session.source.kind === REVIEW_SOURCE;
|
|
6002
6175
|
const reviewRepos = /* @__PURE__ */ new Map();
|
|
6003
6176
|
let reviewEnd = null;
|
|
@@ -6046,7 +6219,7 @@ async function findReviewGaps(input) {
|
|
|
6046
6219
|
let newestCommit = null;
|
|
6047
6220
|
for (const [sessionId, byRepo] of workUnits) {
|
|
6048
6221
|
for (const [repoPath, commits] of byRepo) {
|
|
6049
|
-
const label =
|
|
6222
|
+
const label = basename3(repoPath);
|
|
6050
6223
|
if (scope !== null && !scope.includes(label)) continue;
|
|
6051
6224
|
const times = commits.map((c) => c.at).sort((a, b) => a - b);
|
|
6052
6225
|
const first = times[0] ?? null;
|
|
@@ -6205,7 +6378,7 @@ var ChildProcessRunner = class {
|
|
|
6205
6378
|
if (killTimer !== null) clearTimeout(killTimer);
|
|
6206
6379
|
options.signal?.removeEventListener("abort", onAbort);
|
|
6207
6380
|
};
|
|
6208
|
-
return new Promise((
|
|
6381
|
+
return new Promise((resolve3, reject) => {
|
|
6209
6382
|
child.once("error", (error) => {
|
|
6210
6383
|
if (settled) return;
|
|
6211
6384
|
settled = true;
|
|
@@ -6217,7 +6390,7 @@ var ChildProcessRunner = class {
|
|
|
6217
6390
|
settled = true;
|
|
6218
6391
|
cleanup();
|
|
6219
6392
|
const ended_at = /* @__PURE__ */ new Date();
|
|
6220
|
-
|
|
6393
|
+
resolve3({
|
|
6221
6394
|
command: snapshotCommand,
|
|
6222
6395
|
args: snapshotArgs,
|
|
6223
6396
|
cwd: snapshotCwd,
|
|
@@ -6372,28 +6545,28 @@ function serializeJsonSchema(schema) {
|
|
|
6372
6545
|
|
|
6373
6546
|
// src/storage/basou-dir.ts
|
|
6374
6547
|
import { lstat as lstat4, mkdir as mkdir4 } from "fs/promises";
|
|
6375
|
-
import { join as
|
|
6548
|
+
import { join as join19 } from "path";
|
|
6376
6549
|
function basouPaths(repositoryRoot) {
|
|
6377
|
-
const root =
|
|
6378
|
-
const approvalsBase =
|
|
6550
|
+
const root = join19(repositoryRoot, ".basou");
|
|
6551
|
+
const approvalsBase = join19(root, "approvals");
|
|
6379
6552
|
return {
|
|
6380
6553
|
root,
|
|
6381
|
-
sessions:
|
|
6382
|
-
tasks:
|
|
6554
|
+
sessions: join19(root, "sessions"),
|
|
6555
|
+
tasks: join19(root, "tasks"),
|
|
6383
6556
|
approvals: {
|
|
6384
|
-
pending:
|
|
6385
|
-
resolved:
|
|
6557
|
+
pending: join19(approvalsBase, "pending"),
|
|
6558
|
+
resolved: join19(approvalsBase, "resolved")
|
|
6386
6559
|
},
|
|
6387
|
-
locks:
|
|
6388
|
-
logs:
|
|
6389
|
-
raw:
|
|
6390
|
-
tmp:
|
|
6560
|
+
locks: join19(root, "locks"),
|
|
6561
|
+
logs: join19(root, "logs"),
|
|
6562
|
+
raw: join19(root, "raw"),
|
|
6563
|
+
tmp: join19(root, "tmp"),
|
|
6391
6564
|
files: {
|
|
6392
|
-
manifest:
|
|
6393
|
-
status:
|
|
6394
|
-
handoff:
|
|
6395
|
-
decisions:
|
|
6396
|
-
orientation:
|
|
6565
|
+
manifest: join19(root, "manifest.yaml"),
|
|
6566
|
+
status: join19(root, "status.json"),
|
|
6567
|
+
handoff: join19(root, "handoff.md"),
|
|
6568
|
+
decisions: join19(root, "decisions.md"),
|
|
6569
|
+
orientation: join19(root, "orientation.md")
|
|
6397
6570
|
}
|
|
6398
6571
|
};
|
|
6399
6572
|
}
|
|
@@ -6450,12 +6623,12 @@ function hasErrorCode4(error) {
|
|
|
6450
6623
|
|
|
6451
6624
|
// src/storage/gitignore.ts
|
|
6452
6625
|
import { readFile as readFile8, writeFile as writeFile2 } from "fs/promises";
|
|
6453
|
-
import { join as
|
|
6626
|
+
import { join as join20 } from "path";
|
|
6454
6627
|
var MARKER = "# Basou - default ignore";
|
|
6455
6628
|
var BASOU_GITIGNORE_BLOCK = "# Basou - default ignore\n.basou/logs/\n.basou/raw/\n.basou/tmp/\n.basou/locks/\n.basou/status.json\n.basou/orientation.md\n.basou/sessions/*/events.jsonl\n.basou/sessions/*/artifacts/\n.basou/approvals/pending/\n.basou/approvals/resolved/\n\n# Basou - default commit\n# .basou/manifest.yaml\n# .basou/handoff.md\n# .basou/decisions.md\n# .basou/tasks/\n# .basou/sessions/*/session.yaml\n# .basou/sessions/*/transcript.md\n# .basou/sessions/*/changed-files.json\n";
|
|
6456
6629
|
var BASOU_GITIGNORE_BLOCK_LOCAL_ONLY = "# Basou - default ignore\n# Local-only: basou's trail is never committed (personal/local state,\n# regenerable by re-importing from the agents' own logs). Recommended for\n# monitored repos and any workspace kept out of version control.\n.basou/\n";
|
|
6457
6630
|
async function appendBasouGitignore(repositoryRoot, options = {}) {
|
|
6458
|
-
const gitignorePath =
|
|
6631
|
+
const gitignorePath = join20(repositoryRoot, ".gitignore");
|
|
6459
6632
|
let body;
|
|
6460
6633
|
let existed;
|
|
6461
6634
|
try {
|
|
@@ -6628,7 +6801,7 @@ function hasErrorCode6(error) {
|
|
|
6628
6801
|
// src/storage/session-import.ts
|
|
6629
6802
|
import { mkdir as mkdir5, readFile as readFile10, rm as rm2 } from "fs/promises";
|
|
6630
6803
|
import { homedir as homedir3 } from "os";
|
|
6631
|
-
import { join as
|
|
6804
|
+
import { join as join21 } from "path";
|
|
6632
6805
|
async function importSessionFromJson(paths, manifest, payload, options) {
|
|
6633
6806
|
if (options.taskIdOverride !== void 0 && !TaskIdSchema.safeParse(options.taskIdOverride).success) {
|
|
6634
6807
|
throw new Error(`Invalid task_id: ${options.taskIdOverride}`);
|
|
@@ -6653,7 +6826,7 @@ async function importSessionFromJson(paths, manifest, payload, options) {
|
|
|
6653
6826
|
pathSanitizeReport
|
|
6654
6827
|
};
|
|
6655
6828
|
}
|
|
6656
|
-
const sessionDir =
|
|
6829
|
+
const sessionDir = join21(paths.sessions, newSessionId);
|
|
6657
6830
|
try {
|
|
6658
6831
|
await mkdir5(sessionDir, { recursive: true });
|
|
6659
6832
|
} catch (error) {
|
|
@@ -6667,7 +6840,7 @@ async function importSessionFromJson(paths, manifest, payload, options) {
|
|
|
6667
6840
|
throw error;
|
|
6668
6841
|
}
|
|
6669
6842
|
try {
|
|
6670
|
-
const sessionYamlPath =
|
|
6843
|
+
const sessionYamlPath = join21(sessionDir, "session.yaml");
|
|
6671
6844
|
await linkYamlFile(sessionYamlPath, withIntegrity(sessionRecord, chainResult));
|
|
6672
6845
|
} catch (error) {
|
|
6673
6846
|
await rm2(sessionDir, { recursive: true, force: true }).catch(() => void 0);
|
|
@@ -6835,7 +7008,7 @@ function reuseDerivedIds(priorDerived, freshDerived, sessionId) {
|
|
|
6835
7008
|
async function reimportPreservingId(paths, manifest, priorSessionId, freshPayload, options = {}) {
|
|
6836
7009
|
const sessionId = priorSessionId;
|
|
6837
7010
|
const importSource = freshPayload.session.source.kind;
|
|
6838
|
-
const sessionDir =
|
|
7011
|
+
const sessionDir = join21(paths.sessions, priorSessionId);
|
|
6839
7012
|
const lock = options.dryRun === true ? null : await acquireLock(paths, "session", priorSessionId);
|
|
6840
7013
|
try {
|
|
6841
7014
|
const priorVerdict = await verifyEventsChain(paths, priorSessionId);
|
|
@@ -6877,7 +7050,7 @@ async function reimportPreservingId(paths, manifest, priorSessionId, freshPayloa
|
|
|
6877
7050
|
};
|
|
6878
7051
|
const updatedRecord = { schema_version: "0.1.0", session: preservedInner };
|
|
6879
7052
|
if (options.dryRun !== true) {
|
|
6880
|
-
const eventsPath =
|
|
7053
|
+
const eventsPath = join21(sessionDir, "events.jsonl");
|
|
6881
7054
|
let priorEventsRaw = null;
|
|
6882
7055
|
try {
|
|
6883
7056
|
priorEventsRaw = await readFile10(eventsPath);
|
|
@@ -6889,7 +7062,7 @@ async function reimportPreservingId(paths, manifest, priorSessionId, freshPayloa
|
|
|
6889
7062
|
const chainResult = await writeEventsBulk(sessionDir, mergedEvents, { chain: true });
|
|
6890
7063
|
try {
|
|
6891
7064
|
await overwriteYamlFile(
|
|
6892
|
-
|
|
7065
|
+
join21(sessionDir, "session.yaml"),
|
|
6893
7066
|
withIntegrity(updatedRecord, chainResult)
|
|
6894
7067
|
);
|
|
6895
7068
|
} catch (error) {
|
|
@@ -6913,7 +7086,7 @@ async function reimportPreservingId(paths, manifest, priorSessionId, freshPayloa
|
|
|
6913
7086
|
}
|
|
6914
7087
|
}
|
|
6915
7088
|
async function rechainSessionInPlace(paths, sessionId, options = {}) {
|
|
6916
|
-
const sessionDir =
|
|
7089
|
+
const sessionDir = join21(paths.sessions, sessionId);
|
|
6917
7090
|
let lock;
|
|
6918
7091
|
try {
|
|
6919
7092
|
lock = await acquireLock(paths, "session", sessionId);
|
|
@@ -6946,7 +7119,7 @@ async function rechainSessionInPlace(paths, sessionId, options = {}) {
|
|
|
6946
7119
|
if (verdict.status !== "unchained") {
|
|
6947
7120
|
return { status: "skipped", reason: "tampered" };
|
|
6948
7121
|
}
|
|
6949
|
-
const eventsPath =
|
|
7122
|
+
const eventsPath = join21(sessionDir, "events.jsonl");
|
|
6950
7123
|
let priorRaw;
|
|
6951
7124
|
try {
|
|
6952
7125
|
priorRaw = await readFile10(eventsPath);
|
|
@@ -6994,7 +7167,7 @@ async function rechainSessionInPlace(paths, sessionId, options = {}) {
|
|
|
6994
7167
|
}
|
|
6995
7168
|
try {
|
|
6996
7169
|
await overwriteYamlFile(
|
|
6997
|
-
|
|
7170
|
+
join21(sessionDir, "session.yaml"),
|
|
6998
7171
|
withIntegrity(record, { headHash: chainResult.headHash, count: chainResult.count })
|
|
6999
7172
|
);
|
|
7000
7173
|
} catch (error) {
|
|
@@ -7011,6 +7184,7 @@ async function rechainSessionInPlace(paths, sessionId, options = {}) {
|
|
|
7011
7184
|
var BASOU_CORE_VERSION = "0.1.0";
|
|
7012
7185
|
export {
|
|
7013
7186
|
ACTIVE_GAP_CAP_MS,
|
|
7187
|
+
AGENT_INFRA_DIRS,
|
|
7014
7188
|
ApprovalIdSchema,
|
|
7015
7189
|
ApprovalSchema,
|
|
7016
7190
|
ApprovalStatusSchema,
|
|
@@ -7061,6 +7235,7 @@ export {
|
|
|
7061
7235
|
buildStatusSnapshot,
|
|
7062
7236
|
chainEvents,
|
|
7063
7237
|
chainRawJsonLines,
|
|
7238
|
+
classifyFilesBySourceRoot,
|
|
7064
7239
|
classifySuspect,
|
|
7065
7240
|
claudeCodeAdapterMetadata,
|
|
7066
7241
|
claudeTranscriptToImportPayload,
|
|
@@ -7093,6 +7268,7 @@ export {
|
|
|
7093
7268
|
lineHash,
|
|
7094
7269
|
linkYamlFile,
|
|
7095
7270
|
loadApproval,
|
|
7271
|
+
loadFederatedSessionEntries,
|
|
7096
7272
|
loadSessionEntries,
|
|
7097
7273
|
loadTaskEntries,
|
|
7098
7274
|
normalizeRepoKey,
|