@basou/core 0.19.0 → 0.21.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 +65 -5
- package/dist/index.js +176 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -570,10 +570,14 @@ type ClaudeTranscriptToPayloadOptions = {
|
|
|
570
570
|
* - `command_executed` from each `Bash` tool use, recorded as `bash -c "<cmd>"`
|
|
571
571
|
* (the transcript carries the shell line, not a parsed argv).
|
|
572
572
|
* - `file_changed` from each `Edit` / `Write` / `NotebookEdit` tool use.
|
|
573
|
-
* - `decision_recorded` from each `AskUserQuestion` tool use
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
* question
|
|
573
|
+
* - `decision_recorded` from each `AskUserQuestion` tool use, but ONLY when the
|
|
574
|
+
* recorded answer is a confirmed SELECTION — it exactly matches an option the
|
|
575
|
+
* question offered (`input.questions[].options[].label`). One decision per
|
|
576
|
+
* such question, titled `<question> -> <chosen answer>`. The answer is read
|
|
577
|
+
* from the paired result record's `toolUseResult.answers` map; a question with
|
|
578
|
+
* no recorded answer, or a free-text "Other" reply that matches no offered
|
|
579
|
+
* label, is skipped (it is not a decision, and would otherwise pollute
|
|
580
|
+
* decisions.md / orientation's latest-decision surface).
|
|
577
581
|
*
|
|
578
582
|
* Exit codes and per-command durations are not present in the transcript, so
|
|
579
583
|
* `command_executed.exit_code` is `null` and `duration_ms` is `0`.
|
|
@@ -588,6 +592,62 @@ type ClaudeTranscriptToPayloadOptions = {
|
|
|
588
592
|
*/
|
|
589
593
|
declare function claudeTranscriptToImportPayload(records: ReadonlyArray<ClaudeTranscriptRecord>, options: ClaudeTranscriptToPayloadOptions): SessionImportPayload | null;
|
|
590
594
|
|
|
595
|
+
/**
|
|
596
|
+
* Default minimum number of "action" tool uses (Bash commands + file edits) a
|
|
597
|
+
* session must contain before the Stop-hook nudge treats it as substantive
|
|
598
|
+
* enough to be worth a session-end capture. Below this the session reads as a
|
|
599
|
+
* trivial check / quick question and the hook stays silent rather than nagging.
|
|
600
|
+
*/
|
|
601
|
+
declare const DEFAULT_STOP_HOOK_MIN_ACTIONS = 5;
|
|
602
|
+
type StopHookEvaluationInput = {
|
|
603
|
+
/**
|
|
604
|
+
* Parsed transcript records, one per JSONL line of the current session's
|
|
605
|
+
* transcript. The caller drops malformed lines; this function reads every
|
|
606
|
+
* field defensively, like the importer, since the format is undocumented.
|
|
607
|
+
*/
|
|
608
|
+
records: ReadonlyArray<ClaudeTranscriptRecord>;
|
|
609
|
+
/**
|
|
610
|
+
* The Stop hook's `stop_hook_active` stdin flag: true when Claude is already
|
|
611
|
+
* continuing because of a previous Stop-hook response. When true the nudge
|
|
612
|
+
* stays silent so it can never form a continuation loop.
|
|
613
|
+
*/
|
|
614
|
+
stopHookActive: boolean;
|
|
615
|
+
/** Override the substantive-work threshold (defaults to {@link DEFAULT_STOP_HOOK_MIN_ACTIONS}). */
|
|
616
|
+
minActions?: number;
|
|
617
|
+
};
|
|
618
|
+
/** Why the hook stayed silent (useful for tests and `--json` introspection). */
|
|
619
|
+
type StopHookSilentReason = "stop_hook_active" | "not_substantive" | "already_captured";
|
|
620
|
+
type StopHookEvaluation = {
|
|
621
|
+
kind: "silent";
|
|
622
|
+
reason: StopHookSilentReason;
|
|
623
|
+
commandCount: number;
|
|
624
|
+
fileCount: number;
|
|
625
|
+
} | {
|
|
626
|
+
kind: "nudge";
|
|
627
|
+
additionalContext: string;
|
|
628
|
+
commandCount: number;
|
|
629
|
+
fileCount: number;
|
|
630
|
+
};
|
|
631
|
+
/**
|
|
632
|
+
* Decide whether a finished turn warrants a non-blocking capture nudge.
|
|
633
|
+
*
|
|
634
|
+
* Pure: no disk or environment access. The CLI handler reads the Stop hook's
|
|
635
|
+
* stdin payload and the transcript file, parses the JSONL into `records`, and
|
|
636
|
+
* passes them here. A `nudge` result is rendered as
|
|
637
|
+
* `hookSpecificOutput.additionalContext` (non-blocking — Claude may act on it
|
|
638
|
+
* or stop); a `silent` result emits nothing.
|
|
639
|
+
*
|
|
640
|
+
* The nudge fires only when ALL hold:
|
|
641
|
+
* - not already continuing from a prior nudge (`stopHookActive` is false), so
|
|
642
|
+
* the hook never loops;
|
|
643
|
+
* - the session did substantive work (>= `minActions` Bash commands + edits),
|
|
644
|
+
* so trivial check sessions are left alone;
|
|
645
|
+
* - no capture verb (`basou decision capture` / `decision record` / `note`)
|
|
646
|
+
* was run this session, so a session that already recorded its intent is
|
|
647
|
+
* left alone.
|
|
648
|
+
*/
|
|
649
|
+
declare function evaluateStopHook(input: StopHookEvaluationInput): StopHookEvaluation;
|
|
650
|
+
|
|
591
651
|
/**
|
|
592
652
|
* The `source` string stamped on every event derived from an OpenAI Codex
|
|
593
653
|
* native rollout log, and the matching session `source.kind`.
|
|
@@ -5519,4 +5579,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
|
|
|
5519
5579
|
*/
|
|
5520
5580
|
declare const BASOU_CORE_VERSION = "0.1.0";
|
|
5521
5581
|
|
|
5522
|
-
export { ACTIVE_GAP_CAP_MS, AGENT_INFRA_DIRS, 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 FederatedRoot, 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 LoadFederatedOptions, 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 SourceRootScope, 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, classifyFilesBySourceRoot, 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, loadFederatedSessionEntries, 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 };
|
|
5582
|
+
export { ACTIVE_GAP_CAP_MS, AGENT_INFRA_DIRS, 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, DEFAULT_STOP_HOOK_MIN_ACTIONS, 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 FederatedRoot, 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 LoadFederatedOptions, 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 SourceRootScope, type SourceRootsReconcile, type SourceWorkStats, type StatusCount, StatusSchema, type StatusSnapshot, type StopHookEvaluation, type StopHookEvaluationInput, type StopHookSilentReason, 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, classifyFilesBySourceRoot, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, evaluateStopHook, finalizeSessionYaml, findErrorCode, findReviewGaps, formatDurationMs, genesisHash, getDiff, getSnapshot, importSessionFromJson, inspectChainTail, isGitNotFound, isImportDerivedSource, isLazyExpired, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadFederatedSessionEntries, 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
|
@@ -21,6 +21,73 @@ function summarizeAdapterOutput(_stream, _raw) {
|
|
|
21
21
|
throw new Error("adapter_output summary is not implemented in this release");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// src/adapters/claude-code/stop-hook.ts
|
|
25
|
+
var DEFAULT_STOP_HOOK_MIN_ACTIONS = 5;
|
|
26
|
+
var CAPTURE_COMMAND_PATTERN = /(?:^|[\n;&|(])\s*basou\s+(?:decision\s+(?:capture|record)|note)\b/;
|
|
27
|
+
var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "NotebookEdit"]);
|
|
28
|
+
function evaluateStopHook(input) {
|
|
29
|
+
const minActions = input.minActions ?? DEFAULT_STOP_HOOK_MIN_ACTIONS;
|
|
30
|
+
if (input.stopHookActive) {
|
|
31
|
+
return { kind: "silent", reason: "stop_hook_active", commandCount: 0, fileCount: 0 };
|
|
32
|
+
}
|
|
33
|
+
let commandCount = 0;
|
|
34
|
+
let fileCount = 0;
|
|
35
|
+
let captured = false;
|
|
36
|
+
for (const record of input.records) {
|
|
37
|
+
if (readString(record.type) !== "assistant") continue;
|
|
38
|
+
for (const tool of toolUsesOf(record)) {
|
|
39
|
+
const name = readString(tool.name);
|
|
40
|
+
if (name === void 0) continue;
|
|
41
|
+
if (name === "Bash") {
|
|
42
|
+
commandCount += 1;
|
|
43
|
+
const input2 = isObject(tool.input) ? tool.input : void 0;
|
|
44
|
+
const command = input2 !== void 0 ? readString(input2.command) : void 0;
|
|
45
|
+
if (command !== void 0 && CAPTURE_COMMAND_PATTERN.test(command)) captured = true;
|
|
46
|
+
} else if (FILE_EDIT_TOOLS.has(name)) {
|
|
47
|
+
fileCount += 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (captured) {
|
|
52
|
+
return { kind: "silent", reason: "already_captured", commandCount, fileCount };
|
|
53
|
+
}
|
|
54
|
+
if (commandCount + fileCount < minActions) {
|
|
55
|
+
return { kind: "silent", reason: "not_substantive", commandCount, fileCount };
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
kind: "nudge",
|
|
59
|
+
additionalContext: renderNudge(commandCount, fileCount),
|
|
60
|
+
commandCount,
|
|
61
|
+
fileCount
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function renderNudge(commandCount, fileCount) {
|
|
65
|
+
const ran = `${commandCount} ${commandCount === 1 ? "command" : "commands"}`;
|
|
66
|
+
const edited = `${fileCount} ${fileCount === 1 ? "file" : "files"}`;
|
|
67
|
+
return [
|
|
68
|
+
`This session ran ${ran} and edited ${edited} but recorded no decisions or next step.`,
|
|
69
|
+
"If meaningful decisions were made (the chosen approach, rejected alternatives, and why) or there is a clear next step, capture them now so the next session can resume correctly:",
|
|
70
|
+
' - Decisions: run `basou decision capture` and pipe a JSON array (one object per decision; "title" required, plus optional rationale/alternatives/rejected_reason/linked_files; set "kind":"track" for an unfinished strategic direction).',
|
|
71
|
+
' - Next step: run `basou note "<what you would do next>"`.',
|
|
72
|
+
"If nothing is worth capturing, just stop \u2014 do not invent decisions."
|
|
73
|
+
].join("\n");
|
|
74
|
+
}
|
|
75
|
+
function readString(value) {
|
|
76
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
77
|
+
}
|
|
78
|
+
function isObject(value) {
|
|
79
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
80
|
+
}
|
|
81
|
+
function toolUsesOf(record) {
|
|
82
|
+
const message = isObject(record.message) ? record.message : void 0;
|
|
83
|
+
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
84
|
+
const result = [];
|
|
85
|
+
for (const item of content) {
|
|
86
|
+
if (isObject(item) && readString(item.type) === "tool_use") result.push(item);
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
24
91
|
// src/ids/ulid.ts
|
|
25
92
|
import { isValid as isValidUlid, monotonicFactory } from "ulid";
|
|
26
93
|
var ID_PREFIXES = Object.freeze(["ws", "task", "ses", "evt", "appr", "decision"]);
|
|
@@ -128,21 +195,21 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
128
195
|
const engagementTsMs = [];
|
|
129
196
|
const seenEngagementMessageIds = /* @__PURE__ */ new Set();
|
|
130
197
|
for (const record of records) {
|
|
131
|
-
const ts =
|
|
198
|
+
const ts = readString2(record.timestamp);
|
|
132
199
|
if (ts === void 0) continue;
|
|
133
200
|
if (minTs === void 0 || Date.parse(ts) < Date.parse(minTs)) minTs = ts;
|
|
134
201
|
if (maxTs === void 0 || Date.parse(ts) > Date.parse(maxTs)) maxTs = ts;
|
|
135
|
-
if (workingDir === void 0) workingDir =
|
|
136
|
-
if (claudeSessionId === void 0) claudeSessionId =
|
|
202
|
+
if (workingDir === void 0) workingDir = readString2(record.cwd);
|
|
203
|
+
if (claudeSessionId === void 0) claudeSessionId = readString2(record.sessionId);
|
|
137
204
|
if (record.isSidechain !== true) {
|
|
138
205
|
const tsMs = Date.parse(ts);
|
|
139
206
|
if (Number.isFinite(tsMs)) {
|
|
140
|
-
const recType =
|
|
207
|
+
const recType = readString2(record.type);
|
|
141
208
|
if (recType === "user") {
|
|
142
209
|
if (isHumanUserMessage(record)) engagementTsMs.push(tsMs);
|
|
143
210
|
} else if (recType === "assistant") {
|
|
144
|
-
const msg =
|
|
145
|
-
const mid = msg !== void 0 ?
|
|
211
|
+
const msg = isObject2(record.message) ? record.message : void 0;
|
|
212
|
+
const mid = msg !== void 0 ? readString2(msg.id) : void 0;
|
|
146
213
|
if (mid === void 0 || !seenEngagementMessageIds.has(mid)) {
|
|
147
214
|
if (mid !== void 0) seenEngagementMessageIds.add(mid);
|
|
148
215
|
engagementTsMs.push(tsMs);
|
|
@@ -150,11 +217,11 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
150
217
|
}
|
|
151
218
|
}
|
|
152
219
|
}
|
|
153
|
-
if (
|
|
154
|
-
const message =
|
|
155
|
-
const usage = message !== void 0 &&
|
|
220
|
+
if (readString2(record.type) !== "assistant") continue;
|
|
221
|
+
const message = isObject2(record.message) ? record.message : void 0;
|
|
222
|
+
const usage = message !== void 0 && isObject2(message.usage) ? message.usage : void 0;
|
|
156
223
|
if (usage !== void 0) {
|
|
157
|
-
const messageId = message !== void 0 ?
|
|
224
|
+
const messageId = message !== void 0 ? readString2(message.id) : void 0;
|
|
158
225
|
const alreadyCounted = messageId !== void 0 && seenMessageIds.has(messageId);
|
|
159
226
|
if (!alreadyCounted) {
|
|
160
227
|
if (messageId !== void 0) seenMessageIds.add(messageId);
|
|
@@ -163,33 +230,38 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
163
230
|
cachedInputTokens += readNonNegInt(usage.cache_read_input_tokens);
|
|
164
231
|
}
|
|
165
232
|
}
|
|
166
|
-
const cwd =
|
|
233
|
+
const cwd = readString2(record.cwd) ?? workingDir ?? ".";
|
|
167
234
|
for (const item of toolUses(record)) {
|
|
168
|
-
const name =
|
|
169
|
-
const input =
|
|
235
|
+
const name = readString2(item.name);
|
|
236
|
+
const input = isObject2(item.input) ? item.input : void 0;
|
|
170
237
|
if (input === void 0) continue;
|
|
171
238
|
if (name === "Bash") {
|
|
172
|
-
const command =
|
|
239
|
+
const command = readString2(input.command);
|
|
173
240
|
if (command !== void 0) {
|
|
174
241
|
derived.push(commandExecutedEvent(ts, placeholderSessionId, command, cwd));
|
|
175
242
|
}
|
|
176
243
|
continue;
|
|
177
244
|
}
|
|
178
245
|
if (name === "AskUserQuestion") {
|
|
179
|
-
const useId =
|
|
246
|
+
const useId = readString2(item.id);
|
|
180
247
|
const answers = useId !== void 0 ? askAnswers.get(useId) : void 0;
|
|
181
248
|
if (answers !== void 0) {
|
|
249
|
+
const offeredByQuestion = readOfferedOptions(input);
|
|
182
250
|
for (const [question, answer] of Object.entries(answers)) {
|
|
183
251
|
if (question.length === 0) continue;
|
|
184
252
|
const answerStr = typeof answer === "string" && answer.length > 0 ? answer : void 0;
|
|
185
|
-
|
|
186
|
-
|
|
253
|
+
if (answerStr === void 0) continue;
|
|
254
|
+
const offered = offeredByQuestion.get(question);
|
|
255
|
+
if (offered === void 0 || !offered.has(answerStr.trim())) continue;
|
|
256
|
+
derived.push(
|
|
257
|
+
decisionRecordedEvent(ts, placeholderSessionId, `${question} -> ${answerStr}`)
|
|
258
|
+
);
|
|
187
259
|
}
|
|
188
260
|
}
|
|
189
261
|
continue;
|
|
190
262
|
}
|
|
191
263
|
if (name === "Edit" || name === "Write" || name === "NotebookEdit") {
|
|
192
|
-
const path2 =
|
|
264
|
+
const path2 = readString2(input.file_path) ?? readString2(input.notebook_path);
|
|
193
265
|
if (path2 !== void 0) {
|
|
194
266
|
const changeType = name === "Write" ? "added" : "modified";
|
|
195
267
|
relatedFiles.add(path2);
|
|
@@ -291,35 +363,35 @@ function decisionRecordedEvent(occurredAt, sessionId, title) {
|
|
|
291
363
|
title
|
|
292
364
|
};
|
|
293
365
|
}
|
|
294
|
-
function
|
|
366
|
+
function readString2(value) {
|
|
295
367
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
296
368
|
}
|
|
297
369
|
function readNonNegInt(value) {
|
|
298
370
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
299
371
|
}
|
|
300
|
-
function
|
|
372
|
+
function isObject2(value) {
|
|
301
373
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
302
374
|
}
|
|
303
375
|
function isHumanUserMessage(record) {
|
|
304
|
-
const message =
|
|
376
|
+
const message = isObject2(record.message) ? record.message : void 0;
|
|
305
377
|
if (message === void 0) return false;
|
|
306
378
|
const content = message.content;
|
|
307
379
|
if (typeof content === "string") return content.length > 0;
|
|
308
380
|
if (Array.isArray(content)) {
|
|
309
381
|
return content.some((block) => {
|
|
310
|
-
if (!
|
|
311
|
-
const type =
|
|
382
|
+
if (!isObject2(block)) return false;
|
|
383
|
+
const type = readString2(block.type);
|
|
312
384
|
return type !== void 0 && type !== "tool_result";
|
|
313
385
|
});
|
|
314
386
|
}
|
|
315
387
|
return false;
|
|
316
388
|
}
|
|
317
389
|
function toolUses(record) {
|
|
318
|
-
const message =
|
|
390
|
+
const message = isObject2(record.message) ? record.message : void 0;
|
|
319
391
|
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
320
392
|
const result = [];
|
|
321
393
|
for (const item of content) {
|
|
322
|
-
if (
|
|
394
|
+
if (isObject2(item) && readString2(item.type) === "tool_use") {
|
|
323
395
|
result.push(item);
|
|
324
396
|
}
|
|
325
397
|
}
|
|
@@ -329,20 +401,38 @@ function indexAskAnswers(records) {
|
|
|
329
401
|
const byId = /* @__PURE__ */ new Map();
|
|
330
402
|
for (const record of records) {
|
|
331
403
|
const result = record.toolUseResult;
|
|
332
|
-
if (!
|
|
404
|
+
if (!isObject2(result)) continue;
|
|
333
405
|
const answers = result.answers;
|
|
334
|
-
if (!
|
|
335
|
-
const message =
|
|
406
|
+
if (!isObject2(answers)) continue;
|
|
407
|
+
const message = isObject2(record.message) ? record.message : void 0;
|
|
336
408
|
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
337
409
|
for (const item of content) {
|
|
338
|
-
if (
|
|
339
|
-
const id =
|
|
410
|
+
if (isObject2(item) && readString2(item.type) === "tool_result") {
|
|
411
|
+
const id = readString2(item.tool_use_id);
|
|
340
412
|
if (id !== void 0) byId.set(id, answers);
|
|
341
413
|
}
|
|
342
414
|
}
|
|
343
415
|
}
|
|
344
416
|
return byId;
|
|
345
417
|
}
|
|
418
|
+
function readOfferedOptions(input) {
|
|
419
|
+
const byQuestion = /* @__PURE__ */ new Map();
|
|
420
|
+
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
421
|
+
for (const q of questions) {
|
|
422
|
+
if (!isObject2(q)) continue;
|
|
423
|
+
const text = readString2(q.question);
|
|
424
|
+
if (text === void 0) continue;
|
|
425
|
+
const labels = /* @__PURE__ */ new Set();
|
|
426
|
+
const options = Array.isArray(q.options) ? q.options : [];
|
|
427
|
+
for (const o of options) {
|
|
428
|
+
if (!isObject2(o)) continue;
|
|
429
|
+
const label = readString2(o.label);
|
|
430
|
+
if (label !== void 0) labels.add(label.trim());
|
|
431
|
+
}
|
|
432
|
+
byQuestion.set(text, labels);
|
|
433
|
+
}
|
|
434
|
+
return byQuestion;
|
|
435
|
+
}
|
|
346
436
|
|
|
347
437
|
// src/adapters/codex/rollout-importer.ts
|
|
348
438
|
var CODEX_IMPORT_SOURCE = "codex-import";
|
|
@@ -360,31 +450,31 @@ function codexRolloutToImportPayload(records, options) {
|
|
|
360
450
|
const completions = [];
|
|
361
451
|
const completedTurnIds = /* @__PURE__ */ new Set();
|
|
362
452
|
for (const record of records) {
|
|
363
|
-
const ts =
|
|
453
|
+
const ts = readString3(record.timestamp);
|
|
364
454
|
if (ts === void 0) continue;
|
|
365
455
|
if (minTs === void 0 || Date.parse(ts) < Date.parse(minTs)) minTs = ts;
|
|
366
456
|
if (maxTs === void 0 || Date.parse(ts) > Date.parse(maxTs)) maxTs = ts;
|
|
367
|
-
const payload2 =
|
|
457
|
+
const payload2 = isObject3(record.payload) ? record.payload : void 0;
|
|
368
458
|
if (payload2 === void 0) continue;
|
|
369
|
-
if (
|
|
370
|
-
if (workingDir === void 0) workingDir =
|
|
371
|
-
if (codexSessionId === void 0) codexSessionId =
|
|
459
|
+
if (readString3(record.type) === "session_meta") {
|
|
460
|
+
if (workingDir === void 0) workingDir = readString3(payload2.cwd);
|
|
461
|
+
if (codexSessionId === void 0) codexSessionId = readString3(payload2.id);
|
|
372
462
|
continue;
|
|
373
463
|
}
|
|
374
|
-
if (
|
|
375
|
-
const info =
|
|
376
|
-
const totals = info !== void 0 &&
|
|
464
|
+
if (readString3(record.type) === "event_msg" && readString3(payload2.type) === "token_count") {
|
|
465
|
+
const info = isObject3(payload2.info) ? payload2.info : void 0;
|
|
466
|
+
const totals = info !== void 0 && isObject3(info.total_token_usage) ? info.total_token_usage : void 0;
|
|
377
467
|
if (totals !== void 0) lastTokenTotals = totals;
|
|
378
468
|
continue;
|
|
379
469
|
}
|
|
380
|
-
if (
|
|
381
|
-
const pt =
|
|
470
|
+
if (readString3(record.type) === "event_msg") {
|
|
471
|
+
const pt = readString3(payload2.type);
|
|
382
472
|
if (pt === "user_message" || pt === "agent_message" || pt === "task_started" || pt === "task_complete") {
|
|
383
473
|
const tsMs = Date.parse(ts);
|
|
384
474
|
if (Number.isFinite(tsMs)) engagementTsMs.push(tsMs);
|
|
385
475
|
}
|
|
386
476
|
if (pt === "task_complete") {
|
|
387
|
-
const turnId =
|
|
477
|
+
const turnId = readString3(payload2.turn_id);
|
|
388
478
|
if (turnId === void 0 || !completedTurnIds.has(turnId)) {
|
|
389
479
|
if (turnId !== void 0) completedTurnIds.add(turnId);
|
|
390
480
|
completions.push({
|
|
@@ -395,9 +485,9 @@ function codexRolloutToImportPayload(records, options) {
|
|
|
395
485
|
}
|
|
396
486
|
continue;
|
|
397
487
|
}
|
|
398
|
-
if (
|
|
399
|
-
if (
|
|
400
|
-
if (
|
|
488
|
+
if (readString3(record.type) !== "response_item") continue;
|
|
489
|
+
if (readString3(payload2.type) !== "function_call") continue;
|
|
490
|
+
if (readString3(payload2.name) !== "exec_command") continue;
|
|
401
491
|
const command = readExecCommand(payload2.arguments);
|
|
402
492
|
if (command === void 0) continue;
|
|
403
493
|
const cwd = command.workdir ?? workingDir ?? ".";
|
|
@@ -508,17 +598,17 @@ function commandExecutedEvent2(occurredAt, sessionId, command, cwd, outcome) {
|
|
|
508
598
|
duration_ms: outcome.durationMs
|
|
509
599
|
};
|
|
510
600
|
}
|
|
511
|
-
function
|
|
601
|
+
function readString3(value) {
|
|
512
602
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
513
603
|
}
|
|
514
604
|
function readNonNegInt2(value) {
|
|
515
605
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
516
606
|
}
|
|
517
|
-
function
|
|
607
|
+
function isObject3(value) {
|
|
518
608
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
519
609
|
}
|
|
520
610
|
function readExecCommand(value) {
|
|
521
|
-
const raw =
|
|
611
|
+
const raw = readString3(value);
|
|
522
612
|
if (raw === void 0) return void 0;
|
|
523
613
|
let parsed;
|
|
524
614
|
try {
|
|
@@ -526,19 +616,19 @@ function readExecCommand(value) {
|
|
|
526
616
|
} catch {
|
|
527
617
|
return void 0;
|
|
528
618
|
}
|
|
529
|
-
if (!
|
|
530
|
-
const cmd =
|
|
619
|
+
if (!isObject3(parsed)) return void 0;
|
|
620
|
+
const cmd = readString3(parsed.cmd);
|
|
531
621
|
if (cmd === void 0) return void 0;
|
|
532
|
-
return { cmd, workdir:
|
|
622
|
+
return { cmd, workdir: readString3(parsed.workdir) };
|
|
533
623
|
}
|
|
534
624
|
function readCallId(value, outputs) {
|
|
535
|
-
const callId =
|
|
625
|
+
const callId = readString3(value);
|
|
536
626
|
return callId !== void 0 ? outputs.get(callId) : void 0;
|
|
537
627
|
}
|
|
538
628
|
function turnIntervalFromComplete(endTs, payload, startMsByTurnId) {
|
|
539
629
|
const endMs = Date.parse(endTs);
|
|
540
630
|
if (!Number.isFinite(endMs)) return void 0;
|
|
541
|
-
const turnId =
|
|
631
|
+
const turnId = readString3(payload.turn_id);
|
|
542
632
|
const indexedStart = turnId !== void 0 ? startMsByTurnId.get(turnId) : void 0;
|
|
543
633
|
const durationMs = readNonNegInt2(payload.duration_ms);
|
|
544
634
|
const startMs = indexedStart !== void 0 ? indexedStart : durationMs > 0 ? endMs - durationMs : void 0;
|
|
@@ -548,11 +638,11 @@ function turnIntervalFromComplete(endTs, payload, startMsByTurnId) {
|
|
|
548
638
|
function indexTaskStarts(records) {
|
|
549
639
|
const byTurnId = /* @__PURE__ */ new Map();
|
|
550
640
|
for (const record of records) {
|
|
551
|
-
if (
|
|
552
|
-
const payload =
|
|
553
|
-
if (payload === void 0 ||
|
|
554
|
-
const turnId =
|
|
555
|
-
const startMs = Date.parse(
|
|
641
|
+
if (readString3(record.type) !== "event_msg") continue;
|
|
642
|
+
const payload = isObject3(record.payload) ? record.payload : void 0;
|
|
643
|
+
if (payload === void 0 || readString3(payload.type) !== "task_started") continue;
|
|
644
|
+
const turnId = readString3(payload.turn_id);
|
|
645
|
+
const startMs = Date.parse(readString3(record.timestamp) ?? "");
|
|
556
646
|
if (turnId !== void 0 && Number.isFinite(startMs) && !byTurnId.has(turnId)) {
|
|
557
647
|
byTurnId.set(turnId, startMs);
|
|
558
648
|
}
|
|
@@ -574,12 +664,12 @@ function parseWallTimeMs(output) {
|
|
|
574
664
|
function indexOutputs(records) {
|
|
575
665
|
const byId = /* @__PURE__ */ new Map();
|
|
576
666
|
for (const record of records) {
|
|
577
|
-
if (
|
|
578
|
-
const payload =
|
|
667
|
+
if (readString3(record.type) !== "response_item") continue;
|
|
668
|
+
const payload = isObject3(record.payload) ? record.payload : void 0;
|
|
579
669
|
if (payload === void 0) continue;
|
|
580
|
-
if (
|
|
581
|
-
const callId =
|
|
582
|
-
const output =
|
|
670
|
+
if (readString3(payload.type) !== "function_call_output") continue;
|
|
671
|
+
const callId = readString3(payload.call_id);
|
|
672
|
+
const output = readString3(payload.output);
|
|
583
673
|
if (callId !== void 0 && output !== void 0) byId.set(callId, output);
|
|
584
674
|
}
|
|
585
675
|
return byId;
|
|
@@ -4758,6 +4848,11 @@ function formatOrientationBody(summary, opts) {
|
|
|
4758
4848
|
lines.push(`> hosts: local, ${summary.hosts.join(", ")}`);
|
|
4759
4849
|
}
|
|
4760
4850
|
lines.push("");
|
|
4851
|
+
const banner = stalenessBanner(opts.staleness);
|
|
4852
|
+
if (banner.length > 0) {
|
|
4853
|
+
for (const line of banner) lines.push(line);
|
|
4854
|
+
lines.push("");
|
|
4855
|
+
}
|
|
4761
4856
|
lines.push("## \u4ECA\u3069\u3053\u306B\u3044\u308B");
|
|
4762
4857
|
lines.push("");
|
|
4763
4858
|
if (summary.latestSession !== null) {
|
|
@@ -4957,6 +5052,23 @@ function toolDisplayName(kind) {
|
|
|
4957
5052
|
return kind ?? "\u4E0D\u660E";
|
|
4958
5053
|
}
|
|
4959
5054
|
}
|
|
5055
|
+
function stalenessBanner(staleness) {
|
|
5056
|
+
if (staleness === null) return [];
|
|
5057
|
+
if ((staleness.unverifiableSessions ?? 0) > 0) {
|
|
5058
|
+
return [
|
|
5059
|
+
`> \u26A0\uFE0F **\u6700\u65B0\u3067\u306F\u306A\u3044\u53EF\u80FD\u6027** \u2014 \u5909\u5316\u3057\u305F\u304C\u5B89\u5168\u306B\u53D6\u308A\u8FBC\u3081\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.unverifiableSessions} \u4EF6\u3042\u308A\u307E\u3059\u3002\u7740\u624B\u524D\u306B \`basou verify\` / \`basou refresh --force\`(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
5060
|
+
];
|
|
5061
|
+
}
|
|
5062
|
+
if (staleness.newSessions > 0 || staleness.updatedSessions > 0) {
|
|
5063
|
+
const parts = [];
|
|
5064
|
+
if (staleness.newSessions > 0) parts.push(`\u65B0\u898F ${staleness.newSessions} \u4EF6`);
|
|
5065
|
+
if (staleness.updatedSessions > 0) parts.push(`\u66F4\u65B0 ${staleness.updatedSessions} \u4EF6`);
|
|
5066
|
+
return [
|
|
5067
|
+
`> \u26A0\uFE0F **\u53E4\u3044\u304B\u3082\u3057\u308C\u307E\u305B\u3093** \u2014 \u672A\u53D6\u308A\u8FBC\u307F\u306E\u4F5C\u696D\u304C\u3042\u308A\u307E\u3059(${parts.join("\u30FB")})\u3002\u7740\u624B\u524D\u306B \`basou refresh\` \u3067\u66F4\u65B0\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
5068
|
+
];
|
|
5069
|
+
}
|
|
5070
|
+
return [];
|
|
5071
|
+
}
|
|
4960
5072
|
function freshnessVerdict(summary, staleness, now) {
|
|
4961
5073
|
if (staleness !== null && (staleness.unverifiableSessions ?? 0) > 0) {
|
|
4962
5074
|
return [
|
|
@@ -7349,6 +7461,7 @@ export {
|
|
|
7349
7461
|
CLAUDE_IMPORT_SOURCE,
|
|
7350
7462
|
CODEX_IMPORT_SOURCE,
|
|
7351
7463
|
ChildProcessRunner,
|
|
7464
|
+
DEFAULT_STOP_HOOK_MIN_ACTIONS,
|
|
7352
7465
|
DecisionIdSchema,
|
|
7353
7466
|
EventIdSchema,
|
|
7354
7467
|
EventSchema,
|
|
@@ -7408,6 +7521,7 @@ export {
|
|
|
7408
7521
|
enumerateArchivedTaskIds,
|
|
7409
7522
|
enumerateSessionDirs,
|
|
7410
7523
|
enumerateTaskIds,
|
|
7524
|
+
evaluateStopHook,
|
|
7411
7525
|
finalizeSessionYaml,
|
|
7412
7526
|
findErrorCode,
|
|
7413
7527
|
findReviewGaps,
|