@basou/core 0.14.0 → 0.15.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 -9
- package/dist/index.js +103 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3170,6 +3170,7 @@ type DecisionRecord = {
|
|
|
3170
3170
|
decisionId: string;
|
|
3171
3171
|
title: string;
|
|
3172
3172
|
occurredAt: string;
|
|
3173
|
+
sessionId: string;
|
|
3173
3174
|
};
|
|
3174
3175
|
type NoteRecord = {
|
|
3175
3176
|
body: string;
|
|
@@ -5001,15 +5002,26 @@ declare function readManifest(paths: BasouPaths): Promise<Manifest>;
|
|
|
5001
5002
|
declare const GENERATED_START = "<!-- BASOU:GENERATED:START -->";
|
|
5002
5003
|
/** Marker line that ends the auto-generated region. */
|
|
5003
5004
|
declare const GENERATED_END = "<!-- BASOU:GENERATED:END -->";
|
|
5005
|
+
/** Marker line that begins a managed protocol block in a foreign instruction file. */
|
|
5006
|
+
declare const PROTOCOL_START = "<!-- BASOU:PROTOCOLS:START -->";
|
|
5007
|
+
/** Marker line that ends a managed protocol block. */
|
|
5008
|
+
declare const PROTOCOL_END = "<!-- BASOU:PROTOCOLS:END -->";
|
|
5009
|
+
/** A start/end marker pair. Both lines are matched whole-line, exact. */
|
|
5010
|
+
type Markers = {
|
|
5011
|
+
start: string;
|
|
5012
|
+
end: string;
|
|
5013
|
+
};
|
|
5004
5014
|
/**
|
|
5005
5015
|
* Result of parsing a markdown body for the BASOU:GENERATED marker region.
|
|
5006
5016
|
*
|
|
5007
5017
|
* The spec mandates strict line-level matching (see
|
|
5008
5018
|
* `docs/spec/generated-markdown.md#102-marker-convention`): a marker is
|
|
5009
5019
|
* only recognized when an entire line is exactly the marker string.
|
|
5010
|
-
* Leading/trailing whitespace
|
|
5011
|
-
*
|
|
5012
|
-
*
|
|
5020
|
+
* Leading/trailing whitespace and comment compression are treated as legacy
|
|
5021
|
+
* formats (`no_markers`) so that re-generation refuses to silently overwrite a
|
|
5022
|
+
* mismatched manual edit. A leading UTF-8 BOM is the one exception: it is
|
|
5023
|
+
* tolerated (stripped for matching, re-prepended on render) so a BOM-prefixed
|
|
5024
|
+
* file round-trips instead of duplicating the block.
|
|
5013
5025
|
*/
|
|
5014
5026
|
type MarkerSection = {
|
|
5015
5027
|
kind: "ok";
|
|
@@ -5056,11 +5068,13 @@ declare function writeMarkdownFile(filePath: string, body: string): Promise<void
|
|
|
5056
5068
|
* - `multiple_pairs`: more than one START or END line.
|
|
5057
5069
|
* - `wrong_order`: END appears before START.
|
|
5058
5070
|
*
|
|
5059
|
-
* Matching is strict: leading/trailing whitespace
|
|
5060
|
-
*
|
|
5061
|
-
*
|
|
5071
|
+
* Matching is strict: leading/trailing whitespace and comment compression
|
|
5072
|
+
* (`<!--BASOU:...-->`) bypass the marker and are treated as legacy content. A
|
|
5073
|
+
* leading UTF-8 BOM is the exception: it is stripped before matching and
|
|
5074
|
+
* re-prepended to `before`, so a marker on the first line of a BOM-prefixed
|
|
5075
|
+
* file still matches and the file round-trips.
|
|
5062
5076
|
*/
|
|
5063
|
-
declare function parseMarkers(content: string): MarkerSection;
|
|
5077
|
+
declare function parseMarkers(content: string, markers?: Markers): MarkerSection;
|
|
5064
5078
|
/**
|
|
5065
5079
|
* Build the final markdown body by replacing the BASOU:GENERATED region.
|
|
5066
5080
|
*
|
|
@@ -5072,7 +5086,18 @@ declare function parseMarkers(content: string): MarkerSection;
|
|
|
5072
5086
|
* The caller passes `fileLabel` (e.g. `"handoff.md"` or `"decisions.md"`)
|
|
5073
5087
|
* so the error message is informative without leaking an absolute path.
|
|
5074
5088
|
*/
|
|
5075
|
-
declare function renderWithMarkers(existing: string | null, generated: string, fileLabel: string): string;
|
|
5089
|
+
declare function renderWithMarkers(existing: string | null, generated: string, fileLabel: string, markers?: Markers): string;
|
|
5090
|
+
/**
|
|
5091
|
+
* Remove a marker region from `existing`, returning the body without the block.
|
|
5092
|
+
*
|
|
5093
|
+
* - `no_markers`: returns `existing` unchanged (nothing to remove).
|
|
5094
|
+
* - `ok`: drops both marker lines and the generated region, collapsing the
|
|
5095
|
+
* single newline that terminated the END marker line so no stray blank line
|
|
5096
|
+
* is left behind.
|
|
5097
|
+
* - any other parse result: throws a pathless error referencing `fileLabel`
|
|
5098
|
+
* (mismatched markers must not be silently rewritten).
|
|
5099
|
+
*/
|
|
5100
|
+
declare function removeMarkerSection(existing: string, fileLabel: string, markers?: Markers): string;
|
|
5076
5101
|
|
|
5077
5102
|
/**
|
|
5078
5103
|
* Options for {@link importSessionFromJson}. All fields are optional.
|
|
@@ -5299,4 +5324,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
|
|
|
5299
5324
|
*/
|
|
5300
5325
|
declare const BASOU_CORE_VERSION = "0.1.0";
|
|
5301
5326
|
|
|
5302
|
-
export { ACTIVE_GAP_CAP_MS, type ActiveTimeBasis, type AdapterOutputEvent, type AdoptCandidate, type AdoptCandidateKind, type AppendBasouGitignoreOptions, type AppendBasouGitignoreResult, type AppendEventToExistingInput, type AppendEventToExistingResult, type Approval, type ApprovalApprovedEvent, type ApprovalExpiredEvent, ApprovalIdSchema, type ApprovalLocation, type ApprovalRejectedEvent, type ApprovalRequestedEvent, ApprovalSchema, type ApprovalStatus, ApprovalStatusSchema, type ArchivePlan, type ArchiveTaskInput, type ArchiveTaskResult, type AttachTaskInput, type AttachUpdateTaskStatusInput, type AttachableStatus, BASOU_CORE_VERSION, type BasouPaths, type BulkChainResult, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, type ChainBreakReason, type ChainTailState, type ChainVerdict, type ChainVerdictStatus, type ChainedEvents, ChildProcessRunner, type CitedReview, type ClaudeTranscriptRecord, type ClaudeTranscriptToPayloadOptions, type CodexRolloutRecord, type CodexRolloutToPayloadOptions, type CommandExecutedEvent, type CommandLookup, type CreateAdHocSessionInput, type CreateAdHocSessionResult, type CreateAdHocTaskInput, type CreateManifestInput, type CreateTaskInput, type CreateTaskResult, type DayWorkStats, DecisionIdSchema, type DecisionRecordedEvent, type DecisionsRendererInput, type DecisionsRendererResult, type DeleteTaskInput, type DeleteTaskResult, type DiffResult, type EditTaskInput, type EditTaskResult, type Event, EventIdSchema, EventSchema, EventSourceSchema, type ExistingViewLink, FailedToFinalizeError, type FileChange, type FileChangeStatus, type FileChangedEvent, GENERATED_END, GENERATED_START, type GitSnapshot, type GitSnapshotEvent, type GitignorePlanSummary, type HandoffRendererInput, type HandoffRendererResult, ID_PREFIXES, type IdPrefix, type ImportSessionOptions, type ImportSessionResult, type InstructionFileFact, type InstructionSymlinkFact, type InstructionSymlinkState, IsoTimestampSchema, JSON_SCHEMA_VERSION, type JsonSchemaArtifact, type LoadSessionEntriesOptions, type LoadTaskEntriesOptions, type LoadedApproval, type LockHandle, type LockScope, type Manifest, ManifestSchema, type MarkerSection, type MeasureAvailability, type NoteAddedEvent, type OrientationRendererInput, type OrientationRendererResult, type OrientationSummary, type PrefixedId, type PresetAction, type PresetCollision, type PresetMarkerConflict, type PresetMarkerKind, type PresetPlanSummary, type PresetRepo, type ProcessRunner, type PublishKind, type PublishTarget, type RechainOptions, type RechainResult, type ReconcileAllResult, type ReconcileAllTasksInput, type ReconcileAllTasksOptions, type ReconcileFailure, type ReconcileResult, type ReconcileTaskInput, type RefreshLinkageInput, type RefreshLinkageResult, type ReimportOptions, type ReimportResult, type RenamePlan, type ReplayOptions, type ReplayWarning, type RepoEntry, type RepoGitignoreFacts, type RepoGitignorePlan, type RepoLanguage, type RepoPresetFacts, type RepoPresetPlan, type RepoSymlinkFacts, type RepoSymlinkPlan, type RepoVisibility, type RepoWiringFacts, type ReportApprovalItem, type ReportData, type ReportDecisionItem, type ReportRendererInput, type ReportRendererResult, type ReportSessionItem, type ReportTaskItem, type ReviewGapRepoSummary, type ReviewGapUnit, type ReviewGapVerdict, type ReviewGapsInput, type ReviewGapsSummary, type RiskLevel, RiskLevelSchema, type RosterAdoptionPlan, type RosterDriftSummary, type RunOptions, type RunResult, STUCK_THRESHOLD_MS, type SanitizePathOptions, type SanitizeRelatedFilesResult, SchemaVersionSchema, type Session, type SessionEndedEvent, type SessionEntry, SessionIdSchema, type SessionImportPayload, SessionImportPayloadSchema, type SessionInnerImportInput, SessionInnerImportSchema, type SessionIntegrity, SessionIntegritySchema, type SessionMetrics, SessionMetricsSchema, SessionSchema, type SessionSkipReason, type SessionSourceKind, SessionSourceKindSchema, type SessionStartedEvent, type SessionStatus, type SessionStatusChangedEvent, SessionStatusSchema, type SessionWorkStats, type SourceRootsReconcile, type SourceWorkStats, type StatusCount, StatusSchema, type StatusSnapshot, type SuspectReason, type SymlinkCollision, type SymlinkConflict, type SymlinkPlanSummary, type Task, type TaskArchivedEvent, type TaskCreatedEvent, type TaskDeletedEvent, type TaskDocument, TaskIdSchema, type TaskLinkageRefreshedEvent, type TaskReconciledEvent, TaskSchema, type TaskSkipReason, type TaskStatus, type TaskStatusChangedEvent, type TaskStatusCount, TaskStatusSchema, TaskWriteAfterEventError, type TaskWriteAfterEventPhase, type TokenTotals, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type ViewCollision, type ViewConflict, type ViewLinkState, type ViewRepoFact, type ViewStrayUnknown, type WiringRisk, type WiringSummary, type WorkStatsInput, type WorkStatsResult, type WorkStatsTotals, WorkspaceIdSchema, type WorkspaceViewPlan, type WriteEventsBulkOptions, type WriteTaskFileMode, acquireLock, appendBasouGitignore, appendChainedEvent, appendChainedEventLocked, appendEvent, appendEventToExistingSession, archiveTask, assertBasouRootSafe, basouPaths, buildJsonSchemas, buildStatusSnapshot, chainEvents, chainRawJsonLines, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, finalizeSessionYaml, findErrorCode, findReviewGaps, formatDurationMs, genesisHash, getDiff, getSnapshot, importSessionFromJson, inspectChainTail, isGitNotFound, isImportDerivedSource, isLazyExpired, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadSessionEntries, loadTaskEntries, normalizeRepoKey, normalizeRepoPath, overwriteYamlFile, parseDuration, parseMarkers, pathBasename, planArchive, planGitignore, planRename, planRosterAdoption, planWorkspaceView, prefixedUlid, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, rechainSessionInPlace, reconcileAllTasks, reconcileSourceRoots, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, renderDecisions, renderHandoff, renderOrientation, renderPresetBlock, renderReport, renderWithMarkers, replayEvents, resolveBasouRepositoryRoot, resolveClaudeCodeCommand, resolveRepositoryRoot, resolveSessionId, resolveTaskId, safeSimpleGit, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, serializeEventLine, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, summarizeOrientation, summarizePresetPlan, summarizeRosterDrift, summarizeSymlinkPlan, summarizeWiring, tryRemoteUrl, ulid, unknownManifestKeys, updateTaskStatusWithEvent, verifyEventsChain, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
|
5327
|
+
export { ACTIVE_GAP_CAP_MS, type ActiveTimeBasis, type AdapterOutputEvent, type AdoptCandidate, type AdoptCandidateKind, type AppendBasouGitignoreOptions, type AppendBasouGitignoreResult, type AppendEventToExistingInput, type AppendEventToExistingResult, type Approval, type ApprovalApprovedEvent, type ApprovalExpiredEvent, ApprovalIdSchema, type ApprovalLocation, type ApprovalRejectedEvent, type ApprovalRequestedEvent, ApprovalSchema, type ApprovalStatus, ApprovalStatusSchema, type ArchivePlan, type ArchiveTaskInput, type ArchiveTaskResult, type AttachTaskInput, type AttachUpdateTaskStatusInput, type AttachableStatus, BASOU_CORE_VERSION, type BasouPaths, type BulkChainResult, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, type ChainBreakReason, type ChainTailState, type ChainVerdict, type ChainVerdictStatus, type ChainedEvents, ChildProcessRunner, type CitedReview, type ClaudeTranscriptRecord, type ClaudeTranscriptToPayloadOptions, type CodexRolloutRecord, type CodexRolloutToPayloadOptions, type CommandExecutedEvent, type CommandLookup, type CreateAdHocSessionInput, type CreateAdHocSessionResult, type CreateAdHocTaskInput, type CreateManifestInput, type CreateTaskInput, type CreateTaskResult, type DayWorkStats, DecisionIdSchema, type DecisionRecordedEvent, type DecisionsRendererInput, type DecisionsRendererResult, type DeleteTaskInput, type DeleteTaskResult, type DiffResult, type EditTaskInput, type EditTaskResult, type Event, EventIdSchema, EventSchema, EventSourceSchema, type ExistingViewLink, FailedToFinalizeError, type FileChange, type FileChangeStatus, type FileChangedEvent, GENERATED_END, GENERATED_START, type GitSnapshot, type GitSnapshotEvent, type GitignorePlanSummary, type HandoffRendererInput, type HandoffRendererResult, ID_PREFIXES, type IdPrefix, type ImportSessionOptions, type ImportSessionResult, type InstructionFileFact, type InstructionSymlinkFact, type InstructionSymlinkState, IsoTimestampSchema, JSON_SCHEMA_VERSION, type JsonSchemaArtifact, type LoadSessionEntriesOptions, type LoadTaskEntriesOptions, type LoadedApproval, type LockHandle, type LockScope, type Manifest, ManifestSchema, type MarkerSection, type Markers, type MeasureAvailability, type NoteAddedEvent, type OrientationRendererInput, type OrientationRendererResult, type OrientationSummary, PROTOCOL_END, PROTOCOL_START, type PrefixedId, type PresetAction, type PresetCollision, type PresetMarkerConflict, type PresetMarkerKind, type PresetPlanSummary, type PresetRepo, type ProcessRunner, type PublishKind, type PublishTarget, type RechainOptions, type RechainResult, type ReconcileAllResult, type ReconcileAllTasksInput, type ReconcileAllTasksOptions, type ReconcileFailure, type ReconcileResult, type ReconcileTaskInput, type RefreshLinkageInput, type RefreshLinkageResult, type ReimportOptions, type ReimportResult, type RenamePlan, type ReplayOptions, type ReplayWarning, type RepoEntry, type RepoGitignoreFacts, type RepoGitignorePlan, type RepoLanguage, type RepoPresetFacts, type RepoPresetPlan, type RepoSymlinkFacts, type RepoSymlinkPlan, type RepoVisibility, type RepoWiringFacts, type ReportApprovalItem, type ReportData, type ReportDecisionItem, type ReportRendererInput, type ReportRendererResult, type ReportSessionItem, type ReportTaskItem, type ReviewGapRepoSummary, type ReviewGapUnit, type ReviewGapVerdict, type ReviewGapsInput, type ReviewGapsSummary, type RiskLevel, RiskLevelSchema, type RosterAdoptionPlan, type RosterDriftSummary, type RunOptions, type RunResult, STUCK_THRESHOLD_MS, type SanitizePathOptions, type SanitizeRelatedFilesResult, SchemaVersionSchema, type Session, type SessionEndedEvent, type SessionEntry, SessionIdSchema, type SessionImportPayload, SessionImportPayloadSchema, type SessionInnerImportInput, SessionInnerImportSchema, type SessionIntegrity, SessionIntegritySchema, type SessionMetrics, SessionMetricsSchema, SessionSchema, type SessionSkipReason, type SessionSourceKind, SessionSourceKindSchema, type SessionStartedEvent, type SessionStatus, type SessionStatusChangedEvent, SessionStatusSchema, type SessionWorkStats, type SourceRootsReconcile, type SourceWorkStats, type StatusCount, StatusSchema, type StatusSnapshot, type SuspectReason, type SymlinkCollision, type SymlinkConflict, type SymlinkPlanSummary, type Task, type TaskArchivedEvent, type TaskCreatedEvent, type TaskDeletedEvent, type TaskDocument, TaskIdSchema, type TaskLinkageRefreshedEvent, type TaskReconciledEvent, TaskSchema, type TaskSkipReason, type TaskStatus, type TaskStatusChangedEvent, type TaskStatusCount, TaskStatusSchema, TaskWriteAfterEventError, type TaskWriteAfterEventPhase, type TokenTotals, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type ViewCollision, type ViewConflict, type ViewLinkState, type ViewRepoFact, type ViewStrayUnknown, type WiringRisk, type WiringSummary, type WorkStatsInput, type WorkStatsResult, type WorkStatsTotals, WorkspaceIdSchema, type WorkspaceViewPlan, type WriteEventsBulkOptions, type WriteTaskFileMode, acquireLock, appendBasouGitignore, appendChainedEvent, appendChainedEventLocked, appendEvent, appendEventToExistingSession, archiveTask, assertBasouRootSafe, basouPaths, buildJsonSchemas, buildStatusSnapshot, chainEvents, chainRawJsonLines, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, finalizeSessionYaml, findErrorCode, findReviewGaps, formatDurationMs, genesisHash, getDiff, getSnapshot, importSessionFromJson, inspectChainTail, isGitNotFound, isImportDerivedSource, isLazyExpired, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadSessionEntries, loadTaskEntries, normalizeRepoKey, normalizeRepoPath, overwriteYamlFile, parseDuration, parseMarkers, pathBasename, planArchive, planGitignore, planRename, planRosterAdoption, planWorkspaceView, prefixedUlid, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, rechainSessionInPlace, reconcileAllTasks, reconcileSourceRoots, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, removeMarkerSection, renderDecisions, renderHandoff, renderOrientation, renderPresetBlock, renderReport, renderWithMarkers, replayEvents, resolveBasouRepositoryRoot, resolveClaudeCodeCommand, resolveRepositoryRoot, resolveSessionId, resolveTaskId, safeSimpleGit, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, serializeEventLine, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, summarizeOrientation, summarizePresetPlan, summarizeRosterDrift, summarizeSymlinkPlan, summarizeWiring, tryRemoteUrl, ulid, unknownManifestKeys, updateTaskStatusWithEvent, verifyEventsChain, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
package/dist/index.js
CHANGED
|
@@ -2081,6 +2081,21 @@ function parseDiffNameStatus(raw) {
|
|
|
2081
2081
|
// src/handoff/handoff-renderer.ts
|
|
2082
2082
|
import { join as join13 } from "path";
|
|
2083
2083
|
|
|
2084
|
+
// src/lib/recency.ts
|
|
2085
|
+
var DECISION_TRAILING_ACTIVITY_GAP_MS = 60 * 60 * 1e3;
|
|
2086
|
+
function isTrailingStale(latestActivityAt, recordedAt) {
|
|
2087
|
+
if (latestActivityAt === null) return false;
|
|
2088
|
+
return Date.parse(latestActivityAt) - Date.parse(recordedAt) > DECISION_TRAILING_ACTIVITY_GAP_MS;
|
|
2089
|
+
}
|
|
2090
|
+
function pickLatestSubstantiveEntry(entries) {
|
|
2091
|
+
return [...entries].sort((a, b) => {
|
|
2092
|
+
const aSubstantive = (a.session.session.related_files?.length ?? 0) > 0 ? 1 : 0;
|
|
2093
|
+
const bSubstantive = (b.session.session.related_files?.length ?? 0) > 0 ? 1 : 0;
|
|
2094
|
+
if (aSubstantive !== bSubstantive) return bSubstantive - aSubstantive;
|
|
2095
|
+
return Date.parse(b.session.session.started_at) - Date.parse(a.session.session.started_at);
|
|
2096
|
+
})[0];
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2084
2099
|
// src/storage/tasks.ts
|
|
2085
2100
|
import { createHash as createHash2 } from "crypto";
|
|
2086
2101
|
import { mkdir as mkdir3, readdir as readdir4, readFile as readFile7, rename as rename2, stat as stat3, unlink as unlink3 } from "fs/promises";
|
|
@@ -3799,12 +3814,21 @@ async function renderHandoff(input) {
|
|
|
3799
3814
|
const decisions = [];
|
|
3800
3815
|
const tasksCreated = [];
|
|
3801
3816
|
const tasksStatusChanged = [];
|
|
3817
|
+
let latestActivityAt = null;
|
|
3818
|
+
const noteActivity = (iso) => {
|
|
3819
|
+
if (latestActivityAt === null || Date.parse(iso) > Date.parse(latestActivityAt)) {
|
|
3820
|
+
latestActivityAt = iso;
|
|
3821
|
+
}
|
|
3822
|
+
};
|
|
3802
3823
|
for (const entry of entries) {
|
|
3803
3824
|
const sessionDir = join13(input.paths.sessions, entry.sessionId);
|
|
3825
|
+
const counted = entry.session.session.status !== "archived";
|
|
3826
|
+
if (counted) noteActivity(entry.session.session.ended_at ?? entry.session.session.started_at);
|
|
3804
3827
|
try {
|
|
3805
3828
|
for await (const ev of replayEvents(sessionDir, {
|
|
3806
3829
|
onWarning: (w) => input.onWarning?.(w, entry.sessionId)
|
|
3807
3830
|
})) {
|
|
3831
|
+
if (counted) noteActivity(ev.occurred_at);
|
|
3808
3832
|
if (ev.type === "decision_recorded") {
|
|
3809
3833
|
decisions.push({
|
|
3810
3834
|
decisionId: ev.decision_id,
|
|
@@ -3864,9 +3888,7 @@ async function renderHandoff(input) {
|
|
|
3864
3888
|
const liveEntries = entries.filter(
|
|
3865
3889
|
(e) => e.session.session.status !== "archived" && e.session.session.source.kind !== "import"
|
|
3866
3890
|
);
|
|
3867
|
-
const latestSession =
|
|
3868
|
-
(a, b) => Date.parse(b.session.session.started_at) - Date.parse(a.session.session.started_at)
|
|
3869
|
-
)[0];
|
|
3891
|
+
const latestSession = pickLatestSubstantiveEntry(liveEntries);
|
|
3870
3892
|
const latestFiles = latestSession?.session.session.related_files ?? [];
|
|
3871
3893
|
const sortedFiles = [...new Set(latestFiles)].sort();
|
|
3872
3894
|
const displayedFiles = sortedFiles.slice(0, limit);
|
|
@@ -3880,6 +3902,7 @@ async function renderHandoff(input) {
|
|
|
3880
3902
|
sessionRange,
|
|
3881
3903
|
sessionCount: entries.length,
|
|
3882
3904
|
latestSession,
|
|
3905
|
+
latestActivityAt,
|
|
3883
3906
|
decisions,
|
|
3884
3907
|
pendingApprovalsCount,
|
|
3885
3908
|
suspectCount,
|
|
@@ -3952,6 +3975,16 @@ function formatHandoffBody(args) {
|
|
|
3952
3975
|
} else {
|
|
3953
3976
|
const last = args.decisions[args.decisions.length - 1];
|
|
3954
3977
|
lines.push(`- ${last.title} [${shortIdWithPrefix(last.decisionId)}]`);
|
|
3978
|
+
if (args.latestActivityAt !== null && isTrailingStale(args.latestActivityAt, last.occurredAt)) {
|
|
3979
|
+
lines.push(
|
|
3980
|
+
" - \u6CE8: \u6700\u7D42\u6D3B\u52D5\u306F\u3053\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u4F1A\u8A71\u3067\u65E2\u306B\u89E3\u6C7A\u6E08\u307F\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u3001\u518D\u958B\u524D\u306B\u7D99\u7D9A\u70B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002`basou decision capture` \u3067\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002"
|
|
3981
|
+
);
|
|
3982
|
+
}
|
|
3983
|
+
if (args.latestSession !== void 0 && last.sessionId !== args.latestSession.sessionId) {
|
|
3984
|
+
lines.push(
|
|
3985
|
+
` - \u6CE8: \u3053\u306E\u5224\u65AD\u306F\u6700\u7D42 session \u3068\u306F\u5225\u306E session [${shortIdWithPrefix(last.sessionId)}] \u306E\u3082\u306E\u3067\u3059\u3002`
|
|
3986
|
+
);
|
|
3987
|
+
}
|
|
3955
3988
|
lines.push("");
|
|
3956
3989
|
lines.push(`(${args.decisions.length} decisions total \u2014 see decisions.md)`);
|
|
3957
3990
|
}
|
|
@@ -4305,7 +4338,6 @@ function hasErrorCode3(error) {
|
|
|
4305
4338
|
}
|
|
4306
4339
|
|
|
4307
4340
|
// src/orientation/orientation-renderer.ts
|
|
4308
|
-
var DECISION_TRAILING_ACTIVITY_GAP_MS = 60 * 60 * 1e3;
|
|
4309
4341
|
async function summarizeOrientation(input) {
|
|
4310
4342
|
const limit = input.relatedFilesLimit ?? 10;
|
|
4311
4343
|
const now = new Date(input.nowIso);
|
|
@@ -4333,7 +4365,8 @@ async function summarizeOrientation(input) {
|
|
|
4333
4365
|
decisions.push({
|
|
4334
4366
|
decisionId: ev.decision_id,
|
|
4335
4367
|
title: ev.title,
|
|
4336
|
-
occurredAt: ev.occurred_at
|
|
4368
|
+
occurredAt: ev.occurred_at,
|
|
4369
|
+
sessionId: entry.sessionId
|
|
4337
4370
|
});
|
|
4338
4371
|
}
|
|
4339
4372
|
if (counted && ev.type === "note_added" && ev.kind === "next_step") {
|
|
@@ -4386,9 +4419,7 @@ async function summarizeOrientation(input) {
|
|
|
4386
4419
|
const liveEntries = entries.filter(
|
|
4387
4420
|
(e) => e.session.session.status !== "archived" && e.session.session.source.kind !== "import"
|
|
4388
4421
|
);
|
|
4389
|
-
const latestEntry =
|
|
4390
|
-
(a, b) => Date.parse(b.session.session.started_at) - Date.parse(a.session.session.started_at)
|
|
4391
|
-
)[0];
|
|
4422
|
+
const latestEntry = pickLatestSubstantiveEntry(liveEntries);
|
|
4392
4423
|
const latestSession = latestEntry !== void 0 ? {
|
|
4393
4424
|
sessionId: latestEntry.sessionId,
|
|
4394
4425
|
label: latestEntry.session.session.label ?? null,
|
|
@@ -4474,16 +4505,20 @@ function formatOrientationBody(summary, opts) {
|
|
|
4474
4505
|
lines.push("- \u6700\u7D42 session: (no live sessions)");
|
|
4475
4506
|
}
|
|
4476
4507
|
if (summary.latestDecision !== null) {
|
|
4477
|
-
const
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
);
|
|
4508
|
+
const dec = summary.latestDecision;
|
|
4509
|
+
const decAge = relativeAgeJa(dec.occurredAt, now);
|
|
4510
|
+
lines.push(`- \u76F4\u8FD1\u306E\u5224\u65AD: ${dec.title} [${shortId(dec.decisionId)}] (${decAge})`);
|
|
4481
4511
|
const activityAt = summary.freshness.latestActivityAt;
|
|
4482
|
-
if (activityAt !== null &&
|
|
4512
|
+
if (activityAt !== null && isTrailingStale(activityAt, dec.occurredAt)) {
|
|
4483
4513
|
lines.push(
|
|
4484
4514
|
` - \u6CE8: \u3053\u308C\u306F\u6700\u5F8C\u306B\u300C\u8A18\u9332\u3055\u308C\u305F\u300D\u5224\u65AD\u3067\u3059\u3002\u6700\u7D42\u6D3B\u52D5 (${relativeAgeJa(activityAt, now)}) \u306F\u3053\u308C\u3088\u308A\u5F8C\u306E\u305F\u3081\u3001\u73FE\u5728\u306E\u65B9\u91DD\u304C\u53CD\u6620\u3055\u308C\u3066\u3044\u306A\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002\`basou decision capture\` \u3067\u3053\u306E session \u306E\u5224\u65AD\u3092\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002`
|
|
4485
4515
|
);
|
|
4486
4516
|
}
|
|
4517
|
+
if (summary.latestSession !== null && dec.sessionId !== summary.latestSession.sessionId) {
|
|
4518
|
+
lines.push(
|
|
4519
|
+
` - \u6CE8: \u3053\u306E\u5224\u65AD\u306F\u6700\u7D42 session \u3068\u306F\u5225\u306E session [${shortId(dec.sessionId)}] \u306E\u3082\u306E\u3067\u3059\u3002`
|
|
4520
|
+
);
|
|
4521
|
+
}
|
|
4487
4522
|
if (summary.decisionCount > 1) {
|
|
4488
4523
|
lines.push(` - ${summary.decisionCount} decisions total \u2014 see decisions.md`);
|
|
4489
4524
|
}
|
|
@@ -4539,7 +4574,7 @@ function formatOrientationBody(summary, opts) {
|
|
|
4539
4574
|
`- \u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${noteAge}): ${noteSummary(summary.latestNote.body)} [session ${shortId(summary.latestNote.sessionId)}]`
|
|
4540
4575
|
);
|
|
4541
4576
|
const activityAt = summary.freshness.latestActivityAt;
|
|
4542
|
-
if (activityAt !== null &&
|
|
4577
|
+
if (activityAt !== null && isTrailingStale(activityAt, summary.latestNote.occurredAt)) {
|
|
4543
4578
|
lines.push(
|
|
4544
4579
|
` - \u6CE8: \u3053\u306E\u8D77\u70B9\u306E\u8A18\u9332\u5F8C (\u6700\u7D42\u6D3B\u52D5 ${relativeAgeJa(activityAt, now)}) \u3082\u4F5C\u696D\u304C\u7D9A\u3044\u3066\u3044\u307E\u3059\u3002\u518D\u958B\u70B9\u304C\u53E4\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`
|
|
4545
4580
|
);
|
|
@@ -4549,9 +4584,17 @@ function formatOrientationBody(summary, opts) {
|
|
|
4549
4584
|
lines.push(`- ${t.title} [${shortId(t.id)}]`);
|
|
4550
4585
|
}
|
|
4551
4586
|
if (summary.latestNote === null && summary.plannedTasks.length === 0) {
|
|
4552
|
-
|
|
4553
|
-
if (
|
|
4554
|
-
lines.push(
|
|
4587
|
+
const dec = summary.latestDecision;
|
|
4588
|
+
if (dec === null) {
|
|
4589
|
+
lines.push("- (no planned tasks or recorded next step yet)");
|
|
4590
|
+
} else if (isTrailingStale(summary.freshness.latestActivityAt, dec.occurredAt)) {
|
|
4591
|
+
lines.push(
|
|
4592
|
+
"- (no planned tasks or recorded next step \u2014 \u6700\u7D42\u6D3B\u52D5\u306F\u76F4\u8FD1\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u7D99\u7D9A\u70B9\u3092\u30E6\u30FC\u30B6\u306B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044)"
|
|
4593
|
+
);
|
|
4594
|
+
lines.push(` - \u53C2\u8003 (\u53E4\u3044\u53EF\u80FD\u6027\u30FB\u65B9\u91DD\u3067\u306F\u306A\u3044): ${dec.title}`);
|
|
4595
|
+
} else {
|
|
4596
|
+
lines.push("- (no planned tasks \u2014 direction is inferred from recent decisions)");
|
|
4597
|
+
lines.push(` - \u76F4\u8FD1\u306E\u5224\u65AD: ${dec.title}`);
|
|
4555
4598
|
}
|
|
4556
4599
|
}
|
|
4557
4600
|
lines.push("");
|
|
@@ -6462,6 +6505,9 @@ function hasErrorCode5(error) {
|
|
|
6462
6505
|
import { readFile as readFile9 } from "fs/promises";
|
|
6463
6506
|
var GENERATED_START = "<!-- BASOU:GENERATED:START -->";
|
|
6464
6507
|
var GENERATED_END = "<!-- BASOU:GENERATED:END -->";
|
|
6508
|
+
var PROTOCOL_START = "<!-- BASOU:PROTOCOLS:START -->";
|
|
6509
|
+
var PROTOCOL_END = "<!-- BASOU:PROTOCOLS:END -->";
|
|
6510
|
+
var DEFAULT_MARKERS = { start: GENERATED_START, end: GENERATED_END };
|
|
6465
6511
|
async function readMarkdownFile(filePath) {
|
|
6466
6512
|
try {
|
|
6467
6513
|
return await readFile9(filePath, "utf8");
|
|
@@ -6477,13 +6523,15 @@ async function writeMarkdownFile(filePath, body) {
|
|
|
6477
6523
|
throw new Error("Failed to write markdown file", { cause: error });
|
|
6478
6524
|
}
|
|
6479
6525
|
}
|
|
6480
|
-
function parseMarkers(content) {
|
|
6481
|
-
const
|
|
6526
|
+
function parseMarkers(content, markers = DEFAULT_MARKERS) {
|
|
6527
|
+
const bom = content.charCodeAt(0) === 65279 ? "\uFEFF" : "";
|
|
6528
|
+
const body = bom === "" ? content : content.slice(1);
|
|
6529
|
+
const lines = body.split(/\r?\n/);
|
|
6482
6530
|
const startLines = [];
|
|
6483
6531
|
const endLines = [];
|
|
6484
6532
|
for (let i = 0; i < lines.length; i++) {
|
|
6485
|
-
if (lines[i] ===
|
|
6486
|
-
else if (lines[i] ===
|
|
6533
|
+
if (lines[i] === markers.start) startLines.push(i);
|
|
6534
|
+
else if (lines[i] === markers.end) endLines.push(i);
|
|
6487
6535
|
}
|
|
6488
6536
|
if (startLines.length === 0 && endLines.length === 0) return { kind: "no_markers" };
|
|
6489
6537
|
if (startLines.length === 0) return { kind: "missing_start" };
|
|
@@ -6492,30 +6540,30 @@ function parseMarkers(content) {
|
|
|
6492
6540
|
const startLineIdx = startLines[0];
|
|
6493
6541
|
const endLineIdx = endLines[0];
|
|
6494
6542
|
if (endLineIdx < startLineIdx) return { kind: "wrong_order" };
|
|
6495
|
-
const startOffset = lineStartOffset(
|
|
6496
|
-
const endLineStart = lineStartOffset(
|
|
6497
|
-
const startLineEnd = startOffset +
|
|
6498
|
-
const endLineEnd = endLineStart +
|
|
6499
|
-
const before =
|
|
6500
|
-
const afterStartNewline = skipOneNewline(
|
|
6501
|
-
const beforeEndNewline = trimOneNewline(
|
|
6502
|
-
const generated =
|
|
6503
|
-
const after =
|
|
6543
|
+
const startOffset = lineStartOffset(body, startLineIdx);
|
|
6544
|
+
const endLineStart = lineStartOffset(body, endLineIdx);
|
|
6545
|
+
const startLineEnd = startOffset + markers.start.length;
|
|
6546
|
+
const endLineEnd = endLineStart + markers.end.length;
|
|
6547
|
+
const before = bom + body.slice(0, startOffset);
|
|
6548
|
+
const afterStartNewline = skipOneNewline(body, startLineEnd);
|
|
6549
|
+
const beforeEndNewline = trimOneNewline(body, endLineStart);
|
|
6550
|
+
const generated = body.slice(afterStartNewline, beforeEndNewline);
|
|
6551
|
+
const after = body.slice(endLineEnd);
|
|
6504
6552
|
return { kind: "ok", before, generated, after };
|
|
6505
6553
|
}
|
|
6506
|
-
function renderWithMarkers(existing, generated, fileLabel) {
|
|
6554
|
+
function renderWithMarkers(existing, generated, fileLabel, markers = DEFAULT_MARKERS) {
|
|
6507
6555
|
const normalized = generated.endsWith("\n") ? generated : `${generated}
|
|
6508
6556
|
`;
|
|
6509
6557
|
if (existing === null) {
|
|
6510
|
-
return `${
|
|
6511
|
-
${normalized}${
|
|
6558
|
+
return `${markers.start}
|
|
6559
|
+
${normalized}${markers.end}
|
|
6512
6560
|
`;
|
|
6513
6561
|
}
|
|
6514
|
-
const section = parseMarkers(existing);
|
|
6562
|
+
const section = parseMarkers(existing, markers);
|
|
6515
6563
|
switch (section.kind) {
|
|
6516
6564
|
case "ok":
|
|
6517
|
-
return `${section.before}${
|
|
6518
|
-
${normalized}${
|
|
6565
|
+
return `${section.before}${markers.start}
|
|
6566
|
+
${normalized}${markers.end}${section.after}`;
|
|
6519
6567
|
case "no_markers":
|
|
6520
6568
|
throw new Error(`Markers missing in ${fileLabel}`);
|
|
6521
6569
|
case "missing_start":
|
|
@@ -6525,6 +6573,22 @@ ${normalized}${GENERATED_END}${section.after}`;
|
|
|
6525
6573
|
throw new Error(`Markers mismatched in ${fileLabel}`);
|
|
6526
6574
|
}
|
|
6527
6575
|
}
|
|
6576
|
+
function removeMarkerSection(existing, fileLabel, markers = DEFAULT_MARKERS) {
|
|
6577
|
+
const section = parseMarkers(existing, markers);
|
|
6578
|
+
switch (section.kind) {
|
|
6579
|
+
case "no_markers":
|
|
6580
|
+
return existing;
|
|
6581
|
+
case "ok": {
|
|
6582
|
+
const after = section.after.replace(/^\r?\n/, "");
|
|
6583
|
+
return section.before + after;
|
|
6584
|
+
}
|
|
6585
|
+
case "missing_start":
|
|
6586
|
+
case "missing_end":
|
|
6587
|
+
case "multiple_pairs":
|
|
6588
|
+
case "wrong_order":
|
|
6589
|
+
throw new Error(`Markers mismatched in ${fileLabel}`);
|
|
6590
|
+
}
|
|
6591
|
+
}
|
|
6528
6592
|
function lineStartOffset(content, lineIdx) {
|
|
6529
6593
|
if (lineIdx === 0) return 0;
|
|
6530
6594
|
let offset = 0;
|
|
@@ -6965,6 +7029,8 @@ export {
|
|
|
6965
7029
|
IsoTimestampSchema,
|
|
6966
7030
|
JSON_SCHEMA_VERSION,
|
|
6967
7031
|
ManifestSchema,
|
|
7032
|
+
PROTOCOL_END,
|
|
7033
|
+
PROTOCOL_START,
|
|
6968
7034
|
RiskLevelSchema,
|
|
6969
7035
|
STUCK_THRESHOLD_MS,
|
|
6970
7036
|
SchemaVersionSchema,
|
|
@@ -7055,6 +7121,7 @@ export {
|
|
|
7055
7121
|
reconcileTask,
|
|
7056
7122
|
refreshTaskLinkedSessions,
|
|
7057
7123
|
reimportPreservingId,
|
|
7124
|
+
removeMarkerSection,
|
|
7058
7125
|
renderDecisions,
|
|
7059
7126
|
renderHandoff,
|
|
7060
7127
|
renderOrientation,
|