@basou/core 0.38.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
@@ -107,21 +107,12 @@ declare function removeStopHook(settings: unknown): StopHookRemoval;
107
107
  declare function findBasouStopHookCommand(settings: unknown): string | null;
108
108
 
109
109
  /**
110
- * Schema for `.basou/manifest.yaml`. The minimal manifest carries
111
- * schema_version, basou_version, workspace metadata, project info, enabled
112
- * capabilities, approval policy, adapter config, and git policy. The
113
- * `adapters."claude-code"` key uses a hyphen; downstream code accesses it
114
- * via bracket notation.
115
- *
116
- * Every object here is `looseObject` (NOT the default strip), so unknown keys
117
- * at every level survive parse. The manifest is the declarative source of truth
118
- * and is git-tracked and read-modify-written by `basou project` commands; with
119
- * the default strip, a field this basou does not recognize — a newer version's
120
- * additive field, a future adapter under `adapters`, a hand-added key — would be
121
- * silently dropped on the next write. Preserving them keeps basou from destroying
122
- * config it does not understand (forward-compatible), while known fields are still
123
- * fully type-checked and validated. {@link unknownManifestKeys} surfaces the
124
- * unrecognized top-level keys so preservation is not silent.
110
+ * The manifest, plus one guard the loose object cannot express: a TOP-LEVEL
111
+ * `confidential` is refused. It belongs under `policies`, and because the
112
+ * object is loose, a stray top-level spelling would otherwise parse fine and be
113
+ * silently ignored an operator would believe the workspace is protected while
114
+ * the face is still written. A safety key that is not honoured must fail
115
+ * loudly, not quietly.
125
116
  */
126
117
  declare const ManifestSchema: z.ZodObject<{
127
118
  schema_version: z.ZodString;
@@ -197,6 +188,12 @@ declare const ManifestSchema: z.ZodObject<{
197
188
  self: "self";
198
189
  }>>;
199
190
  }, z.core.$loose>>>;
191
+ channels: z.ZodOptional<z.ZodObject<{
192
+ codex: z.ZodOptional<z.ZodBoolean>;
193
+ }, z.core.$loose>>;
194
+ policies: z.ZodOptional<z.ZodObject<{
195
+ confidential: z.ZodOptional<z.ZodBoolean>;
196
+ }, z.core.$loose>>;
200
197
  }, z.core.$loose>;
201
198
  /** Inferred runtime type for {@link ManifestSchema}. */
202
199
  type Manifest = z.infer<typeof ManifestSchema>;
@@ -821,6 +818,110 @@ declare function resolveCodexCommand(lookup?: CommandLookup): Promise<{
821
818
  command: string;
822
819
  }>;
823
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
+
824
925
  /**
825
926
  * The `source` string stamped on every event derived from an OpenAI Codex
826
927
  * native rollout log, and the matching session `source.kind`.
@@ -6880,4 +6981,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
6880
6981
  */
6881
6982
  declare const BASOU_CORE_VERSION = "0.1.0";
6882
6983
 
