@basou/core 0.39.0 → 0.41.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 +109 -1
- package/dist/index.js +216 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/manifest.schema.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -818,6 +818,110 @@ declare function resolveCodexCommand(lookup?: CommandLookup): Promise<{
|
|
|
818
818
|
command: string;
|
|
819
819
|
}>;
|
|
820
820
|
|
|
821
|
+
/**
|
|
822
|
+
* Pure transforms for registering / removing basou's SessionStart hook inside a
|
|
823
|
+
* parsed Codex `hooks.json` object. No disk or environment access: the CLI reads
|
|
824
|
+
* and writes the file, parses the JSON, and passes the object here so the
|
|
825
|
+
* merge/removal logic stays deterministic and unit-testable. The Codex twin of
|
|
826
|
+
* the Claude Code `settings-hook` transforms.
|
|
827
|
+
*
|
|
828
|
+
* Why a hook, and why this shape: `~/.codex/hooks.json` is user-global, but a
|
|
829
|
+
* hook stores nothing — Codex runs it when a session starts and passes the
|
|
830
|
+
* session's own `cwd` on stdin, and whatever the hook prints on stdout becomes
|
|
831
|
+
* developer context for THAT session only. basou resolves the workspace from
|
|
832
|
+
* that `cwd` and prints that workspace's position. So one installed hook serves
|
|
833
|
+
* every workspace on the machine while no workspace's position is ever written
|
|
834
|
+
* where another workspace's session reads it — the property the retired
|
|
835
|
+
* `~/.codex/AGENTS.md` orientation render could not have.
|
|
836
|
+
*
|
|
837
|
+
* `hooks.json` holds other events and other people's hooks; these functions
|
|
838
|
+
* clone the input and touch ONLY the `hooks.SessionStart` handler that basou
|
|
839
|
+
* owns, preserving everything else byte-for-byte through the round-trip.
|
|
840
|
+
*/
|
|
841
|
+
/**
|
|
842
|
+
* Seconds before Codex kills the hook. `basou orient` reads the store and
|
|
843
|
+
* probes the native logs for staleness; on a large store that is seconds, not
|
|
844
|
+
* minutes. Codex's own default is 600 — far too long for a session-start
|
|
845
|
+
* handler whose failure mode is "the session waits".
|
|
846
|
+
*/
|
|
847
|
+
declare const SESSION_START_HOOK_TIMEOUT_SECONDS = 30;
|
|
848
|
+
/**
|
|
849
|
+
* Which SessionStart sources fire the hook. Codex applies the matcher to the
|
|
850
|
+
* payload's `source`: `startup` (a new session), `resume`, `clear` (context
|
|
851
|
+
* reset). `compact` is left out: the position is already in the context being
|
|
852
|
+
* compacted, and re-injecting ~10 KB after every compaction would crowd the
|
|
853
|
+
* budget the compaction just freed.
|
|
854
|
+
*/
|
|
855
|
+
declare const SESSION_START_HOOK_MATCHER = "startup|resume|clear";
|
|
856
|
+
/**
|
|
857
|
+
* Codex caps each hook's model-visible output at roughly 2,500 tokens by default
|
|
858
|
+
* and spills the rest to a temp file, handing the model a head-and-tail preview
|
|
859
|
+
* plus the path. A position is ~10 KB and is useless truncated — the open
|
|
860
|
+
* tracks and the next step sit at the end — so the cap is disabled for this
|
|
861
|
+
* handler (`0` passes the complete output).
|
|
862
|
+
*/
|
|
863
|
+
declare const SESSION_START_HOOK_CONTEXT_LIMIT = 0;
|
|
864
|
+
/** Shown in the Codex UI while the hook runs. */
|
|
865
|
+
declare const SESSION_START_HOOK_STATUS_MESSAGE = "basou orient";
|
|
866
|
+
declare function isBasouSessionStartHookCommand(command: string): boolean;
|
|
867
|
+
/**
|
|
868
|
+
* Build the shell command basou registers as a Codex SessionStart hook. Uses
|
|
869
|
+
* the node path (the `basou` alias is often absent from a hook's PATH) and a
|
|
870
|
+
* `2>/dev/null || true` wrapper so a stale dist path or any crash fails open —
|
|
871
|
+
* a session start must never be blocked by its orientation. The handler itself
|
|
872
|
+
* is also fail-open, so the wrapper is belt-and-braces. The entry path is
|
|
873
|
+
* shell-quoted for directories containing spaces or metacharacters.
|
|
874
|
+
*/
|
|
875
|
+
declare function buildSessionStartHookCommand(options: {
|
|
876
|
+
cliEntry: string;
|
|
877
|
+
}): string;
|
|
878
|
+
type CodexHooksFile = Record<string, unknown>;
|
|
879
|
+
type SessionStartHookUpsert = {
|
|
880
|
+
hooksFile: CodexHooksFile;
|
|
881
|
+
/** `installed` = a new entry was appended; `updated` = an existing basou entry was rewritten; `unchanged` = already canonical. */
|
|
882
|
+
action: "installed" | "updated" | "unchanged";
|
|
883
|
+
};
|
|
884
|
+
type SessionStartHookRemoval = {
|
|
885
|
+
hooksFile: CodexHooksFile;
|
|
886
|
+
action: "removed" | "absent";
|
|
887
|
+
};
|
|
888
|
+
/**
|
|
889
|
+
* Where basou's handler sits in the file. Codex records trust per handler under
|
|
890
|
+
* `[hooks.state."<hooks.json path>:session_start:<group>:<handler>"]` in
|
|
891
|
+
* `config.toml`, so the two indexes are what `hook status codex` needs to look
|
|
892
|
+
* the trust entry up.
|
|
893
|
+
*/
|
|
894
|
+
type SessionStartHookLocation = {
|
|
895
|
+
command: string;
|
|
896
|
+
groupIndex: number;
|
|
897
|
+
handlerIndex: number;
|
|
898
|
+
/** The matcher of the group the handler sits in (undefined = fires on every source). */
|
|
899
|
+
matcher: string | undefined;
|
|
900
|
+
/**
|
|
901
|
+
* The handler object exactly as installed. Codex hashes the installed fields
|
|
902
|
+
* (not basou's canonical ones) when it decides whether the hook is trusted, so
|
|
903
|
+
* a status check must hash what is in the file.
|
|
904
|
+
*/
|
|
905
|
+
handler: Record<string, unknown>;
|
|
906
|
+
};
|
|
907
|
+
/**
|
|
908
|
+
* Register (or upgrade in place) basou's SessionStart hook. Idempotent: an
|
|
909
|
+
* existing basou handler is rewritten to the canonical fields; a foreign
|
|
910
|
+
* handler, another event, or any other key is left untouched. A new install
|
|
911
|
+
* appends its own matcher group so it never widens or narrows someone else's
|
|
912
|
+
* matcher.
|
|
913
|
+
*/
|
|
914
|
+
declare function upsertSessionStartHook(hooksFile: unknown, command: string): SessionStartHookUpsert;
|
|
915
|
+
/**
|
|
916
|
+
* Remove every basou-owned SessionStart handler. A group emptied by the removal
|
|
917
|
+
* is dropped; a now-empty `hooks.SessionStart` / `hooks` container is deleted so
|
|
918
|
+
* the file does not accumulate empty scaffolding. Foreign handlers and other
|
|
919
|
+
* keys are preserved.
|
|
920
|
+
*/
|
|
921
|
+
declare function removeSessionStartHook(hooksFile: unknown): SessionStartHookRemoval;
|
|
922
|
+
/** Locate the installed basou SessionStart handler, or null if none is registered. */
|
|
923
|
+
declare function findBasouSessionStartHook(hooksFile: unknown): SessionStartHookLocation | null;
|
|
924
|
+
|
|
821
925
|
/**
|
|
822
926
|
* The `source` string stamped on every event derived from an OpenAI Codex
|
|
823
927
|
* native rollout log, and the matching session `source.kind`.
|
|
@@ -2007,6 +2111,8 @@ type ViewStrings = {
|
|
|
2007
2111
|
recentDecisionsLabel: string;
|
|
2008
2112
|
recentNextStepLabel: string;
|
|
2009
2113
|
recentChangedLabel: string;
|
|
2114
|
+
/** Trails the recent-files line when scratch paths were left out of it. */
|
|
2115
|
+
scratchOmitted: (count: number) => string;
|
|
2010
2116
|
trackCloseInstruction: string;
|
|
2011
2117
|
nextStepRecordedLabel: (age: string) => string;
|
|
2012
2118
|
noteStaleNote: (activityAge: string) => string;
|
|
@@ -4224,6 +4330,8 @@ type OrientationSummary = {
|
|
|
4224
4330
|
displayed: string[];
|
|
4225
4331
|
overflow: number;
|
|
4226
4332
|
outOfRoot: string[];
|
|
4333
|
+
/** Scratch paths left out of `displayed` (see `isTransientToolPath`). */
|
|
4334
|
+
omitted: number;
|
|
4227
4335
|
};
|
|
4228
4336
|
/** Tasks whose status is `planned` or `in_progress`. */
|
|
4229
4337
|
inFlightTasks: InFlightTask[];
|
|
@@ -6877,4 +6985,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
|
|
|
6877
6985
|
*/
|
|
6878
6986
|
declare const BASOU_CORE_VERSION = "0.1.0";
|
|
6879
6987
|
|
|
6880
|
-
export { ACTIVE_GAP_CAP_MS, AGENT_INFRA_DIRS, type ActiveTimeBasis, type AdapterOutputEvent, type AdoptCandidate, type AdoptCandidateKind, type AnchorStarterInput, type AnchorStarterRepo, 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 BuildStopHookCommandOptions, type BulkChainResult, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, type ChainBreakReason, type ChainTailState, type ChainVerdict, type ChainVerdictStatus, type ChainedEvents, ChildProcessRunner, type CitedReview, type ClaudeSettings, type ClaudeTranscriptRecord, type ClaudeTranscriptToPayloadOptions, type CodexCommandLookup, type CodexRolloutRecord, type CodexRolloutToPayloadOptions, type CommandExecutedEvent, type CommandLookup, type CreateAdHocSessionInput, type CreateAdHocSessionResult, type CreateAdHocTaskInput, type CreateManifestInput, type CreateTaskInput, type CreateTaskResult, DEFAULT_STOP_HOOK_MIN_EDITS, 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 IncompleteWiring, 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 MissingCanonical, type NoteAddedEvent, ORIENTATION_END, ORIENTATION_START, 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 PresetStrings, type ProcessRunner, type PublishKind, type PublishTarget, REVIEW_RECORD_NO_INPUT_HINT, 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 RepoInstructions, type RepoLanguage, type RepoPathProblem, 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 RetrofitAction, type RetrofitAgentsState, type RetrofitFacts, type RetrofitPlan, type RetrofitReason, type ReviewBlocked, type ReviewFinding, type ReviewGapRepoSummary, type ReviewGapUnit, type ReviewGapVerdict, type ReviewGapsInput, type ReviewGapsSummary, type ReviewGateResult, type ReviewGateSilentReason, type ReviewRecordBlockedInput, type ReviewRecordFindingInput, type ReviewRecordInput, type ReviewRecordedEvent, type RiskLevel, RiskLevelSchema, type RosterAdoptionPlan, type RosterDriftSummary, type RunOptions, type RunResult, STOP_HOOK_TIMEOUT_SECONDS, STUCK_THRESHOLD_MS, type SanitizePathOptions, type SanitizeRelatedFilesResult, SchemaVersionSchema, type SelfReportedReview, 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 StopHookRemoval, type StopHookSilentReason, type StopHookUpsert, 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 UnattachedSelfReports, type UnbindableRepo, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type ViewCollision, type ViewConflict, type ViewLanguage, type ViewLinkState, type ViewPresetInput, type ViewPresetRepo, type ViewRepoFact, type ViewStrayUnknown, type ViewStrings, type ViewWiringFacts, type WiringCollision, type WiringConflict, type WiringDriftSummary, 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, buildReviewRecordLabel, buildReviewRecordedEvent, buildStatusSnapshot, buildStopHookCommand, chainEvents, chainRawJsonLines, classifyFilesBySourceRoot, classifyRetrofit, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexAdapterMetadata, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, evaluateStopHook, finalizeSessionYaml, findBasouStopHookCommand, findErrorCode, findReviewGaps, findUnbindableRepos, formatDurationMs, genesisHash, getDiff, getSnapshot, importSessionFromJson, inspectChainTail, instructionMode, isBasouStopHookCommand, isGitNotFound, isImportDerivedSource, isLazyExpired, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadFederatedSessionEntries, loadSessionEntries, loadTaskEntries, normalizeRepoKey, normalizeRepoPath, overwriteYamlFile, parseDuration, parseMarkers, parseReviewRecordInput, pathBasename, planArchive, planGitignore, planRename, planRosterAdoption, planWorkspaceView, prefixedUlid, presetStrings, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, rechainSessionInPlace, reconcileAllTasks, reconcileSourceRoots, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, removeMarkerSection, removeStopHook, renderAnchorStarter, renderDecisions, renderHandoff, renderOrientation, renderPresetBlock, renderReport, renderViewPresetBlock, renderWithMarkers, replayEvents, resolveAnchorContentLanguage, resolveBasouRepositoryRoot, resolveClaudeCodeCommand, resolveCodexCommand, resolveRepoContentLanguage, resolveRepoRoot, resolveRepositoryRoot, resolveSessionId, resolveTaskId, resolveViewLanguage, resolveViewLanguageFromPaths, safeSimpleGit, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, seedMarkers, serializeEventLine, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, summarizeOrientation, summarizePresetPlan, summarizeRosterDrift, summarizeSymlinkPlan, summarizeWiring, summarizeWiringDrift, tryRemoteUrl, ulid, unknownManifestKeys, updateTaskStatusWithEvent, upsertStopHook, verifyEventsChain, viewStrings, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
|
6988
|
+
export { ACTIVE_GAP_CAP_MS, AGENT_INFRA_DIRS, type ActiveTimeBasis, type AdapterOutputEvent, type AdoptCandidate, type AdoptCandidateKind, type AnchorStarterInput, type AnchorStarterRepo, 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 BuildStopHookCommandOptions, type BulkChainResult, CLAUDE_IMPORT_SOURCE, CODEX_IMPORT_SOURCE, type CaptureMode, type ChainBreakReason, type ChainTailState, type ChainVerdict, type ChainVerdictStatus, type ChainedEvents, ChildProcessRunner, type CitedReview, type ClaudeSettings, type ClaudeTranscriptRecord, type ClaudeTranscriptToPayloadOptions, type CodexCommandLookup, type CodexHooksFile, type CodexRolloutRecord, type CodexRolloutToPayloadOptions, type CommandExecutedEvent, type CommandLookup, type CreateAdHocSessionInput, type CreateAdHocSessionResult, type CreateAdHocTaskInput, type CreateManifestInput, type CreateTaskInput, type CreateTaskResult, DEFAULT_STOP_HOOK_MIN_EDITS, 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 IncompleteWiring, 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 MissingCanonical, type NoteAddedEvent, ORIENTATION_END, ORIENTATION_START, 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 PresetStrings, type ProcessRunner, type PublishKind, type PublishTarget, REVIEW_RECORD_NO_INPUT_HINT, 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 RepoInstructions, type RepoLanguage, type RepoPathProblem, 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 RetrofitAction, type RetrofitAgentsState, type RetrofitFacts, type RetrofitPlan, type RetrofitReason, type ReviewBlocked, type ReviewFinding, type ReviewGapRepoSummary, type ReviewGapUnit, type ReviewGapVerdict, type ReviewGapsInput, type ReviewGapsSummary, type ReviewGateResult, type ReviewGateSilentReason, type ReviewRecordBlockedInput, type ReviewRecordFindingInput, type ReviewRecordInput, type ReviewRecordedEvent, type RiskLevel, RiskLevelSchema, type RosterAdoptionPlan, type RosterDriftSummary, type RunOptions, type RunResult, SESSION_START_HOOK_CONTEXT_LIMIT, SESSION_START_HOOK_MATCHER, SESSION_START_HOOK_STATUS_MESSAGE, SESSION_START_HOOK_TIMEOUT_SECONDS, STOP_HOOK_TIMEOUT_SECONDS, STUCK_THRESHOLD_MS, type SanitizePathOptions, type SanitizeRelatedFilesResult, SchemaVersionSchema, type SelfReportedReview, 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 SessionStartHookLocation, type SessionStartHookRemoval, type SessionStartHookUpsert, 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 StopHookRemoval, type StopHookSilentReason, type StopHookUpsert, 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 UnattachedSelfReports, type UnbindableRepo, type UpdateAdHocTaskStatusInput, type UpdateTaskStatusInput, type UpdateTaskStatusResult, type ViewCollision, type ViewConflict, type ViewLanguage, type ViewLinkState, type ViewPresetInput, type ViewPresetRepo, type ViewRepoFact, type ViewStrayUnknown, type ViewStrings, type ViewWiringFacts, type WiringCollision, type WiringConflict, type WiringDriftSummary, 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, buildReviewRecordLabel, buildReviewRecordedEvent, buildSessionStartHookCommand, buildStatusSnapshot, buildStopHookCommand, chainEvents, chainRawJsonLines, classifyFilesBySourceRoot, classifyRetrofit, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexAdapterMetadata, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, evaluateStopHook, finalizeSessionYaml, findBasouSessionStartHook, findBasouStopHookCommand, findErrorCode, findReviewGaps, findUnbindableRepos, formatDurationMs, genesisHash, getDiff, getSnapshot, importSessionFromJson, inspectChainTail, instructionMode, isBasouSessionStartHookCommand, isBasouStopHookCommand, isGitNotFound, isImportDerivedSource, isLazyExpired, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadFederatedSessionEntries, loadSessionEntries, loadTaskEntries, normalizeRepoKey, normalizeRepoPath, overwriteYamlFile, parseDuration, parseMarkers, parseReviewRecordInput, pathBasename, planArchive, planGitignore, planRename, planRosterAdoption, planWorkspaceView, prefixedUlid, presetStrings, readAllEvents, readManifest, readMarkdownFile, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, rechainSessionInPlace, reconcileAllTasks, reconcileSourceRoots, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, removeMarkerSection, removeSessionStartHook, removeStopHook, renderAnchorStarter, renderDecisions, renderHandoff, renderOrientation, renderPresetBlock, renderReport, renderViewPresetBlock, renderWithMarkers, replayEvents, resolveAnchorContentLanguage, resolveBasouRepositoryRoot, resolveClaudeCodeCommand, resolveCodexCommand, resolveRepoContentLanguage, resolveRepoRoot, resolveRepositoryRoot, resolveSessionId, resolveTaskId, resolveViewLanguage, resolveViewLanguageFromPaths, safeSimpleGit, sanitizePath, sanitizeRelatedFiles, sanitizeWorkingDirectory, seedMarkers, serializeEventLine, serializeJsonSchema, sessionWorkStatsFromEvents, summarizeAdapterOutput, summarizeOrientation, summarizePresetPlan, summarizeRosterDrift, summarizeSymlinkPlan, summarizeWiring, summarizeWiringDrift, tryRemoteUrl, ulid, unknownManifestKeys, updateTaskStatusWithEvent, upsertSessionStartHook, upsertStopHook, verifyEventsChain, viewStrings, writeEventsBulk, writeManifest, writeMarkdownFile, writeStatus, writeTaskFile, writeYamlFile };
|
package/dist/index.js
CHANGED
|
@@ -660,6 +660,135 @@ async function resolveCodexCommand(lookup = isOnPath) {
|
|
|
660
660
|
throw new Error("Codex CLI not found in PATH. Install codex first.");
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
+
// src/adapters/codex/hooks-json.ts
|
|
664
|
+
var SESSION_START_HOOK_TIMEOUT_SECONDS = 30;
|
|
665
|
+
var SESSION_START_HOOK_MATCHER = "startup|resume|clear";
|
|
666
|
+
var SESSION_START_HOOK_CONTEXT_LIMIT = 0;
|
|
667
|
+
var SESSION_START_HOOK_STATUS_MESSAGE = "basou orient";
|
|
668
|
+
var BASOU_SESSION_START_HOOK = /(?:\bbasou|(?:@basou|packages)\/cli\/dist\/index\.js['"]?)\s+hook\s+session-start\b/;
|
|
669
|
+
function isBasouSessionStartHookCommand(command) {
|
|
670
|
+
return BASOU_SESSION_START_HOOK.test(command);
|
|
671
|
+
}
|
|
672
|
+
function shellQuote2(value) {
|
|
673
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
674
|
+
}
|
|
675
|
+
function buildSessionStartHookCommand(options) {
|
|
676
|
+
return `node ${shellQuote2(options.cliEntry)} hook session-start 2>/dev/null || true`;
|
|
677
|
+
}
|
|
678
|
+
function isRecord2(value) {
|
|
679
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
680
|
+
}
|
|
681
|
+
function cloneHooksFile(hooksFile) {
|
|
682
|
+
if (hooksFile === void 0 || hooksFile === null) return {};
|
|
683
|
+
if (!isRecord2(hooksFile)) {
|
|
684
|
+
throw new Error("The Codex hooks.json is not a JSON object.");
|
|
685
|
+
}
|
|
686
|
+
return structuredClone(hooksFile);
|
|
687
|
+
}
|
|
688
|
+
function canonicalHandler(command) {
|
|
689
|
+
return {
|
|
690
|
+
type: "command",
|
|
691
|
+
command,
|
|
692
|
+
timeout: SESSION_START_HOOK_TIMEOUT_SECONDS,
|
|
693
|
+
statusMessage: SESSION_START_HOOK_STATUS_MESSAGE,
|
|
694
|
+
additionalContextLimit: SESSION_START_HOOK_CONTEXT_LIMIT
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function handlerIsCanonical(entry, command) {
|
|
698
|
+
const want = canonicalHandler(command);
|
|
699
|
+
return Object.keys(want).every((k) => entry[k] === want[k]);
|
|
700
|
+
}
|
|
701
|
+
function upsertSessionStartHook(hooksFile, command) {
|
|
702
|
+
const root = cloneHooksFile(hooksFile);
|
|
703
|
+
if (root.hooks === void 0) {
|
|
704
|
+
root.hooks = {};
|
|
705
|
+
} else if (!isRecord2(root.hooks)) {
|
|
706
|
+
throw new Error("The 'hooks' key in the Codex hooks.json is not an object.");
|
|
707
|
+
}
|
|
708
|
+
const hooks = root.hooks;
|
|
709
|
+
if (hooks.SessionStart === void 0) {
|
|
710
|
+
hooks.SessionStart = [];
|
|
711
|
+
} else if (!Array.isArray(hooks.SessionStart)) {
|
|
712
|
+
throw new Error("The 'hooks.SessionStart' key in the Codex hooks.json is not an array.");
|
|
713
|
+
}
|
|
714
|
+
const groups = hooks.SessionStart;
|
|
715
|
+
for (const group of groups) {
|
|
716
|
+
if (!isRecord2(group) || !Array.isArray(group.hooks)) continue;
|
|
717
|
+
for (const entry of group.hooks) {
|
|
718
|
+
if (!isRecord2(entry)) continue;
|
|
719
|
+
if (typeof entry.command === "string" && isBasouSessionStartHookCommand(entry.command)) {
|
|
720
|
+
const unchanged = handlerIsCanonical(entry, command);
|
|
721
|
+
Object.assign(entry, canonicalHandler(command));
|
|
722
|
+
return { hooksFile: root, action: unchanged ? "unchanged" : "updated" };
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
groups.push({ matcher: SESSION_START_HOOK_MATCHER, hooks: [canonicalHandler(command)] });
|
|
727
|
+
return { hooksFile: root, action: "installed" };
|
|
728
|
+
}
|
|
729
|
+
function removeSessionStartHook(hooksFile) {
|
|
730
|
+
const root = cloneHooksFile(hooksFile);
|
|
731
|
+
if (!isRecord2(root.hooks) || !Array.isArray(root.hooks.SessionStart)) {
|
|
732
|
+
return { hooksFile: root, action: "absent" };
|
|
733
|
+
}
|
|
734
|
+
const hooks = root.hooks;
|
|
735
|
+
const groups = hooks.SessionStart;
|
|
736
|
+
let removed = false;
|
|
737
|
+
const kept = [];
|
|
738
|
+
for (const group of groups) {
|
|
739
|
+
if (!isRecord2(group) || !Array.isArray(group.hooks)) {
|
|
740
|
+
kept.push(group);
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
const keptHandlers = group.hooks.filter((entry) => {
|
|
744
|
+
if (isRecord2(entry) && typeof entry.command === "string" && isBasouSessionStartHookCommand(entry.command)) {
|
|
745
|
+
removed = true;
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
return true;
|
|
749
|
+
});
|
|
750
|
+
if (keptHandlers.length === group.hooks.length) {
|
|
751
|
+
kept.push(group);
|
|
752
|
+
} else if (keptHandlers.length > 0) {
|
|
753
|
+
group.hooks = keptHandlers;
|
|
754
|
+
kept.push(group);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (!removed) return { hooksFile: root, action: "absent" };
|
|
758
|
+
if (kept.length === 0) {
|
|
759
|
+
delete hooks.SessionStart;
|
|
760
|
+
} else {
|
|
761
|
+
hooks.SessionStart = kept;
|
|
762
|
+
}
|
|
763
|
+
if (Object.keys(hooks).length === 0) {
|
|
764
|
+
delete root.hooks;
|
|
765
|
+
}
|
|
766
|
+
return { hooksFile: root, action: "removed" };
|
|
767
|
+
}
|
|
768
|
+
function findBasouSessionStartHook(hooksFile) {
|
|
769
|
+
if (!isRecord2(hooksFile) || !isRecord2(hooksFile.hooks) || !Array.isArray(hooksFile.hooks.SessionStart)) {
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
const groups = hooksFile.hooks.SessionStart;
|
|
773
|
+
for (let g = 0; g < groups.length; g++) {
|
|
774
|
+
const group = groups[g];
|
|
775
|
+
if (!isRecord2(group) || !Array.isArray(group.hooks)) continue;
|
|
776
|
+
for (let h = 0; h < group.hooks.length; h++) {
|
|
777
|
+
const entry = group.hooks[h];
|
|
778
|
+
if (isRecord2(entry) && typeof entry.command === "string" && isBasouSessionStartHookCommand(entry.command)) {
|
|
779
|
+
return {
|
|
780
|
+
command: entry.command,
|
|
781
|
+
groupIndex: g,
|
|
782
|
+
handlerIndex: h,
|
|
783
|
+
matcher: typeof group.matcher === "string" ? group.matcher : void 0,
|
|
784
|
+
handler: structuredClone(entry)
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
|
|
663
792
|
// src/adapters/codex/rollout-importer.ts
|
|
664
793
|
var CODEX_IMPORT_SOURCE = "codex-import";
|
|
665
794
|
function codexRolloutToImportPayload(records, options) {
|
|
@@ -1783,31 +1912,26 @@ var WorkspaceMetaSchema = z4.looseObject({
|
|
|
1783
1912
|
view: SourceRootSchema.optional()
|
|
1784
1913
|
});
|
|
1785
1914
|
var ChannelsSchema = z4.looseObject({
|
|
1786
|
-
/**
|
|
1787
|
-
* Render this workspace's orientation into `~/.codex/AGENTS.md` on `basou
|
|
1788
|
-
* refresh` / `basou run codex`. A boolean today; if a face ever needs
|
|
1789
|
-
* per-block control this widens to `boolean | object`, which existing
|
|
1790
|
-
* manifests keep parsing — so the boolean does not foreclose that.
|
|
1791
|
-
*/
|
|
1915
|
+
/** Retired (see above). Parsed for compatibility; has no effect. */
|
|
1792
1916
|
codex: z4.boolean().optional().meta({
|
|
1793
|
-
description: "
|
|
1917
|
+
description: "Retired and ignored. It used to opt this workspace into rendering its orientation into the user-global ~/.codex/AGENTS.md; nothing is written there any more \u2014 a Codex session receives the workspace's position from the SessionStart hook (`basou hook install codex`)."
|
|
1794
1918
|
})
|
|
1795
1919
|
});
|
|
1796
1920
|
var PoliciesSchema = z4.looseObject({
|
|
1797
1921
|
/**
|
|
1798
1922
|
* This workspace's provenance must not persist where another workspace's
|
|
1799
|
-
* tool reads it. That is the GOAL the key states
|
|
1800
|
-
*
|
|
1801
|
-
*
|
|
1802
|
-
* a
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
1805
|
-
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1923
|
+
* tool reads it. That is the GOAL the key states. The one writer it used to
|
|
1924
|
+
* gate — the orientation render into the user-global `~/.codex/AGENTS.md` —
|
|
1925
|
+
* is retired, so today the key gates nothing: basou has no per-workspace path
|
|
1926
|
+
* that writes a position anywhere another workspace's tool reads. It is kept,
|
|
1927
|
+
* parsed, and honoured as a declaration, so a future writer to a shared
|
|
1928
|
+
* surface must consult it before it ships (`basou protocol sync`, a global
|
|
1929
|
+
* render rather than a per-workspace one, does not consult it). A top-level
|
|
1930
|
+
* `confidential` is still refused rather than ignored, for the same reason it
|
|
1931
|
+
* always was: a safety key that is not honoured must fail loudly.
|
|
1808
1932
|
*/
|
|
1809
1933
|
confidential: z4.boolean().optional().meta({
|
|
1810
|
-
description: "
|
|
1934
|
+
description: "Posture: this workspace's provenance must not persist where another workspace's tool reads it. The one writer this used to gate \u2014 rendering the orientation into the user-global ~/.codex/AGENTS.md \u2014 is retired, so today the key gates nothing; it stays declared so a future writer to a shared surface must consult it. A top-level `confidential` is rejected rather than ignored."
|
|
1811
1935
|
})
|
|
1812
1936
|
});
|
|
1813
1937
|
var ManifestObjectSchema = z4.looseObject({
|
|
@@ -1974,6 +2098,7 @@ var EN = {
|
|
|
1974
2098
|
recentDecisionsLabel: "Decisions",
|
|
1975
2099
|
recentNextStepLabel: "Next step",
|
|
1976
2100
|
recentChangedLabel: "Changed",
|
|
2101
|
+
scratchOmitted: (count) => `(+${count} scratch omitted)`,
|
|
1977
2102
|
trackCloseInstruction: "When finished, close it with `basou decision void <decision_id>`. It stays listed here every time until closed.",
|
|
1978
2103
|
nextStepRecordedLabel: (age) => `Next step (recorded, ${age})`,
|
|
1979
2104
|
noteStaleNote: (age) => `Note: work continued after this was recorded (latest activity ${age}), so this starting point may be stale.`,
|
|
@@ -2069,6 +2194,7 @@ var JA = {
|
|
|
2069
2194
|
recentDecisionsLabel: "\u5224\u65AD",
|
|
2070
2195
|
recentNextStepLabel: "\u6B21\u306E\u8D77\u70B9",
|
|
2071
2196
|
recentChangedLabel: "\u5909\u66F4",
|
|
2197
|
+
scratchOmitted: (count) => `(\u4F5C\u696D\u7528\u4E00\u6642\u30D5\u30A1\u30A4\u30EB ${count} \u4EF6\u306F\u9664\u5916)`,
|
|
2072
2198
|
trackCloseInstruction: "\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002\u9589\u3058\u308B\u307E\u3067\u6BCE\u56DE\u3053\u3053\u306B\u8868\u793A\u3055\u308C\u307E\u3059\u3002",
|
|
2073
2199
|
nextStepRecordedLabel: (age) => `\u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${age})`,
|
|
2074
2200
|
noteStaleNote: (age) => `\u6CE8: \u3053\u306E\u8D77\u70B9\u306E\u8A18\u9332\u5F8C (\u6700\u7D42\u6D3B\u52D5 ${age}) \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`,
|
|
@@ -2409,8 +2535,8 @@ async function isStaleLock(lockPath) {
|
|
|
2409
2535
|
}
|
|
2410
2536
|
}
|
|
2411
2537
|
function lockfilePath(paths, scope, resourceId) {
|
|
2412
|
-
const
|
|
2413
|
-
const ulid2 =
|
|
2538
|
+
const sep2 = resourceId.indexOf("_");
|
|
2539
|
+
const ulid2 = sep2 >= 0 ? resourceId.slice(sep2 + 1) : resourceId;
|
|
2414
2540
|
return join3(paths.locks, `${scope}_${ulid2}.lock`);
|
|
2415
2541
|
}
|
|
2416
2542
|
|
|
@@ -3473,6 +3599,29 @@ function pickLatestSubstantiveEntry(entries) {
|
|
|
3473
3599
|
})[0];
|
|
3474
3600
|
}
|
|
3475
3601
|
|
|
3602
|
+
// src/lib/transient-paths.ts
|
|
3603
|
+
import { tmpdir } from "os";
|
|
3604
|
+
import { normalize, sep } from "path";
|
|
3605
|
+
var TEMP_ROOTS = ["/tmp", "/var/tmp"];
|
|
3606
|
+
var MIN_ENCODED_DASHES = 3;
|
|
3607
|
+
function isEncodedWorkingDirectory(segment) {
|
|
3608
|
+
return segment.startsWith("-") && segment.split("-").length - 1 >= MIN_ENCODED_DASHES;
|
|
3609
|
+
}
|
|
3610
|
+
function withPrivateAlias(root) {
|
|
3611
|
+
const normalized = normalize(root);
|
|
3612
|
+
if (normalized.startsWith(`${sep}private${sep}`)) {
|
|
3613
|
+
return [normalized, normalized.slice(`${sep}private`.length)];
|
|
3614
|
+
}
|
|
3615
|
+
return [normalized, `${sep}private${normalized}`];
|
|
3616
|
+
}
|
|
3617
|
+
function isTransientToolPath(filePath, temp = tmpdir()) {
|
|
3618
|
+
const candidate = normalize(filePath);
|
|
3619
|
+
if (!candidate.startsWith(sep)) return false;
|
|
3620
|
+
const root = [...TEMP_ROOTS, temp].flatMap(withPrivateAlias).find((r) => candidate === r || candidate.startsWith(r + sep));
|
|
3621
|
+
if (root === void 0) return false;
|
|
3622
|
+
return candidate.slice(root.length).split(sep).some(isEncodedWorkingDirectory);
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3476
3625
|
// src/storage/tasks.ts
|
|
3477
3626
|
import { createHash as createHash2 } from "crypto";
|
|
3478
3627
|
import { mkdir as mkdir3, readdir as readdir4, readFile as readFile7, rename as rename2, stat as stat3, unlink as unlink3 } from "fs/promises";
|
|
@@ -5292,7 +5441,9 @@ async function renderHandoff(input) {
|
|
|
5292
5441
|
(e) => e.session.session.status !== "archived" && e.session.session.source.kind !== "import"
|
|
5293
5442
|
);
|
|
5294
5443
|
const latestSession = pickLatestSubstantiveEntry(liveEntries);
|
|
5295
|
-
const latestFiles = latestSession?.session.session.related_files ?? []
|
|
5444
|
+
const latestFiles = (latestSession?.session.session.related_files ?? []).filter(
|
|
5445
|
+
(file) => !isTransientToolPath(file)
|
|
5446
|
+
);
|
|
5296
5447
|
const sortedFiles = [...new Set(latestFiles)].sort();
|
|
5297
5448
|
const displayedFiles = sortedFiles.slice(0, limit);
|
|
5298
5449
|
const overflow = Math.max(0, sortedFiles.length - limit);
|
|
@@ -5510,9 +5661,9 @@ function shortHandoffId(sessionId) {
|
|
|
5510
5661
|
return sessionId.slice(0, 10);
|
|
5511
5662
|
}
|
|
5512
5663
|
function shortIdWithPrefix(id) {
|
|
5513
|
-
const
|
|
5514
|
-
if (
|
|
5515
|
-
return id.slice(0,
|
|
5664
|
+
const sep2 = id.indexOf("_");
|
|
5665
|
+
if (sep2 === -1) return id.slice(0, 10);
|
|
5666
|
+
return id.slice(0, sep2 + 1) + id.slice(sep2 + 1, sep2 + 1 + 10);
|
|
5516
5667
|
}
|
|
5517
5668
|
|
|
5518
5669
|
// src/lib/duration.ts
|
|
@@ -5619,10 +5770,10 @@ async function resolveIdInternal(paths, input, kind, options = {}) {
|
|
|
5619
5770
|
// src/lib/source-root-scope.ts
|
|
5620
5771
|
import { promises as fs } from "fs";
|
|
5621
5772
|
import { homedir as osHomedir } from "os";
|
|
5622
|
-
import { basename as basename2, dirname as dirname3, isAbsolute, join as join14, normalize, relative, resolve as resolve2 } from "path";
|
|
5773
|
+
import { basename as basename2, dirname as dirname3, isAbsolute, join as join14, normalize as normalize2, relative, resolve as resolve2 } from "path";
|
|
5623
5774
|
var AGENT_INFRA_DIRS = ["~/.claude", "~/.codex", "~/.basou"];
|
|
5624
5775
|
async function realpathBestEffort(absPath) {
|
|
5625
|
-
let current =
|
|
5776
|
+
let current = normalize2(absPath);
|
|
5626
5777
|
const tail = [];
|
|
5627
5778
|
for (let guard = 0; guard < 4096; guard += 1) {
|
|
5628
5779
|
try {
|
|
@@ -5631,15 +5782,15 @@ async function realpathBestEffort(absPath) {
|
|
|
5631
5782
|
} catch (error) {
|
|
5632
5783
|
const code = error?.code;
|
|
5633
5784
|
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
5634
|
-
return
|
|
5785
|
+
return normalize2(absPath);
|
|
5635
5786
|
}
|
|
5636
5787
|
const parent = dirname3(current);
|
|
5637
|
-
if (parent === current) return
|
|
5788
|
+
if (parent === current) return normalize2(absPath);
|
|
5638
5789
|
tail.push(basename2(current));
|
|
5639
5790
|
current = parent;
|
|
5640
5791
|
}
|
|
5641
5792
|
}
|
|
5642
|
-
return
|
|
5793
|
+
return normalize2(absPath);
|
|
5643
5794
|
}
|
|
5644
5795
|
function expandTilde(p, homedir5) {
|
|
5645
5796
|
if (p === "~") return homedir5;
|
|
@@ -5648,8 +5799,8 @@ function expandTilde(p, homedir5) {
|
|
|
5648
5799
|
}
|
|
5649
5800
|
function toAbsolute(p, workingDirAbs, homedir5) {
|
|
5650
5801
|
const expanded = expandTilde(p, homedir5);
|
|
5651
|
-
if (isAbsolute(expanded)) return
|
|
5652
|
-
return
|
|
5802
|
+
if (isAbsolute(expanded)) return normalize2(expanded);
|
|
5803
|
+
return normalize2(resolve2(workingDirAbs, expanded));
|
|
5653
5804
|
}
|
|
5654
5805
|
function isUnder(child, parent) {
|
|
5655
5806
|
if (child === parent) return true;
|
|
@@ -5666,12 +5817,12 @@ async function classifyFilesBySourceRoot(input) {
|
|
|
5666
5817
|
const rootsAbs = [];
|
|
5667
5818
|
for (const r of declared) {
|
|
5668
5819
|
const expanded = expandTilde(r, homedir5);
|
|
5669
|
-
const abs = isAbsolute(expanded) ?
|
|
5820
|
+
const abs = isAbsolute(expanded) ? normalize2(expanded) : normalize2(resolve2(input.masterRoot, expanded));
|
|
5670
5821
|
rootsAbs.push(await realpathBestEffort(abs));
|
|
5671
5822
|
}
|
|
5672
5823
|
for (const e of input.extraInRoot ?? []) {
|
|
5673
5824
|
const expanded = expandTilde(e, homedir5);
|
|
5674
|
-
const abs = isAbsolute(expanded) ?
|
|
5825
|
+
const abs = isAbsolute(expanded) ? normalize2(expanded) : normalize2(resolve2(homedir5, expanded));
|
|
5675
5826
|
rootsAbs.push(await realpathBestEffort(abs));
|
|
5676
5827
|
}
|
|
5677
5828
|
if (rootsAbs.length === 0) {
|
|
@@ -5804,7 +5955,13 @@ async function summarizeOrientation(input) {
|
|
|
5804
5955
|
const decisionTitles = (bucket?.decisions ?? []).filter((d) => !voidedDecisionIds.has(d.decisionId)).map((d) => d.title);
|
|
5805
5956
|
const notes = bucket?.notes ?? [];
|
|
5806
5957
|
const hasIntent = decisionTitles.length > 0 || notes.length > 0;
|
|
5807
|
-
const files = hasIntent ? [] : [
|
|
5958
|
+
const files = hasIntent ? [] : [
|
|
5959
|
+
...new Set(
|
|
5960
|
+
(entry.session.session.related_files ?? []).filter(
|
|
5961
|
+
(file) => !isTransientToolPath(file)
|
|
5962
|
+
)
|
|
5963
|
+
)
|
|
5964
|
+
].sort().slice(0, FILES_PER_DIGEST);
|
|
5808
5965
|
return {
|
|
5809
5966
|
sessionId: entry.sessionId,
|
|
5810
5967
|
label: entry.session.session.label ?? null,
|
|
@@ -5875,8 +6032,10 @@ async function summarizeOrientation(input) {
|
|
|
5875
6032
|
} catch {
|
|
5876
6033
|
sourceRoots = null;
|
|
5877
6034
|
}
|
|
5878
|
-
const
|
|
6035
|
+
const recordedFiles = latestEntry?.session.session.related_files ?? [];
|
|
6036
|
+
const latestFiles = recordedFiles.filter((file) => !isTransientToolPath(file));
|
|
5879
6037
|
const uniqueFiles = new Set(latestFiles);
|
|
6038
|
+
const omittedFiles = new Set(recordedFiles).size - uniqueFiles.size;
|
|
5880
6039
|
const sortedFiles = [...uniqueFiles].sort();
|
|
5881
6040
|
const displayed = sortedFiles.slice(0, limit);
|
|
5882
6041
|
const overflow = Math.max(0, uniqueFiles.size - limit);
|
|
@@ -5907,7 +6066,7 @@ async function summarizeOrientation(input) {
|
|
|
5907
6066
|
openTracks,
|
|
5908
6067
|
latestNote,
|
|
5909
6068
|
recentDirection,
|
|
5910
|
-
relatedFiles: { displayed, overflow, outOfRoot },
|
|
6069
|
+
relatedFiles: { displayed, overflow, outOfRoot, omitted: omittedFiles },
|
|
5911
6070
|
inFlightTasks,
|
|
5912
6071
|
plannedTasks,
|
|
5913
6072
|
pendingApprovals,
|
|
@@ -5995,10 +6154,16 @@ function formatOrientationBody(summary, opts) {
|
|
|
5995
6154
|
`- ${t.common.latestDecisionLabel}: (no decisions recorded yet; capture with \`basou decision capture\`)`
|
|
5996
6155
|
);
|
|
5997
6156
|
}
|
|
5998
|
-
if (summary.relatedFiles.displayed.length > 0) {
|
|
5999
|
-
const
|
|
6000
|
-
|
|
6001
|
-
|
|
6157
|
+
if (summary.relatedFiles.displayed.length > 0 || summary.relatedFiles.omitted > 0) {
|
|
6158
|
+
const parts = [];
|
|
6159
|
+
if (summary.relatedFiles.displayed.length > 0) {
|
|
6160
|
+
const more = summary.relatedFiles.overflow > 0 ? ` (... +${summary.relatedFiles.overflow} more)` : "";
|
|
6161
|
+
parts.push(`${summary.relatedFiles.displayed.join(", ")}${more}`);
|
|
6162
|
+
}
|
|
6163
|
+
if (summary.relatedFiles.omitted > 0) {
|
|
6164
|
+
parts.push(t.orientation.scratchOmitted(summary.relatedFiles.omitted));
|
|
6165
|
+
}
|
|
6166
|
+
lines.push(`- ${t.common.recentFilesLabel}: ${parts.join(" ")}`);
|
|
6002
6167
|
if (summary.relatedFiles.outOfRoot.length > 0) {
|
|
6003
6168
|
const OUT_OF_ROOT_DISPLAY = 10;
|
|
6004
6169
|
const out = summary.relatedFiles.outOfRoot;
|
|
@@ -6247,9 +6412,9 @@ function suspectText(reason) {
|
|
|
6247
6412
|
return "suspect";
|
|
6248
6413
|
}
|
|
6249
6414
|
function shortId(id) {
|
|
6250
|
-
const
|
|
6251
|
-
if (
|
|
6252
|
-
return id.slice(0,
|
|
6415
|
+
const sep2 = id.indexOf("_");
|
|
6416
|
+
if (sep2 === -1) return id.slice(0, 10);
|
|
6417
|
+
return id.slice(0, sep2 + 1) + id.slice(sep2 + 1, sep2 + 1 + 10);
|
|
6253
6418
|
}
|
|
6254
6419
|
|
|
6255
6420
|
// src/project/anchor-starter.ts
|
|
@@ -9451,6 +9616,10 @@ export {
|
|
|
9451
9616
|
PROTOCOL_START,
|
|
9452
9617
|
REVIEW_RECORD_NO_INPUT_HINT,
|
|
9453
9618
|
RiskLevelSchema,
|
|
9619
|
+
SESSION_START_HOOK_CONTEXT_LIMIT,
|
|
9620
|
+
SESSION_START_HOOK_MATCHER,
|
|
9621
|
+
SESSION_START_HOOK_STATUS_MESSAGE,
|
|
9622
|
+
SESSION_START_HOOK_TIMEOUT_SECONDS,
|
|
9454
9623
|
STOP_HOOK_TIMEOUT_SECONDS,
|
|
9455
9624
|
STUCK_THRESHOLD_MS,
|
|
9456
9625
|
SchemaVersionSchema,
|
|
@@ -9480,6 +9649,7 @@ export {
|
|
|
9480
9649
|
buildJsonSchemas,
|
|
9481
9650
|
buildReviewRecordLabel,
|
|
9482
9651
|
buildReviewRecordedEvent,
|
|
9652
|
+
buildSessionStartHookCommand,
|
|
9483
9653
|
buildStatusSnapshot,
|
|
9484
9654
|
buildStopHookCommand,
|
|
9485
9655
|
chainEvents,
|
|
@@ -9504,6 +9674,7 @@ export {
|
|
|
9504
9674
|
enumerateTaskIds,
|
|
9505
9675
|
evaluateStopHook,
|
|
9506
9676
|
finalizeSessionYaml,
|
|
9677
|
+
findBasouSessionStartHook,
|
|
9507
9678
|
findBasouStopHookCommand,
|
|
9508
9679
|
findErrorCode,
|
|
9509
9680
|
findReviewGaps,
|
|
@@ -9515,6 +9686,7 @@ export {
|
|
|
9515
9686
|
importSessionFromJson,
|
|
9516
9687
|
inspectChainTail,
|
|
9517
9688
|
instructionMode,
|
|
9689
|
+
isBasouSessionStartHookCommand,
|
|
9518
9690
|
isBasouStopHookCommand,
|
|
9519
9691
|
isGitNotFound,
|
|
9520
9692
|
isImportDerivedSource,
|
|
@@ -9556,6 +9728,7 @@ export {
|
|
|
9556
9728
|
refreshTaskLinkedSessions,
|
|
9557
9729
|
reimportPreservingId,
|
|
9558
9730
|
removeMarkerSection,
|
|
9731
|
+
removeSessionStartHook,
|
|
9559
9732
|
removeStopHook,
|
|
9560
9733
|
renderAnchorStarter,
|
|
9561
9734
|
renderDecisions,
|
|
@@ -9596,6 +9769,7 @@ export {
|
|
|
9596
9769
|
ulid,
|
|
9597
9770
|
unknownManifestKeys,
|
|
9598
9771
|
updateTaskStatusWithEvent,
|
|
9772
|
+
upsertSessionStartHook,
|
|
9599
9773
|
upsertStopHook,
|
|
9600
9774
|
verifyEventsChain,
|
|
9601
9775
|
viewStrings,
|