@basou/core 0.21.0 → 0.23.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 +34 -0
- package/dist/index.js +71 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3401,6 +3401,31 @@ type NoteRecord = {
|
|
|
3401
3401
|
occurredAt: string;
|
|
3402
3402
|
host: string | null;
|
|
3403
3403
|
};
|
|
3404
|
+
/**
|
|
3405
|
+
* One recent session condensed to its direction signal, for the "最近の流れ"
|
|
3406
|
+
* (recent direction) section. Across the last N non-archived sessions
|
|
3407
|
+
* (newest first), this surfaces the ARC of recent intent — the decision titles
|
|
3408
|
+
* and next-step notes recorded in EACH session — rather than orientation's
|
|
3409
|
+
* single latest decision/note, which can be stale or missing. When a session
|
|
3410
|
+
* recorded neither a decision nor a note, its top changed files stand in as the
|
|
3411
|
+
* activity signal, so the trajectory stays visible even when explicit capture
|
|
3412
|
+
* was missed (the read-side safety net for the intent-leak gap).
|
|
3413
|
+
*/
|
|
3414
|
+
type RecentSessionDigest = {
|
|
3415
|
+
sessionId: string;
|
|
3416
|
+
label: string | null;
|
|
3417
|
+
/** Session boundary (ended_at ?? started_at); the basis for its relative age. */
|
|
3418
|
+
occurredAt: string;
|
|
3419
|
+
host: string | null;
|
|
3420
|
+
/** Non-voided decision titles recorded in this session, chronological, capped. */
|
|
3421
|
+
decisions: string[];
|
|
3422
|
+
/** Count of this session's non-voided decisions beyond those in `decisions`. */
|
|
3423
|
+
decisionsOverflow: number;
|
|
3424
|
+
/** next_step note bodies recorded in this session, chronological, capped. */
|
|
3425
|
+
notes: string[];
|
|
3426
|
+
/** Top changed files, populated ONLY when the session has no decision and no note. */
|
|
3427
|
+
files: string[];
|
|
3428
|
+
};
|
|
3404
3429
|
type PendingApproval = {
|
|
3405
3430
|
id: string;
|
|
3406
3431
|
risk: string;
|
|
@@ -3474,6 +3499,15 @@ type OrientationSummary = {
|
|
|
3474
3499
|
* step / handoff ("次の起点") surfaced in the forward section; null when none.
|
|
3475
3500
|
*/
|
|
3476
3501
|
latestNote: NoteRecord | null;
|
|
3502
|
+
/**
|
|
3503
|
+
* The last N non-archived sessions (newest first) condensed to their direction
|
|
3504
|
+
* signal — the "最近の流れ" (recent direction) arc. Distinct from the single
|
|
3505
|
+
* latest decision/note: it shows the trajectory of intent across recent
|
|
3506
|
+
* sessions, and falls back to each session's changed files when no decision or
|
|
3507
|
+
* note was captured, so a resuming agent has grounding even when explicit
|
|
3508
|
+
* capture was missed. Empty when no non-archived sessions exist.
|
|
3509
|
+
*/
|
|
3510
|
+
recentDirection: RecentSessionDigest[];
|
|
3477
3511
|
/**
|
|
3478
3512
|
* related_files of the latest session, deduped + sorted + capped at the
|
|
3479
3513
|
* display limit. `outOfRoot` lists the entries (over the FULL deduped set,
|
package/dist/index.js
CHANGED
|
@@ -4646,6 +4646,16 @@ async function summarizeOrientation(input) {
|
|
|
4646
4646
|
const decisions = [];
|
|
4647
4647
|
const tracks = [];
|
|
4648
4648
|
const voidedDecisionIds = /* @__PURE__ */ new Set();
|
|
4649
|
+
const perSession = /* @__PURE__ */ new Map();
|
|
4650
|
+
const recordDirection = (sessionId, kind, value) => {
|
|
4651
|
+
let bucket = perSession.get(sessionId);
|
|
4652
|
+
if (bucket === void 0) {
|
|
4653
|
+
bucket = { decisions: [], notes: [] };
|
|
4654
|
+
perSession.set(sessionId, bucket);
|
|
4655
|
+
}
|
|
4656
|
+
if (kind === "decision" && typeof value !== "string") bucket.decisions.push(value);
|
|
4657
|
+
else if (kind === "note" && typeof value === "string") bucket.notes.push(value);
|
|
4658
|
+
};
|
|
4649
4659
|
let latestActivityAt = null;
|
|
4650
4660
|
let latestNote = null;
|
|
4651
4661
|
const noteActivity = (iso) => {
|
|
@@ -4669,6 +4679,12 @@ async function summarizeOrientation(input) {
|
|
|
4669
4679
|
sessionId: entry.sessionId,
|
|
4670
4680
|
host: entry.host
|
|
4671
4681
|
});
|
|
4682
|
+
if (counted) {
|
|
4683
|
+
recordDirection(entry.sessionId, "decision", {
|
|
4684
|
+
decisionId: ev.decision_id,
|
|
4685
|
+
title: ev.title
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4672
4688
|
if (ev.kind === "track") {
|
|
4673
4689
|
tracks.push({
|
|
4674
4690
|
decisionId: ev.decision_id,
|
|
@@ -4683,6 +4699,7 @@ async function summarizeOrientation(input) {
|
|
|
4683
4699
|
voidedDecisionIds.add(ev.decision_id);
|
|
4684
4700
|
}
|
|
4685
4701
|
if (counted && ev.type === "note_added" && ev.kind === "next_step") {
|
|
4702
|
+
recordDirection(entry.sessionId, "note", ev.body);
|
|
4686
4703
|
if (latestNote === null || Date.parse(ev.occurred_at) > Date.parse(latestNote.occurredAt)) {
|
|
4687
4704
|
latestNote = {
|
|
4688
4705
|
body: ev.body,
|
|
@@ -4714,6 +4731,29 @@ async function summarizeOrientation(input) {
|
|
|
4714
4731
|
const c = Date.parse(b.occurredAt) - Date.parse(a.occurredAt);
|
|
4715
4732
|
return c !== 0 ? c : b.decisionId.localeCompare(a.decisionId);
|
|
4716
4733
|
});
|
|
4734
|
+
const recentDirection = entries.filter((e) => e.session.session.status !== "archived").map((e) => ({
|
|
4735
|
+
entry: e,
|
|
4736
|
+
boundary: e.session.session.ended_at ?? e.session.session.started_at
|
|
4737
|
+
})).sort((a, b) => {
|
|
4738
|
+
const c = Date.parse(b.boundary) - Date.parse(a.boundary);
|
|
4739
|
+
return c !== 0 ? c : b.entry.sessionId.localeCompare(a.entry.sessionId);
|
|
4740
|
+
}).slice(0, RECENT_DIRECTION_SESSIONS).map(({ entry, boundary }) => {
|
|
4741
|
+
const bucket = perSession.get(entry.sessionId);
|
|
4742
|
+
const decisionTitles = (bucket?.decisions ?? []).filter((d) => !voidedDecisionIds.has(d.decisionId)).map((d) => d.title);
|
|
4743
|
+
const notes = bucket?.notes ?? [];
|
|
4744
|
+
const hasIntent = decisionTitles.length > 0 || notes.length > 0;
|
|
4745
|
+
const files = hasIntent ? [] : [...new Set(entry.session.session.related_files ?? [])].sort().slice(0, FILES_PER_DIGEST);
|
|
4746
|
+
return {
|
|
4747
|
+
sessionId: entry.sessionId,
|
|
4748
|
+
label: entry.session.session.label ?? null,
|
|
4749
|
+
occurredAt: boundary,
|
|
4750
|
+
host: entry.host,
|
|
4751
|
+
decisions: decisionTitles.slice(0, DECISIONS_PER_DIGEST),
|
|
4752
|
+
decisionsOverflow: Math.max(0, decisionTitles.length - DECISIONS_PER_DIGEST),
|
|
4753
|
+
notes: notes.slice(0, NOTES_PER_DIGEST),
|
|
4754
|
+
files
|
|
4755
|
+
};
|
|
4756
|
+
});
|
|
4717
4757
|
const taskLoadOpts = {};
|
|
4718
4758
|
if (input.onTaskSkip !== void 0) taskLoadOpts.onSkip = input.onTaskSkip;
|
|
4719
4759
|
const taskEntries = await loadTaskEntries(input.paths, taskLoadOpts);
|
|
@@ -4804,6 +4844,7 @@ async function summarizeOrientation(input) {
|
|
|
4804
4844
|
decisionCount: decisions.length,
|
|
4805
4845
|
openTracks,
|
|
4806
4846
|
latestNote,
|
|
4847
|
+
recentDirection,
|
|
4807
4848
|
relatedFiles: { displayed, overflow, outOfRoot },
|
|
4808
4849
|
inFlightTasks,
|
|
4809
4850
|
plannedTasks,
|
|
@@ -4906,6 +4947,29 @@ function formatOrientationBody(summary, opts) {
|
|
|
4906
4947
|
lines.push("- \u76F4\u8FD1\u306E\u5909\u66F4\u30D5\u30A1\u30A4\u30EB: (none recorded)");
|
|
4907
4948
|
}
|
|
4908
4949
|
lines.push("");
|
|
4950
|
+
lines.push(`## \u6700\u8FD1\u306E\u6D41\u308C (\u76F4\u8FD1 ${RECENT_DIRECTION_SESSIONS} session)`);
|
|
4951
|
+
lines.push("");
|
|
4952
|
+
if (summary.recentDirection.length === 0) {
|
|
4953
|
+
lines.push("- (\u307E\u3060\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093)");
|
|
4954
|
+
} else {
|
|
4955
|
+
for (const s of summary.recentDirection) {
|
|
4956
|
+
const sid = shortId(s.sessionId);
|
|
4957
|
+
const age = relativeAgeJa(s.occurredAt, now);
|
|
4958
|
+
const head = s.label !== null && s.label !== "" ? s.label : sid;
|
|
4959
|
+
lines.push(`- ${head} (${age})${hostSuffix(s.host)}`);
|
|
4960
|
+
if (s.decisions.length > 0) {
|
|
4961
|
+
const more = s.decisionsOverflow > 0 ? ` (+${s.decisionsOverflow})` : "";
|
|
4962
|
+
lines.push(` - \u5224\u65AD: ${s.decisions.map(noteSummary).join("; ")}${more}`);
|
|
4963
|
+
}
|
|
4964
|
+
for (const note of s.notes) {
|
|
4965
|
+
lines.push(` - \u6B21\u306E\u8D77\u70B9: ${noteSummary(note)}`);
|
|
4966
|
+
}
|
|
4967
|
+
if (s.files.length > 0) {
|
|
4968
|
+
lines.push(` - \u5909\u66F4: ${s.files.join(", ")}`);
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
lines.push("");
|
|
4909
4973
|
lines.push("## \u4F55\u304C\u52D5\u304F");
|
|
4910
4974
|
lines.push("");
|
|
4911
4975
|
lines.push(`### \u9032\u884C\u4E2D task (${summary.inFlightTasks.length})`);
|
|
@@ -5064,7 +5128,7 @@ function stalenessBanner(staleness) {
|
|
|
5064
5128
|
if (staleness.newSessions > 0) parts.push(`\u65B0\u898F ${staleness.newSessions} \u4EF6`);
|
|
5065
5129
|
if (staleness.updatedSessions > 0) parts.push(`\u66F4\u65B0 ${staleness.updatedSessions} \u4EF6`);
|
|
5066
5130
|
return [
|
|
5067
|
-
`> \u26A0\uFE0F **\u53E4\u3044\
|
|
5131
|
+
`> \u26A0\uFE0F **\u53E4\u3044\u3067\u3059\uFF08\u672A\u53D6\u308A\u8FBC\u307F ${parts.join("\u30FB")}\uFF09** \u2014 \u7740\u624B\u524D\u306B\u5FC5\u305A \`basou refresh\` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
5068
5132
|
];
|
|
5069
5133
|
}
|
|
5070
5134
|
return [];
|
|
@@ -5081,8 +5145,8 @@ function freshnessVerdict(summary, staleness, now) {
|
|
|
5081
5145
|
if (staleness.newSessions > 0) parts.push(`\u65B0\u898F ${staleness.newSessions} \u4EF6`);
|
|
5082
5146
|
if (staleness.updatedSessions > 0) parts.push(`\u66F4\u65B0 ${staleness.updatedSessions} \u4EF6`);
|
|
5083
5147
|
return [
|
|
5084
|
-
`\u26A0\uFE0F \u53E4\u3044\
|
|
5085
|
-
"`basou refresh` \
|
|
5148
|
+
`\u26A0\uFE0F \u53E4\u3044\u3067\u3059\u3002\u6700\u5F8C\u306E\u53D6\u308A\u8FBC\u307F\u4EE5\u964D\u306B\u672A\u53D6\u308A\u8FBC\u307F\u306E\u4F5C\u696D\u304C\u3042\u308A\u307E\u3059(${parts.join("\u30FB")})\u3002`,
|
|
5149
|
+
"\u7740\u624B\u524D\u306B\u5FC5\u305A `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
5086
5150
|
];
|
|
5087
5151
|
}
|
|
5088
5152
|
if (summary.freshness.newestStartedAt === null) {
|
|
@@ -5133,6 +5197,10 @@ function relativeAge(startedAt, now) {
|
|
|
5133
5197
|
if (ms < 1e3) return "just now";
|
|
5134
5198
|
return `${formatDurationMs(ms)} ago`;
|
|
5135
5199
|
}
|
|
5200
|
+
var RECENT_DIRECTION_SESSIONS = 5;
|
|
5201
|
+
var DECISIONS_PER_DIGEST = 3;
|
|
5202
|
+
var NOTES_PER_DIGEST = 2;
|
|
5203
|
+
var FILES_PER_DIGEST = 3;
|
|
5136
5204
|
var NOTE_SUMMARY_MAX = 200;
|
|
5137
5205
|
function noteSummary(body) {
|
|
5138
5206
|
const oneLine = body.replace(/\s+/g, " ").trim();
|