6883
- 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) {
@@ -1782,7 +1911,30 @@ var WorkspaceMetaSchema = z4.looseObject({
1782
1911
  */
1783
1912
  view: SourceRootSchema.optional()
1784
1913
  });
1785
- var ManifestSchema = z4.looseObject({
1914
+ var ChannelsSchema = z4.looseObject({
1915
+ /** Retired (see above). Parsed for compatibility; has no effect. */
1916
+ codex: z4.boolean().optional().meta({
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`)."
1918
+ })
1919
+ });
1920
+ var PoliciesSchema = z4.looseObject({
1921
+ /**
1922
+ * This workspace's provenance must not persist where another workspace's
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.
1932
+ */
1933
+ confidential: z4.boolean().optional().meta({
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."
1935
+ })
1936
+ });
1937
+ var ManifestObjectSchema = z4.looseObject({
1786
1938
  schema_version: SchemaVersionSchema,
1787
1939
  // Same forward-compatible format gate as schema_version (accept 0.x.y, gate a
1788
1940
  // higher major with an upgrade error) rather than a hard literal. `basou_version`
@@ -1796,9 +1948,20 @@ var ManifestSchema = z4.looseObject({
1796
1948
  adapters: AdaptersSchema,
1797
1949
  git: GitConfigSchema,
1798
1950
  import: ImportConfigSchema.optional(),
1799
- repos: z4.array(RepoEntrySchema).min(1).optional()
1951
+ repos: z4.array(RepoEntrySchema).min(1).optional(),
1952
+ channels: ChannelsSchema.optional(),
1953
+ policies: PoliciesSchema.optional()
1954
+ });
1955
+ var ManifestSchema = ManifestObjectSchema.superRefine((manifest, ctx) => {
1956
+ if ("confidential" in manifest) {
1957
+ ctx.addIssue({
1958
+ code: "custom",
1959
+ path: ["confidential"],
1960
+ message: "`confidential` is declared under `policies` (policies.confidential: true). A top-level `confidential` is not honoured, so it is rejected rather than ignored."
1961
+ });
1962
+ }
1800
1963
  });
1801
- var KNOWN_TOP_LEVEL_KEYS = new Set(Object.keys(ManifestSchema.shape));
1964
+ var KNOWN_TOP_LEVEL_KEYS = new Set(Object.keys(ManifestObjectSchema.shape));
1802
1965
  function unknownManifestKeys(manifest) {
1803
1966
  return Object.keys(manifest).filter((k) => !KNOWN_TOP_LEVEL_KEYS.has(k)).sort();
1804
1967
  }
@@ -9412,6 +9575,10 @@ export {
9412
9575
  PROTOCOL_START,
9413
9576
  REVIEW_RECORD_NO_INPUT_HINT,
9414
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,
9415
9582
  STOP_HOOK_TIMEOUT_SECONDS,
9416
9583
  STUCK_THRESHOLD_MS,
9417
9584
  SchemaVersionSchema,
@@ -9441,6 +9608,7 @@ export {
9441
9608
  buildJsonSchemas,
9442
9609
  buildReviewRecordLabel,
9443
9610
  buildReviewRecordedEvent,
9611
+ buildSessionStartHookCommand,
9444
9612
  buildStatusSnapshot,
9445
9613
  buildStopHookCommand,
9446
9614
  chainEvents,
@@ -9465,6 +9633,7 @@ export {
9465
9633
  enumerateTaskIds,
9466
9634
  evaluateStopHook,
9467
9635
  finalizeSessionYaml,
9636
+ findBasouSessionStartHook,
9468
9637
  findBasouStopHookCommand,
9469
9638
  findErrorCode,
9470
9639
  findReviewGaps,
@@ -9476,6 +9645,7 @@ export {
9476
9645
  importSessionFromJson,
9477
9646
  inspectChainTail,
9478
9647
  instructionMode,
9648
+ isBasouSessionStartHookCommand,
9479
9649
  isBasouStopHookCommand,
9480
9650
  isGitNotFound,
9481
9651
  isImportDerivedSource,
@@ -9517,6 +9687,7 @@ export {
9517
9687
  refreshTaskLinkedSessions,
9518
9688
  reimportPreservingId,
9519
9689
  removeMarkerSection,
9690
+ removeSessionStartHook,
9520
9691
  removeStopHook,
9521
9692
  renderAnchorStarter,
9522
9693
  renderDecisions,
@@ -9557,6 +9728,7 @@ export {
9557
9728
  ulid,
9558
9729
  unknownManifestKeys,
9559
9730
  updateTaskStatusWithEvent,
9731
+ upsertSessionStartHook,
9560
9732
  upsertStopHook,
9561
9733
  verifyEventsChain,
9562
9734
  viewStrings,