@basou/core 0.7.0 → 0.8.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 +58 -1
- package/dist/index.js +146 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/session-import.schema.json +5 -0
- package/schemas/session.schema.json +5 -0
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,7 @@ declare const SessionInnerImportSchema: z.ZodObject<{
|
|
|
112
112
|
}>;
|
|
113
113
|
version: z.ZodLiteral<"0.1.0">;
|
|
114
114
|
external_id: z.ZodOptional<z.ZodString>;
|
|
115
|
+
source_size_bytes: z.ZodOptional<z.ZodNumber>;
|
|
115
116
|
}, z.core.$strip>;
|
|
116
117
|
started_at: z.ZodString;
|
|
117
118
|
ended_at: z.ZodOptional<z.ZodString>;
|
|
@@ -172,6 +173,7 @@ declare const SessionImportPayloadSchema: z.ZodObject<{
|
|
|
172
173
|
}>;
|
|
173
174
|
version: z.ZodLiteral<"0.1.0">;
|
|
174
175
|
external_id: z.ZodOptional<z.ZodString>;
|
|
176
|
+
source_size_bytes: z.ZodOptional<z.ZodNumber>;
|
|
175
177
|
}, z.core.$strip>;
|
|
176
178
|
started_at: z.ZodString;
|
|
177
179
|
ended_at: z.ZodOptional<z.ZodString>;
|
|
@@ -451,6 +453,14 @@ type ClaudeTranscriptToPayloadOptions = {
|
|
|
451
453
|
* back to the `sessionId` read from the records when omitted.
|
|
452
454
|
*/
|
|
453
455
|
externalId?: string;
|
|
456
|
+
/**
|
|
457
|
+
* Byte size of the source transcript that produced `records`, stored as
|
|
458
|
+
* `session.source.source_size_bytes` so a later import can detect growth and
|
|
459
|
+
* re-import the session. The caller passes the size of the buffer it actually
|
|
460
|
+
* read (an immutable snapshot of the parsed bytes), so the stored size always
|
|
461
|
+
* matches the imported content. Omitted => the field is not recorded.
|
|
462
|
+
*/
|
|
463
|
+
sourceSizeBytes?: number;
|
|
454
464
|
};
|
|
455
465
|
/**
|
|
456
466
|
* Transform a Claude Code native transcript into a Basou
|
|
@@ -506,6 +516,14 @@ type CodexRolloutToPayloadOptions = {
|
|
|
506
516
|
* to the id read from the rollout's `session_meta` record when omitted.
|
|
507
517
|
*/
|
|
508
518
|
externalId?: string;
|
|
519
|
+
/**
|
|
520
|
+
* Byte size of the source rollout that produced `records`, stored as
|
|
521
|
+
* `session.source.source_size_bytes` so a later import can detect growth and
|
|
522
|
+
* re-import the session. The caller passes the size of the buffer it actually
|
|
523
|
+
* read (an immutable snapshot of the parsed bytes), so the stored size always
|
|
524
|
+
* matches the imported content. Omitted => the field is not recorded.
|
|
525
|
+
*/
|
|
526
|
+
sourceSizeBytes?: number;
|
|
509
527
|
};
|
|
510
528
|
/**
|
|
511
529
|
* Transform a Codex native rollout log into a Basou {@link SessionImportPayload},
|
|
@@ -1350,6 +1368,7 @@ declare const SessionSchema: z.ZodObject<{
|
|
|
1350
1368
|
}>;
|
|
1351
1369
|
version: z.ZodLiteral<"0.1.0">;
|
|
1352
1370
|
external_id: z.ZodOptional<z.ZodString>;
|
|
1371
|
+
source_size_bytes: z.ZodOptional<z.ZodNumber>;
|
|
1353
1372
|
}, z.core.$strip>;
|
|
1354
1373
|
started_at: z.ZodString;
|
|
1355
1374
|
ended_at: z.ZodOptional<z.ZodString>;
|
|
@@ -3306,6 +3325,44 @@ type ImportSessionResult = {
|
|
|
3306
3325
|
* for `--verbose` rendering.
|
|
3307
3326
|
*/
|
|
3308
3327
|
declare function importSessionFromJson(paths: BasouPaths, manifest: Manifest, payload: SessionImportPayload, options: ImportSessionOptions): Promise<ImportSessionResult>;
|
|
3328
|
+
/** Whether `source` is one of the known import-derived event sources. */
|
|
3329
|
+
declare function isImportDerivedSource(source: string): boolean;
|
|
3330
|
+
/** Options for {@link reimportPreservingId}. */
|
|
3331
|
+
type ReimportOptions = {
|
|
3332
|
+
/** Compute the re-import and return its preview without writing to disk. */
|
|
3333
|
+
dryRun?: boolean;
|
|
3334
|
+
};
|
|
3335
|
+
/** Result of {@link reimportPreservingId}. */
|
|
3336
|
+
type ReimportResult = {
|
|
3337
|
+
status: "reimported";
|
|
3338
|
+
sessionId: PrefixedId<"ses">;
|
|
3339
|
+
/** Total events written to the merged `events.jsonl`. */
|
|
3340
|
+
eventCount: number;
|
|
3341
|
+
/** Non-derived events (human / unknown source) carried over unchanged. */
|
|
3342
|
+
preservedCount: number;
|
|
3343
|
+
/** Derived events whose prior id (and decision_id) was reused. */
|
|
3344
|
+
reusedIdCount: number;
|
|
3345
|
+
} | {
|
|
3346
|
+
status: "skipped";
|
|
3347
|
+
reason: "prior_events_unreadable" | "prior_derived_dropped";
|
|
3348
|
+
};
|
|
3349
|
+
/**
|
|
3350
|
+
* Re-import a source whose native log GREW into the SAME Basou session,
|
|
3351
|
+
* preserving its id and any non-derived events, instead of skipping it (default
|
|
3352
|
+
* dedup) or deleting + recreating it (`--force`). The caller has already
|
|
3353
|
+
* validated `freshPayload` and confirmed (by source byte size) that the source
|
|
3354
|
+
* changed; this function re-derives the adapter's events, reuses prior derived
|
|
3355
|
+
* event ids for unchanged derivations (so `linked_events` references survive),
|
|
3356
|
+
* preserves human / unknown-source events, and rewrites `events.jsonl` +
|
|
3357
|
+
* `session.yaml` atomically under the session lock.
|
|
3358
|
+
*
|
|
3359
|
+
* The whole read-modify-write runs under {@link acquireLock} so a concurrent
|
|
3360
|
+
* writer cannot interleave; `dryRun` computes the result and writes nothing
|
|
3361
|
+
* (and takes no lock). If the prior `events.jsonl` has any line that cannot be
|
|
3362
|
+
* preserved (malformed / schema-invalid / half-written), the re-import is
|
|
3363
|
+
* ABORTED (`status: "skipped"`) rather than risk dropping data on the rewrite.
|
|
3364
|
+
*/
|
|
3365
|
+
declare function reimportPreservingId(paths: BasouPaths, manifest: Manifest, priorSessionId: string, freshPayload: SessionImportPayload, options?: ReimportOptions): Promise<ReimportResult>;
|
|
3309
3366
|
|
|
3310
3367
|
/**
|
|
3311
3368
|
* Walk the cause chain (up to `depth` levels) looking for an Error whose
|
|
@@ -3407,4 +3464,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
|
|
|
3407
3464
|
*/
|
|
3408
3465
|
declare const BASOU_CORE_VERSION = "0.1.0";
|
|
3409
3466
|
|
|
3410
|
-
export { ACTIVE_GAP_CAP_MS, type ActiveTimeBasis, type AdapterOutputEvent, type AppendBasouGitignoreResult, type AppendEventToExistingInput, type AppendEventToExistingResult, type Approval, type ApprovalApprovedEvent, type ApprovalExpiredEvent, ApprovalIdSchema, type ApprovalLocation, type ApprovalRejectedEvent, type ApprovalRequestedEvent, ApprovalSchema, type ApprovalStatus, ApprovalStatusSchema, type ArchiveTaskInput, type ArchiveTaskResult, type AttachTaskInput, type AttachUpdateTaskStatusInput, type AttachableStatus, BASOU_CORE_VERSION, type BasouPaths, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, ChildProcessRunner, 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, FailedToFinalizeError, type FileChange, type FileChangeStatus, type FileChangedEvent, GENERATED_END, GENERATED_START, type GitSnapshot, type GitSnapshotEvent, type HandoffRendererInput, type HandoffRendererResult, ID_PREFIXES, type IdPrefix, type ImportSessionOptions, type ImportSessionResult, 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 PrefixedId, type ProcessRunner, type ReconcileAllResult, type ReconcileAllTasksInput, type ReconcileAllTasksOptions, type ReconcileFailure, type ReconcileResult, type ReconcileTaskInput, type RefreshLinkageInput, type RefreshLinkageResult, type ReplayOptions, type ReplayWarning, type RiskLevel, RiskLevelSchema, 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 SessionMetrics, SessionMetricsSchema, SessionSchema, type SessionSkipReason, type SessionSourceKind, SessionSourceKindSchema, type SessionStartedEvent, type SessionStatus, type SessionStatusChangedEvent, SessionStatusSchema, type SessionWorkStats, type SourceWorkStats, type StatusCount, StatusSchema, type StatusSnapshot, type SuspectReason, type Task, type TaskArchivedEvent, type TaskCreatedEvent, type TaskDeletedEvent, type TaskDocument, TaskIdSchema, type TaskLinkageRefreshedEvent, type TaskReconciledEvent, TaskSchema, type TaskSkipReason, type TaskStatus, type TaskStatusChangedEvent, TaskStatusSchema, TaskWriteAfterEventError, type TaskWriteAfterEventPhase, type TokenTotals, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type WorkStatsInput, type WorkStatsResult, type WorkStatsTotals, WorkspaceIdSchema, type WriteTaskFileMode, acquireLock, appendBasouGitignore, appendEvent, appendEventToExistingSession, archiveTask, assertBasouRootSafe, basouPaths, buildJsonSchemas, buildStatusSnapshot, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, findErrorCode, getDiff, getSnapshot, importSessionFromJson, isLazyExpired, isValidPrefixedId, linkYamlFile, loadApproval, loadSessionEntries, loadTaskEntries, overwriteYamlFile, parseDuration, parseMarkers, prefixedUlid, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, reconcileAllTasks, reconcileTask, refreshTaskLinkedSessions, renderDecisions, renderHandoff, renderWithMarkers, replayEvents, resolveClaudeCodeCommand, resolveRepositoryRoot, resolveSessionId, resolveTaskId, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, tryRemoteUrl, ulid, updateTaskStatusWithEvent, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
|
3467
|
+
export { ACTIVE_GAP_CAP_MS, type ActiveTimeBasis, type AdapterOutputEvent, type AppendBasouGitignoreResult, type AppendEventToExistingInput, type AppendEventToExistingResult, type Approval, type ApprovalApprovedEvent, type ApprovalExpiredEvent, ApprovalIdSchema, type ApprovalLocation, type ApprovalRejectedEvent, type ApprovalRequestedEvent, ApprovalSchema, type ApprovalStatus, ApprovalStatusSchema, type ArchiveTaskInput, type ArchiveTaskResult, type AttachTaskInput, type AttachUpdateTaskStatusInput, type AttachableStatus, BASOU_CORE_VERSION, type BasouPaths, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, ChildProcessRunner, 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, FailedToFinalizeError, type FileChange, type FileChangeStatus, type FileChangedEvent, GENERATED_END, GENERATED_START, type GitSnapshot, type GitSnapshotEvent, type HandoffRendererInput, type HandoffRendererResult, ID_PREFIXES, type IdPrefix, type ImportSessionOptions, type ImportSessionResult, 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 PrefixedId, type ProcessRunner, type ReconcileAllResult, type ReconcileAllTasksInput, type ReconcileAllTasksOptions, type ReconcileFailure, type ReconcileResult, type ReconcileTaskInput, type RefreshLinkageInput, type RefreshLinkageResult, type ReimportOptions, type ReimportResult, type ReplayOptions, type ReplayWarning, type RiskLevel, RiskLevelSchema, 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 SessionMetrics, SessionMetricsSchema, SessionSchema, type SessionSkipReason, type SessionSourceKind, SessionSourceKindSchema, type SessionStartedEvent, type SessionStatus, type SessionStatusChangedEvent, SessionStatusSchema, type SessionWorkStats, type SourceWorkStats, type StatusCount, StatusSchema, type StatusSnapshot, type SuspectReason, type Task, type TaskArchivedEvent, type TaskCreatedEvent, type TaskDeletedEvent, type TaskDocument, TaskIdSchema, type TaskLinkageRefreshedEvent, type TaskReconciledEvent, TaskSchema, type TaskSkipReason, type TaskStatus, type TaskStatusChangedEvent, TaskStatusSchema, TaskWriteAfterEventError, type TaskWriteAfterEventPhase, type TokenTotals, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type WorkStatsInput, type WorkStatsResult, type WorkStatsTotals, WorkspaceIdSchema, type WriteTaskFileMode, acquireLock, appendBasouGitignore, appendEvent, appendEventToExistingSession, archiveTask, assertBasouRootSafe, basouPaths, buildJsonSchemas, buildStatusSnapshot, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, findErrorCode, getDiff, getSnapshot, importSessionFromJson, isImportDerivedSource, isLazyExpired, isValidPrefixedId, linkYamlFile, loadApproval, loadSessionEntries, loadTaskEntries, overwriteYamlFile, parseDuration, parseMarkers, prefixedUlid, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, reconcileAllTasks, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, renderDecisions, renderHandoff, renderWithMarkers, replayEvents, resolveClaudeCodeCommand, resolveRepositoryRoot, resolveSessionId, resolveTaskId, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, tryRemoteUrl, ulid, updateTaskStatusWithEvent, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
package/dist/index.js
CHANGED
|
@@ -224,7 +224,8 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
224
224
|
source: {
|
|
225
225
|
kind: CLAUDE_IMPORT_SOURCE,
|
|
226
226
|
version: "0.1.0",
|
|
227
|
-
...externalId !== void 0 ? { external_id: externalId } : {}
|
|
227
|
+
...externalId !== void 0 ? { external_id: externalId } : {},
|
|
228
|
+
...options.sourceSizeBytes !== void 0 ? { source_size_bytes: options.sourceSizeBytes } : {}
|
|
228
229
|
},
|
|
229
230
|
started_at: minTs,
|
|
230
231
|
ended_at: maxTs,
|
|
@@ -457,7 +458,8 @@ function codexRolloutToImportPayload(records, options) {
|
|
|
457
458
|
source: {
|
|
458
459
|
kind: CODEX_IMPORT_SOURCE,
|
|
459
460
|
version: "0.1.0",
|
|
460
|
-
...externalId !== void 0 ? { external_id: externalId } : {}
|
|
461
|
+
...externalId !== void 0 ? { external_id: externalId } : {},
|
|
462
|
+
...options.sourceSizeBytes !== void 0 ? { source_size_bytes: options.sourceSizeBytes } : {}
|
|
461
463
|
},
|
|
462
464
|
started_at: minTs,
|
|
463
465
|
ended_at: maxTs,
|
|
@@ -1032,7 +1034,15 @@ var SessionSourceSchema = z4.object({
|
|
|
1032
1034
|
// Optional id of the originating session in the SOURCE tool's own
|
|
1033
1035
|
// namespace (e.g. the Claude Code session UUID for a `claude-code-import`).
|
|
1034
1036
|
// Lets re-imports of the same source be deduplicated; absent for live runs.
|
|
1035
|
-
external_id: z4.string().optional()
|
|
1037
|
+
external_id: z4.string().optional(),
|
|
1038
|
+
// Byte size of the source native log at import time, recorded so a later
|
|
1039
|
+
// import can detect that an append-only transcript GREW and re-import it
|
|
1040
|
+
// (scoped, preserving the session id) instead of skipping it as already
|
|
1041
|
+
// imported. Additive optional => no schema_version bump (precedent:
|
|
1042
|
+
// external_id, metrics). Absent on sessions imported before this field
|
|
1043
|
+
// existed (treated as legacy: never auto-re-imported, populated on the next
|
|
1044
|
+
// fresh import or `--force`).
|
|
1045
|
+
source_size_bytes: z4.number().int().nonnegative().optional()
|
|
1036
1046
|
});
|
|
1037
1047
|
var InvocationSchema = z4.object({
|
|
1038
1048
|
command: z4.string().min(1),
|
|
@@ -3922,7 +3932,13 @@ var SessionInnerImportSchema = z10.object({
|
|
|
3922
3932
|
version: z10.literal("0.1.0"),
|
|
3923
3933
|
// Source-tool-native id (e.g. Claude Code session UUID), retained so
|
|
3924
3934
|
// re-imports of the same source can be deduplicated.
|
|
3925
|
-
external_id: z10.string().optional()
|
|
3935
|
+
external_id: z10.string().optional(),
|
|
3936
|
+
// Byte size of the source native log at import time. Declared here too
|
|
3937
|
+
// (not only in session.schema.ts) because this inner `source` object is
|
|
3938
|
+
// a plain z.object: zod strips keys it does not declare, so a field
|
|
3939
|
+
// absent here would be dropped from the parsed payload before persist
|
|
3940
|
+
// and the size could never be stored.
|
|
3941
|
+
source_size_bytes: z10.number().int().nonnegative().optional()
|
|
3926
3942
|
}),
|
|
3927
3943
|
started_at: IsoTimestampSchema,
|
|
3928
3944
|
ended_at: IsoTimestampSchema.optional(),
|
|
@@ -4731,6 +4747,130 @@ function buildSessionRecord(input, manifest, newSessionId, options) {
|
|
|
4731
4747
|
}
|
|
4732
4748
|
};
|
|
4733
4749
|
}
|
|
4750
|
+
var IMPORT_DERIVED_SOURCES = /* @__PURE__ */ new Set([
|
|
4751
|
+
"claude-code-import",
|
|
4752
|
+
"codex-import"
|
|
4753
|
+
]);
|
|
4754
|
+
function isImportDerivedSource(source) {
|
|
4755
|
+
return IMPORT_DERIVED_SOURCES.has(source);
|
|
4756
|
+
}
|
|
4757
|
+
function derivedEventContentKey(event) {
|
|
4758
|
+
const base = `${event.type}\0${event.occurred_at}`;
|
|
4759
|
+
switch (event.type) {
|
|
4760
|
+
case "command_executed":
|
|
4761
|
+
return `${base}\0${event.command}\0${event.args.join("")}\0${event.cwd}`;
|
|
4762
|
+
case "file_changed":
|
|
4763
|
+
return `${base}\0${event.path}\0${event.change_type}`;
|
|
4764
|
+
case "decision_recorded":
|
|
4765
|
+
return `${base}\0${event.title}`;
|
|
4766
|
+
default:
|
|
4767
|
+
return base;
|
|
4768
|
+
}
|
|
4769
|
+
}
|
|
4770
|
+
function reuseDerivedIds(priorDerived, freshDerived, sessionId) {
|
|
4771
|
+
const priorStarted = priorDerived.find((e) => e.type === "session_started");
|
|
4772
|
+
const priorEnded = priorDerived.find((e) => e.type === "session_ended");
|
|
4773
|
+
let startedUsed = false;
|
|
4774
|
+
let endedUsed = false;
|
|
4775
|
+
const middleByKey = /* @__PURE__ */ new Map();
|
|
4776
|
+
for (const e of priorDerived) {
|
|
4777
|
+
if (e.type === "session_started" || e.type === "session_ended") continue;
|
|
4778
|
+
const key = derivedEventContentKey(e);
|
|
4779
|
+
const list = middleByKey.get(key);
|
|
4780
|
+
if (list === void 0) middleByKey.set(key, [e]);
|
|
4781
|
+
else list.push(e);
|
|
4782
|
+
}
|
|
4783
|
+
let reusedIdCount = 0;
|
|
4784
|
+
const withReusedId = (fresh, prior) => {
|
|
4785
|
+
reusedIdCount++;
|
|
4786
|
+
if (fresh.type === "decision_recorded" && prior.type === "decision_recorded") {
|
|
4787
|
+
return { ...fresh, id: prior.id, session_id: sessionId, decision_id: prior.decision_id };
|
|
4788
|
+
}
|
|
4789
|
+
return { ...fresh, id: prior.id, session_id: sessionId };
|
|
4790
|
+
};
|
|
4791
|
+
const events = freshDerived.map((fresh) => {
|
|
4792
|
+
if (fresh.type === "session_started") {
|
|
4793
|
+
if (priorStarted !== void 0) {
|
|
4794
|
+
startedUsed = true;
|
|
4795
|
+
return withReusedId(fresh, priorStarted);
|
|
4796
|
+
}
|
|
4797
|
+
return { ...fresh, id: prefixedUlid("evt"), session_id: sessionId };
|
|
4798
|
+
}
|
|
4799
|
+
if (fresh.type === "session_ended") {
|
|
4800
|
+
if (priorEnded !== void 0) {
|
|
4801
|
+
endedUsed = true;
|
|
4802
|
+
return withReusedId(fresh, priorEnded);
|
|
4803
|
+
}
|
|
4804
|
+
return { ...fresh, id: prefixedUlid("evt"), session_id: sessionId };
|
|
4805
|
+
}
|
|
4806
|
+
const match = middleByKey.get(derivedEventContentKey(fresh))?.shift();
|
|
4807
|
+
if (match !== void 0) return withReusedId(fresh, match);
|
|
4808
|
+
return { ...fresh, id: prefixedUlid("evt"), session_id: sessionId };
|
|
4809
|
+
});
|
|
4810
|
+
const droppedPriorDerived = priorStarted !== void 0 && !startedUsed || priorEnded !== void 0 && !endedUsed || [...middleByKey.values()].some((q) => q.length > 0);
|
|
4811
|
+
return { events, reusedIdCount, droppedPriorDerived };
|
|
4812
|
+
}
|
|
4813
|
+
async function reimportPreservingId(paths, manifest, priorSessionId, freshPayload, options = {}) {
|
|
4814
|
+
const sessionId = priorSessionId;
|
|
4815
|
+
const importSource = freshPayload.session.source.kind;
|
|
4816
|
+
const sessionDir = join14(paths.sessions, priorSessionId);
|
|
4817
|
+
const lock = options.dryRun === true ? null : await acquireLock(paths, "session", priorSessionId);
|
|
4818
|
+
try {
|
|
4819
|
+
let priorUnreadable = false;
|
|
4820
|
+
const priorEvents = await readAllEvents(sessionDir, {
|
|
4821
|
+
onWarning: () => {
|
|
4822
|
+
priorUnreadable = true;
|
|
4823
|
+
}
|
|
4824
|
+
});
|
|
4825
|
+
if (priorUnreadable) {
|
|
4826
|
+
return { status: "skipped", reason: "prior_events_unreadable" };
|
|
4827
|
+
}
|
|
4828
|
+
const priorDerived = priorEvents.filter((e) => e.source === importSource);
|
|
4829
|
+
const preserved = priorEvents.filter((e) => e.source !== importSource);
|
|
4830
|
+
const {
|
|
4831
|
+
events: rederived,
|
|
4832
|
+
reusedIdCount,
|
|
4833
|
+
droppedPriorDerived
|
|
4834
|
+
} = reuseDerivedIds(priorDerived, freshPayload.events, sessionId);
|
|
4835
|
+
if (droppedPriorDerived) {
|
|
4836
|
+
return { status: "skipped", reason: "prior_derived_dropped" };
|
|
4837
|
+
}
|
|
4838
|
+
const mergedEvents = [...rederived, ...preserved].sort(
|
|
4839
|
+
(a, b) => Date.parse(a.occurred_at) - Date.parse(b.occurred_at)
|
|
4840
|
+
);
|
|
4841
|
+
assertChronologicalOrder(mergedEvents);
|
|
4842
|
+
const prior = await readSessionYaml(paths, priorSessionId);
|
|
4843
|
+
const { record } = buildSessionRecord(freshPayload.session, manifest, sessionId, {});
|
|
4844
|
+
const preservedInner = {
|
|
4845
|
+
...record.session,
|
|
4846
|
+
// A human may have linked this imported session to a task
|
|
4847
|
+
// (`basou task link` updates session.yaml.task_id even for imported
|
|
4848
|
+
// sessions); never drop that link on a re-derive.
|
|
4849
|
+
task_id: prior.session.task_id ?? null,
|
|
4850
|
+
// Re-derivation always yields a null summary; keep a prior non-null one.
|
|
4851
|
+
summary: prior.session.summary ?? record.session.summary ?? null
|
|
4852
|
+
};
|
|
4853
|
+
const updatedRecord = { schema_version: "0.1.0", session: preservedInner };
|
|
4854
|
+
if (options.dryRun !== true) {
|
|
4855
|
+
await writeEventsBulk(sessionDir, mergedEvents);
|
|
4856
|
+
try {
|
|
4857
|
+
await overwriteYamlFile(join14(sessionDir, "session.yaml"), updatedRecord);
|
|
4858
|
+
} catch (error) {
|
|
4859
|
+
await writeEventsBulk(sessionDir, priorEvents).catch(() => void 0);
|
|
4860
|
+
throw error;
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
return {
|
|
4864
|
+
status: "reimported",
|
|
4865
|
+
sessionId,
|
|
4866
|
+
eventCount: mergedEvents.length,
|
|
4867
|
+
preservedCount: preserved.length,
|
|
4868
|
+
reusedIdCount
|
|
4869
|
+
};
|
|
4870
|
+
} finally {
|
|
4871
|
+
await lock?.release();
|
|
4872
|
+
}
|
|
4873
|
+
}
|
|
4734
4874
|
|
|
4735
4875
|
// src/index.ts
|
|
4736
4876
|
var BASOU_CORE_VERSION = "0.1.0";
|
|
@@ -4798,6 +4938,7 @@ export {
|
|
|
4798
4938
|
getDiff,
|
|
4799
4939
|
getSnapshot,
|
|
4800
4940
|
importSessionFromJson,
|
|
4941
|
+
isImportDerivedSource,
|
|
4801
4942
|
isLazyExpired,
|
|
4802
4943
|
isValidPrefixedId,
|
|
4803
4944
|
linkYamlFile,
|
|
@@ -4819,6 +4960,7 @@ export {
|
|
|
4819
4960
|
reconcileAllTasks,
|
|
4820
4961
|
reconcileTask,
|
|
4821
4962
|
refreshTaskLinkedSessions,
|
|
4963
|
+
reimportPreservingId,
|
|
4822
4964
|
renderDecisions,
|
|
4823
4965
|
renderHandoff,
|
|
4824
4966
|
renderWithMarkers,
|