@basou/core 0.39.0 → 0.40.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 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`.
@@ -6877,4 +6981,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
6877
6981
  */
6878
6982
  declare const BASOU_CORE_VERSION = "0.1.0";
6879
6983
 
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 };
6984
+ 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: "Opt in to rendering this workspace's orientation into the user-global ~/.codex/AGENTS.md on `basou refresh` and `basou run codex`. Off when absent: that file is auto-loaded by Codex for every project on the machine, so nothing is written there unless the workspace says so."
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; what it gates today is one
1800
- * thing: rendering the orientation into the user-global `~/.codex/AGENTS.md`
1801
- * (`basou refresh` / `basou run codex`) never, regardless of `channels`, so
1802
- * a confidential workspace cannot be re-enabled by a second declaration in
1803
- * the same file. It does not yet govern `basou protocol sync` (a global
1804
- * render, not a per-workspace one), and it gates writing only: it cannot keep
1805
- * another workspace's block out of this workspace's tool (see `basou channel
1806
- * clear`). Stated as a goal rather than as "never write" so that a transient
1807
- * render removed before anyone else can read it remains permissible.
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: "This workspace's provenance must not persist where another workspace's tool reads it. Today this means its orientation is never rendered into the user-global ~/.codex/AGENTS.md by `basou refresh` or `basou run codex`, regardless of `channels`. It does not yet govern `basou protocol sync`, and it gates writing only \u2014 it cannot keep another workspace's block out of this workspace's tool."
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({
@@ -9451,6 +9575,10 @@ export {
9451
9575
  PROTOCOL_START,
9452
9576
  REVIEW_RECORD_NO_INPUT_HINT,
9453
9577
  RiskLevelSchema,
9578
+ SESSION_START_HOOK_CONTEXT_LIMIT,
9579
+ SESSION_START_HOOK_MATCHER,
9580
+ SESSION_START_HOOK_STATUS_MESSAGE,
9581
+ SESSION_START_HOOK_TIMEOUT_SECONDS,
9454
9582
  STOP_HOOK_TIMEOUT_SECONDS,
9455
9583
  STUCK_THRESHOLD_MS,
9456
9584
  SchemaVersionSchema,
@@ -9480,6 +9608,7 @@ export {
9480
9608
  buildJsonSchemas,
9481
9609
  buildReviewRecordLabel,
9482
9610
  buildReviewRecordedEvent,
9611
+ buildSessionStartHookCommand,
9483
9612
  buildStatusSnapshot,
9484
9613
  buildStopHookCommand,
9485
9614
  chainEvents,
@@ -9504,6 +9633,7 @@ export {
9504
9633
  enumerateTaskIds,
9505
9634
  evaluateStopHook,
9506
9635
  finalizeSessionYaml,
9636
+ findBasouSessionStartHook,
9507
9637
  findBasouStopHookCommand,
9508
9638
  findErrorCode,
9509
9639
  findReviewGaps,
@@ -9515,6 +9645,7 @@ export {
9515
9645
  importSessionFromJson,
9516
9646
  inspectChainTail,
9517
9647
  instructionMode,
9648
+ isBasouSessionStartHookCommand,
9518
9649
  isBasouStopHookCommand,
9519
9650
  isGitNotFound,
9520
9651
  isImportDerivedSource,
@@ -9556,6 +9687,7 @@ export {
9556
9687
  refreshTaskLinkedSessions,
9557
9688
  reimportPreservingId,
9558
9689
  removeMarkerSection,
9690
+ removeSessionStartHook,
9559
9691
  removeStopHook,
9560
9692
  renderAnchorStarter,
9561
9693
  renderDecisions,
@@ -9596,6 +9728,7 @@ export {
9596
9728
  ulid,
9597
9729
  unknownManifestKeys,
9598
9730
  updateTaskStatusWithEvent,
9731
+ upsertSessionStartHook,
9599
9732
  upsertStopHook,
9600
9733
  verifyEventsChain,
9601
9734
  viewStrings,